diff options
Diffstat (limited to 'tests')
900 files changed, 42848 insertions, 9477 deletions
diff --git a/tests/auto/android/runtests_androiddeployqt.pl b/tests/auto/android/runtests_androiddeployqt.pl deleted file mode 100755 index 24b44cf9b2..0000000000 --- a/tests/auto/android/runtests_androiddeployqt.pl +++ /dev/null @@ -1,550 +0,0 @@ -#!/usr/bin/perl -w -############################################################################# -## -## Copyright (C) 2012-2013 BogDan Vatra <bogdan@kde.org> -## Copyright (C) 2016 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of the test suite of the Qt Toolkit. -## -## $QT_BEGIN_LICENSE:GPL-EXCEPT$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. -## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 3 as published by the Free Software -## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-3.0.html. -## -## $QT_END_LICENSE$ -## -############################################################################# - -use Cwd; -use Cwd 'abs_path'; -use File::Basename; -use File::Temp 'tempdir'; -use File::Path 'remove_tree'; -use Getopt::Long; -use Pod::Usage; -use XML::Simple; -use Term::ANSIColor; - -### default options -my @stack = cwd; -my $device_serial=""; # "-s device_serial"; -my $deployqt_device_serial=""; # "-device device_serial"; -my $log_out="xml"; -my $max_runtime = 5; -my $className="org.qtproject.qt5.android.bindings.QtActivity"; -my $jobs = 4; -my $testsubset = ""; -my $man = 0; -my $help = 0; -my $make_clean = 0; -my $stop_on_fail = 0; -my $time_out=400; -my $android_toolchain_version = "4.8"; -my $host_arch = "linux-x86"; -my $android_sdk_dir = "$ENV{'ANDROID_SDK_ROOT'}"; -my $android_ndk_dir = "$ENV{'ANDROID_NDK_ROOT'}"; -my $android_to_connect = "$ENV{'ANDROID_DEVICE'}"; -my $ant_tool = `which ant`; -my $silent = 0; -chomp $ant_tool; -my $strip_tool=""; -my $readelf_tool=""; -# for ci usage -my @failures = ''; -my $total_tests = 0; -my $total_failed = 0; -my $failed_insignificants = 0; -my $ci_use = 0; -my $start = time(); -my $uninstall = 0; - -GetOptions('h|help' => \$help - , man => \$man - , 's|serial=s' => \$device_serial - , 't|test=s' => \$testsubset - , 'c|clean' => \$make_clean - , 'j|jobs=i' => \$jobs - , 'logtype=s' => \$log_out - , 'runtime=i' => \$max_runtime - , 'sdk=s' => \$android_sdk_dir - , 'ndk=s' => \$android_ndk_dir - , 'toolchain=s' => \$android_toolchain_version - , 'host=s' => \$host_arch - , 'ant=s' => \$ant_tool - , 'strip=s' => \$strip_tool - , 'readelf=s' => \$readelf_tool - , 'testcase=s' => \$testcase - , 'f|fail' => sub { $stop_on_fail = 1 } - , 'silent' => sub { $silent = 1 } - , 'ci' => sub { $ci_use = 1 } - , 'uninstall' => sub { $uninstall = 1 } - ) or pod2usage(2); -pod2usage(1) if $help; -pod2usage(-verbose => 2) if $man; - -if ($ci_use){ - use QMake::Project; -} -my $adb_tool="$android_sdk_dir/platform-tools/adb"; - -# For CI. Nodes are connecting to test devices over IP, which is stored to env variable -if ($android_to_connect ne ""){ - print " Found device to be connected from env: $android_to_connect \n"; - system("$adb_tool disconnect $android_to_connect"); - system("$adb_tool connect $android_to_connect"); - sleep(2);# let it connect - system("$adb_tool -s $android_to_connect reboot &");# adb bug, it blocks forever - sleep(15); # wait for the device to come up again - system("$adb_tool disconnect $android_to_connect");# cleans up the left adb reboot process - system("$adb_tool connect $android_to_connect"); - $device_serial =$android_to_connect; -} - -system("$adb_tool devices") == 0 or die "No device found, please plug/start at least one device/emulator\n"; # make sure we have at least on device attached - -$deployqt_device_serial = "--device $device_serial" if ($device_serial); -$device_serial = "-s $device_serial" if ($device_serial); -$testsubset="/$testsubset" if ($testsubset); - -$strip_tool="$android_ndk_dir/toolchains/arm-linux-androideabi-$android_toolchain_version/prebuilt/$host_arch/bin/arm-linux-androideabi-strip" unless($strip_tool); -$readelf_tool="$android_ndk_dir/toolchains/arm-linux-androideabi-$android_toolchain_version/prebuilt/$host_arch/bin/arm-linux-androideabi-readelf" unless($readelf_tool); -$readelf_tool="$readelf_tool -d -w "; - -sub dir -{ -# print "@stack\n"; -} - -sub pushd ($) -{ - unless ( chdir $_[0] ) - { - warn "Error: $!\n"; - return; - } - unshift @stack, cwd; - dir; -} - -sub popd () -{ - @stack > 1 and shift @stack; - chdir $stack[0]; - dir; -} - -############################## -# Read possible insignificance -# from pro file -############################## -sub check_if_insignificant -{ - return 0 if ( !$ci_use ); - my $case = shift; - my $insignificant = 0; - my $prj = QMake::Project->new( 'Makefile' ); - $insignificant = $prj->test( 'insignificant_test' ); - return $insignificant; -} - -############################## -# Print output from given -# $testresult.txt file -############################## -sub print_output -{ - my $res_file = shift; - my $case = shift; - my $insignificant = shift; - my $print_all = 0; - $total_tests++; - if (-e $res_file) { - open my $file, $res_file or die "Could not open $res_file: $!"; - while (my $line = <$file>) { - if ($line =~ m/^FAIL/) { - print "$line"; - # Pretend to be like the "real" testrunner and print out - # all steps - $print_all = 1; - } - } - close $file; - if ($print_all) { - # In case we are printing all, the test failed - system("cat $res_file"); - if ($insignificant) { - print " Testrunner: $case failed, but it is marked with insignificant_test\n"; - push (@failures ,(basename($case)." [insignificant]")); - $failed_insignificants++; - } else { - $total_failed++; - push (@failures ,(basename($case))); - } - } else { - my $cmd = "sed -n 'x;\$p' ${res_file}"; - my $summary = qx(${cmd}); - if ($summary =~ m/^Totals/) { - print "$summary"; - } else { - print "Error: The log is incomplete. Looks like you have to increase the timeout."; - # The test log seems inclomplete, considering the test as failed. - if ($insignificant) { - print " Testrunner: $case failed, but it is marked with insignificant_test\n"; - push (@failures ,(basename($case)." [insignificant]")); - $failed_insignificants++; - } else { - $total_failed++; - push (@failures ,(basename($case))); - } - } - } - } else { - if ($insignificant) { - print " Failed to execute $case, but it is marked with insignificant_test\n"; - push (@failures ,(basename($case)." [insignificant]")); - $failed_insignificants++; - } else { - print "Failed to execute $case \n"; - $total_failed++; - push (@failures ,(basename($case))); - } - } -} - -############################## -# Print summary of test run -############################## - -sub print_summary -{ - my $total = time()-$start; - my $h = 0; - my $m = 0; - my $s = 0; - my $exit = 0; - print "=== Timing: =================== TEST RUN COMPLETED! ============================\n"; - if ($total > 60*60) { - $h = int($total/60/60); - $s = int($total - $h*60*60); - - $m = int($s/60); - $s = 0; - print "Total: $h hours $m minutes\n"; - } elsif ($total > 60) { - $m = int($total/60); - $s = int($total - $m*60); - print "Total: $m minutes $s seconds\n"; - } else { - $s = int($total); - print "Total: $s seconds\n"; - } - - print "=== Failures: =================================================================="; - foreach my $failed (@failures) { - print $failed."\n"; - $exit = 1; - } - print "=== Totals: ".$total_tests." tests, ".($total_tests-$total_failed). - " passes, ".$failed_insignificants. - " insignificant fails ======================\n"; - return $exit; -} - - -sub waitForProcess -{ - my $process=shift; - my $action=shift; - my $timeout=shift; - my $sleepPeriod=shift; - $sleepPeriod=1 if !defined($sleepPeriod); - print "Waiting for $process ".$timeout*$sleepPeriod." seconds to" if (!$silent); - print $action?" start...\n":" die...\n" if (!$silent); - while ($timeout--) - { - my $output = `$adb_tool $device_serial shell ps 2>&1`; # get current processes - #FIXME check why $output is not matching m/.*S $process\n/ or m/.*S $process$/ (eol) - my $res=($output =~ m/.*S $process/)?1:0; # check the procress - if ($action == $res) - { - print "... succeed\n" if (!$silent); - return 1; - } - sleep($sleepPeriod); - print "timeount in ".$timeout*$sleepPeriod." seconds\n" if (!$silent); - } - print "... failed\n" if (!$silent); - return 0; -} - -my $src_dir_qt=abs_path(dirname($0)."/../../.."); -my $quadruplor_dir="$src_dir_qt/tests/auto/android"; -my $qmake_path="$src_dir_qt/bin/qmake"; -my $androiddeployqt_path="$src_dir_qt/bin/androiddeployqt"; -my $tests_dir="$src_dir_qt/tests$testsubset"; -my $temp_dir=tempdir(CLEANUP => 1); -my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); -my $output_dir=$stack[0]."/".(1900+$year)."-$mon-$mday-$hour:$min"; -mkdir($output_dir); -unlink("latest"); -system(" ln -s $output_dir latest"); -my $sdk_api=0; -my $output = `$adb_tool $device_serial shell getprop`; # get device properties -if ($output =~ m/.*\[ro.build.version.sdk\]: \[(\d+)\]/) -{ - $sdk_api=int($1); - $sdk_api=5 if ($sdk_api>5 && $sdk_api<8); - $sdk_api=9 if ($sdk_api>9); -} - -sub checkXMLOutput -{ - print color 'bold red'; - my $fileName = shift; - my $XMLOutput = eval { XMLin($fileName, ForceArray => 1) }; - if (!defined($XMLOutput)) { - print "Can't parse the $fileName file, probably the test crased.\n"; - print color 'reset'; - die "Stopping\n" if $stop_on_fail; - return; - } - my $testName = $XMLOutput->{name}; - my $fail = 0; - while (my($node_key, $node_valule) = each (%{$XMLOutput})) { - next if $node_key ne "TestFunction"; - while (my($function_key, $function_valule) = each (%{$node_valule})) { - while (my($test_key, $test_valule) = each (%{$function_valule})) { - next if $test_key ne "Incident"; - for my $incident (@{$test_valule}) { - if (($incident->{type} ne "pass") && ($incident->{type} ne "xfail")) { - print "test $testName::$function_key failed $incident->{file}:$incident->{line}\n"; - $fail = 1; - } - } - } - } - } - print color 'reset'; - die "Stopping\n" if $stop_on_fail and $fail; -} - -sub startTest -{ - my $testName = shift; - my $packageName = "org.qtproject.example.tst_$testName"; - my $intentName = "$packageName/org.qtproject.qt5.android.bindings.QtActivity"; - my $output_file = shift; - my $insignificance = shift; - my $get_xml= 0; - my $get_txt= 0; - my $testLib =""; - if ($log_out eq "xml") { - $testLib="-o /data/data/$packageName/output.xml,xml"; - $get_xml = 1; - } elsif ($log_out eq "txt") { - $testLib="-o /data/data/$packageName/output.txt,txt"; - $get_txt = 1; - } else { - $testLib="-o /data/data/$packageName/output.xml,xml -o /data/data/$packageName/output.txt,txt"; - $get_xml = 1; - $get_txt = 1; - } - - my $cmd="${adb_tool} ${device_serial} shell am start -e applicationArguments \"${testLib}\" -n ${intentName}"; - my $res = qx(${cmd}); - print $res if (!$silent); - #wait to start (if it has not started and quit already) - waitForProcess($packageName,1,10); - - #wait to stop - unless(waitForProcess($packageName,0,$time_out,5)) - { - #killProcess($packageName); - print "Someone should kill $packageName\n"; - system("$adb_tool $device_serial uninstall $packageName") if ($uninstall); - return 1; - } - - # Wait for three seconds to allow process to write all data - sleep(3); - - system("$adb_tool $device_serial pull /data/data/$packageName/output.xml $output_dir/$output_file.xml") if ($get_xml); - - system("$adb_tool $device_serial pull /data/data/$packageName/output.txt $output_dir/$output_file.txt") if ($get_txt); - if ($get_txt){ - print "Test results for $packageName:\n"; - my $insig = - print_output("$output_dir/$output_file.txt", $packageName, $insignificance); - } - system("$adb_tool $device_serial uninstall $packageName") if ($uninstall); - - checkXMLOutput("$output_dir/$output_file.xml") if ($get_xml); - return 1; -} - -########### build qt tests and benchmarks ########### -pushd($tests_dir); -print "Building $tests_dir \n"; -system("make distclean") if ($make_clean); -system("$qmake_path -r") == 0 or die "Can't run qmake\n"; #exec qmake -system("make -j$jobs") == 0 or warn "Can't build all tests\n"; #exec make - -my $testsFiles = ""; -if ($testcase) { - $testsFiles=`find . -name libtst_$testcase.so`; # only tests -} else { - $testsFiles=`find . -name libtst_*.so`; # only tests -} - -foreach (split("\n",$testsFiles)) -{ - chomp; #remove white spaces - pushd(abs_path(dirname($_))); # cd to application dir - my $insig = check_if_insignificant(); - my $cmd="make INSTALL_ROOT=${temp_dir} install"; - my $res = qx(${cmd}); - print $res if (!$silent); - my $application=basename(cwd); - if ($silent) { - $cmd="$androiddeployqt_path --install ${deployqt_device_serial} --output ${temp_dir} --deployment debug --verbose --input android-libtst_${application}.so-deployment-settings.json >/dev/null 2>&1"; - } else { - $cmd="$androiddeployqt_path --install ${deployqt_device_serial} --output ${temp_dir} --deployment debug --verbose --input android-libtst_${application}.so-deployment-settings.json"; - } - $res = qx(${cmd}); - print $res if (!$silent); - my $output_name=dirname($_); - $output_name =~ s/\.//; # remove first "." character - $output_name =~ s/\///; # remove first "/" character - $output_name =~ s/\//_/g; # replace all "/" with "_" - $output_name=$application unless($output_name); - $time_out=$max_runtime*60/5; # 5 minutes time out for a normal test - - $applicationLibrary = `find $temp_dir -name libtst_bench_$application.so`; - - if ($applicationLibrary) - { - $time_out=5*60/5; # 10 minutes for a benchmark - $application = "bench_$application"; - } - else - { - $applicationLibrary = `find $temp_dir -name libtst_$application.so`; - } - - if (!$applicationLibrary) - { - print "Can't find application binary libtst_$application.so in $temp_dir!\n"; - } - else - { - startTest($application, "$output_name", $insig) or warn "Can't run $application ...\n"; - } - - popd(); - remove_tree( $temp_dir, {keep_root => 1} ); -} -print_summary() if ($ci_use); -popd(); - -__END__ - -=head1 NAME - -Script to run all qt tests/benchmarks to an android device/emulator - -=head1 SYNOPSIS - -runtests.pl [options] - -=head1 OPTIONS - -=over 8 -=item B<-f --fail> - -Stop the script when test fails. Default 0 - -=item B<-s --serial = serial> - -Device serial number. May be empty if only one device is attached. - -=item B<-t --test = test_subset> - -Tests subset (e.g. benchmarks, auto, auto/qbuffer, etc.). - -=item B<-c --clean> - -Clean tests before building them. - -=item B<-j --jobs = number> - -Make jobs when building tests. - -=item B<--sdk = sdk_path> - -Android SDK path. - -=item B<--ndk = ndk_path> - -Android NDK path. - -=item B<--ant = ant_tool_path> - -Ant tool path. - -=item B<--strip = strip_tool_path> - -Android strip tool path, used to deploy qt libs. - -=item B<--readelf = readelf_tool_path> - -Android readelf tool path, used to check if a test application uses qt OpenGL. - -=item B<--logtype = xml|txt|both> - -The format of log file, default is xml. - -=item B<--runtime = minutes> - -The timeout period before stopping individual tests from running. - -=item B<-silent> - -Suppress output of system commands. - -=item B<-ci> - -Enables checking if test is insignificant or not. Also prints test -summary after all tests has been executed. - -=item B<-uninstall> - -Uninstalls the test after has been executed. - -=item B<-h --help> - -Print a brief help message and exits. - -=item B<--man> - -Prints the manual page and exits. - -=back - -=head1 DESCRIPTION - -B<This program> will run all qt tests/benchmarks to an android device/emulator. - -=cut diff --git a/tests/auto/cmake/CMakeLists.txt b/tests/auto/cmake/CMakeLists.txt index 5b10a74d3f..ed900f7805 100644 --- a/tests/auto/cmake/CMakeLists.txt +++ b/tests/auto/cmake/CMakeLists.txt @@ -160,3 +160,5 @@ if (NOT CMAKE_VERSION VERSION_LESS 3.8) # Reason: SKIP_* properties were added in CMake 3.8 only expect_pass(test_QTBUG-63422) endif() + +expect_pass(test_import_plugins BINARY ${CMAKE_CTEST_COMMAND}) diff --git a/tests/auto/cmake/cmake.pro b/tests/auto/cmake/cmake.pro index 9c715974f8..06509f4ad3 100644 --- a/tests/auto/cmake/cmake.pro +++ b/tests/auto/cmake/cmake.pro @@ -1,7 +1,12 @@ -# Cause make to do nothing. TEMPLATE = subdirs +# installed_cmake includes this file, and tries to add the mockplugins +# directory relative to itself, but doesn't have its own copy of the directory. +# So, we make the path absolute so it includes this copy of the directory +# instead. +SUBDIRS += $$PWD/mockplugins + CMAKE_QT_MODULES_UNDER_TEST = core network xml sql testlib qtHaveModule(dbus): CMAKE_QT_MODULES_UNDER_TEST += dbus diff --git a/tests/auto/cmake/mockplugins/mock1plugin/mock1plugin.json b/tests/auto/cmake/mockplugins/mock1plugin/mock1plugin.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/tests/auto/cmake/mockplugins/mock1plugin/mock1plugin.json @@ -0,0 +1 @@ +{} diff --git a/tests/auto/cmake/mockplugins/mock1plugin/mock1plugin.pro b/tests/auto/cmake/mockplugins/mock1plugin/mock1plugin.pro new file mode 100644 index 0000000000..1ccbe924ae --- /dev/null +++ b/tests/auto/cmake/mockplugins/mock1plugin/mock1plugin.pro @@ -0,0 +1,9 @@ +TARGET = mock1plugin + +HEADERS += qmock1plugin.h +SOURCES += qmock1plugin.cpp +QT = mockplugins1 + +PLUGIN_TYPE = mockplugin +PLUGIN_CLASS_NAME = QMock1Plugin +load(qt_plugin) diff --git a/tests/auto/cmake/mockplugins/mock1plugin/qmock1plugin.cpp b/tests/auto/cmake/mockplugins/mock1plugin/qmock1plugin.cpp new file mode 100644 index 0000000000..2ee817d80a --- /dev/null +++ b/tests/auto/cmake/mockplugins/mock1plugin/qmock1plugin.cpp @@ -0,0 +1,10 @@ +#include "qmock1plugin.h" + +QT_BEGIN_NAMESPACE + +QString QMock1Plugin::pluginName() const +{ + return "QMock1Plugin"; +} + +QT_END_NAMESPACE diff --git a/tests/auto/cmake/mockplugins/mock1plugin/qmock1plugin.h b/tests/auto/cmake/mockplugins/mock1plugin/qmock1plugin.h new file mode 100644 index 0000000000..e2e114b1d9 --- /dev/null +++ b/tests/auto/cmake/mockplugins/mock1plugin/qmock1plugin.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Kitware, Inc. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMOCK1PLUGIN_H +#define QMOCK1PLUGIN_H + +#include <QObject> +#include <QtMockPlugins1/QMockPlugin> + +QT_BEGIN_NAMESPACE + +class QMock1Plugin : public QObject, public QMockPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QMockPlugin_iid FILE "mock1plugin.json") + Q_INTERFACES(QMockPlugin) +public: + QString pluginName() const override; +}; + +QT_END_NAMESPACE + +#endif // QMOCK1PLUGIN_H diff --git a/tests/auto/cmake/mockplugins/mock2plugin/mock2plugin.json b/tests/auto/cmake/mockplugins/mock2plugin/mock2plugin.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/tests/auto/cmake/mockplugins/mock2plugin/mock2plugin.json @@ -0,0 +1 @@ +{} diff --git a/tests/auto/cmake/mockplugins/mock2plugin/mock2plugin.pro b/tests/auto/cmake/mockplugins/mock2plugin/mock2plugin.pro new file mode 100644 index 0000000000..75dc21cf0a --- /dev/null +++ b/tests/auto/cmake/mockplugins/mock2plugin/mock2plugin.pro @@ -0,0 +1,10 @@ +TARGET = mock2plugin + +HEADERS += qmock2plugin.h +SOURCES += qmock2plugin.cpp +QT = mockplugins1 + +PLUGIN_TYPE = mockplugin +PLUGIN_CLASS_NAME = QMock2Plugin +PLUGIN_EXTENDS = mockplugins1 +load(qt_plugin) diff --git a/tests/auto/cmake/mockplugins/mock2plugin/qmock2plugin.cpp b/tests/auto/cmake/mockplugins/mock2plugin/qmock2plugin.cpp new file mode 100644 index 0000000000..5b3280e884 --- /dev/null +++ b/tests/auto/cmake/mockplugins/mock2plugin/qmock2plugin.cpp @@ -0,0 +1,10 @@ +#include "qmock2plugin.h" + +QT_BEGIN_NAMESPACE + +QString QMock2Plugin::pluginName() const +{ + return "QMock2Plugin"; +} + +QT_END_NAMESPACE diff --git a/tests/auto/cmake/mockplugins/mock2plugin/qmock2plugin.h b/tests/auto/cmake/mockplugins/mock2plugin/qmock2plugin.h new file mode 100644 index 0000000000..be99133dc8 --- /dev/null +++ b/tests/auto/cmake/mockplugins/mock2plugin/qmock2plugin.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Kitware, Inc. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMOCK2PLUGIN_H +#define QMOCK2PLUGIN_H + +#include <QObject> +#include <QtMockPlugins1/QMockPlugin> + +QT_BEGIN_NAMESPACE + +class QMock2Plugin : public QObject, public QMockPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QMockPlugin_iid FILE "mock2plugin.json") + Q_INTERFACES(QMockPlugin) +public: + QString pluginName() const override; +}; + +QT_END_NAMESPACE + +#endif // QMOCK2PLUGIN_H diff --git a/tests/auto/cmake/mockplugins/mock3plugin/mock3plugin.json b/tests/auto/cmake/mockplugins/mock3plugin/mock3plugin.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/tests/auto/cmake/mockplugins/mock3plugin/mock3plugin.json @@ -0,0 +1 @@ +{} diff --git a/tests/auto/cmake/mockplugins/mock3plugin/mock3plugin.pro b/tests/auto/cmake/mockplugins/mock3plugin/mock3plugin.pro new file mode 100644 index 0000000000..ed7df603bb --- /dev/null +++ b/tests/auto/cmake/mockplugins/mock3plugin/mock3plugin.pro @@ -0,0 +1,10 @@ +TARGET = mock3plugin + +HEADERS += qmock3plugin.h +SOURCES += qmock3plugin.cpp +QT = mockplugins1 + +PLUGIN_TYPE = mockplugin +PLUGIN_CLASS_NAME = QMock3Plugin +PLUGIN_EXTENDS = mockplugins1 mockplugins2 +load(qt_plugin) diff --git a/tests/auto/cmake/mockplugins/mock3plugin/qmock3plugin.cpp b/tests/auto/cmake/mockplugins/mock3plugin/qmock3plugin.cpp new file mode 100644 index 0000000000..b38f854e4b --- /dev/null +++ b/tests/auto/cmake/mockplugins/mock3plugin/qmock3plugin.cpp @@ -0,0 +1,10 @@ +#include "qmock3plugin.h" + +QT_BEGIN_NAMESPACE + +QString QMock3Plugin::pluginName() const +{ + return "QMock3Plugin"; +} + +QT_END_NAMESPACE diff --git a/tests/auto/cmake/mockplugins/mock3plugin/qmock3plugin.h b/tests/auto/cmake/mockplugins/mock3plugin/qmock3plugin.h new file mode 100644 index 0000000000..08d1aa68ce --- /dev/null +++ b/tests/auto/cmake/mockplugins/mock3plugin/qmock3plugin.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Kitware, Inc. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMOCK3PLUGIN_H +#define QMOCK3PLUGIN_H + +#include <QObject> +#include <QtMockPlugins1/QMockPlugin> + +QT_BEGIN_NAMESPACE + +class QMock3Plugin : public QObject, public QMockPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QMockPlugin_iid FILE "mock3plugin.json") + Q_INTERFACES(QMockPlugin) +public: + QString pluginName() const override; +}; + +QT_END_NAMESPACE + +#endif // QMOCK3PLUGIN_H diff --git a/tests/auto/cmake/mockplugins/mock4plugin/mock4plugin.json b/tests/auto/cmake/mockplugins/mock4plugin/mock4plugin.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/tests/auto/cmake/mockplugins/mock4plugin/mock4plugin.json @@ -0,0 +1 @@ +{} diff --git a/tests/auto/cmake/mockplugins/mock4plugin/mock4plugin.pro b/tests/auto/cmake/mockplugins/mock4plugin/mock4plugin.pro new file mode 100644 index 0000000000..4dd2d6c547 --- /dev/null +++ b/tests/auto/cmake/mockplugins/mock4plugin/mock4plugin.pro @@ -0,0 +1,10 @@ +TARGET = mock4plugin + +HEADERS += qmock4plugin.h +SOURCES += qmock4plugin.cpp +QT = mockplugins1 + +PLUGIN_TYPE = mockplugin +PLUGIN_CLASS_NAME = QMock4Plugin +PLUGIN_EXTENDS = - +load(qt_plugin) diff --git a/tests/auto/cmake/mockplugins/mock4plugin/qmock4plugin.cpp b/tests/auto/cmake/mockplugins/mock4plugin/qmock4plugin.cpp new file mode 100644 index 0000000000..5deaf7f43f --- /dev/null +++ b/tests/auto/cmake/mockplugins/mock4plugin/qmock4plugin.cpp @@ -0,0 +1,10 @@ +#include "qmock4plugin.h" + +QT_BEGIN_NAMESPACE + +QString QMock4Plugin::pluginName() const +{ + return "QMock4Plugin"; +} + +QT_END_NAMESPACE diff --git a/tests/auto/cmake/mockplugins/mock4plugin/qmock4plugin.h b/tests/auto/cmake/mockplugins/mock4plugin/qmock4plugin.h new file mode 100644 index 0000000000..0776bef002 --- /dev/null +++ b/tests/auto/cmake/mockplugins/mock4plugin/qmock4plugin.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Kitware, Inc. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMOCK4PLUGIN_H +#define QMOCK4PLUGIN_H + +#include <QObject> +#include <QtMockPlugins1/QMockPlugin> + +QT_BEGIN_NAMESPACE + +class QMock4Plugin : public QObject, public QMockPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QMockPlugin_iid FILE "mock4plugin.json") + Q_INTERFACES(QMockPlugin) +public: + QString pluginName() const override; +}; + +QT_END_NAMESPACE + +#endif // QMOCK4PLUGIN_H diff --git a/tests/auto/cmake/mockplugins/mock5plugin/mock5plugin.json b/tests/auto/cmake/mockplugins/mock5plugin/mock5plugin.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/tests/auto/cmake/mockplugins/mock5plugin/mock5plugin.json @@ -0,0 +1 @@ +{} diff --git a/tests/auto/cmake/mockplugins/mock5plugin/mock5plugin.pro b/tests/auto/cmake/mockplugins/mock5plugin/mock5plugin.pro new file mode 100644 index 0000000000..29496868fe --- /dev/null +++ b/tests/auto/cmake/mockplugins/mock5plugin/mock5plugin.pro @@ -0,0 +1,10 @@ +TARGET = mock5plugin + +HEADERS += qmock5plugin.h +SOURCES += qmock5plugin.cpp +QT = mockplugins3 + +PLUGIN_TYPE = mockplugin +PLUGIN_CLASS_NAME = QMock5Plugin +PLUGIN_EXTENDS = - +load(qt_plugin) diff --git a/tests/auto/cmake/mockplugins/mock5plugin/qmock5plugin.cpp b/tests/auto/cmake/mockplugins/mock5plugin/qmock5plugin.cpp new file mode 100644 index 0000000000..c5b4620516 --- /dev/null +++ b/tests/auto/cmake/mockplugins/mock5plugin/qmock5plugin.cpp @@ -0,0 +1,10 @@ +#include "qmock5plugin.h" + +QT_BEGIN_NAMESPACE + +QString QMock5Plugin::pluginName() const +{ + return "QMock5Plugin"; +} + +QT_END_NAMESPACE diff --git a/tests/auto/cmake/mockplugins/mock5plugin/qmock5plugin.h b/tests/auto/cmake/mockplugins/mock5plugin/qmock5plugin.h new file mode 100644 index 0000000000..2f387da203 --- /dev/null +++ b/tests/auto/cmake/mockplugins/mock5plugin/qmock5plugin.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Kitware, Inc. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMOCK5PLUGIN_H +#define QMOCK5PLUGIN_H + +#include <QObject> +#include <QtMockPlugins1/QMockPlugin> + +QT_BEGIN_NAMESPACE + +class QMock5Plugin : public QObject, public QMockPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QMockPlugin_iid FILE "mock5plugin.json") + Q_INTERFACES(QMockPlugin) +public: + QString pluginName() const override; +}; + +QT_END_NAMESPACE + +#endif // QMOCK5PLUGIN_H diff --git a/tests/auto/cmake/mockplugins/mock6plugin/mock6plugin.json b/tests/auto/cmake/mockplugins/mock6plugin/mock6plugin.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/tests/auto/cmake/mockplugins/mock6plugin/mock6plugin.json @@ -0,0 +1 @@ +{} diff --git a/tests/auto/cmake/mockplugins/mock6plugin/mock6plugin.pro b/tests/auto/cmake/mockplugins/mock6plugin/mock6plugin.pro new file mode 100644 index 0000000000..140f198811 --- /dev/null +++ b/tests/auto/cmake/mockplugins/mock6plugin/mock6plugin.pro @@ -0,0 +1,9 @@ +TARGET = mock6plugin + +HEADERS += qmock6plugin.h +SOURCES += qmock6plugin.cpp +QT = mockplugins3 + +PLUGIN_TYPE = mockauxplugin +PLUGIN_CLASS_NAME = QMock6Plugin +load(qt_plugin) diff --git a/tests/auto/cmake/mockplugins/mock6plugin/qmock6plugin.cpp b/tests/auto/cmake/mockplugins/mock6plugin/qmock6plugin.cpp new file mode 100644 index 0000000000..4a0329c68a --- /dev/null +++ b/tests/auto/cmake/mockplugins/mock6plugin/qmock6plugin.cpp @@ -0,0 +1,10 @@ +#include "qmock6plugin.h" + +QT_BEGIN_NAMESPACE + +QString QMock6Plugin::pluginName() const +{ + return "QMock6Plugin"; +} + +QT_END_NAMESPACE diff --git a/tests/auto/cmake/mockplugins/mock6plugin/qmock6plugin.h b/tests/auto/cmake/mockplugins/mock6plugin/qmock6plugin.h new file mode 100644 index 0000000000..6b29b6703b --- /dev/null +++ b/tests/auto/cmake/mockplugins/mock6plugin/qmock6plugin.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Kitware, Inc. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMOCK6PLUGIN_H +#define QMOCK6PLUGIN_H + +#include <QObject> +#include <QtMockPlugins3/QMockAuxPlugin> + +QT_BEGIN_NAMESPACE + +class QMock6Plugin : public QObject, public QMockAuxPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QMockAuxPlugin_iid FILE "mock6plugin.json") + Q_INTERFACES(QMockAuxPlugin) +public: + QString pluginName() const override; +}; + +QT_END_NAMESPACE + +#endif // QMOCK6PLUGIN_H diff --git a/tests/auto/cmake/mockplugins/mockplugins.pro b/tests/auto/cmake/mockplugins/mockplugins.pro new file mode 100644 index 0000000000..830d130a05 --- /dev/null +++ b/tests/auto/cmake/mockplugins/mockplugins.pro @@ -0,0 +1,36 @@ +TEMPLATE = subdirs + +src_mock1plugin.subdir = $$PWD/mock1plugin +src_mock1plugin.target = sub-mockplugin1 +src_mock1plugin.depends = mockplugins1 + +src_mock2plugin.subdir = $$PWD/mock2plugin +src_mock2plugin.target = sub-mockplugin2 +src_mock2plugin.depends = mockplugins1 + +src_mock3plugin.subdir = $$PWD/mock3plugin +src_mock3plugin.target = sub-mockplugin3 +src_mock3plugin.depends = mockplugins1 + +src_mock4plugin.subdir = $$PWD/mock4plugin +src_mock4plugin.target = sub-mockplugin4 +src_mock4plugin.depends = mockplugins1 + +src_mock5plugin.subdir = $$PWD/mock5plugin +src_mock5plugin.target = sub-mockplugin5 +src_mock5plugin.depends = mockplugins3 + +src_mock6plugin.subdir = $$PWD/mock6plugin +src_mock6plugin.target = sub-mockplugin6 +src_mock6plugin.depends = mockplugins3 + +SUBDIRS += \ + mockplugins1 \ + mockplugins2 \ + mockplugins3 \ + src_mock1plugin \ + src_mock2plugin \ + src_mock3plugin \ + src_mock4plugin \ + src_mock5plugin \ + src_mock6plugin diff --git a/tests/auto/cmake/mockplugins/mockplugins1/fake.cpp b/tests/auto/cmake/mockplugins/mockplugins1/fake.cpp new file mode 100644 index 0000000000..f95eba6055 --- /dev/null +++ b/tests/auto/cmake/mockplugins/mockplugins1/fake.cpp @@ -0,0 +1,34 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QtGlobal> + +// Empty exported function needed to create .lib on Windows. +Q_DECL_EXPORT void mockplugins1_foo() { + +} diff --git a/tests/auto/cmake/mockplugins/mockplugins1/mockplugins1.pro b/tests/auto/cmake/mockplugins/mockplugins1/mockplugins1.pro new file mode 100644 index 0000000000..dd98937ee3 --- /dev/null +++ b/tests/auto/cmake/mockplugins/mockplugins1/mockplugins1.pro @@ -0,0 +1,10 @@ +TARGET = QtMockPlugins1 +QT = core +MODULE_PLUGIN_TYPES = mockplugin + +# Fake a git_build, to force qmake to run syncqt.pl when doing a standalone tests build +# like it is done in Coin, otherwise module headers would not be generated. +CONFIG += git_build +HEADERS += qmockplugin.h +SOURCES += fake.cpp # Needed to make libtool / ar happy on macOS +load(qt_module) diff --git a/tests/auto/cmake/mockplugins/mockplugins1/qmockplugin.h b/tests/auto/cmake/mockplugins/mockplugins1/qmockplugin.h new file mode 100644 index 0000000000..9427ae9212 --- /dev/null +++ b/tests/auto/cmake/mockplugins/mockplugins1/qmockplugin.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Kitware, Inc. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMOCKPLUGIN_H +#define QMOCKPLUGIN_H + +#include <QString> +#include <QtPlugin> + +QT_BEGIN_NAMESPACE + +#define QMockPlugin_iid "org.qt-project.Qt.Tests.QMockPlugin" + +class QMockPlugin +{ +public: + virtual ~QMockPlugin() {} + virtual QString pluginName() const = 0; +}; + +Q_DECLARE_INTERFACE(QMockPlugin, QMockPlugin_iid) + +QT_END_NAMESPACE + +#endif // QMOCKPLUGIN_H diff --git a/tests/auto/cmake/mockplugins/mockplugins2/fake.cpp b/tests/auto/cmake/mockplugins/mockplugins2/fake.cpp new file mode 100644 index 0000000000..384623d646 --- /dev/null +++ b/tests/auto/cmake/mockplugins/mockplugins2/fake.cpp @@ -0,0 +1,34 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QtGlobal> + +// Empty exported function needed to create .lib on Windows. +Q_DECL_EXPORT void mockplugins2_foo() { + +} diff --git a/tests/auto/cmake/mockplugins/mockplugins2/mockplugins2.pro b/tests/auto/cmake/mockplugins/mockplugins2/mockplugins2.pro new file mode 100644 index 0000000000..1dd03391e8 --- /dev/null +++ b/tests/auto/cmake/mockplugins/mockplugins2/mockplugins2.pro @@ -0,0 +1,4 @@ +TARGET = QtMockPlugins2 +QT = core +SOURCES += fake.cpp # Needed to make libtool / ar happy on macOS +load(qt_module) diff --git a/tests/auto/cmake/mockplugins/mockplugins3/fake.cpp b/tests/auto/cmake/mockplugins/mockplugins3/fake.cpp new file mode 100644 index 0000000000..9ec2b42181 --- /dev/null +++ b/tests/auto/cmake/mockplugins/mockplugins3/fake.cpp @@ -0,0 +1,34 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QtGlobal> + +// Empty exported function needed to create .lib on Windows. +Q_DECL_EXPORT void mockplugins3_foo() { + +} diff --git a/tests/auto/cmake/mockplugins/mockplugins3/mockplugins3.pro b/tests/auto/cmake/mockplugins/mockplugins3/mockplugins3.pro new file mode 100644 index 0000000000..3651abaafa --- /dev/null +++ b/tests/auto/cmake/mockplugins/mockplugins3/mockplugins3.pro @@ -0,0 +1,11 @@ +TARGET = QtMockPlugins3 +QT = core +MODULE_PLUGIN_TYPES = mockauxplugin + +# Fake a git_build, to force qmake to run syncqt.pl when doing a standalone tests build +# like it is done in Coin, otherwise module headers would not be generated. +CONFIG += git_build +HEADERS += qmockauxplugin.h +SOURCES += fake.cpp # Needed to make libtool / ar happy on macOS + +load(qt_module) diff --git a/tests/auto/cmake/mockplugins/mockplugins3/qmockauxplugin.h b/tests/auto/cmake/mockplugins/mockplugins3/qmockauxplugin.h new file mode 100644 index 0000000000..25e4762bac --- /dev/null +++ b/tests/auto/cmake/mockplugins/mockplugins3/qmockauxplugin.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Kitware, Inc. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMOCKAUXPLUGIN_H +#define QMOCKAUXPLUGIN_H + +#include <QString> +#include <QtPlugin> + +QT_BEGIN_NAMESPACE + +#define QMockAuxPlugin_iid "org.qt-project.Qt.Tests.QMockAuxPlugin" + +class QMockAuxPlugin +{ +public: + virtual ~QMockAuxPlugin() {} + virtual QString pluginName() const = 0; +}; + +Q_DECLARE_INTERFACE(QMockAuxPlugin, QMockAuxPlugin_iid) + +QT_END_NAMESPACE + +#endif // QMOCKAUXPLUGIN_H diff --git a/tests/auto/cmake/test_QTBUG-63422/CMakeLists.txt b/tests/auto/cmake/test_QTBUG-63422/CMakeLists.txt index a0b82caee4..b9b9756699 100644 --- a/tests/auto/cmake/test_QTBUG-63422/CMakeLists.txt +++ b/tests/auto/cmake/test_QTBUG-63422/CMakeLists.txt @@ -1,6 +1,9 @@ cmake_minimum_required(VERSION 2.8) project(test_dependent_modules) +# Need to set the policy to link to qtmain.lib automatically. +cmake_policy(SET CMP0020 NEW) + find_package(Qt5Widgets REQUIRED) set(CMAKE_AUTOMOC ON) diff --git a/tests/auto/cmake/test_import_plugins/CMakeLists.txt b/tests/auto/cmake/test_import_plugins/CMakeLists.txt new file mode 100644 index 0000000000..a793fe211d --- /dev/null +++ b/tests/auto/cmake/test_import_plugins/CMakeLists.txt @@ -0,0 +1,111 @@ + +cmake_minimum_required(VERSION 3.1) + +project(import_plugins_advanced) +enable_testing() + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/FindPackageHints.cmake") + include("${CMAKE_CURRENT_LIST_DIR}/FindPackageHints.cmake") +endif() + +# Need to find Qt5Core explicitly because the MockPlugins1 and MockPlugins2 config files +# are in a different directory (the source dir) when doing a standalone tests build, +# whereas Core is in the installed directory, and due to NO_DEFAULT_PATH being used +# for the Core dependency call in Qt5MockPlugins, Core would not be found in the source +# dir. +find_package(Qt5 COMPONENTS Core REQUIRED HINTS ${Qt5Tests_PREFIX_PATH}) +get_target_property(qt_is_static Qt5::Core TYPE) + +# For a similar reason, we need to find the MockPlugins packages not via COMPONENTS argument, +# but directly, because the location of Qt5Config.cmake is in the installed dir, while +# the MockPlugins are in the source dir, and Qt5Config only looks for packages relative +# to its own location. +# The packages are still successfuly found, because the CMAKE_PREFIX_PATH populated by qmake +# contains both the installed Qt dir, and the Qt source dir. +find_package(Qt5MockPlugins1 REQUIRED HINTS ${Qt5Tests_PREFIX_PATH}) +find_package(Qt5MockPlugins2 REQUIRED HINTS ${Qt5Tests_PREFIX_PATH}) + +function(create_test_executable TARGET_NAME) + set(CHECK_FILE ${CMAKE_BINARY_DIR}/${TARGET_NAME}_check.cpp) + + set(EXPECTED_PLUGINS) + foreach(_p ${ARGN}) + string(APPEND EXPECTED_PLUGINS " \"${_p}\",\n") + endforeach() + configure_file("${CMAKE_SOURCE_DIR}/check.cpp.in" ${CHECK_FILE}) + + add_executable(${TARGET_NAME} main.cpp ${CHECK_FILE}) + target_link_libraries(${TARGET_NAME} Qt5::MockPlugins1) + add_test(test_${TARGET_NAME} ${TARGET_NAME}) +endfunction() + +create_test_executable(default QMock1Plugin QMock2Plugin) +# No call to qt5_import_plugins() for the default + +# TODO This test is known to fail because CMake currently doesn't have a way to +# implement its own equivalent of the PLUGIN_EXTENDS mechanism at generate- +# time (meaning a library only gets linked if a set of other libraries are +# *also* linked.) CMake 3.14 or beyond may have such a mechanism, but until +# then, this test is expected to fail, because QMock3Plugin is not being +# linked even though MockPlugins2 is present. +create_test_executable(default_link QMock1Plugin QMock2Plugin QMock3Plugin) +target_link_libraries(default_link Qt5::MockPlugins2) +set_property(TEST test_default_link PROPERTY DISABLED 1) +# No call to qt5_import_plugins() for the default + +create_test_executable(manual QMock1Plugin QMock2Plugin QMock3Plugin QMock4Plugin) +qt5_import_plugins(manual + INCLUDE Qt5::QMock3Plugin Qt5::QMock4Plugin +) + +create_test_executable(manual_genex QMock1Plugin QMock2Plugin QMock3Plugin) +qt5_import_plugins(manual_genex + INCLUDE $<1:Qt5::QMock3Plugin> $<0:Qt5::QMock4Plugin> +) + +create_test_executable(blacklist QMock1Plugin) +qt5_import_plugins(blacklist + EXCLUDE Qt5::QMock2Plugin Qt5::QMock3Plugin +) + +create_test_executable(blacklist_genex QMock1Plugin) +qt5_import_plugins(blacklist_genex + EXCLUDE $<1:Qt5::QMock2Plugin> $<1:Qt5::QMock3Plugin> $<0:Qt5::QMock1Plugin> +) + +create_test_executable(override QMock3Plugin QMock4Plugin) +qt5_import_plugins(override + INCLUDE_BY_TYPE mockplugin Qt5::QMock3Plugin Qt5::QMock4Plugin +) + +create_test_executable(override_genex QMock3Plugin) +qt5_import_plugins(override_genex + INCLUDE_BY_TYPE mockplugin $<1:Qt5::QMock3Plugin> $<0:Qt5::QMock4Plugin> +) + +create_test_executable(override_mix QMock2Plugin QMock3Plugin) +qt5_import_plugins(override_mix + INCLUDE Qt5::QMock2Plugin + INCLUDE_BY_TYPE mockplugin Qt5::QMock3Plugin +) + +if(NOT WIN32) + # Compiling an empty static array fails on Windows. + create_test_executable(none) + qt5_import_plugins(none + EXCLUDE_BY_TYPE mockplugin + ) +endif() + +create_test_executable(none_mix QMock3Plugin QMock4Plugin) +qt5_import_plugins(none_mix + INCLUDE Qt5::QMock3Plugin Qt5::QMock4Plugin + EXCLUDE_BY_TYPE mockplugin +) + +create_test_executable(recursive QMock5Plugin QMock6Plugin) +qt5_import_plugins(recursive + INCLUDE_BY_TYPE mockplugin Qt5::QMock5Plugin +) diff --git a/tests/auto/cmake/test_import_plugins/check.cpp.in b/tests/auto/cmake/test_import_plugins/check.cpp.in new file mode 100644 index 0000000000..df6ea03d2d --- /dev/null +++ b/tests/auto/cmake/test_import_plugins/check.cpp.in @@ -0,0 +1,8 @@ +#include <QString> +#include <cstddef> + +QString expectedPlugins[] = { +@EXPECTED_PLUGINS@ +}; + +std::size_t numExpectedPlugins = sizeof(expectedPlugins) / sizeof(numExpectedPlugins); diff --git a/tests/auto/cmake/test_import_plugins/main.cpp b/tests/auto/cmake/test_import_plugins/main.cpp new file mode 100644 index 0000000000..9fcc81754b --- /dev/null +++ b/tests/auto/cmake/test_import_plugins/main.cpp @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Kitware, Inc. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QPluginLoader> +#include <QSet> +#include <QString> +#include <QVector> + +#include <cstddef> +#include <iostream> + +extern QString expectedPlugins[]; +extern std::size_t numExpectedPlugins; + +int main(int argc, char **argv) +{ +#ifdef QT_STATIC + QSet<QString> expectedPluginSet; + for (std::size_t i = 0; i < numExpectedPlugins; i++) { + expectedPluginSet.insert(expectedPlugins[i]); + } + + QVector<QStaticPlugin> plugins = QPluginLoader::staticPlugins(); + QSet<QString> actualPluginSet; + for (QStaticPlugin plugin : plugins) { + actualPluginSet.insert(plugin.metaData()["className"].toString()); + } + + if (expectedPluginSet != actualPluginSet) { + std::cerr << "Loaded plugins do not match what was expected!" << std::endl + << "Expected plugins:" << std::endl; + + QList<QString> expectedPluginList = expectedPluginSet.toList(); + expectedPluginList.sort(); + for (QString plugin : expectedPluginList) { + std::cerr << (actualPluginSet.contains(plugin) ? " " : "- ") + << plugin.toStdString() << std::endl; + } + + std::cerr << std::endl << "Actual plugins:" << std::endl; + + QList<QString> actualPluginList = actualPluginSet.toList(); + actualPluginList.sort(); + for (QString plugin : actualPluginList) { + std::cerr << (expectedPluginSet.contains(plugin) ? " " : "+ ") + << plugin.toStdString() << std::endl; + } + + return 1; + } + +#endif + return 0; +} diff --git a/tests/auto/cmake/test_interface/CMakeLists.txt b/tests/auto/cmake/test_interface/CMakeLists.txt index 2af80ea448..fdd1aacc10 100644 --- a/tests/auto/cmake/test_interface/CMakeLists.txt +++ b/tests/auto/cmake/test_interface/CMakeLists.txt @@ -25,6 +25,9 @@ int main(int,char**) { QWidget w; w.show(); return 0; } " ) +# Fix try_compile to inherit the parent configuration. +set(CMAKE_TRY_COMPILE_CONFIGURATION "${CMAKE_BUILD_TYPE}") + # The try_compile works because Qt5::Widgets is listed in the LINK_LIBRARIES, # which causes the includes, defines and appropriate PIC flag to be used. try_compile(_TRY_COMPILE_RES "${CMAKE_CURRENT_BINARY_DIR}/try_compile-test" diff --git a/tests/auto/cmake/test_moc_macro_target/CMakeLists.txt b/tests/auto/cmake/test_moc_macro_target/CMakeLists.txt index e97ac199e8..f3299060fd 100644 --- a/tests/auto/cmake/test_moc_macro_target/CMakeLists.txt +++ b/tests/auto/cmake/test_moc_macro_target/CMakeLists.txt @@ -11,13 +11,13 @@ qt5_generate_moc(main_gen_test.cpp "${CMAKE_CURRENT_BINARY_DIR}/main_gen_test.moc" TARGET Qt5GenerateMacroTest ) -add_executable(Qt5GenerateMacroTest WIN32 main_gen_test.cpp "${CMAKE_CURRENT_BINARY_DIR}/main_gen_test.moc") +add_executable(Qt5GenerateMacroTest main_gen_test.cpp "${CMAKE_CURRENT_BINARY_DIR}/main_gen_test.moc") target_include_directories(Qt5GenerateMacroTest PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/interface") target_link_libraries(Qt5GenerateMacroTest Qt5::Core) qt5_wrap_cpp(moc_file mywrapobject.h TARGET Qt5WrapMacroTest ) -add_executable(Qt5WrapMacroTest WIN32 main_wrap_test.cpp ${moc_file}) +add_executable(Qt5WrapMacroTest main_wrap_test.cpp ${moc_file}) target_include_directories(Qt5WrapMacroTest PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/interface") target_link_libraries(Qt5WrapMacroTest Qt5::Core) diff --git a/tests/auto/concurrent/qtconcurrentfilter/qtconcurrentfilter.pro b/tests/auto/concurrent/qtconcurrentfilter/qtconcurrentfilter.pro index f3684faa61..15345d40db 100644 --- a/tests/auto/concurrent/qtconcurrentfilter/qtconcurrentfilter.pro +++ b/tests/auto/concurrent/qtconcurrentfilter/qtconcurrentfilter.pro @@ -3,3 +3,4 @@ TARGET = tst_qtconcurrentfilter QT = core testlib concurrent SOURCES = tst_qtconcurrentfilter.cpp DEFINES += QT_STRICT_ITERATORS +DEFINES -= QT_NO_LINKED_LIST diff --git a/tests/auto/concurrent/qtconcurrentiteratekernel/tst_qtconcurrentiteratekernel.cpp b/tests/auto/concurrent/qtconcurrentiteratekernel/tst_qtconcurrentiteratekernel.cpp index 2e698e6615..3c77b1ba0b 100644 --- a/tests/auto/concurrent/qtconcurrentiteratekernel/tst_qtconcurrentiteratekernel.cpp +++ b/tests/auto/concurrent/qtconcurrentiteratekernel/tst_qtconcurrentiteratekernel.cpp @@ -88,7 +88,7 @@ QAtomicInt iterations; class PrintFor : public IterateKernel<TestIterator, void> { public: - PrintFor(TestIterator begin, TestIterator end) : IterateKernel<TestIterator, void>(begin, end) { iterations.store(0); } + PrintFor(TestIterator begin, TestIterator end) : IterateKernel<TestIterator, void>(begin, end) { iterations.storeRelaxed(0); } bool runIterations(TestIterator/*beginIterator*/, int begin, int end, void *) { iterations.fetchAndAddRelaxed(end - begin); @@ -107,7 +107,7 @@ public: class SleepPrintFor : public IterateKernel<TestIterator, void> { public: - SleepPrintFor(TestIterator begin, TestIterator end) : IterateKernel<TestIterator, void>(begin, end) { iterations.store(0); } + SleepPrintFor(TestIterator begin, TestIterator end) : IterateKernel<TestIterator, void>(begin, end) { iterations.storeRelaxed(0); } inline bool runIterations(TestIterator/*beginIterator*/, int begin, int end, void *) { QTest::qSleep(200); @@ -127,7 +127,7 @@ public: void tst_QtConcurrentIterateKernel::instantiate() { startThreadEngine(new PrintFor(0, 40)).startBlocking(); - QCOMPARE(iterations.load(), 40); + QCOMPARE(iterations.loadRelaxed(), 40); } void tst_QtConcurrentIterateKernel::cancel() @@ -138,8 +138,8 @@ void tst_QtConcurrentIterateKernel::cancel() f.waitForFinished(); QVERIFY(f.isCanceled()); // the threads might run one iteration each before they are canceled. - QVERIFY2(iterations.load() <= QThread::idealThreadCount(), - (QByteArray::number(iterations.load()) + ' ' + QByteArray::number(QThread::idealThreadCount()))); + QVERIFY2(iterations.loadRelaxed() <= QThread::idealThreadCount(), + (QByteArray::number(iterations.loadRelaxed()) + ' ' + QByteArray::number(QThread::idealThreadCount()))); } } @@ -147,7 +147,7 @@ QAtomicInt counter; class CountFor : public IterateKernel<TestIterator, void> { public: - CountFor(TestIterator begin, TestIterator end) : IterateKernel<TestIterator, void>(begin, end) { iterations.store(0); } + CountFor(TestIterator begin, TestIterator end) : IterateKernel<TestIterator, void>(begin, end) { iterations.storeRelaxed(0); } inline bool runIterations(TestIterator/*beginIterator*/, int begin, int end, void *) { counter.fetchAndAddRelaxed(end - begin); @@ -164,10 +164,10 @@ void tst_QtConcurrentIterateKernel::stresstest() const int iterations = 1000; const int times = 50; for (int i = 0; i < times; ++i) { - counter.store(0); + counter.storeRelaxed(0); CountFor f(0, iterations); f.startBlocking(); - QCOMPARE(counter.load(), iterations); + QCOMPARE(counter.loadRelaxed(), iterations); } } @@ -186,7 +186,7 @@ public: // this class throttles between iterations 100 and 200, // and then records how many threads that run between // iterations 140 and 160. - ThrottleFor(TestIterator begin, TestIterator end) : IterateKernel<TestIterator, void>(begin, end) { iterations.store(0); throttling = false; } + ThrottleFor(TestIterator begin, TestIterator end) : IterateKernel<TestIterator, void>(begin, end) { iterations.storeRelaxed(0); throttling = false; } inline bool runIterations(TestIterator/*beginIterator*/, int begin, int end, void *) { if (200 >= begin && 200 < end) { @@ -217,7 +217,7 @@ public: bool shouldThrottleThread() { - const int load = iterations.load(); + const int load = iterations.loadRelaxed(); return (load > 100 && load < 200); } bool throttling; @@ -226,14 +226,14 @@ public: void tst_QtConcurrentIterateKernel::throttling() { const int totalIterations = 400; - iterations.store(0); + iterations.storeRelaxed(0); threads.clear(); ThrottleFor f(0, totalIterations); f.startBlocking(); - QCOMPARE(iterations.load(), totalIterations); + QCOMPARE(iterations.loadRelaxed(), totalIterations); QCOMPARE(threads.count(), 1); diff --git a/tests/auto/concurrent/qtconcurrentmap/qtconcurrentmap.pro b/tests/auto/concurrent/qtconcurrentmap/qtconcurrentmap.pro index fd8fd0a74a..717d103e44 100644 --- a/tests/auto/concurrent/qtconcurrentmap/qtconcurrentmap.pro +++ b/tests/auto/concurrent/qtconcurrentmap/qtconcurrentmap.pro @@ -3,6 +3,7 @@ TARGET = tst_qtconcurrentmap QT = core testlib concurrent SOURCES = tst_qtconcurrentmap.cpp DEFINES += QT_STRICT_ITERATORS +DEFINES -= QT_NO_LINKED_LIST # Force C++17 if available contains(QT_CONFIG, c++1z): CONFIG += c++1z diff --git a/tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp b/tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp index b864b065e6..383de0b2ce 100644 --- a/tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp +++ b/tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp @@ -127,14 +127,11 @@ void tst_QtConcurrentMap::map() QtConcurrent::map(numberList.begin(), numberList.end(), &Number::multiplyBy2).waitForFinished(); QCOMPARE(numberList, QList<Number>() << 4 << 8 << 12); -#ifdef Q_COMPILER_LAMBDA // lambda QtConcurrent::map(list, [](int &x){x *= 2;}).waitForFinished(); QCOMPARE(list, QList<int>() << 128 << 256 << 384); QtConcurrent::map(list.begin(), list.end(), [](int &x){x *= 2;}).waitForFinished(); QCOMPARE(list, QList<int>() << 256 << 512 << 768); -#endif - } // functors don't take arguments by reference, making these no-ops @@ -160,13 +157,11 @@ void tst_QtConcurrentMap::map() QtConcurrent::map(list.begin(), list.end(), multiplyBy2Immutable).waitForFinished(); QCOMPARE(list, QList<int>() << 1 << 2 << 3); -#ifdef Q_COMPILER_LAMBDA // lambda QtConcurrent::map(list, [](int x){x *= 2;}).waitForFinished(); QCOMPARE(list, QList<int>() << 1 << 2 << 3); QtConcurrent::map(list.begin(), list.end(), [](int x){x *= 2;}).waitForFinished(); QCOMPARE(list, QList<int>() << 1 << 2 << 3); -#endif } // Linked lists and forward iterators @@ -2026,12 +2021,12 @@ int fn(int &i) return i; } -int fnConstNoExcept(const int &i) Q_DECL_NOTHROW +int fnConstNoExcept(const int &i) noexcept { return i; } -int fnNoExcept(int &i) Q_DECL_NOTHROW +int fnNoExcept(int &i) noexcept { return i; } @@ -2046,12 +2041,12 @@ QString changeType(int &) return QString(); } -QString changeTypeConstNoExcept(const int &) Q_DECL_NOTHROW +QString changeTypeConstNoExcept(const int &) noexcept { return QString(); } -QString changeTypeNoExcept(int &) Q_DECL_NOTHROW +QString changeTypeNoExcept(int &) noexcept { return QString(); } @@ -2066,12 +2061,12 @@ int changeTypeQStringList(QStringList &) return 0; } -int changeTypeQStringListConstNoExcept(const QStringList &) Q_DECL_NOTHROW +int changeTypeQStringListConstNoExcept(const QStringList &) noexcept { return 0; } -int changeTypeQStringListNoExcept(QStringList &) Q_DECL_NOTHROW +int changeTypeQStringListNoExcept(QStringList &) noexcept { return 0; } @@ -2101,22 +2096,22 @@ public: return QString(); } - MemFnTester fnNoExcept() Q_DECL_NOTHROW + MemFnTester fnNoExcept() noexcept { return MemFnTester(); } - MemFnTester fnConstNoExcept() const Q_DECL_NOTHROW + MemFnTester fnConstNoExcept() const noexcept { return MemFnTester(); } - QString changeTypeNoExcept() Q_DECL_NOTHROW + QString changeTypeNoExcept() noexcept { return QString(); } - QString changeTypeConstNoExcept() const Q_DECL_NOTHROW + QString changeTypeConstNoExcept() const noexcept { return QString(); } @@ -2186,8 +2181,8 @@ public: void updatePeak() { forever { - const int localPeak = peakInstanceCount.load(); - const int localCurrent = currentInstanceCount.load(); + const int localPeak = peakInstanceCount.loadRelaxed(); + const int localCurrent = currentInstanceCount.loadRelaxed(); if (localCurrent <= localPeak) break; if (peakInstanceCount.testAndSetOrdered(localPeak, localCurrent)) @@ -2225,35 +2220,35 @@ void tst_QtConcurrentMap::throttling() const int allowedTemporaries = QThread::idealThreadCount() * 40; { - currentInstanceCount.store(0); - peakInstanceCount.store(0); + currentInstanceCount.storeRelaxed(0); + peakInstanceCount.storeRelaxed(0); QList<InstanceCounter> instances; for (int i = 0; i < itemcount; ++i) instances.append(InstanceCounter()); - QCOMPARE(currentInstanceCount.load(), itemcount); + QCOMPARE(currentInstanceCount.loadRelaxed(), itemcount); int results = QtConcurrent::blockingMappedReduced(instances, slowMap, fastReduce); QCOMPARE(results, itemcount); - QCOMPARE(currentInstanceCount.load(), itemcount); - QVERIFY(peakInstanceCount.load() < itemcount + allowedTemporaries); + QCOMPARE(currentInstanceCount.loadRelaxed(), itemcount); + QVERIFY(peakInstanceCount.loadRelaxed() < itemcount + allowedTemporaries); } { - QCOMPARE(currentInstanceCount.load(), 0); - peakInstanceCount.store(0); + QCOMPARE(currentInstanceCount.loadRelaxed(), 0); + peakInstanceCount.storeRelaxed(0); QList<InstanceCounter> instances; for (int i = 0; i < itemcount; ++i) instances.append(InstanceCounter()); - QCOMPARE(currentInstanceCount.load(), itemcount); + QCOMPARE(currentInstanceCount.loadRelaxed(), itemcount); int results = QtConcurrent::blockingMappedReduced(instances, fastMap, slowReduce); QCOMPARE(results, itemcount); - QCOMPARE(currentInstanceCount.load(), itemcount); - QVERIFY(peakInstanceCount.load() < itemcount + allowedTemporaries); + QCOMPARE(currentInstanceCount.loadRelaxed(), itemcount); + QVERIFY(peakInstanceCount.loadRelaxed() < itemcount + allowedTemporaries); } } @@ -2385,8 +2380,8 @@ InstanceCounter ic_fn(const InstanceCounter & ic) // assigned over with operator == void tst_QtConcurrentMap::qFutureAssignmentLeak() { - currentInstanceCount.store(0); - peakInstanceCount.store(0); + currentInstanceCount.storeRelaxed(0); + peakInstanceCount.storeRelaxed(0); QFuture<InstanceCounter> future; { QList<InstanceCounter> list; @@ -2405,9 +2400,9 @@ void tst_QtConcurrentMap::qFutureAssignmentLeak() // Use QTRY_COMPARE because QtConcurrent::ThreadEngine::asynchronousFinish() // deletes its internals after signaling finished, so it might still be holding // on to copies of InstanceCounter for a short while. - QTRY_COMPARE(currentInstanceCount.load(), 1000); + QTRY_COMPARE(currentInstanceCount.loadRelaxed(), 1000); future = QFuture<InstanceCounter>(); - QTRY_COMPARE(currentInstanceCount.load(), 0); + QTRY_COMPARE(currentInstanceCount.loadRelaxed(), 0); } inline void increment(int &num) diff --git a/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp b/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp index 1596a9fafd..a4eb2936b5 100644 --- a/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp +++ b/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp @@ -48,12 +48,8 @@ private slots: #ifndef QT_NO_EXCEPTIONS void exceptions(); #endif -#ifdef Q_COMPILER_DECLTYPE void functor(); -#endif -#ifdef Q_COMPILER_LAMBDA void lambda(); -#endif }; void light() @@ -126,23 +122,23 @@ public: class ANoExcept { public: - int member0() Q_DECL_NOTHROW { return 10; } - int member1(int in) Q_DECL_NOTHROW { return in; } + int member0() noexcept { return 10; } + int member1(int in) noexcept { return in; } typedef int result_type; - int operator()() Q_DECL_NOTHROW { return 10; } - int operator()(int in) Q_DECL_NOTHROW { return in; } + int operator()() noexcept { return 10; } + int operator()(int in) noexcept { return in; } }; class AConstNoExcept { public: - int member0() const Q_DECL_NOTHROW { return 10; } - int member1(int in) const Q_DECL_NOTHROW { return in; } + int member0() const noexcept { return 10; } + int member1(int in) const noexcept { return in; } typedef int result_type; - int operator()() const Q_DECL_NOTHROW { return 10; } - int operator()(int in) const Q_DECL_NOTHROW { return in; } + int operator()() const noexcept { return 10; } + int operator()(int in) const noexcept { return in; } }; void tst_QtConcurrentRun::returnValue() @@ -510,17 +506,17 @@ void tst_QtConcurrentRun::recursive() int levels = 15; for (int i = 0; i < QThread::idealThreadCount(); ++i) { - count.store(0); + count.storeRelaxed(0); QThreadPool::globalInstance()->setMaxThreadCount(i); recursiveRun(levels); - QCOMPARE(count.load(), (int)std::pow(2.0, levels) - 1); + QCOMPARE(count.loadRelaxed(), (int)std::pow(2.0, levels) - 1); } for (int i = 0; i < QThread::idealThreadCount(); ++i) { - count.store(0); + count.storeRelaxed(0); QThreadPool::globalInstance()->setMaxThreadCount(i); recursiveResult(levels); - QCOMPARE(count.load(), (int)std::pow(2.0, levels) - 1); + QCOMPARE(count.loadRelaxed(), (int)std::pow(2.0, levels) - 1); } } @@ -574,7 +570,7 @@ public: static QAtomicInt cancel; void run() override { int iter = 60; - while (--iter && !cancel.load()) + while (--iter && !cancel.loadRelaxed()) QThread::currentThread()->msleep(25); } }; @@ -642,13 +638,12 @@ void tst_QtConcurrentRun::exceptions() caught = true; } - SlowTask::cancel.store(true); + SlowTask::cancel.storeRelaxed(true); QVERIFY2(caught, "did not get exception"); } #endif -#ifdef Q_COMPILER_DECLTYPE // Compiler supports decltype struct Functor { int operator()() { return 42; } @@ -706,9 +701,7 @@ void tst_QtConcurrentRun::functor() QtConcurrent::run(&pool, f, 1,2,3,4,5).waitForFinished(); } } -#endif -#ifdef Q_COMPILER_LAMBDA // Compiler supports lambda void tst_QtConcurrentRun::lambda() { @@ -717,14 +710,12 @@ void tst_QtConcurrentRun::lambda() QCOMPARE(QtConcurrent::run([](int a, double b){ return a + b; }, 12, 15).result(), double(12+15)); QCOMPARE(QtConcurrent::run([](int a , int, int, int, int b){ return a + b; }, 1, 2, 3, 4, 5).result(), 1 + 5); -#ifdef Q_COMPILER_INITIALIZER_LISTS { QString str { "Hello World Foo" }; QFuture<QStringList> f1 = QtConcurrent::run([&](){ return str.split(' '); }); auto r = f1.result(); QCOMPARE(r, QStringList({"Hello", "World", "Foo"})); } -#endif // and now with explicit pool: QThreadPool pool; @@ -733,16 +724,13 @@ void tst_QtConcurrentRun::lambda() QCOMPARE(QtConcurrent::run(&pool, [](int a, double b){ return a + b; }, 12, 15).result(), double(12+15)); QCOMPARE(QtConcurrent::run(&pool, [](int a , int, int, int, int b){ return a + b; }, 1, 2, 3, 4, 5).result(), 1 + 5); -#ifdef Q_COMPILER_INITIALIZER_LISTS { QString str { "Hello World Foo" }; QFuture<QStringList> f1 = QtConcurrent::run(&pool, [&](){ return str.split(' '); }); auto r = f1.result(); QCOMPARE(r, QStringList({"Hello", "World", "Foo"})); } -#endif } -#endif QTEST_MAIN(tst_QtConcurrentRun) #include "tst_qtconcurrentrun.moc" diff --git a/tests/auto/concurrent/qtconcurrentthreadengine/tst_qtconcurrentthreadengine.cpp b/tests/auto/concurrent/qtconcurrentthreadengine/tst_qtconcurrentthreadengine.cpp index a68f7d5a4e..d4c669cddc 100644 --- a/tests/auto/concurrent/qtconcurrentthreadengine/tst_qtconcurrentthreadengine.cpp +++ b/tests/auto/concurrent/qtconcurrentthreadengine/tst_qtconcurrentthreadengine.cpp @@ -28,6 +28,7 @@ #include <qtconcurrentthreadengine.h> #include <qexception.h> #include <QThread> +#include <QElapsedTimer> #include <QtTest/QtTest> using namespace QtConcurrent; @@ -186,7 +187,7 @@ class ThrottleAlwaysUser : public ThreadEngine<void> public: ThrottleAlwaysUser() { - count.store(initialCount = 100); + count.storeRelaxed(initialCount = 100); finishing = false; } @@ -198,7 +199,7 @@ public: ThreadFunctionResult threadFunction() { forever { - const int local = count.load(); + const int local = count.loadRelaxed(); if (local == 0) { finishing = true; return ThreadFinished; @@ -223,13 +224,13 @@ void tst_QtConcurrentThreadEngine::throttle() for (int i = 0; i < repeats; ++i) { QFuture<void> f = (new ThrottleAlwaysUser())->startAsynchronously(); f.waitForFinished(); - QCOMPARE(count.load(), 0); + QCOMPARE(count.loadRelaxed(), 0); } for (int i = 0; i < repeats; ++i) { ThrottleAlwaysUser t; t.startBlocking(); - QCOMPARE(count.load(), 0); + QCOMPARE(count.loadRelaxed(), 0); } } @@ -382,7 +383,7 @@ void tst_QtConcurrentThreadEngine::cancelQueuedSlowUser() { const int times = 100; - QTime t; + QElapsedTimer t; t.start(); { diff --git a/tests/auto/corelib/animation/qparallelanimationgroup/BLACKLIST b/tests/auto/corelib/animation/qparallelanimationgroup/BLACKLIST index b5b37b4498..3e42a737df 100644 --- a/tests/auto/corelib/animation/qparallelanimationgroup/BLACKLIST +++ b/tests/auto/corelib/animation/qparallelanimationgroup/BLACKLIST @@ -1,3 +1,2 @@ [deleteChildrenWithRunningGroup] -osx-10.12 osx-10.13 diff --git a/tests/auto/corelib/animation/qpauseanimation/BLACKLIST b/tests/auto/corelib/animation/qpauseanimation/BLACKLIST index e223ec82e2..33cd53d788 100644 --- a/tests/auto/corelib/animation/qpauseanimation/BLACKLIST +++ b/tests/auto/corelib/animation/qpauseanimation/BLACKLIST @@ -1,6 +1,5 @@ [pauseAndPropertyAnimations] -* -[multipleSequentialGroups] osx -[noTimerUpdates] +[multipleSequentialGroups] osx + diff --git a/tests/auto/corelib/animation/qpropertyanimation/BLACKLIST b/tests/auto/corelib/animation/qpropertyanimation/BLACKLIST deleted file mode 100644 index a8719b241a..0000000000 --- a/tests/auto/corelib/animation/qpropertyanimation/BLACKLIST +++ /dev/null @@ -1,6 +0,0 @@ -[statesAndSignals:normal animation] -windows -[startBackwardWithoutEndValue] -windows -[startWithoutStartValue] -osx diff --git a/tests/auto/corelib/animation/qsequentialanimationgroup/BLACKLIST b/tests/auto/corelib/animation/qsequentialanimationgroup/BLACKLIST index 4c999ff88f..e516c0e826 100644 --- a/tests/auto/corelib/animation/qsequentialanimationgroup/BLACKLIST +++ b/tests/auto/corelib/animation/qsequentialanimationgroup/BLACKLIST @@ -1,8 +1,6 @@ -[startGroupWithRunningChild] -windows [finishWithUncontrolledAnimation] -windows -osx-10.12 +windows-10 msvc-2015 osx-10.13 [groupWithZeroDurationAnimations] -osx +osx-10.13 + diff --git a/tests/auto/corelib/codecs/qtextcodec/tst_qtextcodec.cpp b/tests/auto/corelib/codecs/qtextcodec/tst_qtextcodec.cpp index 6cadebfd7f..78b6449a69 100644 --- a/tests/auto/corelib/codecs/qtextcodec/tst_qtextcodec.cpp +++ b/tests/auto/corelib/codecs/qtextcodec/tst_qtextcodec.cpp @@ -263,7 +263,7 @@ void tst_QTextCodec::fromUnicode() If the encoding is a superset of ASCII, test that the byte array is correct (no off by one, no trailing '\0'). */ - QByteArray result = codec->fromUnicode(QStringViewLiteral("abc")); + QByteArray result = codec->fromUnicode(u"abc"); if (result.startsWith('a')) { QCOMPARE(result.size(), 3); QCOMPARE(result, QByteArray("abc")); diff --git a/tests/auto/corelib/corelib.pro b/tests/auto/corelib/corelib.pro index 44e1c519b0..d696e174aa 100644 --- a/tests/auto/corelib/corelib.pro +++ b/tests/auto/corelib/corelib.pro @@ -13,5 +13,7 @@ SUBDIRS = \ plugin \ serialization \ statemachine \ + text \ thread \ + time \ tools diff --git a/tests/auto/corelib/global/global.pro b/tests/auto/corelib/global/global.pro index 139e073644..0f77d191ee 100644 --- a/tests/auto/corelib/global/global.pro +++ b/tests/auto/corelib/global/global.pro @@ -12,3 +12,6 @@ SUBDIRS=\ qtendian \ qglobalstatic \ qhooks + +win32:!winrt: SUBDIRS += \ + qwinregistry diff --git a/tests/auto/corelib/global/qflags/tst_qflags.cpp b/tests/auto/corelib/global/qflags/tst_qflags.cpp index 72b086350e..1568855032 100644 --- a/tests/auto/corelib/global/qflags/tst_qflags.cpp +++ b/tests/auto/corelib/global/qflags/tst_qflags.cpp @@ -142,7 +142,6 @@ void tst_QFlags::signedness() std::is_signed<Qt::Alignment::Int>::value)); } -#if defined(Q_COMPILER_CLASS_ENUM) enum class MyStrictEnum { StrictZero, StrictOne, StrictTwo, StrictFour=4 }; Q_DECLARE_FLAGS( MyStrictFlags, MyStrictEnum ) Q_DECLARE_OPERATORS_FOR_FLAGS( MyStrictFlags ) @@ -154,11 +153,9 @@ Q_STATIC_ASSERT( !QTypeInfo<MyStrictFlags>::isComplex ); Q_STATIC_ASSERT( !QTypeInfo<MyStrictFlags>::isStatic ); Q_STATIC_ASSERT( !QTypeInfo<MyStrictFlags>::isLarge ); Q_STATIC_ASSERT( !QTypeInfo<MyStrictFlags>::isPointer ); -#endif void tst_QFlags::classEnum() { -#if defined(Q_COMPILER_CLASS_ENUM) // The main aim of the test is making sure it compiles // The QCOMPARE are there as an extra MyStrictEnum e1 = MyStrictEnum::StrictOne; @@ -257,27 +254,19 @@ void tst_QFlags::classEnum() // Just to make sure it compiles if (false) qDebug() << f3; -#endif } void tst_QFlags::initializerLists() { -#if defined(Q_COMPILER_INITIALIZER_LISTS) Qt::MouseButtons bts = { Qt::LeftButton, Qt::RightButton }; QVERIFY(bts.testFlag(Qt::LeftButton)); QVERIFY(bts.testFlag(Qt::RightButton)); QVERIFY(!bts.testFlag(Qt::MiddleButton)); -#if defined(Q_COMPILER_CLASS_ENUM) MyStrictNoOpFlags flags = { MyStrictNoOpEnum::StrictOne, MyStrictNoOpEnum::StrictFour }; QVERIFY(flags.testFlag(MyStrictNoOpEnum::StrictOne)); QVERIFY(flags.testFlag(MyStrictNoOpEnum::StrictFour)); QVERIFY(!flags.testFlag(MyStrictNoOpEnum::StrictTwo)); -#endif // Q_COMPILER_CLASS_ENUM - -#else - QSKIP("This test requires C++11 initializer_list support."); -#endif // Q_COMPILER_INITIALIZER_LISTS } void tst_QFlags::testSetFlags() diff --git a/tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp b/tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp index b73a297245..94f0afa5ed 100644 --- a/tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp +++ b/tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2019 The Qt Company Ltd. ** Copyright (C) 2016 by Southwest Research Institute (R) ** Contact: https://www.qt.io/licensing/ ** @@ -40,7 +41,8 @@ private slots: void fuzzyCompare(); void ltgt_data(); void ltgt(); - void qNan(); + void qNaN(); + void infinity(); void float_cast(); void float_cast_data(); void promotionTests(); @@ -48,6 +50,10 @@ private slots: void arithOps(); void floatToFloat16(); void floatFromFloat16(); + void finite_data(); + void finite(); + void properties(); + void limits(); }; void tst_qfloat16::fuzzyCompare_data() @@ -101,6 +107,7 @@ void tst_qfloat16::ltgt_data() QTest::addColumn<float>("val2"); QTest::newRow("zero") << 0.0f << 0.0f; + QTest::newRow("-zero") << -0.0f << 0.0f; QTest::newRow("ten") << 10.0f << 10.0f; QTest::newRow("large") << 100000.0f << 100000.0f; QTest::newRow("small") << 0.0000001f << 0.0000001f; @@ -152,38 +159,66 @@ void tst_qfloat16::ltgt() # pragma GCC optimize "no-fast-math" #endif -void tst_qfloat16::qNan() +void tst_qfloat16::qNaN() { #if defined __FAST_MATH__ && (__GNUC__ * 100 + __GNUC_MINOR__ < 404) QSKIP("Non-conformant fast math mode is enabled, cannot run test"); #endif - qfloat16 nan = qQNaN(); - QVERIFY(!(0. > nan)); - QVERIFY(!(0. < nan)); + using Bounds = std::numeric_limits<qfloat16>; + const qfloat16 nan = Bounds::quiet_NaN(); + const qfloat16 zero(0), one(1); + QVERIFY(!(zero > nan)); + QVERIFY(!(zero < nan)); + QVERIFY(!(zero == nan)); QVERIFY(!qIsInf(nan)); QVERIFY(qIsNaN(nan)); - QVERIFY(qIsNaN(nan + 1.f)); + QVERIFY(qIsNaN(nan + one)); QVERIFY(qIsNaN(-nan)); - qfloat16 inf = qInf(); - QVERIFY(inf > qfloat16(0)); - QVERIFY(-inf < qfloat16(0)); - QVERIFY(!qIsNaN(inf)); - QVERIFY(qIsInf(inf)); - QVERIFY(qIsInf(-inf)); - QVERIFY(qIsInf(2.f*inf)); - QVERIFY(qIsInf(inf*2.f)); - // QTBUG-75812: QEMU/arm64 compiler over-optimizes, so flakily fails 1/inf == 0 :-( - if (qfloat16(9.785e-4f) == qfloat16(9.794e-4f)) - QCOMPARE(qfloat16(1.f) / inf, qfloat16(0.f)); #ifdef Q_CC_INTEL QEXPECT_FAIL("", "ICC optimizes zero * anything to zero", Continue); #endif - QVERIFY(qIsNaN(nan*0.f)); + QVERIFY(qIsNaN(nan * zero)); #ifdef Q_CC_INTEL QEXPECT_FAIL("", "ICC optimizes zero * anything to zero", Continue); #endif - QVERIFY(qIsNaN(inf*0.f)); - QVERIFY(qFuzzyCompare(qfloat16(1.f/inf), qfloat16(0.0))); + QVERIFY(qIsNaN(Bounds::infinity() * zero)); + + QVERIFY(!nan.isNormal()); + QVERIFY(!qIsFinite(nan)); + QVERIFY(!(nan == nan)); + QCOMPARE(nan, nan); // Despite the preceding + QCOMPARE(qFpClassify(nan), FP_NAN); +} + +void tst_qfloat16::infinity() +{ + const qfloat16 huge = std::numeric_limits<qfloat16>::infinity(); + const qfloat16 zero(0), one(1), two(2); + QVERIFY(huge > -huge); + QVERIFY(huge > zero); + QVERIFY(-huge < zero); + QCOMPARE(huge, huge); + QCOMPARE(-huge, -huge); + + // QTBUG-75812 - see overOptimized in the limits() test. + if (qfloat16(9.785e-4f) == qfloat16(9.794e-4f)) { + QCOMPARE(one / huge, zero); + QVERIFY(qFuzzyCompare(one / huge, zero)); // (same thing) + } + + QVERIFY(qIsInf(huge)); + QVERIFY(qIsInf(-huge)); + QVERIFY(qIsInf(two * huge)); + QVERIFY(qIsInf(huge * two)); + + QVERIFY(!huge.isNormal()); + QVERIFY(!(-huge).isNormal()); + QVERIFY(!qIsNaN(huge)); + QVERIFY(!qIsNaN(-huge)); + QVERIFY(!qIsFinite(huge)); + QVERIFY(!qIsFinite(-huge)); + QCOMPARE(qFpClassify(huge), FP_INFINITE); + QCOMPARE(qFpClassify(-huge), FP_INFINITE); } void tst_qfloat16::float_cast_data() @@ -347,5 +382,160 @@ void tst_qfloat16::floatFromFloat16() QCOMPARE(out[i], expected[i]); } +static qfloat16 powf16(qfloat16 base, int raise) +{ + const qfloat16 one(1.f); + if (raise < 0) { + raise = -raise; + base = one / base; + } + qfloat16 answer = (raise & 1) ? base : one; + while (raise > 0) { + raise >>= 1; + base *= base; + if (raise & 1) + answer *= base; + } + return answer; +} + +void tst_qfloat16::finite_data() +{ + using Bounds = std::numeric_limits<qfloat16>; + QTest::addColumn<qfloat16>("value"); + QTest::addColumn<int>("mode"); + + QTest::newRow("zero") << qfloat16(0) << FP_ZERO; + QTest::newRow("-zero") << -qfloat16(0) << FP_ZERO; + QTest::newRow("one") << qfloat16(1) << FP_NORMAL; + QTest::newRow("-one") << qfloat16(-1) << FP_NORMAL; + QTest::newRow("ten") << qfloat16(10) << FP_NORMAL; + QTest::newRow("-ten") << qfloat16(-10) << FP_NORMAL; + QTest::newRow("max") << Bounds::max() << FP_NORMAL; + QTest::newRow("lowest") << Bounds::lowest() << FP_NORMAL; + QTest::newRow("min") << Bounds::min() << FP_NORMAL; + QTest::newRow("-min") << -Bounds::min() << FP_NORMAL; + QTest::newRow("denorm_min") << Bounds::denorm_min() << FP_SUBNORMAL; + QTest::newRow("-denorm_min") << -Bounds::denorm_min() << FP_SUBNORMAL; +} + +void tst_qfloat16::finite() +{ + QFETCH(qfloat16, value); + QFETCH(int, mode); + QCOMPARE(value.isNormal(), mode != FP_SUBNORMAL); + QCOMPARE(value, value); // Fuzzy + QVERIFY(value == value); // Exact + QVERIFY(qIsFinite(value)); + QVERIFY(!qIsInf(value)); + QVERIFY(!qIsNaN(value)); + QCOMPARE(qFpClassify(value), mode); +} + +void tst_qfloat16::properties() +{ + using Bounds = std::numeric_limits<qfloat16>; + QVERIFY(Bounds::is_specialized); + QVERIFY(Bounds::is_signed); + QVERIFY(!Bounds::is_integer); + QVERIFY(!Bounds::is_exact); + QVERIFY(Bounds::is_iec559); + QVERIFY(Bounds::is_bounded); + QVERIFY(!Bounds::is_modulo); + QVERIFY(!Bounds::traps); + QVERIFY(Bounds::has_infinity); + QVERIFY(Bounds::has_quiet_NaN); + QVERIFY(Bounds::has_signaling_NaN); + QCOMPARE(Bounds::has_denorm, std::denorm_present); + QCOMPARE(Bounds::round_style, std::round_to_nearest); + QCOMPARE(Bounds::radix, 2); + // Untested: has_denorm_loss +} + +void tst_qfloat16::limits() // See also: qNaN() and infinity() +{ + // *NOT* using QCOMPARE() on finite qfloat16 values, since that uses fuzzy + // comparison, and we need exact here. + using Bounds = std::numeric_limits<qfloat16>; + + // A few useful values: + const qfloat16 zero(0), one(1), ten(10); + + // The specifics of minus zero: + // (IEEE 754 seems to want -zero < zero, but -0. == 0. and -0.f == 0.f in C++.) + QVERIFY(-zero <= zero); + QVERIFY(-zero == zero); + QVERIFY(!(-zero > zero)); + + // digits in the mantissa, including the implicit 1 before the binary dot at its left: + QVERIFY(qfloat16(1 << (Bounds::digits - 1)) + one > qfloat16(1 << (Bounds::digits - 1))); + QVERIFY(qfloat16(1 << Bounds::digits) + one == qfloat16(1 << Bounds::digits)); + + // There is a wilful of-by-one in how m(ax|in)_exponent are defined; they're + // the lowest and highest n for which radix^{n-1} are normal and finite. + const qfloat16 two(Bounds::radix); + qfloat16 bit = powf16(two, Bounds::max_exponent - 1); + QVERIFY(qIsFinite(bit)); + QVERIFY(qIsInf(bit * two)); + bit = powf16(two, Bounds::min_exponent - 1); + QVERIFY(bit.isNormal()); + QCOMPARE(qFpClassify(bit), FP_NORMAL); + QVERIFY(!(bit / two).isNormal()); + QCOMPARE(qFpClassify(bit / two), FP_SUBNORMAL); + QVERIFY(bit / two > zero); + + // Base ten (with no matching off-by-one idiocy): + // the lowest negative number n such that 10^n is a valid normalized value + qfloat16 low10(powf16(ten, Bounds::min_exponent10)); + QVERIFY(low10 > zero); + QVERIFY(low10.isNormal()); + low10 /= ten; + QVERIFY(low10 == zero || !low10.isNormal()); + // the largest positive number n such that 10^n is a representable finite value + qfloat16 high10(powf16(ten, Bounds::max_exponent10)); + QVERIFY(high10 > zero); + QVERIFY(qIsFinite(high10)); + QVERIFY(!qIsFinite(high10 * ten)); + QCOMPARE(qFpClassify(high10), FP_NORMAL); + + // How many digits are significant ? (Casts avoid linker errors ...) + QCOMPARE(int(Bounds::digits10), 3); // 9.79e-4 has enough sigificant digits: + qfloat16 below(9.785e-4f), above(9.794e-4f); +#if 0 // Sadly, the QEMU x-compile for arm64 "optimizes" comparisons: + const bool overOptimized = false; +#else + const bool overOptimized = (below != above); + if (overOptimized) + QEXPECT_FAIL("", "Over-optimized on ARM", Continue); +#endif // (but it did, so should, pass everywhere else, confirming digits10 is indeed 3). + QVERIFY(below == above); + QCOMPARE(int(Bounds::max_digits10), 5); // we need 5 to distinguish these two: + QVERIFY(qfloat16(1000.5f) != qfloat16(1001.4f)); + + // Actual limiting values of the type: + const qfloat16 rose(one + Bounds::epsilon()); + QVERIFY(rose > one); + if (overOptimized) + QEXPECT_FAIL("", "Over-optimized on ARM", Continue); + QVERIFY(one + Bounds::epsilon() / rose == one); + + QVERIFY(Bounds::max() > zero); + QVERIFY(qIsInf(Bounds::max() * rose)); + + QVERIFY(Bounds::lowest() < zero); + QVERIFY(qIsInf(Bounds::lowest() * rose)); + + QVERIFY(Bounds::min() > zero); + QVERIFY(!(Bounds::min() / rose).isNormal()); + + QVERIFY(Bounds::denorm_min() > zero); + if (overOptimized) + QEXPECT_FAIL("", "Over-optimized on ARM", Continue); + QVERIFY(Bounds::denorm_min() / rose == zero); + if (overOptimized) + QEXPECT_FAIL("", "Over-optimized on ARM", Continue); + QVERIFY(-Bounds::denorm_min() / rose == -zero); +} + QTEST_APPLESS_MAIN(tst_qfloat16) #include "tst_qfloat16.moc" diff --git a/tests/auto/corelib/global/qglobal/qglobal.c b/tests/auto/corelib/global/qglobal/qglobal.c index 0719c4b921..c7124454d0 100644 --- a/tests/auto/corelib/global/qglobal/qglobal.c +++ b/tests/auto/corelib/global/qglobal/qglobal.c @@ -85,7 +85,7 @@ int tst_QtVersion() return QT_VERSION; } -const char *tst_qVersion() Q_DECL_NOTHROW +const char *tst_qVersion() Q_DECL_NOEXCEPT { #if !defined(QT_NAMESPACE) return qVersion(); diff --git a/tests/auto/corelib/global/qglobal/tst_qglobal.cpp b/tests/auto/corelib/global/qglobal/tst_qglobal.cpp index 7800a101ec..b33dec8a61 100644 --- a/tests/auto/corelib/global/qglobal/tst_qglobal.cpp +++ b/tests/auto/corelib/global/qglobal/tst_qglobal.cpp @@ -456,12 +456,8 @@ typedef int (Empty::*memFun) (); } while (false) \ /**/ -#ifdef Q_COMPILER_RVALUE_REFS #define TEST_AlignOf_RValueRef(type, alignment) \ TEST_AlignOf_impl(type, alignment) -#else -#define TEST_AlignOf_RValueRef(type, alignment) do {} while (false) -#endif #define TEST_AlignOf_impl(type, alignment) \ do { \ diff --git a/tests/auto/corelib/global/qglobalstatic/tst_qglobalstatic.cpp b/tests/auto/corelib/global/qglobalstatic/tst_qglobalstatic.cpp index 2d7db813dd..820a0b999b 100644 --- a/tests/auto/corelib/global/qglobalstatic/tst_qglobalstatic.cpp +++ b/tests/auto/corelib/global/qglobalstatic/tst_qglobalstatic.cpp @@ -145,7 +145,7 @@ void tst_QGlobalStatic::exception() exceptionCaught = true; } QVERIFY(exceptionCaught); - QCOMPARE(Q_QGS_throwingGS::guard.load(), 0); + QCOMPARE(Q_QGS_throwingGS::guard.loadRelaxed(), 0); QVERIFY(!throwingGS.exists()); QVERIFY(!throwingGS.isDestroyed()); } @@ -154,10 +154,10 @@ QBasicAtomicInt exceptionControlVar = Q_BASIC_ATOMIC_INITIALIZER(1); Q_GLOBAL_STATIC_WITH_ARGS(ThrowingType, exceptionGS, (exceptionControlVar)) void tst_QGlobalStatic::catchExceptionAndRetry() { - if (exceptionControlVar.load() != 1) + if (exceptionControlVar.loadRelaxed() != 1) QSKIP("This test cannot be run more than once"); - ThrowingType::constructedCount.store(0); - ThrowingType::destructedCount.store(0); + ThrowingType::constructedCount.storeRelaxed(0); + ThrowingType::destructedCount.storeRelaxed(0); bool exceptionCaught = false; try { @@ -165,11 +165,11 @@ void tst_QGlobalStatic::catchExceptionAndRetry() } catch (int) { exceptionCaught = true; } - QCOMPARE(ThrowingType::constructedCount.load(), 1); + QCOMPARE(ThrowingType::constructedCount.loadRelaxed(), 1); QVERIFY(exceptionCaught); exceptionGS(); - QCOMPARE(ThrowingType::constructedCount.load(), 2); + QCOMPARE(ThrowingType::constructedCount.loadRelaxed(), 2); } QBasicAtomicInt threadStressTestControlVar = Q_BASIC_ATOMIC_INITIALIZER(5); @@ -194,9 +194,9 @@ void tst_QGlobalStatic::threadStressTest() } }; - ThrowingType::constructedCount.store(0); - ThrowingType::destructedCount.store(0); - int expectedConstructionCount = threadStressTestControlVar.load() + 1; + ThrowingType::constructedCount.storeRelaxed(0); + ThrowingType::destructedCount.storeRelaxed(0); + int expectedConstructionCount = threadStressTestControlVar.loadRelaxed() + 1; if (expectedConstructionCount <= 0) QSKIP("This test cannot be run more than once"); diff --git a/tests/auto/corelib/global/qlogging/tst_qlogging.cpp b/tests/auto/corelib/global/qlogging/tst_qlogging.cpp index d3ed1a6d0d..17d0f86728 100644 --- a/tests/auto/corelib/global/qlogging/tst_qlogging.cpp +++ b/tests/auto/corelib/global/qlogging/tst_qlogging.cpp @@ -48,8 +48,10 @@ private slots: void defaultHandler(); void installMessageHandler(); +#if QT_DEPRECATED_SINCE(5, 0) void installMsgHandler(); void installBothHandler(); +#endif #ifdef QT_BUILD_INTERNAL void cleanupFuncinfo_data(); @@ -112,7 +114,9 @@ void tst_qmessagehandler::initTestCase() void tst_qmessagehandler::cleanup() { +#if QT_DEPRECATED_SINCE(5, 0) qInstallMsgHandler(0); +#endif qInstallMessageHandler((QtMessageHandler)0); s_type = QtFatalMsg; s_file = 0; @@ -143,6 +147,7 @@ void tst_qmessagehandler::installMessageHandler() QCOMPARE((void*)myHandler, (void*)customMessageHandler); } +#if QT_DEPRECATED_SINCE(5, 0) void tst_qmessagehandler::installMsgHandler() { QtMsgHandler oldHandler = qInstallMsgHandler(customMsgHandler); @@ -172,6 +177,7 @@ void tst_qmessagehandler::installBothHandler() QCOMPARE(s_function, Q_FUNC_INFO); QCOMPARE(s_line, line); } +#endif # define ADD(x) QTest::newRow(x) << Q_FUNC_INFO << x; @@ -254,19 +260,15 @@ public: int rvalue() && { ADD("TestClass1::rvalue"); return 0; } int const_rvalue() const && { ADD("TestClass1::const_rvalue"); return 0; } #endif -#ifdef Q_COMPILER_DECLTYPE int decltype_param(int x = 0, decltype(x) = 0) { ADD("TestClass1::decltype_param"); return x; } template<typename T> int decltype_template_param(T x = 0, decltype(x) = 0) { ADD("TestClass1::decltype_template_param"); return x; } template<typename T> void decltype_template_param2(T x, decltype(x + QString())) { ADD("TestClass1::decltype_template_param2"); } -# ifdef Q_COMPILER_AUTO_FUNCTION auto decltype_return(int x = 0) -> decltype(x) { ADD("TestClass1::decltype_return"); return x; } template <typename T> auto decltype_template_return(T x = 0) -> decltype(x) { ADD("TestClass1::decltype_template_return"); return x; } -# endif -#endif public: TestClass1() @@ -323,15 +325,11 @@ public: std::move(*this).rvalue(); std::move(*this).const_rvalue(); #endif -#ifdef Q_COMPILER_DECLTYPE decltype_param(); decltype_template_param(0); decltype_template_param2(QByteArray(), QString()); -# ifdef Q_COMPILER_AUTO_FUNCTION decltype_return(); decltype_template_return(0); -# endif -#endif } }; @@ -878,12 +876,14 @@ void tst_qmessagehandler::setMessagePattern() #endif // make sure there is no QT_MESSAGE_PATTERN in the environment - QStringList environment = m_baseEnvironment; - QMutableListIterator<QString> iter(environment); - while (iter.hasNext()) { - if (iter.next().startsWith("QT_MESSAGE_PATTERN")) - iter.remove(); - } + QStringList environment; + environment.reserve(m_baseEnvironment.size()); + const auto doesNotStartWith = [](QLatin1String s) { + return [s](const QString &str) { return !str.startsWith(s); }; + }; + std::copy_if(m_baseEnvironment.cbegin(), m_baseEnvironment.cend(), + std::back_inserter(environment), + doesNotStartWith(QLatin1String("QT_MESSAGE_PATTERN"))); process.setEnvironment(environment); process.start(appExe); diff --git a/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp b/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp index 03300c6dbe..a6d600e125 100644 --- a/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp +++ b/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Copyright (C) 2016 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** @@ -42,7 +42,15 @@ class tst_QNumeric: public QObject private slots: void fuzzyCompare_data(); void fuzzyCompare(); - void qNan(); + void rawNaN_data(); + void rawNaN(); +#if QT_CONFIG(signaling_nan) + void distinctNaN(); +#endif + void generalNaN_data(); + void generalNaN(); + void infinity(); + void classifyfp(); void floatDistance_data(); void floatDistance(); void floatDistance_double_data(); @@ -52,6 +60,8 @@ private slots: void mulOverflow_data(); void mulOverflow(); void signedOverflow(); +private: + void checkNaN(double nan); }; void tst_QNumeric::fuzzyCompare_data() @@ -91,39 +101,149 @@ void tst_QNumeric::fuzzyCompare() # pragma GCC optimize "no-fast-math" #endif -void tst_QNumeric::qNan() +void tst_QNumeric::checkNaN(double nan) +{ +#define CHECKNAN(value) \ + do { \ + const double v = (value); \ + QCOMPARE(qFpClassify(v), FP_NAN); \ + QVERIFY(qIsNaN(v)); \ + QVERIFY(!qIsFinite(v)); \ + QVERIFY(!qIsInf(v)); \ + } while (0) + + QVERIFY(!(0 > nan)); + QVERIFY(!(0 < nan)); + QVERIFY(!(0 == nan)); + QVERIFY(!(nan == nan)); + + CHECKNAN(nan); + CHECKNAN(nan + 1); + CHECKNAN(nan - 1); + CHECKNAN(-nan); + CHECKNAN(nan * 2.0); + CHECKNAN(nan / 2.0); + CHECKNAN(1.0 / nan); + CHECKNAN(0.0 / nan); + CHECKNAN(0.0 * nan); + + // When any NaN is expected, any NaN will do: + QCOMPARE(nan, nan); + QCOMPARE(nan, -nan); + QCOMPARE(nan, qQNaN()); +#undef CHECKNAN +} + +void tst_QNumeric::rawNaN_data() { #if defined __FAST_MATH__ && (__GNUC__ * 100 + __GNUC_MINOR__ < 404) QSKIP("Non-conformant fast math mode is enabled, cannot run test"); #endif - double nan = qQNaN(); - QVERIFY(!(0 > nan)); - QVERIFY(!(0 < nan)); - QVERIFY(qIsNaN(nan)); - QVERIFY(qIsNaN(nan + 1)); - QVERIFY(qIsNaN(-nan)); + QTest::addColumn<double>("nan"); + + QTest::newRow("quiet") << qQNaN(); +#if QT_CONFIG(signaling_nan) + QTest::newRow("signaling") << qSNaN(); +#endif +} + +void tst_QNumeric::rawNaN() +{ + QFETCH(double, nan); + checkNaN(nan); +} + +#if QT_CONFIG(signaling_nan) +void tst_QNumeric::distinctNaN() +{ + const double qnan = qQNaN(); + const double snan = qSNaN(); + QVERIFY(memcmp(&qnan, &snan, sizeof(double)) != 0); +} +#endif + +void tst_QNumeric::generalNaN_data() +{ + QTest::addColumn<int>("most"); + QTest::addColumn<int>("next"); + QTest::addColumn<int>("least"); + // Every value with every bit of the exponent set is a NaN. + // Sign and mantissa can be anything without interfering with that. + // The 0x7f bits of most and the 0xf0 bits of next are the exponent. + + QTest::newRow("lowload") << 0x7f << 0xf0 << 1; + QTest::newRow("sign-lowload") << 0xff << 0xf0 << 1; + QTest::newRow("highload") << 0x7f << 0xf1 << 0; + QTest::newRow("sign-highload") << 0xff << 0xf1 << 0; +} +void tst_QNumeric::generalNaN() +{ + QFETCH(int, most); + QFETCH(int, next); + QFETCH(int, least); + double nan; Q_STATIC_ASSERT(sizeof(double) == 8); #ifdef Q_LITTLE_ENDIAN - const uchar bytes[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f }; + const uchar bytes[] = { uchar(least), 0, 0, 0, 0, 0, uchar(next), uchar(most) }; #else - const uchar bytes[] = { 0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; + const uchar bytes[] = { uchar(most), uchar(next), 0, 0, 0, 0, 0, uchar(least) }; #endif memcpy(&nan, bytes, 8); - QVERIFY(!qIsFinite(nan)); - QVERIFY(!qIsInf(nan)); - QVERIFY(qIsNaN(nan)); + checkNaN(nan); +} - double inf = qInf(); +void tst_QNumeric::infinity() +{ + const double inf = qInf(); QVERIFY(inf > 0); QVERIFY(-inf < 0); QVERIFY(qIsInf(inf)); + QCOMPARE(inf, inf); + QCOMPARE(-inf, -inf); QVERIFY(qIsInf(-inf)); - QVERIFY(qIsInf(2*inf)); - QCOMPARE(1/inf, 0.0); - QVERIFY(qIsNaN(0*nan)); - QVERIFY(qIsNaN(0*inf)); - QVERIFY(qFuzzyCompare(1/inf, 0.0)); + QVERIFY(qIsInf(inf + 1)); + QVERIFY(qIsInf(inf - 1)); + QVERIFY(qIsInf(-inf - 1)); + QVERIFY(qIsInf(-inf + 1)); + QVERIFY(qIsInf(inf * 2.0)); + QVERIFY(qIsInf(-inf * 2.0)); + QVERIFY(qIsInf(inf / 2.0)); + QVERIFY(qIsInf(-inf / 2.0)); + QVERIFY(qFuzzyCompare(1.0 / inf, 0.0)); + QCOMPARE(1.0 / inf, 0.0); + QVERIFY(qFuzzyCompare(1.0 / -inf, 0.0)); + QCOMPARE(1.0 / -inf, 0.0); + QVERIFY(qIsNaN(0.0 * inf)); + QVERIFY(qIsNaN(0.0 * -inf)); +} + +void tst_QNumeric::classifyfp() +{ + // NaNs already handled, see checkNaN()'s callers. + + QCOMPARE(qFpClassify(qInf()), FP_INFINITE); + QCOMPARE(qFpClassify(-qInf()), FP_INFINITE); + QCOMPARE(qFpClassify(DBL_MAX * 2.0), FP_INFINITE); + QCOMPARE(qFpClassify(FLT_MAX * 2.f), FP_INFINITE); + QCOMPARE(qFpClassify(DBL_MAX * -2.0), FP_INFINITE); + QCOMPARE(qFpClassify(FLT_MAX * -2.f), FP_INFINITE); + + QCOMPARE(qFpClassify(1.0), FP_NORMAL); + QCOMPARE(qFpClassify(DBL_MAX), FP_NORMAL); + QCOMPARE(qFpClassify(-DBL_MAX), FP_NORMAL); + QCOMPARE(qFpClassify(DBL_MIN), FP_NORMAL); + QCOMPARE(qFpClassify(-DBL_MIN), FP_NORMAL); + QCOMPARE(qFpClassify(DBL_MIN / 2.0), FP_SUBNORMAL); + QCOMPARE(qFpClassify(DBL_MIN / -2.0), FP_SUBNORMAL); + + QCOMPARE(qFpClassify(1.f), FP_NORMAL); + QCOMPARE(qFpClassify(FLT_MAX), FP_NORMAL); + QCOMPARE(qFpClassify(-FLT_MAX), FP_NORMAL); + QCOMPARE(qFpClassify(FLT_MIN), FP_NORMAL); + QCOMPARE(qFpClassify(-FLT_MIN), FP_NORMAL); + QCOMPARE(qFpClassify(FLT_MIN / 2.f), FP_SUBNORMAL); + QCOMPARE(qFpClassify(FLT_MIN / -2.f), FP_SUBNORMAL); } void tst_QNumeric::floatDistance_data() @@ -461,13 +581,13 @@ template <typename Int> static void mulOverflow_template() QCOMPARE(mul_overflow(Int(max / 2), Int(3), &r), true); QCOMPARE(mul_overflow(mid1, Int(mid2 + 1), &r), true); QCOMPARE(mul_overflow(Int(max / 2 + 2), Int(2), &r), true); + QCOMPARE(mul_overflow(Int(max - max / 2), Int(2), &r), true); QCOMPARE(mul_overflow(Int(1ULL << (std::numeric_limits<Int>::digits - 1)), Int(2), &r), true); if (min) { QCOMPARE(mul_overflow(min, Int(2), &r), true); QCOMPARE(mul_overflow(Int(min / 2), Int(3), &r), true); QCOMPARE(mul_overflow(Int(min / 2 - 1), Int(2), &r), true); - QCOMPARE(mul_overflow(Int(min + min/2), Int(2), &r), true); } #endif } diff --git a/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp b/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp index dca49e9f7e..6f9dcc08f9 100644 --- a/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp +++ b/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp @@ -57,7 +57,7 @@ static const double RandomValueFP = double(0.3010463714599609); static void setRNGControl(uint v) { #ifdef QT_BUILD_INTERNAL - qt_randomdevice_control.store(v); + qt_randomdevice_control.storeRelaxed(v); #else Q_UNUSED(v); #endif @@ -511,7 +511,7 @@ void tst_QRandomGenerator::generateNonContiguous() QFETCH(uint, control); RandomGenerator rng(control); - QLinkedList<quint64> list = { 0, 0, 0, 0, 0, 0, 0, 0 }; + std::list<quint64> list(8); auto longerArrayCheck = [&] { QRandomGenerator().generate(list.begin(), list.end()); return find_if(list.begin(), list.end(), [&](quint64 cur) { diff --git a/tests/auto/corelib/global/qwinregistry/qwinregistry.pro b/tests/auto/corelib/global/qwinregistry/qwinregistry.pro new file mode 100644 index 0000000000..eab5df9dc3 --- /dev/null +++ b/tests/auto/corelib/global/qwinregistry/qwinregistry.pro @@ -0,0 +1,8 @@ +CONFIG += testcase +QT += testlib core-private +QT -= gui + +TARGET = tst_qwinregistry +CONFIG += console + +SOURCES += tst_qwinregistry.cpp diff --git a/tests/auto/testlib/selftests/alive/tst_alive.cpp b/tests/auto/corelib/global/qwinregistry/tst_qwinregistry.cpp index eeb77b18c0..ac811de2a1 100644 --- a/tests/auto/testlib/selftests/alive/tst_alive.cpp +++ b/tests/auto/corelib/global/qwinregistry/tst_qwinregistry.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. @@ -26,59 +26,43 @@ ** ****************************************************************************/ - #include <QtTest/QtTest> -#include <QWidget> -#include "qtestalive.cpp" +#include <QtCore/qoperatingsystemversion.h> + +#include <QtCore/private/qwinregistry_p.h> -class tst_Alive: public QObject +class tst_QWinRegistry : public QObject { Q_OBJECT -private slots: - void alive(); - void addMouseDClick() const; +public Q_SLOTS: + void initTestCase(); + +private Q_SLOTS: + void values(); }; -void tst_Alive::alive() +void tst_QWinRegistry::initTestCase() { - QTestAlive a; - a.start(); - - sleep(5); - QCoreApplication::processEvents(); - qDebug("CUT"); - sleep(5); + if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows10) + QSKIP("This test requires registry values present in Windows 10"); } -void tst_Alive::addMouseDClick() const +void tst_QWinRegistry::values() { - class DClickListener : public QWidget - { - public: - DClickListener() : isTested(false) - { - } - - bool isTested; - protected: - virtual void mouseDoubleClickEvent(QMouseEvent * event) - { - isTested = true; - QCOMPARE(event->type(), QEvent::MouseButtonDblClick); - } - }; - - DClickListener listener; - - QTestEventList list; - list.addMouseDClick(Qt::LeftButton); - - list.simulate(&listener); - /* Check that we have been called at all. */ - QVERIFY(listener.isTested); + QWinRegistryKey key(HKEY_LOCAL_MACHINE, LR"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)"); + QVERIFY(key.isValid()); + QVERIFY(!key.stringValue(L"ProductName").isEmpty()); + QVERIFY(key.stringValue(L"NonExistingKey").isEmpty()); + auto majorVersion = key.dwordValue(L"CurrentMajorVersionNumber"); + QVERIFY(majorVersion.second); + QVERIFY(majorVersion.first > 0); + auto nonExistingValue = key.dwordValue(L"NonExistingKey"); + QVERIFY(!nonExistingValue.second); + QCOMPARE(nonExistingValue.first, 0u); } -QTEST_MAIN(tst_Alive) -#include "tst_alive.moc" +QTEST_APPLESS_MAIN(tst_QWinRegistry); + +#include "tst_qwinregistry.moc" diff --git a/tests/auto/corelib/io/largefile/tst_largefile.cpp b/tests/auto/corelib/io/largefile/tst_largefile.cpp index dca7672b8e..e6d2f10c16 100644 --- a/tests/auto/corelib/io/largefile/tst_largefile.cpp +++ b/tests/auto/corelib/io/largefile/tst_largefile.cpp @@ -28,7 +28,6 @@ #include <QTest> -#include <QtAlgorithms> #include <QFile> #include <QFileInfo> #include <QRandomGenerator> @@ -36,6 +35,7 @@ #include <QDebug> +#include <algorithm> #include <cstdlib> #include <cstdio> @@ -489,13 +489,13 @@ void tst_LargeFile::mapFile() // Keep full block mapped to facilitate OS and/or internal reuse by Qt. uchar *baseAddress = largeFile.map(position, blockSize); QVERIFY( baseAddress ); - QVERIFY( qEqual(block.begin(), block.end(), reinterpret_cast<char*>(baseAddress)) ); + QVERIFY( std::equal(block.begin(), block.end(), reinterpret_cast<char*>(baseAddress)) ); for (int offset = 1; offset < blockSize; ++offset) { uchar *address = largeFile.map(position + offset, blockSize - offset); QVERIFY( address ); - if ( !qEqual(block.begin() + offset, block.end(), reinterpret_cast<char*>(address)) ) { + if ( !std::equal(block.begin() + offset, block.end(), reinterpret_cast<char*>(address)) ) { qDebug() << "Expected:" << block.toHex(); qDebug() << "Actual :" << QByteArray(reinterpret_cast<char*>(address), blockSize).toHex(); QVERIFY(false); diff --git a/tests/auto/corelib/io/qdebug/tst_qdebug.cpp b/tests/auto/corelib/io/qdebug/tst_qdebug.cpp index 7b8b1df166..584e66a7db 100644 --- a/tests/auto/corelib/io/qdebug/tst_qdebug.cpp +++ b/tests/auto/corelib/io/qdebug/tst_qdebug.cpp @@ -309,7 +309,7 @@ void tst_QDebug::stateSaver() const QDebug d = qDebug(); { QDebugStateSaver saver(d); - d.nospace() << hex << right << qSetFieldWidth(3) << qSetPadChar('0') << 42; + d.nospace() << Qt::hex << Qt::right << qSetFieldWidth(3) << qSetPadChar('0') << 42; } d << 42; } @@ -327,7 +327,7 @@ void tst_QDebug::stateSaver() const { QDebug d = qDebug(); - d.noquote().nospace() << QStringLiteral("Hello") << hex << 42; + d.noquote().nospace() << QStringLiteral("Hello") << Qt::hex << 42; { QDebugStateSaver saver(d); d.resetFormat(); @@ -506,7 +506,7 @@ void tst_QDebug::qDebugQStringView() const { QLatin1String file, function; int line = 0; - const QStringView inView = QStringViewLiteral("input"); + const QStringView inView = u"input"; MessageHandlerSetter mhs(myMessageHandler); { qDebug() << inView; } @@ -660,7 +660,7 @@ void tst_QDebug::textStreamModifiers() const QString file, function; int line = 0; MessageHandlerSetter mhs(myMessageHandler); - { qDebug() << hex << short(0xf) << int(0xf) << unsigned(0xf) << long(0xf) << qint64(0xf) << quint64(0xf); } + { qDebug() << Qt::hex << short(0xf) << int(0xf) << unsigned(0xf) << long(0xf) << qint64(0xf) << quint64(0xf); } #ifndef QT_NO_MESSAGELOGCONTEXT file = __FILE__; line = __LINE__ - 2; function = Q_FUNC_INFO; #endif @@ -678,7 +678,7 @@ void tst_QDebug::resetFormat() const MessageHandlerSetter mhs(myMessageHandler); { QDebug d = qDebug(); - d.nospace().noquote() << hex << int(0xf); + d.nospace().noquote() << Qt::hex << int(0xf); d.resetFormat() << int(0xf) << QStringLiteral("foo"); } #ifndef QT_NO_MESSAGELOGCONTEXT diff --git a/tests/auto/corelib/io/qdir/Info.plist b/tests/auto/corelib/io/qdir/Info.plist index 7dc5622bde..e1f6fbe24a 100644 --- a/tests/auto/corelib/io/qdir/Info.plist +++ b/tests/auto/corelib/io/qdir/Info.plist @@ -6,8 +6,6 @@ <string>${PRODUCT_NAME}</string> <key>CFBundleExecutable</key> <string>${EXECUTABLE_NAME}</string> - <key>CFBundleGetInfoString</key> - <string>Created by Qt/QMake</string> <key>CFBundleIconFile</key> <string>${ASSETCATALOG_COMPILER_APPICON_NAME}</string> <key>CFBundleIdentifier</key> diff --git a/tests/auto/corelib/io/qdir/tst_qdir.cpp b/tests/auto/corelib/io/qdir/tst_qdir.cpp index b703a8839f..52e7ebadb1 100644 --- a/tests/auto/corelib/io/qdir/tst_qdir.cpp +++ b/tests/auto/corelib/io/qdir/tst_qdir.cpp @@ -349,21 +349,21 @@ void tst_QDir::mkdirRmdir_data() QTest::addColumn<QString>("path"); QTest::addColumn<bool>("recurse"); - QStringList dirs; - dirs << "testdir/one" - << "testdir/two/three/four" - << "testdir/../testdir/three"; - QTest::newRow("plain") << QDir::currentPath() + "/" + dirs.at(0) << false; - QTest::newRow("recursive") << QDir::currentPath() + "/" + dirs.at(1) << true; - QTest::newRow("with-..") << QDir::currentPath() + "/" + dirs.at(2) << false; - - QTest::newRow("relative-plain") << dirs.at(0) << false; - QTest::newRow("relative-recursive") << dirs.at(1) << true; - QTest::newRow("relative-with-..") << dirs.at(2) << false; - - // Ensure that none of these directories already exist - for (int i = 0; i < dirs.count(); ++i) - QVERIFY(!QFile::exists(dirs.at(i))); + const struct { + const char *name; // shall have a prefix added + const char *path; // relative + bool recurse; + } cases[] = { + { "plain", "testdir/one", false }, + { "recursive", "testdir/two/three/four", true }, + { "with-..", "testdir/../testdir/three", false }, + }; + + for (const auto &it : cases) { + QVERIFY(!QFile::exists(it.path)); + QTest::addRow("absolute-%s", it.name) << (QDir::currentPath() + "/") + it.path << it.recurse; + QTest::addRow("relative-%s", it.name) << QString::fromLatin1(it.path) << it.recurse; + } } void tst_QDir::mkdirRmdir() @@ -1268,6 +1268,7 @@ tst_QDir::cleanPath_data() QTest::newRow("drive-above-root") << "A:/.." << "A:/.."; QTest::newRow("unc-server-up") << "//server/path/.." << "//server"; QTest::newRow("unc-server-above-root") << "//server/.." << "//server/.."; + QTest::newRow("longpath") << "\\\\?\\d:\\" << "d:/"; #else QTest::newRow("data15") << "//c:/foo" << "/c:/foo"; #endif // non-windows @@ -1745,6 +1746,7 @@ void tst_QDir::nativeSeparators() QCOMPARE(QDir::toNativeSeparators(QLatin1String("\\")), QString("\\")); QCOMPARE(QDir::fromNativeSeparators(QLatin1String("/")), QString("/")); QCOMPARE(QDir::fromNativeSeparators(QLatin1String("\\")), QString("/")); + QCOMPARE(QDir::fromNativeSeparators(QLatin1String("\\\\?\\C:\\")), QString("C:/")); #else QCOMPARE(QDir::toNativeSeparators(QLatin1String("/")), QString("/")); QCOMPARE(QDir::toNativeSeparators(QLatin1String("\\")), QString("\\")); diff --git a/tests/auto/corelib/io/qfile/BLACKLIST b/tests/auto/corelib/io/qfile/BLACKLIST deleted file mode 100644 index 8366667166..0000000000 --- a/tests/auto/corelib/io/qfile/BLACKLIST +++ /dev/null @@ -1,7 +0,0 @@ -# QTBUG-48455 -[readLineStdin] -msvc-2015 ci -msvc-2017 ci -[readLineStdin_lineByLine] -msvc-2015 ci -msvc-2017 ci diff --git a/tests/auto/corelib/io/qfile/test.pro b/tests/auto/corelib/io/qfile/test.pro index 95389ab3e2..7a2767bf3c 100644 --- a/tests/auto/corelib/io/qfile/test.pro +++ b/tests/auto/corelib/io/qfile/test.pro @@ -23,4 +23,4 @@ TESTDATA += \ Makefile forCopying.txt forRenaming.txt \ resources/file1.ext1 -win32:!winrt: LIBS += -lole32 -luuid +win32:!winrt: QMAKE_USE += ole32 uuid diff --git a/tests/auto/corelib/io/qfile/tst_qfile.cpp b/tests/auto/corelib/io/qfile/tst_qfile.cpp index 678a80c3f7..b8ae95dd93 100644 --- a/tests/auto/corelib/io/qfile/tst_qfile.cpp +++ b/tests/auto/corelib/io/qfile/tst_qfile.cpp @@ -550,6 +550,10 @@ void tst_QFile::exists() QFile unc(uncPath); QVERIFY2(unc.exists(), msgFileDoesNotExist(uncPath).constData()); #endif + + QTest::ignoreMessage(QtWarningMsg, "Broken filename passed to function"); + QVERIFY(!QFile::exists(QDir::currentPath() + QLatin1Char('/') + + QChar(QChar::Null) + QLatin1String("x/y"))); } void tst_QFile::open_data() @@ -2099,7 +2103,7 @@ void tst_QFile::i18nFileName() QVERIFY2(file.open(QFile::WriteOnly | QFile::Text), msgOpenFailed(file).constData()); QTextStream ts(&file); ts.setCodec("UTF-8"); - ts << fileName << endl; + ts << fileName << Qt::endl; } { QFile file(fileName); @@ -2149,7 +2153,7 @@ void tst_QFile::longFileName() QFile file(fileName); QVERIFY2(file.open(QFile::WriteOnly | QFile::Text), msgOpenFailed(file).constData()); QTextStream ts(&file); - ts << fileName << endl; + ts << fileName << Qt::endl; } { QFile file(fileName); diff --git a/tests/auto/corelib/io/qfileinfo/qfileinfo.pro b/tests/auto/corelib/io/qfileinfo/qfileinfo.pro index 496729f9f1..d181d16a3e 100644 --- a/tests/auto/corelib/io/qfileinfo/qfileinfo.pro +++ b/tests/auto/corelib/io/qfileinfo/qfileinfo.pro @@ -5,4 +5,4 @@ SOURCES = tst_qfileinfo.cpp RESOURCES += qfileinfo.qrc \ testdata.qrc -win32:!winrt: LIBS += -ladvapi32 -lnetapi32 +win32:!winrt: QMAKE_USE += advapi32 netapi32 diff --git a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp index 646fb2078a..0597a7d521 100644 --- a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp +++ b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp @@ -49,6 +49,7 @@ #ifdef Q_OS_WIN #include <qt_windows.h> #if !defined(Q_OS_WINRT) +#include <private/qwinregistry_p.h> #include <lm.h> #endif #endif @@ -237,6 +238,15 @@ private slots: void isSymLink_data(); void isSymLink(); + void isSymbolicLink_data(); + void isSymbolicLink(); + + void isShortcut_data(); + void isShortcut(); + + void link_data(); + void link(); + void isHidden_data(); void isHidden(); #if defined(Q_OS_MAC) @@ -1036,7 +1046,9 @@ void tst_QFileInfo::systemFiles() QCOMPARE(fi.metadataChangeTime(), fi.lastModified()); // On Windows, they're the same QVERIFY(fi.birthTime().isValid()); QVERIFY(fi.birthTime() <= fi.lastModified()); +#if QT_DEPRECATED_SINCE(5, 10) QCOMPARE(fi.created(), fi.birthTime()); // On Windows, they're the same +#endif } void tst_QFileInfo::compare_data() @@ -1184,7 +1196,7 @@ void tst_QFileInfo::fileTimes() QTest::qSleep(sleepTime); beforeWrite = QDateTime::currentDateTime().addMSecs(-fsClockSkew); QTextStream ts(&file); - ts << fileName << endl; + ts << fileName << Qt::endl; } { QFileInfo fileInfo(fileName); @@ -1232,17 +1244,12 @@ void tst_QFileInfo::fileTimes() //In Vista the last-access timestamp is not updated when the file is accessed/touched (by default). //To enable this the HKLM\SYSTEM\CurrentControlSet\Control\FileSystem\NtfsDisableLastAccessUpdate //is set to 0, in the test machine. - HKEY key; - if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\FileSystem", - 0, KEY_READ, &key)) { - DWORD disabledAccessTimes = 0; - DWORD size = sizeof(DWORD); - LONG error = RegQueryValueEx(key, L"NtfsDisableLastAccessUpdate" - , NULL, NULL, (LPBYTE)&disabledAccessTimes, &size); - if (ERROR_SUCCESS == error && disabledAccessTimes) - noAccessTime = true; - RegCloseKey(key); - } + const auto disabledAccessTimes = + QWinRegistryKey(HKEY_LOCAL_MACHINE, + LR"(SYSTEM\CurrentControlSet\Control\FileSystem)") + .dwordValue(L"NtfsDisableLastAccessUpdate"); + if (disabledAccessTimes.second && disabledAccessTimes.first != 0) + noAccessTime = true; #endif if (noAccessTime) @@ -1261,7 +1268,7 @@ void tst_QFileInfo::fakeFileTimes_data() QTest::newRow("early") << QDateTime(QDate(1901, 12, 14), QTime(12, 0)); // QTBUG-12006 claims XP handled this (2010-Mar-26 8:46:10) wrong due to an MS API bug: - QTest::newRow("XP-bug") << QDateTime::fromTime_t(1269593170); + QTest::newRow("XP-bug") << QDateTime::fromSecsSinceEpoch(1269593170); } void tst_QFileInfo::fakeFileTimes() @@ -1335,6 +1342,176 @@ void tst_QFileInfo::isSymLink() #endif } +void tst_QFileInfo::isShortcut_data() +{ + QFile::remove("link.lnk"); + QFile::remove("symlink.lnk"); + QFile::remove("link"); + QFile::remove("symlink"); + QFile::remove("directory.lnk"); + QFile::remove("directory"); + + QTest::addColumn<QString>("path"); + QTest::addColumn<bool>("isShortcut"); + + QFile regularFile(m_sourceFile); + QTest::newRow("regular") + << regularFile.fileName() << false; + QTest::newRow("directory") + << QDir::currentPath() << false; +#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) + // windows shortcuts + QVERIFY(regularFile.link("link.lnk")); + QTest::newRow("shortcut") + << "link.lnk" << true; + QVERIFY(regularFile.link("link")); + QTest::newRow("invalid-shortcut") + << "link" << false; + QVERIFY(QFile::link(QDir::currentPath(), "directory.lnk")); + QTest::newRow("directory-shortcut") + << "directory.lnk" << true; +#endif +} + +void tst_QFileInfo::isShortcut() +{ + QFETCH(QString, path); + QFETCH(bool, isShortcut); + + QFileInfo fi(path); + QCOMPARE(fi.isShortcut(), isShortcut); +} + +void tst_QFileInfo::isSymbolicLink_data() +{ + QTest::addColumn<QString>("path"); + QTest::addColumn<bool>("isSymbolicLink"); + + QFile regularFile(m_sourceFile); + QTest::newRow("regular") + << regularFile.fileName() << false; + QTest::newRow("directory") + << QDir::currentPath() << false; + +#ifndef Q_NO_SYMLINKS +#if defined(Q_OS_WIN) +#if !defined(Q_OS_WINRT) + QString errorMessage; + const DWORD creationResult = createSymbolicLink("symlink", m_sourceFile, &errorMessage); + if (creationResult == ERROR_PRIVILEGE_NOT_HELD) { + QWARN(msgInsufficientPrivileges(errorMessage)); + } else { + QVERIFY2(creationResult == ERROR_SUCCESS, qPrintable(errorMessage)); + QTest::newRow("NTFS-symlink") + << "symlink" << true; + } +#endif // !Q_OS_WINRT +#else // Unix: + QVERIFY(regularFile.link("symlink.lnk")); + QTest::newRow("symlink.lnk") + << "symlink.lnk" << true; + QVERIFY(regularFile.link("symlink")); + QTest::newRow("symlink") + << "symlink" << true; + QVERIFY(QFile::link(QDir::currentPath(), "directory")); + QTest::newRow("directory-symlink") + << "directory" << true; +#endif +#endif // !Q_NO_SYMLINKS +} + +void tst_QFileInfo::isSymbolicLink() +{ + QFETCH(QString, path); + QFETCH(bool, isSymbolicLink); + + QFileInfo fi(path); + QCOMPARE(fi.isSymbolicLink(), isSymbolicLink); +} + +void tst_QFileInfo::link_data() +{ + QFile::remove("link"); + QFile::remove("link.lnk"); + QFile::remove("brokenlink"); + QFile::remove("brokenlink.lnk"); + QFile::remove("dummyfile"); + QFile::remove("relative/link"); + + QTest::addColumn<QString>("path"); + QTest::addColumn<bool>("isShortcut"); + QTest::addColumn<bool>("isSymbolicLink"); + QTest::addColumn<QString>("linkTarget"); + + QFile file1(m_sourceFile); + QFile file2("dummyfile"); + file2.open(QIODevice::WriteOnly); + + QTest::newRow("existent file") << m_sourceFile << false << false << ""; +#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) + // windows shortcuts + QVERIFY(file1.link("link.lnk")); + QTest::newRow("link.lnk") + << "link.lnk" << true << false << QFileInfo(m_sourceFile).absoluteFilePath(); + + QVERIFY(file2.link("brokenlink.lnk")); + QTest::newRow("broken link.lnk") + << "brokenlink.lnk" << true << false << QFileInfo("dummyfile").absoluteFilePath(); +#endif + +#ifndef Q_NO_SYMLINKS +#if defined(Q_OS_WIN) +#if !defined(Q_OS_WINRT) + QString errorMessage; + DWORD creationResult = createSymbolicLink("link", m_sourceFile, &errorMessage); + if (creationResult == ERROR_PRIVILEGE_NOT_HELD) { + QWARN(msgInsufficientPrivileges(errorMessage)); + } else { + QVERIFY2(creationResult == ERROR_SUCCESS, qPrintable(errorMessage)); + QTest::newRow("link") + << "link" << false << true << QFileInfo(m_sourceFile).absoluteFilePath(); + } + + creationResult = createSymbolicLink("brokenlink", "dummyfile", &errorMessage); + if (creationResult == ERROR_PRIVILEGE_NOT_HELD) { + QWARN(msgInsufficientPrivileges(errorMessage)); + } else { + QVERIFY2(creationResult == ERROR_SUCCESS, qPrintable(errorMessage)); + QTest::newRow("broken link") + << "brokenlink" << false << true << QFileInfo("dummyfile").absoluteFilePath(); + } +#endif // !Q_OS_WINRT +#else // Unix: + QVERIFY(file1.link("link")); + QTest::newRow("link") + << "link" << false << true << QFileInfo(m_sourceFile).absoluteFilePath(); + + QVERIFY(file2.link("brokenlink")); + QTest::newRow("broken link") + << "brokenlink" << false << true << QFileInfo("dummyfile").absoluteFilePath(); + + QDir::current().mkdir("relative"); + QFile::link("../dummyfile", "relative/link"); + QTest::newRow("relative link") + << "relative/link" << false << true << QFileInfo("dummyfile").absoluteFilePath(); +#endif +#endif // !Q_NO_SYMLINKS + file2.remove(); +} + +void tst_QFileInfo::link() +{ + QFETCH(QString, path); + QFETCH(bool, isShortcut); + QFETCH(bool, isSymbolicLink); + QFETCH(QString, linkTarget); + + QFileInfo fi(path); + QCOMPARE(fi.isShortcut(), isShortcut); + QCOMPARE(fi.isSymbolicLink(), isSymbolicLink); + QCOMPARE(fi.symLinkTarget(), linkTarget); +} + void tst_QFileInfo::isHidden_data() { QTest::addColumn<QString>("path"); @@ -1636,7 +1813,7 @@ void tst_QFileInfo::ntfsJunctionPointsAndSymlinks() QVERIFY2(creationResult == ERROR_SUCCESS, qPrintable(errorMessage)); QFileInfo fi(path); - const bool actualIsSymLink = fi.isSymLink(); + const bool actualIsSymLink = fi.isSymbolicLink(); const QString actualSymLinkTarget = isSymLink ? fi.symLinkTarget() : QString(); const QString actualCanonicalFilePath = isSymLink ? fi.canonicalFilePath() : QString(); // Ensure that junctions, mountpoints are removed. If this fails, do not remove @@ -1665,14 +1842,16 @@ void tst_QFileInfo::brokenShortcut() file.close(); QFileInfo info(linkName); - QVERIFY(info.isSymLink()); + QVERIFY(!info.isSymbolicLink()); + QVERIFY(info.isShortcut()); QVERIFY(!info.exists()); QFile::remove(linkName); QDir current; // QTBUG-21863 QVERIFY(current.mkdir(linkName)); QFileInfo dirInfo(linkName); - QVERIFY(!dirInfo.isSymLink()); + QVERIFY(!dirInfo.isSymbolicLink()); + QVERIFY(!dirInfo.isShortcut()); QVERIFY(dirInfo.isDir()); current.rmdir(linkName); } @@ -1915,7 +2094,7 @@ void tst_QFileInfo::owner() DWORD bufSize = 1024; if (GetUserNameW(usernameBuf, &bufSize)) { userName = QString::fromWCharArray(usernameBuf); - if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && IsUserAdmin()) { + if (IsUserAdmin()) { // Special case : If the user is a member of Administrators group, all files // created by the current user are owned by the Administrators group. LPLOCALGROUP_USERS_INFO_0 pBuf = NULL; @@ -2029,7 +2208,8 @@ static void stateCheck(const QFileInfo &info, const QString &dirname, const QStr QVERIFY(!info.isHidden()); QVERIFY(!info.isFile()); QVERIFY(!info.isDir()); - QVERIFY(!info.isSymLink()); + QVERIFY(!info.isSymbolicLink()); + QVERIFY(!info.isShortcut()); QVERIFY(!info.isBundle()); QVERIFY(!info.isRoot()); QCOMPARE(info.isNativePath(), !filename.isEmpty()); @@ -2042,7 +2222,9 @@ static void stateCheck(const QFileInfo &info, const QString &dirname, const QStr QCOMPARE(info.permissions(), QFile::Permissions()); +#if QT_DEPRECATED_SINCE(5, 10) QVERIFY(!info.created().isValid()); +#endif QVERIFY(!info.birthTime().isValid()); QVERIFY(!info.metadataChangeTime().isValid()); QVERIFY(!info.lastRead().isValid()); @@ -2084,5 +2266,6 @@ void tst_QFileInfo::nonExistingFile() stateCheck(info, dirname, filename); } + QTEST_MAIN(tst_QFileInfo) #include "tst_qfileinfo.moc" diff --git a/tests/auto/corelib/io/qfilesystemwatcher/BLACKLIST b/tests/auto/corelib/io/qfilesystemwatcher/BLACKLIST index 90b714758a..457499591d 100644 --- a/tests/auto/corelib/io/qfilesystemwatcher/BLACKLIST +++ b/tests/auto/corelib/io/qfilesystemwatcher/BLACKLIST @@ -1,6 +1,7 @@ # QTBUG-33574 QTBUG-30943 [signalsEmittedAfterFileMoved] -windows +windows-7sp1 +windows-10 [watchFileAndItsDirectory:native backend-testfile] osx windows diff --git a/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp b/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp index 67ffa91e57..cdd1f6361e 100644 --- a/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp +++ b/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp @@ -46,11 +46,13 @@ public: tst_QFileSystemWatcher(); private slots: +#ifdef QT_BUILD_INTERNAL void basicTest_data(); void basicTest(); void watchDirectory_data(); void watchDirectory(); +#endif void addPath(); void removePath(); @@ -58,8 +60,10 @@ private slots: void removePaths(); void removePathsFilesInSameDirectory(); +#ifdef QT_BUILD_INTERNAL void watchFileAndItsDirectory_data() { basicTest_data(); } void watchFileAndItsDirectory(); +#endif void nonExistingFile(); @@ -67,8 +71,10 @@ private slots: void destroyAfterQCoreApplication(); +#ifdef QT_BUILD_INTERNAL void QTBUG2331(); void QTBUG2331_data() { basicTest_data(); } +#endif void signalsEmittedAfterFileMoved(); @@ -90,6 +96,7 @@ tst_QFileSystemWatcher::tst_QFileSystemWatcher() #endif } +#ifdef QT_BUILD_INTERNAL void tst_QFileSystemWatcher::basicTest_data() { QTest::addColumn<QString>("backend"); @@ -360,6 +367,7 @@ void tst_QFileSystemWatcher::watchDirectory() for (const auto &testDirName : testDirs) QVERIFY(temporaryDir.rmdir(testDirName)); } +#endif // QT_BUILD_INTERNAL void tst_QFileSystemWatcher::addPath() { @@ -502,6 +510,7 @@ void tst_QFileSystemWatcher::removePathsFilesInSameDirectory() QCOMPARE(watcher.files().size(), 0); } +#ifdef QT_BUILD_INTERNAL static QByteArray msgFileOperationFailed(const char *what, const QFile &f) { return what + QByteArrayLiteral(" failed on \"") @@ -601,6 +610,7 @@ void tst_QFileSystemWatcher::watchFileAndItsDirectory() QVERIFY(temporaryDir.rmdir(testDirName)); } +#endif // QT_BUILD_INTERNAL void tst_QFileSystemWatcher::nonExistingFile() { @@ -673,6 +683,7 @@ void tst_QFileSystemWatcher::destroyAfterQCoreApplication() QTest::qWait(30); } +#ifdef QT_BUILD_INTERNAL // regression test for QTBUG2331. // essentially, on windows, directories were not unwatched after being deleted // from the disk, causing all sorts of interesting problems. @@ -696,6 +707,7 @@ void tst_QFileSystemWatcher::QTBUG2331() QTRY_COMPARE(changedSpy.count(), 1); QCOMPARE(watcher.directories(), QStringList()); } +#endif // QT_BUILD_INTERNAL class SignalReceiver : public QObject { diff --git a/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp b/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp index eeeb3bc6e2..8703b15dda 100644 --- a/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp +++ b/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp @@ -496,7 +496,7 @@ void tst_QLockFile::noPermissionsWindows() QSKIP("This test is for desktop Windows only"); #endif #ifdef Q_OS_WIN - if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS7) + if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows7) QSKIP("This test requires at least Windows 7"); #endif if (const int p = processProperties()) { diff --git a/tests/auto/corelib/io/qlockfile/tst_qlockfile.pro b/tests/auto/corelib/io/qlockfile/tst_qlockfile.pro index da2660fd02..e33e22b36f 100644 --- a/tests/auto/corelib/io/qlockfile/tst_qlockfile.pro +++ b/tests/auto/corelib/io/qlockfile/tst_qlockfile.pro @@ -3,4 +3,4 @@ TARGET = tst_qlockfile SOURCES += tst_qlockfile.cpp QT = core-private testlib concurrent -win32:!winrt:LIBS += -ladvapi32 +win32:!winrt: QMAKE_USE += advapi32 diff --git a/tests/auto/corelib/io/qloggingcategory/tst_qloggingcategory.cpp b/tests/auto/corelib/io/qloggingcategory/tst_qloggingcategory.cpp index 11a9b3f189..79ac6b0fc4 100644 --- a/tests/auto/corelib/io/qloggingcategory/tst_qloggingcategory.cpp +++ b/tests/auto/corelib/io/qloggingcategory/tst_qloggingcategory.cpp @@ -104,7 +104,7 @@ public: for (int a = 0; a < _configitemEntryOrder.count(); a++) { out << _configitemEntryOrder[a] << " = " - << _values.value(_configitemEntryOrder[a]) << endl; + << _values.value(_configitemEntryOrder[a]) << Qt::endl; } out.flush(); return ret.toLatin1(); @@ -369,11 +369,9 @@ private slots: } Q_LOGGING_CATEGORY(TST_MACRO_1, "tst.macro.1") -#ifdef Q_COMPILER_VARIADIC_MACROS Q_LOGGING_CATEGORY(TST_MACRO_2, "tst.macro.2", QtDebugMsg) Q_LOGGING_CATEGORY(TST_MACRO_3, "tst.macro.3", QtFatalMsg) Q_LOGGING_CATEGORY(TST_MACRO_4, "tst.macro.4", QtInfoMsg) -#endif void QLoggingCategoryMacro() { @@ -384,7 +382,6 @@ private slots: QCOMPARE(cat1.isWarningEnabled(), true); QCOMPARE(cat1.isCriticalEnabled(), true); -#ifdef Q_COMPILER_VARIADIC_MACROS const QLoggingCategory &cat2 = TST_MACRO_2(); QCOMPARE(cat2.categoryName(), "tst.macro.2"); QCOMPARE(cat2.isDebugEnabled(), true); @@ -405,7 +402,6 @@ private slots: QCOMPARE(cat4.isInfoEnabled(), true); QCOMPARE(cat4.isWarningEnabled(), true); QCOMPARE(cat4.isCriticalEnabled(), true); -#endif } void qCDebugMacros() diff --git a/tests/auto/corelib/io/qnodebug/tst_qnodebug.cpp b/tests/auto/corelib/io/qnodebug/tst_qnodebug.cpp index 569c610e24..b05c89a8bb 100644 --- a/tests/auto/corelib/io/qnodebug/tst_qnodebug.cpp +++ b/tests/auto/corelib/io/qnodebug/tst_qnodebug.cpp @@ -65,7 +65,7 @@ void tst_QNoDebug::noDebugOutput() const void tst_QNoDebug::streaming() const { QDateTime dt(QDate(1,2,3),QTime(4,5,6)); - const QByteArray debugString = dt.toString(QStringViewLiteral("yyyy-MM-dd HH:mm:ss.zzz t")).toLatin1(); + const QByteArray debugString = dt.toString(u"yyyy-MM-dd HH:mm:ss.zzz t").toLatin1(); const QByteArray message = "QDateTime(" + debugString + " Qt::LocalTime)"; QTest::ignoreMessage(QtWarningMsg, message.constData()); qWarning() << dt; diff --git a/tests/auto/corelib/io/qprocess/BLACKLIST b/tests/auto/corelib/io/qprocess/BLACKLIST index b355bb0f75..682bcbc60c 100644 --- a/tests/auto/corelib/io/qprocess/BLACKLIST +++ b/tests/auto/corelib/io/qprocess/BLACKLIST @@ -2,8 +2,5 @@ redhatenterpriselinuxworkstation-6.6 # QTBUG-48455 [fileWriterProcess] -msvc-2015 ci -msvc-2017 ci -[softExitInSlots] -# QTBUG-66903 -windows +windows-10 msvc-2017 + diff --git a/tests/auto/corelib/io/qprocess/testProcessEchoGui/testProcessEchoGui.pro b/tests/auto/corelib/io/qprocess/testProcessEchoGui/testProcessEchoGui.pro index 935f43630c..e41ed0a425 100644 --- a/tests/auto/corelib/io/qprocess/testProcessEchoGui/testProcessEchoGui.pro +++ b/tests/auto/corelib/io/qprocess/testProcessEchoGui/testProcessEchoGui.pro @@ -1,6 +1,6 @@ win32 { SOURCES = main_win.cpp - LIBS += -luser32 + QMAKE_USE += user32 } CONFIG -= qt app_bundle diff --git a/tests/auto/corelib/io/qprocess/testSoftExit/testSoftExit.pro b/tests/auto/corelib/io/qprocess/testSoftExit/testSoftExit.pro index 2cfcb4794e..964c47f6ae 100644 --- a/tests/auto/corelib/io/qprocess/testSoftExit/testSoftExit.pro +++ b/tests/auto/corelib/io/qprocess/testSoftExit/testSoftExit.pro @@ -1,6 +1,6 @@ win32 { SOURCES = main_win.cpp - LIBS += -luser32 + QMAKE_USE += user32 } unix { SOURCES = main_unix.cpp diff --git a/tests/auto/corelib/io/qprocess/tst_qprocess.cpp b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp index c51994c1c1..e799369c8a 100644 --- a/tests/auto/corelib/io/qprocess/tst_qprocess.cpp +++ b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp @@ -32,6 +32,7 @@ #include <QtTest/QtTest> #include <QtCore/QProcess> #include <QtCore/QDir> +#include <QtCore/QElapsedTimer> #include <QtCore/QFile> #include <QtCore/QThread> #include <QtCore/QTemporaryDir> @@ -150,6 +151,13 @@ private slots: void failToStartEmptyArgs_data(); void failToStartEmptyArgs(); +#if QT_DEPRECATED_SINCE(5, 13) + void crashTest2_deprecated(); + void restartProcessDeadlock_deprecated(); + void waitForReadyReadInAReadyReadSlot_deprecated(); + void finishProcessBeforeReadingDone_deprecated(); +#endif + protected slots: void readFromProcess(); void exitLoopSlot(); @@ -186,12 +194,20 @@ void tst_QProcess::getSetCheck() QProcess obj1; // ProcessChannelMode QProcess::readChannelMode() // void QProcess::setProcessChannelMode(ProcessChannelMode) +#if QT_DEPRECATED_SINCE(5, 13) obj1.setProcessChannelMode(QProcess::ProcessChannelMode(QProcess::SeparateChannels)); QCOMPARE(QProcess::ProcessChannelMode(QProcess::SeparateChannels), obj1.readChannelMode()); obj1.setProcessChannelMode(QProcess::ProcessChannelMode(QProcess::MergedChannels)); QCOMPARE(QProcess::ProcessChannelMode(QProcess::MergedChannels), obj1.readChannelMode()); obj1.setProcessChannelMode(QProcess::ProcessChannelMode(QProcess::ForwardedChannels)); QCOMPARE(QProcess::ProcessChannelMode(QProcess::ForwardedChannels), obj1.readChannelMode()); +#endif + obj1.setProcessChannelMode(QProcess::ProcessChannelMode(QProcess::SeparateChannels)); + QCOMPARE(QProcess::ProcessChannelMode(QProcess::SeparateChannels), obj1.processChannelMode()); + obj1.setProcessChannelMode(QProcess::ProcessChannelMode(QProcess::MergedChannels)); + QCOMPARE(QProcess::ProcessChannelMode(QProcess::MergedChannels), obj1.processChannelMode()); + obj1.setProcessChannelMode(QProcess::ProcessChannelMode(QProcess::ForwardedChannels)); + QCOMPARE(QProcess::ProcessChannelMode(QProcess::ForwardedChannels), obj1.processChannelMode()); // ProcessChannel QProcess::readChannel() // void QProcess::setReadChannel(ProcessChannel) @@ -334,12 +350,14 @@ void tst_QProcess::crashTest() qRegisterMetaType<QProcess::ExitStatus>("QProcess::ExitStatus"); QSignalSpy spy(process.data(), &QProcess::errorOccurred); - QSignalSpy spy2(process.data(), static_cast<QProcessErrorSignal>(&QProcess::error)); - QSignalSpy spy3(process.data(), static_cast<QProcessFinishedSignal2>(&QProcess::finished)); - + QSignalSpy spy2(process.data(), static_cast<QProcessFinishedSignal2>(&QProcess::finished)); QVERIFY(spy.isValid()); QVERIFY(spy2.isValid()); + +#if QT_DEPRECATED_SINCE(5, 6) + QSignalSpy spy3(process.data(), static_cast<QProcessErrorSignal>(&QProcess::error)); QVERIFY(spy3.isValid()); +#endif QVERIFY(process->waitForFinished(30000)); @@ -347,10 +365,12 @@ void tst_QProcess::crashTest() QCOMPARE(*static_cast<const QProcess::ProcessError *>(spy.at(0).at(0).constData()), QProcess::Crashed); QCOMPARE(spy2.count(), 1); - QCOMPARE(*static_cast<const QProcess::ProcessError *>(spy2.at(0).at(0).constData()), QProcess::Crashed); + QCOMPARE(*static_cast<const QProcess::ExitStatus *>(spy2.at(0).at(1).constData()), QProcess::CrashExit); +#if QT_DEPRECATED_SINCE(5, 6) QCOMPARE(spy3.count(), 1); - QCOMPARE(*static_cast<const QProcess::ExitStatus *>(spy3.at(0).at(1).constData()), QProcess::CrashExit); + QCOMPARE(*static_cast<const QProcess::ProcessError *>(spy3.at(0).at(0).constData()), QProcess::Crashed); +#endif QCOMPARE(process->exitStatus(), QProcess::CrashExit); @@ -378,7 +398,7 @@ void tst_QProcess::crashTest2() QVERIFY(spy.isValid()); QVERIFY(spy2.isValid()); - QObject::connect(&process, static_cast<QProcessFinishedSignal1>(&QProcess::finished), + QObject::connect(&process, static_cast<QProcessFinishedSignal2>(&QProcess::finished), this, &tst_QProcess::exitLoopSlot); QTestEventLoop::instance().enterLoop(30); @@ -420,7 +440,7 @@ void tst_QProcess::echoTest() process.write(input); - QTime stopWatch; + QElapsedTimer stopWatch; stopWatch.start(); do { QVERIFY(process.isOpen()); @@ -479,7 +499,7 @@ void tst_QProcess::echoTest2() QVERIFY(spy1.isValid()); QVERIFY(spy2.isValid()); - QTime stopWatch; + QElapsedTimer stopWatch; stopWatch.start(); forever { QTestEventLoop::instance().enterLoop(1); @@ -644,9 +664,11 @@ void tst_QProcess::readTimeoutAndThenCrash() qRegisterMetaType<QProcess::ProcessError>("QProcess::ProcessError"); QSignalSpy spy(&process, &QProcess::errorOccurred); - QSignalSpy spy2(&process, static_cast<QProcessErrorSignal>(&QProcess::error)); QVERIFY(spy.isValid()); +#if QT_DEPRECATED_SINCE(5, 6) + QSignalSpy spy2(&process, static_cast<QProcessErrorSignal>(&QProcess::error)); QVERIFY(spy2.isValid()); +#endif process.kill(); @@ -655,8 +677,10 @@ void tst_QProcess::readTimeoutAndThenCrash() QCOMPARE(spy.count(), 1); QCOMPARE(*static_cast<const QProcess::ProcessError *>(spy.at(0).at(0).constData()), QProcess::Crashed); +#if QT_DEPRECATED_SINCE(5, 6) QCOMPARE(spy2.count(), 1); QCOMPARE(*static_cast<const QProcess::ProcessError *>(spy2.at(0).at(0).constData()), QProcess::Crashed); +#endif } void tst_QProcess::waitForFinished() @@ -696,12 +720,11 @@ void tst_QProcess::deadWhileReading() void tst_QProcess::restartProcessDeadlock() { - // The purpose of this test is to detect whether restarting a // process in the finished() connected slot causes a deadlock // because of the way QProcessManager uses its locks. QProcess process; - connect(&process, static_cast<QProcessFinishedSignal1>(&QProcess::finished), + connect(&process, static_cast<QProcessFinishedSignal2>(&QProcess::finished), this, &tst_QProcess::restartProcess); process.start("testProcessEcho/testProcessEcho"); @@ -709,7 +732,7 @@ void tst_QProcess::restartProcessDeadlock() QCOMPARE(process.write("", 1), qlonglong(1)); QVERIFY(process.waitForFinished(5000)); - QObject::disconnect(&process, static_cast<QProcessFinishedSignal1>(&QProcess::finished), nullptr, nullptr); + QObject::disconnect(&process, static_cast<QProcessFinishedSignal2>(&QProcess::finished), nullptr, nullptr); QCOMPARE(process.write("", 1), qlonglong(1)); QVERIFY(process.waitForFinished(5000)); @@ -1026,7 +1049,7 @@ void tst_QProcess::mergedChannels() { QProcess process; process.setProcessChannelMode(QProcess::MergedChannels); - QCOMPARE(process.readChannelMode(), QProcess::MergedChannels); + QCOMPARE(process.processChannelMode(), QProcess::MergedChannels); process.start("testProcessEcho2/testProcessEcho2"); @@ -1154,7 +1177,7 @@ protected: exitCode = 90210; QProcess process; - connect(&process, static_cast<QProcessFinishedSignal1>(&QProcess::finished), + connect(&process, static_cast<QProcessFinishedSignal2>(&QProcess::finished), this, &TestThread::catchExitCode, Qt::DirectConnection); process.start("testProcessEcho/testProcessEcho"); @@ -1228,7 +1251,7 @@ void tst_QProcess::waitForReadyReadInAReadyReadSlot() { QProcess process; connect(&process, &QIODevice::readyRead, this, &tst_QProcess::waitForReadyReadInAReadyReadSlotSlot); - connect(&process, static_cast<QProcessFinishedSignal1>(&QProcess::finished), + connect(&process, static_cast<QProcessFinishedSignal2>(&QProcess::finished), this, &tst_QProcess::exitLoopSlot); bytesAvailable = 0; @@ -1467,15 +1490,19 @@ void tst_QProcess::failToStart() QProcess process; QSignalSpy stateSpy(&process, &QProcess::stateChanged); QSignalSpy errorSpy(&process, &QProcess::errorOccurred); - QSignalSpy errorSpy2(&process, static_cast<QProcessErrorSignal>(&QProcess::error)); - QSignalSpy finishedSpy(&process, static_cast<QProcessFinishedSignal1>(&QProcess::finished)); - QSignalSpy finishedSpy2(&process, static_cast<QProcessFinishedSignal2>(&QProcess::finished)); - + QSignalSpy finishedSpy(&process, static_cast<QProcessFinishedSignal2>(&QProcess::finished)); QVERIFY(stateSpy.isValid()); QVERIFY(errorSpy.isValid()); - QVERIFY(errorSpy2.isValid()); QVERIFY(finishedSpy.isValid()); + +#if QT_DEPRECATED_SINCE(5, 6) + QSignalSpy errorSpy2(&process, static_cast<QProcessErrorSignal>(&QProcess::error)); + QVERIFY(errorSpy2.isValid()); +#endif +#if QT_DEPRECATED_SINCE(5, 13) + QSignalSpy finishedSpy2(&process, static_cast<QProcessFinishedSignal1>(&QProcess::finished)); QVERIFY(finishedSpy2.isValid()); +#endif // OS X and HP-UX have a really low default process limit (~100), so spawning // to many processes here will cause test failures later on. @@ -1490,7 +1517,9 @@ void tst_QProcess::failToStart() for (int j = 0; j < 8; ++j) { for (int i = 0; i < attempts; ++i) { QCOMPARE(errorSpy.count(), j * attempts + i); +#if QT_DEPRECATED_SINCE(5, 6) QCOMPARE(errorSpy2.count(), j * attempts + i); +#endif process.start("/blurp"); switch (j) { @@ -1515,9 +1544,13 @@ void tst_QProcess::failToStart() QCOMPARE(process.error(), QProcess::FailedToStart); QCOMPARE(errorSpy.count(), j * attempts + i + 1); - QCOMPARE(errorSpy2.count(), j * attempts + i + 1); QCOMPARE(finishedSpy.count(), 0); +#if QT_DEPRECATED_SINCE(5, 6) + QCOMPARE(errorSpy2.count(), j * attempts + i + 1); +#endif +#if QT_DEPRECATED_SINCE(5, 13) QCOMPARE(finishedSpy2.count(), 0); +#endif int it = j * attempts + i + 1; @@ -1536,14 +1569,18 @@ void tst_QProcess::failToStartWithWait() QProcess process; QEventLoop loop; QSignalSpy errorSpy(&process, &QProcess::errorOccurred); - QSignalSpy errorSpy2(&process, static_cast<QProcessErrorSignal>(&QProcess::error)); - QSignalSpy finishedSpy(&process, static_cast<QProcessFinishedSignal1>(&QProcess::finished)); - QSignalSpy finishedSpy2(&process, static_cast<QProcessFinishedSignal2>(&QProcess::finished)); - + QSignalSpy finishedSpy(&process, static_cast<QProcessFinishedSignal2>(&QProcess::finished)); QVERIFY(errorSpy.isValid()); - QVERIFY(errorSpy2.isValid()); QVERIFY(finishedSpy.isValid()); + +#if QT_DEPRECATED_SINCE(5, 6) + QSignalSpy errorSpy2(&process, static_cast<QProcessErrorSignal>(&QProcess::error)); + QVERIFY(errorSpy2.isValid()); +#endif +#if QT_DEPRECATED_SINCE(5, 13) + QSignalSpy finishedSpy2(&process, static_cast<QProcessFinishedSignal1>(&QProcess::finished)); QVERIFY(finishedSpy2.isValid()); +#endif for (int i = 0; i < 50; ++i) { process.start("/blurp", QStringList() << "-v" << "-debug"); @@ -1551,9 +1588,14 @@ void tst_QProcess::failToStartWithWait() QCOMPARE(process.error(), QProcess::FailedToStart); QCOMPARE(errorSpy.count(), i + 1); - QCOMPARE(errorSpy2.count(), i + 1); QCOMPARE(finishedSpy.count(), 0); +#if QT_DEPRECATED_SINCE(5, 6) + QCOMPARE(errorSpy2.count(), i + 1); +#endif +#if QT_DEPRECATED_SINCE(5, 13) QCOMPARE(finishedSpy2.count(), 0); +#endif + } } @@ -1565,14 +1607,18 @@ void tst_QProcess::failToStartWithEventLoop() QProcess process; QEventLoop loop; QSignalSpy errorSpy(&process, &QProcess::errorOccurred); - QSignalSpy errorSpy2(&process, static_cast<QProcessErrorSignal>(&QProcess::error)); - QSignalSpy finishedSpy(&process, static_cast<QProcessFinishedSignal1>(&QProcess::finished)); - QSignalSpy finishedSpy2(&process, static_cast<QProcessFinishedSignal2>(&QProcess::finished)); - + QSignalSpy finishedSpy(&process, static_cast<QProcessFinishedSignal2>(&QProcess::finished)); QVERIFY(errorSpy.isValid()); - QVERIFY(errorSpy2.isValid()); QVERIFY(finishedSpy.isValid()); + +#if QT_DEPRECATED_SINCE(5, 6) + QSignalSpy errorSpy2(&process, static_cast<QProcessErrorSignal>(&QProcess::error)); + QVERIFY(errorSpy2.isValid()); +#endif +#if QT_DEPRECATED_SINCE(5, 13) + QSignalSpy finishedSpy2(&process, static_cast<QProcessFinishedSignal1>(&QProcess::finished)); QVERIFY(finishedSpy2.isValid()); +#endif // The error signal may be emitted before start() returns connect(&process, &QProcess::errorOccurred, &loop, &QEventLoop::quit, Qt::QueuedConnection); @@ -1585,9 +1631,13 @@ void tst_QProcess::failToStartWithEventLoop() QCOMPARE(process.error(), QProcess::FailedToStart); QCOMPARE(errorSpy.count(), i + 1); - QCOMPARE(errorSpy2.count(), i + 1); QCOMPARE(finishedSpy.count(), 0); +#if QT_DEPRECATED_SINCE(5, 6) + QCOMPARE(errorSpy2.count(), i + 1); +#endif +#if QT_DEPRECATED_SINCE(5, 13) QCOMPARE(finishedSpy2.count(), 0); +#endif } } @@ -1605,8 +1655,12 @@ void tst_QProcess::failToStartEmptyArgs() qRegisterMetaType<QProcess::ProcessError>("QProcess::ProcessError"); QProcess process; - QSignalSpy errorSpy(&process, static_cast<QProcessErrorSignal>(&QProcess::error)); + QSignalSpy errorSpy(&process, static_cast<QProcessErrorSignal>(&QProcess::errorOccurred)); QVERIFY(errorSpy.isValid()); +#if QT_DEPRECATED_SINCE(5, 6) + QSignalSpy errorSpy2(&process, static_cast<QProcessErrorSignal>(&QProcess::error)); + QVERIFY(errorSpy2.isValid()); +#endif switch (startOverload) { case 0: @@ -1624,6 +1678,9 @@ void tst_QProcess::failToStartEmptyArgs() QVERIFY(!process.waitForStarted()); QCOMPARE(errorSpy.count(), 1); +#if QT_DEPRECATED_SINCE(5, 6) + QCOMPARE(errorSpy2.count(), 1); +#endif QCOMPARE(process.error(), QProcess::FailedToStart); } @@ -1855,24 +1912,32 @@ void tst_QProcess::waitForReadyReadForNonexistantProcess() QProcess process; QSignalSpy errorSpy(&process, &QProcess::errorOccurred); + QSignalSpy finishedSpy(&process, static_cast<QProcessFinishedSignal2>(&QProcess::finished)); + QVERIFY(errorSpy.isValid()); + QVERIFY(finishedSpy.isValid()); + +#if QT_DEPRECATED_SINCE(5, 6) QSignalSpy errorSpy2(&process, static_cast<QProcessErrorSignal>(&QProcess::error)); + QVERIFY(errorSpy2.isValid()); +#endif +#if QT_DEPRECATED_SINCE(5, 13) QSignalSpy finishedSpy1(&process, static_cast<QProcessFinishedSignal1>(&QProcess::finished)); - QSignalSpy finishedSpy2(&process, static_cast<QProcessFinishedSignal2>(&QProcess::finished)); - - QVERIFY(errorSpy.isValid()); - QVERIFY(errorSpy2.isValid()); QVERIFY(finishedSpy1.isValid()); - QVERIFY(finishedSpy2.isValid()); +#endif QVERIFY(!process.waitForReadyRead()); // used to crash process.start("doesntexist"); QVERIFY(!process.waitForReadyRead()); QCOMPARE(errorSpy.count(), 1); QCOMPARE(errorSpy.at(0).at(0).toInt(), 0); + QCOMPARE(finishedSpy.count(), 0); +#if QT_DEPRECATED_SINCE(5, 6) QCOMPARE(errorSpy2.count(), 1); QCOMPARE(errorSpy2.at(0).at(0).toInt(), 0); +#endif +#if QT_DEPRECATED_SINCE(5, 13) QCOMPARE(finishedSpy1.count(), 0); - QCOMPARE(finishedSpy2.count(), 0); +#endif } void tst_QProcess::setStandardInputFile() @@ -2072,7 +2137,7 @@ void tst_QProcess::fileWriterProcess() stdinStr += line; } - QTime stopWatch; + QElapsedTimer stopWatch; stopWatch.start(); const QString fileName = m_temporaryDir.path() + QLatin1String("/fileWriterProcess.txt"); const QString binary = QDir::currentPath() + QLatin1String("/fileWriterProcess/fileWriterProcess"); @@ -2303,14 +2368,18 @@ void tst_QProcess::invalidProgramString() qRegisterMetaType<QProcess::ProcessError>("QProcess::ProcessError"); QSignalSpy spy(&process, &QProcess::errorOccurred); - QSignalSpy spy2(&process, static_cast<QProcessErrorSignal>(&QProcess::error)); QVERIFY(spy.isValid()); +#if QT_DEPRECATED_SINCE(5, 6) + QSignalSpy spy2(&process, static_cast<QProcessErrorSignal>(&QProcess::error)); QVERIFY(spy2.isValid()); +#endif process.start(programString); QCOMPARE(process.error(), QProcess::FailedToStart); QCOMPARE(spy.count(), 1); +#if QT_DEPRECATED_SINCE(5, 6) QCOMPARE(spy2.count(), 1); +#endif QVERIFY(!QProcess::startDetached(programString)); } @@ -2364,7 +2433,7 @@ void tst_QProcess::finishProcessBeforeReadingDone() QProcess process; BlockOnReadStdOut blocker(&process); QEventLoop loop; - connect(&process, static_cast<QProcessFinishedSignal1>(&QProcess::finished), + connect(&process, static_cast<QProcessFinishedSignal2>(&QProcess::finished), &loop, &QEventLoop::quit); process.start("testProcessOutput/testProcessOutput"); QVERIFY(process.waitForStarted()); @@ -2510,5 +2579,106 @@ void tst_QProcess::processEventsInAReadyReadSlot() QVERIFY(process.waitForFinished()); } +#if QT_DEPRECATED_SINCE(5, 13) + +void tst_QProcess::crashTest2_deprecated() +{ + QProcess process; + process.start("testProcessCrash/testProcessCrash"); + QVERIFY(process.waitForStarted(5000)); + + qRegisterMetaType<QProcess::ProcessError>("QProcess::ProcessError"); + qRegisterMetaType<QProcess::ExitStatus>("QProcess::ExitStatus"); + + QSignalSpy spy(&process, static_cast<QProcessErrorSignal>(&QProcess::errorOccurred)); + QSignalSpy spy2(&process, static_cast<QProcessFinishedSignal2>(&QProcess::finished)); + + QVERIFY(spy.isValid()); + QVERIFY(spy2.isValid()); + + QObject::connect(&process, static_cast<QProcessFinishedSignal1>(&QProcess::finished), + this, &tst_QProcess::exitLoopSlot); + + QTestEventLoop::instance().enterLoop(30); + if (QTestEventLoop::instance().timeout()) + QFAIL("Failed to detect crash : operation timed out"); + + QCOMPARE(spy.count(), 1); + QCOMPARE(*static_cast<const QProcess::ProcessError *>(spy.at(0).at(0).constData()), QProcess::Crashed); + + QCOMPARE(spy2.count(), 1); + QCOMPARE(*static_cast<const QProcess::ExitStatus *>(spy2.at(0).at(1).constData()), QProcess::CrashExit); + + QCOMPARE(process.exitStatus(), QProcess::CrashExit); +} + +void tst_QProcess::restartProcessDeadlock_deprecated() +{ + // The purpose of this test is to detect whether restarting a + // process in the finished() connected slot causes a deadlock + // because of the way QProcessManager uses its locks. + QProcess process; + connect(&process, static_cast<QProcessFinishedSignal1>(&QProcess::finished), + this, &tst_QProcess::restartProcess); + + process.start("testProcessEcho/testProcessEcho"); + + QCOMPARE(process.write("", 1), qlonglong(1)); + QVERIFY(process.waitForFinished(5000)); + + QObject::disconnect(&process, static_cast<QProcessFinishedSignal1>(&QProcess::finished), nullptr, nullptr); + + QCOMPARE(process.write("", 1), qlonglong(1)); + QVERIFY(process.waitForFinished(5000)); + QCOMPARE(process.exitStatus(), QProcess::NormalExit); + QCOMPARE(process.exitCode(), 0); +} + +void tst_QProcess::waitForReadyReadInAReadyReadSlot_deprecated() +{ + QProcess process; + connect(&process, &QIODevice::readyRead, this, &tst_QProcess::waitForReadyReadInAReadyReadSlotSlot); + connect(&process, static_cast<QProcessFinishedSignal1>(&QProcess::finished), + this, &tst_QProcess::exitLoopSlot); + bytesAvailable = 0; + + process.start("testProcessEcho/testProcessEcho"); + QVERIFY(process.waitForStarted(5000)); + + QSignalSpy spy(&process, &QProcess::readyRead); + QVERIFY(spy.isValid()); + process.write("foo"); + QTestEventLoop::instance().enterLoop(30); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(spy.count(), 1); + + process.disconnect(); + QVERIFY(process.waitForFinished(5000)); + QCOMPARE(process.exitStatus(), QProcess::NormalExit); + QCOMPARE(process.exitCode(), 0); + QVERIFY(process.bytesAvailable() > bytesAvailable); +} + +void tst_QProcess::finishProcessBeforeReadingDone_deprecated() +{ + QProcess process; + BlockOnReadStdOut blocker(&process); + QEventLoop loop; + connect(&process, static_cast<QProcessFinishedSignal1>(&QProcess::finished), + &loop, &QEventLoop::quit); + process.start("testProcessOutput/testProcessOutput"); + QVERIFY(process.waitForStarted()); + loop.exec(); + QStringList lines = QString::fromLocal8Bit(process.readAllStandardOutput()).split( + QRegExp(QStringLiteral("[\r\n]")), QString::SkipEmptyParts); + QVERIFY(!lines.isEmpty()); + QCOMPARE(lines.last(), QStringLiteral("10239 -this is a number")); + QCOMPARE(process.exitStatus(), QProcess::NormalExit); + QCOMPARE(process.exitCode(), 0); +} + +#endif + QTEST_MAIN(tst_QProcess) #include "tst_qprocess.moc" diff --git a/tests/auto/corelib/io/qresourceengine/qresourceengine_test.pro b/tests/auto/corelib/io/qresourceengine/qresourceengine_test.pro index 3838a72c21..f523116cc9 100644 --- a/tests/auto/corelib/io/qresourceengine/qresourceengine_test.pro +++ b/tests/auto/corelib/io/qresourceengine/qresourceengine_test.pro @@ -22,7 +22,7 @@ android:!android-embedded { RESOURCES += android_testdata.qrc } -win32 { +win32:debug_and_release { CONFIG(debug, debug|release): LIBS += -Lstaticplugin/debug else: LIBS += -Lstaticplugin/release } else { diff --git a/tests/auto/corelib/io/qresourceengine/tst_qresourceengine.cpp b/tests/auto/corelib/io/qresourceengine/tst_qresourceengine.cpp index 0b50c391b8..44c8c4b681 100644 --- a/tests/auto/corelib/io/qresourceengine/tst_qresourceengine.cpp +++ b/tests/auto/corelib/io/qresourceengine/tst_qresourceengine.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2018 Intel Corporation. +** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2019 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. @@ -55,6 +55,10 @@ private slots: void checkStructure(); void searchPath_data(); void searchPath(); +#if QT_DEPRECATED_SINCE(5, 13) + void searchPath_deprecated_data(); + void searchPath_deprecated(); +#endif void doubleSlashInRoot(); void setLocale(); void lastModified(); @@ -420,6 +424,58 @@ void tst_QResourceEngine::checkStructure() void tst_QResourceEngine::searchPath_data() { + auto searchPath = QFileInfo(QFINDTESTDATA("testqrc")).canonicalFilePath(); + + QTest::addColumn<QString>("searchPathPrefix"); + QTest::addColumn<QString>("searchPath"); + QTest::addColumn<QString>("file"); + QTest::addColumn<QByteArray>("expected"); + + QTest::newRow("no_search_path") + << QString() + << QString() + << ":search_file.txt" + << QByteArray("root\n"); + QTest::newRow("path1") + << "searchpath1" + << searchPath + << "searchpath1:searchpath1/search_file.txt" + << QByteArray("path1\n"); + QTest::newRow("no_search_path2") + << QString() + << QString() + << ":/search_file.txt" + << QByteArray("root\n"); + QTest::newRow("path2") + << "searchpath2" + << searchPath + "/searchpath2" + << "searchpath2:search_file.txt" + << QByteArray("path2\n"); +} + +void tst_QResourceEngine::searchPath() +{ + QFETCH(QString, searchPathPrefix); + QFETCH(QString, searchPath); + QFETCH(QString, file); + QFETCH(QByteArray, expected); + + if (!searchPath.isEmpty()) + QDir::addSearchPath(searchPathPrefix, searchPath); + QFile qf(file); + QVERIFY(qf.open(QFile::ReadOnly)); + QByteArray actual = qf.readAll(); + + actual.replace('\r', ""); + + QCOMPARE(actual, expected); + qf.close(); +} + +#if QT_DEPRECATED_SINCE(5, 13) + +void tst_QResourceEngine::searchPath_deprecated_data() +{ QTest::addColumn<QString>("searchPath"); QTest::addColumn<QString>("file"); QTest::addColumn<QByteArray>("expected"); @@ -438,7 +494,7 @@ void tst_QResourceEngine::searchPath_data() << QByteArray("path2\n"); } -void tst_QResourceEngine::searchPath() +void tst_QResourceEngine::searchPath_deprecated() { QFETCH(QString, searchPath); QFETCH(QString, file); @@ -456,6 +512,8 @@ void tst_QResourceEngine::searchPath() qf.close(); } +#endif + void tst_QResourceEngine::checkUnregisterResource_data() { QTest::addColumn<QString>("rcc_file"); @@ -505,15 +563,15 @@ void tst_QResourceEngine::setLocale() // default constructed QResource gets the default locale QResource resource; resource.setFileName("aliasdir/aliasdir.txt"); - QVERIFY(!resource.isCompressed()); + QCOMPARE(resource.compressionAlgorithm(), QResource::NoCompression); // change the default locale and make sure it doesn't affect the resource QLocale::setDefault(QLocale("de_CH")); - QVERIFY(!resource.isCompressed()); + QCOMPARE(resource.compressionAlgorithm(), QResource::NoCompression); // then explicitly set the locale on qresource resource.setLocale(QLocale("de_CH")); - QVERIFY(resource.isCompressed()); + QVERIFY(resource.compressionAlgorithm() != QResource::NoCompression); // the reset the default locale back QLocale::setDefault(QLocale::system()); diff --git a/tests/auto/corelib/io/qsettings/qsettings.pro b/tests/auto/corelib/io/qsettings/qsettings.pro index 79552b62df..98ea337e7f 100644 --- a/tests/auto/corelib/io/qsettings/qsettings.pro +++ b/tests/auto/corelib/io/qsettings/qsettings.pro @@ -5,7 +5,7 @@ SOURCES = tst_qsettings.cpp RESOURCES += qsettings.qrc INCLUDEPATH += $$PWD/../../kernel/qmetatype -msvc: LIBS += advapi32.lib +msvc: QMAKE_USE += advapi32 darwin: LIBS += -framework CoreFoundation DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/corelib/io/qsettings/tst_qsettings.cpp b/tests/auto/corelib/io/qsettings/tst_qsettings.cpp index 8b69518ef7..0f07ba4bb2 100644 --- a/tests/auto/corelib/io/qsettings/tst_qsettings.cpp +++ b/tests/auto/corelib/io/qsettings/tst_qsettings.cpp @@ -54,6 +54,9 @@ #if defined(Q_OS_WIN) #include <QtCore/qt_windows.h> +#ifndef Q_OS_WINRT +# include <private/qwinregistry_p.h> +#endif #else #include <unistd.h> #endif @@ -311,8 +314,11 @@ void tst_QSettings::initTestCase() void tst_QSettings::cleanupTestFiles() { - QSettings::setSystemIniPath(settingsPath("__system__")); - QSettings::setUserIniPath(settingsPath("__user__")); + QSettings::setPath(QSettings::IniFormat, QSettings::SystemScope, settingsPath("__system__")); + QSettings::setPath(QSettings::NativeFormat, QSettings::SystemScope, settingsPath("__system__")); + + QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, settingsPath("__user__")); + QSettings::setPath(QSettings::NativeFormat, QSettings::UserScope, settingsPath("__user__")); QDir settingsDir(settingsPath()); if (settingsDir.exists()) @@ -1363,7 +1369,9 @@ void tst_QSettings::testVariantTypes() if (format >= QSettings::InvalidFormat) { testVal("keysequence", QKeySequence(Qt::ControlModifier + Qt::Key_F1), QKeySequence, KeySequence); } else { - testVal("keysequence", QKeySequence(Qt::ControlModifier + Qt::Key_F1), QString, String); + testVal("keysequence", + QKeySequence(Qt::ControlModifier + Qt::Key_F1).toString(QKeySequence::NativeText), + QString, String); } #undef testVal @@ -3618,16 +3626,13 @@ void tst_QSettings::recursionBug() #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) -static DWORD readKeyType(HKEY handle, const QString &rSubKey) +static DWORD readKeyType(HKEY handle, QStringView rSubKey) { DWORD dataType; DWORD dataSize; - LONG res = RegQueryValueEx(handle, reinterpret_cast<const wchar_t *>(rSubKey.utf16()), 0, &dataType, 0, &dataSize); - - if (res == ERROR_SUCCESS) - return dataType; - - return 0; + LONG res = RegQueryValueEx(handle, reinterpret_cast<const wchar_t *>(rSubKey.utf16()), + nullptr, &dataType, nullptr, &dataSize); + return res == ERROR_SUCCESS ? dataType : 0; } // This is a regression test for QTBUG-13249, where QSettings was storing @@ -3647,29 +3652,12 @@ void tst_QSettings::consistentRegistryStorage() QCOMPARE(settings1.value("quint64_value").toULongLong(), (quint64)1024); settings1.sync(); - HKEY handle; - LONG res; - QString keyName = "Software\\software.org\\KillerAPP"; - res = RegOpenKeyEx(HKEY_CURRENT_USER, reinterpret_cast<const wchar_t *>(keyName.utf16()), 0, KEY_READ, &handle); - if (res == ERROR_SUCCESS) - { - DWORD dataType; - dataType = readKeyType(handle, QString("qint32_value")); - if (dataType != 0) { - QCOMPARE((int)REG_DWORD, (int)dataType); - } - dataType = readKeyType(handle, QString("quint32_value")); - if (dataType != 0) { - QCOMPARE((int)REG_DWORD, (int)dataType); - } - dataType = readKeyType(handle, QString("qint64_value")); - if (dataType != 0) { - QCOMPARE((int)REG_QWORD, (int)dataType); - } - dataType = readKeyType(handle, QString("quint64_value")); - if (dataType != 0) { - QCOMPARE((int)REG_QWORD, (int)dataType); - } + QWinRegistryKey handle(HKEY_CURRENT_USER, LR"(Software\software.org\KillerAPP)"); + if (handle.isValid()) { + QCOMPARE(readKeyType(handle, L"qint32_value"), DWORD(REG_DWORD)); + QCOMPARE(readKeyType(handle, L"quint32_value"), DWORD(REG_DWORD)); + QCOMPARE(readKeyType(handle, L"qint64_value"), DWORD(REG_QWORD)); + QCOMPARE(readKeyType(handle, L"quint64_value"), DWORD(REG_QWORD)); RegCloseKey(handle); } } diff --git a/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp b/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp index 40023d7fea..dae4e66106 100644 --- a/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp +++ b/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp @@ -32,8 +32,8 @@ #include <qstandardpaths.h> #include <qfileinfo.h> #include <qsysinfo.h> -#include <qregexp.h> -#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) && !defined(Q_OS_WINCE) +#include <qregularexpression.h> +#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) # include <qt_windows.h> #endif @@ -131,7 +131,7 @@ static const char * const enumNames[MaxStandardLocation + 1 - int(QStandardPaths void tst_qstandardpaths::initTestCase() { -#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) && !defined(Q_OS_WINCE) +#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) // Disable WOW64 redirection, see testFindExecutable() if (QSysInfo::buildCpuArchitecture() != QSysInfo::currentCpuArchitecture()) { void *oldMode; @@ -140,7 +140,7 @@ void tst_qstandardpaths::initTestCase() qErrnoWarning("Wow64DisableWow64FsRedirection() failed"); QVERIFY(disabledDisableWow64FsRedirection); } -#endif // Q_OS_WIN && !Q_OS_WINRT && !Q_OS_WINCE +#endif // Q_OS_WIN && !Q_OS_WINRT QVERIFY2(m_localConfigTempDir.isValid(), qPrintable(m_localConfigTempDir.errorString())); QVERIFY2(m_globalConfigTempDir.isValid(), qPrintable(m_globalConfigTempDir.errorString())); QVERIFY2(m_localAppTempDir.isValid(), qPrintable(m_localAppTempDir.errorString())); @@ -572,7 +572,8 @@ void tst_qstandardpaths::testAllWritableLocations() void tst_qstandardpaths::testCleanPath() { - const QRegExp filter(QStringLiteral("\\\\")); +#if QT_CONFIG(regularexpression) + const QRegularExpression filter(QStringLiteral("\\\\")); QVERIFY(filter.isValid()); for (int i = 0; i <= QStandardPaths::GenericCacheLocation; ++i) { const QStringList paths = QStandardPaths::standardLocations(QStandardPaths::StandardLocation(i)); @@ -580,6 +581,9 @@ void tst_qstandardpaths::testCleanPath() qPrintable(QString::fromLatin1("Backslash found in %1 %2") .arg(i).arg(paths.join(QLatin1Char(','))))); } +#else + QSKIP("regularexpression feature disabled"); +#endif } void tst_qstandardpaths::testXdgPathCleanup() diff --git a/tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp b/tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp index b8f67c7d37..00417fffa0 100644 --- a/tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp +++ b/tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp @@ -215,7 +215,7 @@ void tst_QTemporaryFile::fileTemplate() if (!fileTemplate.isEmpty()) file.setFileTemplate(fileTemplate); - QCOMPARE(file.open(), true); + QVERIFY2(file.open(), qPrintable(file.errorString())); QString fileName = QFileInfo(file).fileName(); if (prefix.length()) diff --git a/tests/auto/corelib/io/qurl/tst_qurl.cpp b/tests/auto/corelib/io/qurl/tst_qurl.cpp index 9c106c7f58..ef4325d2ea 100644 --- a/tests/auto/corelib/io/qurl/tst_qurl.cpp +++ b/tests/auto/corelib/io/qurl/tst_qurl.cpp @@ -136,8 +136,8 @@ private slots: void emptyQueryOrFragment(); void hasFragment_data(); void hasFragment(); - void setEncodedFragment_data(); - void setEncodedFragment(); + void setFragment_data(); + void setFragment(); void fromEncoded(); void stripTrailingSlash_data(); void stripTrailingSlash(); @@ -350,15 +350,15 @@ void tst_QUrl::comparison() // 6.2.2.1 Make sure hexdecimal characters in percent encoding are // treated case-insensitively QUrl url5; - url5.setEncodedQuery("a=%2a"); + url5.setQuery(QLatin1String("a=%2a")); QUrl url6; - url6.setEncodedQuery("a=%2A"); + url6.setQuery(QLatin1String("a=%2A")); QCOMPARE(url5, url6); QUrl url7; - url7.setEncodedQuery("a=C"); + url7.setQuery(QLatin1String("a=C")); QUrl url8; - url8.setEncodedQuery("a=c"); + url8.setQuery(QLatin1String("a=c")); QVERIFY(url7 != url8); QVERIFY(url7 < url8); @@ -502,7 +502,7 @@ void tst_QUrl::setUrl() QVERIFY(url.isValid()); QCOMPARE(url.scheme(), QString::fromLatin1("file")); QCOMPARE(url.path(), QString::fromLatin1("/")); - QVERIFY(url.encodedQuery().isEmpty()); + QVERIFY(url.query().isEmpty()); QVERIFY(url.userInfo().isEmpty()); QVERIFY(url.authority().isEmpty()); QVERIFY(url.fragment().isEmpty()); @@ -517,7 +517,7 @@ void tst_QUrl::setUrl() QVERIFY(url.isValid()); QCOMPARE(url.scheme(), QString::fromLatin1("http")); QCOMPARE(url.path(), QString()); - QVERIFY(url.encodedQuery().isEmpty()); + QVERIFY(url.query().isEmpty()); QVERIFY(url.userInfo().isEmpty()); QVERIFY(url.fragment().isEmpty()); QCOMPARE(url.host(), QString::fromLatin1("www.foo.bar")); @@ -536,7 +536,7 @@ void tst_QUrl::setUrl() QVERIFY(url.isValid()); QCOMPARE(url.scheme(), QString::fromLatin1("http")); QCOMPARE(url.path(), QString()); - QVERIFY(url.encodedQuery().isEmpty()); + QVERIFY(url.query().isEmpty()); QCOMPARE(url.userName(), QString::fromLatin1("user:")); QCOMPARE(url.password(), QString::fromLatin1("pass@")); QCOMPARE(url.userInfo(), QString::fromLatin1("user%3A:pass@")); @@ -781,7 +781,7 @@ void tst_QUrl::setUrl() QVERIFY(url.isValid()); QCOMPARE(url.scheme(), QString("http")); QCOMPARE(url.host(), QString("1.2.3.4")); - QCOMPARE(url.encodedQuery(), QByteArray("foo")); + QCOMPARE(url.query(QUrl::FullyEncoded), QLatin1String("foo")); } { QUrl url; @@ -798,13 +798,13 @@ void tst_QUrl::setUrl() QCOMPARE(url.scheme(), QString("data")); QCOMPARE(url.host(), QString()); QCOMPARE(url.path(), QString("text/javascript,d5 = 'five\\u0027s';")); - QCOMPARE(url.encodedPath().constData(), "text/javascript,d5%20%3D%20'five%5Cu0027s'%3B"); + QCOMPARE(url.path(QUrl::FullyEncoded), QLatin1String("text/javascript,d5%20%3D%20'five%5Cu0027s'%3B")); } { // invalid port number QUrl url; - url.setEncodedUrl("foo://tel:2147483648"); + url.setUrl(QLatin1String("foo://tel:2147483648"), QUrl::StrictMode); QVERIFY(!url.isValid()); } @@ -1144,7 +1144,7 @@ void tst_QUrl::toString_constructed_data() QTest::addColumn<QString>("host"); QTest::addColumn<int>("port"); QTest::addColumn<QString>("path"); - QTest::addColumn<QByteArray>("query"); + QTest::addColumn<QString>("query"); QTest::addColumn<QString>("fragment"); QTest::addColumn<QString>("asString"); QTest::addColumn<QByteArray>("asEncoded"); @@ -1153,19 +1153,19 @@ void tst_QUrl::toString_constructed_data() QString n(""); QTest::newRow("data1") << n << n << n << QString::fromLatin1("qt-project.org") << -1 << QString::fromLatin1("/index.html") - << QByteArray() << n << QString::fromLatin1("//qt-project.org/index.html") + << QString() << n << QString::fromLatin1("//qt-project.org/index.html") << QByteArray("//qt-project.org/index.html") << 0u; - QTest::newRow("data2") << QString::fromLatin1("file") << n << n << n << -1 << QString::fromLatin1("/root") << QByteArray() + QTest::newRow("data2") << QString::fromLatin1("file") << n << n << n << -1 << QString::fromLatin1("/root") << QString() << n << QString::fromLatin1("file:///root") << QByteArray("file:///root") << 0u; QTest::newRow("userAndPass") << QString::fromLatin1("http") << QString::fromLatin1("dfaure") << QString::fromLatin1("kde") - << "kde.org" << 443 << QString::fromLatin1("/") << QByteArray() << n + << "kde.org" << 443 << QString::fromLatin1("/") << QString() << n << QString::fromLatin1("http://dfaure:kde@kde.org:443/") << QByteArray("http://dfaure:kde@kde.org:443/") << 0u; QTest::newRow("PassWithoutUser") << QString::fromLatin1("http") << n << QString::fromLatin1("kde") - << "kde.org" << 443 << QString::fromLatin1("/") << QByteArray() << n + << "kde.org" << 443 << QString::fromLatin1("/") << QString() << n << QString::fromLatin1("http://:kde@kde.org:443/") << QByteArray("http://:kde@kde.org:443/") << 0u; QTest::newRow("PassWithoutUser-RemovePassword") << QString::fromLatin1("http") << n << QString::fromLatin1("kde") - << "kde.org" << 443 << QString::fromLatin1("/") << QByteArray() << n + << "kde.org" << 443 << QString::fromLatin1("/") << QString() << n << QString::fromLatin1("http://kde.org:443/") << QByteArray("http://kde.org:443/") << uint(QUrl::RemovePassword); } @@ -1178,7 +1178,7 @@ void tst_QUrl::toString_constructed() QFETCH(QString, host); QFETCH(int, port); QFETCH(QString, path); - QFETCH(QByteArray, query); + QFETCH(QString, query); QFETCH(QString, fragment); QFETCH(QString, asString); QFETCH(QByteArray, asEncoded); @@ -1198,7 +1198,7 @@ void tst_QUrl::toString_constructed() if (!path.isEmpty()) url.setPath(path); if (!query.isEmpty()) - url.setEncodedQuery(query); + url.setQuery(query, QUrl::StrictMode); if (!fragment.isEmpty()) url.setFragment(fragment); @@ -1757,7 +1757,7 @@ void tst_QUrl::symmetry() QCOMPARE(url.host(QUrl::EncodeUnicode | QUrl::EncodeSpaces), QString::fromUtf8("www.xn--rksmrgs-5wao1o.se")); QCOMPARE(url.path(), QString::fromLatin1("/pub")); // this will be encoded ... - QCOMPARE(url.encodedQuery().constData(), QString::fromLatin1("a=b&a=d%C3%B8&a=f").toLatin1().constData()); + QCOMPARE(url.query(QUrl::FullyEncoded), QLatin1String("a=b&a=d%C3%B8&a=f")); QCOMPARE(url.fragment(), QString::fromUtf8("vræl")); QUrl onlyHost("//qt-project.org"); @@ -2009,7 +2009,7 @@ void tst_QUrl::hasQuery() QUrl qurl(url); QCOMPARE(qurl.hasQuery(), trueFalse); - QCOMPARE(qurl.encodedQuery().isNull(), !trueFalse); + QCOMPARE(qurl.query().isNull(), !trueFalse); } void tst_QUrl::nameprep() @@ -2192,10 +2192,12 @@ void tst_QUrl::schemeValidator_data() QTest::newRow("percent-encoded") << "%68%74%%74%70://example.com" << false << "%68%74%%74%70"; static const char controls[] = "!\"$&'()*,;<=>[\\]^_`{|}~"; - for (size_t i = 0; i < sizeof(controls) - 1; ++i) - QTest::newRow(("with-" + QByteArray(1, controls[i])).constData()) - << QString("pre%1post://example.com/").arg(QLatin1Char(controls[i])) - << false << QString("pre%1post").arg(QLatin1Char(controls[i])); + for (char control : controls) { + const QString scheme = QLatin1String("pre") + QLatin1Char(control) + QLatin1String("post"); + QTest::newRow((QByteArrayLiteral("with-") + control).constData()) + << (scheme + QLatin1String("://example.com/")) + << false << scheme; + } } void tst_QUrl::schemeValidator() @@ -2342,7 +2344,7 @@ void tst_QUrl::tolerantParser() QVERIFY(url.isValid()); QVERIFY(!url.toString().isEmpty()); QCOMPARE(url.path(), QString("/path with spaces.html")); - url.setEncodedUrl("http://www.example.com/path%20with spaces.html", QUrl::StrictMode); + url.setUrl(QLatin1String("http://www.example.com/path%20with spaces.html"), QUrl::StrictMode); QVERIFY(!url.isValid()); QVERIFY(url.toString().isEmpty()); } @@ -2392,36 +2394,36 @@ void tst_QUrl::tolerantParser() QCOMPARE(url.toEncoded(), QByteArray("%25hello.com/f%25")); QCOMPARE(url.toString(), QString("%25hello.com/f%25")); - url.setEncodedUrl("http://www.host.com/foo.php?P0=[2006-3-8]"); + url.setUrl(QLatin1String("http://www.host.com/foo.php?P0=[2006-3-8]"), QUrl::StrictMode); QVERIFY(url.isValid()); QVERIFY(!url.toString().isEmpty()); - url.setEncodedUrl("http://foo.bar/[image][1].jpg"); + url.setUrl(QLatin1String("http://foo.bar/[image][1].jpg"), QUrl::StrictMode); QVERIFY(url.isValid()); QCOMPARE(url.toString(QUrl::FullyEncoded), QString("http://foo.bar/[image][1].jpg")); QCOMPARE(url.toEncoded(), QByteArray("http://foo.bar/[image][1].jpg")); QCOMPARE(url.toString(), QString("http://foo.bar/[image][1].jpg")); - url.setEncodedUrl("http://foo.bar/%5Bimage%5D%5B1%5D.jpg"); + url.setUrl(QLatin1String("http://foo.bar/%5Bimage%5D%5B1%5D.jpg"), QUrl::StrictMode); QVERIFY(url.isValid()); QCOMPARE(url.toString(QUrl::FullyEncoded), QString("http://foo.bar/%5Bimage%5D%5B1%5D.jpg")); QCOMPARE(url.toEncoded(), QByteArray("http://foo.bar/%5Bimage%5D%5B1%5D.jpg")); QCOMPARE(url.toString(), QString("http://foo.bar/%5Bimage%5D%5B1%5D.jpg")); - url.setEncodedUrl("//[::56:56:56:56:56:56:56]"); + url.setUrl(QLatin1String("//[::56:56:56:56:56:56:56]"), QUrl::StrictMode); QCOMPARE(url.toString(QUrl::FullyEncoded), QString("//[0:56:56:56:56:56:56:56]")); QCOMPARE(url.toEncoded(), QByteArray("//[0:56:56:56:56:56:56:56]")); - url.setEncodedUrl("data:text/css,div%20{%20border-right:%20solid;%20}"); + url.setUrl(QLatin1String("data:text/css,div%20{%20border-right:%20solid;%20}"), QUrl::TolerantMode); QCOMPARE(url.toString(QUrl::FullyEncoded), QString("data:text/css,div%20%7B%20border-right:%20solid;%20%7D")); QCOMPARE(url.toEncoded(), QByteArray("data:text/css,div%20%7B%20border-right:%20solid;%20%7D")); QCOMPARE(url.toString(), QString("data:text/css,div %7B border-right: solid; %7D")); } { - QByteArray tsdgeos("http://google.com/c?c=Translation+%C2%BB+trunk|"); + const QString tsdgeos = QLatin1String("http://google.com/c?c=Translation+%C2%BB+trunk|"); QUrl tsdgeosQUrl; - tsdgeosQUrl.setEncodedUrl(tsdgeos, QUrl::TolerantMode); + tsdgeosQUrl.setUrl(tsdgeos, QUrl::TolerantMode); QVERIFY(tsdgeosQUrl.isValid()); // failed in Qt-4.4, works in Qt-4.5 QByteArray tsdgeosExpected("http://google.com/c?c=Translation+%C2%BB+trunk%7C"); QCOMPARE(QString(tsdgeosQUrl.toEncoded()), QString(tsdgeosExpected)); @@ -2626,31 +2628,31 @@ void tst_QUrl::emptyQueryOrFragment() // start with an empty one QUrl url("http://www.foo.bar/baz"); QVERIFY(!url.hasQuery()); - QVERIFY(url.encodedQuery().isNull()); + QVERIFY(url.query().isNull()); // add encodedQuery url.setQuery("abc=def"); QVERIFY(url.hasQuery()); QCOMPARE(url.query(), QString(QLatin1String("abc=def"))); QCOMPARE(url.toString(), QString(QLatin1String("http://www.foo.bar/baz?abc=def"))); - url.setEncodedQuery("abc=def"); + url.setQuery(QLatin1String("abc=def")); QCOMPARE(url.toString(), QString(QLatin1String("http://www.foo.bar/baz?abc=def"))); // remove encodedQuery url.setQuery(QString()); QVERIFY(!url.hasQuery()); - QVERIFY(url.encodedQuery().isNull()); + QVERIFY(url.query().isNull()); QCOMPARE(url.toString(), QString(QLatin1String("http://www.foo.bar/baz"))); - url.setEncodedQuery(QByteArray()); + url.setQuery(QString()); QCOMPARE(url.toString(), QString(QLatin1String("http://www.foo.bar/baz"))); // add empty encodedQuery url.setQuery(""); QVERIFY(url.hasQuery()); - QVERIFY(url.encodedQuery().isEmpty()); - QVERIFY(!url.encodedQuery().isNull()); + QVERIFY(url.query().isEmpty()); + QVERIFY(!url.query().isNull()); QCOMPARE(url.toString(), QString(QLatin1String("http://www.foo.bar/baz?"))); - url.setEncodedQuery(""); + url.setQuery(QLatin1String("")); QCOMPARE(url.toString(), QString(QLatin1String("http://www.foo.bar/baz?"))); } } @@ -2682,35 +2684,33 @@ void tst_QUrl::hasFragment() QCOMPARE(qurl.fragment().isNull(), !trueFalse); } -void tst_QUrl::setEncodedFragment_data() +void tst_QUrl::setFragment_data() { - QTest::addColumn<QByteArray>("base"); - QTest::addColumn<QByteArray>("fragment"); - QTest::addColumn<QByteArray>("expected"); + QTest::addColumn<QString>("base"); + QTest::addColumn<QString>("fragment"); + QTest::addColumn<QString>("expected"); - typedef QByteArray BA; - QTest::newRow("null") << BA("http://www.kde.org") << BA() << BA("http://www.kde.org"); - QTest::newRow("empty") << BA("http://www.kde.org") << BA("") << BA("http://www.kde.org#"); - QTest::newRow("basic test") << BA("http://www.kde.org") << BA("abc") << BA("http://www.kde.org#abc"); - QTest::newRow("initial url has fragment") << BA("http://www.kde.org#old") << BA("new") << BA("http://www.kde.org#new"); - QTest::newRow("encoded fragment") << BA("http://www.kde.org") << BA("a%20c") << BA("http://www.kde.org#a%20c"); - QTest::newRow("with #") << BA("http://www.kde.org") << BA("a#b") << BA("http://www.kde.org#a%23b"); // toString uses "a#b" - QTest::newRow("unicode") << BA("http://www.kde.org") << BA("\xc3\xa9") << BA("http://www.kde.org#%C3%A9"); - QTest::newRow("binary") << BA("http://www.kde.org") << BA("\x00\xc0\x80", 3) << BA("http://www.kde.org#%00%C0%80"); + QTest::newRow("null") << QString::fromLatin1("http://www.kde.org") << QString() << QString::fromLatin1("http://www.kde.org"); + QTest::newRow("empty") << QString::fromLatin1("http://www.kde.org") << QString::fromLatin1("") << QString::fromLatin1("http://www.kde.org#"); + QTest::newRow("basic test") << QString::fromLatin1("http://www.kde.org") << QString::fromLatin1("abc") << QString::fromLatin1("http://www.kde.org#abc"); + QTest::newRow("initial url has fragment") << QString::fromLatin1("http://www.kde.org#old") << QString::fromLatin1("new") << QString::fromLatin1("http://www.kde.org#new"); + QTest::newRow("encoded fragment") << QString::fromLatin1("http://www.kde.org") << QString::fromLatin1("a%20c") << QString::fromLatin1("http://www.kde.org#a%20c"); + QTest::newRow("with #") << QString::fromLatin1("http://www.kde.org") << QString::fromLatin1("a#b") << QString::fromLatin1("http://www.kde.org#a%23b"); // toString uses "a#b" + QTest::newRow("unicode") << QString::fromLatin1("http://www.kde.org") << QString::fromUtf8("\xc3\xa9") << QString::fromLatin1("http://www.kde.org#%C3%A9"); } -void tst_QUrl::setEncodedFragment() +void tst_QUrl::setFragment() { - QFETCH(QByteArray, base); - QFETCH(QByteArray, fragment); - QFETCH(QByteArray, expected); + QFETCH(QString, base); + QFETCH(QString, fragment); + QFETCH(QString, expected); QUrl u; - u.setEncodedUrl(base, QUrl::TolerantMode); + u.setUrl(base, QUrl::TolerantMode); QVERIFY(u.isValid()); - u.setEncodedFragment(fragment); + u.setFragment(fragment); QVERIFY(u.isValid()); QCOMPARE(!fragment.isNull(), u.hasFragment()); - QCOMPARE(QString::fromLatin1(u.toEncoded()), QString::fromLatin1(expected)); + QCOMPARE(QString::fromUtf8(u.toEncoded()), expected); } void tst_QUrl::fromEncoded() @@ -3258,14 +3258,14 @@ void tst_QUrl::isEmptyForEncodedUrl() { { QUrl url; - url.setEncodedUrl("LABEL=USB_STICK", QUrl::TolerantMode); + url.setUrl(QLatin1String("LABEL=USB_STICK"), QUrl::TolerantMode); QVERIFY( url.isValid() ); QCOMPARE( url.path(), QString("LABEL=USB_STICK") ); QVERIFY( !url.isEmpty() ); } { QUrl url; - url.setEncodedUrl("LABEL=USB_STICK", QUrl::TolerantMode); + url.setUrl(QLatin1String("LABEL=USB_STICK"), QUrl::TolerantMode); QVERIFY( url.isValid() ); QVERIFY( !url.isEmpty() ); QCOMPARE( url.path(), QString("LABEL=USB_STICK") ); @@ -3277,7 +3277,7 @@ void tst_QUrl::isEmptyForEncodedUrl() void tst_QUrl::toEncodedNotUsingUninitializedPath() { QUrl url; - url.setEncodedPath("/test.txt"); + url.setPath(QLatin1String("/test.txt")); url.setHost("example.com"); QCOMPARE(url.toEncoded().constData(), "//example.com/test.txt"); @@ -3389,8 +3389,15 @@ void tst_QUrl::acceptEmptyAuthoritySegments() void tst_QUrl::effectiveTLDs_data() { + // See also: tst_QNetworkCookieJar::setCookiesFromUrl(). + // in tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp QTest::addColumn<QUrl>("domain"); QTest::addColumn<QString>("TLD"); + // TODO: autogenerate test-cases from: + // https://raw.githubusercontent.com/publicsuffix/list/master/tests/test_psl.txt + // checkPublicSuffix(domain, tail) appears in the list if + // either tail is null and domain is public or + // tail is the "registrable" part of domain; i.e. its minimal non-public tail. QTest::newRow("yes0") << QUrl::fromEncoded("http://test.co.uk") << ".co.uk"; QTest::newRow("yes1") << QUrl::fromEncoded("http://test.com") << ".com"; @@ -3657,17 +3664,6 @@ void tst_QUrl::componentEncodings() QCOMPARE(url.toString(formatting), (((QString(toString ))))); // the weird () and space is to align the output - if (formatting == QUrl::FullyEncoded) { - QCOMPARE(url.encodedUserName(), userName.toUtf8()); - QCOMPARE(url.encodedPassword(), password.toUtf8()); - // no encodedUserInfo - QCOMPARE(url.encodedHost(), host.toUtf8()); - // no encodedAuthority - QCOMPARE(url.encodedPath(), path.toUtf8()); - QCOMPARE(url.encodedQuery(), query.toUtf8()); - QCOMPARE(url.encodedFragment(), fragment.toUtf8()); - } - // repeat with the URL we got from toString QUrl url2(toString); QCOMPARE(url2.userName(formatting), userName); @@ -4087,13 +4083,12 @@ public: QVector<QUrl> m_urls; }; -static const UrlStorage * s_urlStorage = 0; +static const UrlStorage * s_urlStorage = nullptr; void tst_QUrl::testThreadingHelper() { const UrlStorage* storage = s_urlStorage; - for (int i = 0 ; i < storage->m_urls.size(); ++i ) { - const QUrl& u = storage->m_urls.at(i); + for (const auto &u : storage->m_urls) { // QVERIFY/QCOMPARE trigger race conditions in helgrind if (!u.isValid()) qFatal("invalid url"); diff --git a/tests/auto/corelib/itemmodels/qabstractitemmodel/tst_qabstractitemmodel.cpp b/tests/auto/corelib/itemmodels/qabstractitemmodel/tst_qabstractitemmodel.cpp index b960ca9220..f305edb2c5 100644 --- a/tests/auto/corelib/itemmodels/qabstractitemmodel/tst_qabstractitemmodel.cpp +++ b/tests/auto/corelib/itemmodels/qabstractitemmodel/tst_qabstractitemmodel.cpp @@ -309,7 +309,8 @@ bool QtTestModel::moveColumns(const QModelIndex &sourceParent, int src, int cnt, void QtTestModel::reset() { - QAbstractItemModel::reset(); + QAbstractItemModel::beginResetModel(); + QAbstractItemModel::endResetModel(); } bool QtTestModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, @@ -1785,13 +1786,12 @@ class ModelWithCustomRole : public QStringListModel { Q_OBJECT public: - ModelWithCustomRole(QObject *parent = 0) - : QStringListModel(parent) - { - QHash<int, QByteArray> roleNames_ = roleNames(); - roleNames_.insert(Qt::UserRole + 1, "custom"); - setRoleNames(roleNames_); - } + using QStringListModel::QStringListModel; + + QHash<int, QByteArray> roleNames() const override + { + return {{Qt::UserRole + 1, QByteArrayLiteral("custom")}}; + } }; ListenerObject::ListenerObject(QAbstractProxyModel *parent) @@ -1830,7 +1830,7 @@ void ListenerObject::slotAboutToBeReset() void ListenerObject::slotReset() { - foreach (const QModelIndex &idx, m_persistentIndexes) { + for (const auto &idx : qAsConst(m_persistentIndexes)) { QVERIFY(!idx.isValid()); } } diff --git a/tests/auto/corelib/itemmodels/qabstractproxymodel/tst_qabstractproxymodel.cpp b/tests/auto/corelib/itemmodels/qabstractproxymodel/tst_qabstractproxymodel.cpp index 886941bff6..adb93b7a75 100644 --- a/tests/auto/corelib/itemmodels/qabstractproxymodel/tst_qabstractproxymodel.cpp +++ b/tests/auto/corelib/itemmodels/qabstractproxymodel/tst_qabstractproxymodel.cpp @@ -313,11 +313,12 @@ public: CustomRole2 }; - StandardItemModelWithCustomRoleNames() { - QHash<int, QByteArray> _roleNames = roleNames(); - _roleNames.insert(CustomRole1, "custom1"); - _roleNames.insert(CustomRole2, "custom2"); - setRoleNames(_roleNames); + QHash<int, QByteArray> roleNames() const override + { + auto result = QStandardItemModel::roleNames(); + result.insert(CustomRole1, QByteArrayLiteral("custom1")); + result.insert(CustomRole2, QByteArrayLiteral("custom2")); + return result; } }; @@ -329,11 +330,10 @@ public: AnotherCustomRole2 }; - AnotherStandardItemModelWithCustomRoleNames() { - QHash<int, QByteArray> _roleNames = roleNames(); - _roleNames.insert(AnotherCustomRole1, "another_custom1"); - _roleNames.insert(AnotherCustomRole2, "another_custom2"); - setRoleNames(_roleNames); + QHash<int, QByteArray> roleNames() const override + { + return {{AnotherCustomRole1, QByteArrayLiteral("another_custom1")}, + {AnotherCustomRole2, QByteArrayLiteral("another_custom2")}}; } }; diff --git a/tests/auto/corelib/itemmodels/qitemmodel/modelstotest.cpp b/tests/auto/corelib/itemmodels/qitemmodel/modelstotest.cpp index dbc7173028..354190e754 100644 --- a/tests/auto/corelib/itemmodels/qitemmodel/modelstotest.cpp +++ b/tests/auto/corelib/itemmodels/qitemmodel/modelstotest.cpp @@ -153,7 +153,7 @@ QAbstractItemModel *ModelsToTest::createModel(const QString &modelType) QStandardItemModel *standardItemModel = new QStandardItemModel; model->setSourceModel(standardItemModel); populateTestArea(model); - model->setFilterRegExp(QRegExp("(^$|I.*)")); + model->setFilterRegularExpression(QRegularExpression("(^$|I.*)")); return model; } diff --git a/tests/auto/corelib/itemmodels/qitemselectionmodel/tst_qitemselectionmodel.cpp b/tests/auto/corelib/itemmodels/qitemselectionmodel/tst_qitemselectionmodel.cpp index 6fbaa28d69..c74101928a 100644 --- a/tests/auto/corelib/itemmodels/qitemselectionmodel/tst_qitemselectionmodel.cpp +++ b/tests/auto/corelib/itemmodels/qitemselectionmodel/tst_qitemselectionmodel.cpp @@ -32,6 +32,9 @@ #include <algorithm> +Q_DECLARE_METATYPE(QItemSelectionModel::SelectionFlag) +Q_DECLARE_METATYPE(Qt::SortOrder) + class tst_QItemSelectionModel : public QObject { Q_OBJECT @@ -1463,7 +1466,7 @@ void tst_QItemSelectionModel::persistentselections() QFETCH(IntList, insertColumns); QFETCH(IntList, deleteRows); QFETCH(IntList, deleteColumns); - QFETCH(PairList, expectedList); + QFETCH(const PairList, expectedList); // make sure the model is sane (5x5) QCOMPARE(model->rowCount(QModelIndex()), 5); @@ -1504,7 +1507,7 @@ void tst_QItemSelectionModel::persistentselections() // check that the selected items are the correct number and indexes QModelIndexList selectedList = selection->selectedIndexes(); QCOMPARE(selectedList.count(), expectedList.count()); - foreach(IntPair pair, expectedList) { + for (const auto &pair : expectedList) { QModelIndex index = model->index(pair.first, pair.second, QModelIndex()); QVERIFY(selectedList.contains(index)); } @@ -1679,7 +1682,7 @@ void tst_QItemSelectionModel::modelLayoutChanged_data() { QTest::addColumn<IntListList>("items"); QTest::addColumn<IntPairPairList>("initialSelectedRanges"); - QTest::addColumn<int>("sortOrder"); + QTest::addColumn<Qt::SortOrder>("sortOrder"); QTest::addColumn<int>("sortColumn"); QTest::addColumn<IntPairPairList>("expectedSelectedRanges"); @@ -1689,7 +1692,7 @@ void tst_QItemSelectionModel::modelLayoutChanged_data() << (IntList() << 3 << 2 << 1 << 0)) << (IntPairPairList() << IntPairPair(IntPair(0, 0), IntPair(3, 1))) - << int(Qt::DescendingOrder) + << Qt::DescendingOrder << 0 << (IntPairPairList() << IntPairPair(IntPair(0, 0), IntPair(3, 1))); @@ -1699,7 +1702,7 @@ void tst_QItemSelectionModel::modelLayoutChanged_data() << (IntList() << 3 << 2 << 1 << 0)) << (IntPairPairList() << IntPairPair(IntPair(0, 0), IntPair(1, 1))) - << int(Qt::DescendingOrder) + << Qt::DescendingOrder << 0 << (IntPairPairList() << IntPairPair(IntPair(2, 0), IntPair(3, 1))); @@ -1709,7 +1712,7 @@ void tst_QItemSelectionModel::modelLayoutChanged_data() << (IntList() << 3 << 2 << 1 << 0)) << (IntPairPairList() << IntPairPair(IntPair(1, 0), IntPair(2, 1))) - << int(Qt::DescendingOrder) + << Qt::DescendingOrder << 0 << (IntPairPairList() << IntPairPair(IntPair(1, 0), IntPair(2, 1))); @@ -1720,7 +1723,7 @@ void tst_QItemSelectionModel::modelLayoutChanged_data() << (IntPairPairList() << IntPairPair(IntPair(1, 0), IntPair(1, 1)) << IntPairPair(IntPair(3, 0), IntPair(3, 1))) - << int(Qt::AscendingOrder) + << Qt::AscendingOrder << 0 << (IntPairPairList() << IntPairPair(IntPair(0, 0), IntPair(0, 1)) @@ -1730,8 +1733,8 @@ void tst_QItemSelectionModel::modelLayoutChanged_data() void tst_QItemSelectionModel::modelLayoutChanged() { QFETCH(IntListList, items); - QFETCH(IntPairPairList, initialSelectedRanges); - QFETCH(int, sortOrder); + QFETCH(const IntPairPairList, initialSelectedRanges); + QFETCH(Qt::SortOrder, sortOrder); QFETCH(int, sortColumn); QFETCH(IntPairPairList, expectedSelectedRanges); @@ -1746,9 +1749,9 @@ void tst_QItemSelectionModel::modelLayoutChanged() // select initial ranges QItemSelectionModel selectionModel(&model); - foreach (IntPairPair range, initialSelectedRanges) { - IntPair tl = range.first; - IntPair br = range.second; + for (const auto &range : initialSelectedRanges) { + const auto &tl = range.first; + const auto &br = range.second; QItemSelection selection( model.index(tl.first, tl.second), model.index(br.first, br.second)); @@ -1756,7 +1759,7 @@ void tst_QItemSelectionModel::modelLayoutChanged() } // sort the model - model.sort(sortColumn, Qt::SortOrder(sortOrder)); + model.sort(sortColumn, sortOrder); // verify that selection is as expected QItemSelection selection = selectionModel.selection(); @@ -2126,43 +2129,43 @@ void tst_QItemSelectionModel::merge_data() { QTest::addColumn<QItemSelection>("init"); QTest::addColumn<QItemSelection>("other"); - QTest::addColumn<int>("command"); + QTest::addColumn<QItemSelectionModel::SelectionFlag>("command"); QTest::addColumn<QItemSelection>("result"); QTest::newRow("Simple select") << QItemSelection() << QItemSelection(model->index(2, 1) , model->index(3, 4)) - << int(QItemSelectionModel::Select) + << QItemSelectionModel::Select << QItemSelection(model->index(2, 1) , model->index(3, 4)); QTest::newRow("Simple deselect") << QItemSelection(model->index(2, 1) , model->index(3, 4)) << QItemSelection(model->index(2, 1) , model->index(3, 4)) - << int(QItemSelectionModel::Deselect) + << QItemSelectionModel::Deselect << QItemSelection(); QTest::newRow("Simple Toggle deselect") << QItemSelection(model->index(2, 1) , model->index(3, 4)) << QItemSelection(model->index(2, 1) , model->index(3, 4)) - << int(QItemSelectionModel::Toggle) + << QItemSelectionModel::Toggle << QItemSelection(); QTest::newRow("Simple Toggle select") << QItemSelection() << QItemSelection(model->index(2, 1) , model->index(3, 4)) - << int(QItemSelectionModel::Toggle) + << QItemSelectionModel::Toggle << QItemSelection(model->index(2, 1) , model->index(3, 4)); QTest::newRow("Add select") << QItemSelection(model->index(2, 1) , model->index(3, 3)) << QItemSelection(model->index(2, 2) , model->index(3, 4)) - << int(QItemSelectionModel::Select) + << QItemSelectionModel::Select << QItemSelection(model->index(2, 1) , model->index(3, 4)); QTest::newRow("Deselect") << QItemSelection(model->index(2, 1) , model->index(3, 4)) << QItemSelection(model->index(2, 2) , model->index(3, 4)) - << int(QItemSelectionModel::Deselect) + << QItemSelectionModel::Deselect << QItemSelection(model->index(2, 1) , model->index(3, 1)); QItemSelection r1(model->index(2, 1) , model->index(3, 1)); @@ -2170,7 +2173,7 @@ void tst_QItemSelectionModel::merge_data() QTest::newRow("Toggle") << QItemSelection(model->index(2, 1) , model->index(3, 3)) << QItemSelection(model->index(2, 2) , model->index(3, 4)) - << int(QItemSelectionModel::Toggle) + << QItemSelectionModel::Toggle << r1; } @@ -2178,15 +2181,18 @@ void tst_QItemSelectionModel::merge() { QFETCH(QItemSelection, init); QFETCH(QItemSelection, other); - QFETCH(int, command); + QFETCH(QItemSelectionModel::SelectionFlag, command); QFETCH(QItemSelection, result); - init.merge(other, QItemSelectionModel::SelectionFlags(command)); + init.merge(other, command); - foreach(const QModelIndex &idx, init.indexes()) - QVERIFY(result.contains(idx)); - foreach(const QModelIndex &idx, result.indexes()) - QVERIFY(init.contains(idx)); + auto verify = [](const QModelIndexList &a, const QItemSelection &b) + { + for (const QModelIndex &idx : a) + QVERIFY(b.contains(idx)); + }; + verify(init.indexes(), result); + verify(result.indexes(), init); } void tst_QItemSelectionModel::isRowSelected() @@ -2211,8 +2217,8 @@ void tst_QItemSelectionModel::childrenDeselectionSignal() } QModelIndex root = model.index(0,0); - QModelIndex par = root.child(0,0); - QModelIndex sel = par.child(0,0); + QModelIndex par = model.index(0, 0, root); + QModelIndex sel = model.index(0, 0, par); QItemSelectionModel selectionModel(&model); selectionModel.select(sel, QItemSelectionModel::SelectCurrent); @@ -2240,9 +2246,9 @@ void tst_QItemSelectionModel::childrenDeselectionSignal() } } - sel = model.index(0, 0).child(0, 0); + sel = model.index(0, 0, model.index(0, 0)); selectionModel.select(sel, QItemSelectionModel::Select); - QModelIndex sel2 = model.index(1, 0).child(0, 0); + QModelIndex sel2 = model.index(0, 0, model.index(1, 0)); selectionModel.select(sel2, QItemSelectionModel::Select); QVERIFY(selectionModel.selection().contains(sel)); @@ -2264,24 +2270,23 @@ void tst_QItemSelectionModel::layoutChangedWithAllSelected1() QCOMPARE(model.rowCount(), 3); QCOMPARE(proxy.rowCount(), 3); - proxy.setFilterRegExp( QRegExp("f")); + proxy.setFilterRegularExpression(QRegularExpression("f")); QCOMPARE(proxy.rowCount(), 2); - QList<QPersistentModelIndex> indexList; - indexList << proxy.index(0,0) << proxy.index(1,0); - selection.select( QItemSelection(indexList.first(), indexList.last()), QItemSelectionModel::Select); + const QList<QPersistentModelIndex> indexList({proxy.index(0,0), proxy.index(1,0)}); + selection.select(QItemSelection(indexList.first(), indexList.last()), QItemSelectionModel::Select); //let's check the selection hasn't changed QCOMPARE(selection.selectedIndexes().count(), indexList.count()); - foreach(QPersistentModelIndex index, indexList) + for (const auto &index : indexList) QVERIFY(selection.isSelected(index)); - proxy.setFilterRegExp(QRegExp()); + proxy.setFilterRegularExpression(QRegularExpression()); QCOMPARE(proxy.rowCount(), 3); //let's check the selection hasn't changed QCOMPARE(selection.selectedIndexes().count(), indexList.count()); - foreach(QPersistentModelIndex index, indexList) + for (const auto &index : indexList) QVERIFY(selection.isSelected(index)); } @@ -2321,9 +2326,8 @@ void tst_QItemSelectionModel::layoutChangedWithAllSelected2() selection.select( QItemSelection(proxy.index(0,0), proxy.index(proxy.rowCount() - 1, proxy.columnCount() - 1)), QItemSelectionModel::Select); - QList<QPersistentModelIndex> indexList; - foreach(const QModelIndex &id, selection.selectedIndexes()) - indexList << id; + const auto selIndexes = selection.selectedIndexes(); + const QList<QPersistentModelIndex> indexList(selIndexes.begin(), selIndexes.end()); proxy.filtering = false; proxy.invalidate(); @@ -2331,7 +2335,7 @@ void tst_QItemSelectionModel::layoutChangedWithAllSelected2() //let's check the selection hasn't changed QCOMPARE(selection.selectedIndexes().count(), indexList.count()); - foreach(QPersistentModelIndex index, indexList) + for (const auto &index : indexList) QVERIFY(selection.isSelected(index)); } @@ -2375,7 +2379,8 @@ public: public slots: void selectionChanged(const QItemSelection & /* selected */, const QItemSelection &deselected) { - foreach(const QModelIndex &index, deselected.indexes()) { + const auto deselIndexes = deselected.indexes(); + for (const auto &index : deselIndexes) { QVERIFY(!m_itemSelectionModel->selection().contains(index)); } QCOMPARE(m_itemSelectionModel->selection().size(), 2); @@ -2633,9 +2638,9 @@ private slots: void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) { - foreach(const QItemSelectionRange &range, selected) + for (const auto &range : selected) QVERIFY(range.isValid()); - foreach(const QItemSelectionRange &range, deselected) + for (const auto &range : deselected) QVERIFY(range.isValid()); } diff --git a/tests/auto/corelib/itemmodels/qsortfilterproxymodel_common/tst_qsortfilterproxymodel.cpp b/tests/auto/corelib/itemmodels/qsortfilterproxymodel_common/tst_qsortfilterproxymodel.cpp index ccce5a44e5..624187349b 100644 --- a/tests/auto/corelib/itemmodels/qsortfilterproxymodel_common/tst_qsortfilterproxymodel.cpp +++ b/tests/auto/corelib/itemmodels/qsortfilterproxymodel_common/tst_qsortfilterproxymodel.cpp @@ -829,7 +829,7 @@ void tst_QSortFilterProxyModel::removeRows_data() void tst_QSortFilterProxyModel::removeRows() { - QFETCH(QStringList, initial); + QFETCH(const QStringList, initial); QFETCH(int, sortOrder); QFETCH(QString, filter); QFETCH(int, position); @@ -843,7 +843,7 @@ void tst_QSortFilterProxyModel::removeRows() proxy.setSourceModel(&model); // prepare model - foreach (QString s, initial) + for (const auto &s : initial) model.appendRow(new QStandardItem(s)); if (sortOrder != -1) @@ -3035,15 +3035,15 @@ void tst_QSortFilterProxyModel::removeRowsRecursive() QList<QPersistentModelIndex> sourceIndexes; QList<QPersistentModelIndex> proxyIndexes; - foreach (QStandardItem *item, items) { + for (const auto item : qAsConst(items)) { QModelIndex idx = item->index(); sourceIndexes << idx; proxyIndexes << proxy.mapFromSource(idx); } - foreach (const QPersistentModelIndex &pidx, sourceIndexes) + for (const auto &pidx : qAsConst(sourceIndexes)) QVERIFY(pidx.isValid()); - foreach (const QPersistentModelIndex &pidx, proxyIndexes) + for (const auto &pidx : qAsConst(proxyIndexes)) QVERIFY(pidx.isValid()); QList<QStandardItem*> itemRow = pItem1->takeRow(0); @@ -3051,9 +3051,9 @@ void tst_QSortFilterProxyModel::removeRowsRecursive() QCOMPARE(itemRow.count(), 1); QCOMPARE(itemRow.first(), pItem11); - foreach (const QPersistentModelIndex &pidx, sourceIndexes) + for (const auto &pidx : qAsConst(sourceIndexes)) QVERIFY(!pidx.isValid()); - foreach (const QPersistentModelIndex &pidx, proxyIndexes) + for (const auto &pidx : qAsConst(proxyIndexes)) QVERIFY(!pidx.isValid()); delete pItem11; @@ -3280,10 +3280,8 @@ void tst_QSortFilterProxyModel::testMultipleProxiesWithSelection() static bool isValid(const QItemSelection &selection) { - foreach (const QItemSelectionRange &range, selection) - if (!range.isValid()) - return false; - return true; + return std::all_of(selection.begin(), selection.end(), + [](const QItemSelectionRange &range) { return range.isValid(); }); } void tst_QSortFilterProxyModel::mapSelectionFromSource() @@ -3737,14 +3735,16 @@ void tst_QSortFilterProxyModel::testParentLayoutChanged() QVERIFY(beforeParents.first() == proxy.mapFromSource(model.indexFromItem(model.invisibleRootItem()->child(1)))); - QList<QPersistentModelIndex> proxy2BeforeList = proxy2ParentsAboutToBeChangedSpy.first().first().value<QList<QPersistentModelIndex> >(); - QList<QPersistentModelIndex> proxy2AfterList = proxy2ParentsChangedSpy.first().first().value<QList<QPersistentModelIndex> >(); + const QList<QPersistentModelIndex> proxy2BeforeList = + proxy2ParentsAboutToBeChangedSpy.first().first().value<QList<QPersistentModelIndex> >(); + const QList<QPersistentModelIndex> proxy2AfterList = + proxy2ParentsChangedSpy.first().first().value<QList<QPersistentModelIndex> >(); QCOMPARE(proxy2BeforeList.size(), beforeParents.size()); QCOMPARE(proxy2AfterList.size(), afterParents.size()); - foreach (const QPersistentModelIndex &idx, proxy2BeforeList) + for (const QPersistentModelIndex &idx : proxy2BeforeList) QVERIFY(beforeParents.contains(proxy2.mapToSource(idx))); - foreach (const QPersistentModelIndex &idx, proxy2AfterList) + for (const QPersistentModelIndex &idx : proxy2AfterList) QVERIFY(afterParents.contains(proxy2.mapToSource(idx))); } @@ -3977,7 +3977,7 @@ void tst_QSortFilterProxyModel::hierarchyFilterInvalidation() QTreeView view; view.setModel(&proxy); - view.setCurrentIndex(proxy.index(2, 0).child(0, 0)); + view.setCurrentIndex(proxy.index(0, 0, proxy.index(2, 0))); view.show(); QVERIFY(QTest::qWaitForWindowExposed(&view)); diff --git a/tests/auto/corelib/itemmodels/qstringlistmodel/tst_qstringlistmodel.cpp b/tests/auto/corelib/itemmodels/qstringlistmodel/tst_qstringlistmodel.cpp index 0b8686560c..3919472b96 100644 --- a/tests/auto/corelib/itemmodels/qstringlistmodel/tst_qstringlistmodel.cpp +++ b/tests/auto/corelib/itemmodels/qstringlistmodel/tst_qstringlistmodel.cpp @@ -333,7 +333,7 @@ template <class C> C sorted(C c) { std::sort(c.begin(), c.end()); - return qMove(c); + return std::move(c); } void tst_QStringListModel::setData_emits_both_roles() diff --git a/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp b/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp index 6adb393ddd..39c90f69b4 100644 --- a/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp +++ b/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp @@ -611,7 +611,7 @@ void tst_QCoreApplication::processEventsAlwaysSendsPostedEvents() TestApplication app(argc, argv); ProcessEventsAlwaysSendsPostedEventsObject object; - QTime t; + QElapsedTimer t; t.start(); int i = 1; do { @@ -775,49 +775,49 @@ private slots: QCoreApplicationPrivate *privateClass = static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(qApp)); { - QCOMPARE(privateClass->quitLockRef.load(), 0); + QCOMPARE(privateClass->quitLockRef.loadRelaxed(), 0); // Test with a lock active so that the refcount doesn't drop to zero during these tests, causing a quit. // (until we exit the scope) QEventLoopLocker locker; - QCOMPARE(privateClass->quitLockRef.load(), 1); + QCOMPARE(privateClass->quitLockRef.loadRelaxed(), 1); JobObject *job1 = new JobObject(this); - QCOMPARE(privateClass->quitLockRef.load(), 2); + QCOMPARE(privateClass->quitLockRef.loadRelaxed(), 2); delete job1; - QCOMPARE(privateClass->quitLockRef.load(), 1); + QCOMPARE(privateClass->quitLockRef.loadRelaxed(), 1); job1 = new JobObject(this); - QCOMPARE(privateClass->quitLockRef.load(), 2); + QCOMPARE(privateClass->quitLockRef.loadRelaxed(), 2); JobObject *job2 = new JobObject(this); - QCOMPARE(privateClass->quitLockRef.load(), 3); + QCOMPARE(privateClass->quitLockRef.loadRelaxed(), 3); delete job1; - QCOMPARE(privateClass->quitLockRef.load(), 2); + QCOMPARE(privateClass->quitLockRef.loadRelaxed(), 2); JobObject *job3 = new JobObject(job2); Q_UNUSED(job3); - QCOMPARE(privateClass->quitLockRef.load(), 3); + QCOMPARE(privateClass->quitLockRef.loadRelaxed(), 3); JobObject *job4 = new JobObject(job2); Q_UNUSED(job4); - QCOMPARE(privateClass->quitLockRef.load(), 4); + QCOMPARE(privateClass->quitLockRef.loadRelaxed(), 4); delete job2; - QCOMPARE(privateClass->quitLockRef.load(), 1); + QCOMPARE(privateClass->quitLockRef.loadRelaxed(), 1); } - QCOMPARE(privateClass->quitLockRef.load(), 0); + QCOMPARE(privateClass->quitLockRef.loadRelaxed(), 0); } }; diff --git a/tests/auto/corelib/kernel/qelapsedtimer/BLACKLIST b/tests/auto/corelib/kernel/qelapsedtimer/BLACKLIST index 4dd71ca9f4..569880e1db 100644 --- a/tests/auto/corelib/kernel/qelapsedtimer/BLACKLIST +++ b/tests/auto/corelib/kernel/qelapsedtimer/BLACKLIST @@ -1,4 +1,3 @@ [elapsed] -windows -osx-10.12 osx-10.13 +windows-10 diff --git a/tests/auto/corelib/kernel/qeventdispatcher/BLACKLIST b/tests/auto/corelib/kernel/qeventdispatcher/BLACKLIST deleted file mode 100644 index 06588188d4..0000000000 --- a/tests/auto/corelib/kernel/qeventdispatcher/BLACKLIST +++ /dev/null @@ -1,6 +0,0 @@ -[sendPostedEvents] -windows -[registerTimer] -windows -winrt -osx diff --git a/tests/auto/corelib/kernel/qeventloop/BLACKLIST b/tests/auto/corelib/kernel/qeventloop/BLACKLIST deleted file mode 100644 index 6ea6314b0a..0000000000 --- a/tests/auto/corelib/kernel/qeventloop/BLACKLIST +++ /dev/null @@ -1,2 +0,0 @@ -[testQuitLock] -windows diff --git a/tests/auto/corelib/kernel/qeventloop/qeventloop.pro b/tests/auto/corelib/kernel/qeventloop/qeventloop.pro index 295a42aa9c..159761c0c6 100644 --- a/tests/auto/corelib/kernel/qeventloop/qeventloop.pro +++ b/tests/auto/corelib/kernel/qeventloop/qeventloop.pro @@ -3,6 +3,6 @@ TARGET = tst_qeventloop QT = core network testlib core-private SOURCES = $$PWD/tst_qeventloop.cpp -win32:!winrt: LIBS += -luser32 +win32:!winrt: QMAKE_USE += user32 qtConfig(glib): DEFINES += HAVE_GLIB diff --git a/tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp b/tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp index 482ed8d130..1f0b8d4b4e 100644 --- a/tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp +++ b/tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp @@ -638,16 +638,16 @@ void tst_QEventLoop::testQuitLock() QEventLoopPrivate* privateClass = static_cast<QEventLoopPrivate*>(QObjectPrivate::get(&eventLoop)); - QCOMPARE(privateClass->quitLockRef.load(), 0); + QCOMPARE(privateClass->quitLockRef.loadRelaxed(), 0); JobObject *job1 = new JobObject(&eventLoop, this); job1->start(500); - QCOMPARE(privateClass->quitLockRef.load(), 1); + QCOMPARE(privateClass->quitLockRef.loadRelaxed(), 1); eventLoop.exec(); - QCOMPARE(privateClass->quitLockRef.load(), 0); + QCOMPARE(privateClass->quitLockRef.loadRelaxed(), 0); job1 = new JobObject(&eventLoop, this); diff --git a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp index 89a06b358e..60000316cc 100644 --- a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp +++ b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp @@ -507,6 +507,7 @@ public slots: { QObject::moveToThread(t); } void slotWithUnregisteredParameterType(MyUnregisteredType); + void slotWithOneUnregisteredParameterType(QString a1, MyUnregisteredType a2); CountedStruct throwingSlot(const CountedStruct &, CountedStruct s2) { #ifndef QT_NO_EXCEPTIONS @@ -520,7 +521,7 @@ public slots: QVector<QtTestObject *> o5, QList<QtTestObject *> o6) { slotResult = QLatin1String("slotWithRegistrableArgument:") + o1->slotResult + o2->slotResult - + o3->slotResult + o4.data()->slotResult + QString::number(o5.size()) + + o3->slotResult + o4.toStrongRef()->slotResult + QString::number(o5.size()) + QString::number(o6.size()); } @@ -604,6 +605,9 @@ void QtTestObject::testSender() void QtTestObject::slotWithUnregisteredParameterType(MyUnregisteredType) { slotResult = "slotWithUnregisteredReturnType"; } +void QtTestObject::slotWithOneUnregisteredParameterType(QString a1, MyUnregisteredType) +{ slotResult = "slotWithUnregisteredReturnType-" + a1; } + void QtTestObject::staticFunction0() { staticResult = "staticFunction0"; @@ -885,6 +889,16 @@ void tst_QMetaObject::invokeQueuedMetaMember() QVERIFY(!QMetaObject::invokeMethod(&obj, "slotWithUnregisteredParameterType", Qt::QueuedConnection, Q_ARG(MyUnregisteredType, t))); QVERIFY(obj.slotResult.isEmpty()); } + + obj.slotResult.clear(); + { + QString a1("Cannot happen"); + MyUnregisteredType t; + QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invoke: Unable to handle unregistered datatype 'MyUnregisteredType'"); + QVERIFY(!QMetaObject::invokeMethod(&obj, "slotWithOneUnregisteredParameterType", Qt::QueuedConnection, + Q_ARG(QString, a1), Q_ARG(MyUnregisteredType, t))); + QVERIFY(obj.slotResult.isEmpty()); + } } void tst_QMetaObject::invokeQueuedPointer() diff --git a/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp b/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp index 56623773a2..9fe7d63727 100644 --- a/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp +++ b/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp @@ -1322,8 +1322,8 @@ bool tst_QMetaObjectBuilder::sameMetaObject return false; } - const QMetaObject * const *objects1 = meta1->d.relatedMetaObjects; - const QMetaObject * const *objects2 = meta2->d.relatedMetaObjects; + const auto *objects1 = meta1->d.relatedMetaObjects; + const auto *objects2 = meta2->d.relatedMetaObjects; if (objects1 && !objects2) return false; if (objects2 && !objects1) @@ -1391,7 +1391,7 @@ private: }; QMetaObject TestObject::staticMetaObject = { - { 0, 0, 0, 0, 0, 0 } + { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr } }; TestObject::TestObject(QObject *parent) diff --git a/tests/auto/corelib/kernel/qmetaproperty/tst_qmetaproperty.cpp b/tests/auto/corelib/kernel/qmetaproperty/tst_qmetaproperty.cpp index 681a5d0146..cc67fc7884 100644 --- a/tests/auto/corelib/kernel/qmetaproperty/tst_qmetaproperty.cpp +++ b/tests/auto/corelib/kernel/qmetaproperty/tst_qmetaproperty.cpp @@ -130,7 +130,7 @@ public: QString m_value; void setValue(const QString &value) { m_value = value; } QString getValue() { return m_value; } - void resetValue() { m_value = QLatin1Literal("reset"); } + void resetValue() { m_value = QLatin1String("reset"); } }; void tst_QMetaProperty::gadget() @@ -140,7 +140,7 @@ void tst_QMetaProperty::gadget() QVERIFY(valueProp.isValid()); { MyGadget g; - QString hello = QLatin1Literal("hello"); + QString hello = QLatin1String("hello"); QVERIFY(valueProp.writeOnGadget(&g, hello)); QCOMPARE(g.m_value, QLatin1String("hello")); QCOMPARE(valueProp.readOnGadget(&g), QVariant(hello)); @@ -242,7 +242,7 @@ void tst_QMetaProperty::conversion() QCOMPARE(custom.str, QString()); // or reset resetable QVERIFY(value7P.write(this, QVariant())); - QCOMPARE(value7, QLatin1Literal("reset")); + QCOMPARE(value7, QLatin1String("reset")); } QTEST_MAIN(tst_QMetaProperty) diff --git a/tests/auto/corelib/kernel/qmetatype/qmetatype.pro b/tests/auto/corelib/kernel/qmetatype/qmetatype.pro index 56b8c071c3..4856b138c3 100644 --- a/tests/auto/corelib/kernel/qmetatype/qmetatype.pro +++ b/tests/auto/corelib/kernel/qmetatype/qmetatype.pro @@ -5,6 +5,7 @@ INCLUDEPATH += $$PWD/../../../other/qvariant_common SOURCES = tst_qmetatype.cpp TESTDATA=./typeFlags.bin DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 +DEFINES -= QT_NO_LINKED_LIST msvc|winrt { # Prevents "fatal error C1128: number of sections exceeded object file format limit". diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp index e2bb7dab2a..12c29a6e13 100644 --- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp +++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp @@ -1499,7 +1499,7 @@ public: typedef MyObject* MyObjectPtr; Q_DECLARE_METATYPE(MyObjectPtr) -#if defined(Q_COMPILER_VARIADIC_MACROS) && !defined(TST_QMETATYPE_BROKEN_COMPILER) +#if !defined(TST_QMETATYPE_BROKEN_COMPILER) static QByteArray createTypeName(const char *begin, const char *va) { QByteArray tn(begin); @@ -1697,7 +1697,7 @@ void tst_QMetaType::automaticTemplateRegistration() QVERIFY(qRegisterMetaType<UnregisteredTypeList>("UnregisteredTypeList") > 0); } -#if defined(Q_COMPILER_VARIADIC_MACROS) && !defined(TST_QMETATYPE_BROKEN_COMPILER) +#if !defined(TST_QMETATYPE_BROKEN_COMPILER) #define FOR_EACH_STATIC_PRIMITIVE_TYPE(F) \ F(bool) \ @@ -1776,7 +1776,7 @@ void tst_QMetaType::automaticTemplateRegistration() CREATE_AND_VERIFY_CONTAINER(QHash, void*, void*) CREATE_AND_VERIFY_CONTAINER(QHash, const void*, const void*) -#endif // Q_COMPILER_VARIADIC_MACROS +#endif // !defined(TST_QMETATYPE_BROKEN_COMPILER) #define TEST_OWNING_SMARTPOINTER(SMARTPOINTER, ELEMENT_TYPE, FLAG_TEST, FROMVARIANTFUNCTION) \ { \ @@ -1807,16 +1807,36 @@ void tst_QMetaType::automaticTemplateRegistration() QCOMPARE(extractedPtr.data()->objectName(), sp.data()->objectName()); \ } +#if QT_DEPRECATED_SINCE(5, 0) TEST_NONOWNING_SMARTPOINTER(QWeakPointer, QObject, WeakPointerToQObject, qWeakPointerFromVariant) TEST_NONOWNING_SMARTPOINTER(QWeakPointer, QFile, WeakPointerToQObject, qWeakPointerFromVariant) TEST_NONOWNING_SMARTPOINTER(QWeakPointer, QTemporaryFile, WeakPointerToQObject, qWeakPointerFromVariant) TEST_NONOWNING_SMARTPOINTER(QWeakPointer, MyObject, WeakPointerToQObject, qWeakPointerFromVariant) +#endif TEST_NONOWNING_SMARTPOINTER(QPointer, QObject, TrackingPointerToQObject, qPointerFromVariant) TEST_NONOWNING_SMARTPOINTER(QPointer, QFile, TrackingPointerToQObject, qPointerFromVariant) TEST_NONOWNING_SMARTPOINTER(QPointer, QTemporaryFile, TrackingPointerToQObject, qPointerFromVariant) TEST_NONOWNING_SMARTPOINTER(QPointer, MyObject, TrackingPointerToQObject, qPointerFromVariant) #undef TEST_NONOWNING_SMARTPOINTER + + +#define TEST_WEAK_SMARTPOINTER(ELEMENT_TYPE, FLAG_TEST) \ + { \ + ELEMENT_TYPE elem; \ + QSharedPointer < ELEMENT_TYPE > shared(new ELEMENT_TYPE); \ + QWeakPointer < ELEMENT_TYPE > sp(shared); \ + sp.toStrongRef()->setObjectName("Test name"); \ + QVariant v = QVariant::fromValue(sp); \ + QCOMPARE(v.typeName(), "QWeakPointer<" #ELEMENT_TYPE ">"); \ + QVERIFY(QMetaType::typeFlags(::qMetaTypeId<QWeakPointer < ELEMENT_TYPE > >()) & QMetaType::FLAG_TEST); \ + } + + TEST_WEAK_SMARTPOINTER(QObject, WeakPointerToQObject) + TEST_WEAK_SMARTPOINTER(QFile, WeakPointerToQObject) + TEST_WEAK_SMARTPOINTER(QTemporaryFile, WeakPointerToQObject) + TEST_WEAK_SMARTPOINTER(MyObject, WeakPointerToQObject) +#undef TEST_WEAK_SMARTPOINTER } template <typename T> @@ -2565,9 +2585,7 @@ Q_DECLARE_METATYPE(UndefinedFunction0); Q_DECLARE_METATYPE(UndefinedFunction1); Q_DECLARE_METATYPE(UndefinedFunction2); Q_DECLARE_METATYPE(UndefinedFunction3); -#ifdef Q_COMPILER_VARIADIC_TEMPLATES Q_DECLARE_METATYPE(UndefinedFunction4); -#endif QTEST_MAIN(tst_QMetaType) #include "tst_qmetatype.moc" diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.h b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.h index 6bda9638f7..22bcb69ac9 100644 --- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.h +++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.h @@ -236,7 +236,7 @@ template<> struct TestValueFactory<QMetaType::QRegExp> { template<> struct TestValueFactory<QMetaType::QRegularExpression> { static QRegularExpression *create() { -#ifndef QT_NO_REGEXP +#if QT_CONFIG(regularexpression) return new QRegularExpression("abc.*def"); #else return 0; diff --git a/tests/auto/corelib/kernel/qobject/BLACKLIST b/tests/auto/corelib/kernel/qobject/BLACKLIST deleted file mode 100644 index 0887a73b4c..0000000000 --- a/tests/auto/corelib/kernel/qobject/BLACKLIST +++ /dev/null @@ -1,2 +0,0 @@ -[moveToThread] -windows diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp index 31268c5cf3..a805bfb747 100644 --- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp +++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp @@ -32,7 +32,6 @@ #include <qcoreapplication.h> #include <qpointer.h> #include <qtimer.h> -#include <qregexp.h> #include <qregularexpression.h> #include <qmetaobject.h> #include <qvariant.h> @@ -82,7 +81,9 @@ private slots: void senderTest(); void declareInterface(); void qpointerResetBeforeDestroyedSignal(); +#ifndef QT_NO_USERDATA void testUserData(); +#endif void childDeletesItsSibling(); void dynamicProperties(); void floatProperty(); @@ -154,6 +155,8 @@ private slots: void mutableFunctor(); void checkArgumentsForNarrowing(); void nullReceiver(); + void functorReferencesConnection(); + void disconnectDisconnects(); }; struct QObjectCreatedOnShutdown @@ -535,91 +538,91 @@ void tst_QObject::findChildren() QObject *op = 0; - op = qFindChild<QObject*>(&o, "o1"); + op = o.findChild<QObject*>("o1"); QCOMPARE(op, &o1); - op = qFindChild<QObject*>(&o, "o2"); + op = o.findChild<QObject*>("o2"); QCOMPARE(op, &o2); - op = qFindChild<QObject*>(&o, "o11"); + op = o.findChild<QObject*>("o11"); QCOMPARE(op, &o11); - op = qFindChild<QObject*>(&o, "o12"); + op = o.findChild<QObject*>("o12"); QCOMPARE(op, &o12); - op = qFindChild<QObject*>(&o, "o111"); + op = o.findChild<QObject*>("o111"); QCOMPARE(op, &o111); - op = qFindChild<QObject*>(&o, "t1"); + op = o.findChild<QObject*>("t1"); QCOMPARE(op, static_cast<QObject *>(&t1)); - op = qFindChild<QObject*>(&o, "t121"); + op = o.findChild<QObject*>("t121"); QCOMPARE(op, static_cast<QObject *>(&t121)); - op = qFindChild<QTimer*>(&o, "t1"); + op = o.findChild<QTimer*>("t1"); QCOMPARE(op, static_cast<QObject *>(&t1)); - op = qFindChild<QTimer*>(&o, "t121"); + op = o.findChild<QTimer*>("t121"); QCOMPARE(op, static_cast<QObject *>(&t121)); - op = qFindChild<QTimer*>(&o, "o12"); + op = o.findChild<QTimer*>("o12"); QCOMPARE(op, static_cast<QObject *>(0)); - op = qFindChild<QObject*>(&o, "o"); + op = o.findChild<QObject*>("o"); QCOMPARE(op, static_cast<QObject *>(0)); - op = qFindChild<QObject*>(&o, "harry"); + op = o.findChild<QObject*>("harry"); QCOMPARE(op, static_cast<QObject *>(0)); - op = qFindChild<QObject*>(&o, "o1"); + op = o.findChild<QObject*>("o1"); QCOMPARE(op, &o1); QList<QObject*> l; QList<QTimer*> tl; - l = qFindChildren<QObject*>(&o, "o1"); + l = o.findChildren<QObject*>("o1"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o1); - l = qFindChildren<QObject*>(&o, "o2"); + l = o.findChildren<QObject*>("o2"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o2); - l = qFindChildren<QObject*>(&o, "o11"); + l = o.findChildren<QObject*>("o11"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o11); - l = qFindChildren<QObject*>(&o, "o12"); + l = o.findChildren<QObject*>("o12"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o12); - l = qFindChildren<QObject*>(&o, "o111"); + l = o.findChildren<QObject*>("o111"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o111); - l = qFindChildren<QObject*>(&o, "t1"); + l = o.findChildren<QObject*>("t1"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), static_cast<QObject *>(&t1)); - l = qFindChildren<QObject*>(&o, "t121"); + l = o.findChildren<QObject*>("t121"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), static_cast<QObject *>(&t121)); - tl = qFindChildren<QTimer*>(&o, "t1"); + tl = o.findChildren<QTimer*>("t1"); QCOMPARE(tl.size(), 1); QCOMPARE(tl.at(0), &t1); - tl = qFindChildren<QTimer*>(&o, "t121"); + tl = o.findChildren<QTimer*>("t121"); QCOMPARE(tl.size(), 1); QCOMPARE(tl.at(0), &t121); - l = qFindChildren<QObject*>(&o, "o"); + l = o.findChildren<QObject*>("o"); QCOMPARE(l.size(), 0); - l = qFindChildren<QObject*>(&o, "harry"); + l = o.findChildren<QObject*>("harry"); QCOMPARE(l.size(), 0); - tl = qFindChildren<QTimer*>(&o, "o12"); + tl = o.findChildren<QTimer*>("o12"); QCOMPARE(tl.size(), 0); - l = qFindChildren<QObject*>(&o, "o1"); + l = o.findChildren<QObject*>("o1"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o1); - l = qFindChildren<QObject*>(&o, QRegExp("o.*")); + l = o.findChildren<QObject*>(QRegularExpression("^o.*$")); QCOMPARE(l.size(), 5); QVERIFY(l.contains(&o1)); QVERIFY(l.contains(&o2)); QVERIFY(l.contains(&o11)); QVERIFY(l.contains(&o12)); QVERIFY(l.contains(&o111)); - l = qFindChildren<QObject*>(&o, QRegExp("t.*")); + l = o.findChildren<QObject*>(QRegularExpression("t.*")); QCOMPARE(l.size(), 2); QVERIFY(l.contains(&t1)); QVERIFY(l.contains(&t121)); - tl = qFindChildren<QTimer*>(&o, QRegExp(".*")); + tl = o.findChildren<QTimer*>(QRegularExpression("^.*$")); QCOMPARE(tl.size(), 3); QVERIFY(tl.contains(&t1)); QVERIFY(tl.contains(&t121)); - tl = qFindChildren<QTimer*>(&o, QRegExp("o.*")); + tl = o.findChildren<QTimer*>(QRegularExpression("^o.*$")); QCOMPARE(tl.size(), 0); - l = qFindChildren<QObject*>(&o, QRegExp("harry")); + l = o.findChildren<QObject*>(QRegularExpression("^harry$")); QCOMPARE(l.size(), 0); l = o.findChildren<QObject*>(QRegularExpression("o.*")); @@ -643,18 +646,18 @@ void tst_QObject::findChildren() QCOMPARE(l.size(), 0); // empty and null string check - op = qFindChild<QObject*>(&o); + op = o.findChild<QObject*>(); QCOMPARE(op, &o1); - op = qFindChild<QObject*>(&o, ""); + op = o.findChild<QObject*>(""); QCOMPARE(op, &unnamed); - op = qFindChild<QObject*>(&o, "unnamed"); + op = o.findChild<QObject*>("unnamed"); QCOMPARE(op, static_cast<QObject *>(0)); - l = qFindChildren<QObject*>(&o); + l = o.findChildren<QObject*>(); QCOMPARE(l.size(), 9); - l = qFindChildren<QObject*>(&o, ""); + l = o.findChildren<QObject*>(""); QCOMPARE(l.size(), 2); - l = qFindChildren<QObject*>(&o, "unnamed"); + l = o.findChildren<QObject*>("unnamed"); QCOMPARE(l.size(), 0); tl = o.findChildren<QTimer *>("t1"); @@ -722,19 +725,19 @@ void tst_QObject::findChildren() QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o1); - l = o.findChildren<QObject*>(QRegExp("o.*"), Qt::FindDirectChildrenOnly); + l = o.findChildren<QObject*>(QRegularExpression("^o.*$"), Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 2); QVERIFY(l.contains(&o1)); QVERIFY(l.contains(&o2)); - l = o.findChildren<QObject*>(QRegExp("t.*"), Qt::FindDirectChildrenOnly); + l = o.findChildren<QObject*>(QRegularExpression("^t.*$"), Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 1); QVERIFY(l.contains(&t1)); - tl = o.findChildren<QTimer*>(QRegExp(".*"), Qt::FindDirectChildrenOnly); + tl = o.findChildren<QTimer*>(QRegularExpression("^.*$"), Qt::FindDirectChildrenOnly); QCOMPARE(tl.size(), 2); QVERIFY(tl.contains(&t1)); - tl = o.findChildren<QTimer*>(QRegExp("o.*"), Qt::FindDirectChildrenOnly); + tl = o.findChildren<QTimer*>(QRegularExpression("^o.*$"), Qt::FindDirectChildrenOnly); QCOMPARE(tl.size(), 0); - l = o.findChildren<QObject*>(QRegExp("harry"), Qt::FindDirectChildrenOnly); + l = o.findChildren<QObject*>(QRegularExpression("^harry$"), Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 0); // empty and null string check @@ -1033,18 +1036,16 @@ public Q_SLOTS: void tst_QObject::connectNotify_connectSlotsByName() { ConnectByNameNotifyReceiverObject testObject; - QList<ConnectByNameNotifySenderObject *> senders = - qFindChildren<ConnectByNameNotifySenderObject *>(&testObject); - for (int i = 0; i < senders.size(); ++i) { - ConnectByNameNotifySenderObject *o = senders.at(i); + const QList<ConnectByNameNotifySenderObject *> senders = + testObject.findChildren<ConnectByNameNotifySenderObject *>(); + for (ConnectByNameNotifySenderObject *o : senders) { QVERIFY(o->connectedSignals.isEmpty()); QVERIFY(o->disconnectedSignals.isEmpty()); } QMetaObject::connectSlotsByName(&testObject); - for (int i = 0; i < senders.size(); ++i) { - ConnectByNameNotifySenderObject *o = senders.at(i); + for (ConnectByNameNotifySenderObject *o : senders) { QCOMPARE(o->connectedSignals.size(), 1); QCOMPARE(o->connectedSignals.at(0), QMetaMethod::fromSignal(&ConnectByNameNotifySenderObject::signal1)); QVERIFY(o->disconnectedSignals.isEmpty()); @@ -1400,6 +1401,7 @@ struct CustomType CustomType(const CustomType &other): i1(other.i1), i2(other.i2), i3(other.i3) { ++instanceCount; playWithObjects(); } ~CustomType() { --instanceCount; playWithObjects(); } + CustomType &operator=(const CustomType &) = default; int i1, i2, i3; int value() { return i1 + i2 + i3; } @@ -1629,7 +1631,7 @@ void tst_QObject::thread() QObject object; // thread affinity for objects with no parent should be the // current thread - QVERIFY(object.thread() != 0); + QVERIFY(object.thread() != nullptr); QCOMPARE(object.thread(), currentThread); // children inherit their parent's thread QObject child(&object); @@ -1641,7 +1643,7 @@ void tst_QObject::thread() { TestThread thr; - QVERIFY(thr.thread() != 0); + QVERIFY(thr.thread() != nullptr); QCOMPARE(thr.thread(), currentThread); thr.object = &object; @@ -1800,8 +1802,8 @@ void tst_QObject::moveToThread() QMetaObject::invokeMethod(object, "deleteLater", Qt::QueuedConnection); thread.wait(); - QVERIFY(opointer == 0); - QVERIFY(cpointer == 0); + QVERIFY(opointer == nullptr); + QVERIFY(cpointer == nullptr); } { @@ -2339,6 +2341,7 @@ void tst_QObject::declareInterface() } +#ifndef QT_NO_USERDATA class CustomData : public QObjectUserData { public: @@ -2377,10 +2380,11 @@ void tst_QObject::testUserData() for (int i=0; i<USER_DATA_COUNT; ++i) { int id = user_data_ids[i]; CustomData *data = static_cast<CustomData *>(my_test_object.userData(id)); - QVERIFY(data != 0); + QVERIFY(data != nullptr); QCOMPARE(data->id, id); } } +#endif // QT_NO_USERDATA class DestroyedListener : public QObject { @@ -3409,12 +3413,11 @@ void tst_QObject::disconnectSelfInSlotAndDeleteAfterEmit() void tst_QObject::dumpObjectInfo() { QObject a, b; - QObject::connect(&a, SIGNAL(destroyed(QObject*)), &b, SLOT(deleteLater())); - a.disconnect(&b); + QObject::connect(&a, &QObject::destroyed, &b, &QObject::deleteLater); QTest::ignoreMessage(QtDebugMsg, "OBJECT QObject::unnamed"); QTest::ignoreMessage(QtDebugMsg, " SIGNALS OUT"); QTest::ignoreMessage(QtDebugMsg, " signal: destroyed(QObject*)"); - QTest::ignoreMessage(QtDebugMsg, " <Disconnected receiver>"); + QTest::ignoreMessage(QtDebugMsg, " <functor or function pointer>"); QTest::ignoreMessage(QtDebugMsg, " SIGNALS IN"); QTest::ignoreMessage(QtDebugMsg, " <None>"); a.dumpObjectInfo(); // should not crash @@ -3626,7 +3629,7 @@ class OverloadObject : public QObject void sig(int i, int j = 12); void sig(QObject *o, QObject *p, QObject *q = 0, QObject *r = 0) const; void other(int a = 0); - void sig(QObject *o, OverloadObject *p = 0, QObject *q = 0, QObject *r = 0); + void sig(QObject *o, OverloadObject *p = 0, QObject *q = 0, QObject *r = nullptr); void sig(double r = 0.5); public slots: void slo(int i, int j = 43) @@ -4793,13 +4796,13 @@ class LotsOfSignalsAndSlots: public QObject public slots: void slot_v() {} - void slot_v_noexcept() Q_DECL_NOTHROW {} + void slot_v_noexcept() noexcept {} void slot_vi(int) {} - void slot_vi_noexcept() Q_DECL_NOTHROW {} + void slot_vi_noexcept() noexcept {} void slot_vii(int, int) {} void slot_viii(int, int, int) {} int slot_i() { return 0; } - int slot_i_noexcept() Q_DECL_NOTHROW { return 0; } + int slot_i_noexcept() noexcept { return 0; } int slot_ii(int) { return 0; } int slot_iii(int, int) { return 0; } int slot_iiii(int, int, int) { return 0; } @@ -4813,18 +4816,18 @@ class LotsOfSignalsAndSlots: public QObject void slot_vPFvvE(fptr) {} void const_slot_v() const {}; - void const_slot_v_noexcept() const Q_DECL_NOTHROW {} + void const_slot_v_noexcept() const noexcept {} void const_slot_vi(int) const {}; - void const_slot_vi_noexcept(int) const Q_DECL_NOTHROW {} + void const_slot_vi_noexcept(int) const noexcept {} static void static_slot_v() {} - static void static_slot_v_noexcept() Q_DECL_NOTHROW {} + static void static_slot_v_noexcept() noexcept {} static void static_slot_vi(int) {} - static void static_slot_vi_noexcept(int) Q_DECL_NOTHROW {} + static void static_slot_vi_noexcept(int) noexcept {} static void static_slot_vii(int, int) {} static void static_slot_viii(int, int, int) {} static int static_slot_i() { return 0; } - static int static_slot_i_noexcept() Q_DECL_NOTHROW { return 0; } + static int static_slot_i_noexcept() noexcept { return 0; } static int static_slot_ii(int) { return 0; } static int static_slot_iii(int, int) { return 0; } static int static_slot_iiii(int, int, int) { return 0; } @@ -4987,11 +4990,11 @@ void tst_QObject::connectCxx0xTypeMatching() } -void receiverFunction_noexcept() Q_DECL_NOTHROW {} -struct Functor_noexcept { void operator()() Q_DECL_NOTHROW {} }; +void receiverFunction_noexcept() noexcept {} +struct Functor_noexcept { void operator()() noexcept {} }; void tst_QObject::connectCxx17Noexcept() { - // this is about connecting signals to slots with the Q_DECL_NOTHROW qualifier + // this is about connecting signals to slots with the noexcept qualifier // as semantics changed due to http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html typedef LotsOfSignalsAndSlots Foo; Foo obj; @@ -5981,7 +5984,7 @@ void ConnectToPrivateSlot::test(SenderObject* obj1) { obj1->signal1(); QCOMPARE(d->receivedCount, 1); QCOMPARE(d->receivedValue, QVariant()); - obj1->signal7(666, QLatin1Literal("_")); + obj1->signal7(666, QLatin1String("_")); QCOMPARE(d->receivedCount, 2); QCOMPARE(d->receivedValue, QVariant(666)); QVERIFY(QObjectPrivate::connect(obj1, &SenderObject::signal2, d, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlot, Qt::UniqueConnection)); @@ -6028,7 +6031,6 @@ void tst_QObject::connectFunctorArgDifference() QStringListModel model; connect(&model, &QStringListModel::rowsInserted, SlotFunctor()); -#if defined(Q_COMPILER_LAMBDA) connect(&timer, &QTimer::timeout, [=](){}); connect(&timer, &QTimer::objectNameChanged, [=](const QString &){}); connect(qApp, &QCoreApplication::aboutToQuit, [=](){}); @@ -6036,7 +6038,6 @@ void tst_QObject::connectFunctorArgDifference() connect(&timer, &QTimer::objectNameChanged, [=](){}); connect(&model, &QStringListModel::rowsInserted, [=](){}); connect(&model, &QStringListModel::rowsInserted, [=](const QModelIndex &){}); -#endif QVERIFY(true); } @@ -6074,7 +6075,6 @@ void tst_QObject::connectFunctorQueued() e.exec(); QCOMPARE(status, 2); -#if defined(Q_COMPILER_LAMBDA) status = 1; connect(&obj, &SenderObject::signal1, this, [&status] { status = 2; }, Qt::QueuedConnection); @@ -6082,7 +6082,6 @@ void tst_QObject::connectFunctorQueued() QCOMPARE(status, 1); e.exec(); QCOMPARE(status, 2); -#endif } void tst_QObject::connectFunctorWithContext() @@ -6116,7 +6115,6 @@ void tst_QObject::connectFunctorWithContext() e.exec(); QCOMPARE(status, 2); -#if defined(Q_COMPILER_LAMBDA) status = 1; connect(&obj, &SenderObject::signal1, this, [this, &status, &obj] { status = 2; QCOMPARE(sender(), &obj); }, Qt::QueuedConnection); @@ -6124,7 +6122,6 @@ void tst_QObject::connectFunctorWithContext() QCOMPARE(status, 1); e.exec(); QCOMPARE(status, 2); -#endif // Free context->deleteLater(); @@ -6434,7 +6431,7 @@ void connectFunctorOverload_impl(Signal signal, int expOverload, QList<QVariant> void tst_QObject::connectFunctorOverloads() { -#if defined (Q_COMPILER_DECLTYPE) && defined (Q_COMPILER_VARIADIC_TEMPLATES) +#if defined (Q_COMPILER_VARIADIC_TEMPLATES) connectFunctorOverload_impl<ComplexFunctor>(&FunctorArgDifferenceObject::signal_ii, 1, (QList<QVariant>() << 1 << 2)); connectFunctorOverload_impl<ComplexFunctor>(&FunctorArgDifferenceObject::signal_iiS, 1, @@ -6608,7 +6605,6 @@ void tst_QObject::disconnectDoesNotLeakFunctor() } QCOMPARE(countedStructObjectsCount, 0); { -#if defined(Q_COMPILER_LAMBDA) CountedStruct s; QCOMPARE(countedStructObjectsCount, 1); QTimer timer; @@ -6618,7 +6614,6 @@ void tst_QObject::disconnectDoesNotLeakFunctor() QCOMPARE(countedStructObjectsCount, 2); QVERIFY(QObject::disconnect(c)); QCOMPARE(countedStructObjectsCount, 1); -#endif // Q_COMPILER_LAMBDA } QCOMPARE(countedStructObjectsCount, 0); } @@ -6666,7 +6661,6 @@ void tst_QObject::contextDoesNotLeakFunctor() } QCOMPARE(countedStructObjectsCount, 0); { -#if defined(Q_COMPILER_LAMBDA) CountedStruct s; QEventLoop e; ContextObject *context = new ContextObject; @@ -6679,7 +6673,6 @@ void tst_QObject::contextDoesNotLeakFunctor() context->deleteLater(); e.exec(); QCOMPARE(countedStructObjectsCount, 1); -#endif // Q_COMPILER_LAMBDA } QCOMPARE(countedStructObjectsCount, 0); } @@ -7487,6 +7480,167 @@ void tst_QObject::nullReceiver() QVERIFY(!connect(&o, SIGNAL(destroyed()), nullObj, SLOT(deleteLater()))); } +void tst_QObject::functorReferencesConnection() +{ + countedStructObjectsCount = 0; + QMetaObject::Connection globalCon; + { + GetSenderObject obj; + CountedStruct counted(&obj); + QCOMPARE(countedStructObjectsCount, 1); + auto c = QSharedPointer<QMetaObject::Connection>::create(); + int slotCalled = 0; + *c = connect(&obj, &GetSenderObject::aSignal, &obj, [&slotCalled, c, counted] { + QObject::disconnect(*c); + slotCalled++; + }); + globalCon = *c; // keep a handle to the connection somewhere; + QVERIFY(globalCon); + QCOMPARE(countedStructObjectsCount, 2); + obj.triggerSignal(); + QCOMPARE(slotCalled, 1); + QCOMPARE(countedStructObjectsCount, 1); + QVERIFY(!globalCon); + obj.triggerSignal(); + QCOMPARE(slotCalled, 1); + QCOMPARE(countedStructObjectsCount, 1); + } + QCOMPARE(countedStructObjectsCount, 0); + + { + GetSenderObject obj; + CountedStruct counted(&obj); + QCOMPARE(countedStructObjectsCount, 1); + auto *rec = new QObject; + int slotCalled = 0; + globalCon = connect(&obj, &GetSenderObject::aSignal, rec, [&slotCalled, rec, counted] { + delete rec; + slotCalled++; + }); + QCOMPARE(countedStructObjectsCount, 2); + obj.triggerSignal(); + QCOMPARE(slotCalled, 1); + QCOMPARE(countedStructObjectsCount, 1); + QVERIFY(!globalCon); + obj.triggerSignal(); + QCOMPARE(slotCalled, 1); + QCOMPARE(countedStructObjectsCount, 1); + } + QCOMPARE(countedStructObjectsCount, 0); + { + int slotCalled = 0; + QEventLoop eventLoop; + { + // Sender will be destroyed when the labda goes out of scope lambda, so it will exit the event loop + auto sender = QSharedPointer<GetSenderObject>::create(); + connect(sender.data(), &QObject::destroyed, &eventLoop, &QEventLoop::quit, Qt::QueuedConnection); + globalCon = connect(sender.data(), &GetSenderObject::aSignal, this, [&slotCalled, sender, &globalCon, this] { + ++slotCalled; + // This signal will be connected, but should never be called as the sender will be destroyed before + auto c2 = connect(sender.data(), &GetSenderObject::aSignal, [] { QFAIL("Should not be called"); }); + QVERIFY(c2); + QVERIFY(QObject::disconnect(sender.data(), nullptr, this, nullptr)); + QVERIFY(!globalCon); // this connection has been disconnected + QVERIFY(c2); // sender should not have been deleted yet, only after the emission is done + }); + QMetaObject::invokeMethod(sender.data(), &GetSenderObject::triggerSignal, Qt::QueuedConnection); + QMetaObject::invokeMethod(sender.data(), &GetSenderObject::triggerSignal, Qt::QueuedConnection); + QMetaObject::invokeMethod(sender.data(), &GetSenderObject::triggerSignal, Qt::QueuedConnection); + } + eventLoop.exec(); + QCOMPARE(slotCalled, 1); + } + + { + GetSenderObject obj; + CountedStruct counted(&obj); + QCOMPARE(countedStructObjectsCount, 1); + auto c1 = QSharedPointer<QMetaObject::Connection>::create(); + auto c2 = QSharedPointer<QMetaObject::Connection>::create(); + int slot1Called = 0; + int slot3Called = 0; + *c1 = connect(&obj, &GetSenderObject::aSignal, &obj, [&slot1Called, &slot3Called, &obj, c1, c2, counted] { + auto c3 = connect(&obj, &GetSenderObject::aSignal, [counted, &slot3Called] { + slot3Called++; + }); + // top-level + the one in the 3 others lambdas + QCOMPARE(countedStructObjectsCount, 4); + QObject::disconnect(*c2); + slot1Called++; + }); + connect(&obj, &GetSenderObject::aSignal, [] {}); // just a dummy signal to fill the connection list + *c2 = connect(&obj, &GetSenderObject::aSignal, [counted, c2] { QFAIL("should not be called"); }); + QVERIFY(c1 && c2); + QCOMPARE(countedStructObjectsCount, 3); // top-level + c1 + c2 + obj.triggerSignal(); + QCOMPARE(slot1Called, 1); + QCOMPARE(slot3Called, 0); + QCOMPARE(countedStructObjectsCount, 3); // top-level + c1 + c3 + QObject::disconnect(*c1); + QCOMPARE(countedStructObjectsCount, 2); // top-level + c3 + obj.triggerSignal(); + QCOMPARE(slot1Called, 1); + QCOMPARE(slot3Called, 1); + } + { + struct DestroyEmit { + Q_DISABLE_COPY(DestroyEmit); + explicit DestroyEmit(SenderObject *obj) : obj(obj) {} + SenderObject *obj; + ~DestroyEmit() { + obj->emitSignal1(); + } + }; + SenderObject obj; + int slot1Called = 0; + int slot2Called = 0; + int slot3Called = 0; + auto c1 = QSharedPointer<QMetaObject::Connection>::create(); + auto de = QSharedPointer<DestroyEmit>::create(&obj); + *c1 = connect(&obj, &SenderObject::signal1, [&slot1Called, &slot3Called, de, c1, &obj] { + connect(&obj, &SenderObject::signal1, [&slot3Called] { slot3Called++; }); + slot1Called++; + QObject::disconnect(*c1); + }); + de.clear(); + connect(&obj, &SenderObject::signal1, [&slot2Called] { slot2Called++; }); + obj.emitSignal1(); + QCOMPARE(slot1Called, 1); + QCOMPARE(slot2Called, 2); // because also called from ~DestroyEmit + QCOMPARE(slot3Called, 1); + } +} + +void tst_QObject::disconnectDisconnects() +{ + // Test what happens if the destructor of an functor slot also disconnects more slot; + + SenderObject s1; + QScopedPointer<QObject> receiver(new QObject); + + auto s2 = QSharedPointer<SenderObject>::create(); + QPointer<QObject> s2_tracker = s2.data(); + int count = 0; + connect(&s1, &SenderObject::signal1, [&count] { count++; }); // α + connect(&s1, &SenderObject::signal1, receiver.data(), [s2] { QFAIL("!!"); }); // β + connect(s2.data(), &SenderObject::signal1, receiver.data(), [] { QFAIL("!!"); }); + connect(&s1, &SenderObject::signal2, receiver.data(), [] { QFAIL("!!"); }); + connect(s2.data(), &SenderObject::signal2, receiver.data(), [] { QFAIL("!!"); }); + connect(&s1, &SenderObject::signal1, [&count] { count++; }); // γ + connect(&s1, &SenderObject::signal2, [&count] { count++; }); // δ + s2.clear(); + + QVERIFY(s2_tracker); + receiver + .reset(); // this will delete the receiver which must also delete s2 as β is disconnected + QVERIFY(!s2_tracker); + // test that the data structures are still in order + s1.emitSignal1(); + QCOMPARE(count, 2); // α + γ + s1.emitSignal2(); + QCOMPARE(count, 3); // + δ +} + // Test for QtPrivate::HasQ_OBJECT_Macro Q_STATIC_ASSERT(QtPrivate::HasQ_OBJECT_Macro<tst_QObject>::Value); Q_STATIC_ASSERT(!QtPrivate::HasQ_OBJECT_Macro<SiblingDeleter>::Value); diff --git a/tests/auto/corelib/kernel/qsharedmemory/tst_qsharedmemory.cpp b/tests/auto/corelib/kernel/qsharedmemory/tst_qsharedmemory.cpp index 55deb8eb1a..fa2d5e3723 100644 --- a/tests/auto/corelib/kernel/qsharedmemory/tst_qsharedmemory.cpp +++ b/tests/auto/corelib/kernel/qsharedmemory/tst_qsharedmemory.cpp @@ -34,6 +34,7 @@ #include <QSharedMemory> #include <QTest> #include <QThread> +#include <QElapsedTimer> #define EXISTING_SHARE "existing" #define EXISTING_SIZE 1024 @@ -645,7 +646,7 @@ public: char *memory = (char*)producer.data(); memory[1] = '0'; - QTime timer; + QElapsedTimer timer; timer.start(); int i = 0; while (i < 5 && timer.elapsed() < 5000) { diff --git a/tests/auto/corelib/kernel/qsignalblocker/tst_qsignalblocker.cpp b/tests/auto/corelib/kernel/qsignalblocker/tst_qsignalblocker.cpp index fd18f00cd0..39b03ade61 100644 --- a/tests/auto/corelib/kernel/qsignalblocker/tst_qsignalblocker.cpp +++ b/tests/auto/corelib/kernel/qsignalblocker/tst_qsignalblocker.cpp @@ -66,7 +66,6 @@ void tst_QSignalBlocker::signalBlocking() void tst_QSignalBlocker::moveAssignment() { -#ifdef Q_COMPILER_RVALUE_REFS QObject o1, o2; // move-assignment: both block other objects @@ -157,10 +156,6 @@ void tst_QSignalBlocker::moveAssignment() QVERIFY(!o1.signalsBlocked()); QVERIFY(!o2.signalsBlocked()); - -#else - QSKIP("This compiler is not in C++11 mode or doesn't support move semantics"); -#endif // Q_COMPILER_RVALUE_REFS } QTEST_MAIN(tst_QSignalBlocker) diff --git a/tests/auto/corelib/kernel/qsocketnotifier/BLACKLIST b/tests/auto/corelib/kernel/qsocketnotifier/BLACKLIST index e68bf84268..f2e5e78592 100644 --- a/tests/auto/corelib/kernel/qsocketnotifier/BLACKLIST +++ b/tests/auto/corelib/kernel/qsocketnotifier/BLACKLIST @@ -1,3 +1,3 @@ [unexpectedDisconnection] -windows -osx +windows-7sp1 +windows-10 msvc-2015 diff --git a/tests/auto/corelib/kernel/qtimer/BLACKLIST b/tests/auto/corelib/kernel/qtimer/BLACKLIST deleted file mode 100644 index 16cbab4587..0000000000 --- a/tests/auto/corelib/kernel/qtimer/BLACKLIST +++ /dev/null @@ -1,5 +0,0 @@ -[remainingTime] -windows -osx -[basic_chrono] -osx diff --git a/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp b/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp index 3b10547dc4..8e0bdac520 100644 --- a/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp +++ b/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp @@ -38,6 +38,7 @@ #include <qtimer.h> #include <qthread.h> +#include <qelapsedtimer.h> #if defined Q_OS_UNIX #include <unistd.h> @@ -46,7 +47,11 @@ class tst_QTimer : public QObject { Q_OBJECT +public: + static void initMain(); + private slots: + void cleanupTestCase(); void zeroTimer(); void singleShotTimeout(); void timeout(); @@ -73,7 +78,12 @@ private slots: void recurseOnTimeoutAndStopTimer(); void singleShotToFunctors(); void singleShot_chrono(); + void singleShot_static(); void crossThreadSingleShotToFunctor(); + void timerOrder(); + void timerOrder_data(); + void timerOrderBackgroundThread(); + void timerOrderBackgroundThread_data() { timerOrder_data(); } void dontBlockEvents(); void postedEventsShouldNotStarveTimers(); @@ -521,7 +531,7 @@ public: QBasicTimer m_timer; int m_interval; - QTime m_startedTime; + QElapsedTimer m_elapsedTimer; QEventLoop eventLoop; inline RestartedTimerFiresTooSoonObject() @@ -533,7 +543,7 @@ public: static int interval = 1000; m_interval = interval; - m_startedTime.start(); + m_elapsedTimer.start(); m_timer.start(interval, this); // alternate between single-shot and 1 sec @@ -547,7 +557,7 @@ public: m_timer.stop(); - int elapsed = m_startedTime.elapsed(); + int elapsed = m_elapsedTimer.elapsed(); if (elapsed < m_interval / 2) { // severely too early! @@ -585,10 +595,10 @@ public: public slots: void longLastingSlot() { - // Don't use timers for this, because we are testing them. - QTime time; - time.start(); - while (time.elapsed() < 200) { + // Don't use QTimer for this, because we are testing it. + QElapsedTimer control; + control.start(); + while (control.elapsed() < 200) { for (int c = 0; c < 100000; c++) {} // Mindless looping. } if (++count >= 2) { @@ -768,7 +778,7 @@ public: quitEventLoop_noexcept(); } - static void quitEventLoop_noexcept() Q_DECL_NOTHROW + static void quitEventLoop_noexcept() noexcept { QVERIFY(!_e.isNull()); _e->quit(); @@ -1033,5 +1043,126 @@ void tst_QTimer::callOnTimeout() QVERIFY(!connection); } +class OrderHelper : public QObject +{ + Q_OBJECT +public: + enum CallType + { + String, + PMF, + Functor, + FunctorNoCtx + }; + Q_ENUM(CallType) + QVector<CallType> calls; + + void triggerCall(CallType callType) + { + switch (callType) + { + case String: + QTimer::singleShot(0, this, SLOT(stringSlot())); + break; + case PMF: + QTimer::singleShot(0, this, &OrderHelper::pmfSlot); + break; + case Functor: + QTimer::singleShot(0, this, [this]() { functorSlot(); }); + break; + case FunctorNoCtx: + QTimer::singleShot(0, [this]() { functorNoCtxSlot(); }); + break; + } + } + +public slots: + void stringSlot() { calls << String; } + void pmfSlot() { calls << PMF; } + void functorSlot() { calls << Functor; } + void functorNoCtxSlot() { calls << FunctorNoCtx; } +}; + +Q_DECLARE_METATYPE(OrderHelper::CallType) + +void tst_QTimer::timerOrder() +{ + QFETCH(QVector<OrderHelper::CallType>, calls); + + OrderHelper helper; + + for (const auto call : calls) + helper.triggerCall(call); + + QTRY_COMPARE(helper.calls, calls); +} + +void tst_QTimer::timerOrder_data() +{ + QTest::addColumn<QVector<OrderHelper::CallType>>("calls"); + + QVector<OrderHelper::CallType> calls = { + OrderHelper::String, OrderHelper::PMF, + OrderHelper::Functor, OrderHelper::FunctorNoCtx + }; + std::sort(calls.begin(), calls.end()); + + int permutation = 0; + do { + QTest::addRow("permutation=%d", permutation) << calls; + ++permutation; + } while (std::next_permutation(calls.begin(), calls.end())); +} + +void tst_QTimer::timerOrderBackgroundThread() +{ +#if !QT_CONFIG(cxx11_future) + QSKIP("This test requires QThread::create"); +#else + auto *thread = QThread::create([this]() { timerOrder(); }); + thread->start(); + QVERIFY(thread->wait()); + delete thread; +#endif +} + +struct StaticSingleShotUser +{ + StaticSingleShotUser() + { + for (auto call : calls()) + helper.triggerCall(call); + } + OrderHelper helper; + + static QVector<OrderHelper::CallType> calls() + { + return {OrderHelper::String, OrderHelper::PMF, + OrderHelper::Functor, OrderHelper::FunctorNoCtx}; + } +}; + +// NOTE: to prevent any static initialization order fiasco, we implement +// initMain() to instantiate staticSingleShotUser before qApp + +static StaticSingleShotUser *s_staticSingleShotUser = nullptr; + +void tst_QTimer::initMain() +{ + s_staticSingleShotUser = new StaticSingleShotUser; +} + +void tst_QTimer::cleanupTestCase() +{ + delete s_staticSingleShotUser; +} + +void tst_QTimer::singleShot_static() +{ + QCoreApplication::processEvents(); + QCOMPARE(s_staticSingleShotUser->helper.calls, s_staticSingleShotUser->calls()); +} + QTEST_MAIN(tst_QTimer) + #include "tst_qtimer.moc" diff --git a/tests/auto/corelib/kernel/qtranslator/tst_qtranslator.cpp b/tests/auto/corelib/kernel/qtranslator/tst_qtranslator.cpp index 40a29c723c..b3efa97dbd 100644 --- a/tests/auto/corelib/kernel/qtranslator/tst_qtranslator.cpp +++ b/tests/auto/corelib/kernel/qtranslator/tst_qtranslator.cpp @@ -310,7 +310,7 @@ struct TranslateThread : public QThread void run() { bool startSignalled = false; - while (terminate.load() == 0) { + while (terminate.loadRelaxed() == 0) { const QString result = QCoreApplication::translate("QPushButton", "Hello %n world(s)!", 0, 0); if (!startSignalled) { diff --git a/tests/auto/corelib/kernel/qvariant/qvariant.pro b/tests/auto/corelib/kernel/qvariant/qvariant.pro index a620be0091..0b5280df86 100644 --- a/tests/auto/corelib/kernel/qvariant/qvariant.pro +++ b/tests/auto/corelib/kernel/qvariant/qvariant.pro @@ -5,6 +5,7 @@ INCLUDEPATH += $$PWD/../../../other/qvariant_common SOURCES = tst_qvariant.cpp RESOURCES += qvariant.qrc DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 +DEFINES -= QT_NO_LINKED_LIST qtConfig(c++14): CONFIG += c++14 qtConfig(c++1z): CONFIG += c++1z !qtConfig(doubleconversion):!qtConfig(system-doubleconversion) { diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index 4da34c407e..074cb07092 100644 --- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -59,12 +59,6 @@ class CustomNonQObject; -#if defined(Q_COMPILER_CLASS_ENUM) -#define ENUM_SIZE(X) : X -#else -#define ENUM_SIZE(X) -#endif - class tst_QVariant : public QObject { Q_OBJECT @@ -82,15 +76,15 @@ public: enum MetaEnumTest_Enum1 : qint64 { MetaEnumTest_Enum1_value = 42, MetaEnumTest_Enum1_bigValue = (Q_INT64_C(1) << 33) + 50 }; Q_ENUM(MetaEnumTest_Enum1) - enum MetaEnumTest_Enum3 ENUM_SIZE(qint64) { MetaEnumTest_Enum3_value = -47, MetaEnumTest_Enum3_bigValue = (Q_INT64_C(1) << 56) + 5, MetaEnumTest_Enum3_bigNegValue = -(Q_INT64_C(1) << 56) - 3 }; + enum MetaEnumTest_Enum3 : qint64 { MetaEnumTest_Enum3_value = -47, MetaEnumTest_Enum3_bigValue = (Q_INT64_C(1) << 56) + 5, MetaEnumTest_Enum3_bigNegValue = -(Q_INT64_C(1) << 56) - 3 }; Q_ENUM(MetaEnumTest_Enum3) - enum MetaEnumTest_Enum4 ENUM_SIZE(quint64) { MetaEnumTest_Enum4_value = 47, MetaEnumTest_Enum4_bigValue = (Q_INT64_C(1) << 52) + 45 }; + enum MetaEnumTest_Enum4 : quint64 { MetaEnumTest_Enum4_value = 47, MetaEnumTest_Enum4_bigValue = (Q_INT64_C(1) << 52) + 45 }; Q_ENUM(MetaEnumTest_Enum4) - enum MetaEnumTest_Enum5 ENUM_SIZE(uint) { MetaEnumTest_Enum5_value = 47 }; + enum MetaEnumTest_Enum5 : uint { MetaEnumTest_Enum5_value = 47 }; Q_ENUM(MetaEnumTest_Enum5) - enum MetaEnumTest_Enum6 ENUM_SIZE(uchar) { MetaEnumTest_Enum6_value = 47 }; + enum MetaEnumTest_Enum6 : uchar { MetaEnumTest_Enum6_value = 47 }; Q_ENUM(MetaEnumTest_Enum6) - enum MetaEnumTest_Enum8 ENUM_SIZE(short) { MetaEnumTest_Enum8_value = 47 }; + enum MetaEnumTest_Enum8 : short { MetaEnumTest_Enum8_value = 47 }; Q_ENUM(MetaEnumTest_Enum8) private slots: @@ -385,9 +379,13 @@ void tst_QVariant::isNull() QString str1; QVariant var1( str1 ); QVERIFY( var1.isNull() ); - +#if QT_DEPRECATED_SINCE(5, 9) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED QVariant var2( QString::null ); +QT_WARNING_POP QVERIFY( var2.isNull() ); +#endif QVariant var3( QString( "blah" ) ); QVERIFY( !var3.isNull() ); @@ -406,10 +404,19 @@ void tst_QVariant::isNull() QVERIFY( var6.isNull() ); QVariant varLL( (qlonglong)0 ); QVERIFY( !varLL.isNull() ); + +#if QT_DEPRECATED_SINCE(5, 9) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED QVariant var7(QString::null); +QT_WARNING_POP QVERIFY(var7.isNull()); +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED var7 = QVariant::fromValue<QString>(QString::null); +QT_WARNING_POP QVERIFY(var7.isNull()); +#endif QVariant var8(QMetaType::Nullptr, nullptr); QVERIFY(var8.isNull()); @@ -431,6 +438,9 @@ void tst_QVariant::isNull() QVERIFY(var11.isNull()); QVERIFY(QVariant::fromValue<int*>(nullptr).isNull()); + + QVariant var12(QVariant::fromValue<QString>(QString())); + QVERIFY(var12.isNull()); } void tst_QVariant::swap() @@ -1728,281 +1738,281 @@ void tst_QVariant::compareNumbers_data() const QTest::newRow("bool3") << QVariant(false) << QVariant(true) << -1; QTest::newRow("bool4") << QVariant(true) << QVariant(false) << +1; - QTest::newRow("char1") << qVariantFromValue(char(0)) << qVariantFromValue(char(0)) << 0; - QTest::newRow("char2") << qVariantFromValue(CHAR_MAX) << qVariantFromValue(CHAR_MAX) << 0; - QTest::newRow("char3") << qVariantFromValue(CHAR_MIN) << qVariantFromValue(CHAR_MIN) << 0; - QTest::newRow("char4") << qVariantFromValue(CHAR_MIN) << qVariantFromValue(CHAR_MAX) << -1; - QTest::newRow("char5") << qVariantFromValue(CHAR_MAX) << qVariantFromValue(CHAR_MIN) << +1; - - QTest::newRow("schar1") << qVariantFromValue(schar(0)) << qVariantFromValue(schar(0)) << 0; - QTest::newRow("schar2") << qVariantFromValue(SCHAR_MAX) << qVariantFromValue(SCHAR_MAX) << 0; - QTest::newRow("schar3") << qVariantFromValue(SCHAR_MIN) << qVariantFromValue(SCHAR_MIN) << 0; - QTest::newRow("schar4") << qVariantFromValue(SCHAR_MIN) << qVariantFromValue(SCHAR_MAX) << -1; - QTest::newRow("schar5") << qVariantFromValue(SCHAR_MAX) << qVariantFromValue(SCHAR_MIN) << +1; - - QTest::newRow("uchar1") << qVariantFromValue(uchar(0)) << qVariantFromValue(uchar(0)) << 0; - QTest::newRow("uchar2") << qVariantFromValue(UCHAR_MAX) << qVariantFromValue(UCHAR_MAX) << 0; - QTest::newRow("uchar3") << qVariantFromValue(uchar(0)) << qVariantFromValue(UCHAR_MAX) << -1; - QTest::newRow("uchar4") << qVariantFromValue(UCHAR_MAX) << qVariantFromValue(uchar(0)) << +1; - - QTest::newRow("short1") << qVariantFromValue(short(0)) << qVariantFromValue(short(0)) << 0; - QTest::newRow("short2") << qVariantFromValue(SHRT_MAX) << qVariantFromValue(SHRT_MAX) << 0; - QTest::newRow("short3") << qVariantFromValue(SHRT_MIN) << qVariantFromValue(SHRT_MIN) << 0; - QTest::newRow("short4") << qVariantFromValue(SHRT_MIN) << qVariantFromValue(SHRT_MAX) << -1; - QTest::newRow("short5") << qVariantFromValue(SHRT_MAX) << qVariantFromValue(SHRT_MIN) << +1; - - QTest::newRow("ushort1") << qVariantFromValue(ushort(0)) << qVariantFromValue(ushort(0)) << 0; - QTest::newRow("ushort2") << qVariantFromValue(USHRT_MAX) << qVariantFromValue(USHRT_MAX) << 0; - QTest::newRow("ushort3") << qVariantFromValue(ushort(0)) << qVariantFromValue(USHRT_MAX) << -1; - QTest::newRow("ushort4") << qVariantFromValue(USHRT_MAX) << qVariantFromValue(ushort(0)) << +1; - - QTest::newRow("int1") << qVariantFromValue(int(0)) << qVariantFromValue(int(0)) << 0; - QTest::newRow("int2") << qVariantFromValue(INT_MAX) << qVariantFromValue(INT_MAX) << 0; - QTest::newRow("int3") << qVariantFromValue(INT_MIN) << qVariantFromValue(INT_MIN) << 0; - QTest::newRow("int4") << qVariantFromValue(INT_MIN) << qVariantFromValue(INT_MAX) << -1; - QTest::newRow("int5") << qVariantFromValue(INT_MAX) << qVariantFromValue(INT_MIN) << +1; - - QTest::newRow("uint1") << qVariantFromValue(uint(0)) << qVariantFromValue(uint(0)) << 0; - QTest::newRow("uint2") << qVariantFromValue(UINT_MAX) << qVariantFromValue(UINT_MAX) << 0; - QTest::newRow("uint3") << qVariantFromValue(uint(0)) << qVariantFromValue(UINT_MAX) << -1; - QTest::newRow("uint4") << qVariantFromValue(UINT_MAX) << qVariantFromValue(uint(0)) << +1; - - QTest::newRow("long1") << qVariantFromValue(long(0)) << qVariantFromValue(long(0)) << 0; - QTest::newRow("long2") << qVariantFromValue(LONG_MAX) << qVariantFromValue(LONG_MAX) << 0; - QTest::newRow("long3") << qVariantFromValue(LONG_MIN) << qVariantFromValue(LONG_MIN) << 0; - QTest::newRow("long4") << qVariantFromValue(LONG_MIN) << qVariantFromValue(LONG_MAX) << -1; - QTest::newRow("long5") << qVariantFromValue(LONG_MAX) << qVariantFromValue(LONG_MIN) << +1; - - QTest::newRow("ulong1") << qVariantFromValue(ulong(0)) << qVariantFromValue(ulong(0)) << 0; - QTest::newRow("ulong2") << qVariantFromValue(ULONG_MAX) << qVariantFromValue(ULONG_MAX) << 0; - QTest::newRow("ulong3") << qVariantFromValue(ulong(0)) << qVariantFromValue(ULONG_MAX) << -1; - QTest::newRow("ulong4") << qVariantFromValue(ULONG_MAX) << qVariantFromValue(ulong(0)) << +1; - - QTest::newRow("llong1") << qVariantFromValue(qlonglong(0)) << qVariantFromValue(qlonglong(0)) << 0; - QTest::newRow("llong2") << qVariantFromValue(LLONG_MAX) << qVariantFromValue(LLONG_MAX) << 0; - QTest::newRow("llong3") << qVariantFromValue(LLONG_MIN) << qVariantFromValue(LLONG_MIN) << 0; - QTest::newRow("llong4") << qVariantFromValue(LLONG_MIN) << qVariantFromValue(LLONG_MAX) << -1; - QTest::newRow("llong5") << qVariantFromValue(LLONG_MAX) << qVariantFromValue(LLONG_MIN) << +1; - - QTest::newRow("ullong1") << qVariantFromValue(qulonglong(0)) << qVariantFromValue(qulonglong(0)) << 0; - QTest::newRow("ullong2") << qVariantFromValue(ULLONG_MAX) << qVariantFromValue(ULLONG_MAX) << 0; - QTest::newRow("ullong3") << qVariantFromValue(qulonglong(0)) << qVariantFromValue(ULLONG_MAX) << -1; - QTest::newRow("ullong4") << qVariantFromValue(ULLONG_MAX) << qVariantFromValue(qulonglong(0)) << +1; - - QTest::newRow("float1") << qVariantFromValue(0.f) << qVariantFromValue(0.f) << 0; - QTest::newRow("float2") << qVariantFromValue(-1.f) << qVariantFromValue(0.f) << -1; - QTest::newRow("float3") << qVariantFromValue(0.f) << qVariantFromValue(-1.f) << +1; - QTest::newRow("float4") << qVariantFromValue(-float(qInf())) << qVariantFromValue(0.f) << -1; - QTest::newRow("float5") << qVariantFromValue(0.f) << qVariantFromValue(-float(qInf())) << +1; - QTest::newRow("float6") << qVariantFromValue(-float(qInf())) << qVariantFromValue(-float(qInf())) << 0; - QTest::newRow("float7") << qVariantFromValue(float(qInf())) << qVariantFromValue(float(qInf())) << 0; - - QTest::newRow("double1") << qVariantFromValue(0.) << qVariantFromValue(0.) << 0; - QTest::newRow("double2") << qVariantFromValue(-1.) << qVariantFromValue(0.) << -1; - QTest::newRow("double3") << qVariantFromValue(0.) << qVariantFromValue(-1.) << +1; - QTest::newRow("double4") << qVariantFromValue(-qInf()) << qVariantFromValue(0.) << -1; - QTest::newRow("double5") << qVariantFromValue(0.) << qVariantFromValue(-qInf()) << +1; - QTest::newRow("double6") << qVariantFromValue(-double(qInf())) << qVariantFromValue(-qInf()) << 0; - QTest::newRow("double7") << qVariantFromValue(qInf()) << qVariantFromValue(qInf()) << 0; - QTest::newRow("double8") << qVariantFromValue(-qInf()) << qVariantFromValue(qInf()) << -1; - QTest::newRow("double9") << qVariantFromValue(qQNaN()) << qVariantFromValue(0.) << INT_MAX; - QTest::newRow("double10") << qVariantFromValue(0.) << qVariantFromValue(qQNaN()) << INT_MAX; - QTest::newRow("double11") << qVariantFromValue(qQNaN()) << qVariantFromValue(qQNaN()) << INT_MAX; + QTest::newRow("char1") << QVariant::fromValue(char(0)) << QVariant::fromValue(char(0)) << 0; + QTest::newRow("char2") << QVariant::fromValue(CHAR_MAX) << QVariant::fromValue(CHAR_MAX) << 0; + QTest::newRow("char3") << QVariant::fromValue(CHAR_MIN) << QVariant::fromValue(CHAR_MIN) << 0; + QTest::newRow("char4") << QVariant::fromValue(CHAR_MIN) << QVariant::fromValue(CHAR_MAX) << -1; + QTest::newRow("char5") << QVariant::fromValue(CHAR_MAX) << QVariant::fromValue(CHAR_MIN) << +1; + + QTest::newRow("schar1") << QVariant::fromValue(schar(0)) << QVariant::fromValue(schar(0)) << 0; + QTest::newRow("schar2") << QVariant::fromValue(SCHAR_MAX) << QVariant::fromValue(SCHAR_MAX) << 0; + QTest::newRow("schar3") << QVariant::fromValue(SCHAR_MIN) << QVariant::fromValue(SCHAR_MIN) << 0; + QTest::newRow("schar4") << QVariant::fromValue(SCHAR_MIN) << QVariant::fromValue(SCHAR_MAX) << -1; + QTest::newRow("schar5") << QVariant::fromValue(SCHAR_MAX) << QVariant::fromValue(SCHAR_MIN) << +1; + + QTest::newRow("uchar1") << QVariant::fromValue(uchar(0)) << QVariant::fromValue(uchar(0)) << 0; + QTest::newRow("uchar2") << QVariant::fromValue(UCHAR_MAX) << QVariant::fromValue(UCHAR_MAX) << 0; + QTest::newRow("uchar3") << QVariant::fromValue(uchar(0)) << QVariant::fromValue(UCHAR_MAX) << -1; + QTest::newRow("uchar4") << QVariant::fromValue(UCHAR_MAX) << QVariant::fromValue(uchar(0)) << +1; + + QTest::newRow("short1") << QVariant::fromValue(short(0)) << QVariant::fromValue(short(0)) << 0; + QTest::newRow("short2") << QVariant::fromValue(SHRT_MAX) << QVariant::fromValue(SHRT_MAX) << 0; + QTest::newRow("short3") << QVariant::fromValue(SHRT_MIN) << QVariant::fromValue(SHRT_MIN) << 0; + QTest::newRow("short4") << QVariant::fromValue(SHRT_MIN) << QVariant::fromValue(SHRT_MAX) << -1; + QTest::newRow("short5") << QVariant::fromValue(SHRT_MAX) << QVariant::fromValue(SHRT_MIN) << +1; + + QTest::newRow("ushort1") << QVariant::fromValue(ushort(0)) << QVariant::fromValue(ushort(0)) << 0; + QTest::newRow("ushort2") << QVariant::fromValue(USHRT_MAX) << QVariant::fromValue(USHRT_MAX) << 0; + QTest::newRow("ushort3") << QVariant::fromValue(ushort(0)) << QVariant::fromValue(USHRT_MAX) << -1; + QTest::newRow("ushort4") << QVariant::fromValue(USHRT_MAX) << QVariant::fromValue(ushort(0)) << +1; + + QTest::newRow("int1") << QVariant::fromValue(int(0)) << QVariant::fromValue(int(0)) << 0; + QTest::newRow("int2") << QVariant::fromValue(INT_MAX) << QVariant::fromValue(INT_MAX) << 0; + QTest::newRow("int3") << QVariant::fromValue(INT_MIN) << QVariant::fromValue(INT_MIN) << 0; + QTest::newRow("int4") << QVariant::fromValue(INT_MIN) << QVariant::fromValue(INT_MAX) << -1; + QTest::newRow("int5") << QVariant::fromValue(INT_MAX) << QVariant::fromValue(INT_MIN) << +1; + + QTest::newRow("uint1") << QVariant::fromValue(uint(0)) << QVariant::fromValue(uint(0)) << 0; + QTest::newRow("uint2") << QVariant::fromValue(UINT_MAX) << QVariant::fromValue(UINT_MAX) << 0; + QTest::newRow("uint3") << QVariant::fromValue(uint(0)) << QVariant::fromValue(UINT_MAX) << -1; + QTest::newRow("uint4") << QVariant::fromValue(UINT_MAX) << QVariant::fromValue(uint(0)) << +1; + + QTest::newRow("long1") << QVariant::fromValue(long(0)) << QVariant::fromValue(long(0)) << 0; + QTest::newRow("long2") << QVariant::fromValue(LONG_MAX) << QVariant::fromValue(LONG_MAX) << 0; + QTest::newRow("long3") << QVariant::fromValue(LONG_MIN) << QVariant::fromValue(LONG_MIN) << 0; + QTest::newRow("long4") << QVariant::fromValue(LONG_MIN) << QVariant::fromValue(LONG_MAX) << -1; + QTest::newRow("long5") << QVariant::fromValue(LONG_MAX) << QVariant::fromValue(LONG_MIN) << +1; + + QTest::newRow("ulong1") << QVariant::fromValue(ulong(0)) << QVariant::fromValue(ulong(0)) << 0; + QTest::newRow("ulong2") << QVariant::fromValue(ULONG_MAX) << QVariant::fromValue(ULONG_MAX) << 0; + QTest::newRow("ulong3") << QVariant::fromValue(ulong(0)) << QVariant::fromValue(ULONG_MAX) << -1; + QTest::newRow("ulong4") << QVariant::fromValue(ULONG_MAX) << QVariant::fromValue(ulong(0)) << +1; + + QTest::newRow("llong1") << QVariant::fromValue(qlonglong(0)) << QVariant::fromValue(qlonglong(0)) << 0; + QTest::newRow("llong2") << QVariant::fromValue(LLONG_MAX) << QVariant::fromValue(LLONG_MAX) << 0; + QTest::newRow("llong3") << QVariant::fromValue(LLONG_MIN) << QVariant::fromValue(LLONG_MIN) << 0; + QTest::newRow("llong4") << QVariant::fromValue(LLONG_MIN) << QVariant::fromValue(LLONG_MAX) << -1; + QTest::newRow("llong5") << QVariant::fromValue(LLONG_MAX) << QVariant::fromValue(LLONG_MIN) << +1; + + QTest::newRow("ullong1") << QVariant::fromValue(qulonglong(0)) << QVariant::fromValue(qulonglong(0)) << 0; + QTest::newRow("ullong2") << QVariant::fromValue(ULLONG_MAX) << QVariant::fromValue(ULLONG_MAX) << 0; + QTest::newRow("ullong3") << QVariant::fromValue(qulonglong(0)) << QVariant::fromValue(ULLONG_MAX) << -1; + QTest::newRow("ullong4") << QVariant::fromValue(ULLONG_MAX) << QVariant::fromValue(qulonglong(0)) << +1; + + QTest::newRow("float1") << QVariant::fromValue(0.f) << QVariant::fromValue(0.f) << 0; + QTest::newRow("float2") << QVariant::fromValue(-1.f) << QVariant::fromValue(0.f) << -1; + QTest::newRow("float3") << QVariant::fromValue(0.f) << QVariant::fromValue(-1.f) << +1; + QTest::newRow("float4") << QVariant::fromValue(-float(qInf())) << QVariant::fromValue(0.f) << -1; + QTest::newRow("float5") << QVariant::fromValue(0.f) << QVariant::fromValue(-float(qInf())) << +1; + QTest::newRow("float6") << QVariant::fromValue(-float(qInf())) << QVariant::fromValue(-float(qInf())) << 0; + QTest::newRow("float7") << QVariant::fromValue(float(qInf())) << QVariant::fromValue(float(qInf())) << 0; + + QTest::newRow("double1") << QVariant::fromValue(0.) << QVariant::fromValue(0.) << 0; + QTest::newRow("double2") << QVariant::fromValue(-1.) << QVariant::fromValue(0.) << -1; + QTest::newRow("double3") << QVariant::fromValue(0.) << QVariant::fromValue(-1.) << +1; + QTest::newRow("double4") << QVariant::fromValue(-qInf()) << QVariant::fromValue(0.) << -1; + QTest::newRow("double5") << QVariant::fromValue(0.) << QVariant::fromValue(-qInf()) << +1; + QTest::newRow("double6") << QVariant::fromValue(-double(qInf())) << QVariant::fromValue(-qInf()) << 0; + QTest::newRow("double7") << QVariant::fromValue(qInf()) << QVariant::fromValue(qInf()) << 0; + QTest::newRow("double8") << QVariant::fromValue(-qInf()) << QVariant::fromValue(qInf()) << -1; + QTest::newRow("double9") << QVariant::fromValue(qQNaN()) << QVariant::fromValue(0.) << INT_MAX; + QTest::newRow("double10") << QVariant::fromValue(0.) << QVariant::fromValue(qQNaN()) << INT_MAX; + QTest::newRow("double11") << QVariant::fromValue(qQNaN()) << QVariant::fromValue(qQNaN()) << INT_MAX; // mixed comparisons // fp + fp - QTest::newRow("float+double1") << qVariantFromValue(0.f) << qVariantFromValue(0.) << 0; - QTest::newRow("float+double2") << qVariantFromValue(-1.f) << qVariantFromValue(0.) << -1; - QTest::newRow("float+double3") << qVariantFromValue(0.f) << qVariantFromValue(-1.) << +1; - QTest::newRow("float+double4") << qVariantFromValue(-float(qInf())) << qVariantFromValue(0.) << -1; - QTest::newRow("float+double5") << qVariantFromValue(0.f) << qVariantFromValue(-qInf()) << +1; - QTest::newRow("float+double6") << qVariantFromValue(-float(qInf())) << qVariantFromValue(-qInf()) << 0; - QTest::newRow("float+double7") << qVariantFromValue(float(qInf())) << qVariantFromValue(qInf()) << 0; - QTest::newRow("float+double8") << qVariantFromValue(-float(qInf())) << qVariantFromValue(qInf()) << -1; - QTest::newRow("float+double9") << qVariantFromValue(qQNaN()) << qVariantFromValue(0.) << INT_MAX; - QTest::newRow("float+double10") << qVariantFromValue(0.) << qVariantFromValue(qQNaN()) << INT_MAX; - QTest::newRow("float+double11") << qVariantFromValue(qQNaN()) << qVariantFromValue(qQNaN()) << INT_MAX; + QTest::newRow("float+double1") << QVariant::fromValue(0.f) << QVariant::fromValue(0.) << 0; + QTest::newRow("float+double2") << QVariant::fromValue(-1.f) << QVariant::fromValue(0.) << -1; + QTest::newRow("float+double3") << QVariant::fromValue(0.f) << QVariant::fromValue(-1.) << +1; + QTest::newRow("float+double4") << QVariant::fromValue(-float(qInf())) << QVariant::fromValue(0.) << -1; + QTest::newRow("float+double5") << QVariant::fromValue(0.f) << QVariant::fromValue(-qInf()) << +1; + QTest::newRow("float+double6") << QVariant::fromValue(-float(qInf())) << QVariant::fromValue(-qInf()) << 0; + QTest::newRow("float+double7") << QVariant::fromValue(float(qInf())) << QVariant::fromValue(qInf()) << 0; + QTest::newRow("float+double8") << QVariant::fromValue(-float(qInf())) << QVariant::fromValue(qInf()) << -1; + QTest::newRow("float+double9") << QVariant::fromValue(qQNaN()) << QVariant::fromValue(0.) << INT_MAX; + QTest::newRow("float+double10") << QVariant::fromValue(0.) << QVariant::fromValue(qQNaN()) << INT_MAX; + QTest::newRow("float+double11") << QVariant::fromValue(qQNaN()) << QVariant::fromValue(qQNaN()) << INT_MAX; // fp + int - QTest::newRow("float+int1") << qVariantFromValue(0.f) << qVariantFromValue(0) << 0; - QTest::newRow("double+int1") << qVariantFromValue(0.) << qVariantFromValue(0) << 0; - QTest::newRow("float+int2") << qVariantFromValue(-1.f) << qVariantFromValue(0) << -1; - QTest::newRow("double+int2") << qVariantFromValue(-1.) << qVariantFromValue(0) << -1; - QTest::newRow("float+int3") << qVariantFromValue(0.f) << qVariantFromValue(-1) << +1; - QTest::newRow("double+int3") << qVariantFromValue(0.) << qVariantFromValue(-1) << +1; - QTest::newRow("float+int4") << qVariantFromValue(1.5f) << qVariantFromValue(1) << +1; - QTest::newRow("double+int4") << qVariantFromValue(1.5) << qVariantFromValue(1) << +1; - QTest::newRow("double+int5") << qVariantFromValue(qInf()) << qVariantFromValue(1) << +1; + QTest::newRow("float+int1") << QVariant::fromValue(0.f) << QVariant::fromValue(0) << 0; + QTest::newRow("double+int1") << QVariant::fromValue(0.) << QVariant::fromValue(0) << 0; + QTest::newRow("float+int2") << QVariant::fromValue(-1.f) << QVariant::fromValue(0) << -1; + QTest::newRow("double+int2") << QVariant::fromValue(-1.) << QVariant::fromValue(0) << -1; + QTest::newRow("float+int3") << QVariant::fromValue(0.f) << QVariant::fromValue(-1) << +1; + QTest::newRow("double+int3") << QVariant::fromValue(0.) << QVariant::fromValue(-1) << +1; + QTest::newRow("float+int4") << QVariant::fromValue(1.5f) << QVariant::fromValue(1) << +1; + QTest::newRow("double+int4") << QVariant::fromValue(1.5) << QVariant::fromValue(1) << +1; + QTest::newRow("double+int5") << QVariant::fromValue(qInf()) << QVariant::fromValue(1) << +1; // fp + uint - QTest::newRow("float+uint1") << qVariantFromValue(0.f) << qVariantFromValue(0U) << 0; - QTest::newRow("double+uint1") << qVariantFromValue(0.) << qVariantFromValue(0U) << 0; - QTest::newRow("float+uint2") << qVariantFromValue(-1.f) << qVariantFromValue(0U) << -1; - QTest::newRow("double+uint2") << qVariantFromValue(-1.) << qVariantFromValue(0U) << -1; - QTest::newRow("float+uint3") << qVariantFromValue(0.f) << qVariantFromValue(1U) << -1; - QTest::newRow("double+uint3") << qVariantFromValue(0.) << qVariantFromValue(1U) << -1; - QTest::newRow("float+uint4") << qVariantFromValue(1.5f) << qVariantFromValue(1U) << +1; - QTest::newRow("double+uint4") << qVariantFromValue(1.5) << qVariantFromValue(1U) << +1; + QTest::newRow("float+uint1") << QVariant::fromValue(0.f) << QVariant::fromValue(0U) << 0; + QTest::newRow("double+uint1") << QVariant::fromValue(0.) << QVariant::fromValue(0U) << 0; + QTest::newRow("float+uint2") << QVariant::fromValue(-1.f) << QVariant::fromValue(0U) << -1; + QTest::newRow("double+uint2") << QVariant::fromValue(-1.) << QVariant::fromValue(0U) << -1; + QTest::newRow("float+uint3") << QVariant::fromValue(0.f) << QVariant::fromValue(1U) << -1; + QTest::newRow("double+uint3") << QVariant::fromValue(0.) << QVariant::fromValue(1U) << -1; + QTest::newRow("float+uint4") << QVariant::fromValue(1.5f) << QVariant::fromValue(1U) << +1; + QTest::newRow("double+uint4") << QVariant::fromValue(1.5) << QVariant::fromValue(1U) << +1; // lower ranked + int - QTest::newRow("bool+int1") << qVariantFromValue(false) << qVariantFromValue(0) << 0; - QTest::newRow("bool+int2") << qVariantFromValue(false) << qVariantFromValue(1) << -1; - QTest::newRow("bool+int3") << qVariantFromValue(true) << qVariantFromValue(0) << +1; - QTest::newRow("bool+int4") << qVariantFromValue(true) << qVariantFromValue(1) << 0; - QTest::newRow("bool+int5") << qVariantFromValue(true) << qVariantFromValue(2) << -1; - - QTest::newRow("char+int1") << qVariantFromValue(char(0)) << qVariantFromValue(0) << 0; - QTest::newRow("char+int2") << qVariantFromValue(char(0)) << qVariantFromValue(1) << -1; - QTest::newRow("char+int3") << qVariantFromValue(char(1)) << qVariantFromValue(0) << +1; - QTest::newRow("char+int4") << qVariantFromValue(char(1)) << qVariantFromValue(1) << 0; + QTest::newRow("bool+int1") << QVariant::fromValue(false) << QVariant::fromValue(0) << 0; + QTest::newRow("bool+int2") << QVariant::fromValue(false) << QVariant::fromValue(1) << -1; + QTest::newRow("bool+int3") << QVariant::fromValue(true) << QVariant::fromValue(0) << +1; + QTest::newRow("bool+int4") << QVariant::fromValue(true) << QVariant::fromValue(1) << 0; + QTest::newRow("bool+int5") << QVariant::fromValue(true) << QVariant::fromValue(2) << -1; + + QTest::newRow("char+int1") << QVariant::fromValue(char(0)) << QVariant::fromValue(0) << 0; + QTest::newRow("char+int2") << QVariant::fromValue(char(0)) << QVariant::fromValue(1) << -1; + QTest::newRow("char+int3") << QVariant::fromValue(char(1)) << QVariant::fromValue(0) << +1; + QTest::newRow("char+int4") << QVariant::fromValue(char(1)) << QVariant::fromValue(1) << 0; if (std::numeric_limits<char>::is_signed) { - QTest::newRow("char+int5") << qVariantFromValue(char(-1)) << qVariantFromValue(0) << -1; - QTest::newRow("char+int6") << qVariantFromValue(char(-1)) << qVariantFromValue(-1) << 0; - } - - QTest::newRow("schar+int1") << qVariantFromValue(schar(0)) << qVariantFromValue(0) << 0; - QTest::newRow("schar+int2") << qVariantFromValue(schar(0)) << qVariantFromValue(1) << -1; - QTest::newRow("schar+int3") << qVariantFromValue(schar(1)) << qVariantFromValue(0) << +1; - QTest::newRow("schar+int4") << qVariantFromValue(schar(1)) << qVariantFromValue(1) << 0; - QTest::newRow("schar+int5") << qVariantFromValue(schar(-1)) << qVariantFromValue(0) << -1; - QTest::newRow("schar+int6") << qVariantFromValue(schar(-1)) << qVariantFromValue(-1) << 0; - - QTest::newRow("uchar+int1") << qVariantFromValue(uchar(0)) << qVariantFromValue(0) << 0; - QTest::newRow("uchar+int2") << qVariantFromValue(uchar(0)) << qVariantFromValue(1) << -1; - QTest::newRow("uchar+int3") << qVariantFromValue(uchar(1)) << qVariantFromValue(0) << +1; - QTest::newRow("uchar+int4") << qVariantFromValue(uchar(1)) << qVariantFromValue(1) << 0; - - QTest::newRow("short+int1") << qVariantFromValue(short(0)) << qVariantFromValue(0) << 0; - QTest::newRow("short+int2") << qVariantFromValue(short(0)) << qVariantFromValue(1) << -1; - QTest::newRow("short+int3") << qVariantFromValue(short(1)) << qVariantFromValue(0) << +1; - QTest::newRow("short+int4") << qVariantFromValue(short(1)) << qVariantFromValue(1) << 0; - QTest::newRow("short+int5") << qVariantFromValue(short(-1)) << qVariantFromValue(0) << -1; - QTest::newRow("short+int6") << qVariantFromValue(short(-1)) << qVariantFromValue(-1) << 0; - - QTest::newRow("ushort+int1") << qVariantFromValue(ushort(0)) << qVariantFromValue(0) << 0; - QTest::newRow("ushort+int2") << qVariantFromValue(ushort(0)) << qVariantFromValue(1) << -1; - QTest::newRow("ushort+int3") << qVariantFromValue(ushort(1)) << qVariantFromValue(0) << +1; - QTest::newRow("ushort+int4") << qVariantFromValue(ushort(1)) << qVariantFromValue(1) << 0; + QTest::newRow("char+int5") << QVariant::fromValue(char(-1)) << QVariant::fromValue(0) << -1; + QTest::newRow("char+int6") << QVariant::fromValue(char(-1)) << QVariant::fromValue(-1) << 0; + } + + QTest::newRow("schar+int1") << QVariant::fromValue(schar(0)) << QVariant::fromValue(0) << 0; + QTest::newRow("schar+int2") << QVariant::fromValue(schar(0)) << QVariant::fromValue(1) << -1; + QTest::newRow("schar+int3") << QVariant::fromValue(schar(1)) << QVariant::fromValue(0) << +1; + QTest::newRow("schar+int4") << QVariant::fromValue(schar(1)) << QVariant::fromValue(1) << 0; + QTest::newRow("schar+int5") << QVariant::fromValue(schar(-1)) << QVariant::fromValue(0) << -1; + QTest::newRow("schar+int6") << QVariant::fromValue(schar(-1)) << QVariant::fromValue(-1) << 0; + + QTest::newRow("uchar+int1") << QVariant::fromValue(uchar(0)) << QVariant::fromValue(0) << 0; + QTest::newRow("uchar+int2") << QVariant::fromValue(uchar(0)) << QVariant::fromValue(1) << -1; + QTest::newRow("uchar+int3") << QVariant::fromValue(uchar(1)) << QVariant::fromValue(0) << +1; + QTest::newRow("uchar+int4") << QVariant::fromValue(uchar(1)) << QVariant::fromValue(1) << 0; + + QTest::newRow("short+int1") << QVariant::fromValue(short(0)) << QVariant::fromValue(0) << 0; + QTest::newRow("short+int2") << QVariant::fromValue(short(0)) << QVariant::fromValue(1) << -1; + QTest::newRow("short+int3") << QVariant::fromValue(short(1)) << QVariant::fromValue(0) << +1; + QTest::newRow("short+int4") << QVariant::fromValue(short(1)) << QVariant::fromValue(1) << 0; + QTest::newRow("short+int5") << QVariant::fromValue(short(-1)) << QVariant::fromValue(0) << -1; + QTest::newRow("short+int6") << QVariant::fromValue(short(-1)) << QVariant::fromValue(-1) << 0; + + QTest::newRow("ushort+int1") << QVariant::fromValue(ushort(0)) << QVariant::fromValue(0) << 0; + QTest::newRow("ushort+int2") << QVariant::fromValue(ushort(0)) << QVariant::fromValue(1) << -1; + QTest::newRow("ushort+int3") << QVariant::fromValue(ushort(1)) << QVariant::fromValue(0) << +1; + QTest::newRow("ushort+int4") << QVariant::fromValue(ushort(1)) << QVariant::fromValue(1) << 0; // lower ranked + uint (without sign change) - QTest::newRow("bool+uint1") << qVariantFromValue(false) << qVariantFromValue(0U) << 0; - QTest::newRow("bool+uint2") << qVariantFromValue(false) << qVariantFromValue(1U) << -1; - QTest::newRow("bool+uint3") << qVariantFromValue(true) << qVariantFromValue(0U) << +1; - QTest::newRow("bool+uint4") << qVariantFromValue(true) << qVariantFromValue(1U) << 0; - QTest::newRow("bool+uint5") << qVariantFromValue(true) << qVariantFromValue(2U) << -1; - - QTest::newRow("char+uint1") << qVariantFromValue(char(0)) << qVariantFromValue(0U) << 0; - QTest::newRow("char+uint2") << qVariantFromValue(char(0)) << qVariantFromValue(1U) << -1; - QTest::newRow("char+uint3") << qVariantFromValue(char(1)) << qVariantFromValue(0U) << +1; - QTest::newRow("char+uint4") << qVariantFromValue(char(1)) << qVariantFromValue(1U) << 0; - - QTest::newRow("schar+uint1") << qVariantFromValue(schar(0)) << qVariantFromValue(0U) << 0; - QTest::newRow("schar+uint2") << qVariantFromValue(schar(0)) << qVariantFromValue(1U) << -1; - QTest::newRow("schar+uint3") << qVariantFromValue(schar(1)) << qVariantFromValue(0U) << +1; - QTest::newRow("schar+uint4") << qVariantFromValue(schar(1)) << qVariantFromValue(1U) << 0; - - QTest::newRow("uchar+uint1") << qVariantFromValue(uchar(0)) << qVariantFromValue(0U) << 0; - QTest::newRow("uchar+uint2") << qVariantFromValue(uchar(0)) << qVariantFromValue(1U) << -1; - QTest::newRow("uchar+uint3") << qVariantFromValue(uchar(1)) << qVariantFromValue(0U) << +1; - QTest::newRow("uchar+uint4") << qVariantFromValue(uchar(1)) << qVariantFromValue(1U) << 0; - - QTest::newRow("short+uint1") << qVariantFromValue(short(0)) << qVariantFromValue(0U) << 0; - QTest::newRow("short+uint2") << qVariantFromValue(short(0)) << qVariantFromValue(1U) << -1; - QTest::newRow("short+uint3") << qVariantFromValue(short(1)) << qVariantFromValue(0U) << +1; - QTest::newRow("short+uint4") << qVariantFromValue(short(1)) << qVariantFromValue(1U) << 0; - - QTest::newRow("ushort+uint1") << qVariantFromValue(ushort(0)) << qVariantFromValue(0U) << 0; - QTest::newRow("ushort+uint2") << qVariantFromValue(ushort(0)) << qVariantFromValue(1U) << -1; - QTest::newRow("ushort+uint3") << qVariantFromValue(ushort(1)) << qVariantFromValue(0U) << +1; - QTest::newRow("ushort+uint4") << qVariantFromValue(ushort(1)) << qVariantFromValue(1U) << 0; + QTest::newRow("bool+uint1") << QVariant::fromValue(false) << QVariant::fromValue(0U) << 0; + QTest::newRow("bool+uint2") << QVariant::fromValue(false) << QVariant::fromValue(1U) << -1; + QTest::newRow("bool+uint3") << QVariant::fromValue(true) << QVariant::fromValue(0U) << +1; + QTest::newRow("bool+uint4") << QVariant::fromValue(true) << QVariant::fromValue(1U) << 0; + QTest::newRow("bool+uint5") << QVariant::fromValue(true) << QVariant::fromValue(2U) << -1; + + QTest::newRow("char+uint1") << QVariant::fromValue(char(0)) << QVariant::fromValue(0U) << 0; + QTest::newRow("char+uint2") << QVariant::fromValue(char(0)) << QVariant::fromValue(1U) << -1; + QTest::newRow("char+uint3") << QVariant::fromValue(char(1)) << QVariant::fromValue(0U) << +1; + QTest::newRow("char+uint4") << QVariant::fromValue(char(1)) << QVariant::fromValue(1U) << 0; + + QTest::newRow("schar+uint1") << QVariant::fromValue(schar(0)) << QVariant::fromValue(0U) << 0; + QTest::newRow("schar+uint2") << QVariant::fromValue(schar(0)) << QVariant::fromValue(1U) << -1; + QTest::newRow("schar+uint3") << QVariant::fromValue(schar(1)) << QVariant::fromValue(0U) << +1; + QTest::newRow("schar+uint4") << QVariant::fromValue(schar(1)) << QVariant::fromValue(1U) << 0; + + QTest::newRow("uchar+uint1") << QVariant::fromValue(uchar(0)) << QVariant::fromValue(0U) << 0; + QTest::newRow("uchar+uint2") << QVariant::fromValue(uchar(0)) << QVariant::fromValue(1U) << -1; + QTest::newRow("uchar+uint3") << QVariant::fromValue(uchar(1)) << QVariant::fromValue(0U) << +1; + QTest::newRow("uchar+uint4") << QVariant::fromValue(uchar(1)) << QVariant::fromValue(1U) << 0; + + QTest::newRow("short+uint1") << QVariant::fromValue(short(0)) << QVariant::fromValue(0U) << 0; + QTest::newRow("short+uint2") << QVariant::fromValue(short(0)) << QVariant::fromValue(1U) << -1; + QTest::newRow("short+uint3") << QVariant::fromValue(short(1)) << QVariant::fromValue(0U) << +1; + QTest::newRow("short+uint4") << QVariant::fromValue(short(1)) << QVariant::fromValue(1U) << 0; + + QTest::newRow("ushort+uint1") << QVariant::fromValue(ushort(0)) << QVariant::fromValue(0U) << 0; + QTest::newRow("ushort+uint2") << QVariant::fromValue(ushort(0)) << QVariant::fromValue(1U) << -1; + QTest::newRow("ushort+uint3") << QVariant::fromValue(ushort(1)) << QVariant::fromValue(0U) << +1; + QTest::newRow("ushort+uint4") << QVariant::fromValue(ushort(1)) << QVariant::fromValue(1U) << 0; // int + qlonglong - QTest::newRow("int+qlonglong1") << qVariantFromValue(0) << qVariantFromValue(Q_INT64_C(0)) << 0; - QTest::newRow("int+qlonglong2") << qVariantFromValue(1) << qVariantFromValue(Q_INT64_C(0)) << +1; - QTest::newRow("int+qlonglong3") << qVariantFromValue(0) << qVariantFromValue(Q_INT64_C(1)) << -1; - QTest::newRow("int+qlonglong4") << qVariantFromValue(1) << qVariantFromValue(Q_INT64_C(1)) << 0; - QTest::newRow("int+qlonglong5") << qVariantFromValue(0) << qVariantFromValue(Q_INT64_C(-1)) << +1; - QTest::newRow("int+qlonglong6") << qVariantFromValue(-1) << qVariantFromValue(Q_INT64_C(0)) << -1; - QTest::newRow("int+qlonglong7") << qVariantFromValue(-1) << qVariantFromValue(Q_INT64_C(-1)) << 0; + QTest::newRow("int+qlonglong1") << QVariant::fromValue(0) << QVariant::fromValue(Q_INT64_C(0)) << 0; + QTest::newRow("int+qlonglong2") << QVariant::fromValue(1) << QVariant::fromValue(Q_INT64_C(0)) << +1; + QTest::newRow("int+qlonglong3") << QVariant::fromValue(0) << QVariant::fromValue(Q_INT64_C(1)) << -1; + QTest::newRow("int+qlonglong4") << QVariant::fromValue(1) << QVariant::fromValue(Q_INT64_C(1)) << 0; + QTest::newRow("int+qlonglong5") << QVariant::fromValue(0) << QVariant::fromValue(Q_INT64_C(-1)) << +1; + QTest::newRow("int+qlonglong6") << QVariant::fromValue(-1) << QVariant::fromValue(Q_INT64_C(0)) << -1; + QTest::newRow("int+qlonglong7") << QVariant::fromValue(-1) << QVariant::fromValue(Q_INT64_C(-1)) << 0; // uint + qulonglong - QTest::newRow("uint+qulonglong1") << qVariantFromValue(0U) << qVariantFromValue(Q_UINT64_C(0)) << 0; - QTest::newRow("uint+qulonglong2") << qVariantFromValue(1U) << qVariantFromValue(Q_UINT64_C(0)) << +1; - QTest::newRow("uint+qulonglong3") << qVariantFromValue(0U) << qVariantFromValue(Q_UINT64_C(1)) << -1; - QTest::newRow("uint+qulonglong4") << qVariantFromValue(1U) << qVariantFromValue(Q_UINT64_C(1)) << 0; + QTest::newRow("uint+qulonglong1") << QVariant::fromValue(0U) << QVariant::fromValue(Q_UINT64_C(0)) << 0; + QTest::newRow("uint+qulonglong2") << QVariant::fromValue(1U) << QVariant::fromValue(Q_UINT64_C(0)) << +1; + QTest::newRow("uint+qulonglong3") << QVariant::fromValue(0U) << QVariant::fromValue(Q_UINT64_C(1)) << -1; + QTest::newRow("uint+qulonglong4") << QVariant::fromValue(1U) << QVariant::fromValue(Q_UINT64_C(1)) << 0; // int + uint (without sign change) - QTest::newRow("int+uint1") << qVariantFromValue(0) << qVariantFromValue(0U) << 0; - QTest::newRow("int+uint2") << qVariantFromValue(1) << qVariantFromValue(0U) << +1; - QTest::newRow("int+uint3") << qVariantFromValue(0) << qVariantFromValue(1U) << -1; - QTest::newRow("int+uint4") << qVariantFromValue(1) << qVariantFromValue(1U) << 0; + QTest::newRow("int+uint1") << QVariant::fromValue(0) << QVariant::fromValue(0U) << 0; + QTest::newRow("int+uint2") << QVariant::fromValue(1) << QVariant::fromValue(0U) << +1; + QTest::newRow("int+uint3") << QVariant::fromValue(0) << QVariant::fromValue(1U) << -1; + QTest::newRow("int+uint4") << QVariant::fromValue(1) << QVariant::fromValue(1U) << 0; // uint + qlonglong - QTest::newRow("uint+qlonglong1") << qVariantFromValue(0U) << qVariantFromValue(Q_INT64_C(0)) << 0; - QTest::newRow("uint+qlonglong2") << qVariantFromValue(1U) << qVariantFromValue(Q_INT64_C(0)) << +1; - QTest::newRow("uint+qlonglong3") << qVariantFromValue(0U) << qVariantFromValue(Q_INT64_C(1)) << -1; - QTest::newRow("uint+qlonglong4") << qVariantFromValue(1U) << qVariantFromValue(Q_INT64_C(1)) << 0; - QTest::newRow("uint+qlonglong5") << qVariantFromValue(0U) << qVariantFromValue(Q_INT64_C(-1)) << +1; + QTest::newRow("uint+qlonglong1") << QVariant::fromValue(0U) << QVariant::fromValue(Q_INT64_C(0)) << 0; + QTest::newRow("uint+qlonglong2") << QVariant::fromValue(1U) << QVariant::fromValue(Q_INT64_C(0)) << +1; + QTest::newRow("uint+qlonglong3") << QVariant::fromValue(0U) << QVariant::fromValue(Q_INT64_C(1)) << -1; + QTest::newRow("uint+qlonglong4") << QVariant::fromValue(1U) << QVariant::fromValue(Q_INT64_C(1)) << 0; + QTest::newRow("uint+qlonglong5") << QVariant::fromValue(0U) << QVariant::fromValue(Q_INT64_C(-1)) << +1; // boundary conditions - QTest::newRow("charmax+intmax") << qVariantFromValue(CHAR_MAX) << qVariantFromValue(INT_MAX) << -1; - QTest::newRow("charmax+uintmax") << qVariantFromValue(CHAR_MAX) << qVariantFromValue(UINT_MAX) << -1; - QTest::newRow("scharmax+intmax") << qVariantFromValue(SCHAR_MAX) << qVariantFromValue(INT_MAX) << -1; - QTest::newRow("scharmax+uintmax") << qVariantFromValue(SCHAR_MAX) << qVariantFromValue(UINT_MAX) << -1; - QTest::newRow("ucharmax+intmax") << qVariantFromValue(UCHAR_MAX) << qVariantFromValue(INT_MAX) << -1; - QTest::newRow("ucharmax+uintmax") << qVariantFromValue(UCHAR_MAX) << qVariantFromValue(UINT_MAX) << -1; - QTest::newRow("shortmax+intmax") << qVariantFromValue(SHRT_MAX) << qVariantFromValue(INT_MAX) << -1; - QTest::newRow("shortmax+uintmax") << qVariantFromValue(SHRT_MAX) << qVariantFromValue(UINT_MAX) << -1; - QTest::newRow("ushortmax+intmax") << qVariantFromValue(USHRT_MAX) << qVariantFromValue(INT_MAX) << -1; - QTest::newRow("ushortmax+uintmax") << qVariantFromValue(USHRT_MAX) << qVariantFromValue(UINT_MAX) << -1; - - QTest::newRow("intmin+qlonglongmin") << qVariantFromValue(INT_MIN) << qVariantFromValue(LLONG_MIN) << +1; - QTest::newRow("intmax+uintmax") << qVariantFromValue(INT_MAX) << qVariantFromValue(UINT_MAX) << -1; - QTest::newRow("intmax+qlonglongmax") << qVariantFromValue(INT_MAX) << qVariantFromValue(LLONG_MAX) << -1; - QTest::newRow("uintmax+qlonglongmax") << qVariantFromValue(UINT_MAX) << qVariantFromValue(LLONG_MAX) << -1; - QTest::newRow("intmax+qulonglongmax") << qVariantFromValue(INT_MAX) << qVariantFromValue(ULLONG_MAX) << -1; - QTest::newRow("qlonglongmax+qulonglongmax") << qVariantFromValue(LLONG_MAX) << qVariantFromValue(ULLONG_MAX) << -1; - QTest::newRow("uintmax+qlonglongmin") << qVariantFromValue(UINT_MAX) << qVariantFromValue(LLONG_MIN) << +1; + QTest::newRow("charmax+intmax") << QVariant::fromValue(CHAR_MAX) << QVariant::fromValue(INT_MAX) << -1; + QTest::newRow("charmax+uintmax") << QVariant::fromValue(CHAR_MAX) << QVariant::fromValue(UINT_MAX) << -1; + QTest::newRow("scharmax+intmax") << QVariant::fromValue(SCHAR_MAX) << QVariant::fromValue(INT_MAX) << -1; + QTest::newRow("scharmax+uintmax") << QVariant::fromValue(SCHAR_MAX) << QVariant::fromValue(UINT_MAX) << -1; + QTest::newRow("ucharmax+intmax") << QVariant::fromValue(UCHAR_MAX) << QVariant::fromValue(INT_MAX) << -1; + QTest::newRow("ucharmax+uintmax") << QVariant::fromValue(UCHAR_MAX) << QVariant::fromValue(UINT_MAX) << -1; + QTest::newRow("shortmax+intmax") << QVariant::fromValue(SHRT_MAX) << QVariant::fromValue(INT_MAX) << -1; + QTest::newRow("shortmax+uintmax") << QVariant::fromValue(SHRT_MAX) << QVariant::fromValue(UINT_MAX) << -1; + QTest::newRow("ushortmax+intmax") << QVariant::fromValue(USHRT_MAX) << QVariant::fromValue(INT_MAX) << -1; + QTest::newRow("ushortmax+uintmax") << QVariant::fromValue(USHRT_MAX) << QVariant::fromValue(UINT_MAX) << -1; + + QTest::newRow("intmin+qlonglongmin") << QVariant::fromValue(INT_MIN) << QVariant::fromValue(LLONG_MIN) << +1; + QTest::newRow("intmax+uintmax") << QVariant::fromValue(INT_MAX) << QVariant::fromValue(UINT_MAX) << -1; + QTest::newRow("intmax+qlonglongmax") << QVariant::fromValue(INT_MAX) << QVariant::fromValue(LLONG_MAX) << -1; + QTest::newRow("uintmax+qlonglongmax") << QVariant::fromValue(UINT_MAX) << QVariant::fromValue(LLONG_MAX) << -1; + QTest::newRow("intmax+qulonglongmax") << QVariant::fromValue(INT_MAX) << QVariant::fromValue(ULLONG_MAX) << -1; + QTest::newRow("qlonglongmax+qulonglongmax") << QVariant::fromValue(LLONG_MAX) << QVariant::fromValue(ULLONG_MAX) << -1; + QTest::newRow("uintmax+qlonglongmin") << QVariant::fromValue(UINT_MAX) << QVariant::fromValue(LLONG_MIN) << +1; // check for no sign-extension issues - QTest::newRow("ushortmax+intzero") << qVariantFromValue(USHRT_MAX) << qVariantFromValue(0) << +1; - QTest::newRow("ushortmax+qlonglongzero") << qVariantFromValue(USHRT_MAX) << qVariantFromValue(Q_INT64_C(0)) << +1; - QTest::newRow("uintmax+qlonglongzero") << qVariantFromValue(UINT_MAX) << qVariantFromValue(Q_INT64_C(0)) << +1; + QTest::newRow("ushortmax+intzero") << QVariant::fromValue(USHRT_MAX) << QVariant::fromValue(0) << +1; + QTest::newRow("ushortmax+qlonglongzero") << QVariant::fromValue(USHRT_MAX) << QVariant::fromValue(Q_INT64_C(0)) << +1; + QTest::newRow("uintmax+qlonglongzero") << QVariant::fromValue(UINT_MAX) << QVariant::fromValue(Q_INT64_C(0)) << +1; // sign changes // the tests below check that a signed negative number sign-changes to a non-zero unsigned number and that // signed -1 sign-changes to unsigned maximum (all bits set, ~0). This works on two's complement machines // (all that Qt supports), and would also work on one's complement. if (std::numeric_limits<char>::is_signed) { - QTest::newRow("signchange-char+uint") << qVariantFromValue(char(-1)) << qVariantFromValue(0U) << +1; - QTest::newRow("signchange-char+uintmax") << qVariantFromValue(char(-1)) << qVariantFromValue(UINT_MAX) << 0; - QTest::newRow("signchange-charmin+uint") << qVariantFromValue(CHAR_MIN) << qVariantFromValue(0U) << +1; - QTest::newRow("signchange-char+qulonglong") << qVariantFromValue(char(-1)) << qVariantFromValue(Q_UINT64_C(0)) << +1; - QTest::newRow("signchange-char+qulonglongmax") << qVariantFromValue(char(-1)) << qVariantFromValue(ULLONG_MAX) << 0; - QTest::newRow("signchange-charmin+qulonglong") << qVariantFromValue(CHAR_MIN) << qVariantFromValue(Q_UINT64_C(0)) << +1; - } - QTest::newRow("signchange-schar+uint") << qVariantFromValue(schar(-1)) << qVariantFromValue(0U) << +1; - QTest::newRow("signchange-schar+uintmax") << qVariantFromValue(schar(-1)) << qVariantFromValue(UINT_MAX) << 0; - QTest::newRow("signchange-scharmin+uint") << qVariantFromValue(SCHAR_MIN) << qVariantFromValue(0U) << +1; - QTest::newRow("signchange-schar+qulonglong") << qVariantFromValue(schar(-1)) << qVariantFromValue(Q_UINT64_C(0)) << +1; - QTest::newRow("signchange-schar+qulonglongmax") << qVariantFromValue(schar(-1)) << qVariantFromValue(ULLONG_MAX) << 0; - QTest::newRow("signchange-scharmin+qulonglong") << qVariantFromValue(SCHAR_MIN) << qVariantFromValue(Q_UINT64_C(0)) << +1; - QTest::newRow("signchange-short+uint") << qVariantFromValue(short(-1)) << qVariantFromValue(0U) << +1; - QTest::newRow("signchange-short+uintmax") << qVariantFromValue(short(-1)) << qVariantFromValue(UINT_MAX) << 0; - QTest::newRow("signchange-shortmin+uint") << qVariantFromValue(SHRT_MIN) << qVariantFromValue(0U) << +1; - QTest::newRow("signchange-short+qulonglong") << qVariantFromValue(short(-1)) << qVariantFromValue(Q_UINT64_C(0)) << +1; - QTest::newRow("signchange-short+qulonglongmax") << qVariantFromValue(short(-1)) << qVariantFromValue(ULLONG_MAX) << 0; - QTest::newRow("signchange-shortmin+qulonglong") << qVariantFromValue(SHRT_MIN) << qVariantFromValue(Q_UINT64_C(0)) << +1; - QTest::newRow("signchange-int+uint") << qVariantFromValue(-1) << qVariantFromValue(0U) << +1; - QTest::newRow("signchange-int+uintmax") << qVariantFromValue(-1) << qVariantFromValue(UINT_MAX) << 0; - QTest::newRow("signchange-intmin+uint") << qVariantFromValue(INT_MIN) << qVariantFromValue(0U) << +1; - QTest::newRow("signchange-int+qulonglong") << qVariantFromValue(-1) << qVariantFromValue(Q_UINT64_C(0)) << +1; - QTest::newRow("signchange-int+qulonglongmax") << qVariantFromValue(-1) << qVariantFromValue(ULLONG_MAX) << 0; - QTest::newRow("signchange-intmin+qulonglong") << qVariantFromValue(INT_MIN) << qVariantFromValue(Q_UINT64_C(0)) << +1; + QTest::newRow("signchange-char+uint") << QVariant::fromValue(char(-1)) << QVariant::fromValue(0U) << +1; + QTest::newRow("signchange-char+uintmax") << QVariant::fromValue(char(-1)) << QVariant::fromValue(UINT_MAX) << 0; + QTest::newRow("signchange-charmin+uint") << QVariant::fromValue(CHAR_MIN) << QVariant::fromValue(0U) << +1; + QTest::newRow("signchange-char+qulonglong") << QVariant::fromValue(char(-1)) << QVariant::fromValue(Q_UINT64_C(0)) << +1; + QTest::newRow("signchange-char+qulonglongmax") << QVariant::fromValue(char(-1)) << QVariant::fromValue(ULLONG_MAX) << 0; + QTest::newRow("signchange-charmin+qulonglong") << QVariant::fromValue(CHAR_MIN) << QVariant::fromValue(Q_UINT64_C(0)) << +1; + } + QTest::newRow("signchange-schar+uint") << QVariant::fromValue(schar(-1)) << QVariant::fromValue(0U) << +1; + QTest::newRow("signchange-schar+uintmax") << QVariant::fromValue(schar(-1)) << QVariant::fromValue(UINT_MAX) << 0; + QTest::newRow("signchange-scharmin+uint") << QVariant::fromValue(SCHAR_MIN) << QVariant::fromValue(0U) << +1; + QTest::newRow("signchange-schar+qulonglong") << QVariant::fromValue(schar(-1)) << QVariant::fromValue(Q_UINT64_C(0)) << +1; + QTest::newRow("signchange-schar+qulonglongmax") << QVariant::fromValue(schar(-1)) << QVariant::fromValue(ULLONG_MAX) << 0; + QTest::newRow("signchange-scharmin+qulonglong") << QVariant::fromValue(SCHAR_MIN) << QVariant::fromValue(Q_UINT64_C(0)) << +1; + QTest::newRow("signchange-short+uint") << QVariant::fromValue(short(-1)) << QVariant::fromValue(0U) << +1; + QTest::newRow("signchange-short+uintmax") << QVariant::fromValue(short(-1)) << QVariant::fromValue(UINT_MAX) << 0; + QTest::newRow("signchange-shortmin+uint") << QVariant::fromValue(SHRT_MIN) << QVariant::fromValue(0U) << +1; + QTest::newRow("signchange-short+qulonglong") << QVariant::fromValue(short(-1)) << QVariant::fromValue(Q_UINT64_C(0)) << +1; + QTest::newRow("signchange-short+qulonglongmax") << QVariant::fromValue(short(-1)) << QVariant::fromValue(ULLONG_MAX) << 0; + QTest::newRow("signchange-shortmin+qulonglong") << QVariant::fromValue(SHRT_MIN) << QVariant::fromValue(Q_UINT64_C(0)) << +1; + QTest::newRow("signchange-int+uint") << QVariant::fromValue(-1) << QVariant::fromValue(0U) << +1; + QTest::newRow("signchange-int+uintmax") << QVariant::fromValue(-1) << QVariant::fromValue(UINT_MAX) << 0; + QTest::newRow("signchange-intmin+uint") << QVariant::fromValue(INT_MIN) << QVariant::fromValue(0U) << +1; + QTest::newRow("signchange-int+qulonglong") << QVariant::fromValue(-1) << QVariant::fromValue(Q_UINT64_C(0)) << +1; + QTest::newRow("signchange-int+qulonglongmax") << QVariant::fromValue(-1) << QVariant::fromValue(ULLONG_MAX) << 0; + QTest::newRow("signchange-intmin+qulonglong") << QVariant::fromValue(INT_MIN) << QVariant::fromValue(Q_UINT64_C(0)) << +1; // no qlonglong+uint, since that should promote to qlonglong and then the comparison is signed (tested above) - QTest::newRow("signchange-qlonglong+qulonglong") << qVariantFromValue(Q_INT64_C(-1)) << qVariantFromValue(Q_UINT64_C(0)) << +1; - QTest::newRow("signchange-qlonglong+qulonglongmax") << qVariantFromValue(Q_INT64_C(-1)) << qVariantFromValue(ULLONG_MAX) << 0; - QTest::newRow("signchange-qlonglongmin+qulonglong") << qVariantFromValue(LLONG_MIN) << qVariantFromValue(Q_UINT64_C(0)) << +1; + QTest::newRow("signchange-qlonglong+qulonglong") << QVariant::fromValue(Q_INT64_C(-1)) << QVariant::fromValue(Q_UINT64_C(0)) << +1; + QTest::newRow("signchange-qlonglong+qulonglongmax") << QVariant::fromValue(Q_INT64_C(-1)) << QVariant::fromValue(ULLONG_MAX) << 0; + QTest::newRow("signchange-qlonglongmin+qulonglong") << QVariant::fromValue(LLONG_MIN) << QVariant::fromValue(Q_UINT64_C(0)) << +1; } void tst_QVariant::compareNumbers() const @@ -2761,6 +2771,14 @@ void tst_QVariant::qvariant_cast_QObject_derived() QCOMPARE(data.value<CustomQObjectDerived *>(), object); QCOMPARE(data.value<CustomQObject *>(), object); } + { + QObject *object = new CustomQObjectDerivedNoMetaType(this); + QVariant data = QVariant::fromValue(object); + QVERIFY(data.canConvert<CustomQObjectDerivedNoMetaType*>()); + QVERIFY(data.convert(qMetaTypeId<CustomQObjectDerivedNoMetaType*>())); + QCOMPARE(data.value<CustomQObjectDerivedNoMetaType*>(), object); + QCOMPARE(data.isNull(), false); + } } struct QObjectWrapper @@ -2861,13 +2879,26 @@ void tst_QVariant::qvariant_cast_QObject_wrapper() QVERIFY(spVar.canConvert<QObject*>()); QCOMPARE(f, spVar.value<QObject*>()); } +#if QT_DEPRECATED_SINCE(5, 0) { QFile *f = new QFile(this); +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED QWeakPointer<QFile> sp(f); +QT_WARNING_POP QVariant spVar = QVariant::fromValue(sp); QVERIFY(spVar.canConvert<QObject*>()); QCOMPARE(f, spVar.value<QObject*>()); } +#endif + { + QFile *f = new QFile(this); + QSharedPointer<QObject> sp(f); + QWeakPointer<QObject> wp = sp; + QVariant wpVar = QVariant::fromValue(wp); + QVERIFY(wpVar.canConvert<QObject*>()); + QCOMPARE(f, wpVar.value<QObject*>()); + } { QFile *f = new QFile(this); QSharedPointer<QFile> sp(f); @@ -3943,7 +3974,7 @@ void tst_QVariant::userConversion() QVERIFY(!(QMetaType::hasRegisteredConverterFunction<QString, Convertible>())); Convertible c = { 123 }; - QVariant v = qVariantFromValue(c); + QVariant v = QVariant::fromValue(c); bool ok; v.toInt(&ok); @@ -3977,7 +4008,7 @@ void tst_QVariant::userConversion() QVERIFY(!(QMetaType::hasRegisteredConverterFunction<QString, BigConvertible>())); BigConvertible c = { 123, 0, 0 }; - QVariant v = qVariantFromValue(c); + QVariant v = QVariant::fromValue(c); bool ok; v.toInt(&ok); @@ -4692,7 +4723,6 @@ Q_DECLARE_METATYPE(EnumTest_Enum0) enum EnumTest_Enum1 : qint64 { EnumTest_Enum1_value = 42, EnumTest_Enum1_bigValue = (Q_INT64_C(1) << 33) + 50 }; Q_DECLARE_METATYPE(EnumTest_Enum1) -#if defined(Q_COMPILER_CLASS_ENUM) enum EnumTest_Enum3 : qint64 { EnumTest_Enum3_value = -47, EnumTest_Enum3_bigValue = (Q_INT64_C(1) << 56) + 5 }; Q_DECLARE_METATYPE(EnumTest_Enum3) enum EnumTest_Enum4 : quint64 { EnumTest_Enum4_value = 47, EnumTest_Enum4_bigValue = (Q_INT64_C(1) << 52) + 45 }; @@ -4705,7 +4735,6 @@ enum class EnumTest_Enum7 { EnumTest_Enum7_value = 47, ensureSignedEnum7 = -1 }; Q_DECLARE_METATYPE(EnumTest_Enum7) enum EnumTest_Enum8 : short { EnumTest_Enum8_value = 47 }; Q_DECLARE_METATYPE(EnumTest_Enum8) -#endif template<typename Enum> void testVariant(Enum value, bool *ok) { @@ -4764,7 +4793,6 @@ void tst_QVariant::enums() QVERIFY(ok); testVariant(EnumTest_Enum1_bigValue, &ok); QVERIFY(ok); -#if defined(Q_COMPILER_CLASS_ENUM) testVariant(EnumTest_Enum3::EnumTest_Enum3_value, &ok); QVERIFY(ok); testVariant(EnumTest_Enum3::EnumTest_Enum3_bigValue, &ok); @@ -4783,7 +4811,6 @@ void tst_QVariant::enums() QVERIFY(ok); testVariant(EnumTest_Enum3::EnumTest_Enum3_value, &ok); QVERIFY(ok); -#endif } template<typename Enum> void testVariantMeta(Enum value, bool *ok, const char *string) diff --git a/tests/auto/corelib/mimetypes/qmimetype/tst_qmimetype.cpp b/tests/auto/corelib/mimetypes/qmimetype/tst_qmimetype.cpp index c74bce3b5b..e1357245f3 100644 --- a/tests/auto/corelib/mimetypes/qmimetype/tst_qmimetype.cpp +++ b/tests/auto/corelib/mimetypes/qmimetype/tst_qmimetype.cpp @@ -91,11 +91,7 @@ static QStringList qMimeTypeGlobPatterns() // ------------------------------------------------------------------------------------------------ -#ifndef Q_COMPILER_RVALUE_REFS -QMIMETYPE_BUILDER -#else QMIMETYPE_BUILDER_FROM_RVALUE_REFS -#endif // ------------------------------------------------------------------------------------------------ diff --git a/tests/auto/corelib/plugin/qlibrary/lib/lib.pro b/tests/auto/corelib/plugin/qlibrary/lib/lib.pro index c44cd46597..2c3305e872 100644 --- a/tests/auto/corelib/plugin/qlibrary/lib/lib.pro +++ b/tests/auto/corelib/plugin/qlibrary/lib/lib.pro @@ -12,7 +12,7 @@ msvc: DEFINES += WIN32_MSVC target.path = $$[QT_INSTALL_TESTS]/tst_qlibrary INSTALLS += target -win32 { +win32:debug_and_release { CONFIG(debug, debug|release) { DESTDIR = ../debug/ } else { diff --git a/tests/auto/corelib/plugin/qlibrary/lib2/lib2.pro b/tests/auto/corelib/plugin/qlibrary/lib2/lib2.pro index bfda0e0194..3db4bed973 100644 --- a/tests/auto/corelib/plugin/qlibrary/lib2/lib2.pro +++ b/tests/auto/corelib/plugin/qlibrary/lib2/lib2.pro @@ -13,12 +13,18 @@ msvc: DEFINES += WIN32_MSVC # We want to test if we can load a shared library with *any* filename... win32 { - CONFIG(debug, debug|release) { - BUILD_FOLDER = debug + + debug_and_release { + CONFIG(debug, debug|release)) { + BUILD_FOLDER = debug + } else { + BUILD_FOLDER = release + } + DESTDIR = ../$$BUILD_FOLDER/ } else { - BUILD_FOLDER = release + BUILD_FOLDER = + DESTDIR = ../ } - DESTDIR = ../$$BUILD_FOLDER/ # vcproj and Makefile generators refer to target differently contains(TEMPLATE,vc.*) { diff --git a/tests/auto/corelib/plugin/qlibrary/tst/tst.pro b/tests/auto/corelib/plugin/qlibrary/tst/tst.pro index 56bef14405..5894bee9d5 100644 --- a/tests/auto/corelib/plugin/qlibrary/tst/tst.pro +++ b/tests/auto/corelib/plugin/qlibrary/tst/tst.pro @@ -3,7 +3,7 @@ TARGET = ../tst_qlibrary QT = core testlib SOURCES = ../tst_qlibrary.cpp -win32 { +win32:debug_and_release { CONFIG(debug, debug|release) { TARGET = ../../debug/tst_qlibrary } else { diff --git a/tests/auto/corelib/plugin/qlibrary/tst_qlibrary.cpp b/tests/auto/corelib/plugin/qlibrary/tst_qlibrary.cpp index c9c9202a80..e0d09b0813 100644 --- a/tests/auto/corelib/plugin/qlibrary/tst_qlibrary.cpp +++ b/tests/auto/corelib/plugin/qlibrary/tst_qlibrary.cpp @@ -30,7 +30,7 @@ #include <QtTest/QtTest> #include <qdir.h> #include <qlibrary.h> -#include <QtCore/QRegExp> +#include <QtCore/QRegularExpression> // Helper macros to let us know if some suffixes and prefixes are valid @@ -414,10 +414,12 @@ void tst_QLibrary::errorString() QFAIL(qPrintable(QString("Unknown operation: %1").arg(operation))); break; } - QRegExp re(errorString); +#if QT_CONFIG(regularexpression) + QRegularExpression re(QRegularExpression::anchoredPattern(errorString)); QString libErrorString = lib.errorString(); + QVERIFY2(re.match(libErrorString).hasMatch(), qPrintable(libErrorString)); +#endif QVERIFY(!lib.isLoaded() || lib.unload()); - QVERIFY2(re.exactMatch(libErrorString), qPrintable(libErrorString)); QCOMPARE(ok, success); } diff --git a/tests/auto/corelib/plugin/qpluginloader/staticplugin/main.cpp b/tests/auto/corelib/plugin/qpluginloader/staticplugin/main.cpp index d891839b1e..6d163ea336 100644 --- a/tests/auto/corelib/plugin/qpluginloader/staticplugin/main.cpp +++ b/tests/auto/corelib/plugin/qpluginloader/staticplugin/main.cpp @@ -31,7 +31,7 @@ class StaticPlugin : public QObject { Q_OBJECT - Q_PLUGIN_METADATA(IID "SomeIID") + Q_PLUGIN_METADATA(IID "SomeIID" URI "qt.test.pluginloader.staticplugin") public: StaticPlugin() {} }; diff --git a/tests/auto/corelib/plugin/qpluginloader/tst/tst.pro b/tests/auto/corelib/plugin/qpluginloader/tst/tst.pro index a3885f4134..d49bff14fd 100644 --- a/tests/auto/corelib/plugin/qpluginloader/tst/tst.pro +++ b/tests/auto/corelib/plugin/qpluginloader/tst/tst.pro @@ -5,7 +5,7 @@ qtConfig(private_tests): QT += core-private SOURCES = ../tst_qpluginloader.cpp ../fakeplugin.cpp HEADERS = ../theplugin/plugininterface.h -win32 { +win32:debug_and_release { CONFIG(debug, debug|release) { TARGET = ../../debug/tst_qpluginloader LIBS += -L../staticplugin/debug diff --git a/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp b/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp index 85763b0388..c4a366d7c6 100644 --- a/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp +++ b/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp @@ -553,6 +553,7 @@ void tst_QPluginLoader::staticPlugins() QCOMPARE(metaData.value("version").toInt() / 0x100, QT_VERSION / 0x100); QCOMPARE(metaData.value("IID").toString(), "SomeIID"); QCOMPARE(metaData.value("ExtraMetaData"), QJsonArray({ "StaticPlugin", "foo" })); + QCOMPARE(metaData.value("URI").toString(), "qt.test.pluginloader.staticplugin"); } diff --git a/tests/auto/corelib/serialization/json/tst_qtjson.cpp b/tests/auto/corelib/serialization/json/tst_qtjson.cpp index 8907704a33..57aa67c142 100644 --- a/tests/auto/corelib/serialization/json/tst_qtjson.cpp +++ b/tests/auto/corelib/serialization/json/tst_qtjson.cpp @@ -436,6 +436,8 @@ void tst_QtJson::testObjectSimple() object.insert("boolean", true); QCOMPARE(object.value("boolean").toBool(), true); QCOMPARE(object.value(QLatin1String("boolean")).toBool(), true); + QJsonObject object2 = object; + QJsonObject object3 = object; QStringList keys = object.keys(); QVERIFY2(keys.contains("number"), "key number not found"); @@ -461,6 +463,40 @@ void tst_QtJson::testObjectSimple() object.insert("string", QString::fromLatin1("foo")); QVERIFY2(object.value(QLatin1String("string")).toString() != before, "value should have been updated"); + // same tests again but with QStringView keys + object2.insert(QStringView(u"value"), value); + QCOMPARE(object2.value("value"), value); + + size = object2.size(); + object2.remove(QStringView(u"boolean")); + QCOMPARE(object2.size(), size - 1); + QVERIFY2(!object2.contains(QStringView(u"boolean")), "key boolean should have been removed"); + + taken = object2.take(QStringView(u"value")); + QCOMPARE(taken, value); + QVERIFY2(!object2.contains("value"), "key value should have been removed"); + + before = object2.value("string").toString(); + object2.insert(QStringView(u"string"), QString::fromLatin1("foo")); + QVERIFY2(object2.value(QStringView(u"string")).toString() != before, "value should have been updated"); + + // same tests again but with QLatin1String keys + object3.insert(QLatin1String("value"), value); + QCOMPARE(object3.value("value"), value); + + size = object3.size(); + object3.remove(QLatin1String("boolean")); + QCOMPARE(object3.size(), size - 1); + QVERIFY2(!object3.contains("boolean"), "key boolean should have been removed"); + + taken = object3.take(QLatin1String("value")); + QCOMPARE(taken, value); + QVERIFY2(!object3.contains("value"), "key value should have been removed"); + + before = object3.value("string").toString(); + object3.insert(QLatin1String("string"), QString::fromLatin1("foo")); + QVERIFY2(object3.value(QLatin1String("string")).toString() != before, "value should have been updated"); + size = object.size(); QJsonObject subobject; subobject.insert("number", 42); @@ -1096,6 +1132,8 @@ void tst_QtJson::undefinedValues() QJsonObject object; object.insert("Key", QJsonValue(QJsonValue::Undefined)); QCOMPARE(object.size(), 0); + object["Key"] = QJsonValue(QJsonValue::Undefined); + QCOMPARE(object.size(), 0); object.insert("Key", QLatin1String("Value")); QCOMPARE(object.size(), 1); @@ -2698,6 +2736,8 @@ void tst_QtJson::longStrings() // test around 15 and 16 bit boundaries, as these are limits // in the data structures (for Latin1String in qjson_p.h) QString s(0x7ff0, 'a'); + QByteArray ba(0x7ff0, 'a'); + ba.append(0x8010 - 0x7ff0, 'c'); for (int i = 0x7ff0; i < 0x8010; i++) { s.append(QLatin1Char('c')); @@ -2714,9 +2754,21 @@ void tst_QtJson::longStrings() /* ... and a QByteArray from the QJsonDocument */ QByteArray a2 = d2.toJson(); QCOMPARE(a1, a2); + + // Test long keys + QJsonObject o1, o2; + o1[s] = 42; + o2[QLatin1String(ba.data(), i + 1)] = 42; + d1.setObject(o1); + d2.setObject(o2); + a1 = d1.toJson(); + a2 = d2.toJson(); + QCOMPARE(a1, a2); } s = QString(0xfff0, 'a'); + ba = QByteArray(0xfff0, 'a'); + ba.append(0x10010 - 0xfff0, 'c'); for (int i = 0xfff0; i < 0x10010; i++) { s.append(QLatin1Char('c')); @@ -2733,6 +2785,16 @@ void tst_QtJson::longStrings() /* ... and a QByteArray from the QJsonDocument */ QByteArray a2 = d2.toJson(); QCOMPARE(a1, a2); + + // Test long keys + QJsonObject o1, o2; + o1[s] = 42; + o2[QLatin1String(ba.data(), i + 1)] = 42; + d1.setObject(o1); + d2.setObject(o2); + a1 = d1.toJson(); + a2 = d2.toJson(); + QCOMPARE(a1, a2); } } @@ -2755,9 +2817,6 @@ void tst_QtJson::testJsonValueRefDefault() void tst_QtJson::arrayInitializerList() { -#ifndef Q_COMPILER_INITIALIZER_LISTS - QSKIP("initializer_list is enabled only with c++11 support"); -#else QVERIFY(QJsonArray{}.isEmpty()); QCOMPARE(QJsonArray{"one"}.count(), 1); QCOMPARE(QJsonArray{1}.count(), 1); @@ -2803,14 +2862,10 @@ void tst_QtJson::arrayInitializerList() QCOMPARE(QJsonValue(a43["one"]), QJsonValue(1)); } } -#endif } void tst_QtJson::objectInitializerList() { -#ifndef Q_COMPILER_INITIALIZER_LISTS - QSKIP("initializer_list is enabled only with c++11 support"); -#else QVERIFY(QJsonObject{}.isEmpty()); { // one property @@ -2850,7 +2905,6 @@ void tst_QtJson::objectInitializerList() QCOMPARE(QJsonValue(nested[0]), QJsonValue("innerValue")); QCOMPARE(QJsonValue(nested[1]), QJsonValue(2.1)); } -#endif } void tst_QtJson::unicodeKeys() diff --git a/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp b/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp index 6fa82ea681..c6733205e5 100644 --- a/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp +++ b/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp @@ -1413,10 +1413,12 @@ void tst_QCborValue::toCbor_data() // The rest of these tests are conversions whose decoding does not yield // back the same QCborValue. +#if QT_CONFIG(signaling_nan) // Signalling NaN get normalized to quiet ones QTest::newRow("Double:snan") << QCborValue(qSNaN()) << raw("\xfb\x7f\xf8\0""\0\0\0\0\0") << QCborValue::EncodingOptions(); QTest::newRow("Float:snan") << QCborValue(qSNaN()) << raw("\xfa\x7f\xc0\0\0") << QCborValue::EncodingOptions(QCborValue::UseFloat); QTest::newRow("Float16:snan") << QCborValue(qSNaN()) << raw("\xf9\x7e\0") << QCborValue::EncodingOptions(QCborValue::UseFloat16); +#endif // Floating point written as integers are read back as integers QTest::newRow("UseInteger:0") << QCborValue(0.) << raw("\x00") << QCborValue::EncodingOptions(QCborValue::UseIntegers); diff --git a/tests/auto/corelib/serialization/qdatastream/qdatastream.pro b/tests/auto/corelib/serialization/qdatastream/qdatastream.pro index 25f8b889a0..469d689f3f 100644 --- a/tests/auto/corelib/serialization/qdatastream/qdatastream.pro +++ b/tests/auto/corelib/serialization/qdatastream/qdatastream.pro @@ -3,6 +3,8 @@ TARGET = tst_qdatastream QT += testlib SOURCES = tst_qdatastream.cpp +DEFINES -= QT_NO_LINKED_LIST + TESTDATA += datastream.q42 android:!android-embedded { diff --git a/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp b/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp index 3ad1794176..8197c386c5 100644 --- a/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp +++ b/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp @@ -113,6 +113,11 @@ private slots: void stream_QRegExp_data(); void stream_QRegExp(); +#if QT_CONFIG(regularexpression) + void stream_QRegularExpression_data(); + void stream_QRegularExpression(); +#endif + void stream_Map_data(); void stream_Map(); @@ -181,6 +186,8 @@ private slots: void streamRealDataTypes(); + void enumTest(); + void floatingPointPrecision(); void compatibility_Qt5(); @@ -219,6 +226,9 @@ private: void writeQSize(QDataStream *s); void writeQString(QDataStream* dev); void writeQRegExp(QDataStream* dev); +#if QT_CONFIG(regularexpression) + void writeQRegularExpression(QDataStream *dev); +#endif void writeMap(QDataStream* dev); void writeHash(QDataStream* dev); void writeqint64(QDataStream *s); @@ -248,6 +258,9 @@ private: void readQSize(QDataStream *s); void readQString(QDataStream *s); void readQRegExp(QDataStream *s); +#if QT_CONFIG(regularexpression) + void readQRegularExpression(QDataStream *s); +#endif void readMap(QDataStream *s); void readHash(QDataStream *s); void readqint64(QDataStream *s); @@ -559,6 +572,69 @@ void tst_QDataStream::readQRegExp(QDataStream *s) // ************************************ +#if QT_CONFIG(regularexpression) +static QRegularExpression QRegularExpressionData(int index) +{ + switch (index) { + case 0: return QRegularExpression(); + case 1: return QRegularExpression(""); + case 2: return QRegularExpression("A", QRegularExpression::CaseInsensitiveOption); + case 3: return QRegularExpression(QRegularExpression::wildcardToRegularExpression("ABCDE FGHI")); + case 4: return QRegularExpression(QRegularExpression::anchoredPattern("This is a long string"), QRegularExpression::CaseInsensitiveOption); + case 5: return QRegularExpression("And again a string with a \nCRLF", QRegularExpression::CaseInsensitiveOption); + case 6: return QRegularExpression("abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRESTUVWXYZ 1234567890 ~`!@#$%^&*()_-+={[}]|\\:;\"'<,>.?/", QRegularExpression::InvertedGreedinessOption); + } + return QRegularExpression("foo"); +} +#define MAX_QREGULAREXPRESSION_DATA 7 + +void tst_QDataStream::stream_QRegularExpression_data() +{ + stream_data(MAX_QREGULAREXPRESSION_DATA); +} + +void tst_QDataStream::stream_QRegularExpression() +{ + STREAM_IMPL(QRegularExpression); +} + +void tst_QDataStream::writeQRegularExpression(QDataStream* s) +{ + QRegularExpression test(QRegularExpressionData(dataIndex(QTest::currentDataTag()))); + *s << test; + *s << QString("Her er det noe tekst"); + *s << test; + *s << QString("nonempty"); + *s << test; + *s << QVariant(test); +} + +void tst_QDataStream::readQRegularExpression(QDataStream *s) +{ + QRegularExpression R; + QString S; + QVariant V; + QRegularExpression test(QRegularExpressionData(dataIndex(QTest::currentDataTag()))); + + *s >> R; + + QCOMPARE(R, test); + *s >> S; + QCOMPARE(S, QString("Her er det noe tekst")); + *s >> R; + QCOMPARE(R, test); + *s >> S; + QCOMPARE(S, QString("nonempty")); + *s >> R; + QCOMPARE(R, test); + *s >> V; + QCOMPARE(V.type(), QVariant::RegularExpression); + QCOMPARE(V.toRegularExpression(), test); +} +#endif //QT_CONFIG(regularexpression) + +// ************************************ + typedef QMap<int, QString> Map; static Map MapData(int index) @@ -2315,10 +2391,10 @@ void tst_QDataStream::setVersion() if (vers == 1) { for (int grp = 0; grp < (int)QPalette::NColorGroups; ++grp) { - QVERIFY(pal1.color((QPalette::ColorGroup)grp, QPalette::Foreground) - == inPal1.color((QPalette::ColorGroup)grp, QPalette::Foreground)); - QVERIFY(pal1.color((QPalette::ColorGroup)grp, QPalette::Background) - == inPal1.color((QPalette::ColorGroup)grp, QPalette::Background)); + QVERIFY(pal1.color((QPalette::ColorGroup)grp, QPalette::WindowText) + == inPal1.color((QPalette::ColorGroup)grp, QPalette::WindowText)); + QVERIFY(pal1.color((QPalette::ColorGroup)grp, QPalette::Window) + == inPal1.color((QPalette::ColorGroup)grp, QPalette::Window)); QVERIFY(pal1.color((QPalette::ColorGroup)grp, QPalette::Light) == inPal1.color((QPalette::ColorGroup)grp, QPalette::Light)); QVERIFY(pal1.color((QPalette::ColorGroup)grp, QPalette::Dark) @@ -3441,6 +3517,90 @@ void tst_QDataStream::floatingPointNaN() } } +void tst_QDataStream::enumTest() +{ + QByteArray ba; + + enum class E1 : qint8 + { + A, + B, + C + }; + { + QDataStream stream(&ba, QIODevice::WriteOnly); + stream << E1::A; + QCOMPARE(ba.size(), int(sizeof(E1))); + } + { + QDataStream stream(ba); + E1 e; + stream >> e; + QCOMPARE(e, E1::A); + } + ba.clear(); + + enum class E2 : qint16 + { + A, + B, + C + }; + { + QDataStream stream(&ba, QIODevice::WriteOnly); + stream << E2::B; + QCOMPARE(ba.size(), int(sizeof(E2))); + } + { + QDataStream stream(ba); + E2 e; + stream >> e; + QCOMPARE(e, E2::B); + } + ba.clear(); + + enum class E4 : qint32 + { + A, + B, + C + }; + { + QDataStream stream(&ba, QIODevice::WriteOnly); + stream << E4::C; + QCOMPARE(ba.size(), int(sizeof(E4))); + } + { + QDataStream stream(ba); + E4 e; + stream >> e; + QCOMPARE(e, E4::C); + } + ba.clear(); + + + enum E + { + A, + B, + C, + D + }; + { + QDataStream stream(&ba, QIODevice::WriteOnly); + stream << E::D; + QCOMPARE(ba.size(), 4); + } + { + QDataStream stream(ba); + E e; + stream >> e; + QCOMPARE(e, E::D); + } + ba.clear(); + +} + void tst_QDataStream::floatingPointPrecision() { QByteArray ba; diff --git a/tests/auto/corelib/serialization/qtextstream/BLACKLIST b/tests/auto/corelib/serialization/qtextstream/BLACKLIST index b54b53cd74..674569e204 100644 --- a/tests/auto/corelib/serialization/qtextstream/BLACKLIST +++ b/tests/auto/corelib/serialization/qtextstream/BLACKLIST @@ -1,3 +1,3 @@ [stillOpenWhenAtEnd] -windows +windows-7sp1 winrt diff --git a/tests/auto/corelib/serialization/qtextstream/readLineStdinProcess/main.cpp b/tests/auto/corelib/serialization/qtextstream/readLineStdinProcess/main.cpp index 41ea5e56f0..2d4aa452ca 100644 --- a/tests/auto/corelib/serialization/qtextstream/readLineStdinProcess/main.cpp +++ b/tests/auto/corelib/serialization/qtextstream/readLineStdinProcess/main.cpp @@ -41,7 +41,7 @@ int main(int argc, char **argv) do { line = qin.readLine(); if (!line.isNull()) - qerr << line << flush; + qerr << line << Qt::flush; } while (!line.isNull()); return 0; } diff --git a/tests/auto/corelib/serialization/qtextstream/tst_qtextstream.cpp b/tests/auto/corelib/serialization/qtextstream/tst_qtextstream.cpp index 8bb35554c8..6381ce5ed0 100644 --- a/tests/auto/corelib/serialization/qtextstream/tst_qtextstream.cpp +++ b/tests/auto/corelib/serialization/qtextstream/tst_qtextstream.cpp @@ -35,6 +35,7 @@ #include <QBuffer> #include <QByteArray> #include <QDebug> +#include <QElapsedTimer> #include <QFile> #include <QTcpSocket> #include <QTemporaryDir> @@ -245,7 +246,7 @@ private: void runOnExit() { QByteArray buffer; - QTextStream(&buffer) << "This will try to use QTextCodec::codecForLocale" << endl; + QTextStream(&buffer) << "This will try to use QTextCodec::codecForLocale" << Qt::endl; } Q_DESTRUCTOR_FUNCTION(runOnExit) @@ -996,7 +997,7 @@ struct CompareIndicesForArray void tst_QTextStream::performance() { // Phase #1 - test speed of reading a huge text file with QFile. - QTime stopWatch; + QElapsedTimer stopWatch; const int N = 3; const char * readMethods[N] = { @@ -1102,7 +1103,7 @@ void tst_QTextStream::hexTest() QByteArray array; QTextStream stream(&array); - stream << showbase << hex << number; + stream << Qt::showbase << Qt::hex << number; stream.flush(); QCOMPARE(array, data); } @@ -1132,7 +1133,7 @@ void tst_QTextStream::binTest() QByteArray array; QTextStream stream(&array); - stream << showbase << bin << number; + stream << Qt::showbase << Qt::bin << number; stream.flush(); QCOMPARE(array.constData(), data.constData()); } @@ -1155,7 +1156,7 @@ void tst_QTextStream::octTest() QByteArray array; QTextStream stream(&array); - stream << showbase << oct << number; + stream << Qt::showbase << Qt::oct << number; stream.flush(); QCOMPARE(array, data); } @@ -1196,7 +1197,7 @@ void tst_QTextStream::ws_manipulator() QTextStream stream(&string); char a, b, c, d; - stream >> a >> ws >> b >> ws >> c >> ws >> d; + stream >> a >> Qt::ws >> b >> Qt::ws >> c >> Qt::ws >> d; QCOMPARE(a, 'a'); QCOMPARE(b, 'b'); QCOMPARE(c, 'c'); @@ -1506,9 +1507,9 @@ void tst_QTextStream::readStdin() stdinProcess.setReadChannel(QProcess::StandardError); QTextStream stream(&stdinProcess); - stream << "1" << endl; - stream << "2" << endl; - stream << "3" << endl; + stream << "1" << Qt::endl; + stream << "2" << Qt::endl; + stream << "3" << Qt::endl; stdinProcess.closeWriteChannel(); @@ -1534,7 +1535,7 @@ void tst_QTextStream::readAllFromStdin() QTextStream stream(&stdinProcess); stream.setCodec("ISO-8859-1"); - stream << "hello world" << flush; + stream << "hello world" << Qt::flush; stdinProcess.closeWriteChannel(); @@ -1623,18 +1624,18 @@ void tst_QTextStream::forcePoint() { QString str; QTextStream stream(&str); - stream << fixed << forcepoint << 1.0 << ' ' << 1 << ' ' << 0 << ' ' << -1.0 << ' ' << -1; + stream << Qt::fixed << Qt::forcepoint << 1.0 << ' ' << 1 << ' ' << 0 << ' ' << -1.0 << ' ' << -1; QCOMPARE(str, QString("1.000000 1 0 -1.000000 -1")); str.clear(); stream.seek(0); - stream << scientific << forcepoint << 1.0 << ' ' << 1 << ' ' << 0 << ' ' << -1.0 << ' ' << -1; + stream << Qt::scientific << Qt::forcepoint << 1.0 << ' ' << 1 << ' ' << 0 << ' ' << -1.0 << ' ' << -1; QCOMPARE(str, QString("1.000000e+00 1 0 -1.000000e+00 -1")); str.clear(); stream.seek(0); stream.setRealNumberNotation(QTextStream::SmartNotation); - stream << forcepoint << 1.0 << ' ' << 1 << ' ' << 0 << ' ' << -1.0 << ' ' << -1; + stream << Qt::forcepoint << 1.0 << ' ' << 1 << ' ' << 0 << ' ' << -1.0 << ' ' << -1; QCOMPARE(str, QString("1.00000 1 0 -1.00000 -1")); } @@ -1644,7 +1645,7 @@ void tst_QTextStream::forceSign() { QString str; QTextStream stream(&str); - stream << forcesign << 1.2 << ' ' << -1.2 << ' ' << 0; + stream << Qt::forcesign << 1.2 << ' ' << -1.2 << ' ' << 0; QCOMPARE(str, QString("+1.2 -1.2 +0")); } @@ -1663,19 +1664,22 @@ void tst_QTextStream::read0d0d0a() Q_DECLARE_METATYPE(QTextStreamFunction); +// Also tests that we can have namespaces that conflict with our QTextStream constants. +namespace ws { QTextStream &noop(QTextStream &s) { return s; } +} void tst_QTextStream::numeralCase_data() { - QTextStreamFunction noop_ = noop; - QTextStreamFunction bin_ = bin; - QTextStreamFunction oct_ = oct; - QTextStreamFunction hex_ = hex; - QTextStreamFunction base = showbase; - QTextStreamFunction ucb = uppercasebase; - QTextStreamFunction lcb = lowercasebase; - QTextStreamFunction ucd = uppercasedigits; - QTextStreamFunction lcd = lowercasedigits; + QTextStreamFunction noop_ = ws::noop; + QTextStreamFunction bin = Qt::bin; + QTextStreamFunction oct = Qt::oct; + QTextStreamFunction hex = Qt::hex; + QTextStreamFunction base = Qt::showbase; + QTextStreamFunction ucb = Qt::uppercasebase; + QTextStreamFunction lcb = Qt::lowercasebase; + QTextStreamFunction ucd = Qt::uppercasedigits; + QTextStreamFunction lcd = Qt::lowercasedigits; QTest::addColumn<QTextStreamFunction>("func1"); QTest::addColumn<QTextStreamFunction>("func2"); @@ -1686,30 +1690,30 @@ void tst_QTextStream::numeralCase_data() QTest::newRow("dec 1") << noop_ << noop_ << noop_ << noop_ << 31 << "31"; QTest::newRow("dec 2") << noop_ << base << noop_ << noop_ << 31 << "31"; - QTest::newRow("hex 1") << hex_ << noop_ << noop_ << noop_ << 31 << "1f"; - QTest::newRow("hex 2") << hex_ << noop_ << noop_ << lcd << 31 << "1f"; - QTest::newRow("hex 3") << hex_ << noop_ << ucb << noop_ << 31 << "1f"; - QTest::newRow("hex 4") << hex_ << noop_ << noop_ << ucd << 31 << "1F"; - QTest::newRow("hex 5") << hex_ << noop_ << lcb << ucd << 31 << "1F"; - QTest::newRow("hex 6") << hex_ << noop_ << ucb << ucd << 31 << "1F"; - QTest::newRow("hex 7") << hex_ << base << noop_ << noop_ << 31 << "0x1f"; - QTest::newRow("hex 8") << hex_ << base << lcb << lcd << 31 << "0x1f"; - QTest::newRow("hex 9") << hex_ << base << ucb << noop_ << 31 << "0X1f"; - QTest::newRow("hex 10") << hex_ << base << ucb << lcd << 31 << "0X1f"; - QTest::newRow("hex 11") << hex_ << base << noop_ << ucd << 31 << "0x1F"; - QTest::newRow("hex 12") << hex_ << base << lcb << ucd << 31 << "0x1F"; - QTest::newRow("hex 13") << hex_ << base << ucb << ucd << 31 << "0X1F"; - - QTest::newRow("bin 1") << bin_ << noop_ << noop_ << noop_ << 31 << "11111"; - QTest::newRow("bin 2") << bin_ << base << noop_ << noop_ << 31 << "0b11111"; - QTest::newRow("bin 3") << bin_ << base << lcb << noop_ << 31 << "0b11111"; - QTest::newRow("bin 4") << bin_ << base << ucb << noop_ << 31 << "0B11111"; - QTest::newRow("bin 5") << bin_ << base << noop_ << ucd << 31 << "0b11111"; - QTest::newRow("bin 6") << bin_ << base << lcb << ucd << 31 << "0b11111"; - QTest::newRow("bin 7") << bin_ << base << ucb << ucd << 31 << "0B11111"; - - QTest::newRow("oct 1") << oct_ << noop_ << noop_ << noop_ << 31 << "37"; - QTest::newRow("oct 2") << oct_ << base << noop_ << noop_ << 31 << "037"; + QTest::newRow("hex 1") << hex << noop_ << noop_ << noop_ << 31 << "1f"; + QTest::newRow("hex 2") << hex << noop_ << noop_ << lcd << 31 << "1f"; + QTest::newRow("hex 3") << hex << noop_ << ucb << noop_ << 31 << "1f"; + QTest::newRow("hex 4") << hex << noop_ << noop_ << ucd << 31 << "1F"; + QTest::newRow("hex 5") << hex << noop_ << lcb << ucd << 31 << "1F"; + QTest::newRow("hex 6") << hex << noop_ << ucb << ucd << 31 << "1F"; + QTest::newRow("hex 7") << hex << base << noop_ << noop_ << 31 << "0x1f"; + QTest::newRow("hex 8") << hex << base << lcb << lcd << 31 << "0x1f"; + QTest::newRow("hex 9") << hex << base << ucb << noop_ << 31 << "0X1f"; + QTest::newRow("hex 10") << hex << base << ucb << lcd << 31 << "0X1f"; + QTest::newRow("hex 11") << hex << base << noop_ << ucd << 31 << "0x1F"; + QTest::newRow("hex 12") << hex << base << lcb << ucd << 31 << "0x1F"; + QTest::newRow("hex 13") << hex << base << ucb << ucd << 31 << "0X1F"; + + QTest::newRow("bin 1") << bin << noop_ << noop_ << noop_ << 31 << "11111"; + QTest::newRow("bin 2") << bin << base << noop_ << noop_ << 31 << "0b11111"; + QTest::newRow("bin 3") << bin << base << lcb << noop_ << 31 << "0b11111"; + QTest::newRow("bin 4") << bin << base << ucb << noop_ << 31 << "0B11111"; + QTest::newRow("bin 5") << bin << base << noop_ << ucd << 31 << "0b11111"; + QTest::newRow("bin 6") << bin << base << lcb << ucd << 31 << "0b11111"; + QTest::newRow("bin 7") << bin << base << ucb << ucd << 31 << "0B11111"; + + QTest::newRow("oct 1") << oct << noop_ << noop_ << noop_ << 31 << "37"; + QTest::newRow("oct 2") << oct << base << noop_ << noop_ << 31 << "037"; } void tst_QTextStream::numeralCase() @@ -1782,9 +1786,9 @@ void tst_QTextStream::nanInf() QString s; QTextStream out(&s); out << qInf() << ' ' << -qInf() << ' ' << qQNaN() - << uppercasedigits << ' ' + << Qt::uppercasedigits << ' ' << qInf() << ' ' << -qInf() << ' ' << qQNaN() - << flush; + << Qt::flush; QCOMPARE(s, QString("inf -inf nan INF -INF NAN")); } @@ -1821,7 +1825,7 @@ void tst_QTextStream::utf8IncompleteAtBufferBoundary() out.setFieldWidth(3); for (int i = 0; i < 1000; ++i) { - out << i << lineContents << endl; + out << i << lineContents << Qt::endl; } } data.close(); @@ -1859,9 +1863,9 @@ void tst_QTextStream::writeSeekWriteNoBOM() int number = 0; QString sizeStr = QLatin1String("Size=") + QString::number(number).rightJustified(10, QLatin1Char('0')); - stream << sizeStr << endl; - stream << "Version=" << QString::number(14) << endl; - stream << "blah blah blah" << endl; + stream << sizeStr << Qt::endl; + stream << "Version=" << QString::number(14) << Qt::endl; + stream << "blah blah blah" << Qt::endl; stream.flush(); QCOMPARE(out.buffer().constData(), "Size=0000000000\nVersion=14\nblah blah blah\n"); @@ -1871,7 +1875,7 @@ void tst_QTextStream::writeSeekWriteNoBOM() stream.seek(0); sizeStr = QLatin1String("Size=") + QString::number(number).rightJustified(10, QLatin1Char('0')); - stream << sizeStr << endl; + stream << sizeStr << Qt::endl; stream.flush(); // Check buffer is still OK @@ -2582,7 +2586,7 @@ void tst_QTextStream::stringview_write_operator_ToDevice() QBuffer buf; buf.open(QBuffer::WriteOnly); QTextStream stream(&buf); - const QStringView expected = QStringViewLiteral("expectedStringView"); + const QStringView expected = u"expectedStringView"; stream << expected; stream.flush(); QCOMPARE(buf.buffer().constData(), "expectedStringView"); @@ -2723,7 +2727,7 @@ void tst_QTextStream::generateBOM() QTextStream stream(&file); stream.setCodec(QTextCodec::codecForName("UTF-16LE")); - stream << "Hello" << endl; + stream << "Hello" << Qt::endl; file.close(); QVERIFY(file.open(QFile::ReadOnly)); @@ -2737,7 +2741,7 @@ void tst_QTextStream::generateBOM() QTextStream stream(&file); stream.setCodec(QTextCodec::codecForName("UTF-16LE")); - stream << bom << "Hello" << endl; + stream << Qt::bom << "Hello" << Qt::endl; file.close(); QVERIFY(file.open(QFile::ReadOnly)); diff --git a/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp b/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp index 8fdf91b090..92a0d8bbfa 100644 --- a/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp +++ b/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp @@ -115,7 +115,7 @@ static QByteArray makeCanonical(const QString &filename, writeDtd << "<!DOCTYPE "; writeDtd << docType; writeDtd << " ["; - writeDtd << endl; + writeDtd << Qt::endl; for (const QXmlStreamNotationDeclaration ¬ation : sorted_by_name(notationDeclarations)) { writeDtd << "<!NOTATION "; writeDtd << notation.name().toString(); @@ -134,11 +134,11 @@ static QByteArray makeCanonical(const QString &filename, } } writeDtd << '>'; - writeDtd << endl; + writeDtd << Qt::endl; } writeDtd << "]>"; - writeDtd << endl; + writeDtd << Qt::endl; writer.writeDTD(dtd); } } else if (reader.isStartElement()) { @@ -253,7 +253,7 @@ public: qFatal("%s: aId must not be an empty string", Q_FUNC_INFO); } - void swap(MissedBaseline &other) Q_DECL_NOTHROW + void swap(MissedBaseline &other) noexcept { qSwap(id, other.id); qSwap(expected, other.expected); @@ -740,7 +740,7 @@ QByteArray tst_QXmlStream::readFile(const QString &filename) const auto attributes = reader.attributes(); if (attributes.size()) { for (const QXmlStreamAttribute &attribute : attributes) { - writer << endl << " Attribute("; + writer << Qt::endl << " Attribute("; if (!attribute.name().isEmpty()) writer << " name=\"" << attribute.name().toString() << '"'; if (!attribute.namespaceUri().isEmpty()) @@ -751,37 +751,37 @@ QByteArray tst_QXmlStream::readFile(const QString &filename) writer << " prefix=\"" << attribute.prefix().toString() << '"'; if (!attribute.value().isEmpty()) writer << " value=\"" << attribute.value().toString() << '"'; - writer << " )" << endl; + writer << " )" << Qt::endl; } } const auto namespaceDeclarations = reader.namespaceDeclarations(); if (namespaceDeclarations.size()) { for (const QXmlStreamNamespaceDeclaration &namespaceDeclaration : namespaceDeclarations) { - writer << endl << " NamespaceDeclaration("; + writer << Qt::endl << " NamespaceDeclaration("; if (!namespaceDeclaration.prefix().isEmpty()) writer << " prefix=\"" << namespaceDeclaration.prefix().toString() << '"'; if (!namespaceDeclaration.namespaceUri().isEmpty()) writer << " namespaceUri=\"" << namespaceDeclaration.namespaceUri().toString() << '"'; - writer << " )" << endl; + writer << " )" << Qt::endl; } } const auto notationDeclarations = reader.notationDeclarations(); if (notationDeclarations.size()) { for (const QXmlStreamNotationDeclaration ¬ationDeclaration : notationDeclarations) { - writer << endl << " NotationDeclaration("; + writer << Qt::endl << " NotationDeclaration("; if (!notationDeclaration.name().isEmpty()) writer << " name=\"" << notationDeclaration.name().toString() << '"'; if (!notationDeclaration.systemId().isEmpty()) writer << " systemId=\"" << notationDeclaration.systemId().toString() << '"'; if (!notationDeclaration.publicId().isEmpty()) writer << " publicId=\"" << notationDeclaration.publicId().toString() << '"'; - writer << " )" << endl; + writer << " )" << Qt::endl; } } const auto entityDeclarations = reader.entityDeclarations(); if (entityDeclarations.size()) { for (const QXmlStreamEntityDeclaration &entityDeclaration : entityDeclarations) { - writer << endl << " EntityDeclaration("; + writer << Qt::endl << " EntityDeclaration("; if (!entityDeclaration.name().isEmpty()) writer << " name=\"" << entityDeclaration.name().toString() << '"'; if (!entityDeclaration.notationName().isEmpty()) @@ -792,13 +792,13 @@ QByteArray tst_QXmlStream::readFile(const QString &filename) writer << " publicId=\"" << entityDeclaration.publicId().toString() << '"'; if (!entityDeclaration.value().isEmpty()) writer << " value=\"" << entityDeclaration.value().toString() << '"'; - writer << " )" << endl; + writer << " )" << Qt::endl; } } - writer << " )" << endl; + writer << " )" << Qt::endl; } if (reader.hasError()) - writer << "ERROR: " << reader.errorString() << endl; + writer << "ERROR: " << reader.errorString() << Qt::endl; return outarray; } @@ -1169,7 +1169,7 @@ int main(int argc, char *argv[]) bool error = false; QByteArray canonical = makeCanonical(argv[2], "doc", error); QTextStream myStdOut(stdout); - myStdOut << canonical << endl; + myStdOut << canonical << Qt::endl; exit(0); } diff --git a/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp b/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp index 810698fb4e..4b13ac45cc 100644 --- a/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp +++ b/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp @@ -336,7 +336,9 @@ void tst_QStateMachine::transitionToRootState() TEST_ACTIVE_CHANGED(initialState, 1); machine.postEvent(new QEvent(QEvent::User)); - QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: No common ancestor for targets and source of transition from state 'initial'"); + QTest::ignoreMessage(QtWarningMsg, + "Unrecoverable error detected in running state machine: " + "Child mode of state machine 'machine' is not 'ExclusiveStates'."); QCoreApplication::processEvents(); QVERIFY(machine.configuration().isEmpty()); QVERIFY(!machine.isRunning()); @@ -1061,7 +1063,8 @@ void tst_QStateMachine::transitionToStateNotInGraph() initialState->addTransition(&independentState); machine.start(); - QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: No common ancestor for targets and source of transition from state 'initialState'"); + QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: " + "Child mode of state machine '' is not 'ExclusiveStates'."); QCoreApplication::processEvents(); QCOMPARE(machine.isRunning(), false); @@ -1734,13 +1737,13 @@ protected: if (e->type() != QEvent::Type(QEvent::User+2)) return false; StringEvent *se = static_cast<StringEvent*>(e); - return (m_value == se->value) && (!m_cond.isValid() || (m_cond.indexIn(m_value) != -1)); + return (m_value == se->value) && (!m_cond.isValid() || m_cond.match(m_value).hasMatch()); } virtual void onTransition(QEvent *) {} private: QString m_value; - QRegExp m_cond; + QRegularExpression m_cond; }; class StringEventPoster : public QState @@ -2099,6 +2102,8 @@ void tst_QStateMachine::parallelRootState() QSignalSpy finishedSpy(&machine, &QStateMachine::finished); QVERIFY(finishedSpy.isValid()); machine.start(); + QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: " + "Child mode of state machine '' is not 'ExclusiveStates'."); QTRY_COMPARE(startedSpy.count(), 1); QCOMPARE(machine.configuration().size(), 4); QVERIFY(machine.configuration().contains(s1)); @@ -3310,14 +3315,15 @@ void tst_QStateMachine::targetStateWithNoParent() QVERIFY(runningSpy.isValid()); machine.start(); - QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: No common ancestor for targets and source of transition from state 's1'"); + QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: " + "Child mode of state machine '' is not 'ExclusiveStates'."); TEST_ACTIVE_CHANGED(s1, 2); QTRY_COMPARE(startedSpy.count(), 1); QCOMPARE(machine.isRunning(), false); QCOMPARE(stoppedSpy.count(), 1); QCOMPARE(finishedSpy.count(), 0); TEST_RUNNING_CHANGED_STARTED_STOPPED; - QCOMPARE(machine.error(), QStateMachine::NoCommonAncestorForTransitionError); + QCOMPARE(machine.error(), QStateMachine::StateMachineChildModeSetToParallelError); } void tst_QStateMachine::targetStateDeleted() @@ -6680,13 +6686,13 @@ void tst_QStateMachine::dontProcessSlotsWhenMachineIsNotRunning() } emitter; initialState.addTransition(&emitter, &Emitter::signalWithNoArg, &finalState); - QTimer::singleShot(0, [&]() { - metaObject()->invokeMethod(&emitter, "emitSignalWithNoArg"); - metaObject()->invokeMethod(&emitter, "emitSignalWithNoArg"); - }); machine.addState(&initialState); machine.addState(&finalState); machine.setInitialState(&initialState); + connect(&machine, &QStateMachine::started, &emitter, [&]() { + metaObject()->invokeMethod(&emitter, "emitSignalWithNoArg"); + metaObject()->invokeMethod(&emitter, "emitSignalWithNoArg"); + }); connect(&machine, &QStateMachine::finished, &emitter.thread, &QThread::quit); machine.start(); QSignalSpy emittedSpy(&emitter, &SignalEmitter::signalWithNoArg); diff --git a/tests/auto/corelib/tools/qbytearray/.gitattributes b/tests/auto/corelib/text/qbytearray/.gitattributes index e04709aa2e..e04709aa2e 100644 --- a/tests/auto/corelib/tools/qbytearray/.gitattributes +++ b/tests/auto/corelib/text/qbytearray/.gitattributes diff --git a/tests/auto/corelib/tools/qbytearray/.gitignore b/tests/auto/corelib/text/qbytearray/.gitignore index 3de7c3fab5..3de7c3fab5 100644 --- a/tests/auto/corelib/tools/qbytearray/.gitignore +++ b/tests/auto/corelib/text/qbytearray/.gitignore diff --git a/tests/auto/corelib/tools/qbytearray/android_testdata.qrc b/tests/auto/corelib/text/qbytearray/android_testdata.qrc index 5d42f0f627..5d42f0f627 100644 --- a/tests/auto/corelib/tools/qbytearray/android_testdata.qrc +++ b/tests/auto/corelib/text/qbytearray/android_testdata.qrc diff --git a/tests/auto/corelib/tools/qbytearray/qbytearray.pro b/tests/auto/corelib/text/qbytearray/qbytearray.pro index c2101b0611..c2101b0611 100644 --- a/tests/auto/corelib/tools/qbytearray/qbytearray.pro +++ b/tests/auto/corelib/text/qbytearray/qbytearray.pro diff --git a/tests/auto/corelib/tools/qbytearray/rfc3252.txt b/tests/auto/corelib/text/qbytearray/rfc3252.txt index b80c61bf0a..b80c61bf0a 100644 --- a/tests/auto/corelib/tools/qbytearray/rfc3252.txt +++ b/tests/auto/corelib/text/qbytearray/rfc3252.txt diff --git a/tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp b/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp index 1ed41793dc..90dfcaef25 100644 --- a/tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp +++ b/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp @@ -138,9 +138,7 @@ private slots: void reserveExtended(); void movablity_data(); void movablity(); -#if defined(Q_COMPILER_LAMBDA) void literals(); -#endif void toUpperLower_data(); void toUpperLower(); void isUpper(); @@ -1361,6 +1359,9 @@ void tst_QByteArray::toDouble_data() QTest::newRow("trailing spaces") << QByteArray("1.2345 \n\r\t") << 1.2345 << true; QTest::newRow("leading junk") << QByteArray("x1.2345") << 0.0 << false; QTest::newRow("trailing junk") << QByteArray("1.2345x") << 0.0 << false; + + QTest::newRow("raw, null plus junk") << QByteArray::fromRawData("1.2\0 junk", 9) << 0.0 << false; + QTest::newRow("raw, null-terminator not included") << QByteArray::fromRawData("2.3", 3) << 2.3 << true; } void tst_QByteArray::toDouble() @@ -1934,7 +1935,7 @@ void tst_QByteArray::repeatedSignature() const { /* repated() should be a const member. */ const QByteArray string; - string.repeated(3); + (void)string.repeated(3); } void tst_QByteArray::repeated() const @@ -2126,7 +2127,7 @@ void tst_QByteArray::movablity() { QFETCH(QByteArray, array); - QVERIFY(!QTypeInfo<QByteArray>::isStatic); + Q_STATIC_ASSERT(!QTypeInfo<QByteArray>::isStatic); const int size = array.size(); const bool isEmpty = array.isEmpty(); @@ -2138,7 +2139,7 @@ void tst_QByteArray::movablity() // we need only memory space not the instance memSpace.~QByteArray(); // move array -> memSpace - memcpy(&memSpace, &array, sizeof(QByteArray)); + memcpy((void *)&memSpace, (const void *)&array, sizeof(QByteArray)); // reconstruct empty QByteArray new (&array) QByteArray; @@ -2148,8 +2149,8 @@ void tst_QByteArray::movablity() QCOMPARE(memSpace.capacity(), capacity); // try to not crash - memSpace.toLower(); - memSpace.toUpper(); + (void)memSpace.toLower(); + (void)memSpace.toUpper(); memSpace.prepend('a'); memSpace.append("b", 1); memSpace.squeeze(); @@ -2165,7 +2166,7 @@ void tst_QByteArray::movablity() // move back memSpace -> array array.~QByteArray(); - memcpy(&array, &memSpace, sizeof(QByteArray)); + memcpy((void *)&array, (const void *)&memSpace, sizeof(QByteArray)); // reconstruct empty QByteArray new (&memSpace) QByteArray; @@ -2189,7 +2190,6 @@ void tst_QByteArray::movablity() QVERIFY(true); } -#if defined(Q_COMPILER_LAMBDA) // Only tested on c++0x compliant compiler or gcc void tst_QByteArray::literals() { @@ -2210,7 +2210,6 @@ void tst_QByteArray::literals() QVERIFY(str2.constData() == s); QVERIFY(str2.data() != s); } -#endif void tst_QByteArray::toUpperLower_data() { @@ -2242,28 +2241,28 @@ void tst_QByteArray::toUpperLower() QCOMPARE(input.toLower(), lower); QByteArray copy = input; - QCOMPARE(qMove(copy).toUpper(), upper); + QCOMPARE(std::move(copy).toUpper(), upper); copy = input; copy.detach(); - QCOMPARE(qMove(copy).toUpper(), upper); + QCOMPARE(std::move(copy).toUpper(), upper); copy = input; - QCOMPARE(qMove(copy).toLower(), lower); + QCOMPARE(std::move(copy).toLower(), lower); copy = input; copy.detach(); - QCOMPARE(qMove(copy).toLower(), lower); + QCOMPARE(std::move(copy).toLower(), lower); copy = lower; - QCOMPARE(qMove(copy).toLower(), lower); + QCOMPARE(std::move(copy).toLower(), lower); copy = lower; copy.detach(); - QCOMPARE(qMove(copy).toLower(), lower); + QCOMPARE(std::move(copy).toLower(), lower); copy = upper; - QCOMPARE(qMove(copy).toUpper(), upper); + QCOMPARE(std::move(copy).toUpper(), upper); copy = upper; copy.detach(); - QCOMPARE(qMove(copy).toUpper(), upper); + QCOMPARE(std::move(copy).toUpper(), upper); } void tst_QByteArray::isUpper() diff --git a/tests/auto/corelib/tools/qbytearray/tst_qbytearray_mac.mm b/tests/auto/corelib/text/qbytearray/tst_qbytearray_mac.mm index 98146e3525..98146e3525 100644 --- a/tests/auto/corelib/tools/qbytearray/tst_qbytearray_mac.mm +++ b/tests/auto/corelib/text/qbytearray/tst_qbytearray_mac.mm diff --git a/tests/auto/corelib/tools/qbytearraylist/qbytearraylist.pro b/tests/auto/corelib/text/qbytearraylist/qbytearraylist.pro index 6c05c288cf..6c05c288cf 100644 --- a/tests/auto/corelib/tools/qbytearraylist/qbytearraylist.pro +++ b/tests/auto/corelib/text/qbytearraylist/qbytearraylist.pro diff --git a/tests/auto/corelib/tools/qbytearraylist/tst_qbytearraylist.cpp b/tests/auto/corelib/text/qbytearraylist/tst_qbytearraylist.cpp index 2d2c536453..09ce41337e 100644 --- a/tests/auto/corelib/tools/qbytearraylist/tst_qbytearraylist.cpp +++ b/tests/auto/corelib/text/qbytearraylist/tst_qbytearraylist.cpp @@ -194,22 +194,22 @@ void tst_QByteArrayList::operator_plus() const { QByteArrayList bal1 = lhs; const QByteArrayList bal2 = rhs; - QCOMPARE(qMove(bal1) + bal2, expectedResult); + QCOMPARE(std::move(bal1) + bal2, expectedResult); } { QList<QByteArray> lba1 = lhs; const QByteArrayList bal2 = rhs; - QCOMPARE(qMove(lba1) + bal2, expectedResult); + QCOMPARE(std::move(lba1) + bal2, expectedResult); } { QByteArrayList bal1 = lhs; const QList<QByteArray> lba2 = rhs; - QCOMPARE(qMove(bal1) + lba2, expectedResult); + QCOMPARE(std::move(bal1) + lba2, expectedResult); } { QList<QByteArray> lba1 = lhs; const QList<QByteArray> lba2 = rhs; - QCOMPARE(qMove(lba1) + lba2, QList<QByteArray>(expectedResult)); // check we don't mess with old code + QCOMPARE(std::move(lba1) + lba2, QList<QByteArray>(expectedResult)); // check we don't mess with old code } // operator += for const lvalues @@ -232,7 +232,7 @@ void tst_QByteArrayList::operator_plus() const QByteArrayList t1 = lhs; QByteArrayList t2 = rhs; - QCOMPARE(qMove(t1) + t2, expectedResult); + QCOMPARE(std::move(t1) + t2, expectedResult); } void tst_QByteArrayList::operator_plus_data() const @@ -287,7 +287,6 @@ void tst_QByteArrayList::indexOf() const void tst_QByteArrayList::initializerList() const { -#ifdef Q_COMPILER_INITIALIZER_LISTS // constructor QByteArrayList v1 = {QByteArray("hello"),"world",QByteArray("plop")}; QCOMPARE(v1, (QByteArrayList() << "hello" << "world" << "plop")); @@ -296,9 +295,6 @@ void tst_QByteArrayList::initializerList() const QByteArrayList v2; v2 = {QByteArray("hello"),"world",QByteArray("plop")}; QCOMPARE(v2, v1); -#else - QSKIP("This test requires C++11 initializer_list support in the compiler."); -#endif } QTEST_APPLESS_MAIN(tst_QByteArrayList) diff --git a/tests/auto/corelib/tools/qbytearraymatcher/qbytearraymatcher.pro b/tests/auto/corelib/text/qbytearraymatcher/qbytearraymatcher.pro index 9d4d5964c9..9d4d5964c9 100644 --- a/tests/auto/corelib/tools/qbytearraymatcher/qbytearraymatcher.pro +++ b/tests/auto/corelib/text/qbytearraymatcher/qbytearraymatcher.pro diff --git a/tests/auto/corelib/tools/qbytearraymatcher/tst_qbytearraymatcher.cpp b/tests/auto/corelib/text/qbytearraymatcher/tst_qbytearraymatcher.cpp index 647a3ae379..647a3ae379 100644 --- a/tests/auto/corelib/tools/qbytearraymatcher/tst_qbytearraymatcher.cpp +++ b/tests/auto/corelib/text/qbytearraymatcher/tst_qbytearraymatcher.cpp diff --git a/tests/auto/corelib/tools/qbytedatabuffer/.gitignore b/tests/auto/corelib/text/qbytedatabuffer/.gitignore index 3024a4dba2..3024a4dba2 100644 --- a/tests/auto/corelib/tools/qbytedatabuffer/.gitignore +++ b/tests/auto/corelib/text/qbytedatabuffer/.gitignore diff --git a/tests/auto/corelib/tools/qbytedatabuffer/qbytedatabuffer.pro b/tests/auto/corelib/text/qbytedatabuffer/qbytedatabuffer.pro index e23018f96a..e23018f96a 100644 --- a/tests/auto/corelib/tools/qbytedatabuffer/qbytedatabuffer.pro +++ b/tests/auto/corelib/text/qbytedatabuffer/qbytedatabuffer.pro diff --git a/tests/auto/corelib/tools/qbytedatabuffer/tst_qbytedatabuffer.cpp b/tests/auto/corelib/text/qbytedatabuffer/tst_qbytedatabuffer.cpp index 59f4d153e6..59f4d153e6 100644 --- a/tests/auto/corelib/tools/qbytedatabuffer/tst_qbytedatabuffer.cpp +++ b/tests/auto/corelib/text/qbytedatabuffer/tst_qbytedatabuffer.cpp diff --git a/tests/auto/corelib/tools/qchar/.gitignore b/tests/auto/corelib/text/qchar/.gitignore index 341b3e6c3f..341b3e6c3f 100644 --- a/tests/auto/corelib/tools/qchar/.gitignore +++ b/tests/auto/corelib/text/qchar/.gitignore diff --git a/tests/auto/corelib/tools/qchar/data/NormalizationTest.txt b/tests/auto/corelib/text/qchar/data/NormalizationTest.txt index 0290080998..0290080998 100644 --- a/tests/auto/corelib/tools/qchar/data/NormalizationTest.txt +++ b/tests/auto/corelib/text/qchar/data/NormalizationTest.txt diff --git a/tests/auto/corelib/tools/qchar/qchar.pro b/tests/auto/corelib/text/qchar/qchar.pro index 70c1222988..70c1222988 100644 --- a/tests/auto/corelib/tools/qchar/qchar.pro +++ b/tests/auto/corelib/text/qchar/qchar.pro diff --git a/tests/auto/corelib/tools/qchar/testdata.qrc b/tests/auto/corelib/text/qchar/testdata.qrc index 7b3fb2461c..7b3fb2461c 100644 --- a/tests/auto/corelib/tools/qchar/testdata.qrc +++ b/tests/auto/corelib/text/qchar/testdata.qrc diff --git a/tests/auto/corelib/tools/qchar/tst_qchar.cpp b/tests/auto/corelib/text/qchar/tst_qchar.cpp index cf4f6d21e2..cf4f6d21e2 100644 --- a/tests/auto/corelib/tools/qchar/tst_qchar.cpp +++ b/tests/auto/corelib/text/qchar/tst_qchar.cpp diff --git a/tests/auto/corelib/tools/qcollator/qcollator.pro b/tests/auto/corelib/text/qcollator/qcollator.pro index 2f3995a75f..b7aa256ded 100644 --- a/tests/auto/corelib/tools/qcollator/qcollator.pro +++ b/tests/auto/corelib/text/qcollator/qcollator.pro @@ -3,4 +3,3 @@ TARGET = tst_qcollator QT = core-private testlib SOURCES = tst_qcollator.cpp DEFINES += QT_NO_CAST_TO_ASCII -qtConfig(icu): DEFINES += QT_USE_ICU diff --git a/tests/auto/corelib/tools/qcollator/tst_qcollator.cpp b/tests/auto/corelib/text/qcollator/tst_qcollator.cpp index 72f88a235d..2ae9c6e159 100644 --- a/tests/auto/corelib/tools/qcollator/tst_qcollator.cpp +++ b/tests/auto/corelib/text/qcollator/tst_qcollator.cpp @@ -47,7 +47,6 @@ private Q_SLOTS: void state(); }; -#ifdef Q_COMPILER_RVALUE_REFS static bool dpointer_is_null(QCollator &c) { char mem[sizeof c]; @@ -58,11 +57,9 @@ static bool dpointer_is_null(QCollator &c) return false; return true; } -#endif void tst_QCollator::moveSemantics() { -#ifdef Q_COMPILER_RVALUE_REFS const QLocale de_AT(QLocale::German, QLocale::Austria); QCollator c1(de_AT); @@ -78,9 +75,6 @@ void tst_QCollator::moveSemantics() c1 = std::move(c2); QCOMPARE(c1.locale(), de_AT); QVERIFY(dpointer_is_null(c2)); -#else - QSKIP("The compiler is not in C++11 mode or does not support move semantics."); -#endif } diff --git a/tests/auto/corelib/tools/qlatin1string/.gitignore b/tests/auto/corelib/text/qlatin1string/.gitignore index dddf56b2df..dddf56b2df 100644 --- a/tests/auto/corelib/tools/qlatin1string/.gitignore +++ b/tests/auto/corelib/text/qlatin1string/.gitignore diff --git a/tests/auto/corelib/tools/qlatin1string/qlatin1string.pro b/tests/auto/corelib/text/qlatin1string/qlatin1string.pro index 61054b40e4..61054b40e4 100644 --- a/tests/auto/corelib/tools/qlatin1string/qlatin1string.pro +++ b/tests/auto/corelib/text/qlatin1string/qlatin1string.pro diff --git a/tests/auto/corelib/tools/qlatin1string/tst_qlatin1string.cpp b/tests/auto/corelib/text/qlatin1string/tst_qlatin1string.cpp index dcfb0aa042..0427c81b85 100644 --- a/tests/auto/corelib/tools/qlatin1string/tst_qlatin1string.cpp +++ b/tests/auto/corelib/text/qlatin1string/tst_qlatin1string.cpp @@ -45,6 +45,7 @@ class tst_QLatin1String : public QObject private Q_SLOTS: void at(); + void arg() const; void midLeftRight(); void nullString(); void emptyString(); @@ -63,6 +64,47 @@ void tst_QLatin1String::at() QCOMPARE(l1[l1.size() - 1], QLatin1Char('d')); } +void tst_QLatin1String::arg() const +{ +#define CHECK1(pattern, arg1, expected) \ + do { \ + auto p = QLatin1String(pattern); \ + QCOMPARE(p.arg(QLatin1String(arg1)), expected); \ + QCOMPARE(p.arg(u"" arg1), expected); \ + QCOMPARE(p.arg(QStringLiteral(arg1)), expected); \ + QCOMPARE(p.arg(QString(QLatin1String(arg1))), expected); \ + } while (false) \ + /*end*/ +#define CHECK2(pattern, arg1, arg2, expected) \ + do { \ + auto p = QLatin1String(pattern); \ + QCOMPARE(p.arg(QLatin1String(arg1), QLatin1String(arg2)), expected); \ + QCOMPARE(p.arg(u"" arg1, QLatin1String(arg2)), expected); \ + QCOMPARE(p.arg(QLatin1String(arg1), u"" arg2), expected); \ + QCOMPARE(p.arg(u"" arg1, u"" arg2), expected); \ + } while (false) \ + /*end*/ + + CHECK1("", "World", ""); + CHECK1("%1", "World", "World"); + CHECK1("!%1?", "World", "!World?"); + CHECK1("%1%1", "World", "WorldWorld"); + CHECK1("%1%2", "World", "World%2"); + CHECK1("%2%1", "World", "%2World"); + + CHECK2("", "Hello", "World", ""); + CHECK2("%1", "Hello", "World", "Hello"); + CHECK2("!%1, %2?", "Hello", "World", "!Hello, World?"); + CHECK2("%1%1", "Hello", "World", "HelloHello"); + CHECK2("%1%2", "Hello", "World", "HelloWorld"); + CHECK2("%2%1", "Hello", "World", "WorldHello"); + +#undef CHECK2 +#undef CHECK1 + + QCOMPARE(QLatin1String(" %2 %2 %1 %3 ").arg(QLatin1Char('c'), QChar::CarriageReturn, u'C'), " \r \r c C "); +} + void tst_QLatin1String::midLeftRight() { const QLatin1String l1("Hello World"); diff --git a/tests/auto/corelib/tools/qlocale/.gitignore b/tests/auto/corelib/text/qlocale/.gitignore index 21ab80a2af..21ab80a2af 100644 --- a/tests/auto/corelib/tools/qlocale/.gitignore +++ b/tests/auto/corelib/text/qlocale/.gitignore diff --git a/tests/auto/corelib/tools/qlocale/qlocale.pro b/tests/auto/corelib/text/qlocale/qlocale.pro index 5161200260..5161200260 100644 --- a/tests/auto/corelib/tools/qlocale/qlocale.pro +++ b/tests/auto/corelib/text/qlocale/qlocale.pro diff --git a/tests/auto/corelib/tools/qlocale/syslocaleapp/syslocaleapp.cpp b/tests/auto/corelib/text/qlocale/syslocaleapp/syslocaleapp.cpp index 1e1bcc8c5f..1e1bcc8c5f 100644 --- a/tests/auto/corelib/tools/qlocale/syslocaleapp/syslocaleapp.cpp +++ b/tests/auto/corelib/text/qlocale/syslocaleapp/syslocaleapp.cpp diff --git a/tests/auto/corelib/tools/qlocale/syslocaleapp/syslocaleapp.pro b/tests/auto/corelib/text/qlocale/syslocaleapp/syslocaleapp.pro index 3e283c05a4..3e283c05a4 100644 --- a/tests/auto/corelib/tools/qlocale/syslocaleapp/syslocaleapp.pro +++ b/tests/auto/corelib/text/qlocale/syslocaleapp/syslocaleapp.pro diff --git a/tests/auto/corelib/tools/qlocale/test/test.pro b/tests/auto/corelib/text/qlocale/test/test.pro index f7243e99a7..f7243e99a7 100644 --- a/tests/auto/corelib/tools/qlocale/test/test.pro +++ b/tests/auto/corelib/text/qlocale/test/test.pro diff --git a/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp index be2e2a2e08..3aa3d97dbc 100644 --- a/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp +++ b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. @@ -423,6 +423,7 @@ void tst_QLocale::defaulted_ctor() } QLocale::setDefault(QLocale(QLocale::C)); + const QString empty; TEST_CTOR("C", C, AnyCountry) TEST_CTOR("bla", C, AnyCountry) @@ -431,7 +432,7 @@ void tst_QLocale::defaulted_ctor() TEST_CTOR("zz...", C, AnyCountry) TEST_CTOR("", C, AnyCountry) TEST_CTOR("en/", C, AnyCountry) - TEST_CTOR(QString::null, C, AnyCountry) + TEST_CTOR(empty, C, AnyCountry) TEST_CTOR("en", English, UnitedStates) TEST_CTOR("en", English, UnitedStates) TEST_CTOR("en.", English, UnitedStates) @@ -1458,8 +1459,8 @@ void tst_QLocale::dayOfWeek() QCOMPARE(QLocale::c().toString(date, "ddd"), shortName); QCOMPARE(QLocale::c().toString(date, "dddd"), longName); - QCOMPARE(QLocale::c().toString(date, QStringViewLiteral("ddd")), shortName); - QCOMPARE(QLocale::c().toString(date, QStringViewLiteral("dddd")), longName); + QCOMPARE(QLocale::c().toString(date, u"ddd"), shortName); + QCOMPARE(QLocale::c().toString(date, u"dddd"), longName); } void tst_QLocale::formatDate_data() @@ -2458,9 +2459,9 @@ void tst_QLocale::timeFormat() QCOMPARE(c.timeFormat(QLocale::NarrowFormat), c.timeFormat(QLocale::ShortFormat)); const QLocale no("no_NO"); - QCOMPARE(no.timeFormat(QLocale::NarrowFormat), QLatin1String("HH.mm")); - QCOMPARE(no.timeFormat(QLocale::ShortFormat), QLatin1String("HH.mm")); - QCOMPARE(no.timeFormat(QLocale::LongFormat), QLatin1String("HH.mm.ss t")); + QCOMPARE(no.timeFormat(QLocale::NarrowFormat), QLatin1String("HH:mm")); + QCOMPARE(no.timeFormat(QLocale::ShortFormat), QLatin1String("HH:mm")); + QCOMPARE(no.timeFormat(QLocale::LongFormat), QLatin1String("HH:mm:ss t")); const QLocale id("id_ID"); QCOMPARE(id.timeFormat(QLocale::ShortFormat), QLatin1String("HH.mm")); @@ -2482,9 +2483,9 @@ void tst_QLocale::dateTimeFormat() QCOMPARE(c.dateTimeFormat(QLocale::NarrowFormat), c.dateTimeFormat(QLocale::ShortFormat)); const QLocale no("no_NO"); - QCOMPARE(no.dateTimeFormat(QLocale::NarrowFormat), QLatin1String("dd.MM.yyyy HH.mm")); - QCOMPARE(no.dateTimeFormat(QLocale::ShortFormat), QLatin1String("dd.MM.yyyy HH.mm")); - QCOMPARE(no.dateTimeFormat(QLocale::LongFormat), QLatin1String("dddd d. MMMM yyyy HH.mm.ss t")); + QCOMPARE(no.dateTimeFormat(QLocale::NarrowFormat), QLatin1String("dd.MM.yyyy HH:mm")); + QCOMPARE(no.dateTimeFormat(QLocale::ShortFormat), QLatin1String("dd.MM.yyyy HH:mm")); + QCOMPARE(no.dateTimeFormat(QLocale::LongFormat), QLatin1String("dddd d. MMMM yyyy HH:mm:ss t")); } void tst_QLocale::monthName() diff --git a/tests/auto/corelib/tools/qregexp/.gitignore b/tests/auto/corelib/text/qregexp/.gitignore index e6e629ee2c..e6e629ee2c 100644 --- a/tests/auto/corelib/tools/qregexp/.gitignore +++ b/tests/auto/corelib/text/qregexp/.gitignore diff --git a/tests/auto/corelib/tools/qregexp/qregexp.pro b/tests/auto/corelib/text/qregexp/qregexp.pro index 5f6ff0a71c..5f6ff0a71c 100644 --- a/tests/auto/corelib/tools/qregexp/qregexp.pro +++ b/tests/auto/corelib/text/qregexp/qregexp.pro diff --git a/tests/auto/corelib/tools/qregexp/tst_qregexp.cpp b/tests/auto/corelib/text/qregexp/tst_qregexp.cpp index a8111af6c1..a8111af6c1 100644 --- a/tests/auto/corelib/tools/qregexp/tst_qregexp.cpp +++ b/tests/auto/corelib/text/qregexp/tst_qregexp.cpp diff --git a/tests/auto/corelib/tools/qregularexpression/.gitignore b/tests/auto/corelib/text/qregularexpression/.gitignore index 4650b4454e..4650b4454e 100644 --- a/tests/auto/corelib/tools/qregularexpression/.gitignore +++ b/tests/auto/corelib/text/qregularexpression/.gitignore diff --git a/tests/auto/corelib/tools/qregularexpression/qregularexpression.pro b/tests/auto/corelib/text/qregularexpression/qregularexpression.pro index ec8189717e..ec8189717e 100644 --- a/tests/auto/corelib/tools/qregularexpression/qregularexpression.pro +++ b/tests/auto/corelib/text/qregularexpression/qregularexpression.pro diff --git a/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.cpp b/tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp index c02756d76a..c02756d76a 100644 --- a/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.cpp +++ b/tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp diff --git a/tests/auto/corelib/tools/qstring/.gitignore b/tests/auto/corelib/text/qstring/.gitignore index c2ea8d0336..c2ea8d0336 100644 --- a/tests/auto/corelib/tools/qstring/.gitignore +++ b/tests/auto/corelib/text/qstring/.gitignore diff --git a/tests/auto/corelib/tools/qstring/double_data.h b/tests/auto/corelib/text/qstring/double_data.h index 0d59ecb5ff..0d59ecb5ff 100644 --- a/tests/auto/corelib/tools/qstring/double_data.h +++ b/tests/auto/corelib/text/qstring/double_data.h diff --git a/tests/auto/corelib/tools/qstring/qstring.pro b/tests/auto/corelib/text/qstring/qstring.pro index ec8a9b5df5..5fff5530b7 100644 --- a/tests/auto/corelib/tools/qstring/qstring.pro +++ b/tests/auto/corelib/text/qstring/qstring.pro @@ -2,8 +2,7 @@ CONFIG += testcase TARGET = tst_qstring QT = core-private testlib SOURCES = tst_qstring.cpp -DEFINES += QT_NO_CAST_TO_ASCII -qtConfig(icu): DEFINES += QT_USE_ICU +# DEFINES += QT_NO_CAST_TO_ASCII # actively #undef-ed by tst_qstring.cpp qtConfig(c++11): CONFIG += c++11 DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/corelib/tools/qstring/tst_qstring.cpp b/tests/auto/corelib/text/qstring/tst_qstring.cpp index e8ed22e427..2108e99f20 100644 --- a/tests/auto/corelib/tools/qstring/tst_qstring.cpp +++ b/tests/auto/corelib/text/qstring/tst_qstring.cpp @@ -37,6 +37,7 @@ # undef QT_ASCII_CAST_WARNINGS #endif +#include <private/qglobal_p.h> // for the icu feature test #include <QtTest/QtTest> #include <qregexp.h> #include <qregularexpression.h> @@ -482,8 +483,8 @@ private slots: void indexOf2(); void indexOf3_data(); // void indexOf3(); - void sprintf(); - void sprintfS(); + void asprintf(); + void asprintfS(); void fill(); void truncate(); void chop_data(); @@ -521,7 +522,9 @@ private slots: void stringRef_local8Bit_data(); void stringRef_local8Bit(); void fromLatin1(); +#if QT_DEPRECATED_SINCE(5, 0) void fromAscii(); +#endif void fromUcs4(); void toUcs4(); void arg(); @@ -575,10 +578,10 @@ private slots: void repeated_data() const; void compareRef(); void arg_locale(); -#ifdef QT_USE_ICU +#if QT_CONFIG(icu) void toUpperLower_icu(); #endif -#if !defined(QT_NO_UNICODE_LITERAL) && defined(Q_COMPILER_LAMBDA) +#if !defined(QT_NO_UNICODE_LITERAL) void literals(); #endif void eightBitLiterals_data(); @@ -612,7 +615,7 @@ QString verifyZeroTermination(const QString &str) int strSize = str.size(); QChar strTerminator = str.constData()[strSize]; if (QChar('\0') != strTerminator) - return QString::fromAscii( + return QString::fromLatin1( "*** Result ('%1') not null-terminated: 0x%2 ***").arg(str) .arg(strTerminator.unicode(), 4, 16, QChar('0')); @@ -625,11 +628,11 @@ QString verifyZeroTermination(const QString &str) const_cast<QChar *>(strData)[strSize] = QChar('x'); if (QChar('x') != str.constData()[strSize]) { - return QString::fromAscii("*** Failed to replace null-terminator in " + return QString::fromLatin1("*** Failed to replace null-terminator in " "result ('%1') ***").arg(str); } if (str != strCopy) { - return QString::fromAscii( "*** Result ('%1') differs from its copy " + return QString::fromLatin1( "*** Result ('%1') differs from its copy " "after null-terminator was replaced ***").arg(str); } const_cast<QChar *>(strData)[strSize] = QChar('\0'); // Restore sanity @@ -1075,9 +1078,8 @@ void tst_QString::isNull() QString a; QVERIFY(a.isNull()); - const char *zero = 0; - a.sprintf( zero ); - QVERIFY(!a.isNull()); + const char *zero = nullptr; + QVERIFY(!QString::asprintf(zero).isNull()); } QT_WARNING_POP @@ -1263,75 +1265,66 @@ static inline const void *ptrValue(quintptr v) return reinterpret_cast<const void *>(v); } -void tst_QString::sprintf() +void tst_QString::asprintf() { QString a; - a.sprintf("COMPARE"); - QCOMPARE(a, QLatin1String("COMPARE")); - a.sprintf("%%%d",1); - QCOMPARE(a, QLatin1String("%1")); - QCOMPARE(a.sprintf("X%dY",2), QLatin1String("X2Y")); - QCOMPARE(a.sprintf("X%9iY", 50000 ), QLatin1String("X 50000Y")); - QCOMPARE(a.sprintf("X%-9sY","hello"), QLatin1String("Xhello Y")); - QCOMPARE(a.sprintf("X%-9iY", 50000 ), QLatin1String("X50000 Y")); - QCOMPARE(a.sprintf("%lf", 1.23), QLatin1String("1.230000")); - QCOMPARE(a.sprintf("%lf", 1.23456789), QLatin1String("1.234568")); - QCOMPARE(a.sprintf("%p", ptrValue(0xbfffd350)), QLatin1String("0xbfffd350")); - QCOMPARE(a.sprintf("%p", ptrValue(0)), QLatin1String("0x0")); + QCOMPARE(QString::asprintf("COMPARE"), QLatin1String("COMPARE")); + QCOMPARE(QString::asprintf("%%%d", 1), QLatin1String("%1")); + QCOMPARE(QString::asprintf("X%dY",2), QLatin1String("X2Y")); + QCOMPARE(QString::asprintf("X%9iY", 50000 ), QLatin1String("X 50000Y")); + QCOMPARE(QString::asprintf("X%-9sY","hello"), QLatin1String("Xhello Y")); + QCOMPARE(QString::asprintf("X%-9iY", 50000 ), QLatin1String("X50000 Y")); + QCOMPARE(QString::asprintf("%lf", 1.23), QLatin1String("1.230000")); + QCOMPARE(QString::asprintf("%lf", 1.23456789), QLatin1String("1.234568")); + QCOMPARE(QString::asprintf("%p", ptrValue(0xbfffd350)), QLatin1String("0xbfffd350")); + QCOMPARE(QString::asprintf("%p", ptrValue(0)), QLatin1String("0x0")); int i = 6; long l = -2; float f = 4.023f; - QString S1; - S1.sprintf("%d %ld %f",i,l,f); - QCOMPARE(S1, QLatin1String("6 -2 4.023000")); + QCOMPARE(QString::asprintf("%d %ld %f", i, l, f), QLatin1String("6 -2 4.023000")); double d = -514.25683; - S1.sprintf("%f",d); - QCOMPARE(S1, QLatin1String("-514.256830")); + QCOMPARE(QString::asprintf("%f", d), QLatin1String("-514.256830")); } -void tst_QString::sprintfS() +void tst_QString::asprintfS() { - QString a; - QCOMPARE(a.sprintf("%.3s", "Hello" ), QLatin1String("Hel")); - QCOMPARE(a.sprintf("%10.3s", "Hello" ), QLatin1String(" Hel")); - QCOMPARE(a.sprintf("%.10s", "Hello" ), QLatin1String("Hello")); - QCOMPARE(a.sprintf("%10.10s", "Hello" ), QLatin1String(" Hello")); - QCOMPARE(a.sprintf("%-10.10s", "Hello" ), QLatin1String("Hello ")); - QCOMPARE(a.sprintf("%-10.3s", "Hello" ), QLatin1String("Hel ")); - QCOMPARE(a.sprintf("%-5.5s", "Hello" ), QLatin1String("Hello")); + QCOMPARE(QString::asprintf("%.3s", "Hello" ), QLatin1String("Hel")); + QCOMPARE(QString::asprintf("%10.3s", "Hello" ), QLatin1String(" Hel")); + QCOMPARE(QString::asprintf("%.10s", "Hello" ), QLatin1String("Hello")); + QCOMPARE(QString::asprintf("%10.10s", "Hello" ), QLatin1String(" Hello")); + QCOMPARE(QString::asprintf("%-10.10s", "Hello" ), QLatin1String("Hello ")); + QCOMPARE(QString::asprintf("%-10.3s", "Hello" ), QLatin1String("Hel ")); + QCOMPARE(QString::asprintf("%-5.5s", "Hello" ), QLatin1String("Hello")); // Check utf8 conversion for %s - QCOMPARE(a.sprintf("%s", "\303\266\303\244\303\274\303\226\303\204\303\234\303\270\303\246\303\245\303\230\303\206\303\205"), QString::fromLatin1("\366\344\374\326\304\334\370\346\345\330\306\305")); + QCOMPARE(QString::asprintf("%s", "\303\266\303\244\303\274\303\226\303\204\303\234\303\270\303\246\303\245\303\230\303\206\303\205"), QString::fromLatin1("\366\344\374\326\304\334\370\346\345\330\306\305")); int n1; - a.sprintf("%s%n%s", "hello", &n1, "goodbye"); + QCOMPARE(QString::asprintf("%s%n%s", "hello", &n1, "goodbye"), QString("hellogoodbye")); QCOMPARE(n1, 5); - QCOMPARE(a, QString("hellogoodbye")); qlonglong n2; - a.sprintf("%s%s%lln%s", "foo", "bar", &n2, "whiz"); + QCOMPARE(QString::asprintf("%s%s%lln%s", "foo", "bar", &n2, "whiz"), QString("foobarwhiz")); QCOMPARE((int)n2, 6); - QCOMPARE(a, QString("foobarwhiz")); { // %ls - QCOMPARE(a.sprintf("%.3ls", qUtf16Printable("Hello")), QLatin1String("Hel")); - QCOMPARE(a.sprintf("%10.3ls", qUtf16Printable("Hello")), QLatin1String(" Hel")); - QCOMPARE(a.sprintf("%.10ls", qUtf16Printable("Hello")), QLatin1String("Hello")); - QCOMPARE(a.sprintf("%10.10ls", qUtf16Printable("Hello")), QLatin1String(" Hello")); - QCOMPARE(a.sprintf("%-10.10ls", qUtf16Printable("Hello")), QLatin1String("Hello ")); - QCOMPARE(a.sprintf("%-10.3ls", qUtf16Printable("Hello")), QLatin1String("Hel ")); - QCOMPARE(a.sprintf("%-5.5ls", qUtf16Printable("Hello")), QLatin1String("Hello")); + QCOMPARE(QString::asprintf("%.3ls", qUtf16Printable("Hello")), QLatin1String("Hel")); + QCOMPARE(QString::asprintf("%10.3ls", qUtf16Printable("Hello")), QLatin1String(" Hel")); + QCOMPARE(QString::asprintf("%.10ls", qUtf16Printable("Hello")), QLatin1String("Hello")); + QCOMPARE(QString::asprintf("%10.10ls", qUtf16Printable("Hello")), QLatin1String(" Hello")); + QCOMPARE(QString::asprintf("%-10.10ls", qUtf16Printable("Hello")), QLatin1String("Hello ")); + QCOMPARE(QString::asprintf("%-10.3ls", qUtf16Printable("Hello")), QLatin1String("Hel ")); + QCOMPARE(QString::asprintf("%-5.5ls", qUtf16Printable("Hello")), QLatin1String("Hello")); // Check utf16 is preserved for %ls - QCOMPARE(a.sprintf("%ls", + QCOMPARE(QString::asprintf("%ls", qUtf16Printable("\303\266\303\244\303\274\303\226\303\204\303\234\303\270\303\246\303\245\303\230\303\206\303\205")), QLatin1String("\366\344\374\326\304\334\370\346\345\330\306\305")); int n; - a.sprintf("%ls%n%s", qUtf16Printable("hello"), &n, "goodbye"); + QCOMPARE(QString::asprintf("%ls%n%s", qUtf16Printable("hello"), &n, "goodbye"), QLatin1String("hellogoodbye")); QCOMPARE(n, 5); - QCOMPARE(a, QLatin1String("hellogoodbye")); } } @@ -2212,12 +2205,12 @@ void tst_QString::toUpper() // call rvalue-ref while shared (the original mustn't change) QString copy = s; - QCOMPARE(qMove(copy).toUpper(), QString("GROSSSTRASSE")); + QCOMPARE(std::move(copy).toUpper(), QString("GROSSSTRASSE")); QCOMPARE(s, QString::fromUtf8("Gro\xc3\x9fstra\xc3\x9f""e")); // call rvalue-ref version on detached case copy.clear(); - QCOMPARE(qMove(s).toUpper(), QString("GROSSSTRASSE")); + QCOMPARE(std::move(s).toUpper(), QString("GROSSSTRASSE")); } QString lower, upper; @@ -2243,7 +2236,7 @@ void tst_QString::toUpper() upper += QChar(QChar::highSurrogate(0x10428)); QCOMPARE(lower.toUpper(), upper); -#ifdef QT_USE_ICU +#if QT_CONFIG(icu) // test doesn't work with ICU support, since QChar is unaware of any locale QEXPECT_FAIL("", "test doesn't work with ICU support, since QChar is unaware of any locale", Continue); QVERIFY(false); @@ -2255,7 +2248,7 @@ void tst_QString::toUpper() if (upper.length() == 1) QVERIFY(upper == QString(1, QChar(i).toUpper())); } -#endif +#endif // icu } void tst_QString::toLower() @@ -2303,7 +2296,7 @@ void tst_QString::toLower() upper += QChar(QChar::highSurrogate(0x10400)); QCOMPARE( upper.toLower(), lower); -#ifdef QT_USE_ICU +#if QT_CONFIG(icu) // test doesn't work with ICU support, since QChar is unaware of any locale QEXPECT_FAIL("", "test doesn't work with ICU support, since QChar is unaware of any locale", Continue); QVERIFY(false); @@ -2315,7 +2308,7 @@ void tst_QString::toLower() if (lower.length() == 1) QVERIFY(str.toLower() == QString(1, QChar(i).toLower())); } -#endif +#endif // icu } void tst_QString::isUpper() @@ -2427,11 +2420,11 @@ void tst_QString::trimmed() QCOMPARE(a.trimmed(), QLatin1String("a")); a="Text"; - QCOMPARE(qMove(a).trimmed(), QLatin1String("Text")); + QCOMPARE(std::move(a).trimmed(), QLatin1String("Text")); a=" "; - QCOMPARE(qMove(a).trimmed(), QLatin1String("")); + QCOMPARE(std::move(a).trimmed(), QLatin1String("")); a=" a "; - QCOMPARE(qMove(a).trimmed(), QLatin1String("a")); + QCOMPARE(std::move(a).trimmed(), QLatin1String("a")); } void tst_QString::simplified_data() @@ -2486,13 +2479,13 @@ void tst_QString::simplified() // without detaching: QString copy1 = full; - QCOMPARE(qMove(full).simplified(), simple); + QCOMPARE(std::move(full).simplified(), simple); QCOMPARE(full, orig_full); // force a detach if (!full.isEmpty()) full[0] = full[0]; - QCOMPARE(qMove(full).simplified(), simple); + QCOMPARE(std::move(full).simplified(), simple); } void tst_QString::insert_data(bool emptyIsNoop) @@ -3789,7 +3782,7 @@ void tst_QString::startsWith() QVERIFY( !a.startsWith("C") ); QVERIFY( !a.startsWith("ABCDEF") ); QVERIFY( a.startsWith("") ); - QVERIFY( a.startsWith(QString::null) ); + QVERIFY( a.startsWith(QString()) ); QVERIFY( a.startsWith('A') ); QVERIFY( a.startsWith(QLatin1Char('A')) ); QVERIFY( a.startsWith(QChar('A')) ); @@ -3816,7 +3809,7 @@ void tst_QString::startsWith() QVERIFY( !a.startsWith("c", Qt::CaseInsensitive) ); QVERIFY( !a.startsWith("abcdef", Qt::CaseInsensitive) ); QVERIFY( a.startsWith("", Qt::CaseInsensitive) ); - QVERIFY( a.startsWith(QString::null, Qt::CaseInsensitive) ); + QVERIFY( a.startsWith(QString(), Qt::CaseInsensitive) ); QVERIFY( a.startsWith('a', Qt::CaseInsensitive) ); QVERIFY( a.startsWith('A', Qt::CaseInsensitive) ); QVERIFY( a.startsWith(QLatin1Char('a'), Qt::CaseInsensitive) ); @@ -3855,7 +3848,7 @@ void tst_QString::startsWith() a = ""; QVERIFY( a.startsWith("") ); - QVERIFY( a.startsWith(QString::null) ); + QVERIFY( a.startsWith(QString()) ); QVERIFY( !a.startsWith("ABC") ); QVERIFY( a.startsWith(QLatin1String("")) ); @@ -3868,7 +3861,7 @@ void tst_QString::startsWith() a = QString(); QVERIFY( !a.startsWith("") ); - QVERIFY( a.startsWith(QString::null) ); + QVERIFY( a.startsWith(QString()) ); QVERIFY( !a.startsWith("ABC") ); QVERIFY( !a.startsWith(QLatin1String("")) ); @@ -3897,7 +3890,7 @@ void tst_QString::endsWith() QVERIFY( !a.endsWith("C") ); QVERIFY( !a.endsWith("ABCDEF") ); QVERIFY( a.endsWith("") ); - QVERIFY( a.endsWith(QString::null) ); + QVERIFY( a.endsWith(QString()) ); QVERIFY( a.endsWith('B') ); QVERIFY( a.endsWith(QLatin1Char('B')) ); QVERIFY( a.endsWith(QChar('B')) ); @@ -3924,7 +3917,7 @@ void tst_QString::endsWith() QVERIFY( !a.endsWith("c", Qt::CaseInsensitive) ); QVERIFY( !a.endsWith("abcdef", Qt::CaseInsensitive) ); QVERIFY( a.endsWith("", Qt::CaseInsensitive) ); - QVERIFY( a.endsWith(QString::null, Qt::CaseInsensitive) ); + QVERIFY( a.endsWith(QString(), Qt::CaseInsensitive) ); QVERIFY( a.endsWith('b', Qt::CaseInsensitive) ); QVERIFY( a.endsWith('B', Qt::CaseInsensitive) ); QVERIFY( a.endsWith(QLatin1Char('b'), Qt::CaseInsensitive) ); @@ -3966,7 +3959,7 @@ void tst_QString::endsWith() a = ""; QVERIFY( a.endsWith("") ); - QVERIFY( a.endsWith(QString::null) ); + QVERIFY( a.endsWith(QString()) ); QVERIFY( !a.endsWith("ABC") ); QVERIFY( !a.endsWith(QLatin1Char(0)) ); QVERIFY( !a.endsWith(QLatin1Char('x')) ); @@ -3978,7 +3971,7 @@ void tst_QString::endsWith() a = QString(); QVERIFY( !a.endsWith("") ); - QVERIFY( a.endsWith(QString::null) ); + QVERIFY( a.endsWith(QString()) ); QVERIFY( !a.endsWith("ABC") ); QVERIFY( !a.endsWith(QLatin1String("")) ); @@ -4294,9 +4287,9 @@ void tst_QString::fromLocal8Bit_data() //QTest::newRow("null5") << QByteArray() << 5 << QString(); //QTest::newRow("empty-1") << QByteArray("\0abcd", 5) << -1 << QString(); //QTest::newRow("empty0") << QByteArray() << 0 << QString(); - //QTest::newRow("empty5") << QByteArray("\0abcd", 5) << 5 << QString::fromAscii("\0abcd", 5); - //QTest::newRow("other-1") << QByteArray("ab\0cd", 5) << -1 << QString::fromAscii("ab"); - //QTest::newRow("other5") << QByteArray("ab\0cd", 5) << 5 << QString::fromAscii("ab\0cd", 5); + //QTest::newRow("empty5") << QByteArray("\0abcd", 5) << 5 << QString::fromLatin1("\0abcd", 5); + //QTest::newRow("other-1") << QByteArray("ab\0cd", 5) << -1 << QString::fromLatin1("ab"); + //QTest::newRow("other5") << QByteArray("ab\0cd", 5) << 5 << QString::fromLatin1("ab\0cd", 5); } void tst_QString::fromLocal8Bit() @@ -4534,7 +4527,7 @@ void tst_QString::toLatin1Roundtrip() // try the rvalue version of toLatin1() QString s = unicodesrc; - QCOMPARE(qMove(s).toLatin1(), latin1); + QCOMPARE(std::move(s).toLatin1(), latin1); // and verify that the moved-from object can still be used s = "foo"; @@ -4600,6 +4593,9 @@ void tst_QString::fromLatin1() QVERIFY(a.size() == 5); } +#if QT_DEPRECATED_SINCE(5, 0) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED void tst_QString::fromAscii() { QString a; @@ -4620,6 +4616,8 @@ void tst_QString::fromAscii() a = QString::fromAscii("\0abcd", 5); QVERIFY(a.size() == 5); } +QT_WARNING_POP +#endif void tst_QString::fromUcs4() { @@ -4769,7 +4767,7 @@ void tst_QString::arg() QCOMPARE( s4.arg("foo"), QLatin1String("[foo]") ); QCOMPARE( s5.arg(QLatin1String("foo")), QLatin1String("[foo]") ); - QCOMPARE( s6.arg(QStringViewLiteral("foo")), QLatin1String("[foo]") ); + QCOMPARE( s6.arg(u"foo"), QLatin1String("[foo]") ); QCOMPARE( s7.arg("foo"), QLatin1String("[foo]") ); QCOMPARE( s8.arg("foo"), QLatin1String("[foo %1]") ); QCOMPARE( s8.arg("foo").arg("bar"), QLatin1String("[foo bar]") ); @@ -4831,14 +4829,14 @@ void tst_QString::arg() QCOMPARE( QString("%1").arg("hello", -10), QLatin1String("hello ") ); QCOMPARE( QString("%1").arg(QLatin1String("hello"), -5), QLatin1String("hello") ); - QCOMPARE( QString("%1").arg(QStringViewLiteral("hello"), -2), QLatin1String("hello") ); + QCOMPARE( QString("%1").arg(u"hello", -2), QLatin1String("hello") ); QCOMPARE( QString("%1").arg("hello", 0), QLatin1String("hello") ); QCOMPARE( QString("%1").arg(QLatin1String("hello"), 2), QLatin1String("hello") ); - QCOMPARE( QString("%1").arg(QStringViewLiteral("hello"), 5), QLatin1String("hello") ); + QCOMPARE( QString("%1").arg(u"hello", 5), QLatin1String("hello") ); QCOMPARE( QString("%1").arg("hello", 10), QLatin1String(" hello") ); QCOMPARE( QString("%1%1").arg("hello"), QLatin1String("hellohello") ); QCOMPARE( QString("%2%1").arg("hello"), QLatin1String("%2hello") ); - QCOMPARE( QString("%1%1").arg(QString::null), QLatin1String("") ); + QCOMPARE( QString("%1%1").arg(QString()), QLatin1String("") ); QCOMPARE( QString("%2%1").arg(""), QLatin1String("%2") ); QCOMPARE( QString("%2 %L1").arg(12345.6789).arg(12345.6789), @@ -4934,9 +4932,7 @@ void tst_QString::doubleOut() QCOMPARE(QString::number(micro), expect); QCOMPARE(QString("%1").arg(micro), expect); { - QString text; - text.sprintf("%g", micro); - QCOMPARE(text, expect); + QCOMPARE(QString::asprintf("%g", micro), expect); } { QString text; @@ -5480,8 +5476,6 @@ void tst_QString::tortureSprintfDouble() { const SprintfDoubleData *data = g_sprintf_double_data; - QString s; - for (; data->fmt != 0; ++data) { double d; char *buff = (char *)&d; @@ -5496,7 +5490,7 @@ void tst_QString::tortureSprintfDouble() for (uint i = 0; i < 8; ++i) buff[7 - i] = data->bytes[i]; # endif - s.sprintf(data->fmt, d); + const QString s = QString::asprintf(data->fmt, d); #ifdef QT_NO_FPU // reduced precision when running with hardfloats in qemu if (d - 0.1 < 1e12) QSKIP("clib sprintf doesn't fill with 0's on this platform"); @@ -5630,7 +5624,7 @@ void tst_QString::localeAwareCompare() QStringRef r2(&s2, 0, s2.length()); if (!locale.isEmpty()) { -#if defined (Q_OS_DARWIN) || defined(QT_USE_ICU) +#if defined (Q_OS_DARWIN) || QT_CONFIG(icu) QSKIP("Setting the locale is not supported on OS X or ICU (you can set the C locale, but that won't affect localeAwareCompare)"); #else const char *newLocale = setlocale(LC_ALL, locale.toLatin1()); @@ -5638,10 +5632,10 @@ void tst_QString::localeAwareCompare() setlocale(LC_ALL, ""); QSKIP("Please install the proper locale on this machine to test properly"); } -#endif +#endif // Darwin || icu } -#ifdef QT_USE_ICU +#if QT_CONFIG(icu) // ### for c1, ICU disagrees with libc on how to compare QEXPECT_FAIL("c1", "ICU disagrees with test", Abort); #endif @@ -6450,32 +6444,24 @@ void tst_QString::QCharRefDetaching() const void tst_QString::sprintfZU() const { { - QString string; size_t s = 6; - string.sprintf("%zu", s); - QCOMPARE(string, QString::fromLatin1("6")); + QCOMPARE(QString::asprintf("%zu", s), QString::fromLatin1("6")); } { - QString string; - string.sprintf("%s\n", "foo"); - QCOMPARE(string, QString::fromLatin1("foo\n")); + QCOMPARE(QString::asprintf("%s\n", "foo"), QString::fromLatin1("foo\n")); } { /* This code crashed. I don't know how to reduce it further. In other words, * both %zu and %s needs to be present. */ size_t s = 6; - QString string; - string.sprintf("%zu%s", s, "foo"); - QCOMPARE(string, QString::fromLatin1("6foo")); + QCOMPARE(QString::asprintf("%zu%s", s, "foo"), QString::fromLatin1("6foo")); } { size_t s = 6; - QString string; - string.sprintf("%zu %s\n", s, "foo"); - QCOMPARE(string, QString::fromLatin1("6 foo\n")); + QCOMPARE(QString::asprintf("%zu %s\n", s, "foo"), QString::fromLatin1("6 foo\n")); } } @@ -6607,7 +6593,7 @@ void tst_QString::arg_locale() } -#ifdef QT_USE_ICU +#if QT_CONFIG(icu) // Qt has to be built with ICU support void tst_QString::toUpperLower_icu() { @@ -6641,9 +6627,9 @@ void tst_QString::toUpperLower_icu() QCOMPARE(l.toLower(sup), sup); QCOMPARE(l.toLower(QString::fromLatin1("i")), QString::fromLatin1("i")); } -#endif +#endif // icu -#if !defined(QT_NO_UNICODE_LITERAL) && defined(Q_COMPILER_LAMBDA) +#if !defined(QT_NO_UNICODE_LITERAL) // Only tested on c++0x compliant compiler or gcc void tst_QString::literals() { diff --git a/tests/auto/corelib/tools/qstring/tst_qstring_mac.mm b/tests/auto/corelib/text/qstring/tst_qstring_mac.mm index 60bd3f9b15..60bd3f9b15 100644 --- a/tests/auto/corelib/tools/qstring/tst_qstring_mac.mm +++ b/tests/auto/corelib/text/qstring/tst_qstring_mac.mm diff --git a/tests/auto/corelib/tools/qstring_no_cast_from_bytearray/qstring_no_cast_from_bytearray.pro b/tests/auto/corelib/text/qstring_no_cast_from_bytearray/qstring_no_cast_from_bytearray.pro index 14dbe779db..14dbe779db 100644 --- a/tests/auto/corelib/tools/qstring_no_cast_from_bytearray/qstring_no_cast_from_bytearray.pro +++ b/tests/auto/corelib/text/qstring_no_cast_from_bytearray/qstring_no_cast_from_bytearray.pro diff --git a/tests/auto/corelib/tools/qstring_no_cast_from_bytearray/tst_qstring_no_cast_from_bytearray.cpp b/tests/auto/corelib/text/qstring_no_cast_from_bytearray/tst_qstring_no_cast_from_bytearray.cpp index 47fbeb6069..47fbeb6069 100644 --- a/tests/auto/corelib/tools/qstring_no_cast_from_bytearray/tst_qstring_no_cast_from_bytearray.cpp +++ b/tests/auto/corelib/text/qstring_no_cast_from_bytearray/tst_qstring_no_cast_from_bytearray.cpp diff --git a/tests/auto/corelib/tools/qstringapisymmetry/.gitignore b/tests/auto/corelib/text/qstringapisymmetry/.gitignore index d28de05438..d28de05438 100644 --- a/tests/auto/corelib/tools/qstringapisymmetry/.gitignore +++ b/tests/auto/corelib/text/qstringapisymmetry/.gitignore diff --git a/tests/auto/corelib/tools/qstringapisymmetry/qstringapisymmetry.pro b/tests/auto/corelib/text/qstringapisymmetry/qstringapisymmetry.pro index a4e91e38bd..a4e91e38bd 100644 --- a/tests/auto/corelib/tools/qstringapisymmetry/qstringapisymmetry.pro +++ b/tests/auto/corelib/text/qstringapisymmetry/qstringapisymmetry.pro diff --git a/tests/auto/corelib/tools/qstringapisymmetry/tst_qstringapisymmetry.cpp b/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp index 82d58becfe..24382a2b61 100644 --- a/tests/auto/corelib/tools/qstringapisymmetry/tst_qstringapisymmetry.cpp +++ b/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com> +** Copyright (C) 2019 Mail.ru Group. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. @@ -48,6 +49,14 @@ QString toQString(const T &t) { return QString(t); } QString toQString(const QStringRef &ref) { return ref.toString(); } QString toQString(QStringView view) { return view.toString(); } +template <typename Iterable> +QStringList toQStringList(const Iterable &i) { + QStringList result; + for (auto &e : i) + result.push_back(toQString(e)); + return result; +} + // FIXME: these are missing at the time of writing, add them, then remove the dummies here: #define MAKE_RELOP(op, A1, A2) \ static bool operator op (A1 lhs, A2 rhs) \ @@ -293,6 +302,26 @@ private Q_SLOTS: void endsWith_QLatin1String_QChar() { endsWith_impl<QLatin1String, QChar>(); } private: + void split_data(bool rhsHasVariableLength = true); + template <typename Haystack, typename Needle> void split_impl() const; + +private Q_SLOTS: + // test all combinations of {QString, QStringRef} x {QString, QLatin1String, QChar}: + void split_QString_QString_data() { split_data(); } + void split_QString_QString() { split_impl<QString, QString>(); } + void split_QString_QLatin1String_data() { split_data(); } + void split_QString_QLatin1String() { split_impl<QString, QLatin1String>(); } + void split_QString_QChar_data() { split_data(false); } + void split_QString_QChar() { split_impl<QString, QChar>(); } + + void split_QStringRef_QString_data() { split_data(); } + void split_QStringRef_QString() { split_impl<QStringRef, QString>(); } + void split_QStringRef_QLatin1String_data() { split_data(); } + void split_QStringRef_QLatin1String() { split_impl<QStringRef, QLatin1String>(); } + void split_QStringRef_QChar_data() { split_data(false); } + void split_QStringRef_QChar() { split_impl<QStringRef, QChar>(); } + +private: void mid_data(); template <typename String> void mid_impl(); @@ -416,6 +445,129 @@ private Q_SLOTS: void toUcs4_QStringRef() { toUcs4_impl<QStringRef>(); } void toUcs4_QStringView_data() { toUcs4_data(); } void toUcs4_QStringView() { toUcs4_impl<QStringView>(); } + +private: + template <typename Haystack, typename Needle> void indexOf_impl() const; + void indexOf_data(); + +private Q_SLOTS: + void indexOf_QString_QString_data() { indexOf_data(); } + void indexOf_QString_QString() { indexOf_impl<QString, QString>(); } + void indexOf_QString_QLatin1String_data() { indexOf_data(); } + void indexOf_QString_QLatin1String() { indexOf_impl<QString, QLatin1String>(); } + void indexOf_QString_QStringRef_data() { indexOf_data(); } + void indexOf_QString_QStringRef() { indexOf_impl<QString, QStringRef>(); } + void indexOf_QString_QStringView_data() { indexOf_data(); } + void indexOf_QString_QStringView() { indexOf_impl<QString, QStringView>(); } + + void indexOf_QLatin1String_QString_data() { indexOf_data(); } + void indexOf_QLatin1String_QString() { indexOf_impl<QLatin1String, QString>(); } + void indexOf_QLatin1String_QLatin1String_data() { indexOf_data(); } + void indexOf_QLatin1String_QLatin1String() { indexOf_impl<QLatin1String, QLatin1String>(); } + void indexOf_QLatin1String_QStringRef_data() { indexOf_data(); } + void indexOf_QLatin1String_QStringRef() { indexOf_impl<QLatin1String, QStringRef>(); } + void indexOf_QLatin1String_QStringView_data() { indexOf_data(); } + void indexOf_QLatin1String_QStringView() { indexOf_impl<QLatin1String, QStringView>(); } + + void indexOf_QStringRef_QString_data() { indexOf_data(); } + void indexOf_QStringRef_QString() { indexOf_impl<QStringRef, QString>(); } + void indexOf_QStringRef_QLatin1String_data() { indexOf_data(); } + void indexOf_QStringRef_QLatin1String() { indexOf_impl<QStringRef, QLatin1String>(); } + void indexOf_QStringRef_QStringRef_data() { indexOf_data(); } + void indexOf_QStringRef_QStringRef() { indexOf_impl<QStringRef, QStringRef>(); } + void indexOf_QStringRef_QStringView_data() { indexOf_data(); } + void indexOf_QStringRef_QStringView() { indexOf_impl<QStringRef, QStringView>(); } + + void indexOf_QStringView_QString_data() { indexOf_data(); } + void indexOf_QStringView_QString() { indexOf_impl<QStringView, QString>(); } + void indexOf_QStringView_QLatin1String_data() { indexOf_data(); } + void indexOf_QStringView_QLatin1String() { indexOf_impl<QStringView, QLatin1String>(); } + void indexOf_QStringView_QStringRef_data() { indexOf_data(); } + void indexOf_QStringView_QStringRef() { indexOf_impl<QStringView, QStringRef>(); } + void indexOf_QStringView_QStringView_data() { indexOf_data(); } + void indexOf_QStringView_QStringView() { indexOf_impl<QStringView, QStringView>(); } + +private: + template <typename Haystack, typename Needle> void contains_impl() const; + void contains_data(); + +private Q_SLOTS: + void contains_QString_QString_data() { contains_data(); } + void contains_QString_QString() { contains_impl<QString, QString>(); } + void contains_QString_QLatin1String_data() { contains_data(); } + void contains_QString_QLatin1String() { contains_impl<QString, QLatin1String>(); } + void contains_QString_QStringRef_data() { contains_data(); } + void contains_QString_QStringRef() { contains_impl<QString, QStringRef>(); } + void contains_QString_QStringView_data() { contains_data(); } + void contains_QString_QStringView() { contains_impl<QString, QStringView>(); } + + void contains_QLatin1String_QString_data() { contains_data(); } + void contains_QLatin1String_QString() { contains_impl<QLatin1String, QString>(); } + void contains_QLatin1String_QLatin1String_data() { contains_data(); } + void contains_QLatin1String_QLatin1String() { contains_impl<QLatin1String, QLatin1String>(); } + void contains_QLatin1String_QStringRef_data() { contains_data(); } + void contains_QLatin1String_QStringRef() { contains_impl<QLatin1String, QStringRef>(); } + void contains_QLatin1String_QStringView_data() { contains_data(); } + void contains_QLatin1String_QStringView() { contains_impl<QLatin1String, QStringView>(); } + + void contains_QStringRef_QString_data() { contains_data(); } + void contains_QStringRef_QString() { contains_impl<QStringRef, QString>(); } + void contains_QStringRef_QLatin1String_data() { contains_data(); } + void contains_QStringRef_QLatin1String() { contains_impl<QStringRef, QLatin1String>(); } + void contains_QStringRef_QStringRef_data() { contains_data(); } + void contains_QStringRef_QStringRef() { contains_impl<QStringRef, QStringRef>(); } + void contains_QStringRef_QStringView_data() { contains_data(); } + void contains_QStringRef_QStringView() { contains_impl<QStringRef, QStringView>(); } + + void contains_QStringView_QString_data() { contains_data(); } + void contains_QStringView_QString() { contains_impl<QStringView, QString>(); } + void contains_QStringView_QLatin1String_data() { contains_data(); } + void contains_QStringView_QLatin1String() { contains_impl<QStringView, QLatin1String>(); } + void contains_QStringView_QStringRef_data() { contains_data(); } + void contains_QStringView_QStringRef() { contains_impl<QStringView, QStringRef>(); } + void contains_QStringView_QStringView_data() { contains_data(); } + void contains_QStringView_QStringView() { contains_impl<QStringView, QStringView>(); } + +private: + template <typename Haystack, typename Needle> void lastIndexOf_impl() const; + void lastIndexOf_data(); + +private Q_SLOTS: + void lastIndexOf_QString_QString_data() { lastIndexOf_data(); } + void lastIndexOf_QString_QString() { lastIndexOf_impl<QString, QString>(); } + void lastIndexOf_QString_QLatin1String_data() { lastIndexOf_data(); } + void lastIndexOf_QString_QLatin1String() { lastIndexOf_impl<QString, QLatin1String>(); } + void lastIndexOf_QString_QStringRef_data() { lastIndexOf_data(); } + void lastIndexOf_QString_QStringRef() { lastIndexOf_impl<QString, QStringRef>(); } + void lastIndexOf_QString_QStringView_data() { lastIndexOf_data(); } + void lastIndexOf_QString_QStringView() { lastIndexOf_impl<QString, QStringView>(); } + + void lastIndexOf_QLatin1String_QString_data() { lastIndexOf_data(); } + void lastIndexOf_QLatin1String_QString() { lastIndexOf_impl<QLatin1String, QString>(); } + void lastIndexOf_QLatin1String_QLatin1String_data() { lastIndexOf_data(); } + void lastIndexOf_QLatin1String_QLatin1String() { lastIndexOf_impl<QLatin1String, QLatin1String>(); } + void lastIndexOf_QLatin1String_QStringRef_data() { lastIndexOf_data(); } + void lastIndexOf_QLatin1String_QStringRef() { lastIndexOf_impl<QLatin1String, QStringRef>(); } + void lastIndexOf_QLatin1String_QStringView_data() { lastIndexOf_data(); } + void lastIndexOf_QLatin1String_QStringView() { lastIndexOf_impl<QLatin1String, QStringView>(); } + + void lastIndexOf_QStringRef_QString_data() { lastIndexOf_data(); } + void lastIndexOf_QStringRef_QString() { lastIndexOf_impl<QStringRef, QString>(); } + void lastIndexOf_QStringRef_QLatin1String_data() { lastIndexOf_data(); } + void lastIndexOf_QStringRef_QLatin1String() { lastIndexOf_impl<QStringRef, QLatin1String>(); } + void lastIndexOf_QStringRef_QStringRef_data() { lastIndexOf_data(); } + void lastIndexOf_QStringRef_QStringRef() { lastIndexOf_impl<QStringRef, QStringRef>(); } + void lastIndexOf_QStringRef_QStringView_data() { lastIndexOf_data(); } + void lastIndexOf_QStringRef_QStringView() { lastIndexOf_impl<QStringRef, QStringView>(); } + + void lastIndexOf_QStringView_QString_data() { lastIndexOf_data(); } + void lastIndexOf_QStringView_QString() { lastIndexOf_impl<QStringView, QString>(); } + void lastIndexOf_QStringView_QLatin1String_data() { lastIndexOf_data(); } + void lastIndexOf_QStringView_QLatin1String() { lastIndexOf_impl<QStringView, QLatin1String>(); } + void lastIndexOf_QStringView_QStringRef_data() { lastIndexOf_data(); } + void lastIndexOf_QStringView_QStringRef() { lastIndexOf_impl<QStringView, QStringRef>(); } + void lastIndexOf_QStringView_QStringView_data() { lastIndexOf_data(); } + void lastIndexOf_QStringView_QStringView() { lastIndexOf_impl<QStringView, QStringView>(); } }; void tst_QStringApiSymmetry::compare_data(bool hasConceptOfNullAndEmpty) @@ -540,6 +692,7 @@ void tst_QStringApiSymmetry::compare_impl() const } static QString empty = QLatin1String(""); +static QString null; // the tests below rely on the fact that these objects' names match their contents: static QString a = QStringLiteral("a"); static QString A = QStringLiteral("A"); @@ -547,6 +700,14 @@ static QString b = QStringLiteral("b"); static QString B = QStringLiteral("B"); static QString c = QStringLiteral("c"); static QString C = QStringLiteral("C"); +static QString d = QStringLiteral("d"); +static QString D = QStringLiteral("D"); +static QString e = QStringLiteral("e"); +static QString E = QStringLiteral("E"); +static QString f = QStringLiteral("f"); +static QString F = QStringLiteral("F"); +static QString g = QStringLiteral("g"); +static QString G = QStringLiteral("G"); static QString ab = QStringLiteral("ab"); static QString aB = QStringLiteral("aB"); static QString Ab = QStringLiteral("Ab"); @@ -738,6 +899,119 @@ void tst_QStringApiSymmetry::endsWith_impl() const QCOMPARE(haystack.endsWith(needle, Qt::CaseInsensitive), resultCIS); } +void tst_QStringApiSymmetry::split_data(bool rhsHasVariableLength) +{ + QTest::addColumn<QStringRef>("haystackU16"); + QTest::addColumn<QLatin1String>("haystackL1"); + QTest::addColumn<QStringRef>("needleU16"); + QTest::addColumn<QLatin1String>("needleL1"); + QTest::addColumn<QStringList>("resultCS"); + QTest::addColumn<QStringList>("resultCIS"); + + if (rhsHasVariableLength) { + QTest::addRow("null ~= null$") << QStringRef{} << QLatin1String{} + << QStringRef{} << QLatin1String{} + << QStringList{{}, {}} << QStringList{{}, {}}; + QTest::addRow("empty ~= null$") << QStringRef{&empty} << QLatin1String("") + << QStringRef{} << QLatin1String{} + << QStringList{empty, empty} << QStringList{empty, empty}; + QTest::addRow("a ~= null$") << QStringRef{&a} << QLatin1String{"a"} + << QStringRef{} << QLatin1String{} + << QStringList{empty, a, empty} << QStringList{empty, a, empty}; + QTest::addRow("null ~= empty$") << QStringRef{} << QLatin1String{} + << QStringRef{&empty} << QLatin1String{""} + << QStringList{{}, {}} << QStringList{{}, {}}; + QTest::addRow("a ~= empty$") << QStringRef{&a} << QLatin1String{"a"} + << QStringRef{&empty} << QLatin1String{""} + << QStringList{empty, a, empty} << QStringList{empty, a, empty}; + QTest::addRow("empty ~= empty$") << QStringRef{&empty} << QLatin1String{""} + << QStringRef{&empty} << QLatin1String{""} + << QStringList{empty, empty} << QStringList{empty, empty}; + } + QTest::addRow("null ~= a$") << QStringRef{} << QLatin1String{} + << QStringRef{&a} << QLatin1String{"a"} + << QStringList{{}} << QStringList{{}}; + QTest::addRow("empty ~= a$") << QStringRef{&empty} << QLatin1String{""} + << QStringRef{&a} << QLatin1String{"a"} + << QStringList{empty} << QStringList{empty}; + +#define ROW(h, n, cs, cis) \ + QTest::addRow("%s ~= %s$", #h, #n) << QStringRef(&h) << QLatin1String(#h) \ + << QStringRef(&n) << QLatin1String(#n) \ + << QStringList cs << QStringList cis + ROW(a, a, ({empty, empty}), ({empty, empty})); + ROW(a, A, {a}, ({empty, empty})); + ROW(a, b, {a}, {a}); + + if (rhsHasVariableLength) + ROW(b, ab, {b}, {b}); + + ROW(ab, b, ({a, empty}), ({a, empty})); + if (rhsHasVariableLength) { + ROW(ab, ab, ({empty, empty}), ({empty, empty})); + ROW(ab, aB, {ab}, ({empty, empty})); + ROW(ab, Ab, {ab}, ({empty, empty})); + } + ROW(ab, c, {ab}, {ab}); + + if (rhsHasVariableLength) + ROW(bc, abc, {bc}, {bc}); + + ROW(Abc, c, ({Ab, empty}), ({Ab, empty})); +#if 0 + if (rhsHasVariableLength) { + ROW(Abc, bc, 1, 1); + ROW(Abc, bC, 0, 1); + ROW(Abc, Bc, 0, 1); + ROW(Abc, BC, 0, 1); + ROW(aBC, bc, 0, 1); + ROW(aBC, bC, 0, 1); + ROW(aBC, Bc, 0, 1); + ROW(aBC, BC, 1, 1); + } +#endif + ROW(ABC, b, {ABC}, ({A, C})); + ROW(ABC, a, {ABC}, ({empty, BC})); +#undef ROW +} + +static QStringList skipped(const QStringList &sl) +{ + QStringList result; + result.reserve(sl.size()); + for (const QString &s : sl) { + if (!s.isEmpty()) + result.push_back(s); + } + return result; +} + +template <typename Haystack, typename Needle> +void tst_QStringApiSymmetry::split_impl() const +{ + QFETCH(const QStringRef, haystackU16); + QFETCH(const QLatin1String, haystackL1); + QFETCH(const QStringRef, needleU16); + QFETCH(const QLatin1String, needleL1); + QFETCH(const QStringList, resultCS); + QFETCH(const QStringList, resultCIS); + + const QStringList skippedResultCS = skipped(resultCS); + const QStringList skippedResultCIS = skipped(resultCIS); + + const auto haystackU8 = haystackU16.toUtf8(); + const auto needleU8 = needleU16.toUtf8(); + + const auto haystack = make<Haystack>(haystackU16, haystackL1, haystackU8); + const auto needle = make<Needle>(needleU16, needleL1, needleU8); + + QCOMPARE(toQStringList(haystack.split(needle)), resultCS); + QCOMPARE(toQStringList(haystack.split(needle, Qt::KeepEmptyParts, Qt::CaseSensitive)), resultCS); + QCOMPARE(toQStringList(haystack.split(needle, Qt::KeepEmptyParts, Qt::CaseInsensitive)), resultCIS); + QCOMPARE(toQStringList(haystack.split(needle, Qt::SkipEmptyParts, Qt::CaseSensitive)), skippedResultCS); + QCOMPARE(toQStringList(haystack.split(needle, Qt::SkipEmptyParts, Qt::CaseInsensitive)), skippedResultCIS); +} + void tst_QStringApiSymmetry::mid_data() { QTest::addColumn<QStringRef>("unicode"); @@ -1216,6 +1490,296 @@ void tst_QStringApiSymmetry::toUcs4_impl() QCOMPARE(unicode.isEmpty(), ucs4.isEmpty()); } +void tst_QStringApiSymmetry::indexOf_data() +{ + QTest::addColumn<QString>("haystackU16"); + QTest::addColumn<QLatin1String>("haystackL1"); + QTest::addColumn<QString>("needleU16"); + QTest::addColumn<QLatin1String>("needleL1"); + QTest::addColumn<qsizetype>("startpos"); + QTest::addColumn<qsizetype>("resultCS"); + QTest::addColumn<qsizetype>("resultCIS"); + + constexpr qsizetype zeroPos = 0; + constexpr qsizetype minus1Pos = -1; + + QTest::addRow("haystack: null, needle: null") << null << QLatin1String() + << null << QLatin1String() << zeroPos << zeroPos << zeroPos; + QTest::addRow("haystack: empty, needle: null") << empty << QLatin1String("") + << null << QLatin1String() << zeroPos << zeroPos << zeroPos; + QTest::addRow("haystack: a, needle: null") << a << QLatin1String("a") + << null << QLatin1String() << zeroPos << zeroPos << zeroPos; + QTest::addRow("haystack: null, needle: empty") << null << QLatin1String() + << empty << QLatin1String("") << zeroPos << zeroPos << zeroPos; + QTest::addRow("haystack: a, needle: empty") << a << QLatin1String("a") + << empty << QLatin1String("") << zeroPos << zeroPos << zeroPos; + QTest::addRow("haystack: empty, needle: empty") << empty << QLatin1String("") + << empty << QLatin1String("") << zeroPos << zeroPos << zeroPos; + QTest::addRow("haystack: empty, needle: a") << empty << QLatin1String("") + << a << QLatin1String("a") << zeroPos << minus1Pos << minus1Pos; + QTest::addRow("haystack: null, needle: a") << null << QLatin1String() + << a << QLatin1String("a") << zeroPos << minus1Pos << minus1Pos; + + +#define ROW(h, n, st, cs, cis) \ + QTest::addRow("haystack: %s, needle: %s", #h, #n) << h << QLatin1String(#h) \ + << n << QLatin1String(#n) \ + << qsizetype(st) << qsizetype(cs) << qsizetype(cis) + + ROW(abc, a, 0, 0, 0); + ROW(abc, A, 0, -1, 0); + ROW(abc, a, 1, -1, -1); + ROW(abc, A, 1, -1, -1); + ROW(abc, b, 0, 1, 1); + ROW(abc, B, 0, -1, 1); + ROW(abc, b, 1, 1, 1); + ROW(abc, B, 1, -1, 1); + ROW(abc, B, 2, -1, -1); + + ROW(ABC, A, 0, 0, 0); + ROW(ABC, a, 0, -1, 0); + ROW(ABC, A, 1, -1, -1); + ROW(ABC, a, 1, -1, -1); + ROW(ABC, B, 0, 1, 1); + ROW(ABC, b, 0, -1, 1); + ROW(ABC, B, 1, 1, 1); + ROW(ABC, b, 1, -1, 1); + ROW(ABC, B, 2, -1, -1); + + ROW(aBc, bc, 0, -1, 1); + ROW(aBc, Bc, 0, 1, 1); + ROW(aBc, bC, 0, -1, 1); + ROW(aBc, BC, 0, -1, 1); + + ROW(AbC, bc, 0, -1, 1); + ROW(AbC, Bc, 0, -1, 1); + ROW(AbC, bC, 0, 1, 1); + ROW(AbC, BC, 0, -1, 1); + ROW(AbC, BC, 1, -1, 1); + ROW(AbC, BC, 2, -1, -1); +#undef ROW + +} + +template <typename Haystack, typename Needle> +void tst_QStringApiSymmetry::indexOf_impl() const +{ + QFETCH(const QString, haystackU16); + QFETCH(const QLatin1String, haystackL1); + QFETCH(const QString, needleU16); + QFETCH(const QLatin1String, needleL1); + QFETCH(const qsizetype, startpos); + QFETCH(const qsizetype, resultCS); + QFETCH(const qsizetype, resultCIS); + + const auto haystackU8 = haystackU16.toUtf8(); + const auto needleU8 = needleU16.toUtf8(); + + const auto haystack = make<Haystack>(QStringRef(&haystackU16), haystackL1, haystackU8); + const auto needle = make<Needle>(QStringRef(&needleU16), needleL1, needleU8); + + using size_type = typename Haystack::size_type; + + QCOMPARE(haystack.indexOf(needle, startpos), size_type(resultCS)); + QCOMPARE(haystack.indexOf(needle, startpos, Qt::CaseSensitive), size_type(resultCS)); + QCOMPARE(haystack.indexOf(needle, startpos, Qt::CaseInsensitive), size_type(resultCIS)); + + if (needle.size() == 1) + { + QCOMPARE(haystack.indexOf(needle[0], startpos), size_type(resultCS)); + QCOMPARE(haystack.indexOf(needle[0], startpos, Qt::CaseSensitive), size_type(resultCS)); + QCOMPARE(haystack.indexOf(needle[0], startpos, Qt::CaseInsensitive), size_type(resultCIS)); + } +} + +static QString ABCDEFGHIEfGEFG = QStringLiteral("ABCDEFGHIEfGEFG"); +static QString EFG = QStringLiteral("EFG"); +static QString efg = QStringLiteral("efg"); +static QString asd = QStringLiteral("asd"); +static QString asdf = QStringLiteral("asdf"); +static QString Z = QStringLiteral("Z"); + +void tst_QStringApiSymmetry::contains_data() +{ + QTest::addColumn<QString>("haystackU16"); + QTest::addColumn<QLatin1String>("haystackL1"); + QTest::addColumn<QString>("needleU16"); + QTest::addColumn<QLatin1String>("needleL1"); + QTest::addColumn<bool>("resultCS"); + QTest::addColumn<bool>("resultCIS"); + + QTest::addRow("haystack: null, needle: null") << null << QLatin1String() + << null << QLatin1String() << true << true; + QTest::addRow("haystack: empty, needle: null") << empty << QLatin1String("") + << null << QLatin1String() << true << true; + QTest::addRow("haystack: a, needle: null") << a << QLatin1String("a") + << null << QLatin1String() << true << true; + QTest::addRow("haystack: null, needle: empty") << null << QLatin1String() + << empty << QLatin1String("") << true << true; + QTest::addRow("haystack: a, needle: empty") << a << QLatin1String("a") + << empty << QLatin1String("") << true << true;; + QTest::addRow("haystack: empty, needle: empty") << empty << QLatin1String("") + << empty << QLatin1String("") << true << true; + QTest::addRow("haystack: empty, needle: a") << empty << QLatin1String("") + << a << QLatin1String("a") << false << false; + QTest::addRow("haystack: null, needle: a") << null << QLatin1String() + << a << QLatin1String("a") << false << false; + +#define ROW(h, n, cs, cis) \ + QTest::addRow("haystack: %s, needle: %s", #h, #n) << h << QLatin1String(#h) \ + << n << QLatin1String(#n) \ + << cs << cis + + ROW(ABCDEFGHIEfGEFG, A, true, true); + ROW(ABCDEFGHIEfGEFG, a, false, true); + ROW(ABCDEFGHIEfGEFG, Z, false, false); + ROW(ABCDEFGHIEfGEFG, EFG, true, true); + ROW(ABCDEFGHIEfGEFG, efg, false, true); + ROW(ABCDEFGHIEfGEFG, E, true, true); + ROW(ABCDEFGHIEfGEFG, e, false, true); +#undef ROW +} + +template <typename Haystack, typename Needle> +void tst_QStringApiSymmetry::contains_impl() const +{ + QFETCH(const QString, haystackU16); + QFETCH(const QLatin1String, haystackL1); + QFETCH(const QString, needleU16); + QFETCH(const QLatin1String, needleL1); + QFETCH(const bool, resultCS); + QFETCH(const bool, resultCIS); + + const auto haystackU8 = haystackU16.toUtf8(); + const auto needleU8 = needleU16.toUtf8(); + + const auto haystack = make<Haystack>(QStringRef(&haystackU16), haystackL1, haystackU8); + const auto needle = make<Needle>(QStringRef(&needleU16), needleL1, needleU8); + + QCOMPARE(haystack.contains(needle), resultCS); + QCOMPARE(haystack.contains(needle, Qt::CaseSensitive), resultCS); + QCOMPARE(haystack.contains(needle, Qt::CaseInsensitive), resultCIS); + + if (needle.size() == 1) + { + QCOMPARE(haystack.contains(needle[0]), resultCS); + QCOMPARE(haystack.contains(needle[0], Qt::CaseSensitive), resultCS); + QCOMPARE(haystack.contains(needle[0], Qt::CaseInsensitive), resultCIS); + } +} + +void tst_QStringApiSymmetry::lastIndexOf_data() +{ + QTest::addColumn<QString>("haystackU16"); + QTest::addColumn<QLatin1String>("haystackL1"); + QTest::addColumn<QString>("needleU16"); + QTest::addColumn<QLatin1String>("needleL1"); + QTest::addColumn<qsizetype>("startpos"); + QTest::addColumn<qsizetype>("resultCS"); + QTest::addColumn<qsizetype>("resultCIS"); + + constexpr qsizetype zeroPos = 0; + constexpr qsizetype minus1Pos = -1; + + QTest::addRow("haystack: null, needle: null") << null << QLatin1String() + << null << QLatin1String() << minus1Pos << minus1Pos << minus1Pos; + QTest::addRow("haystack: empty, needle: null") << empty << QLatin1String("") + << null << QLatin1String() << minus1Pos << minus1Pos << minus1Pos; + QTest::addRow("haystack: a, needle: null") << a << QLatin1String("a") + << null << QLatin1String() << minus1Pos << zeroPos << zeroPos; + QTest::addRow("haystack: null, needle: empty") << null << QLatin1String() + << empty << QLatin1String("") << minus1Pos << minus1Pos << minus1Pos; + QTest::addRow("haystack: a, needle: empty") << a << QLatin1String("a") + << empty << QLatin1String("") << minus1Pos << zeroPos << zeroPos; + QTest::addRow("haystack: empty, needle: empty") << empty << QLatin1String("") + << empty << QLatin1String("") << minus1Pos << minus1Pos << minus1Pos; + QTest::addRow("haystack: empty, needle: a") << empty << QLatin1String("") + << a << QLatin1String("a") << minus1Pos << minus1Pos << minus1Pos; + QTest::addRow("haystack: null, needle: a") << null << QLatin1String() + << a << QLatin1String("a") << minus1Pos << minus1Pos << minus1Pos; + + QTest::addRow("haystack: a, needle: null") << a << QLatin1String("a") + << null << QLatin1String() << qsizetype(1) << qsizetype(1) << qsizetype(1); + QTest::addRow("haystack: a, needle: empty") << a << QLatin1String("a") + << empty << QLatin1String("") << qsizetype(1) << qsizetype(1) << qsizetype(1); + QTest::addRow("haystack: a, needle: null") << a << QLatin1String("a") + << null << QLatin1String() << qsizetype(2) << minus1Pos << minus1Pos; + QTest::addRow("haystack: a, needle: empty") << a << QLatin1String("a") + << empty << QLatin1String("") << qsizetype(2) << minus1Pos << minus1Pos; + +#define ROW(h, n, st, cs, cis) \ + QTest::addRow("haystack: %s, needle: %s", #h, #n) << h << QLatin1String(#h) \ + << n << QLatin1String(#n) \ + << qsizetype(st) << qsizetype(cs) << qsizetype(cis) + + ROW(asd, asdf, -1, -1, -1); + + ROW(ABCDEFGHIEfGEFG, G, -1, 14, 14); + ROW(ABCDEFGHIEfGEFG, g, -1, -1, 14); + ROW(ABCDEFGHIEfGEFG, G, -3, 11, 11); + ROW(ABCDEFGHIEfGEFG, g, -3, -1, 11); + ROW(ABCDEFGHIEfGEFG, G, -5, 6, 6); + ROW(ABCDEFGHIEfGEFG, g, -5, -1, 6); + ROW(ABCDEFGHIEfGEFG, G, 14, 14, 14); + ROW(ABCDEFGHIEfGEFG, g, 14, -1, 14); + ROW(ABCDEFGHIEfGEFG, G, 13, 11, 11); + ROW(ABCDEFGHIEfGEFG, g, 13, -1, 11); + ROW(ABCDEFGHIEfGEFG, G, 15, -1, -1); + ROW(ABCDEFGHIEfGEFG, g, 15, -1, -1); + ROW(ABCDEFGHIEfGEFG, B, 14, 1, 1); + ROW(ABCDEFGHIEfGEFG, b, 14, -1, 1); + ROW(ABCDEFGHIEfGEFG, B, -1, 1, 1); + ROW(ABCDEFGHIEfGEFG, b, -1, -1, 1); + ROW(ABCDEFGHIEfGEFG, B, 1, 1, 1); + ROW(ABCDEFGHIEfGEFG, b, 1, -1, 1); + ROW(ABCDEFGHIEfGEFG, B, 0, -1, -1); + ROW(ABCDEFGHIEfGEFG, b, 0, -1, -1); + ROW(ABCDEFGHIEfGEFG, A, 0, 0, 0); + ROW(ABCDEFGHIEfGEFG, a, 0, -1, 0); + ROW(ABCDEFGHIEfGEFG, A, -15, 0, 0); + ROW(ABCDEFGHIEfGEFG, a, -15, -1, 0); + + ROW(ABCDEFGHIEfGEFG, efg, 0, -1, -1); + ROW(ABCDEFGHIEfGEFG, efg, 15, -1, -1); + ROW(ABCDEFGHIEfGEFG, efg, -15, -1, -1); + ROW(ABCDEFGHIEfGEFG, efg, 14, -1, 12); + ROW(ABCDEFGHIEfGEFG, efg, 12, -1, 12); + ROW(ABCDEFGHIEfGEFG, efg, -12, -1, -1); + ROW(ABCDEFGHIEfGEFG, efg, 11, -1, 9); +#undef ROW +} + +template <typename Haystack, typename Needle> +void tst_QStringApiSymmetry::lastIndexOf_impl() const +{ + QFETCH(const QString, haystackU16); + QFETCH(const QLatin1String, haystackL1); + QFETCH(const QString, needleU16); + QFETCH(const QLatin1String, needleL1); + QFETCH(const qsizetype, startpos); + QFETCH(const qsizetype, resultCS); + QFETCH(const qsizetype, resultCIS); + + const auto haystackU8 = haystackU16.toUtf8(); + const auto needleU8 = needleU16.toUtf8(); + + const auto haystack = make<Haystack>(QStringRef(&haystackU16), haystackL1, haystackU8); + const auto needle = make<Needle>(QStringRef(&needleU16), needleL1, needleU8); + + using size_type = typename Haystack::size_type; + + QCOMPARE(haystack.lastIndexOf(needle, startpos), size_type(resultCS)); + QCOMPARE(haystack.lastIndexOf(needle, startpos, Qt::CaseSensitive), size_type(resultCS)); + QCOMPARE(haystack.lastIndexOf(needle, startpos, Qt::CaseInsensitive), size_type(resultCIS)); + + if (needle.size() == 1) + { + QCOMPARE(haystack.lastIndexOf(needle[0], startpos), size_type(resultCS)); + QCOMPARE(haystack.lastIndexOf(needle[0], startpos, Qt::CaseSensitive), size_type(resultCS)); + QCOMPARE(haystack.lastIndexOf(needle[0], startpos, Qt::CaseInsensitive), size_type(resultCIS)); + } +} + QTEST_APPLESS_MAIN(tst_QStringApiSymmetry) #include "tst_qstringapisymmetry.moc" diff --git a/tests/auto/corelib/tools/qstringbuilder/qstringbuilder.pro b/tests/auto/corelib/text/qstringbuilder/qstringbuilder.pro index d73d541502..d73d541502 100644 --- a/tests/auto/corelib/tools/qstringbuilder/qstringbuilder.pro +++ b/tests/auto/corelib/text/qstringbuilder/qstringbuilder.pro diff --git a/tests/auto/corelib/tools/qstringbuilder/qstringbuilder1/qstringbuilder1.pro b/tests/auto/corelib/text/qstringbuilder/qstringbuilder1/qstringbuilder1.pro index d9cdad1bf5..d9cdad1bf5 100644 --- a/tests/auto/corelib/tools/qstringbuilder/qstringbuilder1/qstringbuilder1.pro +++ b/tests/auto/corelib/text/qstringbuilder/qstringbuilder1/qstringbuilder1.pro diff --git a/tests/auto/corelib/tools/qstringbuilder/qstringbuilder1/stringbuilder.cpp b/tests/auto/corelib/text/qstringbuilder/qstringbuilder1/stringbuilder.cpp index ac7f439248..ac7f439248 100644 --- a/tests/auto/corelib/tools/qstringbuilder/qstringbuilder1/stringbuilder.cpp +++ b/tests/auto/corelib/text/qstringbuilder/qstringbuilder1/stringbuilder.cpp diff --git a/tests/auto/corelib/tools/qstringbuilder/qstringbuilder1/tst_qstringbuilder1.cpp b/tests/auto/corelib/text/qstringbuilder/qstringbuilder1/tst_qstringbuilder1.cpp index 2d320748f2..2d320748f2 100644 --- a/tests/auto/corelib/tools/qstringbuilder/qstringbuilder1/tst_qstringbuilder1.cpp +++ b/tests/auto/corelib/text/qstringbuilder/qstringbuilder1/tst_qstringbuilder1.cpp diff --git a/tests/auto/corelib/tools/qstringbuilder/qstringbuilder2/qstringbuilder2.pro b/tests/auto/corelib/text/qstringbuilder/qstringbuilder2/qstringbuilder2.pro index e134c5d934..e134c5d934 100644 --- a/tests/auto/corelib/tools/qstringbuilder/qstringbuilder2/qstringbuilder2.pro +++ b/tests/auto/corelib/text/qstringbuilder/qstringbuilder2/qstringbuilder2.pro diff --git a/tests/auto/corelib/tools/qstringbuilder/qstringbuilder2/tst_qstringbuilder2.cpp b/tests/auto/corelib/text/qstringbuilder/qstringbuilder2/tst_qstringbuilder2.cpp index 669990c9bc..669990c9bc 100644 --- a/tests/auto/corelib/tools/qstringbuilder/qstringbuilder2/tst_qstringbuilder2.cpp +++ b/tests/auto/corelib/text/qstringbuilder/qstringbuilder2/tst_qstringbuilder2.cpp diff --git a/tests/auto/corelib/tools/qstringbuilder/qstringbuilder3/qstringbuilder3.pro b/tests/auto/corelib/text/qstringbuilder/qstringbuilder3/qstringbuilder3.pro index 29607551c3..29607551c3 100644 --- a/tests/auto/corelib/tools/qstringbuilder/qstringbuilder3/qstringbuilder3.pro +++ b/tests/auto/corelib/text/qstringbuilder/qstringbuilder3/qstringbuilder3.pro diff --git a/tests/auto/corelib/tools/qstringbuilder/qstringbuilder3/tst_qstringbuilder3.cpp b/tests/auto/corelib/text/qstringbuilder/qstringbuilder3/tst_qstringbuilder3.cpp index 397e3326bf..397e3326bf 100644 --- a/tests/auto/corelib/tools/qstringbuilder/qstringbuilder3/tst_qstringbuilder3.cpp +++ b/tests/auto/corelib/text/qstringbuilder/qstringbuilder3/tst_qstringbuilder3.cpp diff --git a/tests/auto/corelib/tools/qstringbuilder/qstringbuilder4/qstringbuilder4.pro b/tests/auto/corelib/text/qstringbuilder/qstringbuilder4/qstringbuilder4.pro index e55848e4bd..e55848e4bd 100644 --- a/tests/auto/corelib/tools/qstringbuilder/qstringbuilder4/qstringbuilder4.pro +++ b/tests/auto/corelib/text/qstringbuilder/qstringbuilder4/qstringbuilder4.pro diff --git a/tests/auto/corelib/tools/qstringbuilder/qstringbuilder4/tst_qstringbuilder4.cpp b/tests/auto/corelib/text/qstringbuilder/qstringbuilder4/tst_qstringbuilder4.cpp index 05ce334c82..05ce334c82 100644 --- a/tests/auto/corelib/tools/qstringbuilder/qstringbuilder4/tst_qstringbuilder4.cpp +++ b/tests/auto/corelib/text/qstringbuilder/qstringbuilder4/tst_qstringbuilder4.cpp diff --git a/tests/auto/corelib/tools/qstringiterator/qstringiterator.pro b/tests/auto/corelib/text/qstringiterator/qstringiterator.pro index 3a1678b5f3..3a1678b5f3 100644 --- a/tests/auto/corelib/tools/qstringiterator/qstringiterator.pro +++ b/tests/auto/corelib/text/qstringiterator/qstringiterator.pro diff --git a/tests/auto/corelib/tools/qstringiterator/tst_qstringiterator.cpp b/tests/auto/corelib/text/qstringiterator/tst_qstringiterator.cpp index 7d5504c22c..7d5504c22c 100644 --- a/tests/auto/corelib/tools/qstringiterator/tst_qstringiterator.cpp +++ b/tests/auto/corelib/text/qstringiterator/tst_qstringiterator.cpp diff --git a/tests/auto/corelib/tools/qstringlist/.gitignore b/tests/auto/corelib/text/qstringlist/.gitignore index 3e0cdc952f..3e0cdc952f 100644 --- a/tests/auto/corelib/tools/qstringlist/.gitignore +++ b/tests/auto/corelib/text/qstringlist/.gitignore diff --git a/tests/auto/corelib/tools/qstringlist/qstringlist.pro b/tests/auto/corelib/text/qstringlist/qstringlist.pro index a87257decb..a87257decb 100644 --- a/tests/auto/corelib/tools/qstringlist/qstringlist.pro +++ b/tests/auto/corelib/text/qstringlist/qstringlist.pro diff --git a/tests/auto/corelib/tools/qstringlist/tst_qstringlist.cpp b/tests/auto/corelib/text/qstringlist/tst_qstringlist.cpp index 42bdf62a93..66d4744454 100644 --- a/tests/auto/corelib/tools/qstringlist/tst_qstringlist.cpp +++ b/tests/auto/corelib/text/qstringlist/tst_qstringlist.cpp @@ -30,13 +30,17 @@ #include <qregexp.h> #include <qregularexpression.h> #include <qstringlist.h> +#include <qvector.h> #include <locale.h> +#include <algorithm> + class tst_QStringList : public QObject { Q_OBJECT private slots: + void constructors(); void sort(); void filter(); void replaceInStrings(); @@ -59,13 +63,44 @@ private slots: void joinChar() const; void joinChar_data() const; -#ifdef Q_COMPILER_INITIALIZER_LISTS void initializeList() const; -#endif }; extern const char email[]; +void tst_QStringList::constructors() +{ + { + QStringList list; + QVERIFY(list.isEmpty()); + QCOMPARE(list.size(), 0); + QVERIFY(list == QStringList()); + } + { + QString str = "abc"; + QStringList list(str); + QVERIFY(!list.isEmpty()); + QCOMPARE(list.size(), 1); + QCOMPARE(list.at(0), str); + } + { + QStringList list{ "a", "b", "c" }; + QVERIFY(!list.isEmpty()); + QCOMPARE(list.size(), 3); + QCOMPARE(list.at(0), "a"); + QCOMPARE(list.at(1), "b"); + QCOMPARE(list.at(2), "c"); + } + { + const QVector<QString> reference{ "a", "b", "c" }; + QCOMPARE(reference.size(), 3); + + QStringList list(reference.cbegin(), reference.cend()); + QCOMPARE(list.size(), reference.size()); + QVERIFY(std::equal(list.cbegin(), list.cend(), reference.cbegin())); + } +} + void tst_QStringList::indexOf_regExp() { QStringList list; @@ -224,6 +259,12 @@ void tst_QStringList::filter() list5 = list5.filter( QRegularExpression("[i]ll") ); list6 << "Bill Gates" << "Bill Clinton"; QCOMPARE( list5, list6 ); + + QStringList list7, list8; + list7 << "Bill Gates" << "Joe Blow" << "Bill Clinton"; + list7 = list7.filter( QStringView(QString("Bill")) ); + list8 << "Bill Gates" << "Bill Clinton"; + QCOMPARE( list7, list8 ); } void tst_QStringList::sort() @@ -281,6 +322,16 @@ void tst_QStringList::replaceInStrings() list10 << "Bill Clinton" << "Bill Gates"; list9.replaceInStrings( QRegularExpression("^(.*), (.*)$"), "\\2 \\1" ); QCOMPARE( list9, list10 ); + + QStringList list11, list12, list13, list14; + list11 << "alpha" << "beta" << "gamma" << "epsilon"; + list12 << "alpha" << "beta" << "gamma" << "epsilon"; + list13 << "alpha" << "beta" << "gamma" << "epsilon"; + list11.replaceInStrings( QStringView(QString("a")), QStringView(QString("o")) ); + list12.replaceInStrings( QStringView(QString("a")), QString("o") ); + list13.replaceInStrings( QString("a"), QStringView(QString("o")) ); + list14 << "olpho" << "beto" << "gommo" << "epsilon"; + QCOMPARE( list11, list12 ); } void tst_QStringList::contains() @@ -392,6 +443,7 @@ void tst_QStringList::join() const QCOMPARE(input.join(separator), expectedResult); QCOMPARE(input.join(QLatin1String(separator.toLatin1())), expectedResult); + QCOMPARE(input.join(QStringView(separator)), expectedResult); } void tst_QStringList::join_data() const @@ -482,8 +534,6 @@ void tst_QStringList::joinEmptiness() const QVERIFY(string.isNull()); } -#ifdef Q_COMPILER_INITIALIZER_LISTS -// C++0x support is required void tst_QStringList::initializeList() const { @@ -491,7 +541,6 @@ void tst_QStringList::initializeList() const QCOMPARE(v1, (QStringList() << "hello" << "world" << "plop")); QCOMPARE(v1, (QStringList{"hello","world","plop"})); } -#endif QTEST_APPLESS_MAIN(tst_QStringList) #include "tst_qstringlist.moc" diff --git a/tests/auto/corelib/tools/qstringmatcher/.gitignore b/tests/auto/corelib/text/qstringmatcher/.gitignore index 3c7caf8490..3c7caf8490 100644 --- a/tests/auto/corelib/tools/qstringmatcher/.gitignore +++ b/tests/auto/corelib/text/qstringmatcher/.gitignore diff --git a/tests/auto/corelib/tools/qstringmatcher/qstringmatcher.pro b/tests/auto/corelib/text/qstringmatcher/qstringmatcher.pro index e34928776f..e34928776f 100644 --- a/tests/auto/corelib/tools/qstringmatcher/qstringmatcher.pro +++ b/tests/auto/corelib/text/qstringmatcher/qstringmatcher.pro diff --git a/tests/auto/corelib/tools/qstringmatcher/tst_qstringmatcher.cpp b/tests/auto/corelib/text/qstringmatcher/tst_qstringmatcher.cpp index 8a55f54449..2d577bb0ab 100644 --- a/tests/auto/corelib/tools/qstringmatcher/tst_qstringmatcher.cpp +++ b/tests/auto/corelib/text/qstringmatcher/tst_qstringmatcher.cpp @@ -100,6 +100,11 @@ void tst_QStringMatcher::indexIn() matcher.setPattern(needle); QCOMPARE(matcher.indexIn(haystack, from), indexIn); + + const auto needleSV = QStringView(needle); + QStringMatcher matcherSV(needleSV); + + QCOMPARE(matcherSV.indexIn(QStringView(haystack), from), indexIn); } void tst_QStringMatcher::setCaseSensitivity_data() @@ -128,6 +133,7 @@ void tst_QStringMatcher::setCaseSensitivity() matcher.setCaseSensitivity(static_cast<Qt::CaseSensitivity> (cs)); QCOMPARE(matcher.indexIn(haystack, from), indexIn); + QCOMPARE(matcher.indexIn(QStringView(haystack), from), indexIn); } void tst_QStringMatcher::assignOperator() diff --git a/tests/auto/corelib/tools/qstringref/qstringref.pro b/tests/auto/corelib/text/qstringref/qstringref.pro index 04f3ba6a92..04f3ba6a92 100644 --- a/tests/auto/corelib/tools/qstringref/qstringref.pro +++ b/tests/auto/corelib/text/qstringref/qstringref.pro diff --git a/tests/auto/corelib/tools/qstringref/tst_qstringref.cpp b/tests/auto/corelib/text/qstringref/tst_qstringref.cpp index 581e9152e6..6f01947131 100644 --- a/tests/auto/corelib/tools/qstringref/tst_qstringref.cpp +++ b/tests/auto/corelib/text/qstringref/tst_qstringref.cpp @@ -596,7 +596,10 @@ void tst_QStringRef::startsWith() QVERIFY(!ref.startsWith("C")); QVERIFY(!ref.startsWith("ABCDEF")); QVERIFY(ref.startsWith("")); + QVERIFY(ref.startsWith(QString())); +#if QT_DEPRECATED_SINCE(5, 9) QVERIFY(ref.startsWith(QString::null)); +#endif QVERIFY(ref.startsWith('A')); QVERIFY(ref.startsWith(QLatin1Char('A'))); QVERIFY(ref.startsWith(QChar('A'))); @@ -623,7 +626,10 @@ void tst_QStringRef::startsWith() QVERIFY(!ref.startsWith("c", Qt::CaseInsensitive)); QVERIFY(!ref.startsWith("abcdef", Qt::CaseInsensitive)); QVERIFY(ref.startsWith("", Qt::CaseInsensitive)); + QVERIFY(ref.startsWith(QString(), Qt::CaseInsensitive)); +#if QT_DEPRECATED_SINCE(5, 9) QVERIFY(ref.startsWith(QString::null, Qt::CaseInsensitive)); +#endif QVERIFY(ref.startsWith('a', Qt::CaseInsensitive)); QVERIFY(ref.startsWith('A', Qt::CaseInsensitive)); QVERIFY(ref.startsWith(QLatin1Char('a'), Qt::CaseInsensitive)); @@ -656,7 +662,10 @@ void tst_QStringRef::startsWith() const QString a = QString::fromLatin1(""); CREATE_REF(a); QVERIFY(ref.startsWith("")); + QVERIFY(ref.startsWith(QString())); +#if QT_DEPRECATED_SINCE(5, 9) QVERIFY(ref.startsWith(QString::null)); +#endif QVERIFY(!ref.startsWith("ABC")); QVERIFY(ref.startsWith(QLatin1String(""))); @@ -670,7 +679,10 @@ void tst_QStringRef::startsWith() { const QStringRef ref; QVERIFY(!ref.startsWith("")); + QVERIFY(ref.startsWith(QString())); +#if QT_DEPRECATED_SINCE(5, 9) QVERIFY(ref.startsWith(QString::null)); +#endif QVERIFY(!ref.startsWith("ABC")); QVERIFY(!ref.startsWith(QLatin1String(""))); @@ -693,7 +705,10 @@ void tst_QStringRef::endsWith() QVERIFY(!ref.endsWith("C")); QVERIFY(!ref.endsWith("ABCDEF")); QVERIFY(ref.endsWith("")); + QVERIFY(ref.endsWith(QString())); +#if QT_DEPRECATED_SINCE(5, 9) QVERIFY(ref.endsWith(QString::null)); +#endif QVERIFY(ref.endsWith('B')); QVERIFY(ref.endsWith(QLatin1Char('B'))); QVERIFY(ref.endsWith(QChar('B'))); @@ -720,7 +735,10 @@ void tst_QStringRef::endsWith() QVERIFY(!ref.endsWith("c", Qt::CaseInsensitive)); QVERIFY(!ref.endsWith("abcdef", Qt::CaseInsensitive)); QVERIFY(ref.endsWith("", Qt::CaseInsensitive)); + QVERIFY(ref.endsWith(QString(), Qt::CaseInsensitive)); +#if QT_DEPRECATED_SINCE(5, 9) QVERIFY(ref.endsWith(QString::null, Qt::CaseInsensitive)); +#endif QVERIFY(ref.endsWith('b', Qt::CaseInsensitive)); QVERIFY(ref.endsWith('B', Qt::CaseInsensitive)); QVERIFY(ref.endsWith(QLatin1Char('b'), Qt::CaseInsensitive)); @@ -754,7 +772,10 @@ void tst_QStringRef::endsWith() const QString a = QString::fromLatin1(""); CREATE_REF(a); QVERIFY(ref.endsWith("")); + QVERIFY(ref.endsWith(QString())); +#if QT_DEPRECATED_SINCE(5, 9) QVERIFY(ref.endsWith(QString::null)); +#endif QVERIFY(!ref.endsWith("ABC")); QVERIFY(!ref.endsWith(QLatin1Char(0))); QVERIFY(!ref.endsWith(QLatin1Char('x'))); @@ -768,7 +789,10 @@ void tst_QStringRef::endsWith() { QStringRef ref; QVERIFY(!ref.endsWith("")); + QVERIFY(ref.endsWith(QString())); +#if QT_DEPRECATED_SINCE(5, 9) QVERIFY(ref.endsWith(QString::null)); +#endif QVERIFY(!ref.endsWith("ABC")); QVERIFY(!ref.endsWith(QLatin1String(""))); diff --git a/tests/auto/corelib/tools/qstringview/.gitignore b/tests/auto/corelib/text/qstringview/.gitignore index 5f757d448a..5f757d448a 100644 --- a/tests/auto/corelib/tools/qstringview/.gitignore +++ b/tests/auto/corelib/text/qstringview/.gitignore diff --git a/tests/auto/corelib/tools/qstringview/qstringview.pro b/tests/auto/corelib/text/qstringview/qstringview.pro index e0e9973c91..e0e9973c91 100644 --- a/tests/auto/corelib/tools/qstringview/qstringview.pro +++ b/tests/auto/corelib/text/qstringview/qstringview.pro diff --git a/tests/auto/corelib/tools/qstringview/tst_qstringview.cpp b/tests/auto/corelib/text/qstringview/tst_qstringview.cpp index e800a0d794..47ce9a6f63 100644 --- a/tests/auto/corelib/tools/qstringview/tst_qstringview.cpp +++ b/tests/auto/corelib/text/qstringview/tst_qstringview.cpp @@ -134,6 +134,8 @@ private Q_SLOTS: void literals() const; void at() const; + void arg() const; + void fromQString() const; void fromQStringRef() const; @@ -249,7 +251,7 @@ void tst_QStringView::constExpr() const Q_STATIC_ASSERT(sv2.empty()); } { - constexpr QStringView sv = QStringViewLiteral(""); + constexpr QStringView sv = u""; Q_STATIC_ASSERT(sv.size() == 0); Q_STATIC_ASSERT(!sv.isNull()); Q_STATIC_ASSERT(sv.empty()); @@ -261,7 +263,7 @@ void tst_QStringView::constExpr() const Q_STATIC_ASSERT(sv2.empty()); } { - constexpr QStringView sv = QStringViewLiteral("Hello"); + constexpr QStringView sv = u"Hello"; Q_STATIC_ASSERT(sv.size() == 5); Q_STATIC_ASSERT(!sv.empty()); Q_STATIC_ASSERT(!sv.isEmpty()); @@ -425,6 +427,47 @@ void tst_QStringView::at() const QCOMPARE(sv.at(4), QChar('o')); QCOMPARE(sv[4], QChar('o')); } +void tst_QStringView::arg() const +{ +#define CHECK1(pattern, arg1, expected) \ + do { \ + auto p = QStringView(u"" pattern); \ + QCOMPARE(p.arg(QLatin1String(arg1)), expected); \ + QCOMPARE(p.arg(u"" arg1), expected); \ + QCOMPARE(p.arg(QStringLiteral(arg1)), expected); \ + QCOMPARE(p.arg(QString(QLatin1String(arg1))), expected); \ + } while (false) \ + /*end*/ +#define CHECK2(pattern, arg1, arg2, expected) \ + do { \ + auto p = QStringView(u"" pattern); \ + QCOMPARE(p.arg(QLatin1String(arg1), QLatin1String(arg2)), expected); \ + QCOMPARE(p.arg(u"" arg1, QLatin1String(arg2)), expected); \ + QCOMPARE(p.arg(QLatin1String(arg1), u"" arg2), expected); \ + QCOMPARE(p.arg(u"" arg1, u"" arg2), expected); \ + } while (false) \ + /*end*/ + + CHECK1("", "World", ""); + CHECK1("%1", "World", "World"); + CHECK1("!%1?", "World", "!World?"); + CHECK1("%1%1", "World", "WorldWorld"); + CHECK1("%1%2", "World", "World%2"); + CHECK1("%2%1", "World", "%2World"); + + CHECK2("", "Hello", "World", ""); + CHECK2("%1", "Hello", "World", "Hello"); + CHECK2("!%1, %2?", "Hello", "World", "!Hello, World?"); + CHECK2("%1%1", "Hello", "World", "HelloHello"); + CHECK2("%1%2", "Hello", "World", "HelloWorld"); + CHECK2("%2%1", "Hello", "World", "WorldHello"); + +#undef CHECK2 +#undef CHECK1 + + QCOMPARE(QStringView(u" %2 %2 %1 %3 ").arg(QLatin1Char('c'), QChar::CarriageReturn, u'C'), " \r \r c C "); +} + void tst_QStringView::fromQString() const { QString null; @@ -619,9 +662,9 @@ void tst_QStringView::conversion_tests(String string) const void tst_QStringView::comparison() { - const QStringView aa = QStringViewLiteral("aa"); - const QStringView upperAa = QStringViewLiteral("AA"); - const QStringView bb = QStringViewLiteral("bb"); + const QStringView aa = u"aa"; + const QStringView upperAa = u"AA"; + const QStringView bb = u"bb"; QVERIFY(aa == aa); QVERIFY(aa != bb); diff --git a/tests/auto/corelib/tools/qtextboundaryfinder/.gitignore b/tests/auto/corelib/text/qtextboundaryfinder/.gitignore index bd0df58233..bd0df58233 100644 --- a/tests/auto/corelib/tools/qtextboundaryfinder/.gitignore +++ b/tests/auto/corelib/text/qtextboundaryfinder/.gitignore diff --git a/tests/auto/corelib/tools/qtextboundaryfinder/data/GraphemeBreakTest.txt b/tests/auto/corelib/text/qtextboundaryfinder/data/GraphemeBreakTest.txt index d7d8f90de0..d7d8f90de0 100644 --- a/tests/auto/corelib/tools/qtextboundaryfinder/data/GraphemeBreakTest.txt +++ b/tests/auto/corelib/text/qtextboundaryfinder/data/GraphemeBreakTest.txt diff --git a/tests/auto/corelib/tools/qtextboundaryfinder/data/LineBreakTest.txt b/tests/auto/corelib/text/qtextboundaryfinder/data/LineBreakTest.txt index 6715446aba..6715446aba 100644 --- a/tests/auto/corelib/tools/qtextboundaryfinder/data/LineBreakTest.txt +++ b/tests/auto/corelib/text/qtextboundaryfinder/data/LineBreakTest.txt diff --git a/tests/auto/corelib/tools/qtextboundaryfinder/data/SentenceBreakTest.txt b/tests/auto/corelib/text/qtextboundaryfinder/data/SentenceBreakTest.txt index 2985b84cf8..2985b84cf8 100644 --- a/tests/auto/corelib/tools/qtextboundaryfinder/data/SentenceBreakTest.txt +++ b/tests/auto/corelib/text/qtextboundaryfinder/data/SentenceBreakTest.txt diff --git a/tests/auto/corelib/tools/qtextboundaryfinder/data/WordBreakTest.txt b/tests/auto/corelib/text/qtextboundaryfinder/data/WordBreakTest.txt index 63761026ce..63761026ce 100644 --- a/tests/auto/corelib/tools/qtextboundaryfinder/data/WordBreakTest.txt +++ b/tests/auto/corelib/text/qtextboundaryfinder/data/WordBreakTest.txt diff --git a/tests/auto/corelib/tools/qtextboundaryfinder/qtextboundaryfinder.pro b/tests/auto/corelib/text/qtextboundaryfinder/qtextboundaryfinder.pro index 3c9f03842d..3c9f03842d 100644 --- a/tests/auto/corelib/tools/qtextboundaryfinder/qtextboundaryfinder.pro +++ b/tests/auto/corelib/text/qtextboundaryfinder/qtextboundaryfinder.pro diff --git a/tests/auto/corelib/tools/qtextboundaryfinder/testdata.qrc b/tests/auto/corelib/text/qtextboundaryfinder/testdata.qrc index 0cc4ccaa57..0cc4ccaa57 100644 --- a/tests/auto/corelib/tools/qtextboundaryfinder/testdata.qrc +++ b/tests/auto/corelib/text/qtextboundaryfinder/testdata.qrc diff --git a/tests/auto/corelib/tools/qtextboundaryfinder/tst_qtextboundaryfinder.cpp b/tests/auto/corelib/text/qtextboundaryfinder/tst_qtextboundaryfinder.cpp index 5701335b4a..a46011ff6c 100644 --- a/tests/auto/corelib/tools/qtextboundaryfinder/tst_qtextboundaryfinder.cpp +++ b/tests/auto/corelib/text/qtextboundaryfinder/tst_qtextboundaryfinder.cpp @@ -192,7 +192,7 @@ static void doTestData(const QString &testString, const QList<int> &expectedBrea // test toPreviousBoundary() { QList<int> expectedBreakPositionsRev = expectedBreakPositions; - std::sort(expectedBreakPositionsRev.begin(), expectedBreakPositionsRev.end(), qGreater<int>()); + std::sort(expectedBreakPositionsRev.begin(), expectedBreakPositionsRev.end(), std::greater<int>()); QList<int> actualBreakPositions; boundaryFinder.toEnd(); diff --git a/tests/auto/corelib/text/text.pro b/tests/auto/corelib/text/text.pro new file mode 100644 index 0000000000..09d58bd74c --- /dev/null +++ b/tests/auto/corelib/text/text.pro @@ -0,0 +1,23 @@ +TEMPLATE = subdirs + +SUBDIRS = \ + qbytearray \ + qbytearraylist \ + qbytearraymatcher \ + qbytedatabuffer \ + qchar \ + qcollator \ + qlatin1string \ + qlocale \ + qregexp \ + qregularexpression \ + qstring \ + qstring_no_cast_from_bytearray \ + qstringapisymmetry \ + qstringbuilder \ + qstringiterator \ + qstringlist \ + qstringmatcher \ + qstringref \ + qstringview \ + qtextboundaryfinder diff --git a/tests/auto/corelib/thread/qatomicint/tst_qatomicint.cpp b/tests/auto/corelib/thread/qatomicint/tst_qatomicint.cpp index cc197cabba..bef491d5f0 100644 --- a/tests/auto/corelib/thread/qatomicint/tst_qatomicint.cpp +++ b/tests/auto/corelib/thread/qatomicint/tst_qatomicint.cpp @@ -31,6 +31,7 @@ #include <QAtomicInt> #include <QCoreApplication> +#include <QElapsedTimer> #include <limits.h> @@ -104,12 +105,12 @@ static void warningFreeHelperTemplate() assemblyMarker<1>(&i); // the loads sometimes generate no assembly output - i.load(); + i.loadRelaxed(); assemblyMarker<11>(&i); i.loadAcquire(); assemblyMarker<12>(&i); - i.store(newValue); + i.storeRelaxed(newValue); assemblyMarker<21>(&i); i.storeRelease(newValue); assemblyMarker<22>(&i); @@ -281,9 +282,9 @@ void tst_QAtomicInt::constructor() { QFETCH(int, value); QAtomicInt atomic1(value); - QCOMPARE(atomic1.load(), value); + QCOMPARE(atomic1.loadRelaxed(), value); QAtomicInt atomic2 = value; - QCOMPARE(atomic2.load(), value); + QCOMPARE(atomic2.loadRelaxed(), value); } void tst_QAtomicInt::copy_constructor_data() @@ -293,16 +294,16 @@ void tst_QAtomicInt::copy_constructor() { QFETCH(int, value); QAtomicInt atomic1(value); - QCOMPARE(atomic1.load(), value); + QCOMPARE(atomic1.loadRelaxed(), value); QAtomicInt atomic2(atomic1); - QCOMPARE(atomic2.load(), value); + QCOMPARE(atomic2.loadRelaxed(), value); QAtomicInt atomic3 = atomic1; - QCOMPARE(atomic3.load(), value); + QCOMPARE(atomic3.loadRelaxed(), value); QAtomicInt atomic4(atomic2); - QCOMPARE(atomic4.load(), value); + QCOMPARE(atomic4.loadRelaxed(), value); QAtomicInt atomic5 = atomic2; - QCOMPARE(atomic5.load(), value); + QCOMPARE(atomic5.loadRelaxed(), value); } void tst_QAtomicInt::assignment_operator_data() @@ -326,13 +327,13 @@ void tst_QAtomicInt::assignment_operator() { QAtomicInt atomic1 = value; atomic1 = newval; - QCOMPARE(atomic1.load(), newval); + QCOMPARE(atomic1.loadRelaxed(), newval); atomic1 = value; - QCOMPARE(atomic1.load(), value); + QCOMPARE(atomic1.loadRelaxed(), value); QAtomicInt atomic2 = newval; atomic1 = atomic2; - QCOMPARE(atomic1.load(), atomic2.load()); + QCOMPARE(atomic1.loadRelaxed(), atomic2.loadRelaxed()); } } @@ -400,7 +401,7 @@ void tst_QAtomicInt::ref() QFETCH(int, value); QAtomicInt x = value; QTEST(x.ref() ? 1 : 0, "result"); - QTEST(x.load(), "expected"); + QTEST(x.loadRelaxed(), "expected"); } void tst_QAtomicInt::deref_data() @@ -419,7 +420,7 @@ void tst_QAtomicInt::deref() QFETCH(int, value); QAtomicInt x = value; QTEST(x.deref() ? 1 : 0, "result"); - QTEST(x.load(), "expected"); + QTEST(x.loadRelaxed(), "expected"); } void tst_QAtomicInt::isTestAndSetNative() @@ -635,25 +636,25 @@ void tst_QAtomicInt::fetchAndStore() { QAtomicInt atomic = value; QCOMPARE(atomic.fetchAndStoreRelaxed(newval), value); - QCOMPARE(atomic.load(), newval); + QCOMPARE(atomic.loadRelaxed(), newval); } { QAtomicInt atomic = value; QCOMPARE(atomic.fetchAndStoreAcquire(newval), value); - QCOMPARE(atomic.load(), newval); + QCOMPARE(atomic.loadRelaxed(), newval); } { QAtomicInt atomic = value; QCOMPARE(atomic.fetchAndStoreRelease(newval), value); - QCOMPARE(atomic.load(), newval); + QCOMPARE(atomic.loadRelaxed(), newval); } { QAtomicInt atomic = value; QCOMPARE(atomic.fetchAndStoreOrdered(newval), value); - QCOMPARE(atomic.load(), newval); + QCOMPARE(atomic.loadRelaxed(), newval); } } @@ -772,28 +773,28 @@ void tst_QAtomicInt::fetchAndAdd() QAtomicInt atomic = value1; result = atomic.fetchAndAddRelaxed(value2); QCOMPARE(result, value1); - QCOMPARE(atomic.load(), value1 + value2); + QCOMPARE(atomic.loadRelaxed(), value1 + value2); } { QAtomicInt atomic = value1; result = atomic.fetchAndAddAcquire(value2); QCOMPARE(result, value1); - QCOMPARE(atomic.load(), value1 + value2); + QCOMPARE(atomic.loadRelaxed(), value1 + value2); } { QAtomicInt atomic = value1; result = atomic.fetchAndAddRelease(value2); QCOMPARE(result, value1); - QCOMPARE(atomic.load(), value1 + value2); + QCOMPARE(atomic.loadRelaxed(), value1 + value2); } { QAtomicInt atomic = value1; result = atomic.fetchAndAddOrdered(value2); QCOMPARE(result, value1); - QCOMPARE(atomic.load(), value1 + value2); + QCOMPARE(atomic.loadRelaxed(), value1 + value2); } } @@ -851,14 +852,14 @@ void tst_QAtomicInt::operators() void tst_QAtomicInt::testAndSet_loop() { - QTime stopWatch; + QElapsedTimer stopWatch; stopWatch.start(); int iterations = 10000000; QAtomicInt val=0; for (int i = 0; i < iterations; ++i) { - int v = val.load(); + int v = val.loadRelaxed(); QVERIFY(val.testAndSetRelaxed(v, v+1)); if ((i % 1000) == 999) { if (stopWatch.elapsed() > 60 * 1000) { @@ -881,7 +882,7 @@ void tst_QAtomicInt::fetchAndAdd_loop() QAtomicInt val=0; for (int i = 0; i < iterations; ++i) { const int prev = val.fetchAndAddRelaxed(1); - QCOMPARE(prev, val.load() -1); + QCOMPARE(prev, val.loadRelaxed() -1); } } @@ -919,7 +920,7 @@ void tst_QAtomicInt::fetchAndAdd_threadedLoop() t1.wait(); t2.wait(); - QCOMPARE(val.load(), 0); + QCOMPARE(val.loadRelaxed(), 0); } QTEST_MAIN(tst_QAtomicInt) diff --git a/tests/auto/corelib/thread/qatomicinteger/tst_qatomicinteger.cpp b/tests/auto/corelib/thread/qatomicinteger/tst_qatomicinteger.cpp index 32e5b8ee56..bfe2a60088 100644 --- a/tests/auto/corelib/thread/qatomicinteger/tst_qatomicinteger.cpp +++ b/tests/auto/corelib/thread/qatomicinteger/tst_qatomicinteger.cpp @@ -270,13 +270,13 @@ void tst_QAtomicIntegerXX::constructor() QFETCH(LargeInt, value); QAtomicInteger<T> atomic(value); - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); QAtomicInteger<T> atomic2 = value; - QCOMPARE(atomic2.load(), T(value)); + QCOMPARE(atomic2.loadRelaxed(), T(value)); - QVERIFY(atomic.load() >= std::numeric_limits<T>::min()); - QVERIFY(atomic.load() <= std::numeric_limits<T>::max()); + QVERIFY(atomic.loadRelaxed() >= std::numeric_limits<T>::min()); + QVERIFY(atomic.loadRelaxed() <= std::numeric_limits<T>::max()); } void tst_QAtomicIntegerXX::copy() @@ -285,17 +285,17 @@ void tst_QAtomicIntegerXX::copy() QAtomicInteger<T> atomic(value); QAtomicInteger<T> copy(atomic); - QCOMPARE(copy.load(), atomic.load()); + QCOMPARE(copy.loadRelaxed(), atomic.loadRelaxed()); QAtomicInteger<T> copy2 = atomic; - QCOMPARE(copy2.load(), atomic.load()); + QCOMPARE(copy2.loadRelaxed(), atomic.loadRelaxed()); // move - QAtomicInteger<T> copy3(qMove(copy)); - QCOMPARE(copy3.load(), atomic.load()); + QAtomicInteger<T> copy3(std::move(copy)); + QCOMPARE(copy3.loadRelaxed(), atomic.loadRelaxed()); - QAtomicInteger<T> copy4 = qMove(copy2); - QCOMPARE(copy4.load(), atomic.load()); + QAtomicInteger<T> copy4 = std::move(copy2); + QCOMPARE(copy4.loadRelaxed(), atomic.loadRelaxed()); } void tst_QAtomicIntegerXX::assign() @@ -305,24 +305,24 @@ void tst_QAtomicIntegerXX::assign() QAtomicInteger<T> atomic(value); QAtomicInteger<T> copy; copy = atomic; - QCOMPARE(copy.load(), atomic.load()); + QCOMPARE(copy.loadRelaxed(), atomic.loadRelaxed()); QAtomicInteger<T> copy2; copy2 = atomic; // operator=(const QAtomicInteger &) - QCOMPARE(copy2.load(), atomic.load()); + QCOMPARE(copy2.loadRelaxed(), atomic.loadRelaxed()); QAtomicInteger<T> copy2bis; - copy2bis = atomic.load(); // operator=(T) - QCOMPARE(copy2bis.load(), atomic.load()); + copy2bis = atomic.loadRelaxed(); // operator=(T) + QCOMPARE(copy2bis.loadRelaxed(), atomic.loadRelaxed()); // move QAtomicInteger<T> copy3; - copy3 = qMove(copy); - QCOMPARE(copy3.load(), atomic.load()); + copy3 = std::move(copy); + QCOMPARE(copy3.loadRelaxed(), atomic.loadRelaxed()); QAtomicInteger<T> copy4; - copy4 = qMove(copy2); - QCOMPARE(copy4.load(), atomic.load()); + copy4 = std::move(copy2); + QCOMPARE(copy4.loadRelaxed(), atomic.loadRelaxed()); } void tst_QAtomicIntegerXX::operatorInteger() @@ -331,7 +331,7 @@ void tst_QAtomicIntegerXX::operatorInteger() QAtomicInteger<T> atomic(value); T val2 = atomic; - QCOMPARE(val2, atomic.load()); + QCOMPARE(val2, atomic.loadRelaxed()); QCOMPARE(val2, T(value)); } @@ -346,7 +346,7 @@ void tst_QAtomicIntegerXX::loadAcquireStoreRelease() QCOMPARE(atomic.loadAcquire(), T(~value)); atomic.storeRelease(value); - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); } void tst_QAtomicIntegerXX::refDeref() @@ -364,16 +364,16 @@ void tst_QAtomicIntegerXX::refDeref() QAtomicInteger<T> atomic(value); if (!needToPreventOverflow) { QCOMPARE(atomic.ref(), (nextValue != 0)); - QCOMPARE(atomic.load(), nextValue); + QCOMPARE(atomic.loadRelaxed(), nextValue); QCOMPARE(atomic.deref(), (value != 0)); } - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); if (!needToPreventUnderflow) { QCOMPARE(atomic.deref(), (prevValue != 0)); - QCOMPARE(atomic.load(), prevValue); + QCOMPARE(atomic.loadRelaxed(), prevValue); QCOMPARE(atomic.ref(), (value != 0)); } - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); if (!needToPreventOverflow) { QCOMPARE(++atomic, nextValue); @@ -392,7 +392,7 @@ void tst_QAtomicIntegerXX::refDeref() QCOMPARE(atomic--, T(value)); QCOMPARE(atomic++, prevValue); } - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); } void tst_QAtomicIntegerXX::testAndSet() @@ -402,16 +402,16 @@ void tst_QAtomicIntegerXX::testAndSet() QAtomicInteger<T> atomic(value); QVERIFY(atomic.testAndSetRelaxed(value, newValue)); - QCOMPARE(atomic.load(), newValue); + QCOMPARE(atomic.loadRelaxed(), newValue); QVERIFY(!atomic.testAndSetRelaxed(value, newValue)); QVERIFY(atomic.testAndSetRelaxed(newValue, value)); - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); QVERIFY(atomic.testAndSetAcquire(value, newValue)); - QCOMPARE(atomic.load(), newValue); + QCOMPARE(atomic.loadRelaxed(), newValue); QVERIFY(!atomic.testAndSetAcquire(value, newValue)); QVERIFY(atomic.testAndSetAcquire(newValue, value)); - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); QVERIFY(atomic.testAndSetRelease(value, newValue)); QCOMPARE(atomic.loadAcquire(), newValue); @@ -434,18 +434,18 @@ void tst_QAtomicIntegerXX::testAndSet3() QAtomicInteger<T> atomic(value); QVERIFY(atomic.testAndSetRelaxed(value, newValue, oldValue)); - QCOMPARE(atomic.load(), newValue); + QCOMPARE(atomic.loadRelaxed(), newValue); QVERIFY(!atomic.testAndSetRelaxed(value, newValue, oldValue)); QCOMPARE(oldValue, newValue); QVERIFY(atomic.testAndSetRelaxed(newValue, value, oldValue)); - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); QVERIFY(atomic.testAndSetAcquire(value, newValue, oldValue)); - QCOMPARE(atomic.load(), newValue); + QCOMPARE(atomic.loadRelaxed(), newValue); QVERIFY(!atomic.testAndSetAcquire(value, newValue, oldValue)); QCOMPARE(oldValue, newValue); QVERIFY(atomic.testAndSetAcquire(newValue, value, oldValue)); - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); QVERIFY(atomic.testAndSetRelease(value, newValue, oldValue)); QCOMPARE(atomic.loadAcquire(), newValue); @@ -469,14 +469,14 @@ void tst_QAtomicIntegerXX::fetchAndStore() QAtomicInteger<T> atomic(value); QCOMPARE(atomic.fetchAndStoreRelaxed(newValue), T(value)); - QCOMPARE(atomic.load(), newValue); + QCOMPARE(atomic.loadRelaxed(), newValue); QCOMPARE(atomic.fetchAndStoreRelaxed(value), newValue); - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); QCOMPARE(atomic.fetchAndStoreAcquire(newValue), T(value)); - QCOMPARE(atomic.load(), newValue); + QCOMPARE(atomic.loadRelaxed(), newValue); QCOMPARE(atomic.fetchAndStoreAcquire(value), newValue); - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); QCOMPARE(atomic.fetchAndStoreRelease(newValue), T(value)); QCOMPARE(atomic.loadAcquire(), newValue); @@ -509,29 +509,29 @@ void tst_QAtomicIntegerXX::fetchAndAdd() if (!needToPreventOverflow) { QCOMPARE(atomic.fetchAndAddRelaxed(parcel1), T(value)); - QCOMPARE(atomic.load(), newValue1); + QCOMPARE(atomic.loadRelaxed(), newValue1); QCOMPARE(atomic.fetchAndAddRelaxed(parcel2), newValue1); } - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); if (!needToPreventUnderflow) { QCOMPARE(atomic.fetchAndAddRelaxed(parcel2), T(value)); - QCOMPARE(atomic.load(), newValue2); + QCOMPARE(atomic.loadRelaxed(), newValue2); QCOMPARE(atomic.fetchAndAddRelaxed(parcel1), newValue2); } - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); if (!needToPreventOverflow) { QCOMPARE(atomic.fetchAndAddAcquire(parcel1), T(value)); - QCOMPARE(atomic.load(), newValue1); + QCOMPARE(atomic.loadRelaxed(), newValue1); QCOMPARE(atomic.fetchAndAddAcquire(parcel2), newValue1); } - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); if (!needToPreventUnderflow) { QCOMPARE(atomic.fetchAndAddAcquire(parcel2), T(value)); - QCOMPARE(atomic.load(), newValue2); + QCOMPARE(atomic.loadRelaxed(), newValue2); QCOMPARE(atomic.fetchAndAddAcquire(parcel1), newValue2); } - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); if (!needToPreventOverflow) { QCOMPARE(atomic.fetchAndAddRelease(parcel1), T(value)); @@ -590,29 +590,29 @@ void tst_QAtomicIntegerXX::fetchAndSub() if (!needToPreventUnderflow) { QCOMPARE(atomic.fetchAndSubRelaxed(parcel1), T(value)); - QCOMPARE(atomic.load(), newValue1); + QCOMPARE(atomic.loadRelaxed(), newValue1); QCOMPARE(atomic.fetchAndSubRelaxed(parcel2), newValue1); } - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); if (!needToPreventOverflow) { QCOMPARE(atomic.fetchAndSubRelaxed(parcel2), T(value)); - QCOMPARE(atomic.load(), newValue2); + QCOMPARE(atomic.loadRelaxed(), newValue2); QCOMPARE(atomic.fetchAndSubRelaxed(parcel1), newValue2); } - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); if (!needToPreventUnderflow) { QCOMPARE(atomic.fetchAndSubAcquire(parcel1), T(value)); - QCOMPARE(atomic.load(), newValue1); + QCOMPARE(atomic.loadRelaxed(), newValue1); QCOMPARE(atomic.fetchAndSubAcquire(parcel2), newValue1); } - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); if (!needToPreventOverflow) { QCOMPARE(atomic.fetchAndSubAcquire(parcel2), T(value)); - QCOMPARE(atomic.load(), newValue2); + QCOMPARE(atomic.loadRelaxed(), newValue2); QCOMPARE(atomic.fetchAndSubAcquire(parcel1), newValue2); } - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); if (!needToPreventUnderflow) { QCOMPARE(atomic.fetchAndSubRelease(parcel1), T(value)); @@ -662,32 +662,32 @@ void tst_QAtomicIntegerXX::fetchAndOr() QCOMPARE(atomic.fetchAndOrRelaxed(zero), T(value)); QCOMPARE(atomic.fetchAndOrRelaxed(one), T(value)); - QCOMPARE(atomic.load(), T(value | 1)); + QCOMPARE(atomic.loadRelaxed(), T(value | 1)); QCOMPARE(atomic.fetchAndOrRelaxed(minusOne), T(value | 1)); - QCOMPARE(atomic.load(), minusOne); + QCOMPARE(atomic.loadRelaxed(), minusOne); - atomic.store(value); + atomic.storeRelaxed(value); QCOMPARE(atomic.fetchAndOrAcquire(zero), T(value)); QCOMPARE(atomic.fetchAndOrAcquire(one), T(value)); - QCOMPARE(atomic.load(), T(value | 1)); + QCOMPARE(atomic.loadRelaxed(), T(value | 1)); QCOMPARE(atomic.fetchAndOrAcquire(minusOne), T(value | 1)); - QCOMPARE(atomic.load(), minusOne); + QCOMPARE(atomic.loadRelaxed(), minusOne); - atomic.store(value); + atomic.storeRelaxed(value); QCOMPARE(atomic.fetchAndOrRelease(zero), T(value)); QCOMPARE(atomic.fetchAndOrRelease(one), T(value)); - QCOMPARE(atomic.load(), T(value | 1)); + QCOMPARE(atomic.loadRelaxed(), T(value | 1)); QCOMPARE(atomic.fetchAndOrRelease(minusOne), T(value | 1)); - QCOMPARE(atomic.load(), minusOne); + QCOMPARE(atomic.loadRelaxed(), minusOne); - atomic.store(value); + atomic.storeRelaxed(value); QCOMPARE(atomic.fetchAndOrOrdered(zero), T(value)); QCOMPARE(atomic.fetchAndOrOrdered(one), T(value)); - QCOMPARE(atomic.load(), T(value | 1)); + QCOMPARE(atomic.loadRelaxed(), T(value | 1)); QCOMPARE(atomic.fetchAndOrOrdered(minusOne), T(value | 1)); - QCOMPARE(atomic.load(), minusOne); + QCOMPARE(atomic.loadRelaxed(), minusOne); - atomic.store(value); + atomic.storeRelaxed(value); QCOMPARE(atomic |= zero, T(value)); QCOMPARE(atomic |= one, T(value | 1)); QCOMPARE(atomic |= minusOne, minusOne); @@ -703,37 +703,37 @@ void tst_QAtomicIntegerXX::fetchAndAnd() T minusOne = T(~0); QCOMPARE(atomic.fetchAndAndRelaxed(minusOne), T(value)); - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); QCOMPARE(atomic.fetchAndAndRelaxed(f), T(value)); - QCOMPARE(atomic.load(), T(value & 0xf)); + QCOMPARE(atomic.loadRelaxed(), T(value & 0xf)); QCOMPARE(atomic.fetchAndAndRelaxed(zero), T(value & 0xf)); - QCOMPARE(atomic.load(), zero); + QCOMPARE(atomic.loadRelaxed(), zero); - atomic.store(value); + atomic.storeRelaxed(value); QCOMPARE(atomic.fetchAndAndAcquire(minusOne), T(value)); - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); QCOMPARE(atomic.fetchAndAndAcquire(f), T(value)); - QCOMPARE(atomic.load(), T(value & 0xf)); + QCOMPARE(atomic.loadRelaxed(), T(value & 0xf)); QCOMPARE(atomic.fetchAndAndAcquire(zero), T(value & 0xf)); - QCOMPARE(atomic.load(), zero); + QCOMPARE(atomic.loadRelaxed(), zero); - atomic.store(value); + atomic.storeRelaxed(value); QCOMPARE(atomic.fetchAndAndRelease(minusOne), T(value)); - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); QCOMPARE(atomic.fetchAndAndRelease(f), T(value)); - QCOMPARE(atomic.load(), T(value & 0xf)); + QCOMPARE(atomic.loadRelaxed(), T(value & 0xf)); QCOMPARE(atomic.fetchAndAndRelease(zero), T(value & 0xf)); - QCOMPARE(atomic.load(), zero); + QCOMPARE(atomic.loadRelaxed(), zero); - atomic.store(value); + atomic.storeRelaxed(value); QCOMPARE(atomic.fetchAndAndOrdered(minusOne), T(value)); - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); QCOMPARE(atomic.fetchAndAndOrdered(f), T(value)); - QCOMPARE(atomic.load(), T(value & 0xf)); + QCOMPARE(atomic.loadRelaxed(), T(value & 0xf)); QCOMPARE(atomic.fetchAndAndOrdered(zero), T(value & 0xf)); - QCOMPARE(atomic.load(), zero); + QCOMPARE(atomic.loadRelaxed(), zero); - atomic.store(value); + atomic.storeRelaxed(value); QCOMPARE(atomic &= minusOne, T(value)); QCOMPARE(atomic &= f, T(value & 0xf)); QCOMPARE(atomic &= zero, zero); @@ -749,48 +749,48 @@ void tst_QAtomicIntegerXX::fetchAndXor() T minusOne = T(~0); QCOMPARE(atomic.fetchAndXorRelaxed(zero), T(value)); - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); QCOMPARE(atomic.fetchAndXorRelaxed(pattern), T(value)); - QCOMPARE(atomic.load(), T(value ^ pattern)); + QCOMPARE(atomic.loadRelaxed(), T(value ^ pattern)); QCOMPARE(atomic.fetchAndXorRelaxed(pattern), T(value ^ pattern)); - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); QCOMPARE(atomic.fetchAndXorRelaxed(minusOne), T(value)); - QCOMPARE(atomic.load(), T(~value)); + QCOMPARE(atomic.loadRelaxed(), T(~value)); QCOMPARE(atomic.fetchAndXorRelaxed(minusOne), T(~value)); - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); QCOMPARE(atomic.fetchAndXorAcquire(zero), T(value)); - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); QCOMPARE(atomic.fetchAndXorAcquire(pattern), T(value)); - QCOMPARE(atomic.load(), T(value ^ pattern)); + QCOMPARE(atomic.loadRelaxed(), T(value ^ pattern)); QCOMPARE(atomic.fetchAndXorAcquire(pattern), T(value ^ pattern)); - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); QCOMPARE(atomic.fetchAndXorAcquire(minusOne), T(value)); - QCOMPARE(atomic.load(), T(~value)); + QCOMPARE(atomic.loadRelaxed(), T(~value)); QCOMPARE(atomic.fetchAndXorAcquire(minusOne), T(~value)); - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); QCOMPARE(atomic.fetchAndXorRelease(zero), T(value)); - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); QCOMPARE(atomic.fetchAndXorRelease(pattern), T(value)); - QCOMPARE(atomic.load(), T(value ^ pattern)); + QCOMPARE(atomic.loadRelaxed(), T(value ^ pattern)); QCOMPARE(atomic.fetchAndXorRelease(pattern), T(value ^ pattern)); - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); QCOMPARE(atomic.fetchAndXorRelease(minusOne), T(value)); - QCOMPARE(atomic.load(), T(~value)); + QCOMPARE(atomic.loadRelaxed(), T(~value)); QCOMPARE(atomic.fetchAndXorRelease(minusOne), T(~value)); - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); QCOMPARE(atomic.fetchAndXorOrdered(zero), T(value)); - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); QCOMPARE(atomic.fetchAndXorOrdered(pattern), T(value)); - QCOMPARE(atomic.load(), T(value ^ pattern)); + QCOMPARE(atomic.loadRelaxed(), T(value ^ pattern)); QCOMPARE(atomic.fetchAndXorOrdered(pattern), T(value ^ pattern)); - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); QCOMPARE(atomic.fetchAndXorOrdered(minusOne), T(value)); - QCOMPARE(atomic.load(), T(~value)); + QCOMPARE(atomic.loadRelaxed(), T(~value)); QCOMPARE(atomic.fetchAndXorOrdered(minusOne), T(~value)); - QCOMPARE(atomic.load(), T(value)); + QCOMPARE(atomic.loadRelaxed(), T(value)); QCOMPARE(atomic ^= zero, T(value)); QCOMPARE(atomic ^= pattern, T(value ^ pattern)); diff --git a/tests/auto/corelib/thread/qatomicpointer/tst_qatomicpointer.cpp b/tests/auto/corelib/thread/qatomicpointer/tst_qatomicpointer.cpp index 0200473cae..a699cf6202 100644 --- a/tests/auto/corelib/thread/qatomicpointer/tst_qatomicpointer.cpp +++ b/tests/auto/corelib/thread/qatomicpointer/tst_qatomicpointer.cpp @@ -75,7 +75,7 @@ void tst_QAtomicPointer::warningFreeHelper() QBasicAtomicPointer<WFHC> p = Q_BASIC_ATOMIC_INITIALIZER(0); - p.load()->bar(); + p.loadRelaxed()->bar(); WFHC *expectedValue = 0; WFHC *newValue = 0; @@ -119,15 +119,15 @@ void tst_QAtomicPointer::constructor() { void *one = this; QAtomicPointer<void> atomic1 = one; - QCOMPARE(atomic1.load(), one); + QCOMPARE(atomic1.loadRelaxed(), one); void *two = &one; QAtomicPointer<void> atomic2 = two; - QCOMPARE(atomic2.load(), two); + QCOMPARE(atomic2.loadRelaxed(), two); void *three = &two; QAtomicPointer<void> atomic3 = three; - QCOMPARE(atomic3.load(), three); + QCOMPARE(atomic3.loadRelaxed(), three); } void tst_QAtomicPointer::copy_constructor() @@ -135,20 +135,20 @@ void tst_QAtomicPointer::copy_constructor() void *one = this; QAtomicPointer<void> atomic1 = one; QAtomicPointer<void> atomic1_copy = atomic1; - QCOMPARE(atomic1_copy.load(), one); - QCOMPARE(atomic1_copy.load(), atomic1.load()); + QCOMPARE(atomic1_copy.loadRelaxed(), one); + QCOMPARE(atomic1_copy.loadRelaxed(), atomic1.loadRelaxed()); void *two = &one; QAtomicPointer<void> atomic2 = two; QAtomicPointer<void> atomic2_copy = atomic2; - QCOMPARE(atomic2_copy.load(), two); - QCOMPARE(atomic2_copy.load(), atomic2.load()); + QCOMPARE(atomic2_copy.loadRelaxed(), two); + QCOMPARE(atomic2_copy.loadRelaxed(), atomic2.loadRelaxed()); void *three = &two; QAtomicPointer<void> atomic3 = three; QAtomicPointer<void> atomic3_copy = atomic3; - QCOMPARE(atomic3_copy.load(), three); - QCOMPARE(atomic3_copy.load(), atomic3.load()); + QCOMPARE(atomic3_copy.loadRelaxed(), three); + QCOMPARE(atomic3_copy.loadRelaxed(), atomic3.loadRelaxed()); } void tst_QAtomicPointer::assignment_operator() @@ -161,17 +161,17 @@ void tst_QAtomicPointer::assignment_operator() QAtomicPointer<void> atomic2 = two; QAtomicPointer<void> atomic3 = three; - QCOMPARE(atomic1.load(), one); - QCOMPARE(atomic2.load(), two); - QCOMPARE(atomic3.load(), three); + QCOMPARE(atomic1.loadRelaxed(), one); + QCOMPARE(atomic2.loadRelaxed(), two); + QCOMPARE(atomic3.loadRelaxed(), three); atomic1 = two; atomic2 = three; atomic3 = one; - QCOMPARE(atomic1.load(), two); - QCOMPARE(atomic2.load(), three); - QCOMPARE(atomic3.load(), one); + QCOMPARE(atomic1.loadRelaxed(), two); + QCOMPARE(atomic2.loadRelaxed(), three); + QCOMPARE(atomic3.loadRelaxed(), one); } void tst_QAtomicPointer::isTestAndSetNative() @@ -234,17 +234,17 @@ void tst_QAtomicPointer::testAndSet() QAtomicPointer<void> atomic2 = two; QAtomicPointer<void> atomic3 = three; - QCOMPARE(atomic1.load(), one); - QCOMPARE(atomic2.load(), two); - QCOMPARE(atomic3.load(), three); + QCOMPARE(atomic1.loadRelaxed(), one); + QCOMPARE(atomic2.loadRelaxed(), two); + QCOMPARE(atomic3.loadRelaxed(), three); QVERIFY(atomic1.testAndSetRelaxed(one, two)); QVERIFY(atomic2.testAndSetRelaxed(two, three)); QVERIFY(atomic3.testAndSetRelaxed(three, one)); - QCOMPARE(atomic1.load(), two); - QCOMPARE(atomic2.load(), three); - QCOMPARE(atomic3.load(), one); + QCOMPARE(atomic1.loadRelaxed(), two); + QCOMPARE(atomic2.loadRelaxed(), three); + QCOMPARE(atomic3.loadRelaxed(), one); } { @@ -252,17 +252,17 @@ void tst_QAtomicPointer::testAndSet() QAtomicPointer<void> atomic2 = two; QAtomicPointer<void> atomic3 = three; - QCOMPARE(atomic1.load(), one); - QCOMPARE(atomic2.load(), two); - QCOMPARE(atomic3.load(), three); + QCOMPARE(atomic1.loadRelaxed(), one); + QCOMPARE(atomic2.loadRelaxed(), two); + QCOMPARE(atomic3.loadRelaxed(), three); QVERIFY(atomic1.testAndSetAcquire(one, two)); QVERIFY(atomic2.testAndSetAcquire(two, three)); QVERIFY(atomic3.testAndSetAcquire(three, one)); - QCOMPARE(atomic1.load(), two); - QCOMPARE(atomic2.load(), three); - QCOMPARE(atomic3.load(), one); + QCOMPARE(atomic1.loadRelaxed(), two); + QCOMPARE(atomic2.loadRelaxed(), three); + QCOMPARE(atomic3.loadRelaxed(), one); } { @@ -270,17 +270,17 @@ void tst_QAtomicPointer::testAndSet() QAtomicPointer<void> atomic2 = two; QAtomicPointer<void> atomic3 = three; - QCOMPARE(atomic1.load(), one); - QCOMPARE(atomic2.load(), two); - QCOMPARE(atomic3.load(), three); + QCOMPARE(atomic1.loadRelaxed(), one); + QCOMPARE(atomic2.loadRelaxed(), two); + QCOMPARE(atomic3.loadRelaxed(), three); QVERIFY(atomic1.testAndSetRelease(one, two)); QVERIFY(atomic2.testAndSetRelease(two, three)); QVERIFY(atomic3.testAndSetRelease(three, one)); - QCOMPARE(atomic1.load(), two); - QCOMPARE(atomic2.load(), three); - QCOMPARE(atomic3.load(), one); + QCOMPARE(atomic1.loadRelaxed(), two); + QCOMPARE(atomic2.loadRelaxed(), three); + QCOMPARE(atomic3.loadRelaxed(), one); } { @@ -288,17 +288,17 @@ void tst_QAtomicPointer::testAndSet() QAtomicPointer<void> atomic2 = two; QAtomicPointer<void> atomic3 = three; - QCOMPARE(atomic1.load(), one); - QCOMPARE(atomic2.load(), two); - QCOMPARE(atomic3.load(), three); + QCOMPARE(atomic1.loadRelaxed(), one); + QCOMPARE(atomic2.loadRelaxed(), two); + QCOMPARE(atomic3.loadRelaxed(), three); QVERIFY(atomic1.testAndSetOrdered(one, two)); QVERIFY(atomic2.testAndSetOrdered(two, three)); QVERIFY(atomic3.testAndSetOrdered(three, one)); - QCOMPARE(atomic1.load(), two); - QCOMPARE(atomic2.load(), three); - QCOMPARE(atomic3.load(), one); + QCOMPARE(atomic1.loadRelaxed(), two); + QCOMPARE(atomic2.loadRelaxed(), three); + QCOMPARE(atomic3.loadRelaxed(), one); } } @@ -362,17 +362,17 @@ void tst_QAtomicPointer::fetchAndStore() QAtomicPointer<void> atomic2 = two; QAtomicPointer<void> atomic3 = three; - QCOMPARE(atomic1.load(), one); - QCOMPARE(atomic2.load(), two); - QCOMPARE(atomic3.load(), three); + QCOMPARE(atomic1.loadRelaxed(), one); + QCOMPARE(atomic2.loadRelaxed(), two); + QCOMPARE(atomic3.loadRelaxed(), three); QCOMPARE(atomic1.fetchAndStoreRelaxed(two), one); QCOMPARE(atomic2.fetchAndStoreRelaxed(three), two); QCOMPARE(atomic3.fetchAndStoreRelaxed(one), three); - QCOMPARE(atomic1.load(), two); - QCOMPARE(atomic2.load(), three); - QCOMPARE(atomic3.load(), one); + QCOMPARE(atomic1.loadRelaxed(), two); + QCOMPARE(atomic2.loadRelaxed(), three); + QCOMPARE(atomic3.loadRelaxed(), one); } { @@ -380,17 +380,17 @@ void tst_QAtomicPointer::fetchAndStore() QAtomicPointer<void> atomic2 = two; QAtomicPointer<void> atomic3 = three; - QCOMPARE(atomic1.load(), one); - QCOMPARE(atomic2.load(), two); - QCOMPARE(atomic3.load(), three); + QCOMPARE(atomic1.loadRelaxed(), one); + QCOMPARE(atomic2.loadRelaxed(), two); + QCOMPARE(atomic3.loadRelaxed(), three); QCOMPARE(atomic1.fetchAndStoreAcquire(two), one); QCOMPARE(atomic2.fetchAndStoreAcquire(three), two); QCOMPARE(atomic3.fetchAndStoreAcquire(one), three); - QCOMPARE(atomic1.load(), two); - QCOMPARE(atomic2.load(), three); - QCOMPARE(atomic3.load(), one); + QCOMPARE(atomic1.loadRelaxed(), two); + QCOMPARE(atomic2.loadRelaxed(), three); + QCOMPARE(atomic3.loadRelaxed(), one); } { @@ -398,17 +398,17 @@ void tst_QAtomicPointer::fetchAndStore() QAtomicPointer<void> atomic2 = two; QAtomicPointer<void> atomic3 = three; - QCOMPARE(atomic1.load(), one); - QCOMPARE(atomic2.load(), two); - QCOMPARE(atomic3.load(), three); + QCOMPARE(atomic1.loadRelaxed(), one); + QCOMPARE(atomic2.loadRelaxed(), two); + QCOMPARE(atomic3.loadRelaxed(), three); QCOMPARE(atomic1.fetchAndStoreRelease(two), one); QCOMPARE(atomic2.fetchAndStoreRelease(three), two); QCOMPARE(atomic3.fetchAndStoreRelease(one), three); - QCOMPARE(atomic1.load(), two); - QCOMPARE(atomic2.load(), three); - QCOMPARE(atomic3.load(), one); + QCOMPARE(atomic1.loadRelaxed(), two); + QCOMPARE(atomic2.loadRelaxed(), three); + QCOMPARE(atomic3.loadRelaxed(), one); } { @@ -416,17 +416,17 @@ void tst_QAtomicPointer::fetchAndStore() QAtomicPointer<void> atomic2 = two; QAtomicPointer<void> atomic3 = three; - QCOMPARE(atomic1.load(), one); - QCOMPARE(atomic2.load(), two); - QCOMPARE(atomic3.load(), three); + QCOMPARE(atomic1.loadRelaxed(), one); + QCOMPARE(atomic2.loadRelaxed(), two); + QCOMPARE(atomic3.loadRelaxed(), three); QCOMPARE(atomic1.fetchAndStoreOrdered(two), one); QCOMPARE(atomic2.fetchAndStoreOrdered(three), two); QCOMPARE(atomic3.fetchAndStoreOrdered(one), three); - QCOMPARE(atomic1.load(), two); - QCOMPARE(atomic2.load(), three); - QCOMPARE(atomic3.load(), one); + QCOMPARE(atomic1.loadRelaxed(), two); + QCOMPARE(atomic2.loadRelaxed(), three); + QCOMPARE(atomic3.loadRelaxed(), one); } } @@ -530,60 +530,60 @@ void tst_QAtomicPointer::fetchAndAdd() // cast to void* in order to avoid QCOMPARE to compare string content of the char* QCOMPARE(static_cast<void*>(pointer1.fetchAndAddRelaxed(valueToAdd)), static_cast<void*>(pc)); QCOMPARE(static_cast<void*>(pointer1.fetchAndAddRelaxed(-valueToAdd)), static_cast<void*>(pc + valueToAdd)); - QCOMPARE(static_cast<void*>(pointer1.load()), static_cast<void*>(pc)); + QCOMPARE(static_cast<void*>(pointer1.loadRelaxed()), static_cast<void*>(pc)); QAtomicPointer<short> pointer2 = ps; QCOMPARE(pointer2.fetchAndAddRelaxed(valueToAdd), ps); QCOMPARE(pointer2.fetchAndAddRelaxed(-valueToAdd), ps + valueToAdd); - QCOMPARE(pointer2.load(), ps); + QCOMPARE(pointer2.loadRelaxed(), ps); QAtomicPointer<int> pointer3 = pi; QCOMPARE(pointer3.fetchAndAddRelaxed(valueToAdd), pi); QCOMPARE(pointer3.fetchAndAddRelaxed(-valueToAdd), pi + valueToAdd); - QCOMPARE(pointer3.load(), pi); + QCOMPARE(pointer3.loadRelaxed(), pi); } { QAtomicPointer<char> pointer1 = pc; QCOMPARE(static_cast<void*>(pointer1.fetchAndAddAcquire(valueToAdd)), static_cast<void*>(pc)); QCOMPARE(static_cast<void*>(pointer1.fetchAndAddAcquire(-valueToAdd)), static_cast<void*>(pc + valueToAdd)); - QCOMPARE(static_cast<void*>(pointer1.load()), static_cast<void*>(pc)); + QCOMPARE(static_cast<void*>(pointer1.loadRelaxed()), static_cast<void*>(pc)); QAtomicPointer<short> pointer2 = ps; QCOMPARE(pointer2.fetchAndAddAcquire(valueToAdd), ps); QCOMPARE(pointer2.fetchAndAddAcquire(-valueToAdd), ps + valueToAdd); - QCOMPARE(pointer2.load(), ps); + QCOMPARE(pointer2.loadRelaxed(), ps); QAtomicPointer<int> pointer3 = pi; QCOMPARE(pointer3.fetchAndAddAcquire(valueToAdd), pi); QCOMPARE(pointer3.fetchAndAddAcquire(-valueToAdd), pi + valueToAdd); - QCOMPARE(pointer3.load(), pi); + QCOMPARE(pointer3.loadRelaxed(), pi); } { QAtomicPointer<char> pointer1 = pc; QCOMPARE(static_cast<void*>(pointer1.fetchAndAddRelease(valueToAdd)), static_cast<void*>(pc)); QCOMPARE(static_cast<void*>(pointer1.fetchAndAddRelease(-valueToAdd)), static_cast<void*>(pc + valueToAdd)); - QCOMPARE(static_cast<void*>(pointer1.load()), static_cast<void*>(pc)); + QCOMPARE(static_cast<void*>(pointer1.loadRelaxed()), static_cast<void*>(pc)); QAtomicPointer<short> pointer2 = ps; QCOMPARE(pointer2.fetchAndAddRelease(valueToAdd), ps); QCOMPARE(pointer2.fetchAndAddRelease(-valueToAdd), ps + valueToAdd); - QCOMPARE(pointer2.load(), ps); + QCOMPARE(pointer2.loadRelaxed(), ps); QAtomicPointer<int> pointer3 = pi; QCOMPARE(pointer3.fetchAndAddRelease(valueToAdd), pi); QCOMPARE(pointer3.fetchAndAddRelease(-valueToAdd), pi + valueToAdd); - QCOMPARE(pointer3.load(), pi); + QCOMPARE(pointer3.loadRelaxed(), pi); } { QAtomicPointer<char> pointer1 = pc; QCOMPARE(static_cast<void*>(pointer1.fetchAndAddOrdered(valueToAdd)), static_cast<void*>(pc)); QCOMPARE(static_cast<void*>(pointer1.fetchAndAddOrdered(-valueToAdd)), static_cast<void*>(pc + valueToAdd)); - QCOMPARE(static_cast<void*>(pointer1.load()), static_cast<void*>(pc)); + QCOMPARE(static_cast<void*>(pointer1.loadRelaxed()), static_cast<void*>(pc)); QAtomicPointer<short> pointer2 = ps; QCOMPARE(pointer2.fetchAndAddOrdered(valueToAdd), ps); QCOMPARE(pointer2.fetchAndAddOrdered(-valueToAdd), ps + valueToAdd); - QCOMPARE(pointer2.load(), ps); + QCOMPARE(pointer2.loadRelaxed(), ps); QAtomicPointer<int> pointer3 = pi; QCOMPARE(pointer3.fetchAndAddOrdered(valueToAdd), pi); QCOMPARE(pointer3.fetchAndAddOrdered(-valueToAdd), pi + valueToAdd); - QCOMPARE(pointer3.load(), pi); + QCOMPARE(pointer3.loadRelaxed(), pi); } } @@ -598,34 +598,34 @@ template <typename T> void constAndVolatile_helper() QAtomicPointer<T> atomic2 = two; QAtomicPointer<T> atomic3 = three; - QVERIFY(atomic1.load() == one); - QVERIFY(atomic2.load() == two); - QVERIFY(atomic3.load() == three); + QVERIFY(atomic1.loadRelaxed() == one); + QVERIFY(atomic2.loadRelaxed() == two); + QVERIFY(atomic3.loadRelaxed() == three); QVERIFY(atomic1.fetchAndStoreRelaxed(two) == one); QVERIFY(atomic2.fetchAndStoreRelaxed(three) == two); QVERIFY(atomic3.fetchAndStoreRelaxed(one) == three); - QVERIFY(atomic1.load() == two); - QVERIFY(atomic2.load() == three); - QVERIFY(atomic3.load() == one); + QVERIFY(atomic1.loadRelaxed() == two); + QVERIFY(atomic2.loadRelaxed() == three); + QVERIFY(atomic3.loadRelaxed() == one); } { QAtomicPointer<T> atomic1 = one; QAtomicPointer<T> atomic2 = two; QAtomicPointer<T> atomic3 = three; - QVERIFY(atomic1.load() == one); - QVERIFY(atomic2.load() == two); - QVERIFY(atomic3.load() == three); + QVERIFY(atomic1.loadRelaxed() == one); + QVERIFY(atomic2.loadRelaxed() == two); + QVERIFY(atomic3.loadRelaxed() == three); QVERIFY(atomic1.testAndSetRelaxed(one, two)); QVERIFY(atomic2.testAndSetRelaxed(two, three)); QVERIFY(atomic3.testAndSetRelaxed(three, one)); - QVERIFY(atomic1.load() == two); - QVERIFY(atomic2.load() == three); - QVERIFY(atomic3.load() == one); + QVERIFY(atomic1.loadRelaxed() == two); + QVERIFY(atomic2.loadRelaxed() == three); + QVERIFY(atomic3.loadRelaxed() == one); } } diff --git a/tests/auto/corelib/thread/qfuture/qfuture.pro b/tests/auto/corelib/thread/qfuture/qfuture.pro index b1667760d6..1f21130af7 100644 --- a/tests/auto/corelib/thread/qfuture/qfuture.pro +++ b/tests/auto/corelib/thread/qfuture/qfuture.pro @@ -3,3 +3,4 @@ TARGET = tst_qfuture QT = core core-private testlib SOURCES = tst_qfuture.cpp DEFINES += QT_STRICT_ITERATORS +DEFINES -= QT_NO_JAVA_STYLE_ITERATORS diff --git a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp index b8c82c2ea0..a42454124e 100644 --- a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp +++ b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp @@ -49,6 +49,24 @@ struct ResultStoreInt : QtPrivate::ResultStoreBase ~ResultStoreInt() { clear<int>(); } }; +class LambdaThread : public QThread +{ +public: + LambdaThread(std::function<void ()> fn) + :m_fn(fn) + { + + } + + void run() override + { + m_fn(); + } + +private: + std::function<void ()> m_fn; +}; + class tst_QFuture: public QObject { Q_OBJECT @@ -67,6 +85,7 @@ private slots: void resultsAsList(); void implicitConversions(); void iterators(); + void iteratorsThread(); void pause(); void throttling(); void voidConversions(); @@ -1144,6 +1163,54 @@ void tst_QFuture::iterators() } } } +void tst_QFuture::iteratorsThread() +{ + const int expectedResultCount = 10; + const int delay = 10; + QFutureInterface<int> futureInterface; + + // Create result producer thread. The results are + // produced with delays in order to make the consumer + // wait. + QSemaphore sem; + LambdaThread thread = {[=, &futureInterface, &sem](){ + for (int i = 1; i <= expectedResultCount; i += 2) { + int result = i; + futureInterface.reportResult(&result); + result = i + 1; + futureInterface.reportResult(&result); + } + + sem.acquire(2); + futureInterface.reportFinished(); + }}; + + futureInterface.reportStarted(); + QFuture<int> future = futureInterface.future(); + + // Iterate over results while the thread is producing them. + thread.start(); + int resultCount = 0; + int resultSum = 0; + for (int result : future) { + sem.release(); + ++resultCount; + resultSum += result; + } + thread.wait(); + + QCOMPARE(resultCount, expectedResultCount); + QCOMPARE(resultSum, expectedResultCount * (expectedResultCount + 1) / 2); + + // Reverse iterate + resultSum = 0; + QFutureIterator<int> it(future); + it.toBack(); + while (it.hasPrevious()) + resultSum += it.previous(); + + QCOMPARE(resultSum, expectedResultCount * (expectedResultCount + 1) / 2); +} class SignalSlotObject : public QObject { diff --git a/tests/auto/corelib/thread/qfuturewatcher/tst_qfuturewatcher.cpp b/tests/auto/corelib/thread/qfuturewatcher/tst_qfuturewatcher.cpp index b2ef516b4e..a322a1c11d 100644 --- a/tests/auto/corelib/thread/qfuturewatcher/tst_qfuturewatcher.cpp +++ b/tests/auto/corelib/thread/qfuturewatcher/tst_qfuturewatcher.cpp @@ -27,6 +27,7 @@ ****************************************************************************/ #include <QCoreApplication> #include <QDebug> +#include <QElapsedTimer> #include <QtTest/QtTest> #include <QtConcurrent> @@ -878,7 +879,7 @@ void tst_QFutureWatcher::incrementalFilterResults() void tst_QFutureWatcher::qfutureSynchronizer() { int taskCount = 1000; - QTime t; + QElapsedTimer t; t.start(); { diff --git a/tests/auto/corelib/thread/qmutex/tst_qmutex.cpp b/tests/auto/corelib/thread/qmutex/tst_qmutex.cpp index 7fb9a861d7..749aa45916 100644 --- a/tests/auto/corelib/thread/qmutex/tst_qmutex.cpp +++ b/tests/auto/corelib/thread/qmutex/tst_qmutex.cpp @@ -69,7 +69,8 @@ private slots: static const int iterations = 100; QAtomicInt lockCount(0); -QMutex normalMutex, recursiveMutex(QMutex::Recursive); +QMutex normalMutex; +QRecursiveMutex recursiveMutex; QSemaphore testsTurn; QSemaphore threadsTurn; @@ -993,9 +994,9 @@ public: QMutex mutex; QWaitCondition cond; - QMutex &test_mutex; + QRecursiveMutex &test_mutex; - inline rmutex_Thread(QMutex &m) : test_mutex(m) { } + inline rmutex_Thread(QRecursiveMutex &m) : test_mutex(m) { } void run() { @@ -1024,7 +1025,7 @@ void tst_QMutex::lock_unlock_locked_tryLock() QMutex mutex; mutex_Thread thread(mutex); - QMutex rmutex(QMutex::Recursive); + QRecursiveMutex rmutex; rmutex_Thread rthread(rmutex); for (int i = 0; i < iterations; ++i) { @@ -1132,7 +1133,7 @@ void tst_QMutex::stressTest() for (int i = 1; i < threadCount; ++i) QVERIFY(threads[i].wait(10000)); QCOMPARE(StressTestThread::errorCount, 0); - qDebug("locked %d times", int(StressTestThread::lockCount.load())); + qDebug("locked %d times", int(StressTestThread::lockCount.loadRelaxed())); } class TryLockRaceThread : public QThread @@ -1286,28 +1287,28 @@ public: quint64 i = 0; while (t.elapsed() < one_minute) { i++; - uint nb = (i * 9 + lockCount.load() * 13) % threadCount; + uint nb = (i * 9 + lockCount.loadRelaxed() * 13) % threadCount; QMutexLocker locker(&mutex[nb]); - if (sentinel[nb].load()) errorCount.ref(); + if (sentinel[nb].loadRelaxed()) errorCount.ref(); if (sentinel[nb].fetchAndAddRelaxed(5)) errorCount.ref(); if (!sentinel[nb].testAndSetRelaxed(5, 0)) errorCount.ref(); - if (sentinel[nb].load()) errorCount.ref(); + if (sentinel[nb].loadRelaxed()) errorCount.ref(); lockCount.ref(); - nb = (nb * 17 + i * 5 + lockCount.load() * 3) % threadCount; + nb = (nb * 17 + i * 5 + lockCount.loadRelaxed() * 3) % threadCount; if (mutex[nb].tryLock()) { - if (sentinel[nb].load()) errorCount.ref(); + if (sentinel[nb].loadRelaxed()) errorCount.ref(); if (sentinel[nb].fetchAndAddRelaxed(16)) errorCount.ref(); if (!sentinel[nb].testAndSetRelaxed(16, 0)) errorCount.ref(); - if (sentinel[nb].load()) errorCount.ref(); + if (sentinel[nb].loadRelaxed()) errorCount.ref(); lockCount.ref(); mutex[nb].unlock(); } - nb = (nb * 15 + i * 47 + lockCount.load() * 31) % threadCount; + nb = (nb * 15 + i * 47 + lockCount.loadRelaxed() * 31) % threadCount; if (mutex[nb].tryLock(2)) { - if (sentinel[nb].load()) errorCount.ref(); + if (sentinel[nb].loadRelaxed()) errorCount.ref(); if (sentinel[nb].fetchAndAddRelaxed(53)) errorCount.ref(); if (!sentinel[nb].testAndSetRelaxed(53, 0)) errorCount.ref(); - if (sentinel[nb].load()) errorCount.ref(); + if (sentinel[nb].loadRelaxed()) errorCount.ref(); lockCount.ref(); mutex[nb].unlock(); } @@ -1327,8 +1328,8 @@ void tst_QMutex::moreStress() QVERIFY(threads[0].wait(one_minute + 10000)); for (int i = 1; i < threadCount; ++i) QVERIFY(threads[i].wait(10000)); - qDebug("locked %d times", MoreStressTestThread::lockCount.load()); - QCOMPARE(MoreStressTestThread::errorCount.load(), 0); + qDebug("locked %d times", MoreStressTestThread::lockCount.loadRelaxed()); + QCOMPARE(MoreStressTestThread::errorCount.loadRelaxed(), 0); } diff --git a/tests/auto/corelib/thread/qmutexlocker/tst_qmutexlocker.cpp b/tests/auto/corelib/thread/qmutexlocker/tst_qmutexlocker.cpp index 67db5d1458..c83e186ca7 100644 --- a/tests/auto/corelib/thread/qmutexlocker/tst_qmutexlocker.cpp +++ b/tests/auto/corelib/thread/qmutexlocker/tst_qmutexlocker.cpp @@ -36,7 +36,7 @@ class tst_QMutexLockerThread : public QThread { public: - QMutex mutex; + QRecursiveMutex mutex; QSemaphore semaphore, testSemaphore; void waitForTest() @@ -45,10 +45,6 @@ public: testSemaphore.acquire(); } - tst_QMutexLockerThread() - : mutex(QMutex::Recursive) - { - } }; class tst_QMutexLocker : public QObject diff --git a/tests/auto/corelib/thread/qreadwritelock/tst_qreadwritelock.cpp b/tests/auto/corelib/thread/qreadwritelock/tst_qreadwritelock.cpp index 8e97229752..47bae585a1 100644 --- a/tests/auto/corelib/thread/qreadwritelock/tst_qreadwritelock.cpp +++ b/tests/auto/corelib/thread/qreadwritelock/tst_qreadwritelock.cpp @@ -29,6 +29,7 @@ #include <QtTest/QtTest> #include <qcoreapplication.h> #include <qreadwritelock.h> +#include <qelapsedtimer.h> #include <qmutex.h> #include <qthread.h> #include <qwaitcondition.h> @@ -237,7 +238,7 @@ void tst_QReadWriteLock::tryReadLock() testsTurn.release(); threadsTurn.acquire(); - QTime timer; + QElapsedTimer timer; timer.start(); QVERIFY(!readWriteLock.tryLockForRead(1000)); QVERIFY(timer.elapsed() >= 1000); @@ -457,7 +458,7 @@ public: void run() { testRwlock.lockForWrite(); - while(release.load()==false) { + while (release.loadRelaxed() == false) { RWTESTSLEEP } testRwlock.unlock(); @@ -477,7 +478,7 @@ public: void run() { testRwlock.lockForRead(); - while(release.load()==false) { + while (release.loadRelaxed() == false) { RWTESTSLEEP } testRwlock.unlock(); @@ -500,7 +501,7 @@ public: int holdTime; int waitTime; bool print; - QTime t; + QElapsedTimer t; inline ReadLockLoopThread(QReadWriteLock &l, int runTime, int holdTime=0, int waitTime=0, bool print=false) :testRwlock(l) ,runTime(runTime) @@ -536,7 +537,7 @@ public: int holdTime; int waitTime; bool print; - QTime t; + QElapsedTimer t; inline WriteLockLoopThread(QReadWriteLock &l, int runTime, int holdTime=0, int waitTime=0, bool print=false) :testRwlock(l) ,runTime(runTime) @@ -574,7 +575,7 @@ public: int runTime; int waitTime; int maxval; - QTime t; + QElapsedTimer t; inline WriteLockCountThread(QReadWriteLock &l, int runTime, int waitTime, int maxval) :testRwlock(l) ,runTime(runTime) @@ -615,7 +616,7 @@ public: QReadWriteLock &testRwlock; int runTime; int waitTime; - QTime t; + QElapsedTimer t; inline ReadLockCountThread(QReadWriteLock &l, int runTime, int waitTime) :testRwlock(l) ,runTime(runTime) @@ -676,7 +677,7 @@ void tst_QReadWriteLock::multipleReadersBlockRelease() { QReadWriteLock testLock; - release.store(false); + release.storeRelaxed(false); threadDone=false; ReadLockReleasableThread rlt1(testLock); ReadLockReleasableThread rlt2(testLock); @@ -686,7 +687,7 @@ void tst_QReadWriteLock::multipleReadersBlockRelease() WriteLockThread wlt(testLock); wlt.start(); sleep(1); - release.store(true); + release.storeRelaxed(true); wlt.wait(); rlt1.wait(); rlt2.wait(); @@ -873,7 +874,7 @@ void tst_QReadWriteLock::deleteOnUnlock() DeleteOnUnlockThread thread2(&lock, &startup, &waitMutex); - QTime t; + QElapsedTimer t; t.start(); while(t.elapsed() < 4000) { lock = new QReadWriteLock(); @@ -899,7 +900,7 @@ void tst_QReadWriteLock::uncontendedLocks() uint count=0; int millisecs=1000; { - QTime t; + QElapsedTimer t; t.start(); while(t.elapsed() <millisecs) { @@ -908,7 +909,7 @@ void tst_QReadWriteLock::uncontendedLocks() } { QReadWriteLock rwlock; - QTime t; + QElapsedTimer t; t.start(); while(t.elapsed() <millisecs) { @@ -919,7 +920,7 @@ void tst_QReadWriteLock::uncontendedLocks() } { QReadWriteLock rwlock; - QTime t; + QElapsedTimer t; t.start(); while(t.elapsed() <millisecs) { diff --git a/tests/auto/corelib/thread/qsemaphore/BLACKLIST b/tests/auto/corelib/thread/qsemaphore/BLACKLIST index 0786f50417..d7af5c420b 100644 --- a/tests/auto/corelib/thread/qsemaphore/BLACKLIST +++ b/tests/auto/corelib/thread/qsemaphore/BLACKLIST @@ -1,3 +1,5 @@ +[tryAcquireWithTimeout] +osx [tryAcquireWithTimeout:0.2s] windows osx-10.12 diff --git a/tests/auto/corelib/thread/qthread/BLACKLIST b/tests/auto/corelib/thread/qthread/BLACKLIST index d75249454f..c683154da1 100644 --- a/tests/auto/corelib/thread/qthread/BLACKLIST +++ b/tests/auto/corelib/thread/qthread/BLACKLIST @@ -1,2 +1,5 @@ [wait3_slowDestructor] -windows +windows-10 +[sleep] +windows-7sp1 + diff --git a/tests/auto/corelib/thread/qthread/tst_qthread.cpp b/tests/auto/corelib/thread/qthread/tst_qthread.cpp index d73dcc1b6d..7be2f48758 100644 --- a/tests/auto/corelib/thread/qthread/tst_qthread.cpp +++ b/tests/auto/corelib/thread/qthread/tst_qthread.cpp @@ -29,7 +29,7 @@ #include <QtTest/QtTest> #include <qcoreapplication.h> -#include <qdatetime.h> +#include <qelapsedtimer.h> #include <qmutex.h> #include <qthread.h> #include <qtimer.h> @@ -110,6 +110,12 @@ private slots: enum { one_minute = 60 * 1000, five_minutes = 5 * one_minute }; +template <class Int> +static QString msgElapsed(Int elapsed) +{ + return QString::fromLatin1("elapsed: %1").arg(elapsed); +} + class SignalRecorder : public QObject { Q_OBJECT @@ -121,7 +127,7 @@ public: { } bool wasActivated() - { return activationCount.load() > 0; } + { return activationCount.loadRelaxed() > 0; } public slots: void slot(); @@ -244,8 +250,8 @@ public: QMutexLocker locker(&mutex); elapsed = 0; - QTime time; - time.start(); + QElapsedTimer timer; + timer.start(); switch (sleepType) { case Second: sleep(interval); @@ -257,7 +263,7 @@ public: usleep(interval); break; } - elapsed = time.elapsed(); + elapsed = timer.elapsed(); cond.wakeOne(); } @@ -591,7 +597,7 @@ void tst_QThread::sleep() thread.interval = 2; thread.start(); QVERIFY(thread.wait(five_minutes)); - QVERIFY(thread.elapsed >= 2000); + QVERIFY2(thread.elapsed >= 2000, qPrintable(msgElapsed(thread.elapsed))); } void tst_QThread::msleep() @@ -601,11 +607,10 @@ void tst_QThread::msleep() thread.interval = 120; thread.start(); QVERIFY(thread.wait(five_minutes)); -#if defined (Q_OS_WIN) - // Since the resolution of QTime is so coarse... - QVERIFY(thread.elapsed >= 100); +#if defined (Q_OS_WIN) // May no longer be needed + QVERIFY2(thread.elapsed >= 100, qPrintable(msgElapsed(thread.elapsed))); #else - QVERIFY(thread.elapsed >= 120); + QVERIFY2(thread.elapsed >= 120, qPrintable(msgElapsed(thread.elapsed))); #endif } @@ -616,11 +621,10 @@ void tst_QThread::usleep() thread.interval = 120000; thread.start(); QVERIFY(thread.wait(five_minutes)); -#if defined (Q_OS_WIN) - // Since the resolution of QTime is so coarse... - QVERIFY(thread.elapsed >= 100); +#if defined (Q_OS_WIN) // May no longer be needed + QVERIFY2(thread.elapsed >= 100, qPrintable(msgElapsed(thread.elapsed))); #else - QVERIFY(thread.elapsed >= 120); + QVERIFY2(thread.elapsed >= 120, qPrintable(msgElapsed(thread.elapsed))); #endif } @@ -902,7 +906,7 @@ void tst_QThread::adoptMultipleThreads() QTestEventLoop::instance().enterLoop(5); QVERIFY(!QTestEventLoop::instance().timeout()); - QCOMPARE(recorder.activationCount.load(), numThreads); + QCOMPARE(recorder.activationCount.loadRelaxed(), numThreads); } void tst_QThread::adoptMultipleThreadsOverlap() @@ -939,7 +943,7 @@ void tst_QThread::adoptMultipleThreadsOverlap() QTestEventLoop::instance().enterLoop(5); QVERIFY(!QTestEventLoop::instance().timeout()); - QCOMPARE(recorder.activationCount.load(), numThreads); + QCOMPARE(recorder.activationCount.loadRelaxed(), numThreads); } // Disconnects on WinCE @@ -948,9 +952,9 @@ void tst_QThread::stressTest() if (EmulationDetector::isRunningArmOnX86()) QSKIP("Qemu uses too much memory for each thread. Test would run out of memory."); - QTime t; - t.start(); - while (t.elapsed() < one_minute) { + QElapsedTimer timer; + timer.start(); + while (timer.elapsed() < one_minute) { Current_Thread t; t.start(); t.wait(one_minute); @@ -1067,13 +1071,15 @@ void tst_QThread::wait2() timer.start(); QVERIFY(!thread.wait(Waiting_Thread::WaitTime)); qint64 elapsed = timer.elapsed(); // On Windows, we sometimes get (WaitTime - 9). - QVERIFY2(elapsed >= Waiting_Thread::WaitTime - 10, qPrintable(QString::fromLatin1("elapsed: %1").arg(elapsed))); + QVERIFY2(elapsed >= Waiting_Thread::WaitTime - 10, + qPrintable(msgElapsed(elapsed))); timer.start(); thread.cond1.wakeOne(); QVERIFY(thread.wait(/*Waiting_Thread::WaitTime * 1.4*/)); elapsed = timer.elapsed(); - QVERIFY2(elapsed - Waiting_Thread::WaitTime >= -1, qPrintable(QString::fromLatin1("elapsed: %1").arg(elapsed))); + QVERIFY2(elapsed - Waiting_Thread::WaitTime >= -1, + qPrintable(msgElapsed(elapsed))); } @@ -1210,7 +1216,7 @@ class DummyEventDispatcher : public QAbstractEventDispatcher { public: DummyEventDispatcher() : QAbstractEventDispatcher() {} bool processEvents(QEventLoop::ProcessEventsFlags) { - visited.store(true); + visited.storeRelaxed(true); emit awake(); QCoreApplication::sendPostedEvents(); return false; @@ -1272,7 +1278,7 @@ void tst_QThread::customEventDispatcher() QMetaObject::invokeMethod(&obj, "visit", Qt::QueuedConnection); loop.exec(); // test that the ED has really been used - QVERIFY(ed->visited.load()); + QVERIFY(ed->visited.loadRelaxed()); QPointer<DummyEventDispatcher> weak_ed(ed); QVERIFY(!weak_ed.isNull()); @@ -1330,6 +1336,8 @@ void tst_QThread::quitLock() QCOMPARE(job->thread(), &thread); loop.exec(); QVERIFY(exitThreadCalled); + + delete job; } void tst_QThread::create() diff --git a/tests/auto/corelib/thread/qthreadonce/qthreadonce.cpp b/tests/auto/corelib/thread/qthreadonce/qthreadonce.cpp index d27884197a..3826fa148e 100644 --- a/tests/auto/corelib/thread/qthreadonce/qthreadonce.cpp +++ b/tests/auto/corelib/thread/qthreadonce/qthreadonce.cpp @@ -32,7 +32,7 @@ #include "qmutex.h" -Q_GLOBAL_STATIC_WITH_ARGS(QMutex, onceInitializationMutex, (QMutex::Recursive)) +Q_GLOBAL_STATIC(QRecursiveMutex, onceInitializationMutex) enum QOnceExtra { MustRunCode = 0x01, diff --git a/tests/auto/corelib/thread/qthreadonce/tst_qthreadonce.cpp b/tests/auto/corelib/thread/qthreadonce/tst_qthreadonce.cpp index a9af182ed8..710288af9e 100644 --- a/tests/auto/corelib/thread/qthreadonce/tst_qthreadonce.cpp +++ b/tests/auto/corelib/thread/qthreadonce/tst_qthreadonce.cpp @@ -56,7 +56,7 @@ class SingletonObject: public QObject Q_OBJECT public: static int runCount; - SingletonObject() { val.store(42); ++runCount; } + SingletonObject() { val.storeRelaxed(42); ++runCount; } ~SingletonObject() { } QBasicAtomicInt val; @@ -112,7 +112,7 @@ void tst_QThreadOnce::sameThread() QCOMPARE(controlVariable, 1); static QSingleton<SingletonObject> s; - QTEST((int)s->val.load(), "expectedValue"); + QTEST((int)s->val.loadRelaxed(), "expectedValue"); s->val.ref(); QCOMPARE(SingletonObject::runCount, 1); @@ -134,7 +134,7 @@ void tst_QThreadOnce::multipleThreads() QCOMPARE(controlVariable, 0); // nothing must have set them yet SingletonObject::runCount = 0; - IncrementThread::runCount.store(0); + IncrementThread::runCount.storeRelaxed(0); // wait for all of them to be ready sem2.acquire(NumberOfThreads); @@ -145,7 +145,7 @@ void tst_QThreadOnce::multipleThreads() delete parent; QCOMPARE(controlVariable, 1); - QCOMPARE((int)IncrementThread::runCount.load(), NumberOfThreads); + QCOMPARE((int)IncrementThread::runCount.loadRelaxed(), NumberOfThreads); QCOMPARE(SingletonObject::runCount, 1); } diff --git a/tests/auto/corelib/thread/qthreadpool/BLACKLIST b/tests/auto/corelib/thread/qthreadpool/BLACKLIST index fc49731687..b8c1f3bf3f 100644 --- a/tests/auto/corelib/thread/qthreadpool/BLACKLIST +++ b/tests/auto/corelib/thread/qthreadpool/BLACKLIST @@ -1,3 +1,4 @@ [expiryTimeoutRace] -osx -linux +opensuse-leap +ubuntu +rhel diff --git a/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp b/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp index 838431cd5a..60e8d8cba2 100644 --- a/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp +++ b/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp @@ -27,7 +27,7 @@ ** ****************************************************************************/ #include <QtTest/QtTest> -#include <qdatetime.h> +#include <qelapsedtimer.h> #include <qthreadpool.h> #include <qstring.h> #include <qmutex.h> @@ -92,7 +92,9 @@ private slots: void priorityStart(); void waitForDone(); void clear(); +#if QT_DEPRECATED_SINCE(5, 9) void cancel(); +#endif void tryTake(); void waitForDoneTimeout(); void destroyingWaitsForTasksToFinish(); @@ -220,16 +222,16 @@ class TestTask : public QRunnable public: void run() { - ran.store(true); + ran.storeRelaxed(true); } }; void tst_QThreadPool::runTask() { QThreadPool manager; - ran.store(false); + ran.storeRelaxed(false); manager.start(new TestTask()); - QTRY_VERIFY(ran.load()); + QTRY_VERIFY(ran.loadRelaxed()); } /* @@ -237,9 +239,9 @@ void tst_QThreadPool::runTask() */ void tst_QThreadPool::singleton() { - ran.store(false); + ran.storeRelaxed(false); QThreadPool::globalInstance()->start(new TestTask()); - QTRY_VERIFY(ran.load()); + QTRY_VERIFY(ran.loadRelaxed()); } QAtomicInt *value = 0; @@ -344,7 +346,7 @@ void tst_QThreadPool::expiryTimeout() // run the task threadPool.start(&task); QVERIFY(task.semaphore.tryAcquire(1, 10000)); - QCOMPARE(task.runCount.load(), 1); + QCOMPARE(task.runCount.loadRelaxed(), 1); QVERIFY(!task.thread->wait(100)); // thread should expire QThread *firstThread = task.thread; @@ -353,7 +355,7 @@ void tst_QThreadPool::expiryTimeout() // run task again, thread should be restarted threadPool.start(&task); QVERIFY(task.semaphore.tryAcquire(1, 10000)); - QCOMPARE(task.runCount.load(), 2); + QCOMPARE(task.runCount.loadRelaxed(), 2); QVERIFY(!task.thread->wait(100)); // thread should expire again QVERIFY(task.thread->wait(10000)); @@ -382,7 +384,7 @@ void tst_QThreadPool::expiryTimeoutRace() // QTBUG-3786 QThread::msleep(50); // exactly the same as the expiry timeout } QVERIFY(task.semaphore.tryAcquire(numTasks, 10000)); - QCOMPARE(task.runCount.load(), numTasks); + QCOMPARE(task.runCount.loadRelaxed(), numTasks); QVERIFY(threadPool.waitForDone(2000)); } @@ -685,7 +687,7 @@ void tst_QThreadPool::reserveAndStart() // QTBUG-21051 QCOMPARE(threadpool->activeThreadCount(), 2); task->waitForStarted.acquire(); task->waitBeforeDone.release(); - QTRY_COMPARE(task->count.load(), 1); + QTRY_COMPARE(task->count.loadRelaxed(), 1); QTRY_COMPARE(threadpool->activeThreadCount(), 1); // now the thread is waiting, but tryStart() will fail since activeThreadCount() >= maxThreadCount() @@ -698,7 +700,7 @@ void tst_QThreadPool::reserveAndStart() // QTBUG-21051 QTRY_COMPARE(threadpool->activeThreadCount(), 2); task->waitForStarted.acquire(); task->waitBeforeDone.release(); - QTRY_COMPARE(task->count.load(), 2); + QTRY_COMPARE(task->count.loadRelaxed(), 2); QTRY_COMPARE(threadpool->activeThreadCount(), 1); threadpool->releaseThread(); @@ -721,14 +723,14 @@ class CountingRunnable : public QRunnable void tst_QThreadPool::start() { const int runs = 1000; - count.store(0); + count.storeRelaxed(0); { QThreadPool threadPool; for (int i = 0; i< runs; ++i) { threadPool.start(new CountingRunnable()); } } - QCOMPARE(count.load(), runs); + QCOMPARE(count.loadRelaxed(), runs); } void tst_QThreadPool::tryStart() @@ -747,7 +749,7 @@ void tst_QThreadPool::tryStart() } }; - count.store(0); + count.storeRelaxed(0); WaitingTask task; QThreadPool threadPool; @@ -757,7 +759,7 @@ void tst_QThreadPool::tryStart() QVERIFY(!threadPool.tryStart(&task)); task.semaphore.release(threadPool.maxThreadCount()); threadPool.waitForDone(); - QCOMPARE(count.load(), threadPool.maxThreadCount()); + QCOMPARE(count.loadRelaxed(), threadPool.maxThreadCount()); } QMutex mutex; @@ -775,7 +777,7 @@ void tst_QThreadPool::tryStartPeakThreadCount() { QMutexLocker lock(&mutex); activeThreads.ref(); - peakActiveThreads.store(qMax(peakActiveThreads.load(), activeThreads.load())); + peakActiveThreads.storeRelaxed(qMax(peakActiveThreads.loadRelaxed(), activeThreads.loadRelaxed())); } QTest::qWait(100); @@ -793,13 +795,13 @@ void tst_QThreadPool::tryStartPeakThreadCount() if (threadPool.tryStart(&task) == false) QTest::qWait(10); } - QCOMPARE(peakActiveThreads.load(), QThread::idealThreadCount()); + QCOMPARE(peakActiveThreads.loadRelaxed(), QThread::idealThreadCount()); for (int i = 0; i < 20; ++i) { if (threadPool.tryStart(&task) == false) QTest::qWait(10); } - QCOMPARE(peakActiveThreads.load(), QThread::idealThreadCount()); + QCOMPARE(peakActiveThreads.loadRelaxed(), QThread::idealThreadCount()); } void tst_QThreadPool::tryStartCount() @@ -877,27 +879,27 @@ void tst_QThreadPool::priorityStart() sem.release(); QVERIFY(threadPool.waitForDone()); - QCOMPARE(firstStarted.load(), expected); + QCOMPARE(firstStarted.loadRelaxed(), expected); } void tst_QThreadPool::waitForDone() { - QTime total, pass; + QElapsedTimer total, pass; total.start(); QThreadPool threadPool; while (total.elapsed() < 10000) { int runs; - count.store(runs = 0); + count.storeRelaxed(runs = 0); pass.restart(); while (pass.elapsed() < 100) { threadPool.start(new CountingRunnable()); ++runs; } threadPool.waitForDone(); - QCOMPARE(count.load(), runs); + QCOMPARE(count.loadRelaxed(), runs); - count.store(runs = 0); + count.storeRelaxed(runs = 0); pass.restart(); while (pass.elapsed() < 100) { threadPool.start(new CountingRunnable()); @@ -905,7 +907,7 @@ void tst_QThreadPool::waitForDone() runs += 2; } threadPool.waitForDone(); - QCOMPARE(count.load(), runs); + QCOMPARE(count.loadRelaxed(), runs); } } @@ -953,16 +955,17 @@ void tst_QThreadPool::clear() QThreadPool threadPool; threadPool.setMaxThreadCount(10); int runs = 2 * threadPool.maxThreadCount(); - count.store(0); + count.storeRelaxed(0); for (int i = 0; i <= runs; i++) { threadPool.start(new BlockingRunnable(sem)); } threadPool.clear(); sem.release(threadPool.maxThreadCount()); threadPool.waitForDone(); - QCOMPARE(count.load(), threadPool.maxThreadCount()); + QCOMPARE(count.loadRelaxed(), threadPool.maxThreadCount()); } +#if QT_DEPRECATED_SINCE(5, 9) void tst_QThreadPool::cancel() { QSemaphore sem(0); @@ -1008,7 +1011,7 @@ void tst_QThreadPool::cancel() // and cause an early return: const QSemaphoreReleaser semReleaser(sem, runs); - count.store(0); + count.storeRelaxed(0); QAtomicInt dtorCounter = 0; QAtomicInt runCounter = 0; for (int i = 0; i < runs; i++) { @@ -1025,15 +1028,16 @@ void tst_QThreadPool::cancel() } runnables[0]->dummy = 0; //valgrind will catch this if cancel() is crazy enough to delete currently running jobs runnables[runs-1]->dummy = 0; - QCOMPARE(dtorCounter.load(), runs - threadPool.maxThreadCount() - 1); + QCOMPARE(dtorCounter.loadRelaxed(), runs - threadPool.maxThreadCount() - 1); sem.release(threadPool.maxThreadCount()); threadPool.waitForDone(); - QCOMPARE(runCounter.load(), threadPool.maxThreadCount()); - QCOMPARE(count.load(), threadPool.maxThreadCount()); - QCOMPARE(dtorCounter.load(), runs - 2); + QCOMPARE(runCounter.loadRelaxed(), threadPool.maxThreadCount()); + QCOMPARE(count.loadRelaxed(), threadPool.maxThreadCount()); + QCOMPARE(dtorCounter.loadRelaxed(), runs - 2); delete runnables[0]; //if the pool deletes them then we'll get double-free crash delete runnables[runs-1]; } +#endif void tst_QThreadPool::tryTake() { @@ -1080,7 +1084,7 @@ void tst_QThreadPool::tryTake() // and cause an early return: const QSemaphoreReleaser semReleaser(sem, Runs); - count.store(0); + count.storeRelaxed(0); QAtomicInt dtorCounter = 0; QAtomicInt runCounter = 0; for (int i = 0; i < Runs; i++) { @@ -1102,23 +1106,23 @@ void tst_QThreadPool::tryTake() } runnables[0]->dummy = 0; // valgrind will catch this if tryTake() is crazy enough to delete currently running jobs - QCOMPARE(dtorCounter.load(), int(Runs - MaxThreadCount)); + QCOMPARE(dtorCounter.loadRelaxed(), int(Runs - MaxThreadCount)); sem.release(MaxThreadCount); threadPool.waitForDone(); - QCOMPARE(runCounter.load(), int(MaxThreadCount)); - QCOMPARE(count.load(), int(MaxThreadCount)); - QCOMPARE(dtorCounter.load(), int(Runs - 1)); + QCOMPARE(runCounter.loadRelaxed(), int(MaxThreadCount)); + QCOMPARE(count.loadRelaxed(), int(MaxThreadCount)); + QCOMPARE(dtorCounter.loadRelaxed(), int(Runs - 1)); delete runnables[0]; // if the pool deletes them then we'll get double-free crash } void tst_QThreadPool::destroyingWaitsForTasksToFinish() { - QTime total, pass; + QElapsedTimer total, pass; total.start(); while (total.elapsed() < 10000) { int runs; - count.store(runs = 0); + count.storeRelaxed(runs = 0); { QThreadPool threadPool; pass.restart(); @@ -1127,9 +1131,9 @@ void tst_QThreadPool::destroyingWaitsForTasksToFinish() ++runs; } } - QCOMPARE(count.load(), runs); + QCOMPARE(count.loadRelaxed(), runs); - count.store(runs = 0); + count.storeRelaxed(runs = 0); { QThreadPool threadPool; pass.restart(); @@ -1139,7 +1143,7 @@ void tst_QThreadPool::destroyingWaitsForTasksToFinish() runs += 2; } } - QCOMPARE(count.load(), runs); + QCOMPARE(count.loadRelaxed(), runs); } } @@ -1204,7 +1208,7 @@ void tst_QThreadPool::stressTest() } }; - QTime total; + QElapsedTimer total; total.start(); while (total.elapsed() < 30000) { Task t; @@ -1322,6 +1326,7 @@ void tst_QThreadPool::waitForDoneAfterTake() QRunnable *runnable = createTask(emptyFunct); manager.start(runnable); QVERIFY(manager.tryTake(runnable)); + delete runnable; } // Add another runnable that will not be removed diff --git a/tests/auto/corelib/thread/qthreadstorage/tst_qthreadstorage.cpp b/tests/auto/corelib/thread/qthreadstorage/tst_qthreadstorage.cpp index ef5d3452d5..3538d90803 100644 --- a/tests/auto/corelib/thread/qthreadstorage/tst_qthreadstorage.cpp +++ b/tests/auto/corelib/thread/qthreadstorage/tst_qthreadstorage.cpp @@ -359,7 +359,7 @@ void tst_QThreadStorage::leakInDestructor() QVERIFY(tls.hasLocalData()); } }; - int c = SPointer::count.load(); + int c = SPointer::count.loadRelaxed(); QThreadStorage<ThreadStorageLocalDataTester *> tls; @@ -383,7 +383,7 @@ void tst_QThreadStorage::leakInDestructor() QVERIFY(t3.wait()); //check all the constructed things have been destructed - QCOMPARE(int(SPointer::count.load()), c); + QCOMPARE(int(SPointer::count.loadRelaxed()), c); } class ThreadStorageResetLocalDataTester { @@ -411,7 +411,7 @@ void tst_QThreadStorage::resetInDestructor() QVERIFY(ThreadStorageResetLocalDataTesterTls()->hasLocalData()); } }; - int c = SPointer::count.load(); + int c = SPointer::count.loadRelaxed(); Thread t1; Thread t2; @@ -424,7 +424,7 @@ void tst_QThreadStorage::resetInDestructor() QVERIFY(t3.wait()); //check all the constructed things have been destructed - QCOMPARE(int(SPointer::count.load()), c); + QCOMPARE(int(SPointer::count.loadRelaxed()), c); } @@ -475,7 +475,7 @@ void tst_QThreadStorage::valueBased() QThreadStorage<QString> tlsString; QThreadStorage<int> tlsInt; - int c = SPointer::count.load(); + int c = SPointer::count.loadRelaxed(); Thread t1(tlsSPointer, tlsString, tlsInt); Thread t2(tlsSPointer, tlsString, tlsInt); @@ -495,7 +495,7 @@ void tst_QThreadStorage::valueBased() QVERIFY(t2.wait()); QVERIFY(t3.wait()); - QCOMPARE(c, int(SPointer::count.load())); + QCOMPARE(c, int(SPointer::count.loadRelaxed())); } diff --git a/tests/auto/corelib/thread/qwaitcondition/BLACKLIST b/tests/auto/corelib/thread/qwaitcondition/BLACKLIST deleted file mode 100644 index 3ff336576b..0000000000 --- a/tests/auto/corelib/thread/qwaitcondition/BLACKLIST +++ /dev/null @@ -1,2 +0,0 @@ -[wakeOne] -windows diff --git a/tests/auto/corelib/thread/qwaitcondition/tst_qwaitcondition.cpp b/tests/auto/corelib/thread/qwaitcondition/tst_qwaitcondition.cpp index 126cb6b180..5363231895 100644 --- a/tests/auto/corelib/thread/qwaitcondition/tst_qwaitcondition.cpp +++ b/tests/auto/corelib/thread/qwaitcondition/tst_qwaitcondition.cpp @@ -481,7 +481,7 @@ void tst_QWaitCondition::wakeOne() } mutex.unlock(); - QCOMPARE(count.load(), ThreadCount); + QCOMPARE(count.loadRelaxed(), ThreadCount); // wake up threads one at a time for (x = 0; x < ThreadCount; ++x) { @@ -502,10 +502,10 @@ void tst_QWaitCondition::wakeOne() } QCOMPARE(exited, 1); - QCOMPARE(count.load(), ThreadCount - (x + 1)); + QCOMPARE(count.loadRelaxed(), ThreadCount - (x + 1)); } - QCOMPARE(count.load(), 0); + QCOMPARE(count.loadRelaxed(), 0); // QReadWriteLock QReadWriteLock readWriteLock; @@ -530,7 +530,7 @@ void tst_QWaitCondition::wakeOne() } readWriteLock.unlock(); - QCOMPARE(count.load(), ThreadCount); + QCOMPARE(count.loadRelaxed(), ThreadCount); // wake up threads one at a time for (x = 0; x < ThreadCount; ++x) { @@ -551,10 +551,10 @@ void tst_QWaitCondition::wakeOne() } QCOMPARE(exited, 1); - QCOMPARE(count.load(), ThreadCount - (x + 1)); + QCOMPARE(count.loadRelaxed(), ThreadCount - (x + 1)); } - QCOMPARE(count.load(), 0); + QCOMPARE(count.loadRelaxed(), 0); } // wake up threads, two at a time @@ -585,7 +585,7 @@ void tst_QWaitCondition::wakeOne() } mutex.unlock(); - QCOMPARE(count.load(), ThreadCount); + QCOMPARE(count.loadRelaxed(), ThreadCount); // wake up threads one at a time for (x = 0; x < ThreadCount; x += 2) { @@ -608,10 +608,10 @@ void tst_QWaitCondition::wakeOne() } QCOMPARE(exited, 2); - QCOMPARE(count.load(), ThreadCount - (x + 2)); + QCOMPARE(count.loadRelaxed(), ThreadCount - (x + 2)); } - QCOMPARE(count.load(), 0); + QCOMPARE(count.loadRelaxed(), 0); // QReadWriteLock QReadWriteLock readWriteLock; @@ -636,7 +636,7 @@ void tst_QWaitCondition::wakeOne() } readWriteLock.unlock(); - QCOMPARE(count.load(), ThreadCount); + QCOMPARE(count.loadRelaxed(), ThreadCount); // wake up threads one at a time for (x = 0; x < ThreadCount; x += 2) { @@ -659,10 +659,10 @@ void tst_QWaitCondition::wakeOne() } QCOMPARE(exited, 2); - QCOMPARE(count.load(), ThreadCount - (x + 2)); + QCOMPARE(count.loadRelaxed(), ThreadCount - (x + 2)); } - QCOMPARE(count.load(), 0); + QCOMPARE(count.loadRelaxed(), 0); } } @@ -692,7 +692,7 @@ void tst_QWaitCondition::wakeAll() } mutex.unlock(); - QCOMPARE(count.load(), ThreadCount); + QCOMPARE(count.loadRelaxed(), ThreadCount); // wake up all threads at once mutex.lock(); @@ -707,7 +707,7 @@ void tst_QWaitCondition::wakeAll() } QCOMPARE(exited, ThreadCount); - QCOMPARE(count.load(), 0); + QCOMPARE(count.loadRelaxed(), 0); // QReadWriteLock QReadWriteLock readWriteLock; @@ -728,7 +728,7 @@ void tst_QWaitCondition::wakeAll() } readWriteLock.unlock(); - QCOMPARE(count.load(), ThreadCount); + QCOMPARE(count.loadRelaxed(), ThreadCount); // wake up all threads at once readWriteLock.lockForWrite(); @@ -743,7 +743,7 @@ void tst_QWaitCondition::wakeAll() } QCOMPARE(exited, ThreadCount); - QCOMPARE(count.load(), 0); + QCOMPARE(count.loadRelaxed(), 0); } } diff --git a/tests/auto/corelib/time/qcalendar/qcalendar.pro b/tests/auto/corelib/time/qcalendar/qcalendar.pro new file mode 100644 index 0000000000..94e8fe8606 --- /dev/null +++ b/tests/auto/corelib/time/qcalendar/qcalendar.pro @@ -0,0 +1,5 @@ +CONFIG += testcase +TARGET = tst_qcalendar +QT = core testlib +SOURCES = \ + tst_qcalendar.cpp diff --git a/tests/auto/corelib/time/qcalendar/tst_qcalendar.cpp b/tests/auto/corelib/time/qcalendar/tst_qcalendar.cpp new file mode 100644 index 0000000000..9b41014394 --- /dev/null +++ b/tests/auto/corelib/time/qcalendar/tst_qcalendar.cpp @@ -0,0 +1,236 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> + +#include <QCalendar> +Q_DECLARE_METATYPE(QCalendar::System) + +class tst_QCalendar : public QObject +{ + Q_OBJECT +private: + void checkYear(const QCalendar &cal, int year, bool normal=false); + +private slots: + void basic_data(); + void basic(); + void nameCase(); + void specific_data(); + void specific(); + void daily_data() { basic_data(); } + void daily(); +}; + +// Support for basic(): +void tst_QCalendar::checkYear(const QCalendar &cal, int year, bool normal) +{ + const int moons = cal.monthsInYear(year); + // Months are numbered from 1 to moons: + QVERIFY(moons > 0); + QVERIFY(!cal.isDateValid(year, moons + 1, 1)); + QVERIFY(!cal.isDateValid(year, 0, 1)); + QVERIFY(moons <= cal.maximumMonthsInYear()); + + const int days = cal.daysInYear(year); + QVERIFY(days > 0); + + int sum = 0; + const int longest = cal.maximumDaysInMonth(); + for (int i = moons; i > 0; i--) { + const int last = cal.daysInMonth(i, year); + sum += last; + // Valid month has some days and no more than max: + QVERIFY(last > 0); + QVERIFY(last <= longest); + // Days are numbered from 1 to last: + QVERIFY(cal.isDateValid(year, i, 1)); + QVERIFY(cal.isDateValid(year, i, last)); + QVERIFY(!cal.isDateValid(year, i, 0)); + QVERIFY(!cal.isDateValid(year, i, last + 1)); + if (normal) // Unspecified year gets same daysInMonth(): + QCOMPARE(cal.daysInMonth(i), last); + } + // Months add up to the whole year: + QCOMPARE(sum, days); +} + +#define CHECKYEAR(cal, year) checkYear(cal, year); \ + if (QTest::currentTestFailed()) \ + return + +#define NORMALYEAR(cal, year) checkYear(cal, year, true); \ + if (QTest::currentTestFailed()) \ + return + +void tst_QCalendar::basic_data() +{ + QTest::addColumn<QCalendar::System>("system"); + + QMetaEnum e = QCalendar::staticMetaObject.enumerator(0); + Q_ASSERT(qstrcmp(e.name(), "System") == 0); + + for (int i = 0; i <= int(QCalendar::System::Last); ++i) { + // There may be gaps in the enum's numbering; and Last is a duplicate: + if (e.value(i) != -1 && qstrcmp(e.key(i), "Last")) + QTest::newRow(e.key(i)) << QCalendar::System(e.value(i)); + } +} + +void tst_QCalendar::basic() +{ + QFETCH(QCalendar::System, system); + QCalendar cal(system); + QVERIFY(cal.isValid()); + QCOMPARE(QCalendar(cal.name()).isGregorian(), cal.isGregorian()); + QCOMPARE(QCalendar(cal.name()).name(), cal.name()); + + if (cal.hasYearZero()) { + CHECKYEAR(cal, 0); + } else { + QCOMPARE(cal.monthsInYear(0), 0); + QCOMPARE(cal.daysInYear(0), 0); + QVERIFY(!cal.isDateValid(0, 1, 1)); + } + + if (cal.isProleptic()) { + CHECKYEAR(cal, -1); + } else { + QCOMPARE(cal.monthsInYear(-1), 0); + QCOMPARE(cal.daysInYear(-1), 0); + QVERIFY(!cal.isDateValid(-1, 1, 1)); + } + + // Look for a leap year in the last decade. + int year = QDate::currentDate().year(cal); + for (int i = 10; i > 0 && !cal.isLeapYear(year); --i) + --year; + if (cal.isLeapYear(year)) { + // ... and a non-leap year within a decade before it. + int leap = year--; + for (int i = 10; i > 0 && cal.isLeapYear(year); --i) + year--; + if (!cal.isLeapYear(year)) + QVERIFY(cal.daysInYear(year) < cal.daysInYear(leap)); + + CHECKYEAR(cal, leap); + } + // Either year is non-leap or we have a decade of leap years together; + // expect daysInMonth() to treat year the same as unspecified. + NORMALYEAR(cal, year); +} + +void tst_QCalendar::nameCase() +{ + QVERIFY(QCalendar::availableCalendars().contains(QStringLiteral("Gregorian"))); +} + +void tst_QCalendar::specific_data() +{ + QTest::addColumn<QCalendar::System>("system"); + // Date in that system: + QTest::addColumn<int>("sysyear"); + QTest::addColumn<int>("sysmonth"); + QTest::addColumn<int>("sysday"); + // Gregorian equivalent: + QTest::addColumn<int>("gregyear"); + QTest::addColumn<int>("gregmonth"); + QTest::addColumn<int>("gregday"); + +#define ADDROW(cal, year, month, day, gy, gm, gd) \ + QTest::newRow(#cal) << QCalendar::System::cal << year << month << day << gy << gm << gd + + ADDROW(Gregorian, 1970, 1, 1, 1970, 1, 1); + + // One known specific date, for each calendar +#ifndef QT_BOOTSTRAPPED + // Julian 1582-10-4 was followed by Gregorian 1582-10-15 + ADDROW(Julian, 1582, 10, 4, 1582, 10, 14); + // Milankovic matches Gregorian for a few centuries + ADDROW(Milankovic, 1923, 3, 20, 1923, 3, 20); +#endif + +#if QT_CONFIG(jalalicalendar) + // Jalali year 1355 started on Gregorian 1976-3-21: + ADDROW(Jalali, 1355, 1, 1, 1976, 3, 21); +#endif // jalali +#if QT_CONFIG(islamiccivilcalendar) + // TODO: confirm this is correct + ADDROW(IslamicCivil, 1, 1, 1, 622, 7, 19); +#endif + +#undef ADDROW +} + +void tst_QCalendar::specific() +{ + QFETCH(QCalendar::System, system); + QFETCH(int, sysyear); + QFETCH(int, sysmonth); + QFETCH(int, sysday); + QFETCH(int, gregyear); + QFETCH(int, gregmonth); + QFETCH(int, gregday); + + const QCalendar cal(system); + const QDate date(sysyear, sysmonth, sysday, cal), gregory(gregyear, gregmonth, gregday); + QCOMPARE(date, gregory); + QCOMPARE(gregory.year(cal), sysyear); + QCOMPARE(gregory.month(cal), sysmonth); + QCOMPARE(gregory.day(cal), sysday); + QCOMPARE(date.year(), gregyear); + QCOMPARE(date.month(), gregmonth); + QCOMPARE(date.day(), gregday); +} + +void tst_QCalendar::daily() +{ + QFETCH(QCalendar::System, system); + QCalendar calendar(system); + const quint64 startJDN = 0, endJDN = 2488070; + // Iterate from -4713-01-01 (Julian calendar) to 2100-01-01 + for (quint64 expect = startJDN; expect <= endJDN; ++expect) + { + QDate date = QDate::fromJulianDay(expect); + auto parts = calendar.partsFromDate(date); + if (!parts.isValid()) + continue; + + const int year = date.year(calendar); + QCOMPARE(year, parts.year); + const int month = date.month(calendar); + QCOMPARE(month, parts.month); + const int day = date.day(calendar); + QCOMPARE(day, parts.day); + const quint64 actual = QDate(year, month, day, calendar).toJulianDay(); + QCOMPARE(actual, expect); + } +} + +QTEST_APPLESS_MAIN(tst_QCalendar) +#include "tst_qcalendar.moc" diff --git a/tests/auto/corelib/tools/qdate/.gitignore b/tests/auto/corelib/time/qdate/.gitignore index 70945d4a86..70945d4a86 100644 --- a/tests/auto/corelib/tools/qdate/.gitignore +++ b/tests/auto/corelib/time/qdate/.gitignore diff --git a/tests/auto/corelib/tools/qdate/qdate.pro b/tests/auto/corelib/time/qdate/qdate.pro index dd7c6cb888..925c3b4c78 100644 --- a/tests/auto/corelib/tools/qdate/qdate.pro +++ b/tests/auto/corelib/time/qdate/qdate.pro @@ -1,4 +1,4 @@ CONFIG += testcase TARGET = tst_qdate -QT = core testlib +QT = core-private testlib SOURCES = tst_qdate.cpp diff --git a/tests/auto/corelib/tools/qdate/tst_qdate.cpp b/tests/auto/corelib/time/qdate/tst_qdate.cpp index ce1e5730dd..73384c35f4 100644 --- a/tests/auto/corelib/tools/qdate/tst_qdate.cpp +++ b/tests/auto/corelib/time/qdate/tst_qdate.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Copyright (C) 2016 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** @@ -27,6 +27,7 @@ ** ****************************************************************************/ +#include <private/qglobal_p.h> // for the icu feature test #include <QtTest/QtTest> #include <qdatetime.h> #include <qlocale.h> @@ -54,6 +55,13 @@ private slots: void weekNumber_invalid(); void weekNumber_data(); void weekNumber(); +#if QT_CONFIG(timezone) + void startOfDay_endOfDay_data(); + void startOfDay_endOfDay(); +#endif + void startOfDay_endOfDay_fixed_data(); + void startOfDay_endOfDay_fixed(); + void startOfDay_endOfDay_bounds(); void julianDaysLimits(); void addDays_data(); void addDays(); @@ -83,6 +91,7 @@ private slots: void negativeYear() const; void printNegativeYear() const; void roundtripGermanLocale() const; +#if QT_CONFIG(textdate) && QT_DEPRECATED_SINCE(5, 10) void shortDayName() const; void standaloneShortDayName() const; void longDayName() const; @@ -91,6 +100,7 @@ private slots: void standaloneShortMonthName() const; void longMonthName() const; void standaloneLongMonthName() const; +#endif // textdate void roundtrip() const; void qdebug() const; private: @@ -456,6 +466,164 @@ void tst_QDate::weekNumber_invalid() QCOMPARE( dt.weekNumber( &yearNumber ), 0 ); } +#if QT_CONFIG(timezone) +void tst_QDate::startOfDay_endOfDay_data() +{ + QTest::addColumn<QDate>("date"); // Typically a spring-forward. + // A zone in which that date's start and end are worth checking: + QTest::addColumn<QByteArray>("zoneName"); + // The start and end times in that zone: + QTest::addColumn<QTime>("start"); + QTest::addColumn<QTime>("end"); + + const QTime initial(0, 0), final(23, 59, 59, 999), invalid(QDateTime().time()); + + QTest::newRow("epoch") + << QDate(1970, 1, 1) << QByteArray("UTC") + << initial << final; + QTest::newRow("Brazil") + << QDate(2008, 10, 19) << QByteArray("America/Sao_Paulo") + << QTime(1, 0) << final; +#if QT_CONFIG(icu) || !defined(Q_OS_WIN) // MS's TZ APIs lack data + QTest::newRow("Sofia") + << QDate(1994, 3, 27) << QByteArray("Europe/Sofia") + << QTime(1, 0) << final; +#endif + QTest::newRow("Kiritimati") + << QDate(1994, 12, 31) << QByteArray("Pacific/Kiritimati") + << invalid << invalid; + QTest::newRow("Samoa") + << QDate(2011, 12, 30) << QByteArray("Pacific/Apia") + << invalid << invalid; + // TODO: find other zones with transitions at/crossing midnight. +} + +void tst_QDate::startOfDay_endOfDay() +{ + QFETCH(QDate, date); + QFETCH(QByteArray, zoneName); + QFETCH(QTime, start); + QFETCH(QTime, end); + const QTimeZone zone(zoneName); + const bool isSystem = QTimeZone::systemTimeZone() == zone; + QDateTime front(date.startOfDay(zone)), back(date.endOfDay(zone)); + if (end.isValid()) + QCOMPARE(date.addDays(1).startOfDay(zone).addMSecs(-1), back); + if (start.isValid()) + QCOMPARE(date.addDays(-1).endOfDay(zone).addMSecs(1), front); + do { // Avoids duplicating these tests for local-time when it *is* zone: + if (start.isValid()) { + QCOMPARE(front.date(), date); + QCOMPARE(front.time(), start); + } + if (end.isValid()) { + QCOMPARE(back.date(), date); + QCOMPARE(back.time(), end); + } + if (front.timeSpec() == Qt::LocalTime) + break; + front = date.startOfDay(Qt::LocalTime); + back = date.endOfDay(Qt::LocalTime); + } while (isSystem); + if (end.isValid()) + QCOMPARE(date.addDays(1).startOfDay(Qt::LocalTime).addMSecs(-1), back); + if (start.isValid()) + QCOMPARE(date.addDays(-1).endOfDay(Qt::LocalTime).addMSecs(1), front); + if (!isSystem) { + // These might fail if system zone coincides with zone; but only if it + // did something similarly unusual on the date picked for this test. + if (start.isValid()) { + QCOMPARE(front.date(), date); + QCOMPARE(front.time(), QTime(0, 0)); + } + if (end.isValid()) { + QCOMPARE(back.date(), date); + QCOMPARE(back.time(), QTime(23, 59, 59, 999)); + } + } +} +#endif // timezone + +void tst_QDate::startOfDay_endOfDay_fixed_data() +{ + const qint64 kilo(1000); + using Bounds = std::numeric_limits<qint64>; + const QDateTime + first(QDateTime::fromMSecsSinceEpoch(Bounds::min() + 1, Qt::UTC)), + start32sign(QDateTime::fromMSecsSinceEpoch(-0x80000000L * kilo, Qt::UTC)), + end32sign(QDateTime::fromMSecsSinceEpoch(0x80000000L * kilo, Qt::UTC)), + end32unsign(QDateTime::fromMSecsSinceEpoch(0x100000000L * kilo, Qt::UTC)), + last(QDateTime::fromMSecsSinceEpoch(Bounds::max(), Qt::UTC)); + + const struct { + const char *name; + QDate date; + } data[] = { + { "epoch", QDate(1970, 1, 1) }, + { "y2k-leap-day", QDate(2000, 2, 29) }, + // Just outside the start and end of 32-bit time_t: + { "pre-sign32", QDate(start32sign.date().year(), 1, 1) }, + { "post-sign32", QDate(end32sign.date().year(), 12, 31) }, + { "post-uint32", QDate(end32unsign.date().year(), 12, 31) }, + // Just inside the start and end of QDateTime's range: + { "first-full", first.date().addDays(1) }, + { "last-full", last.date().addDays(-1) } + }; + + QTest::addColumn<QDate>("date"); + for (const auto &r : data) + QTest::newRow(r.name) << r.date; +} + +void tst_QDate::startOfDay_endOfDay_fixed() +{ + const QTime early(0, 0), late(23, 59, 59, 999); + QFETCH(QDate, date); + + QDateTime start(date.startOfDay(Qt::UTC)); + QDateTime end(date.endOfDay(Qt::UTC)); + QCOMPARE(start.date(), date); + QCOMPARE(end.date(), date); + QCOMPARE(start.time(), early); + QCOMPARE(end.time(), late); + QCOMPARE(date.addDays(1).startOfDay(Qt::UTC).addMSecs(-1), end); + QCOMPARE(date.addDays(-1).endOfDay(Qt::UTC).addMSecs(1), start); + for (int offset = -60 * 16; offset <= 60 * 16; offset += 65) { + start = date.startOfDay(Qt::OffsetFromUTC, offset); + end = date.endOfDay(Qt::OffsetFromUTC, offset); + QCOMPARE(start.date(), date); + QCOMPARE(end.date(), date); + QCOMPARE(start.time(), early); + QCOMPARE(end.time(), late); + QCOMPARE(date.addDays(1).startOfDay(Qt::OffsetFromUTC, offset).addMSecs(-1), end); + QCOMPARE(date.addDays(-1).endOfDay(Qt::OffsetFromUTC, offset).addMSecs(1), start); + } +} + +void tst_QDate::startOfDay_endOfDay_bounds() +{ + // Check the days in which QDateTime's range starts and ends: + using Bounds = std::numeric_limits<qint64>; + const QDateTime + first(QDateTime::fromMSecsSinceEpoch(Bounds::min(), Qt::UTC)), + last(QDateTime::fromMSecsSinceEpoch(Bounds::max(), Qt::UTC)), + epoch(QDateTime::fromMSecsSinceEpoch(0, Qt::UTC)); + // First, check these *are* the start and end of QDateTime's range: + QVERIFY(first.isValid()); + QVERIFY(last.isValid()); + QVERIFY(first < epoch); + QVERIFY(last > epoch); + // QDateTime's addMSecs doesn't check against {und,ov}erflow ... + QVERIFY(!first.addMSecs(-1).isValid() || first.addMSecs(-1) > first); + QVERIFY(!last.addMSecs(1).isValid() || last.addMSecs(1) < last); + + // Now test start/end methods with them: + QCOMPARE(first.date().endOfDay(Qt::UTC).time(), QTime(23, 59, 59, 999)); + QCOMPARE(last.date().startOfDay(Qt::UTC).time(), QTime(0, 0)); + QVERIFY(!first.date().startOfDay(Qt::UTC).isValid()); + QVERIFY(!last.date().endOfDay(Qt::UTC).isValid()); +} + void tst_QDate::julianDaysLimits() { qint64 min = std::numeric_limits<qint64>::min(); @@ -1038,18 +1206,18 @@ void tst_QDate::fromStringFormat_data() // Undo this (inline the C-locale versions) for ### Qt 6 // Get localized names: - QString january = QDate::longMonthName(1); - QString february = QDate::longMonthName(2); - QString march = QDate::longMonthName(3); - QString august = QDate::longMonthName(8); - QString mon = QDate::shortDayName(1); - QString monday = QDate::longDayName(1); - QString tuesday = QDate::longDayName(2); - QString wednesday = QDate::longDayName(3); - QString thursday = QDate::longDayName(4); - QString friday = QDate::longDayName(5); - QString saturday = QDate::longDayName(6); - QString sunday = QDate::longDayName(7); + QString january = QLocale::system().monthName(1, QLocale::LongFormat); + QString february = QLocale::system().monthName(2, QLocale::LongFormat); + QString march = QLocale::system().monthName(3, QLocale::LongFormat); + QString august = QLocale::system().monthName(8, QLocale::LongFormat); + QString mon = QLocale::system().dayName(1, QLocale::ShortFormat); + QString monday = QLocale::system().dayName(1, QLocale::LongFormat); + QString tuesday = QLocale::system().dayName(2, QLocale::LongFormat); + QString wednesday = QLocale::system().dayName(3, QLocale::LongFormat); + QString thursday = QLocale::system().dayName(4, QLocale::LongFormat); + QString friday = QLocale::system().dayName(5, QLocale::LongFormat); + QString saturday = QLocale::system().dayName(6, QLocale::LongFormat); + QString sunday = QLocale::system().dayName(7, QLocale::LongFormat); QTest::newRow("data0") << QString("") << QString("") << defDate(); QTest::newRow("data1") << QString(" ") << QString("") << invalidDate(); @@ -1305,6 +1473,10 @@ void tst_QDate::roundtripGermanLocale() const theDateTime.fromString(theDateTime.toString(Qt::TextDate), Qt::TextDate); } +#if QT_CONFIG(textdate) && QT_DEPRECATED_SINCE(5, 10) +QT_WARNING_PUSH // the methods tested here are all deprecated +QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations") + void tst_QDate::shortDayName() const { QCOMPARE(QDate::shortDayName(0), QString()); @@ -1432,6 +1604,8 @@ void tst_QDate::standaloneLongMonthName() const QCOMPARE(QDate::longMonthName(i, QDate::StandaloneFormat), locale.standaloneMonthName(i, QLocale::LongFormat)); } } +QT_WARNING_POP +#endif // textdate void tst_QDate::roundtrip() const { diff --git a/tests/auto/corelib/tools/qdatetime/.gitignore b/tests/auto/corelib/time/qdatetime/.gitignore index 7784f3a3eb..7784f3a3eb 100644 --- a/tests/auto/corelib/tools/qdatetime/.gitignore +++ b/tests/auto/corelib/time/qdatetime/.gitignore diff --git a/tests/auto/corelib/tools/qdatetime/qdatetime.pro b/tests/auto/corelib/time/qdatetime/qdatetime.pro index 742eb47075..742eb47075 100644 --- a/tests/auto/corelib/tools/qdatetime/qdatetime.pro +++ b/tests/auto/corelib/time/qdatetime/qdatetime.pro diff --git a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp index 544eadd3a2..216ae1f79e 100644 --- a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp +++ b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Copyright (C) 2016 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** @@ -61,6 +61,10 @@ private slots: void timeSpec(); void toSecsSinceEpoch_data(); void toSecsSinceEpoch(); +#if QT_DEPRECATED_SINCE(5, 8) + void toTime_t_data(); + void toTime_t(); +#endif void daylightSavingsTimeChange_data(); void daylightSavingsTimeChange(); void springForward_data(); @@ -147,6 +151,7 @@ private slots: void systemTimeZoneChange() const; void invalid() const; + void range() const; void macTypes(); @@ -355,6 +360,7 @@ void tst_QDateTime::ctor() void tst_QDateTime::operator_eq() { + QVERIFY(QDateTime() != QDateTime(QDate(1970, 1, 1), QTime(0, 0))); // QTBUG-79006 QDateTime dt1(QDate(2004, 3, 24), QTime(23, 45, 57), Qt::UTC); QDateTime dt2(QDate(2005, 3, 11), QTime(), Qt::UTC); dt2 = dt1; @@ -1005,7 +1011,6 @@ void tst_QDateTime::toString_enumformat() { QDateTime dt1(QDate(1995, 5, 20), QTime(12, 34, 56)); - QString str1 = dt1.toString(Qt::TextDate); QVERIFY(!str1.isEmpty()); // It's locale dependent everywhere @@ -1671,6 +1676,36 @@ void tst_QDateTime::currentDateTimeUtc2() void tst_QDateTime::toSecsSinceEpoch_data() { QTest::addColumn<QString>("dateTimeStr"); + QTest::addColumn<bool>("valid"); + + QTest::newRow( "data1" ) << str( 1800, 1, 1, 12, 0, 0 ) << true; + QTest::newRow( "data2" ) << str( 1969, 1, 1, 12, 0, 0 ) << true; + QTest::newRow( "data3" ) << str( 2002, 1, 1, 12, 0, 0 ) << true; + QTest::newRow( "data4" ) << str( 2002, 6, 1, 12, 0, 0 ) << true; + QTest::newRow( "data5" ) << QString("INVALID") << false; + QTest::newRow( "data6" ) << str( 2038, 1, 1, 12, 0, 0 ) << true; + QTest::newRow( "data7" ) << str( 2063, 4, 5, 12, 0, 0 ) << true; // the day of First Contact + QTest::newRow( "data8" ) << str( 2107, 1, 1, 12, 0, 0 ) << true; +} + +void tst_QDateTime::toSecsSinceEpoch() +{ + QFETCH(const QString, dateTimeStr); + const QDateTime datetime = dt(dateTimeStr); + QFETCH(const bool, valid); + QCOMPARE(datetime.isValid(), valid); + + if (valid) { + const qint64 asSecsSinceEpoch = datetime.toSecsSinceEpoch(); + QCOMPARE(asSecsSinceEpoch, datetime.toMSecsSinceEpoch() / 1000); + QCOMPARE(QDateTime::fromSecsSinceEpoch(asSecsSinceEpoch), datetime); + } +} + +#if QT_DEPRECATED_SINCE(5, 8) +void tst_QDateTime::toTime_t_data() +{ + QTest::addColumn<QString>("dateTimeStr"); QTest::addColumn<bool>("res"); QTest::newRow( "data1" ) << str( 1800, 1, 1, 12, 0, 0 ) << false; @@ -1681,31 +1716,24 @@ void tst_QDateTime::toSecsSinceEpoch_data() QTest::newRow( "data6" ) << str( 2038, 1, 1, 12, 0, 0 ) << true; QTest::newRow( "data7" ) << str( 2063, 4, 5, 12, 0, 0 ) << true; // the day of First Contact QTest::newRow( "data8" ) << str( 2107, 1, 1, 12, 0, 0 ) - << bool( sizeof(uint) > 32 && sizeof(time_t) > 32 ); + << bool( sizeof(uint) > 32 && sizeof(time_t) > 32 ); } -void tst_QDateTime::toSecsSinceEpoch() +void tst_QDateTime::toTime_t() { QFETCH( QString, dateTimeStr ); QDateTime datetime = dt( dateTimeStr ); - qint64 asSecsSinceEpoch = datetime.toSecsSinceEpoch(); uint asTime_t = datetime.toTime_t(); QFETCH( bool, res ); if (res) { - QVERIFY( asTime_t != (uint)-1 ); + QVERIFY(asTime_t != uint(-1)); + QCOMPARE(QDateTime::fromTime_t(asTime_t), datetime); } else { - QVERIFY( asTime_t == (uint)-1 ); + QCOMPARE(asTime_t, uint(-1)); } - QCOMPARE(asSecsSinceEpoch, datetime.toMSecsSinceEpoch() / 1000); - - if ( asTime_t != (uint) -1 ) { - QDateTime datetime2 = QDateTime::fromTime_t( asTime_t ); - QCOMPARE(datetime, datetime2); - } - QDateTime datetime2 = QDateTime::fromSecsSinceEpoch(asSecsSinceEpoch); - QCOMPARE(datetime, datetime2); } +#endif void tst_QDateTime::daylightSavingsTimeChange_data() { @@ -1899,8 +1927,8 @@ void tst_QDateTime::operator_eqeq_data() QDateTime dateTime1(QDate(2012, 6, 20), QTime(14, 33, 2, 500)); QDateTime dateTime1a = dateTime1.addMSecs(1); - QDateTime dateTime2(QDate(2012, 20, 6), QTime(14, 33, 2, 500)); - QDateTime dateTime2a = dateTime2.addMSecs(-1); + QDateTime dateTime2(QDate(2012, 20, 6), QTime(14, 33, 2, 500)); // Invalid + QDateTime dateTime2a = dateTime2.addMSecs(-1); // Still invalid QDateTime dateTime3(QDate(1970, 1, 1), QTime(0, 0, 0, 0), Qt::UTC); // UTC epoch QDateTime dateTime3a = dateTime3.addDays(1); QDateTime dateTime3b = dateTime3.addDays(-1); @@ -1916,7 +1944,7 @@ void tst_QDateTime::operator_eqeq_data() QTest::newRow("data2") << dateTime1a << dateTime1a << true << false; QTest::newRow("data3") << dateTime1 << dateTime2 << false << false; QTest::newRow("data4") << dateTime1 << dateTime1a << false << false; - QTest::newRow("data5") << dateTime2 << dateTime2a << false << false; + QTest::newRow("data5") << dateTime2 << dateTime2a << true << false; QTest::newRow("data6") << dateTime2 << dateTime3 << false << false; QTest::newRow("data7") << dateTime3 << dateTime3a << false << false; QTest::newRow("data8") << dateTime3 << dateTime3b << false << false; @@ -2779,9 +2807,9 @@ void tst_QDateTime::getDate() int y = -33, m = -44, d = -55; QDate date; date.getDate(&y, &m, &d); - QVERIFY(date.year() == y); - QVERIFY(date.month() == m); - QVERIFY(date.day() == d); + QCOMPARE(date.year(), y); + QCOMPARE(date.month(), m); + QCOMPARE(date.day(), d); date.getDate(0, 0, 0); } @@ -2793,9 +2821,9 @@ void tst_QDateTime::getDate() date.getDate(&y, 0, 0); date.getDate(0, 0, &d); - QVERIFY(date.year() == y); - QVERIFY(date.month() == m); - QVERIFY(date.day() == d); + QCOMPARE(date.year(), y); + QCOMPARE(date.month(), m); + QCOMPARE(date.day(), d); } } @@ -3322,6 +3350,14 @@ void tst_QDateTime::timeZones() const QCOMPARE(dt3.timeSpec(), dt1.timeSpec()); QCOMPARE(dt3.timeZone(), dt1.timeZone()); + // The start of year 1 should be *describable* in any zone (QTBUG-78051) + dt3 = QDateTime(QDate(1, 1, 1), QTime(0, 0, 0), ausTz); + QVERIFY(dt3.isValid()); + // Likewise the end of year -1 (a.k.a. 1 BCE). + dt3 = dt3.addMSecs(-1); + QVERIFY(dt3.isValid()); + QCOMPARE(dt3, QDateTime(QDate(-1, 12, 31), QTime(23, 59, 59, 999), ausTz)); + // Check datastream serialises the time zone QByteArray tmp; { @@ -3476,6 +3512,15 @@ void tst_QDateTime::invalid() const QCOMPARE(tzDate.timeSpec(), Qt::TimeZone); } +void tst_QDateTime::range() const +{ + using Bounds = std::numeric_limits<qint64>; + QCOMPARE(QDateTime::fromMSecsSinceEpoch(Bounds::min() + 1, Qt::UTC).date().year(), + int(QDateTime::YearRange::First)); + QCOMPARE(QDateTime::fromMSecsSinceEpoch(Bounds::max() - 1, Qt::UTC).date().year(), + int(QDateTime::YearRange::Last)); +} + void tst_QDateTime::macTypes() { #ifndef Q_OS_MAC diff --git a/tests/auto/corelib/tools/qdatetime/tst_qdatetime_mac.mm b/tests/auto/corelib/time/qdatetime/tst_qdatetime_mac.mm index f73c7b9d5d..f73c7b9d5d 100644 --- a/tests/auto/corelib/tools/qdatetime/tst_qdatetime_mac.mm +++ b/tests/auto/corelib/time/qdatetime/tst_qdatetime_mac.mm diff --git a/tests/auto/corelib/tools/qtime/.gitignore b/tests/auto/corelib/time/qtime/.gitignore index 26a4c65cc2..26a4c65cc2 100644 --- a/tests/auto/corelib/tools/qtime/.gitignore +++ b/tests/auto/corelib/time/qtime/.gitignore diff --git a/tests/auto/corelib/tools/qtime/qtime.pro b/tests/auto/corelib/time/qtime/qtime.pro index 0973b7a9ef..0973b7a9ef 100644 --- a/tests/auto/corelib/tools/qtime/qtime.pro +++ b/tests/auto/corelib/time/qtime/qtime.pro diff --git a/tests/auto/corelib/tools/qtime/tst_qtime.cpp b/tests/auto/corelib/time/qtime/tst_qtime.cpp index 3e5724213e..3403c5bf7f 100644 --- a/tests/auto/corelib/tools/qtime/tst_qtime.cpp +++ b/tests/auto/corelib/time/qtime/tst_qtime.cpp @@ -95,8 +95,9 @@ void tst_QTime::addSecs_data() QTest::newRow("Data0") << QTime(0,0,0) << 200 << QTime(0,3,20); QTest::newRow("Data1") << QTime(0,0,0) << 20 << QTime(0,0,20); - QTest::newRow("overflow") << QTime(0,0,0) << (INT_MAX / 1000 + 1) - << QTime(0,0,0).addSecs((INT_MAX / 1000 + 1) % 86400); + QTest::newRow("overflow") + << QTime(0,0,0) << (INT_MAX / 1000 + 1) + << QTime::fromMSecsSinceStartOfDay(((INT_MAX / 1000 + 1) % 86400) * 1000); } void tst_QTime::addSecs() diff --git a/tests/auto/corelib/tools/qtimezone/BLACKLIST b/tests/auto/corelib/time/qtimezone/BLACKLIST index 840c3b1181..840c3b1181 100644 --- a/tests/auto/corelib/tools/qtimezone/BLACKLIST +++ b/tests/auto/corelib/time/qtimezone/BLACKLIST diff --git a/tests/auto/corelib/tools/qtimezone/qtimezone.pro b/tests/auto/corelib/time/qtimezone/qtimezone.pro index 5ec8d008e7..5ec8d008e7 100644 --- a/tests/auto/corelib/tools/qtimezone/qtimezone.pro +++ b/tests/auto/corelib/time/qtimezone/qtimezone.pro diff --git a/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp b/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp index bb6c48a2ed..9904719f7c 100644 --- a/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp +++ b/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp @@ -480,11 +480,10 @@ void tst_QTimeZone::transitionEachZone_data() { 1288488600, -4, 8, 2010 } // 2010-10-31 01:30 UTC; Europe, Russia }; - QString name; const auto zones = QTimeZone::availableTimeZoneIds(); for (int k = sizeof(table) / sizeof(table[0]); k-- > 0; ) { for (const QByteArray &zone : zones) { - name.sprintf("%s@%d", zone.constData(), table[k].year); + const QString name = QString::asprintf("%s@%d", zone.constData(), table[k].year); QTest::newRow(name.toUtf8().constData()) << zone << table[k].baseSecs @@ -916,6 +915,14 @@ void tst_QTimeZone::tzTest() QTzTimeZonePrivate tzp("Europe/Berlin"); QVERIFY(tzp.isValid()); + // Test POSIX-format value for $TZ: + QTzTimeZonePrivate tzposix("MET-1METDST-2,M3.5.0/02:00:00,M10.5.0/03:00:00"); + QVERIFY(tzposix.isValid()); + + QTimeZone tzBrazil("BRT+3"); // parts of Northern Brazil, as a POSIX rule + QVERIFY(tzBrazil.isValid()); + QCOMPARE(tzBrazil.offsetFromUtc(QDateTime(QDate(1111, 11, 11).startOfDay())), -10800); + // Test display names by type, either ICU or abbreviation only QLocale enUS("en_US"); // Only test names in debug mode, names used can vary by ICU version installed diff --git a/tests/auto/corelib/tools/qtimezone/tst_qtimezone_darwin.mm b/tests/auto/corelib/time/qtimezone/tst_qtimezone_darwin.mm index de801e55d0..de801e55d0 100644 --- a/tests/auto/corelib/tools/qtimezone/tst_qtimezone_darwin.mm +++ b/tests/auto/corelib/time/qtimezone/tst_qtimezone_darwin.mm diff --git a/tests/auto/corelib/time/time.pro b/tests/auto/corelib/time/time.pro new file mode 100644 index 0000000000..6f1ee9a8bd --- /dev/null +++ b/tests/auto/corelib/time/time.pro @@ -0,0 +1,7 @@ +TEMPLATE = subdirs +SUBDIRS = \ + qcalendar \ + qdate \ + qdatetime \ + qtime \ + qtimezone diff --git a/tests/auto/corelib/tools/collections/collections.pro b/tests/auto/corelib/tools/collections/collections.pro index 5c04515fa0..e0f9f0a0ea 100644 --- a/tests/auto/corelib/tools/collections/collections.pro +++ b/tests/auto/corelib/tools/collections/collections.pro @@ -4,4 +4,6 @@ SOURCES += tst_collections.cpp QT = core testlib # This test does not work with strict iterators +DEFINES -= QT_NO_LINKED_LIST DEFINES -= QT_STRICT_ITERATORS +DEFINES -= QT_NO_JAVA_STYLE_ITERATORS diff --git a/tests/auto/corelib/tools/collections/tst_collections.cpp b/tests/auto/corelib/tools/collections/tst_collections.cpp index b40b1f0624..e79a4dba29 100644 --- a/tests/auto/corelib/tools/collections/tst_collections.cpp +++ b/tests/auto/corelib/tools/collections/tst_collections.cpp @@ -67,7 +67,6 @@ void foo() #include <algorithm> -#include "qalgorithms.h" #include "qbitarray.h" #include "qbytearray.h" #include "qcache.h" @@ -76,7 +75,7 @@ void foo() #include "qlist.h" #include "qmap.h" #include "qpair.h" -#include "qregexp.h" +#include "qregularexpression.h" #include "qset.h" #include "qstack.h" #include "qstring.h" @@ -105,7 +104,9 @@ private slots: void map(); void bitArray(); void cache(); +#if QT_CONFIG(regularexpression) void regexp(); +#endif void pair(); void sharableQList(); void sharableQLinkedList(); @@ -189,16 +190,6 @@ void tst_Collections::list() QVERIFY(list.size() == 6); QVERIFY(list.end() - list.begin() == list.size()); -#if !defined(Q_CC_MSVC) && !defined(Q_CC_SUN) - QVERIFY(std::binary_search(list.begin(), list.end(), 2) == true); - QVERIFY(std::binary_search(list.begin(), list.end(), 9) == false); -#endif - QVERIFY(qBinaryFind(list.begin(), list.end(), 2) == list.begin() + 1); - QVERIFY(qLowerBound(list.begin(), list.end(), 2) == list.begin() + 1); - QVERIFY(qUpperBound(list.begin(), list.end(), 2) == list.begin() + 2); - QVERIFY(qBinaryFind(list.begin(), list.end(), 9) == list.end()); - QVERIFY(qLowerBound(list.begin(), list.end(), 9) == list.end()); - QVERIFY(qUpperBound(list.begin(), list.end(), 9) == list.end()); { int sum = 0; QListIterator<int> i(list); @@ -580,73 +571,73 @@ void tst_Collections::list() list1 << 0 << 1 << 2 << 3; list1.removeFirst(); - list1.swap(0, 0); + list1.swapItemsAt(0, 0); QVERIFY(list1 == QList<int>() << 1 << 2 << 3); - list1.swap(1, 1); + list1.swapItemsAt(1, 1); QVERIFY(list1 == QList<int>() << 1 << 2 << 3); - list1.swap(2, 2); + list1.swapItemsAt(2, 2); QVERIFY(list1 == QList<int>() << 1 << 2 << 3); - list1.swap(0, 1); + list1.swapItemsAt(0, 1); QVERIFY(list1 == QList<int>() << 2 << 1 << 3); - list1.swap(0, 2); + list1.swapItemsAt(0, 2); QVERIFY(list1 == QList<int>() << 3 << 1 << 2); - list1.swap(1, 2); + list1.swapItemsAt(1, 2); QVERIFY(list1 == QList<int>() << 3 << 2 << 1); - list1.swap(1, 2); + list1.swapItemsAt(1, 2); QVERIFY(list1 == QList<int>() << 3 << 1 << 2); QList<QString> list2; list2 << "1" << "2" << "3"; - list2.swap(0, 0); + list2.swapItemsAt(0, 0); QVERIFY(list2 == QList<QString>() << "1" << "2" << "3"); - list2.swap(1, 1); + list2.swapItemsAt(1, 1); QVERIFY(list2 == QList<QString>() << "1" << "2" << "3"); - list2.swap(2, 2); + list2.swapItemsAt(2, 2); QVERIFY(list2 == QList<QString>() << "1" << "2" << "3"); - list2.swap(0, 1); + list2.swapItemsAt(0, 1); QVERIFY(list2 == QList<QString>() << "2" << "1" << "3"); - list2.swap(0, 2); + list2.swapItemsAt(0, 2); QVERIFY(list2 == QList<QString>() << "3" << "1" << "2"); - list2.swap(1, 2); + list2.swapItemsAt(1, 2); QVERIFY(list2 == QList<QString>() << "3" << "2" << "1"); - list2.swap(1, 2); + list2.swapItemsAt(1, 2); QVERIFY(list2 == QList<QString>() << "3" << "1" << "2"); QList<double> list3; list3 << 1.0 << 2.0 << 3.0; - list3.swap(0, 0); + list3.swapItemsAt(0, 0); QVERIFY(list3 == QList<double>() << 1.0 << 2.0 << 3.0); - list3.swap(1, 1); + list3.swapItemsAt(1, 1); QVERIFY(list3 == QList<double>() << 1.0 << 2.0 << 3.0); - list3.swap(2, 2); + list3.swapItemsAt(2, 2); QVERIFY(list3 == QList<double>() << 1.0 << 2.0 << 3.0); - list3.swap(0, 1); + list3.swapItemsAt(0, 1); QVERIFY(list3 == QList<double>() << 2.0 << 1.0 << 3.0); - list3.swap(0, 2); + list3.swapItemsAt(0, 2); QVERIFY(list3 == QList<double>() << 3.0 << 1.0 << 2.0); - list3.swap(1, 2); + list3.swapItemsAt(1, 2); QVERIFY(list3 == QList<double>() << 3.0 << 2.0 << 1.0); - list3.swap(1, 2); + list3.swapItemsAt(1, 2); QVERIFY(list3 == QList<double>() << 3.0 << 1.0 << 2.0); } @@ -994,16 +985,8 @@ void tst_Collections::vector() v.append(2); QVERIFY(*v.begin() == 2); v.prepend(1); - - v << 3 << 4 << 5 << 6; - QVERIFY(std::binary_search(v.begin(), v.end(), 2) == true); - QVERIFY(std::binary_search(v.begin(), v.end(), 9) == false); - QVERIFY(qBinaryFind(v.begin(), v.end(), 2) == v.begin() + 1); - QVERIFY(qLowerBound(v.begin(), v.end(), 2) == v.begin() + 1); - QVERIFY(qUpperBound(v.begin(), v.end(), 2) == v.begin() + 2); - QVERIFY(qBinaryFind(v.begin(), v.end(), 9) == v.end()); - QVERIFY(qLowerBound(v.begin(), v.end(), 9) == v.end()); - QVERIFY(qUpperBound(v.begin(), v.end(), 9) == v.end()); + QVERIFY(*v.begin() == 1); + QVERIFY(*(v.begin() + 1) == 2); v.clear(); v << 1 << 2 << 3; @@ -1368,7 +1351,7 @@ void tst_Collections::hash() { typedef QHash<QString, QString> Hash; Hash hash; - QString key; + QString key = QLatin1String(" "); for (int i = 0; i < 10; ++i) { key[0] = i + '0'; for (int j = 0; j < 10; ++j) { @@ -2011,13 +1994,17 @@ void tst_Collections::qstring() QString nonNull = ""; QVERIFY(null.left(10).isNull()); QVERIFY(null.mid(0).isNull()); + QVERIFY(null.isNull()); + QVERIFY(!nonNull.isNull()); +#if QT_DEPRECATED_SINCE(5, 9) QVERIFY(null == QString::null); QVERIFY(QString::null == null); QVERIFY(nonNull != QString::null); QVERIFY(QString::null != nonNull); QVERIFY(null == nonNull); QVERIFY(QString::null == QString::null); +#endif QString fill = "123"; fill.fill('a'); @@ -2285,13 +2272,15 @@ void tst_Collections::cache() } +#if QT_CONFIG(regularexpression) void tst_Collections::regexp() { - QRegExp rx("^\\d\\d?$"); - QVERIFY(rx.indexIn("123") == -1); - QVERIFY(rx.indexIn("-6") == -1); - QVERIFY(rx.indexIn("6") == 0) ; + QRegularExpression rx("^\\d\\d?$"); + QVERIFY(!rx.match("123").hasMatch()); + QVERIFY(!rx.match("-6").hasMatch()); + QVERIFY(rx.match("6").hasMatch()) ; } +#endif void tst_Collections::pair() { @@ -2425,7 +2414,7 @@ void testContainer() c1 = newInstance<Container>(); QVERIFY(c1.size() == 4); QVERIFY(c1 == newInstance<Container>()); - Container c2 = qMove(c1); + Container c2 = std::move(c1); QVERIFY(c2.size() == 4); QVERIFY(c2 == newInstance<Container>()); } @@ -2531,14 +2520,18 @@ void tst_Collections::conversions() QCOMPARE(list2.size(), 4); QVERIFY(list2 == (QList<QString>() << STUFF)); +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) QSet<QString> set1 = list1.toSet(); +#else + QSet<QString> set1(list1.begin(), list1.end()); +#endif QCOMPARE(set1.size(), 3); QVERIFY(set1.contains("A")); QVERIFY(set1.contains("B")); QVERIFY(set1.contains("C")); QVERIFY(!set1.contains("D")); - QList<QString> list3 = set1.toList(); + QList<QString> list3 = set1.values(); QCOMPARE(list3.size(), 3); QVERIFY(list3.contains("A")); QVERIFY(list3.contains("B")); @@ -2546,9 +2539,11 @@ void tst_Collections::conversions() QVERIFY(!list3.contains("D")); QVERIFY(QList<int>().toVector().isEmpty()); - QVERIFY(QList<int>().toSet().isEmpty()); QVERIFY(QVector<int>().toList().isEmpty()); +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) + QVERIFY(QList<int>().toSet().isEmpty()); QVERIFY(QSet<int>().toList().isEmpty()); +#endif } { @@ -2563,14 +2558,22 @@ void tst_Collections::conversions() QCOMPARE(list2.size(), 4); QVERIFY(list2 == (QList<QString>() << STUFF)); +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) QSet<QString> set1 = QSet<QString>::fromList(list1); +#else + QSet<QString> set1(list1.begin(), list1.end()); +#endif QCOMPARE(set1.size(), 3); QVERIFY(set1.contains("A")); QVERIFY(set1.contains("B")); QVERIFY(set1.contains("C")); QVERIFY(!set1.contains("D")); +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) QList<QString> list3 = QList<QString>::fromSet(set1); +#else + QList<QString> list3 = set1.values(); +#endif QCOMPARE(list3.size(), 3); QVERIFY(list3.contains("A")); QVERIFY(list3.contains("B")); @@ -2578,9 +2581,11 @@ void tst_Collections::conversions() QVERIFY(!list3.contains("D")); QVERIFY(QVector<int>::fromList(QList<int>()).isEmpty()); - QVERIFY(QSet<int>::fromList(QList<int>()).isEmpty()); QVERIFY(QList<int>::fromVector(QVector<int>()).isEmpty()); +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) + QVERIFY(QSet<int>::fromList(QList<int>()).isEmpty()); QVERIFY(QList<int>::fromSet(QSet<int>()).isEmpty()); +#endif } #undef STUFF } @@ -2776,15 +2781,21 @@ void tst_Collections::vector_stl() for (int i = 0; i < elements.count(); ++i) vector << elements.at(i); +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) std::vector<QString> stdVector = vector.toStdVector(); - +#else + std::vector<QString> stdVector(vector.begin(), vector.end()); +#endif QCOMPARE(int(stdVector.size()), elements.size()); std::vector<QString>::const_iterator it = stdVector.begin(); for (uint j = 0; j < stdVector.size() && it != stdVector.end(); ++j, ++it) QCOMPARE(*it, vector[j]); +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) QCOMPARE(QVector<QString>::fromStdVector(stdVector), vector); +#endif + QCOMPARE(QVector<QString>(stdVector.begin(), stdVector.end()), vector); } void tst_Collections::linkedlist_stl_data() @@ -2830,7 +2841,11 @@ void tst_Collections::list_stl() for (int i = 0; i < elements.count(); ++i) list << elements.at(i); +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) std::list<QString> stdList = list.toStdList(); +#else + std::list<QString> stdList(list.begin(), list.end()); +#endif QCOMPARE(int(stdList.size()), elements.size()); @@ -2838,7 +2853,10 @@ void tst_Collections::list_stl() for (uint j = 0; j < stdList.size() && it != stdList.end(); ++j, ++it) QCOMPARE(*it, list[j]); +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) QCOMPARE(QList<QString>::fromStdList(stdList), list); +#endif + QCOMPARE(QList<QString>(stdList.begin(), stdList.end()), list); } template <typename T> diff --git a/tests/auto/corelib/tools/containerapisymmetry/containerapisymmetry.pro b/tests/auto/corelib/tools/containerapisymmetry/containerapisymmetry.pro index 30dc8026ef..e46d51761e 100644 --- a/tests/auto/corelib/tools/containerapisymmetry/containerapisymmetry.pro +++ b/tests/auto/corelib/tools/containerapisymmetry/containerapisymmetry.pro @@ -5,3 +5,4 @@ QT = core testlib # This test does not work with strict iterators DEFINES -= QT_STRICT_ITERATORS +DEFINES -= QT_NO_LINKED_LIST diff --git a/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp b/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp index 3b8111f1a3..4b085d387d 100644 --- a/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp +++ b/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp @@ -34,13 +34,446 @@ #include "qstring.h" #include "qvarlengtharray.h" #include "qvector.h" +#include "qhash.h" +#include "qdebug.h" +#include <algorithm> +#include <functional> #include <vector> // for reference +#include <list> +#include <set> +#include <map> + +// MSVC has these containers from the Standard Library, but it lacks +// a __has_include mechanism (that we need to use for other stdlibs). +// For the sake of increasing our test coverage, work around the issue. + +#ifdef Q_CC_MSVC +#define COMPILER_HAS_STDLIB_INCLUDE(x) 1 +#else +#define COMPILER_HAS_STDLIB_INCLUDE(x) QT_HAS_INCLUDE(x) +#endif + +#if COMPILER_HAS_STDLIB_INCLUDE(<forward_list>) +#include <forward_list> +#endif +#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>) +#include <unordered_set> +#endif +#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_map>) +#include <unordered_map> +#endif + +struct Movable +{ + explicit Movable(int i = 0) Q_DECL_NOTHROW + : i(i) + { + ++instanceCount; + } + + Movable(const Movable &m) + : i(m.i) + { + ++instanceCount; + } + + ~Movable() + { + --instanceCount; + } + + int i; + static int instanceCount; +}; + +int Movable::instanceCount = 0; +bool operator==(Movable lhs, Movable rhs) Q_DECL_NOTHROW { return lhs.i == rhs.i; } +bool operator!=(Movable lhs, Movable rhs) Q_DECL_NOTHROW { return lhs.i != rhs.i; } +bool operator<(Movable lhs, Movable rhs) Q_DECL_NOTHROW { return lhs.i < rhs.i; } + +uint qHash(Movable m, uint seed = 0) Q_DECL_NOTHROW { return qHash(m.i, seed); } +QDebug &operator<<(QDebug &d, Movable m) +{ + const QDebugStateSaver saver(d); + return d.nospace() << "Movable(" << m.i << ")"; +} + +QT_BEGIN_NAMESPACE +Q_DECLARE_TYPEINFO(Movable, Q_MOVABLE_TYPE); +QT_END_NAMESPACE + +struct Complex +{ + explicit Complex(int i = 0) Q_DECL_NOTHROW + : i(i) + { + ++instanceCount; + } + + Complex(const Complex &c) + : i(c.i) + { + ++instanceCount; + } + + ~Complex() + { + --instanceCount; + } + + int i; + static int instanceCount; +}; + +int Complex::instanceCount = 0; +bool operator==(Complex lhs, Complex rhs) Q_DECL_NOTHROW { return lhs.i == rhs.i; } +bool operator!=(Complex lhs, Complex rhs) Q_DECL_NOTHROW { return lhs.i != rhs.i; } +bool operator<(Complex lhs, Complex rhs) Q_DECL_NOTHROW { return lhs.i < rhs.i; } + +uint qHash(Complex c, uint seed = 0) Q_DECL_NOTHROW { return qHash(c.i, seed); } +QDebug &operator<<(QDebug &d, Complex c) +{ + const QDebugStateSaver saver(d); + return d.nospace() << "Complex(" << c.i << ")"; +} + + +struct DuplicateStrategyTestType +{ + explicit DuplicateStrategyTestType(int i = 0) Q_DECL_NOTHROW + : i(i), + j(++counter) + { + } + + int i; + int j; + + static int counter; +}; + +int DuplicateStrategyTestType::counter = 0; + +// only look at the i member, not j. j allows us to identify which instance +// gets inserted in containers that don't allow for duplicates +bool operator==(DuplicateStrategyTestType lhs, DuplicateStrategyTestType rhs) Q_DECL_NOTHROW +{ + return lhs.i == rhs.i; +} + +bool operator!=(DuplicateStrategyTestType lhs, DuplicateStrategyTestType rhs) Q_DECL_NOTHROW +{ + return lhs.i != rhs.i; +} + +bool operator<(DuplicateStrategyTestType lhs, DuplicateStrategyTestType rhs) Q_DECL_NOTHROW +{ + return lhs.i < rhs.i; +} + +uint qHash(DuplicateStrategyTestType c, uint seed = 0) Q_DECL_NOTHROW +{ + return qHash(c.i, seed); +} + +bool reallyEqual(DuplicateStrategyTestType lhs, DuplicateStrategyTestType rhs) Q_DECL_NOTHROW +{ + return lhs.i == rhs.i && lhs.j == rhs.j; +} + +QDebug &operator<<(QDebug &d, DuplicateStrategyTestType c) +{ + const QDebugStateSaver saver(d); + return d.nospace() << "DuplicateStrategyTestType(" << c.i << "," << c.j << ")"; +} + + +namespace std { +template<> +struct hash<Movable> +{ + std::size_t operator()(Movable m) const Q_DECL_NOTHROW + { + return hash<int>()(m.i); + } +}; + +template<> +struct hash<Complex> +{ + std::size_t operator()(Complex m) const Q_DECL_NOTHROW + { + return hash<int>()(m.i); + } +}; + +template<> +struct hash<DuplicateStrategyTestType> +{ + std::size_t operator()(DuplicateStrategyTestType m) const Q_DECL_NOTHROW + { + return hash<int>()(m.i); + } +}; +} + +// work around the fact that QVarLengthArray has a non-type +// template parameter, and that breaks non_associative_container_duplicates_strategy +template<typename T> +class VarLengthArray : public QVarLengthArray<T> +{ +public: +#ifdef Q_COMPILER_INHERITING_CONSTRUCTORS + using QVarLengthArray<T>::QVarLengthArray; +#else + template<typename InputIterator> + VarLengthArray(InputIterator first, InputIterator last) + : QVarLengthArray<T>(first, last) + { + } + + VarLengthArray(std::initializer_list<T> args) + : QVarLengthArray<T>(args) + { + } +#endif +}; class tst_ContainerApiSymmetry : public QObject { Q_OBJECT + int m_movableInstanceCount; + int m_complexInstanceCount; + +private Q_SLOTS: + void init(); + void cleanup(); + +private: + template <typename Container> + void ranged_ctor_non_associative_impl() const; + + template<template<typename ... T> class Container> + void non_associative_container_duplicates_strategy() const; + + template <typename Container> + void ranged_ctor_associative_impl() const; + +private Q_SLOTS: + // non associative + void ranged_ctor_std_vector_int() { ranged_ctor_non_associative_impl<std::vector<int>>(); } + void ranged_ctor_std_vector_char() { ranged_ctor_non_associative_impl<std::vector<char>>(); } + void ranged_ctor_std_vector_QChar() { ranged_ctor_non_associative_impl<std::vector<QChar>>(); } + void ranged_ctor_std_vector_Movable() { ranged_ctor_non_associative_impl<std::vector<Movable>>(); } + void ranged_ctor_std_vector_Complex() { ranged_ctor_non_associative_impl<std::vector<Complex>>(); } + void ranged_ctor_std_vector_duplicates_strategy() { non_associative_container_duplicates_strategy<std::vector>(); } + + void ranged_ctor_QVector_int() { ranged_ctor_non_associative_impl<QVector<int>>(); } + void ranged_ctor_QVector_char() { ranged_ctor_non_associative_impl<QVector<char>>(); } + void ranged_ctor_QVector_QChar() { ranged_ctor_non_associative_impl<QVector<QChar>>(); } + void ranged_ctor_QVector_Movable() { ranged_ctor_non_associative_impl<QVector<Movable>>(); } + void ranged_ctor_QVector_Complex() { ranged_ctor_non_associative_impl<QVector<Complex>>(); } + void ranged_ctor_QVector_duplicates_strategy() { non_associative_container_duplicates_strategy<QVector>(); } + + void ranged_ctor_QVarLengthArray_int() { ranged_ctor_non_associative_impl<QVarLengthArray<int>>(); } + void ranged_ctor_QVarLengthArray_Movable() { ranged_ctor_non_associative_impl<QVarLengthArray<Movable>>(); } + void ranged_ctor_QVarLengthArray_Complex() { ranged_ctor_non_associative_impl<QVarLengthArray<Complex>>(); } + void ranged_ctor_QVarLengthArray_duplicates_strategy() { non_associative_container_duplicates_strategy<VarLengthArray>(); } // note the VarLengthArray passed + + void ranged_ctor_QList_int() { ranged_ctor_non_associative_impl<QList<int>>(); } + void ranged_ctor_QList_Movable() { ranged_ctor_non_associative_impl<QList<Movable>>(); } + void ranged_ctor_QList_Complex() { ranged_ctor_non_associative_impl<QList<Complex>>(); } + void ranged_ctor_QList_duplicates_strategy() { non_associative_container_duplicates_strategy<QList>(); } + + void ranged_ctor_std_list_int() { ranged_ctor_non_associative_impl<std::list<int>>(); } + void ranged_ctor_std_list_Movable() { ranged_ctor_non_associative_impl<std::list<Movable>>(); } + void ranged_ctor_std_list_Complex() { ranged_ctor_non_associative_impl<std::list<Complex>>(); } + void ranged_ctor_std_list_duplicates_strategy() { non_associative_container_duplicates_strategy<std::list>(); } + + void ranged_ctor_std_forward_list_int() { +#if COMPILER_HAS_STDLIB_INCLUDE(<forward_list>) + ranged_ctor_non_associative_impl<std::forward_list<int>>(); +#else + QSKIP("<forward_list> is needed for this test"); +#endif + } + + void ranged_ctor_std_forward_list_Movable() { +#if COMPILER_HAS_STDLIB_INCLUDE(<forward_list>) + ranged_ctor_non_associative_impl<std::forward_list<Movable>>(); +#else + QSKIP("<forward_list> is needed for this test"); +#endif + } + + void ranged_ctor_std_forward_list_Complex() { +#if COMPILER_HAS_STDLIB_INCLUDE(<forward_list>) + ranged_ctor_non_associative_impl<std::forward_list<Complex>>(); +#else + QSKIP("<forward_list> is needed for this test"); +#endif + } + + void ranged_ctor_std_forward_list_duplicates_strategy() { +#if COMPILER_HAS_STDLIB_INCLUDE(<forward_list>) + non_associative_container_duplicates_strategy<std::forward_list>(); +#else + QSKIP("<forward_list> is needed for this test"); +#endif + } + + void ranged_ctor_QLinkedList_int() { ranged_ctor_non_associative_impl<QLinkedList<int>>(); } + void ranged_ctor_QLinkedList_Movable() { ranged_ctor_non_associative_impl<QLinkedList<Movable>>(); } + void ranged_ctor_QLinkedList_Complex() { ranged_ctor_non_associative_impl<QLinkedList<Complex>>(); } + void ranged_ctor_QLinkedList_duplicates_strategy() { non_associative_container_duplicates_strategy<QLinkedList>(); } + + void ranged_ctor_std_set_int() { ranged_ctor_non_associative_impl<std::set<int>>(); } + void ranged_ctor_std_set_Movable() { ranged_ctor_non_associative_impl<std::set<Movable>>(); } + void ranged_ctor_std_set_Complex() { ranged_ctor_non_associative_impl<std::set<Complex>>(); } + void ranged_ctor_std_set_duplicates_strategy() { non_associative_container_duplicates_strategy<std::set>(); } + + void ranged_ctor_std_multiset_int() { ranged_ctor_non_associative_impl<std::multiset<int>>(); } + void ranged_ctor_std_multiset_Movable() { ranged_ctor_non_associative_impl<std::multiset<Movable>>(); } + void ranged_ctor_std_multiset_Complex() { ranged_ctor_non_associative_impl<std::multiset<Complex>>(); } + void ranged_ctor_std_multiset_duplicates_strategy() { non_associative_container_duplicates_strategy<std::multiset>(); } + + void ranged_ctor_std_unordered_set_int() { +#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>) + ranged_ctor_non_associative_impl<std::unordered_set<int>>(); +#else + QSKIP("<unordered_set> is needed for this test"); +#endif + } + + void ranged_ctor_std_unordered_set_Movable() { +#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>) + ranged_ctor_non_associative_impl<std::unordered_set<Movable>>(); +#else + QSKIP("<unordered_set> is needed for this test"); +#endif + } + + void ranged_ctor_std_unordered_set_Complex() { +#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>) + ranged_ctor_non_associative_impl<std::unordered_set<Complex>>(); +#else + QSKIP("<unordered_set> is needed for this test"); +#endif + } + + void ranged_ctor_unordered_set_duplicates_strategy() { +#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>) + non_associative_container_duplicates_strategy<std::unordered_set>(); +#else + QSKIP("<unordered_set> is needed for this test"); +#endif + } + + + void ranged_ctor_std_unordered_multiset_int() { +#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>) + ranged_ctor_non_associative_impl<std::unordered_multiset<int>>(); +#else + QSKIP("<unordered_set> is needed for this test"); +#endif + } + + void ranged_ctor_std_unordered_multiset_Movable() { +#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>) + ranged_ctor_non_associative_impl<std::unordered_multiset<Movable>>(); +#else + QSKIP("<unordered_set> is needed for this test"); +#endif + } + + void ranged_ctor_std_unordered_multiset_Complex() { +#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>) + ranged_ctor_non_associative_impl<std::unordered_multiset<Complex>>(); +#else + QSKIP("<unordered_set> is needed for this test"); +#endif + } + + void ranged_ctor_std_unordered_multiset_duplicates_strategy() { +#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>) + non_associative_container_duplicates_strategy<std::unordered_multiset>(); +#else + QSKIP("<unordered_set> is needed for this test"); +#endif + } + + void ranged_ctor_QSet_int() { ranged_ctor_non_associative_impl<QSet<int>>(); } + void ranged_ctor_QSet_Movable() { ranged_ctor_non_associative_impl<QSet<Movable>>(); } + void ranged_ctor_QSet_Complex() { ranged_ctor_non_associative_impl<QSet<Complex>>(); } + void ranged_ctor_QSet_duplicates_strategy() { non_associative_container_duplicates_strategy<QSet>(); } + + // associative + void ranged_ctor_std_map_int() { ranged_ctor_associative_impl<std::map<int, int>>(); } + void ranged_ctor_std_map_Movable() { ranged_ctor_associative_impl<std::map<Movable, int>>(); } + void ranged_ctor_std_map_Complex() { ranged_ctor_associative_impl<std::map<Complex, int>>(); } + + void ranged_ctor_std_multimap_int() { ranged_ctor_associative_impl<std::multimap<int, int>>(); } + void ranged_ctor_std_multimap_Movable() { ranged_ctor_associative_impl<std::multimap<Movable, int>>(); } + void ranged_ctor_std_multimap_Complex() { ranged_ctor_associative_impl<std::multimap<Complex, int>>(); } + + void ranged_ctor_unordered_map_int() { +#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_map>) + ranged_ctor_associative_impl<std::unordered_map<int, int>>(); +#else + QSKIP("<unordered_map> is needed for this test"); +#endif + } + + void ranged_ctor_unordered_map_Movable() { +#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_map>) + ranged_ctor_associative_impl<std::unordered_map<Movable, Movable>>(); +#else + QSKIP("<unordered_map> is needed for this test"); +#endif + } + + void ranged_ctor_unordered_map_Complex() { +#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_map>) + ranged_ctor_associative_impl<std::unordered_map<Complex, Complex>>(); +#else + QSKIP("<unordered_map> is needed for this test"); +#endif + } + + void ranged_ctor_QHash_int() { ranged_ctor_associative_impl<QHash<int, int>>(); } + void ranged_ctor_QHash_Movable() { ranged_ctor_associative_impl<QHash<Movable, int>>(); } + void ranged_ctor_QHash_Complex() { ranged_ctor_associative_impl<QHash<Complex, int>>(); } + + void ranged_ctor_unordered_multimap_int() { +#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_map>) + ranged_ctor_associative_impl<std::unordered_multimap<int, int>>(); +#else + QSKIP("<unordered_map> is needed for this test"); +#endif + } + + void ranged_ctor_unordered_multimap_Movable() { +#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_map>) + ranged_ctor_associative_impl<std::unordered_multimap<Movable, Movable>>(); +#else + QSKIP("<unordered_map> is needed for this test"); +#endif + } + + void ranged_ctor_unordered_multimap_Complex() { +#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_map>) + ranged_ctor_associative_impl<std::unordered_multimap<Complex, Complex>>(); +#else + QSKIP("<unordered_map> is needed for this test"); +#endif + } + + void ranged_ctor_QMultiHash_int() { ranged_ctor_associative_impl<QMultiHash<int, int>>(); } + void ranged_ctor_QMultiHash_Movable() { ranged_ctor_associative_impl<QMultiHash<Movable, int>>(); } + void ranged_ctor_QMultiHash_Complex() { ranged_ctor_associative_impl<QMultiHash<Complex, int>>(); } + private: template <typename Container> void front_back_impl() const; @@ -58,6 +491,296 @@ private Q_SLOTS: void front_back_QByteArray() { front_back_impl<QByteArray>(); } }; +void tst_ContainerApiSymmetry::init() +{ + m_movableInstanceCount = Movable::instanceCount; + m_complexInstanceCount = Complex::instanceCount; +} + +void tst_ContainerApiSymmetry::cleanup() +{ + // very simple leak check + QCOMPARE(Movable::instanceCount, m_movableInstanceCount); + QCOMPARE(Complex::instanceCount, m_complexInstanceCount); +} + +template <typename Container> +Container createContainerReference() +{ + using V = typename Container::value_type; + + return {V(0), V(1), V(2), V(0)}; +} + +template <typename Container> +void tst_ContainerApiSymmetry::ranged_ctor_non_associative_impl() const +{ + using V = typename Container::value_type; + + // the double V(0) is deliberate + const auto reference = createContainerReference<Container>(); + + // plain array + const V values1[] = { V(0), V(1), V(2), V(0) }; + + const Container c1(values1, values1 + sizeof(values1)/sizeof(values1[0])); + + // from QList + QList<V> l2; + l2 << V(0) << V(1) << V(2) << V(0); + + const Container c2a(l2.begin(), l2.end()); + const Container c2b(l2.cbegin(), l2.cend()); + + // from std::list + std::list<V> l3; + l3.push_back(V(0)); + l3.push_back(V(1)); + l3.push_back(V(2)); + l3.push_back(V(0)); + const Container c3a(l3.begin(), l3.end()); + + // from const std::list + const std::list<V> l3c = l3; + const Container c3b(l3c.begin(), l3c.end()); + + // from itself + const Container c4(reference.begin(), reference.end()); + + QCOMPARE(c1, reference); + QCOMPARE(c2a, reference); + QCOMPARE(c2b, reference); + QCOMPARE(c3a, reference); + QCOMPARE(c3b, reference); + QCOMPARE(c4, reference); +} + + +// type traits for detecting whether a non-associative container +// accepts duplicated values, and if it doesn't, whether construction/insertion +// prefer the new values (overwriting) or the old values (rejecting) + +struct ContainerAcceptsDuplicateValues {}; +struct ContainerOverwritesDuplicateValues {}; +struct ContainerRejectsDuplicateValues {}; + +template<typename Container> +struct ContainerDuplicatedValuesStrategy {}; + +template<typename ... T> +struct ContainerDuplicatedValuesStrategy<std::vector<T...>> : ContainerAcceptsDuplicateValues {}; + +template<typename ... T> +struct ContainerDuplicatedValuesStrategy<QVector<T...>> : ContainerAcceptsDuplicateValues {}; + +template<typename ... T> +struct ContainerDuplicatedValuesStrategy<QVarLengthArray<T...>> : ContainerAcceptsDuplicateValues {}; + +template<typename ... T> +struct ContainerDuplicatedValuesStrategy<VarLengthArray<T...>> : ContainerAcceptsDuplicateValues {}; + +template<typename ... T> +struct ContainerDuplicatedValuesStrategy<QList<T...>> : ContainerAcceptsDuplicateValues {}; + +template<typename ... T> +struct ContainerDuplicatedValuesStrategy<std::list<T...>> : ContainerAcceptsDuplicateValues {}; + +#if COMPILER_HAS_STDLIB_INCLUDE(<forward_list>) +template<typename ... T> +struct ContainerDuplicatedValuesStrategy<std::forward_list<T...>> : ContainerAcceptsDuplicateValues {}; +#endif + +template<typename ... T> +struct ContainerDuplicatedValuesStrategy<QLinkedList<T...>> : ContainerAcceptsDuplicateValues {}; + +// assuming https://cplusplus.github.io/LWG/lwg-active.html#2844 resolution +template<typename ... T> +struct ContainerDuplicatedValuesStrategy<std::set<T...>> : ContainerRejectsDuplicateValues {}; + +template<typename ... T> +struct ContainerDuplicatedValuesStrategy<std::multiset<T...>> : ContainerAcceptsDuplicateValues {}; + +#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>) +// assuming https://cplusplus.github.io/LWG/lwg-active.html#2844 resolution +template<typename ... T> +struct ContainerDuplicatedValuesStrategy<std::unordered_set<T...>> : ContainerRejectsDuplicateValues {}; + +template<typename ... T> +struct ContainerDuplicatedValuesStrategy<std::unordered_multiset<T...>> : ContainerAcceptsDuplicateValues {}; +#endif + +template<typename ... T> +struct ContainerDuplicatedValuesStrategy<QSet<T...>> : ContainerRejectsDuplicateValues {}; + +template<typename Container> +void non_associative_container_check_duplicates_impl(const std::initializer_list<DuplicateStrategyTestType> &reference, const Container &c, ContainerAcceptsDuplicateValues) +{ + // do a deep check for equality, not ordering + QVERIFY(std::distance(reference.begin(), reference.end()) == std::distance(c.begin(), c.end())); + QVERIFY(std::is_permutation(reference.begin(), reference.end(), c.begin(), &reallyEqual)); +} + +enum class IterationOnReference +{ + ForwardIteration, + ReverseIteration +}; + +template<typename Container> +void non_associative_container_check_duplicates_impl_no_duplicates(const std::initializer_list<DuplicateStrategyTestType> &reference, const Container &c, IterationOnReference ior) +{ + std::vector<DuplicateStrategyTestType> valuesAlreadySeen; + + // iterate on reference forward or backwards, depending on ior. this will give + // us the expected semantics when checking for duplicated values into c + auto it = [&reference, ior]() { + switch (ior) { + case IterationOnReference::ForwardIteration: return reference.begin(); + case IterationOnReference::ReverseIteration: return reference.end() - 1; + }; + return std::initializer_list<DuplicateStrategyTestType>::const_iterator(); + }(); + + const auto &end = [&reference, ior]() { + switch (ior) { + case IterationOnReference::ForwardIteration: return reference.end(); + case IterationOnReference::ReverseIteration: return reference.begin() - 1; + }; + return std::initializer_list<DuplicateStrategyTestType>::const_iterator(); + }(); + + while (it != end) { + const auto &value = *it; + + // check that there is indeed the same value in the container (using operator==) + const auto &valueInContainerIterator = std::find(c.begin(), c.end(), value); + QVERIFY(valueInContainerIterator != c.end()); + QVERIFY(value == *valueInContainerIterator); + + // if the value is a duplicate, we don't expect to find it in the container + // (when doing a deep comparison). otherwise it should be there + + const auto &valuesAlreadySeenIterator = std::find(valuesAlreadySeen.cbegin(), valuesAlreadySeen.cend(), value); + const bool valueIsDuplicated = (valuesAlreadySeenIterator != valuesAlreadySeen.cend()); + + const auto &reallyEqualCheck = [&value](const DuplicateStrategyTestType &v) { return reallyEqual(value, v); }; + QCOMPARE(std::find_if(c.begin(), c.end(), reallyEqualCheck) == c.end(), valueIsDuplicated); + + valuesAlreadySeen.push_back(value); + + switch (ior) { + case IterationOnReference::ForwardIteration: + ++it; + break; + case IterationOnReference::ReverseIteration: + --it; + break; + }; + } + +} + +template<typename Container> +void non_associative_container_check_duplicates_impl(const std::initializer_list<DuplicateStrategyTestType> &reference, const Container &c, ContainerRejectsDuplicateValues) +{ + non_associative_container_check_duplicates_impl_no_duplicates(reference, c, IterationOnReference::ForwardIteration); +} + +template<typename Container> +void non_associative_container_check_duplicates_impl(const std::initializer_list<DuplicateStrategyTestType> &reference, const Container &c, ContainerOverwritesDuplicateValues) +{ + non_associative_container_check_duplicates_impl_no_duplicates(reference, c, IterationOnReference::ReverseIteration); +} + +template<typename Container> +void non_associative_container_check_duplicates(const std::initializer_list<DuplicateStrategyTestType> &reference, const Container &c) +{ + non_associative_container_check_duplicates_impl(reference, c, ContainerDuplicatedValuesStrategy<Container>()); +} + +template<template<class ... T> class Container> +void tst_ContainerApiSymmetry::non_associative_container_duplicates_strategy() const +{ + // first and last are "duplicates" -- they compare equal for operator==, + // but they differ when using reallyEqual + const std::initializer_list<DuplicateStrategyTestType> reference{ DuplicateStrategyTestType{0}, + DuplicateStrategyTestType{1}, + DuplicateStrategyTestType{2}, + DuplicateStrategyTestType{0} }; + Container<DuplicateStrategyTestType> c1{reference}; + non_associative_container_check_duplicates(reference, c1); + + Container<DuplicateStrategyTestType> c2{reference.begin(), reference.end()}; + non_associative_container_check_duplicates(reference, c2); +} + +template <typename Container> +void tst_ContainerApiSymmetry::ranged_ctor_associative_impl() const +{ + using K = typename Container::key_type; + using V = typename Container::mapped_type; + + // The double K(0) is deliberate. The order of the elements matters: + // * for unique-key STL containers, the first one should be the one inserted (cf. LWG 2844) + // * for unique-key Qt containers, the last one should be the one inserted + // * for multi-key sorted containers, the order of insertion of identical keys is also the + // iteration order (which establishes the equality of the containers) + // (although nothing of this is being tested here, that deserves its own testing) + const Container reference{ + { K(0), V(1000) }, + { K(1), V(1001) }, + { K(2), V(1002) }, + { K(0), V(1003) } + }; + + // Note that using anything not convertible to std::pair doesn't work for + // std containers. Their ranged construction is defined in terms of + // insert(value_type), which for std associative containers is + // std::pair<const K, T>. + + // plain array + const std::pair<K, V> values1[] = { + std::make_pair(K(0), V(1000)), + std::make_pair(K(1), V(1001)), + std::make_pair(K(2), V(1002)), + std::make_pair(K(0), V(1003)) + }; + + const Container c1(values1, values1 + sizeof(values1)/sizeof(values1[0])); + + // from QList + QList<std::pair<K, V>> l2; + l2 << std::make_pair(K(0), V(1000)) + << std::make_pair(K(1), V(1001)) + << std::make_pair(K(2), V(1002)) + << std::make_pair(K(0), V(1003)); + + const Container c2a(l2.begin(), l2.end()); + const Container c2b(l2.cbegin(), l2.cend()); + + // from std::list + std::list<std::pair<K, V>> l3; + l3.push_back(std::make_pair(K(0), V(1000))); + l3.push_back(std::make_pair(K(1), V(1001))); + l3.push_back(std::make_pair(K(2), V(1002))); + l3.push_back(std::make_pair(K(0), V(1003))); + const Container c3a(l3.begin(), l3.end()); + + // from const std::list + const std::list<std::pair<K, V>> l3c = l3; + const Container c3b(l3c.begin(), l3c.end()); + + // from itself + const Container c4(reference.begin(), reference.end()); + + QCOMPARE(c1, reference); + QCOMPARE(c2a, reference); + QCOMPARE(c2b, reference); + QCOMPARE(c3a, reference); + QCOMPARE(c3b, reference); + QCOMPARE(c4, reference); +} + template <typename Container> Container make(int size) { diff --git a/tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp b/tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp index 72299402f0..18432e51a6 100644 --- a/tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp +++ b/tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp @@ -48,6 +48,11 @@ class tst_QAlgorithms : public QObject { Q_OBJECT private slots: + void swap(); + void swap2(); + void convenienceAPI(); + +#if QT_DEPRECATED_SINCE(5, 2) void test_qLowerBound_data(); void test_qLowerBound(); void test_qUpperBound_data(); @@ -55,19 +60,23 @@ private slots: void test_qBinaryFind_data(); void test_qBinaryFind(); void qBinaryFindOneEntry(); - void swap(); - void swap2(); void sortEmptyList(); void sortedList(); void sortAPItest(); void stableSortTest(); void stableSortCorrectnessTest_data(); void stableSortCorrectnessTest(); - void convenienceAPI(); + void convenienceAPI_deprecated(); void qCountIterators() const; void qCountContainer() const; void binaryFindOnLargeContainer() const; +#if Q_TEST_PERFORMANCE + void performance(); +#endif + +#endif // QT_DEPRECATED_SINCE(5, 2) + void popCount08_data() { popCount_data_impl(sizeof(quint8 )); } void popCount16_data() { popCount_data_impl(sizeof(quint16)); } void popCount32_data() { popCount_data_impl(sizeof(quint32)); } @@ -96,9 +105,6 @@ private slots: void countLeading64() { countLeading_impl<quint64>(); } private: -#if Q_TEST_PERFORMANCE - void performance(); -#endif void popCount_data_impl(size_t sizeof_T_Int); template <typename T_Int> void popCount_impl(); @@ -112,6 +118,8 @@ private: void countLeading_impl(); }; +#if QT_DEPRECATED_SINCE(5, 2) + class TestInt { public: @@ -172,7 +180,7 @@ ResultSet testRun(ContainerType &container, Algorithm &algorithm, int millisecs) { TestInt::lessThanRefCount = 0; int count = 0; - QTime t; + QElapsedTimer t; t.start(); while(t.elapsed() < millisecs) { ++count; @@ -208,7 +216,7 @@ void printHeader(QStringList &headers) for (int h = 0; h < headers.count(); ++h) { cout << setw(20) << setiosflags(ios_base::left) << headers.at(h).toLatin1().constData(); } - cout << endl; + cout << Qt::endl; } template <typename ContainerType> @@ -220,7 +228,7 @@ void print(ContainerType testContainer) cout << value << " "; } - cout << endl; + cout << Qt::endl; } template <typename Algorithm, typename DataType> @@ -252,11 +260,13 @@ void testAlgorithm(Algorithm algorithm, QStringList &dataSetTypes) lessThan << setiosflags(ios_base::left) << setw(10) << result.lessThanRefCount / result.numSorts; cout << numSorts.str() << lessThan.str(); } - cout << endl; + cout << Qt::endl; } } #endif +#endif // QT_DEPRECATED_SINCE(5, 2) + void tst_QAlgorithms::swap() { { @@ -391,6 +401,17 @@ void tst_QAlgorithms::swap2() } } +void tst_QAlgorithms::convenienceAPI() +{ + // Compile-test for QAlgorithm convenience functions. + + QList<int *> pointerList; + qDeleteAll(pointerList); + qDeleteAll(pointerList.begin(), pointerList.end()); +} + +#if QT_DEPRECATED_SINCE(5, 2) + void tst_QAlgorithms::sortEmptyList() { // Only test if it crashes @@ -676,7 +697,7 @@ void tst_QAlgorithms::stableSortCorrectnessTest() QVERIFY(isSorted(sorted)); } -void tst_QAlgorithms::convenienceAPI() +void tst_QAlgorithms::convenienceAPI_deprecated() { // Compile-test for QAlgorithm convenience functions. QList<int> list, list2; @@ -716,10 +737,6 @@ void tst_QAlgorithms::convenienceAPI() qBinaryFind(list, 1); qBinaryFind(list.begin(), list.end(), 1); qBinaryFind(list.begin(), list.end(), 1, qLess<int>()); - - QList<int *> pointerList; - qDeleteAll(pointerList); - qDeleteAll(pointerList.begin(), pointerList.end()); } template <typename DataType> @@ -765,21 +782,21 @@ public: #if Q_TEST_PERFORMANCE void tst_QAlgorithms::performance() { - cout << endl << "Quick sort" << endl; + cout << Qt::endl << "Quick sort" << Qt::endl; testAlgorithm<QuickSortHelper<TestInt>, TestInt>(QuickSortHelper<TestInt>(), dataSetTypes); - cout << endl << "stable sort" << endl; + cout << Qt::endl << "stable sort" << Qt::endl; testAlgorithm<StableSortHelper<TestInt>, TestInt>(StableSortHelper<TestInt>(), dataSetTypes); - cout << endl << "std::sort" << endl; + cout << Qt::endl << "std::sort" << Qt::endl; testAlgorithm<StlSortHelper<TestInt>, TestInt>(StlSortHelper<TestInt>(), dataSetTypes); - cout << endl << "std::stable_sort" << endl; + cout << Qt::endl << "std::stable_sort" << Qt::endl; testAlgorithm<StlStableSortHelper<TestInt>, TestInt>(StlStableSortHelper<TestInt>(), dataSetTypes); /* - cout << endl << "Sorting lists of ints" << endl; - cout << endl << "Quick sort" << endl; + cout << Qt::endl << "Sorting lists of ints" << Qt::endl; + cout << Qt::endl << "Quick sort" << Qt::endl; testAlgorithm<QuickSortHelper<int>, int>(QuickSortHelper<int>(), dataSetTypes); - cout << endl << "std::sort" << endl; + cout << Qt::endl << "std::sort" << Qt::endl; testAlgorithm<StlSortHelper<int>, int>(StlSortHelper<int>(), dataSetTypes); - cout << endl << "std::stable_sort" << endl; + cout << Qt::endl << "std::stable_sort" << Qt::endl; testAlgorithm<StlStableSortHelper<int>, int>(StlStableSortHelper<int>(), dataSetTypes); */ } @@ -1041,6 +1058,8 @@ void tst_QAlgorithms::binaryFindOnLargeContainer() const QCOMPARE(foundIt.pos(), 1073987655); } +#endif // QT_DEPRECATED_SINCE(5, 2) + // alternative implementation of qPopulationCount for comparison: static Q_DECL_CONSTEXPR const uint bitsSetInNibble[] = { 0, 1, 1, 2, 1, 2, 2, 3, diff --git a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp index a00c962510..25e2f21d03 100644 --- a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp +++ b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp @@ -78,12 +78,8 @@ private slots: void fromRawData_data(); void fromRawData(); void literals(); -#if defined(Q_COMPILER_VARIADIC_MACROS) && defined(Q_COMPILER_LAMBDA) void variadicLiterals(); -#endif -#ifdef Q_COMPILER_RVALUE_REFS void rValueReferences(); -#endif void grow(); }; @@ -95,7 +91,7 @@ void tst_QArrayData::referenceCounting() // Reference counting initialized to 1 (owned) QArrayData array = { { Q_BASIC_ATOMIC_INITIALIZER(1) }, 0, 0, 0, 0 }; - QCOMPARE(array.ref.atomic.load(), 1); + QCOMPARE(array.ref.atomic.loadRelaxed(), 1); QVERIFY(!array.ref.isStatic()); #if !defined(QT_NO_UNSHARABLE_CONTAINERS) @@ -103,19 +99,19 @@ void tst_QArrayData::referenceCounting() #endif QVERIFY(array.ref.ref()); - QCOMPARE(array.ref.atomic.load(), 2); + QCOMPARE(array.ref.atomic.loadRelaxed(), 2); QVERIFY(array.ref.deref()); - QCOMPARE(array.ref.atomic.load(), 1); + QCOMPARE(array.ref.atomic.loadRelaxed(), 1); QVERIFY(array.ref.ref()); - QCOMPARE(array.ref.atomic.load(), 2); + QCOMPARE(array.ref.atomic.loadRelaxed(), 2); QVERIFY(array.ref.deref()); - QCOMPARE(array.ref.atomic.load(), 1); + QCOMPARE(array.ref.atomic.loadRelaxed(), 1); QVERIFY(!array.ref.deref()); - QCOMPARE(array.ref.atomic.load(), 0); + QCOMPARE(array.ref.atomic.loadRelaxed(), 0); // Now would be a good time to free/release allocated data } @@ -125,17 +121,17 @@ void tst_QArrayData::referenceCounting() // Reference counting initialized to 0 (non-sharable) QArrayData array = { { Q_BASIC_ATOMIC_INITIALIZER(0) }, 0, 0, 0, 0 }; - QCOMPARE(array.ref.atomic.load(), 0); + QCOMPARE(array.ref.atomic.loadRelaxed(), 0); QVERIFY(!array.ref.isStatic()); QVERIFY(!array.ref.isSharable()); QVERIFY(!array.ref.ref()); // Reference counting fails, data should be copied - QCOMPARE(array.ref.atomic.load(), 0); + QCOMPARE(array.ref.atomic.loadRelaxed(), 0); QVERIFY(!array.ref.deref()); - QCOMPARE(array.ref.atomic.load(), 0); + QCOMPARE(array.ref.atomic.loadRelaxed(), 0); // Free/release data } @@ -145,7 +141,7 @@ void tst_QArrayData::referenceCounting() // Reference counting initialized to -1 (static read-only data) QArrayData array = { Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, 0, 0 }; - QCOMPARE(array.ref.atomic.load(), -1); + QCOMPARE(array.ref.atomic.loadRelaxed(), -1); QVERIFY(array.ref.isStatic()); #if !defined(QT_NO_UNSHARABLE_CONTAINERS) @@ -153,10 +149,10 @@ void tst_QArrayData::referenceCounting() #endif QVERIFY(array.ref.ref()); - QCOMPARE(array.ref.atomic.load(), -1); + QCOMPARE(array.ref.atomic.loadRelaxed(), -1); QVERIFY(array.ref.deref()); - QCOMPARE(array.ref.atomic.load(), -1); + QCOMPARE(array.ref.atomic.loadRelaxed(), -1); } } @@ -172,8 +168,8 @@ void tst_QArrayData::sharedNullEmpty() QVERIFY(empty->ref.isStatic()); QVERIFY(empty->ref.isShared()); - QCOMPARE(null->ref.atomic.load(), -1); - QCOMPARE(empty->ref.atomic.load(), -1); + QCOMPARE(null->ref.atomic.loadRelaxed(), -1); + QCOMPARE(empty->ref.atomic.loadRelaxed(), -1); #if !defined(QT_NO_UNSHARABLE_CONTAINERS) QVERIFY(null->ref.isSharable()); @@ -183,14 +179,14 @@ void tst_QArrayData::sharedNullEmpty() QVERIFY(null->ref.ref()); QVERIFY(empty->ref.ref()); - QCOMPARE(null->ref.atomic.load(), -1); - QCOMPARE(empty->ref.atomic.load(), -1); + QCOMPARE(null->ref.atomic.loadRelaxed(), -1); + QCOMPARE(empty->ref.atomic.loadRelaxed(), -1); QVERIFY(null->ref.deref()); QVERIFY(empty->ref.deref()); - QCOMPARE(null->ref.atomic.load(), -1); - QCOMPARE(empty->ref.atomic.load(), -1); + QCOMPARE(null->ref.atomic.loadRelaxed(), -1); + QCOMPARE(empty->ref.atomic.loadRelaxed(), -1); QVERIFY(null != empty); @@ -1618,9 +1614,7 @@ void tst_QArrayData::literals() QCOMPARE(v.size(), size_t(11)); // v.capacity() is unspecified, for now -#if defined(Q_COMPILER_VARIADIC_MACROS) && defined(Q_COMPILER_LAMBDA) QVERIFY(v.isStatic()); -#endif #if !defined(QT_NO_UNSHARABLE_CONTAINERS) QVERIFY(v.isSharable()); @@ -1631,9 +1625,20 @@ void tst_QArrayData::literals() QCOMPARE(const_(v)[i], char('A' + i)); QCOMPARE(const_(v)[10], char('\0')); } + + { + struct LiteralType { + int value; + Q_DECL_CONSTEXPR LiteralType(int v = 0) : value(v) {} + }; + + QArrayDataPointer<LiteralType> d = Q_ARRAY_LITERAL(LiteralType, LiteralType(0), LiteralType(1), LiteralType(2)); + QCOMPARE(d->size, 3); + for (int i = 0; i < 3; ++i) + QCOMPARE(d->data()[i].value, i); + } } -#if defined(Q_COMPILER_VARIADIC_MACROS) && defined(Q_COMPILER_LAMBDA) // Variadic Q_ARRAY_LITERAL need to be available in the current configuration. void tst_QArrayData::variadicLiterals() { @@ -1682,9 +1687,7 @@ void tst_QArrayData::variadicLiterals() QCOMPARE(const_(v)[i], i); } } -#endif -#ifdef Q_COMPILER_RVALUE_REFS // std::remove_reference is in C++11, but requires library support template <class T> struct RemoveReference { typedef T Type; }; template <class T> struct RemoveReference<T &> { typedef T Type; }; @@ -1767,7 +1770,6 @@ void tst_QArrayData::rValueReferences() QCOMPARE(v3.size(), size_t(1)); QCOMPARE(v3.front(), 42); } -#endif void tst_QArrayData::grow() { diff --git a/tests/auto/corelib/tools/qcommandlineparser/testhelper/qcommandlineparser_test_helper.cpp b/tests/auto/corelib/tools/qcommandlineparser/testhelper/qcommandlineparser_test_helper.cpp index b9bcecd607..513c811788 100644 --- a/tests/auto/corelib/tools/qcommandlineparser/testhelper/qcommandlineparser_test_helper.cpp +++ b/tests/auto/corelib/tools/qcommandlineparser/testhelper/qcommandlineparser_test_helper.cpp @@ -74,10 +74,12 @@ int main(int argc, char *argv[]) hiddenOption.setDescription(QStringLiteral("THIS SHOULD NEVER APPEAR")); hiddenOption.setFlags(QCommandLineOption::HiddenFromHelp); parser.addOption(hiddenOption); +#if QT_DEPRECATED_SINCE(5, 8) QCommandLineOption hiddenOption2(QStringList() << QStringLiteral("hidden2")); hiddenOption2.setDescription(QStringLiteral("NEITHER SHOULD THIS")); hiddenOption2.setHidden(true); parser.addOption(hiddenOption2); +#endif // This program supports different options depending on the "command" (first argument). // Call parse() to find out the positional arguments. diff --git a/tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.cpp b/tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.cpp index 7980f1f8f4..1e87c76d2f 100644 --- a/tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.cpp +++ b/tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.cpp @@ -44,6 +44,7 @@ private slots: // In-process tests void testInvalidOptions(); + void testDuplicateOption(); void testPositionalArguments(); void testBooleanOption_data(); void testBooleanOption(); @@ -75,6 +76,8 @@ private slots: void testHelpOption(); void testQuoteEscaping(); void testUnknownOption(); + void testHelpAll_data(); + void testHelpAll(); }; static char *empty_argv[] = { 0 }; @@ -104,6 +107,15 @@ void tst_QCommandLineParser::testInvalidOptions() QVERIFY(!parser.addOption(QCommandLineOption(QStringLiteral("-v"), QStringLiteral("Displays version information.")))); } +void tst_QCommandLineParser::testDuplicateOption() +{ + QCoreApplication app(empty_argc, empty_argv); + QCommandLineParser parser; + QVERIFY(parser.addOption(QCommandLineOption(QStringLiteral("h"), QStringLiteral("Hostname."), QStringLiteral("hostname")))); + QTest::ignoreMessage(QtWarningMsg, "QCommandLineParser: already having an option named \"h\""); + parser.addHelpOption(); +} + void tst_QCommandLineParser::testPositionalArguments() { QCoreApplication app(empty_argc, empty_argv); @@ -489,7 +501,7 @@ void tst_QCommandLineParser::testSingleDashWordOptionModes() void tst_QCommandLineParser::testCpp11StyleInitialization() { -#if defined(Q_COMPILER_INITIALIZER_LISTS) && defined(Q_COMPILER_UNIFORM_INIT) +#if defined(Q_COMPILER_UNIFORM_INIT) QCoreApplication app(empty_argc, empty_argv); QCommandLineParser parser; @@ -532,7 +544,8 @@ void tst_QCommandLineParser::testVersionOption() static const char expectedOptionsHelp[] = "Options:\n" - " -h, --help Displays this help.\n" + " -h, --help Displays help on commandline options.\n" + " --help-all Displays help including Qt specific options.\n" " -v, --version Displays version information.\n" " --load <url> Load file from URL.\n" " -o, --output <file> Set output file.\n" @@ -566,8 +579,8 @@ void tst_QCommandLineParser::testHelpOption_data() " parsingMode The parsing mode to test.\n" " command The command to execute.\n"); #ifdef Q_OS_WIN - expectedOutput.replace(" -h, --help Displays this help.\n", - " -?, -h, --help Displays this help.\n"); + expectedOutput.replace(" -h, --help Displays help on commandline options.\n", + " -?, -h, --help Displays help on commandline options.\n"); expectedOutput.replace("testhelper/", "testhelper\\"); #endif @@ -615,8 +628,8 @@ void tst_QCommandLineParser::testHelpOption() "Arguments:\n" " resize Resize the object to a new size.\n"; #ifdef Q_OS_WIN - expectedResizeHelp.replace(" -h, --help Displays this help.\n", - " -?, -h, --help Displays this help.\n"); + expectedResizeHelp.replace(" -h, --help Displays help on commandline options.\n", + " -?, -h, --help Displays help on commandline options.\n"); expectedResizeHelp.replace("testhelper/", "testhelper\\"); #endif QCOMPARE(output, QString(expectedResizeHelp)); @@ -670,6 +683,60 @@ void tst_QCommandLineParser::testUnknownOption() #endif // QT_CONFIG(process) } +void tst_QCommandLineParser::testHelpAll_data() +{ + QTest::addColumn<QCommandLineParser::SingleDashWordOptionMode>("parsingMode"); + QTest::addColumn<QString>("expectedHelpOutput"); + + QString expectedOutput = QString::fromLatin1( + "Usage: testhelper/qcommandlineparser_test_helper [options] parsingMode command\n" + "Test helper\n" + "\n") + + QString::fromLatin1(expectedOptionsHelp) + + QString::fromLatin1( + " --qmljsdebugger <value> Activates the QML/JS debugger with a specified\n" + " port. The value must be of format\n" + " port:1234[,block]. \"block\" makes the application\n" + " wait for a connection.\n" + "\n" + "Arguments:\n" + " parsingMode The parsing mode to test.\n" + " command The command to execute.\n"); +#ifdef Q_OS_WIN + expectedOutput.replace(" -h, --help Displays help on commandline options.\n", + " -?, -h, --help Displays help on commandline options.\n"); + expectedOutput.replace("testhelper/", "testhelper\\"); +#endif + + QTest::newRow("collapsed") << QCommandLineParser::ParseAsCompactedShortOptions << expectedOutput; + QTest::newRow("long") << QCommandLineParser::ParseAsLongOptions << expectedOutput; +} + +void tst_QCommandLineParser::testHelpAll() +{ +#if !QT_CONFIG(process) + QSKIP("This test requires QProcess support"); +#else +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) + QSKIP("Deploying executable applications to file system on Android not supported."); +#endif + + QFETCH(QCommandLineParser::SingleDashWordOptionMode, parsingMode); + QFETCH(QString, expectedHelpOutput); + QCoreApplication app(empty_argc, empty_argv); + QProcess process; + process.start("testhelper/qcommandlineparser_test_helper", QStringList() << QString::number(parsingMode) << "--help-all"); + QVERIFY(process.waitForFinished(5000)); + QCOMPARE(process.exitStatus(), QProcess::NormalExit); + QString output = process.readAll(); +#ifdef Q_OS_WIN + output.replace(QStringLiteral("\r\n"), QStringLiteral("\n")); +#endif + QCOMPARE(output.split('\n'), expectedHelpOutput.split('\n')); // easier to debug than the next line, on failure + QCOMPARE(output, expectedHelpOutput); +#endif // QT_CONFIG(process) +} + QTEST_APPLESS_MAIN(tst_QCommandLineParser) #include "tst_qcommandlineparser.moc" diff --git a/tests/auto/corelib/tools/qcontiguouscache/tst_qcontiguouscache.cpp b/tests/auto/corelib/tools/qcontiguouscache/tst_qcontiguouscache.cpp index 31a5f93822..f305d63d46 100644 --- a/tests/auto/corelib/tools/qcontiguouscache/tst_qcontiguouscache.cpp +++ b/tests/auto/corelib/tools/qcontiguouscache/tst_qcontiguouscache.cpp @@ -68,7 +68,7 @@ void tst_QContiguousCache::assignment() // copy: cc1 = cc2; // move: - cc1 = qMove(cc2); + cc1 = std::move(cc2); } void tst_QContiguousCache::empty() @@ -244,7 +244,7 @@ public: return *this; } - int refCount() const { return d->ref.load(); } + int refCount() const { return d->ref.loadRelaxed(); } private: RefCountingClassData *d; }; diff --git a/tests/auto/corelib/tools/qdatetime/BLACKLIST b/tests/auto/corelib/tools/qdatetime/BLACKLIST deleted file mode 100644 index 3a42ee066b..0000000000 --- a/tests/auto/corelib/tools/qdatetime/BLACKLIST +++ /dev/null @@ -1,2 +0,0 @@ -[timeZoneAbbreviation] -osx diff --git a/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp b/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp index 0196dd2d23..2a9c1e1e41 100644 --- a/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp +++ b/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp @@ -30,9 +30,7 @@ #include <qeasingcurve.h> -#ifdef Q_COMPILER_RVALUE_REFS // cpp11() slot -# include <utility> // for std::move() -#endif +#include <utility> // for std::move() class tst_QEasingCurve : public QObject { @@ -55,6 +53,8 @@ private slots: void testCbrtFloat(); void cpp11(); void quadraticEquation(); + void streamInOut_data(); + void streamInOut(); }; void tst_QEasingCurve::type() @@ -404,6 +404,11 @@ void tst_QEasingCurve::valueForProgress() const qreal error = qAbs(ex - curve.valueForProgress(at.at(i)/qreal(100))); QVERIFY(error <= errorBound); } + + if (type != QEasingCurve::SineCurve && type != QEasingCurve::CosineCurve) { + QVERIFY( !(curve.valueForProgress(0) > 0) ); + QVERIFY( !(curve.valueForProgress(1) < 1) ); + } #endif } @@ -632,6 +637,9 @@ void tst_QEasingCurve::bezierSpline() QCOMPARE(value, ex); QVERIFY(error <= errorBound); } + + QVERIFY( !(bezierEasingCurve.valueForProgress(0) > 0) ); + QVERIFY( !(bezierEasingCurve.valueForProgress(1) < 1) ); } void tst_QEasingCurve::tcbSpline_data() @@ -691,6 +699,9 @@ void tst_QEasingCurve::tcbSpline() QCOMPARE(value, ex); QVERIFY(error <= errorBound); } + + QVERIFY( !(tcbEasingCurve.valueForProgress(0) > 0) ); + QVERIFY( !(tcbEasingCurve.valueForProgress(1) < 1) ); } /*This is single precision code for a cubic root used inside the spline easing curve. @@ -792,7 +803,6 @@ void tst_QEasingCurve::testCbrtFloat() void tst_QEasingCurve::cpp11() { -#ifdef Q_COMPILER_RVALUE_REFS { QEasingCurve ec( QEasingCurve::InOutBack ); QEasingCurve copy = std::move(ec); // move ctor @@ -807,7 +817,6 @@ void tst_QEasingCurve::cpp11() QCOMPARE( copy.type(), QEasingCurve::InOutBack ); QCOMPARE( ec.type(), type ); } -#endif } void tst_QEasingCurve::quadraticEquation() { @@ -879,5 +888,36 @@ void tst_QEasingCurve::quadraticEquation() { } } +void tst_QEasingCurve::streamInOut_data() +{ + QTest::addColumn<int>("version"); + QTest::addColumn<bool>("equality"); + + QTest::newRow("5.11") << int(QDataStream::Qt_5_11) << false; + QTest::newRow("5.13") << int(QDataStream::Qt_5_13) << true; +} + +void tst_QEasingCurve::streamInOut() +{ + QFETCH(int, version); + QFETCH(bool, equality); + + QEasingCurve orig; + orig.addCubicBezierSegment(QPointF(0.43, 0.0025), QPointF(0.38, 0.51), QPointF(0.57, 0.99)); + + QEasingCurve copy; + + QByteArray data; + QDataStream dsw(&data,QIODevice::WriteOnly); + QDataStream dsr(&data,QIODevice::ReadOnly); + + dsw.setVersion(version); + dsr.setVersion(version); + dsw << orig; + dsr >> copy; + + QCOMPARE(copy == orig, equality); +} + QTEST_MAIN(tst_QEasingCurve) #include "tst_qeasingcurve.moc" diff --git a/tests/auto/corelib/tools/qhash/qhash.pro b/tests/auto/corelib/tools/qhash/qhash.pro index 79ffd4e9d1..e96c0d1bf1 100644 --- a/tests/auto/corelib/tools/qhash/qhash.pro +++ b/tests/auto/corelib/tools/qhash/qhash.pro @@ -2,3 +2,5 @@ CONFIG += testcase TARGET = tst_qhash QT = core testlib SOURCES = $$PWD/tst_qhash.cpp + +DEFINES -= QT_NO_JAVA_STYLE_ITERATORS diff --git a/tests/auto/corelib/tools/qhash/tst_qhash.cpp b/tests/auto/corelib/tools/qhash/tst_qhash.cpp index 0015efacfa..f0aaad98bd 100644 --- a/tests/auto/corelib/tools/qhash/tst_qhash.cpp +++ b/tests/auto/corelib/tools/qhash/tst_qhash.cpp @@ -273,7 +273,7 @@ void tst_QHash::insert1() { typedef QHash<QString, QString> Hash; Hash hash; - QString key; + QString key = QLatin1String(" "); for (int i = 0; i < 10; ++i) { key[0] = i + '0'; for (int j = 0; j < 10; ++j) { @@ -1480,7 +1480,6 @@ void tst_QHash::twoArguments_qHash() void tst_QHash::initializerList() { -#ifdef Q_COMPILER_INITIALIZER_LISTS QHash<int, QString> hash = {{1, "bar"}, {1, "hello"}, {2, "initializer_list"}}; QCOMPARE(hash.count(), 2); QCOMPARE(hash[1], QString("hello")); @@ -1507,9 +1506,6 @@ void tst_QHash::initializerList() QMultiHash<int, float> emptyPairs2{{}, {}}; QVERIFY(!emptyPairs2.isEmpty()); -#else - QSKIP("Compiler doesn't support initializer lists"); -#endif } void tst_QHash::eraseValidIteratorOnSharedHash() diff --git a/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp b/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp index 124e3cdf00..f76f3aa0c6 100644 --- a/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp +++ b/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp @@ -34,6 +34,8 @@ #include <sstream> #include <algorithm> +#include <unordered_set> + class tst_QHashFunctions : public QObject { Q_OBJECT @@ -59,6 +61,8 @@ private Q_SLOTS: void range(); void rangeCommutative(); + void stdHash(); + void setGlobalQHashSeed(); }; @@ -281,6 +285,38 @@ void tst_QHashFunctions::rangeCommutative() (void)qHashRangeCommutative(hashables, hashables + numHashables, seed); } +void tst_QHashFunctions::stdHash() +{ + { + std::unordered_set<QString> s = {QStringLiteral("Hello"), QStringLiteral("World")}; + QCOMPARE(s.size(), 2UL); + s.insert(QStringLiteral("Hello")); + QCOMPARE(s.size(), 2UL); + } + + { + std::unordered_set<QStringView> s = {QStringLiteral("Hello"), QStringLiteral("World")}; + QCOMPARE(s.size(), 2UL); + s.insert(QStringLiteral("Hello")); + QCOMPARE(s.size(), 2UL); + } + + { + std::unordered_set<QLatin1String> s = {QLatin1String("Hello"), QLatin1String("World")}; + QCOMPARE(s.size(), 2UL); + s.insert(QLatin1String("Hello")); + QCOMPARE(s.size(), 2UL); + } + + { + std::unordered_set<QByteArray> s = {QByteArrayLiteral("Hello"), QByteArrayLiteral("World")}; + QCOMPARE(s.size(), 2UL); + s.insert(QByteArray("Hello")); + QCOMPARE(s.size(), 2UL); + } + +} + void tst_QHashFunctions::setGlobalQHashSeed() { // Setter works as advertised diff --git a/tests/auto/corelib/tools/qline/tst_qline.cpp b/tests/auto/corelib/tools/qline/tst_qline.cpp index ae65d8f697..31aa5b4e0c 100644 --- a/tests/auto/corelib/tools/qline/tst_qline.cpp +++ b/tests/auto/corelib/tools/qline/tst_qline.cpp @@ -53,8 +53,10 @@ private slots: void testNormalVector(); void testNormalVector_data(); +#if QT_DEPRECATED_SINCE(5, 14) void testAngle(); void testAngle_data(); +#endif void testAngle2(); void testAngle2_data(); @@ -205,7 +207,10 @@ void tst_QLine::testIntersection() QPointF ip; - QLineF::IntersectType itype = a.intersect(b, &ip); + QLineF::IntersectionType itype = a.intersects(b, &ip); +#if QT_DEPRECATED_SINCE(5, 14) + QCOMPARE(a.intersect(b, &ip), itype); +#endif QCOMPARE(int(itype), type); if (type != QLineF::NoIntersection) { @@ -378,6 +383,7 @@ void tst_QLine::testNormalVector() QCOMPARE(n.dy(), qreal(nvy)); } +#if QT_DEPRECATED_SINCE(5, 14) void tst_QLine::testAngle_data() { QTest::addColumn<double>("xa1"); @@ -426,6 +432,7 @@ void tst_QLine::testAngle() double resultAngle = a.angle(b); QCOMPARE(qRound(resultAngle), qRound(angle)); } +#endif void tst_QLine::testAngle2_data() { diff --git a/tests/auto/corelib/tools/qlinkedlist/qlinkedlist.pro b/tests/auto/corelib/tools/qlinkedlist/qlinkedlist.pro index 80630f78ad..c53d553d6d 100644 --- a/tests/auto/corelib/tools/qlinkedlist/qlinkedlist.pro +++ b/tests/auto/corelib/tools/qlinkedlist/qlinkedlist.pro @@ -1,4 +1,7 @@ CONFIG += testcase TARGET = tst_qlinkedlist QT = core testlib +qtConfig(c++14): CONFIG += c++14 +qtConfig(c++1z): CONFIG += c++1z SOURCES = tst_qlinkedlist.cpp +DEFINES -= QT_NO_LINKED_LIST diff --git a/tests/auto/corelib/tools/qlinkedlist/tst_qlinkedlist.cpp b/tests/auto/corelib/tools/qlinkedlist/tst_qlinkedlist.cpp index f17d6695f0..df42b5dea9 100644 --- a/tests/auto/corelib/tools/qlinkedlist/tst_qlinkedlist.cpp +++ b/tests/auto/corelib/tools/qlinkedlist/tst_qlinkedlist.cpp @@ -187,6 +187,7 @@ private slots: void countInt() const; void countMovable() const; void countComplex() const; + void cpp17ctad() const; void emptyInt() const; void emptyMovable() const; void emptyComplex() const; @@ -594,6 +595,33 @@ void tst_QLinkedList::countComplex() const QCOMPARE(liveCount, Complex::getLiveCount()); } +void tst_QLinkedList::cpp17ctad() const +{ +#ifdef __cpp_deduction_guides +#define QVERIFY_IS_LIST_OF(obj, Type) \ + QVERIFY2((std::is_same<decltype(obj), QLinkedList<Type>>::value), \ + QMetaType::typeName(qMetaTypeId<decltype(obj)::value_type>())) +#define CHECK(Type, One, Two, Three) \ + do { \ + const Type v[] = {One, Two, Three}; \ + QLinkedList v1 = {One, Two, Three}; \ + QVERIFY_IS_LIST_OF(v1, Type); \ + QLinkedList v2(v1.begin(), v1.end()); \ + QVERIFY_IS_LIST_OF(v2, Type); \ + QLinkedList v3(std::begin(v), std::end(v)); \ + QVERIFY_IS_LIST_OF(v3, Type); \ + } while (false) \ + /*end*/ + CHECK(int, 1, 2, 3); + CHECK(double, 1.0, 2.0, 3.0); + CHECK(QString, QStringLiteral("one"), QStringLiteral("two"), QStringLiteral("three")); +#undef QVERIFY_IS_LIST_OF +#undef CHECK +#else + QSKIP("This test requires C++17 Constructor Template Argument Deduction support enabled in the compiler."); +#endif +} + template<typename T> void tst_QLinkedList::empty() const { @@ -1005,7 +1033,6 @@ void tst_QLinkedList::testSTLIteratorsComplex() const void tst_QLinkedList::initializeList() const { -#ifdef Q_COMPILER_INITIALIZER_LISTS QLinkedList<int> v1 { 2, 3, 4 }; QCOMPARE(v1, QLinkedList<int>() << 2 << 3 << 4); QCOMPARE(v1, (QLinkedList<int> { 2, 3, 4})); @@ -1014,7 +1041,6 @@ void tst_QLinkedList::initializeList() const QLinkedList<QLinkedList<int>> v3; v3 << v1 << (QLinkedList<int>() << 1) << QLinkedList<int>() << v1; QCOMPARE(v3, v2); -#endif } diff --git a/tests/auto/corelib/tools/qlist/qlist.pro b/tests/auto/corelib/tools/qlist/qlist.pro index 47f0140abb..118c607880 100644 --- a/tests/auto/corelib/tools/qlist/qlist.pro +++ b/tests/auto/corelib/tools/qlist/qlist.pro @@ -1,4 +1,6 @@ CONFIG += testcase TARGET = tst_qlist QT = core testlib +qtConfig(c++14): CONFIG += c++14 +qtConfig(c++1z): CONFIG += c++1z SOURCES = $$PWD/tst_qlist.cpp diff --git a/tests/auto/corelib/tools/qlist/tst_qlist.cpp b/tests/auto/corelib/tools/qlist/tst_qlist.cpp index b3f8130d27..cc9a3a16d1 100644 --- a/tests/auto/corelib/tools/qlist/tst_qlist.cpp +++ b/tests/auto/corelib/tools/qlist/tst_qlist.cpp @@ -310,6 +310,7 @@ private slots: void lastComplex() const; void constFirst() const; void constLast() const; + void cpp17ctad() const; void beginOptimal() const; void beginMovable() const; void beginComplex() const; @@ -364,12 +365,14 @@ private slots: void takeLastOptimal() const; void takeLastMovable() const; void takeLastComplex() const; +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) void toSetOptimal() const; void toSetMovable() const; void toSetComplex() const; void toStdListOptimal() const; void toStdListMovable() const; void toStdListComplex() const; +#endif void toVectorOptimal() const; void toVectorMovable() const; void toVectorComplex() const; @@ -426,8 +429,10 @@ private: template<typename T> void takeAt() const; template<typename T> void takeFirst() const; template<typename T> void takeLast() const; +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) template<typename T> void toSet() const; template<typename T> void toStdList() const; +#endif template<typename T> void toVector() const; template<typename T> void value() const; @@ -860,6 +865,33 @@ void tst_QList::constLast() const QVERIFY(listCopy.isSharedWith(list)); } +void tst_QList::cpp17ctad() const +{ +#ifdef __cpp_deduction_guides +#define QVERIFY_IS_LIST_OF(obj, Type) \ + QVERIFY2((std::is_same<decltype(obj), QList<Type>>::value), \ + QMetaType::typeName(qMetaTypeId<decltype(obj)::value_type>())) +#define CHECK(Type, One, Two, Three) \ + do { \ + const Type v[] = {One, Two, Three}; \ + QList v1 = {One, Two, Three}; \ + QVERIFY_IS_LIST_OF(v1, Type); \ + QList v2(v1.begin(), v1.end()); \ + QVERIFY_IS_LIST_OF(v2, Type); \ + QList v3(std::begin(v), std::end(v)); \ + QVERIFY_IS_LIST_OF(v3, Type); \ + } while (false) \ + /*end*/ + CHECK(int, 1, 2, 3); + CHECK(double, 1.0, 2.0, 3.0); + CHECK(QString, QStringLiteral("one"), QStringLiteral("two"), QStringLiteral("three")); +#undef QVERIFY_IS_LIST_OF +#undef CHECK +#else + QSKIP("This test requires C++17 Constructor Template Argument Deduction support enabled in the compiler."); +#endif +} + template<typename T> void tst_QList::last() const { @@ -1457,11 +1489,11 @@ void tst_QList::swap() const list << T_FOO << T_BAR << T_BAZ; // swap - list.swap(0, 2); + list.swapItemsAt(0, 2); QCOMPARE(list, QList<T>() << T_BAZ << T_BAR << T_FOO); // swap again - list.swap(1, 2); + list.swapItemsAt(1, 2); QCOMPARE(list, QList<T>() << T_BAZ << T_FOO << T_BAR); QList<T> list2; @@ -1595,6 +1627,7 @@ void tst_QList::takeLastComplex() const QCOMPARE(liveCount, Complex::getLiveCount()); } +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) template<typename T> void tst_QList::toSet() const { @@ -1669,6 +1702,7 @@ void tst_QList::toStdListComplex() const toStdList<Complex>(); QCOMPARE(liveCount, Complex::getLiveCount()); } +#endif template<typename T> void tst_QList::toVector() const @@ -1871,7 +1905,6 @@ void tst_QList::testSTLIteratorsComplex() const void tst_QList::initializeList() const { -#ifdef Q_COMPILER_INITIALIZER_LISTS QList<int> v1{2,3,4}; QCOMPARE(v1, QList<int>() << 2 << 3 << 4); QCOMPARE(v1, (QList<int>{2,3,4})); @@ -1880,7 +1913,6 @@ void tst_QList::initializeList() const QList<QList<int>> v3; v3 << v1 << (QList<int>() << 1) << QList<int>() << v1; QCOMPARE(v3, v2); -#endif } template<typename T> diff --git a/tests/auto/corelib/tools/qlocale/BLACKLIST b/tests/auto/corelib/tools/qlocale/BLACKLIST deleted file mode 100644 index 3eac7c10ed..0000000000 --- a/tests/auto/corelib/tools/qlocale/BLACKLIST +++ /dev/null @@ -1,2 +0,0 @@ -[formatTimeZone] -osx diff --git a/tests/auto/corelib/tools/qmap/qmap.pro b/tests/auto/corelib/tools/qmap/qmap.pro index 27820a76c8..2cc772720d 100644 --- a/tests/auto/corelib/tools/qmap/qmap.pro +++ b/tests/auto/corelib/tools/qmap/qmap.pro @@ -2,3 +2,5 @@ CONFIG += testcase TARGET = tst_qmap QT = core testlib SOURCES = $$PWD/tst_qmap.cpp + +DEFINES -= QT_NO_JAVA_STYLE_ITERATORS diff --git a/tests/auto/corelib/tools/qmap/tst_qmap.cpp b/tests/auto/corelib/tools/qmap/tst_qmap.cpp index b39444e76f..d66fd28779 100644 --- a/tests/auto/corelib/tools/qmap/tst_qmap.cpp +++ b/tests/auto/corelib/tools/qmap/tst_qmap.cpp @@ -1319,7 +1319,6 @@ void tst_QMap::checkMostLeftNode() void tst_QMap::initializerList() { -#ifdef Q_COMPILER_INITIALIZER_LISTS QMap<int, QString> map = {{1, "bar"}, {1, "hello"}, {2, "initializer_list"}}; QCOMPARE(map.count(), 2); QCOMPARE(map[1], QString("hello")); @@ -1346,9 +1345,6 @@ void tst_QMap::initializerList() QMultiMap<float, float> emptyPairs2{{}, {}}; QVERIFY(!emptyPairs2.isEmpty()); -#else - QSKIP("Compiler doesn't support initializer lists"); -#endif } void tst_QMap::testInsertWithHint() diff --git a/tests/auto/corelib/tools/qpair/qpair.pro b/tests/auto/corelib/tools/qpair/qpair.pro index 659be887d3..d684a24a57 100644 --- a/tests/auto/corelib/tools/qpair/qpair.pro +++ b/tests/auto/corelib/tools/qpair/qpair.pro @@ -2,3 +2,6 @@ CONFIG += testcase TARGET = tst_qpair QT = core testlib SOURCES = tst_qpair.cpp + +# Force C++17 if available (needed due to Q_COMPILER_DEDUCTION_GUIDES) +contains(QT_CONFIG, c++1z): CONFIG += c++1z diff --git a/tests/auto/corelib/tools/qpair/tst_qpair.cpp b/tests/auto/corelib/tools/qpair/tst_qpair.cpp index dedc353e67..3c972329bc 100644 --- a/tests/auto/corelib/tools/qpair/tst_qpair.cpp +++ b/tests/auto/corelib/tools/qpair/tst_qpair.cpp @@ -39,6 +39,7 @@ private Q_SLOTS: void testConstexpr(); void testConversions(); void taskQTBUG_48780_pairContainingCArray(); + void testDeducationRules(); }; class C { C() {} char _[4]; }; @@ -202,5 +203,30 @@ void tst_QPair::taskQTBUG_48780_pairContainingCArray() Q_UNUSED(pair); } +void tst_QPair::testDeducationRules() +{ +#if defined(__cpp_deduction_guides) && __cpp_deduction_guides >= 201606 + QPair p1{1, 2}; + static_assert(std::is_same<decltype(p1)::first_type, decltype(1)>::value); + static_assert(std::is_same<decltype(p1)::second_type, decltype(2)>::value); + QCOMPARE(p1.first, 1); + QCOMPARE(p1.second, 2); + + QPair p2{QString("string"), 2}; + static_assert(std::is_same<decltype(p2)::first_type, QString>::value); + static_assert(std::is_same<decltype(p2)::second_type, decltype(2)>::value); + QCOMPARE(p2.first, "string"); + QCOMPARE(p2.second, 2); + + QPair p3(p2); + static_assert(std::is_same<decltype(p3)::first_type, decltype(p2)::first_type>::value); + static_assert(std::is_same<decltype(p3)::second_type, decltype(p2)::second_type>::value); + QCOMPARE(p3.first, "string"); + QCOMPARE(p3.second, 2); +#else + QSKIP("Unsupported"); +#endif +} + QTEST_APPLESS_MAIN(tst_QPair) #include "tst_qpair.moc" diff --git a/tests/auto/corelib/tools/qpoint/tst_qpoint.cpp b/tests/auto/corelib/tools/qpoint/tst_qpoint.cpp index 8e184f3ef3..f25492d2db 100644 --- a/tests/auto/corelib/tools/qpoint/tst_qpoint.cpp +++ b/tests/auto/corelib/tools/qpoint/tst_qpoint.cpp @@ -42,6 +42,8 @@ private slots: void getSet_data(); void getSet(); + void transposed(); + void rx(); void ry(); @@ -126,6 +128,11 @@ void tst_QPoint::getSet() QCOMPARE(point.y(), i); } +void tst_QPoint::transposed() +{ + QCOMPARE(QPoint(1, 2).transposed(), QPoint(2, 1)); +} + void tst_QPoint::rx() { const QPoint originalPoint(-1, 0); diff --git a/tests/auto/corelib/tools/qpointf/tst_qpointf.cpp b/tests/auto/corelib/tools/qpointf/tst_qpointf.cpp index d4ccdf7ba6..e78a8e3082 100644 --- a/tests/auto/corelib/tools/qpointf/tst_qpointf.cpp +++ b/tests/auto/corelib/tools/qpointf/tst_qpointf.cpp @@ -46,6 +46,8 @@ private slots: void getSet_data(); void getSet(); + void transposed(); + void rx(); void ry(); @@ -154,6 +156,11 @@ void tst_QPointF::getSet() QCOMPARE(point.y(), r); } +void tst_QPointF::transposed() +{ + QCOMPARE(QPointF(1, 2).transposed(), QPointF(2, 1)); +} + void tst_QPointF::rx() { const QPointF originalPoint(-1, 0); diff --git a/tests/auto/corelib/tools/qscopedpointer/tst_qscopedpointer.cpp b/tests/auto/corelib/tools/qscopedpointer/tst_qscopedpointer.cpp index b943b04e23..ea94cc2999 100644 --- a/tests/auto/corelib/tools/qscopedpointer/tst_qscopedpointer.cpp +++ b/tests/auto/corelib/tools/qscopedpointer/tst_qscopedpointer.cpp @@ -327,7 +327,7 @@ struct RefCounted ~RefCounted() { - QVERIFY( ref.load() == 0 ); + QVERIFY( ref.loadRelaxed() == 0 ); instanceCount.deref(); } @@ -369,13 +369,13 @@ void scopedPointerComparisonTest(const A1 &a1, const A2 &a2, const B &b) void tst_QScopedPointer::comparison() { - QCOMPARE( RefCounted::instanceCount.load(), 0 ); + QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 0 ); { RefCounted *a = new RefCounted; RefCounted *b = new RefCounted; - QCOMPARE( RefCounted::instanceCount.load(), 2 ); + QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 2 ); QScopedPointer<RefCounted> pa1(a); QScopedPointer<RefCounted> pa2(a); @@ -387,16 +387,16 @@ void tst_QScopedPointer::comparison() pa2.take(); - QCOMPARE( RefCounted::instanceCount.load(), 2 ); + QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 2 ); } - QCOMPARE( RefCounted::instanceCount.load(), 0 ); + QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 0 ); { RefCounted *a = new RefCounted[42]; RefCounted *b = new RefCounted[43]; - QCOMPARE( RefCounted::instanceCount.load(), 85 ); + QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 85 ); QScopedArrayPointer<RefCounted> pa1(a); QScopedArrayPointer<RefCounted> pa2(a); @@ -406,10 +406,10 @@ void tst_QScopedPointer::comparison() pa2.take(); - QCOMPARE( RefCounted::instanceCount.load(), 85 ); + QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 85 ); } - QCOMPARE( RefCounted::instanceCount.load(), 0 ); + QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 0 ); { // QScopedSharedPointer is an internal helper class -- it is unsupported! @@ -417,42 +417,42 @@ void tst_QScopedPointer::comparison() RefCounted *a = new RefCounted; RefCounted *b = new RefCounted; - QCOMPARE( RefCounted::instanceCount.load(), 2 ); + QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 2 ); QSharedDataPointer<RefCounted> pa1(a); QSharedDataPointer<RefCounted> pa2(a); QSharedDataPointer<RefCounted> pb(b); - QCOMPARE( a->ref.load(), 2 ); - QCOMPARE( b->ref.load(), 1 ); - QCOMPARE( RefCounted::instanceCount.load(), 2 ); + QCOMPARE( a->ref.loadRelaxed(), 2 ); + QCOMPARE( b->ref.loadRelaxed(), 1 ); + QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 2 ); scopedPointerComparisonTest(pa1, pa2, pb); - QCOMPARE( RefCounted::instanceCount.load(), 2 ); + QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 2 ); } - QCOMPARE( RefCounted::instanceCount.load(), 0 ); + QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 0 ); } void tst_QScopedPointer::array() { - int instCount = RefCounted::instanceCount.load(); + int instCount = RefCounted::instanceCount.loadRelaxed(); { QScopedArrayPointer<RefCounted> array; array.reset(new RefCounted[42]); - QCOMPARE(instCount + 42, RefCounted::instanceCount.load()); + QCOMPARE(instCount + 42, RefCounted::instanceCount.loadRelaxed()); } - QCOMPARE(instCount, RefCounted::instanceCount.load()); + QCOMPARE(instCount, RefCounted::instanceCount.loadRelaxed()); { QScopedArrayPointer<RefCounted> array(new RefCounted[42]); - QCOMPARE(instCount + 42, RefCounted::instanceCount.load()); + QCOMPARE(instCount + 42, RefCounted::instanceCount.loadRelaxed()); array.reset(new RefCounted[28]); - QCOMPARE(instCount + 28, RefCounted::instanceCount.load()); + QCOMPARE(instCount + 28, RefCounted::instanceCount.loadRelaxed()); array.reset(0); - QCOMPARE(instCount, RefCounted::instanceCount.load()); + QCOMPARE(instCount, RefCounted::instanceCount.loadRelaxed()); } - QCOMPARE(instCount, RefCounted::instanceCount.load()); + QCOMPARE(instCount, RefCounted::instanceCount.loadRelaxed()); } diff --git a/tests/auto/corelib/tools/qscopedvaluerollback/tst_qscopedvaluerollback.cpp b/tests/auto/corelib/tools/qscopedvaluerollback/tst_qscopedvaluerollback.cpp index 656dd6a6e3..9b607db608 100644 --- a/tests/auto/corelib/tools/qscopedvaluerollback/tst_qscopedvaluerollback.cpp +++ b/tests/auto/corelib/tools/qscopedvaluerollback/tst_qscopedvaluerollback.cpp @@ -46,6 +46,7 @@ private Q_SLOTS: void rollbackToPreviousCommit(); void exceptions(); void earlyExitScope(); + void moveOnly(); private: void earlyExitScope_helper(int exitpoint, int &member); }; @@ -190,5 +191,17 @@ void tst_QScopedValueRollback::earlyExitScope_helper(int exitpoint, int& member) r.commit(); } +void tst_QScopedValueRollback::moveOnly() +{ + std::unique_ptr<int> uniquePtr; + std::unique_ptr<int> newVal(new int(5)); + QVERIFY(!uniquePtr); + { + QScopedValueRollback<std::unique_ptr<int>> r(uniquePtr, std::move(newVal)); + QVERIFY(uniquePtr); + } + QVERIFY(!uniquePtr); +} + QTEST_MAIN(tst_QScopedValueRollback) #include "tst_qscopedvaluerollback.moc" diff --git a/tests/auto/corelib/tools/qset/qset.pro b/tests/auto/corelib/tools/qset/qset.pro index 10ae3307d1..3ae4bc4805 100644 --- a/tests/auto/corelib/tools/qset/qset.pro +++ b/tests/auto/corelib/tools/qset/qset.pro @@ -1,4 +1,8 @@ CONFIG += testcase TARGET = tst_qset QT = core testlib +qtConfig(c++14): CONFIG += c++14 +qtConfig(c++1z): CONFIG += c++1z SOURCES = tst_qset.cpp + +DEFINES -= QT_NO_JAVA_STYLE_ITERATORS diff --git a/tests/auto/corelib/tools/qset/tst_qset.cpp b/tests/auto/corelib/tools/qset/tst_qset.cpp index 0b60350380..8a545712a2 100644 --- a/tests/auto/corelib/tools/qset/tst_qset.cpp +++ b/tests/auto/corelib/tools/qset/tst_qset.cpp @@ -54,6 +54,7 @@ private slots: void detach(); void isDetached(); void clear(); + void cpp17ctad(); void remove(); void contains(); void containsSet(); @@ -325,6 +326,33 @@ void tst_QSet::clear() QVERIFY(set2.size() == 0); } +void tst_QSet::cpp17ctad() +{ +#ifdef __cpp_deduction_guides +#define QVERIFY_IS_SET_OF(obj, Type) \ + QVERIFY2((std::is_same<decltype(obj), QSet<Type>>::value), \ + QMetaType::typeName(qMetaTypeId<decltype(obj)::value_type>())) +#define CHECK(Type, One, Two, Three) \ + do { \ + const Type v[] = {One, Two, Three}; \ + QSet v1 = {One, Two, Three}; \ + QVERIFY_IS_SET_OF(v1, Type); \ + QSet v2(v1.begin(), v1.end()); \ + QVERIFY_IS_SET_OF(v2, Type); \ + QSet v3(std::begin(v), std::end(v)); \ + QVERIFY_IS_SET_OF(v3, Type); \ + } while (false) \ + /*end*/ + CHECK(int, 1, 2, 3); + CHECK(double, 1.0, 2.0, 3.0); + CHECK(QString, QStringLiteral("one"), QStringLiteral("two"), QStringLiteral("three")); +#undef QVERIFY_IS_SET_OF +#undef CHECK +#else + QSKIP("This test requires C++17 Constructor Template Argument Deduction support enabled in the compiler."); +#endif +} + void tst_QSet::remove() { QSet<QString> set1; @@ -955,7 +983,6 @@ void tst_QSet::makeSureTheComfortFunctionsCompile() void tst_QSet::initializerList() { -#ifdef Q_COMPILER_INITIALIZER_LISTS QSet<int> set = {1, 1, 2, 3, 4, 5}; QCOMPARE(set.count(), 5); QVERIFY(set.contains(1)); @@ -976,9 +1003,6 @@ void tst_QSet::initializerList() QSet<int> set3{{}, {}, {}}; QVERIFY(!set3.isEmpty()); -#else - QSKIP("Compiler doesn't support initializer lists"); -#endif } void tst_QSet::qhash() @@ -1011,15 +1035,7 @@ void tst_QSet::qhash() // check that sets of sets work: // { -#ifdef Q_COMPILER_INITIALIZER_LISTS QSet<QSet<int> > intSetSet = { { 0, 1, 2 }, { 0, 1 }, { 1, 2 } }; -#else - QSet<QSet<int> > intSetSet; - QSet<int> intSet01, intSet12; - intSet01 << 0 << 1; - intSet12 << 1 << 2; - intSetSet << intSet01 << intSet12 << (intSet01|intSet12); -#endif QCOMPARE(intSetSet.size(), 3); } } diff --git a/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp b/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp index 0fe24ed5cb..a9fd282ac9 100644 --- a/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp +++ b/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp @@ -76,10 +76,13 @@ private slots: void functionCallDownCast(); void upCast(); void qobjectWeakManagement(); +#if QT_DEPRECATED_SINCE(5, 0) void noSharedPointerFromWeakQObject(); void sharedPointerFromQObjectWithWeak(); +#endif void weakQObjectFromSharedPointer(); void objectCast(); + void objectCastStdSharedPtr(); void differentPointers(); void virtualBaseDifferentPointers(); #ifndef QTEST_NO_RTTI @@ -91,9 +94,7 @@ private slots: #endif void constCorrectness(); void customDeleter(); -#ifdef Q_COMPILER_LAMBDA void lambdaCustomDeleter(); -#endif void creating(); void creatingCvQualified(); void creatingVariadic(); @@ -231,7 +232,6 @@ struct NoDefaultConstructorConstRef2 NoDefaultConstructorConstRef2(const QByteArray &ba, int i = 42) : str(QString::fromLatin1(ba)), i(i) {} }; -#ifdef Q_COMPILER_RVALUE_REFS struct NoDefaultConstructorRRef1 { int &i; @@ -243,7 +243,6 @@ struct NoDefaultConstructorRRef2 std::unique_ptr<int> i; NoDefaultConstructorRRef2(std::unique_ptr<int> &&i) : i(std::move(i)) {} }; -#endif void tst_QSharedPointer::basics_data() { @@ -301,8 +300,8 @@ void tst_QSharedPointer::basics() QVERIFY(! (ptr == otherData)); QVERIFY(! (otherData == ptr)); } - QVERIFY(!refCountData(ptr) || refCountData(ptr)->weakref.load() == 1); - QVERIFY(!refCountData(ptr) || refCountData(ptr)->strongref.load() == 1); + QVERIFY(!refCountData(ptr) || refCountData(ptr)->weakref.loadRelaxed() == 1); + QVERIFY(!refCountData(ptr) || refCountData(ptr)->strongref.loadRelaxed() == 1); { // create another object: @@ -314,8 +313,8 @@ void tst_QSharedPointer::basics() // otherData is deleted here } - QVERIFY(!refCountData(ptr) || refCountData(ptr)->weakref.load() == 1); - QVERIFY(!refCountData(ptr) || refCountData(ptr)->strongref.load() == 1); + QVERIFY(!refCountData(ptr) || refCountData(ptr)->weakref.loadRelaxed() == 1); + QVERIFY(!refCountData(ptr) || refCountData(ptr)->strongref.loadRelaxed() == 1); { // create a copy: @@ -332,8 +331,8 @@ void tst_QSharedPointer::basics() QCOMPARE(copy.get(), aData); QVERIFY(copy == aData); } - QVERIFY(!refCountData(ptr) || refCountData(ptr)->weakref.load() == 1); - QVERIFY(!refCountData(ptr) || refCountData(ptr)->strongref.load() == 1); + QVERIFY(!refCountData(ptr) || refCountData(ptr)->weakref.loadRelaxed() == 1); + QVERIFY(!refCountData(ptr) || refCountData(ptr)->strongref.loadRelaxed() == 1); { // create a weak reference: @@ -365,8 +364,8 @@ void tst_QSharedPointer::basics() QCOMPARE(strong.data(), aData); QCOMPARE(strong.get(), aData); } - QVERIFY(!refCountData(ptr) || refCountData(ptr)->weakref.load() == 1); - QVERIFY(!refCountData(ptr) || refCountData(ptr)->strongref.load() == 1); + QVERIFY(!refCountData(ptr) || refCountData(ptr)->weakref.loadRelaxed() == 1); + QVERIFY(!refCountData(ptr) || refCountData(ptr)->strongref.loadRelaxed() == 1); // aData is deleted here } @@ -512,7 +511,6 @@ void tst_QSharedPointer::swap() void tst_QSharedPointer::moveSemantics() { -#ifdef Q_COMPILER_RVALUE_REFS QSharedPointer<int> p1, p2(new int(42)), control = p2; QVERIFY(p1 != control); QVERIFY(p1.isNull()); @@ -565,9 +563,6 @@ void tst_QSharedPointer::moveSemantics() QVERIFY(w1.isNull()); QVERIFY(w2.isNull()); QVERIFY(w3.isNull()); -#else - QSKIP("This test requires C++11 rvalue/move semantics support in the compiler."); -#endif } void tst_QSharedPointer::useOfForwardDeclared() @@ -584,10 +579,10 @@ void tst_QSharedPointer::useOfForwardDeclared() // move assignment: QSharedPointer<ForwardDeclared> sp4; - sp4 = qMove(sp); + sp4 = std::move(sp); // and move constuction: - QSharedPointer<ForwardDeclared> sp5 = qMove(sp2); + QSharedPointer<ForwardDeclared> sp5 = std::move(sp2); // swapping: sp4.swap(sp3); @@ -854,15 +849,15 @@ void tst_QSharedPointer::upCast() QVERIFY(baseptr == derivedptr); QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data()); } - QCOMPARE(int(refCountData(baseptr)->weakref.load()), 1); - QCOMPARE(int(refCountData(baseptr)->strongref.load()), 1); + QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1); + QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1); { QWeakPointer<DerivedData> derivedptr = qWeakPointerCast<DerivedData>(baseptr); QVERIFY(baseptr == derivedptr); } - QCOMPARE(int(refCountData(baseptr)->weakref.load()), 1); - QCOMPARE(int(refCountData(baseptr)->strongref.load()), 1); + QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1); + QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1); { QWeakPointer<Data> weakptr = baseptr; @@ -870,16 +865,16 @@ void tst_QSharedPointer::upCast() QVERIFY(baseptr == derivedptr); QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data()); } - QCOMPARE(int(refCountData(baseptr)->weakref.load()), 1); - QCOMPARE(int(refCountData(baseptr)->strongref.load()), 1); + QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1); + QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1); { QSharedPointer<DerivedData> derivedptr = baseptr.staticCast<DerivedData>(); QVERIFY(baseptr == derivedptr); QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data()); } - QCOMPARE(int(refCountData(baseptr)->weakref.load()), 1); - QCOMPARE(int(refCountData(baseptr)->strongref.load()), 1); + QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1); + QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1); } class OtherObject: public QObject @@ -893,6 +888,78 @@ void tst_QSharedPointer::qobjectWeakManagement() QWeakPointer<QObject> weak; weak = QWeakPointer<QObject>(); QVERIFY(weak.isNull()); + QVERIFY(weak.toStrongRef().isNull()); + } + + { + QObject *obj = new QObject; + QSharedPointer<QObject> shared(obj); + QWeakPointer<QObject> weak(shared); + QVERIFY(!weak.isNull()); + QVERIFY(weak.toStrongRef() == obj); + + // now delete + shared.reset(); + QVERIFY(weak.isNull()); + } + safetyCheck(); + + { + // same, bit with operator= + QObject *obj = new QObject; + QSharedPointer<QObject> shared(obj); + QWeakPointer<QObject> weak; + weak = shared; + QVERIFY(!weak.isNull()); + QVERIFY(weak.toStrongRef() == obj); + + // now delete + shared.reset(); + QVERIFY(weak.isNull()); + } + safetyCheck(); + + { + // with two QWeakPointers + QObject *obj = new QObject; + QSharedPointer<QObject> shared(obj); + QWeakPointer<QObject> weak(shared); + + { + QWeakPointer<QObject> weak2(shared); + QVERIFY(!weak2.isNull()); + QVERIFY(weak == weak2); + } + QVERIFY(!weak.isNull()); + + shared.reset(); + QVERIFY(weak.isNull()); + } + safetyCheck(); + + { + // same, but delete the pointer while two QWeakPointers exist + QObject *obj = new QObject; + QSharedPointer<QObject> shared(obj); + QWeakPointer<QObject> weak(shared); + + { + QWeakPointer<QObject> weak2(shared); + QVERIFY(!weak2.isNull()); + + shared.reset(); + QVERIFY(weak.isNull()); + QVERIFY(weak2.isNull()); + } + QVERIFY(weak.isNull()); + } + safetyCheck(); + +#if QT_DEPRECATED_SINCE(5, 0) + { + QWeakPointer<QObject> weak; + weak = QWeakPointer<QObject>(); + QVERIFY(weak.isNull()); QVERIFY(!weak.data()); } @@ -983,8 +1050,10 @@ void tst_QSharedPointer::qobjectWeakManagement() QVERIFY(weak.isNull()); } safetyCheck(); +#endif } +#if QT_DEPRECATED_SINCE(5, 0) void tst_QSharedPointer::noSharedPointerFromWeakQObject() { // you're not allowed to create a QSharedPointer from an unmanaged QObject @@ -1018,18 +1087,32 @@ void tst_QSharedPointer::sharedPointerFromQObjectWithWeak() } QVERIFY(weak.isNull()); } +#endif void tst_QSharedPointer::weakQObjectFromSharedPointer() { - // this is the inverse of the above: you're allowed to create a QWeakPointer - // from a managed QObject - QSharedPointer<QObject> shared(new QObject); - QWeakPointer<QObject> weak = shared.data(); - QVERIFY(!weak.isNull()); +#if QT_DEPRECATED_SINCE(5, 0) + { + // this is the inverse of the above: you're allowed to create a QWeakPointer + // from a managed QObject + QSharedPointer<QObject> shared(new QObject); + QWeakPointer<QObject> weak = shared.data(); + QVERIFY(!weak.isNull()); - // delete: - shared.clear(); - QVERIFY(weak.isNull()); + // delete: + shared.clear(); + QVERIFY(weak.isNull()); + } +#endif + { + QSharedPointer<QObject> shared(new QObject); + QWeakPointer<QObject> weak = shared; + QVERIFY(!weak.isNull()); + + // delete: + shared.clear(); + QVERIFY(weak.isNull()); + } } void tst_QSharedPointer::objectCast() @@ -1126,6 +1209,60 @@ void tst_QSharedPointer::objectCast() safetyCheck(); } + +void tst_QSharedPointer::objectCastStdSharedPtr() +{ + { + OtherObject *data = new OtherObject; + std::shared_ptr<QObject> baseptr = std::shared_ptr<QObject>(data); + QVERIFY(baseptr.get() == data); + + // perform successful object cast + std::shared_ptr<OtherObject> ptr = qobject_pointer_cast<OtherObject>(baseptr); + QVERIFY(ptr.get()); + QVERIFY(ptr.get() == data); + + QVERIFY(baseptr.get() == data); + } + + { + OtherObject *data = new OtherObject; + std::shared_ptr<QObject> baseptr = std::shared_ptr<QObject>(data); + QVERIFY(baseptr.get() == data); + + // perform successful object cast + std::shared_ptr<OtherObject> ptr = qobject_pointer_cast<OtherObject>(std::move(baseptr)); + QVERIFY(ptr.get()); + QVERIFY(ptr.get() == data); + + QVERIFY(!baseptr.get()); + } + + { + QObject *data = new QObject; + std::shared_ptr<QObject> baseptr = std::shared_ptr<QObject>(data); + QVERIFY(baseptr.get() == data); + + // perform unsuccessful object cast + std::shared_ptr<OtherObject> ptr = qobject_pointer_cast<OtherObject>(baseptr); + QVERIFY(!ptr.get()); + + QVERIFY(baseptr.get() == data); + } + + { + QObject *data = new QObject; + std::shared_ptr<QObject> baseptr = std::shared_ptr<QObject>(data); + QVERIFY(baseptr.get() == data); + + // perform unsuccessful object cast + std::shared_ptr<OtherObject> ptr = qobject_pointer_cast<OtherObject>(std::move(baseptr)); + QVERIFY(!ptr.get()); + + QVERIFY(baseptr.get() == data); + } +} + void tst_QSharedPointer::differentPointers() { { @@ -1254,8 +1391,8 @@ void tst_QSharedPointer::dynamicCast() QCOMPARE(derivedptr.data(), aData); QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data()); } - QCOMPARE(int(refCountData(baseptr)->weakref.load()), 1); - QCOMPARE(int(refCountData(baseptr)->strongref.load()), 1); + QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1); + QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1); { QWeakPointer<Data> weakptr = baseptr; @@ -1264,8 +1401,8 @@ void tst_QSharedPointer::dynamicCast() QCOMPARE(derivedptr.data(), aData); QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data()); } - QCOMPARE(int(refCountData(baseptr)->weakref.load()), 1); - QCOMPARE(int(refCountData(baseptr)->strongref.load()), 1); + QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1); + QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1); { QSharedPointer<DerivedData> derivedptr = baseptr.dynamicCast<DerivedData>(); @@ -1273,8 +1410,8 @@ void tst_QSharedPointer::dynamicCast() QCOMPARE(derivedptr.data(), aData); QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data()); } - QCOMPARE(int(refCountData(baseptr)->weakref.load()), 1); - QCOMPARE(int(refCountData(baseptr)->strongref.load()), 1); + QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1); + QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1); } void tst_QSharedPointer::dynamicCastDifferentPointers() @@ -1289,8 +1426,8 @@ void tst_QSharedPointer::dynamicCastDifferentPointers() QCOMPARE(derivedptr.data(), aData); QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data()); } - QCOMPARE(int(refCountData(baseptr)->weakref.load()), 1); - QCOMPARE(int(refCountData(baseptr)->strongref.load()), 1); + QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1); + QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1); { QWeakPointer<Data> weakptr = baseptr; @@ -1299,8 +1436,8 @@ void tst_QSharedPointer::dynamicCastDifferentPointers() QCOMPARE(derivedptr.data(), aData); QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data()); } - QCOMPARE(int(refCountData(baseptr)->weakref.load()), 1); - QCOMPARE(int(refCountData(baseptr)->strongref.load()), 1); + QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1); + QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1); { QSharedPointer<DiffPtrDerivedData> derivedptr = baseptr.dynamicCast<DiffPtrDerivedData>(); @@ -1308,8 +1445,8 @@ void tst_QSharedPointer::dynamicCastDifferentPointers() QCOMPARE(derivedptr.data(), aData); QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data()); } - QCOMPARE(int(refCountData(baseptr)->weakref.load()), 1); - QCOMPARE(int(refCountData(baseptr)->strongref.load()), 1); + QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1); + QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1); { Stuffing *nakedptr = dynamic_cast<Stuffing *>(baseptr.data()); @@ -1334,8 +1471,8 @@ void tst_QSharedPointer::dynamicCastVirtualBase() QCOMPARE(derivedptr.data(), aData); QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data()); } - QCOMPARE(int(refCountData(baseptr)->weakref.load()), 1); - QCOMPARE(int(refCountData(baseptr)->strongref.load()), 1); + QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1); + QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1); { QWeakPointer<Data> weakptr = baseptr; @@ -1344,8 +1481,8 @@ void tst_QSharedPointer::dynamicCastVirtualBase() QCOMPARE(derivedptr.data(), aData); QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data()); } - QCOMPARE(int(refCountData(baseptr)->weakref.load()), 1); - QCOMPARE(int(refCountData(baseptr)->strongref.load()), 1); + QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1); + QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1); { QSharedPointer<VirtualDerived> derivedptr = baseptr.dynamicCast<VirtualDerived>(); @@ -1353,8 +1490,8 @@ void tst_QSharedPointer::dynamicCastVirtualBase() QCOMPARE(derivedptr.data(), aData); QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data()); } - QCOMPARE(int(refCountData(baseptr)->weakref.load()), 1); - QCOMPARE(int(refCountData(baseptr)->strongref.load()), 1); + QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1); + QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1); } void tst_QSharedPointer::dynamicCastFailure() @@ -1366,15 +1503,15 @@ void tst_QSharedPointer::dynamicCastFailure() QSharedPointer<DerivedData> derivedptr = qSharedPointerDynamicCast<DerivedData>(baseptr); QVERIFY(derivedptr.isNull()); } - QCOMPARE(int(refCountData(baseptr)->weakref.load()), 1); - QCOMPARE(int(refCountData(baseptr)->strongref.load()), 1); + QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1); + QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1); { QSharedPointer<DerivedData> derivedptr = baseptr.dynamicCast<DerivedData>(); QVERIFY(derivedptr.isNull()); } - QCOMPARE(int(refCountData(baseptr)->weakref.load()), 1); - QCOMPARE(int(refCountData(baseptr)->strongref.load()), 1); + QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1); + QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1); } void tst_QSharedPointer::dynamicCastFailureNoLeak() @@ -1681,7 +1818,6 @@ void tst_QSharedPointer::customDeleter() safetyCheck(); } -#ifdef Q_COMPILER_LAMBDA // The compiler needs to be in C++11 mode and to support lambdas void tst_QSharedPointer::lambdaCustomDeleter() { @@ -1709,7 +1845,6 @@ void tst_QSharedPointer::lambdaCustomDeleter() } safetyCheck(); } -#endif void customQObjectDeleterFn(QObject *obj) { @@ -1745,8 +1880,8 @@ void tst_QSharedPointer::creating() QCOMPARE(Data::destructorCounter, 1); // valgrind will complain here if something happened to the pointer - QVERIFY(d->weakref.load() == 1); - QVERIFY(d->strongref.load() == 0); + QVERIFY(d->weakref.loadRelaxed() == 1); + QVERIFY(d->strongref.loadRelaxed() == 0); } safetyCheck(); @@ -1981,7 +2116,7 @@ void tst_QSharedPointer::threadStressTest() for (int r = 0; r < 5; ++r) { QVector<QThread*> allThreads(6 * qMax(strongThreadCount, weakThreadCount) + 3, 0); QSharedPointer<ThreadData> base = QSharedPointer<ThreadData>(new ThreadData(&counter)); - counter.store(0); + counter.storeRelaxed(0); // set the pointers for (int i = 0; i < strongThreadCount; ++i) { @@ -2015,8 +2150,8 @@ void tst_QSharedPointer::threadStressTest() // verify that the count is the right range int minValue = strongThreadCount; int maxValue = strongThreadCount + weakThreadCount; - QVERIFY(counter.load() >= minValue); - QVERIFY(counter.load() <= maxValue); + QVERIFY(counter.loadRelaxed() >= minValue); + QVERIFY(counter.loadRelaxed() <= maxValue); } } @@ -2249,11 +2384,9 @@ void tst_QSharedPointer::invalidConstructs_data() << &QTest::QExternalTest::tryCompileFail << "struct IncompatibleCustomDeleter { void operator()(int *); };\n" "QSharedPointer<Data> ptr(new Data, IncompatibleCustomDeleter());\n"; -#ifdef Q_COMPILER_LAMBDA QTest::newRow("incompatible-custom-lambda-deleter") << &QTest::QExternalTest::tryCompileFail << "QSharedPointer<Data> ptr(new Data, [](int *) {});\n"; -#endif QTest::newRow("incompatible-overload") << &QTest::QExternalTest::tryCompileFail @@ -2342,6 +2475,7 @@ void tst_QSharedPointer::qvariantCast() // Intentionally does not compile. // QSharedPointer<int> sop = qSharedPointerFromVariant<int>(v); +#if QT_DEPRECATED_SINCE(5, 0) v = QVariant::fromValue(sp.toWeakRef()); { @@ -2385,6 +2519,7 @@ void tst_QSharedPointer::qvariantCast() QWeakPointer<QThread> other = qWeakPointerFromVariant<QThread>(v); QVERIFY(!other); } +#endif } class SomeClass : public QEnableSharedFromThis<SomeClass> diff --git a/tests/auto/corelib/tools/qsize/tst_qsize.cpp b/tests/auto/corelib/tools/qsize/tst_qsize.cpp index 385ff18ce5..6824bad9c8 100644 --- a/tests/auto/corelib/tools/qsize/tst_qsize.cpp +++ b/tests/auto/corelib/tools/qsize/tst_qsize.cpp @@ -29,6 +29,7 @@ #include <QtTest/QtTest> #include <qsize.h> +Q_DECLARE_METATYPE(QMargins) class tst_QSize : public QObject { @@ -43,6 +44,9 @@ private slots: void boundedTo_data(); void boundedTo(); + void grownOrShrunkBy_data(); + void grownOrShrunkBy(); + void transpose_data(); void transpose(); }; @@ -186,6 +190,46 @@ void tst_QSize::boundedTo() QCOMPARE( input1.boundedTo(input2), expected); } +void tst_QSize::grownOrShrunkBy_data() +{ + QTest::addColumn<QSize>("input"); + QTest::addColumn<QMargins>("margins"); + QTest::addColumn<QSize>("grown"); + QTest::addColumn<QSize>("shrunk"); + + auto row = [](QSize i, QMargins m, QSize g, QSize s) { + QTest::addRow("{%d,%d}/{%d,%d,%d,%d}", i.width(), i.height(), + m.left(), m.top(), m.right(), m.bottom()) + << i << m << g << s; + }; + + const QSize zero = {0, 0}; + const QSize some = {100, 200}; + const QMargins zeroMargins = {}; + const QMargins negative = {-1, -2, -3, -4}; + const QMargins positive = { 1, 2, 3, 4}; + + row(zero, zeroMargins, zero, zero); + row(zero, negative, {-4, -6}, { 4, 6}); + row(zero, positive, { 4, 6}, {-4, -6}); + row(some, zeroMargins, some, some); + row(some, negative, { 96, 194}, {104, 206}); + row(some, positive, {104, 206}, { 96, 194}); +} + +void tst_QSize::grownOrShrunkBy() +{ + QFETCH(const QSize, input); + QFETCH(const QMargins, margins); + QFETCH(const QSize, grown); + QFETCH(const QSize, shrunk); + + QCOMPARE(input.grownBy(margins), grown); + QCOMPARE(input.shrunkBy(margins), shrunk); + QCOMPARE(grown.shrunkBy(margins), input); + QCOMPARE(shrunk.grownBy(margins), input); +} + void tst_QSize::transpose_data() { QTest::addColumn<QSize>("input1"); diff --git a/tests/auto/corelib/tools/qsizef/tst_qsizef.cpp b/tests/auto/corelib/tools/qsizef/tst_qsizef.cpp index 42801d63a9..bbffa74a62 100644 --- a/tests/auto/corelib/tools/qsizef/tst_qsizef.cpp +++ b/tests/auto/corelib/tools/qsizef/tst_qsizef.cpp @@ -29,6 +29,7 @@ #include <QtTest/QtTest> #include <qsize.h> +Q_DECLARE_METATYPE(QMarginsF) class tst_QSizeF : public QObject { @@ -45,6 +46,9 @@ private slots: void boundedTo_data(); void boundedTo(); + void grownOrShrunkBy_data(); + void grownOrShrunkBy(); + void transpose_data(); void transpose(); }; @@ -152,6 +156,46 @@ void tst_QSizeF::boundedTo() { QCOMPARE( input1.boundedTo(input2), expected); } +void tst_QSizeF::grownOrShrunkBy_data() +{ + QTest::addColumn<QSizeF>("input"); + QTest::addColumn<QMarginsF>("margins"); + QTest::addColumn<QSizeF>("grown"); + QTest::addColumn<QSizeF>("shrunk"); + + auto row = [](QSizeF i, QMarginsF m, QSizeF g, QSizeF s) { + QTest::addRow("{%g,%g}/{%g,%g,%g,%g}", i.width(), i.height(), + m.left(), m.top(), m.right(), m.bottom()) + << i << m << g << s; + }; + + const QSizeF zero = {0, 0}; + const QSizeF some = {100, 200}; + const QMarginsF zeroMargins = {}; + const QMarginsF negative = {-1, -2, -3, -4}; + const QMarginsF positive = { 1, 2, 3, 4}; + + row(zero, zeroMargins, zero, zero); + row(zero, negative, {-4, -6}, { 4, 6}); + row(zero, positive, { 4, 6}, {-4, -6}); + row(some, zeroMargins, some, some); + row(some, negative, { 96, 194}, {104, 206}); + row(some, positive, {104, 206}, { 96, 194}); +} + +void tst_QSizeF::grownOrShrunkBy() +{ + QFETCH(const QSizeF, input); + QFETCH(const QMarginsF, margins); + QFETCH(const QSizeF, grown); + QFETCH(const QSizeF, shrunk); + + QCOMPARE(input.grownBy(margins), grown); + QCOMPARE(input.shrunkBy(margins), shrunk); + QCOMPARE(grown.shrunkBy(margins), input); + QCOMPARE(shrunk.grownBy(margins), input); +} + void tst_QSizeF::transpose_data() { QTest::addColumn<QSizeF>("input1"); QTest::addColumn<QSizeF>("expected"); diff --git a/tests/auto/corelib/tools/qtimeline/BLACKLIST b/tests/auto/corelib/tools/qtimeline/BLACKLIST index 5611969b4d..9794b0059f 100644 --- a/tests/auto/corelib/tools/qtimeline/BLACKLIST +++ b/tests/auto/corelib/tools/qtimeline/BLACKLIST @@ -1,9 +1,7 @@ [interpolation] -windows -osx-10.12 -osx-10.13 -[duration] -windows +windows-10 msvc-2015 +osx [frameRate] osx-10.12 osx-10.13 + diff --git a/tests/auto/corelib/tools/qvarlengtharray/qvarlengtharray.pro b/tests/auto/corelib/tools/qvarlengtharray/qvarlengtharray.pro index 108fb33db5..14b2bc213b 100644 --- a/tests/auto/corelib/tools/qvarlengtharray/qvarlengtharray.pro +++ b/tests/auto/corelib/tools/qvarlengtharray/qvarlengtharray.pro @@ -1,4 +1,6 @@ CONFIG += testcase TARGET = tst_qvarlengtharray QT = core testlib +qtConfig(c++14): CONFIG += c++14 +qtConfig(c++1z): CONFIG += c++1z SOURCES = tst_qvarlengtharray.cpp diff --git a/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp b/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp index 5737db760c..a1d0100f96 100644 --- a/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp +++ b/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp @@ -44,6 +44,7 @@ private slots: void realloc(); void reverseIterators(); void count(); + void cpp17ctad(); void first(); void last(); void squeeze(); @@ -57,27 +58,28 @@ private slots: void initializeListComplex(); void insertMove(); void nonCopyable(); + void implicitDefaultCtor(); private: template<typename T> void initializeList(); }; -int fooCtor = 0; -int fooDtor = 0; - -struct Foo +struct Tracker { - int *p; - - Foo() { p = new int; ++fooCtor; } - Foo(const Foo &/*other*/) { p = new int; ++fooCtor; } + static int count; + Tracker() { ++count; } + Tracker(const Tracker &) { ++count; } + Tracker(Tracker &&) { ++count; } - void operator=(const Foo & /* other */) { } + Tracker &operator=(const Tracker &) = default; + Tracker &operator=(Tracker &&) = default; - ~Foo() { delete p; ++fooDtor; } + ~Tracker() { --count; } }; +int Tracker::count = 0; + void tst_QVarLengthArray::append() { QVarLengthArray<QString, 2> v; @@ -129,6 +131,23 @@ void tst_QVarLengthArray::removeLast() v.removeLast(); QCOMPARE(v.size(), 2); } + + { + Tracker t; + QCOMPARE(Tracker::count, 1); + QVarLengthArray<Tracker, 2> v; + v.append(t); + v.append({}); + QCOMPARE(Tracker::count, 3); + v.removeLast(); + QCOMPARE(Tracker::count, 2); + v.append(t); + v.append({}); + QCOMPARE(Tracker::count, 4); + v.removeLast(); + QCOMPARE(Tracker::count, 3); + } + QCOMPARE(Tracker::count, 0); } void tst_QVarLengthArray::oldTests() @@ -699,6 +718,34 @@ void tst_QVarLengthArray::count() } } +void tst_QVarLengthArray::cpp17ctad() +{ +#ifdef __cpp_deduction_guides +#define QVERIFY_IS_VLA_OF(obj, Type) \ + QVERIFY2((std::is_same<decltype(obj), QVarLengthArray<Type>>::value), \ + QMetaType::typeName(qMetaTypeId<decltype(obj)::value_type>())) +#define CHECK(Type, One, Two, Three) \ + do { \ + const Type v[] = {One, Two, Three}; \ + QVarLengthArray v1 = {One, Two, Three}; \ + QVERIFY_IS_VLA_OF(v1, Type); \ + QVarLengthArray v2(v1.begin(), v1.end()); \ + QVERIFY_IS_VLA_OF(v2, Type); \ + QVarLengthArray v3(std::begin(v), std::end(v)); \ + QVERIFY_IS_VLA_OF(v3, Type); \ + } while (false) \ + /*end*/ + CHECK(int, 1, 2, 3); + CHECK(double, 1.0, 2.0, 3.0); + CHECK(QString, QStringLiteral("one"), QStringLiteral("two"), QStringLiteral("three")); +#undef QVERIFY_IS_VLA_OF +#undef CHECK +#else + QSKIP("This test requires C++17 Constructor Template Argument Deduction support enabled in the compiler."); +#endif + +} + void tst_QVarLengthArray::first() { // append some items, make sure it stays sane @@ -908,7 +955,6 @@ void tst_QVarLengthArray::initializeListComplex() template<typename T> void tst_QVarLengthArray::initializeList() { -#ifdef Q_COMPILER_INITIALIZER_LISTS T val1(110); T val2(105); T val3(101); @@ -945,9 +991,6 @@ void tst_QVarLengthArray::initializeList() v6 = {}; // assign empty QCOMPARE(v6.size(), 0); -#else - QSKIP("This tests requires a compiler that supports initializer lists."); -#endif } void tst_QVarLengthArray::insertMove() @@ -1082,5 +1125,11 @@ void tst_QVarLengthArray::nonCopyable() QVERIFY(ptr6 == vec.at(5).get()); } +void tst_QVarLengthArray::implicitDefaultCtor() +{ + QVarLengthArray<int> def = {}; + QCOMPARE(def.size(), 0); +} + QTEST_APPLESS_MAIN(tst_QVarLengthArray) #include "tst_qvarlengtharray.moc" diff --git a/tests/auto/corelib/tools/qvector/qvector.pro b/tests/auto/corelib/tools/qvector/qvector.pro index b9a4ae747b..689d9b87a2 100644 --- a/tests/auto/corelib/tools/qvector/qvector.pro +++ b/tests/auto/corelib/tools/qvector/qvector.pro @@ -1,5 +1,7 @@ CONFIG += testcase qtConfig(c++11): CONFIG += c++11 +qtConfig(c++14): CONFIG += c++14 +qtConfig(c++1z): CONFIG += c++1z TARGET = tst_qvector QT = core testlib SOURCES = $$PWD/tst_qvector.cpp diff --git a/tests/auto/corelib/tools/qvector/tst_qvector.cpp b/tests/auto/corelib/tools/qvector/tst_qvector.cpp index 383318979d..08d5a8cd50 100644 --- a/tests/auto/corelib/tools/qvector/tst_qvector.cpp +++ b/tests/auto/corelib/tools/qvector/tst_qvector.cpp @@ -206,6 +206,9 @@ private slots: void assignmentInt() const; void assignmentMovable() const; void assignmentCustom() const; + void assignFromInitializerListInt() const; + void assignFromInitializerListMovable() const; + void assignFromInitializerListCustom() const; void addInt() const; void addMovable() const; void addCustom() const; @@ -227,6 +230,7 @@ private slots: void countInt() const; void countMovable() const; void countCustom() const; + void cpp17ctad() const; void data() const; void emptyInt() const; void emptyMovable() const; @@ -255,7 +259,6 @@ private slots: void fromListInt() const; void fromListMovable() const; void fromListCustom() const; - void fromStdVector() const; void indexOf() const; void insertInt() const; void insertMovable() const; @@ -294,7 +297,10 @@ private slots: void swapMovable() const; void swapCustom() const; void toList() const; +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) + void fromStdVector() const; void toStdVector() const; +#endif void value() const; void testOperators() const; @@ -327,10 +333,13 @@ private slots: void insertMove() const; + void swapItemsAt() const; + private: template<typename T> void copyConstructor() const; template<typename T> void add() const; template<typename T> void append() const; + template<typename T> void assignFromInitializerList() const; template<typename T> void capacity() const; template<typename T> void clear() const; template<typename T> void count() const; @@ -544,6 +553,40 @@ void tst_QVector::assignmentCustom() const } template<typename T> +void tst_QVector::assignFromInitializerList() const +{ + T val1(SimpleValue<T>::at(1)); + T val2(SimpleValue<T>::at(2)); + T val3(SimpleValue<T>::at(3)); + + QVector<T> v1 = {val1, val2, val3}; + QCOMPARE(v1, QVector<T>() << val1 << val2 << val3); + QCOMPARE(v1, (QVector<T> {val1, val2, val3})); + + v1 = {}; + QCOMPARE(v1.size(), 0); +} + +void tst_QVector::assignFromInitializerListInt() const +{ + assignFromInitializerList<int>(); +} + +void tst_QVector::assignFromInitializerListMovable() const +{ + const int instancesCount = Movable::counter.loadAcquire(); + assignFromInitializerList<Movable>(); + QCOMPARE(instancesCount, Movable::counter.loadAcquire()); +} + +void tst_QVector::assignFromInitializerListCustom() const +{ + const int instancesCount = Custom::counter.loadAcquire(); + assignFromInitializerList<Custom>(); + QCOMPARE(instancesCount, Custom::counter.loadAcquire()); +} + +template<typename T> void tst_QVector::add() const { { @@ -668,7 +711,6 @@ void tst_QVector::appendCustom() const void tst_QVector::appendRvalue() const { -#ifdef Q_COMPILER_RVALUE_REFS QVector<QString> v; v.append("hello"); QString world = "world"; @@ -676,9 +718,6 @@ void tst_QVector::appendRvalue() const QVERIFY(world.isEmpty()); QCOMPARE(v.front(), QString("hello")); QCOMPARE(v.back(), QString("world")); -#else - QSKIP("This test requires that C++11 move semantics support is enabled in the compiler"); -#endif } void tst_QVector::at() const @@ -876,6 +915,33 @@ void tst_QVector::countCustom() const QCOMPARE(instancesCount, Custom::counter.loadAcquire()); } +void tst_QVector::cpp17ctad() const +{ +#ifdef __cpp_deduction_guides +#define QVERIFY_IS_VECTOR_OF(obj, Type) \ + QVERIFY2((std::is_same<decltype(obj), QVector<Type>>::value), \ + QMetaType::typeName(qMetaTypeId<decltype(obj)::value_type>())) +#define CHECK(Type, One, Two, Three) \ + do { \ + const Type v[] = {One, Two, Three}; \ + QVector v1 = {One, Two, Three}; \ + QVERIFY_IS_VECTOR_OF(v1, Type); \ + QVector v2(v1.begin(), v1.end()); \ + QVERIFY_IS_VECTOR_OF(v2, Type); \ + QVector v3(std::begin(v), std::end(v)); \ + QVERIFY_IS_VECTOR_OF(v3, Type); \ + } while (false) \ + /*end*/ + CHECK(int, 1, 2, 3); + CHECK(double, 1.0, 2.0, 3.0); + CHECK(QString, QStringLiteral("one"), QStringLiteral("two"), QStringLiteral("three")); +#undef QVERIFY_IS_VECTOR_OF +#undef CHECK +#else + QSKIP("This test requires C++17 Constructor Template Argument Deduction support enabled in the compiler."); +#endif +} + void tst_QVector::data() const { QVector<int> myvec; @@ -1403,6 +1469,7 @@ void tst_QVector::fromListCustom() const QCOMPARE(instancesCount, Custom::counter.loadAcquire()); } +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) void tst_QVector::fromStdVector() const { // stl = :( @@ -1416,6 +1483,7 @@ void tst_QVector::fromStdVector() const // test it converts ok QCOMPARE(myvec, QVector<QString>() << "aaa" << "bbb" << "ninjas" << "pirates"); } +#endif void tst_QVector::indexOf() const { @@ -2308,6 +2376,7 @@ void tst_QVector::toList() const QCOMPARE(myvec, QVector<QString>() << "A" << "B" << "C"); } +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) void tst_QVector::toStdVector() const { QVector<QString> myvec; @@ -2320,6 +2389,7 @@ void tst_QVector::toStdVector() const QCOMPARE(myvec, QVector<QString>() << "A" << "B" << "C"); } +#endif void tst_QVector::value() const { @@ -2526,7 +2596,6 @@ void tst_QVector::reallocAfterCopy() template<typename T> void tst_QVector::initializeList() { -#ifdef Q_COMPILER_INITIALIZER_LISTS T val1(SimpleValue<T>::at(1)); T val2(SimpleValue<T>::at(2)); T val3(SimpleValue<T>::at(3)); @@ -2543,7 +2612,6 @@ void tst_QVector::initializeList() QVector<T> v4({}); QCOMPARE(v4.size(), 0); -#endif } void tst_QVector::initializeListInt() @@ -2853,7 +2921,7 @@ void tst_QVector::detachThreadSafety() const struct : QThread { void run() override { - QVector<T> copy(*detachThreadSafetyData<T>()->load()); + QVector<T> copy(*detachThreadSafetyData<T>()->loadRelaxed()); QVERIFY(!copy.isDetached()); detachThreadSafetyLock.release(); detachThreadSafetyLock.acquire(100); @@ -2963,5 +3031,22 @@ void tst_QVector::insertMove() const QCOMPARE(Movable::counter.loadAcquire(), instancesCount); } +void tst_QVector::swapItemsAt() const +{ + QVector<int> v; + v << 0 << 1 << 2 << 3; + + v.swapItemsAt(0, 2); + QCOMPARE(v.at(0), 2); + QCOMPARE(v.at(2), 0); + + auto copy = v; + copy.swapItemsAt(0, 2); + QCOMPARE(v.at(0), 2); + QCOMPARE(v.at(2), 0); + QCOMPARE(copy.at(0), 0); + QCOMPARE(copy.at(2), 2); +} + QTEST_MAIN(tst_QVector) #include "tst_qvector.moc" diff --git a/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp b/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp index 05579dce6e..7c4d1071ce 100644 --- a/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp +++ b/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp @@ -260,12 +260,10 @@ void tst_QVersionNumber::constructorExplicit() QCOMPARE(v5.segments(), v6.segments()); -#ifdef Q_COMPILER_INITIALIZER_LISTS QVersionNumber v7(4, 5, 6); QVersionNumber v8 = {4, 5, 6}; QCOMPARE(v7.segments(), v8.segments()); -#endif } void tst_QVersionNumber::constructorCopy_data() @@ -436,7 +434,7 @@ void tst_QVersionNumber::normalized() QFETCH(QVersionNumber, expected); QCOMPARE(version.normalized(), expected); - QCOMPARE(qMove(version).normalized(), expected); + QCOMPARE(std::move(version).normalized(), expected); } void tst_QVersionNumber::isNormalized_data() @@ -586,30 +584,28 @@ void tst_QVersionNumber::serialize() void tst_QVersionNumber::moveSemantics() { -#ifdef Q_COMPILER_RVALUE_REFS // QVersionNumber(QVersionNumber &&) { QVersionNumber v1(1, 2, 3); - QVersionNumber v2 = qMove(v1); + QVersionNumber v2 = std::move(v1); QCOMPARE(v2, QVersionNumber(1, 2, 3)); } // QVersionNumber &operator=(QVersionNumber &&) { QVersionNumber v1(1, 2, 3); QVersionNumber v2; - v2 = qMove(v1); + v2 = std::move(v1); QCOMPARE(v2, QVersionNumber(1, 2, 3)); } // QVersionNumber(QVector<int> &&) { QVector<int> segments = QVector<int>() << 1 << 2 << 3; QVersionNumber v1(segments); - QVersionNumber v2(qMove(segments)); + QVersionNumber v2(std::move(segments)); QVERIFY(!v1.isNull()); QVERIFY(!v2.isNull()); QCOMPARE(v1, v2); } -#endif #ifdef Q_COMPILER_REF_QUALIFIERS // normalized() { @@ -620,7 +616,7 @@ void tst_QVersionNumber::moveSemantics() QVERIFY(!v.isNull()); QVERIFY(!nv.isNull()); QVERIFY(nv.isNormalized()); - nv = qMove(v).normalized(); + nv = std::move(v).normalized(); QVERIFY(!nv.isNull()); QVERIFY(nv.isNormalized()); } @@ -632,13 +628,10 @@ void tst_QVersionNumber::moveSemantics() segments = v.segments(); QVERIFY(!v.isNull()); QVERIFY(!segments.empty()); - segments = qMove(v).segments(); + segments = std::move(v).segments(); QVERIFY(!segments.empty()); } #endif -#if !defined(Q_COMPILER_RVALUE_REFS) && !defined(Q_COMPILER_REF_QUALIFIERS) - QSKIP("This test requires C++11 move semantics support in the compiler."); -#endif } void tst_QVersionNumber::qtVersion() diff --git a/tests/auto/corelib/tools/tools.pro b/tests/auto/corelib/tools/tools.pro index 2a975e67d1..49b2a1f075 100644 --- a/tests/auto/corelib/tools/tools.pro +++ b/tests/auto/corelib/tools/tools.pro @@ -6,30 +6,20 @@ SUBDIRS=\ qarraydata \ qarraydata_strictiterators \ qbitarray \ - qbytearray \ - qbytearraylist \ - qbytearraymatcher \ - qbytedatabuffer \ qcache \ - qchar \ - qcollator \ qcommandlineparser \ qcontiguouscache \ qcryptographichash \ - qdate \ - qdatetime \ qeasingcurve \ qexplicitlyshareddatapointer \ qfreelist \ qhash \ qhash_strictiterators \ qhashfunctions \ - qlatin1string \ qline \ qlinkedlist \ qlist \ qlist_strictiterators \ - qlocale \ qmakearray \ qmap \ qmap_strictiterators \ @@ -41,28 +31,15 @@ SUBDIRS=\ qpointf \ qqueue \ qrect \ - qregexp \ - qregularexpression \ qringbuffer \ qscopedpointer \ qscopedvaluerollback \ + qscopeguard \ qset \ qsharedpointer \ qsize \ qsizef \ qstl \ - qstring \ - qstring_no_cast_from_bytearray \ - qstringapisymmetry \ - qstringbuilder \ - qstringiterator \ - qstringlist \ - qstringmatcher \ - qstringref \ - qstringview \ - qtextboundaryfinder \ - qtime \ - qtimezone \ qtimeline \ qvarlengtharray \ qvector \ diff --git a/tests/auto/dbus/qdbusabstractadaptor/qdbusabstractadaptor/BLACKLIST b/tests/auto/dbus/qdbusabstractadaptor/qdbusabstractadaptor/BLACKLIST new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/dbus/qdbusabstractadaptor/qdbusabstractadaptor/BLACKLIST diff --git a/tests/auto/dbus/qdbusconnection_spyhook/BLACKLIST b/tests/auto/dbus/qdbusconnection_spyhook/BLACKLIST new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/dbus/qdbusconnection_spyhook/BLACKLIST diff --git a/tests/auto/dbus/qdbusthreading/tst_qdbusthreading.cpp b/tests/auto/dbus/qdbusthreading/tst_qdbusthreading.cpp index 018b7c2a35..b4690268c8 100644 --- a/tests/auto/dbus/qdbusthreading/tst_qdbusthreading.cpp +++ b/tests/auto/dbus/qdbusthreading/tst_qdbusthreading.cpp @@ -197,8 +197,8 @@ tst_QDBusThreading::tst_QDBusThreading() void tst_QDBusThreading::joinThreads() { - threadJoin.acquire(threadJoinCount.load()); - threadJoinCount.store(0); + threadJoin.acquire(threadJoinCount.loadRelaxed()); + threadJoinCount.storeRelaxed(0); } bool tst_QDBusThreading::waitForSignal(QObject *obj, const char *signal, int delay) diff --git a/tests/auto/gui/gui.pro b/tests/auto/gui/gui.pro index e0c8123f26..c90fc48251 100644 --- a/tests/auto/gui/gui.pro +++ b/tests/auto/gui/gui.pro @@ -13,6 +13,7 @@ SUBDIRS = \ text \ util \ itemmodels \ + rhi !qtConfig(opengl)|winrt: SUBDIRS -= qopengl qopenglconfig diff --git a/tests/auto/gui/image/qicoimageformat/tst_qicoimageformat.cpp b/tests/auto/gui/image/qicoimageformat/tst_qicoimageformat.cpp index 2dbb078ae0..fe12175081 100644 --- a/tests/auto/gui/image/qicoimageformat/tst_qicoimageformat.cpp +++ b/tests/auto/gui/image/qicoimageformat/tst_qicoimageformat.cpp @@ -164,7 +164,7 @@ void tst_QIcoImageFormat::imageCount_data() QTest::newRow("16px,32px - 16 colors") << "valid/TIMER01.ICO" << 2; QTest::newRow("16px16c, 32px32c, 32px256c 1") << "valid/WORLD.ico" << 3; QTest::newRow("16px16c, 32px32c, 32px256c 2") << "valid/WORLDH.ico" << 3; - QTest::newRow("invalid floppy (first 8 bytes = 0xff)") << "invalid/35floppy.ico" << 0; + QTest::newRow("invalid floppy (first 8 bytes = 0xff)") << "invalid/35floppy.ico" << -1; QTest::newRow("includes 32BPP w/alpha") << "valid/semitransparent.ico" << 9; QTest::newRow("PNG compression") << "valid/Qt.ico" << 4; QTest::newRow("CUR file") << "valid/yellow.cur" << 1; @@ -177,7 +177,6 @@ void tst_QIcoImageFormat::imageCount() QImageReader reader(m_IconPath + QLatin1Char('/') + fileName); QCOMPARE(reader.imageCount(), count); - } void tst_QIcoImageFormat::jumpToNextImage_data() @@ -218,7 +217,7 @@ void tst_QIcoImageFormat::loopCount_data() QTest::addColumn<int>("count"); QTest::newRow("floppy (16px,32px - 16 colors)") << "valid/35FLOPPY.ICO" << 0; - QTest::newRow("invalid floppy (first 8 bytes = 0xff)") << "invalid/35floppy.ico" << 0; + QTest::newRow("invalid floppy (first 8 bytes = 0xff)") << "invalid/35floppy.ico" << -1; } void tst_QIcoImageFormat::loopCount() @@ -228,6 +227,7 @@ void tst_QIcoImageFormat::loopCount() QImageReader reader(m_IconPath + QLatin1Char('/') + fileName); QCOMPARE(reader.loopCount(), count); + QCOMPARE(reader.canRead(), count < 0 ? false : true); } void tst_QIcoImageFormat::nextImageDelay_data() @@ -256,7 +256,7 @@ void tst_QIcoImageFormat::nextImageDelay() QImageReader reader(m_IconPath + QLatin1Char('/') + fileName); if (count == -1) { - QCOMPARE(reader.nextImageDelay(), 0); + QCOMPARE(reader.nextImageDelay(), -1); } else { int i; for (i = 0; i < count; i++) { diff --git a/tests/auto/gui/image/qimage/qimage.pro b/tests/auto/gui/image/qimage/qimage.pro index b40866892e..0593cfbc23 100644 --- a/tests/auto/gui/image/qimage/qimage.pro +++ b/tests/auto/gui/image/qimage/qimage.pro @@ -7,7 +7,7 @@ qtConfig(c++11): CONFIG += c++11 android:!android-embedded: RESOURCES += qimage.qrc -win32:!winrt: LIBS += -lgdi32 -luser32 +win32:!winrt: QMAKE_USE += user32 gdi32 darwin: LIBS += -framework CoreGraphics TESTDATA += images/* diff --git a/tests/auto/gui/image/qimage/tst_qimage.cpp b/tests/auto/gui/image/qimage/tst_qimage.cpp index 4d41b5e873..2a9b92ed35 100644 --- a/tests/auto/gui/image/qimage/tst_qimage.cpp +++ b/tests/auto/gui/image/qimage/tst_qimage.cpp @@ -303,6 +303,8 @@ static QLatin1String formatToString(QImage::Format format) return QLatin1String("RGBA64pm"); case QImage::Format_Grayscale16: return QLatin1String("Grayscale16"); + case QImage::Format_BGR888: + return QLatin1String("BGR888"); default: break; }; @@ -844,6 +846,13 @@ void tst_QImage::convertToFormat_data() QTest::newRow("blue rgb32 -> rgb888") << int(QImage::Format_RGB32) << 0xff0000ff << int(QImage::Format_RGB888) << 0xff0000ff; + QTest::newRow("red rgb32 -> bgr888") << int(QImage::Format_RGB32) << 0xffff0000 + << int(QImage::Format_BGR888) << 0xffff0000; + QTest::newRow("green rgb32 -> bgr888") << int(QImage::Format_RGB32) << 0xff00ff00 + << int(QImage::Format_BGR888) << 0xff00ff00; + QTest::newRow("blue rgb32 -> bgr888") << int(QImage::Format_RGB32) << 0xff0000ff + << int(QImage::Format_BGR888) << 0xff0000ff; + QTest::newRow("red rgb16 -> rgb888") << int(QImage::Format_RGB16) << 0xffff0000 << int(QImage::Format_RGB888) << 0xffff0000; QTest::newRow("green rgb16 -> rgb888") << int(QImage::Format_RGB16) << 0xff00ff00 @@ -858,6 +867,13 @@ void tst_QImage::convertToFormat_data() QTest::newRow("blue rgb888 -> argb32") << int(QImage::Format_RGB888) << 0xff0000ff << int(QImage::Format_ARGB32) << 0xff0000ff; + QTest::newRow("red bgr888 -> argb32") << int(QImage::Format_RGB888) << 0xffff0000 + << int(QImage::Format_ARGB32) << 0xffff0000; + QTest::newRow("green bgr888 -> argb32") << int(QImage::Format_RGB888) << 0xff00ff00 + << int(QImage::Format_ARGB32) << 0xff00ff00; + QTest::newRow("blue bgr888 -> argb32") << int(QImage::Format_RGB888) << 0xff0000ff + << int(QImage::Format_ARGB32) << 0xff0000ff; + QTest::newRow("red rgb888 -> rgbx8888") << int(QImage::Format_RGB888) << 0xffff0000 << int(QImage::Format_RGBX8888) << 0xffff0000; QTest::newRow("green rgb888 -> rgbx8888") << int(QImage::Format_RGB888) << 0xff00ff00 @@ -1338,6 +1354,12 @@ void tst_QImage::setPixel_data() << 0xff00ff00 << 0x00ff00u; QTest::newRow("RGB888 blue") << int(QImage::Format_RGB888) << 0xff0000ff << 0x0000ffu; + QTest::newRow("BGR888 red") << int(QImage::Format_BGR888) + << 0xffff0000 << 0x0000ffu; + QTest::newRow("BGR888 green") << int(QImage::Format_BGR888) + << 0xff00ff00 << 0x00ff00u; + QTest::newRow("BGR888 blue") << int(QImage::Format_BGR888) + << 0xff0000ff << 0xff0000u; #if Q_BYTE_ORDER == Q_BIG_ENDIAN QTest::newRow("RGBA8888 red") << int(QImage::Format_RGBA8888) << 0xffff0000u << 0xff0000ffu; @@ -1425,6 +1447,7 @@ void tst_QImage::setPixel() case int(QImage::Format_ARGB8565_Premultiplied): case int(QImage::Format_ARGB8555_Premultiplied): case int(QImage::Format_RGB888): + case int(QImage::Format_BGR888): { for (int y = 0; y < h; ++y) { const quint24 *row = (const quint24*)(img.scanLine(y)); @@ -1852,7 +1875,9 @@ void tst_QImage::smoothScale4_data() QTest::addColumn<QImage::Format>("format"); QTest::newRow("RGB32") << QImage::Format_RGB32; +#if QT_CONFIG(raster_64bit) QTest::newRow("RGBx64") << QImage::Format_RGBX64; +#endif } void tst_QImage::smoothScale4() @@ -2107,6 +2132,12 @@ void tst_QImage::paintEngine() QCOMPARE(engine, img.paintEngine()); QCOMPARE(img, expected); + + { + QImage img1(16, 16, QImage::Format_ARGB32); + QImage img2 = img1; + QVERIFY(img2.paintEngine()); + } } void tst_QImage::setAlphaChannelWhilePainting() @@ -2443,6 +2474,7 @@ void tst_QImage::mirrored_data() QTest::newRow("Format_RGB555, vertical") << QImage::Format_RGB555 << true << false << 16 << 16; QTest::newRow("Format_ARGB8555_Premultiplied, vertical") << QImage::Format_ARGB8555_Premultiplied << true << false << 16 << 16; QTest::newRow("Format_RGB888, vertical") << QImage::Format_RGB888 << true << false << 16 << 16; + QTest::newRow("Format_BGR888, vertical") << QImage::Format_BGR888 << true << false << 16 << 16; QTest::newRow("Format_RGB444, vertical") << QImage::Format_RGB444 << true << false << 16 << 16; QTest::newRow("Format_RGBX8888, vertical") << QImage::Format_RGBX8888 << true << false << 16 << 16; QTest::newRow("Format_RGBA8888_Premultiplied, vertical") << QImage::Format_RGBA8888_Premultiplied << true << false << 16 << 16; @@ -3403,7 +3435,7 @@ void tst_QImage::ditherGradient_data() QTest::newRow("rgb32 -> rgb666 (dithering)") << rgb32 << QImage::Format_RGB666 << int(Qt::PreferDither | Qt::OrderedDither) << 129; // Test we get the same results for opaque input in the ARGBPM implementation. - rgb32 = qMove(rgb32).convertToFormat(QImage::Format_ARGB32_Premultiplied); + rgb32 = std::move(rgb32).convertToFormat(QImage::Format_ARGB32_Premultiplied); QTest::newRow("argb32pm -> argb4444pm (no dither)") << rgb32 << QImage::Format_ARGB4444_Premultiplied << 0 << 16; QTest::newRow("argb32pm -> rgb444 (dithering)") << rgb32 << QImage::Format_RGB444 << int(Qt::PreferDither | Qt::OrderedDither) << 33; QTest::newRow("argb32pm -> argb4444pm (dithering)") << rgb32 << QImage::Format_ARGB4444_Premultiplied << int(Qt::PreferDither | Qt::OrderedDither) << 33; @@ -3412,6 +3444,7 @@ void tst_QImage::ditherGradient_data() QTest::newRow("argb32pm -> argb6666pm (no dither)") << rgb32 << QImage::Format_ARGB6666_Premultiplied << 0 << 64; QTest::newRow("argb32pm -> argb6666pm (dithering)") << rgb32 << QImage::Format_ARGB6666_Premultiplied << int(Qt::PreferDither | Qt::OrderedDither) << 129; +#if QT_CONFIG(raster_64bit) QImage rgb30(1024, 16, QImage::Format_RGB30); QLinearGradient gradient30(QRectF(rgb30.rect()).topLeft(), QRectF(rgb30.rect()).topRight()); gradient30.setColorAt(0.0, QColor(0, 0, 0)); @@ -3424,6 +3457,7 @@ void tst_QImage::ditherGradient_data() QTest::newRow("rgb30 -> rgb32 (dithering)") << rgb30 << QImage::Format_RGB32 << int(Qt::PreferDither | Qt::OrderedDither) << 513; QTest::newRow("rgb30 -> rgb888 (no dither)") << rgb30 << QImage::Format_RGB888 << 0 << 256; QTest::newRow("rgb30 -> rgb888 (dithering)") << rgb30 << QImage::Format_RGB888 << int(Qt::PreferDither | Qt::OrderedDither) << 513; +#endif } void tst_QImage::ditherGradient() diff --git a/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp b/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp index d17a171728..22d96e76f9 100644 --- a/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp +++ b/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp @@ -30,6 +30,7 @@ #include <QtTest/QtTest> #include <QBuffer> +#include <QColorSpace> #include <QDebug> #include <QImage> #include <QImageReader> @@ -158,6 +159,9 @@ private slots: void saveFormat_data(); void saveFormat(); + void saveColorSpace_data(); + void saveColorSpace(); + void readText_data(); void readText(); @@ -1859,6 +1863,7 @@ void tst_QImageReader::saveFormat_data() QTest::newRow("Format_RGB555") << QImage::Format_RGB555; QTest::newRow("Format_ARGB8555_Premultiplied") << QImage::Format_ARGB8555_Premultiplied; QTest::newRow("Format_RGB888") << QImage::Format_RGB888; + QTest::newRow("Format_BGR888") << QImage::Format_BGR888; QTest::newRow("Format_RGB444") << QImage::Format_RGB444; QTest::newRow("Format_ARGB4444_Premultiplied") << QImage::Format_ARGB4444_Premultiplied; QTest::newRow("Format_RGBA64") << QImage::Format_RGBA64; @@ -1883,6 +1888,40 @@ void tst_QImageReader::saveFormat() QCOMPARE(stored, converted); } +void tst_QImageReader::saveColorSpace_data() +{ + QTest::addColumn<QColorSpace::NamedColorSpace>("namedColorSpace"); + + QTest::newRow("sRGB") << QColorSpace::SRgb; + QTest::newRow("sRGB(linear)") << QColorSpace::SRgbLinear; + QTest::newRow("AdobeRGB") << QColorSpace::AdobeRgb; + QTest::newRow("DisplayP3") << QColorSpace::DisplayP3; + QTest::newRow("ProPhotoRgb") << QColorSpace::ProPhotoRgb; +} + +void tst_QImageReader::saveColorSpace() +{ + QFETCH(QColorSpace::NamedColorSpace, namedColorSpace); + + QImage orig(":/images/kollada.png"); + + orig.setColorSpace(namedColorSpace); + QBuffer buf; + buf.open(QIODevice::WriteOnly); + QVERIFY(orig.save(&buf, "png")); + buf.close(); + QImage stored = QImage::fromData(buf.buffer(), "png"); + + QCOMPARE(stored, orig); + QCOMPARE(stored.colorSpace(), orig.colorSpace()); + + buf.open(QIODevice::WriteOnly); + QVERIFY(orig.save(&buf, "jpeg")); + buf.close(); + stored = QImage::fromData(buf.buffer(), "jpeg"); + + QCOMPARE(stored.colorSpace(), orig.colorSpace()); +} void tst_QImageReader::readText_data() { diff --git a/tests/auto/gui/image/qpixmap/qpixmap.pro b/tests/auto/gui/image/qpixmap/qpixmap.pro index e6a020af1a..c9219dad1d 100644 --- a/tests/auto/gui/image/qpixmap/qpixmap.pro +++ b/tests/auto/gui/image/qpixmap/qpixmap.pro @@ -5,7 +5,7 @@ QT += core-private gui-private testlib qtHaveModule(widgets): QT += widgets widgets-private SOURCES += tst_qpixmap.cpp -win32:!winrt:LIBS += -lgdi32 -luser32 +win32:!winrt: QMAKE_USE += user32 gdi32 RESOURCES += qpixmap.qrc TESTDATA += convertFromImage/* convertFromToHICON/* loadFromData/* images/* diff --git a/tests/auto/gui/image/qpixmap/tst_qpixmap.cpp b/tests/auto/gui/image/qpixmap/tst_qpixmap.cpp index 4d31d80246..ba5df809f2 100644 --- a/tests/auto/gui/image/qpixmap/tst_qpixmap.cpp +++ b/tests/auto/gui/image/qpixmap/tst_qpixmap.cpp @@ -267,10 +267,6 @@ void tst_QPixmap::fromImage() image.fill(0x7f7f7f7f); const QPixmap pixmap = QPixmap::fromImage(image); -#if 0 // Used to be included in Qt4 for Q_WS_X11 - if (pixmap.handle()->classId() == QPlatformPixmap::X11Class && !pixmap.x11PictureHandle()) - QSKIP("Requires XRender support"); -#endif const QImage result = pixmap.toImage(); image = image.convertToFormat(result.format()); QCOMPARE(result, image); @@ -491,11 +487,6 @@ void tst_QPixmap::fill() else pm = QPixmap(400, 400); -#if 0 // Used to be included in Qt4 for Q_WS_X11 - if (!bitmap && pm.handle()->classId() == QPlatformPixmap::X11Class && !pm.x11PictureHandle()) - QSKIP("Requires XRender support"); -#endif - pm.fill(color); if (syscolor && !bitmap && pm.depth() < 24) { QSKIP("Test does not work on displays without true color"); @@ -521,10 +512,6 @@ void tst_QPixmap::fill() void tst_QPixmap::fill_transparent() { QPixmap pixmap(10, 10); -#if 0 // Used to be included in Qt4 for Q_WS_X11 - if (pixmap.handle()->classId() == QPlatformPixmap::X11Class && !pixmap.x11PictureHandle()) - QSKIP("Requires XRender support"); -#endif pixmap.fill(Qt::transparent); QVERIFY(pixmap.hasAlphaChannel()); } diff --git a/tests/auto/gui/image/qpixmapcache/tst_qpixmapcache.cpp b/tests/auto/gui/image/qpixmapcache/tst_qpixmapcache.cpp index 158530428d..3158883ef5 100644 --- a/tests/auto/gui/image/qpixmapcache/tst_qpixmapcache.cpp +++ b/tests/auto/gui/image/qpixmapcache/tst_qpixmapcache.cpp @@ -104,18 +104,28 @@ void tst_QPixmapCache::cacheLimit() void tst_QPixmapCache::setCacheLimit() { + QPixmap res; QPixmap *p1 = new QPixmap(2, 3); QPixmapCache::insert("P1", *p1); +#if QT_DEPRECATED_SINCE(5, 13) QVERIFY(QPixmapCache::find("P1") != 0); +#endif + QVERIFY(QPixmapCache::find("P1", &res)); delete p1; QPixmapCache::setCacheLimit(0); +#if QT_DEPRECATED_SINCE(5, 13) QVERIFY(!QPixmapCache::find("P1")); +#endif + QVERIFY(!QPixmapCache::find("P1", &res)); p1 = new QPixmap(2, 3); QPixmapCache::setCacheLimit(1000); QPixmapCache::insert("P1", *p1); +#if QT_DEPRECATED_SINCE(5, 13) QVERIFY(QPixmapCache::find("P1") != 0); +#endif + QVERIFY(QPixmapCache::find("P1", &res)); delete p1; @@ -200,6 +210,7 @@ void tst_QPixmapCache::find() QVERIFY(QPixmapCache::insert("P1", p1)); QPixmap p2; +#if QT_DEPRECATED_SINCE(5, 13) QVERIFY(QPixmapCache::find("P1", p2)); QCOMPARE(p2.width(), 10); QCOMPARE(p2.height(), 10); @@ -209,6 +220,12 @@ void tst_QPixmapCache::find() QPixmap *p3 = QPixmapCache::find("P1"); QVERIFY(p3); QCOMPARE(p1, *p3); +#endif + + QVERIFY(QPixmapCache::find("P1", &p2)); + QCOMPARE(p2.width(), 10); + QCOMPARE(p2.height(), 10); + QCOMPARE(p1, p2); //The int part of the API QPixmapCache::Key key = QPixmapCache::insert(p1); @@ -261,6 +278,7 @@ void tst_QPixmapCache::insert() } int num = 0; +#if QT_DEPRECATED_SINCE(5, 13) for (int k = 0; k < numberOfKeys; ++k) { if (QPixmapCache::find(QString::number(k))) ++num; @@ -268,6 +286,16 @@ void tst_QPixmapCache::insert() if (QPixmapCache::find("0")) ++num; + num = 0; +#endif + QPixmap res; + for (int k = 0; k < numberOfKeys; ++k) { + if (QPixmapCache::find(QString::number(k), &res)) + ++num; + } + + if (QPixmapCache::find("0", &res)) + ++num; QVERIFY(num <= estimatedNum); QPixmap p3; @@ -340,17 +368,17 @@ void tst_QPixmapCache::remove() p1.fill(Qt::yellow); QPixmap p2; - QVERIFY(QPixmapCache::find("red", p2)); + QVERIFY(QPixmapCache::find("red", &p2)); QVERIFY(p1.toImage() != p2.toImage()); QVERIFY(p1.toImage() == p1.toImage()); // sanity check QPixmapCache::remove("red"); - QVERIFY(!QPixmapCache::find("red")); + QVERIFY(!QPixmapCache::find("red", &p2)); QPixmapCache::remove("red"); - QVERIFY(!QPixmapCache::find("red")); + QVERIFY(!QPixmapCache::find("red", &p2)); QPixmapCache::remove("green"); - QVERIFY(!QPixmapCache::find("green")); + QVERIFY(!QPixmapCache::find("green", &p2)); //The int part of the API QPixmapCache::clear(); @@ -392,7 +420,7 @@ void tst_QPixmapCache::remove() key = QPixmapCache::insert(p1); QPixmapCache::remove(key); QVERIFY(QPixmapCache::find(key, &p1) == 0); - QVERIFY(QPixmapCache::find("red") != 0); + QVERIFY(QPixmapCache::find("red", &p1) != 0); } void tst_QPixmapCache::clear() @@ -408,14 +436,14 @@ void tst_QPixmapCache::clear() const int numberOfKeys = estimatedNum + 1000; for (int i = 0; i < numberOfKeys; ++i) - QVERIFY(QPixmapCache::find("x" + QString::number(i)) == 0); + QVERIFY(!QPixmapCache::find("x" + QString::number(i), &p1)); for (int j = 0; j < numberOfKeys; ++j) QPixmapCache::insert(QString::number(j), p1); int num = 0; for (int k = 0; k < numberOfKeys; ++k) { - if (QPixmapCache::find(QString::number(k), p1)) + if (QPixmapCache::find(QString::number(k), &p1)) ++num; } QVERIFY(num > 0); @@ -423,7 +451,7 @@ void tst_QPixmapCache::clear() QPixmapCache::clear(); for (int k = 0; k < numberOfKeys; ++k) - QVERIFY(!QPixmapCache::find(QString::number(k))); + QVERIFY(!QPixmapCache::find(QString::number(k), &p1)); //The int part of the API QPixmap p2(10, 10); diff --git a/tests/auto/gui/itemmodels/qstandarditem/tst_qstandarditem.cpp b/tests/auto/gui/itemmodels/qstandarditem/tst_qstandarditem.cpp index 2deb84fa5f..b6921fc0bb 100644 --- a/tests/auto/gui/itemmodels/qstandarditem/tst_qstandarditem.cpp +++ b/tests/auto/gui/itemmodels/qstandarditem/tst_qstandarditem.cpp @@ -311,12 +311,14 @@ void tst_QStandardItem::getSetFlags() item.setCheckable(true); QCOMPARE(item.checkState(), Qt::Checked); +#if QT_DEPRECATED_SINCE(5, 6) // deprecated API item.setTristate(true); QVERIFY(item.isTristate()); QVERIFY(item.flags() & Qt::ItemIsTristate); item.setTristate(false); QVERIFY(!(item.flags() & Qt::ItemIsTristate)); +#endif } void tst_QStandardItem::getSetRowAndColumnCount() diff --git a/tests/auto/gui/itemmodels/qstandarditemmodel/tst_qstandarditemmodel.cpp b/tests/auto/gui/itemmodels/qstandarditemmodel/tst_qstandarditemmodel.cpp index 550f70890e..bc8bc38da6 100644 --- a/tests/auto/gui/itemmodels/qstandarditemmodel/tst_qstandarditemmodel.cpp +++ b/tests/auto/gui/itemmodels/qstandarditemmodel/tst_qstandarditemmodel.cpp @@ -734,7 +734,7 @@ void tst_QStandardItemModel::data() currentRoles.clear(); // bad args m_model->setData(QModelIndex(), "bla", Qt::DisplayRole); - QCOMPARE(currentRoles, {}); + QCOMPARE(currentRoles, QVector<int>{}); QIcon icon; for (int r=0; r < m_model->rowCount(); ++r) { @@ -742,9 +742,9 @@ void tst_QStandardItemModel::data() m_model->setData(m_model->index(r,c), "initialitem", Qt::DisplayRole); QCOMPARE(currentRoles, QVector<int>({Qt::DisplayRole, Qt::EditRole})); m_model->setData(m_model->index(r,c), "tooltip", Qt::ToolTipRole); - QCOMPARE(currentRoles, {Qt::ToolTipRole}); + QCOMPARE(currentRoles, QVector<int>{Qt::ToolTipRole}); m_model->setData(m_model->index(r,c), icon, Qt::DecorationRole); - QCOMPARE(currentRoles, {Qt::DecorationRole}); + QCOMPARE(currentRoles, QVector<int>{Qt::DecorationRole}); } } @@ -761,7 +761,7 @@ void tst_QStandardItemModel::clearItemData() { currentRoles.clear(); QVERIFY(!m_model->clearItemData(QModelIndex())); - QCOMPARE(currentRoles, {}); + QCOMPARE(currentRoles, QVector<int>{}); const QModelIndex idx = m_model->index(0, 0); const QMap<int, QVariant> oldData = m_model->itemData(idx); m_model->setData(idx, QLatin1String("initialitem"), Qt::DisplayRole); @@ -773,7 +773,7 @@ void tst_QStandardItemModel::clearItemData() QCOMPARE(idx.data(Qt::ToolTipRole), QVariant()); QCOMPARE(idx.data(Qt::DisplayRole), QVariant()); QCOMPARE(idx.data(Qt::EditRole), QVariant()); - QCOMPARE(currentRoles, {}); + QCOMPARE(currentRoles, QVector<int>{}); m_model->setItemData(idx, oldData); currentRoles.clear(); } diff --git a/tests/auto/gui/kernel/noqteventloop/noqteventloop.pro b/tests/auto/gui/kernel/noqteventloop/noqteventloop.pro index 7e98704aea..293a6a8581 100644 --- a/tests/auto/gui/kernel/noqteventloop/noqteventloop.pro +++ b/tests/auto/gui/kernel/noqteventloop/noqteventloop.pro @@ -5,4 +5,4 @@ QT += core-private network gui-private testlib SOURCES += tst_noqteventloop.cpp -qtConfig(dynamicgl):win32:!winrt: LIBS += -luser32 +qtConfig(dynamicgl):win32:!winrt: QMAKE_USE += user32 diff --git a/tests/auto/gui/kernel/noqteventloop/tst_noqteventloop.cpp b/tests/auto/gui/kernel/noqteventloop/tst_noqteventloop.cpp index 4fca9a07fc..3d1876f00f 100644 --- a/tests/auto/gui/kernel/noqteventloop/tst_noqteventloop.cpp +++ b/tests/auto/gui/kernel/noqteventloop/tst_noqteventloop.cpp @@ -36,6 +36,7 @@ #include <QtNetwork/qtcpserver.h> #include <QtNetwork/qtcpsocket.h> #include <QtCore/qelapsedtimer.h> +#include <QtCore/qtimer.h> #include <QtCore/qt_windows.h> @@ -49,7 +50,7 @@ class tst_NoQtEventLoop : public QObject private slots: void consumeMouseEvents(); void consumeSocketEvents(); - + void deliverEventsInLivelock(); }; class Window : public QRasterWindow @@ -258,8 +259,8 @@ void tst_NoQtEventLoop::consumeMouseEvents() ::SetWindowPos(mainWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); - Window *childWindow = new Window; - childWindow->setParent(QWindow::fromWinId((WId)mainWnd)); + QWindow *mainWindow = QWindow::fromWinId(reinterpret_cast<WId>(mainWnd)); + Window *childWindow = new Window(mainWindow); childWindow->setGeometry(margin, topVerticalMargin, width - 2 * margin, height - margin - topVerticalMargin); childWindow->show(); @@ -276,6 +277,7 @@ void tst_NoQtEventLoop::consumeMouseEvents() if (g_exit) break; } + delete mainWindow; QCOMPARE(testThread->passed(), true); @@ -311,6 +313,34 @@ void tst_NoQtEventLoop::consumeSocketEvents() QVERIFY(server.hasPendingConnections()); } +void tst_NoQtEventLoop::deliverEventsInLivelock() +{ + int argc = 1; + char *argv[] = { const_cast<char *>("test"), 0 }; + QGuiApplication app(argc, argv); + + QTimer livelockTimer; + livelockTimer.start(0); + QTimer::singleShot(100, Qt::CoarseTimer, &livelockTimer, &QTimer::stop); + + QElapsedTimer elapsedTimer; + elapsedTimer.start(); + + // Exec own message loop + MSG msg; + forever { + if (elapsedTimer.hasExpired(3000) || !livelockTimer.isActive()) + break; + + if (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + } + + QVERIFY(!livelockTimer.isActive()); +} + #include <tst_noqteventloop.moc> QTEST_APPLESS_MAIN(tst_NoQtEventLoop) diff --git a/tests/auto/gui/kernel/qdrag/tst_qdrag.cpp b/tests/auto/gui/kernel/qdrag/tst_qdrag.cpp index 68852f5a3f..d67b17fd43 100644 --- a/tests/auto/gui/kernel/qdrag/tst_qdrag.cpp +++ b/tests/auto/gui/kernel/qdrag/tst_qdrag.cpp @@ -68,10 +68,17 @@ void tst_QDrag::getSetCheck() QCOMPARE((QMimeData *)0, obj1.mimeData()); // delete var1; // No delete, since QDrag takes ownership - Qt::DropAction result = obj1.start(); + Qt::DropAction result = obj1.exec(); + QCOMPARE(result, Qt::IgnoreAction); + result = obj1.exec(Qt::MoveAction | Qt::LinkAction); + QCOMPARE(result, Qt::IgnoreAction); + +#if QT_DEPRECATED_SINCE(5, 13) + result = obj1.start(); QCOMPARE(result, Qt::IgnoreAction); result = obj1.start(Qt::MoveAction | Qt::LinkAction); QCOMPARE(result, Qt::IgnoreAction); +#endif } QTEST_MAIN(tst_QDrag) diff --git a/tests/auto/gui/kernel/qguiapplication/BLACKLIST b/tests/auto/gui/kernel/qguiapplication/BLACKLIST index 9a670237b7..e6ffe78ae3 100644 --- a/tests/auto/gui/kernel/qguiapplication/BLACKLIST +++ b/tests/auto/gui/kernel/qguiapplication/BLACKLIST @@ -1,4 +1,3 @@ [focusObject] -opensuse -opensuse-leap -ubuntu +ubuntu-16.04 +opensuse-42.3 diff --git a/tests/auto/gui/kernel/qguiapplication/qguiapplication.pro b/tests/auto/gui/kernel/qguiapplication/qguiapplication.pro index 895c2a0307..34b75a8397 100644 --- a/tests/auto/gui/kernel/qguiapplication/qguiapplication.pro +++ b/tests/auto/gui/kernel/qguiapplication/qguiapplication.pro @@ -6,6 +6,7 @@ INCLUDEPATH += $$CORE_TEST_PATH TARGET = tst_qguiapplication QT += gui-private +DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x050E00 SOURCES += tst_qguiapplication.cpp RESOURCES = tst_qguiapplication.qrc diff --git a/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp b/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp index a304981cd1..5ee25677bf 100644 --- a/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp +++ b/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp @@ -184,7 +184,7 @@ void tst_QGuiApplication::windowIcon() class DummyWindow : public QWindow { public: - DummyWindow() : m_focusObject(0) {} + DummyWindow() : m_focusObject(nullptr) {} virtual QObject *focusObject() const { @@ -204,7 +204,7 @@ public: void tst_QGuiApplication::focusObject() { int argc = 0; - QGuiApplication app(argc, 0); + QGuiApplication app(argc, nullptr); if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation)) QSKIP("QWindow::requestActivate() is not supported."); @@ -271,15 +271,15 @@ void tst_QGuiApplication::focusObject() void tst_QGuiApplication::allWindows() { int argc = 0; - QGuiApplication app(argc, 0); + QGuiApplication app(argc, nullptr); QWindow *window1 = new QWindow; QWindow *window2 = new QWindow(window1); QVERIFY(app.allWindows().contains(window1)); QVERIFY(app.allWindows().contains(window2)); QCOMPARE(app.allWindows().count(), 2); delete window1; - window1 = 0; - window2 = 0; + window1 = nullptr; + window2 = nullptr; QVERIFY(!app.allWindows().contains(window2)); QVERIFY(!app.allWindows().contains(window1)); QCOMPARE(app.allWindows().count(), 0); @@ -288,15 +288,15 @@ void tst_QGuiApplication::allWindows() void tst_QGuiApplication::topLevelWindows() { int argc = 0; - QGuiApplication app(argc, 0); + QGuiApplication app(argc, nullptr); QWindow *window1 = new QWindow; QWindow *window2 = new QWindow(window1); QVERIFY(app.topLevelWindows().contains(window1)); QVERIFY(!app.topLevelWindows().contains(window2)); QCOMPARE(app.topLevelWindows().count(), 1); delete window1; - window1 = 0; - window2 = 0; + window1 = nullptr; + window2 = nullptr; QVERIFY(!app.topLevelWindows().contains(window2)); QVERIFY(!app.topLevelWindows().contains(window1)); QCOMPARE(app.topLevelWindows().count(), 0); @@ -306,7 +306,7 @@ class ShowCloseShowWindow : public QWindow { Q_OBJECT public: - ShowCloseShowWindow(bool showAgain, QWindow *parent = 0) + ShowCloseShowWindow(bool showAgain, QWindow *parent = nullptr) : QWindow(parent), showAgain(showAgain) { QTimer::singleShot(0, this, SLOT(doClose())); @@ -331,7 +331,7 @@ private: void tst_QGuiApplication::abortQuitOnShow() { int argc = 0; - QGuiApplication app(argc, 0); + QGuiApplication app(argc, nullptr); const QRect screenGeometry = QGuiApplication::primaryScreen()->availableVirtualGeometry(); QScopedPointer<QWindow> window1(new ShowCloseShowWindow(false)); @@ -366,7 +366,7 @@ protected: } public: - FocusChangeWindow() : QWindow(), windowDuringFocusAboutToChange(0), windowDuringFocusOut(0) {} + FocusChangeWindow() : QWindow(), windowDuringFocusAboutToChange(nullptr), windowDuringFocusOut(nullptr) {} QWindow *windowDuringFocusAboutToChange; QWindow *windowDuringFocusOut; @@ -378,7 +378,7 @@ void tst_QGuiApplication::changeFocusWindow() QSKIP("WinRt does not support multiple native windows."); #endif int argc = 0; - QGuiApplication app(argc, 0); + QGuiApplication app(argc, nullptr); if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation)) QSKIP("QWindow::requestActivate() is not supported."); @@ -430,7 +430,7 @@ void tst_QGuiApplication::changeFocusWindow() void tst_QGuiApplication::keyboardModifiers() { int argc = 0; - QGuiApplication app(argc, 0); + QGuiApplication app(argc, nullptr); const QRect screenGeometry = QGuiApplication::primaryScreen()->availableVirtualGeometry(); QScopedPointer<QWindow> window(new QWindow); @@ -564,7 +564,7 @@ public: int leaves; int enters; - inline explicit BlockableWindow(QWindow *parent = 0) + inline explicit BlockableWindow(QWindow *parent = nullptr) : QWindow(parent), blocked(false), leaves(0), enters(0) {} bool event(QEvent *e) @@ -601,7 +601,7 @@ void tst_QGuiApplication::modalWindow() QSKIP("WinRt does not support multiple native windows."); #endif int argc = 0; - QGuiApplication app(argc, 0); + QGuiApplication app(argc, nullptr); const QRect screenGeometry = QGuiApplication::primaryScreen()->availableVirtualGeometry(); int x = screenGeometry.left() + spacing; @@ -654,7 +654,7 @@ void tst_QGuiApplication::modalWindow() window2->show(); QVERIFY(QTest::qWaitForWindowExposed(window1.data())); QVERIFY(QTest::qWaitForWindowExposed(window2.data())); - QCOMPARE(app.modalWindow(), static_cast<QWindow *>(0)); + QCOMPARE(app.modalWindow(), static_cast<QWindow *>(nullptr)); QCOMPARE(window1->blocked, 0); QCOMPARE(childWindow1->blocked, 0); QCOMPARE(window2->blocked, 0); @@ -698,7 +698,7 @@ void tst_QGuiApplication::modalWindow() // everything is unblocked when applicationModalWindow1 is hidden applicationModalWindow1->hide(); - QCOMPARE(app.modalWindow(), static_cast<QWindow *>(0)); + QCOMPARE(app.modalWindow(), static_cast<QWindow *>(nullptr)); QCOMPARE(window1->blocked, 0); QCOMPARE(childWindow1->blocked, 0); // QTBUG-32242, blocked status needs to be set on children as well. QCOMPARE(window2->blocked, 0); @@ -750,7 +750,7 @@ void tst_QGuiApplication::modalWindow() // hide windowModalWindow2, windowModalWindow1 and window1 are unblocked windowModalWindow2->hide(); - QCOMPARE(app.modalWindow(), static_cast<QWindow *>(0)); + QCOMPARE(app.modalWindow(), static_cast<QWindow *>(nullptr)); QCOMPARE(window1->blocked, 0); QCOMPARE(window2->blocked, 0); QCOMPARE(windowModalWindow1->blocked, 0); @@ -815,7 +815,7 @@ void tst_QGuiApplication::modalWindow() // hide windowModalWindow1, everything is unblocked windowModalWindow1->hide(); - QCOMPARE(app.modalWindow(), static_cast<QWindow *>(0)); + QCOMPARE(app.modalWindow(), static_cast<QWindow *>(nullptr)); QCOMPARE(window1->blocked, 0); QCOMPARE(window2->blocked, 0); QCOMPARE(windowModalWindow1->blocked, 0); @@ -829,7 +829,7 @@ void tst_QGuiApplication::modalWindow() void tst_QGuiApplication::quitOnLastWindowClosed() { int argc = 0; - QGuiApplication app(argc, 0); + QGuiApplication app(argc, nullptr); const QRect screenGeometry = QGuiApplication::primaryScreen()->availableVirtualGeometry(); QTimer timer; @@ -869,7 +869,7 @@ void tst_QGuiApplication::quitOnLastWindowClosed() void tst_QGuiApplication::quitOnLastWindowClosedMulti() { int argc = 0; - QGuiApplication app(argc, 0); + QGuiApplication app(argc, nullptr); const QRect screenGeometry = QGuiApplication::primaryScreen()->availableVirtualGeometry(); QTimer timer; @@ -909,7 +909,7 @@ void tst_QGuiApplication::quitOnLastWindowClosedMulti() void tst_QGuiApplication::dontQuitOnLastWindowClosed() { int argc = 0; - QGuiApplication app(argc, 0); + QGuiApplication app(argc, nullptr); app.setQuitOnLastWindowClosed(false); QTimer timer; @@ -959,7 +959,7 @@ public: { if (key == "testplugin") return new TestPlugin; - return 0; + return nullptr; } }; @@ -989,9 +989,13 @@ void tst_QGuiApplication::genericPluginsAndWindowSystemEvents() QCoreApplication::postEvent(&testReceiver, new QEvent(QEvent::User)); QCOMPARE(testReceiver.customEvents, 0); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + QStaticPlugin testPluginInfo(qt_plugin_instance, qt_plugin_query_metadata); +#else QStaticPlugin testPluginInfo; testPluginInfo.instance = qt_plugin_instance; testPluginInfo.rawMetaData = qt_plugin_query_metadata; +#endif qRegisterStaticPluginFunction(testPluginInfo); int argc = 3; char *argv[] = { const_cast<char*>(QTest::currentAppName()), const_cast<char*>("-plugin"), const_cast<char*>("testplugin") }; @@ -1065,7 +1069,7 @@ void tst_QGuiApplication::testSetPaletteAttribute() QVERIFY(!QCoreApplication::testAttribute(Qt::AA_SetPalette)); QPalette palette; - palette.setColor(QPalette::Foreground, Qt::red); + palette.setColor(QPalette::WindowText, Qt::red); QGuiApplication::setPalette(palette); QVERIFY(QCoreApplication::testAttribute(Qt::AA_SetPalette)); @@ -1122,7 +1126,7 @@ void tst_QGuiApplication::settableStyleHints() int argc = 0; QScopedPointer<QGuiApplication> app; if (appInstance) - app.reset(new QGuiApplication(argc, 0)); + app.reset(new QGuiApplication(argc, nullptr)); const int keyboardInputInterval = 555; QGuiApplication::styleHints()->setKeyboardInputInterval(keyboardInputInterval); diff --git a/tests/auto/gui/kernel/qguieventdispatcher/BLACKLIST b/tests/auto/gui/kernel/qguieventdispatcher/BLACKLIST index b1590a5ccf..d2c51922a8 100644 --- a/tests/auto/gui/kernel/qguieventdispatcher/BLACKLIST +++ b/tests/auto/gui/kernel/qguieventdispatcher/BLACKLIST @@ -1,5 +1,3 @@ -[sendPostedEvents] -windows [registerTimer] -windows winrt + diff --git a/tests/auto/gui/kernel/qguieventloop/BLACKLIST b/tests/auto/gui/kernel/qguieventloop/BLACKLIST deleted file mode 100644 index 03acb2f5b0..0000000000 --- a/tests/auto/gui/kernel/qguieventloop/BLACKLIST +++ /dev/null @@ -1,2 +0,0 @@ -[testQuitLock] -osx-10.12 diff --git a/tests/auto/gui/kernel/qguimetatype/tst_qguimetatype.cpp b/tests/auto/gui/kernel/qguimetatype/tst_qguimetatype.cpp index b2572188b9..3ce65a6785 100644 --- a/tests/auto/gui/kernel/qguimetatype/tst_qguimetatype.cpp +++ b/tests/auto/gui/kernel/qguimetatype/tst_qguimetatype.cpp @@ -191,7 +191,7 @@ template<> struct TestValueFactory<QMetaType::QTextLength> { static QTextLength *create() { return new QTextLength(QTextLength::PercentageLength, 50); } }; template<> struct TestValueFactory<QMetaType::QTextFormat> { - static QTextFormat *create() { return new QTextFormat(QTextFormat::TableFormat); } + static QTextFormat *create() { return new QTextFormat(QTextFormat::FrameFormat); } }; template<> struct TestValueFactory<QMetaType::QMatrix> { static QMatrix *create() { return new QMatrix(10, 20, 30, 40, 50, 60); } diff --git a/tests/auto/gui/kernel/qkeyevent/tst_qkeyevent.cpp b/tests/auto/gui/kernel/qkeyevent/tst_qkeyevent.cpp index bad021c3b0..87a47bd93b 100644 --- a/tests/auto/gui/kernel/qkeyevent/tst_qkeyevent.cpp +++ b/tests/auto/gui/kernel/qkeyevent/tst_qkeyevent.cpp @@ -121,7 +121,7 @@ static QByteArray modifiersTestRowName(const QString &keySequence) if (uc > 32 && uc < 128) str << '"' << c << '"'; else - str << "U+" << hex << uc << dec; + str << "U+" << Qt::hex << uc << Qt::dec; if (i < size - 1) str << ','; } @@ -155,7 +155,7 @@ void tst_QKeyEvent::modifiers_data() modifierCombinations.append(modifierCombination); } - qSort(modifierCombinations.begin(), modifierCombinations.end(), orderByModifier); + std::sort(modifierCombinations.begin(), modifierCombinations.end(), orderByModifier); QTest::addColumn<Qt::KeyboardModifiers>("modifiers"); foreach (const QVector<int> combination, modifierCombinations) { diff --git a/tests/auto/gui/kernel/qkeysequence/tst_qkeysequence.cpp b/tests/auto/gui/kernel/qkeysequence/tst_qkeysequence.cpp index f8b6bf064a..874468c954 100644 --- a/tests/auto/gui/kernel/qkeysequence/tst_qkeysequence.cpp +++ b/tests/auto/gui/kernel/qkeysequence/tst_qkeysequence.cpp @@ -86,7 +86,7 @@ static const MacSpecialKey * const MacSpecialKeyEntriesEnd = entries + NumEntrie static QChar macSymbolForQtKey(int key) { - const MacSpecialKey *i = qBinaryFind(entries, MacSpecialKeyEntriesEnd, key); + const MacSpecialKey *i = std::lower_bound(entries, MacSpecialKeyEntriesEnd, key); if (i == MacSpecialKeyEntriesEnd) return QChar(); return QChar(i->macSymbol); diff --git a/tests/auto/gui/kernel/qpalette/tst_qpalette.cpp b/tests/auto/gui/kernel/qpalette/tst_qpalette.cpp index 7f29b1c24e..6ce6422f48 100644 --- a/tests/auto/gui/kernel/qpalette/tst_qpalette.cpp +++ b/tests/auto/gui/kernel/qpalette/tst_qpalette.cpp @@ -141,21 +141,20 @@ void tst_QPalette::copySemantics() void tst_QPalette::moveSemantics() { -#ifdef Q_COMPILER_RVALUE_REFS QPalette src(Qt::red), dst; const QPalette control = src; QVERIFY(src != dst); QCOMPARE(src, control); QVERIFY(!dst.isCopyOf(src)); QVERIFY(!dst.isCopyOf(control)); - dst = qMove(src); // move assignment + dst = std::move(src); // move assignment QVERIFY(!dst.isCopyOf(src)); // isCopyOf() works on moved-from palettes, too QVERIFY(dst.isCopyOf(control)); QCOMPARE(dst, control); src = control; // check moved-from 'src' can still be assigned to (doesn't crash) QVERIFY(src.isCopyOf(dst)); QVERIFY(src.isCopyOf(control)); - QPalette dst2(qMove(src)); // move construction + QPalette dst2(std::move(src)); // move construction QVERIFY(!src.isCopyOf(dst)); QVERIFY(!src.isCopyOf(dst2)); QVERIFY(!src.isCopyOf(control)); @@ -163,9 +162,6 @@ void tst_QPalette::moveSemantics() QVERIFY(dst2.isCopyOf(dst)); QVERIFY(dst2.isCopyOf(control)); // check moved-from 'src' can still be destroyed (doesn't crash) -#else - QSKIP("Compiler doesn't support C++11 move semantics"); -#endif } void tst_QPalette::setBrush() diff --git a/tests/auto/gui/kernel/qtouchevent/BLACKLIST b/tests/auto/gui/kernel/qtouchevent/BLACKLIST index 8e78d7e41f..dcda77bce7 100644 --- a/tests/auto/gui/kernel/qtouchevent/BLACKLIST +++ b/tests/auto/gui/kernel/qtouchevent/BLACKLIST @@ -1,6 +1,2 @@ -[basicRawEventTranslation] -linux [multiPointRawEventTranslationOnTouchScreen] -linux -[multiPointRawEventTranslationOnTouchPad] -linux +ubuntu-16.04 diff --git a/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp b/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp index 13dc924f93..54bb8fe0bd 100644 --- a/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp +++ b/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp @@ -26,7 +26,7 @@ ** ****************************************************************************/ -#include <QtWidgets/QDesktopWidget> +#include <QtGui/QScreen> #include <QtWidgets/QGraphicsItem> #include <QtWidgets/QGraphicsScene> #include <QtWidgets/QGraphicsView> @@ -617,7 +617,7 @@ void tst_QTouchEvent::basicRawEventTranslation() QPointF pos = touchWidget.rect().center(); QPointF screenPos = touchWidget.mapToGlobal(pos.toPoint()); QPointF delta(10, 10); - QRectF screenGeometry = QApplication::desktop()->screenGeometry(&touchWidget); + QRectF screenGeometry = touchWidget.screen()->geometry(); QTouchEvent::TouchPoint rawTouchPoint; rawTouchPoint.setId(0); @@ -753,7 +753,7 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchScreen() QPointF leftScreenPos = leftWidget.mapToGlobal(leftPos.toPoint()); QPointF rightScreenPos = rightWidget.mapToGlobal(rightPos.toPoint()); QPointF centerScreenPos = touchWidget.mapToGlobal(centerPos.toPoint()); - QRectF screenGeometry = QApplication::desktop()->screenGeometry(&touchWidget); + QRectF screenGeometry = touchWidget.screen()->geometry(); QList<QTouchEvent::TouchPoint> rawTouchPoints; rawTouchPoints.append(QTouchEvent::TouchPoint(0)); @@ -968,7 +968,7 @@ void tst_QTouchEvent::touchOnMultipleTouchscreens() QPointF pos = touchWidget.rect().center(); QPointF screenPos = touchWidget.mapToGlobal(pos.toPoint()); QPointF delta(10, 10); - QRectF screenGeometry = QApplication::desktop()->screenGeometry(&touchWidget); + QRectF screenGeometry = touchWidget.screen()->geometry(); QVector<QTouchEvent::TouchPoint> rawTouchPoints(3); rawTouchPoints[0].setId(0); @@ -1131,7 +1131,7 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchPad() QPointF leftScreenPos = leftWidget.mapToGlobal(leftPos.toPoint()); QPointF rightScreenPos = rightWidget.mapToGlobal(rightPos.toPoint()); QPointF centerScreenPos = touchWidget.mapToGlobal(centerPos.toPoint()); - QRectF screenGeometry = QApplication::desktop()->screenGeometry(&touchWidget); + QRectF screenGeometry = touchWidget.screen()->geometry(); QList<QTouchEvent::TouchPoint> rawTouchPoints; rawTouchPoints.append(QTouchEvent::TouchPoint(0)); @@ -1348,7 +1348,7 @@ void tst_QTouchEvent::basicRawEventTranslationOfIds() screenPos << touchWidget.mapToGlobal(pos[i].toPoint()); } QPointF delta(10, 10); - QRectF screenGeometry = QApplication::desktop()->screenGeometry(&touchWidget); + QRectF screenGeometry = touchWidget.screen()->geometry(); QVector<QPointF> rawPosList; rawPosList << QPointF(12, 34) << QPointF(56, 78); @@ -1629,7 +1629,7 @@ void tst_QTouchEvent::deleteInRawEventTranslation() QPointF leftScreenPos = leftWidget->mapToGlobal(leftPos.toPoint()); QPointF centerScreenPos = centerWidget->mapToGlobal(centerPos.toPoint()); QPointF rightScreenPos = rightWidget->mapToGlobal(rightPos.toPoint()); - QRectF screenGeometry = QApplication::desktop()->screenGeometry(&touchWidget); + QRectF screenGeometry = touchWidget.screen()->geometry(); QList<QTouchEvent::TouchPoint> rawTouchPoints; rawTouchPoints.append(QTouchEvent::TouchPoint(0)); diff --git a/tests/auto/gui/kernel/qwindow/BLACKLIST b/tests/auto/gui/kernel/qwindow/BLACKLIST index 1820499a53..27463adf99 100644 --- a/tests/auto/gui/kernel/qwindow/BLACKLIST +++ b/tests/auto/gui/kernel/qwindow/BLACKLIST @@ -1,3 +1,5 @@ +[positioning] +opensuse-leap [positioning:default] linux osx-10.12 ci @@ -5,39 +7,19 @@ winrt [positioning:fake] osx-10.12 ci [modalWithChildWindow] -ubuntu-16.04 # QTBUG-66851 -opensuse -opensuse-leap # QTBUG-69160 -android +opensuse-leap [setVisible] # QTBUG-69154 android [modalWindowEnterEventOnHide_QTBUG35109] -ubuntu-16.04 -osx ci +osx [spuriousMouseMove] -windows ci # QTBUG-69162 -android -[modalDialogClosingOneOfTwoModal] -osx -[modalWindowModallity] -osx -# QTBUG-69163 -android -[visibility] -osx-10.12 ci - +windows-10 [testInputEvents] rhel-7.4 -[isActive] -# QTBUG-67768 -ubuntu -# QTBUG-69157 -android - [exposeEventOnShrink_QTBUG54040] # QTBUG-69155 android diff --git a/tests/auto/gui/kernel/qwindow/qwindow.pro b/tests/auto/gui/kernel/qwindow/qwindow.pro index 844b3e8507..e7931ca773 100644 --- a/tests/auto/gui/kernel/qwindow/qwindow.pro +++ b/tests/auto/gui/kernel/qwindow/qwindow.pro @@ -5,4 +5,4 @@ QT += core-private gui-private testlib SOURCES += tst_qwindow.cpp -qtConfig(dynamicgl):win32:!winrt: LIBS += -luser32 +qtConfig(dynamicgl):win32:!winrt: QMAKE_USE += user32 diff --git a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp index 4f26950192..60f89fcb4e 100644 --- a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp +++ b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp @@ -893,7 +893,13 @@ void tst_QWindow::isActive() QTRY_COMPARE(QGuiApplication::focusWindow(), &window); QCoreApplication::processEvents(); QTRY_COMPARE(dialog.received(QEvent::FocusOut), 1); - QTRY_COMPARE(window.received(QEvent::FocusIn), 3); + // We should be checking for exactly three, but since this is a try-compare _loop_, we might + // loose and regain focus multiple times in the event of a system popup. This has been observed + // to fail on Windows, see QTBUG-77769. + QTRY_VERIFY2(window.received(QEvent::FocusIn) >= 3, + qPrintable( + QStringLiteral("Expected more than three focus in events, received: %1") + .arg(window.received(QEvent::FocusIn)))); QVERIFY(window.isActive()); diff --git a/tests/auto/gui/math3d/qmatrixnxn/tst_qmatrixnxn.cpp b/tests/auto/gui/math3d/qmatrixnxn/tst_qmatrixnxn.cpp index 96d983c8f7..e19f76d830 100644 --- a/tests/auto/gui/math3d/qmatrixnxn/tst_qmatrixnxn.cpp +++ b/tests/auto/gui/math3d/qmatrixnxn/tst_qmatrixnxn.cpp @@ -2861,8 +2861,10 @@ void tst_QMatrixNxN::convertGeneric() QMatrix4x4 m4(m1); QVERIFY(isSame(m4, unique4x4)); +#if QT_DEPRECATED_SINCE(5, 0) QMatrix4x4 m5 = qGenericMatrixToMatrix4x4(m1); QVERIFY(isSame(m5, unique4x4)); +#endif static float const conv4x4[12] = { 1.0f, 2.0f, 3.0f, 4.0f, @@ -2874,8 +2876,10 @@ void tst_QMatrixNxN::convertGeneric() QMatrix4x3 m10 = m9.toGenericMatrix<4, 3>(); QVERIFY(isSame(m10, conv4x4)); +#if QT_DEPRECATED_SINCE(5, 0) QMatrix4x3 m11 = qGenericMatrixFromMatrix4x4<4, 3>(m9); QVERIFY(isSame(m11, conv4x4)); +#endif } // Copy of "flagBits" in qmatrix4x4.h. diff --git a/tests/auto/gui/math3d/qquaternion/tst_qquaternion.cpp b/tests/auto/gui/math3d/qquaternion/tst_qquaternion.cpp index 097dd111d3..8041fb5439 100644 --- a/tests/auto/gui/math3d/qquaternion/tst_qquaternion.cpp +++ b/tests/auto/gui/math3d/qquaternion/tst_qquaternion.cpp @@ -778,7 +778,10 @@ void tst_QQuaternion::conjugate() QQuaternion v1(w1, x1, y1, z1); QQuaternion v2(w1, -x1, -y1, -z1); +#if QT_DEPRECATED_SINCE(5, 5) QCOMPARE(v1.conjugate(), v2); +#endif + QCOMPARE(v1.conjugated(), v2); } // Test quaternion creation from an axis and an angle. diff --git a/tests/auto/gui/painting/painting.pro b/tests/auto/gui/painting/painting.pro index 831fffab30..26e84c1b15 100644 --- a/tests/auto/gui/painting/painting.pro +++ b/tests/auto/gui/painting/painting.pro @@ -3,6 +3,7 @@ SUBDIRS=\ qpainterpath \ qpainterpathstroker \ qcolor \ + qcolorspace \ qbrush \ qregion \ qpagelayout \ diff --git a/tests/auto/gui/painting/qbrush/tst_qbrush.cpp b/tests/auto/gui/painting/qbrush/tst_qbrush.cpp index ce6ce15767..f35d4f330b 100644 --- a/tests/auto/gui/painting/qbrush/tst_qbrush.cpp +++ b/tests/auto/gui/painting/qbrush/tst_qbrush.cpp @@ -338,9 +338,9 @@ void tst_QBrush::gradientPresets() QCOMPARE(lg->finalStop(), QPointF(1, 0)); QCOMPARE(lg->stops().size(), 3); - QCOMPARE(lg->stops().at(0), QGradientStop(0, QColor(QLatin1Literal("#ff9a9e")))); - QCOMPARE(lg->stops().at(1), QGradientStop(0.99, QColor(QLatin1Literal("#fad0c4")))); - QCOMPARE(lg->stops().at(2), QGradientStop(1, QColor(QLatin1Literal("#fad0c4")))); + QCOMPARE(lg->stops().at(0), QGradientStop(0, QColor(QLatin1String("#ff9a9e")))); + QCOMPARE(lg->stops().at(1), QGradientStop(0.99, QColor(QLatin1String("#fad0c4")))); + QCOMPARE(lg->stops().at(2), QGradientStop(1, QColor(QLatin1String("#fad0c4")))); QGradient invalidPreset(QGradient::Preset(-1)); diff --git a/tests/auto/gui/painting/qcolor/tst_qcolor.cpp b/tests/auto/gui/painting/qcolor/tst_qcolor.cpp index 17289e0b85..07c820dc86 100644 --- a/tests/auto/gui/painting/qcolor/tst_qcolor.cpp +++ b/tests/auto/gui/painting/qcolor/tst_qcolor.cpp @@ -33,7 +33,7 @@ #include <qcolor.h> #include <qdebug.h> -#include <private/qcolorprofile_p.h> +#include <private/qcolortrclut_p.h> #include <private/qdrawingprimitive_sse2_p.h> #include <qrgba64.h> @@ -64,12 +64,17 @@ private slots: void globalColors_data(); void globalColors(); +#if defined(Q_COMPILER_CONSTEXPR) & defined(Q_COMPILER_UNIFORM_INIT) + void colorConstants_data(); + void colorConstants(); +#endif void setRed(); void setGreen(); void setBlue(); void setRgb(); + void setRgbF(); void setRgba(); void setHsv(); void setCmyk(); @@ -93,8 +98,8 @@ private slots: void convertTo(); - void light(); - void dark(); + void lighter(); + void darker(); void specConstructor_data(); void specConstructor(); @@ -110,10 +115,6 @@ private slots: void qcolorprofile_data(); void qcolorprofile(); - -#if 0 // Used to be included in Qt4 for Q_WS_X11 - void setallowX11ColorNames(); -#endif }; // Testing get/set functions @@ -187,28 +188,28 @@ void tst_QColor::getSetCheck() // void QColor::setRedF(qreal) obj1.setRedF(0.0); QCOMPARE(obj1.redF(), qreal(0.0)); - obj1.setRedF(-0.2); - QCOMPARE(obj1.redF(), qreal(0.0)); // range<0.0, 1.0 - obj1.setRedF(1.1); - QCOMPARE(obj1.redF(), qreal(1.0)); // range<0.0, 1.0 + obj1.setRedF(-0.25); + QCOMPARE(obj1.redF(), qreal(-0.25)); + obj1.setRedF(1.25); + QCOMPARE(obj1.redF(), qreal(1.25)); // qreal QColor::greenF() // void QColor::setGreenF(qreal) obj1.setGreenF(0.0); QCOMPARE(obj1.greenF(), qreal(0.0)); - obj1.setGreenF(-0.2); - QCOMPARE(obj1.greenF(), qreal(0.0)); // range<0.0, 1.0 - obj1.setGreenF(1.1); - QCOMPARE(obj1.greenF(), qreal(1.0)); // range<0.0, 1.0 + obj1.setGreenF(-0.25); + QCOMPARE(obj1.greenF(), qreal(-0.25)); + obj1.setGreenF(1.5); + QCOMPARE(obj1.greenF(), qreal(1.5)); // qreal QColor::blueF() // void QColor::setBlueF(qreal) obj1.setBlueF(0.0); QCOMPARE(obj1.blueF(), qreal(0.0)); - obj1.setBlueF(-0.2); - QCOMPARE(obj1.blueF(), qreal(0.0)); // range<0.0, 1.0 - obj1.setBlueF(1.1); - QCOMPARE(obj1.blueF(), qreal(1.0)); // range<0.0, 1.0 + obj1.setBlueF(-0.5); + QCOMPARE(obj1.blueF(), qreal(-0.5)); + obj1.setBlueF(2.0); + QCOMPARE(obj1.blueF(), qreal(2.0)); // QRgb QColor::rgba() // void QColor::setRgba(QRgb) @@ -367,6 +368,191 @@ void tst_QColor::globalColors() QCOMPARE(color.rgba(), argb); } +#if defined(Q_COMPILER_CONSTEXPR) & defined(Q_COMPILER_UNIFORM_INIT) +void tst_QColor::colorConstants_data() +{ + QTest::addColumn<QColor>("color"); + QTest::addColumn<QRgb>("argb"); + + QTest::newRow("invalid") << QColor() << 0xff000000; + QTest::newRow("global color color0") << QColorConstants::Color0 << 0xff000000u; + QTest::newRow("global color color1") << QColorConstants::Color1 << 0xffffffffu; + QTest::newRow("global color black") << QColorConstants::Black << 0xff000000u; + QTest::newRow("global color white") << QColorConstants::White << 0xffffffffu; + QTest::newRow("global color darkGray") << QColorConstants::DarkGray << 0xff808080u; + QTest::newRow("global color gray") << QColorConstants::Gray << 0xffa0a0a4u; + QTest::newRow("global color lightGray") << QColorConstants::LightGray << 0xffc0c0c0u; + QTest::newRow("global color red") << QColorConstants::Red << 0xffff0000u; + QTest::newRow("global color green") << QColorConstants::Green << 0xff00ff00u; + QTest::newRow("global color blue") << QColorConstants::Blue << 0xff0000ffu; + QTest::newRow("global color cyan") << QColorConstants::Cyan << 0xff00ffffu; + QTest::newRow("global color magenta") << QColorConstants::Magenta << 0xffff00ffu; + QTest::newRow("global color yellow") << QColorConstants::Yellow << 0xffffff00u; + QTest::newRow("global color darkRed") << QColorConstants::DarkRed << 0xff800000u; + QTest::newRow("global color darkGreen") << QColorConstants::DarkGreen << 0xff008000u; + QTest::newRow("global color darkBlue") << QColorConstants::DarkBlue << 0xff000080u; + QTest::newRow("global color darkCyan") << QColorConstants::DarkCyan << 0xff008080u; + QTest::newRow("global color darkMagenta") << QColorConstants::DarkMagenta << 0xff800080u; + QTest::newRow("global color darkYellow") << QColorConstants::DarkYellow << 0xff808000u; + QTest::newRow("global color transparent") << QColorConstants::Transparent << 0x00000000u; + + QTest::newRow("SVG aliceblue") << QColorConstants::Svg::aliceblue << 0xfff0f8ffu; + QTest::newRow("SVG antiquewhite") << QColorConstants::Svg::antiquewhite << 0xfffaebd7u; + QTest::newRow("SVG aqua") << QColorConstants::Svg::aqua << 0xff00ffffu; + QTest::newRow("SVG aquamarine") << QColorConstants::Svg::aquamarine << 0xff7fffd4u; + QTest::newRow("SVG azure") << QColorConstants::Svg::azure << 0xfff0ffffu; + QTest::newRow("SVG beige") << QColorConstants::Svg::beige << 0xfff5f5dcu; + QTest::newRow("SVG bisque") << QColorConstants::Svg::bisque << 0xffffe4c4u; + QTest::newRow("SVG black") << QColorConstants::Svg::black << 0xff000000u; + QTest::newRow("SVG blanchedalmond") << QColorConstants::Svg::blanchedalmond << 0xffffebcdu; + QTest::newRow("SVG blue") << QColorConstants::Svg::blue << 0xff0000ffu; + QTest::newRow("SVG blueviolet") << QColorConstants::Svg::blueviolet << 0xff8a2be2u; + QTest::newRow("SVG brown") << QColorConstants::Svg::brown << 0xffa52a2au; + QTest::newRow("SVG burlywood") << QColorConstants::Svg::burlywood << 0xffdeb887u; + QTest::newRow("SVG cadetblue") << QColorConstants::Svg::cadetblue << 0xff5f9ea0u; + QTest::newRow("SVG chartreuse") << QColorConstants::Svg::chartreuse << 0xff7fff00u; + QTest::newRow("SVG chocolate") << QColorConstants::Svg::chocolate << 0xffd2691eu; + QTest::newRow("SVG coral") << QColorConstants::Svg::coral << 0xffff7f50u; + QTest::newRow("SVG cornflowerblue") << QColorConstants::Svg::cornflowerblue << 0xff6495edu; + QTest::newRow("SVG cornsilk") << QColorConstants::Svg::cornsilk << 0xfffff8dcu; + QTest::newRow("SVG crimson") << QColorConstants::Svg::crimson << 0xffdc143cu; + QTest::newRow("SVG cyan") << QColorConstants::Svg::cyan << 0xff00ffffu; + QTest::newRow("SVG darkblue") << QColorConstants::Svg::darkblue << 0xff00008bu; + QTest::newRow("SVG darkcyan") << QColorConstants::Svg::darkcyan << 0xff008b8bu; + QTest::newRow("SVG darkgoldenrod") << QColorConstants::Svg::darkgoldenrod << 0xffb8860bu; + QTest::newRow("SVG darkgray") << QColorConstants::Svg::darkgray << 0xffa9a9a9u; + QTest::newRow("SVG darkgreen") << QColorConstants::Svg::darkgreen << 0xff006400u; + QTest::newRow("SVG darkgrey") << QColorConstants::Svg::darkgrey << 0xffa9a9a9u; + QTest::newRow("SVG darkkhaki") << QColorConstants::Svg::darkkhaki << 0xffbdb76bu; + QTest::newRow("SVG darkmagenta") << QColorConstants::Svg::darkmagenta << 0xff8b008bu; + QTest::newRow("SVG darkolivegreen") << QColorConstants::Svg::darkolivegreen << 0xff556b2fu; + QTest::newRow("SVG darkorange") << QColorConstants::Svg::darkorange << 0xffff8c00u; + QTest::newRow("SVG darkorchid") << QColorConstants::Svg::darkorchid << 0xff9932ccu; + QTest::newRow("SVG darkred") << QColorConstants::Svg::darkred << 0xff8b0000u; + QTest::newRow("SVG darksalmon") << QColorConstants::Svg::darksalmon << 0xffe9967au; + QTest::newRow("SVG darkseagreen") << QColorConstants::Svg::darkseagreen << 0xff8fbc8fu; + QTest::newRow("SVG darkslateblue") << QColorConstants::Svg::darkslateblue << 0xff483d8bu; + QTest::newRow("SVG darkslategray") << QColorConstants::Svg::darkslategray << 0xff2f4f4fu; + QTest::newRow("SVG darkslategrey") << QColorConstants::Svg::darkslategrey << 0xff2f4f4fu; + QTest::newRow("SVG darkturquoise") << QColorConstants::Svg::darkturquoise << 0xff00ced1u; + QTest::newRow("SVG darkviolet") << QColorConstants::Svg::darkviolet << 0xff9400d3u; + QTest::newRow("SVG deeppink") << QColorConstants::Svg::deeppink << 0xffff1493u; + QTest::newRow("SVG deepskyblue") << QColorConstants::Svg::deepskyblue << 0xff00bfffu; + QTest::newRow("SVG dimgray") << QColorConstants::Svg::dimgray << 0xff696969u; + QTest::newRow("SVG dimgrey") << QColorConstants::Svg::dimgrey << 0xff696969u; + QTest::newRow("SVG dodgerblue") << QColorConstants::Svg::dodgerblue << 0xff1e90ffu; + QTest::newRow("SVG firebrick") << QColorConstants::Svg::firebrick << 0xffb22222u; + QTest::newRow("SVG floralwhite") << QColorConstants::Svg::floralwhite << 0xfffffaf0u; + QTest::newRow("SVG forestgreen") << QColorConstants::Svg::forestgreen << 0xff228b22u; + QTest::newRow("SVG fuchsia") << QColorConstants::Svg::fuchsia << 0xffff00ffu; + QTest::newRow("SVG gainsboro") << QColorConstants::Svg::gainsboro << 0xffdcdcdcu; + QTest::newRow("SVG ghostwhite") << QColorConstants::Svg::ghostwhite << 0xfff8f8ffu; + QTest::newRow("SVG gold") << QColorConstants::Svg::gold << 0xffffd700u; + QTest::newRow("SVG goldenrod") << QColorConstants::Svg::goldenrod << 0xffdaa520u; + QTest::newRow("SVG gray") << QColorConstants::Svg::gray << 0xff808080u; + QTest::newRow("SVG green") << QColorConstants::Svg::green << 0xff008000u; + QTest::newRow("SVG greenyellow") << QColorConstants::Svg::greenyellow << 0xffadff2fu; + QTest::newRow("SVG grey") << QColorConstants::Svg::grey << 0xff808080u; + QTest::newRow("SVG honeydew") << QColorConstants::Svg::honeydew << 0xfff0fff0u; + QTest::newRow("SVG hotpink") << QColorConstants::Svg::hotpink << 0xffff69b4u; + QTest::newRow("SVG indianred") << QColorConstants::Svg::indianred << 0xffcd5c5cu; + QTest::newRow("SVG indigo") << QColorConstants::Svg::indigo << 0xff4b0082u; + QTest::newRow("SVG ivory") << QColorConstants::Svg::ivory << 0xfffffff0u; + QTest::newRow("SVG khaki") << QColorConstants::Svg::khaki << 0xfff0e68cu; + QTest::newRow("SVG lavender") << QColorConstants::Svg::lavender << 0xffe6e6fau; + QTest::newRow("SVG lavenderblush") << QColorConstants::Svg::lavenderblush << 0xfffff0f5u; + QTest::newRow("SVG lawngreen") << QColorConstants::Svg::lawngreen << 0xff7cfc00u; + QTest::newRow("SVG lemonchiffon") << QColorConstants::Svg::lemonchiffon << 0xfffffacdu; + QTest::newRow("SVG lightblue") << QColorConstants::Svg::lightblue << 0xffadd8e6u; + QTest::newRow("SVG lightcoral") << QColorConstants::Svg::lightcoral << 0xfff08080u; + QTest::newRow("SVG lightcyan") << QColorConstants::Svg::lightcyan << 0xffe0ffffu; + QTest::newRow("SVG lightgoldenrodyellow") << QColorConstants::Svg::lightgoldenrodyellow << 0xfffafad2u; + QTest::newRow("SVG lightgray") << QColorConstants::Svg::lightgray << 0xffd3d3d3u; + QTest::newRow("SVG lightgreen") << QColorConstants::Svg::lightgreen << 0xff90ee90u; + QTest::newRow("SVG lightgrey") << QColorConstants::Svg::lightgrey << 0xffd3d3d3u; + QTest::newRow("SVG lightpink") << QColorConstants::Svg::lightpink << 0xffffb6c1u; + QTest::newRow("SVG lightsalmon") << QColorConstants::Svg::lightsalmon << 0xffffa07au; + QTest::newRow("SVG lightseagreen") << QColorConstants::Svg::lightseagreen << 0xff20b2aau; + QTest::newRow("SVG lightskyblue") << QColorConstants::Svg::lightskyblue << 0xff87cefau; + QTest::newRow("SVG lightslategray") << QColorConstants::Svg::lightslategray << 0xff778899u; + QTest::newRow("SVG lightslategrey") << QColorConstants::Svg::lightslategrey << 0xff778899u; + QTest::newRow("SVG lightsteelblue") << QColorConstants::Svg::lightsteelblue << 0xffb0c4deu; + QTest::newRow("SVG lightyellow") << QColorConstants::Svg::lightyellow << 0xffffffe0u; + QTest::newRow("SVG lime") << QColorConstants::Svg::lime << 0xff00ff00u; + QTest::newRow("SVG limegreen") << QColorConstants::Svg::limegreen << 0xff32cd32u; + QTest::newRow("SVG linen") << QColorConstants::Svg::linen << 0xfffaf0e6u; + QTest::newRow("SVG magenta") << QColorConstants::Svg::magenta << 0xffff00ffu; + QTest::newRow("SVG maroon") << QColorConstants::Svg::maroon << 0xff800000u; + QTest::newRow("SVG mediumaquamarine") << QColorConstants::Svg::mediumaquamarine << 0xff66cdaau; + QTest::newRow("SVG mediumblue") << QColorConstants::Svg::mediumblue << 0xff0000cdu; + QTest::newRow("SVG mediumorchid") << QColorConstants::Svg::mediumorchid << 0xffba55d3u; + QTest::newRow("SVG mediumpurple") << QColorConstants::Svg::mediumpurple << 0xff9370dbu; + QTest::newRow("SVG mediumseagreen") << QColorConstants::Svg::mediumseagreen << 0xff3cb371u; + QTest::newRow("SVG mediumslateblue") << QColorConstants::Svg::mediumslateblue << 0xff7b68eeu; + QTest::newRow("SVG mediumspringgreen") << QColorConstants::Svg::mediumspringgreen << 0xff00fa9au; + QTest::newRow("SVG mediumturquoise") << QColorConstants::Svg::mediumturquoise << 0xff48d1ccu; + QTest::newRow("SVG mediumvioletred") << QColorConstants::Svg::mediumvioletred << 0xffc71585u; + QTest::newRow("SVG midnightblue") << QColorConstants::Svg::midnightblue << 0xff191970u; + QTest::newRow("SVG mintcream") << QColorConstants::Svg::mintcream << 0xfff5fffau; + QTest::newRow("SVG mistyrose") << QColorConstants::Svg::mistyrose << 0xffffe4e1u; + QTest::newRow("SVG moccasin") << QColorConstants::Svg::moccasin << 0xffffe4b5u; + QTest::newRow("SVG navajowhite") << QColorConstants::Svg::navajowhite << 0xffffdeadu; + QTest::newRow("SVG navy") << QColorConstants::Svg::navy << 0xff000080u; + QTest::newRow("SVG oldlace") << QColorConstants::Svg::oldlace << 0xfffdf5e6u; + QTest::newRow("SVG olive") << QColorConstants::Svg::olive << 0xff808000u; + QTest::newRow("SVG olivedrab") << QColorConstants::Svg::olivedrab << 0xff6b8e23u; + QTest::newRow("SVG orange") << QColorConstants::Svg::orange << 0xffffa500u; + QTest::newRow("SVG orangered") << QColorConstants::Svg::orangered << 0xffff4500u; + QTest::newRow("SVG orchid") << QColorConstants::Svg::orchid << 0xffda70d6u; + QTest::newRow("SVG palegoldenrod") << QColorConstants::Svg::palegoldenrod << 0xffeee8aau; + QTest::newRow("SVG palegreen") << QColorConstants::Svg::palegreen << 0xff98fb98u; + QTest::newRow("SVG paleturquoise") << QColorConstants::Svg::paleturquoise << 0xffafeeeeu; + QTest::newRow("SVG palevioletred") << QColorConstants::Svg::palevioletred << 0xffdb7093u; + QTest::newRow("SVG papayawhip") << QColorConstants::Svg::papayawhip << 0xffffefd5u; + QTest::newRow("SVG peachpuff") << QColorConstants::Svg::peachpuff << 0xffffdab9u; + QTest::newRow("SVG peru") << QColorConstants::Svg::peru << 0xffcd853fu; + QTest::newRow("SVG pink") << QColorConstants::Svg::pink << 0xffffc0cbu; + QTest::newRow("SVG plum") << QColorConstants::Svg::plum << 0xffdda0ddu; + QTest::newRow("SVG powderblue") << QColorConstants::Svg::powderblue << 0xffb0e0e6u; + QTest::newRow("SVG purple") << QColorConstants::Svg::purple << 0xff800080u; + QTest::newRow("SVG red") << QColorConstants::Svg::red << 0xffff0000u; + QTest::newRow("SVG rosybrown") << QColorConstants::Svg::rosybrown << 0xffbc8f8fu; + QTest::newRow("SVG royalblue") << QColorConstants::Svg::royalblue << 0xff4169e1u; + QTest::newRow("SVG saddlebrown") << QColorConstants::Svg::saddlebrown << 0xff8b4513u; + QTest::newRow("SVG salmon") << QColorConstants::Svg::salmon << 0xfffa8072u; + QTest::newRow("SVG sandybrown") << QColorConstants::Svg::sandybrown << 0xfff4a460u; + QTest::newRow("SVG seagreen") << QColorConstants::Svg::seagreen << 0xff2e8b57u; + QTest::newRow("SVG seashell") << QColorConstants::Svg::seashell << 0xfffff5eeu; + QTest::newRow("SVG sienna") << QColorConstants::Svg::sienna << 0xffa0522du; + QTest::newRow("SVG silver") << QColorConstants::Svg::silver << 0xffc0c0c0u; + QTest::newRow("SVG skyblue") << QColorConstants::Svg::skyblue << 0xff87ceebu; + QTest::newRow("SVG slateblue") << QColorConstants::Svg::slateblue << 0xff6a5acdu; + QTest::newRow("SVG slategray") << QColorConstants::Svg::slategray << 0xff708090u; + QTest::newRow("SVG slategrey") << QColorConstants::Svg::slategrey << 0xff708090u; + QTest::newRow("SVG snow") << QColorConstants::Svg::snow << 0xfffffafau; + QTest::newRow("SVG springgreen") << QColorConstants::Svg::springgreen << 0xff00ff7fu; + QTest::newRow("SVG steelblue") << QColorConstants::Svg::steelblue << 0xff4682b4u; + QTest::newRow("SVG tan") << QColorConstants::Svg::tan << 0xffd2b48cu; + QTest::newRow("SVG teal") << QColorConstants::Svg::teal << 0xff008080u; + QTest::newRow("SVG thistle") << QColorConstants::Svg::thistle << 0xffd8bfd8u; + QTest::newRow("SVG tomato") << QColorConstants::Svg::tomato << 0xffff6347u; + QTest::newRow("SVG turquoise") << QColorConstants::Svg::turquoise << 0xff40e0d0u; + QTest::newRow("SVG violet") << QColorConstants::Svg::violet << 0xffee82eeu; + QTest::newRow("SVG wheat") << QColorConstants::Svg::wheat << 0xfff5deb3u; + QTest::newRow("SVG white") << QColorConstants::Svg::white << 0xffffffffu; + QTest::newRow("SVG whitesmoke") << QColorConstants::Svg::whitesmoke << 0xfff5f5f5u; + QTest::newRow("SVG yellow") << QColorConstants::Svg::yellow << 0xffffff00u; + QTest::newRow("SVG yellowgreen") << QColorConstants::Svg::yellowgreen << 0xff9acd32u; +} + +void tst_QColor::colorConstants() +{ + QFETCH(QColor, color); + QFETCH(QRgb, argb); + QCOMPARE(color.rgba(), argb); +} +#endif // defined(Q_COMPILER_CONSTEXPR) & defined(Q_COMPILER_UNIFORM_INIT) + /* CSS color names = SVG 1.0 color names + transparent (rgba(0,0,0,0)) */ @@ -677,30 +863,81 @@ void tst_QColor::setRgb() { QColor color; - for (int A = 0; A <= USHRT_MAX; ++A) { - { - // 0-255 - int a = A >> 8; - QRgb rgb = qRgba(0, 0, 0, a); + for (int a = 0; a <= 255; ++a) { + QRgb rgb = qRgba(0, 0, 0, a); - color.setRgb(0, 0, 0, a); - QCOMPARE(color.alpha(), a); - QCOMPARE(color.rgb(), qRgb(0, 0, 0)); + color.setRgb(0, 0, 0, a); + QCOMPARE(color.alpha(), a); + QCOMPARE(color.rgb(), qRgb(0, 0, 0)); - color.setRgb(rgb); - QCOMPARE(color.alpha(), 255); - QCOMPARE(color.rgb(), qRgb(0, 0, 0)); + color.setRgb(rgb); + QCOMPARE(color.alpha(), 255); + QCOMPARE(color.rgb(), qRgb(0, 0, 0)); - int r, g, b, a2; - color.setRgb(0, 0, 0, a); - color.getRgb(&r, &g, &b, &a2); - QCOMPARE(a2, a); + int r, g, b, a2; + color.setRgb(0, 0, 0, a); + color.getRgb(&r, &g, &b, &a2); + QCOMPARE(a2, a); - QColor c(0, 0, 0); - c.setAlpha(a); - QCOMPARE(c.alpha(), a); - } + QColor c(0, 0, 0); + c.setAlpha(a); + QCOMPARE(c.alpha(), a); + } + + for (int r = 0; r <= 255; ++r) { + QRgb rgb = qRgb(r, 0, 0); + color.setRgb(r, 0, 0); + QCOMPARE(color.red(), r); + QCOMPARE(color.rgb(), rgb); + + color.setRgb(rgb); + QCOMPARE(color.red(), r); + QCOMPARE(color.rgb(), rgb); + + int r2, g, b, a; + color.getRgb(&r2, &g, &b, &a); + QCOMPARE(r2, r); + } + + for (int g = 0; g <= 255; ++g) { + QRgb rgb = qRgb(0, g, 0); + + color.setRgb(0, g, 0); + QCOMPARE(color.green(), g); + QCOMPARE(color.rgb(), rgb); + + color.setRgb(rgb); + QCOMPARE(color.green(), g); + QCOMPARE(color.rgb(), rgb); + + int r, g2, b, a; + color.getRgb(&r, &g2, &b, &a); + QCOMPARE(g2, g); + } + + for (int b = 0; b <= 255; ++b) { + QRgb rgb = qRgb(0, 0, b); + + color.setRgb(0, 0, b); + QCOMPARE(color.blue(), b); + QCOMPARE(color.rgb(), rgb); + + color.setRgb(rgb); + QCOMPARE(color.blue(), b); + QCOMPARE(color.rgb(), rgb); + + int r, g, b2, a; + color.getRgb(&r, &g, &b2, &a); + QCOMPARE(b2, b); + } +} + +void tst_QColor::setRgbF() +{ + QColor color; + + for (int A = 0; A <= USHRT_MAX; ++A) { { // 0.0-1.0 qreal a = A / qreal(USHRT_MAX); @@ -720,24 +957,6 @@ void tst_QColor::setRgb() for (int R = 0; R <= USHRT_MAX; ++R) { { - // 0-255 - int r = R >> 8; - QRgb rgb = qRgb(r, 0, 0); - - color.setRgb(r, 0, 0); - QCOMPARE(color.red(), r); - QCOMPARE(color.rgb(), rgb); - - color.setRgb(rgb); - QCOMPARE(color.red(), r); - QCOMPARE(color.rgb(), rgb); - - int r2, g, b, a; - color.getRgb(&r2, &g, &b, &a); - QCOMPARE(r2, r); - } - - { // 0.0-1.0 qreal r = R / qreal(USHRT_MAX); color.setRgbF(r, 0.0, 0.0); @@ -751,24 +970,6 @@ void tst_QColor::setRgb() for (int G = 0; G <= USHRT_MAX; ++G) { { - // 0-255 - int g = G >> 8; - QRgb rgb = qRgb(0, g, 0); - - color.setRgb(0, g, 0); - QCOMPARE(color.green(), g); - QCOMPARE(color.rgb(), rgb); - - color.setRgb(rgb); - QCOMPARE(color.green(), g); - QCOMPARE(color.rgb(), rgb); - - int r, g2, b, a; - color.getRgb(&r, &g2, &b, &a); - QCOMPARE(g2, g); - } - - { // 0.0-1.0 qreal g = G / qreal(USHRT_MAX); color.setRgbF(0.0, g, 0.0); @@ -782,32 +983,53 @@ void tst_QColor::setRgb() for (int B = 0; B <= USHRT_MAX; ++B) { { - // 0-255 - int b = B >> 8; - QRgb rgb = qRgb(0, 0, b); + // 0.0-1.0 + qreal b = B / qreal(USHRT_MAX); + color.setRgbF(0.0, 0.0, b); + QCOMPARE(color.blueF(), b); - color.setRgb(0, 0, b); - QCOMPARE(color.blue(), b); - QCOMPARE(color.rgb(), rgb); + qreal r, g, b2, a; + color.getRgbF(&r, &g, &b2, &a); + QCOMPARE(b2, b); + } + } - color.setRgb(rgb); - QCOMPARE(color.blue(), b); - QCOMPARE(color.rgb(), rgb); + for (int R = -128; R <= 512; ++R) { + { + // extended RGB + qreal r = R / qreal(256); + color.setRgbF(r, 0.0, 0.0); + QCOMPARE(qfloat16(color.redF()), qfloat16(r)); - int r, g, b2, a; - color.getRgb(&r, &g, &b2, &a); - QCOMPARE(b2, b); + qreal r2, g, b, a; + color.getRgbF(&r2, &g, &b, &a); + QCOMPARE(qfloat16(r2), qfloat16(r)); } + } + for (int G = -128; G <= 512; ++G) { { - // 0.0-1.0 - qreal b = B / qreal(USHRT_MAX); + // extended RGB + qreal g = G / qreal(256); + color.setRgbF(0.0, g, 0.0); + QCOMPARE(qfloat16(color.greenF()), qfloat16(g)); + + qreal r, g2, b, a; + color.getRgbF(&r, &g2, &b, &a); + QCOMPARE(qfloat16(g2), qfloat16(g)); + } + } + + for (int B = -128; B <= 512; ++B) { + { + // extended RGB + qreal b = B / qreal(256); color.setRgbF(0.0, 0.0, b); - QCOMPARE(color.blueF(), b); + QCOMPARE(qfloat16(color.blueF()), qfloat16(b)); qreal r, g, b2, a; color.getRgbF(&r, &g, &b2, &a); - QCOMPARE(b2, b); + QCOMPARE(qfloat16(b2), qfloat16(b)); } } } @@ -1382,17 +1604,17 @@ void tst_QColor::convertTo() QCOMPARE(invalid.spec(), QColor::Invalid); } -void tst_QColor::light() +void tst_QColor::lighter() { QColor gray(Qt::gray); - QColor lighter = gray.light(); + QColor lighter = gray.lighter(); QVERIFY(lighter.value() > gray.value()); } -void tst_QColor::dark() +void tst_QColor::darker() { QColor gray(Qt::gray); - QColor darker = gray.dark(); + QColor darker = gray.darker(); QVERIFY(darker.value() < gray.value()); } @@ -1423,62 +1645,6 @@ void tst_QColor::achromaticHslHue() QCOMPARE(hsl.hslHue(), -1); } -#if 0 // Used to be included in Qt4 for Q_WS_X11 -void tst_QColor::setallowX11ColorNames() -{ - RGBData x11RgbTbl[] = { - // a few standard X11 color names - { "DodgerBlue1", qRgb(30, 144, 255) }, - { "DodgerBlue2", qRgb(28, 134, 238) }, - { "DodgerBlue3", qRgb(24, 116, 205) }, - { "DodgerBlue4", qRgb(16, 78, 139) }, - { "SteelBlue1", qRgb(99, 184, 255) }, - { "SteelBlue2", qRgb(92, 172, 238) }, - { "SteelBlue3", qRgb(79, 148, 205) }, - { "SteelBlue4", qRgb(54, 100, 139) }, - { "DeepSkyBlue1", qRgb(0, 191, 255) }, - { "DeepSkyBlue2", qRgb(0, 178, 238) }, - { "DeepSkyBlue3", qRgb(0, 154, 205) }, - { "DeepSkyBlue4", qRgb(0, 104, 139) }, - { "SkyBlue1", qRgb(135, 206, 255) }, - { "SkyBlue2", qRgb(126, 192, 238) }, - { "SkyBlue3", qRgb(108, 166, 205) }, - { "SkyBlue4", qRgb(74, 112, 139) } - }; - static const int x11RgbTblSize = sizeof(x11RgbTbl) / sizeof(RGBData); - - // X11 color names should not work by default - QVERIFY(!QColor::allowX11ColorNames()); - for (int i = 0; i < x11RgbTblSize; ++i) { - QString colorName = QLatin1String(x11RgbTbl[i].name); - QColor color; - color.setNamedColor(colorName); - QVERIFY(!color.isValid()); - } - - // enable X11 color names - QColor::setAllowX11ColorNames(true); - QVERIFY(QColor::allowX11ColorNames()); - for (int i = 0; i < x11RgbTblSize; ++i) { - QString colorName = QLatin1String(x11RgbTbl[i].name); - QColor color; - color.setNamedColor(colorName); - QColor expected(x11RgbTbl[i].value); - QCOMPARE(color, expected); - } - - // should be able to turn off X11 color names - QColor::setAllowX11ColorNames(false); - QVERIFY(!QColor::allowX11ColorNames()); - for (int i = 0; i < x11RgbTblSize; ++i) { - QString colorName = QLatin1String(x11RgbTbl[i].name); - QColor color; - color.setNamedColor(colorName); - QVERIFY(!color.isValid()); - } -} -#endif - void tst_QColor::premultiply() { // Tests that qPremultiply(qUnpremultiply(x)) returns x. @@ -1632,14 +1798,13 @@ void tst_QColor::qcolorprofile_data() QTest::newRow("gamma=1.7") << qreal(1.7) << 2; QTest::newRow("gamma=2.0") << qreal(2.0) << 8; QTest::newRow("gamma=2.31") << qreal(2.31) << 33; - QTest::newRow("SRgb") << qreal(0.0) << 7; } void tst_QColor::qcolorprofile() { QFETCH(qreal, gammaC); QFETCH(int, tolerance); - QColorProfile *cp = (gammaC == 0) ? QColorProfile::fromSRgb(): QColorProfile::fromGamma(gammaC); + QColorTrcLut *cp = QColorTrcLut::fromGamma(gammaC); // Test we are accurate for most values after converting through gamma-correction. int error = 0; diff --git a/tests/auto/gui/painting/qcolorspace/qcolorspace.pro b/tests/auto/gui/painting/qcolorspace/qcolorspace.pro new file mode 100644 index 0000000000..14bd699bf7 --- /dev/null +++ b/tests/auto/gui/painting/qcolorspace/qcolorspace.pro @@ -0,0 +1,9 @@ +CONFIG += testcase +QT += testlib gui-private core-private + +TARGET = tst_qcolorspace +SOURCES += tst_qcolorspace.cpp + +RESOURCES += $$files(resources/*) + +TESTDATA += resources/* diff --git a/tests/auto/gui/painting/qcolorspace/resources/HP_ZR30w.icc b/tests/auto/gui/painting/qcolorspace/resources/HP_ZR30w.icc Binary files differnew file mode 100644 index 0000000000..b3f860714c --- /dev/null +++ b/tests/auto/gui/painting/qcolorspace/resources/HP_ZR30w.icc diff --git a/tests/auto/gui/painting/qcolorspace/resources/ProPhoto.jpg b/tests/auto/gui/painting/qcolorspace/resources/ProPhoto.jpg Binary files differnew file mode 100644 index 0000000000..481d35ca8e --- /dev/null +++ b/tests/auto/gui/painting/qcolorspace/resources/ProPhoto.jpg diff --git a/tests/auto/gui/painting/qcolorspace/resources/sRGB2014.icc b/tests/auto/gui/painting/qcolorspace/resources/sRGB2014.icc Binary files differnew file mode 100644 index 0000000000..49afbfef10 --- /dev/null +++ b/tests/auto/gui/painting/qcolorspace/resources/sRGB2014.icc diff --git a/tests/auto/gui/painting/qcolorspace/tst_qcolorspace.cpp b/tests/auto/gui/painting/qcolorspace/tst_qcolorspace.cpp new file mode 100644 index 0000000000..531e14d25b --- /dev/null +++ b/tests/auto/gui/painting/qcolorspace/tst_qcolorspace.cpp @@ -0,0 +1,448 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include <qcolorspace.h> +#include <qimage.h> +#include <qimagereader.h> + +#include <private/qcolorspace_p.h> + +Q_DECLARE_METATYPE(QColorSpace::NamedColorSpace) +Q_DECLARE_METATYPE(QColorSpace::Primaries) +Q_DECLARE_METATYPE(QColorSpace::TransferFunction) + +class tst_QColorSpace : public QObject +{ + Q_OBJECT + +public: + tst_QColorSpace(); + +private slots: + void movable(); + void namedColorSpaces_data(); + void namedColorSpaces(); + + void toIccProfile_data(); + void toIccProfile(); + + void fromIccProfile_data(); + void fromIccProfile(); + + void imageConversion_data(); + void imageConversion(); + + void loadImage(); + + void primaries(); + void primariesXyz(); + +#ifdef QT_BUILD_INTERNAL + void primaries2_data(); + void primaries2(); +#endif + + void invalidPrimaries(); + + void changeTransferFunction(); + void changePrimaries(); +}; + +tst_QColorSpace::tst_QColorSpace() +{ } + + +void tst_QColorSpace::movable() +{ + QColorSpace cs1 = QColorSpace::SRgb; + QColorSpace cs2 = QColorSpace::SRgbLinear; + QVERIFY(cs1.isValid()); + QVERIFY(cs2.isValid()); + QCOMPARE(cs1, QColorSpace::SRgb); + + cs2 = std::move(cs1); + QVERIFY(!cs1.isValid()); + QVERIFY(cs2.isValid()); + QCOMPARE(cs2, QColorSpace::SRgb); + QVERIFY(cs1 != QColorSpace::SRgb); + QCOMPARE(cs1, QColorSpace()); + + QColorSpace cs3(std::move(cs2)); + QVERIFY(!cs2.isValid()); + QVERIFY(cs3.isValid()); + QCOMPARE(cs3, QColorSpace::SRgb); + QCOMPARE(cs2, QColorSpace()); +} + +void tst_QColorSpace::namedColorSpaces_data() +{ + QTest::addColumn<QColorSpace::NamedColorSpace>("namedColorSpace"); + QTest::addColumn<QColorSpace::Primaries>("primariesId"); + QTest::addColumn<QColorSpace::TransferFunction>("transferFunctionId"); + + QTest::newRow("sRGB") << QColorSpace::SRgb + << QColorSpace::Primaries::SRgb + << QColorSpace::TransferFunction::SRgb; + QTest::newRow("sRGB Linear") << QColorSpace::SRgbLinear + << QColorSpace::Primaries::SRgb + << QColorSpace::TransferFunction::Linear; + QTest::newRow("Adobe RGB") << QColorSpace::AdobeRgb + << QColorSpace::Primaries::AdobeRgb + << QColorSpace::TransferFunction::Gamma; + QTest::newRow("Display-P3") << QColorSpace::DisplayP3 + << QColorSpace::Primaries::DciP3D65 + << QColorSpace::TransferFunction::SRgb; + QTest::newRow("ProPhoto RGB") << QColorSpace::ProPhotoRgb + << QColorSpace::Primaries::ProPhotoRgb + << QColorSpace::TransferFunction::ProPhotoRgb; +} + +void tst_QColorSpace::namedColorSpaces() +{ + QFETCH(QColorSpace::NamedColorSpace, namedColorSpace); + QFETCH(QColorSpace::Primaries, primariesId); + QFETCH(QColorSpace::TransferFunction, transferFunctionId); + + QColorSpace colorSpace = namedColorSpace; + + QVERIFY(colorSpace.isValid()); + + QCOMPARE(colorSpace, namedColorSpace); + QCOMPARE(colorSpace.primaries(), primariesId); + QCOMPARE(colorSpace.transferFunction(), transferFunctionId); +} + + +void tst_QColorSpace::toIccProfile_data() +{ + namedColorSpaces_data(); +} + +void tst_QColorSpace::toIccProfile() +{ + QFETCH(QColorSpace::NamedColorSpace, namedColorSpace); + QFETCH(QColorSpace::Primaries, primariesId); + QFETCH(QColorSpace::TransferFunction, transferFunctionId); + + Q_UNUSED(primariesId); + Q_UNUSED(transferFunctionId); + + QColorSpace colorSpace = namedColorSpace; + QByteArray iccProfile = colorSpace.iccProfile(); + QVERIFY(!iccProfile.isEmpty()); + + QColorSpace colorSpace2 = QColorSpace::fromIccProfile(iccProfile); + QVERIFY(colorSpace2.isValid()); + + QCOMPARE(colorSpace2, colorSpace); + + QByteArray iccProfile2 = colorSpace2.iccProfile(); + QVERIFY(!iccProfile2.isEmpty()); + + QCOMPARE(iccProfile2, iccProfile); +} + +void tst_QColorSpace::fromIccProfile_data() +{ + QTest::addColumn<QString>("testProfile"); + QTest::addColumn<QColorSpace::NamedColorSpace>("namedColorSpace"); + QTest::addColumn<QColorSpace::TransferFunction>("transferFunction"); + QTest::addColumn<QString>("description"); + + QString prefix = QFINDTESTDATA("resources/"); + // Read the official sRGB ICCv2 profile: + QTest::newRow("sRGB2014 (ICCv2)") << prefix + "sRGB2014.icc" << QColorSpace::SRgb + << QColorSpace::TransferFunction::SRgb << QString("sRGB2014"); + // My monitor's profile: + QTest::newRow("HP ZR30w (ICCv4)") << prefix + "HP_ZR30w.icc" << QColorSpace::NamedColorSpace(0) + << QColorSpace::TransferFunction::Gamma << QString("HP Z30i"); +} + +void tst_QColorSpace::fromIccProfile() +{ + QFETCH(QString, testProfile); + QFETCH(QColorSpace::NamedColorSpace, namedColorSpace); + QFETCH(QColorSpace::TransferFunction, transferFunction); + QFETCH(QString, description); + + QFile file(testProfile); + file.open(QIODevice::ReadOnly); + QByteArray iccProfile = file.readAll(); + QColorSpace fileColorSpace = QColorSpace::fromIccProfile(iccProfile); + QVERIFY(fileColorSpace.isValid()); + + if (namedColorSpace) + QCOMPARE(fileColorSpace, namedColorSpace); + + QCOMPARE(fileColorSpace.transferFunction(), transferFunction); + QCOMPARE(QColorSpacePrivate::get(fileColorSpace)->description, description); +} + +void tst_QColorSpace::imageConversion_data() +{ + QTest::addColumn<QColorSpace::NamedColorSpace>("fromColorSpace"); + QTest::addColumn<QColorSpace::NamedColorSpace>("toColorSpace"); + QTest::addColumn<int>("tolerance"); + + QTest::newRow("sRGB -> Display-P3") << QColorSpace::SRgb << QColorSpace::DisplayP3 << 0; + QTest::newRow("sRGB -> Adobe RGB") << QColorSpace::SRgb << QColorSpace::AdobeRgb << 2; + QTest::newRow("Display-P3 -> sRGB") << QColorSpace::DisplayP3 << QColorSpace::SRgb << 0; + QTest::newRow("Adobe RGB -> sRGB") << QColorSpace::AdobeRgb << QColorSpace::SRgb << 2; + QTest::newRow("Display-P3 -> Adobe RGB") << QColorSpace::DisplayP3 << QColorSpace::AdobeRgb << 2; + QTest::newRow("sRGB -> sRGB Linear") << QColorSpace::SRgb << QColorSpace::SRgbLinear << 0; +} + +void tst_QColorSpace::imageConversion() +{ + QFETCH(QColorSpace::NamedColorSpace, fromColorSpace); + QFETCH(QColorSpace::NamedColorSpace, toColorSpace); + QFETCH(int, tolerance); + + QImage testImage(256, 1, QImage::Format_RGB32); + + for (int i = 0; i < 256; ++i) + testImage.setPixel(i, 0, qRgb(i, i, i)); + + testImage.setColorSpace(fromColorSpace); + QCOMPARE(testImage.colorSpace(), QColorSpace(fromColorSpace)); + + testImage.convertToColorSpace(toColorSpace); + QCOMPARE(testImage.colorSpace(), QColorSpace(toColorSpace)); + + int lastRed = 0; + int lastGreen = 0; + int lastBlue = 0; + for (int i = 0; i < 256; ++i) { + QRgb p = testImage.pixel(i, 0); + QVERIFY(qRed(p) >= lastRed); + QVERIFY(qGreen(p) >= lastGreen); + QVERIFY(qBlue(p) >= lastBlue); + lastRed = qRed(p); + lastGreen = qGreen(p); + lastBlue = qBlue(p); + } + + lastRed = 0; + lastGreen = 0; + lastBlue = 0; + testImage.convertToColorSpace(fromColorSpace); + QCOMPARE(testImage.colorSpace(), QColorSpace(fromColorSpace)); + for (int i = 0; i < 256; ++i) { + QRgb p = testImage.pixel(i, 0); + QVERIFY(qAbs(qRed(p) - qGreen(p)) <= tolerance); + QVERIFY(qAbs(qRed(p) - qBlue(p)) <= tolerance); + QVERIFY((lastRed - qRed(p)) <= (tolerance / 2)); + QVERIFY((lastGreen - qGreen(p)) <= (tolerance / 2)); + QVERIFY((lastBlue - qBlue(p)) <= (tolerance / 2)); + lastRed = qRed(p); + lastGreen = qGreen(p); + lastBlue = qBlue(p); + } +} + + +void tst_QColorSpace::loadImage() +{ + QString prefix = QFINDTESTDATA("resources/"); + QImageReader reader(prefix + "ProPhoto.jpg"); + QImage image = reader.read(); + + QVERIFY(!image.isNull()); + QVERIFY(image.colorSpace().isValid()); + QCOMPARE(image.colorSpace(), QColorSpace::ProPhotoRgb); + QVERIFY(!image.colorSpace().iccProfile().isEmpty()); + + QColorSpace defaultProPhotoRgb = QColorSpace::ProPhotoRgb; + QVERIFY(!defaultProPhotoRgb.iccProfile().isEmpty()); + + // Test the iccProfile getter returns the ICC profile from the image + // which since we didn't write it, isn't identical to our defaults. + QVERIFY(defaultProPhotoRgb.iccProfile() != image.colorSpace().iccProfile()); + + QColorTransform transform = image.colorSpace().transformationToColorSpace(QColorSpace::SRgb); + qreal maxRed = 0; + qreal maxBlue = 0; + qreal maxRed2 = 0; + qreal maxBlue2 = 0; + for (int y = 0; y < image.height(); ++y) { + for (int x = 0; x < image.width(); ++x) { + QColor p = image.pixelColor(x, y); + maxRed = std::max(maxRed, p.redF()); + maxBlue = std::max(maxBlue, p.blueF()); + p = transform.map(p); + maxRed2 = std::max(maxRed2, p.redF()); + maxBlue2 = std::max(maxBlue2, p.blueF()); + + } + } + // ProPhotoRgb can be a lot more red and blue than SRgb can, so it will have lower values. + QVERIFY(maxRed2 > maxRed); + QVERIFY(maxBlue2 > maxBlue); +} + +void tst_QColorSpace::primaries() +{ + QColor black = QColor::fromRgbF(0.0, 0.0, 0.0); + QColor white = QColor::fromRgbF(1.0, 1.0, 1.0); + QColor red = QColor::fromRgbF(1.0, 0.0, 0.0); + QColor green = QColor::fromRgbF(0.0, 1.0, 0.0); + QColor blue = QColor::fromRgbF(0.0, 0.0, 1.0); + + QColorTransform toAdobeRgb = QColorSpace(QColorSpace::SRgb).transformationToColorSpace(QColorSpace::AdobeRgb); + + QColor tblack = toAdobeRgb.map(black); + QColor twhite = toAdobeRgb.map(white); + QColor tred = toAdobeRgb.map(red); + QColor tgreen = toAdobeRgb.map(green); + QColor tblue = toAdobeRgb.map(blue); + + // Black is black + QCOMPARE(tblack, black); + + // This white hasn't changed + QCOMPARE(twhite, white); + + // Adobe's red and blue gamut corners are the same as sRGB's + // So, a color in the red corner, will stay in the red corner + // the same for blue, but not for green. + QVERIFY(tred.greenF() < 0.001); + QVERIFY(tred.blueF() < 0.001); + QVERIFY(tblue.redF() < 0.001); + QVERIFY(tblue.greenF() < 0.001); + QVERIFY(tgreen.redF() > 0.2); + QVERIFY(tgreen.blueF() > 0.2); +} + +void tst_QColorSpace::primariesXyz() +{ + QColorSpace sRgb = QColorSpace::SRgb; + QColorSpace adobeRgb = QColorSpace::AdobeRgb; + QColorSpace displayP3 = QColorSpace::DisplayP3; + QColorSpace proPhotoRgb = QColorSpace::ProPhotoRgb; + + // Check if our calculated matrices, match the precalculated ones. + QCOMPARE(QColorSpacePrivate::get(sRgb)->toXyz, QColorMatrix::toXyzFromSRgb()); + QCOMPARE(QColorSpacePrivate::get(adobeRgb)->toXyz, QColorMatrix::toXyzFromAdobeRgb()); + QCOMPARE(QColorSpacePrivate::get(displayP3)->toXyz, QColorMatrix::toXyzFromDciP3D65()); + QCOMPARE(QColorSpacePrivate::get(proPhotoRgb)->toXyz, QColorMatrix::toXyzFromProPhotoRgb()); +} + +#ifdef QT_BUILD_INTERNAL +void tst_QColorSpace::primaries2_data() +{ + QTest::addColumn<QColorSpace::Primaries>("primariesId"); + + QTest::newRow("sRGB") << QColorSpace::Primaries::SRgb; + QTest::newRow("DCI-P3 (D65)") << QColorSpace::Primaries::DciP3D65; + QTest::newRow("Adobe RGB (1998)") << QColorSpace::Primaries::AdobeRgb; + QTest::newRow("ProPhoto RGB") << QColorSpace::Primaries::ProPhotoRgb; +} + +void tst_QColorSpace::primaries2() +{ + QFETCH(QColorSpace::Primaries, primariesId); + QColorSpacePrimaries primaries(primariesId); + + QColorSpace original(primariesId, QColorSpace::TransferFunction::Linear); + QColorSpace custom1(primaries.whitePoint, primaries.redPoint, + primaries.greenPoint, primaries.bluePoint, QColorSpace::TransferFunction::Linear); + QCOMPARE(original, custom1); + + // A custom color swizzled color-space: + QColorSpace custom2(primaries.whitePoint, primaries.bluePoint, + primaries.greenPoint, primaries.redPoint, QColorSpace::TransferFunction::Linear); + + QVERIFY(custom1 != custom2); + QColor color1(255, 127, 63); + QColor color2 = custom1.transformationToColorSpace(custom2).map(color1); + QCOMPARE(color2.red(), color1.blue()); + QCOMPARE(color2.green(), color1.green()); + QCOMPARE(color2.blue(), color1.red()); + QCOMPARE(color2.alpha(), color1.alpha()); + QColor color3 = custom2.transformationToColorSpace(custom1).map(color2); + QCOMPARE(color3.red(), color1.red()); + QCOMPARE(color3.green(), color1.green()); + QCOMPARE(color3.blue(), color1.blue()); + QCOMPARE(color3.alpha(), color1.alpha()); +} +#endif + +void tst_QColorSpace::invalidPrimaries() +{ + QColorSpace custom(QPointF(), QPointF(), QPointF(), QPointF(), QColorSpace::TransferFunction::Linear); + QVERIFY(!custom.isValid()); +} + +void tst_QColorSpace::changeTransferFunction() +{ + QColorSpace sRgb = QColorSpace::SRgb; + + QColorSpace sRgbLinear = sRgb.withTransferFunction(QColorSpace::TransferFunction::Linear); + QCOMPARE(sRgbLinear.transferFunction(), QColorSpace::TransferFunction::Linear); + QCOMPARE(sRgbLinear.gamma(), 1.0f); + QCOMPARE(sRgbLinear.primaries(), QColorSpace::Primaries::SRgb); + QCOMPARE(sRgbLinear, QColorSpace::SRgbLinear); + QCOMPARE(sRgbLinear, QColorSpace(QColorSpace::SRgbLinear)); + QVERIFY(sRgbLinear != sRgb); + QCOMPARE(sRgbLinear.withTransferFunction(QColorSpace::TransferFunction::SRgb), sRgb); + + QColorSpace aRgb = QColorSpace::AdobeRgb; + aRgb.setTransferFunction(QColorSpace::TransferFunction::SRgb); + QCOMPARE(aRgb.transferFunction(), QColorSpace::TransferFunction::SRgb); + QCOMPARE(aRgb.primaries(), QColorSpace::Primaries::AdobeRgb); + QVERIFY(aRgb != QColorSpace(QColorSpace::AdobeRgb)); + QVERIFY(aRgb != sRgb); + QCOMPARE(aRgb.withTransferFunction(QColorSpace::TransferFunction::Gamma, 2.2f), + QColorSpace(QColorSpace::AdobeRgb)); + QVERIFY(aRgb != QColorSpace(QColorSpace::AdobeRgb)); + aRgb.setTransferFunction(QColorSpace::TransferFunction::Gamma, 2.2f); + QVERIFY(aRgb == QColorSpace(QColorSpace::AdobeRgb)); + + QColorSpace undefined; + QCOMPARE(undefined.withTransferFunction(QColorSpace::TransferFunction::Linear), undefined); + undefined.setTransferFunction(QColorSpace::TransferFunction::SRgb); + QCOMPARE(undefined, QColorSpace()); +} + +void tst_QColorSpace::changePrimaries() +{ + QColorSpace cs = QColorSpace::SRgb; + cs.setPrimaries(QColorSpace::Primaries::DciP3D65); + QVERIFY(cs.isValid()); + QCOMPARE(cs, QColorSpace(QColorSpace::DisplayP3)); + cs.setTransferFunction(QColorSpace::TransferFunction::Linear); + cs.setPrimaries(QPointF(0.3127, 0.3290), QPointF(0.640, 0.330), + QPointF(0.3000, 0.6000), QPointF(0.150, 0.060)); + QCOMPARE(cs, QColorSpace(QColorSpace::SRgbLinear)); +} + +QTEST_MAIN(tst_QColorSpace) +#include "tst_qcolorspace.moc" diff --git a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp index bc0baed15c..6e48439944 100644 --- a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp +++ b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp @@ -123,14 +123,18 @@ private slots: void drawPath2(); void drawPath3(); +#if QT_DEPRECATED_SINCE(5, 13) void drawRoundRect_data() { fillData(); } void drawRoundRect(); +#endif + void drawRoundedRect_data() { fillData(); } + void drawRoundedRect(); void qimageFormats_data(); void qimageFormats(); void textOnTransparentImage(); -#ifndef QT_NO_WIDGETS +#if !defined(QT_NO_WIDGETS) && QT_DEPRECATED_SINCE(5, 13) void initFrom(); #endif @@ -153,10 +157,10 @@ private slots: void clippedLines(); void clippedPolygon_data(); void clippedPolygon(); - void clippedText(); void clipBoundingRect(); + void transformedClip(); void setOpacity_data(); void setOpacity(); @@ -185,10 +189,12 @@ private slots: void gradientPixelFormat_data(); void gradientPixelFormat(); +#if QT_CONFIG(raster_64bit) void linearGradientRgb30_data(); void linearGradientRgb30(); void radialGradientRgb30_data(); void radialGradientRgb30(); +#endif void fpe_pixmapTransform(); void fpe_zeroLengthLines(); @@ -368,10 +374,10 @@ void tst_QPainter::getSetCheck() // bool QPainter::matrixEnabled() // void QPainter::setMatrixEnabled(bool) - obj1.setMatrixEnabled(false); - QCOMPARE(false, obj1.matrixEnabled()); - obj1.setMatrixEnabled(true); - QCOMPARE(true, obj1.matrixEnabled()); + obj1.setWorldMatrixEnabled(false); + QCOMPARE(false, obj1.worldMatrixEnabled()); + obj1.setWorldMatrixEnabled(true); + QCOMPARE(true, obj1.worldMatrixEnabled()); // bool QPainter::viewTransformEnabled() // void QPainter::setViewTransformEnabled(bool) @@ -455,11 +461,6 @@ void tst_QPainter::drawPixmap_comp() destPm.fill(c1); srcPm.fill(c2); -#if 0 // Used to be included in Qt4 for Q_WS_X11 - if (!destPm.x11PictureHandle()) - QSKIP("Requires XRender support"); -#endif - QPainter p(&destPm); p.drawPixmap(0, 0, srcPm); p.end(); @@ -677,12 +678,14 @@ static QRect getPaintedSize(const QPixmap &pm, const QColor &background) } #ifndef QT_NO_WIDGETS + +#if QT_DEPRECATED_SINCE(5, 13) void tst_QPainter::initFrom() { QWidget *widget = new QWidget(); QPalette pal = widget->palette(); - pal.setColor(QPalette::Foreground, QColor(255, 0, 0)); - pal.setBrush(QPalette::Background, QColor(0, 255, 0)); + pal.setColor(QPalette::WindowText, QColor(255, 0, 0)); + pal.setBrush(QPalette::Window, QColor(0, 255, 0)); widget->setPalette(pal); widget->show(); @@ -696,11 +699,12 @@ void tst_QPainter::initFrom() p.initFrom(widget); QCOMPARE(p.font(), font); - QCOMPARE(p.pen().color(), pal.color(QPalette::Foreground)); - QCOMPARE(p.background(), pal.background()); + QCOMPARE(p.pen().color(), pal.color(QPalette::WindowText)); + QCOMPARE(p.background(), pal.window()); delete widget; } +#endif void tst_QPainter::drawBorderPixmap() { @@ -1544,6 +1548,7 @@ void tst_QPainter::drawClippedEllipse() } +#if QT_DEPRECATED_SINCE(5, 13) void tst_QPainter::drawRoundRect() { QFETCH(QRect, rect); @@ -1578,6 +1583,42 @@ void tst_QPainter::drawRoundRect() QCOMPARE(painted.height(), rect.height() + increment); } } +#endif + +void tst_QPainter::drawRoundedRect() +{ + QFETCH(QRect, rect); + QFETCH(bool, usePen); + +#ifdef Q_OS_DARWIN + if (QTest::currentDataTag() == QByteArray("rect(6, 12, 3, 14) with pen") || + QTest::currentDataTag() == QByteArray("rect(6, 17, 3, 25) with pen") || + QTest::currentDataTag() == QByteArray("rect(10, 6, 10, 3) with pen") || + QTest::currentDataTag() == QByteArray("rect(10, 12, 10, 14) with pen") || + QTest::currentDataTag() == QByteArray("rect(13, 45, 17, 80) with pen") || + QTest::currentDataTag() == QByteArray("rect(13, 50, 17, 91) with pen") || + QTest::currentDataTag() == QByteArray("rect(17, 6, 24, 3) with pen") || + QTest::currentDataTag() == QByteArray("rect(24, 12, 38, 14) with pen")) + QSKIP("The Mac paint engine is off-by-one on certain rect sizes"); +#endif + QPixmap pixmap(rect.x() + rect.width() + 10, + rect.y() + rect.height() + 10); + { + pixmap.fill(Qt::white); + QPainter p(&pixmap); + p.setRenderHint(QPainter::Qt4CompatiblePainting); + p.setPen(usePen ? QPen(Qt::black) : QPen(Qt::NoPen)); + p.setBrush(Qt::black); + p.drawRoundedRect(rect, 25, 25, Qt::RelativeSize); + p.end(); + + int increment = usePen ? 1 : 0; + + const QRect painted = getPaintedSize(pixmap, Qt::white); + QCOMPARE(painted.width(), rect.width() + increment); + QCOMPARE(painted.height(), rect.height() + increment); + } +} void tst_QPainter::qimageFormats_data() { @@ -1591,6 +1632,7 @@ void tst_QPainter::qimageFormats_data() QTest::newRow("Qimage::Format_RGB555") << QImage::Format_RGB555; QTest::newRow("Qimage::Format_ARGB8555_Premultiplied") << QImage::Format_ARGB8555_Premultiplied; QTest::newRow("Qimage::Format_RGB888") << QImage::Format_RGB888; + QTest::newRow("Qimage::Format_BGR888") << QImage::Format_BGR888; QTest::newRow("Qimage::Format_A2RGB30_Premultiplied") << QImage::Format_A2RGB30_Premultiplied; QTest::newRow("Qimage::Format_RGB30") << QImage::Format_RGB30; } @@ -1660,9 +1702,13 @@ void tst_QPainter::combinedMatrix() p.translate(0.5, 0.5); + QTransform ct = p.combinedTransform(); +#if QT_DEPRECATED_SINCE(5, 13) QMatrix cm = p.combinedMatrix(); + QCOMPARE(cm, ct.toAffine()); +#endif - QPointF pt = QPointF(0, 0) * cm; + QPointF pt = QPointF(0, 0) * ct.toAffine(); QCOMPARE(pt.x(), 48.0); QCOMPARE(pt.y(), 16.0); @@ -1977,7 +2023,7 @@ void tst_QPainter::clippedFillPath_data() << pen2; path = QPainterPath(); - path.addRoundRect(QRect(15, 15, 50, 50), 20); + path.addRoundedRect(QRect(15, 15, 50, 50), 20, Qt::RelativeSize); QTest::newRow("round rect 0") << QSize(100, 100) << path << QRect(15, 15, 49, 49) << QBrush(Qt::NoBrush) @@ -3195,7 +3241,7 @@ void tst_QPainter::largeImagePainting() p.translate(4, 0); } - p.resetMatrix(); + p.resetTransform(); for (int i = 4; i < img.height(); i += 4) { p.translate(0, 4); @@ -3946,6 +3992,7 @@ void tst_QPainter::gradientInterpolation() } } +#if QT_CONFIG(raster_64bit) void tst_QPainter::linearGradientRgb30_data() { QTest::addColumn<QColor>("stop0"); @@ -4004,6 +4051,7 @@ void tst_QPainter::radialGradientRgb30() QVERIFY(qGray(p1.rgb()) >= qGray(p2.rgb())); } } +#endif void tst_QPainter::drawPolygon() { @@ -4084,14 +4132,18 @@ void tst_QPainter::inactivePainter() p.setClipRegion(region); p.setClipping(true); +#if QT_DEPRECATED_SINCE(5, 13) p.combinedMatrix(); +#endif p.combinedTransform(); p.compositionMode(); p.setCompositionMode(QPainter::CompositionMode_Plus); p.device(); +#if QT_DEPRECATED_SINCE(5, 13) p.deviceMatrix(); +#endif p.deviceTransform(); p.font(); @@ -4115,7 +4167,9 @@ void tst_QPainter::inactivePainter() p.setRenderHint(QPainter::Antialiasing, true); p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, false); +#if QT_DEPRECATED_SINCE(5, 13) p.resetMatrix(); +#endif p.resetTransform(); p.rotate(1); p.scale(2, 2); @@ -4131,8 +4185,10 @@ void tst_QPainter::inactivePainter() p.window(); p.setWindow(QRect(10, 10, 620, 460)); +#if QT_DEPRECATED_SINCE(5, 13) p.worldMatrix(); p.setWorldMatrix(QMatrix().translate(43, 21), true); +#endif p.setWorldMatrixEnabled(true); p.transform(); @@ -4533,6 +4589,53 @@ void tst_QPainter::clipBoundingRect() } +void tst_QPainter::transformedClip() +{ + QImage img(8, 4, QImage::Format_ARGB32_Premultiplied); + QImage img2(img.size(), img.format()); + QRect clip(0, 0, 2, 1); + QTransform xf; + xf.translate(0.2, 0); + xf.scale(2.2, 1); + // setClipRect(QRectF) + { + img.fill(Qt::green); + QPainter p(&img); + p.setTransform(xf); + p.setClipRect(QRectF(clip)); + p.fillRect(img.rect(), Qt::white); + } + // setClipRect(QRect) + { + img2.fill(Qt::green); + QPainter p(&img2); + p.setTransform(xf); + p.setClipRect(clip); + p.fillRect(img2.rect(), Qt::white); + QCOMPARE(img, img2); + } + // setClipRegion + { + img2.fill(Qt::green); + QPainter p(&img2); + p.setTransform(xf); + p.setClipRegion(QRegion(clip) + QRect(0, 3, 1, 1)); // dummy extra rect to avoid single-rect codepath + p.fillRect(img2.rect(), Qt::white); + QCOMPARE(img.copy(0, 0, 8, 2), img2.copy(0, 0, 8, 2)); + } + // setClipPath + { + img2.fill(Qt::green); + QPainter p(&img2); + p.setTransform(xf); + QPainterPath path; + path.addRect(clip); + p.setClipPath(path); + p.fillRect(img2.rect(), Qt::white); + QCOMPARE(img, img2); + } +} + #if defined(Q_OS_MAC) // Only Mac supports sub pixel positions in raster engine currently void tst_QPainter::drawText_subPixelPositionsInRaster_qtbug5053() @@ -4884,14 +4987,18 @@ void tst_QPainter::blendARGBonRGB_data() << QPainter::CompositionMode_SourceOver << qRgba(255, 0, 0, 85) << 85; QTest::newRow("ARGB_PM over RGB30") << QImage::Format_RGB30 << QImage::Format_ARGB32_Premultiplied << QPainter::CompositionMode_SourceOver << qRgba(85, 0, 0, 85) << 85; +#if QT_CONFIG(raster_64bit) QTest::newRow("ARGB source RGB30") << QImage::Format_RGB30 << QImage::Format_ARGB32 << QPainter::CompositionMode_Source << qRgba(255, 0, 0, 85) << 85; QTest::newRow("ARGB source RGB30") << QImage::Format_RGB30 << QImage::Format_ARGB32 << QPainter::CompositionMode_Source << qRgba(255, 0, 0, 120) << 85; +#endif QTest::newRow("ARGB_PM source RGB30") << QImage::Format_RGB30 << QImage::Format_ARGB32_Premultiplied << QPainter::CompositionMode_Source << qRgba(85, 0, 0, 85) << 85; +#if QT_CONFIG(raster_64bit) QTest::newRow("ARGB_PM source RGB30") << QImage::Format_RGB30 << QImage::Format_ARGB32_Premultiplied << QPainter::CompositionMode_Source << qRgba(180, 0, 0, 180) << 170; +#endif QTest::newRow("ARGB source-in RGB30") << QImage::Format_RGB30 << QImage::Format_ARGB32 << QPainter::CompositionMode_SourceIn << qRgba(255, 0, 0, 85) << 85; QTest::newRow("ARGB_PM source-in RGB30") << QImage::Format_RGB30 << QImage::Format_ARGB32_Premultiplied diff --git a/tests/auto/gui/painting/qpainterpath/tst_qpainterpath.cpp b/tests/auto/gui/painting/qpainterpath/tst_qpainterpath.cpp index 67cf9a321a..86a8965cec 100644 --- a/tests/auto/gui/painting/qpainterpath/tst_qpainterpath.cpp +++ b/tests/auto/gui/painting/qpainterpath/tst_qpainterpath.cpp @@ -88,7 +88,9 @@ private slots: void testToFillPolygons(); +#if QT_CONFIG(signaling_nan) void testNaNandInfinites(); +#endif void closing(); @@ -1228,6 +1230,7 @@ void tst_QPainterPath::testToFillPolygons() QCOMPARE(polygons.first().count(QPointF(70, 50)), 0); } +#if QT_CONFIG(signaling_nan) void tst_QPainterPath::testNaNandInfinites() { QPainterPath path1; @@ -1271,6 +1274,7 @@ void tst_QPainterPath::testNaNandInfinites() path1.lineTo(QPointF(1, 1)); QVERIFY(path1 != path2); } +#endif // signaling_nan void tst_QPainterPath::connectPathDuplicatePoint() { diff --git a/tests/auto/gui/painting/qpathclipper/paths.cpp b/tests/auto/gui/painting/qpathclipper/paths.cpp index 077527e1a0..1328befd1b 100644 --- a/tests/auto/gui/painting/qpathclipper/paths.cpp +++ b/tests/auto/gui/painting/qpathclipper/paths.cpp @@ -578,7 +578,7 @@ QPainterPath Paths::node() m_rect.setHeight(100); QPainterPath shape; - shape.addRoundRect(m_rect, 25); + shape.addRoundedRect(m_rect, 25, Qt::RelativeSize); const int conWidth = 10; const int xOffset = 7; diff --git a/tests/auto/gui/painting/qpdfwriter/tst_qpdfwriter.cpp b/tests/auto/gui/painting/qpdfwriter/tst_qpdfwriter.cpp index c1a8f7f0de..9e9b0db366 100644 --- a/tests/auto/gui/painting/qpdfwriter/tst_qpdfwriter.cpp +++ b/tests/auto/gui/painting/qpdfwriter/tst_qpdfwriter.cpp @@ -154,12 +154,7 @@ void tst_QPdfWriter::testPageMetrics() if (setMargins) { // Setup the given margins - QPdfWriter::Margins margins; - margins.left = leftMMf; - margins.right = rightMMf; - margins.top = topMMf; - margins.bottom = bottomMMf; - writer.setMargins(margins); + writer.setPageMargins({leftMMf, topMMf, rightMMf, bottomMMf}, QPageLayout::Millimeter); QCOMPARE(writer.margins().left, leftMMf); QCOMPARE(writer.margins().right, rightMMf); QCOMPARE(writer.margins().top, topMMf); @@ -169,7 +164,7 @@ void tst_QPdfWriter::testPageMetrics() // Set the given size, in Portrait mode if (pageSize < 0) { - writer.setPageSizeMM(sizeMMf); + writer.setPageSize(QPageSize(sizeMMf, QPageSize::Millimeter)); QCOMPARE(writer.pageSize(), QPdfWriter::Custom); QCOMPARE(writer.pageLayout().pageSize().id(), QPageSize::Custom); } else { @@ -221,7 +216,7 @@ void tst_QPdfWriter::testPageMetrics() // Now while in Landscape mode, set the size again, results should be the same if (pageSize < 0) { - writer.setPageSizeMM(sizeMMf); + writer.setPageSize(QPageSize(sizeMMf, QPageSize::Millimeter)); QCOMPARE(writer.pageSize(), QPdfWriter::Custom); QCOMPARE(writer.pageLayout().pageSize().id(), QPageSize::Custom); } else { @@ -255,7 +250,7 @@ void tst_QPdfWriter::qtbug59443() QTemporaryFile file; QVERIFY2(file.open(), qPrintable(file.errorString())); QPdfWriter writer(file.fileName()); - writer.setPageSize(QPdfWriter::A4); + writer.setPageSize(QPageSize(QPageSize::A4)); QTextDocument doc; doc.documentLayout()->setPaintDevice(&writer); diff --git a/tests/auto/gui/painting/qpen/tst_qpen.cpp b/tests/auto/gui/painting/qpen/tst_qpen.cpp index ef65d653ce..295ae27d17 100644 --- a/tests/auto/gui/painting/qpen/tst_qpen.cpp +++ b/tests/auto/gui/painting/qpen/tst_qpen.cpp @@ -95,7 +95,7 @@ void tst_QPen::move() QPen p1(Qt::black); // check that moving does the right thing: - QPen p2 = qMove(p1); // could be move or copy construction, so don't check p1's state + QPen p2 = std::move(p1); // could be move or copy construction, so don't check p1's state QCOMPARE(p2.color(), QColor(Qt::black)); // this, executed ehre, would crash: @@ -110,7 +110,7 @@ void tst_QPen::move() QCOMPARE(p1.color(), QColor(Qt::yellow)); // check that moved-from QPens p2, p3 can still be safely destroyed: - QPen p5 = qMove(p2); + QPen p5 = std::move(p2); // intentionally no more statements beyond this point } @@ -120,7 +120,7 @@ void tst_QPen::move_assign() QPen p1(Qt::black), p2(Qt::white); // check that moving does the right thing: - p2 = qMove(p1); // could be move or copy assignment, so don't check p1's state + p2 = std::move(p1); // could be move or copy assignment, so don't check p1's state QCOMPARE(p2.color(), QColor(Qt::black)); // check that move-assigned-from QPen p1 can still be used, albeit @@ -137,7 +137,7 @@ void tst_QPen::move_assign() // check that moved-from QPens p2, p3 can still be safely destroyed: QPen p5; - p5 = qMove(p2); + p5 = std::move(p2); // intentionally no more statements beyond this point } diff --git a/tests/auto/gui/painting/qregion/tst_qregion.cpp b/tests/auto/gui/painting/qregion/tst_qregion.cpp index 24c4583819..d1ea7706b9 100644 --- a/tests/auto/gui/painting/qregion/tst_qregion.cpp +++ b/tests/auto/gui/painting/qregion/tst_qregion.cpp @@ -33,9 +33,6 @@ #include <qbitmap.h> #include <qpainter.h> #include <qpolygon.h> -#if 0 // Used to be included in Qt4 for Q_WS_X11 -#include <private/qt_x11_p.h> -#endif class tst_QRegion : public QObject { @@ -79,9 +76,6 @@ private slots: void isEmpty_data(); void isEmpty(); -#if 0 /* Used to be included in Qt4 for Q_WS_X11 */ && defined(QT_BUILD_INTERNAL) - void clipRectangles(); -#endif void regionFromPath(); void scaleRegions_data(); @@ -910,24 +904,6 @@ void tst_QRegion::isEmpty() #endif } -#if 0 /* Used to be included in Qt4 for Q_WS_X11 */ && defined(QT_BUILD_INTERNAL) -void tst_QRegion::clipRectangles() -{ - QRegion region(30, 30, 30, 30); - int num = 0; - qt_getClipRects(region, num); - QCOMPARE(num, 1); - - region += QRegion(10, 10, 10, 10); - XRectangle *rects2 = static_cast<XRectangle *>(qt_getClipRects(region, num)); - QCOMPARE(num, 2); - - // Here's the important part (Y-sorted): - QCOMPARE(int(rects2[0].y), 10); - QCOMPARE(int(rects2[1].y), 30); -} -#endif - void tst_QRegion::regionFromPath() { { diff --git a/tests/auto/gui/qopengl/BLACKLIST b/tests/auto/gui/qopengl/BLACKLIST index a036106c57..10e0520bd9 100644 --- a/tests/auto/gui/qopengl/BLACKLIST +++ b/tests/auto/gui/qopengl/BLACKLIST @@ -1,10 +1,2 @@ -[fboRendering] -windows -[QTBUG15621_triangulatingStrokerDivZero] -windows -[imageFormatPainting] -windows -[openGLPaintDevice] -windows [wglContextWrap] windows diff --git a/tests/auto/gui/qopenglconfig/tst_qopenglconfig.cpp b/tests/auto/gui/qopenglconfig/tst_qopenglconfig.cpp index f8dfdbd3b0..b82b277781 100644 --- a/tests/auto/gui/qopenglconfig/tst_qopenglconfig.cpp +++ b/tests/auto/gui/qopenglconfig/tst_qopenglconfig.cpp @@ -200,7 +200,7 @@ static void dumpGlConfiguration(QOpenGLContext &context, QTextStream &str) << "\nShading language : " << reinterpret_cast<const char *>(functions.glGetString(GL_SHADING_LANGUAGE_VERSION)) << "\nFormat : " << context.format(); - QList<QByteArray> extensionList = context.extensions().toList(); + QList<QByteArray> extensionList = context.extensions().values(); std::sort(extensionList.begin(), extensionList.end()); const int extensionCount = extensionList.size(); str << "\n\nFound " << extensionCount << " extensions:\n"; @@ -233,9 +233,9 @@ void tst_QOpenGlConfig::testGlConfiguration() static inline QByteArray msgSetMismatch(const QSet<QString> &expected, const QSet<QString> &actual) { - const QString result = QStringList(expected.toList()).join(QLatin1Char(',')) + const QString result = QStringList(expected.values()).join(QLatin1Char(',')) + QLatin1String(" != ") - + QStringList(actual.toList()).join(QLatin1Char(',')); + + QStringList(actual.values()).join(QLatin1Char(',')); return result.toLatin1(); } diff --git a/tests/auto/gui/rhi/qrhi/data/compile.bat b/tests/auto/gui/rhi/qrhi/data/compile.bat new file mode 100644 index 0000000000..5b8a77b833 --- /dev/null +++ b/tests/auto/gui/rhi/qrhi/data/compile.bat @@ -0,0 +1,48 @@ +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: +:: Copyright (C) 2019 The Qt Company Ltd. +:: Contact: https://www.qt.io/licensing/ +:: +:: This file is part of the QtQuick module of the Qt Toolkit. +:: +:: $QT_BEGIN_LICENSE:LGPL$ +:: Commercial License Usage +:: Licensees holding valid commercial Qt licenses may use this file in +:: accordance with the commercial license agreement provided with the +:: Software or, alternatively, in accordance with the terms contained in +:: a written agreement between you and The Qt Company. For licensing terms +:: and conditions see https://www.qt.io/terms-conditions. For further +:: information use the contact form at https://www.qt.io/contact-us. +:: +:: GNU Lesser General Public License Usage +:: Alternatively, this file may be used under the terms of the GNU Lesser +:: General Public License version 3 as published by the Free Software +:: Foundation and appearing in the file LICENSE.LGPL3 included in the +:: packaging of this file. Please review the following information to +:: ensure the GNU Lesser General Public License version 3 requirements +:: will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +:: +:: GNU General Public License Usage +:: Alternatively, this file may be used under the terms of the GNU +:: General Public License version 2.0 or (at your option) the GNU General +:: Public license version 3 or any later version approved by the KDE Free +:: Qt Foundation. The licenses are as published by the Free Software +:: Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +:: included in the packaging of this file. Please review the following +:: information to ensure the GNU General Public License requirements will +:: be met: https://www.gnu.org/licenses/gpl-2.0.html and +:: https://www.gnu.org/licenses/gpl-3.0.html. +:: +:: $QT_END_LICENSE$ +:: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +:: Note the -c argument: we do not want runtime HLSL compilation since that is +:: not an option on UWP (WinRT). This means that running qsb must happen on Windows. + +qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 12 -o simple.vert.qsb simple.vert +qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 12 -o simple.frag.qsb simple.frag +qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 12 -o simpletextured.vert.qsb simpletextured.vert +qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 12 -o simpletextured.frag.qsb simpletextured.frag +qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 12 -o textured.vert.qsb textured.vert +qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 12 -o textured.frag.qsb textured.frag diff --git a/tests/auto/gui/rhi/qrhi/data/qt256.png b/tests/auto/gui/rhi/qrhi/data/qt256.png Binary files differnew file mode 100644 index 0000000000..30c621c9c6 --- /dev/null +++ b/tests/auto/gui/rhi/qrhi/data/qt256.png diff --git a/tests/auto/gui/rhi/qrhi/data/simple.frag b/tests/auto/gui/rhi/qrhi/data/simple.frag new file mode 100644 index 0000000000..2aa500e09a --- /dev/null +++ b/tests/auto/gui/rhi/qrhi/data/simple.frag @@ -0,0 +1,8 @@ +#version 440 + +layout(location = 0) out vec4 fragColor; + +void main() +{ + fragColor = vec4(1.0, 0.0, 0.0, 1.0); +} diff --git a/tests/auto/gui/rhi/qrhi/data/simple.frag.qsb b/tests/auto/gui/rhi/qrhi/data/simple.frag.qsb Binary files differnew file mode 100644 index 0000000000..264b71ec0f --- /dev/null +++ b/tests/auto/gui/rhi/qrhi/data/simple.frag.qsb diff --git a/tests/auto/gui/rhi/qrhi/data/simple.vert b/tests/auto/gui/rhi/qrhi/data/simple.vert new file mode 100644 index 0000000000..16ee61beca --- /dev/null +++ b/tests/auto/gui/rhi/qrhi/data/simple.vert @@ -0,0 +1,10 @@ +#version 440 + +layout(location = 0) in vec4 position; + +out gl_PerVertex { vec4 gl_Position; }; + +void main() +{ + gl_Position = position; +} diff --git a/tests/auto/gui/rhi/qrhi/data/simple.vert.qsb b/tests/auto/gui/rhi/qrhi/data/simple.vert.qsb Binary files differnew file mode 100644 index 0000000000..59080b60c6 --- /dev/null +++ b/tests/auto/gui/rhi/qrhi/data/simple.vert.qsb diff --git a/tests/auto/gui/rhi/qrhi/data/simpletextured.frag b/tests/auto/gui/rhi/qrhi/data/simpletextured.frag new file mode 100644 index 0000000000..630df7b807 --- /dev/null +++ b/tests/auto/gui/rhi/qrhi/data/simpletextured.frag @@ -0,0 +1,13 @@ +#version 440 + +layout(location = 0) in vec2 uv; +layout(location = 0) out vec4 fragColor; + +layout(binding = 0) uniform sampler2D tex; + +void main() +{ + vec4 c = texture(tex, uv); + c.rgb *= c.a; + fragColor = c; +} diff --git a/tests/auto/gui/rhi/qrhi/data/simpletextured.frag.qsb b/tests/auto/gui/rhi/qrhi/data/simpletextured.frag.qsb Binary files differnew file mode 100644 index 0000000000..f302702aa9 --- /dev/null +++ b/tests/auto/gui/rhi/qrhi/data/simpletextured.frag.qsb diff --git a/tests/auto/gui/rhi/qrhi/data/simpletextured.vert b/tests/auto/gui/rhi/qrhi/data/simpletextured.vert new file mode 100644 index 0000000000..1dd204f84d --- /dev/null +++ b/tests/auto/gui/rhi/qrhi/data/simpletextured.vert @@ -0,0 +1,14 @@ +#version 440 + +layout(location = 0) in vec4 position; +layout(location = 1) in vec2 texcoord; + +layout(location = 0) out vec2 uv; + +out gl_PerVertex { vec4 gl_Position; }; + +void main() +{ + uv = texcoord; + gl_Position = position; +} diff --git a/tests/auto/gui/rhi/qrhi/data/simpletextured.vert.qsb b/tests/auto/gui/rhi/qrhi/data/simpletextured.vert.qsb Binary files differnew file mode 100644 index 0000000000..e4f12bfb9e --- /dev/null +++ b/tests/auto/gui/rhi/qrhi/data/simpletextured.vert.qsb diff --git a/tests/auto/gui/rhi/qrhi/data/textured.frag b/tests/auto/gui/rhi/qrhi/data/textured.frag new file mode 100644 index 0000000000..605410b028 --- /dev/null +++ b/tests/auto/gui/rhi/qrhi/data/textured.frag @@ -0,0 +1,19 @@ +#version 440 + +layout(location = 0) in vec2 uv; +layout(location = 0) out vec4 fragColor; + +layout(std140, binding = 0) uniform buf { + mat4 matrix; + float opacity; +} ubuf; + +layout(binding = 1) uniform sampler2D tex; + +void main() +{ + vec4 c = texture(tex, uv); + c.a *= ubuf.opacity; + c.rgb *= c.a; + fragColor = c; +} diff --git a/tests/auto/gui/rhi/qrhi/data/textured.frag.qsb b/tests/auto/gui/rhi/qrhi/data/textured.frag.qsb Binary files differnew file mode 100644 index 0000000000..0a039137ec --- /dev/null +++ b/tests/auto/gui/rhi/qrhi/data/textured.frag.qsb diff --git a/tests/auto/gui/rhi/qrhi/data/textured.vert b/tests/auto/gui/rhi/qrhi/data/textured.vert new file mode 100644 index 0000000000..f1ccf2ee50 --- /dev/null +++ b/tests/auto/gui/rhi/qrhi/data/textured.vert @@ -0,0 +1,19 @@ +#version 440 + +layout(location = 0) in vec4 position; +layout(location = 1) in vec2 texcoord; + +layout(location = 0) out vec2 uv; + +layout(std140, binding = 0) uniform buf { + mat4 matrix; + float opacity; +} ubuf; + +out gl_PerVertex { vec4 gl_Position; }; + +void main() +{ + uv = texcoord; + gl_Position = ubuf.matrix * position; +} diff --git a/tests/auto/gui/rhi/qrhi/data/textured.vert.qsb b/tests/auto/gui/rhi/qrhi/data/textured.vert.qsb Binary files differnew file mode 100644 index 0000000000..7853f77943 --- /dev/null +++ b/tests/auto/gui/rhi/qrhi/data/textured.vert.qsb diff --git a/tests/auto/gui/rhi/qrhi/qrhi.pro b/tests/auto/gui/rhi/qrhi/qrhi.pro new file mode 100644 index 0000000000..58000ed514 --- /dev/null +++ b/tests/auto/gui/rhi/qrhi/qrhi.pro @@ -0,0 +1,8 @@ +TARGET = tst_qrhi +CONFIG += testcase + +QT += testlib gui-private + +SOURCES += tst_qrhi.cpp + +RESOURCES += qrhi.qrc diff --git a/tests/auto/gui/rhi/qrhi/qrhi.qrc b/tests/auto/gui/rhi/qrhi/qrhi.qrc new file mode 100644 index 0000000000..f161d8aad6 --- /dev/null +++ b/tests/auto/gui/rhi/qrhi/qrhi.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/"> + <file>data</file> + </qresource> +</RCC> diff --git a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp new file mode 100644 index 0000000000..768b227ecd --- /dev/null +++ b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp @@ -0,0 +1,1729 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QThread> +#include <QFile> +#include <QOffscreenSurface> +#include <QPainter> + +#include <QtGui/private/qrhi_p.h> +#include <QtGui/private/qrhinull_p.h> + +#if QT_CONFIG(opengl) +# include <QOpenGLContext> +# include <QtGui/private/qrhigles2_p.h> +# define TST_GL +#endif + +#if QT_CONFIG(vulkan) +# include <QVulkanInstance> +# include <QtGui/private/qrhivulkan_p.h> +# define TST_VK +#endif + +#ifdef Q_OS_WIN +#include <QtGui/private/qrhid3d11_p.h> +# define TST_D3D11 +#endif + +#ifdef Q_OS_DARWIN +# include <QtGui/private/qrhimetal_p.h> +# define TST_MTL +#endif + +Q_DECLARE_METATYPE(QRhi::Implementation) +Q_DECLARE_METATYPE(QRhiInitParams *) + +class tst_QRhi : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + void cleanupTestCase(); + + void rhiTestData(); + void create_data(); + void create(); + void nativeHandles_data(); + void nativeHandles(); + void resourceUpdateBatchBuffer_data(); + void resourceUpdateBatchBuffer(); + void resourceUpdateBatchRGBATextureUpload_data(); + void resourceUpdateBatchRGBATextureUpload(); + void resourceUpdateBatchRGBATextureCopy_data(); + void resourceUpdateBatchRGBATextureCopy(); + void resourceUpdateBatchRGBATextureMip_data(); + void resourceUpdateBatchRGBATextureMip(); + void invalidPipeline_data(); + void invalidPipeline(); + void renderToTextureSimple_data(); + void renderToTextureSimple(); + void renderToTextureTexturedQuad_data(); + void renderToTextureTexturedQuad(); + void renderToTextureTexturedQuadAndUniformBuffer_data(); + void renderToTextureTexturedQuadAndUniformBuffer(); + void renderToWindowSimple_data(); + void renderToWindowSimple(); + +private: + struct { + QRhiNullInitParams null; +#ifdef TST_GL + QRhiGles2InitParams gl; +#endif +#ifdef TST_VK + QRhiVulkanInitParams vk; +#endif +#ifdef TST_D3D11 + QRhiD3D11InitParams d3d; +#endif +#ifdef TST_MTL + QRhiMetalInitParams mtl; +#endif + } initParams; + +#ifdef TST_VK + QVulkanInstance vulkanInstance; +#endif + QOffscreenSurface *fallbackSurface = nullptr; +}; + +void tst_QRhi::initTestCase() +{ +#ifdef TST_GL + fallbackSurface = QRhiGles2InitParams::newFallbackSurface(); + initParams.gl.fallbackSurface = fallbackSurface; +#endif + +#ifdef TST_VK +#ifndef Q_OS_ANDROID + vulkanInstance.setLayers({ QByteArrayLiteral("VK_LAYER_LUNARG_standard_validation") }); +#else + vulkanInstance.setLayers({ QByteArrayLiteral("VK_LAYER_GOOGLE_threading"), + QByteArrayLiteral("VK_LAYER_LUNARG_parameter_validation"), + QByteArrayLiteral("VK_LAYER_LUNARG_object_tracker"), + QByteArrayLiteral("VK_LAYER_LUNARG_core_validation"), + QByteArrayLiteral("VK_LAYER_LUNARG_image"), + QByteArrayLiteral("VK_LAYER_LUNARG_swapchain"), + QByteArrayLiteral("VK_LAYER_GOOGLE_unique_objects") }); +#endif + vulkanInstance.setExtensions(QByteArrayList() + << "VK_KHR_get_physical_device_properties2"); + vulkanInstance.create(); + initParams.vk.inst = &vulkanInstance; +#endif + +#ifdef TST_D3D11 + initParams.d3d.enableDebugLayer = true; +#endif +} + +void tst_QRhi::cleanupTestCase() +{ +#ifdef TST_VK + vulkanInstance.destroy(); +#endif + + delete fallbackSurface; +} + +void tst_QRhi::rhiTestData() +{ + QTest::addColumn<QRhi::Implementation>("impl"); + QTest::addColumn<QRhiInitParams *>("initParams"); + + QTest::newRow("Null") << QRhi::Null << static_cast<QRhiInitParams *>(&initParams.null); +#ifdef TST_GL + QTest::newRow("OpenGL") << QRhi::OpenGLES2 << static_cast<QRhiInitParams *>(&initParams.gl); +#endif +#ifdef TST_VK + if (vulkanInstance.isValid()) + QTest::newRow("Vulkan") << QRhi::Vulkan << static_cast<QRhiInitParams *>(&initParams.vk); +#endif +#ifdef TST_D3D11 + QTest::newRow("Direct3D 11") << QRhi::D3D11 << static_cast<QRhiInitParams *>(&initParams.d3d); +#endif +#ifdef TST_MTL + QTest::newRow("Metal") << QRhi::Metal << static_cast<QRhiInitParams *>(&initParams.mtl); +#endif +} + +void tst_QRhi::create_data() +{ + rhiTestData(); +} + +static int aligned(int v, int a) +{ + return (v + a - 1) & ~(a - 1); +} + +void tst_QRhi::create() +{ + // Merely attempting to create a QRhi should survive, with an error when + // not supported. (of course, there is always a chance we encounter a crash + // due to some random graphics stack...) + + QFETCH(QRhi::Implementation, impl); + QFETCH(QRhiInitParams *, initParams); + + QScopedPointer<QRhi> rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr)); + + if (rhi) { + QCOMPARE(rhi->backend(), impl); + QCOMPARE(rhi->thread(), QThread::currentThread()); + + // do a basic smoke test for the apis that do not directly render anything + + int cleanupOk = 0; + QRhi *rhiPtr = rhi.data(); + auto cleanupFunc = [rhiPtr, &cleanupOk](QRhi *dyingRhi) { + if (rhiPtr == dyingRhi) + cleanupOk += 1; + }; + rhi->addCleanupCallback(cleanupFunc); + rhi->runCleanup(); + QCOMPARE(cleanupOk, 1); + cleanupOk = 0; + rhi->addCleanupCallback(cleanupFunc); + + QRhiResourceUpdateBatch *resUpd = rhi->nextResourceUpdateBatch(); + QVERIFY(resUpd); + resUpd->release(); + + QVERIFY(!rhi->supportedSampleCounts().isEmpty()); + QVERIFY(rhi->supportedSampleCounts().contains(1)); + + QVERIFY(rhi->ubufAlignment() > 0); + QCOMPARE(rhi->ubufAligned(123), aligned(123, rhi->ubufAlignment())); + + QCOMPARE(rhi->mipLevelsForSize(QSize(512, 300)), 10); + QCOMPARE(rhi->sizeForMipLevel(0, QSize(512, 300)), QSize(512, 300)); + QCOMPARE(rhi->sizeForMipLevel(1, QSize(512, 300)), QSize(256, 150)); + QCOMPARE(rhi->sizeForMipLevel(2, QSize(512, 300)), QSize(128, 75)); + QCOMPARE(rhi->sizeForMipLevel(9, QSize(512, 300)), QSize(1, 1)); + + const bool fbUp = rhi->isYUpInFramebuffer(); + const bool ndcUp = rhi->isYUpInNDC(); + const bool d0to1 = rhi->isClipDepthZeroToOne(); + const QMatrix4x4 corrMat = rhi->clipSpaceCorrMatrix(); + if (impl == QRhi::OpenGLES2) { + QVERIFY(fbUp); + QVERIFY(ndcUp); + QVERIFY(!d0to1); + QVERIFY(corrMat.isIdentity()); + } else if (impl == QRhi::Vulkan) { + QVERIFY(!fbUp); + QVERIFY(!ndcUp); + QVERIFY(d0to1); + QVERIFY(!corrMat.isIdentity()); + } else if (impl == QRhi::D3D11) { + QVERIFY(!fbUp); + QVERIFY(ndcUp); + QVERIFY(d0to1); + QVERIFY(!corrMat.isIdentity()); + } else if (impl == QRhi::Metal) { + QVERIFY(!fbUp); + QVERIFY(ndcUp); + QVERIFY(d0to1); + QVERIFY(!corrMat.isIdentity()); + } + + const int texMin = rhi->resourceLimit(QRhi::TextureSizeMin); + const int texMax = rhi->resourceLimit(QRhi::TextureSizeMax); + const int maxAtt = rhi->resourceLimit(QRhi::MaxColorAttachments); + const int framesInFlight = rhi->resourceLimit(QRhi::FramesInFlight); + QVERIFY(texMin >= 1); + QVERIFY(texMax >= texMin); + QVERIFY(maxAtt >= 1); + QVERIFY(framesInFlight >= 1); + + QVERIFY(rhi->nativeHandles()); + QVERIFY(rhi->profiler()); + + const QRhi::Feature features[] = { + QRhi::MultisampleTexture, + QRhi::MultisampleRenderBuffer, + QRhi::DebugMarkers, + QRhi::Timestamps, + QRhi::Instancing, + QRhi::CustomInstanceStepRate, + QRhi::PrimitiveRestart, + QRhi::NonDynamicUniformBuffers, + QRhi::NonFourAlignedEffectiveIndexBufferOffset, + QRhi::NPOTTextureRepeat, + QRhi::RedOrAlpha8IsRed, + QRhi::ElementIndexUint, + QRhi::Compute, + QRhi::WideLines, + QRhi::VertexShaderPointSize, + QRhi::BaseVertex, + QRhi::BaseInstance, + QRhi::TriangleFanTopology, + QRhi::ReadBackNonUniformBuffer, + QRhi::ReadBackNonBaseMipLevel + }; + for (size_t i = 0; i <sizeof(features) / sizeof(QRhi::Feature); ++i) + rhi->isFeatureSupported(features[i]); + + QVERIFY(rhi->isTextureFormatSupported(QRhiTexture::RGBA8)); + + rhi->releaseCachedResources(); + + QVERIFY(!rhi->isDeviceLost()); + + rhi.reset(); + QCOMPARE(cleanupOk, 1); + } +} + +void tst_QRhi::nativeHandles_data() +{ + rhiTestData(); +} + +void tst_QRhi::nativeHandles() +{ + QFETCH(QRhi::Implementation, impl); + QFETCH(QRhiInitParams *, initParams); + + QScopedPointer<QRhi> rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr)); + if (!rhi) + QSKIP("QRhi could not be created, skipping testing native handles"); + + // QRhi::nativeHandles() + { + const QRhiNativeHandles *rhiHandles = rhi->nativeHandles(); + Q_ASSERT(rhiHandles); + + switch (impl) { + case QRhi::Null: + break; +#ifdef TST_VK + case QRhi::Vulkan: + { + const QRhiVulkanNativeHandles *vkHandles = static_cast<const QRhiVulkanNativeHandles *>(rhiHandles); + QVERIFY(vkHandles->physDev); + QVERIFY(vkHandles->dev); + QVERIFY(vkHandles->gfxQueueFamilyIdx >= 0); + QVERIFY(vkHandles->gfxQueue); + QVERIFY(vkHandles->cmdPool); + QVERIFY(vkHandles->vmemAllocator); + } + break; +#endif +#ifdef TST_GL + case QRhi::OpenGLES2: + { + const QRhiGles2NativeHandles *glHandles = static_cast<const QRhiGles2NativeHandles *>(rhiHandles); + QVERIFY(glHandles->context); + QVERIFY(glHandles->context->isValid()); + glHandles->context->doneCurrent(); + QVERIFY(!QOpenGLContext::currentContext()); + rhi->makeThreadLocalNativeContextCurrent(); + QVERIFY(QOpenGLContext::currentContext() == glHandles->context); + } + break; +#endif +#ifdef TST_D3D11 + case QRhi::D3D11: + { + const QRhiD3D11NativeHandles *d3dHandles = static_cast<const QRhiD3D11NativeHandles *>(rhiHandles); + QVERIFY(d3dHandles->dev); + QVERIFY(d3dHandles->context); + } + break; +#endif +#ifdef TST_MTL + case QRhi::Metal: + { + const QRhiMetalNativeHandles *mtlHandles = static_cast<const QRhiMetalNativeHandles *>(rhiHandles); + QVERIFY(mtlHandles->dev); + QVERIFY(mtlHandles->cmdQueue); + } + break; +#endif + default: + Q_ASSERT(false); + } + } + + // QRhiTexture::nativeHandles() + { + QScopedPointer<QRhiTexture> tex(rhi->newTexture(QRhiTexture::RGBA8, QSize(512, 256))); + QVERIFY(tex->build()); + + const QRhiNativeHandles *texHandles = tex->nativeHandles(); + QVERIFY(texHandles); + + switch (impl) { + case QRhi::Null: + break; +#ifdef TST_VK + case QRhi::Vulkan: + { + const QRhiVulkanTextureNativeHandles *vkHandles = static_cast<const QRhiVulkanTextureNativeHandles *>(texHandles); + QVERIFY(vkHandles->image); + QVERIFY(vkHandles->layout >= 1); // VK_IMAGE_LAYOUT_GENERAL + QVERIFY(vkHandles->layout <= 8); // VK_IMAGE_LAYOUT_PREINITIALIZED + } + break; +#endif +#ifdef TST_GL + case QRhi::OpenGLES2: + { + const QRhiGles2TextureNativeHandles *glHandles = static_cast<const QRhiGles2TextureNativeHandles *>(texHandles); + QVERIFY(glHandles->texture); + } + break; +#endif +#ifdef TST_D3D11 + case QRhi::D3D11: + { + const QRhiD3D11TextureNativeHandles *d3dHandles = static_cast<const QRhiD3D11TextureNativeHandles *>(texHandles); + QVERIFY(d3dHandles->texture); + } + break; +#endif +#ifdef TST_MTL + case QRhi::Metal: + { + const QRhiMetalTextureNativeHandles *mtlHandles = static_cast<const QRhiMetalTextureNativeHandles *>(texHandles); + QVERIFY(mtlHandles->texture); + } + break; +#endif + default: + Q_ASSERT(false); + } + } + + // QRhiCommandBuffer::nativeHandles() + { + QRhiCommandBuffer *cb = nullptr; + QRhi::FrameOpResult result = rhi->beginOffscreenFrame(&cb); + QVERIFY(result == QRhi::FrameOpSuccess); + QVERIFY(cb); + + const QRhiNativeHandles *cbHandles = cb->nativeHandles(); + // no null check here, backends where not applicable will return null + + switch (impl) { + case QRhi::Null: + break; +#ifdef TST_VK + case QRhi::Vulkan: + { + const QRhiVulkanCommandBufferNativeHandles *vkHandles = static_cast<const QRhiVulkanCommandBufferNativeHandles *>(cbHandles); + QVERIFY(vkHandles); + QVERIFY(vkHandles->commandBuffer); + } + break; +#endif +#ifdef TST_GL + case QRhi::OpenGLES2: + break; +#endif +#ifdef TST_D3D11 + case QRhi::D3D11: + break; +#endif +#ifdef TST_MTL + case QRhi::Metal: + { + const QRhiMetalCommandBufferNativeHandles *mtlHandles = static_cast<const QRhiMetalCommandBufferNativeHandles *>(cbHandles); + QVERIFY(mtlHandles); + QVERIFY(mtlHandles->commandBuffer); + QVERIFY(!mtlHandles->encoder); + + QScopedPointer<QRhiTexture> tex(rhi->newTexture(QRhiTexture::RGBA8, QSize(512, 512), 1, QRhiTexture::RenderTarget)); + QVERIFY(tex->build()); + QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget({ tex.data() })); + QScopedPointer<QRhiRenderPassDescriptor> rpDesc(rt->newCompatibleRenderPassDescriptor()); + QVERIFY(rpDesc); + rt->setRenderPassDescriptor(rpDesc.data()); + QVERIFY(rt->build()); + cb->beginPass(rt.data(), Qt::red, { 1.0f, 0 }); + QVERIFY(static_cast<const QRhiMetalCommandBufferNativeHandles *>(cb->nativeHandles())->encoder); + cb->endPass(); + } + break; +#endif + default: + Q_ASSERT(false); + } + + rhi->endOffscreenFrame(); + } + + // QRhiRenderPassDescriptor::nativeHandles() + { + QScopedPointer<QRhiTexture> tex(rhi->newTexture(QRhiTexture::RGBA8, QSize(512, 512), 1, QRhiTexture::RenderTarget)); + QVERIFY(tex->build()); + QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget({ tex.data() })); + QScopedPointer<QRhiRenderPassDescriptor> rpDesc(rt->newCompatibleRenderPassDescriptor()); + QVERIFY(rpDesc); + rt->setRenderPassDescriptor(rpDesc.data()); + QVERIFY(rt->build()); + + const QRhiNativeHandles *rpHandles = rpDesc->nativeHandles(); + switch (impl) { + case QRhi::Null: + break; +#ifdef TST_VK + case QRhi::Vulkan: + { + const QRhiVulkanRenderPassNativeHandles *vkHandles = static_cast<const QRhiVulkanRenderPassNativeHandles *>(rpHandles); + QVERIFY(vkHandles); + QVERIFY(vkHandles->renderPass); + } + break; +#endif +#ifdef TST_GL + case QRhi::OpenGLES2: + break; +#endif +#ifdef TST_D3D11 + case QRhi::D3D11: + break; +#endif +#ifdef TST_MTL + case QRhi::Metal: + break; +#endif + default: + Q_ASSERT(false); + } + } +} + +static bool submitResourceUpdates(QRhi *rhi, QRhiResourceUpdateBatch *batch) +{ + QRhiCommandBuffer *cb = nullptr; + QRhi::FrameOpResult result = rhi->beginOffscreenFrame(&cb); + if (result != QRhi::FrameOpSuccess) { + qWarning("beginOffscreenFrame returned %d", result); + return false; + } + if (!cb) { + qWarning("No command buffer from beginOffscreenFrame"); + return false; + } + cb->resourceUpdate(batch); + rhi->endOffscreenFrame(); + return true; +} + +void tst_QRhi::resourceUpdateBatchBuffer_data() +{ + rhiTestData(); +} + +void tst_QRhi::resourceUpdateBatchBuffer() +{ + QFETCH(QRhi::Implementation, impl); + QFETCH(QRhiInitParams *, initParams); + + QScopedPointer<QRhi> rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr)); + if (!rhi) + QSKIP("QRhi could not be created, skipping testing buffer resource updates"); + + const int bufferSize = 23; + const QByteArray a(bufferSize, 'A'); + const QByteArray b(bufferSize, 'B'); + + // dynamic buffer, updates, readback + { + QScopedPointer<QRhiBuffer> dynamicBuffer(rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, bufferSize)); + QVERIFY(dynamicBuffer->build()); + + QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch(); + QVERIFY(batch); + + batch->updateDynamicBuffer(dynamicBuffer.data(), 10, bufferSize - 10, a.constData()); + batch->updateDynamicBuffer(dynamicBuffer.data(), 0, 12, b.constData()); + + QRhiBufferReadbackResult readResult; + bool readCompleted = false; + readResult.completed = [&readCompleted] { readCompleted = true; }; + batch->readBackBuffer(dynamicBuffer.data(), 5, 10, &readResult); + + QVERIFY(submitResourceUpdates(rhi.data(), batch)); + + // Offscreen frames are synchronous, so the readback must have + // completed at this point. With swapchain frames this would not be the + // case. + QVERIFY(readCompleted); + QVERIFY(readResult.data.size() == 10); + QCOMPARE(readResult.data.left(7), QByteArrayLiteral("BBBBBBB")); + QCOMPARE(readResult.data.mid(7), QByteArrayLiteral("AAA")); + } + + // static buffer, updates, readback + { + QScopedPointer<QRhiBuffer> dynamicBuffer(rhi->newBuffer(QRhiBuffer::Static, QRhiBuffer::VertexBuffer, bufferSize)); + QVERIFY(dynamicBuffer->build()); + + QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch(); + QVERIFY(batch); + + batch->uploadStaticBuffer(dynamicBuffer.data(), 10, bufferSize - 10, a.constData()); + batch->uploadStaticBuffer(dynamicBuffer.data(), 0, 12, b.constData()); + + QRhiBufferReadbackResult readResult; + bool readCompleted = false; + readResult.completed = [&readCompleted] { readCompleted = true; }; + + if (rhi->isFeatureSupported(QRhi::ReadBackNonUniformBuffer)) + batch->readBackBuffer(dynamicBuffer.data(), 5, 10, &readResult); + + QVERIFY(submitResourceUpdates(rhi.data(), batch)); + + if (rhi->isFeatureSupported(QRhi::ReadBackNonUniformBuffer)) { + QVERIFY(readCompleted); + QVERIFY(readResult.data.size() == 10); + QCOMPARE(readResult.data.left(7), QByteArrayLiteral("BBBBBBB")); + QCOMPARE(readResult.data.mid(7), QByteArrayLiteral("AAA")); + } else { + qDebug("Skipping verifying buffer contents because readback is not supported"); + } + } +} + +inline bool imageRGBAEquals(const QImage &a, const QImage &b) +{ + const int maxFuzz = 1; + + if (a.size() != b.size()) + return false; + + const QImage image0 = a.convertToFormat(QImage::Format_RGBA8888_Premultiplied); + const QImage image1 = b.convertToFormat(QImage::Format_RGBA8888_Premultiplied); + + const int width = image0.width(); + const int height = image0.height(); + for (int y = 0; y < height; ++y) { + const quint32 *p0 = reinterpret_cast<const quint32 *>(image0.constScanLine(y)); + const quint32 *p1 = reinterpret_cast<const quint32 *>(image1.constScanLine(y)); + int x = width - 1; + while (x-- >= 0) { + const QRgb c0(*p0++); + const QRgb c1(*p1++); + const int red = qAbs(qRed(c0) - qRed(c1)); + const int green = qAbs(qGreen(c0) - qGreen(c1)); + const int blue = qAbs(qBlue(c0) - qBlue(c1)); + const int alpha = qAbs(qAlpha(c0) - qAlpha(c1)); + if (red > maxFuzz || green > maxFuzz || blue > maxFuzz || alpha > maxFuzz) + return false; + } + } + + return true; +} + +void tst_QRhi::resourceUpdateBatchRGBATextureUpload_data() +{ + rhiTestData(); +} + +void tst_QRhi::resourceUpdateBatchRGBATextureUpload() +{ + QFETCH(QRhi::Implementation, impl); + QFETCH(QRhiInitParams *, initParams); + + QScopedPointer<QRhi> rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr)); + if (!rhi) + QSKIP("QRhi could not be created, skipping testing texture resource updates"); + + QImage image(234, 123, QImage::Format_RGBA8888_Premultiplied); + image.fill(Qt::red); + QPainter painter; + const QPoint greenRectPos(35, 50); + const QSize greenRectSize(100, 50); + painter.begin(&image); + painter.fillRect(QRect(greenRectPos, greenRectSize), Qt::green); + painter.end(); + + // simple image upload; uploading and reading back RGBA8 is supported by the Null backend even + { + QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA8, image.size(), + 1, QRhiTexture::UsedAsTransferSource)); + QVERIFY(texture->build()); + + QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch(); + batch->uploadTexture(texture.data(), image); + + QRhiReadbackResult readResult; + bool readCompleted = false; + readResult.completed = [&readCompleted] { readCompleted = true; }; + batch->readBackTexture(texture.data(), &readResult); + + QVERIFY(submitResourceUpdates(rhi.data(), batch)); + // like with buffers, the readback is now complete due to endOffscreenFrame() + QVERIFY(readCompleted); + QCOMPARE(readResult.format, QRhiTexture::RGBA8); + QCOMPARE(readResult.pixelSize, image.size()); + + QImage wrapperImage(reinterpret_cast<const uchar *>(readResult.data.constData()), + readResult.pixelSize.width(), readResult.pixelSize.height(), + image.format()); + + QVERIFY(imageRGBAEquals(image, wrapperImage)); + } + + // the same with raw data + { + QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA8, image.size(), + 1, QRhiTexture::UsedAsTransferSource)); + QVERIFY(texture->build()); + + QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch(); + + QRhiTextureUploadEntry upload(0, 0, { image.constBits(), int(image.sizeInBytes()) }); + QRhiTextureUploadDescription uploadDesc(upload); + batch->uploadTexture(texture.data(), uploadDesc); + + QRhiReadbackResult readResult; + bool readCompleted = false; + readResult.completed = [&readCompleted] { readCompleted = true; }; + batch->readBackTexture(texture.data(), &readResult); + + QVERIFY(submitResourceUpdates(rhi.data(), batch)); + QVERIFY(readCompleted); + QCOMPARE(readResult.format, QRhiTexture::RGBA8); + QCOMPARE(readResult.pixelSize, image.size()); + + QImage wrapperImage(reinterpret_cast<const uchar *>(readResult.data.constData()), + readResult.pixelSize.width(), readResult.pixelSize.height(), + image.format()); + + QVERIFY(imageRGBAEquals(image, wrapperImage)); + } + + // partial image upload at a non-zero destination position + { + const QSize copySize(30, 40); + const int gap = 10; + const QSize fullSize(copySize.width() + gap, copySize.height() + gap); + QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA8, fullSize, + 1, QRhiTexture::UsedAsTransferSource)); + QVERIFY(texture->build()); + + QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch(); + + QImage clearImage(fullSize, image.format()); + clearImage.fill(Qt::black); + batch->uploadTexture(texture.data(), clearImage); + + // copy green pixels of copySize to (gap, gap), leaving a black bar of + // gap pixels on the left and top + QRhiTextureSubresourceUploadDescription desc; + desc.setImage(image); + desc.setSourceSize(copySize); + desc.setDestinationTopLeft(QPoint(gap, gap)); + desc.setSourceTopLeft(greenRectPos); + + batch->uploadTexture(texture.data(), QRhiTextureUploadDescription({ 0, 0, desc })); + + QRhiReadbackResult readResult; + bool readCompleted = false; + readResult.completed = [&readCompleted] { readCompleted = true; }; + batch->readBackTexture(texture.data(), &readResult); + + QVERIFY(submitResourceUpdates(rhi.data(), batch)); + QVERIFY(readCompleted); + QCOMPARE(readResult.format, QRhiTexture::RGBA8); + QCOMPARE(readResult.pixelSize, clearImage.size()); + + QImage wrapperImage(reinterpret_cast<const uchar *>(readResult.data.constData()), + readResult.pixelSize.width(), readResult.pixelSize.height(), + image.format()); + + QVERIFY(!imageRGBAEquals(clearImage, wrapperImage)); + + QImage expectedImage = clearImage; + QPainter painter(&expectedImage); + painter.fillRect(QRect(QPoint(gap, gap), QSize(copySize)), Qt::green); + painter.end(); + + QVERIFY(imageRGBAEquals(expectedImage, wrapperImage)); + } + + // the same (partial upload) with raw data as source + { + const QSize copySize(30, 40); + const int gap = 10; + const QSize fullSize(copySize.width() + gap, copySize.height() + gap); + QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA8, fullSize, + 1, QRhiTexture::UsedAsTransferSource)); + QVERIFY(texture->build()); + + QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch(); + + QImage clearImage(fullSize, image.format()); + clearImage.fill(Qt::black); + batch->uploadTexture(texture.data(), clearImage); + + // SourceTopLeft is not supported for non-QImage-based uploads. + const QImage im = image.copy(QRect(greenRectPos, copySize)); + QRhiTextureSubresourceUploadDescription desc; + desc.setData(QByteArray::fromRawData(reinterpret_cast<const char *>(im.constBits()), + int(im.sizeInBytes()))); + desc.setSourceSize(copySize); + desc.setDestinationTopLeft(QPoint(gap, gap)); + + batch->uploadTexture(texture.data(), QRhiTextureUploadDescription({ 0, 0, desc })); + + QRhiReadbackResult readResult; + bool readCompleted = false; + readResult.completed = [&readCompleted] { readCompleted = true; }; + batch->readBackTexture(texture.data(), &readResult); + + QVERIFY(submitResourceUpdates(rhi.data(), batch)); + QVERIFY(readCompleted); + QCOMPARE(readResult.format, QRhiTexture::RGBA8); + QCOMPARE(readResult.pixelSize, clearImage.size()); + + QImage wrapperImage(reinterpret_cast<const uchar *>(readResult.data.constData()), + readResult.pixelSize.width(), readResult.pixelSize.height(), + image.format()); + + QVERIFY(!imageRGBAEquals(clearImage, wrapperImage)); + + QImage expectedImage = clearImage; + QPainter painter(&expectedImage); + painter.fillRect(QRect(QPoint(gap, gap), QSize(copySize)), Qt::green); + painter.end(); + + QVERIFY(imageRGBAEquals(expectedImage, wrapperImage)); + } + + // now a QImage from an actual file + { + QImage inputImage; + inputImage.load(QLatin1String(":/data/qt256.png")); + QVERIFY(!inputImage.isNull()); + inputImage = std::move(inputImage).convertToFormat(image.format()); + + QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA8, inputImage.size(), + 1, QRhiTexture::UsedAsTransferSource)); + QVERIFY(texture->build()); + + QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch(); + batch->uploadTexture(texture.data(), inputImage); + + QRhiReadbackResult readResult; + bool readCompleted = false; + readResult.completed = [&readCompleted] { readCompleted = true; }; + batch->readBackTexture(texture.data(), &readResult); + + QVERIFY(submitResourceUpdates(rhi.data(), batch)); + QVERIFY(readCompleted); + QImage wrapperImage(reinterpret_cast<const uchar *>(readResult.data.constData()), + readResult.pixelSize.width(), readResult.pixelSize.height(), + inputImage.format()); + + QVERIFY(imageRGBAEquals(inputImage, wrapperImage)); + } +} + +void tst_QRhi::resourceUpdateBatchRGBATextureCopy_data() +{ + rhiTestData(); +} + +void tst_QRhi::resourceUpdateBatchRGBATextureCopy() +{ + QFETCH(QRhi::Implementation, impl); + QFETCH(QRhiInitParams *, initParams); + + QScopedPointer<QRhi> rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr)); + if (!rhi) + QSKIP("QRhi could not be created, skipping testing texture resource updates"); + + QImage red(256, 256, QImage::Format_RGBA8888_Premultiplied); + red.fill(Qt::red); + + QImage green(35, 73, red.format()); + green.fill(Qt::green); + + QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch(); + + QScopedPointer<QRhiTexture> redTexture(rhi->newTexture(QRhiTexture::RGBA8, red.size(), + 1, QRhiTexture::UsedAsTransferSource)); + QVERIFY(redTexture->build()); + batch->uploadTexture(redTexture.data(), red); + + QScopedPointer<QRhiTexture> greenTexture(rhi->newTexture(QRhiTexture::RGBA8, green.size(), + 1, QRhiTexture::UsedAsTransferSource)); + QVERIFY(greenTexture->build()); + batch->uploadTexture(greenTexture.data(), green); + + // 1. simple copy red -> texture; 2. subimage copy green -> texture; 3. partial subimage copy green -> texture + { + QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA8, red.size(), + 1, QRhiTexture::UsedAsTransferSource)); + QVERIFY(texture->build()); + + // 1. + batch->copyTexture(texture.data(), redTexture.data()); + + QRhiReadbackResult readResult; + bool readCompleted = false; + readResult.completed = [&readCompleted] { readCompleted = true; }; + batch->readBackTexture(texture.data(), &readResult); + QVERIFY(submitResourceUpdates(rhi.data(), batch)); + QVERIFY(readCompleted); + QImage wrapperImage(reinterpret_cast<const uchar *>(readResult.data.constData()), + readResult.pixelSize.width(), readResult.pixelSize.height(), + red.format()); + QVERIFY(imageRGBAEquals(red, wrapperImage)); + + batch = rhi->nextResourceUpdateBatch(); + readCompleted = false; + + // 2. + QRhiTextureCopyDescription copyDesc; + copyDesc.setDestinationTopLeft(QPoint(15, 23)); + batch->copyTexture(texture.data(), greenTexture.data(), copyDesc); + + batch->readBackTexture(texture.data(), &readResult); + QVERIFY(submitResourceUpdates(rhi.data(), batch)); + QVERIFY(readCompleted); + wrapperImage = QImage(reinterpret_cast<const uchar *>(readResult.data.constData()), + readResult.pixelSize.width(), readResult.pixelSize.height(), + red.format()); + + QImage expectedImage = red; + QPainter painter(&expectedImage); + painter.drawImage(copyDesc.destinationTopLeft(), green); + painter.end(); + + QVERIFY(imageRGBAEquals(expectedImage, wrapperImage)); + + batch = rhi->nextResourceUpdateBatch(); + readCompleted = false; + + // 3. + copyDesc.setDestinationTopLeft(QPoint(125, 89)); + copyDesc.setSourceTopLeft(QPoint(5, 5)); + copyDesc.setPixelSize(QSize(26, 45)); + batch->copyTexture(texture.data(), greenTexture.data(), copyDesc); + + batch->readBackTexture(texture.data(), &readResult); + QVERIFY(submitResourceUpdates(rhi.data(), batch)); + QVERIFY(readCompleted); + wrapperImage = QImage(reinterpret_cast<const uchar *>(readResult.data.constData()), + readResult.pixelSize.width(), readResult.pixelSize.height(), + red.format()); + + painter.begin(&expectedImage); + painter.drawImage(copyDesc.destinationTopLeft(), green, + QRect(copyDesc.sourceTopLeft(), copyDesc.pixelSize())); + painter.end(); + + QVERIFY(imageRGBAEquals(expectedImage, wrapperImage)); + } +} + +void tst_QRhi::resourceUpdateBatchRGBATextureMip_data() +{ + rhiTestData(); +} + +void tst_QRhi::resourceUpdateBatchRGBATextureMip() +{ + QFETCH(QRhi::Implementation, impl); + QFETCH(QRhiInitParams *, initParams); + + QScopedPointer<QRhi> rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr)); + if (!rhi) + QSKIP("QRhi could not be created, skipping testing texture resource updates"); + + + QImage red(512, 512, QImage::Format_RGBA8888_Premultiplied); + red.fill(Qt::red); + + const QRhiTexture::Flags textureFlags = + QRhiTexture::UsedAsTransferSource + | QRhiTexture::MipMapped + | QRhiTexture::UsedWithGenerateMips; + QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA8, red.size(), 1, textureFlags)); + QVERIFY(texture->build()); + + QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch(); + batch->uploadTexture(texture.data(), red); + batch->generateMips(texture.data()); + QVERIFY(submitResourceUpdates(rhi.data(), batch)); + + const int levelCount = rhi->mipLevelsForSize(red.size()); + QCOMPARE(levelCount, 10); + for (int level = 0; level < levelCount; ++level) { + batch = rhi->nextResourceUpdateBatch(); + + QRhiReadbackDescription readDesc(texture.data()); + readDesc.setLevel(level); + QRhiReadbackResult readResult; + bool readCompleted = false; + readResult.completed = [&readCompleted] { readCompleted = true; }; + batch->readBackTexture(readDesc, &readResult); + + QVERIFY(submitResourceUpdates(rhi.data(), batch)); + QVERIFY(readCompleted); + + const QSize expectedSize = rhi->sizeForMipLevel(level, texture->pixelSize()); + QCOMPARE(readResult.pixelSize, expectedSize); + + QImage wrapperImage(reinterpret_cast<const uchar *>(readResult.data.constData()), + readResult.pixelSize.width(), readResult.pixelSize.height(), + red.format()); + QImage expectedImage; + if (level == 0 || rhi->isFeatureSupported(QRhi::ReadBackNonBaseMipLevel)) { + // Compare to a scaled version; we can do this safely only because we + // only have plain red pixels in the source image. + expectedImage = red.scaled(expectedSize); + } else { + qDebug("Expecting all-zero image for level %d because reading back a level other than 0 is not supported", level); + expectedImage = QImage(readResult.pixelSize, red.format()); + expectedImage.fill(0); + } + QVERIFY(imageRGBAEquals(expectedImage, wrapperImage)); + } +} + +static QShader loadShader(const char *name) +{ + QFile f(QString::fromUtf8(name)); + if (f.open(QIODevice::ReadOnly)) { + const QByteArray contents = f.readAll(); + return QShader::fromSerialized(contents); + } + return QShader(); +} + +void tst_QRhi::invalidPipeline_data() +{ + rhiTestData(); +} + +void tst_QRhi::invalidPipeline() +{ + QFETCH(QRhi::Implementation, impl); + QFETCH(QRhiInitParams *, initParams); + + QScopedPointer<QRhi> rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr)); + if (!rhi) + QSKIP("QRhi could not be created, skipping testing empty shader"); + + QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA8, QSize(256, 256), 1, QRhiTexture::RenderTarget)); + QVERIFY(texture->build()); + QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget({ texture.data() })); + QScopedPointer<QRhiRenderPassDescriptor> rpDesc(rt->newCompatibleRenderPassDescriptor()); + rt->setRenderPassDescriptor(rpDesc.data()); + QVERIFY(rt->build()); + + QRhiCommandBuffer *cb = nullptr; + QVERIFY(rhi->beginOffscreenFrame(&cb) == QRhi::FrameOpSuccess); + QVERIFY(cb); + + QScopedPointer<QRhiShaderResourceBindings> srb(rhi->newShaderResourceBindings()); + QVERIFY(srb->build()); + + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ { 2 * sizeof(float) } }); + inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float2, 0 } }); + + // no stages + QScopedPointer<QRhiGraphicsPipeline> pipeline(rhi->newGraphicsPipeline()); + pipeline->setVertexInputLayout(inputLayout); + pipeline->setShaderResourceBindings(srb.data()); + pipeline->setRenderPassDescriptor(rpDesc.data()); + QVERIFY(!pipeline->build()); + + QShader vs; + QShader fs; + + // no shaders in the stages + pipeline.reset(rhi->newGraphicsPipeline()); + pipeline->setShaderStages({ { QRhiShaderStage::Vertex, vs }, { QRhiShaderStage::Fragment, fs } }); + pipeline->setVertexInputLayout(inputLayout); + pipeline->setShaderResourceBindings(srb.data()); + pipeline->setRenderPassDescriptor(rpDesc.data()); + QVERIFY(!pipeline->build()); + + vs = loadShader(":/data/simple.vert.qsb"); + QVERIFY(vs.isValid()); + fs = loadShader(":/data/simple.frag.qsb"); + QVERIFY(fs.isValid()); + + // no vertex stage + pipeline.reset(rhi->newGraphicsPipeline()); + pipeline->setShaderStages({ { QRhiShaderStage::Fragment, fs } }); + pipeline->setVertexInputLayout(inputLayout); + pipeline->setShaderResourceBindings(srb.data()); + pipeline->setRenderPassDescriptor(rpDesc.data()); + QVERIFY(!pipeline->build()); + + // no vertex inputs + pipeline.reset(rhi->newGraphicsPipeline()); + pipeline->setShaderStages({ { QRhiShaderStage::Vertex, vs }, { QRhiShaderStage::Fragment, fs } }); + pipeline->setRenderPassDescriptor(rpDesc.data()); + pipeline->setShaderResourceBindings(srb.data()); + QVERIFY(!pipeline->build()); + + // no renderpass descriptor + pipeline.reset(rhi->newGraphicsPipeline()); + pipeline->setShaderStages({ { QRhiShaderStage::Vertex, vs }, { QRhiShaderStage::Fragment, fs } }); + pipeline->setVertexInputLayout(inputLayout); + pipeline->setShaderResourceBindings(srb.data()); + QVERIFY(!pipeline->build()); + + // no shader resource bindings + pipeline.reset(rhi->newGraphicsPipeline()); + pipeline->setShaderStages({ { QRhiShaderStage::Vertex, vs }, { QRhiShaderStage::Fragment, fs } }); + pipeline->setVertexInputLayout(inputLayout); + pipeline->setRenderPassDescriptor(rpDesc.data()); + QVERIFY(!pipeline->build()); + + // correct + pipeline.reset(rhi->newGraphicsPipeline()); + pipeline->setShaderStages({ { QRhiShaderStage::Vertex, vs }, { QRhiShaderStage::Fragment, fs } }); + pipeline->setVertexInputLayout(inputLayout); + pipeline->setRenderPassDescriptor(rpDesc.data()); + pipeline->setShaderResourceBindings(srb.data()); + QVERIFY(pipeline->build()); +} + +void tst_QRhi::renderToTextureSimple_data() +{ + rhiTestData(); +} + +void tst_QRhi::renderToTextureSimple() +{ + QFETCH(QRhi::Implementation, impl); + QFETCH(QRhiInitParams *, initParams); + + QScopedPointer<QRhi> rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr)); + if (!rhi) + QSKIP("QRhi could not be created, skipping testing rendering"); + + const QSize outputSize(1920, 1080); + QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA8, outputSize, 1, + QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource)); + QVERIFY(texture->build()); + + QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget({ texture.data() })); + QScopedPointer<QRhiRenderPassDescriptor> rpDesc(rt->newCompatibleRenderPassDescriptor()); + rt->setRenderPassDescriptor(rpDesc.data()); + QVERIFY(rt->build()); + + QRhiCommandBuffer *cb = nullptr; + QVERIFY(rhi->beginOffscreenFrame(&cb) == QRhi::FrameOpSuccess); + QVERIFY(cb); + + QRhiResourceUpdateBatch *updates = rhi->nextResourceUpdateBatch(); + + static const float vertices[] = { + -1.0f, -1.0f, + 1.0f, -1.0f, + 0.0f, 1.0f + }; + QScopedPointer<QRhiBuffer> vbuf(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertices))); + QVERIFY(vbuf->build()); + updates->uploadStaticBuffer(vbuf.data(), vertices); + + QScopedPointer<QRhiShaderResourceBindings> srb(rhi->newShaderResourceBindings()); + QVERIFY(srb->build()); + + QScopedPointer<QRhiGraphicsPipeline> pipeline(rhi->newGraphicsPipeline()); + QShader vs = loadShader(":/data/simple.vert.qsb"); + QVERIFY(vs.isValid()); + QShader fs = loadShader(":/data/simple.frag.qsb"); + QVERIFY(fs.isValid()); + pipeline->setShaderStages({ { QRhiShaderStage::Vertex, vs }, { QRhiShaderStage::Fragment, fs } }); + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ { 2 * sizeof(float) } }); + inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float2, 0 } }); + pipeline->setVertexInputLayout(inputLayout); + pipeline->setShaderResourceBindings(srb.data()); + pipeline->setRenderPassDescriptor(rpDesc.data()); + + QVERIFY(pipeline->build()); + + cb->beginPass(rt.data(), Qt::blue, { 1.0f, 0 }, updates); + cb->setGraphicsPipeline(pipeline.data()); + cb->setViewport({ 0, 0, float(outputSize.width()), float(outputSize.height()) }); + QRhiCommandBuffer::VertexInput vbindings(vbuf.data(), 0); + cb->setVertexInput(0, 1, &vbindings); + cb->draw(3); + + QRhiReadbackResult readResult; + QImage result; + readResult.completed = [&readResult, &result] { + result = QImage(reinterpret_cast<const uchar *>(readResult.data.constData()), + readResult.pixelSize.width(), readResult.pixelSize.height(), + QImage::Format_RGBA8888_Premultiplied); // non-owning, no copy needed because readResult outlives result + }; + QRhiResourceUpdateBatch *readbackBatch = rhi->nextResourceUpdateBatch(); + readbackBatch->readBackTexture({ texture.data() }, &readResult); + cb->endPass(readbackBatch); + + rhi->endOffscreenFrame(); + // Offscreen frames are synchronous, so the readback is guaranteed to + // complete at this point. This would not be the case with swapchain-based + // frames. + QCOMPARE(result.size(), texture->pixelSize()); + + if (impl == QRhi::Null) + return; + + // Now we have a red rectangle on blue background. + const int y = 100; + const quint32 *p = reinterpret_cast<const quint32 *>(result.constScanLine(y)); + int x = result.width() - 1; + int redCount = 0; + int blueCount = 0; + const int maxFuzz = 1; + while (x-- >= 0) { + const QRgb c(*p++); + if (qRed(c) >= (255 - maxFuzz) && qGreen(c) == 0 && qBlue(c) == 0) + ++redCount; + else if (qRed(c) == 0 && qGreen(c) == 0 && qBlue(c) >= (255 - maxFuzz)) + ++blueCount; + else + QFAIL("Encountered a pixel that is neither red or blue"); + } + + QCOMPARE(redCount + blueCount, texture->pixelSize().width()); + + // The triangle is "pointing up" in the resulting image with OpenGL + // (because Y is up both in normalized device coordinates and in images) + // and Vulkan (because Y is down in both and the vertex data was specified + // with Y up in mind), but "pointing down" with D3D (because Y is up in NDC + // but down in images). + if (rhi->isYUpInFramebuffer() == rhi->isYUpInNDC()) + QVERIFY(redCount < blueCount); + else + QVERIFY(redCount > blueCount); +} + +void tst_QRhi::renderToTextureTexturedQuad_data() +{ + rhiTestData(); +} + +void tst_QRhi::renderToTextureTexturedQuad() +{ + QFETCH(QRhi::Implementation, impl); + QFETCH(QRhiInitParams *, initParams); + + QScopedPointer<QRhi> rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr)); + if (!rhi) + QSKIP("QRhi could not be created, skipping testing rendering"); + + QImage inputImage; + inputImage.load(QLatin1String(":/data/qt256.png")); + QVERIFY(!inputImage.isNull()); + + QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA8, inputImage.size(), 1, + QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource)); + QVERIFY(texture->build()); + + QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget({ texture.data() })); + QScopedPointer<QRhiRenderPassDescriptor> rpDesc(rt->newCompatibleRenderPassDescriptor()); + rt->setRenderPassDescriptor(rpDesc.data()); + QVERIFY(rt->build()); + + QRhiCommandBuffer *cb = nullptr; + QVERIFY(rhi->beginOffscreenFrame(&cb) == QRhi::FrameOpSuccess); + QVERIFY(cb); + + QRhiResourceUpdateBatch *updates = rhi->nextResourceUpdateBatch(); + + static const float verticesUvs[] = { + -1.0f, -1.0f, 0.0f, 0.0f, + 1.0f, -1.0f, 1.0f, 0.0f, + -1.0f, 1.0f, 0.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f + }; + QScopedPointer<QRhiBuffer> vbuf(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(verticesUvs))); + QVERIFY(vbuf->build()); + updates->uploadStaticBuffer(vbuf.data(), verticesUvs); + + QScopedPointer<QRhiTexture> inputTexture(rhi->newTexture(QRhiTexture::RGBA8, inputImage.size())); + QVERIFY(inputTexture->build()); + updates->uploadTexture(inputTexture.data(), inputImage); + + QScopedPointer<QRhiSampler> sampler(rhi->newSampler(QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None, + QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge)); + QVERIFY(sampler->build()); + + QScopedPointer<QRhiShaderResourceBindings> srb(rhi->newShaderResourceBindings()); + srb->setBindings({ + QRhiShaderResourceBinding::sampledTexture(0, QRhiShaderResourceBinding::FragmentStage, inputTexture.data(), sampler.data()) + }); + QVERIFY(srb->build()); + + QScopedPointer<QRhiGraphicsPipeline> pipeline(rhi->newGraphicsPipeline()); + pipeline->setTopology(QRhiGraphicsPipeline::TriangleStrip); + QShader vs = loadShader(":/data/simpletextured.vert.qsb"); + QVERIFY(vs.isValid()); + QShader fs = loadShader(":/data/simpletextured.frag.qsb"); + QVERIFY(fs.isValid()); + pipeline->setShaderStages({ { QRhiShaderStage::Vertex, vs }, { QRhiShaderStage::Fragment, fs } }); + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ { 4 * sizeof(float) } }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float2, 0 }, + { 0, 1, QRhiVertexInputAttribute::Float2, 2 * sizeof(float) } + }); + pipeline->setVertexInputLayout(inputLayout); + pipeline->setShaderResourceBindings(srb.data()); + pipeline->setRenderPassDescriptor(rpDesc.data()); + + QVERIFY(pipeline->build()); + + cb->beginPass(rt.data(), Qt::black, { 1.0f, 0 }, updates); + cb->setGraphicsPipeline(pipeline.data()); + cb->setShaderResources(); + cb->setViewport({ 0, 0, float(texture->pixelSize().width()), float(texture->pixelSize().height()) }); + QRhiCommandBuffer::VertexInput vbindings(vbuf.data(), 0); + cb->setVertexInput(0, 1, &vbindings); + cb->draw(4); + + QRhiReadbackResult readResult; + QImage result; + readResult.completed = [&readResult, &result] { + result = QImage(reinterpret_cast<const uchar *>(readResult.data.constData()), + readResult.pixelSize.width(), readResult.pixelSize.height(), + QImage::Format_RGBA8888_Premultiplied); + }; + QRhiResourceUpdateBatch *readbackBatch = rhi->nextResourceUpdateBatch(); + readbackBatch->readBackTexture({ texture.data() }, &readResult); + cb->endPass(readbackBatch); + + rhi->endOffscreenFrame(); + + QVERIFY(!result.isNull()); + + if (impl == QRhi::Null) + return; + + // Flip with D3D and Metal because these have Y down in images. Vulkan does + // not need this because there Y is down both in images and in NDC, which + // just happens to give correct results with our OpenGL-targeted vertex and + // UV data. + if (rhi->isYUpInFramebuffer() != rhi->isYUpInNDC()) + result = std::move(result).mirrored(); + + // check a few points that are expected to match regardless of the implementation + QRgb white = qRgba(255, 255, 255, 255); + QCOMPARE(result.pixel(79, 77), white); + QCOMPARE(result.pixel(124, 81), white); + QCOMPARE(result.pixel(128, 149), white); + QCOMPARE(result.pixel(120, 189), white); + QCOMPARE(result.pixel(116, 185), white); + + QRgb empty = qRgba(0, 0, 0, 0); + QCOMPARE(result.pixel(11, 45), empty); + QCOMPARE(result.pixel(246, 202), empty); + QCOMPARE(result.pixel(130, 18), empty); + QCOMPARE(result.pixel(4, 227), empty); + + QVERIFY(qGreen(result.pixel(32, 52)) > 2 * qRed(result.pixel(32, 52))); + QVERIFY(qGreen(result.pixel(32, 52)) > 2 * qBlue(result.pixel(32, 52))); + QVERIFY(qGreen(result.pixel(214, 191)) > 2 * qRed(result.pixel(214, 191))); + QVERIFY(qGreen(result.pixel(214, 191)) > 2 * qBlue(result.pixel(214, 191))); +} + +void tst_QRhi::renderToTextureTexturedQuadAndUniformBuffer_data() +{ + rhiTestData(); +} + +void tst_QRhi::renderToTextureTexturedQuadAndUniformBuffer() +{ + QFETCH(QRhi::Implementation, impl); + QFETCH(QRhiInitParams *, initParams); + + QScopedPointer<QRhi> rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr)); + if (!rhi) + QSKIP("QRhi could not be created, skipping testing rendering"); + + QImage inputImage; + inputImage.load(QLatin1String(":/data/qt256.png")); + QVERIFY(!inputImage.isNull()); + + QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA8, inputImage.size(), 1, + QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource)); + QVERIFY(texture->build()); + + QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget({ texture.data() })); + QScopedPointer<QRhiRenderPassDescriptor> rpDesc(rt->newCompatibleRenderPassDescriptor()); + rt->setRenderPassDescriptor(rpDesc.data()); + QVERIFY(rt->build()); + + QRhiCommandBuffer *cb = nullptr; + QVERIFY(rhi->beginOffscreenFrame(&cb) == QRhi::FrameOpSuccess); + QVERIFY(cb); + + QRhiResourceUpdateBatch *updates = rhi->nextResourceUpdateBatch(); + + static const float verticesUvs[] = { + -1.0f, -1.0f, 0.0f, 0.0f, + 1.0f, -1.0f, 1.0f, 0.0f, + -1.0f, 1.0f, 0.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f + }; + QScopedPointer<QRhiBuffer> vbuf(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(verticesUvs))); + QVERIFY(vbuf->build()); + updates->uploadStaticBuffer(vbuf.data(), verticesUvs); + + // There will be two renderpasses. One renders with no transformation and + // an opacity of 0.5, the second has a rotation. Bake the uniform data for + // both into a single buffer. + + const int UNIFORM_BLOCK_SIZE = 64 + 4; // matrix + opacity + const int secondUbufOffset = rhi->ubufAligned(UNIFORM_BLOCK_SIZE); + const int UBUF_SIZE = secondUbufOffset + UNIFORM_BLOCK_SIZE; + + QScopedPointer<QRhiBuffer> ubuf(rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, UBUF_SIZE)); + QVERIFY(ubuf->build()); + + QMatrix4x4 matrix; + updates->updateDynamicBuffer(ubuf.data(), 0, 64, matrix.constData()); + float opacity = 0.5f; + updates->updateDynamicBuffer(ubuf.data(), 64, 4, &opacity); + + // rotation by 45 degrees around the Z axis + matrix.rotate(45, 0, 0, 1); + updates->updateDynamicBuffer(ubuf.data(), secondUbufOffset, 64, matrix.constData()); + updates->updateDynamicBuffer(ubuf.data(), secondUbufOffset + 64, 4, &opacity); + + QScopedPointer<QRhiTexture> inputTexture(rhi->newTexture(QRhiTexture::RGBA8, inputImage.size())); + QVERIFY(inputTexture->build()); + updates->uploadTexture(inputTexture.data(), inputImage); + + QScopedPointer<QRhiSampler> sampler(rhi->newSampler(QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None, + QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge)); + QVERIFY(sampler->build()); + + const QRhiShaderResourceBinding::StageFlags commonVisibility = QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage; + QScopedPointer<QRhiShaderResourceBindings> srb0(rhi->newShaderResourceBindings()); + srb0->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, commonVisibility, ubuf.data(), 0, UNIFORM_BLOCK_SIZE), + QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, inputTexture.data(), sampler.data()) + }); + QVERIFY(srb0->build()); + + QScopedPointer<QRhiShaderResourceBindings> srb1(rhi->newShaderResourceBindings()); + srb1->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, commonVisibility, ubuf.data(), secondUbufOffset, UNIFORM_BLOCK_SIZE), + QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, inputTexture.data(), sampler.data()) + }); + QVERIFY(srb1->build()); + QVERIFY(srb1->isLayoutCompatible(srb0.data())); // hence no need for a second pipeline + + QScopedPointer<QRhiGraphicsPipeline> pipeline(rhi->newGraphicsPipeline()); + pipeline->setTopology(QRhiGraphicsPipeline::TriangleStrip); + QShader vs = loadShader(":/data/textured.vert.qsb"); + QVERIFY(vs.isValid()); + QShaderDescription shaderDesc = vs.description(); + QVERIFY(!shaderDesc.uniformBlocks().isEmpty()); + QCOMPARE(shaderDesc.uniformBlocks().first().size, UNIFORM_BLOCK_SIZE); + + QShader fs = loadShader(":/data/textured.frag.qsb"); + QVERIFY(fs.isValid()); + shaderDesc = fs.description(); + QVERIFY(!shaderDesc.uniformBlocks().isEmpty()); + QCOMPARE(shaderDesc.uniformBlocks().first().size, UNIFORM_BLOCK_SIZE); + + pipeline->setShaderStages({ { QRhiShaderStage::Vertex, vs }, { QRhiShaderStage::Fragment, fs } }); + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ { 4 * sizeof(float) } }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float2, 0 }, + { 0, 1, QRhiVertexInputAttribute::Float2, 2 * sizeof(float) } + }); + pipeline->setVertexInputLayout(inputLayout); + pipeline->setShaderResourceBindings(srb0.data()); + pipeline->setRenderPassDescriptor(rpDesc.data()); + + QVERIFY(pipeline->build()); + + cb->beginPass(rt.data(), Qt::black, { 1.0f, 0 }, updates); + cb->setGraphicsPipeline(pipeline.data()); + cb->setShaderResources(); + cb->setViewport({ 0, 0, float(texture->pixelSize().width()), float(texture->pixelSize().height()) }); + QRhiCommandBuffer::VertexInput vbindings(vbuf.data(), 0); + cb->setVertexInput(0, 1, &vbindings); + cb->draw(4); + + QRhiReadbackResult readResult0; + QImage result0; + readResult0.completed = [&readResult0, &result0] { + result0 = QImage(reinterpret_cast<const uchar *>(readResult0.data.constData()), + readResult0.pixelSize.width(), readResult0.pixelSize.height(), + QImage::Format_RGBA8888_Premultiplied); + }; + QRhiResourceUpdateBatch *readbackBatch = rhi->nextResourceUpdateBatch(); + readbackBatch->readBackTexture({ texture.data() }, &readResult0); + cb->endPass(readbackBatch); + + // second pass (rotated) + cb->beginPass(rt.data(), Qt::black, { 1.0f, 0 }); + cb->setGraphicsPipeline(pipeline.data()); + cb->setShaderResources(srb1.data()); // sources data from a different offset in ubuf + cb->setViewport({ 0, 0, float(texture->pixelSize().width()), float(texture->pixelSize().height()) }); + cb->setVertexInput(0, 1, &vbindings); + cb->draw(4); + + QRhiReadbackResult readResult1; + QImage result1; + readResult1.completed = [&readResult1, &result1] { + result1 = QImage(reinterpret_cast<const uchar *>(readResult1.data.constData()), + readResult1.pixelSize.width(), readResult1.pixelSize.height(), + QImage::Format_RGBA8888_Premultiplied); + }; + readbackBatch = rhi->nextResourceUpdateBatch(); + readbackBatch->readBackTexture({ texture.data() }, &readResult1); + cb->endPass(readbackBatch); + + rhi->endOffscreenFrame(); + + QVERIFY(!result0.isNull()); + QVERIFY(!result1.isNull()); + + if (rhi->isYUpInFramebuffer() != rhi->isYUpInNDC()) { + result0 = std::move(result0).mirrored(); + result1 = std::move(result1).mirrored(); + } + + if (impl == QRhi::Null) + return; + + // opacity 0.5 (premultiplied) + static const auto checkSemiWhite = [](const QRgb &c) { + QRgb semiWhite127 = qPremultiply(qRgba(255, 255, 255, 127)); + QRgb semiWhite128 = qPremultiply(qRgba(255, 255, 255, 128)); + return c == semiWhite127 || c == semiWhite128; + }; + QVERIFY(checkSemiWhite(result0.pixel(79, 77))); + QVERIFY(checkSemiWhite(result0.pixel(124, 81))); + QVERIFY(checkSemiWhite(result0.pixel(128, 149))); + QVERIFY(checkSemiWhite(result0.pixel(120, 189))); + QVERIFY(checkSemiWhite(result0.pixel(116, 185))); + QVERIFY(checkSemiWhite(result0.pixel(191, 172))); + + QRgb empty = qRgba(0, 0, 0, 0); + QCOMPARE(result0.pixel(11, 45), empty); + QCOMPARE(result0.pixel(246, 202), empty); + QCOMPARE(result0.pixel(130, 18), empty); + QCOMPARE(result0.pixel(4, 227), empty); + + // also rotated 45 degrees around Z + QRgb black = qRgba(0, 0, 0, 255); + QCOMPARE(result1.pixel(20, 23), black); + QCOMPARE(result1.pixel(47, 5), black); + QCOMPARE(result1.pixel(238, 22), black); + QCOMPARE(result1.pixel(250, 203), black); + QCOMPARE(result1.pixel(224, 237), black); + QCOMPARE(result1.pixel(12, 221), black); + + QVERIFY(checkSemiWhite(result1.pixel(142, 67))); + QVERIFY(checkSemiWhite(result1.pixel(81, 79))); + QVERIFY(checkSemiWhite(result1.pixel(79, 168))); + QVERIFY(checkSemiWhite(result1.pixel(146, 204))); + QVERIFY(checkSemiWhite(result1.pixel(186, 156))); + + QCOMPARE(result1.pixel(204, 45), empty); + QCOMPARE(result1.pixel(28, 178), empty); +} + +void tst_QRhi::renderToWindowSimple_data() +{ + rhiTestData(); +} + +void tst_QRhi::renderToWindowSimple() +{ + QFETCH(QRhi::Implementation, impl); + QFETCH(QRhiInitParams *, initParams); + +#ifdef Q_OS_WINRT + if (impl == QRhi::D3D11) + QSKIP("Skipping window-based QRhi rendering on WinRT as the platform and the D3D11 backend are not prepared for this yet"); +#endif + + QScopedPointer<QRhi> rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr)); + if (!rhi) + QSKIP("QRhi could not be created, skipping testing rendering"); + + QScopedPointer<QWindow> window(new QWindow); + switch (impl) { + case QRhi::OpenGLES2: + Q_FALLTHROUGH(); + case QRhi::D3D11: + window->setSurfaceType(QSurface::OpenGLSurface); + break; + case QRhi::Metal: + window->setSurfaceType(QSurface::MetalSurface); + break; + case QRhi::Vulkan: + window->setSurfaceType(QSurface::VulkanSurface); +#if QT_CONFIG(vulkan) + window->setVulkanInstance(&vulkanInstance); +#endif + break; + default: + break; + } + + window->setGeometry(0, 0, 640, 480); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + QScopedPointer<QRhiSwapChain> swapChain(rhi->newSwapChain()); + swapChain->setWindow(window.data()); + swapChain->setFlags(QRhiSwapChain::UsedAsTransferSource); + QScopedPointer<QRhiRenderPassDescriptor> rpDesc(swapChain->newCompatibleRenderPassDescriptor()); + swapChain->setRenderPassDescriptor(rpDesc.data()); + QVERIFY(swapChain->buildOrResize()); + + QRhiResourceUpdateBatch *updates = rhi->nextResourceUpdateBatch(); + + static const float vertices[] = { + -1.0f, -1.0f, + 1.0f, -1.0f, + 0.0f, 1.0f + }; + QScopedPointer<QRhiBuffer> vbuf(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertices))); + QVERIFY(vbuf->build()); + updates->uploadStaticBuffer(vbuf.data(), vertices); + + QScopedPointer<QRhiShaderResourceBindings> srb(rhi->newShaderResourceBindings()); + QVERIFY(srb->build()); + + QScopedPointer<QRhiGraphicsPipeline> pipeline(rhi->newGraphicsPipeline()); + QShader vs = loadShader(":/data/simple.vert.qsb"); + QVERIFY(vs.isValid()); + QShader fs = loadShader(":/data/simple.frag.qsb"); + QVERIFY(fs.isValid()); + pipeline->setShaderStages({ { QRhiShaderStage::Vertex, vs }, { QRhiShaderStage::Fragment, fs } }); + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ { 2 * sizeof(float) } }); + inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float2, 0 } }); + pipeline->setVertexInputLayout(inputLayout); + pipeline->setShaderResourceBindings(srb.data()); + pipeline->setRenderPassDescriptor(rpDesc.data()); + + QVERIFY(pipeline->build()); + + const int framesInFlight = rhi->resourceLimit(QRhi::FramesInFlight); + QVERIFY(framesInFlight >= 1); + const int FRAME_COUNT = framesInFlight + 1; + bool readCompleted = false; + QRhiReadbackResult readResult; + QImage result; + int readbackWidth = 0; + + for (int frameNo = 0; frameNo < FRAME_COUNT; ++frameNo) { + QVERIFY(rhi->beginFrame(swapChain.data()) == QRhi::FrameOpSuccess); + QRhiCommandBuffer *cb = swapChain->currentFrameCommandBuffer(); + QRhiRenderTarget *rt = swapChain->currentFrameRenderTarget(); + const QSize outputSize = swapChain->currentPixelSize(); + QCOMPARE(rt->pixelSize(), outputSize); + QRhiViewport viewport(0, 0, float(outputSize.width()), float(outputSize.height())); + + cb->beginPass(rt, Qt::blue, { 1.0f, 0 }, updates); + updates = nullptr; + cb->setGraphicsPipeline(pipeline.data()); + cb->setViewport(viewport); + QRhiCommandBuffer::VertexInput vbindings(vbuf.data(), 0); + cb->setVertexInput(0, 1, &vbindings); + cb->draw(3); + + if (frameNo == 0) { + readResult.completed = [&readCompleted, &readResult, &result, &rhi] { + readCompleted = true; + QImage wrapperImage(reinterpret_cast<const uchar *>(readResult.data.constData()), + readResult.pixelSize.width(), readResult.pixelSize.height(), + QImage::Format_ARGB32_Premultiplied); + if (readResult.format == QRhiTexture::RGBA8) + wrapperImage = wrapperImage.rgbSwapped(); + if (rhi->isYUpInFramebuffer() == rhi->isYUpInNDC()) + result = wrapperImage.mirrored(); + else + result = wrapperImage.copy(); + }; + QRhiResourceUpdateBatch *readbackBatch = rhi->nextResourceUpdateBatch(); + readbackBatch->readBackTexture({}, &readResult); // read back the current backbuffer + readbackWidth = outputSize.width(); + cb->endPass(readbackBatch); + } else { + cb->endPass(); + } + + rhi->endFrame(swapChain.data()); + } + + // The readback is asynchronous here. However it is guaranteed that it + // finished at latest after rendering QRhi::FramesInFlight frames after the + // one that enqueues the readback. + QVERIFY(readCompleted); + QVERIFY(readbackWidth > 0); + + if (impl == QRhi::Null) + return; + + // Now we have a red rectangle on blue background. + const int y = 50; + const quint32 *p = reinterpret_cast<const quint32 *>(result.constScanLine(y)); + int x = result.width() - 1; + int redCount = 0; + int blueCount = 0; + const int maxFuzz = 1; + while (x-- >= 0) { + const QRgb c(*p++); + if (qRed(c) >= (255 - maxFuzz) && qGreen(c) == 0 && qBlue(c) == 0) + ++redCount; + else if (qRed(c) == 0 && qGreen(c) == 0 && qBlue(c) >= (255 - maxFuzz)) + ++blueCount; + else + QFAIL("Encountered a pixel that is neither red or blue"); + } + + QCOMPARE(redCount + blueCount, readbackWidth); + QVERIFY(redCount < blueCount); +} + +#include <tst_qrhi.moc> +QTEST_MAIN(tst_QRhi) diff --git a/tests/auto/gui/rhi/qshader/data/color.vert b/tests/auto/gui/rhi/qshader/data/color.vert new file mode 100644 index 0000000000..c92f71b9e1 --- /dev/null +++ b/tests/auto/gui/rhi/qshader/data/color.vert @@ -0,0 +1,18 @@ +#version 440 + +layout(location = 0) in vec4 position; +layout(location = 1) in vec3 color; +layout(location = 0) out vec3 v_color; + +layout(std140, binding = 0) uniform buf { + mat4 mvp; + float opacity; +} ubuf; + +out gl_PerVertex { vec4 gl_Position; }; + +void main() +{ + v_color = color; + gl_Position = ubuf.mvp * position; +} diff --git a/tests/auto/gui/rhi/qshader/data/color.vert.qsb b/tests/auto/gui/rhi/qshader/data/color.vert.qsb Binary files differnew file mode 100644 index 0000000000..7d02d823d2 --- /dev/null +++ b/tests/auto/gui/rhi/qshader/data/color.vert.qsb diff --git a/tests/auto/gui/rhi/qshader/data/color_simple.vert.qsb b/tests/auto/gui/rhi/qshader/data/color_simple.vert.qsb Binary files differnew file mode 100644 index 0000000000..c82ba7e8e7 --- /dev/null +++ b/tests/auto/gui/rhi/qshader/data/color_simple.vert.qsb diff --git a/tests/auto/gui/rhi/qshader/qshader.pro b/tests/auto/gui/rhi/qshader/qshader.pro new file mode 100644 index 0000000000..5d9ef8304d --- /dev/null +++ b/tests/auto/gui/rhi/qshader/qshader.pro @@ -0,0 +1,8 @@ +TARGET = tst_qshader +CONFIG += testcase + +QT += testlib gui-private + +SOURCES += tst_qshader.cpp + +RESOURCES += qshader.qrc diff --git a/tests/auto/gui/rhi/qshader/qshader.qrc b/tests/auto/gui/rhi/qshader/qshader.qrc new file mode 100644 index 0000000000..f161d8aad6 --- /dev/null +++ b/tests/auto/gui/rhi/qshader/qshader.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/"> + <file>data</file> + </qresource> +</RCC> diff --git a/tests/auto/gui/rhi/qshader/tst_qshader.cpp b/tests/auto/gui/rhi/qshader/tst_qshader.cpp new file mode 100644 index 0000000000..21f0cc7895 --- /dev/null +++ b/tests/auto/gui/rhi/qshader/tst_qshader.cpp @@ -0,0 +1,233 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QFile> +#include <QtGui/private/qshaderdescription_p_p.h> +#include <QtGui/private/qshader_p_p.h> + +class tst_QShader : public QObject +{ + Q_OBJECT + +private slots: + void simpleCompileCheckResults(); + void genVariants(); + void shaderDescImplicitSharing(); + void bakedShaderImplicitSharing(); +}; + +static QShader getShader(const QString &name) +{ + QFile f(name); + if (f.open(QIODevice::ReadOnly)) + return QShader::fromSerialized(f.readAll()); + + return QShader(); +} + +void tst_QShader::simpleCompileCheckResults() +{ + QShader s = getShader(QLatin1String(":/data/color_simple.vert.qsb")); + QVERIFY(s.isValid()); + QCOMPARE(s.availableShaders().count(), 1); + + const QShaderCode shader = s.shader(QShaderKey(QShader::SpirvShader, + QShaderVersion(100))); + QVERIFY(!shader.shader().isEmpty()); + QCOMPARE(shader.entryPoint(), QByteArrayLiteral("main")); + + const QShaderDescription desc = s.description(); + QVERIFY(desc.isValid()); + QCOMPARE(desc.inputVariables().count(), 2); + for (const QShaderDescription::InOutVariable &v : desc.inputVariables()) { + switch (v.location) { + case 0: + QCOMPARE(v.name, QLatin1String("position")); + QCOMPARE(v.type, QShaderDescription::Vec4); + break; + case 1: + QCOMPARE(v.name, QLatin1String("color")); + QCOMPARE(v.type, QShaderDescription::Vec3); + break; + default: + QVERIFY(false); + break; + } + } + QCOMPARE(desc.outputVariables().count(), 1); + for (const QShaderDescription::InOutVariable &v : desc.outputVariables()) { + switch (v.location) { + case 0: + QCOMPARE(v.name, QLatin1String("v_color")); + QCOMPARE(v.type, QShaderDescription::Vec3); + break; + default: + QVERIFY(false); + break; + } + } + QCOMPARE(desc.uniformBlocks().count(), 1); + const QShaderDescription::UniformBlock blk = desc.uniformBlocks().first(); + QCOMPARE(blk.blockName, QLatin1String("buf")); + QCOMPARE(blk.structName, QLatin1String("ubuf")); + QCOMPARE(blk.size, 68); + QCOMPARE(blk.binding, 0); + QCOMPARE(blk.descriptorSet, 0); + QCOMPARE(blk.members.count(), 2); + for (int i = 0; i < blk.members.count(); ++i) { + const QShaderDescription::BlockVariable v = blk.members[i]; + switch (i) { + case 0: + QCOMPARE(v.offset, 0); + QCOMPARE(v.size, 64); + QCOMPARE(v.name, QLatin1String("mvp")); + QCOMPARE(v.type, QShaderDescription::Mat4); + QCOMPARE(v.matrixStride, 16); + break; + case 1: + QCOMPARE(v.offset, 64); + QCOMPARE(v.size, 4); + QCOMPARE(v.name, QLatin1String("opacity")); + QCOMPARE(v.type, QShaderDescription::Float); + break; + default: + QVERIFY(false); + break; + } + } +} + +void tst_QShader::genVariants() +{ + QShader s = getShader(QLatin1String(":/data/color.vert.qsb")); + // spirv, glsl 100, glsl 330, glsl 120, hlsl 50, msl 12 + // + batchable variants + QVERIFY(s.isValid()); + QCOMPARE(s.availableShaders().count(), 2 * 6); + + int batchableVariantCount = 0; + int batchableGlslVariantCount = 0; + for (const QShaderKey &key : s.availableShaders()) { + if (key.sourceVariant() == QShader::BatchableVertexShader) { + ++batchableVariantCount; + if (key.source() == QShader::GlslShader) { + ++batchableGlslVariantCount; + const QByteArray src = s.shader(key).shader(); + QVERIFY(src.contains(QByteArrayLiteral("_qt_order * "))); + } + } + } + QCOMPARE(batchableVariantCount, 6); + QCOMPARE(batchableGlslVariantCount, 3); +} + +void tst_QShader::shaderDescImplicitSharing() +{ + QShader s = getShader(QLatin1String(":/data/color_simple.vert.qsb")); + QVERIFY(s.isValid()); + QCOMPARE(s.availableShaders().count(), 1); + QVERIFY(s.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100)))); + + QShaderDescription d0 = s.description(); + QVERIFY(d0.isValid()); + QCOMPARE(d0.inputVariables().count(), 2); + QCOMPARE(d0.outputVariables().count(), 1); + QCOMPARE(d0.uniformBlocks().count(), 1); + + QShaderDescription d1 = d0; + QVERIFY(QShaderDescriptionPrivate::get(&d0) == QShaderDescriptionPrivate::get(&d1)); + QCOMPARE(d0.inputVariables().count(), 2); + QCOMPARE(d0.outputVariables().count(), 1); + QCOMPARE(d0.uniformBlocks().count(), 1); + QCOMPARE(d1.inputVariables().count(), 2); + QCOMPARE(d1.outputVariables().count(), 1); + QCOMPARE(d1.uniformBlocks().count(), 1); + + d1.detach(); + QVERIFY(QShaderDescriptionPrivate::get(&d0) != QShaderDescriptionPrivate::get(&d1)); + QCOMPARE(d0.inputVariables().count(), 2); + QCOMPARE(d0.outputVariables().count(), 1); + QCOMPARE(d0.uniformBlocks().count(), 1); + QCOMPARE(d1.inputVariables().count(), 2); + QCOMPARE(d1.outputVariables().count(), 1); + QCOMPARE(d1.uniformBlocks().count(), 1); +} + +void tst_QShader::bakedShaderImplicitSharing() +{ + QShader s0 = getShader(QLatin1String(":/data/color_simple.vert.qsb")); + QVERIFY(s0.isValid()); + QCOMPARE(s0.availableShaders().count(), 1); + QVERIFY(s0.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100)))); + + { + QShader s1 = s0; + QVERIFY(QShaderPrivate::get(&s0) == QShaderPrivate::get(&s1)); + QCOMPARE(s0.availableShaders().count(), 1); + QVERIFY(s0.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100)))); + QCOMPARE(s1.availableShaders().count(), 1); + QVERIFY(s1.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100)))); + QCOMPARE(s0.stage(), s1.stage()); + QCOMPARE(s0, s1); + + s1.detach(); + QVERIFY(QShaderPrivate::get(&s0) != QShaderPrivate::get(&s1)); + QCOMPARE(s0.availableShaders().count(), 1); + QVERIFY(s0.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100)))); + QCOMPARE(s1.availableShaders().count(), 1); + QVERIFY(s1.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100)))); + QCOMPARE(s0.stage(), s1.stage()); + QCOMPARE(s0, s1); + } + + { + QShader s1 = s0; + QVERIFY(QShaderPrivate::get(&s0) == QShaderPrivate::get(&s1)); + QCOMPARE(s0.stage(), s1.stage()); + + s1.setStage(QShader::FragmentStage); // call a setter to trigger a detach + QVERIFY(QShaderPrivate::get(&s0) != QShaderPrivate::get(&s1)); + QCOMPARE(s0.availableShaders().count(), 1); + QVERIFY(s0.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100)))); + QCOMPARE(s1.availableShaders().count(), 1); + QVERIFY(s1.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100)))); + QShaderDescription d0 = s0.description(); + QCOMPARE(d0.inputVariables().count(), 2); + QCOMPARE(d0.outputVariables().count(), 1); + QCOMPARE(d0.uniformBlocks().count(), 1); + QShaderDescription d1 = s1.description(); + QCOMPARE(d1.inputVariables().count(), 2); + QCOMPARE(d1.outputVariables().count(), 1); + QCOMPARE(d1.uniformBlocks().count(), 1); + QVERIFY(s0 != s1); + } +} + +#include <tst_qshader.moc> +QTEST_MAIN(tst_QShader) diff --git a/tests/auto/gui/rhi/rhi.pro b/tests/auto/gui/rhi/rhi.pro new file mode 100644 index 0000000000..cc548b7b8a --- /dev/null +++ b/tests/auto/gui/rhi/rhi.pro @@ -0,0 +1,4 @@ +TEMPLATE=subdirs +SUBDIRS= \ + qshader \ + qrhi diff --git a/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp b/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp index 7dbeb13aa7..7764a716ca 100644 --- a/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp +++ b/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp @@ -78,6 +78,8 @@ private slots: void extractBorder(); void noTextDecoration(); void quotedAndUnquotedIdentifiers(); + void whitespaceValues_data(); + void whitespaceValues(); }; void tst_QCssParser::scanner_data() @@ -1746,6 +1748,33 @@ void tst_QCssParser::quotedAndUnquotedIdentifiers() QCOMPARE(decls.at(1).d->values.first().toString(), QLatin1String("bold")); } +void tst_QCssParser::whitespaceValues_data() +{ + QTest::addColumn<QString>("value"); + + QTest::newRow("normal") << "normal"; + QTest::newRow("inherit") << "inherit"; + QTest::newRow("nowrap") << "nowrap"; + QTest::newRow("pre") << "pre"; + QTest::newRow("pre-wrap") << "pre-wrap"; + QTest::newRow("pre-line") << "pre-line"; +} + +void tst_QCssParser::whitespaceValues() +{ + QFETCH(QString, value); + QCss::Parser parser(QString("foo { white-space: %1 }").arg(value)); + QCss::StyleSheet sheet; + QVERIFY(parser.parse(&sheet)); + + QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ? + sheet.styleRules.at(0) : *sheet.nameIndex.begin(); + QCOMPARE(rule.declarations.size(), 1); + + QCOMPARE(rule.declarations.at(0).d->property, QLatin1String("white-space")); + QCOMPARE(rule.declarations.at(0).d->values.first().toString(), value); +} + QTEST_MAIN(tst_QCssParser) #include "tst_qcssparser.moc" diff --git a/tests/auto/gui/text/qfont/BLACKLIST b/tests/auto/gui/text/qfont/BLACKLIST deleted file mode 100644 index 42cb8408f4..0000000000 --- a/tests/auto/gui/text/qfont/BLACKLIST +++ /dev/null @@ -1,2 +0,0 @@ -[defaultFamily] -b2qt diff --git a/tests/auto/gui/text/qfont/tst_qfont.cpp b/tests/auto/gui/text/qfont/tst_qfont.cpp index 66f3ee0d2c..d722856366 100644 --- a/tests/auto/gui/text/qfont/tst_qfont.cpp +++ b/tests/auto/gui/text/qfont/tst_qfont.cpp @@ -58,7 +58,9 @@ private slots: void insertAndRemoveSubstitutions(); void serialize_data(); void serialize(); +#if QT_DEPRECATED_SINCE(5, 13) void lastResortFont(); +#endif void styleName(); void defaultFamily_data(); void defaultFamily(); @@ -486,6 +488,7 @@ void tst_QFont::serialize() } } +#if QT_DEPRECATED_SINCE(5, 13) // QFont::lastResortFont() may abort with qFatal() on QWS/QPA // if absolutely no font is found. Just as ducumented for QFont::lastResortFont(). // This happens on our CI machines which run QWS autotests. @@ -496,6 +499,7 @@ void tst_QFont::lastResortFont() QFont font; QVERIFY(!font.lastResortFont().isEmpty()); } +#endif void tst_QFont::styleName() { @@ -537,10 +541,10 @@ void tst_QFont::defaultFamily_data() QTest::addColumn<QStringList>("acceptableFamilies"); QTest::newRow("serif") << QFont::Serif << (QStringList() << "Times New Roman" << "Times" << "Droid Serif" << getPlatformGenericFont("serif").split(",")); - QTest::newRow("monospace") << QFont::Monospace << (QStringList() << "Courier New" << "Monaco" << "Droid Sans Mono" << getPlatformGenericFont("monospace").split(",")); + QTest::newRow("monospace") << QFont::Monospace << (QStringList() << "Courier New" << "Monaco" << "Menlo" << "Droid Sans Mono" << getPlatformGenericFont("monospace").split(",")); QTest::newRow("cursive") << QFont::Cursive << (QStringList() << "Comic Sans MS" << "Apple Chancery" << "Roboto" << "Droid Sans" << getPlatformGenericFont("cursive").split(",")); QTest::newRow("fantasy") << QFont::Fantasy << (QStringList() << "Impact" << "Zapfino" << "Roboto" << "Droid Sans" << getPlatformGenericFont("fantasy").split(",")); - QTest::newRow("sans-serif") << QFont::SansSerif << (QStringList() << "Arial" << "Lucida Grande" << "Roboto" << "Droid Sans" << "Segoe UI" << getPlatformGenericFont("sans-serif").split(",")); + QTest::newRow("sans-serif") << QFont::SansSerif << (QStringList() << "Arial" << "Lucida Grande" << "Helvetica" << "Roboto" << "Droid Sans" << "Segoe UI" << getPlatformGenericFont("sans-serif").split(",")); } void tst_QFont::defaultFamily() @@ -630,37 +634,37 @@ void tst_QFont::sharing() QFont f; f.setStyleHint(QFont::Serif); f.exactMatch(); // loads engine - QCOMPARE(QFontPrivate::get(f)->ref.load(), 1); + QCOMPARE(QFontPrivate::get(f)->ref.loadRelaxed(), 1); QVERIFY(QFontPrivate::get(f)->engineData); - QCOMPARE(QFontPrivate::get(f)->engineData->ref.load(), 1 + refs_by_cache); + QCOMPARE(QFontPrivate::get(f)->engineData->ref.loadRelaxed(), 1 + refs_by_cache); QFont f2(f); QCOMPARE(QFontPrivate::get(f2), QFontPrivate::get(f)); - QCOMPARE(QFontPrivate::get(f2)->ref.load(), 2); + QCOMPARE(QFontPrivate::get(f2)->ref.loadRelaxed(), 2); QVERIFY(QFontPrivate::get(f2)->engineData); QCOMPARE(QFontPrivate::get(f2)->engineData, QFontPrivate::get(f)->engineData); - QCOMPARE(QFontPrivate::get(f2)->engineData->ref.load(), 1 + refs_by_cache); + QCOMPARE(QFontPrivate::get(f2)->engineData->ref.loadRelaxed(), 1 + refs_by_cache); f2.setKerning(!f.kerning()); QVERIFY(QFontPrivate::get(f2) != QFontPrivate::get(f)); - QCOMPARE(QFontPrivate::get(f2)->ref.load(), 1); + QCOMPARE(QFontPrivate::get(f2)->ref.loadRelaxed(), 1); QVERIFY(QFontPrivate::get(f2)->engineData); QCOMPARE(QFontPrivate::get(f2)->engineData, QFontPrivate::get(f)->engineData); - QCOMPARE(QFontPrivate::get(f2)->engineData->ref.load(), 2 + refs_by_cache); + QCOMPARE(QFontPrivate::get(f2)->engineData->ref.loadRelaxed(), 2 + refs_by_cache); f2 = f; QCOMPARE(QFontPrivate::get(f2), QFontPrivate::get(f)); - QCOMPARE(QFontPrivate::get(f2)->ref.load(), 2); + QCOMPARE(QFontPrivate::get(f2)->ref.loadRelaxed(), 2); QVERIFY(QFontPrivate::get(f2)->engineData); QCOMPARE(QFontPrivate::get(f2)->engineData, QFontPrivate::get(f)->engineData); - QCOMPARE(QFontPrivate::get(f2)->engineData->ref.load(), 1 + refs_by_cache); + QCOMPARE(QFontPrivate::get(f2)->engineData->ref.loadRelaxed(), 1 + refs_by_cache); if (f.pointSize() > 0) f2.setPointSize(f.pointSize() * 2 / 3); else f2.setPixelSize(f.pixelSize() * 2 / 3); QVERIFY(QFontPrivate::get(f2) != QFontPrivate::get(f)); - QCOMPARE(QFontPrivate::get(f2)->ref.load(), 1); + QCOMPARE(QFontPrivate::get(f2)->ref.loadRelaxed(), 1); QVERIFY(!QFontPrivate::get(f2)->engineData); QVERIFY(QFontPrivate::get(f2)->engineData != QFontPrivate::get(f)->engineData); } diff --git a/tests/auto/gui/text/qfontcache/tst_qfontcache.cpp b/tests/auto/gui/text/qfontcache/tst_qfontcache.cpp index 785cc3fef2..3d3211c7a2 100644 --- a/tests/auto/gui/text/qfontcache/tst_qfontcache.cpp +++ b/tests/auto/gui/text/qfontcache/tst_qfontcache.cpp @@ -217,7 +217,7 @@ void tst_QFontCache::clear() #ifdef QT_BUILD_INTERNAL QList<QFontEngine *> leakedEngines = QFontEngine_stopCollectingEngines(); -for (int i = 0; i < leakedEngines.size(); ++i) qWarning() << i << leakedEngines.at(i) << leakedEngines.at(i)->ref.load(); +for (int i = 0; i < leakedEngines.size(); ++i) qWarning() << i << leakedEngines.at(i) << leakedEngines.at(i)->ref.loadRelaxed(); // and we are not leaking! QCOMPARE(leakedEngines.size(), 0); #endif diff --git a/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp b/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp index 064e37f73c..2b69801b59 100644 --- a/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp +++ b/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp @@ -211,8 +211,8 @@ void tst_QFontDatabase::widthTwoTimes() f.setPixelSize(pixelSize); QFontMetrics fm(f); - int w1 = fm.charWidth(text, 0); - int w2 = fm.charWidth(text, 0); + int w1 = fm.horizontalAdvance(text, 0); + int w2 = fm.horizontalAdvance(text, 0); QCOMPARE(w1, w2); } diff --git a/tests/auto/gui/text/qglyphrun/BLACKLIST b/tests/auto/gui/text/qglyphrun/BLACKLIST index d8dbdabb4b..57f32c683d 100644 --- a/tests/auto/gui/text/qglyphrun/BLACKLIST +++ b/tests/auto/gui/text/qglyphrun/BLACKLIST @@ -1,4 +1,3 @@ [mixedScripts] ubuntu-18.04 b2qt -windows diff --git a/tests/auto/gui/text/qstatictext/tst_qstatictext.cpp b/tests/auto/gui/text/qstatictext/tst_qstatictext.cpp index d00dc251d8..b091edb64d 100644 --- a/tests/auto/gui/text/qstatictext/tst_qstatictext.cpp +++ b/tests/auto/gui/text/qstatictext/tst_qstatictext.cpp @@ -681,7 +681,7 @@ static bool checkPixels(const QImage &image, if (pixel != expectedRgb1 && pixel != expectedRgb2) { QString message; QDebug(&message) << "Color mismatch in image" << image - << "at" << x << ',' << y << ':' << showbase << hex << pixel + << "at" << x << ',' << y << ':' << Qt::showbase << Qt::hex << pixel << "(expected: " << expectedRgb1 << ',' << expectedRgb2 << ')'; *errorMessage = message.toLocal8Bit(); return false; diff --git a/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp b/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp index 58810f73c1..52e56feb5a 100644 --- a/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp +++ b/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp @@ -50,6 +50,7 @@ #include <QDomDocument> #include "common.h" +// #define DEBUG_WRITE_OUTPUT QT_FORWARD_DECLARE_CLASS(QTextDocument) @@ -196,6 +197,7 @@ private: void backgroundImage_checkExpectedHtml(const QTextDocument &doc); void buildRegExpData(); static QString cssFontSizeString(const QFont &font); + void writeActualAndExpected(const char* testTag, const QString &actual, const QString &expected); QTextDocument *doc; QTextCursor cursor; @@ -224,6 +226,27 @@ QString tst_QTextDocument::cssFontSizeString(const QFont &font) : QString::number(font.pixelSize()) + QStringLiteral("px"); } +void tst_QTextDocument::writeActualAndExpected(const char *testTag, const QString &actual, const QString &expected) +{ +#ifdef DEBUG_WRITE_OUTPUT + { + QFile out(QDir::temp().absoluteFilePath(QLatin1String(testTag) + QLatin1String("-actual.html"))); + out.open(QFile::WriteOnly); + out.write(actual.toUtf8()); + out.close(); + } { + QFile out(QDir::temp().absoluteFilePath(QLatin1String(testTag) + QLatin1String("-expected.html"))); + out.open(QFile::WriteOnly); + out.write(expected.toUtf8()); + out.close(); + } +#else + Q_UNUSED(testTag) + Q_UNUSED(actual) + Q_UNUSED(expected) +#endif +} + // Testing get/set functions void tst_QTextDocument::getSetCheck() { @@ -1765,6 +1788,8 @@ void tst_QTextDocument::toHtml() QString output = doc->toHtml(); + writeActualAndExpected(QTest::currentDataTag(), output, expectedOutput); + QCOMPARE(output, expectedOutput); QDomDocument document; @@ -1962,6 +1987,8 @@ void tst_QTextDocument::toHtmlRootFrameProperties() expectedOutput.replace("DEFAULTBLOCKSTYLE", "style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\""); expectedOutput.append(htmlTail); + writeActualAndExpected(QTest::currentTestFunction(), doc.toHtml(), expectedOutput); + QCOMPARE(doc.toHtml(), expectedOutput); } @@ -2734,6 +2761,8 @@ void tst_QTextDocument::backgroundImage_checkExpectedHtml(const QTextDocument &d .arg(defaultFont.weight() * 8) .arg((defaultFont.italic() ? "italic" : "normal")); + writeActualAndExpected(QTest::currentTestFunction(), doc.toHtml(), expectedHtml); + QCOMPARE(doc.toHtml(), expectedHtml); } diff --git a/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp b/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp index fe0b6dae49..b6917f1208 100644 --- a/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp +++ b/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp @@ -34,6 +34,7 @@ #include <qtextdocumentfragment.h> #include <qtexttable.h> #include <qtextlist.h> +#include <qregularexpression.h> #include <qdebug.h> #include <private/qtextdocument_p.h> @@ -180,6 +181,11 @@ private slots: void html_tableCellBackground(); void css_bodyBackground(); void css_tableCellBackground(); + void css_tableCellBorder(); + void css_tableCellBorderShorthand(); + void css_tableCellAllBordersShorthand(); + void css_tableCellOverrideOneBorder(); + void css_tableBorderCollapse(); void css_fontWeight(); void css_float(); void css_textIndent(); @@ -944,7 +950,7 @@ void tst_QTextDocumentFragment::namedAnchorFragments3() QCOMPARE(it.fragment().text(), QString::fromLatin1("T")); QVERIFY(it.fragment().charFormat().isAnchor()); - QCOMPARE(it.fragment().charFormat().anchorName(), QString("target")); + QCOMPARE(it.fragment().charFormat().anchorNames().constFirst(), QLatin1String("target")); QStringList targets; targets << "target" << "target2"; QCOMPARE(it.fragment().charFormat().anchorNames(), targets); @@ -1271,11 +1277,11 @@ void tst_QTextDocumentFragment::html_whitespace_data() QTest::newRow("2") << QString("<span> </span><span>nowhitespacehereplease</span>") << QString::fromLatin1("nowhitespacehereplease"); - QTest::newRow("3") << QString("<span style=\"white-space: pre;\"> white space here </span>") - << QString::fromLatin1(" white space here "); + QTest::newRow("3") << QString("<span style=\"white-space: pre;\"> white space \n\n here </span>") + << QString::fromLatin1(" white space \n\n here "); - QTest::newRow("4") << QString("<span style=\"white-space: pre-wrap;\"> white space here </span>") - << QString::fromLatin1(" white space here "); + QTest::newRow("4") << QString("<span style=\"white-space: pre-wrap;\"> white space \n\n here </span>") + << QString::fromLatin1(" white space \n\n here "); QTest::newRow("5") << QString("<a href=\"One.html\">One</a> <a href=\"Two.html\">Two</a> <b>Three</b>\n" "<b>Four</b>") @@ -1290,6 +1296,12 @@ void tst_QTextDocumentFragment::html_whitespace_data() QTest::newRow("8") << QString("<table><tr><td><i>Blah</i></td></tr></table> <i>Blub</i>") << QString("\nBlah\nBlub"); + QTest::newRow("9") << QString("<span style=\"white-space: nowrap;\"> white space \n\n here </span>") + << QString::fromLatin1("white space here "); + + QTest::newRow("10") << QString("<span style=\"white-space: pre-line;\"> white space \n\n here </span>") + << QString::fromLatin1("white space\n\nhere "); + QTest::newRow("task116492") << QString("<p>a<font=\"Times\"> b </font>c</p>") << QString("a b c"); @@ -1746,6 +1758,135 @@ void tst_QTextDocumentFragment::css_tableCellBackground() QCOMPARE(cell.format().background().style(), Qt::TexturePattern); } +void tst_QTextDocumentFragment::css_tableCellBorder() +{ + const char html[] = "<body><table><tr><td style=\"border-width:8px;border-color:green;border-style:groove;border-left-style:dashed;border-left-color:red;border-left-width:4px\">Foo</td></tr></table></body>"; + doc->setHtml(html); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + + QTextTableCell cell = table->cellAt(0, 0); + QTextTableCellFormat cellFormat = cell.format().toTableCellFormat(); + QCOMPARE(cellFormat.leftBorder(), qreal(4)); + QCOMPARE(cellFormat.leftBorderBrush(), QBrush(QColor("red"))); + QCOMPARE(cellFormat.leftBorderStyle(), QTextFrameFormat::BorderStyle_Dashed); + + QCOMPARE(cellFormat.rightBorder(), qreal(8)); + QCOMPARE(cellFormat.rightBorderBrush(), QBrush(QColor("green"))); + QCOMPARE(cellFormat.rightBorderStyle(), QTextFrameFormat::BorderStyle_Groove); + + QCOMPARE(cellFormat.bottomBorder(), qreal(8)); + QCOMPARE(cellFormat.bottomBorderBrush(), QBrush(QColor("green"))); + QCOMPARE(cellFormat.bottomBorderStyle(), QTextFrameFormat::BorderStyle_Groove); + + QCOMPARE(cellFormat.topBorder(), qreal(8)); + QCOMPARE(cellFormat.topBorderBrush(), QBrush(QColor("green"))); + QCOMPARE(cellFormat.topBorderStyle(), QTextFrameFormat::BorderStyle_Groove); +} + +void tst_QTextDocumentFragment::css_tableCellBorderShorthand() +{ + const char html[] = "<body><table><tr><td style=\"border-left:1px solid green;border-right:2px dashed red;border-bottom:3px dotted yellow;border-top:4px dot-dash blue\">Foo</td></tr></table></body>"; + doc->setHtml(html); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + + QTextTableCell cell = table->cellAt(0, 0); + QTextTableCellFormat cellFormat = cell.format().toTableCellFormat(); + QCOMPARE(cellFormat.leftBorder(), qreal(1)); + QCOMPARE(cellFormat.leftBorderBrush(), QBrush(QColor("green"))); + QCOMPARE(cellFormat.leftBorderStyle(), QTextFrameFormat::BorderStyle_Solid); + + QCOMPARE(cellFormat.rightBorder(), qreal(2)); + QCOMPARE(cellFormat.rightBorderBrush(), QBrush(QColor("red"))); + QCOMPARE(cellFormat.rightBorderStyle(), QTextFrameFormat::BorderStyle_Dashed); + + QCOMPARE(cellFormat.bottomBorder(), qreal(3)); + QCOMPARE(cellFormat.bottomBorderBrush(), QBrush(QColor("yellow"))); + QCOMPARE(cellFormat.bottomBorderStyle(), QTextFrameFormat::BorderStyle_Dotted); + + QCOMPARE(cellFormat.topBorder(), qreal(4)); + QCOMPARE(cellFormat.topBorderBrush(), QBrush(QColor("blue"))); + QCOMPARE(cellFormat.topBorderStyle(), QTextFrameFormat::BorderStyle_DotDash); +} + +void tst_QTextDocumentFragment::css_tableCellAllBordersShorthand() +{ + const char html[] = "<body><table><tr><td style=\"border:2px dashed green\">Foo</td></tr></table></body>"; + doc->setHtml(html); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + + QTextTableCell cell = table->cellAt(0, 0); + QTextTableCellFormat cellFormat = cell.format().toTableCellFormat(); + QCOMPARE(cellFormat.leftBorder(), qreal(2)); + QCOMPARE(cellFormat.leftBorderBrush(), QBrush(QColor("green"))); + QCOMPARE(cellFormat.leftBorderStyle(), QTextFrameFormat::BorderStyle_Dashed); + + QCOMPARE(cellFormat.rightBorder(), qreal(2)); + QCOMPARE(cellFormat.rightBorderBrush(), QBrush(QColor("green"))); + QCOMPARE(cellFormat.rightBorderStyle(), QTextFrameFormat::BorderStyle_Dashed); + + QCOMPARE(cellFormat.bottomBorder(), qreal(2)); + QCOMPARE(cellFormat.bottomBorderBrush(), QBrush(QColor("green"))); + QCOMPARE(cellFormat.bottomBorderStyle(), QTextFrameFormat::BorderStyle_Dashed); + + QCOMPARE(cellFormat.topBorder(), qreal(2)); + QCOMPARE(cellFormat.topBorderBrush(), QBrush(QColor("green"))); + QCOMPARE(cellFormat.topBorderStyle(), QTextFrameFormat::BorderStyle_Dashed); +} + +void tst_QTextDocumentFragment::css_tableCellOverrideOneBorder() +{ + const char html[] = "<body><table><tr><td style=\"border:2px dashed green;border-left:4px solid red\">Foo</td></tr></table></body>"; + doc->setHtml(html); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + + QTextTableCell cell = table->cellAt(0, 0); + QTextTableCellFormat cellFormat = cell.format().toTableCellFormat(); + QCOMPARE(cellFormat.leftBorder(), qreal(4)); + QCOMPARE(cellFormat.leftBorderBrush(), QBrush(QColor("red"))); + QCOMPARE(cellFormat.leftBorderStyle(), QTextFrameFormat::BorderStyle_Solid); + + QCOMPARE(cellFormat.rightBorder(), qreal(2)); + QCOMPARE(cellFormat.rightBorderBrush(), QBrush(QColor("green"))); + QCOMPARE(cellFormat.rightBorderStyle(), QTextFrameFormat::BorderStyle_Dashed); + + QCOMPARE(cellFormat.bottomBorder(), qreal(2)); + QCOMPARE(cellFormat.bottomBorderBrush(), QBrush(QColor("green"))); + QCOMPARE(cellFormat.bottomBorderStyle(), QTextFrameFormat::BorderStyle_Dashed); + + QCOMPARE(cellFormat.topBorder(), qreal(2)); + QCOMPARE(cellFormat.topBorderBrush(), QBrush(QColor("green"))); + QCOMPARE(cellFormat.topBorderStyle(), QTextFrameFormat::BorderStyle_Dashed); +} + +void tst_QTextDocumentFragment::css_tableBorderCollapse() +{ + const char html[] = "<body><table style=\"border-collapse:collapse\"><tr><td>Foo</td></tr></table></body>"; + doc->setHtml(html); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + + QCOMPARE(table->format().borderCollapse(), true); +} + void tst_QTextDocumentFragment::css_cellPaddings() { const char html[] = "<body><table><tr><td style=\"padding-left:1\">Foo</td>" @@ -1925,7 +2066,7 @@ void tst_QTextDocumentFragment::html_nobr() QString text = doc->begin().begin().fragment().text(); QString expectedText = input; - expectedText.replace(QRegExp("\\s+"), QString(QChar::Nbsp)); + expectedText.replace(QRegularExpression("\\s+"), QString(QChar::Nbsp)); QCOMPARE(text, expectedText); } diff --git a/tests/auto/gui/text/qtextdocumentlayout/BLACKLIST b/tests/auto/gui/text/qtextdocumentlayout/BLACKLIST index b13b2497d3..5c81e74aa0 100644 --- a/tests/auto/gui/text/qtextdocumentlayout/BLACKLIST +++ b/tests/auto/gui/text/qtextdocumentlayout/BLACKLIST @@ -1,2 +1,4 @@ [imageAtRightAlignedTab] -linux +rhel-6.6 +rhel-7.4 +rhel-7.6 diff --git a/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp b/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp index f0a32c2ed4..2dcca0209e 100644 --- a/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp +++ b/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp @@ -138,6 +138,7 @@ private slots: void noModificationOfInputString(); void superscriptCrash_qtbug53911(); void showLineAndParagraphSeparatorsCrash(); + void koreanWordWrap(); void tooManyDirectionalCharctersCrash_qtbug77819(); private: @@ -2067,7 +2068,12 @@ void tst_QTextLayout::cursorInLigatureWithMultipleLines() void tst_QTextLayout::xToCursorForLigatures() { +#if defined(Q_OS_WIN32) + QTextLayout layout("fi", QFont("Calibri", 20)); +#else QTextLayout layout("fi", QFont("Times", 20)); +#endif + layout.setCacheEnabled(true); layout.beginLayout(); QTextLine line = layout.createLine(); @@ -2228,7 +2234,6 @@ void tst_QTextLayout::superscriptCrash_qtbug53911() for (int j = 0; j < 4; ++j) { QTextLayout* newTextLayout = new QTextLayout(); newTextLayout->setText(layoutText); - QList<QTextLayout::FormatRange> formatRanges; QTextLayout::FormatRange formatRange; formatRange.format.setFont(QFont()); @@ -2257,8 +2262,7 @@ void tst_QTextLayout::superscriptCrash_qtbug53911() formatRange.start = 0; formatRange.length = layoutText.size(); - formatRanges << formatRange; - newTextLayout->setAdditionalFormats(formatRanges); + newTextLayout->setFormats({formatRange}); textLayouts.push_front(newTextLayout); } @@ -2289,10 +2293,7 @@ void tst_QTextLayout::nbspWithFormat() formatRange.length = 1; formatRange.format.setFontUnderline(true); - QList<QTextLayout::FormatRange> overrides; - overrides.append(formatRange); - - layout.setAdditionalFormats(overrides); + layout.setFormats({formatRange}); layout.beginLayout(); forever { @@ -2310,6 +2311,31 @@ void tst_QTextLayout::nbspWithFormat() QCOMPARE(layout.lineAt(1).textLength(), s2.length() + 1 + s3.length()); } +void tst_QTextLayout::koreanWordWrap() +{ + QString s = QString::fromUtf8("안녕하세요 여러분!"); + QTextLayout layout; + QTextOption option = layout.textOption(); + option.setWrapMode(QTextOption::WordWrap); + option.setFlags(QTextOption::Flag(QTextOption::IncludeTrailingSpaces)); + layout.setTextOption(option); + layout.setText(s); + + QFontMetrics metrics(layout.font()); + + layout.beginLayout(); + forever { + QTextLine line = layout.createLine(); + if (!line.isValid()) + break; + line.setLineWidth(metrics.horizontalAdvance(s) * 0.8); + } + layout.endLayout(); + QCOMPARE(layout.lineCount(), 2); + QCOMPARE(layout.lineAt(0).textLength(), 6); + QCOMPARE(layout.lineAt(1).textLength(), 4); +} + void tst_QTextLayout::tooManyDirectionalCharctersCrash_qtbug77819() { QString data; diff --git a/tests/auto/gui/text/qtextlist/tst_qtextlist.cpp b/tests/auto/gui/text/qtextlist/tst_qtextlist.cpp index d623ce4044..93e40e7f23 100644 --- a/tests/auto/gui/text/qtextlist/tst_qtextlist.cpp +++ b/tests/auto/gui/text/qtextlist/tst_qtextlist.cpp @@ -314,7 +314,7 @@ void tst_QTextList::partialRemoval() selection.deleteChar(); // deletes the second list QVERIFY(!secondList); - QVERIFY(!firstList->isEmpty()); + QVERIFY(firstList->count() > 0); doc->undo(); } diff --git a/tests/auto/gui/text/qtextmarkdownimporter/data/headingBulletsContinuations.md b/tests/auto/gui/text/qtextmarkdownimporter/data/headingBulletsContinuations.md new file mode 100644 index 0000000000..99eb633d17 --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownimporter/data/headingBulletsContinuations.md @@ -0,0 +1,28 @@ +# heading +- bullet 1 + continuation line 1, indented via tab +- bullet 2 + continuation line 2, indented via 4 spaces +- bullet 3 + + continuation paragraph 3, indented via tab + + - bullet 3.1 + + continuation paragraph 3.1, indented via 4 spaces + + - bullet 3.2 + continuation line, indented via 2 tabs +- bullet 4 + + continuation paragraph 4, indented via 4 spaces + and continuing onto another line too + +- bullet 5 + + continuation paragraph 5, indented via 2 spaces and continuing onto another + line too + +- bullet 6 + +plain old paragraph at the end diff --git a/tests/auto/gui/text/qtextmarkdownimporter/data/thematicBreaks.md b/tests/auto/gui/text/qtextmarkdownimporter/data/thematicBreaks.md new file mode 100644 index 0000000000..7a0d5388ad --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownimporter/data/thematicBreaks.md @@ -0,0 +1,17 @@ +Heading +------- +*** +stars +- bullet + ** not a bullet or a rule, just two stars +- [ ] unchecked + + --- indented too far, so not a rule +* * * +stars with tabs between +*** +stars with whitespace after +--- +hyphens with whitespace after +_____ +underscores with whitespace after diff --git a/tests/auto/gui/text/qtextmarkdownimporter/qtextmarkdownimporter.pro b/tests/auto/gui/text/qtextmarkdownimporter/qtextmarkdownimporter.pro new file mode 100644 index 0000000000..7b7fb61244 --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownimporter/qtextmarkdownimporter.pro @@ -0,0 +1,9 @@ +CONFIG += testcase +TARGET = tst_qtextmarkdownimporter +QT += core-private gui-private testlib +SOURCES += tst_qtextmarkdownimporter.cpp +TESTDATA += \ + data/thematicBreaks.md \ + data/headingBulletsContinuations.md \ + +DEFINES += SRCDIR=\\\"$$PWD\\\" diff --git a/tests/auto/gui/text/qtextmarkdownimporter/tst_qtextmarkdownimporter.cpp b/tests/auto/gui/text/qtextmarkdownimporter/tst_qtextmarkdownimporter.cpp new file mode 100644 index 0000000000..8f51a7a474 --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownimporter/tst_qtextmarkdownimporter.cpp @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QTextDocument> +#include <QTextCursor> +#include <QTextBlock> +#include <QTextList> +#include <QTextTable> +#include <QBuffer> +#include <QDebug> + +#include <private/qtextmarkdownimporter_p.h> + +// #define DEBUG_WRITE_HTML + +Q_LOGGING_CATEGORY(lcTests, "qt.text.tests") + +static const QChar LineBreak = QChar(0x2028); +static const QChar Tab = QLatin1Char('\t'); +static const QChar Space = QLatin1Char(' '); +static const QChar Period = QLatin1Char('.'); + +class tst_QTextMarkdownImporter : public QObject +{ + Q_OBJECT + +private slots: + void headingBulletsContinuations(); + void thematicBreaks(); +}; + +void tst_QTextMarkdownImporter::headingBulletsContinuations() +{ + const QStringList expectedBlocks = QStringList() << + "" << // we could do without this blank line before the heading, but currently it happens + "heading" << + "bullet 1 continuation line 1, indented via tab" << + "bullet 2 continuation line 2, indented via 4 spaces" << + "bullet 3" << + "continuation paragraph 3, indented via tab" << + "bullet 3.1" << + "continuation paragraph 3.1, indented via 4 spaces" << + "bullet 3.2 continuation line, indented via 2 tabs" << + "bullet 4" << + "continuation paragraph 4, indented via 4 spaces and continuing onto another line too" << + "bullet 5" << + // indenting by only 2 spaces is perhaps non-standard but currently is OK + "continuation paragraph 5, indented via 2 spaces and continuing onto another line too" << + "bullet 6" << + "plain old paragraph at the end"; + + QFile f(QFINDTESTDATA("data/headingBulletsContinuations.md")); + QVERIFY(f.open(QFile::ReadOnly | QIODevice::Text)); + QString md = QString::fromUtf8(f.readAll()); + f.close(); + + QTextDocument doc; + QTextMarkdownImporter(QTextMarkdownImporter::DialectGitHub).import(&doc, md); + QTextFrame::iterator iterator = doc.rootFrame()->begin(); + QTextFrame *currentFrame = iterator.currentFrame(); + QStringList::const_iterator expectedIt = expectedBlocks.constBegin(); + int i = 0; + while (!iterator.atEnd()) { + // There are no child frames + QCOMPARE(iterator.currentFrame(), currentFrame); + // Check whether we got the right child block + QTextBlock block = iterator.currentBlock(); + QCOMPARE(block.text().contains(LineBreak), false); + QCOMPARE(block.text().contains(Tab), false); + QVERIFY(!block.text().startsWith(Space)); + int expectedIndentation = 0; + if (block.text().contains(QLatin1String("continuation paragraph"))) + expectedIndentation = (block.text().contains(Period) ? 2 : 1); + qCDebug(lcTests) << i << "child block" << block.text() << "indentation" << block.blockFormat().indent(); + QVERIFY(expectedIt != expectedBlocks.constEnd()); + QCOMPARE(block.text(), *expectedIt); + if (i > 2) + QCOMPARE(block.blockFormat().indent(), expectedIndentation); + ++iterator; + ++expectedIt; + ++i; + } + QCOMPARE(expectedIt, expectedBlocks.constEnd()); + +#ifdef DEBUG_WRITE_HTML + { + QFile out("/tmp/headingBulletsContinuations.html"); + out.open(QFile::WriteOnly); + out.write(doc.toHtml().toLatin1()); + out.close(); + } +#endif +} + +void tst_QTextMarkdownImporter::thematicBreaks() +{ + int horizontalRuleCount = 0; + int textLinesCount = 0; + + QFile f(QFINDTESTDATA("data/thematicBreaks.md")); + QVERIFY(f.open(QFile::ReadOnly | QIODevice::Text)); + QString md = QString::fromUtf8(f.readAll()); + f.close(); + + QTextDocument doc; + QTextMarkdownImporter(QTextMarkdownImporter::DialectGitHub).import(&doc, md); + QTextFrame::iterator iterator = doc.rootFrame()->begin(); + QTextFrame *currentFrame = iterator.currentFrame(); + int i = 0; + while (!iterator.atEnd()) { + // There are no child frames + QCOMPARE(iterator.currentFrame(), currentFrame); + // Check whether the block is text or a horizontal rule + QTextBlock block = iterator.currentBlock(); + if (block.blockFormat().hasProperty(QTextFormat::BlockTrailingHorizontalRulerWidth)) + ++horizontalRuleCount; + else if (!block.text().isEmpty()) + ++textLinesCount; + qCDebug(lcTests) << i << (block.blockFormat().hasProperty(QTextFormat::BlockTrailingHorizontalRulerWidth) ? QLatin1String("- - -") : block.text()); + ++iterator; + ++i; + } + QCOMPARE(horizontalRuleCount, 5); + QCOMPARE(textLinesCount, 9); + +#ifdef DEBUG_WRITE_HTML + { + QFile out("/tmp/thematicBreaks.html"); + out.open(QFile::WriteOnly); + out.write(doc.toHtml().toLatin1()); + out.close(); + } +#endif +} + +QTEST_MAIN(tst_QTextMarkdownImporter) +#include "tst_qtextmarkdownimporter.moc" diff --git a/tests/auto/gui/text/qtextmarkdownwriter/BLACKLIST b/tests/auto/gui/text/qtextmarkdownwriter/BLACKLIST new file mode 100644 index 0000000000..0ce46130ce --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownwriter/BLACKLIST @@ -0,0 +1,2 @@ +[rewriteDocument] +winrt diff --git a/tests/auto/gui/text/qtextmarkdownwriter/data/blockquotes.md b/tests/auto/gui/text/qtextmarkdownwriter/data/blockquotes.md new file mode 100644 index 0000000000..6336d0219f --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownwriter/data/blockquotes.md @@ -0,0 +1,62 @@ +In 1958, Mahatma Gandhi was quoted as follows: + +> The Earth provides enough to satisfy every man's need but not for every man's +> greed. + +In [The CommonMark Specification](https://spec.commonmark.org/0.29/) John +MacFarlane writes: + +> What distinguishes Markdown from many other lightweight markup syntaxes, +> which are often easier to write, is its readability. As Gruber writes: + +> > The overriding design goal for Markdown's formatting syntax is to make it +> > as readable as possible. The idea is that a Markdown-formatted document should +> > be publishable as-is, as plain text, without looking like it's been marked up +> > with tags or formatting instructions. ( +> > [http://daringfireball.net/projects/markdown/](http://daringfireball.net/projects/markdown/) +> > ) + +> The point can be illustrated by comparing a sample of AsciiDoc with an +> equivalent sample of Markdown. Here is a sample of AsciiDoc from the AsciiDoc +> manual: + +> ``` AsciiDoc +> 1. List item one. +> + +> List item one continued with a second paragraph followed by an +> Indented block. +> + +> ................. +> $ ls *.sh +> $ mv *.sh ~/tmp +> ................. +> + +> List item continued with a third paragraph. +> +> 2. List item two continued with an open block. +> ... +> ``` +The quotation includes an embedded quotation and a code quotation and ends with +an ellipsis due to being incomplete. + +Now let's have an indented code block: + + #include <stdio.h> + + int main(void) + { + printf("# hello markdown\n"); + return 0; + } + +and end with a fenced code block: +~~~ pseudocode +#include <something.h> +#include <else.h> + +a block { + a statement; + another statement; +} +~~~ + diff --git a/tests/auto/gui/text/qtextmarkdownwriter/data/example.md b/tests/auto/gui/text/qtextmarkdownwriter/data/example.md new file mode 100644 index 0000000000..0c3f34e09d --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownwriter/data/example.md @@ -0,0 +1,95 @@ +# QTextEdit + +The QTextEdit widget is an advanced editor that supports formatted rich text. +It can be used to display HTML and other rich document formats. Internally, +QTextEdit uses the QTextDocument class to describe both the high-level +structure of each document and the low-level formatting of paragraphs. + +If you are viewing this document in the textedit example, you can edit this +document to explore Qt's rich text editing features. We have included some +comments in each of the following sections to encourage you to experiment. + +## Font and Paragraph Styles + +QTextEdit supports **bold**, *italic*, and ~~strikethrough~~ font styles, and can +display multicolored text. Font families such as Times New Roman and `Courier` +can also be used directly. *If you place the cursor in a region of styled text, +the controls in the tool bars will change to reflect the current style.* + +Paragraphs can be formatted so that the text is left-aligned, right-aligned, +centered, or fully justified. + +*Try changing the alignment of some text and resize the editor to see how the +text layout changes.* + +## Lists + +Different kinds of lists can be included in rich text documents. Standard +bullet lists can be nested, using different symbols for each level of the list: + +- Disc symbols are typically used for top-level list items. + * Circle symbols can be used to distinguish between items in lower-level + lists. + + Square symbols provide a reasonable alternative to discs and circles. + +Ordered lists can be created that can be used for tables of contents. Different +characters can be used to enumerate items, and we can use both Roman and Arabic +numerals in the same list structure: + +1. Introduction +2. Qt Tools + 1) Qt Assistant + 2) Qt Designer + 1. Form Editor + 2. Component Architecture + 3) Qt Linguist + +The list will automatically be renumbered if you add or remove items. *Try +adding new sections to the above list or removing existing item to see the +numbers change.* + +## Images + +Inline images are treated like ordinary ranges of characters in the text +editor, so they flow with the surrounding text. Images can also be selected in +the same way as text, making it easy to cut, copy, and paste them. + +![image](images/logo32.png) *Try to select this image by clicking and dragging +over it with the mouse, or use the text cursor to select it by holding down +Shift and using the arrow keys. You can then cut or copy it, and paste it into +different parts of this document.* + +## Tables + +QTextEdit can arrange and format tables, supporting features such as row and +column spans, text formatting within cells, and size constraints for columns. + + +| |Development Tools |Programming Techniques |Graphical User Interfaces| +|-------------|------------------------------------|---------------------------|-------------------------| +|9:00 - 11:00 |Introduction to Qt ||| +|11:00 - 13:00|Using qmake |Object-oriented Programming|Layouts in Qt | +|13:00 - 15:00|Qt Designer Tutorial |Extreme Programming |Writing Custom Styles | +|15:00 - 17:00|Qt Linguist and Internationalization| | | + +*Try adding text to the cells in the table and experiment with the alignment of +the paragraphs.* + +## Hyperlinks + +QTextEdit is designed to support hyperlinks between documents, and this feature +is used extensively in +[Qt Assistant](http://doc.qt.io/qt-5/qtassistant-index.html). Hyperlinks are +automatically created when an HTML file is imported into an editor. Since the +rich text framework supports hyperlinks natively, they can also be created +programatically. + +## Undo and Redo + +Full support for undo and redo operations is built into QTextEdit and the +underlying rich text framework. Operations on a document can be packaged +together to make editing a more comfortable experience for the user. + +*Try making changes to this document and press `Ctrl+Z` to undo them. You can +always recover the original contents of the document.* + diff --git a/tests/auto/gui/text/qtextmarkdownwriter/data/headingsAndLists.md b/tests/auto/gui/text/qtextmarkdownwriter/data/headingsAndLists.md new file mode 100644 index 0000000000..d5d14fb168 --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownwriter/data/headingsAndLists.md @@ -0,0 +1,12 @@ +# heading 1 + +- list item 1 +- list item 2 + +## heading 2 + +1) list item 1 +2) list item 2 + +the end paragraph + diff --git a/tests/auto/gui/text/qtextmarkdownwriter/data/wordWrap.md b/tests/auto/gui/text/qtextmarkdownwriter/data/wordWrap.md new file mode 100644 index 0000000000..dacb0acf77 --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownwriter/data/wordWrap.md @@ -0,0 +1,13 @@ +[The CommonMark Specification](https://spec.commonmark.org/0.29/) is the +conservative formal specification of the Markdown format, while +[GitHub Flavored Markdown](https://guides.github.com/features/mastering-markdown/#GitHub-flavored-markdown) +adds extra features such as task lists and tables. + +Qt owes thanks to the authors of the [MD4C parser](https://github.com/mity/md4c) +for making markdown import possible. The QTextMarkdownWriter class does not +have such dependencies, and also has not yet been tested as extensively, so we +do not yet guarantee that we are able to rewrite every Markdown document that +you are able to read and display with Text or QTextEdit. But you are free to +write [bugs](https://bugreports.qt.io) about any troublesome cases that you +encounter. + diff --git a/tests/auto/gui/text/qtextmarkdownwriter/qtextmarkdownwriter.pro b/tests/auto/gui/text/qtextmarkdownwriter/qtextmarkdownwriter.pro new file mode 100644 index 0000000000..6144710b99 --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownwriter/qtextmarkdownwriter.pro @@ -0,0 +1,9 @@ +CONFIG += testcase +TARGET = tst_qtextmarkdownwriter +QT += core-private gui-private testlib +SOURCES += tst_qtextmarkdownwriter.cpp +TESTDATA += \ + data/example.md \ + data/blockquotes.md \ + +DEFINES += SRCDIR=\\\"$$PWD\\\" diff --git a/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp b/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp new file mode 100644 index 0000000000..1e6c354f17 --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp @@ -0,0 +1,464 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QTextDocument> +#include <QTextCursor> +#include <QTextBlock> +#include <QTextList> +#include <QTextTable> +#include <QBuffer> +#include <QDebug> + +#include <private/qtextmarkdownwriter_p.h> + +// #define DEBUG_WRITE_OUTPUT + +class tst_QTextMarkdownWriter : public QObject +{ + Q_OBJECT +public slots: + void init(); + void cleanup(); + +private slots: + void testWriteParagraph_data(); + void testWriteParagraph(); + void testWriteList(); + void testWriteNestedBulletLists_data(); + void testWriteNestedBulletLists(); + void testWriteNestedNumericLists(); + void testWriteTable(); + void rewriteDocument_data(); + void rewriteDocument(); + void fromHtml_data(); + void fromHtml(); + +private: + QString documentToUnixMarkdown(); + +private: + QTextDocument *document; +}; + +void tst_QTextMarkdownWriter::init() +{ + document = new QTextDocument(); +} + +void tst_QTextMarkdownWriter::cleanup() +{ + delete document; +} + +void tst_QTextMarkdownWriter::testWriteParagraph_data() +{ + QTest::addColumn<QString>("input"); + QTest::addColumn<QString>("output"); + + QTest::newRow("empty") << "" << + ""; + QTest::newRow("spaces") << "foobar word" << + "foobar word\n\n"; + QTest::newRow("starting spaces") << " starting spaces" << + " starting spaces\n\n"; + QTest::newRow("trailing spaces") << "trailing spaces " << + "trailing spaces \n\n"; + QTest::newRow("tab") << "word\ttab x" << + "word\ttab x\n\n"; + QTest::newRow("tab2") << "word\t\ttab\tx" << + "word\t\ttab\tx\n\n"; + QTest::newRow("misc") << "foobar word\ttab x" << + "foobar word\ttab x\n\n"; + QTest::newRow("misc2") << "\t \tFoo" << + "\t \tFoo\n\n"; +} + +void tst_QTextMarkdownWriter::testWriteParagraph() +{ + QFETCH(QString, input); + QFETCH(QString, output); + + QTextCursor cursor(document); + cursor.insertText(input); + + QCOMPARE(documentToUnixMarkdown(), output); +} + +void tst_QTextMarkdownWriter::testWriteList() +{ + QTextCursor cursor(document); + QTextList *list = cursor.createList(QTextListFormat::ListDisc); + cursor.insertText("ListItem 1"); + list->add(cursor.block()); + cursor.insertBlock(); + cursor.insertText("ListItem 2"); + list->add(cursor.block()); + + QCOMPARE(documentToUnixMarkdown(), QString::fromLatin1( + "- ListItem 1\n- ListItem 2\n")); +} + +void tst_QTextMarkdownWriter::testWriteNestedBulletLists_data() +{ + QTest::addColumn<bool>("checkbox"); + QTest::addColumn<bool>("checked"); + QTest::addColumn<bool>("continuationLine"); + QTest::addColumn<bool>("continuationParagraph"); + QTest::addColumn<QString>("expectedOutput"); + + QTest::newRow("plain bullets") << false << false << false << false << + "- ListItem 1\n * ListItem 2\n + ListItem 3\n- ListItem 4\n * ListItem 5\n"; + QTest::newRow("bullets with continuation lines") << false << false << true << false << + "- ListItem 1\n * ListItem 2\n + ListItem 3 with text that won't fit on one line and thus needs a\n continuation\n- ListItem 4\n * ListItem 5 with text that won't fit on one line and thus needs a\n continuation\n"; + QTest::newRow("bullets with continuation paragraphs") << false << false << false << true << + "- ListItem 1\n\n * ListItem 2\n + ListItem 3\n\n continuation\n\n- ListItem 4\n\n * ListItem 5\n\n continuation\n\n"; + QTest::newRow("unchecked") << true << false << false << false << + "- [ ] ListItem 1\n * [ ] ListItem 2\n + [ ] ListItem 3\n- [ ] ListItem 4\n * [ ] ListItem 5\n"; + QTest::newRow("checked") << true << true << false << false << + "- [x] ListItem 1\n * [x] ListItem 2\n + [x] ListItem 3\n- [x] ListItem 4\n * [x] ListItem 5\n"; + QTest::newRow("checked with continuation lines") << true << true << true << false << + "- [x] ListItem 1\n * [x] ListItem 2\n + [x] ListItem 3 with text that won't fit on one line and thus needs a\n continuation\n- [x] ListItem 4\n * [x] ListItem 5 with text that won't fit on one line and thus needs a\n continuation\n"; + QTest::newRow("checked with continuation paragraphs") << true << true << false << true << + "- [x] ListItem 1\n\n * [x] ListItem 2\n + [x] ListItem 3\n\n continuation\n\n- [x] ListItem 4\n\n * [x] ListItem 5\n\n continuation\n\n"; +} + +void tst_QTextMarkdownWriter::testWriteNestedBulletLists() +{ + QFETCH(bool, checkbox); + QFETCH(bool, checked); + QFETCH(bool, continuationParagraph); + QFETCH(bool, continuationLine); + QFETCH(QString, expectedOutput); + + QTextCursor cursor(document); + QTextBlockFormat blockFmt = cursor.blockFormat(); + if (checkbox) { + blockFmt.setMarker(checked ? QTextBlockFormat::MarkerType::Checked : QTextBlockFormat::MarkerType::Unchecked); + cursor.setBlockFormat(blockFmt); + } + + QTextList *list1 = cursor.createList(QTextListFormat::ListDisc); + cursor.insertText("ListItem 1"); + list1->add(cursor.block()); + + QTextListFormat fmt2; + fmt2.setStyle(QTextListFormat::ListCircle); + fmt2.setIndent(2); + QTextList *list2 = cursor.insertList(fmt2); + cursor.insertText("ListItem 2"); + + QTextListFormat fmt3; + fmt3.setStyle(QTextListFormat::ListSquare); + fmt3.setIndent(3); + cursor.insertList(fmt3); + cursor.insertText(continuationLine ? + "ListItem 3 with text that won't fit on one line and thus needs a continuation" : + "ListItem 3"); + if (continuationParagraph) { + QTextBlockFormat blockFmt; + blockFmt.setIndent(2); + cursor.insertBlock(blockFmt); + cursor.insertText("continuation"); + } + + cursor.insertBlock(blockFmt); + cursor.insertText("ListItem 4"); + list1->add(cursor.block()); + + cursor.insertBlock(); + cursor.insertText(continuationLine ? + "ListItem 5 with text that won't fit on one line and thus needs a continuation" : + "ListItem 5"); + list2->add(cursor.block()); + if (continuationParagraph) { + QTextBlockFormat blockFmt; + blockFmt.setIndent(2); + cursor.insertBlock(blockFmt); + cursor.insertText("continuation"); + } + + QString output = documentToUnixMarkdown(); +#ifdef DEBUG_WRITE_OUTPUT + { + QFile out("/tmp/" + QLatin1String(QTest::currentDataTag()) + ".md"); + out.open(QFile::WriteOnly); + out.write(output.toUtf8()); + out.close(); + } +#endif + QCOMPARE(documentToUnixMarkdown(), expectedOutput); +} + +void tst_QTextMarkdownWriter::testWriteNestedNumericLists() +{ + QTextCursor cursor(document); + + QTextList *list1 = cursor.createList(QTextListFormat::ListDecimal); + cursor.insertText("ListItem 1"); + list1->add(cursor.block()); + + QTextListFormat fmt2; + fmt2.setStyle(QTextListFormat::ListLowerAlpha); + fmt2.setNumberSuffix(QLatin1String(")")); + fmt2.setIndent(2); + QTextList *list2 = cursor.insertList(fmt2); + cursor.insertText("ListItem 2"); + + QTextListFormat fmt3; + fmt3.setStyle(QTextListFormat::ListDecimal); + fmt3.setIndent(3); + cursor.insertList(fmt3); + cursor.insertText("ListItem 3"); + + cursor.insertBlock(); + cursor.insertText("ListItem 4"); + list1->add(cursor.block()); + + cursor.insertBlock(); + cursor.insertText("ListItem 5"); + list2->add(cursor.block()); + + // There's no QTextList API to set the starting number so we hard-coded all lists to start at 1 (QTBUG-65384) + QCOMPARE(documentToUnixMarkdown(), QString::fromLatin1( + "1. ListItem 1\n 1) ListItem 2\n 1. ListItem 3\n2. ListItem 4\n 2) ListItem 5\n")); +} + +void tst_QTextMarkdownWriter::testWriteTable() +{ + QTextCursor cursor(document); + QTextTable * table = cursor.insertTable(4, 3); + cursor = table->cellAt(0, 0).firstCursorPosition(); + // valid Markdown tables need headers, but QTextTable doesn't make that distinction + // so QTextMarkdownWriter assumes the first row of any table is a header + cursor.insertText("one"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("two"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("three"); + cursor.movePosition(QTextCursor::NextCell); + + cursor.insertText("alice"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("bob"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("carl"); + cursor.movePosition(QTextCursor::NextCell); + + cursor.insertText("dennis"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("eric"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("fiona"); + cursor.movePosition(QTextCursor::NextCell); + + cursor.insertText("gina"); + /* + |one |two |three| + |------|----|-----| + |alice |bob |carl | + |dennis|eric|fiona| + |gina | | | + */ + + QString md = documentToUnixMarkdown(); + +#ifdef DEBUG_WRITE_OUTPUT + { + QFile out("/tmp/table.md"); + out.open(QFile::WriteOnly); + out.write(md.toUtf8()); + out.close(); + } +#endif + + QString expected = QString::fromLatin1( + "\n|one |two |three|\n|------|----|-----|\n|alice |bob |carl |\n|dennis|eric|fiona|\n|gina | | |\n\n"); + QCOMPARE(md, expected); + + // create table with merged cells + document->clear(); + cursor = QTextCursor(document); + table = cursor.insertTable(3, 3); + table->mergeCells(0, 0, 1, 2); + table->mergeCells(1, 1, 1, 2); + cursor = table->cellAt(0, 0).firstCursorPosition(); + cursor.insertText("a"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("b"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("c"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("d"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("e"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("f"); + /* + +---+-+ + |a |b| + +---+-+ + |c| d| + +-+-+-+ + |e|f| | + +-+-+-+ + + generates + + |a ||b| + |-|-|-| + |c|d || + |e|f| | + + */ + + md = documentToUnixMarkdown(); + +#ifdef DEBUG_WRITE_OUTPUT + { + QFile out("/tmp/table-merged-cells.md"); + out.open(QFile::WriteOnly); + out.write(md.toUtf8()); + out.close(); + } +#endif + + QCOMPARE(md, QString::fromLatin1("\n|a ||b|\n|-|-|-|\n|c|d ||\n|e|f| |\n\n")); +} + +void tst_QTextMarkdownWriter::rewriteDocument_data() +{ + QTest::addColumn<QString>("inputFile"); + + QTest::newRow("block quotes") << "blockquotes.md"; + QTest::newRow("example") << "example.md"; + QTest::newRow("list items after headings") << "headingsAndLists.md"; + QTest::newRow("word wrap") << "wordWrap.md"; +} + +void tst_QTextMarkdownWriter::rewriteDocument() +{ + QFETCH(QString, inputFile); + QTextDocument doc; + QFile f(QFINDTESTDATA("data/" + inputFile)); + QVERIFY(f.open(QFile::ReadOnly | QIODevice::Text)); + QString orig = QString::fromUtf8(f.readAll()); + f.close(); + doc.setMarkdown(orig); + QString md = doc.toMarkdown(); + +#ifdef DEBUG_WRITE_OUTPUT + QFile out("/tmp/rewrite-" + inputFile); + out.open(QFile::WriteOnly); + out.write(md.toUtf8()); + out.close(); +#endif + + QCOMPARE(md, orig); +} + +void tst_QTextMarkdownWriter::fromHtml_data() +{ + QTest::addColumn<QString>("expectedInput"); + QTest::addColumn<QString>("expectedOutput"); + + QTest::newRow("long URL") << + "<span style=\"font-style:italic;\">https://www.example.com/dir/subdir/subsubdir/subsubsubdir/subsubsubsubdir/subsubsubsubsubdir/</span>" << + "*https://www.example.com/dir/subdir/subsubdir/subsubsubdir/subsubsubsubdir/subsubsubsubsubdir/*\n\n"; + QTest::newRow("non-emphasis inline asterisk") << "3 * 4" << "3 * 4\n\n"; + QTest::newRow("arithmetic") << "(2 * a * x + b)^2 = b^2 - 4 * a * c" << "(2 * a * x + b)^2 = b^2 - 4 * a * c\n\n"; + QTest::newRow("escaped asterisk after newline") << + "The first sentence of this paragraph holds 80 characters, then there's a star. * This is wrapped, but is <em>not</em> a bullet point." << + "The first sentence of this paragraph holds 80 characters, then there's a star.\n\\* This is wrapped, but is *not* a bullet point.\n\n"; + QTest::newRow("escaped plus after newline") << + "The first sentence of this paragraph holds 80 characters, then there's a plus. + This is wrapped, but is <em>not</em> a bullet point." << + "The first sentence of this paragraph holds 80 characters, then there's a plus.\n\\+ This is wrapped, but is *not* a bullet point.\n\n"; + QTest::newRow("escaped hyphen after newline") << + "The first sentence of this paragraph holds 80 characters, then there's a minus. - This is wrapped, but is <em>not</em> a bullet point." << + "The first sentence of this paragraph holds 80 characters, then there's a minus.\n\\- This is wrapped, but is *not* a bullet point.\n\n"; + QTest::newRow("list items with indented continuations") << + "<ul><li>bullet<p>continuation paragraph</p></li><li>another bullet<br/>continuation line</li></ul>" << + "- bullet\n\n continuation paragraph\n\n- another bullet\n continuation line\n"; + QTest::newRow("nested list items with continuations") << + "<ul><li>bullet<p>continuation paragraph</p></li><li>another bullet<br/>continuation line</li><ul><li>bullet<p>continuation paragraph</p></li><li>another bullet<br/>continuation line</li></ul></ul>" << + "- bullet\n\n continuation paragraph\n\n- another bullet\n continuation line\n\n - bullet\n\n continuation paragraph\n\n - another bullet\n continuation line\n"; + QTest::newRow("nested ordered list items with continuations") << + "<ol><li>item<p>continuation paragraph</p></li><li>another item<br/>continuation line</li><ol><li>item<p>continuation paragraph</p></li><li>another item<br/>continuation line</li></ol><li>another</li><li>another</li></ol>" << + "1. item\n\n continuation paragraph\n\n2. another item\n continuation line\n\n 1. item\n\n continuation paragraph\n\n 2. another item\n continuation line\n\n3. another\n4. another\n"; + QTest::newRow("thematic break") << + "something<hr/>something else" << + "something\n\n- - -\nsomething else\n\n"; + QTest::newRow("block quote") << + "<p>In 1958, Mahatma Gandhi was quoted as follows:</p><blockquote>The Earth provides enough to satisfy every man's need but not for every man's greed.</blockquote>" << + "In 1958, Mahatma Gandhi was quoted as follows:\n\n> The Earth provides enough to satisfy every man's need but not for every man's\n> greed.\n\n"; + QTest::newRow("image") << + "<img src=\"/url\" alt=\"foo\" title=\"title\"/>" << + "![foo](/url \"title\")\n\n"; + QTest::newRow("code") << + "<pre class=\"language-pseudocode\">\n#include \"foo.h\"\n\nblock {\n statement();\n}\n\n</pre>" << + "``` pseudocode\n#include \"foo.h\"\n\nblock {\n statement();\n}\n```\n\n"; + // TODO +// QTest::newRow("escaped number and paren after double newline") << +// "<p>(The first sentence of this paragraph is a line, the next paragraph has a number</p>13) but that's not part of an ordered list" << +// "(The first sentence of this paragraph is a line, the next paragraph has a number\n\n13\\) but that's not part of an ordered list\n\n"; +// QTest::newRow("preformats with embedded backticks") << +// "<pre>none `one` ``two``</pre><pre>```three``` ````four````</pre>plain" << +// "``` none `one` ``two`` ```\n\n````` ```three``` ````four```` `````\n\nplain\n\n"; +} + +void tst_QTextMarkdownWriter::fromHtml() +{ + QFETCH(QString, expectedInput); + QFETCH(QString, expectedOutput); + + document->setHtml(expectedInput); + QString output = documentToUnixMarkdown(); + +#ifdef DEBUG_WRITE_OUTPUT + { + QFile out("/tmp/" + QLatin1String(QTest::currentDataTag()) + ".md"); + out.open(QFile::WriteOnly); + out.write(output.toUtf8()); + out.close(); + } +#endif + + QCOMPARE(output, expectedOutput); +} + +QString tst_QTextMarkdownWriter::documentToUnixMarkdown() +{ + QString ret; + QTextStream ts(&ret, QIODevice::WriteOnly); + QTextMarkdownWriter writer(ts, QTextDocument::MarkdownDialectGitHub); + writer.writeAll(document); + return ret; +} + +QTEST_MAIN(tst_QTextMarkdownWriter) +#include "tst_qtextmarkdownwriter.moc" diff --git a/tests/auto/gui/text/qtexttable/qtexttable.pro b/tests/auto/gui/text/qtexttable/qtexttable.pro index 2faadfcb0d..73e94d5735 100644 --- a/tests/auto/gui/text/qtexttable/qtexttable.pro +++ b/tests/auto/gui/text/qtexttable/qtexttable.pro @@ -1,6 +1,6 @@ CONFIG += testcase TARGET = tst_qtexttable -QT += testlib +QT += testlib gui-private qtHaveModule(widgets): QT += widgets SOURCES += tst_qtexttable.cpp diff --git a/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp b/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp index 22f00c677d..7b2ff4cc10 100644 --- a/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp +++ b/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp @@ -44,11 +44,14 @@ #include <QPainter> #include <QPaintEngine> #endif +#include <private/qpagedpaintdevice_p.h> typedef QList<int> IntList; QT_FORWARD_DECLARE_CLASS(QTextDocument) +Q_DECLARE_METATYPE(QTextFrameFormat::BorderStyle); + class tst_QTextTable : public QObject { Q_OBJECT @@ -91,9 +94,11 @@ private slots: void QTBUG11282_insertBeforeMergedEnding(); #endif void QTBUG22011_insertBeforeRowSpan(); -#ifndef QT_NO_PRINTER +#if !defined(QT_NO_PRINTER) && defined(QT_BUILD_INTERNAL) void QTBUG31330_renderBackground(); #endif + void checkBorderAttributes_data(); + void checkBorderAttributes(); private: QTextTable *create2x2Table(); @@ -1025,7 +1030,7 @@ void tst_QTextTable::QTBUG22011_insertBeforeRowSpan() QCOMPARE(table->columns(), 6); } -#ifndef QT_NO_PRINTER +#if !defined(QT_NO_PRINTER) && defined(QT_BUILD_INTERNAL) namespace { class QTBUG31330_PaintDevice : public QPagedPaintDevice { @@ -1065,11 +1070,46 @@ public: {} }; + class QDummyPagedPaintDevicePrivate : public QPagedPaintDevicePrivate + { + bool setPageLayout(const QPageLayout &newPageLayout) override + { + m_pageLayout = newPageLayout; + return m_pageLayout.isEquivalentTo(newPageLayout); + } + + bool setPageSize(const QPageSize &pageSize) override + { + m_pageLayout.setPageSize(pageSize); + return m_pageLayout.pageSize().isEquivalentTo(pageSize); + } + + bool setPageOrientation(QPageLayout::Orientation orientation) override + { + m_pageLayout.setOrientation(orientation); + return m_pageLayout.orientation() == orientation; + } + + bool setPageMargins(const QMarginsF &margins, QPageLayout::Unit units) override + { + m_pageLayout.setUnits(units); + m_pageLayout.setMargins(margins); + return m_pageLayout.margins() == margins && m_pageLayout.units() == units; + } + + QPageLayout pageLayout() const override + { + return m_pageLayout; + } + + QPageLayout m_pageLayout; + }; + int pages; QPaintEngine* engine; QTBUG31330_PaintDevice(QPaintEngine* engine) - : pages(1), engine(engine) + : QPagedPaintDevice(new QDummyPagedPaintDevicePrivate), pages(1), engine(engine) { QPageLayout layout = pageLayout(); layout.setUnits(QPageLayout::Point); @@ -1134,5 +1174,109 @@ void tst_QTextTable::QTBUG31330_renderBackground() } #endif +void tst_QTextTable::checkBorderAttributes_data() +{ + QTest::addColumn<QString>("html"); + QTest::addColumn<qreal>("topBorderWidth"); + QTest::addColumn<qreal>("bottomBorderWidth"); + QTest::addColumn<qreal>("leftBorderWidth"); + QTest::addColumn<qreal>("rightBorderWidth"); + QTest::addColumn<QTextFrameFormat::BorderStyle>("topBorderStyle"); + QTest::addColumn<QTextFrameFormat::BorderStyle>("bottomBorderStyle"); + QTest::addColumn<QTextFrameFormat::BorderStyle>("leftBorderStyle"); + QTest::addColumn<QTextFrameFormat::BorderStyle>("rightBorderStyle"); + QTest::addColumn<QBrush>("topBorderBrush"); + QTest::addColumn<QBrush>("bottomBorderBrush"); + QTest::addColumn<QBrush>("leftBorderBrush"); + QTest::addColumn<QBrush>("rightBorderBrush"); + + const QString tableHtmlStart = QStringLiteral("<html><head><style>"); + const QString tableHtmlEnd = QStringLiteral("</style></head><body>" + "<table border=\"1\"><tr><td>One</td><td>Two</td></tr>" + "<tr><td>Three</td><td>Four</td></tr></table></body></html>"); + QTest::newRow("1px-solid-colors") + << QString("%1" + "td {" + "border-top: 1px solid red;" + "border-bottom: 1px solid blue;" + "border-left: 1px solid green;" + "border-right: 1px solid yellow;" + "}" + "%2").arg(tableHtmlStart).arg(tableHtmlEnd) + << 1.0 << 1.0 << 1.0 << 1.0 + << QTextFrameFormat::BorderStyle_Solid << QTextFrameFormat::BorderStyle_Solid + << QTextFrameFormat::BorderStyle_Solid << QTextFrameFormat::BorderStyle_Solid + << QBrush(Qt::red) << QBrush(Qt::blue) << QBrush(Qt::darkGreen) << QBrush(Qt::yellow); + QTest::newRow("MixedWidth-solid-colors") + << QString("%1" + "td {" + "border-top: 1px solid red;" + "border-bottom: 2px solid blue;" + "border-left: 3px solid green;" + "border-right: 4px solid yellow;" + "}" + "%2").arg(tableHtmlStart).arg(tableHtmlEnd) + << 1.0 << 2.0 << 3.0 << 4.0 + << QTextFrameFormat::BorderStyle_Solid << QTextFrameFormat::BorderStyle_Solid + << QTextFrameFormat::BorderStyle_Solid << QTextFrameFormat::BorderStyle_Solid + << QBrush(Qt::red) << QBrush(Qt::blue) << QBrush(Qt::darkGreen) << QBrush(Qt::yellow); + QTest::newRow("MixedWidth-MixedStyle-colors") + << QString("%1" + "td {" + "border-top: 1px solid red;" + "border-bottom: 2px dotted blue;" + "border-left: 3px dashed green;" + "border-right: 4px inset yellow;" + "}" + "%2").arg(tableHtmlStart).arg(tableHtmlEnd) + << 1.0 << 2.0 << 3.0 << 4.0 + << QTextFrameFormat::BorderStyle_Solid << QTextFrameFormat::BorderStyle_Dotted + << QTextFrameFormat::BorderStyle_Dashed << QTextFrameFormat::BorderStyle_Inset + << QBrush(Qt::red) << QBrush(Qt::blue) << QBrush(Qt::darkGreen) << QBrush(Qt::yellow); +} + +void tst_QTextTable::checkBorderAttributes() +{ + QFETCH(QString, html); + QFETCH(qreal, topBorderWidth); + QFETCH(qreal, bottomBorderWidth); + QFETCH(qreal, leftBorderWidth); + QFETCH(qreal, rightBorderWidth); + QFETCH(QTextFrameFormat::BorderStyle, topBorderStyle); + QFETCH(QTextFrameFormat::BorderStyle, bottomBorderStyle); + QFETCH(QTextFrameFormat::BorderStyle, leftBorderStyle); + QFETCH(QTextFrameFormat::BorderStyle, rightBorderStyle); + QFETCH(QBrush, topBorderBrush); + QFETCH(QBrush, bottomBorderBrush); + QFETCH(QBrush, leftBorderBrush); + QFETCH(QBrush, rightBorderBrush); + + QTextDocument doc; + doc.setHtml(html); + QTextCursor cursor(doc.firstBlock()); + cursor.movePosition(QTextCursor::Right); + + QTextTable *currentTable = cursor.currentTable(); + QVERIFY(currentTable); + for (int row = 0; row < 2; row++) { + for (int column = 0; column < 2; column++) { + QTextTableCell cell = currentTable->cellAt(row, column); + QTextCharFormat cellFormat = cell.format(); + QCOMPARE(cellFormat.doubleProperty(QTextFormat::TableCellTopBorder), topBorderWidth); + QCOMPARE(cellFormat.doubleProperty(QTextFormat::TableCellBottomBorder), bottomBorderWidth); + QCOMPARE(cellFormat.doubleProperty(QTextFormat::TableCellLeftBorder), leftBorderWidth); + QCOMPARE(cellFormat.doubleProperty(QTextFormat::TableCellRightBorder), rightBorderWidth); + QCOMPARE(cellFormat.property(QTextFormat::TableCellTopBorderStyle), topBorderStyle); + QCOMPARE(cellFormat.property(QTextFormat::TableCellBottomBorderStyle), bottomBorderStyle); + QCOMPARE(cellFormat.property(QTextFormat::TableCellLeftBorderStyle), leftBorderStyle); + QCOMPARE(cellFormat.property(QTextFormat::TableCellRightBorderStyle), rightBorderStyle); + QCOMPARE(cellFormat.brushProperty(QTextFormat::TableCellTopBorderBrush), topBorderBrush); + QCOMPARE(cellFormat.brushProperty(QTextFormat::TableCellBottomBorderBrush), bottomBorderBrush); + QCOMPARE(cellFormat.brushProperty(QTextFormat::TableCellLeftBorderBrush), leftBorderBrush); + QCOMPARE(cellFormat.brushProperty(QTextFormat::TableCellRightBorderBrush), rightBorderBrush); + } + } +} + QTEST_MAIN(tst_QTextTable) #include "tst_qtexttable.moc" diff --git a/tests/auto/gui/text/text.pro b/tests/auto/gui/text/text.pro index 6b033fb506..794d9ea8d3 100644 --- a/tests/auto/gui/text/text.pro +++ b/tests/auto/gui/text/text.pro @@ -28,12 +28,16 @@ SUBDIRS=\ win32:SUBDIRS -= qtextpiecetable +qtConfig(textmarkdownreader): SUBDIRS += qtextmarkdownimporter +qtConfig(textmarkdownwriter): SUBDIRS += qtextmarkdownwriter + !qtConfig(private_tests): SUBDIRS -= \ qfontcache \ qcssparser \ qtextlayout \ qtextpiecetable \ qzip \ + qtextmarkdownwriter \ qtextodfwriter !qtHaveModule(xml): SUBDIRS -= \ diff --git a/tests/auto/gui/util/qdesktopservices/tst_qdesktopservices.cpp b/tests/auto/gui/util/qdesktopservices/tst_qdesktopservices.cpp index add23d46cf..4d95345de9 100644 --- a/tests/auto/gui/util/qdesktopservices/tst_qdesktopservices.cpp +++ b/tests/auto/gui/util/qdesktopservices/tst_qdesktopservices.cpp @@ -39,7 +39,9 @@ class tst_qdesktopservices : public QObject private slots: void openUrl(); void handlers(); +#if QT_DEPRECATED_SINCE(5, 0) void testDataLocation(); +#endif }; void tst_qdesktopservices::openUrl() @@ -89,6 +91,7 @@ void tst_qdesktopservices::handlers() #define Q_XDG_PLATFORM #endif +#if QT_DEPRECATED_SINCE(5, 0) void tst_qdesktopservices::testDataLocation() { // This is the one point where QDesktopServices and QStandardPaths differ. @@ -115,6 +118,7 @@ void tst_qdesktopservices::testDataLocation() #endif } } +#endif QTEST_MAIN(tst_qdesktopservices) diff --git a/tests/auto/network-settings.h b/tests/auto/network-settings.h index f162c3ae9f..77298342af 100644 --- a/tests/auto/network-settings.h +++ b/tests/auto/network-settings.h @@ -72,15 +72,20 @@ public: } #ifdef QT_NETWORK_LIB - static QHostAddress serverIP() + static QHostAddress getServerIpImpl(const QString &serverName) { - const QHostInfo info = QHostInfo::fromName(serverName()); + const QHostInfo info = QHostInfo::fromName(serverName); if (info.error()) { QTest::qFail(qPrintable(info.errorString()), __FILE__, __LINE__); return QHostAddress(); } return info.addresses().constFirst(); } + + static QHostAddress serverIP() + { + return getServerIpImpl(serverName()); + } #endif static bool compareReplyIMAP(QByteArray const& actual) @@ -104,8 +109,8 @@ public: static bool compareReplyFtp(QByteArray const& actual) { // output would be e.g. "220 (vsFTPd 2.3.5)\r\n221 Goodbye.\r\n" - QRegExp ftpVersion(QStringLiteral("220 \\(vsFTPd \\d+\\.\\d+.\\d+\\)\\r\\n221 Goodbye.\\r\\n")); - return ftpVersion.exactMatch(actual); + QRegularExpression ftpVersion(QRegularExpression::anchoredPattern(QStringLiteral("220 \\(vsFTPd \\d+\\.\\d+.\\d+\\)\\r\\n221 Goodbye.\\r\\n"))); + return ftpVersion.match(actual).hasMatch(); } static bool hasIPv6() @@ -214,4 +219,67 @@ public: return serverName(); #endif } + static QString imapServerName() + { +#ifdef QT_TEST_SERVER_NAME + return QString("cyrus.") % serverDomainName(); +#else + return serverName(); +#endif + } + + static QString echoServerName() + { +#ifdef QT_TEST_SERVER_NAME + return QString("echo.") % serverDomainName(); +#else + return serverName(); +#endif + } + + static QString firewallServerName() + { +#ifdef QT_TEST_SERVER_NAME + return QString("iptables.") % serverDomainName(); +#else + return serverName(); +#endif + } + +#ifdef QT_NETWORK_LIB + static QHostAddress imapServerIp() + { + return getServerIpImpl(imapServerName()); + } + + static QHostAddress httpServerIp() + { + return getServerIpImpl(httpServerName()); + } + + static QHostAddress httpProxyServerIp() + { + return getServerIpImpl(httpProxyServerName()); + } + + static QHostAddress socksProxyServerIp() + { + return getServerIpImpl(socksProxyServerName()); + } + + static QHostAddress ftpProxyServerIp() + { + return getServerIpImpl(ftpProxyServerName()); + } + + static QHostAddress ftpServerIp() + { + return getServerIpImpl(ftpServerName()); + } + + static QHostAddress firewallServerIp() + { + return getServerIpImpl(firewallServerName()); + } +#endif }; diff --git a/tests/auto/network/access/http2/http2srv.cpp b/tests/auto/network/access/http2/http2srv.cpp index 5a99d4e50c..a8eebf5a24 100644 --- a/tests/auto/network/access/http2/http2srv.cpp +++ b/tests/auto/network/access/http2/http2srv.cpp @@ -76,7 +76,7 @@ void fill_push_header(const HttpHeader &originalRequest, HttpHeader &promisedReq } -Http2Server::Http2Server(H2Type type, const Http2::RawSettings &ss, const Http2::RawSettings &cs) +Http2Server::Http2Server(H2Type type, const RawSettings &ss, const RawSettings &cs) : connectionType(type), serverSettings(ss), expectedClientSettings(cs) @@ -218,7 +218,7 @@ void Http2Server::sendDATA(quint32 streamID, quint32 windowSize) quint32 bytesToSend = std::min<quint32>(windowSize, responseBody.size() - offset); quint32 bytesSent = 0; - const quint32 frameSizeLimit(clientSetting(Settings::MAX_FRAME_SIZE_ID, Http2::maxFrameSize)); + const quint32 frameSizeLimit(clientSetting(Settings::MAX_FRAME_SIZE_ID, Http2::minPayloadLimit)); const uchar *src = reinterpret_cast<const uchar *>(responseBody.constData() + offset); const bool last = offset + bytesToSend == quint32(responseBody.size()); @@ -236,6 +236,10 @@ void Http2Server::sendDATA(quint32 streamID, quint32 windowSize) src += chunkSize; bytesToSend -= chunkSize; bytesSent += chunkSize; + if (frameSizeLimit != Http2::minPayloadLimit) { + // Our test is probably interested in how many DATA frames were sent. + emit sendingData(); + } } if (interrupted.loadAcquire()) @@ -767,7 +771,7 @@ void Http2Server::sendResponse(quint32 streamID, bool emptyBody) Q_ASSERT(activeRequests.find(streamID) != activeRequests.end()); const quint32 maxFrameSize(clientSetting(Settings::MAX_FRAME_SIZE_ID, - Http2::maxFrameSize)); + Http2::maxPayloadSize)); if (pushPromiseEnabled) { // A real server supporting PUSH_PROMISE will probably first send diff --git a/tests/auto/network/access/http2/http2srv.h b/tests/auto/network/access/http2/http2srv.h index 4ef4b25101..3105684d59 100644 --- a/tests/auto/network/access/http2/http2srv.h +++ b/tests/auto/network/access/http2/http2srv.h @@ -42,6 +42,7 @@ #include <QtCore/qbytearray.h> #include <QtCore/qatomic.h> #include <QtCore/qglobal.h> +#include <QtCore/qmap.h> #include <vector> #include <map> @@ -69,13 +70,15 @@ enum class H2Type { h2cDirect, // Clear text direct }; +using RawSettings = QMap<Http2::Settings, quint32>; + class Http2Server : public QTcpServer { Q_OBJECT public: - Http2Server(H2Type type, const Http2::RawSettings &serverSettings, - const Http2::RawSettings &clientSettings); + Http2Server(H2Type type, const RawSettings &serverSettings, + const RawSettings &clientSettings); ~Http2Server(); @@ -125,6 +128,7 @@ Q_SIGNALS: void receivedRequest(quint32 streamID); void receivedData(quint32 streamID); void windowUpdate(quint32 streamID); + void sendingData(); private slots: void connectionEstablished(); @@ -147,8 +151,8 @@ private: bool settingsSent = false; bool waitingClientAck = false; - Http2::RawSettings serverSettings; - Http2::RawSettings expectedClientSettings; + RawSettings serverSettings; + RawSettings expectedClientSettings; bool connectionError = false; diff --git a/tests/auto/network/access/http2/tst_http2.cpp b/tests/auto/network/access/http2/tst_http2.cpp index ea939dfdea..c264956d7b 100644 --- a/tests/auto/network/access/http2/tst_http2.cpp +++ b/tests/auto/network/access/http2/tst_http2.cpp @@ -32,8 +32,10 @@ #include <QtNetwork/private/http2protocol_p.h> #include <QtNetwork/qnetworkaccessmanager.h> +#include <QtNetwork/qhttp2configuration.h> #include <QtNetwork/qnetworkrequest.h> #include <QtNetwork/qnetworkreply.h> + #include <QtCore/qglobal.h> #include <QtCore/qobject.h> #include <QtCore/qthread.h> @@ -66,6 +68,26 @@ Q_DECLARE_METATYPE(QNetworkRequest::Attribute) QT_BEGIN_NAMESPACE +QHttp2Configuration qt_defaultH2Configuration() +{ + QHttp2Configuration config; + config.setStreamReceiveWindowSize(Http2::qtDefaultStreamReceiveWindowSize); + config.setSessionReceiveWindowSize(Http2::maxSessionReceiveWindowSize); + config.setServerPushEnabled(false); + return config; +} + +RawSettings qt_H2ConfigurationToSettings(const QHttp2Configuration &config = qt_defaultH2Configuration()) +{ + RawSettings settings; + settings[Http2::Settings::ENABLE_PUSH_ID] = config.serverPushEnabled(); + settings[Http2::Settings::INITIAL_WINDOW_SIZE_ID] = config.streamReceiveWindowSize(); + if (config.maxFrameSize() != Http2::minPayloadLimit) + settings[Http2::Settings::MAX_FRAME_SIZE_ID] = config.maxFrameSize(); + return settings; +} + + class tst_Http2 : public QObject { Q_OBJECT @@ -87,6 +109,7 @@ private slots: void earlyResponse(); void connectToHost_data(); void connectToHost(); + void maxFrameSize(); protected slots: // Slots to listen to our in-process server: @@ -110,12 +133,13 @@ private: // small payload. void runEventLoop(int ms = 5000); void stopEventLoop(); - Http2Server *newServer(const Http2::RawSettings &serverSettings, H2Type connectionType, - const Http2::ProtocolParameters &clientSettings = {}); + Http2Server *newServer(const RawSettings &serverSettings, H2Type connectionType, + const RawSettings &clientSettings = qt_H2ConfigurationToSettings()); // Send a get or post request, depending on a payload (empty or not). void sendRequest(int streamNumber, QNetworkRequest::Priority priority = QNetworkRequest::NormalPriority, - const QByteArray &payload = QByteArray()); + const QByteArray &payload = QByteArray(), + const QHttp2Configuration &clientConfiguration = qt_defaultH2Configuration()); QUrl requestUrl(H2Type connnectionType) const; quint16 serverPort = 0; @@ -131,14 +155,14 @@ private: bool prefaceOK = false; bool serverGotSettingsACK = false; - static const Http2::RawSettings defaultServerSettings; + static const RawSettings defaultServerSettings; }; #define STOP_ON_FAILURE \ if (QTest::currentTestFailed()) \ return; -const Http2::RawSettings tst_Http2::defaultServerSettings{{Http2::Settings::MAX_CONCURRENT_STREAMS_ID, 100}}; +const RawSettings tst_Http2::defaultServerSettings{{Http2::Settings::MAX_CONCURRENT_STREAMS_ID, 100}}; namespace { @@ -308,18 +332,15 @@ void tst_Http2::flowControlClientSide() nRequests = 10; windowUpdates = 0; - Http2::ProtocolParameters params; + QHttp2Configuration params; // A small window size for a session, and even a smaller one per stream - // this will result in WINDOW_UPDATE frames both on connection stream and // per stream. - params.maxSessionReceiveWindowSize = Http2::defaultSessionWindowSize * 5; - params.settingsFrameData[Settings::INITIAL_WINDOW_SIZE_ID] = Http2::defaultSessionWindowSize; - // Inform our manager about non-default settings: - manager->setProperty(Http2::http2ParametersPropertyName, QVariant::fromValue(params)); - - const Http2::RawSettings serverSettings = {{Settings::MAX_CONCURRENT_STREAMS_ID, quint32(3)}}; - ServerPtr srv(newServer(serverSettings, defaultConnectionType(), params)); + params.setSessionReceiveWindowSize(Http2::defaultSessionWindowSize * 5); + params.setStreamReceiveWindowSize(Http2::defaultSessionWindowSize); + const RawSettings serverSettings = {{Settings::MAX_CONCURRENT_STREAMS_ID, quint32(3)}}; + ServerPtr srv(newServer(serverSettings, defaultConnectionType(), qt_H2ConfigurationToSettings(params))); const QByteArray respond(int(Http2::defaultSessionWindowSize * 10), 'x'); srv->setResponseBody(respond); @@ -330,7 +351,7 @@ void tst_Http2::flowControlClientSide() QVERIFY(serverPort != 0); for (int i = 0; i < nRequests; ++i) - sendRequest(i); + sendRequest(i, QNetworkRequest::NormalPriority, {}, params); runEventLoop(120000); STOP_ON_FAILURE @@ -359,7 +380,7 @@ void tst_Http2::flowControlServerSide() serverPort = 0; nRequests = 10; - const Http2::RawSettings serverSettings = {{Settings::MAX_CONCURRENT_STREAMS_ID, 7}}; + const RawSettings serverSettings = {{Settings::MAX_CONCURRENT_STREAMS_ID, 7}}; ServerPtr srv(newServer(serverSettings, defaultConnectionType())); @@ -392,12 +413,11 @@ void tst_Http2::pushPromise() serverPort = 0; nRequests = 1; - Http2::ProtocolParameters params; + QHttp2Configuration params; // Defaults are good, except ENABLE_PUSH: - params.settingsFrameData[Settings::ENABLE_PUSH_ID] = 1; - manager->setProperty(Http2::http2ParametersPropertyName, QVariant::fromValue(params)); + params.setServerPushEnabled(true); - ServerPtr srv(newServer(defaultServerSettings, defaultConnectionType(), params)); + ServerPtr srv(newServer(defaultServerSettings, defaultConnectionType(), qt_H2ConfigurationToSettings(params))); srv->enablePushPromise(true, QByteArray("/script.js")); QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection); @@ -410,6 +430,7 @@ void tst_Http2::pushPromise() QNetworkRequest request(url); request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, QVariant(true)); + request.setHttp2Configuration(params); auto reply = manager->get(request); connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished); @@ -681,6 +702,73 @@ void tst_Http2::connectToHost() QVERIFY(reply->isFinished()); } +void tst_Http2::maxFrameSize() +{ +#if !QT_CONFIG(ssl) + QSKIP("TLS support is needed for this test"); +#endif // QT_CONFIG(ssl) + + // Here we test we send 'MAX_FRAME_SIZE' setting in our + // 'SETTINGS'. If done properly, our server will not chunk + // the payload into several DATA frames. + +#if QT_CONFIG(securetransport) + // Normally on macOS we use plain text only for SecureTransport + // does not support ALPN on the server side. With 'direct encrytped' + // we have to use TLS sockets (== private key) and thus suppress a + // keychain UI asking for permission to use a private key. + // Our CI has this, but somebody testing locally - will have a problem. + qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", QByteArray("1")); + auto envRollback = qScopeGuard([](){ + qunsetenv("QT_SSL_USE_TEMPORARY_KEYCHAIN"); + }); +#endif // QT_CONFIG(securetransport) + + auto connectionType = H2Type::h2Alpn; + auto attribute = QNetworkRequest::HTTP2AllowedAttribute; + if (clearTextHTTP2) { + connectionType = H2Type::h2Direct; + attribute = QNetworkRequest::Http2DirectAttribute; + } + + auto h2Config = qt_defaultH2Configuration(); + h2Config.setMaxFrameSize(Http2::minPayloadLimit * 3); + + serverPort = 0; + nRequests = 1; + + ServerPtr srv(newServer(defaultServerSettings, connectionType, + qt_H2ConfigurationToSettings(h2Config))); + srv->setResponseBody(QByteArray(Http2::minPayloadLimit * 2, 'q')); + QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection); + runEventLoop(); + QVERIFY(serverPort != 0); + + const QSignalSpy frameCounter(srv.data(), &Http2Server::sendingData); + auto url = requestUrl(connectionType); + url.setPath(QString("/stream1.html")); + + QNetworkRequest request(url); + request.setAttribute(attribute, QVariant(true)); + request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain")); + request.setHttp2Configuration(h2Config); + + QNetworkReply *reply = manager->get(request); + reply->ignoreSslErrors(); + connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished); + + runEventLoop(); + STOP_ON_FAILURE + + // Normally, with a 16kb limit, our server would split such + // a response into 3 'DATA' frames (16kb + 16kb + 0|END_STREAM). + QCOMPARE(frameCounter.count(), 1); + + QVERIFY(nRequests == 0); + QVERIFY(prefaceOK); + QVERIFY(serverGotSettingsACK); +} + void tst_Http2::serverStarted(quint16 port) { serverPort = port; @@ -692,7 +780,6 @@ void tst_Http2::clearHTTP2State() windowUpdates = 0; prefaceOK = false; serverGotSettingsACK = false; - manager->setProperty(Http2::http2ParametersPropertyName, QVariant()); } void tst_Http2::runEventLoop(int ms) @@ -705,12 +792,11 @@ void tst_Http2::stopEventLoop() eventLoop.exitLoop(); } -Http2Server *tst_Http2::newServer(const Http2::RawSettings &serverSettings, H2Type connectionType, - const Http2::ProtocolParameters &clientSettings) +Http2Server *tst_Http2::newServer(const RawSettings &serverSettings, H2Type connectionType, + const RawSettings &clientSettings) { using namespace Http2; - auto srv = new Http2Server(connectionType, serverSettings, - clientSettings.settingsFrameData); + auto srv = new Http2Server(connectionType, serverSettings, clientSettings); using Srv = Http2Server; using Cl = tst_Http2; @@ -732,7 +818,8 @@ Http2Server *tst_Http2::newServer(const Http2::RawSettings &serverSettings, H2Ty void tst_Http2::sendRequest(int streamNumber, QNetworkRequest::Priority priority, - const QByteArray &payload) + const QByteArray &payload, + const QHttp2Configuration &h2Config) { auto url = requestUrl(defaultConnectionType()); url.setPath(QString("/stream%1.html").arg(streamNumber)); @@ -742,6 +829,7 @@ void tst_Http2::sendRequest(int streamNumber, request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, QVariant(true)); request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain")); request.setPriority(priority); + request.setHttp2Configuration(h2Config); QNetworkReply *reply = nullptr; if (payload.size()) diff --git a/tests/auto/network/access/qabstractnetworkcache/BLACKLIST b/tests/auto/network/access/qabstractnetworkcache/BLACKLIST deleted file mode 100644 index 2ad52f8b31..0000000000 --- a/tests/auto/network/access/qabstractnetworkcache/BLACKLIST +++ /dev/null @@ -1,2 +0,0 @@ -[cacheControl] -windows diff --git a/tests/auto/network/access/qabstractnetworkcache/qabstractnetworkcache.pro b/tests/auto/network/access/qabstractnetworkcache/qabstractnetworkcache.pro index 1874f001ab..c722100ead 100644 --- a/tests/auto/network/access/qabstractnetworkcache/qabstractnetworkcache.pro +++ b/tests/auto/network/access/qabstractnetworkcache/qabstractnetworkcache.pro @@ -5,3 +5,5 @@ SOURCES += tst_qabstractnetworkcache.cpp TESTDATA += tests/* +CONFIG += unsupported/testserver +QT_TEST_SERVER_LIST = apache2 diff --git a/tests/auto/network/access/qabstractnetworkcache/tst_qabstractnetworkcache.cpp b/tests/auto/network/access/qabstractnetworkcache/tst_qabstractnetworkcache.cpp index b8d9adf7a1..182e3e9547 100644 --- a/tests/auto/network/access/qabstractnetworkcache/tst_qabstractnetworkcache.cpp +++ b/tests/auto/network/access/qabstractnetworkcache/tst_qabstractnetworkcache.cpp @@ -39,7 +39,7 @@ #include <algorithm> -#define TESTFILE QLatin1String("http://") + QtNetworkSettings::serverName() + QLatin1String("/qtest/cgi-bin/") +#define TESTFILE QLatin1String("http://") + QtNetworkSettings::httpServerName() + QLatin1String("/qtest/cgi-bin/") class tst_QAbstractNetworkCache : public QObject { @@ -127,8 +127,13 @@ Q_DECLARE_METATYPE(QNetworkRequest::CacheLoadControl) void tst_QAbstractNetworkCache::initTestCase() { +#if defined(QT_TEST_SERVER) + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpServerName(), 80)); +#else if (!QtNetworkSettings::verifyTestNetworkSettings()) QSKIP("No network test server available"); +#endif + #ifndef QT_NO_BEARERMANAGEMENT netConfMan = new QNetworkConfigurationManager(this); networkConfiguration = netConfMan->defaultConfiguration(); diff --git a/tests/auto/network/access/qftp/BLACKLIST b/tests/auto/network/access/qftp/BLACKLIST index 96d9274653..0a99f3eb00 100644 --- a/tests/auto/network/access/qftp/BLACKLIST +++ b/tests/auto/network/access/qftp/BLACKLIST @@ -6,5 +6,11 @@ redhatenterpriselinuxworkstation-6.6 [activeMode:WithoutProxyWithSession] redhatenterpriselinuxworkstation-6.6 +[list] +opensuse-leap +windows-7sp1 +windows-10 msvc-2015 +ubuntu +osx [list:epsvNotSupported] * diff --git a/tests/auto/network/access/qftp/qftp.pro b/tests/auto/network/access/qftp/qftp.pro index 1959c1acac..c78020c5f8 100644 --- a/tests/auto/network/access/qftp/qftp.pro +++ b/tests/auto/network/access/qftp/qftp.pro @@ -4,3 +4,6 @@ SOURCES += tst_qftp.cpp requires(qtConfig(private_tests)) QT = core network network-private testlib + +CONFIG += unsupported/testserver +QT_TEST_SERVER_LIST = vsftpd ftp-proxy squid danted diff --git a/tests/auto/network/access/qftp/tst_qftp.cpp b/tests/auto/network/access/qftp/tst_qftp.cpp index 1a8f264c28..2068738a67 100644 --- a/tests/auto/network/access/qftp/tst_qftp.cpp +++ b/tests/auto/network/access/qftp/tst_qftp.cpp @@ -43,6 +43,7 @@ #include <QtNetwork/private/qnetworksession_p.h> #include <QTcpServer> #include <QHostInfo> +#include <QElapsedTimer> #include <QTcpSocket> #include "../../../network-settings.h" @@ -208,7 +209,14 @@ void tst_QFtp::initTestCase_data() void tst_QFtp::initTestCase() { +#if defined(QT_TEST_SERVER) + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::ftpServerName(), 21)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::ftpProxyServerName(), 2121)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::socksProxyServerName(), 1080)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpProxyServerName(), 3128)); +#else QVERIFY(QtNetworkSettings::verifyTestNetworkSettings()); +#endif #ifndef QT_NO_BEARERMANAGEMENT QNetworkConfigurationManager manager; networkSessionImplicit = QSharedPointer<QNetworkSession>::create(manager.defaultConfiguration()); @@ -235,9 +243,9 @@ void tst_QFtp::init() if (setProxy) { #ifndef QT_NO_NETWORKPROXY if (proxyType == QNetworkProxy::Socks5Proxy) { - QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080)); + QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1080)); } else if (proxyType == QNetworkProxy::HttpProxy) { - QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3128)); + QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::httpProxyServerName(), 3128)); } #else // !QT_NO_NETWORKPROXY Q_UNUSED(proxyType); @@ -316,8 +324,8 @@ void tst_QFtp::connectToHost_data() QTest::addColumn<uint>("port"); QTest::addColumn<int>("state"); - QTest::newRow( "ok01" ) << QtNetworkSettings::serverName() << (uint)21 << (int)QFtp::Connected; - QTest::newRow( "error01" ) << QtNetworkSettings::serverName() << (uint)2222 << (int)QFtp::Unconnected; + QTest::newRow( "ok01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << (int)QFtp::Connected; + QTest::newRow( "error01" ) << QtNetworkSettings::ftpServerName() << (uint)2222 << (int)QFtp::Unconnected; QTest::newRow( "error02" ) << QString("foo.bar") << (uint)21 << (int)QFtp::Unconnected; } @@ -402,13 +410,13 @@ void tst_QFtp::login_data() QTest::addColumn<QString>("password"); QTest::addColumn<int>("success"); - QTest::newRow( "ok01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << 1; - QTest::newRow( "ok02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftp") << QString("") << 1; - QTest::newRow( "ok03" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftp") << QString("foo") << 1; - QTest::newRow( "ok04" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") << 1; + QTest::newRow( "ok01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << 1; + QTest::newRow( "ok02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftp") << QString("") << 1; + QTest::newRow( "ok03" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftp") << QString("foo") << 1; + QTest::newRow( "ok04" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << 1; - QTest::newRow( "error01" ) << QtNetworkSettings::serverName() << (uint)21 << QString("foo") << QString("") << 0; - QTest::newRow( "error02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("foo") << QString("bar") << 0; + QTest::newRow( "error01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("foo") << QString("") << 0; + QTest::newRow( "error02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("foo") << QString("bar") << 0; } void tst_QFtp::login() @@ -448,12 +456,12 @@ void tst_QFtp::close_data() QTest::addColumn<QString>("password"); QTest::addColumn<bool>("login"); - QTest::newRow( "login01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << true; - QTest::newRow( "login02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftp") << QString() << true; - QTest::newRow( "login03" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftp") << QString("foo") << true; - QTest::newRow( "login04" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") << true; + QTest::newRow( "login01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << true; + QTest::newRow( "login02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftp") << QString() << true; + QTest::newRow( "login03" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftp") << QString("foo") << true; + QTest::newRow( "login04" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << true; - QTest::newRow( "no-login01" ) << QtNetworkSettings::serverName() << (uint)21 << QString("") << QString("") << false; + QTest::newRow( "no-login01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("") << QString("") << false; } void tst_QFtp::close() @@ -503,17 +511,17 @@ void tst_QFtp::list_data() flukeQtest << "rfc3252.txt"; flukeQtest << "upload"; - QTest::newRow( "workDir01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString() << 1 << flukeRoot; - QTest::newRow( "workDir02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") << QString() << 1 << flukeRoot; + QTest::newRow( "workDir01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString() << 1 << flukeRoot; + QTest::newRow( "workDir02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString() << 1 << flukeRoot; - QTest::newRow( "relPath01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("qtest") << 1 << flukeQtest; - QTest::newRow( "relPath02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") << QString("qtest") << 1 << flukeQtest; + QTest::newRow( "relPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("qtest") << 1 << flukeQtest; + QTest::newRow( "relPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString("qtest") << 1 << flukeQtest; - QTest::newRow( "absPath01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("/qtest") << 1 << flukeQtest; - QTest::newRow( "absPath02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") << QString("/var/ftp/qtest") << 1 << flukeQtest; + QTest::newRow( "absPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("/qtest") << 1 << flukeQtest; + QTest::newRow( "absPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString("/var/ftp/qtest") << 1 << flukeQtest; - QTest::newRow( "nonExist01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("foo") << 1 << QStringList(); - QTest::newRow( "nonExist02" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("/foo") << 1 << QStringList(); + QTest::newRow( "nonExist01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("foo") << 1 << QStringList(); + QTest::newRow( "nonExist02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("/foo") << 1 << QStringList(); // ### The microsoft server does not seem to work properly at the moment -- // I am also not able to open a data connection with other, non-Qt FTP // clients to it. @@ -573,14 +581,14 @@ void tst_QFtp::cd_data() flukeQtest << "rfc3252.txt"; flukeQtest << "upload"; - QTest::newRow( "relPath01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("qtest") << 1 << flukeQtest; - QTest::newRow( "relPath02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") << QString("qtest") << 1 << flukeQtest; + QTest::newRow( "relPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("qtest") << 1 << flukeQtest; + QTest::newRow( "relPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString("qtest") << 1 << flukeQtest; - QTest::newRow( "absPath01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("/qtest") << 1 << flukeQtest; - QTest::newRow( "absPath02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") << QString("/var/ftp/qtest") << 1 << flukeQtest; + QTest::newRow( "absPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("/qtest") << 1 << flukeQtest; + QTest::newRow( "absPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString("/var/ftp/qtest") << 1 << flukeQtest; - QTest::newRow( "nonExist01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("foo") << 0 << QStringList(); - QTest::newRow( "nonExist03" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("/foo") << 0 << QStringList(); + QTest::newRow( "nonExist01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("foo") << 0 << QStringList(); + QTest::newRow( "nonExist03" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("/foo") << 0 << QStringList(); } void tst_QFtp::cd() @@ -635,19 +643,19 @@ void tst_QFtp::get_data() // test the two get() overloads in one routine for ( int i=0; i<2; i++ ) { const QByteArray iB = QByteArray::number(i); - QTest::newRow(("relPath01_" + iB).constData()) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() + QTest::newRow(("relPath01_" + iB).constData()) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << "qtest/rfc3252" << 1 << rfc3252 << (bool)(i==1); - QTest::newRow(("relPath02_" + iB).constData()) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") + QTest::newRow(("relPath02_" + iB).constData()) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << "qtest/rfc3252" << 1 << rfc3252 << (bool)(i==1); - QTest::newRow(("absPath01_" + iB).constData()) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() + QTest::newRow(("absPath01_" + iB).constData()) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << "/qtest/rfc3252" << 1 << rfc3252 << (bool)(i==1); - QTest::newRow(("absPath02_" + iB).constData()) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") + QTest::newRow(("absPath02_" + iB).constData()) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << "/var/ftp/qtest/rfc3252" << 1 << rfc3252 << (bool)(i==1); - QTest::newRow(("nonExist01_" + iB).constData()) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() + QTest::newRow(("nonExist01_" + iB).constData()) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("foo") << 0 << QByteArray() << (bool)(i==1); - QTest::newRow(("nonExist02_" + iB).constData()) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() + QTest::newRow(("nonExist02_" + iB).constData()) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("/foo") << 0 << QByteArray() << (bool)(i==1); } } @@ -727,31 +735,31 @@ void tst_QFtp::put_data() // test the two put() overloads in one routine with a file name containing // U+0x00FC (latin small letter u with diaeresis) for QTBUG-52303, testing UTF-8 for ( int i=0; i<2; i++ ) { - QTest::newRow(("relPath01_" + QByteArray::number(i)).constData()) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() + QTest::newRow(("relPath01_" + QByteArray::number(i)).constData()) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << (QLatin1String("qtest/upload/rel01_") + QChar(0xfc) + QLatin1String("%1")) << rfc3252 << (bool)(i==1) << 1; /* - QTest::newRow( QString("relPath02_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") + QTest::newRow( QString("relPath02_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString("qtest/upload/rel02_%1") << rfc3252 << (bool)(i==1) << 1; - QTest::newRow( QString("relPath03_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") + QTest::newRow( QString("relPath03_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString("qtest/upload/rel03_%1") << QByteArray() << (bool)(i==1) << 1; - QTest::newRow( QString("relPath04_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") + QTest::newRow( QString("relPath04_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString("qtest/upload/rel04_%1") << bigData << (bool)(i==1) << 1; - QTest::newRow( QString("absPath01_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() + QTest::newRow( QString("absPath01_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("/qtest/upload/abs01_%1") << rfc3252 << (bool)(i==1) << 1; - QTest::newRow( QString("absPath02_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") + QTest::newRow( QString("absPath02_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString("/srv/ftp/qtest/upload/abs02_%1") << rfc3252 << (bool)(i==1) << 1; - QTest::newRow( QString("nonExist01_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() + QTest::newRow( QString("nonExist01_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("foo") << QByteArray() << (bool)(i==1) << 0; - QTest::newRow( QString("nonExist02_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() + QTest::newRow( QString("nonExist02_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("/foo") << QByteArray() << (bool)(i==1) << 0; */ @@ -877,22 +885,22 @@ void tst_QFtp::mkdir_data() QTest::addColumn<QString>("dirToCreate"); QTest::addColumn<int>("success"); - QTest::newRow( "relPath01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() + QTest::newRow( "relPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << "qtest/upload" << QString("rel01_%1") << 1; - QTest::newRow( "relPath02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") + QTest::newRow( "relPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << "qtest/upload" << QString("rel02_%1") << 1; - QTest::newRow( "relPath03" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") + QTest::newRow( "relPath03" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << "qtest/upload" << QString("rel03_%1") << 1; - QTest::newRow( "absPath01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() + QTest::newRow( "absPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << "." << QString("/qtest/upload/abs01_%1") << 1; - QTest::newRow( "absPath02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") + QTest::newRow( "absPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << "." << QString("/var/ftp/qtest/upload/abs02_%1") << 1; - // QTest::newRow( "nonExist01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("foo") << 0; - QTest::newRow( "nonExist01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() + // QTest::newRow( "nonExist01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("foo") << 0; + QTest::newRow( "nonExist01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << "." << QString("foo") << 0; - QTest::newRow( "nonExist02" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() + QTest::newRow( "nonExist02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << "." << QString("/foo") << 0; } @@ -979,7 +987,7 @@ void tst_QFtp::mkdir() void tst_QFtp::mkdir2() { ftp = new QFtp; - ftp->connectToHost(QtNetworkSettings::serverName()); + ftp->connectToHost(QtNetworkSettings::ftpServerName()); ftp->login(); current_id = ftp->cd("kake/test"); @@ -1026,39 +1034,39 @@ void tst_QFtp::rename_data() QTest::addColumn<QString>("renamedFile"); QTest::addColumn<int>("success"); - QTest::newRow("relPath01") << QtNetworkSettings::serverName() << QString() << QString() + QTest::newRow("relPath01") << QtNetworkSettings::ftpServerName() << QString() << QString() << "qtest/upload" << QString("rel_old01_%1") << QString("rel_new01_%1") << QString("qtest/upload/rel_old01_%1") << QString("qtest/upload/rel_new01_%1") << 1; - QTest::newRow("relPath02") << QtNetworkSettings::serverName() << QString("ftptest") << "password" + QTest::newRow("relPath02") << QtNetworkSettings::ftpServerName() << QString("ftptest") << "password" << "qtest/upload" << QString("rel_old02_%1") << QString("rel_new02_%1") << QString("qtest/upload/rel_old02_%1") << QString("qtest/upload/rel_new02_%1") << 1; - QTest::newRow("relPath03") << QtNetworkSettings::serverName() << QString("ftptest") << "password" + QTest::newRow("relPath03") << QtNetworkSettings::ftpServerName() << QString("ftptest") << "password" << "qtest/upload" << QString("rel_old03_%1")<< QString("rel_new03_%1") << QString("qtest/upload/rel_old03_%1") << QString("qtest/upload/rel_new03_%1") << 1; - QTest::newRow("absPath01") << QtNetworkSettings::serverName() << QString() << QString() + QTest::newRow("absPath01") << QtNetworkSettings::ftpServerName() << QString() << QString() << QString() << QString("/qtest/upload/abs_old01_%1") << QString("/qtest/upload/abs_new01_%1") << QString("/qtest/upload/abs_old01_%1") << QString("/qtest/upload/abs_new01_%1") << 1; - QTest::newRow("absPath02") << QtNetworkSettings::serverName() << QString("ftptest") << "password" + QTest::newRow("absPath02") << QtNetworkSettings::ftpServerName() << QString("ftptest") << "password" << QString() << QString("/var/ftp/qtest/upload/abs_old02_%1") << QString("/var/ftp/qtest/upload/abs_new02_%1") << QString("/var/ftp/qtest/upload/abs_old02_%1") << QString("/var/ftp/qtest/upload/abs_new02_%1") << 1; - QTest::newRow("nonExist01") << QtNetworkSettings::serverName() << QString() << QString() + QTest::newRow("nonExist01") << QtNetworkSettings::ftpServerName() << QString() << QString() << QString() << QString("foo") << "new_foo" << QString() << QString() << 0; - QTest::newRow("nonExist02") << QtNetworkSettings::serverName() << QString() << QString() + QTest::newRow("nonExist02") << QtNetworkSettings::ftpServerName() << QString() << QString() << QString() << QString("/foo") << QString("/new_foo") << QString() << QString() @@ -1220,7 +1228,7 @@ void tst_QFtp::commandSequence_data() { // some "constants" QStringList argConnectToHost01; - argConnectToHost01 << QtNetworkSettings::serverName() << "21"; + argConnectToHost01 << QtNetworkSettings::ftpServerName() << "21"; QStringList argLogin01, argLogin02, argLogin03, argLogin04; argLogin01 << QString() << QString(); @@ -1351,13 +1359,13 @@ void tst_QFtp::abort_data() QTest::addColumn<QString>("file"); QTest::addColumn<QByteArray>("uploadData"); - QTest::newRow( "get_fluke01" ) << QtNetworkSettings::serverName() << (uint)21 << QString("qtest/bigfile") << QByteArray(); - QTest::newRow( "get_fluke02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("qtest/rfc3252") << QByteArray(); + QTest::newRow( "get_fluke01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("qtest/bigfile") << QByteArray(); + QTest::newRow( "get_fluke02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("qtest/rfc3252") << QByteArray(); // Qt/CE test environment has too little memory for this test QByteArray bigData( 10*1024*1024, 0 ); bigData.fill( 'B' ); - QTest::newRow( "put_fluke01" ) << QtNetworkSettings::serverName() << (uint)21 << QString("qtest/upload/abort_put") << bigData; + QTest::newRow( "put_fluke01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("qtest/upload/abort_put") << bigData; } void tst_QFtp::abort() @@ -1402,7 +1410,7 @@ void tst_QFtp::abort() if ( it.value().success ) { // The FTP server on fluke is sadly returning a success, even when // the operation was aborted. So we have to use some heuristics. - if ( host == QtNetworkSettings::serverName() ) { + if ( host == QtNetworkSettings::ftpServerName() ) { if ( cmd == QFtp::Get ) { QVERIFY2(bytesDone <= bytesTotal, msgComparison(bytesDone, "<=", bytesTotal)); } else { @@ -1449,11 +1457,11 @@ void tst_QFtp::bytesAvailable_data() QTest::addColumn<qlonglong>("bytesAvailFinished"); QTest::addColumn<qlonglong>("bytesAvailDone"); - QTest::newRow( "fluke01" ) << QtNetworkSettings::serverName() << QString("qtest/bigfile") << 0 << (qlonglong)519240 << (qlonglong)519240 << (qlonglong)519240; - QTest::newRow( "fluke02" ) << QtNetworkSettings::serverName() << QString("qtest/rfc3252") << 0 << (qlonglong)25962 << (qlonglong)25962 << (qlonglong)25962; + QTest::newRow( "fluke01" ) << QtNetworkSettings::ftpServerName() << QString("qtest/bigfile") << 0 << (qlonglong)519240 << (qlonglong)519240 << (qlonglong)519240; + QTest::newRow( "fluke02" ) << QtNetworkSettings::ftpServerName() << QString("qtest/rfc3252") << 0 << (qlonglong)25962 << (qlonglong)25962 << (qlonglong)25962; - QTest::newRow( "fluke03" ) << QtNetworkSettings::serverName() << QString("qtest/bigfile") << 1 << (qlonglong)519240 << (qlonglong)0 << (qlonglong)0; - QTest::newRow( "fluke04" ) << QtNetworkSettings::serverName() << QString("qtest/rfc3252") << 1 << (qlonglong)25962 << (qlonglong)0 << (qlonglong)0; + QTest::newRow( "fluke03" ) << QtNetworkSettings::ftpServerName() << QString("qtest/bigfile") << 1 << (qlonglong)519240 << (qlonglong)0 << (qlonglong)0; + QTest::newRow( "fluke04" ) << QtNetworkSettings::ftpServerName() << QString("qtest/rfc3252") << 1 << (qlonglong)25962 << (qlonglong)0 << (qlonglong)0; } void tst_QFtp::bytesAvailable() @@ -1498,7 +1506,7 @@ void tst_QFtp::activeMode() file.open(QIODevice::ReadWrite); QFtp ftp; ftp.setTransferMode(QFtp::Active); - ftp.connectToHost(QtNetworkSettings::serverName(), 21); + ftp.connectToHost(QtNetworkSettings::ftpServerName(), 21); ftp.login(); ftp.list(); ftp.get("/qtest/rfc3252.txt", &file); @@ -1534,14 +1542,14 @@ void tst_QFtp::proxy_data() flukeQtest << "rfc3252.txt"; flukeQtest << "upload"; - QTest::newRow( "proxy_relPath01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("qtest") << 1 << flukeQtest; - QTest::newRow( "proxy_relPath02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") << QString("qtest") << 1 << flukeQtest; + QTest::newRow( "proxy_relPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("qtest") << 1 << flukeQtest; + QTest::newRow( "proxy_relPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString("qtest") << 1 << flukeQtest; - QTest::newRow( "proxy_absPath01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("/qtest") << 1 << flukeQtest; - QTest::newRow( "proxy_absPath02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") << QString("/var/ftp/qtest") << 1 << flukeQtest; + QTest::newRow( "proxy_absPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("/qtest") << 1 << flukeQtest; + QTest::newRow( "proxy_absPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString("/var/ftp/qtest") << 1 << flukeQtest; - QTest::newRow( "proxy_nonExist01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("foo") << 0 << QStringList(); - QTest::newRow( "proxy_nonExist03" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("/foo") << 0 << QStringList(); + QTest::newRow( "proxy_nonExist01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("foo") << 0 << QStringList(); + QTest::newRow( "proxy_nonExist03" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("/foo") << 0 << QStringList(); } void tst_QFtp::proxy() @@ -1553,7 +1561,7 @@ void tst_QFtp::proxy() QFETCH( QString, dir ); ftp = newFtp(); - addCommand( QFtp::SetProxy, ftp->setProxy( QtNetworkSettings::serverName(), 2121 ) ); + addCommand( QFtp::SetProxy, ftp->setProxy( QtNetworkSettings::ftpProxyServerName(), 2121 ) ); addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); addCommand( QFtp::Login, ftp->login( user, password ) ); addCommand( QFtp::Cd, ftp->cd( dir ) ); @@ -1589,7 +1597,7 @@ void tst_QFtp::binaryAscii() init(); ftp = newFtp(); - addCommand(QFtp::ConnectToHost, ftp->connectToHost(QtNetworkSettings::serverName(), 21)); + addCommand(QFtp::ConnectToHost, ftp->connectToHost(QtNetworkSettings::ftpServerName(), 21)); addCommand(QFtp::Login, ftp->login("ftptest", "password")); addCommand(QFtp::Cd, ftp->cd("qtest/upload")); addCommand(QFtp::Put, ftp->put(putData, file, QFtp::Ascii)); @@ -1599,7 +1607,7 @@ void tst_QFtp::binaryAscii() delete ftp; ftp = 0; if ( QTestEventLoop::instance().timeout() ) - QFAIL( msgTimedOut(QtNetworkSettings::serverName()) ); + QFAIL( msgTimedOut(QtNetworkSettings::ftpServerName()) ); ResMapIt it = resultMap.find(QFtp::Put); QVERIFY(it != resultMap.end()); @@ -1611,7 +1619,7 @@ void tst_QFtp::binaryAscii() init(); ftp = newFtp(); - addCommand(QFtp::ConnectToHost, ftp->connectToHost(QtNetworkSettings::serverName(), 21)); + addCommand(QFtp::ConnectToHost, ftp->connectToHost(QtNetworkSettings::ftpServerName(), 21)); addCommand(QFtp::Login, ftp->login("ftptest", "password")); addCommand(QFtp::Cd, ftp->cd("qtest/upload")); addCommand(QFtp::Get, ftp->get(file, &getBuf, QFtp::Binary)); @@ -1621,7 +1629,7 @@ void tst_QFtp::binaryAscii() delete ftp; ftp = 0; if ( QTestEventLoop::instance().timeout() ) - QFAIL( msgTimedOut(QtNetworkSettings::serverName()) ); + QFAIL( msgTimedOut(QtNetworkSettings::ftpServerName()) ); ResMapIt it2 = resultMap.find(QFtp::Get); QVERIFY(it2 != resultMap.end()); @@ -1634,7 +1642,7 @@ void tst_QFtp::binaryAscii() // cleanup (i.e. remove the file) -- this also tests the remove command init(); ftp = newFtp(); - addCommand(QFtp::ConnectToHost, ftp->connectToHost(QtNetworkSettings::serverName(), 21)); + addCommand(QFtp::ConnectToHost, ftp->connectToHost(QtNetworkSettings::ftpServerName(), 21)); addCommand(QFtp::Login, ftp->login("ftptest", "password")); addCommand(QFtp::Cd, ftp->cd("qtest/upload")); addCommand(QFtp::Remove, ftp->remove(file)); @@ -1644,13 +1652,13 @@ void tst_QFtp::binaryAscii() delete ftp; ftp = 0; if ( QTestEventLoop::instance().timeout() ) - QFAIL( msgTimedOut(QtNetworkSettings::serverName()) ); + QFAIL( msgTimedOut(QtNetworkSettings::ftpServerName()) ); it = resultMap.find( QFtp::Remove ); QVERIFY( it != resultMap.end() ); QCOMPARE( it.value().success, 1 ); - QVERIFY(!fileExists(QtNetworkSettings::serverName(), 21, "ftptest", "password", file)); + QVERIFY(!fileExists(QtNetworkSettings::ftpServerName(), 21, "ftptest", "password", file)); } @@ -2067,7 +2075,7 @@ void tst_QFtp::doneSignal() QFtp ftp; QSignalSpy spy(&ftp, SIGNAL(done(bool))); - ftp.connectToHost(QtNetworkSettings::serverName()); + ftp.connectToHost(QtNetworkSettings::ftpServerName()); ftp.login("anonymous"); ftp.list(); ftp.close(); @@ -2137,7 +2145,7 @@ void tst_QFtp::qtbug7359Crash() QFtp ftp; ftp.connectToHost("127.0.0.1"); - QTime t; + QElapsedTimer t; int elapsed; t.start(); diff --git a/tests/auto/network/access/qhttpnetworkconnection/qhttpnetworkconnection.pro b/tests/auto/network/access/qhttpnetworkconnection/qhttpnetworkconnection.pro index d32b651b86..84e6f857a1 100644 --- a/tests/auto/network/access/qhttpnetworkconnection/qhttpnetworkconnection.pro +++ b/tests/auto/network/access/qhttpnetworkconnection/qhttpnetworkconnection.pro @@ -4,3 +4,6 @@ SOURCES += tst_qhttpnetworkconnection.cpp requires(qtConfig(private_tests)) QT = core-private network-private testlib + +CONFIG += unsupported/testserver +QT_TEST_SERVER_LIST = apache2 diff --git a/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp b/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp index 84766f5484..0a9320118d 100644 --- a/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp +++ b/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp @@ -50,6 +50,7 @@ private: bool finishedCalled; bool finishedWithErrorCalled; QNetworkReply::NetworkError netErrorCode; + QString (*httpServerName)() = QtNetworkSettings::httpServerName; private Q_SLOTS: void initTestCase(); @@ -101,7 +102,11 @@ private Q_SLOTS: void tst_QHttpNetworkConnection::initTestCase() { +#if defined(QT_TEST_SERVER) + QVERIFY(QtNetworkSettings::verifyConnection(httpServerName(), 80)); +#else QVERIFY(QtNetworkSettings::verifyTestNetworkSettings()); +#endif } void tst_QHttpNetworkConnection::options_data() @@ -126,10 +131,9 @@ void tst_QHttpNetworkConnection::head_data() QTest::addColumn<QString>("statusString"); QTest::addColumn<int>("contentLength"); - QTest::newRow("success-internal") << "http://" << QtNetworkSettings::serverName() << "/qtest/rfc3252.txt" << ushort(80) << false << 200 << "OK" << 25962; - - QTest::newRow("failure-path") << "http://" << QtNetworkSettings::serverName() << "/t" << ushort(80) << false << 404 << "Not Found" << -1; - QTest::newRow("failure-protocol") << "" << QtNetworkSettings::serverName() << "/qtest/rfc3252.txt" << ushort(80) << false << 400 << "Bad Request" << -1; + QTest::newRow("success-internal") << "http://" << httpServerName() << "/qtest/rfc3252.txt" << ushort(80) << false << 200 << "OK" << 25962; + QTest::newRow("failure-path") << "http://" << httpServerName() << "/t" << ushort(80) << false << 404 << "Not Found" << -1; + QTest::newRow("failure-protocol") << "" << httpServerName() << "/qtest/rfc3252.txt" << ushort(80) << false << 400 << "Bad Request" << -1; } void tst_QHttpNetworkConnection::head() @@ -175,10 +179,10 @@ void tst_QHttpNetworkConnection::get_data() QTest::addColumn<int>("contentLength"); QTest::addColumn<int>("downloadSize"); - QTest::newRow("success-internal") << "http://" << QtNetworkSettings::serverName() << "/qtest/rfc3252.txt" << ushort(80) << false << 200 << "OK" << 25962 << 25962; + QTest::newRow("success-internal") << "http://" << httpServerName() << "/qtest/rfc3252.txt" << ushort(80) << false << 200 << "OK" << 25962 << 25962; - QTest::newRow("failure-path") << "http://" << QtNetworkSettings::serverName() << "/t" << ushort(80) << false << 404 << "Not Found" << -1 << -1; - QTest::newRow("failure-protocol") << "" << QtNetworkSettings::serverName() << "/qtest/rfc3252.txt" << ushort(80) << false << 400 << "Bad Request" << -1 << -1; + QTest::newRow("failure-path") << "http://" << httpServerName() << "/t" << ushort(80) << false << 404 << "Not Found" << -1 << -1; + QTest::newRow("failure-protocol") << "" << httpServerName() << "/qtest/rfc3252.txt" << ushort(80) << false << 400 << "Bad Request" << -1 << -1; } void tst_QHttpNetworkConnection::get() @@ -244,8 +248,8 @@ void tst_QHttpNetworkConnection::put_data() QTest::addColumn<QString>("data"); QTest::addColumn<bool>("succeed"); - QTest::newRow("success-internal") << "http://" << QtNetworkSettings::serverName() << "/dav/file1.txt" << ushort(80) << false << "Hello World\nEnd of file\n"<<true; - QTest::newRow("fail-internal") << "http://" << QtNetworkSettings::serverName() << "/dav2/file1.txt" << ushort(80) << false << "Hello World\nEnd of file\n"<<false; + QTest::newRow("success-internal") << "http://" << httpServerName() << "/dav/file1.txt" << ushort(80) << false << "Hello World\nEnd of file\n"<<true; + QTest::newRow("fail-internal") << "http://" << httpServerName() << "/dav2/file1.txt" << ushort(80) << false << "Hello World\nEnd of file\n"<<false; QTest::newRow("fail-host") << "http://" << "invalid.test.qt-project.org" << "/dav2/file1.txt" << ushort(80) << false << "Hello World\nEnd of file\n"<<false; } @@ -324,8 +328,8 @@ void tst_QHttpNetworkConnection::post_data() QTest::addColumn<int>("contentLength"); QTest::addColumn<int>("downloadSize"); - QTest::newRow("success-internal") << "http://" << QtNetworkSettings::serverName() << "/qtest/cgi-bin/echo.cgi" << ushort(80) << false << "7 bytes" << 200 << "OK" << 7 << 7; - QTest::newRow("failure-internal") << "http://" << QtNetworkSettings::serverName() << "/t" << ushort(80) << false << "Hello World" << 404 << "Not Found" << -1 << -1; + QTest::newRow("success-internal") << "http://" << httpServerName() << "/qtest/cgi-bin/echo.cgi" << ushort(80) << false << "7 bytes" << 200 << "OK" << 7 << 7; + QTest::newRow("failure-internal") << "http://" << httpServerName() << "/t" << ushort(80) << false << "Hello World" << 404 << "Not Found" << -1 << -1; } void tst_QHttpNetworkConnection::post() @@ -449,11 +453,11 @@ void tst_QHttpNetworkConnection::get401_data() QTest::addColumn<QString>("password"); QTest::addColumn<int>("statusCode"); - QTest::newRow("no-credentials") << "http://" << QtNetworkSettings::serverName() << "/qtest/rfcs-auth/index.html" << ushort(80) << false << false << "" << ""<<401; - QTest::newRow("invalid-credentials") << "http://" << QtNetworkSettings::serverName() << "/qtest/rfcs-auth/index.html" << ushort(80) << false << true << "test" << "test"<<401; - QTest::newRow("valid-credentials") << "http://" << QtNetworkSettings::serverName() << "/qtest/rfcs-auth/index.html" << ushort(80) << false << true << "httptest" << "httptest"<<200; - QTest::newRow("digest-authentication-invalid") << "http://" << QtNetworkSettings::serverName() << "/qtest/auth-digest/index.html" << ushort(80) << false << true << "wrong" << "wrong"<<401; - QTest::newRow("digest-authentication-valid") << "http://" << QtNetworkSettings::serverName() << "/qtest/auth-digest/index.html" << ushort(80) << false << true << "httptest" << "httptest"<<200; + QTest::newRow("no-credentials") << "http://" << httpServerName() << "/qtest/rfcs-auth/index.html" << ushort(80) << false << false << "" << ""<<401; + QTest::newRow("invalid-credentials") << "http://" << httpServerName() << "/qtest/rfcs-auth/index.html" << ushort(80) << false << true << "test" << "test"<<401; + QTest::newRow("valid-credentials") << "http://" << httpServerName() << "/qtest/rfcs-auth/index.html" << ushort(80) << false << true << "httptest" << "httptest"<<200; + QTest::newRow("digest-authentication-invalid") << "http://" << httpServerName() << "/qtest/auth-digest/index.html" << ushort(80) << false << true << "wrong" << "wrong"<<401; + QTest::newRow("digest-authentication-valid") << "http://" << httpServerName() << "/qtest/auth-digest/index.html" << ushort(80) << false << true << "httptest" << "httptest"<<200; } void tst_QHttpNetworkConnection::get401() @@ -508,9 +512,9 @@ void tst_QHttpNetworkConnection::compression_data() QTest::addColumn<bool>("autoCompress"); QTest::addColumn<QString>("contentCoding"); - QTest::newRow("success-autogzip-temp") << "http://" << QtNetworkSettings::serverName() << "/qtest/rfcs/rfc2616.html" << ushort(80) << false << 200 << "OK" << -1 << 418321 << true << ""; - QTest::newRow("success-nogzip-temp") << "http://" << QtNetworkSettings::serverName() << "/qtest/rfcs/rfc2616.html" << ushort(80) << false << 200 << "OK" << 418321 << 418321 << false << "identity"; - QTest::newRow("success-manualgzip-temp") << "http://" << QtNetworkSettings::serverName() << "/qtest/deflate/rfc2616.html" << ushort(80) << false << 200 << "OK" << 119124 << 119124 << false << "gzip"; + QTest::newRow("success-autogzip-temp") << "http://" << httpServerName() << "/qtest/rfcs/rfc2616.html" << ushort(80) << false << 200 << "OK" << -1 << 418321 << true << ""; + QTest::newRow("success-nogzip-temp") << "http://" << httpServerName() << "/qtest/rfcs/rfc2616.html" << ushort(80) << false << 200 << "OK" << 418321 << 418321 << false << "identity"; + QTest::newRow("success-manualgzip-temp") << "http://" << httpServerName() << "/qtest/deflate/rfc2616.html" << ushort(80) << false << 200 << "OK" << 119124 << 119124 << false << "gzip"; } @@ -586,9 +590,9 @@ void tst_QHttpNetworkConnection::ignoresslerror_data() // fluke's certificate is signed by a non-standard authority. // Since we don't introduce that CA into the SSL verification chain, // connecting should fail. - QTest::newRow("success-init") << "https://" << QtNetworkSettings::serverName() << "/" << ushort(443) << true << true << false << 200; - QTest::newRow("success-fromSignal") << "https://" << QtNetworkSettings::serverName() << "/" << ushort(443) << true << false << true << 200; - QTest::newRow("failure") << "https://" << QtNetworkSettings::serverName() << "/" << ushort(443) << true << false << false << 100; + QTest::newRow("success-init") << "https://" << httpServerName() << "/" << ushort(443) << true << true << false << 200; + QTest::newRow("success-fromSignal") << "https://" << httpServerName() << "/" << ushort(443) << true << false << true << 200; + QTest::newRow("failure") << "https://" << httpServerName() << "/" << ushort(443) << true << false << false << 100; } void tst_QHttpNetworkConnection::ignoresslerror() @@ -635,7 +639,7 @@ void tst_QHttpNetworkConnection::nossl_data() QTest::addColumn<bool>("encrypt"); QTest::addColumn<QNetworkReply::NetworkError>("networkError"); - QTest::newRow("protocol-error") << "https://" << QtNetworkSettings::serverName() << "/" << ushort(443) << true <<QNetworkReply::ProtocolUnknownError; + QTest::newRow("protocol-error") << "https://" << httpServerName() << "/" << ushort(443) << true <<QNetworkReply::ProtocolUnknownError; } void tst_QHttpNetworkConnection::nossl() @@ -696,7 +700,7 @@ void tst_QHttpNetworkConnection::getMultiple() QFETCH(bool, pipeliningAllowed); QFETCH(int, requestCount); - QHttpNetworkConnection connection(connectionCount, QtNetworkSettings::serverName()); + QHttpNetworkConnection connection(connectionCount, httpServerName()); QList<QHttpNetworkRequest*> requests; QList<QHttpNetworkReply*> replies; @@ -705,7 +709,7 @@ void tst_QHttpNetworkConnection::getMultiple() // depending on what you use the results will vary. // for the "real" results, use a URL that has "internet latency" for you. Then (6 connections, pipelining) will win. // for LAN latency, you will possibly get that (1 connection, no pipelining) is the fastest - QHttpNetworkRequest *request = new QHttpNetworkRequest("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"); + QHttpNetworkRequest *request = new QHttpNetworkRequest("http://" + httpServerName() + "/qtest/rfc3252.txt"); if (pipeliningAllowed) request->setPipeliningAllowed(true); requests.append(request); @@ -723,7 +727,7 @@ void tst_QHttpNetworkConnection::getMultipleWithPipeliningAndMultiplePriorities( quint16 requestCount = 100; // use 2 connections. - QHttpNetworkConnection connection(2, QtNetworkSettings::serverName()); + QHttpNetworkConnection connection(2, httpServerName()); QList<QHttpNetworkRequest*> requests; QList<QHttpNetworkReply*> replies; @@ -731,9 +735,9 @@ void tst_QHttpNetworkConnection::getMultipleWithPipeliningAndMultiplePriorities( for (int i = 0; i < requestCount; i++) { QHttpNetworkRequest *request = 0; if (i % 3) - request = new QHttpNetworkRequest("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt", QHttpNetworkRequest::Get); + request = new QHttpNetworkRequest("http://" + httpServerName() + "/qtest/rfc3252.txt", QHttpNetworkRequest::Get); else - request = new QHttpNetworkRequest("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt", QHttpNetworkRequest::Head); + request = new QHttpNetworkRequest("http://" + httpServerName() + "/qtest/rfc3252.txt", QHttpNetworkRequest::Head); if (i % 2 || i % 3) request->setPipeliningAllowed(true); @@ -800,9 +804,9 @@ void tst_QHttpNetworkConnection::getMultipleWithPriorities() { quint16 requestCount = 100; // use 2 connections. - QHttpNetworkConnection connection(2, QtNetworkSettings::serverName()); + QHttpNetworkConnection connection(2, httpServerName()); GetMultipleWithPrioritiesReceiver receiver(requestCount); - QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"); + QUrl url("http://" + httpServerName() + "/qtest/rfc3252.txt"); QList<QHttpNetworkRequest*> requests; QList<QHttpNetworkReply*> replies; @@ -854,10 +858,10 @@ void tst_QHttpNetworkConnection::getEmptyWithPipelining() { quint16 requestCount = 50; // use 2 connections. - QHttpNetworkConnection connection(2, QtNetworkSettings::serverName()); + QHttpNetworkConnection connection(2, httpServerName()); GetEmptyWithPipeliningReceiver receiver(requestCount); - QUrl url("http://" + QtNetworkSettings::serverName() + "/cgi-bin/echo.cgi"); // a get on this = getting an empty file + QUrl url("http://" + httpServerName() + "/cgi-bin/echo.cgi"); // a get on this = getting an empty file QList<QHttpNetworkRequest*> requests; QList<QHttpNetworkReply*> replies; @@ -901,8 +905,8 @@ void tst_QHttpNetworkConnection::getAndEverythingShouldBePipelined() { quint16 requestCount = 100; // use 1 connection. - QHttpNetworkConnection connection(1, QtNetworkSettings::serverName()); - QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"); + QHttpNetworkConnection connection(1, httpServerName()); + QUrl url("http://" + httpServerName() + "/qtest/rfc3252.txt"); QList<QHttpNetworkRequest*> requests; QList<QHttpNetworkReply*> replies; @@ -937,8 +941,8 @@ void tst_QHttpNetworkConnection::getAndThenDeleteObject_data() void tst_QHttpNetworkConnection::getAndThenDeleteObject() { // yes, this will leak if the testcase fails. I don't care. It must not fail then :P - QHttpNetworkConnection *connection = new QHttpNetworkConnection(QtNetworkSettings::serverName()); - QHttpNetworkRequest request("http://" + QtNetworkSettings::serverName() + "/qtest/bigfile"); + QHttpNetworkConnection *connection = new QHttpNetworkConnection(httpServerName()); + QHttpNetworkRequest request("http://" + httpServerName() + "/qtest/bigfile"); QHttpNetworkReply *reply = connection->sendRequest(request); reply->setDownstreamLimited(true); diff --git a/tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp b/tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp index 6c3443a735..0924b1e223 100644 --- a/tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp +++ b/tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp @@ -60,12 +60,13 @@ private slots: class MyCookieJar: public QNetworkCookieJar { public: - inline QList<QNetworkCookie> allCookies() const - { return QNetworkCookieJar::allCookies(); } - inline void setAllCookies(const QList<QNetworkCookie> &cookieList) - { QNetworkCookieJar::setAllCookies(cookieList); } + ~MyCookieJar() override; + using QNetworkCookieJar::allCookies; + using QNetworkCookieJar::setAllCookies; }; +MyCookieJar::~MyCookieJar() = default; + void tst_QNetworkCookieJar::getterSetter() { MyCookieJar jar; @@ -165,6 +166,10 @@ void tst_QNetworkCookieJar::setCookiesFromUrl_data() // 2. anything .ck is an effective TLD ('*.ck'), but 'www.ck' is an exception result.clear(); preset.clear(); + cookie.setDomain(".ck"); + QTest::newRow("effective-tld.ck-denied") << preset << cookie << "http://foo.ck" << result << false; + result.clear(); + preset.clear(); cookie.setDomain(".foo.ck"); result += cookie; QTest::newRow("effective-tld2-accepted2") << preset << cookie << "http://foo.ck" << result << true; diff --git a/tests/auto/network/access/qnetworkreply/BLACKLIST b/tests/auto/network/access/qnetworkreply/BLACKLIST index 4d29a830e9..2a0651f96f 100644 --- a/tests/auto/network/access/qnetworkreply/BLACKLIST +++ b/tests/auto/network/access/qnetworkreply/BLACKLIST @@ -1,47 +1,128 @@ # See qtbase/src/testlib/qtestblacklist.cpp for format -osx [authenticationCacheAfterCancel] -windows -[httpAbort] -* +windows-7sp1 +windows-10 msvc-2015 +[backgroundRequestInterruption] +opensuse-leap +windows-10 msvc-2015 +b2qt +ubuntu +osx [backgroundRequestInterruption:ftp, bg, nobg] * [getErrors:ftp-host] linux # QTBUG-71953 +[getFromHttp] +* !android !winrt [getFromHttp:success-external] * [getFromHttpIntoBuffer] -windows +osx [getFromHttpIntoBuffer2] -windows +windows-10 [headFromHttp] -windows -[ioGetFromHttpWithSocksProxy] -windows +windows-10 msvc-2017 [ioPostToHttpFromSocket] -windows # QTBUG-66247 +windows-7sp1 +windows-10 msvc-2017 +osx [ioHttpRedirect] -windows # QTBUG-66602 +windows-10 [ioHttpRedirectMultipartPost] -* # QTBUG-66247 +b2qt +windows-10 msvc-2015 +ubuntu +rhel [ioHttpRedirectPolicy] -* -[ioHttpRedirectPostPut] -linux -windows +opensuse-leap +b2qt +ubuntu +windows-10 [putToFtp] -windows ci -[putToFtpWithInvalidCredentials] -windows ci +windows-10 [putWithServerClosingConnectionImmediately] -windows -[qtbug28035browserDoesNotLoadQtProjectOrgCorrectly] -windows -[getFromUnreachableIp] -windows msvc-2017 -[ioHttpRedirectErrors:too-many-redirects] -rhel-6.6 ci +windows-7sp1 +windows-10 +osx +[backgroundRequest] +osx-10.12 +[connectToIPv6Address] +osx-10.12 +[deleteFromHttp] +osx-10.12 +[downloadProgress] +osx-10.12 +[encrypted] +osx-10.13 +[httpCanReadLine] +osx-10.12 +[httpRecursiveCreation] +osx +[httpWithNoCredentialUsage] +osx-10.12 +[ignoreSslErrorsList] +osx +[ignoreSslErrorsListWithSlot] +osx +[ioGetFromBuiltinHttp] +osx +[ioGetFromHttp] +osx-10.12 +[ioPostToHttpFromFile] +osx-10.13 +[ioPostToHttpFromSocketSynchronous] +osx +[ioPostToHttpUploadProgress] +osx +[ioPutToHttpFromFile] +osx-10.13 +[lastModifiedHeaderForHttp] +osx-10.12 +[multipartSkipIndices] +osx-10.12 +[nestedEventLoops] +osx +[postToHttp] +osx-10.12 +[postToHttpMultipart] +osx-10.12 +[postToHttpSynchronous] +osx-10.12 +[postToHttps] +osx +[postToHttpsMultipart] +osx +[postToHttpsSynchronous] +osx +[putGetDeleteGetFromHttp] +osx-10.12 +[putToHttpSynchronous] +osx-10.12 +[putToHttps] +osx +[putToHttpsSynchronous] +osx +[putWithRateLimiting] +osx-10.13 +[qtbug13431replyThrottling] +osx-10.12 +[receiveCookiesFromHttp] +osx +[receiveCookiesFromHttpSynchronous] +osx +[sendCookies] +osx +[sendCookiesSynchronous] +osx +[sendCustomRequestToHttp] +osx-10.12 +[sslConfiguration] +osx +[synchronousRequest] +osx +[backgroundRequestConnectInBackground] +osx diff --git a/tests/auto/network/access/qnetworkreply/test/test.pro b/tests/auto/network/access/qnetworkreply/test/test.pro index 9d36352abc..4cc1f6431e 100644 --- a/tests/auto/network/access/qnetworkreply/test/test.pro +++ b/tests/auto/network/access/qnetworkreply/test/test.pro @@ -15,5 +15,5 @@ TESTDATA += ../empty ../rfc3252.txt ../resource ../bigfile ../*.jpg ../certs \ !android:!winrt: TEST_HELPER_INSTALLS = ../echo/echo +CONFIG += unsupported/testserver QT_TEST_SERVER_LIST = vsftpd apache2 ftp-proxy danted squid -include($$dirname(_QMAKE_CONF_)/tests/auto/testserver.pri) diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp index 8627a37e12..418e1caf68 100644 --- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp @@ -32,8 +32,11 @@ #include <QtCore/QDataStream> #include <QtCore/QUrl> #include <QtCore/QEventLoop> +#include <QtCore/QElapsedTimer> #include <QtCore/QFile> #include <QtCore/QRandomGenerator> +#include <QtCore/QRegularExpression> +#include <QtCore/QRegularExpressionMatch> #include <QtCore/QSharedPointer> #include <QtCore/QScopedPointer> #include <QtCore/QTemporaryFile> @@ -123,7 +126,7 @@ class tst_QNetworkReply: public QObject if (!seedCreated) { seedCreated = true; // not thread-safe, but who cares } - return QString::number(QTime(0, 0, 0).msecsTo(QTime::currentTime())) + return QString::number(QTime::currentTime().msecsSinceStartOfDay()) + QLatin1Char('-') + QString::number(QCoreApplication::applicationPid()) + QLatin1Char('-') + QString::number(QRandomGenerator::global()->generate()); } @@ -503,6 +506,11 @@ private Q_SLOTS: void putWithServerClosingConnectionImmediately(); #endif + void autoDeleteRepliesAttribute_data(); + void autoDeleteRepliesAttribute(); + void autoDeleteReplies_data(); + void autoDeleteReplies(); + // NOTE: This test must be last! void parentingRepliesToTheApp(); private: @@ -1142,7 +1150,7 @@ protected: } // now write in "blocking mode", this is where the rate measuring starts - QTime timer; + QElapsedTimer timer; timer.start(); //const qint64 writtenBefore = dataIndex; //qint64 measuredTotalBytes = wantedSize - writtenBefore; @@ -1241,7 +1249,7 @@ protected: } qint64 bytesRead = 0; - QTime stopWatch; + QElapsedTimer stopWatch; stopWatch.start(); do { if (device->bytesAvailable() == 0) { @@ -1552,7 +1560,7 @@ void tst_QNetworkReply::initTestCase() QDir::setSearchPaths("testdata", QStringList() << testDataDir); #ifndef QT_NO_SSL - QSslSocket::defaultCaCertificates(); //preload certificates + QSslConfiguration::defaultConfiguration().caCertificates(); //preload certificates #endif #ifndef QT_NO_BEARERMANAGEMENT netConfMan = new QNetworkConfigurationManager(this); @@ -4142,10 +4150,10 @@ void tst_QNetworkReply::ioGetFromHttpWithCache() request.setAttribute(QNetworkRequest::CacheSaveControlAttribute, false); QFETCH(QStringList, extraHttpHeaders); - QStringListIterator it(extraHttpHeaders); - while (it.hasNext()) { - QString header = it.next(); - QString value = it.next(); + QVERIFY(extraHttpHeaders.size() % 2 == 0); + for (auto it = extraHttpHeaders.cbegin(), end = extraHttpHeaders.cend(); it != end; /*double-stepping*/) { + QString header = *it++; + QString value = *it++; request.setRawHeader(header.toLatin1(), value.toLatin1()); // To latin1? Deal with it! } @@ -5143,8 +5151,8 @@ void tst_QNetworkReply::ioGetFromBuiltinHttp() const int rate = 200; // in kB per sec RateControlledReader reader(server, reply.data(), rate, bufferSize); - QTime loopTime; - loopTime.start(); + QElapsedTimer loopTimer; + loopTimer.start(); const int result = waitForFinish(reply); if (notEnoughDataForFastSender) { @@ -5154,7 +5162,7 @@ void tst_QNetworkReply::ioGetFromBuiltinHttp() QVERIFY2(result == Success, msgWaitForFinished(reply)); - const int elapsedTime = loopTime.elapsed(); + const int elapsedTime = loopTimer.elapsed(); server.wait(); reader.wrapUp(); @@ -5440,12 +5448,12 @@ void tst_QNetworkReply::rateControl() RateControlledReader reader(sender, reply.data(), rate, 20); // this test is designed to run for 25 seconds at most - QTime loopTime; - loopTime.start(); + QElapsedTimer loopTimer; + loopTimer.start(); QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply)); - int elapsedTime = loopTime.elapsed(); + int elapsedTime = loopTimer.elapsed(); if (!errorSpy.isEmpty()) { qDebug() << "ERROR!" << errorSpy[0][0] << reply->errorString(); @@ -6115,8 +6123,8 @@ void tst_QNetworkReply::httpConnectionCount() } int pendingConnectionCount = 0; - QTime time; - time.start(); + QElapsedTimer timer; + timer.start(); while(pendingConnectionCount <= 20) { QTestEventLoop::instance().enterLoop(1); @@ -6128,7 +6136,7 @@ void tst_QNetworkReply::httpConnectionCount() } // at max. wait 10 sec - if (time.elapsed() > 10000) + if (timer.elapsed() > 10000) break; } @@ -6418,7 +6426,8 @@ void tst_QNetworkReply::abortOnEncrypted() QSKIP("Server fails to listen. Skipping since QTcpServer is covered in another test."); server.connect(&server, &SslServer::newEncryptedConnection, [&server]() { - connect(server.socket, &QTcpSocket::readyRead, server.socket, []() { + // MSVC 201X C4573-misunderstands connect() or QObject::connect(), so use server.connect(): + server.connect(server.socket, &QTcpSocket::readyRead, server.socket, []() { // This slot must not be invoked! QVERIFY(false); }); @@ -6466,8 +6475,8 @@ void tst_QNetworkReply::sslSessionSharing_data() void tst_QNetworkReply::sslSessionSharing() { -#ifdef QT_SECURETRANSPORT - QSKIP("Not implemented with SecureTransport"); +#if QT_CONFIG(schannel) || defined(QT_SECURETRANSPORT) + QSKIP("Not implemented with SecureTransport/Schannel"); #endif QString urlString("https://" + QtNetworkSettings::httpServerName()); @@ -6534,8 +6543,8 @@ void tst_QNetworkReply::sslSessionSharingFromPersistentSession_data() void tst_QNetworkReply::sslSessionSharingFromPersistentSession() { -#ifdef QT_SECURETRANSPORT - QSKIP("Not implemented with SecureTransport"); +#if QT_CONFIG(schannel) || defined(QT_SECURETRANSPORT) + QSKIP("Not implemented with SecureTransport/Schannel"); #endif QString urlString("https://" + QtNetworkSettings::httpServerName()); @@ -7905,9 +7914,10 @@ void tst_QNetworkReply::synchronousAuthenticationCache() "Content-Type: text/plain\r\n" "\r\n" "auth"; - QRegExp rx("Authorization: Basic ([^\r\n]*)\r\n"); - if (rx.indexIn(receivedData) > 0) { - if (QByteArray::fromBase64(rx.cap(1).toLatin1()) == "login:password") { + QRegularExpression rx("Authorization: Basic ([^\r\n]*)\r\n"); + QRegularExpressionMatch match = rx.match(receivedData); + if (match.hasMatch()) { + if (QByteArray::fromBase64(match.captured(1).toLatin1()) == "login:password") { dataToTransmit = "HTTP/1.0 200 OK\r\n" "Content-Type: text/plain\r\n" @@ -8143,16 +8153,17 @@ void tst_QNetworkReply::backgroundRequest() SLOT(sslErrors(QNetworkReply*,QList<QSslError>))); #endif - const QWeakPointer<const QNetworkSession> session = QNetworkAccessManagerPrivate::getNetworkSession(&manager); - QVERIFY(session); - QNetworkSession::UsagePolicies original = session.data()->usagePolicies(); - QNetworkSessionPrivate::setUsagePolicies(*const_cast<QNetworkSession *>(session.data()), QNetworkSession::UsagePolicies(policy)); + const QWeakPointer<const QNetworkSession> sessionWeakPtr = QNetworkAccessManagerPrivate::getNetworkSession(&manager); + QVERIFY(!sessionWeakPtr.isNull()); + auto session = const_cast<QNetworkSession *>(sessionWeakPtr.toStrongRef().data()); + QNetworkSession::UsagePolicies original = session->usagePolicies(); + QNetworkSessionPrivate::setUsagePolicies(*session, QNetworkSession::UsagePolicies(policy)); QNetworkReplyPtr reply(manager.get(request)); QVERIFY(waitForFinish(reply) != Timeout); if (session) - QNetworkSessionPrivate::setUsagePolicies(*const_cast<QNetworkSession *>(session.data()), original); + QNetworkSessionPrivate::setUsagePolicies(*session, original); QVERIFY(reply->isFinished()); QCOMPARE(reply->error(), error); @@ -8190,6 +8201,9 @@ void tst_QNetworkReply::backgroundRequestInterruption_data() void tst_QNetworkReply::backgroundRequestInterruption() { #ifndef QT_NO_BEARERMANAGEMENT + if (QNetworkStatusMonitor::isEnabled() && QByteArray(QTest::currentDataTag()).startsWith("http")) + QSKIP("This test (currently) doesn't make any sense when QNetworkStatusMonitor is enabled"); + QFETCH(QUrl, url); QFETCH(bool, background); QFETCH(QNetworkReply::NetworkError, error); @@ -8207,10 +8221,11 @@ void tst_QNetworkReply::backgroundRequestInterruption() SLOT(sslErrors(QNetworkReply*,QList<QSslError>))); #endif - const QWeakPointer<const QNetworkSession> session = QNetworkAccessManagerPrivate::getNetworkSession(&manager); - QVERIFY(session); - QNetworkSession::UsagePolicies original = session.data()->usagePolicies(); - QNetworkSessionPrivate::setUsagePolicies(*const_cast<QNetworkSession *>(session.data()), QNetworkSession::NoPolicy); + const QWeakPointer<const QNetworkSession> sessionWeakPtr = QNetworkAccessManagerPrivate::getNetworkSession(&manager); + QVERIFY(!sessionWeakPtr.isNull()); + auto session = const_cast<QNetworkSession *>(sessionWeakPtr.toStrongRef().data()); + QNetworkSession::UsagePolicies original = session->usagePolicies(); + QNetworkSessionPrivate::setUsagePolicies(*session, QNetworkSession::NoPolicy); request.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, 8192); QNetworkReplyPtr reply(manager.get(request)); @@ -8219,14 +8234,14 @@ void tst_QNetworkReply::backgroundRequestInterruption() QSignalSpy spy(reply.data(), SIGNAL(readyRead())); QTRY_VERIFY(spy.count() > 0); - QNetworkSessionPrivate::setUsagePolicies(*const_cast<QNetworkSession *>(session.data()), QNetworkSession::NoBackgroundTrafficPolicy); + QNetworkSessionPrivate::setUsagePolicies(*session, QNetworkSession::NoBackgroundTrafficPolicy); // After we have changed the policy we can download at full speed. reply->setReadBufferSize(0); QVERIFY(waitForFinish(reply) != Timeout); if (session) - QNetworkSessionPrivate::setUsagePolicies(*const_cast<QNetworkSession *>(session.data()), original); + QNetworkSessionPrivate::setUsagePolicies(*session, original); QVERIFY(reply->isFinished()); QCOMPARE(reply->error(), error); @@ -8266,8 +8281,8 @@ void tst_QNetworkReply::backgroundRequestConnectInBackground() QWeakPointer<const QNetworkSession> session = QNetworkAccessManagerPrivate::getNetworkSession(&manager); //force QNAM to reopen the session. - if (session && session.data()->isOpen()) { - const_cast<QNetworkSession *>(session.data())->close(); + if (session && session.toStrongRef().data()->isOpen()) { + const_cast<QNetworkSession *>(session.toStrongRef().data())->close(); QCoreApplication::processEvents(); //let signals propagate inside QNAM } @@ -8276,19 +8291,19 @@ void tst_QNetworkReply::backgroundRequestConnectInBackground() session = QNetworkAccessManagerPrivate::getNetworkSession(&manager); QVERIFY(session); - QNetworkSession::UsagePolicies original = session.data()->usagePolicies(); - QNetworkSessionPrivate::setUsagePolicies(*const_cast<QNetworkSession *>(session.data()), QNetworkSession::NoPolicy); + QNetworkSession::UsagePolicies original = session.toStrongRef().data()->usagePolicies(); + QNetworkSessionPrivate::setUsagePolicies(*const_cast<QNetworkSession *>(session.toStrongRef().data()), QNetworkSession::NoPolicy); QNetworkReplyPtr reply(manager.get(request)); QVERIFY(waitForFinish(reply) != Timeout); session = QNetworkAccessManagerPrivate::getNetworkSession(&manager); if (session) { - QVariant cib = session.data()->sessionProperty(QStringLiteral("ConnectInBackground")); + QVariant cib = session.toStrongRef().data()->sessionProperty(QStringLiteral("ConnectInBackground")); if (!cib.isValid()) QSKIP("inconclusive - ConnectInBackground session property not supported by the bearer plugin"); QCOMPARE(cib.toBool(), background); - QNetworkSessionPrivate::setUsagePolicies(*const_cast<QNetworkSession *>(session.data()), original); + QNetworkSessionPrivate::setUsagePolicies(*const_cast<QNetworkSession *>(session.toStrongRef().data()), original); } else { QSKIP("inconclusive - network session has been destroyed"); } @@ -9167,6 +9182,166 @@ void tst_QNetworkReply::putWithServerClosingConnectionImmediately() #endif +void tst_QNetworkReply::autoDeleteRepliesAttribute_data() +{ + QTest::addColumn<QUrl>("destination"); + + QTest::newRow("http") << QUrl("http://QInvalidDomain.qt/test"); + QTest::newRow("https") << QUrl("https://QInvalidDomain.qt/test"); + QTest::newRow("ftp") << QUrl("ftp://QInvalidDomain.qt/test"); + QTest::newRow("file") << QUrl("file:///thisfolderdoesn'texist/probably.txt"); +#ifdef Q_OS_WIN + // Only supported on windows. + QTest::newRow("remote-file") << QUrl("file://QInvalidHost/thisfolderdoesn'texist/probably.txt"); +#endif + QTest::newRow("qrc") << QUrl("qrc:///path/to/nowhere"); + QTest::newRow("data") << QUrl("data:,Some%20plaintext%20data"); +} + +void tst_QNetworkReply::autoDeleteRepliesAttribute() +{ + QFETCH(QUrl, destination); + { + // Get + QNetworkRequest request(destination); + request.setAttribute(QNetworkRequest::AutoDeleteReplyOnFinishAttribute, true); + QNetworkReply *reply = manager.get(request); + QSignalSpy finishedSpy(reply, &QNetworkReply::finished); + QSignalSpy destroyedSpy(reply, &QObject::destroyed); + QVERIFY(finishedSpy.wait()); + QCOMPARE(destroyedSpy.count(), 0); + QVERIFY(destroyedSpy.wait()); + } + { + // Post + QNetworkRequest request(destination); + request.setAttribute(QNetworkRequest::AutoDeleteReplyOnFinishAttribute, true); + QNetworkReply *reply = manager.post(request, QByteArrayLiteral("datastring")); + QSignalSpy finishedSpy(reply, &QNetworkReply::finished); + QSignalSpy destroyedSpy(reply, &QObject::destroyed); + QVERIFY(finishedSpy.wait()); + QCOMPARE(destroyedSpy.count(), 0); + QVERIFY(destroyedSpy.wait()); + } + // Now repeated, but without the attribute to make sure it does not get deleted automatically. + // We need two calls to processEvents to test that the QNetworkReply doesn't get deleted. + // The first call executes a metacall event which adds the deleteLater meta event which + // would be executed in the second call. But that shouldn't happen without the attribute. + { + // Get + QNetworkRequest request(destination); + QScopedPointer<QNetworkReply> reply(manager.get(request)); + QSignalSpy finishedSpy(reply.data(), &QNetworkReply::finished); + QSignalSpy destroyedSpy(reply.data(), &QObject::destroyed); + QVERIFY(finishedSpy.wait()); + QCOMPARE(destroyedSpy.count(), 0); + QCoreApplication::processEvents(); + QCoreApplication::processEvents(); + QCOMPARE(destroyedSpy.count(), 0); + } + { + // Post + QNetworkRequest request(destination); + QScopedPointer<QNetworkReply> reply(manager.post(request, QByteArrayLiteral("datastring"))); + QSignalSpy finishedSpy(reply.data(), &QNetworkReply::finished); + QSignalSpy destroyedSpy(reply.data(), &QObject::destroyed); + QVERIFY(finishedSpy.wait()); + QCOMPARE(destroyedSpy.count(), 0); + QCoreApplication::processEvents(); + QCoreApplication::processEvents(); + QCOMPARE(destroyedSpy.count(), 0); + } +} + +void tst_QNetworkReply::autoDeleteReplies_data() +{ + autoDeleteRepliesAttribute_data(); +} + +void tst_QNetworkReply::autoDeleteReplies() +{ + QFETCH(QUrl, destination); + manager.setAutoDeleteReplies(true); + auto cleanup = qScopeGuard([this] { manager.setAutoDeleteReplies(false); }); + { + // Get + QNetworkRequest request(destination); + QNetworkReply *reply = manager.get(request); + QSignalSpy finishedSpy(reply, &QNetworkReply::finished); + QSignalSpy destroyedSpy(reply, &QObject::destroyed); + QVERIFY(finishedSpy.wait()); + QCOMPARE(destroyedSpy.count(), 0); + QVERIFY(destroyedSpy.wait()); + } + { + // Post + QNetworkRequest request(destination); + QNetworkReply *reply = manager.post(request, QByteArrayLiteral("datastring")); + QSignalSpy finishedSpy(reply, &QNetworkReply::finished); + QSignalSpy destroyedSpy(reply, &QObject::destroyed); + QVERIFY(finishedSpy.wait()); + QCOMPARE(destroyedSpy.count(), 0); + QVERIFY(destroyedSpy.wait()); + } + // Here we repeat the test, but override the auto-deletion in the QNetworkRequest + // We need two calls to processEvents to test that the QNetworkReply doesn't get deleted. + // The first call executes a metacall event which adds the deleteLater meta event which + // would be executed in the second call. But that shouldn't happen in this case. + { + // Get + QNetworkRequest request(destination); + request.setAttribute(QNetworkRequest::AutoDeleteReplyOnFinishAttribute, false); + QScopedPointer<QNetworkReply> reply(manager.get(request)); + QSignalSpy finishedSpy(reply.data(), &QNetworkReply::finished); + QSignalSpy destroyedSpy(reply.data(), &QObject::destroyed); + QVERIFY(finishedSpy.wait()); + QCOMPARE(destroyedSpy.count(), 0); + QCoreApplication::processEvents(); + QCoreApplication::processEvents(); + QCOMPARE(destroyedSpy.count(), 0); + } + { + // Post + QNetworkRequest request(destination); + request.setAttribute(QNetworkRequest::AutoDeleteReplyOnFinishAttribute, false); + QScopedPointer<QNetworkReply> reply(manager.post(request, QByteArrayLiteral("datastring"))); + QSignalSpy finishedSpy(reply.data(), &QNetworkReply::finished); + QSignalSpy destroyedSpy(reply.data(), &QObject::destroyed); + QVERIFY(finishedSpy.wait()); + QCOMPARE(destroyedSpy.count(), 0); + QCoreApplication::processEvents(); + QCoreApplication::processEvents(); + QCOMPARE(destroyedSpy.count(), 0); + } + // Now we repeat the test with autoDeleteReplies set to false + cleanup.dismiss(); + manager.setAutoDeleteReplies(false); + { + // Get + QNetworkRequest request(destination); + QScopedPointer<QNetworkReply> reply(manager.get(request)); + QSignalSpy finishedSpy(reply.data(), &QNetworkReply::finished); + QSignalSpy destroyedSpy(reply.data(), &QObject::destroyed); + QVERIFY(finishedSpy.wait()); + QCOMPARE(destroyedSpy.count(), 0); + QCoreApplication::processEvents(); + QCoreApplication::processEvents(); + QCOMPARE(destroyedSpy.count(), 0); + } + { + // Post + QNetworkRequest request(destination); + QScopedPointer<QNetworkReply> reply(manager.post(request, QByteArrayLiteral("datastring"))); + QSignalSpy finishedSpy(reply.data(), &QNetworkReply::finished); + QSignalSpy destroyedSpy(reply.data(), &QObject::destroyed); + QVERIFY(finishedSpy.wait()); + QCOMPARE(destroyedSpy.count(), 0); + QCoreApplication::processEvents(); + QCoreApplication::processEvents(); + QCOMPARE(destroyedSpy.count(), 0); + } +} + // NOTE: This test must be last testcase in tst_qnetworkreply! void tst_QNetworkReply::parentingRepliesToTheApp() { diff --git a/tests/auto/network/access/qnetworkrequest/tst_qnetworkrequest.cpp b/tests/auto/network/access/qnetworkrequest/tst_qnetworkrequest.cpp index 7a3def410a..6637be0174 100644 --- a/tests/auto/network/access/qnetworkrequest/tst_qnetworkrequest.cpp +++ b/tests/auto/network/access/qnetworkrequest/tst_qnetworkrequest.cpp @@ -41,6 +41,7 @@ class tst_QNetworkRequest: public QObject private slots: void ctor_data(); void ctor(); + void implicitDefaultCtor(); void setUrl_data(); void setUrl(); void setRawHeader_data(); @@ -78,6 +79,12 @@ void tst_QNetworkRequest::ctor() } } +void tst_QNetworkRequest::implicitDefaultCtor() +{ + QNetworkRequest r = {}; + Q_UNUSED(r); +} + void tst_QNetworkRequest::setUrl_data() { ctor_data(); diff --git a/tests/auto/network/access/spdy/BLACKLIST b/tests/auto/network/access/spdy/BLACKLIST index b13eae1000..5cf79327be 100644 --- a/tests/auto/network/access/spdy/BLACKLIST +++ b/tests/auto/network/access/spdy/BLACKLIST @@ -1,4 +1,7 @@ [download] -linux +opensuse-leap [upload] -linux +opensuse-leap +ubuntu-18.04 +b2qt + diff --git a/tests/auto/network/kernel/qauthenticator/tst_qauthenticator.cpp b/tests/auto/network/kernel/qauthenticator/tst_qauthenticator.cpp index 55053842dc..8cef351554 100644 --- a/tests/auto/network/kernel/qauthenticator/tst_qauthenticator.cpp +++ b/tests/auto/network/kernel/qauthenticator/tst_qauthenticator.cpp @@ -93,7 +93,7 @@ void tst_QAuthenticator::basicAuth() QCOMPARE(priv->phase, QAuthenticatorPrivate::Start); - QCOMPARE(priv->calculateResponse("GET", "/").constData(), QByteArray("Basic " + expectedReply).constData()); + QCOMPARE(priv->calculateResponse("GET", "/", "").constData(), QByteArray("Basic " + expectedReply).constData()); } void tst_QAuthenticator::ntlmAuth_data() @@ -133,9 +133,9 @@ void tst_QAuthenticator::ntlmAuth() headers << qMakePair<QByteArray, QByteArray>("WWW-Authenticate", "NTLM"); priv->parseHttpResponse(headers, /*isProxy = */ false); if (sso) - QVERIFY(priv->calculateResponse("GET", "/").startsWith("NTLM ")); + QVERIFY(priv->calculateResponse("GET", "/", "").startsWith("NTLM ")); else - QCOMPARE(priv->calculateResponse("GET", "/").constData(), "NTLM TlRMTVNTUAABAAAABYIIAAAAAAAAAAAAAAAAAAAAAAA="); + QCOMPARE(priv->calculateResponse("GET", "/", "").constData(), "NTLM TlRMTVNTUAABAAAABYIIAAAAAAAAAAAAAAAAAAAAAAA="); // NTLM phase 2: challenge headers.clear(); @@ -146,7 +146,7 @@ void tst_QAuthenticator::ntlmAuth() QEXPECT_FAIL("with-realm-sso", "NTLM authentication code doesn't extract the realm", Continue); QCOMPARE(auth.realm(), realm); - QVERIFY(priv->calculateResponse("GET", "/").startsWith("NTLM ")); + QVERIFY(priv->calculateResponse("GET", "/", "").startsWith("NTLM ")); } void tst_QAuthenticator::equalityOperators() diff --git a/tests/auto/network/kernel/qdnslookup/BLACKLIST b/tests/auto/network/kernel/qdnslookup/BLACKLIST index edf6436384..f07a8ce9a3 100644 --- a/tests/auto/network/kernel/qdnslookup/BLACKLIST +++ b/tests/auto/network/kernel/qdnslookup/BLACKLIST @@ -1,2 +1,2 @@ [lookup] -ci +* diff --git a/tests/auto/network/kernel/qhostaddress/qhostaddress.pro b/tests/auto/network/kernel/qhostaddress/qhostaddress.pro index b5d6ea6459..d170d879e6 100644 --- a/tests/auto/network/kernel/qhostaddress/qhostaddress.pro +++ b/tests/auto/network/kernel/qhostaddress/qhostaddress.pro @@ -4,4 +4,4 @@ SOURCES += tst_qhostaddress.cpp QT = core network-private testlib -win32:LIBS += -lws2_32 +win32: QMAKE_USE += ws2_32 diff --git a/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp b/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp index 224e4d61a9..48f05a4604 100644 --- a/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp +++ b/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp @@ -375,11 +375,14 @@ QT_WARNING_DISABLE_DEPRECATED void tst_QHostAddress::assignment() { QHostAddress address; + +#if QT_DEPRECATED_SINCE(5, 8) address = "127.0.0.1"; QCOMPARE(address, QHostAddress("127.0.0.1")); address = "::1"; QCOMPARE(address, QHostAddress("::1")); +#endif // WinRT does not support sockaddr_in #ifndef Q_OS_WINRT diff --git a/tests/auto/network/kernel/qhostinfo/qhostinfo.pro b/tests/auto/network/kernel/qhostinfo/qhostinfo.pro index 3d8457dd46..d358cdf52c 100644 --- a/tests/auto/network/kernel/qhostinfo/qhostinfo.pro +++ b/tests/auto/network/kernel/qhostinfo/qhostinfo.pro @@ -6,6 +6,6 @@ SOURCES += tst_qhostinfo.cpp requires(qtConfig(private_tests)) QT = core-private network-private testlib -win32:LIBS += -lws2_32 +win32: QMAKE_USE += ws2_32 winrt: WINRT_MANIFEST.capabilities += internetClientServer diff --git a/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp b/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp index 7640d52583..a603b2d879 100644 --- a/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp +++ b/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp @@ -180,7 +180,6 @@ void tst_QHostInfo::staticInformation() void tst_QHostInfo::initTestCase() { - QVERIFY(QtNetworkSettings::verifyTestNetworkSettings()); #ifndef QT_NO_BEARERMANAGEMENT //start the default network netConfMan = new QNetworkConfigurationManager(this); @@ -241,8 +240,6 @@ void tst_QHostInfo::lookupIPv4_data() QTest::addColumn<QString>("addresses"); QTest::addColumn<int>("err"); - // Test server lookup - QTest::newRow("lookup_01") << QtNetworkSettings::serverName() << QtNetworkSettings::serverIP().toString() << int(QHostInfo::NoError); QTest::newRow("empty") << "" << "" << int(QHostInfo::HostNotFound); QTest::newRow("single_ip4") << "a-single" TEST_DOMAIN << "192.0.2.1" << int(QHostInfo::NoError); diff --git a/tests/auto/network/kernel/qnetworkdatagram/tst_qnetworkdatagram.cpp b/tests/auto/network/kernel/qnetworkdatagram/tst_qnetworkdatagram.cpp index 5eedd1043b..cd6019090f 100644 --- a/tests/auto/network/kernel/qnetworkdatagram/tst_qnetworkdatagram.cpp +++ b/tests/auto/network/kernel/qnetworkdatagram/tst_qnetworkdatagram.cpp @@ -131,7 +131,7 @@ void tst_QNetworkDatagram::makeReply() QNetworkDatagram copy = dgram; copy.setData(copy.data()); { - QNetworkDatagram reply = qMove(copy).makeReply("World"); + QNetworkDatagram reply = std::move(copy).makeReply("World"); QCOMPARE(reply.data(), QByteArray("World")); QCOMPARE(reply.senderAddress(), QHostAddress(localAddress)); QCOMPARE(reply.senderPort(), localAddress.isEmpty() ? -1 : dgram.destinationPort()); diff --git a/tests/auto/network/socket/platformsocketengine/BLACKLIST b/tests/auto/network/socket/platformsocketengine/BLACKLIST index 8e1a55995e..f1f88d26d1 100644 --- a/tests/auto/network/socket/platformsocketengine/BLACKLIST +++ b/tests/auto/network/socket/platformsocketengine/BLACKLIST @@ -1 +1,11 @@ +[tcpLoopbackPerformance] +windows-10 msvc-2015 +windows-7sp1 +[receiveUrgentData] +windows-10 msvc-2015 +windows-7sp1 +[serverTest] +windows-10 msvc-2015 +windows-7sp1 +[tcpLoopbackPerformance] windows diff --git a/tests/auto/network/socket/platformsocketengine/platformsocketengine.pri b/tests/auto/network/socket/platformsocketengine/platformsocketengine.pri index 46c722deba..868439de6a 100644 --- a/tests/auto/network/socket/platformsocketengine/platformsocketengine.pri +++ b/tests/auto/network/socket/platformsocketengine/platformsocketengine.pri @@ -4,7 +4,7 @@ QNETWORK_SRC = $$QT_SOURCE_TREE/src/network INCLUDEPATH += $$QNETWORK_SRC -win32:LIBS += -lws2_32 +win32: QMAKE_USE += ws2_32 unix:qtConfig(reduce_exports) { SOURCES += $$QNETWORK_SRC/socket/qnativesocketengine_unix.cpp diff --git a/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp b/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp index 01168cc0d6..ffc63ee46a 100644 --- a/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp +++ b/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp @@ -32,7 +32,7 @@ #include <qcoreapplication.h> #include <qdatastream.h> #include <qhostaddress.h> -#include <qdatetime.h> +#include <qelapsedtimer.h> #ifdef Q_OS_UNIX #include <unistd.h> @@ -403,7 +403,7 @@ void tst_PlatformSocketEngine::udpLoopbackPerformance() QHostAddress localhost = QHostAddress::LocalHost; qlonglong readBytes = 0; - QTime timer; + QElapsedTimer timer; timer.start(); while (timer.elapsed() < 5000) { udpSocket2.write(message1.data(), message1.size()); @@ -462,7 +462,7 @@ void tst_PlatformSocketEngine::tcpLoopbackPerformance() QByteArray message1(messageSize, '@'); QByteArray answer(messageSize, '@'); - QTime timer; + QElapsedTimer timer; timer.start(); qlonglong readBytes = 0; while (timer.elapsed() < 5000) { diff --git a/tests/auto/network/socket/qhttpsocketengine/BLACKLIST b/tests/auto/network/socket/qhttpsocketengine/BLACKLIST index 8e1a55995e..ceb3b7862e 100644 --- a/tests/auto/network/socket/qhttpsocketengine/BLACKLIST +++ b/tests/auto/network/socket/qhttpsocketengine/BLACKLIST @@ -1 +1,5 @@ +[downloadBigFile] +windows-10 msvc-2015 +windows-7sp1 +[ensureEofTriggersNotification] windows diff --git a/tests/auto/network/socket/qhttpsocketengine/qhttpsocketengine.pro b/tests/auto/network/socket/qhttpsocketengine/qhttpsocketengine.pro index 56a4fb8aee..63f41f4eb7 100644 --- a/tests/auto/network/socket/qhttpsocketengine/qhttpsocketengine.pro +++ b/tests/auto/network/socket/qhttpsocketengine/qhttpsocketengine.pro @@ -10,3 +10,8 @@ MOC_DIR=tmp requires(qtConfig(private_tests)) QT = core-private network-private testlib +# TODO: For now linux-only, because cyrus is linux-only atm ... +linux { + CONFIG += unsupported/testserver + QT_TEST_SERVER_LIST = squid danted cyrus apache2 +} diff --git a/tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp b/tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp index 68f3ea059b..64241014d7 100644 --- a/tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp +++ b/tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp @@ -38,6 +38,7 @@ #include <qhostaddress.h> #include <qtcpsocket.h> #include <qdebug.h> +#include <qelapsedtimer.h> #include <qtcpserver.h> #include "../../../network-settings.h" @@ -122,7 +123,14 @@ public slots: void tst_QHttpSocketEngine::initTestCase() { +#ifdef QT_TEST_SERVER + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpProxyServerName(), 3128)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::socksProxyServerName(), 1080)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpServerName(), 80)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::imapServerName(), 143)); +#else QVERIFY(QtNetworkSettings::verifyTestNetworkSettings()); +#endif } void tst_QHttpSocketEngine::init() @@ -171,7 +179,7 @@ void tst_QHttpSocketEngine::errorTest_data() QTest::newRow("proxy-host-not-found") << "this-host-does-not-exist." << 1080 << QString() << QString() << int(QAbstractSocket::ProxyNotFoundError); - QTest::newRow("proxy-connection-refused") << QtNetworkSettings::serverName() << 2 << QString() + QTest::newRow("proxy-connection-refused") << QtNetworkSettings::socksProxyServerName() << 2 << QString() << QString() << int(QAbstractSocket::ProxyConnectionRefusedError); @@ -278,13 +286,12 @@ void tst_QHttpSocketEngine::simpleConnectToIMAP() QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState); - socketDevice.setProxy(QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3128)); - - QVERIFY(!socketDevice.connectToHost(QtNetworkSettings::serverIP(), 143)); + socketDevice.setProxy(QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::httpProxyServerName(), 3128)); + QVERIFY(!socketDevice.connectToHost(QtNetworkSettings::imapServerIp(), 143)); QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectingState); QVERIFY(socketDevice.waitForWrite()); QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectedState); - QCOMPARE(socketDevice.peerAddress(), QtNetworkSettings::serverIP()); + QCOMPARE(socketDevice.peerAddress(), QtNetworkSettings::imapServerIp()); QVERIFY(!socketDevice.localAddress().isNull()); QVERIFY(socketDevice.localPort() > 0); @@ -292,10 +299,10 @@ void tst_QHttpSocketEngine::simpleConnectToIMAP() QVERIFY(socketDevice.waitForRead()); // Read the greeting - qint64 available = socketDevice.bytesAvailable(); + qint64 available = int(socketDevice.bytesAvailable()); QVERIFY(available > 0); QByteArray array; - array.resize(available); + array.resize(int(available)); QVERIFY(socketDevice.read(array.data(), array.size()) == available); // Check that the greeting is what we expect it to be @@ -310,9 +317,9 @@ void tst_QHttpSocketEngine::simpleConnectToIMAP() // Wait for the response QVERIFY(socketDevice.waitForRead()); - available = socketDevice.bytesAvailable(); + available = int(socketDevice.bytesAvailable()); QVERIFY(available > 0); - array.resize(available); + array.resize(int(available)); QVERIFY(socketDevice.read(array.data(), array.size()) == available); // Check that the greeting is what we expect it to be @@ -321,7 +328,7 @@ void tst_QHttpSocketEngine::simpleConnectToIMAP() // Wait for the response QVERIFY(socketDevice.waitForRead()); char c; - QCOMPARE(socketDevice.read(&c, sizeof(c)), (qint64) -1); + QCOMPARE(socketDevice.read(&c, sizeof(c)), qint64(-1)); QCOMPARE(socketDevice.error(), QAbstractSocket::RemoteHostClosedError); QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState); } @@ -335,10 +342,10 @@ void tst_QHttpSocketEngine::simpleErrorsAndStates() // Initialize device QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); - socketDevice.setProxy(QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3128)); + socketDevice.setProxy(QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::httpProxyServerName(), 3128)); QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState); - QVERIFY(!socketDevice.connectToHost(QHostAddress(QtNetworkSettings::serverName()), 8088)); + QVERIFY(!socketDevice.connectToHost(QHostAddress(QtNetworkSettings::socksProxyServerName()), 8088)); QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectingState); if (socketDevice.waitForWrite(30000)) { QVERIFY(socketDevice.state() == QAbstractSocket::ConnectedState || @@ -391,7 +398,7 @@ void tst_QHttpSocketEngine::tcpLoopbackPerformance() QByteArray message1(messageSize, '@'); QByteArray answer(messageSize, '@'); - QTime timer; + QElapsedTimer timer; timer.start(); qlonglong readBytes = 0; while (timer.elapsed() < 30000) { @@ -422,7 +429,7 @@ void tst_QHttpSocketEngine::tcpSocketBlockingTest() QTcpSocket socket; // Connect - socket.connectToHost(QtNetworkSettings::serverName(), 143); + socket.connectToHost(QtNetworkSettings::imapServerName(), 143); QVERIFY(socket.waitForConnected()); QCOMPARE(socket.state(), QTcpSocket::ConnectedState); @@ -479,7 +486,7 @@ void tst_QHttpSocketEngine::tcpSocketNonBlockingTest() tcpSocketNonBlocking_socket = &socket; // Connect - socket.connectToHost(QtNetworkSettings::serverName(), 143); + socket.connectToHost(QtNetworkSettings::imapServerName(), 143); QVERIFY(socket.state() == QTcpSocket::HostLookupState || socket.state() == QTcpSocket::ConnectingState); @@ -607,13 +614,13 @@ void tst_QHttpSocketEngine::downloadBigFile() connect(tmpSocket, SIGNAL(connected()), SLOT(exitLoopSlot())); connect(tmpSocket, SIGNAL(readyRead()), SLOT(downloadBigFileSlot())); - tmpSocket->connectToHost(QtNetworkSettings::serverName(), 80); + tmpSocket->connectToHost(QtNetworkSettings::httpServerName(), 80); QTestEventLoop::instance().enterLoop(30); if (QTestEventLoop::instance().timeout()) QFAIL("Network operation timed out"); - QByteArray hostName = QtNetworkSettings::serverName().toLatin1(); + QByteArray hostName = QtNetworkSettings::httpServerName().toLatin1(); QCOMPARE(tmpSocket->state(), QAbstractSocket::ConnectedState); QVERIFY(tmpSocket->write("GET /qtest/mediumfile HTTP/1.0\r\n") > 0); QVERIFY(tmpSocket->write("Host: ") > 0); @@ -623,7 +630,7 @@ void tst_QHttpSocketEngine::downloadBigFile() bytesAvailable = 0; - QTime stopWatch; + QElapsedTimer stopWatch; stopWatch.start(); QTestEventLoop::instance().enterLoop(60); @@ -664,13 +671,13 @@ void tst_QHttpSocketEngine::passwordAuth() QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState); - socketDevice.setProxy(QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3128, "qsockstest", "password")); + socketDevice.setProxy(QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::httpProxyServerName(), 3128, "qsockstest", "password")); - QVERIFY(!socketDevice.connectToHost(QtNetworkSettings::serverIP(), 143)); + QVERIFY(!socketDevice.connectToHost(QtNetworkSettings::imapServerIp(), 143)); QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectingState); QVERIFY(socketDevice.waitForWrite()); QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectedState); - QCOMPARE(socketDevice.peerAddress(), QtNetworkSettings::serverIP()); + QCOMPARE(socketDevice.peerAddress(), QtNetworkSettings::imapServerIp()); // Wait for the greeting QVERIFY(socketDevice.waitForRead()); diff --git a/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp b/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp index 45ab275510..732f7eef00 100644 --- a/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp +++ b/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp @@ -32,6 +32,7 @@ #include <qtextstream.h> #include <qdatastream.h> +#include <qelapsedtimer.h> #include <QtNetwork/qlocalsocket.h> #include <QtNetwork/qlocalserver.h> @@ -552,7 +553,7 @@ void tst_QLocalSocket::sendData() QCOMPARE(serverSocket->state(), QLocalSocket::ConnectedState); QTextStream out(serverSocket); QTextStream in(&socket); - out << testLine << endl; + out << testLine << Qt::endl; bool wrote = serverSocket->waitForBytesWritten(3000); if (!socket.canReadLine()) { @@ -877,7 +878,7 @@ public: QLocalSocket *serverSocket = server.nextPendingConnection(); QVERIFY(serverSocket); QTextStream out(serverSocket); - out << testLine << endl; + out << testLine << Qt::endl; QCOMPARE(serverSocket->state(), QLocalSocket::ConnectedState); QVERIFY2(serverSocket->waitForBytesWritten(), serverSocket->errorString().toLatin1().constData()); QCOMPARE(serverSocket->errorString(), QString("Unknown error")); @@ -1031,7 +1032,7 @@ void tst_QLocalSocket::waitForDisconnect() QLocalSocket *serverSocket = server.nextPendingConnection(); QVERIFY(serverSocket); socket.disconnectFromServer(); - QTime timer; + QElapsedTimer timer; timer.start(); QVERIFY(serverSocket->waitForDisconnected(3000)); QVERIFY(timer.elapsed() < 2000); diff --git a/tests/auto/network/socket/qsocks5socketengine/BLACKLIST b/tests/auto/network/socket/qsocks5socketengine/BLACKLIST index 60526827bf..61fff6ee00 100644 --- a/tests/auto/network/socket/qsocks5socketengine/BLACKLIST +++ b/tests/auto/network/socket/qsocks5socketengine/BLACKLIST @@ -1,8 +1,11 @@ [udpTest] * [passwordAuth] -* -[serverTest] -windows +ubuntu-18.04 +# QTBUG-74162 +[passwordAuth2] +ubuntu [downloadBigFile] -windows +windows-10 msvc-2015 +windows-7sp1 + diff --git a/tests/auto/network/socket/qsocks5socketengine/qsocks5socketengine.pro b/tests/auto/network/socket/qsocks5socketengine/qsocks5socketengine.pro index 71ceafa133..243eab9480 100644 --- a/tests/auto/network/socket/qsocks5socketengine/qsocks5socketengine.pro +++ b/tests/auto/network/socket/qsocks5socketengine/qsocks5socketengine.pro @@ -11,3 +11,9 @@ MOC_DIR=tmp QT = core-private network-private testlib requires(qtConfig(private_tests)) + +# Only on Linux until cyrus has been added to docker-compose-for-{windows,macOS}.yml and tested +linux { + CONFIG += unsupported/testserver + QT_TEST_SERVER_LIST = danted apache2 cyrus +} diff --git a/tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp b/tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp index 1212ea20e5..464054f8a6 100644 --- a/tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp +++ b/tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp @@ -137,7 +137,13 @@ private slots: void tst_QSocks5SocketEngine::initTestCase() { +#ifdef QT_TEST_SERVER + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::socksProxyServerName(), 1080)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpServerName(), 80)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::imapServerName(), 143)); +#else QVERIFY(QtNetworkSettings::verifyTestNetworkSettings()); +#endif } //--------------------------------------------------------------------------- @@ -293,13 +299,13 @@ void tst_QSocks5SocketEngine::simpleConnectToIMAP() QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState); - socketDevice.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080)); + socketDevice.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1080)); - QVERIFY(!socketDevice.connectToHost(QtNetworkSettings::serverIP(), 143)); + QVERIFY(!socketDevice.connectToHost(QtNetworkSettings::imapServerIp(), 143)); QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectingState); QVERIFY(socketDevice.waitForWrite()); QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectedState); - QCOMPARE(socketDevice.peerAddress(), QtNetworkSettings::serverIP()); + QCOMPARE(socketDevice.peerAddress(), QtNetworkSettings::imapServerIp()); // Wait for the greeting QVERIFY(socketDevice.waitForRead()); @@ -347,10 +353,10 @@ void tst_QSocks5SocketEngine::simpleErrorsAndStates() // Initialize device QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); - socketDevice.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080)); + socketDevice.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1080)); QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState); - QVERIFY(!socketDevice.connectToHost(QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first(), 8088)); + QVERIFY(!socketDevice.connectToHost(QHostInfo::fromName(QtNetworkSettings::socksProxyServerName()).addresses().first(), 8088)); QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectingState); if (socketDevice.waitForWrite(15000)) { QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState || @@ -433,7 +439,7 @@ void tst_QSocks5SocketEngine::serverTest() // Initialize a Tcp socket QVERIFY(server.initialize(QAbstractSocket::TcpSocket)); - QNetworkProxy proxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080); + QNetworkProxy proxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1080); server.setProxy(proxy); @@ -510,7 +516,7 @@ void tst_QSocks5SocketEngine::udpTest() QVERIFY(udpSocket.initialize(QAbstractSocket::UdpSocket)); QVERIFY(udpSocket.isValid()); - QNetworkProxy proxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080); + QNetworkProxy proxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1080); udpSocket.setProxy(proxy); @@ -564,7 +570,7 @@ void tst_QSocks5SocketEngine::tcpSocketBlockingTest() QTcpSocket socket; // Connect - socket.connectToHost(QtNetworkSettings::serverName(), 143); + socket.connectToHost(QtNetworkSettings::imapServerName(), 143); QVERIFY(socket.waitForConnected()); QCOMPARE(socket.state(), QTcpSocket::ConnectedState); @@ -635,7 +641,7 @@ void tst_QSocks5SocketEngine::tcpSocketNonBlockingTest() }); // Connect - socket.connectToHost(QtNetworkSettings::serverName(), 143); + socket.connectToHost(QtNetworkSettings::imapServerName(), 143); QVERIFY(socket.state() == QTcpSocket::HostLookupState || socket.state() == QTcpSocket::ConnectingState); @@ -754,13 +760,13 @@ void tst_QSocks5SocketEngine::downloadBigFile() << " (" << stopWatch.elapsed() << "ms)"; }); - socket.connectToHost(QtNetworkSettings::serverName(), 80); + socket.connectToHost(QtNetworkSettings::httpServerName(), 80); QTestEventLoop::instance().enterLoop(30); if (QTestEventLoop::instance().timeout()) QFAIL("Network operation timed out"); - QByteArray hostName = QtNetworkSettings::serverName().toLatin1(); + QByteArray hostName = QtNetworkSettings::httpServerName().toLatin1(); QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); QVERIFY(socket.write("GET /qtest/mediumfile HTTP/1.0\r\n") > 0); QVERIFY(socket.write("HOST: ") > 0); @@ -791,13 +797,13 @@ void tst_QSocks5SocketEngine::passwordAuth() QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState); - socketDevice.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080, "qsockstest", "password")); + socketDevice.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1080, "qsockstest", "password")); // Connect to imap.trolltech.com's IP - QVERIFY(!socketDevice.connectToHost(QtNetworkSettings::serverIP(), 143)); + QVERIFY(!socketDevice.connectToHost(QtNetworkSettings::imapServerIp(), 143)); QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectingState); QVERIFY(socketDevice.waitForWrite()); - if (!socketDevice.connectToHost(QtNetworkSettings::serverIP(), 143)) { + if (!socketDevice.connectToHost(QtNetworkSettings::imapServerIp(), 143)) { qDebug("%d, %s", socketDevice.error(), socketDevice.errorString().toLatin1().constData()); } QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectedState); @@ -857,19 +863,19 @@ void tst_QSocks5SocketEngine::passwordAuth2() QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState); - socketDevice.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081)); + socketDevice.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1081)); socketDevice.setReceiver(this); - QVERIFY(!socketDevice.connectToHost(QtNetworkSettings::serverIP(), 143)); + QVERIFY(!socketDevice.connectToHost(QtNetworkSettings::imapServerIp(), 143)); QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectingState); while (socketDevice.state() == QAbstractSocket::ConnectingState) { QVERIFY(socketDevice.waitForWrite()); - socketDevice.connectToHost(QtNetworkSettings::serverIP(), 143); + socketDevice.connectToHost(QtNetworkSettings::imapServerIp(), 143); } if (socketDevice.state() != QAbstractSocket::ConnectedState) qDebug("%d, %s", socketDevice.error(), socketDevice.errorString().toLatin1().constData()); QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectedState); - QCOMPARE(socketDevice.peerAddress(), QtNetworkSettings::serverIP()); + QCOMPARE(socketDevice.peerAddress(), QtNetworkSettings::imapServerIp()); // Wait for the greeting QVERIFY(socketDevice.waitForRead()); diff --git a/tests/auto/network/socket/qtcpserver/BLACKLIST b/tests/auto/network/socket/qtcpserver/BLACKLIST index f8b61808cc..e268468bdb 100644 --- a/tests/auto/network/socket/qtcpserver/BLACKLIST +++ b/tests/auto/network/socket/qtcpserver/BLACKLIST @@ -1,13 +1,16 @@ -windows -[linkLocal] -linux [listenWhileListening:WithSocks5Proxy] linux windows +[ipv6Server] +windows-7sp1 +windows-10 msvc-2017 [ipv6Server:WithoutProxy] windows osx -[clientServerLoop:WithSocks5Proxy] -linux -[crashTests:WithSocks5Proxy] -linux +[eagainBlockingAccept] +windows-7sp1 +windows-10 +[serverAddress] +windows-7sp1 +windows-10 + diff --git a/tests/auto/network/socket/qtcpserver/crashingServer/main.cpp b/tests/auto/network/socket/qtcpserver/crashingServer/main.cpp index 1a8e7920d3..5c66ef6520 100644 --- a/tests/auto/network/socket/qtcpserver/crashingServer/main.cpp +++ b/tests/auto/network/socket/qtcpserver/crashingServer/main.cpp @@ -29,14 +29,14 @@ #include <QtCore> #include <QtNetwork> -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) && defined(Q_CC_MSVC) +#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) && defined(Q_CC_MSVC) # include <crtdbg.h> #endif int main(int argc, char *argv[]) { // Windows: Suppress crash notification dialog. -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) && defined(Q_CC_MSVC) +#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) && defined(Q_CC_MSVC) _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG); #endif QCoreApplication app(argc, argv); diff --git a/tests/auto/network/socket/qtcpserver/test/test.pro b/tests/auto/network/socket/qtcpserver/test/test.pro index 4491523383..7e2e60a1e3 100644 --- a/tests/auto/network/socket/qtcpserver/test/test.pro +++ b/tests/auto/network/socket/qtcpserver/test/test.pro @@ -1,7 +1,7 @@ CONFIG += testcase SOURCES += ../tst_qtcpserver.cpp -win32:LIBS += -lws2_32 +win32: QMAKE_USE += ws2_32 TARGET = ../tst_qtcpserver @@ -16,3 +16,9 @@ win32 { QT = core network testlib MOC_DIR=tmp + +# Only on Linux until cyrus has been added to docker-compose-for-{windows,macOS}.yml and tested +linux { + CONFIG += unsupported/testserver + QT_TEST_SERVER_LIST = danted cyrus squid ftp-proxy +} diff --git a/tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp b/tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp index 161d94d642..849d8b0ed1 100644 --- a/tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp +++ b/tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp @@ -160,8 +160,15 @@ void tst_QTcpServer::initTestCase_data() void tst_QTcpServer::initTestCase() { +#ifdef QT_TEST_SERVER + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::socksProxyServerName(), 1080)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpProxyServerName(), 3128)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::ftpProxyServerName(), 2121)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::imapServerName(), 143)); +#else if (!QtNetworkSettings::verifyTestNetworkSettings()) QSKIP("No network test server available"); +#endif #ifndef QT_NO_BEARERMANAGEMENT QNetworkConfigurationManager man; networkSession = new QNetworkSession(man.defaultConfiguration(), this); @@ -177,7 +184,7 @@ void tst_QTcpServer::init() #ifndef QT_NO_NETWORKPROXY QFETCH_GLOBAL(int, proxyType); if (proxyType == QNetworkProxy::Socks5Proxy) { - QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080)); + QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1080)); } #else // !QT_NO_NETWORKPROXY QSKIP("No proxy support"); @@ -513,7 +520,7 @@ void tst_QTcpServer::waitForConnectionTest() } QTcpSocket findLocalIpSocket; - findLocalIpSocket.connectToHost(QtNetworkSettings::serverName(), 143); + findLocalIpSocket.connectToHost(QtNetworkSettings::imapServerName(), 143); QVERIFY(findLocalIpSocket.waitForConnected(5000)); QTcpServer server; @@ -668,16 +675,18 @@ void tst_QTcpServer::invalidProxy_data() QTest::addColumn<int>("port"); QTest::addColumn<int>("expectedError"); - QString fluke = QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first().toString(); - QTest::newRow("ftp-proxy") << int(QNetworkProxy::FtpCachingProxy) << fluke << 143 + const QString imapIp = QtNetworkSettings::imapServerIp().toString(); + const QString httpProxyIp = QtNetworkSettings::httpProxyServerIp().toString(); + const QString socksIp = QtNetworkSettings::socksProxyServerIp().toString(); + QTest::newRow("ftp-proxy") << int(QNetworkProxy::FtpCachingProxy) << imapIp << 143 << int(QAbstractSocket::UnsupportedSocketOperationError); - QTest::newRow("http-proxy") << int(QNetworkProxy::HttpProxy) << fluke << 3128 + QTest::newRow("http-proxy") << int(QNetworkProxy::HttpProxy) << httpProxyIp << 3128 << int(QAbstractSocket::UnsupportedSocketOperationError); QTest::newRow("no-such-host") << int(QNetworkProxy::Socks5Proxy) << "invalid.test.qt-project.org" << 1080 << int(QAbstractSocket::ProxyNotFoundError); - QTest::newRow("socks5-on-http") << int(QNetworkProxy::Socks5Proxy) << fluke << 3128 + QTest::newRow("socks5-on-http") << int(QNetworkProxy::Socks5Proxy) << httpProxyIp << 3128 << int(QAbstractSocket::SocketTimeoutError); } @@ -740,48 +749,48 @@ void tst_QTcpServer::proxyFactory_data() // tests that do get to listen - proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080); + proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1080); QTest::newRow("socks5") << proxyList << proxyList.at(0) << false << int(QAbstractSocket::UnknownSocketError); proxyList.clear(); - proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3128) - << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080); + proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3128) + << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1080); QTest::newRow("cachinghttp+socks5") << proxyList << proxyList.at(1) << false << int(QAbstractSocket::UnknownSocketError); proxyList.clear(); - proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121) - << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3128) - << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080); + proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121) + << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3128) + << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1080); QTest::newRow("ftp+cachinghttp+socks5") << proxyList << proxyList.at(2) << false << int(QAbstractSocket::UnknownSocketError); // tests that fail to listen proxyList.clear(); - proxyList << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3128); + proxyList << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::httpProxyServerName(), 3128); QTest::newRow("http") << proxyList << proxyList.at(0) << true << int(QAbstractSocket::UnsupportedSocketOperationError); proxyList.clear(); - proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3128); + proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3128); QTest::newRow("cachinghttp") << proxyList << QNetworkProxy() << true << int(QAbstractSocket::UnsupportedSocketOperationError); proxyList.clear(); - proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121); + proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121); QTest::newRow("ftp") << proxyList << QNetworkProxy() << true << int(QAbstractSocket::UnsupportedSocketOperationError); proxyList.clear(); - proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121) - << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3128); + proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121) + << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3128); QTest::newRow("ftp+cachinghttp") << proxyList << QNetworkProxy() << true << int(QAbstractSocket::UnsupportedSocketOperationError); @@ -872,11 +881,6 @@ void tst_QTcpServer::serverAddress_data() { QTest::addColumn<QHostAddress>("listenAddress"); QTest::addColumn<QHostAddress>("serverAddress"); -#ifdef Q_OS_WIN - if (QSysInfo::windowsVersion() < QSysInfo::WV_6_0) - QTest::newRow("Any") << QHostAddress(QHostAddress::Any) << QHostAddress(QHostAddress::AnyIPv4); //windows XP doesn't support dual stack sockets - else -#endif if (QtNetworkSettings::hasIPv6()) QTest::newRow("Any") << QHostAddress(QHostAddress::Any) << QHostAddress(QHostAddress::Any); else diff --git a/tests/auto/network/socket/qtcpsocket/BLACKLIST b/tests/auto/network/socket/qtcpsocket/BLACKLIST index d724897b74..07532710b3 100644 --- a/tests/auto/network/socket/qtcpsocket/BLACKLIST +++ b/tests/auto/network/socket/qtcpsocket/BLACKLIST @@ -1,13 +1,11 @@ -[bindThenResolveHost:first-fail] -windows +[bind] +windows-10 msvc-2015 +windows-7sp1 [bind:[::]] windows [bind:[::]:randomport] windows -[invalidProxy:socks5-on-http] -windows [timeoutConnect:ip] windows # QTBUG-66247 -[taskQtBug5799ConnectionErrorEventLoop] -windows + diff --git a/tests/auto/network/socket/qtcpsocket/test/test.pro b/tests/auto/network/socket/qtcpsocket/test/test.pro index 337e75b372..4c07b1ec66 100644 --- a/tests/auto/network/socket/qtcpsocket/test/test.pro +++ b/tests/auto/network/socket/qtcpsocket/test/test.pro @@ -2,8 +2,8 @@ CONFIG += testcase QT = core-private network-private testlib SOURCES += ../tst_qtcpsocket.cpp -win32:LIBS += -lws2_32 +win32: QMAKE_USE += ws2_32 TARGET = tst_qtcpsocket win32 { @@ -15,3 +15,9 @@ win32 { } else { DESTDIR = ../ } + +# Only on Linux until cyrus has been added to docker-compose-for-{windows,macOS}.yml and tested +linux { + CONFIG += unsupported/testserver + QT_TEST_SERVER_LIST = danted squid apache2 ftp-proxy vsftpd iptables cyrus +} diff --git a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp index 10b09629bc..75b9b23259 100644 --- a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp +++ b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp @@ -66,7 +66,7 @@ #endif #include <QTextStream> #include <QThread> -#include <QTime> +#include <QElapsedTimer> #include <QTimer> #include <QDebug> // RVCT compiles also unused inline methods @@ -236,7 +236,6 @@ private: qint64 bytesAvailable; qint64 expectedLength; bool readingBody; - QTime timer; QByteArray expectedReplyIMAP_cached; @@ -316,7 +315,7 @@ tst_QTcpSocket::tst_QTcpSocket() connect(earlyConstructedSockets->endPoints[1], SIGNAL(bytesWritten(qint64)), this, SLOT(earlySocketBytesSent(qint64))); earlyConstructedSockets->endPoints[1]->write("hello work"); - firstFailInfo.setAddresses(QList<QHostAddress>() << QHostAddress("224.0.0.0") << QtNetworkSettings::serverIP()); + firstFailInfo.setAddresses(QList<QHostAddress>() << QHostAddress("224.0.0.0") << QtNetworkSettings::httpServerIp()); } void tst_QTcpSocket::initTestCase_data() @@ -325,7 +324,6 @@ void tst_QTcpSocket::initTestCase_data() QTest::addColumn<int>("proxyType"); QTest::addColumn<bool>("ssl"); - qDebug() << QtNetworkSettings::serverName(); QTest::newRow("WithoutProxy") << false << 0 << false; QTest::newRow("WithSocks5Proxy") << true << int(Socks5Proxy) << false; QTest::newRow("WithSocks5ProxyAuth") << true << int(Socks5Proxy | AuthBasic) << false; @@ -351,7 +349,17 @@ void tst_QTcpSocket::initTestCase_data() void tst_QTcpSocket::initTestCase() { +#ifdef QT_TEST_SERVER + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpServerName(), 80)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpProxyServerName(), 3128)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::imapServerName(), 143)); + //QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::firewallServerName(), 1357)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::socksProxyServerName(), 1080)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::ftpServerName(), 21)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::ftpProxyServerName(), 2121)); +#else QVERIFY(QtNetworkSettings::verifyTestNetworkSettings()); +#endif } void tst_QTcpSocket::init() @@ -360,30 +368,33 @@ void tst_QTcpSocket::init() if (setProxy) { #ifndef QT_NO_NETWORKPROXY QFETCH_GLOBAL(int, proxyType); - QList<QHostAddress> addresses = QHostInfo::fromName(QtNetworkSettings::serverName()).addresses(); - QVERIFY2(addresses.count() > 0, "failed to get ip address for test server"); - QString fluke = addresses.first().toString(); + QList<QHostAddress> socks5Addresses = QHostInfo::fromName(QtNetworkSettings::socksProxyServerName()).addresses(); + QList<QHostAddress> httpProxyAddresses = QHostInfo::fromName(QtNetworkSettings::httpProxyServerName()).addresses(); + QVERIFY2(socks5Addresses.count() > 0, "failed to get ip address for SOCKS5 proxy server"); + QVERIFY2(httpProxyAddresses.count() > 0, "failed to get ip address for HTTP proxy server"); + QString socks5Address = socks5Addresses.first().toString(); + QString httpProxyAddress = httpProxyAddresses.first().toString(); QNetworkProxy proxy; switch (proxyType) { case Socks5Proxy: - proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, fluke, 1080); + proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, socks5Address, 1080); break; case Socks5Proxy | AuthBasic: - proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, fluke, 1081); + proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, socks5Address, 1081); break; case HttpProxy | NoAuth: - proxy = QNetworkProxy(QNetworkProxy::HttpProxy, fluke, 3128); + proxy = QNetworkProxy(QNetworkProxy::HttpProxy, httpProxyAddress, 3128); break; case HttpProxy | AuthBasic: - proxy = QNetworkProxy(QNetworkProxy::HttpProxy, fluke, 3129); + proxy = QNetworkProxy(QNetworkProxy::HttpProxy, httpProxyAddress, 3129); break; case HttpProxy | AuthNtlm: - proxy = QNetworkProxy(QNetworkProxy::HttpProxy, fluke, 3130); + proxy = QNetworkProxy(QNetworkProxy::HttpProxy, httpProxyAddress, 3130); break; } QNetworkProxy::setApplicationProxy(proxy); @@ -643,8 +654,8 @@ void tst_QTcpSocket::bind() void tst_QTcpSocket::bindThenResolveHost_data() { QTest::addColumn<QString>("hostName"); - QTest::newRow("ip-literal") << QtNetworkSettings::serverIP().toString(); - QTest::newRow("name") << QtNetworkSettings::serverName(); + QTest::newRow("ip-literal") << QtNetworkSettings::httpServerIp().toString(); + QTest::newRow("name") << QtNetworkSettings::httpServerName(); QTest::newRow("first-fail") << firstFailName; } @@ -714,7 +725,7 @@ void tst_QTcpSocket::setSocketDescriptor() #ifdef Q_OS_WIN // need the dummy to ensure winsock is started QTcpSocket *dummy = newSocket(); - dummy->connectToHost(QtNetworkSettings::serverName(), 143); + dummy->connectToHost(QtNetworkSettings::imapServerName(), 143); QVERIFY(dummy->waitForConnected()); SOCKET sock = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); @@ -736,7 +747,7 @@ void tst_QTcpSocket::setSocketDescriptor() QCOMPARE(socket->socketDescriptor(), (qintptr)sock); qt_qhostinfo_clear_cache(); //avoid the HostLookupState being skipped due to address being in cache from previous test. - socket->connectToHost(QtNetworkSettings::serverName(), 80); + socket->connectToHost(QtNetworkSettings::httpServerName(), 80); QCOMPARE(socket->state(), QTcpSocket::HostLookupState); QCOMPARE(socket->socketDescriptor(), (qintptr)sock); QVERIFY(socket->waitForConnected(10000)); @@ -757,7 +768,7 @@ void tst_QTcpSocket::socketDescriptor() QTcpSocket *socket = newSocket(); QCOMPARE(socket->socketDescriptor(), (qintptr)-1); - socket->connectToHost(QtNetworkSettings::serverName(), 143); + socket->connectToHost(QtNetworkSettings::imapServerName(), 143); QVERIFY(socket->state() == QAbstractSocket::HostLookupState || socket->state() == QAbstractSocket::ConnectingState); QVERIFY(socket->waitForConnected(10000)); @@ -774,7 +785,7 @@ void tst_QTcpSocket::blockingIMAP() QTcpSocket *socket = newSocket(); // Connect - socket->connectToHost(QtNetworkSettings::serverName(), 143); + socket->connectToHost(QtNetworkSettings::imapServerName(), 143); QVERIFY(socket->waitForConnected(10000)); QCOMPARE(socket->state(), QTcpSocket::ConnectedState); QVERIFY(socket->isValid()); @@ -851,6 +862,15 @@ void tst_QTcpSocket::hostNotFound() socket->connectToHost("nosuchserver.qt-project.org", 80); QVERIFY(!socket->waitForConnected()); QCOMPARE(socket->state(), QTcpSocket::UnconnectedState); +#ifdef QT_TEST_SERVER + QFETCH_GLOBAL(bool, setProxy); + QFETCH_GLOBAL(int, proxyType); + if (setProxy && (proxyType & HttpProxy) == HttpProxy) { + QEXPECT_FAIL("", "QTBUG-73953: The version of Squid in the docker container behaves " + "differently to the one in the network testing server, returning 503 " + "when we expect 404", Continue); + } +#endif QCOMPARE(int(socket->error()), int(QTcpSocket::HostNotFoundError)); delete socket; @@ -860,8 +880,8 @@ void tst_QTcpSocket::hostNotFound() void tst_QTcpSocket::timeoutConnect_data() { QTest::addColumn<QString>("address"); - QTest::newRow("host") << QtNetworkSettings::serverName(); - QTest::newRow("ip") << QtNetworkSettings::serverIP().toString(); + QTest::newRow("host") << QtNetworkSettings::firewallServerName(); + QTest::newRow("ip") << QtNetworkSettings::firewallServerIp().toString(); } void tst_QTcpSocket::timeoutConnect() @@ -909,7 +929,7 @@ void tst_QTcpSocket::nonBlockingIMAP() nonBlockingIMAP_socket = socket; // Connect - socket->connectToHost(QtNetworkSettings::serverName(), 143); + socket->connectToHost(QtNetworkSettings::imapServerName(), 143); QVERIFY(socket->state() == QTcpSocket::HostLookupState || socket->state() == QTcpSocket::ConnectingState); @@ -1035,7 +1055,7 @@ void tst_QTcpSocket::delayedClose() connect(socket, SIGNAL(connected()), SLOT(nonBlockingIMAP_connected())); connect(socket, SIGNAL(disconnected()), SLOT(exitLoopSlot())); - socket->connectToHost(QtNetworkSettings::serverName(), 143); + socket->connectToHost(QtNetworkSettings::imapServerName(), 143); enterLoop(30); if (timeout()) @@ -1081,7 +1101,7 @@ QByteArray tst_QTcpSocket::expectedReplyIMAP() void tst_QTcpSocket::fetchExpectedReplyIMAP() { QTcpSocket *socket = newSocket(); - socket->connectToHost(QtNetworkSettings::serverName(), 143); + socket->connectToHost(QtNetworkSettings::imapServerName(), 143); QVERIFY2(socket->waitForConnected(10000), qPrintable(socket->errorString())); QVERIFY2(socket->state() == QTcpSocket::ConnectedState, qPrintable(socket->errorString())); @@ -1100,7 +1120,7 @@ void tst_QTcpSocket::fetchExpectedReplyIMAP() void tst_QTcpSocket::partialRead() { QTcpSocket *socket = newSocket(); - socket->connectToHost(QtNetworkSettings::serverName(), 143); + socket->connectToHost(QtNetworkSettings::imapServerName(), 143); QVERIFY(socket->waitForConnected(10000)); QCOMPARE(socket->state(), QTcpSocket::ConnectedState); char buf[512]; @@ -1124,7 +1144,7 @@ void tst_QTcpSocket::partialRead() void tst_QTcpSocket::unget() { QTcpSocket *socket = newSocket(); - socket->connectToHost(QtNetworkSettings::serverName(), 143); + socket->connectToHost(QtNetworkSettings::imapServerName(), 143); QVERIFY(socket->waitForConnected(10000)); QCOMPARE(socket->state(), QTcpSocket::ConnectedState); char buf[512]; @@ -1161,7 +1181,7 @@ void tst_QTcpSocket::readRegularFile_readyRead() void tst_QTcpSocket::readAllAfterClose() { QTcpSocket *socket = newSocket(); - socket->connectToHost(QtNetworkSettings::serverName(), 143); + socket->connectToHost(QtNetworkSettings::imapServerName(), 143); connect(socket, SIGNAL(readyRead()), SLOT(readRegularFile_readyRead())); enterLoop(10); if (timeout()) @@ -1201,7 +1221,7 @@ void tst_QTcpSocket::openCloseOpenClose() QCOMPARE(socket->state(), QTcpSocket::UnconnectedState); - socket->connectToHost(QtNetworkSettings::serverName(), 143); + socket->connectToHost(QtNetworkSettings::imapServerName(), 143); QVERIFY(socket->waitForConnected(10000)); socket->close(); } @@ -1224,7 +1244,7 @@ void tst_QTcpSocket::connectDisconnectConnectDisconnect() QCOMPARE(int(socket->peerPort()), 0); QCOMPARE(socket->peerAddress(), QHostAddress()); - socket->connectToHost(QtNetworkSettings::serverName(), 143); + socket->connectToHost(QtNetworkSettings::imapServerName(), 143); QVERIFY(socket->waitForReadyRead(10000)); QCOMPARE(QString::fromLatin1(socket->read(4)), QString("* OK")); @@ -1428,7 +1448,7 @@ void tst_QTcpSocket::disconnectWhileLookingUp() // just connect and disconnect, then make sure nothing weird happened QTcpSocket *socket = newSocket(); - socket->connectToHost(QtNetworkSettings::serverName(), 21); + socket->connectToHost(QtNetworkSettings::ftpServerName(), 21); // check that connect is in progress QVERIFY(socket->state() != QAbstractSocket::UnconnectedState); @@ -1476,7 +1496,7 @@ void tst_QTcpSocket::downloadBigFile() connect(tmpSocket, SIGNAL(readyRead()), SLOT(downloadBigFileSlot())); connect(tmpSocket, SIGNAL(disconnected()), SLOT(exitLoopSlot())); - tmpSocket->connectToHost(QtNetworkSettings::serverName(), 80); + tmpSocket->connectToHost(QtNetworkSettings::httpServerName(), 80); enterLoop(30); if (timeout()) { @@ -1485,7 +1505,7 @@ void tst_QTcpSocket::downloadBigFile() QFAIL("Network operation timed out"); } - QByteArray hostName = QtNetworkSettings::serverName().toLatin1(); + QByteArray hostName = QtNetworkSettings::httpServerName().toLatin1(); QCOMPARE(tmpSocket->state(), QAbstractSocket::ConnectedState); QVERIFY(tmpSocket->write("GET /qtest/mediumfile HTTP/1.0\r\n") > 0); QVERIFY(tmpSocket->write("HOST: ") > 0); @@ -1497,7 +1517,7 @@ void tst_QTcpSocket::downloadBigFile() expectedLength = 0; readingBody = false; - QTime stopWatch; + QElapsedTimer stopWatch; stopWatch.start(); enterLoop(600); @@ -1551,7 +1571,7 @@ void tst_QTcpSocket::downloadBigFileSlot() void tst_QTcpSocket::readLine() { QTcpSocket *socket = newSocket(); - socket->connectToHost(QtNetworkSettings::serverName(), 143); + socket->connectToHost(QtNetworkSettings::imapServerName(), 143); QVERIFY(socket->waitForConnected(5000)); while (!socket->canReadLine()) @@ -1600,7 +1620,7 @@ void tst_QTcpSocket::readLine() void tst_QTcpSocket::readLineString() { QTcpSocket *socket = newSocket(); - socket->connectToHost(QtNetworkSettings::serverName(), 143); + socket->connectToHost(QtNetworkSettings::imapServerName(), 143); QVERIFY(socket->waitForReadyRead(10000)); QByteArray arr = socket->readLine(); @@ -1613,7 +1633,7 @@ void tst_QTcpSocket::readLineString() void tst_QTcpSocket::readChunks() { QTcpSocket *socket = newSocket(); - socket->connectToHost(QtNetworkSettings::serverName(), 143); + socket->connectToHost(QtNetworkSettings::imapServerName(), 143); QVERIFY(socket->waitForConnected(10000)); QVERIFY(socket->waitForReadyRead(5000)); @@ -1633,7 +1653,7 @@ void tst_QTcpSocket::readChunks() void tst_QTcpSocket::waitForBytesWritten() { QTcpSocket *socket = newSocket(); - socket->connectToHost(QtNetworkSettings::serverName(), 80); + socket->connectToHost(QtNetworkSettings::httpServerName(), 80); QVERIFY(socket->waitForConnected(10000)); socket->write("GET / HTTP/1.0\r\n\r\n"); @@ -1651,7 +1671,7 @@ void tst_QTcpSocket::waitForBytesWrittenMinusOne() QSKIP("QTBUG-24451 - indefinite wait may hang"); #endif QTcpSocket *socket = newSocket(); - socket->connectToHost(QtNetworkSettings::serverName(), 80); + socket->connectToHost(QtNetworkSettings::httpServerName(), 80); QVERIFY(socket->waitForConnected(10000)); socket->write("GET / HTTP/1.0\r\n\r\n"); @@ -1666,7 +1686,7 @@ void tst_QTcpSocket::waitForBytesWrittenMinusOne() void tst_QTcpSocket::waitForReadyRead() { QTcpSocket *socket = newSocket(); - socket->connectToHost(QtNetworkSettings::serverName(), 80); + socket->connectToHost(QtNetworkSettings::httpServerName(), 80); socket->write("GET / HTTP/1.0\r\n\r\n"); QVERIFY(socket->waitForReadyRead(5000)); delete socket; @@ -1679,7 +1699,7 @@ void tst_QTcpSocket::waitForReadyReadMinusOne() QSKIP("QTBUG-24451 - indefinite wait may hang"); #endif QTcpSocket *socket = newSocket(); - socket->connectToHost(QtNetworkSettings::serverName(), 80); + socket->connectToHost(QtNetworkSettings::httpServerName(), 80); socket->write("GET / HTTP/1.0\r\n\r\n"); QVERIFY(socket->waitForReadyRead(-1)); delete socket; @@ -1692,7 +1712,7 @@ void tst_QTcpSocket::flush() socket->flush(); connect(socket, SIGNAL(connected()), SLOT(exitLoopSlot())); - socket->connectToHost(QtNetworkSettings::serverName(), 143); + socket->connectToHost(QtNetworkSettings::imapServerName(), 143); enterLoop(60); QVERIFY(socket->isOpen()); @@ -1709,7 +1729,7 @@ void tst_QTcpSocket::flush() void tst_QTcpSocket::synchronousApi() { QTcpSocket *ftpSocket = newSocket(); - ftpSocket->connectToHost(QtNetworkSettings::serverName(), 21); + ftpSocket->connectToHost(QtNetworkSettings::ftpServerName(), 21); ftpSocket->write("QUIT\r\n"); QVERIFY(ftpSocket->waitForDisconnected(10000)); QVERIFY(ftpSocket->bytesAvailable() > 0); @@ -1756,10 +1776,10 @@ void tst_QTcpSocket::recursiveReadyRead() QSignalSpy spy(testSocket, SIGNAL(readyRead())); - testSocket->connectToHost(QtNetworkSettings::serverName(), 143); + testSocket->connectToHost(QtNetworkSettings::imapServerName(), 143); enterLoop(30); QVERIFY2(!timeout(), - "Timed out when connecting to QtNetworkSettings::serverName()."); + "Timed out when connecting to QtNetworkSettings::imapServerName()."); enterLoop(30); QVERIFY2(!timeout(), @@ -1793,7 +1813,7 @@ void tst_QTcpSocket::recursiveReadyReadSlot() void tst_QTcpSocket::atEnd() { QTcpSocket *socket = newSocket(); - socket->connectToHost(QtNetworkSettings::serverName(), 21); + socket->connectToHost(QtNetworkSettings::ftpServerName(), 21); QVERIFY(socket->waitForReadyRead(15000)); QTextStream stream(socket); @@ -1801,9 +1821,15 @@ void tst_QTcpSocket::atEnd() QString greeting = stream.readLine(); QVERIFY(stream.atEnd()); +#ifdef QT_TEST_SERVER + // Test server must use some vsFTPd 3.x.x version + QVERIFY2(greeting.length() == sizeof("220 (vsFTPd 3.x.x)")-1, qPrintable(greeting)); + QVERIFY2(greeting.startsWith("220 (vsFTPd 3."), qPrintable(greeting)); +#else // Test server must use some vsFTPd 2.x.x version QVERIFY2(greeting.length() == sizeof("220 (vsFTPd 2.x.x)")-1, qPrintable(greeting)); QVERIFY2(greeting.startsWith("220 (vsFTPd 2."), qPrintable(greeting)); +#endif QVERIFY2(greeting.endsWith(QLatin1Char(')')), qPrintable(greeting)); delete socket; @@ -1834,7 +1860,7 @@ protected: connect(socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), Qt::DirectConnection); - socket->connectToHost(QtNetworkSettings::serverName(), 21); + socket->connectToHost(QtNetworkSettings::ftpServerName(), 21); socket->write("QUIT\r\n"); exec(); @@ -1908,7 +1934,7 @@ void tst_QTcpSocket::waitForReadyReadInASlot() tmpSocket = socket; connect(socket, SIGNAL(connected()), this, SLOT(waitForReadyReadInASlotSlot())); - socket->connectToHost(QtNetworkSettings::serverName(), 80); + socket->connectToHost(QtNetworkSettings::httpServerName(), 80); socket->write("GET / HTTP/1.0\r\n\r\n"); enterLoop(30); @@ -2092,7 +2118,7 @@ void tst_QTcpSocket::waitForConnectedInHostLookupSlot() timer.start(15000); connect(tmpSocket, SIGNAL(hostFound()), this, SLOT(hostLookupSlot())); - tmpSocket->connectToHost(QtNetworkSettings::serverName(), 143); + tmpSocket->connectToHost(QtNetworkSettings::imapServerName(), 143); // only execute the loop if not already connected if (tmpSocket->state() != QAbstractSocket::ConnectedState) @@ -2147,7 +2173,7 @@ public slots: inline void doIt() { attemptedToConnect = true; - sock->connectToHost(QtNetworkSettings::serverName(), 80); + sock->connectToHost(QtNetworkSettings::httpServerName(), 80); #if defined(Q_OS_MAC) pthread_yield_np(); @@ -2198,7 +2224,7 @@ void tst_QTcpSocket::readyReadSignalsAfterWaitForReadyRead() QSignalSpy readyReadSpy(socket, SIGNAL(readyRead())); // Connect - socket->connectToHost(QtNetworkSettings::serverName(), 143); + socket->connectToHost(QtNetworkSettings::imapServerName(), 143); // Wait for the read QVERIFY(socket->waitForReadyRead(10000)); @@ -2334,7 +2360,7 @@ void tst_QTcpSocket::localAddressEmptyOnBSD() void tst_QTcpSocket::zeroAndMinusOneReturns() { QTcpSocket *socket = newSocket(); - socket->connectToHost(QtNetworkSettings::serverName(), 80); + socket->connectToHost(QtNetworkSettings::httpServerName(), 80); socket->write("GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n"); QVERIFY(socket->waitForReadyRead(15000)); @@ -2395,7 +2421,7 @@ void tst_QTcpSocket::connectionRefused() connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), &QTestEventLoop::instance(), SLOT(exitLoop())); - socket->connectToHost(QtNetworkSettings::serverName(), 144); + socket->connectToHost(QtNetworkSettings::httpServerName(), 144); enterLoop(10); disconnect(socket, SIGNAL(error(QAbstractSocket::SocketError)), @@ -2475,7 +2501,7 @@ void tst_QTcpSocket::suddenRemoteDisconnect() QEventLoop loop; connect(&serverProcess, SIGNAL(finished(int)), &loop, SLOT(quit())); connect(&clientProcess, SIGNAL(finished(int)), &loop, SLOT(quit())); - QTime stopWatch; + QElapsedTimer stopWatch; stopWatch.start(); QTimer::singleShot(20000, &loop, SLOT(quit())); @@ -2515,7 +2541,7 @@ void tst_QTcpSocket::connectToMultiIP() // rationale: this domain resolves to 3 A-records, 2 of them are // invalid. QTcpSocket should never spend more than 30 seconds per IP, and // 30s*2 = 60s. - QTime stopWatch; + QElapsedTimer stopWatch; stopWatch.start(); socket->connectToHost("multi.dev.qt-project.org", 80); QVERIFY(socket->waitForConnected(60500)); @@ -2542,7 +2568,7 @@ void tst_QTcpSocket::moveToThread0() { // Case 1: Moved after connecting, before waiting for connection. QTcpSocket *socket = newSocket();; - socket->connectToHost(QtNetworkSettings::serverName(), 143); + socket->connectToHost(QtNetworkSettings::imapServerName(), 143); socket->moveToThread(0); QVERIFY(socket->waitForConnected(5000)); socket->write("XXX LOGOUT\r\n"); @@ -2554,7 +2580,7 @@ void tst_QTcpSocket::moveToThread0() // Case 2: Moved before connecting QTcpSocket *socket = newSocket(); socket->moveToThread(0); - socket->connectToHost(QtNetworkSettings::serverName(), 143); + socket->connectToHost(QtNetworkSettings::imapServerName(), 143); QVERIFY(socket->waitForConnected(5000)); socket->write("XXX LOGOUT\r\n"); QVERIFY(socket->waitForBytesWritten(5000)); @@ -2564,7 +2590,7 @@ void tst_QTcpSocket::moveToThread0() { // Case 3: Moved after writing, while waiting for bytes to be written. QTcpSocket *socket = newSocket(); - socket->connectToHost(QtNetworkSettings::serverName(), 143); + socket->connectToHost(QtNetworkSettings::imapServerName(), 143); QVERIFY(socket->waitForConnected(5000)); socket->write("XXX LOGOUT\r\n"); socket->moveToThread(0); @@ -2575,7 +2601,7 @@ void tst_QTcpSocket::moveToThread0() { // Case 4: Moved after writing, while waiting for response. QTcpSocket *socket = newSocket(); - socket->connectToHost(QtNetworkSettings::serverName(), 143); + socket->connectToHost(QtNetworkSettings::imapServerName(), 143); QVERIFY(socket->waitForConnected(5000)); socket->write("XXX LOGOUT\r\n"); QVERIFY(socket->waitForBytesWritten(5000)); @@ -2706,8 +2732,8 @@ void tst_QTcpSocket::taskQtBug5799ConnectionErrorWaitForConnected() // use waitForConnected, e.g. this should use a synchronous select() on the OS level QTcpSocket socket; - socket.connectToHost(QtNetworkSettings::serverName(), 12346); - QTime timer; + socket.connectToHost(QtNetworkSettings::httpServerName(), 12346); + QElapsedTimer timer; timer.start(); socket.waitForConnected(10000); QVERIFY2(timer.elapsed() < 9900, "Connection to closed port timed out instead of refusing, something is wrong"); @@ -2726,7 +2752,7 @@ void tst_QTcpSocket::taskQtBug5799ConnectionErrorEventLoop() // This testcase uses an event loop QTcpSocket socket; connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)), &QTestEventLoop::instance(), SLOT(exitLoop())); - socket.connectToHost(QtNetworkSettings::serverName(), 12346); + socket.connectToHost(QtNetworkSettings::httpServerName(), 12346); QTestEventLoop::instance().enterLoop(10); QVERIFY2(!QTestEventLoop::instance().timeout(), "Connection to closed port timed out instead of refusing, something is wrong"); @@ -2739,7 +2765,7 @@ void tst_QTcpSocket::taskQtBug7054TimeoutErrorResetting() { QTcpSocket *socket = newSocket(); - socket->connectToHost(QtNetworkSettings::serverName(), 443); + socket->connectToHost(QtNetworkSettings::httpServerName(), 443); QVERIFY(socket->waitForConnected(5*1000)); QCOMPARE(socket->error(), QAbstractSocket::UnknownSocketError); @@ -2768,10 +2794,12 @@ void tst_QTcpSocket::invalidProxy_data() QTest::addColumn<bool>("failsAtConnect"); QTest::addColumn<int>("expectedError"); - QString fluke = QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first().toString(); - QTest::newRow("ftp-proxy") << int(QNetworkProxy::FtpCachingProxy) << fluke << 21 << true + const QString ftpAddress = QtNetworkSettings::ftpServerIp().toString(); + const QString httpProxyAddress = QtNetworkSettings::httpProxyServerIp().toString(); + const QString socksProxyAddress = QtNetworkSettings::socksProxyServerIp().toString(); + QTest::newRow("ftp-proxy") << int(QNetworkProxy::FtpCachingProxy) << ftpAddress << 21 << true << int(QAbstractSocket::UnsupportedSocketOperationError); - QTest::newRow("http-caching-proxy") << int(QNetworkProxy::HttpCachingProxy) << fluke << 3128 << true + QTest::newRow("http-caching-proxy") << int(QNetworkProxy::HttpCachingProxy) << httpProxyAddress << 3128 << true << int(QAbstractSocket::UnsupportedSocketOperationError); QTest::newRow("no-such-host-socks5") << int(QNetworkProxy::Socks5Proxy) << "this-host-will-never-exist.qt-project.org" << 1080 << false @@ -2779,9 +2807,9 @@ void tst_QTcpSocket::invalidProxy_data() QTest::newRow("no-such-host-http") << int(QNetworkProxy::HttpProxy) << "this-host-will-never-exist.qt-project.org" << 3128 << false << int(QAbstractSocket::ProxyNotFoundError); - QTest::newRow("http-on-socks5") << int(QNetworkProxy::HttpProxy) << fluke << 1080 << false + QTest::newRow("http-on-socks5") << int(QNetworkProxy::HttpProxy) << socksProxyAddress << 1080 << false << int(QAbstractSocket::ProxyConnectionClosedError); - QTest::newRow("socks5-on-http") << int(QNetworkProxy::Socks5Proxy) << fluke << 3128 << false + QTest::newRow("socks5-on-http") << int(QNetworkProxy::Socks5Proxy) << httpProxyAddress << 3128 << false << int(QAbstractSocket::SocketTimeoutError); } @@ -2800,7 +2828,7 @@ void tst_QTcpSocket::invalidProxy() QTcpSocket *socket = newSocket(); socket->setProxy(proxy); - socket->connectToHost(QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first().toString(), 80); + socket->connectToHost(QtNetworkSettings::httpServerIp().toString(), 80); if (failsAtConnect) { QCOMPARE(socket->state(), QAbstractSocket::UnconnectedState); @@ -2852,48 +2880,48 @@ void tst_QTcpSocket::proxyFactory_data() // tests that do connect - proxyList << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129); + proxyList << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::httpProxyServerName(), 3129); QTest::newRow("http") << proxyList << proxyList.at(0) << false << int(QAbstractSocket::UnknownSocketError); proxyList.clear(); - proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081); + proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1081); QTest::newRow("socks5") << proxyList << proxyList.at(0) << false << int(QAbstractSocket::UnknownSocketError); proxyList.clear(); - proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129) - << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081); + proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3129) + << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1081); QTest::newRow("cachinghttp+socks5") << proxyList << proxyList.at(1) << false << int(QAbstractSocket::UnknownSocketError); proxyList.clear(); - proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121) - << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129) - << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081); + proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121) + << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3129) + << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1081); QTest::newRow("ftp+cachinghttp+socks5") << proxyList << proxyList.at(2) << false << int(QAbstractSocket::UnknownSocketError); // tests that fail to connect proxyList.clear(); - proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129); + proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3129); QTest::newRow("cachinghttp") << proxyList << QNetworkProxy() << true << int(QAbstractSocket::UnsupportedSocketOperationError); proxyList.clear(); - proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121); + proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121); QTest::newRow("ftp") << proxyList << QNetworkProxy() << true << int(QAbstractSocket::UnsupportedSocketOperationError); proxyList.clear(); - proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121) - << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129); + proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121) + << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3129); QTest::newRow("ftp+cachinghttp") << proxyList << QNetworkProxy() << true << int(QAbstractSocket::UnsupportedSocketOperationError); @@ -2914,7 +2942,7 @@ void tst_QTcpSocket::proxyFactory() QNetworkProxyFactory::setApplicationProxyFactory(factory); QTcpSocket *socket = newSocket(); - QString host = QtNetworkSettings::serverName(); + QString host = QtNetworkSettings::httpServerName(); socket->connectToHost(host, 80); // Verify that the factory was called properly diff --git a/tests/auto/network/socket/qudpsocket/BLACKLIST b/tests/auto/network/socket/qudpsocket/BLACKLIST index 0d56f6c827..bc6068d695 100644 --- a/tests/auto/network/socket/qudpsocket/BLACKLIST +++ b/tests/auto/network/socket/qudpsocket/BLACKLIST @@ -1,26 +1,10 @@ [writeDatagramToNonExistingPeer] -windows -osx -[asyncReadDatagram] -osx -[multicastLeaveAfterClose] -osx -[readyRead] -osx +windows-10 msvc-2017 +windows-10 msvc-2015 +windows-7sp1 [readyReadForEmptyDatagram] -osx +opensuse-leap [echo] -linux -osx -[ipv6Loop] -osx -[loop] -osx -[broadcasting] -osx -[zeroLengthDatagram] -osx -[linkLocalIPv6] -linux +opensuse-42.3 [readyReadForEmptyDatagram] linux diff --git a/tests/auto/network/socket/qudpsocket/clientserver/main.cpp b/tests/auto/network/socket/qudpsocket/clientserver/main.cpp index cc3e90671a..8172cd4f6f 100644 --- a/tests/auto/network/socket/qudpsocket/clientserver/main.cpp +++ b/tests/auto/network/socket/qudpsocket/clientserver/main.cpp @@ -54,7 +54,7 @@ public: printf("ok\n"); break; case UnconnectedClient: - peerAddress = host; + peerAddress = QHostAddress(host); peerPort = port; if (bind(QHostAddress::Any, port + 1, ShareAddress | ReuseAddressHint)) { startTimer(250); diff --git a/tests/auto/network/socket/qudpsocket/test/test.pro b/tests/auto/network/socket/qudpsocket/test/test.pro index e856776ddc..994b360370 100644 --- a/tests/auto/network/socket/qudpsocket/test/test.pro +++ b/tests/auto/network/socket/qudpsocket/test/test.pro @@ -6,7 +6,7 @@ QT = core network testlib MOC_DIR=tmp -win32 { +win32:debug_and_release { CONFIG(debug, debug|release) { DESTDIR = ../debug } else { @@ -17,3 +17,9 @@ win32 { } TARGET = tst_qudpsocket + +# Only on Linux until 'echo' has been added to docker-compose-for-{windows,macOS}.yml and tested +linux { + CONFIG += unsupported/testserver + QT_TEST_SERVER_LIST = danted echo +} diff --git a/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp b/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp index 707c1acf48..0f419e9de4 100644 --- a/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp +++ b/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp @@ -40,6 +40,7 @@ #include <qhostinfo.h> #include <qtcpsocket.h> #include <qmap.h> +#include <qelapsedtimer.h> #include <qnetworkdatagram.h> #include <QNetworkProxy> #include <QNetworkInterface> @@ -235,6 +236,7 @@ void tst_QUdpSocket::initTestCase_data() // hack: we only enable the Socks5 over UDP tests on the old // test server, because they fail on the new one. See QTBUG-35490 bool newTestServer = true; +#ifndef QT_TEST_SERVER QTcpSocket socket; socket.connectToHost(QtNetworkSettings::serverName(), 22); if (socket.waitForConnected(10000)) { @@ -244,6 +246,7 @@ void tst_QUdpSocket::initTestCase_data() newTestServer = false; socket.disconnectFromHost(); } +#endif QTest::addColumn<bool>("setProxy"); QTest::addColumn<int>("proxyType"); @@ -257,8 +260,13 @@ void tst_QUdpSocket::initTestCase_data() void tst_QUdpSocket::initTestCase() { +#ifdef QT_TEST_SERVER + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::socksProxyServerName(), 1080)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::echoServerName(), 7)); +#else if (!QtNetworkSettings::verifyTestNetworkSettings()) QSKIP("No network test server available"); +#endif allAddresses = QNetworkInterface::allAddresses(); m_skipUnsupportedIPv6Tests = shouldSkipIpv6TestsForBrokenSetsockopt(); @@ -300,7 +308,7 @@ void tst_QUdpSocket::init() #if QT_CONFIG(socks5) QFETCH_GLOBAL(int, proxyType); if (proxyType == QNetworkProxy::Socks5Proxy) { - QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080)); + QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1080)); } #else QSKIP("No proxy support"); @@ -915,7 +923,7 @@ void tst_QUdpSocket::performance() client.connectToHost(serverAddress, server.localPort()); QVERIFY(client.waitForConnected(10000)); - QTime stopWatch; + QElapsedTimer stopWatch; stopWatch.start(); qint64 nbytes = 0; @@ -981,7 +989,7 @@ void tst_QUdpSocket::writeDatagramToNonExistingPeer_data() QTest::addColumn<bool>("bind"); QTest::addColumn<QHostAddress>("peerAddress"); QHostAddress localhost(QHostAddress::LocalHost); - QList<QHostAddress> serverAddresses(QHostInfo::fromName(QtNetworkSettings::serverName()).addresses()); + QList<QHostAddress> serverAddresses(QHostInfo::fromName(QtNetworkSettings::socksProxyServerName()).addresses()); if (serverAddresses.isEmpty()) return; @@ -995,7 +1003,7 @@ void tst_QUdpSocket::writeDatagramToNonExistingPeer_data() void tst_QUdpSocket::writeDatagramToNonExistingPeer() { - if (QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().isEmpty()) + if (QHostInfo::fromName(QtNetworkSettings::socksProxyServerName()).addresses().isEmpty()) QFAIL("Could not find test server address"); QFETCH(bool, bind); QFETCH(QHostAddress, peerAddress); @@ -1015,7 +1023,7 @@ void tst_QUdpSocket::writeToNonExistingPeer_data() { QTest::addColumn<QHostAddress>("peerAddress"); QHostAddress localhost(QHostAddress::LocalHost); - QList<QHostAddress> serverAddresses(QHostInfo::fromName(QtNetworkSettings::serverName()).addresses()); + QList<QHostAddress> serverAddresses(QHostInfo::fromName(QtNetworkSettings::socksProxyServerName()).addresses()); if (serverAddresses.isEmpty()) return; @@ -1028,7 +1036,7 @@ void tst_QUdpSocket::writeToNonExistingPeer_data() void tst_QUdpSocket::writeToNonExistingPeer() { QSKIP("Connected-mode UDP sockets and their behaviour are erratic"); - if (QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().isEmpty()) + if (QHostInfo::fromName(QtNetworkSettings::socksProxyServerName()).addresses().isEmpty()) QFAIL("Could not find test server address"); QFETCH(QHostAddress, peerAddress); quint16 peerPort = 34534; @@ -1551,7 +1559,7 @@ void tst_QUdpSocket::echo_data() void tst_QUdpSocket::echo() { QFETCH(bool, connect); - QHostInfo info = QHostInfo::fromName(QtNetworkSettings::serverName()); + QHostInfo info = QHostInfo::fromName(QtNetworkSettings::echoServerName()); QVERIFY(info.addresses().count()); QHostAddress remote = info.addresses().first(); diff --git a/tests/auto/network/ssl/qsslcertificate/BLACKLIST b/tests/auto/network/ssl/qsslcertificate/BLACKLIST index 25509a5ca8..9494ee2278 100644 --- a/tests/auto/network/ssl/qsslcertificate/BLACKLIST +++ b/tests/auto/network/ssl/qsslcertificate/BLACKLIST @@ -1,3 +1,13 @@ # OpenSSL version is too new. Rich will fix :) [subjectAndIssuerAttributes] -* +ubuntu-16.04 +rhel-7.6 +opensuse-leap +windows-7sp1 +ubuntu-18.04 +rhel-7.4 +b2qt +windows-10 msvc-2017 +windows-10 msvc-2015 +opensuse-42.3 + diff --git a/tests/auto/network/ssl/qsslcertificate/tst_qsslcertificate.cpp b/tests/auto/network/ssl/qsslcertificate/tst_qsslcertificate.cpp index 88be13f41d..efc0c26076 100644 --- a/tests/auto/network/ssl/qsslcertificate/tst_qsslcertificate.cpp +++ b/tests/auto/network/ssl/qsslcertificate/tst_qsslcertificate.cpp @@ -401,9 +401,7 @@ void tst_QSslCertificate::subjectAlternativeNames() certificate.subjectAlternativeNames(); // verify that each entry in subjAltNames is present in fileContents - QMapIterator<QSsl::AlternativeNameEntryType, QString> it(altSubjectNames); - while (it.hasNext()) { - it.next(); + for (auto it = altSubjectNames.cbegin(), end = altSubjectNames.cend(); it != end; ++it) { QByteArray type; if (it.key() == QSsl::EmailEntry) type = "email"; @@ -814,7 +812,7 @@ void tst_QSslCertificate::task256066toPem() void tst_QSslCertificate::nulInCN() { -#if defined(QT_SECURETRANSPORT) || defined(Q_OS_WINRT) || QT_CONFIG(schannel) +#if QT_CONFIG(securetransport) || defined(Q_OS_WINRT) || QT_CONFIG(schannel) QSKIP("Generic QSslCertificatePrivate fails this test"); #endif QList<QSslCertificate> certList = @@ -833,7 +831,7 @@ void tst_QSslCertificate::nulInCN() void tst_QSslCertificate::nulInSan() { -#if defined(QT_SECURETRANSPORT) || defined(Q_OS_WINRT) || QT_CONFIG(schannel) +#if QT_CONFIG(securetransport) || defined(Q_OS_WINRT) || QT_CONFIG(schannel) QSKIP("Generic QSslCertificatePrivate fails this test"); #endif QList<QSslCertificate> certList = @@ -968,7 +966,7 @@ void tst_QSslCertificate::subjectAndIssuerAttributes() void tst_QSslCertificate::verify() { -#ifdef QT_SECURETRANSPORT +#if QT_CONFIG(securetransport) QSKIP("Not implemented in SecureTransport"); #endif QList<QSslError> errors; diff --git a/tests/auto/network/ssl/qsslkey/BLACKLIST b/tests/auto/network/ssl/qsslkey/BLACKLIST index f9bc0af6de..19fb15cd1f 100644 --- a/tests/auto/network/ssl/qsslkey/BLACKLIST +++ b/tests/auto/network/ssl/qsslkey/BLACKLIST @@ -1,2 +1,9 @@ -redhatenterpriselinuxworkstation +[constructor] rhel +[length] +rhel +[toEncryptedPemOrDer] +rhel +[toPemOrDer] +rhel + diff --git a/tests/auto/network/ssl/qsslkey/rsa-with-passphrase-aes128.pem b/tests/auto/network/ssl/qsslkey/rsa-with-passphrase-aes128.pem new file mode 100644 index 0000000000..1a8751874e --- /dev/null +++ b/tests/auto/network/ssl/qsslkey/rsa-with-passphrase-aes128.pem @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-128-CBC,A2A6F6BA67CFB2A992BA4FD3A0984B59 + +L5G1mwcXwW30lFty1HaEHlswFXAGk9+qf0TdYYNAAvVrsTMgfMq/6xM5XWo3IgbN +gG4K6T57gQkAywn+upqMHobB+7qc3DRzYlrm89gb74gHOe95l/iUJp4ii+ROLcmY +fg/vNmDSB/D0eM91WfwId7ticYD29+BUbbnqSYyY2S7K7DytYLpXqg3u335GYCdT +JwOsgcgbOICytkgK6c9ZDF3IrkzvWospVuiG5IfpLQkUXlJO3YGJ/oGf1BXnRd/b +kTzUiimUVunX62muHaUXKkAmXS8FCdB0puI+52pzLJ5FHdFxCcnwSG09TmoXbwwa +KoNM+IshNHPBGM7QxflVbSDxDaF1FWLwWSb8+Fhb2fTpfEGMxRCQ8HB1ZeMV4E5W +DSiNhih8ziC0k957ZYv8iuLanoM1YYIdToHeBwjyBJA836eIcq/ElY2QtKUq5PRw ++sU1BdG+f9rf4iAPHpgWZAKFmJ42ya71bEEVAmfysAOPuc4hpn3SsDTtihm9RKc9 +l7LWJHaTnTu6yJA+vMJwAmPWg+IdG5vntbb93X4cgl5ZadBySRtv37wWyQPnQcFh +ytX8z2CJNIFJb0ik8bXc39zOxExoTu/o86IuVJ87jFdS1wz3PRek6dJdl15icx76 +yAT0YB2/ZlRcRrO9hSm0D6P+sLOh//dyhhFAlUrDxqrKngI3KF4kgIrSlva3wmx2 +t16SiUKu6FGQZk6/KYOV27Cy+8UJEqlrNJzy+wSFi26d6e6xWTIR2ItzQCxhYDmq +Tpx0Mh0ml2+bgrKRoDAL5z6UNy0Pc6bYQjvMznIeiuGvL8bAKTDUFwbmrZqNScsl +tW7yNZG9iSJnAZGMTxuOhSvJRpQkxIcLICd+lsUxWZ2YvFxtSORuRNSwaC7oxtTD +gIXV08ayoDbDmcguqTXWuCxtguxNANjhsUOetNHL8iP8QFrzAd5Ith9FgASCIBJJ +3X7vL2YGc3E6DlAJE01loqySU/cnu6/zQapLB9BIzdtoLliwdrJ7PS8FSsBDfZ2X +i6/7gb1jxYkJAS1NqrUMJw6BphRAwF8ny+FtPJ23Oaf+1vRIGiHsh8qw6XBfwFw9 +vtsUUL19r+8zMpvIB6gf34TLuM7AW7idu3c/486EWgZBDL3mOTd3fsyADKv/HCk7 +c8M2dsafxI6QkTlWsB8G5vkZ8lCGKHjrmPWjfD7NXi+CvXIrDY+gOeVN3PlQCU/2 +zF2vIxKtR0CXuxLzIjFhIgTYR5G5ZnddMmHeVkZdPRl7szGtrxOA4QGJQ6ZT4W2e +O1whVU2KB0aBYskhClimapM5ypRkcNQ97cUR6/iNgdgSLqxGHCGeMR9bEyLl7/wr +M0XeDjdVfm/Tj548oHgb0SKLsfL6nnKwqB2viKj81moK9A/wO1Ec9RNaw0jtp2j3 +VIUnPj0GqEjnkHc2jWY2yt4SD6e2AZHwLyWi1q3pixZo1CFiEgFXxwNyYwyeJ6jV +CJHPRzoNjZ8dkvgRjsXdnWwN316JBNVcH8k7CCmg/8Gq3yAojXG1z8VJZ06GHckd +meCL1t89OgwIAmIsysKu7+DrKtSlhkQclZmdG6IrQzuPKaHzTPTDgg3ef3jQ4YQO +-----END RSA PRIVATE KEY----- diff --git a/tests/auto/network/ssl/qsslkey/rsa-with-passphrase-aes192.pem b/tests/auto/network/ssl/qsslkey/rsa-with-passphrase-aes192.pem new file mode 100644 index 0000000000..db74877a5a --- /dev/null +++ b/tests/auto/network/ssl/qsslkey/rsa-with-passphrase-aes192.pem @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-192-CBC,B408346ADE790F8CF0C902A4F0712B34 + +SwzPBGxmwW2JddOyug1LrWjlZn8siSp5yezjK1x/z2+J2r/vvH8OjGnA387tFtae +WVTmhT1ixQXMDI1UJuKx0gzrG2449c+BUVe2VXFPLZ2ocSgoXbBpVkfhEqtLAn91 +MSOpQMxvobQKltKhxgXGvuBJwhwfT7yK5HamohFGbxLUh4Dh+NBXwoYH4Qt+kM7C +kV8VIKvkr/QAL/SRxNoY8rVResPgYvUjdtiGSNZ6CZhNRu42Q2FqbH817cE0NDsN +il/xvWu4T/6VY1KpwMad/v6BhO45EeKz7YjbF/3Y5jj2JV9r45uf79lM9htMBw0d +L+Cc3YHeFffgU8NZo0+iUoroXcb7mjWNmgYksbkaZPbLG383YXAXwbkQS7zDMVIx +QhXn9w+78hNmEV/7PQ8mGXHEFwnfSR05phXoj8IyL5v0grRMA2dsjfxCgfQjH+kc +Miwr5pD/Flw175OpPFCb2qladdTKoIWiVShspbteoRC0EuiWHzkl5z6Tneyb/sam +yduLmSYD+RA6OBgUPY95Xm4AowlFFsuV/fxYZ53rFf4cZn9Z6VBVmvIEmapV7CtB +JzyIVclocwM0ag5u/esdEt/jndJq9chZlIsDS30y3gP6Rlqk5mj90DAs98l28FVG +WY9jP0babk8mxjYCcnAy7ikUc0D+vJVO6OTmfO3dkGjLpMBM6OlvfhN/0qeXrMDI +nU2qOshUrVna2kRe6FrcvosFTD8wvQ1/BjmCp1iWWsGdc/q1BqI3pgOlgq3TYfl6 +iUJoji3V2iexH+GPkHsrs+kii1clsO2tgIP7doIooSVkcTsRTHHxKeeHn3qL2028 +pTvieIFD/T4biLZ9Q8sX3XWiHNmXZlCx8lX8MDjTavWES8gY4H5Sr6FjRMy1qpZY +5w1aAyJ9YZ0J/jLPmFxt8mWgqHPiPlrQkryBBE3l1MSQ/hCEwlf9dP8a+ayINfd7 +3yNkHKjZ5fuoA+TZUQb/fyVM5o1zJ8ML01PaXWrMEgr3b36QL+Ivo2Rpnp9FpwuH +E405cwCEy5fNSyhHFqqatCbsPl80nkP8OpW6jdWvNy9u0Ap9PS+MbHGq/pfkaazl +fbKGOckrENzEXi6Uj/yY/0sMtbTJuC70n09X3edHyhl/RJPPUoNnwDM5W1FHfS3r +qqSOl/r3y5pEErRdBpR4wEgB7DCLBALGDPfXNAAga4ez/Z2X9Zj234+4ZbUzWoLN +1ER0QYyxLN7oz1qMA15J7nRyRIhDXNlXjyISOqy26T6/d4X0M+6RhNWfT/MHAjJ8 +6ogoGlQUITV3gPO4R6+FGZMF4R6zZXuKVtOXyzRwWnCLfo4gzBHmq+5mmCjGWRq8 +rSSkc6334bYuZOaEoR5EM5sh6ewkjSDPRrKR7EHO02YbiscyT/99TwT5pdIOPK3u +2T6/40fSmCWQyBLuWxV9CMD+rB/q8Ja5KisEseck7PgI2pMmHfiD5yQXhKR9eDrB +sRqZxjgRYxup+/0CIBshL8s1R88xelhXyIKyqFfVudM09yAZxEJLQhpDZ27g45ea +FMX2Ve+ah2NjYBgzAhwKouWg5RyWb6X99NsrCEU75fn/ek86LGs3FxRgB4Uv7Udv +-----END RSA PRIVATE KEY----- diff --git a/tests/auto/network/ssl/qsslkey/rsa-with-passphrase-aes256.pem b/tests/auto/network/ssl/qsslkey/rsa-with-passphrase-aes256.pem new file mode 100644 index 0000000000..3d96b3166e --- /dev/null +++ b/tests/auto/network/ssl/qsslkey/rsa-with-passphrase-aes256.pem @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-256-CBC,0F2F4695C8FFA35F4076FA0273A3A4E3 + +GCnMcAhhGuNkJ7SSMBrgNOaDfRtG22J0mdf/0VbrMOJF40P13YBjN3Kd6LpTqBya +TCIaxQqtfjH1ffhJk8qhwG7uJFGgcY9i0dkrEYklgThzTVqHp7FsQ2jjgJs5HKpc +euuVD1bxtuc9qI2hq4miA7Z/uDe3M34n+3xcpqccWS1dLFNFZ+fIDwIazfDCu3ah +fUQHDeWLwOqYiQxhUjjrHpZkI1FE2JYZFaf4zIagIIgzI2O+33fgbrTSoeN5meRs +F7V2fhDpyEoIlchwAmp6HE6ngtKP4Ecju00yn99AO42fn097yEVwvGFClQTaIzur +aPEtuKZ4kdc/lmzL2tqNcZckq28ZxpeMq0Fgdcpeg5sDcut811scOjQLFs551On1 +j3E1WfiLoBLKgd9cgmCrZb8hMO+UjcCaV7Jv3T9vDrbvhWs/YhTTwo8UFVplh7Vx +R1h3cKfzlbtOC5WHXGNK5dBu7SnpEk0+pscY5cxTrzN0odjMbbsjZQmKDZXbmZON +USzG3Qtafm6Nw/jwQeIjeqaxSho6xGdadTteGaURw6iGio3h0c6/dHayCsxye4tk +vODa0ZdJASwVh1605qDk9n/iYUT5B46KJCYwO/iN2kUmOcUcZeBqEfV1GfRmepZJ +bwM4sipzE15hOJ5DKSkHWnSlByRMAdSrMxZWraKUczn5frEBAqEFLlBAvf/FnjWa +yZJitgryCI2Y2bww1DEMnTCX345kUQIFmmjbzTIXnM28gW+fR3Br9dCf2FAsLNKr +tru1cYXocPaCUHEqS+XZqVb6BQVQ11YAAde0+x9RknJgsBc9Y7TLobaDBvrV5/nK +T3vm8el08upum6qPTPh6Z0zBbjx4sp6DYT977N1dYeH4n+0JqcSwIeZg/VAdG0RL +GzgZVADpiRlStmy65W95KExBjbO0tRTVk/nB1U1nfLbsswp9EKxXgwtpE/ECeTOi +hzeJBSsXGZ/ZXu/y+NlIu0B/GasFbfrHKslSSrUPTjGEtaEbLNiOEu2Etu3lRcMZ +oDtMxgNR0TUgCS5nte8lLauYYfB6IuxZXpvJdcI5ushqdOJvvYgJ9Yb2ZPlY8Bt5 +C92Ga69aPcMYk24BPpe15eBbXMsFF8RF+CprVoUPCc+PcuROtxdt+rqoqjQeZPmV +WQqq+pT2bychpwD7U5jxQnu4u2m+zeBXyk80euBbwEld9BCgfk9mFj6CdBJSEiGV +qL0ivxd3mDaIKPGd5tcbrOMK2uD7duZY7FrQpAYgryoQJoUHccL7cr9fDC75akHg +AbrG1+vAYEla/y+SlOg5VTHhiuIl17ZGMViXSqh7iqnnD0dNsZ/HDvk3XouhNxQy +RQmfdqyIqLuAcfWwQxCQ2E/oMUIHjNhyYmfLVLVGsfxuevMa1eJv7rZ5vIkD2Vpe +4VveZkNDSpCCNqnvub8+bMW+UXyzbxEZbK5PLkRp7cvtKdA5CUbTlT4060IV0YZ1 +vfMtzXRw8JDD9c1F1WF14afk+y9kvZN88XOH12bSKj+Re06Xx7OzuYU8fclq/pZB +UZVtRETFnLgb8neMuz3vCoPWK/DSHDZGAAicxq7vTljyoU/QP71Dw7UJIAuYx6Mc +-----END RSA PRIVATE KEY----- diff --git a/tests/auto/network/ssl/qsslkey/tst_qsslkey.cpp b/tests/auto/network/ssl/qsslkey/tst_qsslkey.cpp index 28476fce5b..f94756ed73 100644 --- a/tests/auto/network/ssl/qsslkey/tst_qsslkey.cpp +++ b/tests/auto/network/ssl/qsslkey/tst_qsslkey.cpp @@ -30,6 +30,7 @@ #include <QtTest/QtTest> #include <qsslkey.h> #include <qsslsocket.h> +#include <QScopeGuard> #include <QtNetwork/qhostaddress.h> #include <QtNetwork/qnetworkproxy.h> @@ -233,15 +234,50 @@ void tst_QSslKey::constructorHandle() QByteArray passphrase; if (QByteArray(QTest::currentDataTag()).contains("-pkcs8-")) passphrase = "1234"; + BIO* bio = q_BIO_new(q_BIO_s_mem()); q_BIO_write(bio, pem.constData(), pem.length()); - QSslKey key(func(bio, nullptr, nullptr, static_cast<void *>(passphrase.data())), type); + EVP_PKEY *origin = func(bio, nullptr, nullptr, static_cast<void *>(passphrase.data())); +#if QT_CONFIG(opensslv11) + q_EVP_PKEY_up_ref(origin); +#endif + QSslKey key(origin, type); +#if !QT_CONFIG(opensslv11) + q_BIO_write(bio, pem.constData(), pem.length()); + origin = func(bio, nullptr, nullptr, static_cast<void *>(passphrase.data())); +#endif q_BIO_free(bio); + EVP_PKEY *handle = q_EVP_PKEY_new(); + switch (algorithm) { + case QSsl::Rsa: + q_EVP_PKEY_set1_RSA(handle, static_cast<RSA *>(key.handle())); + break; + case QSsl::Dsa: + q_EVP_PKEY_set1_DSA(handle, static_cast<DSA *>(key.handle())); + break; + case QSsl::Dh: + q_EVP_PKEY_set1_DH(handle, static_cast<DH *>(key.handle())); + break; +#ifndef OPENSSL_NO_EC + case QSsl::Ec: + q_EVP_PKEY_set1_EC_KEY(handle, static_cast<EC_KEY *>(key.handle())); + break; +#endif + default: + break; + } + + auto cleanup = qScopeGuard([origin, handle] { + q_EVP_PKEY_free(origin); + q_EVP_PKEY_free(handle); + }); + QVERIFY(!key.isNull()); QCOMPARE(key.algorithm(), algorithm); QCOMPARE(key.type(), type); QCOMPARE(key.length(), length); + QCOMPARE(q_EVP_PKEY_cmp(origin, handle), 1); #endif } @@ -430,15 +466,25 @@ void tst_QSslKey::toEncryptedPemOrDer() void tst_QSslKey::passphraseChecks_data() { QTest::addColumn<QString>("fileName"); - - QTest::newRow("DES") << (testDataDir + "rsa-with-passphrase-des.pem"); - QTest::newRow("3DES") << (testDataDir + "rsa-with-passphrase-3des.pem"); - QTest::newRow("RC2") << (testDataDir + "rsa-with-passphrase-rc2.pem"); + QTest::addColumn<QByteArray>("passphrase"); + + const QByteArray pass("123"); + const QByteArray aesPass("1234"); + + QTest::newRow("DES") << QString(testDataDir + "rsa-with-passphrase-des.pem") << pass; + QTest::newRow("3DES") << QString(testDataDir + "rsa-with-passphrase-3des.pem") << pass; + QTest::newRow("RC2") << QString(testDataDir + "rsa-with-passphrase-rc2.pem") << pass; +#if (!defined(QT_NO_OPENSSL) && !defined(OPENSSL_NO_AES)) || (defined(QT_NO_OPENSSL) && QT_CONFIG(ssl)) + QTest::newRow("AES128") << QString(testDataDir + "rsa-with-passphrase-aes128.pem") << aesPass; + QTest::newRow("AES192") << QString(testDataDir + "rsa-with-passphrase-aes192.pem") << aesPass; + QTest::newRow("AES256") << QString(testDataDir + "rsa-with-passphrase-aes256.pem") << aesPass; +#endif // (OpenSSL && AES) || generic backend } void tst_QSslKey::passphraseChecks() { QFETCH(QString, fileName); + QFETCH(QByteArray, passphrase); QFile keyFile(fileName); QVERIFY(keyFile.exists()); @@ -471,7 +517,7 @@ void tst_QSslKey::passphraseChecks() keyFile.open(QIODevice::ReadOnly); else keyFile.reset(); - QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "123"); + QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, passphrase); QVERIFY(!key.isNull()); // correct passphrase } } @@ -516,79 +562,135 @@ void tst_QSslKey::encrypt_data() QTest::addColumn<QByteArray>("key"); QTest::addColumn<QByteArray>("plainText"); QTest::addColumn<QByteArray>("cipherText"); + QTest::addColumn<QByteArray>("iv"); + QByteArray iv("abcdefgh"); QTest::newRow("DES-CBC, length 0") << QSslKeyPrivate::DesCbc << QByteArray("01234567") << QByteArray() - << QByteArray::fromHex("956585228BAF9B1F"); + << QByteArray::fromHex("956585228BAF9B1F") + << iv; QTest::newRow("DES-CBC, length 1") << QSslKeyPrivate::DesCbc << QByteArray("01234567") << QByteArray(1, 'a') - << QByteArray::fromHex("E6880AF202BA3C12"); + << QByteArray::fromHex("E6880AF202BA3C12") + << iv; QTest::newRow("DES-CBC, length 2") << QSslKeyPrivate::DesCbc << QByteArray("01234567") << QByteArray(2, 'a') - << QByteArray::fromHex("A82492386EED6026"); + << QByteArray::fromHex("A82492386EED6026") + << iv; QTest::newRow("DES-CBC, length 3") << QSslKeyPrivate::DesCbc << QByteArray("01234567") << QByteArray(3, 'a') - << QByteArray::fromHex("90B76D5B79519CBA"); + << QByteArray::fromHex("90B76D5B79519CBA") + << iv; QTest::newRow("DES-CBC, length 4") << QSslKeyPrivate::DesCbc << QByteArray("01234567") << QByteArray(4, 'a') - << QByteArray::fromHex("63E3DD6FED87052A"); + << QByteArray::fromHex("63E3DD6FED87052A") + << iv; QTest::newRow("DES-CBC, length 5") << QSslKeyPrivate::DesCbc << QByteArray("01234567") << QByteArray(5, 'a') - << QByteArray::fromHex("03ACDB0EACBDFA94"); + << QByteArray::fromHex("03ACDB0EACBDFA94") + << iv; QTest::newRow("DES-CBC, length 6") << QSslKeyPrivate::DesCbc << QByteArray("01234567") << QByteArray(6, 'a') - << QByteArray::fromHex("7D95024E42A3A88A"); + << QByteArray::fromHex("7D95024E42A3A88A") + << iv; QTest::newRow("DES-CBC, length 7") << QSslKeyPrivate::DesCbc << QByteArray("01234567") << QByteArray(7, 'a') - << QByteArray::fromHex("5003436B8A8E42E9"); + << QByteArray::fromHex("5003436B8A8E42E9") + << iv; QTest::newRow("DES-CBC, length 8") << QSslKeyPrivate::DesCbc << QByteArray("01234567") << QByteArray(8, 'a') - << QByteArray::fromHex("E4C1F054BF5521C0A4A0FD4A2BC6C1B1"); + << QByteArray::fromHex("E4C1F054BF5521C0A4A0FD4A2BC6C1B1") + << iv; QTest::newRow("DES-EDE3-CBC, length 0") << QSslKeyPrivate::DesEde3Cbc << QByteArray("0123456789abcdefghijklmn") << QByteArray() - << QByteArray::fromHex("3B2B4CD0B0FD495F"); + << QByteArray::fromHex("3B2B4CD0B0FD495F") + << iv; QTest::newRow("DES-EDE3-CBC, length 8") << QSslKeyPrivate::DesEde3Cbc << QByteArray("0123456789abcdefghijklmn") << QByteArray(8, 'a') - << QByteArray::fromHex("F2A5A87763C54A72A3224103D90CDB03"); + << QByteArray::fromHex("F2A5A87763C54A72A3224103D90CDB03") + << iv; QTest::newRow("RC2-40-CBC, length 0") << QSslKeyPrivate::Rc2Cbc << QByteArray("01234") << QByteArray() - << QByteArray::fromHex("6D05D52392FF6E7A"); + << QByteArray::fromHex("6D05D52392FF6E7A") + << iv; QTest::newRow("RC2-40-CBC, length 8") << QSslKeyPrivate::Rc2Cbc << QByteArray("01234") << QByteArray(8, 'a') - << QByteArray::fromHex("75768E64C5749072A5D168F3AFEB0005"); + << QByteArray::fromHex("75768E64C5749072A5D168F3AFEB0005") + << iv; QTest::newRow("RC2-64-CBC, length 0") << QSslKeyPrivate::Rc2Cbc << QByteArray("01234567") << QByteArray() - << QByteArray::fromHex("ADAE6BF70F420130"); + << QByteArray::fromHex("ADAE6BF70F420130") + << iv; QTest::newRow("RC2-64-CBC, length 8") << QSslKeyPrivate::Rc2Cbc << QByteArray("01234567") << QByteArray(8, 'a') - << QByteArray::fromHex("C7BF5C80AFBE9FBEFBBB9FD935F6D0DF"); + << QByteArray::fromHex("C7BF5C80AFBE9FBEFBBB9FD935F6D0DF") + << iv; QTest::newRow("RC2-128-CBC, length 0") << QSslKeyPrivate::Rc2Cbc << QByteArray("012345679abcdefg") << QByteArray() - << QByteArray::fromHex("1E965D483A13C8FB"); + << QByteArray::fromHex("1E965D483A13C8FB") + << iv; QTest::newRow("RC2-128-CBC, length 8") << QSslKeyPrivate::Rc2Cbc << QByteArray("012345679abcdefg") << QByteArray(8, 'a') - << QByteArray::fromHex("5AEC1A5B295660B02613454232F7DECE"); + << QByteArray::fromHex("5AEC1A5B295660B02613454232F7DECE") + << iv; + +#if (!defined(QT_NO_OPENSSL) && !defined(OPENSSL_NO_AES)) || (defined(QT_NO_OPENSSL) && QT_CONFIG(ssl)) + // AES needs a longer IV + iv = QByteArray("abcdefghijklmnop"); + QTest::newRow("AES-128-CBC, length 0") + << QSslKeyPrivate::Aes128Cbc << QByteArray("012345679abcdefg") + << QByteArray() + << QByteArray::fromHex("28DE1A9AA26601C30DD2527407121D1A") + << iv; + QTest::newRow("AES-128-CBC, length 8") + << QSslKeyPrivate::Aes128Cbc << QByteArray("012345679abcdefg") + << QByteArray(8, 'a') + << QByteArray::fromHex("08E880B1BA916F061C1E801D7F44D0EC") + << iv; + + QTest::newRow("AES-192-CBC, length 0") + << QSslKeyPrivate::Aes192Cbc << QByteArray("0123456789abcdefghijklmn") + << QByteArray() + << QByteArray::fromHex("E169E0E205CDC2BA895B7CF6097673B1") + << iv; + QTest::newRow("AES-192-CBC, length 8") + << QSslKeyPrivate::Aes192Cbc << QByteArray("0123456789abcdefghijklmn") + << QByteArray(8, 'a') + << QByteArray::fromHex("3A227D6A3A13237316D30AA17FF9B0A7") + << iv; + + QTest::newRow("AES-256-CBC, length 0") + << QSslKeyPrivate::Aes256Cbc << QByteArray("0123456789abcdefghijklmnopqrstuv") + << QByteArray() + << QByteArray::fromHex("4BAACAA0D22199C97DE206C465B7B14A") + << iv; + QTest::newRow("AES-256-CBC, length 8") + << QSslKeyPrivate::Aes256Cbc << QByteArray("0123456789abcdefghijklmnopqrstuv") + << QByteArray(8, 'a') + << QByteArray::fromHex("879C8C25EC135CDF0B14490A0A7C2F67") + << iv; +#endif // (OpenSSL && AES) || generic backend } void tst_QSslKey::encrypt() @@ -597,7 +699,7 @@ void tst_QSslKey::encrypt() QFETCH(QByteArray, key); QFETCH(QByteArray, plainText); QFETCH(QByteArray, cipherText); - QByteArray iv("abcdefgh"); + QFETCH(QByteArray, iv); #if defined(Q_OS_WINRT) || QT_CONFIG(schannel) QEXPECT_FAIL("RC2-40-CBC, length 0", "WinRT/Schannel treats RC2 as 128-bit", Abort); diff --git a/tests/auto/network/ssl/qsslsocket/BLACKLIST b/tests/auto/network/ssl/qsslsocket/BLACKLIST index 555822d1e6..7b4a29f463 100644 --- a/tests/auto/network/ssl/qsslsocket/BLACKLIST +++ b/tests/auto/network/ssl/qsslsocket/BLACKLIST @@ -1,7 +1,11 @@ +[deprecatedProtocols] windows +[spontaneousWrite] +windows-7sp1 [connectToHostEncrypted] osx-10.13 [setSslConfiguration] -osx-10.13 +windows-10 msvc-2015 +windows-7sp1 [connectToHostEncryptedWithVerificationPeerName] osx-10.13 diff --git a/tests/auto/network/ssl/qsslsocket/certs/qt-test-server-cert.pem b/tests/auto/network/ssl/qsslsocket/certs/qt-test-server-cert.pem new file mode 100644 index 0000000000..43c8794ce2 --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket/certs/qt-test-server-cert.pem @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIIClTCCAf4CCQC2xMhNhwvATDANBgkqhkiG9w0BAQQFADCBjjELMAkGA1UEChMC +UXQxGTAXBgNVBAsTEENvcmUgQW5kIE5ldHdvcmsxGzAZBgkqhkiG9w0BCQEWDG5v +Ym9keS5xdC5pbzENMAsGA1UEBxMET3NsbzENMAsGA1UECBMET3NsbzELMAkGA1UE +BhMCTk8xHDAaBgNVBAMUEyoudGVzdC1uZXQucXQubG9jYWwwHhcNMTgwNzAxMTgz +NjI3WhcNNDgwNjIzMTgzNjI3WjCBjjELMAkGA1UEChMCUXQxGTAXBgNVBAsTEENv +cmUgQW5kIE5ldHdvcmsxGzAZBgkqhkiG9w0BCQEWDG5vYm9keS5xdC5pbzENMAsG +A1UEBxMET3NsbzENMAsGA1UECBMET3NsbzELMAkGA1UEBhMCTk8xHDAaBgNVBAMU +EyoudGVzdC1uZXQucXQubG9jYWwwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGB +AM2q22/WNMmn8cC+5EEYGeICySLmp9W6Ay6eKHr0Xxp3X3epETuPfvAuxp7rOtkS +18EMUegkUj8jw0IMEcbyHKFC/rTCaYOt93CxGBXMIChiMPAsFeYzGa/D6xzAkfcR +aJRQ+Ek3CDLXPnXfo7xpABXezYcPXAJrgsgBfWrwHdxzAgMBAAEwDQYJKoZIhvcN +AQEEBQADgYEAZu/lQPy8PXeyyYGamOVms/FZKJ48BH1y8KC3BeBU5FYnhvgG7pz8 +Wz9JKvt2t/r45wQeAkNL6HnGUBhPJsHMjPHl5KktqN+db3D+FQygBeS2V1+zmC0X +UZNRE4aWiHvt1Lq+pTx89SOMOpfqWfh4qTQKiE5jC2V4DeCNQ3u7uI8= +-----END CERTIFICATE----- diff --git a/tests/auto/network/ssl/qsslsocket/qsslsocket.pro b/tests/auto/network/ssl/qsslsocket/qsslsocket.pro index 1260dc9410..51fcff9a8d 100644 --- a/tests/auto/network/ssl/qsslsocket/qsslsocket.pro +++ b/tests/auto/network/ssl/qsslsocket/qsslsocket.pro @@ -18,3 +18,10 @@ TESTDATA += certs DEFINES += SRCDIR=\\\"$$PWD/\\\" requires(qtConfig(private_tests)) + +# DOCKERTODO: it's 'linux' because it requires cyrus, which +# is linux-only for now ... +linux { + CONFIG += unsupported/testserver + QT_TEST_SERVER_LIST = squid danted cyrus apache2 echo +} diff --git a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp index 66475e55ad..4e02320362 100644 --- a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp +++ b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp @@ -29,6 +29,7 @@ #include <QtCore/qglobal.h> #include <QtCore/qthread.h> +#include <QtCore/qelapsedtimer.h> #include <QtNetwork/qhostaddress.h> #include <QtNetwork/qhostinfo.h> #include <QtNetwork/qnetworkproxy.h> @@ -310,6 +311,21 @@ Q_DECLARE_METATYPE(tst_QSslSocket::PskConnectTestType) int tst_QSslSocket::loopLevel = 0; +namespace { + +QString httpServerCertChainPath() +{ + // DOCKERTODO: note how we use CA certificate on the real server. The docker container + // is using a different cert with a "special" CN. Check if it's important! +#ifdef QT_TEST_SERVER + return tst_QSslSocket::testDataDir + QStringLiteral("certs/qt-test-server-cert.pem"); +#else + return tst_QSslSocket::testDataDir + QStringLiteral("certs/qt-test-server-cacert.pem"); +#endif // QT_TEST_SERVER +} + +} // unnamed namespace + tst_QSslSocket::tst_QSslSocket() { #ifndef QT_NO_SSL @@ -363,8 +379,19 @@ void tst_QSslSocket::initTestCase() qDebug("Using SSL library %s (%ld)", qPrintable(QSslSocket::sslLibraryVersionString()), QSslSocket::sslLibraryVersionNumber()); +#ifdef QT_TEST_SERVER + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::socksProxyServerName(), 1080)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::socksProxyServerName(), 1081)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpProxyServerName(), 3128)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpProxyServerName(), 3129)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpProxyServerName(), 3130)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpServerName(), 443)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::imapServerName(), 993)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::echoServerName(), 13)); +#else QVERIFY(QtNetworkSettings::verifyTestNetworkSettings()); -#endif +#endif // QT_TEST_SERVER +#endif // QT_NO_SSL } void tst_QSslSocket::init() @@ -373,28 +400,29 @@ void tst_QSslSocket::init() if (setProxy) { #ifndef QT_NO_NETWORKPROXY QFETCH_GLOBAL(int, proxyType); - QString fluke = QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first().toString(); + const QString socksProxyAddr = QtNetworkSettings::socksProxyServerIp().toString(); + const QString httpProxyAddr = QtNetworkSettings::httpProxyServerIp().toString(); QNetworkProxy proxy; switch (proxyType) { case Socks5Proxy: - proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, fluke, 1080); + proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, socksProxyAddr, 1080); break; case Socks5Proxy | AuthBasic: - proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, fluke, 1081); + proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, socksProxyAddr, 1081); break; case HttpProxy | NoAuth: - proxy = QNetworkProxy(QNetworkProxy::HttpProxy, fluke, 3128); + proxy = QNetworkProxy(QNetworkProxy::HttpProxy, httpProxyAddr, 3128); break; case HttpProxy | AuthBasic: - proxy = QNetworkProxy(QNetworkProxy::HttpProxy, fluke, 3129); + proxy = QNetworkProxy(QNetworkProxy::HttpProxy, httpProxyAddr, 3129); break; case HttpProxy | AuthNtlm: - proxy = QNetworkProxy(QNetworkProxy::HttpProxy, fluke, 3130); + proxy = QNetworkProxy(QNetworkProxy::HttpProxy, httpProxyAddr, 3130); break; } QNetworkProxy::setApplicationProxy(proxy); @@ -518,6 +546,7 @@ void tst_QSslSocket::constructing() // verify that changing the default config doesn't affect this socket // (on Unix, the ca certs might be empty, depending on whether we load // them on demand or not, so set them explicitly) +#if QT_DEPRECATED_SINCE(5, 5) socket.setCaCertificates(QSslSocket::systemCaCertificates()); QSslSocket::setDefaultCaCertificates(QList<QSslCertificate>()); QSslSocket::setDefaultCiphers(QList<QSslCipher>()); @@ -529,6 +558,25 @@ void tst_QSslSocket::constructing() QVERIFY(QSslConfiguration::defaultConfiguration().ciphers().isEmpty()); QSslConfiguration::setDefaultConfiguration(savedDefault); +#endif + + auto sslConfig = socket.sslConfiguration(); + sslConfig.setCaCertificates(QSslConfiguration::systemCaCertificates()); + socket.setSslConfiguration(sslConfig); + + auto defaultConfig = QSslConfiguration::defaultConfiguration(); + defaultConfig.setCaCertificates(QList<QSslCertificate>()); + defaultConfig.setCiphers(QList<QSslCipher>()); + QSslConfiguration::setDefaultConfiguration(defaultConfig); + + QVERIFY(!socket.sslConfiguration().caCertificates().isEmpty()); + QVERIFY(!socket.sslConfiguration().ciphers().isEmpty()); + + // verify the default as well: + QVERIFY(QSslConfiguration::defaultConfiguration().caCertificates().isEmpty()); + QVERIFY(QSslConfiguration::defaultConfiguration().ciphers().isEmpty()); + + QSslConfiguration::setDefaultConfiguration(savedDefault); } void tst_QSslSocket::simpleConnect() @@ -555,7 +603,7 @@ void tst_QSslSocket::simpleConnect() connect(&socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(exitLoop())); // Start connecting - socket.connectToHost(QtNetworkSettings::serverName(), 993); + socket.connectToHost(QtNetworkSettings::imapServerName(), 993); QCOMPARE(socket.state(), QAbstractSocket::HostLookupState); enterLoop(10); @@ -610,7 +658,7 @@ void tst_QSslSocket::simpleConnectWithIgnore() connect(&socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(exitLoop())); // Start connecting - socket.connectToHost(QtNetworkSettings::serverName(), 993); + socket.connectToHost(QtNetworkSettings::imapServerName(), 993); QVERIFY(socket.state() != QAbstractSocket::UnconnectedState); // something must be in progress enterLoop(10); @@ -642,7 +690,7 @@ void tst_QSslSocket::sslErrors_data() QString name = QtNetworkSettings::serverLocalName(); QTest::newRow(qPrintable(name)) << name << 993; - name = QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first().toString(); + name = QtNetworkSettings::httpServerIp().toString(); QTest::newRow(qPrintable(name)) << name << 443; } @@ -659,7 +707,20 @@ void tst_QSslSocket::sslErrors() QSignalSpy sslErrorsSpy(socket.data(), SIGNAL(sslErrors(QList<QSslError>))); QSignalSpy peerVerifyErrorSpy(socket.data(), SIGNAL(peerVerifyError(QSslError))); - socket->connectToHostEncrypted(host, port); +#ifdef QT_TEST_SERVER + // On the old test server we had the same certificate on different services. + // The idea of this test is to fail with 'HostNameMismatch', when we're using + // either serverLocalName() or IP address directly. With Docker we connect + // to IMAP server, and we have to connect using imapServerName() and passing + // 'host' as peerVerificationName to the overload of connectToHostEncrypted(). + if (port == 993) { + socket->connectToHostEncrypted(QtNetworkSettings::imapServerName(), port, host); + } else +#endif // QT_TEST_SERVER + { + socket->connectToHostEncrypted(host, port); + } + if (!socket->waitForConnected()) QSKIP("Skipping flaky test - See QTBUG-29941"); socket->waitForEncrypted(10000); @@ -670,7 +731,7 @@ void tst_QSslSocket::sslErrors() const auto socketSslErrors = socket->sslErrors(); for (const QSslError &err : socketSslErrors) sslErrors << err.error(); - qSort(sslErrors); + std::sort(sslErrors.begin(), sslErrors.end()); QVERIFY(sslErrors.contains(QSslError::HostNameMismatch)); QVERIFY(sslErrors.contains(FLUKE_CERTIFICATE_ERROR)); @@ -680,7 +741,7 @@ void tst_QSslSocket::sslErrors() const auto sslErrorsSpyErrors = qvariant_cast<QList<QSslError> >(qAsConst(sslErrorsSpy).first().first()); for (const QSslError &err : sslErrorsSpyErrors) emittedErrors << err.error(); - qSort(emittedErrors); + std::sort(emittedErrors.begin(), emittedErrors.end()); QCOMPARE(sslErrors, emittedErrors); // check the same errors were emitted by peerVerifyError @@ -689,7 +750,7 @@ void tst_QSslSocket::sslErrors() const QList<QVariantList> &peerVerifyList = peerVerifyErrorSpy; for (const QVariantList &args : peerVerifyList) peerErrors << qvariant_cast<QSslError>(args.first()).error(); - qSort(peerErrors); + std::sort(peerErrors.begin(), peerErrors.end()); QCOMPARE(sslErrors, peerErrors); } @@ -715,18 +776,41 @@ void tst_QSslSocket::ciphers() { if (!QSslSocket::supportsSsl()) return; - +#if QT_DEPRECATED_SINCE(5, 5) + { + QSslSocket socket; + QCOMPARE(socket.ciphers(), QSslSocket::defaultCiphers()); + socket.setCiphers(QList<QSslCipher>()); + QVERIFY(socket.ciphers().isEmpty()); + socket.setCiphers(socket.defaultCiphers()); + QCOMPARE(socket.ciphers(), QSslSocket::defaultCiphers()); + socket.setCiphers(socket.defaultCiphers()); + QCOMPARE(socket.ciphers(), QSslSocket::defaultCiphers()); + + // Task 164356 + socket.setCiphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"); + } +#endif QSslSocket socket; - QCOMPARE(socket.ciphers(), QSslSocket::defaultCiphers()); - socket.setCiphers(QList<QSslCipher>()); - QVERIFY(socket.ciphers().isEmpty()); - socket.setCiphers(socket.defaultCiphers()); - QCOMPARE(socket.ciphers(), QSslSocket::defaultCiphers()); - socket.setCiphers(socket.defaultCiphers()); - QCOMPARE(socket.ciphers(), QSslSocket::defaultCiphers()); + QCOMPARE(socket.sslConfiguration().ciphers(), QSslConfiguration::defaultConfiguration().ciphers()); + + auto sslConfig = socket.sslConfiguration(); + sslConfig.setCiphers(QList<QSslCipher>()); + socket.setSslConfiguration(sslConfig); + QVERIFY(socket.sslConfiguration().ciphers().isEmpty()); + + sslConfig.setCiphers(QSslConfiguration::defaultConfiguration().ciphers()); + socket.setSslConfiguration(sslConfig); + QCOMPARE(socket.sslConfiguration().ciphers(), QSslConfiguration::defaultConfiguration().ciphers()); + + sslConfig.setCiphers(QSslConfiguration::defaultConfiguration().ciphers()); + socket.setSslConfiguration(sslConfig); + QCOMPARE(socket.sslConfiguration().ciphers(), QSslConfiguration::defaultConfiguration().ciphers()); // Task 164356 - socket.setCiphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"); + sslConfig.setCiphers({QSslCipher("ALL"), QSslCipher("!ADH"), QSslCipher("!LOW"), + QSslCipher("!EXP"), QSslCipher("!MD5"), QSslCipher("@STRENGTH")}); + socket.setSslConfiguration(sslConfig); } void tst_QSslSocket::connectToHostEncrypted() @@ -739,13 +823,13 @@ void tst_QSslSocket::connectToHostEncrypted() socket->setProtocol(QSsl::SslProtocol::TlsV1_1); #endif this->socket = socket.data(); - QVERIFY(socket->addCaCertificates(testDataDir + "certs/qt-test-server-cacert.pem")); + QVERIFY(socket->addCaCertificates(httpServerCertChainPath())); #ifdef QSSLSOCKET_CERTUNTRUSTED_WORKAROUND connect(socket.data(), SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(untrustedWorkaroundSlot(QList<QSslError>))); #endif - socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); // This should pass unconditionally when using fluke's CA certificate. // or use untrusted certificate workaround @@ -758,7 +842,7 @@ void tst_QSslSocket::connectToHostEncrypted() QCOMPARE(socket->mode(), QSslSocket::SslClientMode); - socket->connectToHost(QtNetworkSettings::serverName(), 13); + socket->connectToHost(QtNetworkSettings::echoServerName(), 13); QCOMPARE(socket->mode(), QSslSocket::UnencryptedMode); @@ -776,14 +860,18 @@ void tst_QSslSocket::connectToHostEncryptedWithVerificationPeerName() #endif this->socket = socket.data(); - socket->addCaCertificates(testDataDir + "certs/qt-test-server-cacert.pem"); + socket->addCaCertificates(httpServerCertChainPath()); #ifdef QSSLSOCKET_CERTUNTRUSTED_WORKAROUND connect(socket.data(), SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(untrustedWorkaroundSlot(QList<QSslError>))); #endif - // connect to the server with its local name, but use the full name for verification. - socket->connectToHostEncrypted(QtNetworkSettings::serverLocalName(), 443, QtNetworkSettings::serverName()); +#ifdef QT_TEST_SERVER + socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443, QtNetworkSettings::httpServerName()); +#else + // Connect to the server with its local name, but use the full name for verification. + socket->connectToHostEncrypted(QtNetworkSettings::serverLocalName(), 443, QtNetworkSettings::httpServerName()); +#endif // This should pass unconditionally when using fluke's CA certificate. QFETCH_GLOBAL(bool, setProxy); @@ -805,7 +893,7 @@ void tst_QSslSocket::sessionCipher() this->socket = socket.data(); connect(socket.data(), SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot())); QVERIFY(socket->sessionCipher().isNull()); - socket->connectToHost(QtNetworkSettings::serverName(), 443 /* https */); + socket->connectToHost(QtNetworkSettings::httpServerName(), 443 /* https */); QVERIFY2(socket->waitForConnected(10000), qPrintable(socket->errorString())); QVERIFY(socket->sessionCipher().isNull()); socket->startClientEncryption(); @@ -813,11 +901,14 @@ void tst_QSslSocket::sessionCipher() QSKIP("Skipping flaky test - See QTBUG-29941"); QVERIFY(!socket->sessionCipher().isNull()); - qDebug() << "Supported Ciphers:" << QSslSocket::supportedCiphers(); - qDebug() << "Default Ciphers:" << QSslSocket::defaultCiphers(); + qDebug() << "Supported Ciphers:" << QSslConfiguration::supportedCiphers(); + qDebug() << "Default Ciphers:" << QSslConfiguration::defaultConfiguration().ciphers(); qDebug() << "Session Cipher:" << socket->sessionCipher(); +#if QT_DEPRECATED_SINCE(5, 5) QVERIFY(QSslSocket::supportedCiphers().contains(socket->sessionCipher())); +#endif + QVERIFY(QSslConfiguration::supportedCiphers().contains(socket->sessionCipher())); socket->disconnectFromHost(); QVERIFY(socket->waitForDisconnected()); } @@ -840,12 +931,16 @@ void tst_QSslSocket::localCertificate() // values. This test should just run the codepath inside qsslsocket_openssl.cpp QSslSocketPtr socket = newSocket(); - QList<QSslCertificate> localCert = QSslCertificate::fromPath(testDataDir + "certs/qt-test-server-cacert.pem"); - socket->setCaCertificates(localCert); + QList<QSslCertificate> localCert = QSslCertificate::fromPath(httpServerCertChainPath()); + + auto sslConfig = socket->sslConfiguration(); + sslConfig.setCaCertificates(localCert); + socket->setSslConfiguration(sslConfig); + socket->setLocalCertificate(testDataDir + "certs/fluke.cert"); socket->setPrivateKey(testDataDir + "certs/fluke.key"); - socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); QFETCH_GLOBAL(bool, setProxy); if (setProxy && !socket->waitForEncrypted(10000)) QSKIP("Skipping flaky test - See QTBUG-29941"); @@ -868,8 +963,7 @@ void tst_QSslSocket::peerCertificateChain() QSslSocketPtr socket = newSocket(); this->socket = socket.data(); - - QList<QSslCertificate> caCertificates = QSslCertificate::fromPath(testDataDir + "certs/qt-test-server-cacert.pem"); + QList<QSslCertificate> caCertificates = QSslCertificate::fromPath(httpServerCertChainPath()); QCOMPARE(caCertificates.count(), 1); socket->addCaCertificates(caCertificates); #ifdef QSSLSOCKET_CERTUNTRUSTED_WORKAROUND @@ -877,7 +971,7 @@ void tst_QSslSocket::peerCertificateChain() this, SLOT(untrustedWorkaroundSlot(QList<QSslError>))); #endif - socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); QCOMPARE(socket->mode(), QSslSocket::UnencryptedMode); QVERIFY(socket->peerCertificateChain().isEmpty()); QFETCH_GLOBAL(bool, setProxy); @@ -906,7 +1000,7 @@ void tst_QSslSocket::peerCertificateChain() QVERIFY(socket->waitForDisconnected()); // now do it again back to the original server - socket->connectToHost(QtNetworkSettings::serverName(), 443); + socket->connectToHost(QtNetworkSettings::httpServerName(), 443); QCOMPARE(socket->mode(), QSslSocket::UnencryptedMode); QVERIFY(socket->peerCertificateChain().isEmpty()); QVERIFY2(socket->waitForConnected(10000), qPrintable(socket->errorString())); @@ -945,13 +1039,17 @@ void tst_QSslSocket::privateKeyOpaque() // values. This test should just run the codepath inside qsslsocket_openssl.cpp QSslSocketPtr socket = newSocket(); - QList<QSslCertificate> localCert = QSslCertificate::fromPath(testDataDir + "certs/qt-test-server-cacert.pem"); - socket->setCaCertificates(localCert); + QList<QSslCertificate> localCert = QSslCertificate::fromPath(httpServerCertChainPath()); + + auto sslConfig = socket->sslConfiguration(); + sslConfig.setCaCertificates(localCert); + socket->setSslConfiguration(sslConfig); + socket->setLocalCertificate(testDataDir + "certs/fluke.cert"); socket->setPrivateKey(QSslKey(reinterpret_cast<Qt::HANDLE>(pkey))); socket->setPeerVerifyMode(QSslSocket::QueryPeer); - socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); QFETCH_GLOBAL(bool, setProxy); if (setProxy && !socket->waitForEncrypted(10000)) QSKIP("Skipping flaky test - See QTBUG-29941"); @@ -965,9 +1063,12 @@ void tst_QSslSocket::protocol() QSslSocketPtr socket = newSocket(); this->socket = socket.data(); - QList<QSslCertificate> certs = QSslCertificate::fromPath(testDataDir + "certs/qt-test-server-cacert.pem"); + QList<QSslCertificate> certs = QSslCertificate::fromPath(httpServerCertChainPath()); + + auto sslConfig = socket->sslConfiguration(); + sslConfig.setCaCertificates(certs); + socket->setSslConfiguration(sslConfig); - socket->setCaCertificates(certs); #ifdef QSSLSOCKET_CERTUNTRUSTED_WORKAROUND connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(untrustedWorkaroundSlot(QList<QSslError>))); @@ -979,13 +1080,13 @@ void tst_QSslSocket::protocol() // qt-test-server allows TLSV1. socket->setProtocol(QSsl::TlsV1_0); QCOMPARE(socket->protocol(), QSsl::TlsV1_0); - socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); if (setProxy && !socket->waitForEncrypted()) QSKIP("Skipping flaky test - See QTBUG-29941"); QCOMPARE(socket->protocol(), QSsl::TlsV1_0); socket->abort(); QCOMPARE(socket->protocol(), QSsl::TlsV1_0); - socket->connectToHost(QtNetworkSettings::serverName(), 443); + socket->connectToHost(QtNetworkSettings::httpServerName(), 443); QVERIFY2(socket->waitForConnected(), qPrintable(socket->errorString())); socket->startClientEncryption(); if (setProxy && !socket->waitForEncrypted()) @@ -998,13 +1099,13 @@ void tst_QSslSocket::protocol() // qt-test-server probably doesn't allow TLSV1.1 socket->setProtocol(QSsl::TlsV1_1); QCOMPARE(socket->protocol(), QSsl::TlsV1_1); - socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); if (setProxy && !socket->waitForEncrypted()) QSKIP("Skipping flaky test - See QTBUG-29941"); QCOMPARE(socket->protocol(), QSsl::TlsV1_1); socket->abort(); QCOMPARE(socket->protocol(), QSsl::TlsV1_1); - socket->connectToHost(QtNetworkSettings::serverName(), 443); + socket->connectToHost(QtNetworkSettings::httpServerName(), 443); QVERIFY2(socket->waitForConnected(), qPrintable(socket->errorString())); socket->startClientEncryption(); if (setProxy && !socket->waitForEncrypted()) @@ -1016,13 +1117,13 @@ void tst_QSslSocket::protocol() // qt-test-server probably doesn't allows TLSV1.2 socket->setProtocol(QSsl::TlsV1_2); QCOMPARE(socket->protocol(), QSsl::TlsV1_2); - socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); if (setProxy && !socket->waitForEncrypted()) QSKIP("Skipping flaky test - See QTBUG-29941"); QCOMPARE(socket->protocol(), QSsl::TlsV1_2); socket->abort(); QCOMPARE(socket->protocol(), QSsl::TlsV1_2); - socket->connectToHost(QtNetworkSettings::serverName(), 443); + socket->connectToHost(QtNetworkSettings::httpServerName(), 443); QVERIFY2(socket->waitForConnected(), qPrintable(socket->errorString())); socket->startClientEncryption(); if (setProxy && !socket->waitForEncrypted()) @@ -1036,13 +1137,13 @@ void tst_QSslSocket::protocol() // qt-test-server probably doesn't allow TLSV1.3 socket->setProtocol(QSsl::TlsV1_3); QCOMPARE(socket->protocol(), QSsl::TlsV1_3); - socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); if (setProxy && !socket->waitForEncrypted()) QSKIP("TLS 1.3 is not supported by the test server or the test is flaky - see QTBUG-29941"); QCOMPARE(socket->protocol(), QSsl::TlsV1_3); socket->abort(); QCOMPARE(socket->protocol(), QSsl::TlsV1_3); - socket->connectToHost(QtNetworkSettings::serverName(), 443); + socket->connectToHost(QtNetworkSettings::httpServerName(), 443); QVERIFY2(socket->waitForConnected(), qPrintable(socket->errorString())); socket->startClientEncryption(); if (setProxy && !socket->waitForEncrypted()) @@ -1055,13 +1156,13 @@ void tst_QSslSocket::protocol() // qt-test-server allows SSLV3, so it allows AnyProtocol. socket->setProtocol(QSsl::AnyProtocol); QCOMPARE(socket->protocol(), QSsl::AnyProtocol); - socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); if (setProxy && !socket->waitForEncrypted()) QSKIP("Skipping flaky test - See QTBUG-29941"); QCOMPARE(socket->protocol(), QSsl::AnyProtocol); socket->abort(); QCOMPARE(socket->protocol(), QSsl::AnyProtocol); - socket->connectToHost(QtNetworkSettings::serverName(), 443); + socket->connectToHost(QtNetworkSettings::httpServerName(), 443); QVERIFY2(socket->waitForConnected(), qPrintable(socket->errorString())); socket->startClientEncryption(); if (setProxy && !socket->waitForEncrypted()) @@ -1073,13 +1174,13 @@ void tst_QSslSocket::protocol() // qt-test-server allows TlsV1, so it allows TlsV1SslV3 socket->setProtocol(QSsl::TlsV1SslV3); QCOMPARE(socket->protocol(), QSsl::TlsV1SslV3); - socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); if (setProxy && !socket->waitForEncrypted()) QSKIP("Skipping flaky test - See QTBUG-29941"); QCOMPARE(socket->protocol(), QSsl::TlsV1SslV3); socket->abort(); QCOMPARE(socket->protocol(), QSsl::TlsV1SslV3); - socket->connectToHost(QtNetworkSettings::serverName(), 443); + socket->connectToHost(QtNetworkSettings::httpServerName(), 443); if (setProxy && !socket->waitForConnected()) QSKIP("Skipping flaky test - See QTBUG-29941"); socket->startClientEncryption(); @@ -1115,7 +1216,7 @@ public: QString m_keyFile; QString m_certFile; QString m_interFile; - QString ciphers; + QList<QSslCipher> ciphers; signals: void socketError(QAbstractSocket::SocketError); @@ -1165,7 +1266,9 @@ protected: } if (!ciphers.isEmpty()) { - socket->setCiphers(ciphers); + auto sslConfig = socket->sslConfiguration(); + sslConfig.setCiphers(ciphers); + socket->setSslConfiguration(sslConfig); } QVERIFY(socket->setSocketDescriptor(socketDescriptor, QAbstractSocket::ConnectedState)); @@ -1315,7 +1418,7 @@ void tst_QSslSocket::serverCipherPreferences() // First using the default (server preference) { SslServer server; - server.ciphers = QString("AES128-SHA:AES256-SHA"); + server.ciphers = {QSslCipher("AES128-SHA"), QSslCipher("AES256-SHA")}; QVERIFY(server.listen()); QEventLoop loop; @@ -1323,7 +1426,10 @@ void tst_QSslSocket::serverCipherPreferences() QSslSocket client; socket = &client; - socket->setCiphers("AES256-SHA:AES128-SHA"); + + auto sslConfig = socket->sslConfiguration(); + sslConfig.setCiphers({QSslCipher("AES256-SHA"), QSslCipher("AES128-SHA")}); + socket->setSslConfiguration(sslConfig); // upon SSL wrong version error, error will be triggered, not sslErrors connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), &loop, SLOT(quit())); @@ -1344,7 +1450,7 @@ void tst_QSslSocket::serverCipherPreferences() QSslConfiguration config = QSslConfiguration::defaultConfiguration(); config.setSslOption(QSsl::SslOptionDisableServerCipherPreference, true); server.config = config; - server.ciphers = QString("AES128-SHA:AES256-SHA"); + server.ciphers = {QSslCipher("AES128-SHA"), QSslCipher("AES256-SHA")}; QVERIFY(server.listen()); QEventLoop loop; @@ -1352,7 +1458,10 @@ void tst_QSslSocket::serverCipherPreferences() QSslSocket client; socket = &client; - socket->setCiphers("AES256-SHA:AES128-SHA"); + + auto sslConfig = socket->sslConfiguration(); + sslConfig.setCiphers({QSslCipher("AES256-SHA"), QSslCipher("AES128-SHA")}); + socket->setSslConfiguration(sslConfig); // upon SSL wrong version error, error will be triggered, not sslErrors connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), &loop, SLOT(quit())); @@ -1376,12 +1485,30 @@ void tst_QSslSocket::setCaCertificates() if (!QSslSocket::supportsSsl()) return; +#if QT_DEPRECATED_SINCE(5, 5) + { + QSslSocket socket; + QCOMPARE(socket.caCertificates(), QSslSocket::defaultCaCertificates()); + socket.setCaCertificates(QSslCertificate::fromPath(testDataDir + "certs/qt-test-server-cacert.pem")); + QCOMPARE(socket.caCertificates().size(), 1); + socket.setCaCertificates(socket.defaultCaCertificates()); + QCOMPARE(socket.caCertificates(), QSslSocket::defaultCaCertificates()); + } +#endif QSslSocket socket; - QCOMPARE(socket.caCertificates(), QSslSocket::defaultCaCertificates()); - socket.setCaCertificates(QSslCertificate::fromPath(testDataDir + "certs/qt-test-server-cacert.pem")); - QCOMPARE(socket.caCertificates().size(), 1); - socket.setCaCertificates(socket.defaultCaCertificates()); - QCOMPARE(socket.caCertificates(), QSslSocket::defaultCaCertificates()); + QCOMPARE(socket.sslConfiguration().caCertificates(), + QSslConfiguration::defaultConfiguration().caCertificates()); + + auto sslConfig = socket.sslConfiguration(); + sslConfig.setCaCertificates( + QSslCertificate::fromPath(testDataDir + "certs/qt-test-server-cacert.pem")); + socket.setSslConfiguration(sslConfig); + QCOMPARE(socket.sslConfiguration().caCertificates().size(), 1); + + sslConfig.setCaCertificates(QSslConfiguration::defaultConfiguration().caCertificates()); + socket.setSslConfiguration(sslConfig); + QCOMPARE(socket.sslConfiguration().caCertificates(), + QSslConfiguration::defaultConfiguration().caCertificates()); } void tst_QSslSocket::setLocalCertificate() @@ -1491,7 +1618,7 @@ void tst_QSslSocket::setSslConfiguration_data() QTest::newRow("empty") << QSslConfiguration() << false; QSslConfiguration conf = QSslConfiguration::defaultConfiguration(); QTest::newRow("default") << conf << false; // does not contain test server cert - QList<QSslCertificate> testServerCert = QSslCertificate::fromPath(testDataDir + "certs/qt-test-server-cacert.pem"); + QList<QSslCertificate> testServerCert = QSslCertificate::fromPath(httpServerCertChainPath()); conf.setCaCertificates(testServerCert); QTest::newRow("set-root-cert") << conf << true; conf.setProtocol(QSsl::SecureProtocols); @@ -1510,7 +1637,7 @@ void tst_QSslSocket::setSslConfiguration() socket->setProtocol(QSsl::SslProtocol::TlsV1_1); #endif this->socket = socket.data(); - socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); QFETCH(bool, works); QFETCH_GLOBAL(bool, setProxy); if (setProxy && (socket->waitForEncrypted(10000) != works)) @@ -1530,7 +1657,7 @@ void tst_QSslSocket::waitForEncrypted() this->socket = socket.data(); connect(this->socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot())); - socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); QFETCH_GLOBAL(bool, setProxy); if (setProxy && !socket->waitForEncrypted(10000)) @@ -1549,7 +1676,7 @@ void tst_QSslSocket::waitForEncryptedMinusOne() this->socket = socket.data(); connect(this->socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot())); - socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); QFETCH_GLOBAL(bool, setProxy); if (setProxy && !socket->waitForEncrypted(-1)) @@ -1565,7 +1692,7 @@ void tst_QSslSocket::waitForConnectedEncryptedReadyRead() this->socket = socket.data(); connect(this->socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot())); - socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 993); + socket->connectToHostEncrypted(QtNetworkSettings::imapServerName(), 993); QVERIFY2(socket->waitForConnected(10000), qPrintable(socket->errorString())); QFETCH_GLOBAL(bool, setProxy); @@ -1594,19 +1721,43 @@ void tst_QSslSocket::addDefaultCaCertificate() if (!QSslSocket::supportsSsl()) return; +#if QT_DEPRECATED_SINCE(5, 5) + { + // Reset the global CA chain + QSslSocket::setDefaultCaCertificates(QSslSocket::systemCaCertificates()); + + QList<QSslCertificate> flukeCerts = QSslCertificate::fromPath(httpServerCertChainPath()); + QCOMPARE(flukeCerts.size(), 1); + QList<QSslCertificate> globalCerts = QSslSocket::defaultCaCertificates(); + QVERIFY(!globalCerts.contains(flukeCerts.first())); + QSslSocket::addDefaultCaCertificate(flukeCerts.first()); + QCOMPARE(QSslSocket::defaultCaCertificates().size(), globalCerts.size() + 1); + QVERIFY(QSslSocket::defaultCaCertificates().contains(flukeCerts.first())); + + // Restore the global CA chain + QSslSocket::setDefaultCaCertificates(QSslSocket::systemCaCertificates()); + } +#endif + // Reset the global CA chain - QSslSocket::setDefaultCaCertificates(QSslSocket::systemCaCertificates()); + auto sslConfig = QSslConfiguration::defaultConfiguration(); + sslConfig.setCaCertificates(QSslConfiguration::systemCaCertificates()); + QSslConfiguration::setDefaultConfiguration(sslConfig); - QList<QSslCertificate> flukeCerts = QSslCertificate::fromPath(testDataDir + "certs/qt-test-server-cacert.pem"); + QList<QSslCertificate> flukeCerts = QSslCertificate::fromPath(httpServerCertChainPath()); QCOMPARE(flukeCerts.size(), 1); - QList<QSslCertificate> globalCerts = QSslSocket::defaultCaCertificates(); + QList<QSslCertificate> globalCerts = QSslConfiguration::defaultConfiguration().caCertificates(); QVERIFY(!globalCerts.contains(flukeCerts.first())); QSslSocket::addDefaultCaCertificate(flukeCerts.first()); - QCOMPARE(QSslSocket::defaultCaCertificates().size(), globalCerts.size() + 1); - QVERIFY(QSslSocket::defaultCaCertificates().contains(flukeCerts.first())); + QCOMPARE(QSslConfiguration::defaultConfiguration().caCertificates().size(), + globalCerts.size() + 1); + QVERIFY(QSslConfiguration::defaultConfiguration().caCertificates() + .contains(flukeCerts.first())); // Restore the global CA chain - QSslSocket::setDefaultCaCertificates(QSslSocket::systemCaCertificates()); + sslConfig = QSslConfiguration::defaultConfiguration(); + sslConfig.setCaCertificates(QSslConfiguration::systemCaCertificates()); + QSslConfiguration::setDefaultConfiguration(sslConfig); } void tst_QSslSocket::addDefaultCaCertificates() @@ -1622,9 +1773,16 @@ void tst_QSslSocket::defaultCaCertificates() if (!QSslSocket::supportsSsl()) return; - QList<QSslCertificate> certs = QSslSocket::defaultCaCertificates(); +#if QT_DEPRECATED_SINCE(5, 5) + { + QList<QSslCertificate> certs = QSslSocket::defaultCaCertificates(); + QVERIFY(certs.size() > 1); + QCOMPARE(certs, QSslSocket::systemCaCertificates()); + } +#endif + QList<QSslCertificate> certs = QSslConfiguration::defaultConfiguration().caCertificates(); QVERIFY(certs.size() > 1); - QCOMPARE(certs, QSslSocket::systemCaCertificates()); + QCOMPARE(certs, QSslConfiguration::systemCaCertificates()); } void tst_QSslSocket::defaultCiphers() @@ -1632,12 +1790,22 @@ void tst_QSslSocket::defaultCiphers() if (!QSslSocket::supportsSsl()) return; - QList<QSslCipher> ciphers = QSslSocket::defaultCiphers(); +#if QT_DEPRECATED_SINCE(5, 5) + { + QList<QSslCipher> ciphers = QSslSocket::defaultCiphers(); + QVERIFY(ciphers.size() > 1); + + QSslSocket socket; + QCOMPARE(socket.defaultCiphers(), ciphers); + QCOMPARE(socket.ciphers(), ciphers); + } +#endif + QList<QSslCipher> ciphers = QSslConfiguration::defaultConfiguration().ciphers(); QVERIFY(ciphers.size() > 1); QSslSocket socket; - QCOMPARE(socket.defaultCiphers(), ciphers); - QCOMPARE(socket.ciphers(), ciphers); + QCOMPARE(socket.sslConfiguration().defaultConfiguration().ciphers(), ciphers); + QCOMPARE(socket.sslConfiguration().ciphers(), ciphers); } void tst_QSslSocket::resetDefaultCiphers() @@ -1657,11 +1825,21 @@ void tst_QSslSocket::supportedCiphers() if (!QSslSocket::supportsSsl()) return; - QList<QSslCipher> ciphers = QSslSocket::supportedCiphers(); +#if QT_DEPRECATED_SINCE(5, 5) + { + QList<QSslCipher> ciphers = QSslSocket::supportedCiphers(); + QVERIFY(ciphers.size() > 1); + + QSslSocket socket; + QCOMPARE(socket.supportedCiphers(), ciphers); + } +#endif + + QList<QSslCipher> ciphers = QSslConfiguration::supportedCiphers(); QVERIFY(ciphers.size() > 1); QSslSocket socket; - QCOMPARE(socket.supportedCiphers(), ciphers); + QCOMPARE(socket.sslConfiguration().supportedCiphers(), ciphers); } void tst_QSslSocket::systemCaCertificates() @@ -1669,9 +1847,16 @@ void tst_QSslSocket::systemCaCertificates() if (!QSslSocket::supportsSsl()) return; - QList<QSslCertificate> certs = QSslSocket::systemCaCertificates(); +#if QT_DEPRECATED_SINCE(5, 5) + { + QList<QSslCertificate> certs = QSslSocket::systemCaCertificates(); + QVERIFY(certs.size() > 1); + QCOMPARE(certs, QSslSocket::defaultCaCertificates()); + } +#endif + QList<QSslCertificate> certs = QSslConfiguration::systemCaCertificates(); QVERIFY(certs.size() > 1); - QCOMPARE(certs, QSslSocket::defaultCaCertificates()); + QCOMPARE(certs, QSslConfiguration::defaultConfiguration().systemCaCertificates()); } void tst_QSslSocket::wildcardCertificateNames() @@ -1946,7 +2131,7 @@ public slots: QTestEventLoop::instance().exitLoop(); } void waitSomeMore(QSslSocket *socket) { - QTime t; + QElapsedTimer t; t.start(); while (!socket->encryptedBytesAvailable()) { QCoreApplication::processEvents(QEventLoop::AllEvents | QEventLoop::WaitForMoreEvents, 250); @@ -1968,7 +2153,7 @@ void tst_QSslSocket::setReadBufferSize_task_250027() QSslSocketPtr socket = newSocket(); socket->setReadBufferSize(1000); // limit to 1 kb/sec socket->ignoreSslErrors(); - socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); socket->ignoreSslErrors(); QVERIFY2(socket->waitForConnected(10*1000), qPrintable(socket->errorString())); if (setProxy && !socket->waitForEncrypted(10*1000)) @@ -1981,7 +2166,7 @@ void tst_QSslSocket::setReadBufferSize_task_250027() // provoke a response by sending a request socket->write("GET /qtest/fluke.gif HTTP/1.0\n"); // this file is 27 KB socket->write("Host: "); - socket->write(QtNetworkSettings::serverName().toLocal8Bit().constData()); + socket->write(QtNetworkSettings::httpServerName().toLocal8Bit().constData()); socket->write("\n"); socket->write("Connection: close\n"); socket->write("\n"); @@ -2232,7 +2417,7 @@ void tst_QSslSocket::verifyMode() socket.setPeerVerifyMode(QSslSocket::VerifyPeer); QCOMPARE(socket.peerVerifyMode(), QSslSocket::VerifyPeer); - socket.connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + socket.connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); if (socket.waitForEncrypted()) QSKIP("Skipping flaky test - See QTBUG-29941"); @@ -2271,7 +2456,7 @@ void tst_QSslSocket::verifyDepth() void tst_QSslSocket::disconnectFromHostWhenConnecting() { QSslSocketPtr socket = newSocket(); - socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 993); + socket->connectToHostEncrypted(QtNetworkSettings::imapServerName(), 993); socket->ignoreSslErrors(); socket->write("XXXX LOGOUT\r\n"); QAbstractSocket::SocketState state = socket->state(); @@ -2300,7 +2485,7 @@ void tst_QSslSocket::disconnectFromHostWhenConnecting() void tst_QSslSocket::disconnectFromHostWhenConnected() { QSslSocketPtr socket = newSocket(); - socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 993); + socket->connectToHostEncrypted(QtNetworkSettings::imapServerName(), 993); socket->ignoreSslErrors(); if (!socket->waitForEncrypted(5000)) QSKIP("Skipping flaky test - See QTBUG-29941"); @@ -2387,13 +2572,13 @@ void tst_QSslSocket::resetProxy() // make sure the connection works, and then set a nonsense proxy, and then // make sure it does not work anymore QSslSocket socket; - socket.addCaCertificates(testDataDir + "certs/qt-test-server-cacert.pem"); + socket.addCaCertificates(httpServerCertChainPath()); socket.setProxy(goodProxy); - socket.connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + socket.connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); QVERIFY2(socket.waitForConnected(10000), qPrintable(socket.errorString())); socket.abort(); socket.setProxy(badProxy); - socket.connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + socket.connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); QVERIFY(! socket.waitForConnected(10000)); // don't forget to login @@ -2406,13 +2591,13 @@ void tst_QSslSocket::resetProxy() // set the nonsense proxy and make sure the connection does not work, // and then set the right proxy and make sure it works QSslSocket socket2; - socket2.addCaCertificates(testDataDir + "certs/qt-test-server-cacert.pem"); + socket2.addCaCertificates(httpServerCertChainPath()); socket2.setProxy(badProxy); - socket2.connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + socket2.connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); QVERIFY(! socket2.waitForConnected(10000)); socket2.abort(); socket2.setProxy(goodProxy); - socket2.connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + socket2.connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); QVERIFY2(socket2.waitForConnected(10000), qPrintable(socket.errorString())); #endif // QT_NO_NETWORKPROXY } @@ -2425,7 +2610,7 @@ void tst_QSslSocket::ignoreSslErrorsList_data() // construct the list of errors that we will get with the SSL handshake and that we will ignore QList<QSslError> expectedSslErrors; // fromPath gives us a list of certs, but it actually only contains one - QList<QSslCertificate> certs = QSslCertificate::fromPath(testDataDir + "certs/qt-test-server-cacert.pem"); + QList<QSslCertificate> certs = QSslCertificate::fromPath(httpServerCertChainPath()); QSslError rightError(FLUKE_CERTIFICATE_ERROR, certs.at(0)); QSslError wrongError(FLUKE_CERTIFICATE_ERROR); @@ -2456,7 +2641,7 @@ void tst_QSslSocket::ignoreSslErrorsList() QFETCH(int, expectedSslErrorSignalCount); QSignalSpy sslErrorsSpy(&socket, SIGNAL(error(QAbstractSocket::SocketError))); - socket.connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + socket.connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); bool expectEncryptionSuccess = (expectedSslErrorSignalCount == 0); if (socket.waitForEncrypted(10000) != expectEncryptionSuccess) @@ -2487,7 +2672,7 @@ void tst_QSslSocket::ignoreSslErrorsListWithSlot() this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); connect(&socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorListSlot(QList<QSslError>))); - socket.connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + socket.connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); QFETCH(int, expectedSslErrorSignalCount); bool expectEncryptionSuccess = (expectedSslErrorSignalCount == 0); @@ -2529,14 +2714,14 @@ void tst_QSslSocket::readFromClosedSocket() socket->setProtocol(QSsl::SslProtocol::TlsV1_1); #endif socket->ignoreSslErrors(); - socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); socket->ignoreSslErrors(); socket->waitForConnected(); socket->waitForEncrypted(); // provoke a response by sending a request socket->write("GET /qtest/fluke.gif HTTP/1.1\n"); socket->write("Host: "); - socket->write(QtNetworkSettings::serverName().toLocal8Bit().constData()); + socket->write(QtNetworkSettings::httpServerName().toLocal8Bit().constData()); socket->write("\n"); socket->write("\n"); socket->waitForBytesWritten(); @@ -2560,7 +2745,7 @@ void tst_QSslSocket::writeBigChunk() this->socket = socket.data(); connect(this->socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot())); - socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); QByteArray data; data.resize(1024*1024*10); // 10 MB @@ -2719,7 +2904,9 @@ void tst_QSslSocket::resume_data() QTest::newRow("DoNotIgnoreErrors") << false << QList<QSslError>() << false; QTest::newRow("ignoreAllErrors") << true << QList<QSslError>() << true; - QList<QSslCertificate> certs = QSslCertificate::fromPath(testDataDir + "certs/qt-test-server-cacert.pem"); + // Note, httpServerCertChainPath() it's ... because we use the same certificate on + // different services. We'll be actually connecting to IMAP server. + QList<QSslCertificate> certs = QSslCertificate::fromPath(httpServerCertChainPath()); QSslError rightError(FLUKE_CERTIFICATE_ERROR, certs.at(0)); QSslError wrongError(FLUKE_CERTIFICATE_ERROR); errorsList.append(wrongError); @@ -2733,7 +2920,9 @@ void tst_QSslSocket::resume() { // make sure the server certificate is not in the list of accepted certificates, // we want to trigger the sslErrors signal - QSslSocket::setDefaultCaCertificates(QSslSocket::systemCaCertificates()); + auto sslConfig = QSslConfiguration::defaultConfiguration(); + sslConfig.setCaCertificates(QSslConfiguration::systemCaCertificates()); + QSslConfiguration::setDefaultConfiguration(sslConfig); QFETCH(bool, ignoreErrorsAfterPause); QFETCH(QList<QSslError>, errorsToIgnore); @@ -2752,7 +2941,7 @@ void tst_QSslSocket::resume() this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)), &QTestEventLoop::instance(), SLOT(exitLoop())); - socket.connectToHostEncrypted(QtNetworkSettings::serverName(), 993); + socket.connectToHostEncrypted(QtNetworkSettings::imapServerName(), 993); QTestEventLoop::instance().enterLoop(10); QFETCH_GLOBAL(bool, setProxy); if (setProxy && QTestEventLoop::instance().timeout()) @@ -3053,7 +3242,7 @@ void tst_QSslSocket::dhServer() return; SslServer server; - server.ciphers = QLatin1String("DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA"); + server.ciphers = {QSslCipher("DHE-RSA-AES256-SHA"), QSslCipher("DHE-DSS-AES256-SHA")}; QVERIFY(server.listen()); QEventLoop loop; @@ -3082,7 +3271,7 @@ void tst_QSslSocket::dhServerCustomParamsNull() return; SslServer server; - server.ciphers = QLatin1String("DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA"); + server.ciphers = {QSslCipher("DHE-RSA-AES256-SHA"), QSslCipher("DHE-DSS-AES256-SHA")}; QSslConfiguration cfg = server.config; cfg.setDiffieHellmanParameters(QSslDiffieHellmanParameters()); @@ -3118,7 +3307,7 @@ void tst_QSslSocket::dhServerCustomParams() return; SslServer server; - server.ciphers = QLatin1String("DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA"); + server.ciphers = {QSslCipher("DHE-RSA-AES256-SHA"), QSslCipher("DHE-DSS-AES256-SHA")}; QSslConfiguration cfg = server.config; @@ -3167,7 +3356,7 @@ void tst_QSslSocket::ecdhServer() return; SslServer server; - server.ciphers = QLatin1String("ECDHE-RSA-AES128-SHA"); + server.ciphers = {QSslCipher("ECDHE-RSA-AES128-SHA")}; QVERIFY(server.listen()); QEventLoop loop; @@ -3255,14 +3444,14 @@ void tst_QSslSocket::verifyClientCertificate_data() void tst_QSslSocket::verifyClientCertificate() { -#ifdef QT_SECURETRANSPORT +#if QT_CONFIG(securetransport) // We run both client and server on the same machine, // this means, client can update keychain with client's certificates, // and server later will use the same certificates from the same // keychain thus making tests fail (wrong number of certificates, // success instead of failure etc.). QSKIP("This test can not work with Secure Transport"); -#endif +#endif // QT_CONFIG(securetransport) #ifdef Q_OS_WINRT QSKIP("Server-side encryption is not implemented on WinRT."); #endif @@ -3344,7 +3533,7 @@ void tst_QSslSocket::verifyClientCertificate() void tst_QSslSocket::readBufferMaxSize() { -#if defined(QT_SECURETRANSPORT) || QT_CONFIG(schannel) +#if QT_CONFIG(securetransport) || QT_CONFIG(schannel) // QTBUG-55170: // SecureTransport back-end was ignoring read-buffer // size limit, resulting (potentially) in a constantly @@ -3401,7 +3590,7 @@ void tst_QSslSocket::readBufferMaxSize() QCOMPARE(client->bytesAvailable() + readSoFar, message.size()); #else // Not needed, QSslSocket works correctly with other back-ends. -#endif +#endif // QT_CONFIG(securetransport) || QT_CONFIG(schannel) } void tst_QSslSocket::setEmptyDefaultConfiguration() // this test should be last, as it has some side effects @@ -3418,7 +3607,7 @@ void tst_QSslSocket::setEmptyDefaultConfiguration() // this test should be last, socket = client.data(); connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot())); - socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); QFETCH_GLOBAL(bool, setProxy); if (setProxy && socket->waitForEncrypted(4000)) QSKIP("Skipping flaky test - See QTBUG-29941"); @@ -3537,7 +3726,7 @@ public: bool ignoreSslErrors; QSslSocket::PeerVerifyMode peerVerifyMode; QSsl::SslProtocol protocol; - QString ciphers; + QList<QSslCipher> ciphers; PskProvider m_pskProvider; protected: @@ -3551,7 +3740,9 @@ protected: connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot())); if (!ciphers.isEmpty()) { - socket->setCiphers(ciphers); + auto sslConfig = socket->sslConfiguration(); + sslConfig.setCiphers(ciphers); + socket->setSslConfiguration(sslConfig); } QVERIFY(socket->setSocketDescriptor(socketDescriptor, QAbstractSocket::ConnectedState)); @@ -3593,7 +3784,7 @@ void tst_QSslSocket::simplePskConnect() QSKIP("No SSL support"); bool pskCipherFound = false; - const QList<QSslCipher> supportedCiphers = QSslSocket::supportedCiphers(); + const QList<QSslCipher> supportedCiphers = QSslConfiguration::supportedCiphers(); for (const QSslCipher &cipher : supportedCiphers) { if (cipher.name() == PSK_CIPHER_WITHOUT_AUTH) { pskCipherFound = true; @@ -3645,7 +3836,9 @@ void tst_QSslSocket::simplePskConnect() connect(&socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(exitLoop())); // force a PSK cipher w/o auth - socket.setCiphers(PSK_CIPHER_WITHOUT_AUTH); + auto sslConfig = socket.sslConfiguration(); + sslConfig.setCiphers({QSslCipher(PSK_CIPHER_WITHOUT_AUTH)}); + socket.setSslConfiguration(sslConfig); PskProvider provider; @@ -3914,7 +4107,9 @@ void tst_QSslSocket::pskServer() connect(&socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(exitLoop())); // force a PSK cipher w/o auth - socket.setCiphers(PSK_CIPHER_WITHOUT_AUTH); + auto sslConfig = socket.sslConfiguration(); + sslConfig.setCiphers({QSslCipher(PSK_CIPHER_WITHOUT_AUTH)}); + socket.setSslConfiguration(sslConfig); PskProvider provider; provider.setIdentity(PSK_CLIENT_IDENTITY); @@ -4117,7 +4312,7 @@ void tst_QSslSocket::forwardReadChannelFinished() }); connect(&socket, &QSslSocket::readChannelFinished, &QTestEventLoop::instance(), &QTestEventLoop::exitLoop); - socket.connectToHostEncrypted(QtNetworkSettings::serverLocalName(), 443); + socket.connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); enterLoop(10); QVERIFY(readChannelFinishedSpy.count()); } diff --git a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/qsslsocket_onDemandCertificates_member.pro b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/qsslsocket_onDemandCertificates_member.pro index 05755ff606..8585a3c861 100644 --- a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/qsslsocket_onDemandCertificates_member.pro +++ b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/qsslsocket_onDemandCertificates_member.pro @@ -17,3 +17,9 @@ win32 { DEFINES += SRCDIR=\\\"$$PWD/\\\" requires(qtConfig(private_tests)) + +# DOCKERTODO: linux, docker is disabled on macOS/Windows. +linux { + CONFIG += unsupported/testserver + QT_TEST_SERVER_LIST = squid danted +} diff --git a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/tst_qsslsocket_onDemandCertificates_member.cpp b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/tst_qsslsocket_onDemandCertificates_member.cpp index 25c2701f69..3b28e7a803 100644 --- a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/tst_qsslsocket_onDemandCertificates_member.cpp +++ b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/tst_qsslsocket_onDemandCertificates_member.cpp @@ -102,7 +102,15 @@ void tst_QSslSocket_onDemandCertificates_member::initTestCase_data() void tst_QSslSocket_onDemandCertificates_member::initTestCase() { +#ifdef QT_TEST_SERVER + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::socksProxyServerName(), 1080)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::socksProxyServerName(), 1081)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpProxyServerName(), 3128)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpProxyServerName(), 3129)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpProxyServerName(), 3130)); +#else QVERIFY(QtNetworkSettings::verifyTestNetworkSettings()); +#endif // QT_TEST_SERVER } void tst_QSslSocket_onDemandCertificates_member::init() @@ -110,28 +118,29 @@ void tst_QSslSocket_onDemandCertificates_member::init() QFETCH_GLOBAL(bool, setProxy); if (setProxy) { QFETCH_GLOBAL(int, proxyType); - QString testServer = QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first().toString(); + const auto socksAddr = QtNetworkSettings::socksProxyServerIp().toString(); + const auto squidAddr = QtNetworkSettings::httpProxyServerIp().toString(); QNetworkProxy proxy; switch (proxyType) { case Socks5Proxy: - proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, testServer, 1080); + proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, socksAddr, 1080); break; case Socks5Proxy | AuthBasic: - proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, testServer, 1081); + proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, socksAddr, 1081); break; case HttpProxy | NoAuth: - proxy = QNetworkProxy(QNetworkProxy::HttpProxy, testServer, 3128); + proxy = QNetworkProxy(QNetworkProxy::HttpProxy, squidAddr, 3128); break; case HttpProxy | AuthBasic: - proxy = QNetworkProxy(QNetworkProxy::HttpProxy, testServer, 3129); + proxy = QNetworkProxy(QNetworkProxy::HttpProxy, squidAddr, 3129); break; case HttpProxy | AuthNtlm: - proxy = QNetworkProxy(QNetworkProxy::HttpProxy, testServer, 3130); + proxy = QNetworkProxy(QNetworkProxy::HttpProxy, squidAddr, 3130); break; } QNetworkProxy::setApplicationProxy(proxy); @@ -202,10 +211,23 @@ void tst_QSslSocket_onDemandCertificates_member::onDemandRootCertLoadingMemberMe { const QString host("www.qt.io"); +#if QT_DEPRECATED_SINCE(5, 5) + { + // not using any root certs -> should not work + QSslSocketPtr socket2 = newSocket(); + this->socket = socket2.data(); + socket2->setCaCertificates(QList<QSslCertificate>()); + socket2->connectToHostEncrypted(host, 443); + QVERIFY(!waitForEncrypted(socket2.data())); + } +#endif + // not using any root certs -> should not work QSslSocketPtr socket2 = newSocket(); this->socket = socket2.data(); - socket2->setCaCertificates(QList<QSslCertificate>()); + auto sslConfig = socket2->sslConfiguration(); + sslConfig.setCaCertificates(QList<QSslCertificate>()); + socket2->setSslConfiguration(sslConfig); socket2->connectToHostEncrypted(host, 443); QVERIFY(!waitForEncrypted(socket2.data())); @@ -215,10 +237,23 @@ void tst_QSslSocket_onDemandCertificates_member::onDemandRootCertLoadingMemberMe socket->connectToHostEncrypted(host, 443); QVERIFY2(waitForEncrypted(socket.data()), qPrintable(socket->errorString())); +#if QT_DEPRECATED_SINCE(5, 5) + { + // not using any root certs again -> should not work + QSslSocketPtr socket3 = newSocket(); + this->socket = socket3.data(); + socket3->setCaCertificates(QList<QSslCertificate>()); + socket3->connectToHostEncrypted(host, 443); + QVERIFY(!waitForEncrypted(socket3.data())); + } +#endif + // not using any root certs again -> should not work QSslSocketPtr socket3 = newSocket(); this->socket = socket3.data(); - socket3->setCaCertificates(QList<QSslCertificate>()); + sslConfig = socket3->sslConfiguration(); + sslConfig.setCaCertificates(QList<QSslCertificate>()); + socket3->setSslConfiguration(sslConfig); socket3->connectToHostEncrypted(host, 443); QVERIFY(!waitForEncrypted(socket3.data())); diff --git a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_static/qsslsocket_onDemandCertificates_static.pro b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_static/qsslsocket_onDemandCertificates_static.pro index c345d7379f..158ecbee37 100644 --- a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_static/qsslsocket_onDemandCertificates_static.pro +++ b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_static/qsslsocket_onDemandCertificates_static.pro @@ -16,3 +16,9 @@ win32 { DEFINES += SRCDIR=\\\"$$PWD/\\\" requires(qtConfig(private_tests)) + +#DOCKERTODO Linux, docker is disabled on macOS and Windows. +linux { + CONFIG += unsupported/testserver + QT_TEST_SERVER_LIST = squid danted +} diff --git a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_static/tst_qsslsocket_onDemandCertificates_static.cpp b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_static/tst_qsslsocket_onDemandCertificates_static.cpp index 503edc0bff..a441d13619 100644 --- a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_static/tst_qsslsocket_onDemandCertificates_static.cpp +++ b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_static/tst_qsslsocket_onDemandCertificates_static.cpp @@ -98,7 +98,15 @@ void tst_QSslSocket_onDemandCertificates_static::initTestCase_data() void tst_QSslSocket_onDemandCertificates_static::initTestCase() { +#ifdef QT_TEST_SERVER + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::socksProxyServerName(), 1080)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::socksProxyServerName(), 1081)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpProxyServerName(), 3128)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpProxyServerName(), 3129)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpProxyServerName(), 3130)); +#else QVERIFY(QtNetworkSettings::verifyTestNetworkSettings()); +#endif // QT_TEST_SERVER } void tst_QSslSocket_onDemandCertificates_static::init() @@ -106,28 +114,30 @@ void tst_QSslSocket_onDemandCertificates_static::init() QFETCH_GLOBAL(bool, setProxy); if (setProxy) { QFETCH_GLOBAL(int, proxyType); - QString testServer = QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first().toString(); + const auto socksAddr = QtNetworkSettings::socksProxyServerIp().toString(); + const auto squidAddr = QtNetworkSettings::httpProxyServerIp().toString(); + QNetworkProxy proxy; switch (proxyType) { case Socks5Proxy: - proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, testServer, 1080); + proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, socksAddr, 1080); break; case Socks5Proxy | AuthBasic: - proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, testServer, 1081); + proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, socksAddr, 1081); break; case HttpProxy | NoAuth: - proxy = QNetworkProxy(QNetworkProxy::HttpProxy, testServer, 3128); + proxy = QNetworkProxy(QNetworkProxy::HttpProxy, squidAddr, 3128); break; case HttpProxy | AuthBasic: - proxy = QNetworkProxy(QNetworkProxy::HttpProxy, testServer, 3129); + proxy = QNetworkProxy(QNetworkProxy::HttpProxy, squidAddr, 3129); break; case HttpProxy | AuthNtlm: - proxy = QNetworkProxy(QNetworkProxy::HttpProxy, testServer, 3130); + proxy = QNetworkProxy(QNetworkProxy::HttpProxy, squidAddr, 3130); break; } QNetworkProxy::setApplicationProxy(proxy); @@ -168,6 +178,7 @@ void tst_QSslSocket_onDemandCertificates_static::onDemandRootCertLoadingStaticMe { QString host("www.qt.io"); +#if QT_DEPRECATED_SINCE(5, 5) // not using any root certs -> should not work QSslSocket::setDefaultCaCertificates(QList<QSslCertificate>()); QSslSocketPtr socket = newSocket(); @@ -190,6 +201,7 @@ void tst_QSslSocket_onDemandCertificates_static::onDemandRootCertLoadingStaticMe QVERIFY(!socket3->waitForEncrypted()); QSslSocket::setDefaultCaCertificates(QSslSocket::systemCaCertificates()); +#endif // setting empty default configuration -> should not work QSslConfiguration conf; diff --git a/tests/auto/opengl/qgl/BLACKLIST b/tests/auto/opengl/qgl/BLACKLIST index d3165a51e5..ec75ea16eb 100644 --- a/tests/auto/opengl/qgl/BLACKLIST +++ b/tests/auto/opengl/qgl/BLACKLIST @@ -1,25 +1,8 @@ -[glWidgetRendering] -windows -winrt -[glFBORendering] -windows -winrt -[multipleFBOInterleavedRendering] -windows -winrt -[glPBufferRendering] -windows -winrt -[replaceClipping] -windows -winrt -[clipTest] -windows -winrt [graphicsViewClipping] -windows -winrt -linux ci -[glFBOUseInGLWidget] -windows -winrt +ubuntu-16.04 +rhel-7.6 +opensuse-leap +ubuntu-18.04 +rhel-7.4 +opensuse-42.3 + diff --git a/tests/auto/opengl/qgl/tst_qgl.cpp b/tests/auto/opengl/qgl/tst_qgl.cpp index 053c4b026b..3cc9592fb1 100644 --- a/tests/auto/opengl/qgl/tst_qgl.cpp +++ b/tests/auto/opengl/qgl/tst_qgl.cpp @@ -60,6 +60,8 @@ public: tst_QGL(); virtual ~tst_QGL(); + static void initMain(); + private slots: void initTestCase(); void getSetCheck(); @@ -101,6 +103,11 @@ tst_QGL::~tst_QGL() { } +void tst_QGL::initMain() +{ + QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling); +} + void tst_QGL::initTestCase() { QGLWidget glWidget; diff --git a/tests/auto/opengl/qglthreads/tst_qglthreads.cpp b/tests/auto/opengl/qglthreads/tst_qglthreads.cpp index b7b5b505a0..e12f6d9c18 100644 --- a/tests/auto/opengl/qglthreads/tst_qglthreads.cpp +++ b/tests/auto/opengl/qglthreads/tst_qglthreads.cpp @@ -33,6 +33,7 @@ #include <qpa/qplatformintegration.h> #include <QtWidgets/QApplication> #include <QtOpenGL/QtOpenGL> +#include <qelapsedtimer.h> #include "tst_qglthreads.h" #ifndef QT_OPENGL_ES_2 @@ -74,9 +75,9 @@ public: } void run() { - QTime time; - time.start(); - while (time.elapsed() < RUNNING_TIME) { + QElapsedTimer timer; + timer.start(); + while (timer.elapsed() < RUNNING_TIME) { lock(); waitForReadyToSwap(); @@ -291,11 +292,11 @@ public: } void run() { - QTime time; - time.start(); + QElapsedTimer timer; + timer.start(); failure = false; - while (time.elapsed() < RUNNING_TIME && !failure) { + while (timer.elapsed() < RUNNING_TIME && !failure) { m_widget->makeCurrent(); @@ -466,13 +467,13 @@ public: public slots: void draw() { bool beginFailed = false; - QTime time; - time.start(); + QElapsedTimer timer; + timer.start(); int rotAngle = 10; device->prepareDevice(); QPaintDevice *paintDevice = device->realPaintDevice(); QSize s(paintDevice->width(), paintDevice->height()); - while (time.elapsed() < RUNNING_TIME) { + while (timer.elapsed() < RUNNING_TIME) { QPainter p; if (!p.begin(paintDevice)) { beginFailed = true; @@ -605,9 +606,6 @@ void tst_QGLThreads::painterOnPixmapInThread() if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL) || !QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedPixmaps)) QSKIP("No platformsupport for ThreadedOpenGL or ThreadedPixmaps"); -#if 0 // Used to be included in Qt4 for Q_WS_X11 - QSKIP("Drawing text in threads onto X11 drawables currently crashes on some X11 servers."); -#endif PaintThreadManager<PixmapWrapper> painterThreads(5); painterThreads.start(); diff --git a/tests/auto/other/compiler/tst_compiler.cpp b/tests/auto/other/compiler/tst_compiler.cpp index b2b45bb237..de15f4c62d 100644 --- a/tests/auto/other/compiler/tst_compiler.cpp +++ b/tests/auto/other/compiler/tst_compiler.cpp @@ -842,7 +842,7 @@ void tst_Compiler::cxx11_constexpr() static constexpr QBasicAtomicInt atomic = Q_BASIC_ATOMIC_INITIALIZER(1); static constexpr int i = constexprValue(); QCOMPARE(i, constexprValue()); - QCOMPARE(atomic.load(), 1); + QCOMPARE(atomic.loadRelaxed(), 1); #endif } diff --git a/tests/auto/other/gestures/BLACKLIST b/tests/auto/other/gestures/BLACKLIST index c465ff316e..2af5d40359 100644 --- a/tests/auto/other/gestures/BLACKLIST +++ b/tests/auto/other/gestures/BLACKLIST @@ -3,17 +3,25 @@ rhel-7.4 rhel-7.6 ubuntu-18.04 [customGesture] -# QTBUG-67254 -ubuntu -opensuse opensuse-leap +# QTBUG-67254 +opensuse-42.3 [graphicsItemGesture] ubuntu-18.04 +rhel-7.4 +rhel-7.6 [graphicsItemTreeGesture] ubuntu-18.04 [graphicsView] ubuntu-18.04 +rhel-7.4 +rhel-7.6 [explicitGraphicsObjectTarget] ubuntu-18.04 +rhel-7.4 +rhel-7.6 [autoCancelGestures2] ubuntu-18.04 +rhel-7.4 +rhel-7.6 + diff --git a/tests/auto/other/lancelot/paintcommands.cpp b/tests/auto/other/lancelot/paintcommands.cpp index 8fd22caa16..215a4c2a29 100644 --- a/tests/auto/other/lancelot/paintcommands.cpp +++ b/tests/auto/other/lancelot/paintcommands.cpp @@ -365,6 +365,7 @@ void PaintCommands::staticInit() "^gradient_setCoordinateMode\\s+(\\w*)$", "gradient_setCoordinateMode <coordinate method enum>", "gradient_setCoordinateMode ObjectBoundingMode"); + DECL_PAINTCOMMANDSECTION("drawing ops"); DECL_PAINTCOMMAND("drawPoint", command_drawPoint, "^drawPoint\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)$", @@ -454,6 +455,14 @@ void PaintCommands::staticInit() "\n - where t means tile" "\n - and s is an offset in the tile", "drawTiledPixmap :/images/alpha.png "); + DECL_PAINTCOMMAND("fillRect", command_fillRect, + "^fillRect\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s*(\\w*)?$", + "fillRect <x> <y> <w> <h> [color]\n - Uses current brush if no color given", + "fillRect 10 10 20 20 blue"); + DECL_PAINTCOMMAND("fillRectF", command_fillRectF, + "^fillRectF\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s*(\\w*)?$", + "fillRectF <x> <y> <w> <h> [color]\n - Uses current brush if no color given", + "fillRectF 10.5 10.5 20.2 20.2 blue"); DECL_PAINTCOMMANDSECTION("painterPaths"); DECL_PAINTCOMMAND("path_moveTo", command_path_moveTo, @@ -1208,7 +1217,7 @@ void PaintCommands::command_drawRoundRect(QRegularExpressionMatch re) QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED - m_painter->drawRoundRect(x, y, w, h, xs, ys); + m_painter->drawRoundedRect(x, y, w, h, xs, ys, Qt::RelativeSize); QT_WARNING_POP } @@ -1331,6 +1340,46 @@ void PaintCommands::command_drawTextDocument(QRegularExpressionMatch re) m_painter->restore(); } +/***************************************************************************************************/ +void PaintCommands::command_fillRect(QRegularExpressionMatch re) +{ + QStringList caps = re.capturedTexts(); + int x = convertToInt(caps.at(1)); + int y = convertToInt(caps.at(2)); + int w = convertToInt(caps.at(3)); + int h = convertToInt(caps.at(4)); + + if (!caps.at(5).isEmpty()) { + QColor color = convertToColor(caps.at(5)); + if (m_verboseMode) + printf(" -(lance) fillRect(%d, %d, %d, %d, %s)\n", x, y, w, h, qPrintable(color.name())); + m_painter->fillRect(x, y, w, h, color); + } else { + if (m_verboseMode) + printf(" -(lance) fillRect(%d, %d, %d, %d)\n", x, y, w, h); + m_painter->fillRect(x, y, w, h, m_painter->brush()); + } +} + +void PaintCommands::command_fillRectF(QRegularExpressionMatch re) +{ + QStringList caps = re.capturedTexts(); + double x = convertToDouble(caps.at(1)); + double y = convertToDouble(caps.at(2)); + double w = convertToDouble(caps.at(3)); + double h = convertToDouble(caps.at(4)); + + if (!caps.at(5).isEmpty()) { + QColor color = convertToColor(caps.at(5)); + if (m_verboseMode) + printf(" -(lance) fillRectF(%.2f, %.2f, %.2f, %.2f, %s)\n", x, y, w, h, qPrintable(color.name())); + m_painter->fillRect(QRectF(x, y, w, h), color); + } else { + if (m_verboseMode) + printf(" -(lance) fillRectF(%.2f, %.2f, %.2f, %.2f)\n", x, y, w, h); + m_painter->fillRect(QRectF(x, y, w, h), m_painter->brush()); + } +} /***************************************************************************************************/ void PaintCommands::command_noop(QRegularExpressionMatch) @@ -2484,12 +2533,6 @@ void PaintCommands::command_surface_begin(QRegularExpressionMatch re) m_painter->fillRect(QRect(0, 0, qRound(w), qRound(h)), Qt::transparent); m_painter->restore(); #endif -#if 0 // Used to be included in Qt4 for Q_WS_X11 - } else if (m_type == WidgetType) { - m_surface_pixmap = QPixmap(qRound(w), qRound(h)); - m_surface_pixmap.fill(Qt::transparent); - m_painter = new QPainter(&m_surface_pixmap); -#endif } else { QImage::Format surface_format; if (QImage::toPixelFormat(m_format).alphaUsage() != QPixelFormat::UsesAlpha) @@ -2541,11 +2584,6 @@ void PaintCommands::command_surface_end(QRegularExpressionMatch) m_painter->beginNativePainting(); m_painter->endNativePainting(); #endif -#if 0 // Used to be included in Qt4 for Q_WS_X11 - } else if (m_type == WidgetType) { - m_painter->drawPixmap(m_surface_rect.topLeft(), m_surface_pixmap); - m_surface_pixmap = QPixmap(); -#endif } else { m_painter->drawImage(m_surface_rect, m_surface_image); m_surface_image = QImage(); diff --git a/tests/auto/other/lancelot/paintcommands.h b/tests/auto/other/lancelot/paintcommands.h index 79bdab634a..816ecd6fa2 100644 --- a/tests/auto/other/lancelot/paintcommands.h +++ b/tests/auto/other/lancelot/paintcommands.h @@ -200,6 +200,10 @@ private: void command_drawStaticText(QRegularExpressionMatch re); void command_drawTextDocument(QRegularExpressionMatch re); void command_drawTiledPixmap(QRegularExpressionMatch re); + void command_fillRect(QRegularExpressionMatch re); + void command_fillRectF(QRegularExpressionMatch re); + + // paths void command_path_addEllipse(QRegularExpressionMatch re); void command_path_addPolygon(QRegularExpressionMatch re); void command_path_addRect(QRegularExpressionMatch re); diff --git a/tests/auto/other/lancelot/scripts/fillrect.qps b/tests/auto/other/lancelot/scripts/fillrect.qps new file mode 100644 index 0000000000..103ef2646a --- /dev/null +++ b/tests/auto/other/lancelot/scripts/fillrect.qps @@ -0,0 +1,121 @@ +setRenderHint Antialiasing false + +# offscreen +translate 0 -200 + +begin_block rects +# int API +fillRect 10 10 20 20 green +fillRect 40 10 20 20 +drawRect 70 10 20 20 + +# float API, int values +fillRectF 10.0 40.0 20.0 20.0 green +fillRectF 40.0 40.0 20.0 20.0 +drawRect 70.0 40.0 20.0 20.0 + +# float API, float values +fillRectF 10.0 70.0 20.5 20.5 green +fillRectF 40.0 70.0 20.5 20.5 +drawRect 70.0 70.0 20.5 20.5 + +# alignment, int api, color +fillRect 10 100 10 10 green +fillRect 20 100 10 10 green +fillRect 10 110 10 10 green +fillRect 20 110 10 10 green + +# alignment, int api, brush +fillRect 40 100 10 10 +fillRect 50 100 10 10 +fillRect 40 110 10 10 +fillRect 50 110 10 10 + +# alignment comparison +drawRect 70 100 10 10 +drawRect 80 100 10 10 +drawRect 70 110 10 10 +drawRect 80 110 10 10 + +# alignment, float api, color +fillRectF 10.0 130.0 10.0 10.0 green +fillRectF 20.0 130.0 10.0 10.0 green +fillRectF 10.0 140.0 10.0 10.0 green +fillRectF 20.0 140.0 10.0 10.0 green + +# alignment, float api, brush +fillRectF 40.0 130.0 10.0 10.0 +fillRectF 50.0 130.0 10.0 10.0 +fillRectF 40.0 140.0 10.0 10.0 +fillRectF 50.0 140.0 10.0 10.0 + +# alignment comparison +drawRect 70.0 130.0 10.0 10.0 +drawRect 80.0 130.0 10.0 10.0 +drawRect 70.0 140.0 10.0 10.0 +drawRect 80.0 140.0 10.0 10.0 + +end_block + +begin_block row + +repeat_block rects + +save +translate 100.2 0.2 +repeat_block rects +restore + +save +translate 200.5 0.5 +repeat_block rects +restore + +save +translate 300.7 0.7 +repeat_block rects +restore + +end_block + +# end of block defs + +resetMatrix + +setPen NoPen +setBrush green +repeat_block row + +save +translate 500 50 +scale 0.42 0.42 +repeat_block row +restore + +save +translate 0 160 +scale 1.8 0.8 +repeat_block row +restore + +save +translate 650 320 +rotate 80 +repeat_block row +restore + +save +setBrush green Dense2Pattern +translate 0 400 +repeat_block row +restore + +save +gradient_clearStops +gradient_appendStop 0 green +gradient_appendStop 1 blue +gradient_setCoordinateMode ObjectBoundingMode +gradient_setLinear 0.0 0.0 1.0 1.0 +translate 0 600 +repeat_block row +restore diff --git a/tests/auto/other/lancelot/scripts/fillrect_aa.qps b/tests/auto/other/lancelot/scripts/fillrect_aa.qps new file mode 100644 index 0000000000..3232899661 --- /dev/null +++ b/tests/auto/other/lancelot/scripts/fillrect_aa.qps @@ -0,0 +1,121 @@ +setRenderHint Antialiasing true + +# offscreen +translate 0 -200 + +begin_block rects +# int API +fillRect 10 10 20 20 green +fillRect 40 10 20 20 +drawRect 70 10 20 20 + +# float API, int values +fillRectF 10.0 40.0 20.0 20.0 green +fillRectF 40.0 40.0 20.0 20.0 +drawRect 70.0 40.0 20.0 20.0 + +# float API, float values +fillRectF 10.0 70.0 20.5 20.5 green +fillRectF 40.0 70.0 20.5 20.5 +drawRect 70.0 70.0 20.5 20.5 + +# alignment, int api, color +fillRect 10 100 10 10 green +fillRect 20 100 10 10 green +fillRect 10 110 10 10 green +fillRect 20 110 10 10 green + +# alignment, int api, brush +fillRect 40 100 10 10 +fillRect 50 100 10 10 +fillRect 40 110 10 10 +fillRect 50 110 10 10 + +# alignment comparison +drawRect 70 100 10 10 +drawRect 80 100 10 10 +drawRect 70 110 10 10 +drawRect 80 110 10 10 + +# alignment, float api, color +fillRectF 10.0 130.0 10.0 10.0 green +fillRectF 20.0 130.0 10.0 10.0 green +fillRectF 10.0 140.0 10.0 10.0 green +fillRectF 20.0 140.0 10.0 10.0 green + +# alignment, float api, brush +fillRectF 40.0 130.0 10.0 10.0 +fillRectF 50.0 130.0 10.0 10.0 +fillRectF 40.0 140.0 10.0 10.0 +fillRectF 50.0 140.0 10.0 10.0 + +# alignment comparison +drawRect 70.0 130.0 10.0 10.0 +drawRect 80.0 130.0 10.0 10.0 +drawRect 70.0 140.0 10.0 10.0 +drawRect 80.0 140.0 10.0 10.0 + +end_block + +begin_block row + +repeat_block rects + +save +translate 100.2 0.2 +repeat_block rects +restore + +save +translate 200.5 0.5 +repeat_block rects +restore + +save +translate 300.7 0.7 +repeat_block rects +restore + +end_block + +# end of block defs + +resetMatrix + +setPen NoPen +setBrush green +repeat_block row + +save +translate 500 50 +scale 0.42 0.42 +repeat_block row +restore + +save +translate 0 160 +scale 1.8 0.8 +repeat_block row +restore + +save +translate 650 320 +rotate 80 +repeat_block row +restore + +save +setBrush green Dense2Pattern +translate 0 400 +repeat_block row +restore + +save +gradient_clearStops +gradient_appendStop 0 green +gradient_appendStop 1 blue +gradient_setCoordinateMode ObjectBoundingMode +gradient_setLinear 0.0 0.0 1.0 1.0 +translate 0 600 +repeat_block row +restore diff --git a/tests/auto/other/macplist/tst_macplist.cpp b/tests/auto/other/macplist/tst_macplist.cpp index 755cc462f5..dec63b1b66 100644 --- a/tests/auto/other/macplist/tst_macplist.cpp +++ b/tests/auto/other/macplist/tst_macplist.cpp @@ -59,8 +59,6 @@ void tst_MacPlist::test_plist_data() " <string></string>\n" " <key>CFBundlePackageType</key>\n" " <string>APPL</string>\n" -" <key>CFBundleGetInfoString</key>\n" -" <string>Created by Qt/QMake</string>\n" " <key>CFBundleExecutable</key>\n" " <string>app</string>\n" " <key>CFBundleIdentifier</key>\n" @@ -77,8 +75,6 @@ void tst_MacPlist::test_plist_data() " <string></string>\n" " <key>CFBundlePackageType</key>\n" " <string>APPL</string>\n" -" <key>CFBundleGetInfoString</key>\n" -" <string>Created by Qt/QMake</string>\n" " <key>CFBundleExecutable</key>\n" " <string>app</string>\n" " <key>CFBundleIdentifier</key>\n" @@ -97,8 +93,6 @@ void tst_MacPlist::test_plist_data() " <string></string>\n" " <key>CFBundlePackageType</key>\n" " <string>APPL</string>\n" -" <key>CFBundleGetInfoString</key>\n" -" <string>Created by Qt/QMake</string>\n" " <key>CFBundleExecutable</key>\n" " <string>app</string>\n" " <key>CFBundleIdentifier</key>\n" @@ -117,8 +111,6 @@ void tst_MacPlist::test_plist_data() " <string></string>\n" " <key>CFBundlePackageType</key>\n" " <string>APPL</string>\n" -" <key>CFBundleGetInfoString</key>\n" -" <string>Created by Qt/QMake</string>\n" " <key>CFBundleExecutable</key>\n" " <string>app</string>\n" " <key>CFBundleIdentifier</key>\n" @@ -137,8 +129,6 @@ void tst_MacPlist::test_plist_data() " <string></string>\n" " <key>CFBundlePackageType</key>\n" " <string>APPL</string>\n" -" <key>CFBundleGetInfoString</key>\n" -" <string>Created by Qt/QMake</string>\n" " <key>CFBundleExecutable</key>\n" " <string>app</string>\n" " <key>CFBundleIdentifier</key>\n" diff --git a/tests/auto/other/networkselftest/BLACKLIST b/tests/auto/other/networkselftest/BLACKLIST index 4a958b43a5..55ebad985d 100644 --- a/tests/auto/other/networkselftest/BLACKLIST +++ b/tests/auto/other/networkselftest/BLACKLIST @@ -1,4 +1,5 @@ # QTBUG-27571 [ftpProxyServer] -windows 32bit -windows 64bit +windows-7sp1 +windows-10 + diff --git a/tests/auto/other/networkselftest/tst_networkselftest.cpp b/tests/auto/other/networkselftest/tst_networkselftest.cpp index dc353d2090..1b125d8825 100644 --- a/tests/auto/other/networkselftest/tst_networkselftest.cpp +++ b/tests/auto/other/networkselftest/tst_networkselftest.cpp @@ -29,6 +29,7 @@ #include <QtTest/QtTest> #include <QtNetwork/QtNetwork> #include <QtCore/QDateTime> +#include <QtCore/QElapsedTimer> #include <QtCore/QTextStream> #include <QtCore/QRandomGenerator> #include <QtCore/QStandardPaths> @@ -195,7 +196,7 @@ static bool doSocketFlush(QTcpSocket *socket, int timeout = 4000) #ifndef QT_NO_SSL QSslSocket *sslSocket = qobject_cast<QSslSocket *>(socket); #endif - QTime timer; + QElapsedTimer timer; timer.start(); int t = timeout; forever { @@ -421,7 +422,7 @@ void tst_NetworkSelfTest::serverReachability() QTcpSocket socket; socket.connectToHost(QtNetworkSettings::serverName(), 12346); - QTime timer; + QElapsedTimer timer; timer.start(); socket.waitForConnected(10000); QVERIFY2(timer.elapsed() < 9900, "Connection to closed port timed out instead of refusing, something is wrong"); diff --git a/tests/auto/other/qabstractitemmodelutils/dynamictreemodel.cpp b/tests/auto/other/qabstractitemmodelutils/dynamictreemodel.cpp index fc979bce2d..ecc95d30b6 100644 --- a/tests/auto/other/qabstractitemmodelutils/dynamictreemodel.cpp +++ b/tests/auto/other/qabstractitemmodelutils/dynamictreemodel.cpp @@ -80,13 +80,9 @@ qint64 DynamicTreeModel::findParentId(qint64 searchId) const if (searchId <= 0) return -1; - QHashIterator<qint64, QList<QList<qint64> > > i(m_childItems); - while (i.hasNext()) { - i.next(); - QListIterator<QList<qint64> > j(i.value()); - while (j.hasNext()) { - QList<qint64> l = j.next(); - if (l.contains(searchId)) + for (auto i = m_childItems.cbegin(), end = m_childItems.cend(); i != end; ++i) { + for (const auto &list : i.value()) { + if (list.contains(searchId)) return i.key(); } } @@ -163,13 +159,12 @@ ModelChangeCommand::ModelChangeCommand(DynamicTreeModel *model, QObject *parent) { } -QModelIndex ModelChangeCommand::findIndex(QList<int> rows) +QModelIndex ModelChangeCommand::findIndex(const QList<int> &rows) const { const int col = 0; QModelIndex parent = QModelIndex(); - QListIterator<int> i(rows); - while (i.hasNext()) { - parent = m_model->index(i.next(), col, parent); + for (int row : rows) { + parent = m_model->index(row, col, parent); if (!parent.isValid()) qFatal("%s: parent must be valid", Q_FUNC_INFO); } @@ -233,7 +228,7 @@ void ModelMoveCommand::doCommand() if (srcParent == destParent) d = m_destRow - (m_endRow - m_startRow + 1); else - d = m_destRow - (m_endRow - m_startRow) + 1; + d = m_destRow; } foreach (const qint64 id, l) diff --git a/tests/auto/other/qabstractitemmodelutils/dynamictreemodel.h b/tests/auto/other/qabstractitemmodelutils/dynamictreemodel.h index 709751dd27..0807ffbe94 100644 --- a/tests/auto/other/qabstractitemmodelutils/dynamictreemodel.h +++ b/tests/auto/other/qabstractitemmodelutils/dynamictreemodel.h @@ -97,7 +97,7 @@ public: m_rowNumbers = rowNumbers; } - QModelIndex findIndex(QList<int> rows); + QModelIndex findIndex(const QList<int> &rows) const; void setStartRow(int row) { diff --git a/tests/auto/other/qaccessibility/qaccessibility.pro b/tests/auto/other/qaccessibility/qaccessibility.pro index 3587c38e76..6f3740a24f 100644 --- a/tests/auto/other/qaccessibility/qaccessibility.pro +++ b/tests/auto/other/qaccessibility/qaccessibility.pro @@ -11,5 +11,6 @@ win32 { !winrt { QT += windowsuiautomation_support-private } - LIBS += -luuid -loleacc -loleaut32 -lole32 + LIBS += -loleacc -loleaut32 + QMAKE_USE += ole32 uuid } diff --git a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp index bc45487599..7d7fa6403b 100644 --- a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp +++ b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp @@ -2580,6 +2580,7 @@ void tst_QAccessibility::dialogButtonBoxTest() case QDialogButtonBox::GnomeLayout: case QDialogButtonBox::KdeLayout: case QDialogButtonBox::MacLayout: + case QDialogButtonBox::AndroidLayout: expectedOrder << QDialogButtonBox::tr("Help") << QDialogButtonBox::tr("Reset") << QDialogButtonBox::tr("OK"); diff --git a/tests/auto/other/qaccessibilitymac/BLACKLIST b/tests/auto/other/qaccessibilitymac/BLACKLIST deleted file mode 100644 index f53fa7e853..0000000000 --- a/tests/auto/other/qaccessibilitymac/BLACKLIST +++ /dev/null @@ -1,2 +0,0 @@ -[hierarchyTest] -osx-10.12 ci diff --git a/tests/auto/other/qfocusevent/BLACKLIST b/tests/auto/other/qfocusevent/BLACKLIST deleted file mode 100644 index 0b03472587..0000000000 --- a/tests/auto/other/qfocusevent/BLACKLIST +++ /dev/null @@ -1,6 +0,0 @@ -[checkReason_Shortcut] -osx-10.12 ci -[checkReason_ActiveWindow] -osx-10.12 ci -winrt - diff --git a/tests/auto/other/qnetworkaccessmanager_and_qprogressdialog/BLACKLIST b/tests/auto/other/qnetworkaccessmanager_and_qprogressdialog/BLACKLIST index aea819fc2e..6173488c00 100644 --- a/tests/auto/other/qnetworkaccessmanager_and_qprogressdialog/BLACKLIST +++ b/tests/auto/other/qnetworkaccessmanager_and_qprogressdialog/BLACKLIST @@ -1,2 +1,4 @@ +[downloadCheck] +windows-10 [downloadCheck:with-zeroCopy] windows diff --git a/tests/auto/other/qobjectrace/tst_qobjectrace.cpp b/tests/auto/other/qobjectrace/tst_qobjectrace.cpp index 0d656e223c..e09d304ff3 100644 --- a/tests/auto/other/qobjectrace/tst_qobjectrace.cpp +++ b/tests/auto/other/qobjectrace/tst_qobjectrace.cpp @@ -85,7 +85,7 @@ class RaceThread : public QThread { Q_OBJECT RaceObject *object; - QTime stopWatch; + QElapsedTimer stopWatch; public: RaceThread() @@ -378,6 +378,10 @@ public: connect(timer, &QTimer::timeout, this, &DeleteReceiverRaceReceiver::onTimeout); timer->start(1); } + ~DeleteReceiverRaceReceiver() + { + delete receiver; + } void onTimeout() { @@ -410,7 +414,7 @@ void tst_QObjectRace::disconnectRace() { enum { ThreadCount = 20, TimeLimit = 3000 }; - QCOMPARE(countedStructObjectsCount.load(), 0u); + QCOMPARE(countedStructObjectsCount.loadRelaxed(), 0u); { QScopedPointer<DisconnectRaceSenderObject> sender(new DisconnectRaceSenderObject()); @@ -428,15 +432,15 @@ void tst_QObjectRace::disconnectRace() for (int i = 0; i < ThreadCount; ++i) { threads[i]->requestInterruption(); - QVERIFY(threads[i]->wait(300)); + QVERIFY(threads[i]->wait()); delete threads[i]; } senderThread->quit(); - QVERIFY(senderThread->wait(300)); + QVERIFY(senderThread->wait()); } - QCOMPARE(countedStructObjectsCount.load(), 0u); + QCOMPARE(countedStructObjectsCount.loadRelaxed(), 0u); { QScopedPointer<DisconnectRaceSenderObject> sender(new DisconnectRaceSenderObject()); @@ -453,16 +457,16 @@ void tst_QObjectRace::disconnectRace() QTest::qWait(TimeLimit); senderThread->requestInterruption(); - QVERIFY(senderThread->wait(300)); + QVERIFY(senderThread->wait()); for (int i = 0; i < ThreadCount; ++i) { threads[i]->quit(); - QVERIFY(threads[i]->wait(300)); + QVERIFY(threads[i]->wait()); delete threads[i]; } } - QCOMPARE(countedStructObjectsCount.load(), 0u); + QCOMPARE(countedStructObjectsCount.loadRelaxed(), 0u); } QTEST_MAIN(tst_QObjectRace) diff --git a/tests/auto/other/toolsupport/tst_toolsupport.cpp b/tests/auto/other/toolsupport/tst_toolsupport.cpp index f31a755f9e..ab7bca8322 100644 --- a/tests/auto/other/toolsupport/tst_toolsupport.cpp +++ b/tests/auto/other/toolsupport/tst_toolsupport.cpp @@ -126,20 +126,20 @@ void tst_toolsupport::offsets_data() #ifdef Q_PROCESSOR_X86 // x86 32-bit has weird alignment rules. Refer to QtPrivate::AlignOf in // qglobal.h for more details. - data << 168 << 248; + data << 152 << 224; #else - data << 172 << 248; + data << 156 << 224; #endif } #endif { QTest::newRow("QDateTimePrivate::m_msecs") - << pmm_to_offsetof(&QDateTimePrivate::m_msecs) << 0 << 0; + << pmm_to_offsetof(&QDateTimePrivate::m_msecs) << 8 << 8; QTest::newRow("QDateTimePrivate::m_status") - << pmm_to_offsetof(&QDateTimePrivate::m_status) << 8 << 8; + << pmm_to_offsetof(&QDateTimePrivate::m_status) << 4 << 4; QTest::newRow("QDateTimePrivate::m_offsetFromUtc") - << pmm_to_offsetof(&QDateTimePrivate::m_offsetFromUtc) << 12 << 12; + << pmm_to_offsetof(&QDateTimePrivate::m_offsetFromUtc) << 16 << 16; QTest::newRow("QDateTimePrivate::m_timeZone") << pmm_to_offsetof(&QDateTimePrivate::m_timeZone) << 20 << 24; } diff --git a/tests/auto/printsupport/kernel/qprinter/tst_qprinter.cpp b/tests/auto/printsupport/kernel/qprinter/tst_qprinter.cpp index abe4325278..7529bad833 100644 --- a/tests/auto/printsupport/kernel/qprinter/tst_qprinter.cpp +++ b/tests/auto/printsupport/kernel/qprinter/tst_qprinter.cpp @@ -1315,7 +1315,9 @@ void tst_QPrinter::pageSize() // Test set/get QPrinter::PaperSize expected = QPrinter::A4; QPrinterInfo info = QPrinterInfo::printerInfo(native.printerName()); - foreach (QPrinter::PaperSize supported, info.supportedPaperSizes()) { + const auto &pageSizes = info.supportedPageSizes(); + for (const auto &pageSize : pageSizes) { + const QPrinter::PaperSize supported = QPrinter::PaperSize(pageSize.id()); if (supported != QPrinter::Custom && supported != native.paperSize()) { expected = supported; break; @@ -1359,7 +1361,9 @@ void tst_QPrinter::paperSize() // Test set/get QPrinter::PaperSize expected = QPrinter::A4; QPrinterInfo info = QPrinterInfo::printerInfo(native.printerName()); - foreach (QPrinter::PaperSize supported, info.supportedPaperSizes()) { + const auto &pageSizes = info.supportedPageSizes(); + for (const auto &pageSize : pageSizes) { + const QPrinter::PaperSize supported = QPrinter::PaperSize(pageSize.id()); if (supported != QPrinter::Custom && supported != native.paperSize()) { expected = supported; break; diff --git a/tests/auto/printsupport/kernel/qprinterinfo/tst_qprinterinfo.cpp b/tests/auto/printsupport/kernel/qprinterinfo/tst_qprinterinfo.cpp index 92a06cda00..81b49a3a87 100644 --- a/tests/auto/printsupport/kernel/qprinterinfo/tst_qprinterinfo.cpp +++ b/tests/auto/printsupport/kernel/qprinterinfo/tst_qprinterinfo.cpp @@ -94,17 +94,16 @@ QString tst_QPrinterInfo::getDefaultPrinterFromSystem() command << "lpstat" << "-d"; QString output = getOutputFromCommand(command); - QRegExp noDefaultReg("[^:]*no .*default"); - int pos = noDefaultReg.indexIn(output); - if (pos >= 0) { + QRegularExpression noDefaultReg("[^:]*no .*default"); + QRegularExpressionMatch match; + match = noDefaultReg.match(output); + if (match.hasMatch()) return QString(); - } - QRegExp defaultReg("default.*: *([a-zA-Z0-9_-]+)"); - defaultReg.indexIn(output); - printer = defaultReg.cap(1); + QRegularExpression defaultReg("default.*: *([a-zA-Z0-9_-]+)"); + match = defaultReg.match(output); + printer = match.captured(1); #endif // Q_OS_UNIX - return printer; } @@ -121,10 +120,12 @@ QStringList tst_QPrinterInfo::getPrintersFromSystem() QString output = getOutputFromCommand(command); QStringList list = output.split(QChar::fromLatin1('\n')); - QRegExp reg("^[Pp]rinter ([.a-zA-Z0-9-_@]+)"); + QRegularExpression reg("^[Pp]rinter ([.a-zA-Z0-9-_@]+)"); + QRegularExpressionMatch match; for (int c = 0; c < list.size(); ++c) { - if (reg.indexIn(list[c]) >= 0) { - QString printer = reg.cap(1); + match = reg.match(list[c]); + if (match.hasMatch()) { + QString printer = match.captured(1); ans << printer; } } @@ -300,8 +301,13 @@ void tst_QPrinterInfo::testConstructors() QCOMPARE(copy1.supportsCustomPageSizes(), printers.at(i).supportsCustomPageSizes()); QCOMPARE(copy1.minimumPhysicalPageSize(), printers.at(i).minimumPhysicalPageSize()); QCOMPARE(copy1.maximumPhysicalPageSize(), printers.at(i).maximumPhysicalPageSize()); - QCOMPARE(copy1.supportedPaperSizes(), printers.at(i).supportedPaperSizes()); + QCOMPARE(copy1.supportedPageSizes(), printers.at(i).supportedPageSizes()); +#if QT_DEPRECATED_SINCE(5, 3) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED QCOMPARE(copy1.supportedSizesWithNames(), printers.at(i).supportedSizesWithNames()); +QT_WARNING_POP +#endif QCOMPARE(copy1.supportedResolutions(), printers.at(i).supportedResolutions()); QCOMPARE(copy1.defaultDuplexMode(), printers.at(i).defaultDuplexMode()); QCOMPARE(copy1.supportedDuplexModes(), printers.at(i).supportedDuplexModes()); @@ -321,8 +327,13 @@ void tst_QPrinterInfo::testConstructors() QCOMPARE(copy2.supportsCustomPageSizes(), printers.at(i).supportsCustomPageSizes()); QCOMPARE(copy2.minimumPhysicalPageSize(), printers.at(i).minimumPhysicalPageSize()); QCOMPARE(copy2.maximumPhysicalPageSize(), printers.at(i).maximumPhysicalPageSize()); - QCOMPARE(copy2.supportedPaperSizes(), printers.at(i).supportedPaperSizes()); + QCOMPARE(copy2.supportedPageSizes(), printers.at(i).supportedPageSizes()); +#if QT_DEPRECATED_SINCE(5, 3) + QT_WARNING_PUSH + QT_WARNING_DISABLE_DEPRECATED QCOMPARE(copy2.supportedSizesWithNames(), printers.at(i).supportedSizesWithNames()); + QT_WARNING_POP +#endif QCOMPARE(copy2.supportedResolutions(), printers.at(i).supportedResolutions()); QCOMPARE(copy2.defaultDuplexMode(), printers.at(i).defaultDuplexMode()); QCOMPARE(copy2.supportedDuplexModes(), printers.at(i).supportedDuplexModes()); diff --git a/tests/auto/sql/kernel/qsqldatabase/tst_databases.h b/tests/auto/sql/kernel/qsqldatabase/tst_databases.h index 55875359ff..174db2863e 100644 --- a/tests/auto/sql/kernel/qsqldatabase/tst_databases.h +++ b/tests/auto/sql/kernel/qsqldatabase/tst_databases.h @@ -34,7 +34,8 @@ #include <QSqlDriver> #include <QSqlError> #include <QSqlQuery> -#include <QRegExp> +#include <QRegularExpression> +#include <QRegularExpressionMatch> #include <QDir> #include <QScopedPointer> #include <QVariant> @@ -511,13 +512,13 @@ public: QSqlQuery q( "SELECT banner FROM v$version", db ); q.next(); - QRegExp vers( "([0-9]+)\\.[0-9\\.]+[0-9]" ); - - if ( vers.indexIn( q.value( 0 ).toString() ) ) { + QRegularExpression vers("([0-9]+)\\.[0-9\\.]+[0-9]"); + QRegularExpressionMatch match = vers.match(q.value(0).toString()); + if (match.hasMatch()) { bool ok; - ver = vers.cap( 1 ).toInt( &ok ); + ver = match.captured(1).toInt(&ok); - if ( !ok ) + if (!ok) ver = -1; } diff --git a/tests/auto/sql/kernel/qsqldatabase/tst_qsqldatabase.cpp b/tests/auto/sql/kernel/qsqldatabase/tst_qsqldatabase.cpp index f309231b10..c59250e36e 100644 --- a/tests/auto/sql/kernel/qsqldatabase/tst_qsqldatabase.cpp +++ b/tests/auto/sql/kernel/qsqldatabase/tst_qsqldatabase.cpp @@ -34,7 +34,7 @@ #include <qsqlrecord.h> #include <qsqlfield.h> #include <qsqlindex.h> -#include <qregexp.h> +#include <qregularexpression.h> #include <qvariant.h> #include <qdatetime.h> #include <qdebug.h> @@ -228,7 +228,7 @@ struct FieldDef { QString fieldName() const { QString rt = typeName; - rt.replace(QRegExp("\\s"), QString("_")); + rt.replace(QRegularExpression("\\s"), QString("_")); int i = rt.indexOf(QLatin1Char('(')); if (i == -1) i = rt.length(); diff --git a/tests/auto/sql/kernel/qsqlerror/tst_qsqlerror.cpp b/tests/auto/sql/kernel/qsqlerror/tst_qsqlerror.cpp index 08c6039e37..871ac24be4 100644 --- a/tests/auto/sql/kernel/qsqlerror/tst_qsqlerror.cpp +++ b/tests/auto/sql/kernel/qsqlerror/tst_qsqlerror.cpp @@ -42,10 +42,13 @@ public: virtual ~tst_QSqlError(); private slots: +#if QT_DEPRECATED_SINCE(5, 1) void getSetCheck(); +#endif void construction(); void moveOperator(); void operators(); + void qtbug_74575(); }; tst_QSqlError::tst_QSqlError() @@ -56,6 +59,7 @@ tst_QSqlError::~tst_QSqlError() { } +#if QT_DEPRECATED_SINCE(5, 1) // Testing get/set functions void tst_QSqlError::getSetCheck() { @@ -82,14 +86,28 @@ void tst_QSqlError::getSetCheck() obj1.setNumber(INT_MAX); QCOMPARE(INT_MAX, obj1.number()); } +#endif void tst_QSqlError::construction() { - QSqlError obj1("drivertext", "databasetext", QSqlError::UnknownError, 123); +#if QT_DEPRECATED_SINCE(5, 3) + { + QSqlError obj1("drivertext", "databasetext", QSqlError::UnknownError, 123); + QCOMPARE(obj1.driverText(), QString("drivertext")); + QCOMPARE(obj1.databaseText(), QString("databasetext")); + QCOMPARE(obj1.type(), QSqlError::UnknownError); + QCOMPARE(obj1.number(), 123); + QCOMPARE(obj1.nativeErrorCode(), QStringLiteral("123")); + QVERIFY(obj1.isValid()); + } +#endif + QSqlError obj1("drivertext", "databasetext", QSqlError::UnknownError, QStringLiteral("123")); QCOMPARE(obj1.driverText(), QString("drivertext")); QCOMPARE(obj1.databaseText(), QString("databasetext")); QCOMPARE(obj1.type(), QSqlError::UnknownError); +#if QT_DEPRECATED_SINCE(5, 3) QCOMPARE(obj1.number(), 123); +#endif QCOMPARE(obj1.nativeErrorCode(), QStringLiteral("123")); QVERIFY(obj1.isValid()); @@ -97,7 +115,9 @@ void tst_QSqlError::construction() QCOMPARE(obj2.driverText(), obj1.driverText()); QCOMPARE(obj2.databaseText(), obj1.databaseText()); QCOMPARE(obj2.type(), obj1.type()); +#if QT_DEPRECATED_SINCE(5, 3) QCOMPARE(obj2.number(), obj1.number()); +#endif QCOMPARE(obj2.nativeErrorCode(), obj1.nativeErrorCode()); QVERIFY(obj2.isValid()); @@ -105,7 +125,9 @@ void tst_QSqlError::construction() QCOMPARE(obj3.driverText(), obj2.driverText()); QCOMPARE(obj3.databaseText(), obj2.databaseText()); QCOMPARE(obj3.type(), obj2.type()); +#if QT_DEPRECATED_SINCE(5, 3) QCOMPARE(obj3.number(), obj2.number()); +#endif QCOMPARE(obj3.nativeErrorCode(), obj2.nativeErrorCode()); QVERIFY(obj3.isValid()); @@ -113,8 +135,11 @@ void tst_QSqlError::construction() QVERIFY(!obj4.isValid()); QCOMPARE(obj4.driverText(), QString()); QCOMPARE(obj4.databaseText(), QString()); + QCOMPARE(obj4.text(), QString()); QCOMPARE(obj4.type(), QSqlError::NoError); +#if QT_DEPRECATED_SINCE(5, 3) QCOMPARE(obj4.number(), -1); +#endif QCOMPARE(obj4.nativeErrorCode(), QString()); QSqlError obj5(QStringLiteral("drivertext"), QStringLiteral("databasetext"), @@ -122,7 +147,9 @@ void tst_QSqlError::construction() QCOMPARE(obj5.driverText(), QString("drivertext")); QCOMPARE(obj5.databaseText(), QString("databasetext")); QCOMPARE(obj5.type(), QSqlError::UnknownError); +#if QT_DEPRECATED_SINCE(5, 3) QCOMPARE(obj5.number(), 123); +#endif QCOMPARE(obj5.nativeErrorCode(), QStringLiteral("123")); QVERIFY(obj5.isValid()); @@ -131,17 +158,31 @@ void tst_QSqlError::construction() QCOMPARE(obj6.driverText(), QString("drivertext")); QCOMPARE(obj6.databaseText(), QString("databasetext")); QCOMPARE(obj6.type(), QSqlError::UnknownError); +#if QT_DEPRECATED_SINCE(5, 3) QCOMPARE(obj6.number(), 0); +#endif QCOMPARE(obj6.nativeErrorCode(), QStringLiteral("Err123")); QVERIFY(obj6.isValid()); - // Default constructed object as constructed before Qt 5.3 - QSqlError obj7(QString(), QString(), QSqlError::NoError, -1); +#if QT_DEPRECATED_SINCE(5, 3) + { + // Default constructed object as constructed before Qt 5.3 + QSqlError obj7(QString(), QString(), QSqlError::NoError, -1); + QVERIFY(!obj7.isValid()); + QCOMPARE(obj7.driverText(), QString()); + QCOMPARE(obj7.databaseText(), QString()); + QCOMPARE(obj7.type(), QSqlError::NoError); + QCOMPARE(obj7.number(), -1); + QCOMPARE(obj7.nativeErrorCode(), QString()); + } +#endif + + // Default constructed object + QSqlError obj7; QVERIFY(!obj7.isValid()); QCOMPARE(obj7.driverText(), QString()); QCOMPARE(obj7.databaseText(), QString()); QCOMPARE(obj7.type(), QSqlError::NoError); - QCOMPARE(obj7.number(), -1); QCOMPARE(obj7.nativeErrorCode(), QString()); // Move constructor @@ -149,37 +190,59 @@ void tst_QSqlError::construction() QCOMPARE(obj8.driverText(), obj2.driverText()); QCOMPARE(obj8.databaseText(), obj2.databaseText()); QCOMPARE(obj8.type(), obj2.type()); +#if QT_DEPRECATED_SINCE(5, 3) QCOMPARE(obj8.number(), obj2.number()); +#endif QCOMPARE(obj8.nativeErrorCode(), obj2.nativeErrorCode()); QVERIFY(obj8.isValid()); } void tst_QSqlError::moveOperator() { - QSqlError obj1("drivertext", "databasetext", QSqlError::UnknownError, 123), obj2; + QSqlError obj1("drivertext", "databasetext", QSqlError::UnknownError, QStringLiteral("123")), obj2; obj2 = std::move(obj1); QCOMPARE(obj2.driverText(), QString("drivertext")); QCOMPARE(obj2.databaseText(), QString("databasetext")); QCOMPARE(obj2.type(), QSqlError::UnknownError); +#if QT_DEPRECATED_SINCE(5, 3) QCOMPARE(obj2.number(), 123); +#endif QCOMPARE(obj2.nativeErrorCode(), QStringLiteral("123")); QVERIFY(obj2.isValid()); } void tst_QSqlError::operators() { - QSqlError error1; - QSqlError error2; - QSqlError error3; - - error1.setType(QSqlError::NoError); - error2.setType(QSqlError::NoError); - error3.setType(QSqlError::UnknownError); + QSqlError error1(QString(), QString(), QSqlError::NoError); + QSqlError error2(QString(), QString(), QSqlError::NoError); + QSqlError error3(QString(), QString(), QSqlError::UnknownError); QCOMPARE(error1, error2); QVERIFY(error1 != error3); } +void tst_QSqlError::qtbug_74575() +{ + const QString driverText(QStringLiteral("drivertext")); + const QString databaseText(QStringLiteral("databasetext")); + const QString databaseTextNewline(QStringLiteral("databasetext\n")); + + QSqlError error1(driverText, databaseText, + QSqlError::UnknownError, QStringLiteral("123")); + QCOMPARE(error1.text(), databaseText + QLatin1Char(' ') + driverText); + + QSqlError error2(QString(), databaseText, + QSqlError::UnknownError, QStringLiteral("123")); + QCOMPARE(error2.text(), databaseText); + + QSqlError error3(driverText, QString(), + QSqlError::UnknownError, QStringLiteral("123")); + QCOMPARE(error3.text(), driverText); + + QSqlError error4(driverText, databaseTextNewline, + QSqlError::UnknownError, QStringLiteral("123")); + QCOMPARE(error4.text(), databaseTextNewline + driverText); +} QTEST_MAIN(tst_QSqlError) #include "tst_qsqlerror.moc" diff --git a/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp b/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp index fd7f24f308..c75767a513 100644 --- a/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp +++ b/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp @@ -185,12 +185,6 @@ private slots: void mysql_timeType_data() { generic_data("QMYSQL"); } void mysql_timeType(); -#ifdef NOT_READY_YET - void task_229811(); - void task_229811_data() { generic_data(); } - void task_234422_data() { generic_data(); } - void task_234422(); -#endif void task_217003_data() { generic_data(); } void task_217003(); @@ -3462,90 +3456,6 @@ void tst_QSqlQuery::crashQueryOnCloseDatabase() } } -#ifdef NOT_READY_YET -// For task: 229811 -void tst_QSqlQuery::task_229811() -{ - QFETCH( QString, dbName ); - QSqlDatabase db = QSqlDatabase::database( dbName ); - CHECK_DATABASE( db ); - - if (!db.driverName().startsWith( "QODBC" )) return; - - QSqlQuery q( db ); - - const QString tableName(qTableName("task_229811", __FILE__, db)); - - if ( !q.exec( "CREATE TABLE " + tableName + " (Word varchar(20))" ) ) { - qDebug() << "Warning" << q.lastError(); - } - - QVERIFY_SQL( q, exec( "INSERT INTO " + tableName + " values ('Albert')" ) ); - QVERIFY_SQL( q, exec( "INSERT INTO " + tableName + " values ('Beehive')" ) ); - QVERIFY_SQL( q, exec( "INSERT INTO " + tableName + " values ('Alimony')" ) ); - QVERIFY_SQL( q, exec( "INSERT INTO " + tableName + " values ('Bohemian')" ) ); - QVERIFY_SQL( q, exec( "INSERT INTO " + tableName + " values ('AllStars')" ) ); - - - QString stmt = "SELECT * FROM " + tableName + " WHERE Word LIKE :name"; - QVERIFY_SQL(q,prepare(stmt)); - q.bindValue(":name", "A%"); - QVERIFY_SQL(q,exec()); - - QVERIFY(q.isActive()); - QVERIFY(q.isSelect()); - QVERIFY(q.first()); - - QSqlRecord rec = q.record(); - QCOMPARE(rec.field(0).value().toString(), QString("Albert")); - QVERIFY(q.next()); - rec = q.record(); - QCOMPARE(rec.field(0).value().toString(), QString("Alimony")); - QVERIFY(q.next()); - rec = q.record(); - QCOMPARE(rec.field(0).value().toString(),QString("AllStars")); - - q.exec("DROP TABLE " + tableName ); -} - -void tst_QSqlQuery::task_234422() -{ - QFETCH( QString, dbName ); - QSqlDatabase db = QSqlDatabase::database( dbName ); - CHECK_DATABASE( db ); - - QSqlQuery query(db); - QStringList m_airlines; - QStringList m_countries; - - m_airlines << "Lufthansa" << "SAS" << "United" << "KLM" << "Aeroflot"; - m_countries << "DE" << "SE" << "US" << "NL" << "RU"; - - const QString tableName(qTableName("task_234422", __FILE__, db)); - - QVERIFY_SQL(query,exec("CREATE TABLE " + tableName + " (id int primary key, " - "name varchar(20), homecountry varchar(2))")); - for (int i = 0; i < m_airlines.count(); ++i) { - QVERIFY(query.exec(QString("INSERT INTO " + tableName + " values(%1, '%2', '%3')") - .arg(i).arg(m_airlines[i], m_countries[i]))); - } - - QVERIFY_SQL(query, exec("SELECT name FROM " + tableName)); - QVERIFY(query.isSelect()); - QVERIFY(query.first()); - QVERIFY(query.next()); - QCOMPARE(query.at(), 1); - - QSqlQuery query2(query); - - QVERIFY_SQL(query2,exec()); - QVERIFY(query2.first()); - QCOMPARE(query2.at(), 0); - QCOMPARE(query.at(), 1); -} - -#endif - void tst_QSqlQuery::task_233829() { QFETCH( QString, dbName ); diff --git a/tests/auto/sql/kernel/qsqlthread/tst_qsqlthread.cpp b/tests/auto/sql/kernel/qsqlthread/tst_qsqlthread.cpp index 09a842eb83..aa2cc05b56 100644 --- a/tests/auto/sql/kernel/qsqlthread/tst_qsqlthread.cpp +++ b/tests/auto/sql/kernel/qsqlthread/tst_qsqlthread.cpp @@ -345,7 +345,7 @@ void tst_QSqlThread::cleanupTestCase() void tst_QSqlThread::init() { threadFinishedCount = 0; - counter.store(4); + counter.storeRelaxed(4); } void tst_QSqlThread::cleanup() diff --git a/tests/auto/sql/models/qsqltablemodel/tst_qsqltablemodel.cpp b/tests/auto/sql/models/qsqltablemodel/tst_qsqltablemodel.cpp index b617151a36..44dd4a74cf 100644 --- a/tests/auto/sql/models/qsqltablemodel/tst_qsqltablemodel.cpp +++ b/tests/auto/sql/models/qsqltablemodel/tst_qsqltablemodel.cpp @@ -32,6 +32,7 @@ #include <QtSql> #include <QtSql/private/qsqltablemodel_p.h> #include <QThread> +#include <QElapsedTimer> const QString test(qTableName("test", __FILE__, QSqlDatabase())), test2(qTableName("test2", __FILE__, QSqlDatabase())), @@ -1804,12 +1805,12 @@ void tst_QSqlTableModel::sqlite_bigTable() QSqlQuery q(db); QVERIFY_SQL( q, exec("create table "+bigtable+"(id int primary key, name varchar)")); QVERIFY_SQL( q, prepare("insert into "+bigtable+"(id, name) values (?, ?)")); - QTime startTime; - startTime.start(); + QElapsedTimer timing; + timing.start(); for (int i = 0; i < 10000; ++i) { q.addBindValue(i); q.addBindValue(QString::number(i)); - if(i%1000 == 0 && startTime.elapsed() > 5000) + if (i % 1000 == 0 && timing.elapsed() > 5000) qDebug() << i << "records written"; QVERIFY_SQL( q, exec()); } diff --git a/tests/auto/testlib/initmain/initmain.pro b/tests/auto/testlib/initmain/initmain.pro new file mode 100644 index 0000000000..4c12aba08d --- /dev/null +++ b/tests/auto/testlib/initmain/initmain.pro @@ -0,0 +1,5 @@ +CONFIG += testcase +SOURCES += tst_initmain.cpp +QT = core testlib + +TARGET = tst_initmain diff --git a/tests/auto/testlib/initmain/tst_initmain.cpp b/tests/auto/testlib/initmain/tst_initmain.cpp new file mode 100644 index 0000000000..f08f82c5ec --- /dev/null +++ b/tests/auto/testlib/initmain/tst_initmain.cpp @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtCore/QCoreApplication> +#include <QtTest/QtTest> + +class tst_InitMain : public QObject +{ + Q_OBJECT + +public: + static void initMain() { m_initMainCalled = true; } + +private slots: + void testcase(); + +private: + static bool m_initMainCalled; +}; + +bool tst_InitMain::m_initMainCalled = false; + +void tst_InitMain::testcase() +{ + QVERIFY(m_initMainCalled); +} + +QTEST_MAIN(tst_InitMain) + +#include "tst_initmain.moc" diff --git a/tests/auto/testlib/qabstractitemmodeltester/tst_qabstractitemmodeltester.cpp b/tests/auto/testlib/qabstractitemmodeltester/tst_qabstractitemmodeltester.cpp index 60aa350145..b305eee0ec 100644 --- a/tests/auto/testlib/qabstractitemmodeltester/tst_qabstractitemmodeltester.cpp +++ b/tests/auto/testlib/qabstractitemmodeltester/tst_qabstractitemmodeltester.cpp @@ -63,7 +63,7 @@ void tst_QAbstractItemModelTester::stringListModel() model.setStringList(QStringList() << "a" << "e" << "plop" << "b" << "c"); proxy.setDynamicSortFilter(true); - proxy.setFilterRegExp(QRegExp("[^b]")); + proxy.setFilterRegularExpression(QRegularExpression("[^b]")); } void tst_QAbstractItemModelTester::treeWidgetModel() diff --git a/tests/auto/testlib/qsignalspy/tst_qsignalspy.cpp b/tests/auto/testlib/qsignalspy/tst_qsignalspy.cpp index df241c030e..9555c2a844 100644 --- a/tests/auto/testlib/qsignalspy/tst_qsignalspy.cpp +++ b/tests/auto/testlib/qsignalspy/tst_qsignalspy.cpp @@ -65,6 +65,11 @@ private slots: void waitFunctionPointer_signalEmittedLater(); void waitFunctionPointer_signalEmittedTooLate(); void waitFunctionPointer_signalEmittedMultipleTimes(); + + void spyOnMetaMethod(); + + void spyOnMetaMethod_invalid(); + void spyOnMetaMethod_invalid_data(); }; class QtTestObject: public QObject @@ -432,5 +437,52 @@ void tst_QSignalSpy::waitFunctionPointer_signalEmittedMultipleTimes() QCOMPARE(spy.count(), 3); } +void tst_QSignalSpy::spyOnMetaMethod() +{ + QObject obj; + auto mo = obj.metaObject(); + + auto signalIndex = mo->indexOfSignal("objectNameChanged(QString)"); + QVERIFY(signalIndex != -1); + + auto signal = mo->method(signalIndex); + QVERIFY(signal.isValid()); + QCOMPARE(signal.methodType(), QMetaMethod::Signal); + + QSignalSpy spy(&obj, signal); + QVERIFY(spy.isValid()); + + obj.setObjectName("A new object name"); + QCOMPARE(spy.count(), 1); +} + +Q_DECLARE_METATYPE(QMetaMethod); +void tst_QSignalSpy::spyOnMetaMethod_invalid() +{ + QFETCH(QObject*, object); + QFETCH(QMetaMethod, signal); + + QSignalSpy spy(object, signal); + QVERIFY(!spy.isValid()); +} + +void tst_QSignalSpy::spyOnMetaMethod_invalid_data() +{ + QTest::addColumn<QObject*>("object"); + QTest::addColumn<QMetaMethod>("signal"); + + QTest::addRow("Invalid object") + << static_cast<QObject*>(nullptr) + << QMetaMethod(); + + QTest::addRow("Empty signal") + << new QObject(this) + << QMetaMethod(); + + QTest::addRow("Method is not a signal") + << new QObject(this) + << QObject::staticMetaObject.method(QObject::staticMetaObject.indexOfMethod("deleteLater()")); +} + QTEST_MAIN(tst_QSignalSpy) #include "tst_qsignalspy.moc" diff --git a/tests/auto/testlib/selftests/alive/.gitignore b/tests/auto/testlib/selftests/alive/.gitignore deleted file mode 100644 index 561285c5d0..0000000000 --- a/tests/auto/testlib/selftests/alive/.gitignore +++ /dev/null @@ -1 +0,0 @@ -tst_alive diff --git a/tests/auto/testlib/selftests/alive/alive.pro b/tests/auto/testlib/selftests/alive/alive.pro deleted file mode 100644 index bda0db2282..0000000000 --- a/tests/auto/testlib/selftests/alive/alive.pro +++ /dev/null @@ -1,10 +0,0 @@ -SOURCES += tst_alive.cpp -QT = core testlib - -mac:CONFIG -= app_bundle -CONFIG -= debug_and_release_target - - -TARGET = alive - -include($$QT_SOURCE_TREE/src/testlib/selfcover.pri) diff --git a/tests/auto/testlib/selftests/alive/qtestalive.cpp b/tests/auto/testlib/selftests/alive/qtestalive.cpp deleted file mode 100644 index 0200f2a563..0000000000 --- a/tests/auto/testlib/selftests/alive/qtestalive.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include <qcoreapplication.h> -#include <qcoreevent.h> -#include <qthread.h> - -class QTestAliveEvent: public QEvent -{ -public: - - enum { AliveEventType = QEvent::User + 422 }; - - explicit inline QTestAliveEvent(int aSequenceId) - : QEvent(QEvent::Type(AliveEventType)), seqId(aSequenceId) - {} - inline int sequenceId() const { return seqId; } - -private: - int seqId; -}; - -class QTestAlivePinger: public QObject -{ -public: - QTestAlivePinger(QObject *receiver, QObject *parent = 0); - bool event(QEvent *e); - -protected: - void timerEvent(QTimerEvent *event); - -private: - QObject *rec; - int timerId; - int currentSequenceId; - int lastSequenceId; -}; - -QTestAlivePinger::QTestAlivePinger(QObject *receiver, QObject *parent) - : QObject(parent), rec(receiver), currentSequenceId(0), lastSequenceId(0) -{ - if (!rec) - qFatal("Null receiver object passed to QTestAlivePinger::QTestAlivePinger()"); - timerId = startTimer(850); -} - -bool QTestAlivePinger::event(QEvent *event) -{ - // pong received - if (int(event->type()) == QTestAliveEvent::AliveEventType) { - QTestAliveEvent *e = static_cast<QTestAliveEvent *>(event); - //qDebug("PONG %d received", e->sequenceId()); - // if the events are not delivered in order, we don't care. - if (e->sequenceId() > lastSequenceId) - lastSequenceId = e->sequenceId(); - return true; - } - return QObject::event(event); -} - -void QTestAlivePinger::timerEvent(QTimerEvent *event) -{ - if (event->timerId() != timerId) - return; - - if (lastSequenceId < currentSequenceId - 2) { - qWarning("TEST LAGS %d PINGS behind!", currentSequenceId - lastSequenceId); - } - ++currentSequenceId; - //qDebug("PING %d", currentSequenceId); - QCoreApplication::postEvent(rec, new QTestAliveEvent(currentSequenceId)); -} - -class QTestAlive: public QThread -{ -public: - QTestAlive(QObject *parent = 0); - ~QTestAlive(); - void run(); - - bool event(QEvent *e); - -private: - QTestAlivePinger *pinger; -}; - -QTestAlive::QTestAlive(QObject *parent) - : QThread(parent), pinger(0) -{ -} - -QTestAlive::~QTestAlive() -{ - quit(); - while (isRunning()); -} - -bool QTestAlive::event(QEvent *e) -{ - if (int(e->type()) == QTestAliveEvent::AliveEventType && pinger) { - // ping received, send back the pong - //qDebug("PONG %d", static_cast<QTestAliveEvent *>(e)->sequenceId()); - QCoreApplication::postEvent(pinger, - new QTestAliveEvent(static_cast<QTestAliveEvent *>(e)->sequenceId())); - return true; - } - return QThread::event(e); -} - -void QTestAlive::run() -{ - if (!QCoreApplication::instance()) - qFatal("QTestAlive::run(): Cannot start QTestAlive without a QCoreApplication instance."); - - QTestAlivePinger p(this); - pinger = &p; - exec(); - pinger = 0; -} - - diff --git a/tests/auto/testlib/selftests/blacklisted/tst_blacklisted.cpp b/tests/auto/testlib/selftests/blacklisted/tst_blacklisted.cpp index 2f6d633e9d..49c08982ad 100644 --- a/tests/auto/testlib/selftests/blacklisted/tst_blacklisted.cpp +++ b/tests/auto/testlib/selftests/blacklisted/tst_blacklisted.cpp @@ -75,6 +75,17 @@ void tst_Blacklisted::xpass() QVERIFY2(true, "This test should BXPASS"); } +#ifndef Q_OS_WIN +#include <signal.h> +#include <setjmp.h> + +static jmp_buf state; +static void abort_handler(int signal) +{ + longjmp(state, 1); +} +#endif + void tst_Blacklisted::messages() { qWarning("This is a warning that should not appear in silent test output"); @@ -83,7 +94,15 @@ void tst_Blacklisted::messages() qCritical("This is a critical message that should not appear in silent test output"); qInfo("This is an info message that should not appear in silent test output"); QTestLog::info("This is an internal testlib info message that should not appear in silent test output", __FILE__, __LINE__); - qFatal("This is a fatal error message that should still appear in silent test output"); + +#ifndef Q_OS_WIN + // We're testing qFatal, but we don't want to actually std::abort() ! + auto prior = signal(SIGABRT, abort_handler); + if (setjmp(state)) + signal(SIGABRT, prior); + else +#endif + qFatal("This is a fatal error message that should still appear in silent test output"); } QTEST_MAIN(tst_Blacklisted) diff --git a/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp b/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp index 8e2c7694a5..fb01b19d16 100644 --- a/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp +++ b/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp @@ -256,7 +256,7 @@ void tst_Cmptest::compare_boolfuncs() namespace { template <typename T> -T *null() Q_DECL_NOTHROW { return nullptr; } +T *null() noexcept { return nullptr; } } void tst_Cmptest::compare_to_nullptr() @@ -466,6 +466,8 @@ void tst_Cmptest::compareQPixmaps_data() const QPixmap pixmap1(xpmPixmapData1); const QPixmap pixmap2(xpmPixmapData2); const QPixmap pixmap3(xpmPixmapData3); + QPixmap pixmapWrongDpr = pixmap1.scaled(2, 2); + pixmapWrongDpr.setDevicePixelRatio(2); QTest::newRow("both null") << QPixmap() << QPixmap(); QTest::newRow("one null") << QPixmap() << pixmap1; @@ -473,6 +475,7 @@ void tst_Cmptest::compareQPixmaps_data() QTest::newRow("equal") << pixmap1 << pixmap1; QTest::newRow("different size") << pixmap1 << pixmap3; QTest::newRow("different pixels") << pixmap1 << pixmap2; + QTest::newRow("different dpr") << pixmap1 << pixmapWrongDpr; } void tst_Cmptest::compareQPixmaps() @@ -492,6 +495,8 @@ void tst_Cmptest::compareQImages_data() const QImage image2(QPixmap(xpmPixmapData2).toImage()); const QImage image1Indexed = image1.convertToFormat(QImage::Format_Indexed8); const QImage image3(QPixmap(xpmPixmapData3).toImage()); + QImage imageWrongDpr = image1.scaled(2, 2); + imageWrongDpr.setDevicePixelRatio(2); QTest::newRow("both null") << QImage() << QImage(); QTest::newRow("one null") << QImage() << image1; @@ -500,6 +505,7 @@ void tst_Cmptest::compareQImages_data() QTest::newRow("different size") << image1 << image3; QTest::newRow("different format") << image1 << image1Indexed; QTest::newRow("different pixels") << image1 << image2; + QTest::newRow("different dpr") << image1 << imageWrongDpr; } void tst_Cmptest::compareQImages() diff --git a/tests/auto/testlib/selftests/expected_cmptest.lightxml b/tests/auto/testlib/selftests/expected_cmptest.lightxml index 58b5a5e530..f108933585 100644 --- a/tests/auto/testlib/selftests/expected_cmptest.lightxml +++ b/tests/auto/testlib/selftests/expected_cmptest.lightxml @@ -209,6 +209,12 @@ <DataTag><![CDATA[different pixels]]></DataTag> <Description><![CDATA[Compared values are not the same]]></Description> </Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp" line="0"> + <DataTag><![CDATA[different dpr]]></DataTag> + <Description><![CDATA[Compared QPixmaps differ in device pixel ratio. + Actual (opA): 1 + Expected (opB): 2]]></Description> +</Incident> <Duration msecs="0"/> </TestFunction> <TestFunction name="compareQImages"> @@ -246,6 +252,12 @@ <DataTag><![CDATA[different pixels]]></DataTag> <Description><![CDATA[Compared values are not the same]]></Description> </Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp" line="0"> + <DataTag><![CDATA[different dpr]]></DataTag> + <Description><![CDATA[Compared QImages differ in device pixel ratio. + Actual (opA): 1 + Expected (opB): 2]]></Description> +</Incident> <Duration msecs="0"/> </TestFunction> <TestFunction name="compareQRegion"> diff --git a/tests/auto/testlib/selftests/expected_cmptest.tap b/tests/auto/testlib/selftests/expected_cmptest.tap index 238db2fc2b..dc9cb5c950 100644 --- a/tests/auto/testlib/selftests/expected_cmptest.tap +++ b/tests/auto/testlib/selftests/expected_cmptest.tap @@ -245,9 +245,9 @@ not ok 32 - compareQPixmaps(one null) found: 1 (opA).isNull() expected: 0 (opB).isNull() actual: 1 (opA).isNull() - at: tst_Cmptest::compareQPixmaps() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:483) + at: tst_Cmptest::compareQPixmaps() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:486) file: qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp - line: 483 + line: 486 ... not ok 33 - compareQPixmaps(other null) --- @@ -257,9 +257,9 @@ not ok 33 - compareQPixmaps(other null) found: 0 (opA).isNull() expected: 1 (opB).isNull() actual: 0 (opA).isNull() - at: tst_Cmptest::compareQPixmaps() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:483) + at: tst_Cmptest::compareQPixmaps() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:486) file: qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp - line: 483 + line: 486 ... ok 34 - compareQPixmaps(equal) not ok 35 - compareQPixmaps(different size) @@ -270,19 +270,31 @@ not ok 35 - compareQPixmaps(different size) found: 11x20 (opA) expected: 20x20 (opB) actual: 11x20 (opA) - at: tst_Cmptest::compareQPixmaps() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:483) + at: tst_Cmptest::compareQPixmaps() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:486) file: qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp - line: 483 + line: 486 ... not ok 36 - compareQPixmaps(different pixels) --- # Compared values are not the same - at: tst_Cmptest::compareQPixmaps() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:483) + at: tst_Cmptest::compareQPixmaps() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:486) file: qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp - line: 483 + line: 486 ... -ok 37 - compareQImages(both null) -not ok 38 - compareQImages(one null) +not ok 37 - compareQPixmaps(different dpr) + --- + type: QCOMPARE + message: Compared QPixmaps differ in device pixel ratio. + wanted: 2 (opB) + found: 1 (opA) + expected: 2 (opB) + actual: 1 (opA) + at: tst_Cmptest::compareQPixmaps() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:486) + file: qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp + line: 486 + ... +ok 38 - compareQImages(both null) +not ok 39 - compareQImages(one null) --- type: QCOMPARE message: Compared QImages differ. @@ -290,11 +302,11 @@ not ok 38 - compareQImages(one null) found: 1 (opA).isNull() expected: 0 (opB).isNull() actual: 1 (opA).isNull() - at: tst_Cmptest::compareQImages() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:510) + at: tst_Cmptest::compareQImages() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:516) file: qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp - line: 510 + line: 516 ... -not ok 39 - compareQImages(other null) +not ok 40 - compareQImages(other null) --- type: QCOMPARE message: Compared QImages differ. @@ -302,12 +314,12 @@ not ok 39 - compareQImages(other null) found: 0 (opA).isNull() expected: 1 (opB).isNull() actual: 0 (opA).isNull() - at: tst_Cmptest::compareQImages() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:510) + at: tst_Cmptest::compareQImages() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:516) file: qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp - line: 510 + line: 516 ... -ok 40 - compareQImages(equal) -not ok 41 - compareQImages(different size) +ok 41 - compareQImages(equal) +not ok 42 - compareQImages(different size) --- type: QCOMPARE message: Compared QImages differ in size. @@ -315,11 +327,11 @@ not ok 41 - compareQImages(different size) found: 11x20 (opA) expected: 20x20 (opB) actual: 11x20 (opA) - at: tst_Cmptest::compareQImages() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:510) + at: tst_Cmptest::compareQImages() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:516) file: qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp - line: 510 + line: 516 ... -not ok 42 - compareQImages(different format) +not ok 43 - compareQImages(different format) --- type: QCOMPARE message: Compared QImages differ in format. @@ -327,19 +339,31 @@ not ok 42 - compareQImages(different format) found: 6 (opA) expected: 3 (opB) actual: 6 (opA) - at: tst_Cmptest::compareQImages() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:510) + at: tst_Cmptest::compareQImages() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:516) file: qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp - line: 510 + line: 516 ... -not ok 43 - compareQImages(different pixels) +not ok 44 - compareQImages(different pixels) --- # Compared values are not the same - at: tst_Cmptest::compareQImages() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:510) + at: tst_Cmptest::compareQImages() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:516) + file: qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp + line: 516 + ... +not ok 45 - compareQImages(different dpr) + --- + type: QCOMPARE + message: Compared QImages differ in device pixel ratio. + wanted: 2 (opB) + found: 1 (opA) + expected: 2 (opB) + actual: 1 (opA) + at: tst_Cmptest::compareQImages() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:516) file: qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp - line: 510 + line: 516 ... -ok 44 - compareQRegion(equal-empty) -not ok 45 - compareQRegion(1-empty) +ok 46 - compareQRegion(equal-empty) +not ok 47 - compareQRegion(1-empty) --- type: QCOMPARE message: Compared values are not the same @@ -347,12 +371,12 @@ not ok 45 - compareQRegion(1-empty) found: QRegion(200x50+10+10) (rA) expected: QRegion(null) (rB) actual: QRegion(200x50+10+10) (rA) - at: tst_Cmptest::compareQRegion() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:533) + at: tst_Cmptest::compareQRegion() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:539) file: qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp - line: 533 + line: 539 ... -ok 46 - compareQRegion(equal) -not ok 47 - compareQRegion(different lists) +ok 48 - compareQRegion(equal) +not ok 49 - compareQRegion(different lists) --- type: QCOMPARE message: Compared values are not the same @@ -360,11 +384,11 @@ not ok 47 - compareQRegion(different lists) found: QRegion(200x50+10+10) (rA) expected: QRegion(2 rectangles, 50x200+100+200, 200x50+10+10) (rB) actual: QRegion(200x50+10+10) (rA) - at: tst_Cmptest::compareQRegion() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:533) + at: tst_Cmptest::compareQRegion() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:539) file: qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp - line: 533 + line: 539 ... -not ok 48 - compareQVector2D() +not ok 50 - compareQVector2D() --- type: QCOMPARE message: Compared values are not the same @@ -372,11 +396,11 @@ not ok 48 - compareQVector2D() found: QVector2D(1, 2) (v2a) expected: QVector2D(1, 3) (v2b) actual: QVector2D(1, 2) (v2a) - at: tst_Cmptest::compareQVector2D() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:542) + at: tst_Cmptest::compareQVector2D() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:548) file: qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp - line: 542 + line: 548 ... -not ok 49 - compareQVector3D() +not ok 51 - compareQVector3D() --- type: QCOMPARE message: Compared values are not the same @@ -384,11 +408,11 @@ not ok 49 - compareQVector3D() found: QVector3D(1, 2, 3) (v3a) expected: QVector3D(1, 3, 3) (v3b) actual: QVector3D(1, 2, 3) (v3a) - at: tst_Cmptest::compareQVector3D() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:551) + at: tst_Cmptest::compareQVector3D() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:557) file: qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp - line: 551 + line: 557 ... -not ok 50 - compareQVector4D() +not ok 52 - compareQVector4D() --- type: QCOMPARE message: Compared values are not the same @@ -396,11 +420,11 @@ not ok 50 - compareQVector4D() found: QVector4D(1, 2, 3, 4) (v4a) expected: QVector4D(1, 3, 3, 4) (v4b) actual: QVector4D(1, 2, 3, 4) (v4a) - at: tst_Cmptest::compareQVector4D() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:560) + at: tst_Cmptest::compareQVector4D() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:566) file: qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp - line: 560 + line: 566 ... -not ok 51 - verify() +not ok 53 - verify() --- type: QVERIFY message: Verification failed @@ -408,11 +432,11 @@ not ok 51 - verify() found: false (opaqueFunc() < 2) expected: true (opaqueFunc() < 2) actual: false (opaqueFunc() < 2) - at: tst_Cmptest::verify() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:572) + at: tst_Cmptest::verify() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:578) file: qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp - line: 572 + line: 578 ... -not ok 52 - verify2() +not ok 54 - verify2() --- type: QVERIFY message: 42 @@ -420,11 +444,11 @@ not ok 52 - verify2() found: false (opaqueFunc() < 2) expected: true (opaqueFunc() < 2) actual: false (opaqueFunc() < 2) - at: tst_Cmptest::verify2() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:578) + at: tst_Cmptest::verify2() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:584) file: qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp - line: 578 + line: 584 ... -not ok 53 - tryVerify() +not ok 55 - tryVerify() --- type: QVERIFY message: Verification failed @@ -432,11 +456,11 @@ not ok 53 - tryVerify() found: false (opaqueFunc() < 2) expected: true (opaqueFunc() < 2) actual: false (opaqueFunc() < 2) - at: tst_Cmptest::tryVerify() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:584) + at: tst_Cmptest::tryVerify() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:590) file: qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp - line: 584 + line: 590 ... -not ok 54 - tryVerify2() +not ok 56 - tryVerify2() --- type: QVERIFY message: 42 @@ -444,13 +468,13 @@ not ok 54 - tryVerify2() found: false (opaqueFunc() < 2) expected: true (opaqueFunc() < 2) actual: false (opaqueFunc() < 2) - at: tst_Cmptest::tryVerify2() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:590) + at: tst_Cmptest::tryVerify2() (qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp:596) file: qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp - line: 590 + line: 596 ... -ok 55 - verifyExplicitOperatorBool() -ok 56 - cleanupTestCase() -1..56 -# tests 56 +ok 57 - verifyExplicitOperatorBool() +ok 58 - cleanupTestCase() +1..58 +# tests 58 # pass 18 -# fail 38 +# fail 40 diff --git a/tests/auto/testlib/selftests/expected_cmptest.teamcity b/tests/auto/testlib/selftests/expected_cmptest.teamcity index 422d0cbfdf..426fddb20f 100644 --- a/tests/auto/testlib/selftests/expected_cmptest.teamcity +++ b/tests/auto/testlib/selftests/expected_cmptest.teamcity @@ -95,6 +95,9 @@ ##teamcity[testStarted name='compareQPixmaps(different pixels)' flowId='tst_Cmptest'] ##teamcity[testFailed name='compareQPixmaps(different pixels)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(0)|]' details='Compared values are not the same' flowId='tst_Cmptest'] ##teamcity[testFinished name='compareQPixmaps(different pixels)' flowId='tst_Cmptest'] +##teamcity[testStarted name='compareQPixmaps(different dpr)' flowId='tst_Cmptest'] +##teamcity[testFailed name='compareQPixmaps(different dpr)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(0)|]' details='Compared QPixmaps differ in device pixel ratio.|n Actual (opA): 1|n Expected (opB): 2' flowId='tst_Cmptest'] +##teamcity[testFinished name='compareQPixmaps(different dpr)' flowId='tst_Cmptest'] ##teamcity[testStarted name='compareQImages(both null)' flowId='tst_Cmptest'] ##teamcity[testFinished name='compareQImages(both null)' flowId='tst_Cmptest'] ##teamcity[testStarted name='compareQImages(one null)' flowId='tst_Cmptest'] @@ -114,6 +117,9 @@ ##teamcity[testStarted name='compareQImages(different pixels)' flowId='tst_Cmptest'] ##teamcity[testFailed name='compareQImages(different pixels)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(0)|]' details='Compared values are not the same' flowId='tst_Cmptest'] ##teamcity[testFinished name='compareQImages(different pixels)' flowId='tst_Cmptest'] +##teamcity[testStarted name='compareQImages(different dpr)' flowId='tst_Cmptest'] +##teamcity[testFailed name='compareQImages(different dpr)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(0)|]' details='Compared QImages differ in device pixel ratio.|n Actual (opA): 1|n Expected (opB): 2' flowId='tst_Cmptest'] +##teamcity[testFinished name='compareQImages(different dpr)' flowId='tst_Cmptest'] ##teamcity[testStarted name='compareQRegion(equal-empty)' flowId='tst_Cmptest'] ##teamcity[testFinished name='compareQRegion(equal-empty)' flowId='tst_Cmptest'] ##teamcity[testStarted name='compareQRegion(1-empty)' flowId='tst_Cmptest'] diff --git a/tests/auto/testlib/selftests/expected_cmptest.txt b/tests/auto/testlib/selftests/expected_cmptest.txt index e1aa81c1a1..08877ef74d 100644 --- a/tests/auto/testlib/selftests/expected_cmptest.txt +++ b/tests/auto/testlib/selftests/expected_cmptest.txt @@ -104,6 +104,10 @@ FAIL! : tst_Cmptest::compareQPixmaps(different size) Compared QPixmaps differ i Loc: [qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(0)] FAIL! : tst_Cmptest::compareQPixmaps(different pixels) Compared values are not the same Loc: [qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(0)] +FAIL! : tst_Cmptest::compareQPixmaps(different dpr) Compared QPixmaps differ in device pixel ratio. + Actual (opA): 1 + Expected (opB): 2 + Loc: [qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(0)] PASS : tst_Cmptest::compareQImages(both null) FAIL! : tst_Cmptest::compareQImages(one null) Compared QImages differ. Actual (opA).isNull(): 1 @@ -124,6 +128,10 @@ FAIL! : tst_Cmptest::compareQImages(different format) Compared QImages differ i Loc: [qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(0)] FAIL! : tst_Cmptest::compareQImages(different pixels) Compared values are not the same Loc: [qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(0)] +FAIL! : tst_Cmptest::compareQImages(different dpr) Compared QImages differ in device pixel ratio. + Actual (opA): 1 + Expected (opB): 2 + Loc: [qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(0)] PASS : tst_Cmptest::compareQRegion(equal-empty) FAIL! : tst_Cmptest::compareQRegion(1-empty) Compared values are not the same Actual (rA): QRegion(200x50+10+10) @@ -156,5 +164,5 @@ FAIL! : tst_Cmptest::tryVerify2() 'opaqueFunc() < 2' returned FALSE. (42) Loc: [qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(0)] PASS : tst_Cmptest::verifyExplicitOperatorBool() PASS : tst_Cmptest::cleanupTestCase() -Totals: 18 passed, 38 failed, 0 skipped, 0 blacklisted, 0ms +Totals: 18 passed, 40 failed, 0 skipped, 0 blacklisted, 0ms ********* Finished testing of tst_Cmptest ********* diff --git a/tests/auto/testlib/selftests/expected_cmptest.xml b/tests/auto/testlib/selftests/expected_cmptest.xml index 1c5a17631a..daf2560f1b 100644 --- a/tests/auto/testlib/selftests/expected_cmptest.xml +++ b/tests/auto/testlib/selftests/expected_cmptest.xml @@ -211,6 +211,12 @@ <DataTag><![CDATA[different pixels]]></DataTag> <Description><![CDATA[Compared values are not the same]]></Description> </Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp" line="0"> + <DataTag><![CDATA[different dpr]]></DataTag> + <Description><![CDATA[Compared QPixmaps differ in device pixel ratio. + Actual (opA): 1 + Expected (opB): 2]]></Description> +</Incident> <Duration msecs="0"/> </TestFunction> <TestFunction name="compareQImages"> @@ -248,6 +254,12 @@ <DataTag><![CDATA[different pixels]]></DataTag> <Description><![CDATA[Compared values are not the same]]></Description> </Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp" line="0"> + <DataTag><![CDATA[different dpr]]></DataTag> + <Description><![CDATA[Compared QImages differ in device pixel ratio. + Actual (opA): 1 + Expected (opB): 2]]></Description> +</Incident> <Duration msecs="0"/> </TestFunction> <TestFunction name="compareQRegion"> diff --git a/tests/auto/testlib/selftests/expected_cmptest.xunitxml b/tests/auto/testlib/selftests/expected_cmptest.xunitxml index 99823d1c1c..397db4c3e4 100644 --- a/tests/auto/testlib/selftests/expected_cmptest.xunitxml +++ b/tests/auto/testlib/selftests/expected_cmptest.xunitxml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<testsuite errors="0" failures="38" tests="26" name="tst_Cmptest"> +<testsuite errors="0" failures="40" tests="26" name="tst_Cmptest"> <properties> <property value="@INSERT_QT_VERSION_HERE@" name="QTestVersion"/> <property value="@INSERT_QT_VERSION_HERE@" name="QtVersion"/> @@ -98,6 +98,9 @@ Actual (opA): 11x20 Expected (opB): 20x20" result="fail"/> <failure tag="different pixels" message="Compared values are not the same" result="fail"/> + <failure tag="different dpr" message="Compared QPixmaps differ in device pixel ratio. + Actual (opA): 1 + Expected (opB): 2" result="fail"/> </testcase> <testcase result="fail" name="compareQImages"> <failure tag="one null" message="Compared QImages differ. @@ -113,6 +116,9 @@ Actual (opA): 6 Expected (opB): 3" result="fail"/> <failure tag="different pixels" message="Compared values are not the same" result="fail"/> + <failure tag="different dpr" message="Compared QImages differ in device pixel ratio. + Actual (opA): 1 + Expected (opB): 2" result="fail"/> </testcase> <testcase result="fail" name="compareQRegion"> <failure tag="1-empty" message="Compared values are not the same diff --git a/tests/auto/testlib/selftests/expected_crashes_5.txt b/tests/auto/testlib/selftests/expected_crashes_5.txt new file mode 100644 index 0000000000..088b9c5324 --- /dev/null +++ b/tests/auto/testlib/selftests/expected_crashes_5.txt @@ -0,0 +1,5 @@ +********* Start testing of tst_Crashes ********* +Config: Using QtTest library @INSERT_QT_VERSION_HERE@, Qt @INSERT_QT_VERSION_HERE@ +PASS : tst_Crashes::initTestCase() +QFATAL : tst_Crashes::crash() Received signal 11 + Function time: ms Total time: ms diff --git a/tests/auto/testlib/selftests/expected_float.lightxml b/tests/auto/testlib/selftests/expected_float.lightxml index 458f2277e6..5f5114bb2e 100644 --- a/tests/auto/testlib/selftests/expected_float.lightxml +++ b/tests/auto/testlib/selftests/expected_float.lightxml @@ -8,15 +8,15 @@ <Duration msecs="0"/> </TestFunction> <TestFunction name="doubleComparisons"> -<Incident type="pass" file="" line="0"> - <DataTag><![CDATA[should PASS 1]]></DataTag> -</Incident> <Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> <DataTag><![CDATA[should FAIL 1]]></DataTag> <Description><![CDATA[Compared doubles are not the same (fuzzy compare) Actual (operandLeft) : 1 Expected (operandRight): 3]]></Description> </Incident> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[should PASS 1]]></DataTag> +</Incident> <Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> <DataTag><![CDATA[should FAIL 2]]></DataTag> <Description><![CDATA[Compared doubles are not the same (fuzzy compare) @@ -428,21 +428,24 @@ <Duration msecs="0"/> </TestFunction> <TestFunction name="float16Comparisons"> -<Incident type="pass" file="" line="0"> - <DataTag><![CDATA[should SUCCEED 1]]></DataTag> -</Incident> <Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> <DataTag><![CDATA[should FAIL 1]]></DataTag> <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) Actual (operandLeft) : 1 Expected (operandRight): 3]]></Description> </Incident> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[should PASS 1]]></DataTag> +</Incident> <Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> <DataTag><![CDATA[should FAIL 2]]></DataTag> <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) Actual (operandLeft) : 0.0001 Expected (operandRight): 0.0003]]></Description> </Incident> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[should PASS 2]]></DataTag> +</Incident> <Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> <DataTag><![CDATA[should FAIL 3]]></DataTag> <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) @@ -450,7 +453,187 @@ Expected (operandRight): 99]]></Description> </Incident> <Incident type="pass" file="" line="0"> - <DataTag><![CDATA[should SUCCEED 2]]></DataTag> + <DataTag><![CDATA[should PASS 3]]></DataTag> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL 4]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 5.93e-05 + Expected (operandRight): 5.87e-05]]></Description> +</Incident> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[should PASS 4]]></DataTag> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL 5]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 5.94e+04 + Expected (operandRight): 5.88e+04]]></Description> +</Incident> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[should PASS: NaN == NaN]]></DataTag> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: NaN != 0]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : nan + Expected (operandRight): 0]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: 0 != NaN]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 0 + Expected (operandRight): nan]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: NaN != 1]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : nan + Expected (operandRight): 1]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: 1 != NaN]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 1 + Expected (operandRight): nan]]></Description> +</Incident> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[should PASS: inf == inf]]></DataTag> +</Incident> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[should PASS: -inf == -inf]]></DataTag> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: inf != -inf]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : inf + Expected (operandRight): -inf]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: -inf != inf]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -inf + Expected (operandRight): inf]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: inf != nan]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : inf + Expected (operandRight): nan]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: nan != inf]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : nan + Expected (operandRight): inf]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: -inf != nan]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -inf + Expected (operandRight): nan]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: nan != -inf]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : nan + Expected (operandRight): -inf]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: inf != 0]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : inf + Expected (operandRight): 0]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: 0 != inf]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 0 + Expected (operandRight): inf]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: -inf != 0]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -inf + Expected (operandRight): 0]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: 0 != -inf]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 0 + Expected (operandRight): -inf]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: inf != 1]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : inf + Expected (operandRight): 1]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: 1 != inf]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 1 + Expected (operandRight): inf]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: -inf != 1]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -inf + Expected (operandRight): 1]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: 1 != -inf]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 1 + Expected (operandRight): -inf]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: inf != max]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : inf + Expected (operandRight): 6.55e+04]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: inf != -max]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : inf + Expected (operandRight): -6.55e+04]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: max != inf]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 6.55e+04 + Expected (operandRight): inf]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: -max != inf]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -6.55e+04 + Expected (operandRight): inf]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: -inf != max]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -inf + Expected (operandRight): 6.55e+04]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: -inf != -max]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -inf + Expected (operandRight): -6.55e+04]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: max != -inf]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 6.55e+04 + Expected (operandRight): -inf]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: -max != -inf]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -6.55e+04 + Expected (operandRight): -inf]]></Description> </Incident> <Duration msecs="0"/> </TestFunction> diff --git a/tests/auto/testlib/selftests/expected_float.tap b/tests/auto/testlib/selftests/expected_float.tap index 277dd2b1d4..9da51b93b3 100644 --- a/tests/auto/testlib/selftests/expected_float.tap +++ b/tests/auto/testlib/selftests/expected_float.tap @@ -1,8 +1,7 @@ TAP version 13 # tst_float ok 1 - initTestCase() -ok 2 - doubleComparisons(should PASS 1) -not ok 3 - doubleComparisons(should FAIL 1) +not ok 2 - doubleComparisons(should FAIL 1) --- type: QCOMPARE message: Compared doubles are not the same (fuzzy compare) @@ -10,10 +9,11 @@ not ok 3 - doubleComparisons(should FAIL 1) found: 1 (operandLeft) expected: 3 (operandRight) actual: 1 (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... +ok 3 - doubleComparisons(should PASS 1) not ok 4 - doubleComparisons(should FAIL 2) --- type: QCOMPARE @@ -22,9 +22,9 @@ not ok 4 - doubleComparisons(should FAIL 2) found: 1e-07 (operandLeft) expected: 3e-07 (operandRight) actual: 1e-07 (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... ok 5 - doubleComparisons(should PASS 2) not ok 6 - doubleComparisons(should FAIL 3) @@ -35,9 +35,9 @@ not ok 6 - doubleComparisons(should FAIL 3) found: 999999999999 (operandLeft) expected: 999999999998 (operandRight) actual: 999999999999 (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... ok 7 - doubleComparisons(should PASS 3) not ok 8 - doubleComparisons(should FAIL 4) @@ -48,9 +48,9 @@ not ok 8 - doubleComparisons(should FAIL 4) found: 9.99999999999e-311 (operandLeft) expected: 9.99999999997e-311 (operandRight) actual: 9.99999999999e-311 (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... ok 9 - doubleComparisons(should PASS 4) not ok 10 - doubleComparisons(should FAIL 5) @@ -61,9 +61,9 @@ not ok 10 - doubleComparisons(should FAIL 5) found: 9.99999999999e+306 (operandLeft) expected: 9.99999999997e+306 (operandRight) actual: 9.99999999999e+306 (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... ok 11 - doubleComparisons(should PASS: NaN == NaN) not ok 12 - doubleComparisons(should FAIL: NaN != 0) @@ -74,9 +74,9 @@ not ok 12 - doubleComparisons(should FAIL: NaN != 0) found: nan (operandLeft) expected: 0 (operandRight) actual: nan (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... not ok 13 - doubleComparisons(should FAIL: 0 != NaN) --- @@ -86,9 +86,9 @@ not ok 13 - doubleComparisons(should FAIL: 0 != NaN) found: 0 (operandLeft) expected: nan (operandRight) actual: 0 (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... not ok 14 - doubleComparisons(should FAIL: NaN != 1) --- @@ -98,9 +98,9 @@ not ok 14 - doubleComparisons(should FAIL: NaN != 1) found: nan (operandLeft) expected: 1 (operandRight) actual: nan (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... not ok 15 - doubleComparisons(should FAIL: 1 != NaN) --- @@ -110,9 +110,9 @@ not ok 15 - doubleComparisons(should FAIL: 1 != NaN) found: 1 (operandLeft) expected: nan (operandRight) actual: 1 (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... ok 16 - doubleComparisons(should PASS: inf == inf) ok 17 - doubleComparisons(should PASS: -inf == -inf) @@ -124,9 +124,9 @@ not ok 18 - doubleComparisons(should FAIL: inf != -inf) found: inf (operandLeft) expected: -inf (operandRight) actual: inf (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... not ok 19 - doubleComparisons(should FAIL: -inf != inf) --- @@ -136,9 +136,9 @@ not ok 19 - doubleComparisons(should FAIL: -inf != inf) found: -inf (operandLeft) expected: inf (operandRight) actual: -inf (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... not ok 20 - doubleComparisons(should FAIL: inf != nan) --- @@ -148,9 +148,9 @@ not ok 20 - doubleComparisons(should FAIL: inf != nan) found: inf (operandLeft) expected: nan (operandRight) actual: inf (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... not ok 21 - doubleComparisons(should FAIL: nan != inf) --- @@ -160,9 +160,9 @@ not ok 21 - doubleComparisons(should FAIL: nan != inf) found: nan (operandLeft) expected: inf (operandRight) actual: nan (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... not ok 22 - doubleComparisons(should FAIL: -inf != nan) --- @@ -172,9 +172,9 @@ not ok 22 - doubleComparisons(should FAIL: -inf != nan) found: -inf (operandLeft) expected: nan (operandRight) actual: -inf (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... not ok 23 - doubleComparisons(should FAIL: nan != -inf) --- @@ -184,9 +184,9 @@ not ok 23 - doubleComparisons(should FAIL: nan != -inf) found: nan (operandLeft) expected: -inf (operandRight) actual: nan (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... not ok 24 - doubleComparisons(should FAIL: inf != 0) --- @@ -196,9 +196,9 @@ not ok 24 - doubleComparisons(should FAIL: inf != 0) found: inf (operandLeft) expected: 0 (operandRight) actual: inf (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... not ok 25 - doubleComparisons(should FAIL: 0 != inf) --- @@ -208,9 +208,9 @@ not ok 25 - doubleComparisons(should FAIL: 0 != inf) found: 0 (operandLeft) expected: inf (operandRight) actual: 0 (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... not ok 26 - doubleComparisons(should FAIL: -inf != 0) --- @@ -220,9 +220,9 @@ not ok 26 - doubleComparisons(should FAIL: -inf != 0) found: -inf (operandLeft) expected: 0 (operandRight) actual: -inf (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... not ok 27 - doubleComparisons(should FAIL: 0 != -inf) --- @@ -232,9 +232,9 @@ not ok 27 - doubleComparisons(should FAIL: 0 != -inf) found: 0 (operandLeft) expected: -inf (operandRight) actual: 0 (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... not ok 28 - doubleComparisons(should FAIL: inf != 1) --- @@ -244,9 +244,9 @@ not ok 28 - doubleComparisons(should FAIL: inf != 1) found: inf (operandLeft) expected: 1 (operandRight) actual: inf (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... not ok 29 - doubleComparisons(should FAIL: 1 != inf) --- @@ -256,9 +256,9 @@ not ok 29 - doubleComparisons(should FAIL: 1 != inf) found: 1 (operandLeft) expected: inf (operandRight) actual: 1 (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... not ok 30 - doubleComparisons(should FAIL: -inf != 1) --- @@ -268,9 +268,9 @@ not ok 30 - doubleComparisons(should FAIL: -inf != 1) found: -inf (operandLeft) expected: 1 (operandRight) actual: -inf (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... not ok 31 - doubleComparisons(should FAIL: 1 != -inf) --- @@ -280,9 +280,9 @@ not ok 31 - doubleComparisons(should FAIL: 1 != -inf) found: 1 (operandLeft) expected: -inf (operandRight) actual: 1 (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... not ok 32 - doubleComparisons(should FAIL: inf != max) --- @@ -292,9 +292,9 @@ not ok 32 - doubleComparisons(should FAIL: inf != max) found: inf (operandLeft) expected: 1.79769313486e+308 (operandRight) actual: inf (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... not ok 33 - doubleComparisons(should FAIL: inf != -max) --- @@ -304,9 +304,9 @@ not ok 33 - doubleComparisons(should FAIL: inf != -max) found: inf (operandLeft) expected: -1.79769313486e+308 (operandRight) actual: inf (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... not ok 34 - doubleComparisons(should FAIL: max != inf) --- @@ -316,9 +316,9 @@ not ok 34 - doubleComparisons(should FAIL: max != inf) found: 1.79769313486e+308 (operandLeft) expected: inf (operandRight) actual: 1.79769313486e+308 (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... not ok 35 - doubleComparisons(should FAIL: -max != inf) --- @@ -328,9 +328,9 @@ not ok 35 - doubleComparisons(should FAIL: -max != inf) found: -1.79769313486e+308 (operandLeft) expected: inf (operandRight) actual: -1.79769313486e+308 (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... not ok 36 - doubleComparisons(should FAIL: -inf != max) --- @@ -340,9 +340,9 @@ not ok 36 - doubleComparisons(should FAIL: -inf != max) found: -inf (operandLeft) expected: 1.79769313486e+308 (operandRight) actual: -inf (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... not ok 37 - doubleComparisons(should FAIL: -inf != -max) --- @@ -352,9 +352,9 @@ not ok 37 - doubleComparisons(should FAIL: -inf != -max) found: -inf (operandLeft) expected: -1.79769313486e+308 (operandRight) actual: -inf (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... not ok 38 - doubleComparisons(should FAIL: max != -inf) --- @@ -364,9 +364,9 @@ not ok 38 - doubleComparisons(should FAIL: max != -inf) found: 1.79769313486e+308 (operandLeft) expected: -inf (operandRight) actual: 1.79769313486e+308 (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... not ok 39 - doubleComparisons(should FAIL: -max != -inf) --- @@ -376,9 +376,9 @@ not ok 39 - doubleComparisons(should FAIL: -max != -inf) found: -1.79769313486e+308 (operandLeft) expected: -inf (operandRight) actual: -1.79769313486e+308 (operandLeft) - at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:54) + at: tst_float::doubleComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:103) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 54 + line: 103 ... not ok 40 - floatComparisons(should FAIL 1) --- @@ -388,9 +388,9 @@ not ok 40 - floatComparisons(should FAIL 1) found: 1 (operandLeft) expected: 3 (operandRight) actual: 1 (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... ok 41 - floatComparisons(should PASS 1) not ok 42 - floatComparisons(should FAIL 2) @@ -401,9 +401,9 @@ not ok 42 - floatComparisons(should FAIL 2) found: 1e-07 (operandLeft) expected: 3e-07 (operandRight) actual: 1e-07 (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... ok 43 - floatComparisons(should PASS 2) not ok 44 - floatComparisons(should FAIL 3) @@ -414,9 +414,9 @@ not ok 44 - floatComparisons(should FAIL 3) found: 99999 (operandLeft) expected: 99998 (operandRight) actual: 99999 (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... ok 45 - floatComparisons(should PASS 3) not ok 46 - floatComparisons(should FAIL 4) @@ -427,9 +427,9 @@ not ok 46 - floatComparisons(should FAIL 4) found: 9.9999e-40 (operandLeft) expected: 9.99971e-40 (operandRight) actual: 9.9999e-40 (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... ok 47 - floatComparisons(should PASS 4) not ok 48 - floatComparisons(should FAIL 5) @@ -440,9 +440,9 @@ not ok 48 - floatComparisons(should FAIL 5) found: 9.9999e+37 (operandLeft) expected: 9.9997e+37 (operandRight) actual: 9.9999e+37 (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... ok 49 - floatComparisons(should PASS: NaN == NaN) not ok 50 - floatComparisons(should FAIL: NaN != 0) @@ -453,9 +453,9 @@ not ok 50 - floatComparisons(should FAIL: NaN != 0) found: nan (operandLeft) expected: 0 (operandRight) actual: nan (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... not ok 51 - floatComparisons(should FAIL: 0 != NaN) --- @@ -465,9 +465,9 @@ not ok 51 - floatComparisons(should FAIL: 0 != NaN) found: 0 (operandLeft) expected: nan (operandRight) actual: 0 (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... not ok 52 - floatComparisons(should FAIL: NaN != 1) --- @@ -477,9 +477,9 @@ not ok 52 - floatComparisons(should FAIL: NaN != 1) found: nan (operandLeft) expected: 1 (operandRight) actual: nan (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... not ok 53 - floatComparisons(should FAIL: 1 != NaN) --- @@ -489,9 +489,9 @@ not ok 53 - floatComparisons(should FAIL: 1 != NaN) found: 1 (operandLeft) expected: nan (operandRight) actual: 1 (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... ok 54 - floatComparisons(should PASS: inf == inf) ok 55 - floatComparisons(should PASS: -inf == -inf) @@ -503,9 +503,9 @@ not ok 56 - floatComparisons(should FAIL: inf != -inf) found: inf (operandLeft) expected: -inf (operandRight) actual: inf (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... not ok 57 - floatComparisons(should FAIL: -inf != inf) --- @@ -515,9 +515,9 @@ not ok 57 - floatComparisons(should FAIL: -inf != inf) found: -inf (operandLeft) expected: inf (operandRight) actual: -inf (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... not ok 58 - floatComparisons(should FAIL: inf != nan) --- @@ -527,9 +527,9 @@ not ok 58 - floatComparisons(should FAIL: inf != nan) found: inf (operandLeft) expected: nan (operandRight) actual: inf (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... not ok 59 - floatComparisons(should FAIL: nan != inf) --- @@ -539,9 +539,9 @@ not ok 59 - floatComparisons(should FAIL: nan != inf) found: nan (operandLeft) expected: inf (operandRight) actual: nan (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... not ok 60 - floatComparisons(should FAIL: -inf != nan) --- @@ -551,9 +551,9 @@ not ok 60 - floatComparisons(should FAIL: -inf != nan) found: -inf (operandLeft) expected: nan (operandRight) actual: -inf (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... not ok 61 - floatComparisons(should FAIL: nan != -inf) --- @@ -563,9 +563,9 @@ not ok 61 - floatComparisons(should FAIL: nan != -inf) found: nan (operandLeft) expected: -inf (operandRight) actual: nan (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... not ok 62 - floatComparisons(should FAIL: inf != 0) --- @@ -575,9 +575,9 @@ not ok 62 - floatComparisons(should FAIL: inf != 0) found: inf (operandLeft) expected: 0 (operandRight) actual: inf (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... not ok 63 - floatComparisons(should FAIL: 0 != inf) --- @@ -587,9 +587,9 @@ not ok 63 - floatComparisons(should FAIL: 0 != inf) found: 0 (operandLeft) expected: inf (operandRight) actual: 0 (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... not ok 64 - floatComparisons(should FAIL: -inf != 0) --- @@ -599,9 +599,9 @@ not ok 64 - floatComparisons(should FAIL: -inf != 0) found: -inf (operandLeft) expected: 0 (operandRight) actual: -inf (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... not ok 65 - floatComparisons(should FAIL: 0 != -inf) --- @@ -611,9 +611,9 @@ not ok 65 - floatComparisons(should FAIL: 0 != -inf) found: 0 (operandLeft) expected: -inf (operandRight) actual: 0 (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... not ok 66 - floatComparisons(should FAIL: inf != 1) --- @@ -623,9 +623,9 @@ not ok 66 - floatComparisons(should FAIL: inf != 1) found: inf (operandLeft) expected: 1 (operandRight) actual: inf (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... not ok 67 - floatComparisons(should FAIL: 1 != inf) --- @@ -635,9 +635,9 @@ not ok 67 - floatComparisons(should FAIL: 1 != inf) found: 1 (operandLeft) expected: inf (operandRight) actual: 1 (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... not ok 68 - floatComparisons(should FAIL: -inf != 1) --- @@ -647,9 +647,9 @@ not ok 68 - floatComparisons(should FAIL: -inf != 1) found: -inf (operandLeft) expected: 1 (operandRight) actual: -inf (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... not ok 69 - floatComparisons(should FAIL: 1 != -inf) --- @@ -659,9 +659,9 @@ not ok 69 - floatComparisons(should FAIL: 1 != -inf) found: 1 (operandLeft) expected: -inf (operandRight) actual: 1 (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... not ok 70 - floatComparisons(should FAIL: inf != max) --- @@ -671,9 +671,9 @@ not ok 70 - floatComparisons(should FAIL: inf != max) found: inf (operandLeft) expected: 3.40282e+38 (operandRight) actual: inf (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... not ok 71 - floatComparisons(should FAIL: inf != -max) --- @@ -683,9 +683,9 @@ not ok 71 - floatComparisons(should FAIL: inf != -max) found: inf (operandLeft) expected: -3.40282e+38 (operandRight) actual: inf (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... not ok 72 - floatComparisons(should FAIL: max != inf) --- @@ -695,9 +695,9 @@ not ok 72 - floatComparisons(should FAIL: max != inf) found: 3.40282e+38 (operandLeft) expected: inf (operandRight) actual: 3.40282e+38 (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... not ok 73 - floatComparisons(should FAIL: -max != inf) --- @@ -707,9 +707,9 @@ not ok 73 - floatComparisons(should FAIL: -max != inf) found: -3.40282e+38 (operandLeft) expected: inf (operandRight) actual: -3.40282e+38 (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... not ok 74 - floatComparisons(should FAIL: -inf != max) --- @@ -719,9 +719,9 @@ not ok 74 - floatComparisons(should FAIL: -inf != max) found: -inf (operandLeft) expected: 3.40282e+38 (operandRight) actual: -inf (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... not ok 75 - floatComparisons(should FAIL: -inf != -max) --- @@ -731,9 +731,9 @@ not ok 75 - floatComparisons(should FAIL: -inf != -max) found: -inf (operandLeft) expected: -3.40282e+38 (operandRight) actual: -inf (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... not ok 76 - floatComparisons(should FAIL: max != -inf) --- @@ -743,9 +743,9 @@ not ok 76 - floatComparisons(should FAIL: max != -inf) found: 3.40282e+38 (operandLeft) expected: -inf (operandRight) actual: 3.40282e+38 (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... not ok 77 - floatComparisons(should FAIL: -max != -inf) --- @@ -755,12 +755,11 @@ not ok 77 - floatComparisons(should FAIL: -max != -inf) found: -3.40282e+38 (operandLeft) expected: -inf (operandRight) actual: -3.40282e+38 (operandLeft) - at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:127) + at: tst_float::floatComparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:137) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 127 + line: 137 ... -ok 78 - float16Comparisons(should SUCCEED 1) -not ok 79 - float16Comparisons(should FAIL 1) +not ok 78 - float16Comparisons(should FAIL 1) --- type: QCOMPARE message: Compared qfloat16s are not the same (fuzzy compare) @@ -768,10 +767,11 @@ not ok 79 - float16Comparisons(should FAIL 1) found: 1 (operandLeft) expected: 3 (operandRight) actual: 1 (operandLeft) - at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:200) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 200 + line: 171 ... +ok 79 - float16Comparisons(should PASS 1) not ok 80 - float16Comparisons(should FAIL 2) --- type: QCOMPARE @@ -780,11 +780,12 @@ not ok 80 - float16Comparisons(should FAIL 2) found: 0.0001 (operandLeft) expected: 0.0003 (operandRight) actual: 0.0001 (operandLeft) - at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:200) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 200 + line: 171 ... -not ok 81 - float16Comparisons(should FAIL 3) +ok 81 - float16Comparisons(should PASS 2) +not ok 82 - float16Comparisons(should FAIL 3) --- type: QCOMPARE message: Compared qfloat16s are not the same (fuzzy compare) @@ -792,12 +793,352 @@ not ok 81 - float16Comparisons(should FAIL 3) found: 98 (operandLeft) expected: 99 (operandRight) actual: 98 (operandLeft) - at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:200) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 200 + line: 171 ... -ok 82 - float16Comparisons(should SUCCEED 2) -not ok 83 - compareFloatTests(1e0) +ok 83 - float16Comparisons(should PASS 3) +not ok 84 - float16Comparisons(should FAIL 4) + --- + type: QCOMPARE + message: Compared qfloat16s are not the same (fuzzy compare) + wanted: 5.87e-05 (operandRight) + found: 5.93e-05 (operandLeft) + expected: 5.87e-05 (operandRight) + actual: 5.93e-05 (operandLeft) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) + file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp + line: 171 + ... +ok 85 - float16Comparisons(should PASS 4) +not ok 86 - float16Comparisons(should FAIL 5) + --- + type: QCOMPARE + message: Compared qfloat16s are not the same (fuzzy compare) + wanted: 5.88e+04 (operandRight) + found: 5.94e+04 (operandLeft) + expected: 5.88e+04 (operandRight) + actual: 5.94e+04 (operandLeft) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) + file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp + line: 171 + ... +ok 87 - float16Comparisons(should PASS: NaN == NaN) +not ok 88 - float16Comparisons(should FAIL: NaN != 0) + --- + type: QCOMPARE + message: Compared qfloat16s are not the same (fuzzy compare) + wanted: 0 (operandRight) + found: nan (operandLeft) + expected: 0 (operandRight) + actual: nan (operandLeft) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) + file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp + line: 171 + ... +not ok 89 - float16Comparisons(should FAIL: 0 != NaN) + --- + type: QCOMPARE + message: Compared qfloat16s are not the same (fuzzy compare) + wanted: nan (operandRight) + found: 0 (operandLeft) + expected: nan (operandRight) + actual: 0 (operandLeft) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) + file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp + line: 171 + ... +not ok 90 - float16Comparisons(should FAIL: NaN != 1) + --- + type: QCOMPARE + message: Compared qfloat16s are not the same (fuzzy compare) + wanted: 1 (operandRight) + found: nan (operandLeft) + expected: 1 (operandRight) + actual: nan (operandLeft) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) + file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp + line: 171 + ... +not ok 91 - float16Comparisons(should FAIL: 1 != NaN) + --- + type: QCOMPARE + message: Compared qfloat16s are not the same (fuzzy compare) + wanted: nan (operandRight) + found: 1 (operandLeft) + expected: nan (operandRight) + actual: 1 (operandLeft) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) + file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp + line: 171 + ... +ok 92 - float16Comparisons(should PASS: inf == inf) +ok 93 - float16Comparisons(should PASS: -inf == -inf) +not ok 94 - float16Comparisons(should FAIL: inf != -inf) + --- + type: QCOMPARE + message: Compared qfloat16s are not the same (fuzzy compare) + wanted: -inf (operandRight) + found: inf (operandLeft) + expected: -inf (operandRight) + actual: inf (operandLeft) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) + file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp + line: 171 + ... +not ok 95 - float16Comparisons(should FAIL: -inf != inf) + --- + type: QCOMPARE + message: Compared qfloat16s are not the same (fuzzy compare) + wanted: inf (operandRight) + found: -inf (operandLeft) + expected: inf (operandRight) + actual: -inf (operandLeft) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) + file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp + line: 171 + ... +not ok 96 - float16Comparisons(should FAIL: inf != nan) + --- + type: QCOMPARE + message: Compared qfloat16s are not the same (fuzzy compare) + wanted: nan (operandRight) + found: inf (operandLeft) + expected: nan (operandRight) + actual: inf (operandLeft) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) + file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp + line: 171 + ... +not ok 97 - float16Comparisons(should FAIL: nan != inf) + --- + type: QCOMPARE + message: Compared qfloat16s are not the same (fuzzy compare) + wanted: inf (operandRight) + found: nan (operandLeft) + expected: inf (operandRight) + actual: nan (operandLeft) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) + file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp + line: 171 + ... +not ok 98 - float16Comparisons(should FAIL: -inf != nan) + --- + type: QCOMPARE + message: Compared qfloat16s are not the same (fuzzy compare) + wanted: nan (operandRight) + found: -inf (operandLeft) + expected: nan (operandRight) + actual: -inf (operandLeft) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) + file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp + line: 171 + ... +not ok 99 - float16Comparisons(should FAIL: nan != -inf) + --- + type: QCOMPARE + message: Compared qfloat16s are not the same (fuzzy compare) + wanted: -inf (operandRight) + found: nan (operandLeft) + expected: -inf (operandRight) + actual: nan (operandLeft) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) + file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp + line: 171 + ... +not ok 100 - float16Comparisons(should FAIL: inf != 0) + --- + type: QCOMPARE + message: Compared qfloat16s are not the same (fuzzy compare) + wanted: 0 (operandRight) + found: inf (operandLeft) + expected: 0 (operandRight) + actual: inf (operandLeft) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) + file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp + line: 171 + ... +not ok 101 - float16Comparisons(should FAIL: 0 != inf) + --- + type: QCOMPARE + message: Compared qfloat16s are not the same (fuzzy compare) + wanted: inf (operandRight) + found: 0 (operandLeft) + expected: inf (operandRight) + actual: 0 (operandLeft) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) + file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp + line: 171 + ... +not ok 102 - float16Comparisons(should FAIL: -inf != 0) + --- + type: QCOMPARE + message: Compared qfloat16s are not the same (fuzzy compare) + wanted: 0 (operandRight) + found: -inf (operandLeft) + expected: 0 (operandRight) + actual: -inf (operandLeft) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) + file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp + line: 171 + ... +not ok 103 - float16Comparisons(should FAIL: 0 != -inf) + --- + type: QCOMPARE + message: Compared qfloat16s are not the same (fuzzy compare) + wanted: -inf (operandRight) + found: 0 (operandLeft) + expected: -inf (operandRight) + actual: 0 (operandLeft) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) + file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp + line: 171 + ... +not ok 104 - float16Comparisons(should FAIL: inf != 1) + --- + type: QCOMPARE + message: Compared qfloat16s are not the same (fuzzy compare) + wanted: 1 (operandRight) + found: inf (operandLeft) + expected: 1 (operandRight) + actual: inf (operandLeft) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) + file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp + line: 171 + ... +not ok 105 - float16Comparisons(should FAIL: 1 != inf) + --- + type: QCOMPARE + message: Compared qfloat16s are not the same (fuzzy compare) + wanted: inf (operandRight) + found: 1 (operandLeft) + expected: inf (operandRight) + actual: 1 (operandLeft) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) + file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp + line: 171 + ... +not ok 106 - float16Comparisons(should FAIL: -inf != 1) + --- + type: QCOMPARE + message: Compared qfloat16s are not the same (fuzzy compare) + wanted: 1 (operandRight) + found: -inf (operandLeft) + expected: 1 (operandRight) + actual: -inf (operandLeft) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) + file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp + line: 171 + ... +not ok 107 - float16Comparisons(should FAIL: 1 != -inf) + --- + type: QCOMPARE + message: Compared qfloat16s are not the same (fuzzy compare) + wanted: -inf (operandRight) + found: 1 (operandLeft) + expected: -inf (operandRight) + actual: 1 (operandLeft) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) + file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp + line: 171 + ... +not ok 108 - float16Comparisons(should FAIL: inf != max) + --- + type: QCOMPARE + message: Compared qfloat16s are not the same (fuzzy compare) + wanted: 6.55e+04 (operandRight) + found: inf (operandLeft) + expected: 6.55e+04 (operandRight) + actual: inf (operandLeft) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) + file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp + line: 171 + ... +not ok 109 - float16Comparisons(should FAIL: inf != -max) + --- + type: QCOMPARE + message: Compared qfloat16s are not the same (fuzzy compare) + wanted: -6.55e+04 (operandRight) + found: inf (operandLeft) + expected: -6.55e+04 (operandRight) + actual: inf (operandLeft) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) + file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp + line: 171 + ... +not ok 110 - float16Comparisons(should FAIL: max != inf) + --- + type: QCOMPARE + message: Compared qfloat16s are not the same (fuzzy compare) + wanted: inf (operandRight) + found: 6.55e+04 (operandLeft) + expected: inf (operandRight) + actual: 6.55e+04 (operandLeft) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) + file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp + line: 171 + ... +not ok 111 - float16Comparisons(should FAIL: -max != inf) + --- + type: QCOMPARE + message: Compared qfloat16s are not the same (fuzzy compare) + wanted: inf (operandRight) + found: -6.55e+04 (operandLeft) + expected: inf (operandRight) + actual: -6.55e+04 (operandLeft) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) + file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp + line: 171 + ... +not ok 112 - float16Comparisons(should FAIL: -inf != max) + --- + type: QCOMPARE + message: Compared qfloat16s are not the same (fuzzy compare) + wanted: 6.55e+04 (operandRight) + found: -inf (operandLeft) + expected: 6.55e+04 (operandRight) + actual: -inf (operandLeft) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) + file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp + line: 171 + ... +not ok 113 - float16Comparisons(should FAIL: -inf != -max) + --- + type: QCOMPARE + message: Compared qfloat16s are not the same (fuzzy compare) + wanted: -6.55e+04 (operandRight) + found: -inf (operandLeft) + expected: -6.55e+04 (operandRight) + actual: -inf (operandLeft) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) + file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp + line: 171 + ... +not ok 114 - float16Comparisons(should FAIL: max != -inf) + --- + type: QCOMPARE + message: Compared qfloat16s are not the same (fuzzy compare) + wanted: -inf (operandRight) + found: 6.55e+04 (operandLeft) + expected: -inf (operandRight) + actual: 6.55e+04 (operandLeft) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) + file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp + line: 171 + ... +not ok 115 - float16Comparisons(should FAIL: -max != -inf) + --- + type: QCOMPARE + message: Compared qfloat16s are not the same (fuzzy compare) + wanted: -inf (operandRight) + found: -6.55e+04 (operandLeft) + expected: -inf (operandRight) + actual: -6.55e+04 (operandLeft) + at: tst_float::float16Comparisons() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:171) + file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp + line: 171 + ... +not ok 116 - compareFloatTests(1e0) --- type: QCOMPARE message: Compared floats are not the same (fuzzy compare) @@ -805,11 +1146,11 @@ not ok 83 - compareFloatTests(1e0) found: 1 (t1) expected: 3 (t3) actual: 1 (t1) - at: tst_float::compareFloatTests() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:245) + at: tst_float::compareFloatTests() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:210) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 245 + line: 210 ... -not ok 84 - compareFloatTests(1e-7) +not ok 117 - compareFloatTests(1e-7) --- type: QCOMPARE message: Compared floats are not the same (fuzzy compare) @@ -817,11 +1158,11 @@ not ok 84 - compareFloatTests(1e-7) found: 1e-07 (t1) expected: 3e-07 (t3) actual: 1e-07 (t1) - at: tst_float::compareFloatTests() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:245) + at: tst_float::compareFloatTests() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:210) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 245 + line: 210 ... -not ok 85 - compareFloatTests(1e+7) +not ok 118 - compareFloatTests(1e+7) --- type: QCOMPARE message: Compared floats are not the same (fuzzy compare) @@ -829,12 +1170,12 @@ not ok 85 - compareFloatTests(1e+7) found: 1e+07 (t1) expected: 3e+07 (t3) actual: 1e+07 (t1) - at: tst_float::compareFloatTests() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:245) + at: tst_float::compareFloatTests() (qtbase/tests/auto/testlib/selftests/float/tst_float.cpp:210) file: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp - line: 245 + line: 210 ... -ok 86 - cleanupTestCase() -1..86 -# tests 86 -# pass 18 -# fail 68 +ok 119 - cleanupTestCase() +1..119 +# tests 119 +# pass 23 +# fail 96 diff --git a/tests/auto/testlib/selftests/expected_float.teamcity b/tests/auto/testlib/selftests/expected_float.teamcity index e23bc722b1..af81296c42 100644 --- a/tests/auto/testlib/selftests/expected_float.teamcity +++ b/tests/auto/testlib/selftests/expected_float.teamcity @@ -1,11 +1,11 @@ ##teamcity[testSuiteStarted name='tst_float' flowId='tst_float'] ##teamcity[testStarted name='initTestCase()' flowId='tst_float'] ##teamcity[testFinished name='initTestCase()' flowId='tst_float'] -##teamcity[testStarted name='doubleComparisons(should PASS 1)' flowId='tst_float'] -##teamcity[testFinished name='doubleComparisons(should PASS 1)' flowId='tst_float'] ##teamcity[testStarted name='doubleComparisons(should FAIL 1)' flowId='tst_float'] ##teamcity[testFailed name='doubleComparisons(should FAIL 1)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared doubles are not the same (fuzzy compare)|n Actual (operandLeft) : 1|n Expected (operandRight): 3' flowId='tst_float'] ##teamcity[testFinished name='doubleComparisons(should FAIL 1)' flowId='tst_float'] +##teamcity[testStarted name='doubleComparisons(should PASS 1)' flowId='tst_float'] +##teamcity[testFinished name='doubleComparisons(should PASS 1)' flowId='tst_float'] ##teamcity[testStarted name='doubleComparisons(should FAIL 2)' flowId='tst_float'] ##teamcity[testFailed name='doubleComparisons(should FAIL 2)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared doubles are not the same (fuzzy compare)|n Actual (operandLeft) : 1e-07|n Expected (operandRight): 3e-07' flowId='tst_float'] ##teamcity[testFinished name='doubleComparisons(should FAIL 2)' flowId='tst_float'] @@ -215,19 +215,113 @@ ##teamcity[testStarted name='floatComparisons(should FAIL: -max != -inf)' flowId='tst_float'] ##teamcity[testFailed name='floatComparisons(should FAIL: -max != -inf)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared floats are not the same (fuzzy compare)|n Actual (operandLeft) : -3.40282e+38|n Expected (operandRight): -inf' flowId='tst_float'] ##teamcity[testFinished name='floatComparisons(should FAIL: -max != -inf)' flowId='tst_float'] -##teamcity[testStarted name='float16Comparisons(should SUCCEED 1)' flowId='tst_float'] -##teamcity[testFinished name='float16Comparisons(should SUCCEED 1)' flowId='tst_float'] ##teamcity[testStarted name='float16Comparisons(should FAIL 1)' flowId='tst_float'] ##teamcity[testFailed name='float16Comparisons(should FAIL 1)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : 1|n Expected (operandRight): 3' flowId='tst_float'] ##teamcity[testFinished name='float16Comparisons(should FAIL 1)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should PASS 1)' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should PASS 1)' flowId='tst_float'] ##teamcity[testStarted name='float16Comparisons(should FAIL 2)' flowId='tst_float'] ##teamcity[testFailed name='float16Comparisons(should FAIL 2)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : 0.0001|n Expected (operandRight): 0.0003' flowId='tst_float'] ##teamcity[testFinished name='float16Comparisons(should FAIL 2)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should PASS 2)' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should PASS 2)' flowId='tst_float'] ##teamcity[testStarted name='float16Comparisons(should FAIL 3)' flowId='tst_float'] ##teamcity[testFailed name='float16Comparisons(should FAIL 3)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : 98|n Expected (operandRight): 99' flowId='tst_float'] ##teamcity[testFinished name='float16Comparisons(should FAIL 3)' flowId='tst_float'] -##teamcity[testStarted name='float16Comparisons(should SUCCEED 2)' flowId='tst_float'] -##teamcity[testFinished name='float16Comparisons(should SUCCEED 2)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should PASS 3)' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should PASS 3)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should FAIL 4)' flowId='tst_float'] +##teamcity[testFailed name='float16Comparisons(should FAIL 4)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : 5.93e-05|n Expected (operandRight): 5.87e-05' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should FAIL 4)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should PASS 4)' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should PASS 4)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should FAIL 5)' flowId='tst_float'] +##teamcity[testFailed name='float16Comparisons(should FAIL 5)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : 5.94e+04|n Expected (operandRight): 5.88e+04' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should FAIL 5)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should PASS: NaN == NaN)' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should PASS: NaN == NaN)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should FAIL: NaN != 0)' flowId='tst_float'] +##teamcity[testFailed name='float16Comparisons(should FAIL: NaN != 0)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : nan|n Expected (operandRight): 0' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should FAIL: NaN != 0)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should FAIL: 0 != NaN)' flowId='tst_float'] +##teamcity[testFailed name='float16Comparisons(should FAIL: 0 != NaN)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : 0|n Expected (operandRight): nan' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should FAIL: 0 != NaN)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should FAIL: NaN != 1)' flowId='tst_float'] +##teamcity[testFailed name='float16Comparisons(should FAIL: NaN != 1)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : nan|n Expected (operandRight): 1' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should FAIL: NaN != 1)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should FAIL: 1 != NaN)' flowId='tst_float'] +##teamcity[testFailed name='float16Comparisons(should FAIL: 1 != NaN)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : 1|n Expected (operandRight): nan' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should FAIL: 1 != NaN)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should PASS: inf == inf)' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should PASS: inf == inf)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should PASS: -inf == -inf)' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should PASS: -inf == -inf)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should FAIL: inf != -inf)' flowId='tst_float'] +##teamcity[testFailed name='float16Comparisons(should FAIL: inf != -inf)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : inf|n Expected (operandRight): -inf' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should FAIL: inf != -inf)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should FAIL: -inf != inf)' flowId='tst_float'] +##teamcity[testFailed name='float16Comparisons(should FAIL: -inf != inf)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : -inf|n Expected (operandRight): inf' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should FAIL: -inf != inf)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should FAIL: inf != nan)' flowId='tst_float'] +##teamcity[testFailed name='float16Comparisons(should FAIL: inf != nan)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : inf|n Expected (operandRight): nan' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should FAIL: inf != nan)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should FAIL: nan != inf)' flowId='tst_float'] +##teamcity[testFailed name='float16Comparisons(should FAIL: nan != inf)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : nan|n Expected (operandRight): inf' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should FAIL: nan != inf)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should FAIL: -inf != nan)' flowId='tst_float'] +##teamcity[testFailed name='float16Comparisons(should FAIL: -inf != nan)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : -inf|n Expected (operandRight): nan' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should FAIL: -inf != nan)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should FAIL: nan != -inf)' flowId='tst_float'] +##teamcity[testFailed name='float16Comparisons(should FAIL: nan != -inf)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : nan|n Expected (operandRight): -inf' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should FAIL: nan != -inf)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should FAIL: inf != 0)' flowId='tst_float'] +##teamcity[testFailed name='float16Comparisons(should FAIL: inf != 0)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : inf|n Expected (operandRight): 0' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should FAIL: inf != 0)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should FAIL: 0 != inf)' flowId='tst_float'] +##teamcity[testFailed name='float16Comparisons(should FAIL: 0 != inf)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : 0|n Expected (operandRight): inf' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should FAIL: 0 != inf)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should FAIL: -inf != 0)' flowId='tst_float'] +##teamcity[testFailed name='float16Comparisons(should FAIL: -inf != 0)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : -inf|n Expected (operandRight): 0' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should FAIL: -inf != 0)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should FAIL: 0 != -inf)' flowId='tst_float'] +##teamcity[testFailed name='float16Comparisons(should FAIL: 0 != -inf)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : 0|n Expected (operandRight): -inf' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should FAIL: 0 != -inf)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should FAIL: inf != 1)' flowId='tst_float'] +##teamcity[testFailed name='float16Comparisons(should FAIL: inf != 1)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : inf|n Expected (operandRight): 1' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should FAIL: inf != 1)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should FAIL: 1 != inf)' flowId='tst_float'] +##teamcity[testFailed name='float16Comparisons(should FAIL: 1 != inf)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : 1|n Expected (operandRight): inf' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should FAIL: 1 != inf)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should FAIL: -inf != 1)' flowId='tst_float'] +##teamcity[testFailed name='float16Comparisons(should FAIL: -inf != 1)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : -inf|n Expected (operandRight): 1' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should FAIL: -inf != 1)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should FAIL: 1 != -inf)' flowId='tst_float'] +##teamcity[testFailed name='float16Comparisons(should FAIL: 1 != -inf)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : 1|n Expected (operandRight): -inf' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should FAIL: 1 != -inf)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should FAIL: inf != max)' flowId='tst_float'] +##teamcity[testFailed name='float16Comparisons(should FAIL: inf != max)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : inf|n Expected (operandRight): 6.55e+04' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should FAIL: inf != max)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should FAIL: inf != -max)' flowId='tst_float'] +##teamcity[testFailed name='float16Comparisons(should FAIL: inf != -max)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : inf|n Expected (operandRight): -6.55e+04' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should FAIL: inf != -max)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should FAIL: max != inf)' flowId='tst_float'] +##teamcity[testFailed name='float16Comparisons(should FAIL: max != inf)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : 6.55e+04|n Expected (operandRight): inf' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should FAIL: max != inf)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should FAIL: -max != inf)' flowId='tst_float'] +##teamcity[testFailed name='float16Comparisons(should FAIL: -max != inf)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : -6.55e+04|n Expected (operandRight): inf' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should FAIL: -max != inf)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should FAIL: -inf != max)' flowId='tst_float'] +##teamcity[testFailed name='float16Comparisons(should FAIL: -inf != max)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : -inf|n Expected (operandRight): 6.55e+04' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should FAIL: -inf != max)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should FAIL: -inf != -max)' flowId='tst_float'] +##teamcity[testFailed name='float16Comparisons(should FAIL: -inf != -max)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : -inf|n Expected (operandRight): -6.55e+04' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should FAIL: -inf != -max)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should FAIL: max != -inf)' flowId='tst_float'] +##teamcity[testFailed name='float16Comparisons(should FAIL: max != -inf)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : 6.55e+04|n Expected (operandRight): -inf' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should FAIL: max != -inf)' flowId='tst_float'] +##teamcity[testStarted name='float16Comparisons(should FAIL: -max != -inf)' flowId='tst_float'] +##teamcity[testFailed name='float16Comparisons(should FAIL: -max != -inf)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared qfloat16s are not the same (fuzzy compare)|n Actual (operandLeft) : -6.55e+04|n Expected (operandRight): -inf' flowId='tst_float'] +##teamcity[testFinished name='float16Comparisons(should FAIL: -max != -inf)' flowId='tst_float'] ##teamcity[testStarted name='compareFloatTests(1e0)' flowId='tst_float'] ##teamcity[testFailed name='compareFloatTests(1e0)' message='Failure! |[Loc: qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)|]' details='Compared floats are not the same (fuzzy compare)|n Actual (t1): 1|n Expected (t3): 3' flowId='tst_float'] ##teamcity[testFinished name='compareFloatTests(1e0)' flowId='tst_float'] diff --git a/tests/auto/testlib/selftests/expected_float.txt b/tests/auto/testlib/selftests/expected_float.txt index 6419a13f86..d22a52a63d 100644 --- a/tests/auto/testlib/selftests/expected_float.txt +++ b/tests/auto/testlib/selftests/expected_float.txt @@ -1,11 +1,11 @@ ********* Start testing of tst_float ********* Config: Using QtTest library PASS : tst_float::initTestCase() -PASS : tst_float::doubleComparisons(should PASS 1) FAIL! : tst_float::doubleComparisons(should FAIL 1) Compared doubles are not the same (fuzzy compare) Actual (operandLeft) : 1 Expected (operandRight): 3 Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +PASS : tst_float::doubleComparisons(should PASS 1) FAIL! : tst_float::doubleComparisons(should FAIL 2) Compared doubles are not the same (fuzzy compare) Actual (operandLeft) : 1e-07 Expected (operandRight): 3e-07 @@ -263,20 +263,137 @@ FAIL! : tst_float::floatComparisons(should FAIL: -max != -inf) Compared floats Actual (operandLeft) : -3.40282e+38 Expected (operandRight): -inf Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] -PASS : tst_float::float16Comparisons(should SUCCEED 1) FAIL! : tst_float::float16Comparisons(should FAIL 1) Compared qfloat16s are not the same (fuzzy compare) Actual (operandLeft) : 1 Expected (operandRight): 3 Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +PASS : tst_float::float16Comparisons(should PASS 1) FAIL! : tst_float::float16Comparisons(should FAIL 2) Compared qfloat16s are not the same (fuzzy compare) Actual (operandLeft) : 0.0001 Expected (operandRight): 0.0003 Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +PASS : tst_float::float16Comparisons(should PASS 2) FAIL! : tst_float::float16Comparisons(should FAIL 3) Compared qfloat16s are not the same (fuzzy compare) Actual (operandLeft) : 98 Expected (operandRight): 99 Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] -PASS : tst_float::float16Comparisons(should SUCCEED 2) +PASS : tst_float::float16Comparisons(should PASS 3) +FAIL! : tst_float::float16Comparisons(should FAIL 4) Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 5.93e-05 + Expected (operandRight): 5.87e-05 + Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +PASS : tst_float::float16Comparisons(should PASS 4) +FAIL! : tst_float::float16Comparisons(should FAIL 5) Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 5.94e+04 + Expected (operandRight): 5.88e+04 + Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +PASS : tst_float::float16Comparisons(should PASS: NaN == NaN) +FAIL! : tst_float::float16Comparisons(should FAIL: NaN != 0) Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : nan + Expected (operandRight): 0 + Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +FAIL! : tst_float::float16Comparisons(should FAIL: 0 != NaN) Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 0 + Expected (operandRight): nan + Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +FAIL! : tst_float::float16Comparisons(should FAIL: NaN != 1) Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : nan + Expected (operandRight): 1 + Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +FAIL! : tst_float::float16Comparisons(should FAIL: 1 != NaN) Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 1 + Expected (operandRight): nan + Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +PASS : tst_float::float16Comparisons(should PASS: inf == inf) +PASS : tst_float::float16Comparisons(should PASS: -inf == -inf) +FAIL! : tst_float::float16Comparisons(should FAIL: inf != -inf) Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : inf + Expected (operandRight): -inf + Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +FAIL! : tst_float::float16Comparisons(should FAIL: -inf != inf) Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -inf + Expected (operandRight): inf + Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +FAIL! : tst_float::float16Comparisons(should FAIL: inf != nan) Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : inf + Expected (operandRight): nan + Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +FAIL! : tst_float::float16Comparisons(should FAIL: nan != inf) Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : nan + Expected (operandRight): inf + Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +FAIL! : tst_float::float16Comparisons(should FAIL: -inf != nan) Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -inf + Expected (operandRight): nan + Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +FAIL! : tst_float::float16Comparisons(should FAIL: nan != -inf) Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : nan + Expected (operandRight): -inf + Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +FAIL! : tst_float::float16Comparisons(should FAIL: inf != 0) Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : inf + Expected (operandRight): 0 + Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +FAIL! : tst_float::float16Comparisons(should FAIL: 0 != inf) Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 0 + Expected (operandRight): inf + Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +FAIL! : tst_float::float16Comparisons(should FAIL: -inf != 0) Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -inf + Expected (operandRight): 0 + Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +FAIL! : tst_float::float16Comparisons(should FAIL: 0 != -inf) Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 0 + Expected (operandRight): -inf + Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +FAIL! : tst_float::float16Comparisons(should FAIL: inf != 1) Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : inf + Expected (operandRight): 1 + Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +FAIL! : tst_float::float16Comparisons(should FAIL: 1 != inf) Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 1 + Expected (operandRight): inf + Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +FAIL! : tst_float::float16Comparisons(should FAIL: -inf != 1) Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -inf + Expected (operandRight): 1 + Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +FAIL! : tst_float::float16Comparisons(should FAIL: 1 != -inf) Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 1 + Expected (operandRight): -inf + Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +FAIL! : tst_float::float16Comparisons(should FAIL: inf != max) Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : inf + Expected (operandRight): 6.55e+04 + Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +FAIL! : tst_float::float16Comparisons(should FAIL: inf != -max) Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : inf + Expected (operandRight): -6.55e+04 + Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +FAIL! : tst_float::float16Comparisons(should FAIL: max != inf) Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 6.55e+04 + Expected (operandRight): inf + Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +FAIL! : tst_float::float16Comparisons(should FAIL: -max != inf) Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -6.55e+04 + Expected (operandRight): inf + Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +FAIL! : tst_float::float16Comparisons(should FAIL: -inf != max) Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -inf + Expected (operandRight): 6.55e+04 + Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +FAIL! : tst_float::float16Comparisons(should FAIL: -inf != -max) Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -inf + Expected (operandRight): -6.55e+04 + Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +FAIL! : tst_float::float16Comparisons(should FAIL: max != -inf) Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 6.55e+04 + Expected (operandRight): -inf + Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] +FAIL! : tst_float::float16Comparisons(should FAIL: -max != -inf) Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -6.55e+04 + Expected (operandRight): -inf + Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] FAIL! : tst_float::compareFloatTests(1e0) Compared floats are not the same (fuzzy compare) Actual (t1): 1 Expected (t3): 3 @@ -290,5 +407,5 @@ FAIL! : tst_float::compareFloatTests(1e+7) Compared floats are not the same (fu Expected (t3): 3e+07 Loc: [qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(0)] PASS : tst_float::cleanupTestCase() -Totals: 18 passed, 68 failed, 0 skipped, 0 blacklisted, 0ms +Totals: 23 passed, 96 failed, 0 skipped, 0 blacklisted, 0ms ********* Finished testing of tst_float ********* diff --git a/tests/auto/testlib/selftests/expected_float.xml b/tests/auto/testlib/selftests/expected_float.xml index 65d2c5ad96..247bce9577 100644 --- a/tests/auto/testlib/selftests/expected_float.xml +++ b/tests/auto/testlib/selftests/expected_float.xml @@ -10,15 +10,15 @@ <Duration msecs="0"/> </TestFunction> <TestFunction name="doubleComparisons"> -<Incident type="pass" file="" line="0"> - <DataTag><![CDATA[should PASS 1]]></DataTag> -</Incident> <Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> <DataTag><![CDATA[should FAIL 1]]></DataTag> <Description><![CDATA[Compared doubles are not the same (fuzzy compare) Actual (operandLeft) : 1 Expected (operandRight): 3]]></Description> </Incident> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[should PASS 1]]></DataTag> +</Incident> <Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> <DataTag><![CDATA[should FAIL 2]]></DataTag> <Description><![CDATA[Compared doubles are not the same (fuzzy compare) @@ -430,21 +430,24 @@ <Duration msecs="0"/> </TestFunction> <TestFunction name="float16Comparisons"> -<Incident type="pass" file="" line="0"> - <DataTag><![CDATA[should SUCCEED 1]]></DataTag> -</Incident> <Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> <DataTag><![CDATA[should FAIL 1]]></DataTag> <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) Actual (operandLeft) : 1 Expected (operandRight): 3]]></Description> </Incident> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[should PASS 1]]></DataTag> +</Incident> <Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> <DataTag><![CDATA[should FAIL 2]]></DataTag> <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) Actual (operandLeft) : 0.0001 Expected (operandRight): 0.0003]]></Description> </Incident> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[should PASS 2]]></DataTag> +</Incident> <Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> <DataTag><![CDATA[should FAIL 3]]></DataTag> <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) @@ -452,7 +455,187 @@ Expected (operandRight): 99]]></Description> </Incident> <Incident type="pass" file="" line="0"> - <DataTag><![CDATA[should SUCCEED 2]]></DataTag> + <DataTag><![CDATA[should PASS 3]]></DataTag> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL 4]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 5.93e-05 + Expected (operandRight): 5.87e-05]]></Description> +</Incident> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[should PASS 4]]></DataTag> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL 5]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 5.94e+04 + Expected (operandRight): 5.88e+04]]></Description> +</Incident> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[should PASS: NaN == NaN]]></DataTag> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: NaN != 0]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : nan + Expected (operandRight): 0]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: 0 != NaN]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 0 + Expected (operandRight): nan]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: NaN != 1]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : nan + Expected (operandRight): 1]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: 1 != NaN]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 1 + Expected (operandRight): nan]]></Description> +</Incident> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[should PASS: inf == inf]]></DataTag> +</Incident> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[should PASS: -inf == -inf]]></DataTag> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: inf != -inf]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : inf + Expected (operandRight): -inf]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: -inf != inf]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -inf + Expected (operandRight): inf]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: inf != nan]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : inf + Expected (operandRight): nan]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: nan != inf]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : nan + Expected (operandRight): inf]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: -inf != nan]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -inf + Expected (operandRight): nan]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: nan != -inf]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : nan + Expected (operandRight): -inf]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: inf != 0]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : inf + Expected (operandRight): 0]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: 0 != inf]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 0 + Expected (operandRight): inf]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: -inf != 0]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -inf + Expected (operandRight): 0]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: 0 != -inf]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 0 + Expected (operandRight): -inf]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: inf != 1]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : inf + Expected (operandRight): 1]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: 1 != inf]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 1 + Expected (operandRight): inf]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: -inf != 1]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -inf + Expected (operandRight): 1]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: 1 != -inf]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 1 + Expected (operandRight): -inf]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: inf != max]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : inf + Expected (operandRight): 6.55e+04]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: inf != -max]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : inf + Expected (operandRight): -6.55e+04]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: max != inf]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 6.55e+04 + Expected (operandRight): inf]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: -max != inf]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -6.55e+04 + Expected (operandRight): inf]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: -inf != max]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -inf + Expected (operandRight): 6.55e+04]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: -inf != -max]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -inf + Expected (operandRight): -6.55e+04]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: max != -inf]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 6.55e+04 + Expected (operandRight): -inf]]></Description> +</Incident> +<Incident type="fail" file="qtbase/tests/auto/testlib/selftests/float/tst_float.cpp" line="0"> + <DataTag><![CDATA[should FAIL: -max != -inf]]></DataTag> + <Description><![CDATA[Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -6.55e+04 + Expected (operandRight): -inf]]></Description> </Incident> <Duration msecs="0"/> </TestFunction> diff --git a/tests/auto/testlib/selftests/expected_float.xunitxml b/tests/auto/testlib/selftests/expected_float.xunitxml index 9b2af9b616..602f9252a4 100644 --- a/tests/auto/testlib/selftests/expected_float.xunitxml +++ b/tests/auto/testlib/selftests/expected_float.xunitxml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<testsuite errors="0" failures="68" tests="6" name="tst_float"> +<testsuite errors="0" failures="96" tests="6" name="tst_float"> <properties> <property value="@INSERT_QT_VERSION_HERE@" name="QTestVersion"/> <property value="@INSERT_QT_VERSION_HERE@" name="QtVersion"/> @@ -206,6 +206,90 @@ <failure tag="should FAIL 3" message="Compared qfloat16s are not the same (fuzzy compare) Actual (operandLeft) : 98 Expected (operandRight): 99" result="fail"/> + <failure tag="should FAIL 4" message="Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 5.93e-05 + Expected (operandRight): 5.87e-05" result="fail"/> + <failure tag="should FAIL 5" message="Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 5.94e+04 + Expected (operandRight): 5.88e+04" result="fail"/> + <failure tag="should FAIL: NaN != 0" message="Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : nan + Expected (operandRight): 0" result="fail"/> + <failure tag="should FAIL: 0 != NaN" message="Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 0 + Expected (operandRight): nan" result="fail"/> + <failure tag="should FAIL: NaN != 1" message="Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : nan + Expected (operandRight): 1" result="fail"/> + <failure tag="should FAIL: 1 != NaN" message="Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 1 + Expected (operandRight): nan" result="fail"/> + <failure tag="should FAIL: inf != -inf" message="Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : inf + Expected (operandRight): -inf" result="fail"/> + <failure tag="should FAIL: -inf != inf" message="Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -inf + Expected (operandRight): inf" result="fail"/> + <failure tag="should FAIL: inf != nan" message="Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : inf + Expected (operandRight): nan" result="fail"/> + <failure tag="should FAIL: nan != inf" message="Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : nan + Expected (operandRight): inf" result="fail"/> + <failure tag="should FAIL: -inf != nan" message="Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -inf + Expected (operandRight): nan" result="fail"/> + <failure tag="should FAIL: nan != -inf" message="Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : nan + Expected (operandRight): -inf" result="fail"/> + <failure tag="should FAIL: inf != 0" message="Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : inf + Expected (operandRight): 0" result="fail"/> + <failure tag="should FAIL: 0 != inf" message="Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 0 + Expected (operandRight): inf" result="fail"/> + <failure tag="should FAIL: -inf != 0" message="Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -inf + Expected (operandRight): 0" result="fail"/> + <failure tag="should FAIL: 0 != -inf" message="Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 0 + Expected (operandRight): -inf" result="fail"/> + <failure tag="should FAIL: inf != 1" message="Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : inf + Expected (operandRight): 1" result="fail"/> + <failure tag="should FAIL: 1 != inf" message="Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 1 + Expected (operandRight): inf" result="fail"/> + <failure tag="should FAIL: -inf != 1" message="Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -inf + Expected (operandRight): 1" result="fail"/> + <failure tag="should FAIL: 1 != -inf" message="Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 1 + Expected (operandRight): -inf" result="fail"/> + <failure tag="should FAIL: inf != max" message="Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : inf + Expected (operandRight): 6.55e+04" result="fail"/> + <failure tag="should FAIL: inf != -max" message="Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : inf + Expected (operandRight): -6.55e+04" result="fail"/> + <failure tag="should FAIL: max != inf" message="Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 6.55e+04 + Expected (operandRight): inf" result="fail"/> + <failure tag="should FAIL: -max != inf" message="Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -6.55e+04 + Expected (operandRight): inf" result="fail"/> + <failure tag="should FAIL: -inf != max" message="Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -inf + Expected (operandRight): 6.55e+04" result="fail"/> + <failure tag="should FAIL: -inf != -max" message="Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -inf + Expected (operandRight): -6.55e+04" result="fail"/> + <failure tag="should FAIL: max != -inf" message="Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : 6.55e+04 + Expected (operandRight): -inf" result="fail"/> + <failure tag="should FAIL: -max != -inf" message="Compared qfloat16s are not the same (fuzzy compare) + Actual (operandLeft) : -6.55e+04 + Expected (operandRight): -inf" result="fail"/> </testcase> <testcase result="fail" name="compareFloatTests"> <failure tag="1e0" message="Compared floats are not the same (fuzzy compare) diff --git a/tests/auto/testlib/selftests/expected_globaldata.lightxml b/tests/auto/testlib/selftests/expected_globaldata.lightxml index f66c4c552d..1212e4b364 100644 --- a/tests/auto/testlib/selftests/expected_globaldata.lightxml +++ b/tests/auto/testlib/selftests/expected_globaldata.lightxml @@ -12,174 +12,195 @@ </TestFunction> <TestFunction name="testGlobal"> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 1]]></DataTag> - <Description><![CDATA[init testGlobal local 1]]></Description> + <DataTag><![CDATA[global=false:local=false]]></DataTag> + <Description><![CDATA[init testGlobal local=false]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 1]]></DataTag> + <DataTag><![CDATA[global=false:local=false]]></DataTag> <Description><![CDATA[global: false]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 1]]></DataTag> + <DataTag><![CDATA[global=false:local=false]]></DataTag> <Description><![CDATA[local: false]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 1]]></DataTag> - <Description><![CDATA[cleanup testGlobal local 1]]></Description> + <DataTag><![CDATA[global=false:local=false]]></DataTag> + <Description><![CDATA[cleanup testGlobal local=false]]></Description> </Message> <Incident type="pass" file="" line="0"> - <DataTag><![CDATA[1:local 1]]></DataTag> + <DataTag><![CDATA[global=false:local=false]]></DataTag> </Incident> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 2]]></DataTag> - <Description><![CDATA[init testGlobal local 2]]></Description> + <DataTag><![CDATA[global=false:local=true]]></DataTag> + <Description><![CDATA[init testGlobal local=true]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 2]]></DataTag> + <DataTag><![CDATA[global=false:local=true]]></DataTag> <Description><![CDATA[global: false]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 2]]></DataTag> + <DataTag><![CDATA[global=false:local=true]]></DataTag> <Description><![CDATA[local: true]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 2]]></DataTag> - <Description><![CDATA[cleanup testGlobal local 2]]></Description> + <DataTag><![CDATA[global=false:local=true]]></DataTag> + <Description><![CDATA[cleanup testGlobal local=true]]></Description> </Message> <Incident type="pass" file="" line="0"> - <DataTag><![CDATA[1:local 2]]></DataTag> + <DataTag><![CDATA[global=false:local=true]]></DataTag> </Incident> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[2:local 1]]></DataTag> - <Description><![CDATA[init testGlobal local 1]]></Description> + <DataTag><![CDATA[global=true:local=false]]></DataTag> + <Description><![CDATA[init testGlobal local=false]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[2:local 1]]></DataTag> + <DataTag><![CDATA[global=true:local=false]]></DataTag> <Description><![CDATA[global: true]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[2:local 1]]></DataTag> + <DataTag><![CDATA[global=true:local=false]]></DataTag> <Description><![CDATA[local: false]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[2:local 1]]></DataTag> - <Description><![CDATA[cleanup testGlobal local 1]]></Description> + <DataTag><![CDATA[global=true:local=false]]></DataTag> + <Description><![CDATA[cleanup testGlobal local=false]]></Description> </Message> <Incident type="pass" file="" line="0"> - <DataTag><![CDATA[2:local 1]]></DataTag> + <DataTag><![CDATA[global=true:local=false]]></DataTag> </Incident> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[2:local 2]]></DataTag> - <Description><![CDATA[init testGlobal local 2]]></Description> + <DataTag><![CDATA[global=true:local=true]]></DataTag> + <Description><![CDATA[init testGlobal local=true]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[2:local 2]]></DataTag> + <DataTag><![CDATA[global=true:local=true]]></DataTag> <Description><![CDATA[global: true]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[2:local 2]]></DataTag> + <DataTag><![CDATA[global=true:local=true]]></DataTag> <Description><![CDATA[local: true]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[2:local 2]]></DataTag> - <Description><![CDATA[cleanup testGlobal local 2]]></Description> + <DataTag><![CDATA[global=true:local=true]]></DataTag> + <Description><![CDATA[cleanup testGlobal local=true]]></Description> </Message> <Incident type="pass" file="" line="0"> - <DataTag><![CDATA[2:local 2]]></DataTag> + <DataTag><![CDATA[global=true:local=true]]></DataTag> </Incident> <Duration msecs="0"/> </TestFunction> <TestFunction name="skip"> <Message type="skip" file="qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp" line="0"> - <DataTag><![CDATA[1]]></DataTag> + <DataTag><![CDATA[global=false]]></DataTag> <Description><![CDATA[skipping]]></Description> </Message> <Duration msecs="0"/> </TestFunction> <TestFunction name="skipLocal"> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 1]]></DataTag> - <Description><![CDATA[init skipLocal local 1]]></Description> + <DataTag><![CDATA[global=false:local=false]]></DataTag> + <Description><![CDATA[init skipLocal local=false]]></Description> </Message> <Message type="skip" file="qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp" line="0"> - <DataTag><![CDATA[1:local 1]]></DataTag> + <DataTag><![CDATA[global=false:local=false]]></DataTag> <Description><![CDATA[skipping]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 1]]></DataTag> - <Description><![CDATA[cleanup skipLocal local 1]]></Description> + <DataTag><![CDATA[global=false:local=false]]></DataTag> + <Description><![CDATA[cleanup skipLocal local=false]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 2]]></DataTag> - <Description><![CDATA[init skipLocal local 2]]></Description> + <DataTag><![CDATA[global=false:local=true]]></DataTag> + <Description><![CDATA[init skipLocal local=true]]></Description> </Message> <Message type="skip" file="qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp" line="0"> - <DataTag><![CDATA[1:local 2]]></DataTag> + <DataTag><![CDATA[global=false:local=true]]></DataTag> <Description><![CDATA[skipping]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 2]]></DataTag> - <Description><![CDATA[cleanup skipLocal local 2]]></Description> + <DataTag><![CDATA[global=false:local=true]]></DataTag> + <Description><![CDATA[cleanup skipLocal local=true]]></Description> +</Message> +<Message type="qdebug" file="" line="0"> + <DataTag><![CDATA[global=true:local=false]]></DataTag> + <Description><![CDATA[init skipLocal local=false]]></Description> +</Message> +<Message type="skip" file="qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp" line="0"> + <DataTag><![CDATA[global=true:local=false]]></DataTag> + <Description><![CDATA[skipping]]></Description> +</Message> +<Message type="qdebug" file="" line="0"> + <DataTag><![CDATA[global=true:local=false]]></DataTag> + <Description><![CDATA[cleanup skipLocal local=false]]></Description> +</Message> +<Message type="qdebug" file="" line="0"> + <DataTag><![CDATA[global=true:local=true]]></DataTag> + <Description><![CDATA[init skipLocal local=true]]></Description> +</Message> +<Message type="skip" file="qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp" line="0"> + <DataTag><![CDATA[global=true:local=true]]></DataTag> + <Description><![CDATA[skipping]]></Description> +</Message> +<Message type="qdebug" file="" line="0"> + <DataTag><![CDATA[global=true:local=true]]></DataTag> + <Description><![CDATA[cleanup skipLocal local=true]]></Description> </Message> <Duration msecs="0"/> </TestFunction> <TestFunction name="skipSingle"> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 1]]></DataTag> - <Description><![CDATA[init skipSingle local 1]]></Description> + <DataTag><![CDATA[global=false:local=false]]></DataTag> + <Description><![CDATA[init skipSingle local=false]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 1]]></DataTag> + <DataTag><![CDATA[global=false:local=false]]></DataTag> <Description><![CDATA[global: false local: false]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 1]]></DataTag> - <Description><![CDATA[cleanup skipSingle local 1]]></Description> + <DataTag><![CDATA[global=false:local=false]]></DataTag> + <Description><![CDATA[cleanup skipSingle local=false]]></Description> </Message> <Incident type="pass" file="" line="0"> - <DataTag><![CDATA[1:local 1]]></DataTag> + <DataTag><![CDATA[global=false:local=false]]></DataTag> </Incident> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 2]]></DataTag> - <Description><![CDATA[init skipSingle local 2]]></Description> + <DataTag><![CDATA[global=false:local=true]]></DataTag> + <Description><![CDATA[init skipSingle local=true]]></Description> </Message> -<Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 2]]></DataTag> - <Description><![CDATA[global: false local: true]]></Description> +<Message type="skip" file="qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp" line="0"> + <DataTag><![CDATA[global=false:local=true]]></DataTag> + <Description><![CDATA[Skipping]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 2]]></DataTag> - <Description><![CDATA[cleanup skipSingle local 2]]></Description> + <DataTag><![CDATA[global=false:local=true]]></DataTag> + <Description><![CDATA[cleanup skipSingle local=true]]></Description> </Message> -<Incident type="pass" file="" line="0"> - <DataTag><![CDATA[1:local 2]]></DataTag> -</Incident> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[2:local 1]]></DataTag> - <Description><![CDATA[init skipSingle local 1]]></Description> + <DataTag><![CDATA[global=true:local=false]]></DataTag> + <Description><![CDATA[init skipSingle local=false]]></Description> </Message> <Message type="skip" file="qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp" line="0"> - <DataTag><![CDATA[2:local 1]]></DataTag> - <Description><![CDATA[skipping]]></Description> + <DataTag><![CDATA[global=true:local=false]]></DataTag> + <Description><![CDATA[Skipping]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[2:local 1]]></DataTag> - <Description><![CDATA[cleanup skipSingle local 1]]></Description> + <DataTag><![CDATA[global=true:local=false]]></DataTag> + <Description><![CDATA[cleanup skipSingle local=false]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[2:local 2]]></DataTag> - <Description><![CDATA[init skipSingle local 2]]></Description> + <DataTag><![CDATA[global=true:local=true]]></DataTag> + <Description><![CDATA[init skipSingle local=true]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[2:local 2]]></DataTag> + <DataTag><![CDATA[global=true:local=true]]></DataTag> <Description><![CDATA[global: true local: true]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[2:local 2]]></DataTag> - <Description><![CDATA[cleanup skipSingle local 2]]></Description> + <DataTag><![CDATA[global=true:local=true]]></DataTag> + <Description><![CDATA[cleanup skipSingle local=true]]></Description> </Message> <Incident type="pass" file="" line="0"> - <DataTag><![CDATA[2:local 2]]></DataTag> + <DataTag><![CDATA[global=true:local=true]]></DataTag> </Incident> <Duration msecs="0"/> </TestFunction> diff --git a/tests/auto/testlib/selftests/expected_globaldata.tap b/tests/auto/testlib/selftests/expected_globaldata.tap index 580cf3a7a8..4d61b7437b 100644 --- a/tests/auto/testlib/selftests/expected_globaldata.tap +++ b/tests/auto/testlib/selftests/expected_globaldata.tap @@ -2,51 +2,56 @@ TAP version 13 # tst_globaldata # initTestCase initTestCase (null) ok 1 - initTestCase() -# init testGlobal local 1 +# init testGlobal local=false # global: false # local: false -# cleanup testGlobal local 1 -ok 2 - testGlobal(1:local 1) -# init testGlobal local 2 +# cleanup testGlobal local=false +ok 2 - testGlobal(global=false:local=false) +# init testGlobal local=true # global: false # local: true -# cleanup testGlobal local 2 -ok 3 - testGlobal(1:local 2) -# init testGlobal local 1 +# cleanup testGlobal local=true +ok 3 - testGlobal(global=false:local=true) +# init testGlobal local=false # global: true # local: false -# cleanup testGlobal local 1 -ok 4 - testGlobal(2:local 1) -# init testGlobal local 2 +# cleanup testGlobal local=false +ok 4 - testGlobal(global=true:local=false) +# init testGlobal local=true # global: true # local: true -# cleanup testGlobal local 2 -ok 5 - testGlobal(2:local 2) -ok 6 - skip(1) # SKIP skipping -# init skipLocal local 1 -ok 7 - skipLocal(1:local 1) # SKIP skipping -# cleanup skipLocal local 1 -# init skipLocal local 2 -ok 8 - skipLocal(1:local 2) # SKIP skipping -# cleanup skipLocal local 2 -# init skipSingle local 1 +# cleanup testGlobal local=true +ok 5 - testGlobal(global=true:local=true) +ok 6 - skip(global=false) # SKIP skipping +# init skipLocal local=false +ok 7 - skipLocal(global=false:local=false) # SKIP skipping +# cleanup skipLocal local=false +# init skipLocal local=true +ok 8 - skipLocal(global=false:local=true) # SKIP skipping +# cleanup skipLocal local=true +# init skipLocal local=false +ok 9 - skipLocal(global=true:local=false) # SKIP skipping +# cleanup skipLocal local=false +# init skipLocal local=true +ok 10 - skipLocal(global=true:local=true) # SKIP skipping +# cleanup skipLocal local=true +# init skipSingle local=false # global: false local: false -# cleanup skipSingle local 1 -ok 9 - skipSingle(1:local 1) -# init skipSingle local 2 -# global: false local: true -# cleanup skipSingle local 2 -ok 10 - skipSingle(1:local 2) -# init skipSingle local 1 -ok 11 - skipSingle(2:local 1) # SKIP skipping -# cleanup skipSingle local 1 -# init skipSingle local 2 +# cleanup skipSingle local=false +ok 11 - skipSingle(global=false:local=false) +# init skipSingle local=true +ok 12 - skipSingle(global=false:local=true) # SKIP Skipping +# cleanup skipSingle local=true +# init skipSingle local=false +ok 13 - skipSingle(global=true:local=false) # SKIP Skipping +# cleanup skipSingle local=false +# init skipSingle local=true # global: true local: true -# cleanup skipSingle local 2 -ok 12 - skipSingle(2:local 2) +# cleanup skipSingle local=true +ok 14 - skipSingle(global=true:local=true) # cleanupTestCase cleanupTestCase (null) -ok 13 - cleanupTestCase() -1..13 -# tests 13 -# pass 9 +ok 15 - cleanupTestCase() +1..15 +# tests 15 +# pass 8 # fail 0 diff --git a/tests/auto/testlib/selftests/expected_globaldata.teamcity b/tests/auto/testlib/selftests/expected_globaldata.teamcity index 5d623a3285..f76f6090ba 100644 --- a/tests/auto/testlib/selftests/expected_globaldata.teamcity +++ b/tests/auto/testlib/selftests/expected_globaldata.teamcity @@ -2,30 +2,31 @@ ##teamcity[testStarted name='initTestCase()' flowId='tst_globaldata'] ##teamcity[testStdOut name='initTestCase()' out='QDEBUG: initTestCase initTestCase (null)' flowId='tst_globaldata'] ##teamcity[testFinished name='initTestCase()' flowId='tst_globaldata'] -##teamcity[testStarted name='testGlobal(local 1)' flowId='tst_globaldata'] -##teamcity[testStdOut name='testGlobal(local 1)' out='QDEBUG: init testGlobal local 1|nQDEBUG: global: false|nQDEBUG: local: false|nQDEBUG: cleanup testGlobal local 1' flowId='tst_globaldata'] -##teamcity[testFinished name='testGlobal(local 1)' flowId='tst_globaldata'] -##teamcity[testStarted name='testGlobal(local 2)' flowId='tst_globaldata'] -##teamcity[testStdOut name='testGlobal(local 2)' out='QDEBUG: init testGlobal local 2|nQDEBUG: global: false|nQDEBUG: local: true|nQDEBUG: cleanup testGlobal local 2' flowId='tst_globaldata'] -##teamcity[testFinished name='testGlobal(local 2)' flowId='tst_globaldata'] -##teamcity[testStarted name='testGlobal(local 1)' flowId='tst_globaldata'] -##teamcity[testStdOut name='testGlobal(local 1)' out='QDEBUG: init testGlobal local 1|nQDEBUG: global: true|nQDEBUG: local: false|nQDEBUG: cleanup testGlobal local 1' flowId='tst_globaldata'] -##teamcity[testFinished name='testGlobal(local 1)' flowId='tst_globaldata'] -##teamcity[testStarted name='testGlobal(local 2)' flowId='tst_globaldata'] -##teamcity[testStdOut name='testGlobal(local 2)' out='QDEBUG: init testGlobal local 2|nQDEBUG: global: true|nQDEBUG: local: true|nQDEBUG: cleanup testGlobal local 2' flowId='tst_globaldata'] -##teamcity[testFinished name='testGlobal(local 2)' flowId='tst_globaldata'] +##teamcity[testStarted name='testGlobal(local=false)' flowId='tst_globaldata'] +##teamcity[testStdOut name='testGlobal(local=false)' out='QDEBUG: init testGlobal local=false|nQDEBUG: global: false|nQDEBUG: local: false|nQDEBUG: cleanup testGlobal local=false' flowId='tst_globaldata'] +##teamcity[testFinished name='testGlobal(local=false)' flowId='tst_globaldata'] +##teamcity[testStarted name='testGlobal(local=true)' flowId='tst_globaldata'] +##teamcity[testStdOut name='testGlobal(local=true)' out='QDEBUG: init testGlobal local=true|nQDEBUG: global: false|nQDEBUG: local: true|nQDEBUG: cleanup testGlobal local=true' flowId='tst_globaldata'] +##teamcity[testFinished name='testGlobal(local=true)' flowId='tst_globaldata'] +##teamcity[testStarted name='testGlobal(local=false)' flowId='tst_globaldata'] +##teamcity[testStdOut name='testGlobal(local=false)' out='QDEBUG: init testGlobal local=false|nQDEBUG: global: true|nQDEBUG: local: false|nQDEBUG: cleanup testGlobal local=false' flowId='tst_globaldata'] +##teamcity[testFinished name='testGlobal(local=false)' flowId='tst_globaldata'] +##teamcity[testStarted name='testGlobal(local=true)' flowId='tst_globaldata'] +##teamcity[testStdOut name='testGlobal(local=true)' out='QDEBUG: init testGlobal local=true|nQDEBUG: global: true|nQDEBUG: local: true|nQDEBUG: cleanup testGlobal local=true' flowId='tst_globaldata'] +##teamcity[testFinished name='testGlobal(local=true)' flowId='tst_globaldata'] ##teamcity[testIgnored name='skip()' message='skipping |[Loc: qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp(0)|]' flowId='tst_globaldata'] -##teamcity[testIgnored name='skipLocal(local 1)' message='skipping |[Loc: qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp(0)|]' flowId='tst_globaldata'] -##teamcity[testIgnored name='skipLocal(local 2)' message='skipping |[Loc: qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp(0)|]' flowId='tst_globaldata'] -##teamcity[testStarted name='skipSingle(local 1)' flowId='tst_globaldata'] -##teamcity[testStdOut name='skipSingle(local 1)' out='QDEBUG: init skipLocal local 1|nQDEBUG: cleanup skipLocal local 1|nQDEBUG: init skipLocal local 2|nQDEBUG: cleanup skipLocal local 2|nQDEBUG: init skipSingle local 1|nQDEBUG: global: false local: false|nQDEBUG: cleanup skipSingle local 1' flowId='tst_globaldata'] -##teamcity[testFinished name='skipSingle(local 1)' flowId='tst_globaldata'] -##teamcity[testStarted name='skipSingle(local 2)' flowId='tst_globaldata'] -##teamcity[testStdOut name='skipSingle(local 2)' out='QDEBUG: init skipSingle local 2|nQDEBUG: global: false local: true|nQDEBUG: cleanup skipSingle local 2' flowId='tst_globaldata'] -##teamcity[testFinished name='skipSingle(local 2)' flowId='tst_globaldata'] -##teamcity[testIgnored name='skipSingle(local 1)' message='skipping |[Loc: qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp(0)|]' flowId='tst_globaldata'] -##teamcity[testStdOut name='skipSingle(local 2)' out='QDEBUG: init skipSingle local 1|nQDEBUG: cleanup skipSingle local 1|nQDEBUG: init skipSingle local 2|nQDEBUG: global: true local: true|nQDEBUG: cleanup skipSingle local 2' flowId='tst_globaldata'] -##teamcity[testFinished name='skipSingle(local 2)' flowId='tst_globaldata'] +##teamcity[testIgnored name='skipLocal(local=false)' message='skipping |[Loc: qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp(0)|]' flowId='tst_globaldata'] +##teamcity[testIgnored name='skipLocal(local=true)' message='skipping |[Loc: qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp(0)|]' flowId='tst_globaldata'] +##teamcity[testIgnored name='skipLocal(local=false)' message='skipping |[Loc: qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp(0)|]' flowId='tst_globaldata'] +##teamcity[testIgnored name='skipLocal(local=true)' message='skipping |[Loc: qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp(0)|]' flowId='tst_globaldata'] +##teamcity[testStarted name='skipSingle(local=false)' flowId='tst_globaldata'] +##teamcity[testStdOut name='skipSingle(local=false)' out='QDEBUG: init skipLocal local=false|nQDEBUG: cleanup skipLocal local=false|nQDEBUG: init skipLocal local=true|nQDEBUG: cleanup skipLocal local=true|nQDEBUG: init skipLocal local=false|nQDEBUG: cleanup skipLocal local=false|nQDEBUG: init skipLocal local=true|nQDEBUG: cleanup skipLocal local=true|nQDEBUG: init skipSingle local=false|nQDEBUG: global: false local: false|nQDEBUG: cleanup skipSingle local=false' flowId='tst_globaldata'] +##teamcity[testFinished name='skipSingle(local=false)' flowId='tst_globaldata'] +##teamcity[testIgnored name='skipSingle(local=true)' message='Skipping |[Loc: qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp(0)|]' flowId='tst_globaldata'] +##teamcity[testIgnored name='skipSingle(local=false)' message='Skipping |[Loc: qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp(0)|]' flowId='tst_globaldata'] +##teamcity[testStarted name='skipSingle(local=true)' flowId='tst_globaldata'] +##teamcity[testStdOut name='skipSingle(local=true)' out='QDEBUG: init skipSingle local=true|nQDEBUG: cleanup skipSingle local=true|nQDEBUG: init skipSingle local=false|nQDEBUG: cleanup skipSingle local=false|nQDEBUG: init skipSingle local=true|nQDEBUG: global: true local: true|nQDEBUG: cleanup skipSingle local=true' flowId='tst_globaldata'] +##teamcity[testFinished name='skipSingle(local=true)' flowId='tst_globaldata'] ##teamcity[testStarted name='cleanupTestCase()' flowId='tst_globaldata'] ##teamcity[testStdOut name='cleanupTestCase()' out='QDEBUG: cleanupTestCase cleanupTestCase (null)' flowId='tst_globaldata'] ##teamcity[testFinished name='cleanupTestCase()' flowId='tst_globaldata'] diff --git a/tests/auto/testlib/selftests/expected_globaldata.txt b/tests/auto/testlib/selftests/expected_globaldata.txt index b12f4a2a69..016b5e8299 100644 --- a/tests/auto/testlib/selftests/expected_globaldata.txt +++ b/tests/auto/testlib/selftests/expected_globaldata.txt @@ -2,53 +2,61 @@ Config: Using QtTest library QDEBUG : tst_globaldata::initTestCase() initTestCase initTestCase (null) PASS : tst_globaldata::initTestCase() -QDEBUG : tst_globaldata::testGlobal(1:local 1) init testGlobal local 1 -QDEBUG : tst_globaldata::testGlobal(1:local 1) global: false -QDEBUG : tst_globaldata::testGlobal(1:local 1) local: false -QDEBUG : tst_globaldata::testGlobal(1:local 1) cleanup testGlobal local 1 -PASS : tst_globaldata::testGlobal(1:local 1) -QDEBUG : tst_globaldata::testGlobal(1:local 2) init testGlobal local 2 -QDEBUG : tst_globaldata::testGlobal(1:local 2) global: false -QDEBUG : tst_globaldata::testGlobal(1:local 2) local: true -QDEBUG : tst_globaldata::testGlobal(1:local 2) cleanup testGlobal local 2 -PASS : tst_globaldata::testGlobal(1:local 2) -QDEBUG : tst_globaldata::testGlobal(2:local 1) init testGlobal local 1 -QDEBUG : tst_globaldata::testGlobal(2:local 1) global: true -QDEBUG : tst_globaldata::testGlobal(2:local 1) local: false -QDEBUG : tst_globaldata::testGlobal(2:local 1) cleanup testGlobal local 1 -PASS : tst_globaldata::testGlobal(2:local 1) -QDEBUG : tst_globaldata::testGlobal(2:local 2) init testGlobal local 2 -QDEBUG : tst_globaldata::testGlobal(2:local 2) global: true -QDEBUG : tst_globaldata::testGlobal(2:local 2) local: true -QDEBUG : tst_globaldata::testGlobal(2:local 2) cleanup testGlobal local 2 -PASS : tst_globaldata::testGlobal(2:local 2) -SKIP : tst_globaldata::skip(1) skipping +QDEBUG : tst_globaldata::testGlobal(global=false:local=false) init testGlobal local=false +QDEBUG : tst_globaldata::testGlobal(global=false:local=false) global: false +QDEBUG : tst_globaldata::testGlobal(global=false:local=false) local: false +QDEBUG : tst_globaldata::testGlobal(global=false:local=false) cleanup testGlobal local=false +PASS : tst_globaldata::testGlobal(global=false:local=false) +QDEBUG : tst_globaldata::testGlobal(global=false:local=true) init testGlobal local=true +QDEBUG : tst_globaldata::testGlobal(global=false:local=true) global: false +QDEBUG : tst_globaldata::testGlobal(global=false:local=true) local: true +QDEBUG : tst_globaldata::testGlobal(global=false:local=true) cleanup testGlobal local=true +PASS : tst_globaldata::testGlobal(global=false:local=true) +QDEBUG : tst_globaldata::testGlobal(global=true:local=false) init testGlobal local=false +QDEBUG : tst_globaldata::testGlobal(global=true:local=false) global: true +QDEBUG : tst_globaldata::testGlobal(global=true:local=false) local: false +QDEBUG : tst_globaldata::testGlobal(global=true:local=false) cleanup testGlobal local=false +PASS : tst_globaldata::testGlobal(global=true:local=false) +QDEBUG : tst_globaldata::testGlobal(global=true:local=true) init testGlobal local=true +QDEBUG : tst_globaldata::testGlobal(global=true:local=true) global: true +QDEBUG : tst_globaldata::testGlobal(global=true:local=true) local: true +QDEBUG : tst_globaldata::testGlobal(global=true:local=true) cleanup testGlobal local=true +PASS : tst_globaldata::testGlobal(global=true:local=true) +SKIP : tst_globaldata::skip(global=false) skipping Loc: [qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp(0)] -QDEBUG : tst_globaldata::skipLocal(1:local 1) init skipLocal local 1 -SKIP : tst_globaldata::skipLocal(1:local 1) skipping +QDEBUG : tst_globaldata::skipLocal(global=false:local=false) init skipLocal local=false +SKIP : tst_globaldata::skipLocal(global=false:local=false) skipping Loc: [qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp(0)] -QDEBUG : tst_globaldata::skipLocal(1:local 1) cleanup skipLocal local 1 -QDEBUG : tst_globaldata::skipLocal(1:local 2) init skipLocal local 2 -SKIP : tst_globaldata::skipLocal(1:local 2) skipping +QDEBUG : tst_globaldata::skipLocal(global=false:local=false) cleanup skipLocal local=false +QDEBUG : tst_globaldata::skipLocal(global=false:local=true) init skipLocal local=true +SKIP : tst_globaldata::skipLocal(global=false:local=true) skipping Loc: [qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp(0)] -QDEBUG : tst_globaldata::skipLocal(1:local 2) cleanup skipLocal local 2 -QDEBUG : tst_globaldata::skipSingle(1:local 1) init skipSingle local 1 -QDEBUG : tst_globaldata::skipSingle(1:local 1) global: false local: false -QDEBUG : tst_globaldata::skipSingle(1:local 1) cleanup skipSingle local 1 -PASS : tst_globaldata::skipSingle(1:local 1) -QDEBUG : tst_globaldata::skipSingle(1:local 2) init skipSingle local 2 -QDEBUG : tst_globaldata::skipSingle(1:local 2) global: false local: true -QDEBUG : tst_globaldata::skipSingle(1:local 2) cleanup skipSingle local 2 -PASS : tst_globaldata::skipSingle(1:local 2) -QDEBUG : tst_globaldata::skipSingle(2:local 1) init skipSingle local 1 -SKIP : tst_globaldata::skipSingle(2:local 1) skipping +QDEBUG : tst_globaldata::skipLocal(global=false:local=true) cleanup skipLocal local=true +QDEBUG : tst_globaldata::skipLocal(global=true:local=false) init skipLocal local=false +SKIP : tst_globaldata::skipLocal(global=true:local=false) skipping Loc: [qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp(0)] -QDEBUG : tst_globaldata::skipSingle(2:local 1) cleanup skipSingle local 1 -QDEBUG : tst_globaldata::skipSingle(2:local 2) init skipSingle local 2 -QDEBUG : tst_globaldata::skipSingle(2:local 2) global: true local: true -QDEBUG : tst_globaldata::skipSingle(2:local 2) cleanup skipSingle local 2 -PASS : tst_globaldata::skipSingle(2:local 2) +QDEBUG : tst_globaldata::skipLocal(global=true:local=false) cleanup skipLocal local=false +QDEBUG : tst_globaldata::skipLocal(global=true:local=true) init skipLocal local=true +SKIP : tst_globaldata::skipLocal(global=true:local=true) skipping + Loc: [qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp(0)] +QDEBUG : tst_globaldata::skipLocal(global=true:local=true) cleanup skipLocal local=true +QDEBUG : tst_globaldata::skipSingle(global=false:local=false) init skipSingle local=false +QDEBUG : tst_globaldata::skipSingle(global=false:local=false) global: false local: false +QDEBUG : tst_globaldata::skipSingle(global=false:local=false) cleanup skipSingle local=false +PASS : tst_globaldata::skipSingle(global=false:local=false) +QDEBUG : tst_globaldata::skipSingle(global=false:local=true) init skipSingle local=true +SKIP : tst_globaldata::skipSingle(global=false:local=true) Skipping + Loc: [qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp(0)] +QDEBUG : tst_globaldata::skipSingle(global=false:local=true) cleanup skipSingle local=true +QDEBUG : tst_globaldata::skipSingle(global=true:local=false) init skipSingle local=false +SKIP : tst_globaldata::skipSingle(global=true:local=false) Skipping + Loc: [qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp(0)] +QDEBUG : tst_globaldata::skipSingle(global=true:local=false) cleanup skipSingle local=false +QDEBUG : tst_globaldata::skipSingle(global=true:local=true) init skipSingle local=true +QDEBUG : tst_globaldata::skipSingle(global=true:local=true) global: true local: true +QDEBUG : tst_globaldata::skipSingle(global=true:local=true) cleanup skipSingle local=true +PASS : tst_globaldata::skipSingle(global=true:local=true) QDEBUG : tst_globaldata::cleanupTestCase() cleanupTestCase cleanupTestCase (null) PASS : tst_globaldata::cleanupTestCase() -Totals: 9 passed, 0 failed, 4 skipped, 0 blacklisted, 0ms +Totals: 8 passed, 0 failed, 7 skipped, 0 blacklisted, 0ms ********* Finished testing of tst_globaldata ********* diff --git a/tests/auto/testlib/selftests/expected_globaldata.xml b/tests/auto/testlib/selftests/expected_globaldata.xml index 0f705ef352..9aa48c8f16 100644 --- a/tests/auto/testlib/selftests/expected_globaldata.xml +++ b/tests/auto/testlib/selftests/expected_globaldata.xml @@ -14,174 +14,195 @@ </TestFunction> <TestFunction name="testGlobal"> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 1]]></DataTag> - <Description><![CDATA[init testGlobal local 1]]></Description> + <DataTag><![CDATA[global=false:local=false]]></DataTag> + <Description><![CDATA[init testGlobal local=false]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 1]]></DataTag> + <DataTag><![CDATA[global=false:local=false]]></DataTag> <Description><![CDATA[global: false]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 1]]></DataTag> + <DataTag><![CDATA[global=false:local=false]]></DataTag> <Description><![CDATA[local: false]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 1]]></DataTag> - <Description><![CDATA[cleanup testGlobal local 1]]></Description> + <DataTag><![CDATA[global=false:local=false]]></DataTag> + <Description><![CDATA[cleanup testGlobal local=false]]></Description> </Message> <Incident type="pass" file="" line="0"> - <DataTag><![CDATA[1:local 1]]></DataTag> + <DataTag><![CDATA[global=false:local=false]]></DataTag> </Incident> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 2]]></DataTag> - <Description><![CDATA[init testGlobal local 2]]></Description> + <DataTag><![CDATA[global=false:local=true]]></DataTag> + <Description><![CDATA[init testGlobal local=true]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 2]]></DataTag> + <DataTag><![CDATA[global=false:local=true]]></DataTag> <Description><![CDATA[global: false]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 2]]></DataTag> + <DataTag><![CDATA[global=false:local=true]]></DataTag> <Description><![CDATA[local: true]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 2]]></DataTag> - <Description><![CDATA[cleanup testGlobal local 2]]></Description> + <DataTag><![CDATA[global=false:local=true]]></DataTag> + <Description><![CDATA[cleanup testGlobal local=true]]></Description> </Message> <Incident type="pass" file="" line="0"> - <DataTag><![CDATA[1:local 2]]></DataTag> + <DataTag><![CDATA[global=false:local=true]]></DataTag> </Incident> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[2:local 1]]></DataTag> - <Description><![CDATA[init testGlobal local 1]]></Description> + <DataTag><![CDATA[global=true:local=false]]></DataTag> + <Description><![CDATA[init testGlobal local=false]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[2:local 1]]></DataTag> + <DataTag><![CDATA[global=true:local=false]]></DataTag> <Description><![CDATA[global: true]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[2:local 1]]></DataTag> + <DataTag><![CDATA[global=true:local=false]]></DataTag> <Description><![CDATA[local: false]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[2:local 1]]></DataTag> - <Description><![CDATA[cleanup testGlobal local 1]]></Description> + <DataTag><![CDATA[global=true:local=false]]></DataTag> + <Description><![CDATA[cleanup testGlobal local=false]]></Description> </Message> <Incident type="pass" file="" line="0"> - <DataTag><![CDATA[2:local 1]]></DataTag> + <DataTag><![CDATA[global=true:local=false]]></DataTag> </Incident> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[2:local 2]]></DataTag> - <Description><![CDATA[init testGlobal local 2]]></Description> + <DataTag><![CDATA[global=true:local=true]]></DataTag> + <Description><![CDATA[init testGlobal local=true]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[2:local 2]]></DataTag> + <DataTag><![CDATA[global=true:local=true]]></DataTag> <Description><![CDATA[global: true]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[2:local 2]]></DataTag> + <DataTag><![CDATA[global=true:local=true]]></DataTag> <Description><![CDATA[local: true]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[2:local 2]]></DataTag> - <Description><![CDATA[cleanup testGlobal local 2]]></Description> + <DataTag><![CDATA[global=true:local=true]]></DataTag> + <Description><![CDATA[cleanup testGlobal local=true]]></Description> </Message> <Incident type="pass" file="" line="0"> - <DataTag><![CDATA[2:local 2]]></DataTag> + <DataTag><![CDATA[global=true:local=true]]></DataTag> </Incident> <Duration msecs="0"/> </TestFunction> <TestFunction name="skip"> <Message type="skip" file="qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp" line="0"> - <DataTag><![CDATA[1]]></DataTag> + <DataTag><![CDATA[global=false]]></DataTag> <Description><![CDATA[skipping]]></Description> </Message> <Duration msecs="0"/> </TestFunction> <TestFunction name="skipLocal"> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 1]]></DataTag> - <Description><![CDATA[init skipLocal local 1]]></Description> + <DataTag><![CDATA[global=false:local=false]]></DataTag> + <Description><![CDATA[init skipLocal local=false]]></Description> </Message> <Message type="skip" file="qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp" line="0"> - <DataTag><![CDATA[1:local 1]]></DataTag> + <DataTag><![CDATA[global=false:local=false]]></DataTag> <Description><![CDATA[skipping]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 1]]></DataTag> - <Description><![CDATA[cleanup skipLocal local 1]]></Description> + <DataTag><![CDATA[global=false:local=false]]></DataTag> + <Description><![CDATA[cleanup skipLocal local=false]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 2]]></DataTag> - <Description><![CDATA[init skipLocal local 2]]></Description> + <DataTag><![CDATA[global=false:local=true]]></DataTag> + <Description><![CDATA[init skipLocal local=true]]></Description> </Message> <Message type="skip" file="qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp" line="0"> - <DataTag><![CDATA[1:local 2]]></DataTag> + <DataTag><![CDATA[global=false:local=true]]></DataTag> <Description><![CDATA[skipping]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 2]]></DataTag> - <Description><![CDATA[cleanup skipLocal local 2]]></Description> + <DataTag><![CDATA[global=false:local=true]]></DataTag> + <Description><![CDATA[cleanup skipLocal local=true]]></Description> +</Message> +<Message type="qdebug" file="" line="0"> + <DataTag><![CDATA[global=true:local=false]]></DataTag> + <Description><![CDATA[init skipLocal local=false]]></Description> +</Message> +<Message type="skip" file="qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp" line="0"> + <DataTag><![CDATA[global=true:local=false]]></DataTag> + <Description><![CDATA[skipping]]></Description> +</Message> +<Message type="qdebug" file="" line="0"> + <DataTag><![CDATA[global=true:local=false]]></DataTag> + <Description><![CDATA[cleanup skipLocal local=false]]></Description> +</Message> +<Message type="qdebug" file="" line="0"> + <DataTag><![CDATA[global=true:local=true]]></DataTag> + <Description><![CDATA[init skipLocal local=true]]></Description> +</Message> +<Message type="skip" file="qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp" line="0"> + <DataTag><![CDATA[global=true:local=true]]></DataTag> + <Description><![CDATA[skipping]]></Description> +</Message> +<Message type="qdebug" file="" line="0"> + <DataTag><![CDATA[global=true:local=true]]></DataTag> + <Description><![CDATA[cleanup skipLocal local=true]]></Description> </Message> <Duration msecs="0"/> </TestFunction> <TestFunction name="skipSingle"> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 1]]></DataTag> - <Description><![CDATA[init skipSingle local 1]]></Description> + <DataTag><![CDATA[global=false:local=false]]></DataTag> + <Description><![CDATA[init skipSingle local=false]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 1]]></DataTag> + <DataTag><![CDATA[global=false:local=false]]></DataTag> <Description><![CDATA[global: false local: false]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 1]]></DataTag> - <Description><![CDATA[cleanup skipSingle local 1]]></Description> + <DataTag><![CDATA[global=false:local=false]]></DataTag> + <Description><![CDATA[cleanup skipSingle local=false]]></Description> </Message> <Incident type="pass" file="" line="0"> - <DataTag><![CDATA[1:local 1]]></DataTag> + <DataTag><![CDATA[global=false:local=false]]></DataTag> </Incident> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 2]]></DataTag> - <Description><![CDATA[init skipSingle local 2]]></Description> + <DataTag><![CDATA[global=false:local=true]]></DataTag> + <Description><![CDATA[init skipSingle local=true]]></Description> </Message> -<Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 2]]></DataTag> - <Description><![CDATA[global: false local: true]]></Description> +<Message type="skip" file="qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp" line="0"> + <DataTag><![CDATA[global=false:local=true]]></DataTag> + <Description><![CDATA[Skipping]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[1:local 2]]></DataTag> - <Description><![CDATA[cleanup skipSingle local 2]]></Description> + <DataTag><![CDATA[global=false:local=true]]></DataTag> + <Description><![CDATA[cleanup skipSingle local=true]]></Description> </Message> -<Incident type="pass" file="" line="0"> - <DataTag><![CDATA[1:local 2]]></DataTag> -</Incident> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[2:local 1]]></DataTag> - <Description><![CDATA[init skipSingle local 1]]></Description> + <DataTag><![CDATA[global=true:local=false]]></DataTag> + <Description><![CDATA[init skipSingle local=false]]></Description> </Message> <Message type="skip" file="qtbase/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp" line="0"> - <DataTag><![CDATA[2:local 1]]></DataTag> - <Description><![CDATA[skipping]]></Description> + <DataTag><![CDATA[global=true:local=false]]></DataTag> + <Description><![CDATA[Skipping]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[2:local 1]]></DataTag> - <Description><![CDATA[cleanup skipSingle local 1]]></Description> + <DataTag><![CDATA[global=true:local=false]]></DataTag> + <Description><![CDATA[cleanup skipSingle local=false]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[2:local 2]]></DataTag> - <Description><![CDATA[init skipSingle local 2]]></Description> + <DataTag><![CDATA[global=true:local=true]]></DataTag> + <Description><![CDATA[init skipSingle local=true]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[2:local 2]]></DataTag> + <DataTag><![CDATA[global=true:local=true]]></DataTag> <Description><![CDATA[global: true local: true]]></Description> </Message> <Message type="qdebug" file="" line="0"> - <DataTag><![CDATA[2:local 2]]></DataTag> - <Description><![CDATA[cleanup skipSingle local 2]]></Description> + <DataTag><![CDATA[global=true:local=true]]></DataTag> + <Description><![CDATA[cleanup skipSingle local=true]]></Description> </Message> <Incident type="pass" file="" line="0"> - <DataTag><![CDATA[2:local 2]]></DataTag> + <DataTag><![CDATA[global=true:local=true]]></DataTag> </Incident> <Duration msecs="0"/> </TestFunction> diff --git a/tests/auto/testlib/selftests/expected_globaldata.xunitxml b/tests/auto/testlib/selftests/expected_globaldata.xunitxml index bdd7e3f00a..de184c2fdd 100644 --- a/tests/auto/testlib/selftests/expected_globaldata.xunitxml +++ b/tests/auto/testlib/selftests/expected_globaldata.xunitxml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<testsuite errors="37" failures="0" tests="6" name="tst_globaldata"> +<testsuite errors="43" failures="0" tests="6" name="tst_globaldata"> <properties> <property value="@INSERT_QT_VERSION_HERE@" name="QTestVersion"/> <property value="@INSERT_QT_VERSION_HERE@" name="QtVersion"/> @@ -9,88 +9,100 @@ <!-- message="initTestCase initTestCase (null)" type="qdebug" --> </testcase> <testcase result="pass" name="testGlobal"> - <!-- tag="1:local 1" message="init testGlobal local 1" type="qdebug" --> - <!-- tag="1:local 1" message="global: false" type="qdebug" --> - <!-- tag="1:local 1" message="local: false" type="qdebug" --> - <!-- tag="1:local 1" message="cleanup testGlobal local 1" type="qdebug" --> - <!-- tag="1:local 2" message="init testGlobal local 2" type="qdebug" --> - <!-- tag="1:local 2" message="global: false" type="qdebug" --> - <!-- tag="1:local 2" message="local: true" type="qdebug" --> - <!-- tag="1:local 2" message="cleanup testGlobal local 2" type="qdebug" --> - <!-- tag="2:local 1" message="init testGlobal local 1" type="qdebug" --> - <!-- tag="2:local 1" message="global: true" type="qdebug" --> - <!-- tag="2:local 1" message="local: false" type="qdebug" --> - <!-- tag="2:local 1" message="cleanup testGlobal local 1" type="qdebug" --> - <!-- tag="2:local 2" message="init testGlobal local 2" type="qdebug" --> - <!-- tag="2:local 2" message="global: true" type="qdebug" --> - <!-- tag="2:local 2" message="local: true" type="qdebug" --> - <!-- tag="2:local 2" message="cleanup testGlobal local 2" type="qdebug" --> + <!-- tag="global=false:local=false" message="init testGlobal local=false" type="qdebug" --> + <!-- tag="global=false:local=false" message="global: false" type="qdebug" --> + <!-- tag="global=false:local=false" message="local: false" type="qdebug" --> + <!-- tag="global=false:local=false" message="cleanup testGlobal local=false" type="qdebug" --> + <!-- tag="global=false:local=true" message="init testGlobal local=true" type="qdebug" --> + <!-- tag="global=false:local=true" message="global: false" type="qdebug" --> + <!-- tag="global=false:local=true" message="local: true" type="qdebug" --> + <!-- tag="global=false:local=true" message="cleanup testGlobal local=true" type="qdebug" --> + <!-- tag="global=true:local=false" message="init testGlobal local=false" type="qdebug" --> + <!-- tag="global=true:local=false" message="global: true" type="qdebug" --> + <!-- tag="global=true:local=false" message="local: false" type="qdebug" --> + <!-- tag="global=true:local=false" message="cleanup testGlobal local=false" type="qdebug" --> + <!-- tag="global=true:local=true" message="init testGlobal local=true" type="qdebug" --> + <!-- tag="global=true:local=true" message="global: true" type="qdebug" --> + <!-- tag="global=true:local=true" message="local: true" type="qdebug" --> + <!-- tag="global=true:local=true" message="cleanup testGlobal local=true" type="qdebug" --> </testcase> <testcase name="skip"> - <!-- tag="1" message="skipping" type="skip" --> + <!-- tag="global=false" message="skipping" type="skip" --> </testcase> <testcase name="skipLocal"> - <!-- tag="1:local 1" message="init skipLocal local 1" type="qdebug" --> - <!-- tag="1:local 1" message="skipping" type="skip" --> - <!-- tag="1:local 1" message="cleanup skipLocal local 1" type="qdebug" --> - <!-- tag="1:local 2" message="init skipLocal local 2" type="qdebug" --> - <!-- tag="1:local 2" message="skipping" type="skip" --> - <!-- tag="1:local 2" message="cleanup skipLocal local 2" type="qdebug" --> + <!-- tag="global=false:local=false" message="init skipLocal local=false" type="qdebug" --> + <!-- tag="global=false:local=false" message="skipping" type="skip" --> + <!-- tag="global=false:local=false" message="cleanup skipLocal local=false" type="qdebug" --> + <!-- tag="global=false:local=true" message="init skipLocal local=true" type="qdebug" --> + <!-- tag="global=false:local=true" message="skipping" type="skip" --> + <!-- tag="global=false:local=true" message="cleanup skipLocal local=true" type="qdebug" --> + <!-- tag="global=true:local=false" message="init skipLocal local=false" type="qdebug" --> + <!-- tag="global=true:local=false" message="skipping" type="skip" --> + <!-- tag="global=true:local=false" message="cleanup skipLocal local=false" type="qdebug" --> + <!-- tag="global=true:local=true" message="init skipLocal local=true" type="qdebug" --> + <!-- tag="global=true:local=true" message="skipping" type="skip" --> + <!-- tag="global=true:local=true" message="cleanup skipLocal local=true" type="qdebug" --> </testcase> <testcase result="pass" name="skipSingle"> - <!-- tag="1:local 1" message="init skipSingle local 1" type="qdebug" --> - <!-- tag="1:local 1" message="global: false local: false" type="qdebug" --> - <!-- tag="1:local 1" message="cleanup skipSingle local 1" type="qdebug" --> - <!-- tag="1:local 2" message="init skipSingle local 2" type="qdebug" --> - <!-- tag="1:local 2" message="global: false local: true" type="qdebug" --> - <!-- tag="1:local 2" message="cleanup skipSingle local 2" type="qdebug" --> - <!-- tag="2:local 1" message="init skipSingle local 1" type="qdebug" --> - <!-- tag="2:local 1" message="skipping" type="skip" --> - <!-- tag="2:local 1" message="cleanup skipSingle local 1" type="qdebug" --> - <!-- tag="2:local 2" message="init skipSingle local 2" type="qdebug" --> - <!-- tag="2:local 2" message="global: true local: true" type="qdebug" --> - <!-- tag="2:local 2" message="cleanup skipSingle local 2" type="qdebug" --> + <!-- tag="global=false:local=false" message="init skipSingle local=false" type="qdebug" --> + <!-- tag="global=false:local=false" message="global: false local: false" type="qdebug" --> + <!-- tag="global=false:local=false" message="cleanup skipSingle local=false" type="qdebug" --> + <!-- tag="global=false:local=true" message="init skipSingle local=true" type="qdebug" --> + <!-- tag="global=false:local=true" message="Skipping" type="skip" --> + <!-- tag="global=false:local=true" message="cleanup skipSingle local=true" type="qdebug" --> + <!-- tag="global=true:local=false" message="init skipSingle local=false" type="qdebug" --> + <!-- tag="global=true:local=false" message="Skipping" type="skip" --> + <!-- tag="global=true:local=false" message="cleanup skipSingle local=false" type="qdebug" --> + <!-- tag="global=true:local=true" message="init skipSingle local=true" type="qdebug" --> + <!-- tag="global=true:local=true" message="global: true local: true" type="qdebug" --> + <!-- tag="global=true:local=true" message="cleanup skipSingle local=true" type="qdebug" --> </testcase> <testcase result="pass" name="cleanupTestCase"> <!-- message="cleanupTestCase cleanupTestCase (null)" type="qdebug" --> </testcase> <system-err> <![CDATA[initTestCase initTestCase (null)]]> -<![CDATA[init testGlobal local 1]]> +<![CDATA[init testGlobal local=false]]> <![CDATA[global: false]]> <![CDATA[local: false]]> -<![CDATA[cleanup testGlobal local 1]]> -<![CDATA[init testGlobal local 2]]> +<![CDATA[cleanup testGlobal local=false]]> +<![CDATA[init testGlobal local=true]]> <![CDATA[global: false]]> <![CDATA[local: true]]> -<![CDATA[cleanup testGlobal local 2]]> -<![CDATA[init testGlobal local 1]]> +<![CDATA[cleanup testGlobal local=true]]> +<![CDATA[init testGlobal local=false]]> <![CDATA[global: true]]> <![CDATA[local: false]]> -<![CDATA[cleanup testGlobal local 1]]> -<![CDATA[init testGlobal local 2]]> +<![CDATA[cleanup testGlobal local=false]]> +<![CDATA[init testGlobal local=true]]> <![CDATA[global: true]]> <![CDATA[local: true]]> -<![CDATA[cleanup testGlobal local 2]]> +<![CDATA[cleanup testGlobal local=true]]> <![CDATA[skipping]]> -<![CDATA[init skipLocal local 1]]> +<![CDATA[init skipLocal local=false]]> <![CDATA[skipping]]> -<![CDATA[cleanup skipLocal local 1]]> -<![CDATA[init skipLocal local 2]]> +<![CDATA[cleanup skipLocal local=false]]> +<![CDATA[init skipLocal local=true]]> <![CDATA[skipping]]> -<![CDATA[cleanup skipLocal local 2]]> -<![CDATA[init skipSingle local 1]]> -<![CDATA[global: false local: false]]> -<![CDATA[cleanup skipSingle local 1]]> -<![CDATA[init skipSingle local 2]]> -<![CDATA[global: false local: true]]> -<![CDATA[cleanup skipSingle local 2]]> -<![CDATA[init skipSingle local 1]]> +<![CDATA[cleanup skipLocal local=true]]> +<![CDATA[init skipLocal local=false]]> +<![CDATA[skipping]]> +<![CDATA[cleanup skipLocal local=false]]> +<![CDATA[init skipLocal local=true]]> <![CDATA[skipping]]> -<![CDATA[cleanup skipSingle local 1]]> -<![CDATA[init skipSingle local 2]]> +<![CDATA[cleanup skipLocal local=true]]> +<![CDATA[init skipSingle local=false]]> +<![CDATA[global: false local: false]]> +<![CDATA[cleanup skipSingle local=false]]> +<![CDATA[init skipSingle local=true]]> +<![CDATA[Skipping]]> +<![CDATA[cleanup skipSingle local=true]]> +<![CDATA[init skipSingle local=false]]> +<![CDATA[Skipping]]> +<![CDATA[cleanup skipSingle local=false]]> +<![CDATA[init skipSingle local=true]]> <![CDATA[global: true local: true]]> -<![CDATA[cleanup skipSingle local 2]]> +<![CDATA[cleanup skipSingle local=true]]> <![CDATA[cleanupTestCase cleanupTestCase (null)]]> </system-err> </testsuite> diff --git a/tests/auto/testlib/selftests/expected_signaldumper.lightxml b/tests/auto/testlib/selftests/expected_signaldumper.lightxml new file mode 100644 index 0000000000..443f649bb6 --- /dev/null +++ b/tests/auto/testlib/selftests/expected_signaldumper.lightxml @@ -0,0 +1,585 @@ +<Environment> + <QtVersion>@INSERT_QT_VERSION_HERE@</QtVersion> + <QtBuild/> + <QTestVersion>@INSERT_QT_VERSION_HERE@</QTestVersion> +</Environment> +<TestFunction name="initTestCase"> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: QThread(_POINTER_) started ()]]></Description> +</Message> +<Incident type="pass" file="" line="0" /> + <Duration msecs="0"/> +</TestFunction> +<TestFunction name="noConnections"> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Incident type="pass" file="" line="0" /> + <Duration msecs="0"/> +</TestFunction> +<TestFunction name="oneSlot"> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> +</Incident> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> +</Incident> + <Duration msecs="0"/> +</TestFunction> +<TestFunction name="oneSlotOldSyntax"> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Slot: SignalSlotClass(_POINTER_) slotWithParameters(int,char)]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> +</Incident> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> +</Incident> + <Duration msecs="0"/> +</TestFunction> +<TestFunction name="twoSlots"> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> +</Incident> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> +</Incident> + <Duration msecs="0"/> +</TestFunction> +<TestFunction name="twoSlotsOldSyntax"> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Slot: SignalSlotClass(_POINTER_) slotWithParameters(int,char)]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Slot: SignalSlotClass(_POINTER_) slotWithParameters(int,char)]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> +</Incident> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> +</Incident> + <Duration msecs="0"/> +</TestFunction> +<TestFunction name="signalForwarding"> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Signal: SignalSlotClass(_POINTER_) nestedSignalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> +</Incident> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) nestedSignalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> +</Incident> + <Duration msecs="0"/> +</TestFunction> +<TestFunction name="signalForwardingOldSyntax"> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Slot: SignalSlotClass(_POINTER_) nestedSignal()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Slot: SignalSlotClass(_POINTER_) nestedSignalWithParameters(int,char)]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Signal: SignalSlotClass(_POINTER_) nestedSignalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Slot: SignalSlotClass(_POINTER_) nestedSignal()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> +</Incident> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) nestedSignalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> +</Incident> + <Duration msecs="0"/> +</TestFunction> +<TestFunction name="slotEmittingSignal"> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> +</Incident> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> +</Incident> + <Duration msecs="0"/> +</TestFunction> +<TestFunction name="slotEmittingSignalOldSyntax"> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Slot: SignalSlotClass(_POINTER_) emitSecondSignal()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> +</Incident> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> +</Incident> + <Duration msecs="0"/> +</TestFunction> +<TestFunction name="variousTypes"> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) qStringSignal (QString(Test string))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) qStringRefSignal ((QString&)@_POINTER_)]]></Description> +</Message> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) qStringConstRefSignal (QString(Test string))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) qByteArraySignal (QByteArray(Test bytearray))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) qListSignal (QList<int>())]]></Description> +</Message> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) qVectorSignal (QVector<int>())]]></Description> +</Message> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) qVectorRefSignal ((QVector<int>&)@_POINTER_)]]></Description> +</Message> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) qVectorConstRefSignal (QVector<int>())]]></Description> +</Message> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) qVectorConstPointerSignal ((const QVector<int>*)_POINTER_)]]></Description> +</Message> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) qVectorPointerConstSignal ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) qVariantSignal (QVariant())]]></Description> +</Message> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) qVariantSignal (QVariant())]]></Description> +</Message> +<Incident type="pass" file="" line="0" /> + <Duration msecs="0"/> +</TestFunction> +<TestFunction name="deletingSender"> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Incident type="pass" file="" line="0" /> + <Duration msecs="0"/> +</TestFunction> +<TestFunction name="cleanupTestCase"> +<Incident type="pass" file="" line="0" /> + <Duration msecs="0"/> +</TestFunction> +<Message type="info" file="" line="0"> + <Description><![CDATA[ Signal: QThread(_POINTER_) finished ()]]></Description> +</Message> +<Duration msecs="0"/> diff --git a/tests/auto/testlib/selftests/expected_signaldumper.tap b/tests/auto/testlib/selftests/expected_signaldumper.tap new file mode 100644 index 0000000000..e2d664f4f1 --- /dev/null +++ b/tests/auto/testlib/selftests/expected_signaldumper.tap @@ -0,0 +1,153 @@ +TAP version 13 +# tst_Signaldumper +# Signal: QThread(_POINTER_) started () +ok 1 - initTestCase() +# Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +# Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +ok 2 - noConnections() +# Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +# Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +# Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +ok 3 - oneSlot(direct) +# Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +# Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +# Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +ok 4 - oneSlot(queued) +# Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +# Slot: SignalSlotClass(_POINTER_) slotWithoutParameters() +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +# Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +# Slot: SignalSlotClass(_POINTER_) slotWithParameters(int,char) +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +# Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +# Slot: SignalSlotClass(_POINTER_) slotWithoutParameters() +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +ok 5 - oneSlotOldSyntax(direct) +# Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +# Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +# Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +ok 6 - oneSlotOldSyntax(queued) +# Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +# Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +# Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +ok 7 - twoSlots(direct) +# Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +# Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +# Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +ok 8 - twoSlots(queued) +# Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +# Slot: SignalSlotClass(_POINTER_) slotWithoutParameters() +# Slot: SignalSlotClass(_POINTER_) slotWithoutParameters() +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +# Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +# Slot: SignalSlotClass(_POINTER_) slotWithParameters(int,char) +# Slot: SignalSlotClass(_POINTER_) slotWithParameters(int,char) +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +# Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +# Slot: SignalSlotClass(_POINTER_) slotWithoutParameters() +# Slot: SignalSlotClass(_POINTER_) slotWithoutParameters() +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +ok 9 - twoSlotsOldSyntax(direct) +# Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +# Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +# Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +ok 10 - twoSlotsOldSyntax(queued) +# Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +# Signal: SignalSlotClass(_POINTER_) nestedSignal () +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +# Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +# Signal: SignalSlotClass(_POINTER_) nestedSignalWithParameters (int(242), char(m)) +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +# Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +# Signal: SignalSlotClass(_POINTER_) nestedSignal () +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +ok 11 - signalForwarding(direct) +# Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +# Signal: SignalSlotClass(_POINTER_) nestedSignal () +# Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +# Signal: SignalSlotClass(_POINTER_) nestedSignalWithParameters (int(242), char(m)) +# Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +# Signal: SignalSlotClass(_POINTER_) nestedSignal () +ok 12 - signalForwarding(queued) +# Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +# Slot: SignalSlotClass(_POINTER_) nestedSignal() +# Signal: SignalSlotClass(_POINTER_) nestedSignal () +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +# Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +# Slot: SignalSlotClass(_POINTER_) nestedSignalWithParameters(int,char) +# Signal: SignalSlotClass(_POINTER_) nestedSignalWithParameters (int(242), char(m)) +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +# Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +# Slot: SignalSlotClass(_POINTER_) nestedSignal() +# Signal: SignalSlotClass(_POINTER_) nestedSignal () +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +ok 13 - signalForwardingOldSyntax(direct) +# Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +# Signal: SignalSlotClass(_POINTER_) nestedSignal () +# Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +# Signal: SignalSlotClass(_POINTER_) nestedSignalWithParameters (int(242), char(m)) +# Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +# Signal: SignalSlotClass(_POINTER_) nestedSignal () +ok 14 - signalForwardingOldSyntax(queued) +# Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +# Signal: SignalSlotClass(_POINTER_) nestedSignal () +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +ok 15 - slotEmittingSignal(direct) +# Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +# Signal: SignalSlotClass(_POINTER_) nestedSignal () +ok 16 - slotEmittingSignal(queued) +# Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +# Slot: SignalSlotClass(_POINTER_) emitSecondSignal() +# Signal: SignalSlotClass(_POINTER_) nestedSignal () +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +ok 17 - slotEmittingSignalOldSyntax(direct) +# Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +# Signal: QEventDispatcherPlatform(_POINTER_) awake () +# Signal: SignalSlotClass(_POINTER_) nestedSignal () +ok 18 - slotEmittingSignalOldSyntax(queued) +# Signal: SignalSlotClass(_POINTER_) qStringSignal (QString(Test string)) +# Signal: SignalSlotClass(_POINTER_) qStringRefSignal ((QString&)@_POINTER_) +# Signal: SignalSlotClass(_POINTER_) qStringConstRefSignal (QString(Test string)) +# Signal: SignalSlotClass(_POINTER_) qByteArraySignal (QByteArray(Test bytearray)) +# Signal: SignalSlotClass(_POINTER_) qListSignal (QList<int>()) +# Signal: SignalSlotClass(_POINTER_) qVectorSignal (QVector<int>()) +# Signal: SignalSlotClass(_POINTER_) qVectorRefSignal ((QVector<int>&)@_POINTER_) +# Signal: SignalSlotClass(_POINTER_) qVectorConstRefSignal (QVector<int>()) +# Signal: SignalSlotClass(_POINTER_) qVectorConstPointerSignal ((const QVector<int>*)_POINTER_) +# Signal: SignalSlotClass(_POINTER_) qVectorPointerConstSignal () +# Signal: SignalSlotClass(_POINTER_) qVariantSignal (QVariant()) +# Signal: SignalSlotClass(_POINTER_) qVariantSignal (QVariant()) +ok 19 - variousTypes() +# Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +ok 20 - deletingSender() +ok 21 - cleanupTestCase() +# Signal: QThread(_POINTER_) finished () +1..21 +# tests 21 +# pass 21 +# fail 0 diff --git a/tests/auto/testlib/selftests/expected_signaldumper.teamcity b/tests/auto/testlib/selftests/expected_signaldumper.teamcity new file mode 100644 index 0000000000..0fc568e086 --- /dev/null +++ b/tests/auto/testlib/selftests/expected_signaldumper.teamcity @@ -0,0 +1,64 @@ +##teamcity[testSuiteStarted name='tst_Signaldumper' flowId='tst_Signaldumper'] +##teamcity[testStarted name='initTestCase()' flowId='tst_Signaldumper'] +##teamcity[testStdOut name='initTestCase()' out='INFO: Signal: QThread(_POINTER_) started ()' flowId='tst_Signaldumper'] +##teamcity[testFinished name='initTestCase()' flowId='tst_Signaldumper'] +##teamcity[testStarted name='noConnections()' flowId='tst_Signaldumper'] +##teamcity[testStdOut name='noConnections()' out='INFO: Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()|nINFO: Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))' flowId='tst_Signaldumper'] +##teamcity[testFinished name='noConnections()' flowId='tst_Signaldumper'] +##teamcity[testStarted name='oneSlot(direct)' flowId='tst_Signaldumper'] +##teamcity[testStdOut name='oneSlot(direct)' out='INFO: Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()|nINFO: Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()|nINFO: Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()' flowId='tst_Signaldumper'] +##teamcity[testFinished name='oneSlot(direct)' flowId='tst_Signaldumper'] +##teamcity[testStarted name='oneSlot(queued)' flowId='tst_Signaldumper'] +##teamcity[testStdOut name='oneSlot(queued)' out='INFO: Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()|nINFO: Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()|nINFO: Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()' flowId='tst_Signaldumper'] +##teamcity[testFinished name='oneSlot(queued)' flowId='tst_Signaldumper'] +##teamcity[testStarted name='oneSlotOldSyntax(direct)' flowId='tst_Signaldumper'] +##teamcity[testStdOut name='oneSlotOldSyntax(direct)' out='INFO: Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()|nINFO: Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()|nINFO: Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))|nINFO: Slot: SignalSlotClass(_POINTER_) slotWithParameters(int,char)|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()|nINFO: Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))|nINFO: Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()' flowId='tst_Signaldumper'] +##teamcity[testFinished name='oneSlotOldSyntax(direct)' flowId='tst_Signaldumper'] +##teamcity[testStarted name='oneSlotOldSyntax(queued)' flowId='tst_Signaldumper'] +##teamcity[testStdOut name='oneSlotOldSyntax(queued)' out='INFO: Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()|nINFO: Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()|nINFO: Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()' flowId='tst_Signaldumper'] +##teamcity[testFinished name='oneSlotOldSyntax(queued)' flowId='tst_Signaldumper'] +##teamcity[testStarted name='twoSlots(direct)' flowId='tst_Signaldumper'] +##teamcity[testStdOut name='twoSlots(direct)' out='INFO: Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()|nINFO: Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()|nINFO: Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()' flowId='tst_Signaldumper'] +##teamcity[testFinished name='twoSlots(direct)' flowId='tst_Signaldumper'] +##teamcity[testStarted name='twoSlots(queued)' flowId='tst_Signaldumper'] +##teamcity[testStdOut name='twoSlots(queued)' out='INFO: Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()|nINFO: Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()|nINFO: Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()' flowId='tst_Signaldumper'] +##teamcity[testFinished name='twoSlots(queued)' flowId='tst_Signaldumper'] +##teamcity[testStarted name='twoSlotsOldSyntax(direct)' flowId='tst_Signaldumper'] +##teamcity[testStdOut name='twoSlotsOldSyntax(direct)' out='INFO: Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()|nINFO: Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()|nINFO: Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()|nINFO: Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))|nINFO: Slot: SignalSlotClass(_POINTER_) slotWithParameters(int,char)|nINFO: Slot: SignalSlotClass(_POINTER_) slotWithParameters(int,char)|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()|nINFO: Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))|nINFO: Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()|nINFO: Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()' flowId='tst_Signaldumper'] +##teamcity[testFinished name='twoSlotsOldSyntax(direct)' flowId='tst_Signaldumper'] +##teamcity[testStarted name='twoSlotsOldSyntax(queued)' flowId='tst_Signaldumper'] +##teamcity[testStdOut name='twoSlotsOldSyntax(queued)' out='INFO: Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()|nINFO: Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()|nINFO: Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()' flowId='tst_Signaldumper'] +##teamcity[testFinished name='twoSlotsOldSyntax(queued)' flowId='tst_Signaldumper'] +##teamcity[testStarted name='signalForwarding(direct)' flowId='tst_Signaldumper'] +##teamcity[testStdOut name='signalForwarding(direct)' out='INFO: Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()|nINFO: Signal: SignalSlotClass(_POINTER_) nestedSignal ()|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()|nINFO: Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))|nINFO: Signal: SignalSlotClass(_POINTER_) nestedSignalWithParameters (int(242), char(m))|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()|nINFO: Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))|nINFO: Signal: SignalSlotClass(_POINTER_) nestedSignal ()|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()' flowId='tst_Signaldumper'] +##teamcity[testFinished name='signalForwarding(direct)' flowId='tst_Signaldumper'] +##teamcity[testStarted name='signalForwarding(queued)' flowId='tst_Signaldumper'] +##teamcity[testStdOut name='signalForwarding(queued)' out='INFO: Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()|nINFO: Signal: SignalSlotClass(_POINTER_) nestedSignal ()|nINFO: Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()|nINFO: Signal: SignalSlotClass(_POINTER_) nestedSignalWithParameters (int(242), char(m))|nINFO: Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()|nINFO: Signal: SignalSlotClass(_POINTER_) nestedSignal ()' flowId='tst_Signaldumper'] +##teamcity[testFinished name='signalForwarding(queued)' flowId='tst_Signaldumper'] +##teamcity[testStarted name='signalForwardingOldSyntax(direct)' flowId='tst_Signaldumper'] +##teamcity[testStdOut name='signalForwardingOldSyntax(direct)' out='INFO: Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()|nINFO: Slot: SignalSlotClass(_POINTER_) nestedSignal()|nINFO: Signal: SignalSlotClass(_POINTER_) nestedSignal ()|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()|nINFO: Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))|nINFO: Slot: SignalSlotClass(_POINTER_) nestedSignalWithParameters(int,char)|nINFO: Signal: SignalSlotClass(_POINTER_) nestedSignalWithParameters (int(242), char(m))|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()|nINFO: Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))|nINFO: Slot: SignalSlotClass(_POINTER_) nestedSignal()|nINFO: Signal: SignalSlotClass(_POINTER_) nestedSignal ()|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()' flowId='tst_Signaldumper'] +##teamcity[testFinished name='signalForwardingOldSyntax(direct)' flowId='tst_Signaldumper'] +##teamcity[testStarted name='signalForwardingOldSyntax(queued)' flowId='tst_Signaldumper'] +##teamcity[testStdOut name='signalForwardingOldSyntax(queued)' out='INFO: Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()|nINFO: Signal: SignalSlotClass(_POINTER_) nestedSignal ()|nINFO: Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()|nINFO: Signal: SignalSlotClass(_POINTER_) nestedSignalWithParameters (int(242), char(m))|nINFO: Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()|nINFO: Signal: SignalSlotClass(_POINTER_) nestedSignal ()' flowId='tst_Signaldumper'] +##teamcity[testFinished name='signalForwardingOldSyntax(queued)' flowId='tst_Signaldumper'] +##teamcity[testStarted name='slotEmittingSignal(direct)' flowId='tst_Signaldumper'] +##teamcity[testStdOut name='slotEmittingSignal(direct)' out='INFO: Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()|nINFO: Signal: SignalSlotClass(_POINTER_) nestedSignal ()|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()' flowId='tst_Signaldumper'] +##teamcity[testFinished name='slotEmittingSignal(direct)' flowId='tst_Signaldumper'] +##teamcity[testStarted name='slotEmittingSignal(queued)' flowId='tst_Signaldumper'] +##teamcity[testStdOut name='slotEmittingSignal(queued)' out='INFO: Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()|nINFO: Signal: SignalSlotClass(_POINTER_) nestedSignal ()' flowId='tst_Signaldumper'] +##teamcity[testFinished name='slotEmittingSignal(queued)' flowId='tst_Signaldumper'] +##teamcity[testStarted name='slotEmittingSignalOldSyntax(direct)' flowId='tst_Signaldumper'] +##teamcity[testStdOut name='slotEmittingSignalOldSyntax(direct)' out='INFO: Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()|nINFO: Slot: SignalSlotClass(_POINTER_) emitSecondSignal()|nINFO: Signal: SignalSlotClass(_POINTER_) nestedSignal ()|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()' flowId='tst_Signaldumper'] +##teamcity[testFinished name='slotEmittingSignalOldSyntax(direct)' flowId='tst_Signaldumper'] +##teamcity[testStarted name='slotEmittingSignalOldSyntax(queued)' flowId='tst_Signaldumper'] +##teamcity[testStdOut name='slotEmittingSignalOldSyntax(queued)' out='INFO: Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()|nINFO: Signal: QEventDispatcherPlatform(_POINTER_) awake ()|nINFO: Signal: SignalSlotClass(_POINTER_) nestedSignal ()' flowId='tst_Signaldumper'] +##teamcity[testFinished name='slotEmittingSignalOldSyntax(queued)' flowId='tst_Signaldumper'] +##teamcity[testStarted name='variousTypes()' flowId='tst_Signaldumper'] +##teamcity[testStdOut name='variousTypes()' out='INFO: Signal: SignalSlotClass(_POINTER_) qStringSignal (QString(Test string))|nINFO: Signal: SignalSlotClass(_POINTER_) qStringRefSignal ((QString&)@_POINTER_)|nINFO: Signal: SignalSlotClass(_POINTER_) qStringConstRefSignal (QString(Test string))|nINFO: Signal: SignalSlotClass(_POINTER_) qByteArraySignal (QByteArray(Test bytearray))|nINFO: Signal: SignalSlotClass(_POINTER_) qListSignal (QList<int>())|nINFO: Signal: SignalSlotClass(_POINTER_) qVectorSignal (QVector<int>())|nINFO: Signal: SignalSlotClass(_POINTER_) qVectorRefSignal ((QVector<int>&)@_POINTER_)|nINFO: Signal: SignalSlotClass(_POINTER_) qVectorConstRefSignal (QVector<int>())|nINFO: Signal: SignalSlotClass(_POINTER_) qVectorConstPointerSignal ((const QVector<int>*)_POINTER_)|nINFO: Signal: SignalSlotClass(_POINTER_) qVectorPointerConstSignal ()|nINFO: Signal: SignalSlotClass(_POINTER_) qVariantSignal (QVariant())|nINFO: Signal: SignalSlotClass(_POINTER_) qVariantSignal (QVariant())' flowId='tst_Signaldumper'] +##teamcity[testFinished name='variousTypes()' flowId='tst_Signaldumper'] +##teamcity[testStarted name='deletingSender()' flowId='tst_Signaldumper'] +##teamcity[testStdOut name='deletingSender()' out='INFO: Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()' flowId='tst_Signaldumper'] +##teamcity[testFinished name='deletingSender()' flowId='tst_Signaldumper'] +##teamcity[testStarted name='cleanupTestCase()' flowId='tst_Signaldumper'] +##teamcity[testFinished name='cleanupTestCase()' flowId='tst_Signaldumper'] +##teamcity[testSuiteFinished name='tst_Signaldumper' flowId='tst_Signaldumper'] diff --git a/tests/auto/testlib/selftests/expected_signaldumper.txt b/tests/auto/testlib/selftests/expected_signaldumper.txt new file mode 100644 index 0000000000..0ee8cd38a2 --- /dev/null +++ b/tests/auto/testlib/selftests/expected_signaldumper.txt @@ -0,0 +1,151 @@ +********* Start testing of tst_Signaldumper ********* +Config: Using QtTest library +INFO : tst_Signaldumper::initTestCase() Signal: QThread(_POINTER_) started () +PASS : tst_Signaldumper::initTestCase() +INFO : tst_Signaldumper::noConnections() Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +INFO : tst_Signaldumper::noConnections() Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +PASS : tst_Signaldumper::noConnections() +INFO : tst_Signaldumper::oneSlot(direct) Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +INFO : tst_Signaldumper::oneSlot(direct) Signal: QEventDispatcherPlatform(_POINTER_) awake () +INFO : tst_Signaldumper::oneSlot(direct) Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +INFO : tst_Signaldumper::oneSlot(direct) Signal: QEventDispatcherPlatform(_POINTER_) awake () +INFO : tst_Signaldumper::oneSlot(direct) Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +INFO : tst_Signaldumper::oneSlot(direct) Signal: QEventDispatcherPlatform(_POINTER_) awake () +PASS : tst_Signaldumper::oneSlot(direct) +INFO : tst_Signaldumper::oneSlot(queued) Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +INFO : tst_Signaldumper::oneSlot(queued) Signal: QEventDispatcherPlatform(_POINTER_) awake () +INFO : tst_Signaldumper::oneSlot(queued) Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +INFO : tst_Signaldumper::oneSlot(queued) Signal: QEventDispatcherPlatform(_POINTER_) awake () +INFO : tst_Signaldumper::oneSlot(queued) Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +INFO : tst_Signaldumper::oneSlot(queued) Signal: QEventDispatcherPlatform(_POINTER_) awake () +PASS : tst_Signaldumper::oneSlot(queued) +INFO : tst_Signaldumper::oneSlotOldSyntax(direct) Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +INFO : tst_Signaldumper::oneSlotOldSyntax(direct) Slot: SignalSlotClass(_POINTER_) slotWithoutParameters() +INFO : tst_Signaldumper::oneSlotOldSyntax(direct) Signal: QEventDispatcherPlatform(_POINTER_) awake () +INFO : tst_Signaldumper::oneSlotOldSyntax(direct) Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +INFO : tst_Signaldumper::oneSlotOldSyntax(direct) Slot: SignalSlotClass(_POINTER_) slotWithParameters(int,char) +INFO : tst_Signaldumper::oneSlotOldSyntax(direct) Signal: QEventDispatcherPlatform(_POINTER_) awake () +INFO : tst_Signaldumper::oneSlotOldSyntax(direct) Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +INFO : tst_Signaldumper::oneSlotOldSyntax(direct) Slot: SignalSlotClass(_POINTER_) slotWithoutParameters() +INFO : tst_Signaldumper::oneSlotOldSyntax(direct) Signal: QEventDispatcherPlatform(_POINTER_) awake () +PASS : tst_Signaldumper::oneSlotOldSyntax(direct) +INFO : tst_Signaldumper::oneSlotOldSyntax(queued) Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +INFO : tst_Signaldumper::oneSlotOldSyntax(queued) Signal: QEventDispatcherPlatform(_POINTER_) awake () +INFO : tst_Signaldumper::oneSlotOldSyntax(queued) Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +INFO : tst_Signaldumper::oneSlotOldSyntax(queued) Signal: QEventDispatcherPlatform(_POINTER_) awake () +INFO : tst_Signaldumper::oneSlotOldSyntax(queued) Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +INFO : tst_Signaldumper::oneSlotOldSyntax(queued) Signal: QEventDispatcherPlatform(_POINTER_) awake () +PASS : tst_Signaldumper::oneSlotOldSyntax(queued) +INFO : tst_Signaldumper::twoSlots(direct) Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +INFO : tst_Signaldumper::twoSlots(direct) Signal: QEventDispatcherPlatform(_POINTER_) awake () +INFO : tst_Signaldumper::twoSlots(direct) Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +INFO : tst_Signaldumper::twoSlots(direct) Signal: QEventDispatcherPlatform(_POINTER_) awake () +INFO : tst_Signaldumper::twoSlots(direct) Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +INFO : tst_Signaldumper::twoSlots(direct) Signal: QEventDispatcherPlatform(_POINTER_) awake () +PASS : tst_Signaldumper::twoSlots(direct) +INFO : tst_Signaldumper::twoSlots(queued) Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +INFO : tst_Signaldumper::twoSlots(queued) Signal: QEventDispatcherPlatform(_POINTER_) awake () +INFO : tst_Signaldumper::twoSlots(queued) Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +INFO : tst_Signaldumper::twoSlots(queued) Signal: QEventDispatcherPlatform(_POINTER_) awake () +INFO : tst_Signaldumper::twoSlots(queued) Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +INFO : tst_Signaldumper::twoSlots(queued) Signal: QEventDispatcherPlatform(_POINTER_) awake () +PASS : tst_Signaldumper::twoSlots(queued) +INFO : tst_Signaldumper::twoSlotsOldSyntax(direct) Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +INFO : tst_Signaldumper::twoSlotsOldSyntax(direct) Slot: SignalSlotClass(_POINTER_) slotWithoutParameters() +INFO : tst_Signaldumper::twoSlotsOldSyntax(direct) Slot: SignalSlotClass(_POINTER_) slotWithoutParameters() +INFO : tst_Signaldumper::twoSlotsOldSyntax(direct) Signal: QEventDispatcherPlatform(_POINTER_) awake () +INFO : tst_Signaldumper::twoSlotsOldSyntax(direct) Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +INFO : tst_Signaldumper::twoSlotsOldSyntax(direct) Slot: SignalSlotClass(_POINTER_) slotWithParameters(int,char) +INFO : tst_Signaldumper::twoSlotsOldSyntax(direct) Slot: SignalSlotClass(_POINTER_) slotWithParameters(int,char) +INFO : tst_Signaldumper::twoSlotsOldSyntax(direct) Signal: QEventDispatcherPlatform(_POINTER_) awake () +INFO : tst_Signaldumper::twoSlotsOldSyntax(direct) Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +INFO : tst_Signaldumper::twoSlotsOldSyntax(direct) Slot: SignalSlotClass(_POINTER_) slotWithoutParameters() +INFO : tst_Signaldumper::twoSlotsOldSyntax(direct) Slot: SignalSlotClass(_POINTER_) slotWithoutParameters() +INFO : tst_Signaldumper::twoSlotsOldSyntax(direct) Signal: QEventDispatcherPlatform(_POINTER_) awake () +PASS : tst_Signaldumper::twoSlotsOldSyntax(direct) +INFO : tst_Signaldumper::twoSlotsOldSyntax(queued) Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +INFO : tst_Signaldumper::twoSlotsOldSyntax(queued) Signal: QEventDispatcherPlatform(_POINTER_) awake () +INFO : tst_Signaldumper::twoSlotsOldSyntax(queued) Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +INFO : tst_Signaldumper::twoSlotsOldSyntax(queued) Signal: QEventDispatcherPlatform(_POINTER_) awake () +INFO : tst_Signaldumper::twoSlotsOldSyntax(queued) Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +INFO : tst_Signaldumper::twoSlotsOldSyntax(queued) Signal: QEventDispatcherPlatform(_POINTER_) awake () +PASS : tst_Signaldumper::twoSlotsOldSyntax(queued) +INFO : tst_Signaldumper::signalForwarding(direct) Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +INFO : tst_Signaldumper::signalForwarding(direct) Signal: SignalSlotClass(_POINTER_) nestedSignal () +INFO : tst_Signaldumper::signalForwarding(direct) Signal: QEventDispatcherPlatform(_POINTER_) awake () +INFO : tst_Signaldumper::signalForwarding(direct) Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +INFO : tst_Signaldumper::signalForwarding(direct) Signal: SignalSlotClass(_POINTER_) nestedSignalWithParameters (int(242), char(m)) +INFO : tst_Signaldumper::signalForwarding(direct) Signal: QEventDispatcherPlatform(_POINTER_) awake () +INFO : tst_Signaldumper::signalForwarding(direct) Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +INFO : tst_Signaldumper::signalForwarding(direct) Signal: SignalSlotClass(_POINTER_) nestedSignal () +INFO : tst_Signaldumper::signalForwarding(direct) Signal: QEventDispatcherPlatform(_POINTER_) awake () +PASS : tst_Signaldumper::signalForwarding(direct) +INFO : tst_Signaldumper::signalForwarding(queued) Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +INFO : tst_Signaldumper::signalForwarding(queued) Signal: QEventDispatcherPlatform(_POINTER_) awake () +INFO : tst_Signaldumper::signalForwarding(queued) Signal: SignalSlotClass(_POINTER_) nestedSignal () +INFO : tst_Signaldumper::signalForwarding(queued) Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +INFO : tst_Signaldumper::signalForwarding(queued) Signal: QEventDispatcherPlatform(_POINTER_) awake () +INFO : tst_Signaldumper::signalForwarding(queued) Signal: SignalSlotClass(_POINTER_) nestedSignalWithParameters (int(242), char(m)) +INFO : tst_Signaldumper::signalForwarding(queued) Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +INFO : tst_Signaldumper::signalForwarding(queued) Signal: QEventDispatcherPlatform(_POINTER_) awake () +INFO : tst_Signaldumper::signalForwarding(queued) Signal: SignalSlotClass(_POINTER_) nestedSignal () +PASS : tst_Signaldumper::signalForwarding(queued) +INFO : tst_Signaldumper::signalForwardingOldSyntax(direct) Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +INFO : tst_Signaldumper::signalForwardingOldSyntax(direct) Slot: SignalSlotClass(_POINTER_) nestedSignal() +INFO : tst_Signaldumper::signalForwardingOldSyntax(direct) Signal: SignalSlotClass(_POINTER_) nestedSignal () +INFO : tst_Signaldumper::signalForwardingOldSyntax(direct) Signal: QEventDispatcherPlatform(_POINTER_) awake () +INFO : tst_Signaldumper::signalForwardingOldSyntax(direct) Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +INFO : tst_Signaldumper::signalForwardingOldSyntax(direct) Slot: SignalSlotClass(_POINTER_) nestedSignalWithParameters(int,char) +INFO : tst_Signaldumper::signalForwardingOldSyntax(direct) Signal: SignalSlotClass(_POINTER_) nestedSignalWithParameters (int(242), char(m)) +INFO : tst_Signaldumper::signalForwardingOldSyntax(direct) Signal: QEventDispatcherPlatform(_POINTER_) awake () +INFO : tst_Signaldumper::signalForwardingOldSyntax(direct) Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +INFO : tst_Signaldumper::signalForwardingOldSyntax(direct) Slot: SignalSlotClass(_POINTER_) nestedSignal() +INFO : tst_Signaldumper::signalForwardingOldSyntax(direct) Signal: SignalSlotClass(_POINTER_) nestedSignal () +INFO : tst_Signaldumper::signalForwardingOldSyntax(direct) Signal: QEventDispatcherPlatform(_POINTER_) awake () +PASS : tst_Signaldumper::signalForwardingOldSyntax(direct) +INFO : tst_Signaldumper::signalForwardingOldSyntax(queued) Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +INFO : tst_Signaldumper::signalForwardingOldSyntax(queued) Signal: QEventDispatcherPlatform(_POINTER_) awake () +INFO : tst_Signaldumper::signalForwardingOldSyntax(queued) Signal: SignalSlotClass(_POINTER_) nestedSignal () +INFO : tst_Signaldumper::signalForwardingOldSyntax(queued) Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +INFO : tst_Signaldumper::signalForwardingOldSyntax(queued) Signal: QEventDispatcherPlatform(_POINTER_) awake () +INFO : tst_Signaldumper::signalForwardingOldSyntax(queued) Signal: SignalSlotClass(_POINTER_) nestedSignalWithParameters (int(242), char(m)) +INFO : tst_Signaldumper::signalForwardingOldSyntax(queued) Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m)) +INFO : tst_Signaldumper::signalForwardingOldSyntax(queued) Signal: QEventDispatcherPlatform(_POINTER_) awake () +INFO : tst_Signaldumper::signalForwardingOldSyntax(queued) Signal: SignalSlotClass(_POINTER_) nestedSignal () +PASS : tst_Signaldumper::signalForwardingOldSyntax(queued) +INFO : tst_Signaldumper::slotEmittingSignal(direct) Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +INFO : tst_Signaldumper::slotEmittingSignal(direct) Signal: SignalSlotClass(_POINTER_) nestedSignal () +INFO : tst_Signaldumper::slotEmittingSignal(direct) Signal: QEventDispatcherPlatform(_POINTER_) awake () +PASS : tst_Signaldumper::slotEmittingSignal(direct) +INFO : tst_Signaldumper::slotEmittingSignal(queued) Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +INFO : tst_Signaldumper::slotEmittingSignal(queued) Signal: QEventDispatcherPlatform(_POINTER_) awake () +INFO : tst_Signaldumper::slotEmittingSignal(queued) Signal: SignalSlotClass(_POINTER_) nestedSignal () +PASS : tst_Signaldumper::slotEmittingSignal(queued) +INFO : tst_Signaldumper::slotEmittingSignalOldSyntax(direct) Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +INFO : tst_Signaldumper::slotEmittingSignalOldSyntax(direct) Slot: SignalSlotClass(_POINTER_) emitSecondSignal() +INFO : tst_Signaldumper::slotEmittingSignalOldSyntax(direct) Signal: SignalSlotClass(_POINTER_) nestedSignal () +INFO : tst_Signaldumper::slotEmittingSignalOldSyntax(direct) Signal: QEventDispatcherPlatform(_POINTER_) awake () +PASS : tst_Signaldumper::slotEmittingSignalOldSyntax(direct) +INFO : tst_Signaldumper::slotEmittingSignalOldSyntax(queued) Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +INFO : tst_Signaldumper::slotEmittingSignalOldSyntax(queued) Signal: QEventDispatcherPlatform(_POINTER_) awake () +INFO : tst_Signaldumper::slotEmittingSignalOldSyntax(queued) Signal: SignalSlotClass(_POINTER_) nestedSignal () +PASS : tst_Signaldumper::slotEmittingSignalOldSyntax(queued) +INFO : tst_Signaldumper::variousTypes() Signal: SignalSlotClass(_POINTER_) qStringSignal (QString(Test string)) +INFO : tst_Signaldumper::variousTypes() Signal: SignalSlotClass(_POINTER_) qStringRefSignal ((QString&)@_POINTER_) +INFO : tst_Signaldumper::variousTypes() Signal: SignalSlotClass(_POINTER_) qStringConstRefSignal (QString(Test string)) +INFO : tst_Signaldumper::variousTypes() Signal: SignalSlotClass(_POINTER_) qByteArraySignal (QByteArray(Test bytearray)) +INFO : tst_Signaldumper::variousTypes() Signal: SignalSlotClass(_POINTER_) qListSignal (QList<int>()) +INFO : tst_Signaldumper::variousTypes() Signal: SignalSlotClass(_POINTER_) qVectorSignal (QVector<int>()) +INFO : tst_Signaldumper::variousTypes() Signal: SignalSlotClass(_POINTER_) qVectorRefSignal ((QVector<int>&)@_POINTER_) +INFO : tst_Signaldumper::variousTypes() Signal: SignalSlotClass(_POINTER_) qVectorConstRefSignal (QVector<int>()) +INFO : tst_Signaldumper::variousTypes() Signal: SignalSlotClass(_POINTER_) qVectorConstPointerSignal ((const QVector<int>*)_POINTER_) +INFO : tst_Signaldumper::variousTypes() Signal: SignalSlotClass(_POINTER_) qVectorPointerConstSignal () +INFO : tst_Signaldumper::variousTypes() Signal: SignalSlotClass(_POINTER_) qVariantSignal (QVariant()) +INFO : tst_Signaldumper::variousTypes() Signal: SignalSlotClass(_POINTER_) qVariantSignal (QVariant()) +PASS : tst_Signaldumper::variousTypes() +INFO : tst_Signaldumper::deletingSender() Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +PASS : tst_Signaldumper::deletingSender() +PASS : tst_Signaldumper::cleanupTestCase() +INFO : tst_Signaldumper::UnknownTestFunc() Signal: QThread(_POINTER_) finished () +Totals: 21 passed, 0 failed, 0 skipped, 0 blacklisted, 0ms +********* Finished testing of tst_Signaldumper ********* diff --git a/tests/auto/testlib/selftests/expected_signaldumper.xml b/tests/auto/testlib/selftests/expected_signaldumper.xml new file mode 100644 index 0000000000..f11a0c3ce6 --- /dev/null +++ b/tests/auto/testlib/selftests/expected_signaldumper.xml @@ -0,0 +1,588 @@ +<?xml version="1.0" encoding="UTF-8"?> +<TestCase name="tst_Signaldumper"> +<Environment> + <QtVersion>@INSERT_QT_VERSION_HERE@</QtVersion> + <QtBuild/> + <QTestVersion>@INSERT_QT_VERSION_HERE@</QTestVersion> +</Environment> +<TestFunction name="initTestCase"> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: QThread(_POINTER_) started ()]]></Description> +</Message> +<Incident type="pass" file="" line="0" /> + <Duration msecs="0"/> +</TestFunction> +<TestFunction name="noConnections"> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Incident type="pass" file="" line="0" /> + <Duration msecs="0"/> +</TestFunction> +<TestFunction name="oneSlot"> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> +</Incident> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> +</Incident> + <Duration msecs="0"/> +</TestFunction> +<TestFunction name="oneSlotOldSyntax"> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Slot: SignalSlotClass(_POINTER_) slotWithParameters(int,char)]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> +</Incident> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> +</Incident> + <Duration msecs="0"/> +</TestFunction> +<TestFunction name="twoSlots"> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> +</Incident> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> +</Incident> + <Duration msecs="0"/> +</TestFunction> +<TestFunction name="twoSlotsOldSyntax"> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Slot: SignalSlotClass(_POINTER_) slotWithParameters(int,char)]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Slot: SignalSlotClass(_POINTER_) slotWithParameters(int,char)]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> +</Incident> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> +</Incident> + <Duration msecs="0"/> +</TestFunction> +<TestFunction name="signalForwarding"> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Signal: SignalSlotClass(_POINTER_) nestedSignalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> +</Incident> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) nestedSignalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> +</Incident> + <Duration msecs="0"/> +</TestFunction> +<TestFunction name="signalForwardingOldSyntax"> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Slot: SignalSlotClass(_POINTER_) nestedSignal()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Slot: SignalSlotClass(_POINTER_) nestedSignalWithParameters(int,char)]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Signal: SignalSlotClass(_POINTER_) nestedSignalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Slot: SignalSlotClass(_POINTER_) nestedSignal()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> +</Incident> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) nestedSignalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> +</Incident> + <Duration msecs="0"/> +</TestFunction> +<TestFunction name="slotEmittingSignal"> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> +</Incident> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> +</Incident> + <Duration msecs="0"/> +</TestFunction> +<TestFunction name="slotEmittingSignalOldSyntax"> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Slot: SignalSlotClass(_POINTER_) emitSecondSignal()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[ Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[direct]]></DataTag> +</Incident> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]></Description> +</Message> +<Incident type="pass" file="" line="0"> + <DataTag><![CDATA[queued]]></DataTag> +</Incident> + <Duration msecs="0"/> +</TestFunction> +<TestFunction name="variousTypes"> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) qStringSignal (QString(Test string))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) qStringRefSignal ((QString&)@_POINTER_)]]></Description> +</Message> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) qStringConstRefSignal (QString(Test string))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) qByteArraySignal (QByteArray(Test bytearray))]]></Description> +</Message> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) qListSignal (QList<int>())]]></Description> +</Message> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) qVectorSignal (QVector<int>())]]></Description> +</Message> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) qVectorRefSignal ((QVector<int>&)@_POINTER_)]]></Description> +</Message> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) qVectorConstRefSignal (QVector<int>())]]></Description> +</Message> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) qVectorConstPointerSignal ((const QVector<int>*)_POINTER_)]]></Description> +</Message> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) qVectorPointerConstSignal ()]]></Description> +</Message> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) qVariantSignal (QVariant())]]></Description> +</Message> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) qVariantSignal (QVariant())]]></Description> +</Message> +<Incident type="pass" file="" line="0" /> + <Duration msecs="0"/> +</TestFunction> +<TestFunction name="deletingSender"> +<Message type="info" file="" line="0"> + <Description><![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]></Description> +</Message> +<Incident type="pass" file="" line="0" /> + <Duration msecs="0"/> +</TestFunction> +<TestFunction name="cleanupTestCase"> +<Incident type="pass" file="" line="0" /> + <Duration msecs="0"/> +</TestFunction> +<Message type="info" file="" line="0"> + <Description><![CDATA[ Signal: QThread(_POINTER_) finished ()]]></Description> +</Message> +<Duration msecs="0"/> +</TestCase> diff --git a/tests/auto/testlib/selftests/expected_signaldumper.xunitxml b/tests/auto/testlib/selftests/expected_signaldumper.xunitxml new file mode 100644 index 0000000000..cbf7075ba1 --- /dev/null +++ b/tests/auto/testlib/selftests/expected_signaldumper.xunitxml @@ -0,0 +1,288 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<testsuite errors="126" failures="0" tests="13" name="tst_Signaldumper"> + <properties> + <property value="@INSERT_QT_VERSION_HERE@" name="QTestVersion"/> + <property value="@INSERT_QT_VERSION_HERE@" name="QtVersion"/> + <property value="" name="QtBuild"/> + </properties> + <testcase result="pass" name="initTestCase"> + <!-- message="Signal: QThread(_POINTER_) started ()" type="info" --> + </testcase> + <testcase result="pass" name="noConnections"> + <!-- message="Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()" type="info" --> + <!-- message="Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))" type="info" --> + </testcase> + <testcase result="pass" name="oneSlot"> + <!-- tag="direct" message="Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()" type="info" --> + <!-- tag="direct" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="direct" message="Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))" type="info" --> + <!-- tag="direct" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="direct" message="Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))" type="info" --> + <!-- tag="direct" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="queued" message="Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()" type="info" --> + <!-- tag="queued" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="queued" message="Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))" type="info" --> + <!-- tag="queued" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="queued" message="Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))" type="info" --> + <!-- tag="queued" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + </testcase> + <testcase result="pass" name="oneSlotOldSyntax"> + <!-- tag="direct" message="Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()" type="info" --> + <!-- tag="direct" message=" Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()" type="info" --> + <!-- tag="direct" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="direct" message="Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))" type="info" --> + <!-- tag="direct" message=" Slot: SignalSlotClass(_POINTER_) slotWithParameters(int,char)" type="info" --> + <!-- tag="direct" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="direct" message="Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))" type="info" --> + <!-- tag="direct" message=" Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()" type="info" --> + <!-- tag="direct" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="queued" message="Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()" type="info" --> + <!-- tag="queued" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="queued" message="Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))" type="info" --> + <!-- tag="queued" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="queued" message="Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))" type="info" --> + <!-- tag="queued" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + </testcase> + <testcase result="pass" name="twoSlots"> + <!-- tag="direct" message="Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()" type="info" --> + <!-- tag="direct" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="direct" message="Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))" type="info" --> + <!-- tag="direct" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="direct" message="Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))" type="info" --> + <!-- tag="direct" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="queued" message="Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()" type="info" --> + <!-- tag="queued" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="queued" message="Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))" type="info" --> + <!-- tag="queued" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="queued" message="Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))" type="info" --> + <!-- tag="queued" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + </testcase> + <testcase result="pass" name="twoSlotsOldSyntax"> + <!-- tag="direct" message="Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()" type="info" --> + <!-- tag="direct" message=" Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()" type="info" --> + <!-- tag="direct" message=" Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()" type="info" --> + <!-- tag="direct" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="direct" message="Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))" type="info" --> + <!-- tag="direct" message=" Slot: SignalSlotClass(_POINTER_) slotWithParameters(int,char)" type="info" --> + <!-- tag="direct" message=" Slot: SignalSlotClass(_POINTER_) slotWithParameters(int,char)" type="info" --> + <!-- tag="direct" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="direct" message="Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))" type="info" --> + <!-- tag="direct" message=" Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()" type="info" --> + <!-- tag="direct" message=" Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()" type="info" --> + <!-- tag="direct" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="queued" message="Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()" type="info" --> + <!-- tag="queued" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="queued" message="Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))" type="info" --> + <!-- tag="queued" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="queued" message="Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))" type="info" --> + <!-- tag="queued" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + </testcase> + <testcase result="pass" name="signalForwarding"> + <!-- tag="direct" message="Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()" type="info" --> + <!-- tag="direct" message=" Signal: SignalSlotClass(_POINTER_) nestedSignal ()" type="info" --> + <!-- tag="direct" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="direct" message="Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))" type="info" --> + <!-- tag="direct" message=" Signal: SignalSlotClass(_POINTER_) nestedSignalWithParameters (int(242), char(m))" type="info" --> + <!-- tag="direct" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="direct" message="Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))" type="info" --> + <!-- tag="direct" message=" Signal: SignalSlotClass(_POINTER_) nestedSignal ()" type="info" --> + <!-- tag="direct" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="queued" message="Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()" type="info" --> + <!-- tag="queued" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="queued" message="Signal: SignalSlotClass(_POINTER_) nestedSignal ()" type="info" --> + <!-- tag="queued" message="Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))" type="info" --> + <!-- tag="queued" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="queued" message="Signal: SignalSlotClass(_POINTER_) nestedSignalWithParameters (int(242), char(m))" type="info" --> + <!-- tag="queued" message="Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))" type="info" --> + <!-- tag="queued" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="queued" message="Signal: SignalSlotClass(_POINTER_) nestedSignal ()" type="info" --> + </testcase> + <testcase result="pass" name="signalForwardingOldSyntax"> + <!-- tag="direct" message="Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()" type="info" --> + <!-- tag="direct" message=" Slot: SignalSlotClass(_POINTER_) nestedSignal()" type="info" --> + <!-- tag="direct" message=" Signal: SignalSlotClass(_POINTER_) nestedSignal ()" type="info" --> + <!-- tag="direct" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="direct" message="Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))" type="info" --> + <!-- tag="direct" message=" Slot: SignalSlotClass(_POINTER_) nestedSignalWithParameters(int,char)" type="info" --> + <!-- tag="direct" message=" Signal: SignalSlotClass(_POINTER_) nestedSignalWithParameters (int(242), char(m))" type="info" --> + <!-- tag="direct" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="direct" message="Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))" type="info" --> + <!-- tag="direct" message=" Slot: SignalSlotClass(_POINTER_) nestedSignal()" type="info" --> + <!-- tag="direct" message=" Signal: SignalSlotClass(_POINTER_) nestedSignal ()" type="info" --> + <!-- tag="direct" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="queued" message="Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()" type="info" --> + <!-- tag="queued" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="queued" message="Signal: SignalSlotClass(_POINTER_) nestedSignal ()" type="info" --> + <!-- tag="queued" message="Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))" type="info" --> + <!-- tag="queued" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="queued" message="Signal: SignalSlotClass(_POINTER_) nestedSignalWithParameters (int(242), char(m))" type="info" --> + <!-- tag="queued" message="Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))" type="info" --> + <!-- tag="queued" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="queued" message="Signal: SignalSlotClass(_POINTER_) nestedSignal ()" type="info" --> + </testcase> + <testcase result="pass" name="slotEmittingSignal"> + <!-- tag="direct" message="Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()" type="info" --> + <!-- tag="direct" message=" Signal: SignalSlotClass(_POINTER_) nestedSignal ()" type="info" --> + <!-- tag="direct" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="queued" message="Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()" type="info" --> + <!-- tag="queued" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="queued" message="Signal: SignalSlotClass(_POINTER_) nestedSignal ()" type="info" --> + </testcase> + <testcase result="pass" name="slotEmittingSignalOldSyntax"> + <!-- tag="direct" message="Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()" type="info" --> + <!-- tag="direct" message=" Slot: SignalSlotClass(_POINTER_) emitSecondSignal()" type="info" --> + <!-- tag="direct" message=" Signal: SignalSlotClass(_POINTER_) nestedSignal ()" type="info" --> + <!-- tag="direct" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="queued" message="Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()" type="info" --> + <!-- tag="queued" message="Signal: QEventDispatcherPlatform(_POINTER_) awake ()" type="info" --> + <!-- tag="queued" message="Signal: SignalSlotClass(_POINTER_) nestedSignal ()" type="info" --> + </testcase> + <testcase result="pass" name="variousTypes"> + <!-- message="Signal: SignalSlotClass(_POINTER_) qStringSignal (QString(Test string))" type="info" --> + <!-- message="Signal: SignalSlotClass(_POINTER_) qStringRefSignal ((QString&)@_POINTER_)" type="info" --> + <!-- message="Signal: SignalSlotClass(_POINTER_) qStringConstRefSignal (QString(Test string))" type="info" --> + <!-- message="Signal: SignalSlotClass(_POINTER_) qByteArraySignal (QByteArray(Test bytearray))" type="info" --> + <!-- message="Signal: SignalSlotClass(_POINTER_) qListSignal (QList<int>())" type="info" --> + <!-- message="Signal: SignalSlotClass(_POINTER_) qVectorSignal (QVector<int>())" type="info" --> + <!-- message="Signal: SignalSlotClass(_POINTER_) qVectorRefSignal ((QVector<int>&)@_POINTER_)" type="info" --> + <!-- message="Signal: SignalSlotClass(_POINTER_) qVectorConstRefSignal (QVector<int>())" type="info" --> + <!-- message="Signal: SignalSlotClass(_POINTER_) qVectorConstPointerSignal ((const QVector<int>*)_POINTER_)" type="info" --> + <!-- message="Signal: SignalSlotClass(_POINTER_) qVectorPointerConstSignal ()" type="info" --> + <!-- message="Signal: SignalSlotClass(_POINTER_) qVariantSignal (QVariant())" type="info" --> + <!-- message="Signal: SignalSlotClass(_POINTER_) qVariantSignal (QVariant())" type="info" --> + </testcase> + <testcase result="pass" name="deletingSender"> + <!-- message="Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()" type="info" --> + </testcase> + <testcase result="pass" name="cleanupTestCase"> + <!-- message=" Signal: QThread(_POINTER_) finished ()" type="info" --> + </testcase> + <system-err> +<![CDATA[Signal: QThread(_POINTER_) started ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]> +<![CDATA[ Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]> +<![CDATA[ Slot: SignalSlotClass(_POINTER_) slotWithParameters(int,char)]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]> +<![CDATA[ Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]> +<![CDATA[ Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()]]> +<![CDATA[ Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]> +<![CDATA[ Slot: SignalSlotClass(_POINTER_) slotWithParameters(int,char)]]> +<![CDATA[ Slot: SignalSlotClass(_POINTER_) slotWithParameters(int,char)]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]> +<![CDATA[ Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()]]> +<![CDATA[ Slot: SignalSlotClass(_POINTER_) slotWithoutParameters()]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]> +<![CDATA[ Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]> +<![CDATA[ Signal: SignalSlotClass(_POINTER_) nestedSignalWithParameters (int(242), char(m))]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]> +<![CDATA[ Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) nestedSignalWithParameters (int(242), char(m))]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]> +<![CDATA[ Slot: SignalSlotClass(_POINTER_) nestedSignal()]]> +<![CDATA[ Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]> +<![CDATA[ Slot: SignalSlotClass(_POINTER_) nestedSignalWithParameters(int,char)]]> +<![CDATA[ Signal: SignalSlotClass(_POINTER_) nestedSignalWithParameters (int(242), char(m))]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]> +<![CDATA[ Slot: SignalSlotClass(_POINTER_) nestedSignal()]]> +<![CDATA[ Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) nestedSignalWithParameters (int(242), char(m))]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithParameters (int(242), char(m))]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]> +<![CDATA[ Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]> +<![CDATA[ Slot: SignalSlotClass(_POINTER_) emitSecondSignal()]]> +<![CDATA[ Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]> +<![CDATA[Signal: QEventDispatcherPlatform(_POINTER_) awake ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) nestedSignal ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) qStringSignal (QString(Test string))]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) qStringRefSignal ((QString&)@_POINTER_)]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) qStringConstRefSignal (QString(Test string))]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) qByteArraySignal (QByteArray(Test bytearray))]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) qListSignal (QList<int>())]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) qVectorSignal (QVector<int>())]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) qVectorRefSignal ((QVector<int>&)@_POINTER_)]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) qVectorConstRefSignal (QVector<int>())]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) qVectorConstPointerSignal ((const QVector<int>*)_POINTER_)]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) qVectorPointerConstSignal ()]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) qVariantSignal (QVariant())]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) qVariantSignal (QVariant())]]> +<![CDATA[Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()]]> +<![CDATA[ Signal: QThread(_POINTER_) finished ()]]> + </system-err> +</testsuite> diff --git a/tests/auto/testlib/selftests/float/tst_float.cpp b/tests/auto/testlib/selftests/float/tst_float.cpp index 49d00ac0e0..cefd8a57c4 100644 --- a/tests/auto/testlib/selftests/float/tst_float.cpp +++ b/tests/auto/testlib/selftests/float/tst_float.cpp @@ -46,6 +46,55 @@ private slots: void compareFloatTests_data() const; }; +template<typename F> +static void nonFinite_data(F zero, F one) +{ + using Bounds = std::numeric_limits<F>; + + // QCOMPARE special-cases non-finite values + if (Bounds::has_quiet_NaN) { + const F nan = Bounds::quiet_NaN(); + QTest::newRow("should PASS: NaN == NaN") << nan << nan; + QTest::newRow("should FAIL: NaN != 0") << nan << zero; + QTest::newRow("should FAIL: 0 != NaN") << zero << nan; + QTest::newRow("should FAIL: NaN != 1") << nan << one; + QTest::newRow("should FAIL: 1 != NaN") << one << nan; + } + + if (Bounds::has_infinity) { + const F uge = Bounds::infinity(); + QTest::newRow("should PASS: inf == inf") << uge << uge; + QTest::newRow("should PASS: -inf == -inf") << -uge << -uge; + QTest::newRow("should FAIL: inf != -inf") << uge << -uge; + QTest::newRow("should FAIL: -inf != inf") << -uge << uge; + if (Bounds::has_quiet_NaN) { + const F nan = Bounds::quiet_NaN(); + QTest::newRow("should FAIL: inf != nan") << uge << nan; + QTest::newRow("should FAIL: nan != inf") << nan << uge; + QTest::newRow("should FAIL: -inf != nan") << -uge << nan; + QTest::newRow("should FAIL: nan != -inf") << nan << -uge; + } + QTest::newRow("should FAIL: inf != 0") << uge << zero; + QTest::newRow("should FAIL: 0 != inf") << zero << uge; + QTest::newRow("should FAIL: -inf != 0") << -uge << zero; + QTest::newRow("should FAIL: 0 != -inf") << zero << -uge; + QTest::newRow("should FAIL: inf != 1") << uge << one; + QTest::newRow("should FAIL: 1 != inf") << one << uge; + QTest::newRow("should FAIL: -inf != 1") << -uge << one; + QTest::newRow("should FAIL: 1 != -inf") << one << -uge; + + const F big = Bounds::max(); + QTest::newRow("should FAIL: inf != max") << uge << big; + QTest::newRow("should FAIL: inf != -max") << uge << -big; + QTest::newRow("should FAIL: max != inf") << big << uge; + QTest::newRow("should FAIL: -max != inf") << -big << uge; + QTest::newRow("should FAIL: -inf != max") << -uge << big; + QTest::newRow("should FAIL: -inf != -max") << -uge << -big; + QTest::newRow("should FAIL: max != -inf") << big << -uge; + QTest::newRow("should FAIL: -max != -inf") << -big << -uge; + } +} + void tst_float::doubleComparisons() const { QFETCH(double, operandLeft); @@ -58,65 +107,26 @@ void tst_float::doubleComparisons_data() const { QTest::addColumn<double>("operandLeft"); QTest::addColumn<double>("operandRight"); + double zero(0.), one(1.); - QTest::newRow("should PASS 1") << 0. << 0.; - QTest::newRow("should FAIL 1") << 1.00000 << 3.00000; - QTest::newRow("should FAIL 2") << 1.00000e-7 << 3.00000e-7; + QTest::newRow("should FAIL 1") << one << 3.; + QTest::newRow("should PASS 1") << zero << zero; + QTest::newRow("should FAIL 2") << 1.e-7 << 3.e-7; // QCOMPARE for doubles uses qFuzzyCompare(), which succeeds if the numbers // differ by no more than 1e-12 times the smaller value. Thus // QCOMPARE(1e12-2, 1e12-1) should fail, while QCOMPARE(1e12+1, 1e12+2) // should pass. - QTest::newRow("should PASS 2") << 1e12 + 1. << 1e12 + 2.; - QTest::newRow("should FAIL 3") << 1e12 - 1. << 1e12 - 2.; + QTest::newRow("should PASS 2") << 1e12 + one << 1e12 + 2.; + QTest::newRow("should FAIL 3") << 1e12 - one << 1e12 - 2.; // ... but rounding makes that a bit unrelaible when scaled close to the bounds. QTest::newRow("should PASS 3") << 1e-310 + 1e-322 << 1e-310 + 2e-322; QTest::newRow("should FAIL 4") << 1e-310 - 1e-322 << 1e-310 - 3e-322; QTest::newRow("should PASS 4") << 1e307 + 1e295 << 1e307 + 2e295; QTest::newRow("should FAIL 5") << 1e307 - 1e295 << 1e307 - 3e295; - // QCOMPARE special-cases non-finite values - if (std::numeric_limits<double>::has_quiet_NaN) { - const double nan = std::numeric_limits<double>::quiet_NaN(); - QTest::newRow("should PASS: NaN == NaN") << nan << nan; - QTest::newRow("should FAIL: NaN != 0") << nan << 0.; - QTest::newRow("should FAIL: 0 != NaN") << 0. << nan; - QTest::newRow("should FAIL: NaN != 1") << nan << 1.; - QTest::newRow("should FAIL: 1 != NaN") << 1. << nan; - } - if (std::numeric_limits<double>::has_infinity) { - const double uge = std::numeric_limits<double>::infinity(); - QTest::newRow("should PASS: inf == inf") << uge << uge; - QTest::newRow("should PASS: -inf == -inf") << -uge << -uge; - QTest::newRow("should FAIL: inf != -inf") << uge << -uge; - QTest::newRow("should FAIL: -inf != inf") << -uge << uge; - if (std::numeric_limits<double>::has_quiet_NaN) { - const double nan = std::numeric_limits<double>::quiet_NaN(); - QTest::newRow("should FAIL: inf != nan") << uge << nan; - QTest::newRow("should FAIL: nan != inf") << nan << uge; - QTest::newRow("should FAIL: -inf != nan") << -uge << nan; - QTest::newRow("should FAIL: nan != -inf") << nan << -uge; - } - QTest::newRow("should FAIL: inf != 0") << uge << 0.; - QTest::newRow("should FAIL: 0 != inf") << 0. << uge; - QTest::newRow("should FAIL: -inf != 0") << -uge << 0.; - QTest::newRow("should FAIL: 0 != -inf") << 0. << -uge; - QTest::newRow("should FAIL: inf != 1") << uge << 1.; - QTest::newRow("should FAIL: 1 != inf") << 1. << uge; - QTest::newRow("should FAIL: -inf != 1") << -uge << 1.; - QTest::newRow("should FAIL: 1 != -inf") << 1. << -uge; - - const double big = std::numeric_limits<double>::max(); - QTest::newRow("should FAIL: inf != max") << uge << big; - QTest::newRow("should FAIL: inf != -max") << uge << -big; - QTest::newRow("should FAIL: max != inf") << big << uge; - QTest::newRow("should FAIL: -max != inf") << -big << uge; - QTest::newRow("should FAIL: -inf != max") << -uge << big; - QTest::newRow("should FAIL: -inf != -max") << -uge << -big; - QTest::newRow("should FAIL: max != -inf") << big << -uge; - QTest::newRow("should FAIL: -max != -inf") << -big << -uge; - } + nonFinite_data(zero, one); } void tst_float::floatComparisons() const @@ -131,65 +141,26 @@ void tst_float::floatComparisons_data() const { QTest::addColumn<float>("operandLeft"); QTest::addColumn<float>("operandRight"); + float zero(0.f), one(1.f); - QTest::newRow("should FAIL 1") << 1.00000f << 3.00000f; - QTest::newRow("should PASS 1") << 0.f << 0.f; - QTest::newRow("should FAIL 2") << 1.00000e-7f << 3.00000e-7f; + QTest::newRow("should FAIL 1") << one << 3.f; + QTest::newRow("should PASS 1") << zero << zero; + QTest::newRow("should FAIL 2") << 1.e-7f << 3.e-7f; // QCOMPARE for floats uses qFuzzyCompare(), which succeeds if the numbers // differ by no more than 1e-5 times the smaller value. Thus // QCOMPARE(1e5-2, 1e5-1) should fail, while QCOMPARE(1e5+1, 1e5+2) // should pass. - QTest::newRow("should PASS 2") << 1e5f + 1.f << 1e5f + 2.f; - QTest::newRow("should FAIL 3") << 1e5f - 1.f << 1e5f - 2.f; + QTest::newRow("should PASS 2") << 1e5f + one << 1e5f + 2.f; + QTest::newRow("should FAIL 3") << 1e5f - one << 1e5f - 2.f; // ... but rounding makes that a bit unrelaible when scaled close to the bounds. QTest::newRow("should PASS 3") << 1e-39f + 1e-44f << 1e-39f + 2e-44f; QTest::newRow("should FAIL 4") << 1e-39f - 1e-44f << 1e-39f - 3e-44f; QTest::newRow("should PASS 4") << 1e38f + 1e33f << 1e38f + 2e33f; QTest::newRow("should FAIL 5") << 1e38f - 1e33f << 1e38f - 3e33f; - // QCOMPARE special-cases non-finite values - if (std::numeric_limits<float>::has_quiet_NaN) { - const float nan = std::numeric_limits<float>::quiet_NaN(); - QTest::newRow("should PASS: NaN == NaN") << nan << nan; - QTest::newRow("should FAIL: NaN != 0") << nan << 0.f; - QTest::newRow("should FAIL: 0 != NaN") << 0.f << nan; - QTest::newRow("should FAIL: NaN != 1") << nan << 1.f; - QTest::newRow("should FAIL: 1 != NaN") << 1.f << nan; - } - if (std::numeric_limits<float>::has_infinity) { - const float uge = std::numeric_limits<float>::infinity(); - QTest::newRow("should PASS: inf == inf") << uge << uge; - QTest::newRow("should PASS: -inf == -inf") << -uge << -uge; - QTest::newRow("should FAIL: inf != -inf") << uge << -uge; - QTest::newRow("should FAIL: -inf != inf") << -uge << uge; - if (std::numeric_limits<float>::has_quiet_NaN) { - const float nan = std::numeric_limits<float>::quiet_NaN(); - QTest::newRow("should FAIL: inf != nan") << uge << nan; - QTest::newRow("should FAIL: nan != inf") << nan << uge; - QTest::newRow("should FAIL: -inf != nan") << -uge << nan; - QTest::newRow("should FAIL: nan != -inf") << nan << -uge; - } - QTest::newRow("should FAIL: inf != 0") << uge << 0.f; - QTest::newRow("should FAIL: 0 != inf") << 0.f << uge; - QTest::newRow("should FAIL: -inf != 0") << -uge << 0.f; - QTest::newRow("should FAIL: 0 != -inf") << 0.f << -uge; - QTest::newRow("should FAIL: inf != 1") << uge << 1.f; - QTest::newRow("should FAIL: 1 != inf") << 1.f << uge; - QTest::newRow("should FAIL: -inf != 1") << -uge << 1.f; - QTest::newRow("should FAIL: 1 != -inf") << 1.f << -uge; - - const float big = std::numeric_limits<float>::max(); - QTest::newRow("should FAIL: inf != max") << uge << big; - QTest::newRow("should FAIL: inf != -max") << uge << -big; - QTest::newRow("should FAIL: max != inf") << big << uge; - QTest::newRow("should FAIL: -max != inf") << -big << uge; - QTest::newRow("should FAIL: -inf != max") << -uge << big; - QTest::newRow("should FAIL: -inf != -max") << -uge << -big; - QTest::newRow("should FAIL: max != -inf") << big << -uge; - QTest::newRow("should FAIL: -max != -inf") << -big << -uge; - } + nonFinite_data(zero, one); } void tst_float::float16Comparisons() const @@ -204,28 +175,22 @@ void tst_float::float16Comparisons_data() const { QTest::addColumn<qfloat16>("operandLeft"); QTest::addColumn<qfloat16>("operandRight"); + qfloat16 zero(0), one(1); - QTest::newRow("should SUCCEED 1") - << qfloat16(0) - << qfloat16(0); - - QTest::newRow("should FAIL 1") - << qfloat16(1.000) - << qfloat16(3.000); - - QTest::newRow("should FAIL 2") - << qfloat16(1.000e-4f) - << qfloat16(3.000e-4f); + QTest::newRow("should FAIL 1") << one << qfloat16(3); + QTest::newRow("should PASS 1") << zero << zero; + QTest::newRow("should FAIL 2") << qfloat16(1e-4f) << qfloat16(3e-4f); // QCOMPARE for qfloat16s uses qFuzzyCompare() - - QTest::newRow("should FAIL 3") - << qfloat16(98) - << qfloat16(99); - - QTest::newRow("should SUCCEED 2") - << qfloat16(1001) - << qfloat16(1002); + QTest::newRow("should PASS 2") << qfloat16(1001) << qfloat16(1002); + QTest::newRow("should FAIL 3") << qfloat16(98) << qfloat16(99); + // ... which gets a bit unreliable near to the type's bounds + QTest::newRow("should PASS 3") << qfloat16(6e-5f) + qfloat16(6e-7f) << qfloat16(6e-5f) + qfloat16(11e-7f); + QTest::newRow("should FAIL 4") << qfloat16(6e-5f) - qfloat16(7e-7f) << qfloat16(6e-5f) - qfloat16(13e-7f); + QTest::newRow("should PASS 4") << qfloat16(6e4) + qfloat16(700) << qfloat16(6e4) + qfloat16(1200); + QTest::newRow("should FAIL 5") << qfloat16(6e4) - qfloat16(600) << qfloat16(6e4) - qfloat16(1200); + + nonFinite_data(zero, one); } void tst_float::compareFloatTests() const diff --git a/tests/auto/testlib/selftests/generate_expected_output.py b/tests/auto/testlib/selftests/generate_expected_output.py index 9ec87c8fc6..48ecbf0289 100755 --- a/tests/auto/testlib/selftests/generate_expected_output.py +++ b/tests/auto/testlib/selftests/generate_expected_output.py @@ -92,6 +92,17 @@ class Cleaner (object): (r'(Loc: \[[^[\]()]+)\(\d+\)', r'\1(0)'), # txt (r'(\[Loc: [^[\]()]+)\(\d+\)', r'\1(0)'), # teamcity (r'(<(?:Incident|Message)\b.*\bfile=.*\bline=)"\d+"', r'\1"0"'), # lightxml, xml + # Pointers printed by signal dumper: + (r'\(\b[a-f0-9]{8,}\b\)', r'(_POINTER_)'), + # Example/for reference: + # ((QString&)@55f5fbb8dd40) + # ((const QVector<int>*)7ffd671d4558) + (r'\((\((?:const )?\w+(?:<[^>]+>)?[*&]*\)@?)\b[a-f\d]{8,}\b\)', r'(\1_POINTER_)'), + # For xml output there is no '<', '>' or '&', so we need an alternate version for that: + # ((QVector<int>&)@5608b455e640) + (r'\((\((?:const )?\w+(?:<(?:[^&]|&(?!gt;))*>)?(?:\*|&)?\)@?)[a-z\d]+\b\)', r'(\1_POINTER_)'), + # QEventDispatcher{Glib,Win32,etc.} + (r'\bQEventDispatcher\w+\b', r'QEventDispatcherPlatform'), ), precook = re.compile): """Private implementation details of __init__().""" @@ -296,6 +307,7 @@ def generateTestData(testname, clean, "benchlibcounting": "-eventcounter", "printdatatags": "-datatags", "printdatatagswithglobaltags": "-datatags", + "signaldumper": "-vs", "silent": "-silent", "verbose1": "-v1", "verbose2": "-v2", diff --git a/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp b/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp index 6c0ae1f43c..3c5c2c8f37 100644 --- a/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp +++ b/tests/auto/testlib/selftests/globaldata/tst_globaldata.cpp @@ -66,9 +66,10 @@ void tst_globaldata::initTestCase() void tst_globaldata::initTestCase_data() { - QTest::addColumn<bool>("booli"); - QTest::newRow("1") << false; - QTest::newRow("2") << true; + // QFETCH_GLOBAL shall iterate these, for every test: + QTest::addColumn<bool>("global"); + QTest::newRow("global=false") << false; + QTest::newRow("global=true") << true; } void tst_globaldata::cleanupTestCase() @@ -94,41 +95,42 @@ void tst_globaldata::cleanup() void tst_globaldata::testGlobal_data() { - QTest::addColumn<bool>("booll"); - QTest::newRow("local 1") << false; - QTest::newRow("local 2") << true; + QTest::addColumn<bool>("local"); + QTest::newRow("local=false") << false; + QTest::newRow("local=true") << true; } void tst_globaldata::testGlobal() { - QFETCH_GLOBAL(bool, booli); - qDebug() << "global:" << booli; - QFETCH(bool, booll); - qDebug() << "local:" << booll; + QFETCH_GLOBAL(bool, global); + qDebug() << "global:" << global; + QFETCH(bool, local); + qDebug() << "local:" << local; } void tst_globaldata::skip_data() { - QTest::addColumn<bool>("booll"); - QTest::newRow("local 1") << false; - QTest::newRow("local 2") << true; - + testGlobal_data(); QSKIP("skipping"); } void tst_globaldata::skip() { - qDebug() << "this line should never be reached"; + // A skip in _data() causes the whole test to be skipped, for all global rows. + QVERIFY(!"This line should never be reached."); } void tst_globaldata::skipSingle() { - QFETCH_GLOBAL(bool, booli); - QFETCH(bool, booll); - - if (booli && !booll) - QSKIP("skipping"); - qDebug() << "global:" << booli << "local:" << booll; + QFETCH_GLOBAL(bool, global); + QFETCH(bool, local); + + // A skip in the last run of one global row used to suppress the test in the + // next global row (where a skip in an earlier run of the first row did not). + if (global ^ local) + QSKIP("Skipping"); + qDebug() << "global:" << global << "local:" << local; + QCOMPARE(global, local); } void tst_globaldata::skipLocal() diff --git a/tests/auto/testlib/selftests/selftests.pri b/tests/auto/testlib/selftests/selftests.pri index b4568dd3e1..2cad0b7e17 100644 --- a/tests/auto/testlib/selftests/selftests.pri +++ b/tests/auto/testlib/selftests/selftests.pri @@ -1,5 +1,4 @@ SUBPROGRAMS = \ - #alive \ assert \ badxml \ benchlibcallgrind \ @@ -37,6 +36,7 @@ SUBPROGRAMS = \ printdatatagswithglobaltags \ qexecstringlist \ silent \ + signaldumper \ singleskip \ skip \ skipcleanup \ diff --git a/tests/auto/testlib/selftests/signaldumper/signaldumper.pro b/tests/auto/testlib/selftests/signaldumper/signaldumper.pro new file mode 100644 index 0000000000..8780b18419 --- /dev/null +++ b/tests/auto/testlib/selftests/signaldumper/signaldumper.pro @@ -0,0 +1,9 @@ +SOURCES += tst_signaldumper.cpp +QT = core testlib-private + +macos:CONFIG -= app_bundle +CONFIG -= debug_and_release_target + +TARGET = signaldumper + +include($$QT_SOURCE_TREE/src/testlib/selfcover.pri) diff --git a/tests/auto/testlib/selftests/signaldumper/tst_signaldumper.cpp b/tests/auto/testlib/selftests/signaldumper/tst_signaldumper.cpp new file mode 100644 index 0000000000..08592e222d --- /dev/null +++ b/tests/auto/testlib/selftests/signaldumper/tst_signaldumper.cpp @@ -0,0 +1,428 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QCoreApplication> +#include <QtTest/QtTest> +#include <private/qtestlog_p.h> + +class tst_Signaldumper : public QObject +{ + Q_OBJECT + + void addConnectionTypeData(); + +private slots: + void noConnections(); + void oneSlot_data(); + void oneSlot(); + void oneSlotOldSyntax_data(); + void oneSlotOldSyntax(); + void twoSlots_data(); + void twoSlots(); + void twoSlotsOldSyntax_data(); + void twoSlotsOldSyntax(); + void signalForwarding_data(); + void signalForwarding(); + void signalForwardingOldSyntax_data(); + void signalForwardingOldSyntax(); + void slotEmittingSignal_data(); + void slotEmittingSignal(); + void slotEmittingSignalOldSyntax_data(); + void slotEmittingSignalOldSyntax(); + + void variousTypes(); + + void deletingSender(); +}; + +void tst_Signaldumper::addConnectionTypeData() +{ + QTest::addColumn<Qt::ConnectionType>("connectionType"); + QTest::newRow("direct") << Qt::ConnectionType::DirectConnection; + QTest::newRow("queued") << Qt::ConnectionType::QueuedConnection; +} + +/* + Simple class to keep the slots and signals separate from the test +*/ +class SignalSlotClass : public QObject +{ + Q_OBJECT + +public: + SignalSlotClass(); + +public slots: + void slotWithoutParameters() {} + void slotWithParameters(int i, char c) { Q_UNUSED(i); Q_UNUSED(c); } + void emitSecondSignal() { emit nestedSignal(); } + +signals: + void signalWithoutParameters(); + void signalWithParameters(int i, char c); + + void nestedSignal(); + void nestedSignalWithParameters(int i, char c); + + // For the "variousTypes" test + void qStringSignal(QString string); + void qStringRefSignal(QString &string); + void qStringConstRefSignal(const QString &string); + void qByteArraySignal(QByteArray byteArray); + void qListSignal(QList<int> list); + void qVectorSignal(QVector<int> vector); + void qVectorRefSignal(QVector<int> &vector); + void qVectorConstRefSignal(const QVector<int> &vector); + void qVectorConstPointerSignal(const QVector<int> *vector); + void qVectorPointerConstSignal(QVector<int> *const vector); + void qVariantSignal(QVariant variant); +}; + +SignalSlotClass::SignalSlotClass() +{ + // For printing signal argument in "variousTypes" test + qRegisterMetaType<QVector<int>>(); + qRegisterMetaType<QList<int>>(); +} + +void tst_Signaldumper::noConnections() +{ + SignalSlotClass signalSlotOwner; + + emit signalSlotOwner.signalWithoutParameters(); + emit signalSlotOwner.signalWithParameters(242, 'm'); +} + +void tst_Signaldumper::oneSlot_data() +{ + addConnectionTypeData(); +} + +void tst_Signaldumper::oneSlot() +{ + QFETCH(Qt::ConnectionType, connectionType); + + SignalSlotClass signalSlotOwner; + // parameterless to parameterless + auto connection = connect(&signalSlotOwner, &SignalSlotClass::signalWithoutParameters, + &signalSlotOwner, &SignalSlotClass::slotWithoutParameters, connectionType); + emit signalSlotOwner.signalWithoutParameters(); + + QCoreApplication::processEvents(); + disconnect(connection); + + // parameters to parameters + connection = connect(&signalSlotOwner, &SignalSlotClass::signalWithParameters, + &signalSlotOwner, &SignalSlotClass::slotWithParameters, connectionType); + emit signalSlotOwner.signalWithParameters(242, 'm'); + + QCoreApplication::processEvents(); + disconnect(connection); + + // parameters to no parameters + connection = connect(&signalSlotOwner, &SignalSlotClass::signalWithParameters, + &signalSlotOwner, &SignalSlotClass::slotWithoutParameters, connectionType); + emit signalSlotOwner.signalWithParameters(242, 'm'); + + QCoreApplication::processEvents(); + disconnect(connection); +} + +void tst_Signaldumper::oneSlotOldSyntax_data() +{ + addConnectionTypeData(); +} + +void tst_Signaldumper::oneSlotOldSyntax() +{ + QFETCH(Qt::ConnectionType, connectionType); + + SignalSlotClass signalSlotOwner; + // parameterless to parameterless + auto connection = connect(&signalSlotOwner, SIGNAL(signalWithoutParameters()), + &signalSlotOwner, SLOT(slotWithoutParameters()), connectionType); + emit signalSlotOwner.signalWithoutParameters(); + + QCoreApplication::processEvents(); + disconnect(connection); + + // parameters to parameters + connection = connect(&signalSlotOwner, SIGNAL(signalWithParameters(int, char)), + &signalSlotOwner, SLOT(slotWithParameters(int, char)), connectionType); + emit signalSlotOwner.signalWithParameters(242, 'm'); + + QCoreApplication::processEvents(); + disconnect(connection); + + // parameters to no parameters + connection = connect(&signalSlotOwner, SIGNAL(signalWithParameters(int, char)), + &signalSlotOwner, SLOT(slotWithoutParameters()), connectionType); + emit signalSlotOwner.signalWithParameters(242, 'm'); + + QCoreApplication::processEvents(); + disconnect(connection); +} + +void tst_Signaldumper::twoSlots_data() +{ + addConnectionTypeData(); +} + +void tst_Signaldumper::twoSlots() +{ + QFETCH(Qt::ConnectionType, connectionType); + + // Now, instead of creating two slots or two objects, we will just do the same connection twice. + // The same slot will then be invoked twice. + + SignalSlotClass signalSlotOwner; + // parameterless to parameterless + auto connection = connect(&signalSlotOwner, &SignalSlotClass::signalWithoutParameters, + &signalSlotOwner, &SignalSlotClass::slotWithoutParameters, connectionType); + auto connection2 = connect(&signalSlotOwner, &SignalSlotClass::signalWithoutParameters, + &signalSlotOwner, &SignalSlotClass::slotWithoutParameters, connectionType); + emit signalSlotOwner.signalWithoutParameters(); + + QCoreApplication::processEvents(); + disconnect(connection); + disconnect(connection2); + + // parameters to parameters + connection = connect(&signalSlotOwner, &SignalSlotClass::signalWithParameters, + &signalSlotOwner, &SignalSlotClass::slotWithParameters, connectionType); + connection2 = connect(&signalSlotOwner, &SignalSlotClass::signalWithParameters, + &signalSlotOwner, &SignalSlotClass::slotWithParameters, connectionType); + emit signalSlotOwner.signalWithParameters(242, 'm'); + + QCoreApplication::processEvents(); + disconnect(connection); + disconnect(connection2); + + // parameters to no parameters + connection = connect(&signalSlotOwner, &SignalSlotClass::signalWithParameters, + &signalSlotOwner, &SignalSlotClass::slotWithoutParameters, connectionType); + connection2 = connect(&signalSlotOwner, &SignalSlotClass::signalWithParameters, + &signalSlotOwner, &SignalSlotClass::slotWithoutParameters, connectionType); + emit signalSlotOwner.signalWithParameters(242, 'm'); + + QCoreApplication::processEvents(); + disconnect(connection); + disconnect(connection2); +} + +void tst_Signaldumper::twoSlotsOldSyntax_data() +{ + addConnectionTypeData(); +} + +void tst_Signaldumper::twoSlotsOldSyntax() +{ + QFETCH(Qt::ConnectionType, connectionType); + + // Now, instead of creating two slots or two objects, we will just do the same connection twice. + // The same slot will then be invoked twice. + + SignalSlotClass signalSlotOwner; + // parameterless to parameterless + auto connection = connect(&signalSlotOwner, SIGNAL(signalWithoutParameters()), + &signalSlotOwner, SLOT(slotWithoutParameters()), connectionType); + auto connection2 = connect(&signalSlotOwner, SIGNAL(signalWithoutParameters()), + &signalSlotOwner, SLOT(slotWithoutParameters()), connectionType); + emit signalSlotOwner.signalWithoutParameters(); + + QCoreApplication::processEvents(); + disconnect(connection); + disconnect(connection2); + + // parameters to parameters + connection = connect(&signalSlotOwner, SIGNAL(signalWithParameters(int, char)), + &signalSlotOwner, SLOT(slotWithParameters(int, char)), connectionType); + connection2 = connect(&signalSlotOwner, SIGNAL(signalWithParameters(int, char)), + &signalSlotOwner, SLOT(slotWithParameters(int, char)), connectionType); + emit signalSlotOwner.signalWithParameters(242, 'm'); + + QCoreApplication::processEvents(); + disconnect(connection); + disconnect(connection2); + + // parameters to no parameters + connection = connect(&signalSlotOwner, SIGNAL(signalWithParameters(int, char)), + &signalSlotOwner, SLOT(slotWithoutParameters()), connectionType); + connection2 = connect(&signalSlotOwner, SIGNAL(signalWithParameters(int, char)), + &signalSlotOwner, SLOT(slotWithoutParameters()), connectionType); + emit signalSlotOwner.signalWithParameters(242, 'm'); + + QCoreApplication::processEvents(); + disconnect(connection); + disconnect(connection2); +} + +void tst_Signaldumper::signalForwarding_data() +{ + addConnectionTypeData(); +} + +void tst_Signaldumper::signalForwarding() +{ + QFETCH(Qt::ConnectionType, connectionType); + + SignalSlotClass signalSlotOwner; + + // parameterless signal to parameterless signal + auto connection = connect(&signalSlotOwner, &SignalSlotClass::signalWithoutParameters, + &signalSlotOwner, &SignalSlotClass::nestedSignal, connectionType); + emit signalSlotOwner.signalWithoutParameters(); + + QCoreApplication::processEvents(); + disconnect(connection); + + // parameter(full) signal to parameter(full) signal + connection = connect(&signalSlotOwner, &SignalSlotClass::signalWithParameters, + &signalSlotOwner, &SignalSlotClass::nestedSignalWithParameters, connectionType); + emit signalSlotOwner.signalWithParameters(242, 'm'); + + QCoreApplication::processEvents(); + disconnect(connection); + + // parameter(full) signal to parameterless signal + connection = connect(&signalSlotOwner, &SignalSlotClass::signalWithParameters, + &signalSlotOwner, &SignalSlotClass::nestedSignal, connectionType); + emit signalSlotOwner.signalWithParameters(242, 'm'); + + QCoreApplication::processEvents(); + disconnect(connection); +} + +void tst_Signaldumper::signalForwardingOldSyntax_data() +{ + addConnectionTypeData(); +} + +void tst_Signaldumper::signalForwardingOldSyntax() +{ + QFETCH(Qt::ConnectionType, connectionType); + + SignalSlotClass signalSlotOwner; + + // parameterless signal to parameterless signal + auto connection = connect(&signalSlotOwner, SIGNAL(signalWithoutParameters()), + &signalSlotOwner, SIGNAL(nestedSignal()), connectionType); + emit signalSlotOwner.signalWithoutParameters(); + + QCoreApplication::processEvents(); + disconnect(connection); + + // parameter(full) signal to parameter(full) signal + connection = connect(&signalSlotOwner, SIGNAL(signalWithParameters(int, char)), + &signalSlotOwner, SIGNAL(nestedSignalWithParameters(int, char)), connectionType); + emit signalSlotOwner.signalWithParameters(242, 'm'); + + QCoreApplication::processEvents(); + disconnect(connection); + + // parameter(full) signal to parameterless signal + connection = connect(&signalSlotOwner, SIGNAL(signalWithParameters(int, char)), + &signalSlotOwner, SIGNAL(nestedSignal()), connectionType); + emit signalSlotOwner.signalWithParameters(242, 'm'); + + QCoreApplication::processEvents(); + disconnect(connection); +} + +void tst_Signaldumper::slotEmittingSignal_data() +{ + addConnectionTypeData(); +} + +void tst_Signaldumper::slotEmittingSignal() +{ + QFETCH(Qt::ConnectionType, connectionType); + + SignalSlotClass signalSlotOwner; + + auto connection = connect(&signalSlotOwner, &SignalSlotClass::signalWithoutParameters, + &signalSlotOwner, &SignalSlotClass::emitSecondSignal, connectionType); + emit signalSlotOwner.signalWithoutParameters(); + QCoreApplication::processEvents(); + disconnect(connection); +} + +void tst_Signaldumper::slotEmittingSignalOldSyntax_data() +{ + addConnectionTypeData(); +} + +void tst_Signaldumper::slotEmittingSignalOldSyntax() +{ + QFETCH(Qt::ConnectionType, connectionType); + + SignalSlotClass signalSlotOwner; + + auto connection = connect(&signalSlotOwner, SIGNAL(signalWithoutParameters()), + &signalSlotOwner, SLOT(emitSecondSignal()), connectionType); + emit signalSlotOwner.signalWithoutParameters(); + QCoreApplication::processEvents(); + disconnect(connection); +} + +void tst_Signaldumper::variousTypes() +{ + SignalSlotClass signalSlotOwner; + QString string = QString::fromLatin1("Test string"); + emit signalSlotOwner.qStringSignal(string); + emit signalSlotOwner.qStringRefSignal(string); + emit signalSlotOwner.qStringConstRefSignal(string); + emit signalSlotOwner.qByteArraySignal(QByteArray("Test bytearray")); + + QList<int> list{1, 2, 3, 242}; + emit signalSlotOwner.qListSignal(list); + + QVector<int> vector{1, 2, 3, 242}; + emit signalSlotOwner.qVectorSignal(vector); + emit signalSlotOwner.qVectorRefSignal(vector); + emit signalSlotOwner.qVectorConstRefSignal(vector); + emit signalSlotOwner.qVectorConstPointerSignal(&vector); + emit signalSlotOwner.qVectorPointerConstSignal(&vector); + + QVariant variant = 24; + emit signalSlotOwner.qVariantSignal(variant); + variant = QVariant(string); + emit signalSlotOwner.qVariantSignal(variant); +} + +void tst_Signaldumper::deletingSender() +{ + SignalSlotClass *signalSlotOwner = new SignalSlotClass(); + connect(signalSlotOwner, &SignalSlotClass::signalWithoutParameters, [signalSlotOwner]() { + delete signalSlotOwner; + }); + emit signalSlotOwner->signalWithoutParameters(); +} + +QTEST_MAIN(tst_Signaldumper) +#include "tst_signaldumper.moc" diff --git a/tests/auto/testlib/selftests/silent/tst_silent.cpp b/tests/auto/testlib/selftests/silent/tst_silent.cpp index 97fbbfd30a..cf3c35dec4 100644 --- a/tests/auto/testlib/selftests/silent/tst_silent.cpp +++ b/tests/auto/testlib/selftests/silent/tst_silent.cpp @@ -72,6 +72,17 @@ void tst_Silent::xpass() QVERIFY2(true, "This test should XPASS"); } +#ifndef Q_OS_WIN +#include <signal.h> +#include <setjmp.h> + +static jmp_buf state; +static void abort_handler(int signal) +{ + longjmp(state, 1); +} +#endif + void tst_Silent::messages() { qWarning("This is a warning that should not appear in silent test output"); @@ -80,7 +91,15 @@ void tst_Silent::messages() qCritical("This is a critical message that should not appear in silent test output"); qInfo("This is an info message that should not appear in silent test output"); QTestLog::info("This is an internal testlib info message that should not appear in silent test output", __FILE__, __LINE__); - qFatal("This is a fatal error message that should still appear in silent test output"); + +#ifndef Q_OS_WIN + // We're testing qFatal, but we don't want to actually std::abort() ! + auto prior = signal(SIGABRT, abort_handler); + if (setjmp(state)) + signal(SIGABRT, prior); + else +#endif + qFatal("This is a fatal error message that should still appear in silent test output"); } QTEST_MAIN(tst_Silent) diff --git a/tests/auto/testlib/selftests/sleep/tst_sleep.cpp b/tests/auto/testlib/selftests/sleep/tst_sleep.cpp index b7b141afd0..95cb68521d 100644 --- a/tests/auto/testlib/selftests/sleep/tst_sleep.cpp +++ b/tests/auto/testlib/selftests/sleep/tst_sleep.cpp @@ -28,6 +28,7 @@ #include <QtCore/QCoreApplication> +#include <QtCore/QElapsedTimer> #include <QtTest/QtTest> class tst_Sleep: public QObject @@ -41,7 +42,7 @@ private slots: void tst_Sleep::sleep() { - QTime t; + QElapsedTimer t; t.start(); QTest::qSleep(100); diff --git a/tests/auto/testlib/selftests/tst_selftests.cpp b/tests/auto/testlib/selftests/tst_selftests.cpp index e8d6fe228b..331ae48135 100644 --- a/tests/auto/testlib/selftests/tst_selftests.cpp +++ b/tests/auto/testlib/selftests/tst_selftests.cpp @@ -439,7 +439,6 @@ void tst_Selftests::runSubTest_data() QTest::addColumn<bool>("crashes"); QStringList tests = QStringList() -// << "alive" // timer dependent #if !defined(Q_OS_WIN) // On windows, assert does nothing in release mode and blocks execution // with a popup window in debug mode. @@ -488,6 +487,7 @@ void tst_Selftests::runSubTest_data() << "printdatatags" << "printdatatagswithglobaltags" << "qexecstringlist" + << "signaldumper" << "silent" << "singleskip" << "skip" @@ -553,6 +553,9 @@ void tst_Selftests::runSubTest_data() else if (subtest == "printdatatagswithglobaltags") { arguments << "-datatags"; } + else if (subtest == "signaldumper") { + arguments << "-vs"; + } else if (subtest == "silent") { arguments << "-silent"; } @@ -950,6 +953,29 @@ bool tst_Selftests::compareLine(const QString &logger, const QString &subdir, if (actualLine.startsWith(QLatin1String("Totals:")) && expectedLine.startsWith(QLatin1String("Totals:"))) return true; + const QLatin1String pointerPlaceholder("_POINTER_"); + if (expectedLine.contains(pointerPlaceholder) + && (expectedLine.contains(QLatin1String("Signal: ")) + || expectedLine.contains(QLatin1String("Slot: ")))) { + QString actual = actualLine; + // We don't care about the pointer of the object to whom the signal belongs, so we + // replace it with _POINTER_, e.g.: + // Signal: SignalSlotClass(7ffd72245410) signalWithoutParameters () + // Signal: QThread(7ffd72245410) started () + // After this instance pointer we may have further pointers and + // references (with an @ prefix) as parameters of the signal or + // slot being invoked. + // Signal: SignalSlotClass(_POINTER_) qStringRefSignal ((QString&)@55f5fbb8dd40) + actual.replace(QRegularExpression("\\b[a-f0-9]{8,}\\b"), pointerPlaceholder); + // Also change QEventDispatcher{Glib,Win32,etc.} to QEventDispatcherPlatform + actual.replace(QRegularExpression("\\b(QEventDispatcher)\\w+\\b"), QLatin1String("\\1Platform")); + if (actual != expectedLine) { + *errorMessage = msgMismatch(actual, expectedLine); + return false; + } + return true; + } + *errorMessage = msgMismatch(actualLine, expectedLine); return false; } diff --git a/tests/auto/testlib/testlib.pro b/tests/auto/testlib/testlib.pro index 587c76a189..55f1f9b87b 100644 --- a/tests/auto/testlib/testlib.pro +++ b/tests/auto/testlib/testlib.pro @@ -1,5 +1,6 @@ TEMPLATE = subdirs SUBDIRS = \ + initmain \ outformat \ qsignalspy \ selftests \ diff --git a/tests/auto/testserver.pri b/tests/auto/testserver.pri deleted file mode 100644 index 26e7f6ab8a..0000000000 --- a/tests/auto/testserver.pri +++ /dev/null @@ -1,216 +0,0 @@ -# Integrating docker-based test servers into Qt Test framework -# -# This file adds support for docker-based test servers built by testcase -# projects that need them. To enable this feature, any automated test can -# include testserver.pri in its project file. This instructs qmake to insert -# additional targets into the generated Makefile. The 'check' target then brings -# up test servers before running the testcase, and shuts them down afterwards. -# -# TESTSERVER_COMPOSE_FILE -# - Contains the path of docker-compose file -# This configuration file defines the services used for autotests. It tells the -# docker engine how to build up the docker images and containers. In qtbase, a -# shared docker-compose file is located in the tests folder. -# Example: TESTSERVER_COMPOSE_FILE = \ -# $$dirname(_QMAKE_CONF_)/tests/testserver/docker-compose.yml -# -# The user must run the provisioning scripts in advance before attempting to -# build the test servers. The docker_testserver.sh script is used to build up -# the docker images into the docker-cache. It handles the immutable parts of the -# server installation that rarely need adjustment, such as downloading packages. -# Example: qt5/coin/provisioning/.../testserver/docker_testserver.sh -# -# QT_TEST_SERVER_LIST -# - A list of test servers to bring up for this testcase -# These test servers should be defined in $$TESTSERVER_COMPOSE_FILE. Each -# testcase can define the test servers it depends on. -# Example: QT_TEST_SERVER_LIST = apache2 squid vsftpd ftp-proxy danted -# -# Pre-processor defines needed for the application: -# QT_TEST_SERVER -# - A preprocessor macro used for testcase to change testing parameters at -# compile time -# This macro is predefined for docker-based test servers and is passed as a -# compiler option (-DQT_TEST_SERVER). The testcase can then check whether -# docker-based servers are in use and change the testing parameters, such as -# host name or port number, at compile time. An example can be found in -# network-settings.h. -# -# Example: -# #if defined(QT_TEST_SERVER) -# Change the testing parameters at compile time -# #endif -# -# QT_TEST_SERVER_DOMAIN -# - A preprocessor macro that holds the server domain name -# Provided for the helper functions in network-settings.h. Use function -# serverDomainName() in your application instead. -# -# Additional make targets: -# 1. check_network - A renamed target from the check target of testcase feature. -# 2. testserver_clean - Clean up server containers/images and tidy away related -# files. - -# The docker test server should only be integrated in the leaf Makefile. -# If debug_and_release option is in use, skip the meta-Makefile except for -# Makefile.Debug and Makefile.Release. -debug_and_release:!build_pass: return() - -DOCKER_ENABLED = 1 - -equals(QMAKE_HOST.os, Darwin) { - DOCKER_ENABLED = 0 - message("Not using docker network test server on macOS, see QTQAINFRA-2717 and QTQAINFRA-2750") -} - -TESTSERVER_VERSION = "" - -equals(DOCKER_ENABLED, 1) { - TESTSERVER_VERSION = $$system(docker-compose --version) -} - -isEmpty(TESTSERVER_VERSION) { - # Make check with server "qt-test-server.qt-test-net" as a fallback -} else { - # Make check with docker test servers - equals(QMAKE_HOST.os, Linux) { - # For the platform supporting docker bridge network, each container is - # assigned a unique hostname and connected to the same network domain - # to communicate with the others. - DEFINES += QT_TEST_SERVER_NAME - DNSDOMAIN = test-net.qt.local - } else { - # For the others, the containers are deployed into a virtual machine - # using the host network. All the containers share the same hostname of - # the virtual machine, and they are connected to the same network domain. - # NOTE: In Windows, Apple Bonjour only works within a single local domain. - DNSDOMAIN = local - } - - equals(QMAKE_HOST.os, Darwin) { - # There is no docker bridge on macOS. It is impossible to ping a container. - # Docker docs recommends using port mapping to connect to a container; - # but it causes a port conflict if the user is running a service that - # binds the same port on the host. An alternative solution is to deploy - # the docker environment into VirtualBox using docker-machine. - TESTSERVER_COMPOSE_FILE = \ - $$dirname(_QMAKE_CONF_)/tests/testserver/docker-compose-for-macOS.yml - - # The connection configuration for the target machine - MACHINE_CONFIG = $(shell docker-machine config qt-test-server) - - # The environment variables passed to the docker-compose file - TEST_ENV = 'MACHINE_IP=$(shell docker-machine ip qt-test-server)' - TEST_ENV += 'TEST_DOMAIN=$$DNSDOMAIN' - TEST_CMD = env - } else:equals(QMAKE_HOST.os, Windows) { - # There is no docker bridge on Windows. It is impossible to ping a container. - # Use docker-machine to deploy the docker environment into VirtualBox. - TESTSERVER_COMPOSE_FILE = \ - $$dirname(_QMAKE_CONF_)/tests/testserver/docker-compose-for-windows.yml - - # The connection configuration for the target machine - MACHINE_CONFIG = (docker-machine config qt-test-server) - - # The environment variables passed to the docker-compose file - TEST_ENV = '\$\$env:MACHINE_IP = docker-machine ip qt-test-server;' - TEST_ENV += '\$\$env:TEST_DOMAIN = $$shell_quote(\"$$DNSDOMAIN\");' - - # Docker-compose CLI environment variables: - # Enable path conversion from Windows-style to Unix-style in volume definitions. - TEST_ENV += '\$\$env:COMPOSE_CONVERT_WINDOWS_PATHS = $$shell_quote(\"true\");' - - TEST_CMD = 'PowerShell -noprofile' - CONFIG += PowerShell - } else { - TESTSERVER_COMPOSE_FILE = $$dirname(_QMAKE_CONF_)/tests/testserver/docker-compose.yml - - # The environment variables passed to the docker-compose file - TEST_ENV = 'TEST_DOMAIN=$$DNSDOMAIN' - TEST_CMD = env - } - - # The domain name is relevant to https keycert (qnetworkreply/crts/qt-test-net-cacert.pem). - DEFINES += QT_TEST_SERVER QT_TEST_SERVER_DOMAIN=$$shell_quote(\"$${DNSDOMAIN}\") - - # Ensure that the docker-compose file is provided. It is a configuration - # file which is mandatory for all docker-compose commands. You can get more - # detail from the description of TESTSERVER_COMPOSE_FILE above. There is - # also an example showing how to configure it manually. - FILE_PRETEST_MSG = "Project variable 'TESTSERVER_COMPOSE_FILE' is not set" - PowerShell { - testserver_pretest.commands = echo $$TESTSERVER_VERSION && - testserver_pretest.commands += \ - $$TEST_CMD if ([String]::IsNullOrEmpty($$shell_quote(\"$$TESTSERVER_COMPOSE_FILE\"))) \ - {Write-Error $$shell_quote(\"$$FILE_PRETEST_MSG\")} && - } else { - testserver_pretest.commands = $(info "testserver:" $$TESTSERVER_VERSION) - testserver_pretest.commands += $(if $$TESTSERVER_COMPOSE_FILE,,$(error $$FILE_PRETEST_MSG)) - } - - # Make sure docker-machine is both created and running. The docker_machine - # script is used to deploy the docker environment into VirtualBox. - # Example: qt5/coin/provisioning/common/shared/testserver/docker_machine.sh - !isEmpty(MACHINE_CONFIG) { - MACHINE_LIST_CMD = docker-machine ls -q --filter "Name=^qt-test-server\$\$" - MACHINE_LIST_MSG = "Docker machine qt-test-server not found" - PowerShell { - testserver_pretest.commands += $$TEST_CMD if (!($$MACHINE_LIST_CMD)) \ - {Write-Error $$shell_quote(\"$$MACHINE_LIST_MSG\")} && - } else { - testserver_pretest.commands += \ - $(if $(shell $$MACHINE_LIST_CMD),,$(error $$MACHINE_LIST_MSG)) - } - - MACHINE_STATE_CMD = \ - docker-machine ls -q --filter "State=Running" --filter "Name=^qt-test-server\$\$" - MACHINE_START_CMD = docker-machine start qt-test-server - MACHINE_RECERT = docker-machine regenerate-certs -f qt-test-server - PowerShell { - testserver_pretest.commands += \ - $$TEST_CMD if (!($$MACHINE_STATE_CMD)) {$$MACHINE_START_CMD; $$MACHINE_RECERT} && - } else { - testserver_pretest.commands += \ - $(if $(shell $$MACHINE_STATE_CMD),,\ - $(shell $$MACHINE_START_CMD > /dev/null && $$MACHINE_RECERT > /dev/null)) - } - } - - # Before starting the test servers, it requires the user to run the setup - # script (coin/provisioning/.../testserver/docker_testserver.sh) in advance. - IMAGE_PRETEST_CMD = docker $$MACHINE_CONFIG images -aq "qt-test-server-*" - IMAGE_PRETEST_MSG = "Docker image qt-test-server-* not found" - PowerShell { - testserver_pretest.commands += $$TEST_CMD if (!($$IMAGE_PRETEST_CMD)) \ - {Write-Error $$shell_quote(\"$$IMAGE_PRETEST_MSG\")} - } else { - testserver_pretest.commands += \ - $(if $(shell $$IMAGE_PRETEST_CMD),,$(error $$IMAGE_PRETEST_MSG)) - } - - # Rename the check target of testcase feature - check.target = check_network - testserver_test.target = check - - # Pretesting test servers environment - testserver_test.depends = testserver_pretest - - # Bring up test servers and make sure the services are ready. - !isEmpty(TEST_CMD): testserver_test.commands = $$TEST_CMD $$TEST_ENV - testserver_test.commands += docker-compose $$MACHINE_CONFIG -f $$TESTSERVER_COMPOSE_FILE up \ - --detach --force-recreate --timeout 1 $${QT_TEST_SERVER_LIST} && - - # Check test cases with docker-based test servers. - testserver_test.commands += $(MAKE) -f $(MAKEFILE) check_network && - - # Stop and remove test servers after testing. - !isEmpty(TEST_CMD): testserver_test.commands += $$TEST_CMD $$TEST_ENV - testserver_test.commands += docker-compose $$MACHINE_CONFIG -f $$TESTSERVER_COMPOSE_FILE down \ - --timeout 1 - - # Destroy test servers and tidy away related files. - testserver_clean.commands = docker-compose $$MACHINE_CONFIG -f $$TESTSERVER_COMPOSE_FILE down \ - --rmi all - - QMAKE_EXTRA_TARGETS += testserver_pretest testserver_test testserver_clean -} diff --git a/tests/auto/tools/moc/cxx-attributes.h b/tests/auto/tools/moc/cxx-attributes.h new file mode 100644 index 0000000000..eff6a3ec41 --- /dev/null +++ b/tests/auto/tools/moc/cxx-attributes.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CXXATTRIBUTE_H +#define CXXATTRIBUTE_H + +#include <QtCore/QObject> + +class CppAttribute : public QObject +{ + Q_OBJECT +signals: + [[deprecated]] void deprecatedSignal(); + +public slots: + [[deprecated]] void deprecatedSlot() {} + [[deprecated]] [[tst_moc::maybe_unused]] int deprecatedSlot2() { return 42; } + [[deprecated("reason")]] void deprecatedReason() {} + [[deprecated("reason[")]] void deprecatedReasonWithLBRACK() {} + [[deprecated("reason[[")]] void deprecatedReasonWith2LBRACK() {} + [[deprecated("reason]")]] void deprecatedReasonWithRBRACK() {} + [[deprecated("reason]]")]] void deprecatedReasonWith2RBRACK() {} + void slotWithArguments([[tst_moc::maybe_unused]] int) {} +#if !defined(_MSC_VER) || _MSC_VER >= 1912 + // On MSVC it causes: + // moc_cxx-attributes.cpp(133): fatal error C1001: An internal error has occurred in the compiler. + Q_INVOKABLE [[tst_moc::noreturn]] void noreturnSlot() { throw "unused"; } + [[tst_moc::noreturn]] Q_SCRIPTABLE void noreturnSlot2() { throw "unused"; } + [[deprecated]] int returnInt() { return 0; } + Q_SLOT [[tst_moc::noreturn]] [[deprecated]] void noreturnDeprecatedSlot() { throw "unused"; } + Q_INVOKABLE void noreturnSlot3() [[tst_moc::noreturn]] { throw "unused"; } +#endif +}; + +#ifdef Q_MOC_RUN +# define TEST_COMPILER_DEPRECATION [[deprecated]] +# define TEST_COMPILER_DEPRECATION_X(x) [[deprecated(x)]] +#else +# define TEST_COMPILER_DEPRECATION Q_DECL_ENUMERATOR_DEPRECATED +# define TEST_COMPILER_DEPRECATION_X(x) Q_DECL_ENUMERATOR_DEPRECATED_X(x) +#endif + +namespace TestQNamespaceDeprecated { + Q_NAMESPACE + enum class TestEnum1 { + Key1 = 11, + Key2 TEST_COMPILER_DEPRECATION, + Key3 TEST_COMPILER_DEPRECATION_X("reason"), + Key4 TEST_COMPILER_DEPRECATION_X("reason["), + Key5 TEST_COMPILER_DEPRECATION_X("reason[["), + Key6 TEST_COMPILER_DEPRECATION_X("reason]"), + Key7 TEST_COMPILER_DEPRECATION_X("reason]]"), + }; + Q_ENUM_NS(TestEnum1) + + // try to dizzy moc by adding a struct in between + struct TestGadget { + Q_GADGET + public: + enum class TestGEnum1 { + Key1 = 13, + Key2 TEST_COMPILER_DEPRECATION, + Key3 TEST_COMPILER_DEPRECATION_X("reason") + }; + Q_ENUM(TestGEnum1) + }; + + enum class TestFlag1 { + None = 0, + Flag1 = 1, + Flag2 TEST_COMPILER_DEPRECATION = 2, + Flag3 TEST_COMPILER_DEPRECATION_X("reason") = 3, + Any = Flag1 | Flag2 | Flag3 + }; + Q_FLAG_NS(TestFlag1) +} + +#endif // CXXATTRIBUTE_H diff --git a/tests/auto/tools/moc/cxx11-enums.h b/tests/auto/tools/moc/cxx11-enums.h index cc14c0acda..d5bd228f12 100644 --- a/tests/auto/tools/moc/cxx11-enums.h +++ b/tests/auto/tools/moc/cxx11-enums.h @@ -30,7 +30,6 @@ #define CXX11_ENUMS_H #include <QtCore/QObject> -#if defined(Q_COMPILER_CLASS_ENUM) || defined(Q_MOC_RUN) class CXX11Enums { Q_GADGET @@ -73,21 +72,4 @@ public: Q_FLAGS(ClassFlags) }; -#else -//workaround to get the moc compiled code to compile -class CXX11Enums -{ - Q_GADGET -public: - struct EnumClass { enum { A0, A1, A2, A3 }; }; - struct TypedEnumClass { enum { C0, C1, C2, C3 }; }; - enum NormalEnum { D2 = 2, D3, D0 =0 , D1 }; - enum TypedEnum { B0, B1 , B2, B3 }; -}; - -class CXX11Enums2 : public CXX11Enums -{ - Q_GADGET -}; -#endif #endif // CXX11_ENUMS_H diff --git a/tests/auto/tools/moc/moc.pro b/tests/auto/tools/moc/moc.pro index 3cbc9ebb5e..ad8c093add 100644 --- a/tests/auto/tools/moc/moc.pro +++ b/tests/auto/tools/moc/moc.pro @@ -29,7 +29,8 @@ HEADERS += using-namespaces.h no-keywords.h task87883.h c-comments.h backslash-n non-gadget-parent-class.h grand-parent-gadget-class.h \ related-metaobjects-in-gadget.h \ related-metaobjects-name-conflict.h \ - namespace.h cxx17-namespaces.h + namespace.h cxx17-namespaces.h \ + cxx-attributes.h if(*-g++*|*-icc*|*-clang*|*-llvm):!win32-*: HEADERS += os9-newlines.h win-newlines.h diff --git a/tests/auto/tools/moc/parse-defines.h b/tests/auto/tools/moc/parse-defines.h index 7b0fa29d7c..bd22b0b9af 100644 --- a/tests/auto/tools/moc/parse-defines.h +++ b/tests/auto/tools/moc/parse-defines.h @@ -51,7 +51,6 @@ #define PD_CLASSINFO Q_CLASSINFO -#if defined(Q_COMPILER_VARIADIC_MACROS) || defined (Q_MOC_RUN) #define PD_VARARG(x, ...) x(__VA_ARGS__) #if defined(Q_CC_GNU) || defined(Q_MOC_RUN) @@ -61,7 +60,6 @@ #define PD_VARARGEXT(x, ...) x(__VA_ARGS__) #endif -#endif #define PD_ADD_SUFFIX(x) PD_DEFINE1(x,_SUFFIX) #define PD_DEFINE_ITSELF PD_ADD_SUFFIX(PD_DEFINE_ITSELF) @@ -100,7 +98,6 @@ public slots: PD_TEST_IDENTIFIER_ARG(void, combined6()) {} -#if defined(Q_COMPILER_VARIADIC_MACROS) || defined (Q_MOC_RUN) PD_VARARG(void vararg1) {} PD_VARARG(void vararg2, int) {} PD_VARARG(void vararg3, int, int) {} @@ -108,14 +105,6 @@ public slots: PD_VARARGEXT(void vararg4) {} PD_VARARGEXT(void vararg5, int) {} PD_VARARGEXT(void vararg6, int, int) {} -#else - void vararg1() {} - void vararg2(int) {} - void vararg3(int,int) {} - void vararg4() {} - void vararg5(int) {} - void vararg6(int,int) {} -#endif #define OUTERFUNCTION(x) x #define INNERFUNCTION(x) OUTERFUNCTION(x) diff --git a/tests/auto/tools/moc/tst_moc.cpp b/tests/auto/tools/moc/tst_moc.cpp index 50321c322b..89f563f11d 100644 --- a/tests/auto/tools/moc/tst_moc.cpp +++ b/tests/auto/tools/moc/tst_moc.cpp @@ -71,6 +71,7 @@ #include "grand-parent-gadget-class.h" #include "namespace.h" #include "cxx17-namespaces.h" +#include "cxx-attributes.h" #ifdef Q_MOC_RUN // check that moc can parse these constructs, they are being used in Windows winsock2.h header @@ -148,6 +149,17 @@ namespace TestQNamespace { Q_FLAG_NS(TestFlag2) } + +#define TESTEXPORTMACRO Q_DECL_EXPORT + +namespace TestExportNamespace { + Q_NAMESPACE_EXPORT(TESTEXPORTMACRO) + enum class MyEnum { + Key1, Key2 + }; + Q_ENUM_NS(MyEnum) +} + QT_USE_NAMESPACE template <bool b> struct QTBUG_31218 {}; @@ -704,6 +716,7 @@ private slots: void optionsFileError(); void testQNamespace(); void cxx17Namespaces(); + void cxxAttributes(); signals: void sigWithUnsignedArg(unsigned foo); @@ -1040,7 +1053,7 @@ void tst_Moc::testExtraDataForEnum() const QMetaObject *mobjUser = &EnumUserClass::staticMetaObject; QCOMPARE(mobjUser->enumeratorCount(), 0); - const QMetaObject * const *objects = mobjUser->d.relatedMetaObjects; + const auto *objects = mobjUser->d.relatedMetaObjects; QVERIFY(objects); QCOMPARE(objects[0], mobjSource); QVERIFY(!objects[1]); @@ -1424,6 +1437,16 @@ void tst_Moc::environmentIncludePaths() // plugin_metadata.h contains a plugin which we register here. Since we're not building this // application as a plugin, we need top copy some of the initializer code found in qplugin.h: extern "C" QObject *qt_plugin_instance(); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +extern "C" QPluginMetaData qt_plugin_query_metadata(); +class StaticPluginInstance{ +public: + StaticPluginInstance() { + QStaticPlugin plugin(qt_plugin_instance, qt_plugin_query_metadata); + qRegisterStaticPluginFunction(plugin); + } +}; +#else extern "C" const char *qt_plugin_query_metadata(); class StaticPluginInstance{ public: @@ -1432,6 +1455,7 @@ public: qRegisterStaticPluginFunction(plugin); } }; +#endif static StaticPluginInstance staticInstance; void tst_Moc::specifyMetaTagsFromCmdline() { @@ -3555,10 +3579,9 @@ namespace QTBUG32933_relatedObjectsDontIncludeItself { void tst_Moc::QTBUG32933_relatedObjectsDontIncludeItself() { const QMetaObject *mo = &QTBUG32933_relatedObjectsDontIncludeItself::NS::Obj::staticMetaObject; - const QMetaObject * const *objects = mo->d.relatedMetaObjects; + const auto *objects = mo->d.relatedMetaObjects; // the related objects should be empty because the enums is in the same object. QVERIFY(!objects); - } class UnrelatedClass : public QObject @@ -3664,7 +3687,7 @@ void tst_Moc::relatedMetaObjectsNameConflict() // load all specified metaobjects int a set QSet<const QMetaObject*> dependency; - const QMetaObject *const *i = dependingObject->d.relatedMetaObjects; + const auto *i = dependingObject->d.relatedMetaObjects; while (*i) { dependency.insert(*i); ++i; @@ -3848,6 +3871,14 @@ static void checkEnum(const QMetaEnum &enumerator, const QByteArray &name, const } } +class EnumFromNamespaceClass : public QObject +{ + Q_OBJECT + Q_PROPERTY(FooNamespace::Enum1 prop READ prop CONSTANT) +public: + FooNamespace::Enum1 prop() { return FooNamespace::Enum1::Key2; } +}; + void tst_Moc::testQNamespace() { QCOMPARE(TestQNamespace::staticMetaObject.enumeratorCount(), 4); @@ -3872,9 +3903,18 @@ void tst_Moc::testQNamespace() QCOMPARE(meta.enclosingMetaObject(), &TestQNamespace::staticMetaObject); QCOMPARE(meta.keyCount(), 2); + QCOMPARE(TestExportNamespace::staticMetaObject.enumeratorCount(), 1); + checkEnum(TestExportNamespace::staticMetaObject.enumerator(0), "MyEnum", + {{"Key1", 0}, {"Key2", 1}}); + QCOMPARE(FooNamespace::staticMetaObject.enumeratorCount(), 1); QCOMPARE(FooNamespace::FooNestedNamespace::staticMetaObject.enumeratorCount(), 2); QCOMPARE(FooNamespace::FooNestedNamespace::FooMoreNestedNamespace::staticMetaObject.enumeratorCount(), 1); + + EnumFromNamespaceClass obj; + const QVariant prop = obj.property("prop"); + QCOMPARE(prop.type(), QMetaType::Int); + QCOMPARE(prop.toInt(), int(FooNamespace::Enum1::Key2)); } void tst_Moc::cxx17Namespaces() @@ -3896,6 +3936,41 @@ void tst_Moc::cxx17Namespaces() QCOMPARE(QMetaEnum::fromType<CXX17Namespace::A::B::C::D::ClassInNamespace::GadEn>().value(0), 3); } +void tst_Moc::cxxAttributes() +{ + auto so = CppAttribute::staticMetaObject; + QCOMPARE(so.className(), "CppAttribute"); + QCOMPARE(so.enumeratorCount(), 0); + QVERIFY(so.indexOfSignal("deprecatedSignal") != 1); + for (auto a: {"deprecatedSlot", "deprecatedSlot2", "deprecatedReason", "deprecatedReasonWithLBRACK", + "deprecatedReasonWith2LBRACK", "deprecatedReasonWithRBRACK", "deprecatedReasonWith2RBRACK", + "slotWithArguments" +#if !defined(_MSC_VER) || _MSC_VER >= 1912 + , "noreturnSlot", "noreturnSlot2", "returnInt", "noreturnDeprecatedSlot", + "noreturnSlot3" +#endif + }) { + QVERIFY(so.indexOfSlot(a) != 1); + } + + QCOMPARE(TestQNamespaceDeprecated::staticMetaObject.enumeratorCount(), 2); + checkEnum(TestQNamespaceDeprecated::staticMetaObject.enumerator(0), "TestEnum1", + {{"Key1", 11}, {"Key2", 12}, {"Key3", 13}, {"Key4", 14}, {"Key5", 15}, {"Key6", 16}, + {"Key7", 17}}); + checkEnum(TestQNamespaceDeprecated::staticMetaObject.enumerator(1), "TestFlag1", + {{"None", 0}, {"Flag1", 1}, {"Flag2", 2}, {"Flag3", 3}, {"Any", 1 | 2 | 3}}); + + QCOMPARE(TestQNamespaceDeprecated::TestGadget::staticMetaObject.enumeratorCount(), 1); + checkEnum(TestQNamespaceDeprecated::TestGadget::staticMetaObject.enumerator(0), "TestGEnum1", + {{"Key1", 13}, {"Key2", 14}, {"Key3", 15}}); + + QMetaEnum meta = QMetaEnum::fromType<TestQNamespaceDeprecated::TestEnum1>(); + QVERIFY(meta.isValid()); + QCOMPARE(meta.name(), "TestEnum1"); + QCOMPARE(meta.enclosingMetaObject(), &TestQNamespaceDeprecated::staticMetaObject); + QCOMPARE(meta.keyCount(), 7); +} + QTEST_MAIN(tst_Moc) // the generated code must compile with QT_NO_KEYWORDS diff --git a/tests/auto/tools/qmake/testcompiler.cpp b/tests/auto/tools/qmake/testcompiler.cpp index e769f955c4..8ab8d5d721 100644 --- a/tests/auto/tools/qmake/testcompiler.cpp +++ b/tests/auto/tools/qmake/testcompiler.cpp @@ -164,15 +164,17 @@ bool TestCompiler::runCommand(const QString &cmd, const QStringList &args, bool return errorOut(); } - child.setReadChannel(QProcess::StandardError); child.waitForFinished(-1); bool ok = child.exitStatus() == QProcess::NormalExit && (expectFail ^ (child.exitCode() == 0)); - foreach (const QByteArray &output, child.readAllStandardError().split('\n')) { - testOutput_.append(QString::fromLocal8Bit(output)); - - if (output.startsWith("Project MESSAGE: FAILED")) - ok = false; + for (auto channel : { QProcess::StandardOutput, QProcess::StandardError }) { + child.setReadChannel(channel); + while (!child.atEnd()) { + const QString output = QString::fromLocal8Bit(child.readLine()); + if (output.startsWith("Project MESSAGE: FAILED")) + ok = false; + testOutput_.append(output); + } } return ok ? true : errorOut(); @@ -292,8 +294,10 @@ bool TestCompiler::make( const QString &workPath, const QString &target, bool ex D.setCurrent( workPath ); QStringList args = makeArgs_; - if (makeCmd_.contains("nmake", Qt::CaseInsensitive)) + if (makeCmd_.contains("nmake", Qt::CaseInsensitive) || + makeCmd_.contains("jom", Qt::CaseInsensitive)) { args << "/NOLOGO"; + } if (!target.isEmpty()) args << target; diff --git a/tests/auto/tools/qmake/testcompiler.h b/tests/auto/tools/qmake/testcompiler.h index e22a2c6c3d..d80cd8d53a 100644 --- a/tests/auto/tools/qmake/testcompiler.h +++ b/tests/auto/tools/qmake/testcompiler.h @@ -73,13 +73,17 @@ public: bool removeProject( const QString &workPath, const QString &project ); // removes the file specified by 'fileName' on the 'workPath' bool removeFile( const QString &workPath, const QString &fileName ); - // returns each line of stdout of the last command append with a "new line" character(s) to suit the platform + + // Returns each line of stdout/stderr of the last commands + // separated by platform-specific line endings. QString commandOutput() const; + // clear the results of storage of stdout for running previous commands void clearCommandOutput(); -private: bool runCommand(const QString &cmd, const QStringList &args, bool expectFail = false); + +private: bool errorOut(); QString makeCmd_; diff --git a/tests/auto/tools/qmake/testdata/conflicting_targets/conflicting_targets.pro b/tests/auto/tools/qmake/testdata/conflicting_targets/conflicting_targets.pro new file mode 100644 index 0000000000..bd0d4d824a --- /dev/null +++ b/tests/auto/tools/qmake/testdata/conflicting_targets/conflicting_targets.pro @@ -0,0 +1,5 @@ +TEMPLATE = app +CONFIG += debug_and_release build_all +TARGET = bah +DESTDIR = shu +SOURCES += main.cpp diff --git a/tests/auto/tools/qmake/testdata/conflicting_targets/main.cpp b/tests/auto/tools/qmake/testdata/conflicting_targets/main.cpp new file mode 100644 index 0000000000..39de28135a --- /dev/null +++ b/tests/auto/tools/qmake/testdata/conflicting_targets/main.cpp @@ -0,0 +1,4 @@ +int main(int, char **) +{ + return 0; +} diff --git a/tests/auto/tools/qmake/testdata/windows_resources/inter.inc b/tests/auto/tools/qmake/testdata/windows_resources/inter.inc new file mode 100644 index 0000000000..0c2594214e --- /dev/null +++ b/tests/auto/tools/qmake/testdata/windows_resources/inter.inc @@ -0,0 +1 @@ +#include "version.inc" diff --git a/tests/auto/tools/qmake/testdata/windows_resources/main.cpp b/tests/auto/tools/qmake/testdata/windows_resources/main.cpp new file mode 100644 index 0000000000..237c8ce181 --- /dev/null +++ b/tests/auto/tools/qmake/testdata/windows_resources/main.cpp @@ -0,0 +1 @@ +int main() {} diff --git a/tests/auto/tools/qmake/testdata/windows_resources/version.inc b/tests/auto/tools/qmake/testdata/windows_resources/version.inc new file mode 100644 index 0000000000..b797c9acce --- /dev/null +++ b/tests/auto/tools/qmake/testdata/windows_resources/version.inc @@ -0,0 +1,28 @@ +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGS 0x0L + FILEFLAGSMASK 0x3fL + FILEOS 0x00040004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "CompanyName", "The Qt Company Ltd" + VALUE "FileDescription", "A Good File" + VALUE "FileVersion", "1.0.0.0" + VALUE "LegalCopyright", "Copyright (C) 2019 The Qt Company Ltd." + VALUE "InternalName", "foo" + VALUE "OriginalFilename", "foo.exe" + VALUE "ProductName", "A Good Product" + VALUE "ProductVersion", "1.0.0.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END diff --git a/tests/auto/tools/qmake/testdata/windows_resources/windows_resources.pro b/tests/auto/tools/qmake/testdata/windows_resources/windows_resources.pro new file mode 100644 index 0000000000..80a5e5c19a --- /dev/null +++ b/tests/auto/tools/qmake/testdata/windows_resources/windows_resources.pro @@ -0,0 +1,4 @@ +QT = core +SOURCES = main.cpp +RC_FILE = windows_resources.rc +TEMPLATE = app diff --git a/tests/auto/tools/qmake/testdata/windows_resources/windows_resources.rc b/tests/auto/tools/qmake/testdata/windows_resources/windows_resources.rc new file mode 100644 index 0000000000..4df652de35 --- /dev/null +++ b/tests/auto/tools/qmake/testdata/windows_resources/windows_resources.rc @@ -0,0 +1,2 @@ +#include "winver.h" +#include "inter.inc" diff --git a/tests/auto/tools/qmake/tst_qmake.cpp b/tests/auto/tools/qmake/tst_qmake.cpp index 09e725f98a..9b434a7b5b 100644 --- a/tests/auto/tools/qmake/tst_qmake.cpp +++ b/tests/auto/tools/qmake/tst_qmake.cpp @@ -33,6 +33,7 @@ #include <QDir> #include <QDirIterator> #include <QObject> +#include <QRegularExpression> #include <QStandardPaths> #include <QTemporaryDir> @@ -75,14 +76,17 @@ private slots: void findMocs(); void findDeps(); void rawString(); -#if defined(Q_OS_MAC) +#if defined(Q_OS_DARWIN) void bundle_spaces(); +#elif defined(Q_OS_WIN) + void windowsResources(); #endif void substitutes(); void project(); void proFileCache(); void qinstall(); void resources(); + void conflictingTargets(); private: TestCompiler test_compiler; @@ -423,7 +427,7 @@ void tst_qmake::prompt() { #if 0 QProcess qmake; - qmake.setReadChannelMode(QProcess::MergedChannels); + qmake.setProcessChannelMode(QProcess::MergedChannels); qmake.setWorkingDirectory(QLatin1String("testdata/prompt")); qmake.start(QLatin1String("qmake CONFIG-=debug_and_release CONFIG-=debug CONFIG+=release"), QIODevice::Text | QIODevice::ReadWrite); @@ -511,7 +515,8 @@ struct TempFile } }; -#if defined(Q_OS_MAC) +#if defined(Q_OS_DARWIN) + void tst_qmake::bundle_spaces() { QString workDir = base_path + "/testdata/bundle-spaces"; @@ -542,7 +547,34 @@ void tst_qmake::bundle_spaces() QVERIFY( !non_existing_file.exists() ); QVERIFY( test_compiler.removeMakefile(workDir) ); } -#endif // defined(Q_OS_MAC) + +#elif defined(Q_OS_WIN) // defined(Q_OS_DARWIN) + +void tst_qmake::windowsResources() +{ + QString workDir = base_path + "/testdata/windows_resources"; + QVERIFY(test_compiler.qmake(workDir, "windows_resources")); + QVERIFY(test_compiler.make(workDir)); + + // Another "make" must not rebuild the .res file + test_compiler.clearCommandOutput(); + QVERIFY(test_compiler.make(workDir)); + QVERIFY(!test_compiler.commandOutput().contains("windows_resources.rc")); + test_compiler.clearCommandOutput(); + + // Wait a second to make sure we get a new timestamp in the touch below + QTest::qWait(1000); + + // Touch the deepest include of the .rc file + QVERIFY(test_compiler.runCommand("cmd", QStringList{"/c", + "echo.>>" + QDir::toNativeSeparators(workDir + "/version.inc")})); + + // The next "make" must rebuild the .res file + QVERIFY(test_compiler.make(workDir)); + QVERIFY(test_compiler.commandOutput().contains("windows_resources.rc")); +} + +#endif // defined(Q_OS_WIN) void tst_qmake::substitutes() { @@ -717,5 +749,18 @@ void tst_qmake::resources() QVERIFY(test_compiler.make(workDir)); } +void tst_qmake::conflictingTargets() +{ + QString workDir = base_path + "/testdata/conflicting_targets"; + QVERIFY(test_compiler.qmake(workDir, "conflicting_targets")); + const QRegularExpression rex("Targets of builds '([^']+)' and '([^']+)' conflict"); + auto match = rex.match(test_compiler.commandOutput()); + QVERIFY(match.hasMatch()); + QStringList builds = { match.captured(1), match.captured(2) }; + std::sort(builds.begin(), builds.end()); + const QStringList expectedBuilds{"Debug", "Release"}; + QCOMPARE(builds, expectedBuilds); +} + QTEST_MAIN(tst_qmake) #include "tst_qmake.moc" diff --git a/tests/auto/tools/qmakelib/qmakelib.pro b/tests/auto/tools/qmakelib/qmakelib.pro index 29f17f6a14..5e9e9fe637 100644 --- a/tests/auto/tools/qmakelib/qmakelib.pro +++ b/tests/auto/tools/qmakelib/qmakelib.pro @@ -1,7 +1,7 @@ CONFIG += testcase TARGET = tst_qmakelib QT = core testlib -win32: LIBS += -ladvapi32 +win32: QMAKE_USE += advapi32 INCLUDEPATH += ../../../../qmake/library VPATH += ../../../../qmake/library diff --git a/tests/auto/tools/rcc/data/depfile/simple.d.expected b/tests/auto/tools/rcc/data/depfile/simple.d.expected new file mode 100644 index 0000000000..a89b61bdc7 --- /dev/null +++ b/tests/auto/tools/rcc/data/depfile/simple.d.expected @@ -0,0 +1 @@ +simple.qrc.cpp: ../images/images/circle.png ../images/images/square.png diff --git a/tests/auto/tools/rcc/data/depfile/simple.qrc b/tests/auto/tools/rcc/data/depfile/simple.qrc new file mode 100644 index 0000000000..521dc4d4a0 --- /dev/null +++ b/tests/auto/tools/rcc/data/depfile/simple.qrc @@ -0,0 +1,6 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file>../images/images/circle.png</file> + <file>../images/images/square.png</file> +</qresource> +</RCC> diff --git a/tests/auto/tools/rcc/data/depfile/specialchar$file.txt b/tests/auto/tools/rcc/data/depfile/specialchar$file.txt new file mode 100644 index 0000000000..5da849b5c6 --- /dev/null +++ b/tests/auto/tools/rcc/data/depfile/specialchar$file.txt @@ -0,0 +1 @@ +ABC diff --git a/tests/auto/tools/rcc/data/depfile/specialchar.d.expected b/tests/auto/tools/rcc/data/depfile/specialchar.d.expected new file mode 100644 index 0000000000..9dd1af0958 --- /dev/null +++ b/tests/auto/tools/rcc/data/depfile/specialchar.d.expected @@ -0,0 +1 @@ +specialchar.qrc.cpp: specialchar$$file.txt ../images/images/subdir/triangle.png diff --git a/tests/auto/tools/rcc/data/depfile/specialchar.qrc b/tests/auto/tools/rcc/data/depfile/specialchar.qrc new file mode 100644 index 0000000000..133cbc7655 --- /dev/null +++ b/tests/auto/tools/rcc/data/depfile/specialchar.qrc @@ -0,0 +1,6 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file>../images/images/subdir/triangle.png</file> + <file>specialchar$file.txt</file> +</qresource> +</RCC> diff --git a/tests/auto/tools/rcc/data/sizes/size-2-0-35-1_python.expected b/tests/auto/tools/rcc/data/sizes/size-2-0-35-1_python.expected new file mode 100644 index 0000000000..9dcd131af5 --- /dev/null +++ b/tests/auto/tools/rcc/data/sizes/size-2-0-35-1_python.expected @@ -0,0 +1,68 @@ +# Resource object code (Python 3) +# Created by: object code +# Created by: The Resource Compiler for Qt version 5.14.0 +# WARNING! All changes made in this file will be lost! + +from PySide2 import QtCore + +qt_resource_data = b"\ +\x00\x00\x00\x02\ +0\ +1\ +\x00\x00\x00#\ +0\ +123456789 012345\ +6789 0123456789 \ +12\ +\x00\x00\x00\x01\ +@\ +\ +\x00\x00\x00\x00\ +\ +" + +qt_resource_name = b"\ +\x00\x04\ +\x00\x06\xa8\xa1\ +\x00d\ +\x00a\x00t\x00a\ +\x00\x0a\ +\x04\x08\x0a\xb4\ +\x00d\ +\x00a\x00t\x00a\x00-\x002\x00.\x00t\x00x\x00t\ +\x00\x0b\ +\x00\xb5Ot\ +\x00d\ +\x00a\x00t\x00a\x00-\x003\x005\x00.\x00t\x00x\x00t\ +\x00\x0a\ +\x04\x11\x0a\xb4\ +\x00d\ +\x00a\x00t\x00a\x00-\x001\x00.\x00t\x00x\x00t\ +\x00\x0a\ +\x04\x0e\x0a\xb4\ +\x00d\ +\x00a\x00t\x00a\x00-\x000\x00.\x00t\x00x\x00t\ +" + +qt_resource_struct = b"\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\ +\x00\x00\x00\x00\x00\x00\x00\x00\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x04\x00\x00\x00\x02\ +\x00\x00\x00\x00\x00\x00\x00\x00\ +\x00\x00\x00(\x00\x00\x00\x00\x00\x01\x00\x00\x00\x06\ +IGNORE: (time stamp) +\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ +IGNORE: (time stamp) +\x00\x00\x00^\x00\x00\x00\x00\x00\x01\x00\x00\x002\ +IGNORE: (time stamp) +\x00\x00\x00D\x00\x00\x00\x00\x00\x01\x00\x00\x00-\ +IGNORE: (time stamp) +" + +def qInitResources(): + QtCore.qRegisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data) + +def qCleanupResources(): + QtCore.qUnregisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data) + +qInitResources() diff --git a/tests/auto/tools/rcc/tst_rcc.cpp b/tests/auto/tools/rcc/tst_rcc.cpp index c810c6e364..42a4134e5f 100644 --- a/tests/auto/tools/rcc/tst_rcc.cpp +++ b/tests/auto/tools/rcc/tst_rcc.cpp @@ -46,6 +46,33 @@ typedef QMap<QString, QString> QStringMap; Q_DECLARE_METATYPE(QStringMap) +static QByteArray msgProcessStartFailed(const QProcess &p) +{ + const QString result = QLatin1String("Could not start \"") + + QDir::toNativeSeparators(p.program()) + QLatin1String("\": ") + + p.errorString(); + return result.toLocal8Bit(); +} + +static QByteArray msgProcessTimeout(const QProcess &p) +{ + return '"' + QDir::toNativeSeparators(p.program()).toLocal8Bit() + + "\" timed out."; +} + +static QByteArray msgProcessCrashed(QProcess &p) +{ + return '"' + QDir::toNativeSeparators(p.program()).toLocal8Bit() + + "\" crashed.\n" + p.readAllStandardError(); +} + +static QByteArray msgProcessFailed(QProcess &p) +{ + return '"' + QDir::toNativeSeparators(p.program()).toLocal8Bit() + + "\" returned " + QByteArray::number(p.exitCode()) + ":\n" + + p.readAllStandardError(); +} + class tst_rcc : public QObject { Q_OBJECT @@ -62,10 +89,16 @@ private slots: void readback_data(); void readback(); + void depFileGeneration_data(); + void depFileGeneration(); + + void python(); + void cleanupTestCase(); private: QString m_rcc; + QString m_dataPath; }; void tst_rcc::initTestCase() @@ -74,20 +107,19 @@ void tst_rcc::initTestCase() // we must force a certain hash order when testing or tst_rcc will fail, see QTBUG-25078 QVERIFY(qputenv("QT_RCC_TEST", "1")); m_rcc = QLibraryInfo::location(QLibraryInfo::BinariesPath) + QLatin1String("/rcc"); -} -QString findExpectedFile(const QString &base) -{ - QString expectedrccfile = base; + m_dataPath = QFINDTESTDATA("data"); + QVERIFY(!m_dataPath.isEmpty()); +} - // Must be updated with each minor release. - if (QFileInfo(expectedrccfile + QLatin1String(".450")).exists()) - expectedrccfile += QLatin1String(".450"); - return expectedrccfile; +static inline bool isPythonComment(const QString &line) +{ + return line.startsWith(QLatin1Char('#')); } -static QString doCompare(const QStringList &actual, const QStringList &expected) +static QString doCompare(const QStringList &actual, const QStringList &expected, + const QString &timeStampPath) { if (actual.size() != expected.size()) { return QString("Length count different: actual: %1, expected: %2") @@ -95,13 +127,21 @@ static QString doCompare(const QStringList &actual, const QStringList &expected) } QByteArray ba; + const bool isPython = isPythonComment(expected.constFirst()); for (int i = 0, n = expected.size(); i != n; ++i) { QString expectedLine = expected.at(i); if (expectedLine.startsWith("IGNORE:")) continue; + if (isPython && isPythonComment(expectedLine) && isPythonComment(actual.at(i))) + continue; if (expectedLine.startsWith("TIMESTAMP:")) { const QString relativePath = expectedLine.mid(strlen("TIMESTAMP:")); - const quint64 timeStamp = QFileInfo(relativePath).lastModified().toMSecsSinceEpoch(); + const QFileInfo fi(timeStampPath + QLatin1Char('/') + relativePath); + if (!fi.isFile()) { + ba.append("File " + fi.absoluteFilePath().toUtf8() + " does not exist!"); + break; + } + const quint64 timeStamp = quint64(fi.lastModified().toMSecsSinceEpoch()); expectedLine.clear(); for (int shift = 56; shift >= 0; shift -= 8) { expectedLine.append(QLatin1String("0x")); @@ -110,7 +150,7 @@ static QString doCompare(const QStringList &actual, const QStringList &expected) } } if (expectedLine != actual.at(i)) { - qDebug() << "LINES" << i << "DIFFER"; + qDebug() << "LINES" << (i + 1) << "DIFFER"; ba.append( "\n<<<<<< actual\n" + actual.at(i) + "\n======\n" + expectedLine + "\n>>>>>> expected\n" @@ -126,49 +166,53 @@ void tst_rcc::rcc_data() QTest::addColumn<QString>("qrcfile"); QTest::addColumn<QString>("expected"); - QString dataPath = QFINDTESTDATA("data/images/"); - if (dataPath.isEmpty()) - QFAIL("data path not found"); - QTest::newRow("images") << dataPath << "images.qrc" << "images.expected"; + const QString imagesPath = m_dataPath + QLatin1String("/images"); + QTest::newRow("images") << imagesPath << "images.qrc" << "images.expected"; - QString sizesPath = QFINDTESTDATA("data/sizes/"); - if (sizesPath.isEmpty()) - QFAIL("data path not found"); + const QString sizesPath = m_dataPath + QLatin1String("/sizes"); QTest::newRow("size-0") << sizesPath << "size-0.qrc" << "size-0.expected"; QTest::newRow("size-1") << sizesPath << "size-1.qrc" << "size-1.expected"; QTest::newRow("size-2-0-35-1") << sizesPath << "size-2-0-35-1.qrc" << "size-2-0-35-1.expected"; } +static QStringList readLinesFromFile(const QString &fileName, + QString::SplitBehavior splitBehavior) +{ + QFile file(fileName); + + bool ok = file.open(QIODevice::ReadOnly | QIODevice::Text); + if (!ok) { + QWARN(qPrintable(QString::fromLatin1("Could not open testdata file %1: %2") + .arg(fileName, file.errorString()))); + } + + return QString::fromUtf8(file.readAll()).split(QLatin1Char('\n'), splitBehavior); +} + void tst_rcc::rcc() { QFETCH(QString, directory); QFETCH(QString, qrcfile); QFETCH(QString, expected); - if (!QDir::setCurrent(directory)) { - QString message = QString::fromLatin1("Unable to cd from '%1' to '%2'").arg(QDir::currentPath(), directory); - QFAIL(qPrintable(message)); - } - // If the file expectedoutput.txt exists, compare the // console output with the content of that file - const QString expected2 = findExpectedFile(expected); - QFile expectedFile(expected2); - if (!expectedFile.exists()) { - qDebug() << "NO EXPECTATIONS? " << expected2; - return; - } // Launch; force no compression, otherwise the output would be different // depending on the compression algorithm we're using QProcess process; + process.setWorkingDirectory(directory); process.start(m_rcc, { "-no-compress", qrcfile }); + QVERIFY2(process.waitForStarted(), msgProcessStartFailed(process).constData()); if (!process.waitForFinished()) { - const QString path = QString::fromLocal8Bit(qgetenv("PATH")); - QString message = QString::fromLatin1("'%1' could not be found when run from '%2'. Path: '%3' "). - arg(m_rcc, QDir::currentPath(), path); - QFAIL(qPrintable(message)); + process.kill(); + QFAIL(msgProcessTimeout(process).constData()); } + QVERIFY2(process.exitStatus() == QProcess::NormalExit, + msgProcessCrashed(process).constData()); + QVERIFY2(process.exitCode() == 0, + msgProcessFailed(process).constData()); + const QChar cr = QLatin1Char('\r'); const QString err = QString::fromLocal8Bit(process.readAllStandardError()).remove(cr); const QString out = QString::fromLatin1(process.readAllStandardOutput()).remove(cr); @@ -181,63 +225,20 @@ void tst_rcc::rcc() const QChar nl = QLatin1Char('\n'); const QStringList actualLines = out.split(nl); - QVERIFY(expectedFile.open(QIODevice::ReadOnly|QIODevice::Text)); - const QStringList expectedLines = QString::fromLatin1(expectedFile.readAll()).split(nl); + const QStringList expectedLines = + readLinesFromFile(directory + QLatin1Char('/') + expected, QString::KeepEmptyParts); + QVERIFY(!expectedLines.isEmpty()); - const QString diff = doCompare(actualLines, expectedLines); + const QString diff = doCompare(actualLines, expectedLines, directory); if (diff.size()) QFAIL(qPrintable(diff)); } - - -static void createRccBinaryData(const QString &rcc, const QString &baseDir, - const QString &qrcFileName, const QString &rccFileName) -{ - QString currentDir = QDir::currentPath(); - QDir::setCurrent(baseDir); - - // same as above: force no compression - QProcess rccProcess; - rccProcess.start(rcc, { "-binary", "-no-compress", "-o", rccFileName, qrcFileName }); - bool ok = rccProcess.waitForFinished(); - if (!ok) { - QString errorString = QString::fromLatin1("Could not start rcc (is it in PATH?): %1").arg(rccProcess.errorString()); - QFAIL(qPrintable(errorString)); - } - - QByteArray output = rccProcess.readAllStandardOutput(); - if (!output.isEmpty()) { - QString errorMessage = QString::fromLatin1("rcc stdout: %1").arg(QString::fromLocal8Bit(output)); - QWARN(qPrintable(errorMessage)); - } - - output = rccProcess.readAllStandardError(); - if (!output.isEmpty()) { - QString errorMessage = QString::fromLatin1("rcc stderr: %1").arg(QString::fromLocal8Bit(output)); - QWARN(qPrintable(errorMessage)); - } - - QDir::setCurrent(currentDir); -} - -static QStringList readLinesFromFile(const QString &fileName) -{ - QFile file(fileName); - - bool ok = file.open(QIODevice::ReadOnly | QIODevice::Text); - if (!ok) - QWARN(qPrintable(QString::fromLatin1("Could not open testdata file %1: %2").arg(fileName, file.errorString()))); - - QStringList lines = QString::fromUtf8(file.readAll()).split(QLatin1Char('\n'), QString::SkipEmptyParts); - return lines; -} - static QStringMap readExpectedFiles(const QString &fileName) { QStringMap expectedFiles; - QStringList lines = readLinesFromFile(fileName); + QStringList lines = readLinesFromFile(fileName, QString::SkipEmptyParts); foreach (const QString &line, lines) { QString resourceFileName = line.section(QLatin1Char(' '), 0, 0, QString::SectionSkipEmpty); QString actualFileName = line.section(QLatin1Char(' '), 1, 1, QString::SectionSkipEmpty); @@ -268,9 +269,7 @@ void tst_rcc::binary_data() QTest::addColumn<QString>("baseDirectory"); QTest::addColumn<QStringMap>("expectedFiles"); - QString dataPath = QFINDTESTDATA("data/binary/"); - if (dataPath.isEmpty()) - QFAIL("data path not found"); + QString dataPath = m_dataPath + QLatin1String("/binary/"); QDirIterator iter(dataPath, QStringList() << QLatin1String("*.qrc")); while (iter.hasNext()) @@ -279,12 +278,33 @@ void tst_rcc::binary_data() QFileInfo qrcFileInfo = iter.fileInfo(); QString absoluteBaseName = QFileInfo(qrcFileInfo.absolutePath(), qrcFileInfo.baseName()).absoluteFilePath(); QString rccFileName = absoluteBaseName + QLatin1String(".rcc"); - createRccBinaryData(m_rcc, dataPath, qrcFileInfo.absoluteFilePath(), rccFileName); + + // same as above: force no compression + QProcess rccProcess; + rccProcess.setWorkingDirectory(dataPath); + rccProcess.start(m_rcc, { "-binary", "-no-compress", "-o", rccFileName, qrcFileInfo.absoluteFilePath() }); + QVERIFY2(rccProcess.waitForStarted(), msgProcessStartFailed(rccProcess).constData()); + if (!rccProcess.waitForFinished()) { + rccProcess.kill(); + QFAIL(msgProcessTimeout(rccProcess).constData()); + } + QVERIFY2(rccProcess.exitStatus() == QProcess::NormalExit, + msgProcessCrashed(rccProcess).constData()); + QVERIFY2(rccProcess.exitCode() == 0, + msgProcessFailed(rccProcess).constData()); + + QByteArray output = rccProcess.readAllStandardOutput(); + if (!output.isEmpty()) + qWarning("rcc stdout: %s", output.constData()); + + output = rccProcess.readAllStandardError(); + if (!output.isEmpty()) + qWarning("rcc stderr: %s", output.constData()); QString localeFileName = absoluteBaseName + QLatin1String(".locale"); QFile localeFile(localeFileName); if (localeFile.exists()) { - QStringList locales = readLinesFromFile(localeFileName); + QStringList locales = readLinesFromFile(localeFileName, QString::SkipEmptyParts); foreach (const QString &locale, locales) { QString expectedFileName = QString::fromLatin1("%1.%2.%3").arg(absoluteBaseName, locale, QLatin1String("expected")); QStringMap expectedFiles = readExpectedFiles(expectedFileName); @@ -386,16 +406,12 @@ void tst_rcc::readback() QFETCH(QString, resourceName); QFETCH(QString, fileSystemName); - QString dataPath = QFINDTESTDATA("data/"); - if (dataPath.isEmpty()) - QFAIL("data path not found"); - QFile resourceFile(resourceName); QVERIFY(resourceFile.open(QIODevice::ReadOnly)); QByteArray resourceData = resourceFile.readAll(); resourceFile.close(); - QFile fileSystemFile(dataPath + fileSystemName); + QFile fileSystemFile(m_dataPath + QLatin1Char('/') + fileSystemName); QVERIFY(fileSystemFile.open(QIODevice::ReadOnly)); QByteArray fileSystemData = fileSystemFile.readAll(); fileSystemFile.close(); @@ -403,13 +419,85 @@ void tst_rcc::readback() QCOMPARE(resourceData, fileSystemData); } +void tst_rcc::depFileGeneration_data() +{ + QTest::addColumn<QString>("qrcfile"); + QTest::addColumn<QString>("depfile"); + QTest::addColumn<QString>("expected"); + + QTest::newRow("simple") << "simple.qrc" << "simple.d" << "simple.d.expected"; + QTest::newRow("specialchar") << "specialchar.qrc" << "specialchar.d" << "specialchar.d.expected"; +} + +void tst_rcc::depFileGeneration() +{ + QFETCH(QString, qrcfile); + QFETCH(QString, depfile); + QFETCH(QString, expected); + const QString directory = m_dataPath + QLatin1String("/depfile"); + + QProcess process; + process.setWorkingDirectory(directory); + process.start(m_rcc, { "-d", depfile, "-o", qrcfile + ".cpp", qrcfile }); + QVERIFY2(process.waitForStarted(), msgProcessStartFailed(process).constData()); + if (!process.waitForFinished()) { + process.kill(); + QFAIL(msgProcessTimeout(process).constData()); + } + QVERIFY2(process.exitStatus() == QProcess::NormalExit, + msgProcessCrashed(process).constData()); + QVERIFY2(process.exitCode() == 0, + msgProcessFailed(process).constData()); + + QFile depFileOutput(directory + QLatin1String("/") + depfile); + QVERIFY(depFileOutput.open(QIODevice::ReadOnly | QIODevice::Text)); + QByteArray depFileData = depFileOutput.readAll(); + depFileOutput.close(); + + QFile depFileExpected(directory + QLatin1String("/") + expected); + QVERIFY(depFileExpected.open(QIODevice::ReadOnly | QIODevice::Text)); + QByteArray expectedData = depFileExpected.readAll(); + depFileExpected.close(); + + QCOMPARE(depFileData, expectedData); +} + +void tst_rcc::python() +{ + const QString path = m_dataPath + QLatin1String("/sizes"); + const QString testFileRoot = path + QLatin1String("/size-2-0-35-1"); + const QString qrcFile = testFileRoot + QLatin1String(".qrc"); + const QString expectedFile = testFileRoot + QLatin1String("_python.expected"); + const QString actualFile = testFileRoot + QLatin1String(".rcc"); + + QProcess process; + process.setWorkingDirectory(path); + process.start(m_rcc, { "-g", "python", "-o", actualFile, qrcFile}); + QVERIFY2(process.waitForStarted(), msgProcessStartFailed(process).constData()); + if (!process.waitForFinished()) { + process.kill(); + QFAIL(msgProcessTimeout(process).constData()); + } + QVERIFY2(process.exitStatus() == QProcess::NormalExit, + msgProcessCrashed(process).constData()); + QVERIFY2(process.exitCode() == 0, + msgProcessFailed(process).constData()); + + const auto actualLines = readLinesFromFile(actualFile, QString::KeepEmptyParts); + QVERIFY(!actualLines.isEmpty()); + const auto expectedLines = readLinesFromFile(expectedFile, QString::KeepEmptyParts); + QVERIFY(!expectedLines.isEmpty()); + const QString diff = doCompare(actualLines, expectedLines, path); + if (!diff.isEmpty()) + QFAIL(qPrintable(diff)); +} + void tst_rcc::cleanupTestCase() { - QString dataPath = QFINDTESTDATA("data/binary/"); - if (dataPath.isEmpty()) - return; - QDir dataDir(dataPath); + QDir dataDir(m_dataPath + QLatin1String("/binary")); QFileInfoList entries = dataDir.entryInfoList(QStringList() << QLatin1String("*.rcc")); + QDir dataDepDir(m_dataPath + QLatin1String("/depfile")); + entries += dataDepDir.entryInfoList({QLatin1String("*.d"), QLatin1String("*.qrc.cpp")}); foreach (const QFileInfo &entry, entries) QFile::remove(entry.absoluteFilePath()); } diff --git a/tests/auto/tools/uic/baseline/dialog.ui b/tests/auto/tools/uic/baseline/dialog.ui index e99d6fb3c4..936cc2eee8 100644 --- a/tests/auto/tools/uic/baseline/dialog.ui +++ b/tests/auto/tools/uic/baseline/dialog.ui @@ -1,4 +1,4 @@ -<ui version="4.0" > +<ui version="4.0" connectslotsbyname="false"> <class>Dialog</class> <widget class="QDialog" name="Dialog" > <property name="geometry" > diff --git a/tests/auto/tools/uic/baseline/dialog.ui.h b/tests/auto/tools/uic/baseline/dialog.ui.h index aeed71d058..cd6449873e 100644 --- a/tests/auto/tools/uic/baseline/dialog.ui.h +++ b/tests/auto/tools/uic/baseline/dialog.ui.h @@ -52,8 +52,6 @@ public: retranslateUi(Dialog); - - QMetaObject::connectSlotsByName(Dialog); } // setupUi void retranslateUi(QDialog *Dialog) diff --git a/tests/auto/tools/uic/baseline/qfiledialog.ui.h b/tests/auto/tools/uic/baseline/qfiledialog.ui.h index 9e51ee6a7c..52f8d25c75 100644 --- a/tests/auto/tools/uic/baseline/qfiledialog.ui.h +++ b/tests/auto/tools/uic/baseline/qfiledialog.ui.h @@ -291,7 +291,7 @@ public: detailModeButton->setToolTip(QCoreApplication::translate("QFileDialog", "Detail View", nullptr)); #endif // QT_CONFIG(tooltip) fileTypeLabel->setText(QCoreApplication::translate("QFileDialog", "Files of type:", nullptr)); - Q_UNUSED(QFileDialog); + (void)QFileDialog; } // retranslateUi }; diff --git a/tests/auto/tools/uic/tst_uic.cpp b/tests/auto/tools/uic/tst_uic.cpp index f9553028fe..5b2f1f008b 100644 --- a/tests/auto/tools/uic/tst_uic.cpp +++ b/tests/auto/tools/uic/tst_uic.cpp @@ -36,17 +36,27 @@ #include <QtCore/QTemporaryDir> #include <QtCore/QRegularExpression> #include <QtCore/QStandardPaths> +#include <QtCore/QVector> #include <cstdio> static const char keepEnvVar[] = "UIC_KEEP_GENERATED_FILES"; static const char diffToStderrEnvVar[] = "UIC_STDERR_DIFF"; +struct TestEntry +{ + QByteArray name; + QString baselineBaseName; + QString generatedFileName; +}; + class tst_uic : public QObject { Q_OBJECT public: + using TestEntries = QVector<TestEntry>; + tst_uic(); private Q_SLOTS: @@ -63,13 +73,20 @@ private Q_SLOTS: void compare(); void compare_data() const; + void python(); + void python_data() const; + void runCompare(); private: + void populateTestEntries(); + const QString m_command; QString m_baseline; QTemporaryDir m_generated; + TestEntries m_testEntries; QRegularExpression m_versionRegexp; + QString m_python; }; tst_uic::tst_uic() @@ -85,6 +102,32 @@ static QByteArray msgProcessStartFailed(const QString &command, const QString &w return result.toLocal8Bit(); } +// Locate Python and check whether PySide2 is installed +static QString locatePython(QTemporaryDir &generatedDir) +{ + QString python = QStandardPaths::findExecutable(QLatin1String("python")); + if (python.isEmpty()) { + qWarning("Cannot locate python, skipping tests"); + return QString(); + } + QFile importTestFile(generatedDir.filePath(QLatin1String("import_test.py"))); + if (!importTestFile.open(QIODevice::WriteOnly| QIODevice::Text)) + return QString(); + importTestFile.write("import PySide2.QtCore\n"); + importTestFile.close(); + QProcess process; + process.start(python, {importTestFile.fileName()}); + if (!process.waitForStarted() || !process.waitForFinished()) + return QString(); + if (process.exitStatus() != QProcess::NormalExit || process.exitCode() != 0) { + const QString stdErr = QString::fromLocal8Bit(process.readAllStandardError()).simplified(); + qWarning("PySide2 is not installed (%s)", qPrintable(stdErr)); + return QString(); + } + importTestFile.remove(); + return python; +} + void tst_uic::initTestCase() { QVERIFY2(m_generated.isValid(), qPrintable(m_generated.errorString())); @@ -105,7 +148,28 @@ void tst_uic::initTestCase() arg(QDir::currentPath()); if (!outLines.empty()) msg += outLines.front(); + populateTestEntries(); + QVERIFY(!m_testEntries.isEmpty()); qDebug("%s", qPrintable(msg)); + + m_python = locatePython(m_generated); +} + +void tst_uic::populateTestEntries() +{ + const QString generatedPrefix = m_generated.path() + QLatin1Char('/'); + QDir baseline(m_baseline); + const QString baseLinePrefix = baseline.path() + QLatin1Char('/'); + const QFileInfoList baselineFiles = + baseline.entryInfoList(QStringList(QString::fromLatin1("*.ui")), QDir::Files); + m_testEntries.reserve(baselineFiles.size()); + for (const QFileInfo &baselineFile : baselineFiles) { + const QString baseName = baselineFile.baseName(); + const QString baselineBaseName = baseLinePrefix + baseName; + const QString generatedFile = generatedPrefix + baselineFile.fileName() + + QLatin1String(".h"); + m_testEntries.append(TestEntry{baseName.toLocal8Bit(), baselineBaseName, generatedFile}); + } } static const char helpFormat[] = R"( @@ -171,22 +235,12 @@ void tst_uic::run_data() const QTest::addColumn<QString>("generatedFile"); QTest::addColumn<QStringList>("options"); - QDir generated(m_generated.path()); - QDir baseline(m_baseline); - const QFileInfoList baselineFiles = baseline.entryInfoList(QStringList("*.ui"), QDir::Files); - foreach (const QFileInfo &baselineFile, baselineFiles) { - const QString generatedFile = generated.absolutePath() - + QLatin1Char('/') + baselineFile.fileName() - + QLatin1String(".h"); - + for (const TestEntry &te : m_testEntries) { QStringList options; - if (baselineFile.fileName() == QLatin1String("qttrid.ui")) + if (te.name == QByteArrayLiteral("qttrid")) options << QStringList(QLatin1String("-idbased")); - - QTest::newRow(qPrintable(baselineFile.baseName())) - << baselineFile.absoluteFilePath() - << generatedFile - << options; + QTest::newRow(te.name.constData()) << (te.baselineBaseName + QLatin1String(".ui")) + << te.generatedFileName << options; } } @@ -264,15 +318,9 @@ void tst_uic::compare_data() const QTest::addColumn<QString>("originalFile"); QTest::addColumn<QString>("generatedFile"); - QDir generated(m_generated.path()); - QDir baseline(m_baseline); - const QFileInfoList baselineFiles = baseline.entryInfoList(QStringList("*.h"), QDir::Files); - foreach (const QFileInfo &baselineFile, baselineFiles) { - const QString generatedFile = generated.absolutePath() - + QLatin1Char('/') + baselineFile.fileName(); - QTest::newRow(qPrintable(baselineFile.baseName())) - << baselineFile.absoluteFilePath() - << generatedFile; + for (const TestEntry &te : m_testEntries) { + QTest::newRow(te.name.constData()) << (te.baselineBaseName + QLatin1String(".ui.h")) + << te.generatedFileName; } } @@ -280,7 +328,7 @@ void tst_uic::runTranslation() { QProcess process; - QDir baseline(m_baseline); + const QDir baseline(m_baseline); QDir generated(m_generated.path()); generated.mkdir(QLatin1String("translation")); @@ -327,5 +375,75 @@ void tst_uic::runCompare() QCOMPARE(generatedFileContents, originalFileContents); } +// Let uic generate Python code and verify that it is syntactically +// correct by compiling it into .pyc. This test is executed only +// when python with an installed Qt for Python is detected (see locatePython()). + +static inline QByteArray msgCompilePythonFailed(const QByteArray &error) +{ + // If there is a line with blanks and caret indicating an error in the line + // above, insert the cursor into the offending line and remove the caret. + QByteArrayList lines = error.trimmed().split('\n'); + for (int i = lines.size() - 1; i > 0; --i) { + const auto &line = lines.at(i); + const int caret = line.indexOf('^'); + if (caret == 0 || (caret > 0 && line.at(caret - 1) == ' ')) { + lines.removeAt(i); + lines[i - 1].insert(caret, '|'); + break; + } + } + return lines.join('\n'); +} + +void tst_uic::python_data() const +{ + QTest::addColumn<QString>("originalFile"); + QTest::addColumn<QString>("generatedFile"); + + const int size = m_python.isEmpty() + ? qMin(1, m_testEntries.size()) : m_testEntries.size(); + for (int i = 0; i < size; ++i) { + const TestEntry &te = m_testEntries.at(i); + // qprintsettingsoutput: variable named 'from' clashes with Python + if (!te.baselineBaseName.endsWith(QLatin1String("/qprintsettingsoutput"))) { + QString generatedFile = te.generatedFileName; + generatedFile.chop(1); // foo.h -> foo.py + generatedFile.append(QLatin1String("py")); + QTest::newRow(te.name.constData()) + << (te.baselineBaseName + QLatin1String(".ui")) + << generatedFile; + } + } +} + +void tst_uic::python() +{ + QFETCH(QString, originalFile); + QFETCH(QString, generatedFile); + if (m_python.isEmpty()) + QSKIP("Python was not found"); + + QStringList uicArguments{QLatin1String("-g"), QLatin1String("python"), + originalFile, QLatin1String("-o"), generatedFile}; + QProcess process; + process.setWorkingDirectory(m_generated.path()); + process.start(m_command, uicArguments); + QVERIFY2(process.waitForStarted(), msgProcessStartFailed(m_command, process.errorString())); + QVERIFY(process.waitForFinished()); + QCOMPARE(process.exitStatus(), QProcess::NormalExit); + QCOMPARE(process.exitCode(), 0); + QVERIFY(QFileInfo::exists(generatedFile)); + + // Test Python code generation by compiling the file + QStringList compileArguments{QLatin1String("-m"), QLatin1String("py_compile"), generatedFile}; + process.start(m_python, compileArguments); + QVERIFY2(process.waitForStarted(), msgProcessStartFailed(m_command, process.errorString())); + QVERIFY(process.waitForFinished()); + const bool compiled = process.exitStatus() == QProcess::NormalExit + && process.exitCode() == 0; + QVERIFY2(compiled, msgCompilePythonFailed(process.readAllStandardError()).constData()); +} + QTEST_MAIN(tst_uic) #include "tst_uic.moc" diff --git a/tests/auto/widgets/dialogs/qdialog/BLACKLIST b/tests/auto/widgets/dialogs/qdialog/BLACKLIST index dd6a8bfff9..72e3dff6dd 100644 --- a/tests/auto/widgets/dialogs/qdialog/BLACKLIST +++ b/tests/auto/widgets/dialogs/qdialog/BLACKLIST @@ -1,4 +1,4 @@ [snapToDefaultButton] -osx +osx-10.14 [showFullScreen] osx-10.13 ci diff --git a/tests/auto/widgets/dialogs/qdialog/tst_qdialog.cpp b/tests/auto/widgets/dialogs/qdialog/tst_qdialog.cpp index c840dabc1a..a494d7119a 100644 --- a/tests/auto/widgets/dialogs/qdialog/tst_qdialog.cpp +++ b/tests/auto/widgets/dialogs/qdialog/tst_qdialog.cpp @@ -52,7 +52,9 @@ class DummyDialog : public QDialog { public: DummyDialog(): QDialog() {} +#if QT_DEPRECATED_SINCE(5, 13) using QDialog::showExtension; +#endif }; class tst_QDialog : public QObject @@ -64,8 +66,10 @@ public: private slots: void cleanup(); void getSetCheck(); +#if QT_DEPRECATED_SINCE(5, 13) void showExtension_data(); void showExtension(); +#endif void defaultButtons(); void showMaximized(); void showMinimized(); @@ -76,6 +80,9 @@ private slots: void deleteInExec(); #if QT_CONFIG(sizegrip) void showSizeGrip(); +#if QT_DEPRECATED_SINCE(5, 13) + void showSizeGrip_deprecated(); +#endif #endif void setVisible(); void reject(); @@ -89,6 +96,7 @@ private slots: void tst_QDialog::getSetCheck() { QDialog obj1; +#if QT_DEPRECATED_SINCE(5, 13) // QWidget* QDialog::extension() // void QDialog::setExtension(QWidget*) QWidget *var1 = new QWidget; @@ -97,6 +105,7 @@ void tst_QDialog::getSetCheck() obj1.setExtension((QWidget *)0); QCOMPARE((QWidget *)0, obj1.extension()); // No delete var1, since setExtension takes ownership +#endif // int QDialog::result() // void QDialog::setResult(int) @@ -146,6 +155,7 @@ void tst_QDialog::cleanup() QVERIFY(QApplication::topLevelWidgets().isEmpty()); } +#if QT_DEPRECATED_SINCE(5, 13) void tst_QDialog::showExtension_data() { QTest::addColumn<QSize>("dlgSize"); @@ -197,6 +207,7 @@ void tst_QDialog::showExtension() testWidget.setExtension( 0 ); } +#endif void tst_QDialog::defaultButtons() { @@ -422,9 +433,37 @@ void tst_QDialog::deleteInExec() } #if QT_CONFIG(sizegrip) + // From Task 124269 void tst_QDialog::showSizeGrip() { + QDialog dialog(nullptr); + dialog.show(); + QWidget *ext = new QWidget(&dialog); + QVERIFY(!dialog.isSizeGripEnabled()); + + dialog.setSizeGripEnabled(true); + QPointer<QSizeGrip> sizeGrip = dialog.findChild<QSizeGrip *>(); + QVERIFY(sizeGrip); + QVERIFY(sizeGrip->isVisible()); + QVERIFY(dialog.isSizeGripEnabled()); + + dialog.setSizeGripEnabled(false); + QVERIFY(!dialog.isSizeGripEnabled()); + + dialog.setSizeGripEnabled(true); + sizeGrip = dialog.findChild<QSizeGrip *>(); + QVERIFY(sizeGrip); + QVERIFY(sizeGrip->isVisible()); + sizeGrip->hide(); + dialog.hide(); + dialog.show(); + QVERIFY(!sizeGrip->isVisible()); +} + +#if QT_DEPRECATED_SINCE(5, 13) +void tst_QDialog::showSizeGrip_deprecated() +{ QDialog dialog(0); dialog.show(); QWidget *ext = new QWidget(&dialog); @@ -476,7 +515,9 @@ void tst_QDialog::showSizeGrip() dialog.show(); QVERIFY(!sizeGrip->isVisible()); } -#endif +#endif // QT_DEPRECATED_SINCE(5, 13) + +#endif // QT_CONFIG(sizegrip) void tst_QDialog::setVisible() { diff --git a/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp b/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp index 748c8aaa84..2131e45f29 100644 --- a/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp +++ b/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp @@ -800,7 +800,10 @@ void tst_QFiledialog::isReadOnly() QAction* renameAction = fd.findChild<QAction*>("qt_rename_action"); QAction* deleteAction = fd.findChild<QAction*>("qt_delete_action"); +#if QT_DEPRECATED_SINCE(5, 13) QCOMPARE(fd.isReadOnly(), false); +#endif + QCOMPARE(fd.testOption(QFileDialog::ReadOnly), false); // This is dependent upon the file/dir, find cross platform way to test //fd.setDirectory(QDir::home()); @@ -1421,6 +1424,16 @@ void tst_QFiledialog::clearLineEdit() QTRY_VERIFY(fd.directory().absolutePath() != workDirPath); QVERIFY(lineEdit->text().isEmpty()); + + // QTBUG-71415: When pressing back, the selection (activated + // directory) should be restored. + QToolButton *backButton = fd.findChild<QToolButton*>("backButton"); + QVERIFY(backButton); + QTreeView *treeView = fd.findChildren<QTreeView*>("treeView").value(0); + QVERIFY(treeView); + backButton->click(); + QTRY_COMPARE(treeView->selectionModel()->selectedIndexes().value(0).data().toString(), + dirName); } void tst_QFiledialog::enableChooseButton() diff --git a/tests/auto/widgets/dialogs/qfiledialog2/BLACKLIST b/tests/auto/widgets/dialogs/qfiledialog2/BLACKLIST index e0887d8ad1..875855b59e 100644 --- a/tests/auto/widgets/dialogs/qfiledialog2/BLACKLIST +++ b/tests/auto/widgets/dialogs/qfiledialog2/BLACKLIST @@ -1,2 +1,4 @@ [QTBUG4419_lineEditSelectAll] -osx +osx-10.12 +osx-10.14 +osx-10.13 diff --git a/tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp b/tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp index 869418371c..40eff1e4c3 100644 --- a/tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp +++ b/tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp @@ -378,24 +378,24 @@ void tst_QFileDialog2::task143519_deleteAndRenameActionBehavior() // defaults QVERIFY(openContextMenu(fd)); QCOMPARE(fd.selectedFiles(), QStringList(ctx.file.fileName())); - QCOMPARE(rm->isEnabled(), !fd.isReadOnly()); - QCOMPARE(mv->isEnabled(), !fd.isReadOnly()); + QCOMPARE(rm->isEnabled(), !fd.testOption(QFileDialog::ReadOnly)); + QCOMPARE(mv->isEnabled(), !fd.testOption(QFileDialog::ReadOnly)); // change to non-defaults: - fd.setReadOnly(!fd.isReadOnly()); + fd.setOption(QFileDialog::ReadOnly, !fd.testOption(QFileDialog::ReadOnly)); QVERIFY(openContextMenu(fd)); QCOMPARE(fd.selectedFiles().size(), 1); - QCOMPARE(rm->isEnabled(), !fd.isReadOnly()); - QCOMPARE(mv->isEnabled(), !fd.isReadOnly()); + QCOMPARE(rm->isEnabled(), !fd.testOption(QFileDialog::ReadOnly)); + QCOMPARE(mv->isEnabled(), !fd.testOption(QFileDialog::ReadOnly)); // and changed back to defaults: - fd.setReadOnly(!fd.isReadOnly()); + fd.setOption(QFileDialog::ReadOnly, !fd.testOption(QFileDialog::ReadOnly)); QVERIFY(openContextMenu(fd)); QCOMPARE(fd.selectedFiles().size(), 1); - QCOMPARE(rm->isEnabled(), !fd.isReadOnly()); - QCOMPARE(mv->isEnabled(), !fd.isReadOnly()); + QCOMPARE(rm->isEnabled(), !fd.testOption(QFileDialog::ReadOnly)); + QCOMPARE(mv->isEnabled(), !fd.testOption(QFileDialog::ReadOnly)); } #endif // !QT_NO_CONTEXTMENU && !QT_NO_MENU diff --git a/tests/auto/widgets/dialogs/qfilesystemmodel/BLACKLIST b/tests/auto/widgets/dialogs/qfilesystemmodel/BLACKLIST index f78d23c6b1..aae2cacc3b 100644 --- a/tests/auto/widgets/dialogs/qfilesystemmodel/BLACKLIST +++ b/tests/auto/widgets/dialogs/qfilesystemmodel/BLACKLIST @@ -1,13 +1,16 @@ winrt +[sort] +winrt [sort:QFileDialog usage] ubuntu b2qt [specialFiles] -ubuntu b2qt [dirsBeforeFiles] -ubuntu +winrt b2qt -windows +ubuntu +windows-10 rhel -suse-leap +[drives] +winrt diff --git a/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp b/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp index 665a116a3a..f8f40e8488 100644 --- a/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp +++ b/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp @@ -65,18 +65,18 @@ } \ } while(0) -class tst_QFileSystemModel : public QObject { - Q_OBJECT +Q_DECLARE_METATYPE(QDir::Filters) +Q_DECLARE_METATYPE(QFileDevice::Permissions) -public: - tst_QFileSystemModel(); +Q_LOGGING_CATEGORY(lcFileSystemModel, "qt.widgets.tests.qfilesystemmodel") -public Q_SLOTS: - void init(); - void cleanup(); +class tst_QFileSystemModel : public QObject { + Q_OBJECT private slots: void initTestCase(); + void cleanup(); + void indexPath(); void rootPath(); @@ -128,48 +128,33 @@ private slots: void fileInfo(); protected: - bool createFiles(const QString &test_path, const QStringList &initial_files, int existingFileCount = 0, const QStringList &intial_dirs = QStringList()); - QModelIndex prepareTestModelRoot(const QString &test_path, QSignalSpy **spy2 = nullptr, - QSignalSpy **spy3 = nullptr); + bool createFiles(QFileSystemModel *model, const QString &test_path, + const QStringList &initial_files, int existingFileCount = 0, + const QStringList &initial_dirs = QStringList()); + QModelIndex prepareTestModelRoot(QFileSystemModel *model, const QString &test_path, + QSignalSpy **spy2 = nullptr, QSignalSpy **spy3 = nullptr); private: - QFileSystemModel *model; QString flatDirTestPath; QTemporaryDir m_tempDir; }; -tst_QFileSystemModel::tst_QFileSystemModel() : model(0) -{ -} - -void tst_QFileSystemModel::init() -{ - cleanup(); - QCOMPARE(model, nullptr); - model = new QFileSystemModel; -} - void tst_QFileSystemModel::cleanup() { - delete model; - model = 0; - QString tmp = flatDirTestPath; - QDir dir(tmp); - if (dir.exists(tmp)) { - QStringList list = dir.entryList(QDir::AllEntries | QDir::System | QDir::Hidden | QDir::NoDotAndDotDot); - for (int i = 0; i < list.count(); ++i) { - QFileInfo fi(dir.path() + '/' + list.at(i)); - if (fi.exists() && fi.isFile()) { - QFile p(fi.absoluteFilePath()); - p.setPermissions(QFile::ReadUser | QFile::ReadOwner | QFile::ExeOwner | QFile::ExeUser | QFile::WriteUser | QFile::WriteOwner | QFile::WriteOther); - QFile dead(dir.path() + '/' + list.at(i)); - dead.remove(); + QDir dir(flatDirTestPath); + if (dir.exists()) { + const QDir::Filters filters = QDir::AllEntries | QDir::System | QDir::Hidden | QDir::NoDotAndDotDot; + const QFileInfoList list = dir.entryInfoList(filters); + for (const QFileInfo &fi : list) { + if (fi.isDir()) { + QVERIFY(dir.rmdir(fi.fileName())); + } else { + QFile dead(fi.absoluteFilePath()); + dead.setPermissions(QFile::ReadUser | QFile::ReadOwner | QFile::ExeOwner | QFile::ExeUser | QFile::WriteUser | QFile::WriteOwner | QFile::WriteOther); + QVERIFY(dead.remove()); } - if (fi.exists() && fi.isDir()) - QVERIFY(dir.rmdir(list.at(i))); } - list = dir.entryList(QDir::AllEntries | QDir::System | QDir::Hidden | QDir::NoDotAndDotDot); - QCOMPARE(list.count(), 0); + QVERIFY(dir.entryInfoList(filters).isEmpty()); } } @@ -182,6 +167,7 @@ void tst_QFileSystemModel::initTestCase() void tst_QFileSystemModel::indexPath() { #if !defined(Q_OS_WIN) + QScopedPointer<QFileSystemModel> model(new QFileSystemModel); int depth = QDir::currentPath().count('/'); model->setRootPath(QDir::currentPath()); QString backPath; @@ -195,9 +181,10 @@ void tst_QFileSystemModel::indexPath() void tst_QFileSystemModel::rootPath() { + QScopedPointer<QFileSystemModel> model(new QFileSystemModel); QCOMPARE(model->rootPath(), QString(QDir().path())); - QSignalSpy rootChanged(model, SIGNAL(rootPathChanged(QString))); + QSignalSpy rootChanged(model.data(), &QFileSystemModel::rootPathChanged); QModelIndex root = model->setRootPath(model->rootPath()); root = model->setRootPath("this directory shouldn't exist"); QCOMPARE(rootChanged.count(), 0); @@ -243,6 +230,7 @@ void tst_QFileSystemModel::rootPath() void tst_QFileSystemModel::readOnly() { + QScopedPointer<QFileSystemModel> model(new QFileSystemModel); QCOMPARE(model->isReadOnly(), true); QTemporaryFile file(flatDirTestPath + QStringLiteral("/XXXXXX.dat")); QVERIFY2(file.open(), qPrintable(file.errorString())); @@ -263,19 +251,21 @@ void tst_QFileSystemModel::readOnly() class CustomFileIconProvider : public QFileIconProvider { public: - CustomFileIconProvider() : QFileIconProvider() { - mb = qApp->style()->standardIcon(QStyle::SP_MessageBoxCritical); - dvd = qApp->style()->standardIcon(QStyle::SP_DriveDVDIcon); + CustomFileIconProvider() : QFileIconProvider() + { + auto style = QApplication::style(); + mb = style->standardIcon(QStyle::SP_MessageBoxCritical); + dvd = style->standardIcon(QStyle::SP_DriveDVDIcon); } - virtual QIcon icon(const QFileInfo &info) const + QIcon icon(const QFileInfo &info) const override { if (info.isDir()) return mb; return QFileIconProvider::icon(info); } - virtual QIcon icon(IconType type) const + QIcon icon(IconType type) const override { if (type == QFileIconProvider::Folder) return dvd; @@ -289,69 +279,67 @@ private: void tst_QFileSystemModel::iconProvider() { + QScopedPointer<QFileSystemModel> model(new QFileSystemModel); QVERIFY(model->iconProvider()); - QFileIconProvider *p = new QFileIconProvider(); - model->setIconProvider(p); - QCOMPARE(model->iconProvider(), p); - model->setIconProvider(0); - delete p; + QScopedPointer<QFileIconProvider> provider(new QFileIconProvider); + model->setIconProvider(provider.data()); + QCOMPARE(model->iconProvider(), provider.data()); + model->setIconProvider(nullptr); + provider.reset(); - QFileSystemModel *myModel = new QFileSystemModel(); + QScopedPointer<QFileSystemModel> myModel(new QFileSystemModel); const QStringList documentPaths = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation); QVERIFY(!documentPaths.isEmpty()); - const QString documentPath = documentPaths.front(); - myModel->setRootPath(documentPath); + myModel->setRootPath(documentPaths.constFirst()); //We change the provider, icons must be updated - CustomFileIconProvider *custom = new CustomFileIconProvider(); - myModel->setIconProvider(custom); + provider.reset(new CustomFileIconProvider); + myModel->setIconProvider(provider.data()); - QPixmap mb = qApp->style()->standardIcon(QStyle::SP_MessageBoxCritical).pixmap(50, 50); + QPixmap mb = QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical).pixmap(50, 50); QCOMPARE(myModel->fileIcon(myModel->index(QDir::homePath())).pixmap(50, 50), mb); - delete myModel; - delete custom; } -bool tst_QFileSystemModel::createFiles(const QString &test_path, const QStringList &initial_files, int existingFileCount, const QStringList &initial_dirs) +bool tst_QFileSystemModel::createFiles(QFileSystemModel *model, const QString &test_path, + const QStringList &initial_files, int existingFileCount, + const QStringList &initial_dirs) { - //qDebug() << (model->rowCount(model->index(test_path))) << existingFileCount << initial_files; + qCDebug(lcFileSystemModel) << (model->rowCount(model->index(test_path))) << existingFileCount << initial_files; bool timedOut = false; TRY_WAIT((model->rowCount(model->index(test_path)) == existingFileCount), &timedOut); if (timedOut) return false; - for (int i = 0; i < initial_dirs.count(); ++i) { - QDir dir(test_path); - if (!dir.exists()) { - qWarning() << "error" << test_path << "doesn't exists"; - return false; - } - if(!dir.mkdir(initial_dirs.at(i))) { - qWarning() << "error" << "failed to make" << initial_dirs.at(i); + QDir dir(test_path); + if (!dir.exists()) { + qWarning() << "error" << test_path << "doesn't exist"; + return false; + } + for (const auto &initial_dir : initial_dirs) { + if (!dir.mkdir(initial_dir)) { + qWarning() << "error" << "failed to make" << initial_dir; return false; } - //qDebug() << test_path + '/' + initial_dirs.at(i) << (QFile::exists(test_path + '/' + initial_dirs.at(i))); + qCDebug(lcFileSystemModel) << test_path + '/' + initial_dir << (QFile::exists(test_path + '/' + initial_dir)); } - for (int i = 0; i < initial_files.count(); ++i) { - QFile file(test_path + '/' + initial_files.at(i)); + for (const auto &initial_file : initial_files) { + QFile file(test_path + '/' + initial_file); if (!file.open(QIODevice::WriteOnly | QIODevice::Append)) { - qDebug() << "failed to open file" << initial_files.at(i); + qDebug() << "failed to open file" << initial_file; return false; } if (!file.resize(1024 + file.size())) { - qDebug() << "failed to resize file" << initial_files.at(i); + qDebug() << "failed to resize file" << initial_file; return false; } if (!file.flush()) { - qDebug() << "failed to flush file" << initial_files.at(i); + qDebug() << "failed to flush file" << initial_file; return false; } file.close(); #if defined(Q_OS_WIN) - if (initial_files.at(i)[0] == '.') { - QString hiddenFile = QDir::toNativeSeparators(file.fileName()); - wchar_t nativeHiddenFile[MAX_PATH]; - memset(nativeHiddenFile, 0, sizeof(nativeHiddenFile)); - hiddenFile.toWCharArray(nativeHiddenFile); + if (initial_file[0] == '.') { + const QString hiddenFile = QDir::toNativeSeparators(file.fileName()); + const auto nativeHiddenFile = reinterpret_cast<const wchar_t *>(hiddenFile.utf16()); #ifndef Q_OS_WINRT DWORD currentAttributes = ::GetFileAttributes(nativeHiddenFile); #else // !Q_OS_WINRT @@ -370,13 +358,13 @@ bool tst_QFileSystemModel::createFiles(const QString &test_path, const QStringLi } } #endif - //qDebug() << test_path + '/' + initial_files.at(i) << (QFile::exists(test_path + '/' + initial_files.at(i))); + qCDebug(lcFileSystemModel) << test_path + '/' + initial_file << (QFile::exists(test_path + '/' + initial_file)); } return true; } -QModelIndex tst_QFileSystemModel::prepareTestModelRoot(const QString &test_path, QSignalSpy **spy2, - QSignalSpy **spy3) +QModelIndex tst_QFileSystemModel::prepareTestModelRoot(QFileSystemModel *model, const QString &test_path, + QSignalSpy **spy2, QSignalSpy **spy3) { if (model->rowCount(model->index(test_path)) != 0) return QModelIndex(); @@ -387,9 +375,8 @@ QModelIndex tst_QFileSystemModel::prepareTestModelRoot(const QString &test_path, *spy3 = new QSignalSpy(model, &QFileSystemModel::rowsAboutToBeInserted); QStringList files = { "b", "d", "f", "h", "j", ".a", ".c", ".e", ".g" }; - QString l = "b,d,f,h,j,.a,.c,.e,.g"; - if (!createFiles(test_path, files)) + if (!createFiles(model, test_path, files)) return QModelIndex(); QModelIndex root = model->setRootPath(test_path); @@ -406,10 +393,10 @@ QModelIndex tst_QFileSystemModel::prepareTestModelRoot(const QString &test_path, void tst_QFileSystemModel::rowCount() { - const QString tmp = flatDirTestPath; QSignalSpy *spy2 = nullptr; QSignalSpy *spy3 = nullptr; - QModelIndex root = prepareTestModelRoot(flatDirTestPath, &spy2, &spy3); + QScopedPointer<QFileSystemModel> model(new QFileSystemModel); + QModelIndex root = prepareTestModelRoot(model.data(), flatDirTestPath, &spy2, &spy3); QVERIFY(root.isValid()); QVERIFY(spy2 && spy2->count() > 0); @@ -419,11 +406,11 @@ void tst_QFileSystemModel::rowCount() void tst_QFileSystemModel::rowsInserted_data() { QTest::addColumn<int>("count"); - QTest::addColumn<int>("ascending"); + QTest::addColumn<Qt::SortOrder>("ascending"); for (int i = 0; i < 4; ++i) { const QByteArray iB = QByteArray::number(i); - QTest::newRow(("Qt::AscendingOrder " + iB).constData()) << i << (int)Qt::AscendingOrder; - QTest::newRow(("Qt::DescendingOrder " + iB).constData()) << i << (int)Qt::DescendingOrder; + QTest::newRow(("Qt::AscendingOrder " + iB).constData()) << i << Qt::AscendingOrder; + QTest::newRow(("Qt::DescendingOrder " + iB).constData()) << i << Qt::DescendingOrder; } } @@ -436,20 +423,21 @@ static inline QString lastEntry(const QModelIndex &root) void tst_QFileSystemModel::rowsInserted() { const QString tmp = flatDirTestPath; - QModelIndex root = prepareTestModelRoot(tmp); + QScopedPointer<QFileSystemModel> model(new QFileSystemModel); + QModelIndex root = prepareTestModelRoot(model.data(), tmp); QVERIFY(root.isValid()); - QFETCH(int, ascending); + QFETCH(Qt::SortOrder, ascending); QFETCH(int, count); - model->sort(0, (Qt::SortOrder)ascending); + model->sort(0, ascending); - QSignalSpy spy0(model, SIGNAL(rowsInserted(QModelIndex,int,int))); - QSignalSpy spy1(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int))); + QSignalSpy spy0(model.data(), &QAbstractItemModel::rowsInserted); + QSignalSpy spy1(model.data(), &QAbstractItemModel::rowsAboutToBeInserted); int oldCount = model->rowCount(root); QStringList files; for (int i = 0; i < count; ++i) files.append(QLatin1Char('c') + QString::number(i)); - QVERIFY(createFiles(tmp, files, 5)); + QVERIFY(createFiles(model.data(), tmp, files, 5)); QTRY_COMPARE(model->rowCount(root), oldCount + count); int totalRowsInserted = 0; for (int i = 0; i < spy0.count(); ++i) { @@ -469,7 +457,7 @@ void tst_QFileSystemModel::rowsInserted() } if (count == 0) QCOMPARE(spy1.count(), 0); else QVERIFY(spy1.count() >= 1); - QVERIFY(createFiles(tmp, QStringList(".hidden_file"), 5 + count)); + QVERIFY(createFiles(model.data(), tmp, QStringList(".hidden_file"), 5 + count)); if (count != 0) QTRY_VERIFY(spy0.count() >= 1); @@ -489,19 +477,21 @@ void tst_QFileSystemModel::rowsRemoved_data() void tst_QFileSystemModel::rowsRemoved() { const QString tmp = flatDirTestPath; - QModelIndex root = prepareTestModelRoot(tmp); + QScopedPointer<QFileSystemModel> model(new QFileSystemModel); + QModelIndex root = prepareTestModelRoot(model.data(), tmp); QVERIFY(root.isValid()); QFETCH(int, count); - QFETCH(int, ascending); - model->sort(0, (Qt::SortOrder)ascending); + QFETCH(Qt::SortOrder, ascending); + model->sort(0, ascending); - QSignalSpy spy0(model, SIGNAL(rowsRemoved(QModelIndex,int,int))); - QSignalSpy spy1(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int))); + QSignalSpy spy0(model.data(), &QAbstractItemModel::rowsRemoved); + QSignalSpy spy1(model.data(), &QAbstractItemModel::rowsAboutToBeRemoved); int oldCount = model->rowCount(root); for (int i = count - 1; i >= 0; --i) { - //qDebug() << "removing" << model->index(i, 0, root).data().toString(); - QVERIFY(QFile::remove(tmp + '/' + model->index(i, 0, root).data().toString())); + const QString fileName = model->index(i, 0, root).data().toString(); + qCDebug(lcFileSystemModel) << "removing" << fileName; + QVERIFY(QFile::remove(tmp + QLatin1Char('/') + fileName)); } for (int i = 0 ; i < 10; ++i) { if (count != 0) { @@ -520,18 +510,23 @@ void tst_QFileSystemModel::rowsRemoved() lst.append(model->index(i, 0, root).data().toString()); if (model->rowCount(root) == oldCount - count) break; - qDebug() << "still have:" << lst << QFile::exists(tmp + '/' + QString(".a")); + qCDebug(lcFileSystemModel) << "still have:" << lst << QFile::exists(tmp + QLatin1String("/.a")); QDir tmpLister(tmp); - qDebug() << tmpLister.entryList(); + qCDebug(lcFileSystemModel) << tmpLister.entryList(); } QTRY_COMPARE(model->rowCount(root), oldCount - count); - QVERIFY(QFile::exists(tmp + '/' + QString(".a"))); - QVERIFY(QFile::remove(tmp + '/' + QString(".a"))); - QVERIFY(QFile::remove(tmp + '/' + QString(".c"))); + QVERIFY(QFile::exists(tmp + QLatin1String("/.a"))); + QVERIFY(QFile::remove(tmp + QLatin1String("/.a"))); + QVERIFY(QFile::remove(tmp + QLatin1String("/.c"))); - if (count != 0) QVERIFY(spy0.count() >= 1); else QCOMPARE(spy0.count(), 0); - if (count != 0) QVERIFY(spy1.count() >= 1); else QCOMPARE(spy1.count(), 0); + if (count != 0) { + QVERIFY(spy0.count() >= 1); + QVERIFY(spy1.count() >= 1); + } else { + QCOMPARE(spy0.count(), 0); + QCOMPARE(spy1.count(), 0); + } } void tst_QFileSystemModel::dataChanged_data() @@ -544,18 +539,19 @@ void tst_QFileSystemModel::dataChanged() QSKIP("This can't be tested right now since we don't watch files, only directories."); const QString tmp = flatDirTestPath; - QModelIndex root = prepareTestModelRoot(tmp); + QScopedPointer<QFileSystemModel> model(new QFileSystemModel); + QModelIndex root = prepareTestModelRoot(model.data(), tmp); QVERIFY(root.isValid()); QFETCH(int, count); - QFETCH(int, assending); - model->sort(0, (Qt::SortOrder)assending); + QFETCH(Qt::SortOrder, ascending); + model->sort(0, ascending); - QSignalSpy spy(model, SIGNAL(dataChanged(QModelIndex,QModelIndex))); + QSignalSpy spy(model.data(), &QAbstractItemModel::dataChanged); QStringList files; for (int i = 0; i < count; ++i) files.append(model->index(i, 0, root).data().toString()); - createFiles(tmp, files); + createFiles(model.data(), tmp, files); QTest::qWait(WAITTIME); @@ -566,64 +562,68 @@ void tst_QFileSystemModel::filters_data() { QTest::addColumn<QStringList>("files"); QTest::addColumn<QStringList>("dirs"); - QTest::addColumn<int>("dirFilters"); + QTest::addColumn<QDir::Filters>("dirFilters"); QTest::addColumn<QStringList>("nameFilters"); QTest::addColumn<int>("rowCount"); - QTest::newRow("no dirs") << (QStringList() << "a" << "b" << "c") << QStringList() << (int)(QDir::Dirs) << QStringList() << 2; - QTest::newRow("no dirs - dot") << (QStringList() << "a" << "b" << "c") << QStringList() << (int)(QDir::Dirs | QDir::NoDot) << QStringList() << 1; - QTest::newRow("no dirs - dotdot") << (QStringList() << "a" << "b" << "c") << QStringList() << (int)(QDir::Dirs | QDir::NoDotDot) << QStringList() << 1; - QTest::newRow("no dirs - dotanddotdot") << (QStringList() << "a" << "b" << "c") << QStringList() << (int)(QDir::Dirs | QDir::NoDotAndDotDot) << QStringList() << 0; - QTest::newRow("one dir - dot") << (QStringList() << "a" << "b" << "c") << (QStringList() << "Z") << (int)(QDir::Dirs | QDir::NoDot) << QStringList() << 2; - QTest::newRow("one dir - dotdot") << (QStringList() << "a" << "b" << "c") << (QStringList() << "Z") << (int)(QDir::Dirs | QDir::NoDotDot) << QStringList() << 2; - QTest::newRow("one dir - dotanddotdot") << (QStringList() << "a" << "b" << "c") << (QStringList() << "Z") << (int)(QDir::Dirs | QDir::NoDotAndDotDot) << QStringList() << 1; - QTest::newRow("one dir") << (QStringList() << "a" << "b" << "c") << (QStringList() << "Z") << (int)(QDir::Dirs) << QStringList() << 3; - QTest::newRow("no dir + hidden") << (QStringList() << "a" << "b" << "c") << QStringList() << (int)(QDir::Dirs | QDir::Hidden) << QStringList() << 2; - QTest::newRow("dir+hid+files") << (QStringList() << "a" << "b" << "c") << QStringList() << - (int)(QDir::Dirs | QDir::Files | QDir::Hidden) << QStringList() << 5; - QTest::newRow("dir+file+hid-dot .A") << (QStringList() << "a" << "b" << "c") << (QStringList() << ".A") << - (int)(QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot) << QStringList() << 4; - QTest::newRow("dir+files+hid+dot A") << (QStringList() << "a" << "b" << "c") << (QStringList() << "AFolder") << - (int)(QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot) << (QStringList() << "A*") << 2; - QTest::newRow("dir+files+hid+dot+cas1") << (QStringList() << "a" << "b" << "c") << (QStringList() << "Z") << - (int)(QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot | QDir::CaseSensitive) << (QStringList() << "Z") << 1; - QTest::newRow("dir+files+hid+dot+cas2") << (QStringList() << "a" << "b" << "c") << (QStringList() << "Z") << - (int)(QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot | QDir::CaseSensitive) << (QStringList() << "a") << 1; - QTest::newRow("dir+files+hid+dot+cas+alldir") << (QStringList() << "a" << "b" << "c") << (QStringList() << "Z") << - (int)(QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot | QDir::CaseSensitive | QDir::AllDirs) << (QStringList() << "Z") << 1; - - QTest::newRow("case sensitive") << (QStringList() << "Antiguagdb" << "Antiguamtd" - << "Antiguamtp" << "afghanistangdb" << "afghanistanmtd") - << QStringList() << (int)(QDir::Files) << QStringList() << 5; + + const QStringList abcList{QLatin1String("a"), QLatin1String("b"), QLatin1String("c")}; + const QStringList zList{QLatin1String("Z")}; + + QTest::newRow("no dirs") << abcList << QStringList() << QDir::Filters(QDir::Dirs) << QStringList() << 2; + QTest::newRow("no dirs - dot") << abcList << QStringList() << (QDir::Dirs | QDir::NoDot) << QStringList() << 1; + QTest::newRow("no dirs - dotdot") << abcList << QStringList() << (QDir::Dirs | QDir::NoDotDot) << QStringList() << 1; + QTest::newRow("no dirs - dotanddotdot") << abcList << QStringList() << (QDir::Dirs | QDir::NoDotAndDotDot) << QStringList() << 0; + QTest::newRow("one dir - dot") << abcList << zList << (QDir::Dirs | QDir::NoDot) << QStringList() << 2; + QTest::newRow("one dir - dotdot") << abcList << zList << (QDir::Dirs | QDir::NoDotDot) << QStringList() << 2; + QTest::newRow("one dir - dotanddotdot") << abcList << zList << (QDir::Dirs | QDir::NoDotAndDotDot) << QStringList() << 1; + QTest::newRow("one dir") << abcList << zList << QDir::Filters(QDir::Dirs) << QStringList() << 3; + QTest::newRow("no dir + hidden") << abcList << QStringList() << (QDir::Dirs | QDir::Hidden) << QStringList() << 2; + QTest::newRow("dir+hid+files") << abcList << QStringList() << + (QDir::Dirs | QDir::Files | QDir::Hidden) << QStringList() << 5; + QTest::newRow("dir+file+hid-dot .A") << abcList << QStringList{QLatin1String(".A")} << + (QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot) << QStringList() << 4; + QTest::newRow("dir+files+hid+dot A") << abcList << QStringList{QLatin1String("AFolder")} << + (QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot) << QStringList{QLatin1String("A*")} << 2; + QTest::newRow("dir+files+hid+dot+cas1") << abcList << zList << + (QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot | QDir::CaseSensitive) << zList << 1; + QTest::newRow("dir+files+hid+dot+cas2") << abcList << zList << + (QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot | QDir::CaseSensitive) << QStringList{QLatin1String("a")} << 1; + QTest::newRow("dir+files+hid+dot+cas+alldir") << abcList << zList << + (QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot | QDir::CaseSensitive | QDir::AllDirs) << zList << 1; + + QTest::newRow("case sensitive") << QStringList{QLatin1String("Antiguagdb"), QLatin1String("Antiguamtd"), + QLatin1String("Antiguamtp"), QLatin1String("afghanistangdb"), QLatin1String("afghanistanmtd")} + << QStringList() << QDir::Filters(QDir::Files) << QStringList() << 5; } void tst_QFileSystemModel::filters() { QString tmp = flatDirTestPath; - QVERIFY(createFiles(tmp, QStringList())); + QScopedPointer<QFileSystemModel> model(new QFileSystemModel); + QVERIFY(createFiles(model.data(), tmp, QStringList())); QModelIndex root = model->setRootPath(tmp); QFETCH(QStringList, files); QFETCH(QStringList, dirs); - QFETCH(int, dirFilters); + QFETCH(QDir::Filters, dirFilters); QFETCH(QStringList, nameFilters); QFETCH(int, rowCount); if (nameFilters.count() > 0) model->setNameFilters(nameFilters); model->setNameFilterDisables(false); - model->setFilter((QDir::Filters)dirFilters); + model->setFilter(dirFilters); - QVERIFY(createFiles(tmp, files, 0, dirs)); + QVERIFY(createFiles(model.data(), tmp, files, 0, dirs)); QTRY_COMPARE(model->rowCount(root), rowCount); // Make sure that we do what QDir does QDir xFactor(tmp); - QDir::Filters filters = (QDir::Filters)dirFilters; QStringList dirEntries; if (nameFilters.count() > 0) - dirEntries = xFactor.entryList(nameFilters, filters); + dirEntries = xFactor.entryList(nameFilters, dirFilters); else - dirEntries = xFactor.entryList(filters); + dirEntries = xFactor.entryList(dirFilters); QCOMPARE(dirEntries.count(), rowCount); @@ -667,12 +667,13 @@ void tst_QFileSystemModel::nameFilters() { QStringList list; list << "a" << "b" << "c"; + QScopedPointer<QFileSystemModel> model(new QFileSystemModel); model->setNameFilters(list); model->setNameFilterDisables(false); QCOMPARE(model->nameFilters(), list); QString tmp = flatDirTestPath; - QVERIFY(createFiles(tmp, list)); + QVERIFY(createFiles(model.data(), tmp, list)); QModelIndex root = model->setRootPath(tmp); QTRY_COMPARE(model->rowCount(root), 3); @@ -693,15 +694,17 @@ void tst_QFileSystemModel::setData_data() << QDir::temp().absolutePath() + '/' + "a" << false; */ + + const QStringList abcList{QLatin1String("a"), QLatin1String("b"), QLatin1String("c")}; QTest::newRow("in current dir") << QString() - << (QStringList() << "a" << "b" << "c") + << abcList << "a" << "d" << true; QTest::newRow("in subdir") << "s" - << (QStringList() << "a" << "b" << "c") + << abcList << "a" << "d" << true; @@ -709,7 +712,8 @@ void tst_QFileSystemModel::setData_data() void tst_QFileSystemModel::setData() { - QSignalSpy spy(model, SIGNAL(fileRenamed(QString,QString,QString))); + QScopedPointer<QFileSystemModel> model(new QFileSystemModel); + QSignalSpy spy(model.data(), &QFileSystemModel::fileRenamed); QFETCH(QString, subdirName); QFETCH(QStringList, files); QFETCH(QString, oldFileName); @@ -722,7 +726,7 @@ void tst_QFileSystemModel::setData() QVERIFY(dir.mkdir(subdirName)); tmp.append('/' + subdirName); } - QVERIFY(createFiles(tmp, files)); + QVERIFY(createFiles(model.data(), tmp, files)); QModelIndex tmpIdx = model->setRootPath(flatDirTestPath); if (!subdirName.isEmpty()) { tmpIdx = model->index(tmp); @@ -760,6 +764,7 @@ void tst_QFileSystemModel::sortPersistentIndex() const QFileInfo fileInfo(file.fileName()); file.close(); QTRY_VERIFY(QDir(flatDirTestPath).entryInfoList().contains(fileInfo)); + QScopedPointer<QFileSystemModel> model(new QFileSystemModel); QModelIndex root = model->setRootPath(flatDirTestPath); QTRY_VERIFY(model->rowCount(root) > 0); @@ -786,8 +791,9 @@ void tst_QFileSystemModel::sort() { QFETCH(bool, fileDialogMode); - MyFriendFileSystemModel *myModel = new MyFriendFileSystemModel(); - QTreeView *tree = new QTreeView(); + QScopedPointer<MyFriendFileSystemModel> myModel(new MyFriendFileSystemModel); + QTreeView tree; + tree.setWindowTitle(QTest::currentTestFunction()); if (fileDialogMode && EmulationDetector::isRunningArmOnX86()) QSKIP("Crashes in QEMU. QTBUG-70572"); @@ -816,24 +822,23 @@ void tst_QFileSystemModel::sort() myModel->setRootPath(""); myModel->setFilter(QDir::AllEntries | QDir::System | QDir::Hidden); - tree->setSortingEnabled(true); - tree->setModel(myModel); - tree->show(); - tree->resize(800, 800); - QVERIFY(QTest::qWaitForWindowActive(tree)); - tree->header()->setSortIndicator(1,Qt::DescendingOrder); - tree->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents); + tree.setSortingEnabled(true); + tree.setModel(myModel.data()); + tree.show(); + tree.resize(800, 800); + QVERIFY(QTest::qWaitForWindowActive(&tree)); + tree.header()->setSortIndicator(1, Qt::DescendingOrder); + tree.header()->setSectionResizeMode(0, QHeaderView::ResizeToContents); QStringList dirsToOpen; - do - { - dirsToOpen<<dir.absolutePath(); + do { + dirsToOpen << dir.absolutePath(); } while (dir.cdUp()); for (int i = dirsToOpen.size() -1 ; i > 0 ; --i) { QString path = dirsToOpen[i]; - tree->expand(myModel->index(path, 0)); + tree.expand(myModel->index(path, 0)); } - tree->expand(myModel->index(dirPath, 0)); + tree.expand(myModel->index(dirPath, 0)); QModelIndex parent = myModel->index(dirPath, 0); QList<QString> expectedOrder; expectedOrder << tempFile2.fileName() << tempFile.fileName() << dirPath + QChar('/') + ".." << dirPath + QChar('/') + "."; @@ -859,15 +864,13 @@ void tst_QFileSystemModel::sort() QTRY_COMPARE(dirPath + QChar('/') + myModel->index(i, 1, parent).data(QFileSystemModel::FileNameRole).toString(), expectedOrder.at(i)); } } - - delete tree; - delete myModel; } void tst_QFileSystemModel::mkdir() { QString tmp = flatDirTestPath; QString newFolderPath = QDir::toNativeSeparators(tmp + '/' + "NewFoldermkdirtest4"); + QScopedPointer<QFileSystemModel> model(new QFileSystemModel); QModelIndex tmpDir = model->index(tmp); QVERIFY(tmpDir.isValid()); QDir bestatic(newFolderPath); @@ -902,6 +905,7 @@ void tst_QFileSystemModel::deleteFile() qWarning() << "unable to create" << newFilePath; } newFile.close(); + QScopedPointer<QFileSystemModel> model(new QFileSystemModel); QModelIndex idx = model->index(newFilePath); QVERIFY(idx.isValid()); QVERIFY(model->remove(idx)); @@ -963,7 +967,8 @@ void tst_QFileSystemModel::caseSensitivity() QString tmp = flatDirTestPath; QStringList files; files << "a" << "c" << "C"; - QVERIFY(createFiles(tmp, files)); + QScopedPointer<QFileSystemModel> model(new QFileSystemModel); + QVERIFY(createFiles(model.data(), tmp, files)); QModelIndex root = model->index(tmp); QStringList paths; QModelIndexList indexes; @@ -1013,13 +1018,14 @@ void tst_QFileSystemModel::dirsBeforeFiles() const int itemCount = 3; for (int i = 0; i < itemCount; ++i) { - QLatin1Char c('a' + i); - dir.mkdir(c + QLatin1String("-dir")); + QLatin1Char c('a' + char(i)); + QVERIFY(dir.mkdir(c + QLatin1String("-dir"))); QFile file(flatDirTestPath + QLatin1Char('/') + c + QLatin1String("-file")); - file.open(QIODevice::ReadWrite); + QVERIFY(file.open(QIODevice::ReadWrite)); file.close(); } + QScopedPointer<QFileSystemModel> model(new QFileSystemModel); QModelIndex root = model->setRootPath(flatDirTestPath); // Wait for model to be notified by the file system watcher QTRY_COMPARE(model->rowCount(root), 2 * itemCount); @@ -1073,7 +1079,7 @@ static inline QByteArray permissionRowName(bool readOnly, int permission) void tst_QFileSystemModel::permissions_data() { - QTest::addColumn<int>("permissions"); + QTest::addColumn<QFileDevice::Permissions>("permissions"); QTest::addColumn<bool>("readOnly"); static const int permissions[] = { @@ -1081,22 +1087,23 @@ void tst_QFileSystemModel::permissions_data() QFile::ReadOwner, QFile::WriteOwner|QFile::ReadOwner, }; - for (size_t i = 0; i < sizeof permissions / sizeof *permissions; ++i) { - QTest::newRow(permissionRowName(false, permissions[i]).constData()) << permissions[i] << false; - QTest::newRow(permissionRowName(true, permissions[i]).constData()) << permissions[i] << true; + for (int permission : permissions) { + QTest::newRow(permissionRowName(false, permission).constData()) << QFileDevice::Permissions(permission) << false; + QTest::newRow(permissionRowName(true, permission).constData()) << QFileDevice::Permissions(permission) << true; } } void tst_QFileSystemModel::permissions() // checks QTBUG-20503 { - QFETCH(int, permissions); + QFETCH(QFileDevice::Permissions, permissions); QFETCH(bool, readOnly); const QString tmp = flatDirTestPath; const QString file = tmp + QLatin1String("/f"); - QVERIFY(createFiles(tmp, QStringList() << "f")); + QScopedPointer<QFileSystemModel> model(new QFileSystemModel); + QVERIFY(createFiles(model.data(), tmp, QStringList{QLatin1String("f")})); - QVERIFY(QFile::setPermissions(file, QFile::Permissions(permissions))); + QVERIFY(QFile::setPermissions(file, permissions)); const QModelIndex root = model->setRootPath(tmp); diff --git a/tests/auto/widgets/dialogs/qmessagebox/BLACKLIST b/tests/auto/widgets/dialogs/qmessagebox/BLACKLIST index da52809aad..8d8a7c2105 100644 --- a/tests/auto/widgets/dialogs/qmessagebox/BLACKLIST +++ b/tests/auto/widgets/dialogs/qmessagebox/BLACKLIST @@ -1,2 +1,4 @@ [defaultButton] -* +opensuse-leap +rhel-7.6 +ubuntu diff --git a/tests/auto/widgets/dialogs/qprogressdialog/BLACKLIST b/tests/auto/widgets/dialogs/qprogressdialog/BLACKLIST index 1789f51507..2b784414cd 100644 --- a/tests/auto/widgets/dialogs/qprogressdialog/BLACKLIST +++ b/tests/auto/widgets/dialogs/qprogressdialog/BLACKLIST @@ -1,2 +1,2 @@ [autoShow] -osx ci +osx-10.13 diff --git a/tests/auto/widgets/dialogs/qprogressdialog/tst_qprogressdialog.cpp b/tests/auto/widgets/dialogs/qprogressdialog/tst_qprogressdialog.cpp index 2ada4fedb6..6f527e7b6b 100644 --- a/tests/auto/widgets/dialogs/qprogressdialog/tst_qprogressdialog.cpp +++ b/tests/auto/widgets/dialogs/qprogressdialog/tst_qprogressdialog.cpp @@ -252,7 +252,7 @@ class QTestTranslator : public QTranslator { const QString m_str; public: - explicit QTestTranslator(QString str) : m_str(qMove(str)) {} + explicit QTestTranslator(QString str) : m_str(std::move(str)) {} QString translate(const char *, const char *sourceText, const char *, int) const override { return m_str + sourceText + m_str; } @@ -265,7 +265,7 @@ class QTranslatorGuard { Translator t; public: template <typename Arg> - explicit QTranslatorGuard(Arg a) : t(qMove(a)) + explicit QTranslatorGuard(Arg a) : t(std::move(a)) { qApp->installTranslator(&t); } ~QTranslatorGuard() { qApp->removeTranslator(&t); } diff --git a/tests/auto/widgets/dialogs/qwizard/tst_qwizard.cpp b/tests/auto/widgets/dialogs/qwizard/tst_qwizard.cpp index 24cbd2e35c..6091975acb 100644 --- a/tests/auto/widgets/dialogs/qwizard/tst_qwizard.cpp +++ b/tests/auto/widgets/dialogs/qwizard/tst_qwizard.cpp @@ -417,7 +417,7 @@ void tst_QWizard::setPixmap() QVERIFY(wizard.pixmap(QWizard::BannerPixmap).isNull()); QVERIFY(wizard.pixmap(QWizard::LogoPixmap).isNull()); QVERIFY(wizard.pixmap(QWizard::WatermarkPixmap).isNull()); - if (QSysInfo::macVersion() <= Q_MV_OSX(10, 13)) + if (QOperatingSystemVersion::current() <= QOperatingSystemVersion::MacOSHighSierra) QVERIFY(!wizard.pixmap(QWizard::BackgroundPixmap).isNull()); else QVERIFY(wizard.pixmap(QWizard::BackgroundPixmap).isNull()); @@ -425,7 +425,7 @@ void tst_QWizard::setPixmap() QVERIFY(page->pixmap(QWizard::BannerPixmap).isNull()); QVERIFY(page->pixmap(QWizard::LogoPixmap).isNull()); QVERIFY(page->pixmap(QWizard::WatermarkPixmap).isNull()); - if (QSysInfo::macVersion() <= Q_MV_OSX(10, 13)) + if (QOperatingSystemVersion::current() <= QOperatingSystemVersion::MacOSHighSierra) QVERIFY(!wizard.pixmap(QWizard::BackgroundPixmap).isNull()); else QVERIFY(page->pixmap(QWizard::BackgroundPixmap).isNull()); diff --git a/tests/auto/widgets/effects/qgraphicseffect/BLACKLIST b/tests/auto/widgets/effects/qgraphicseffect/BLACKLIST index 4833af527f..64a92d18aa 100644 --- a/tests/auto/widgets/effects/qgraphicseffect/BLACKLIST +++ b/tests/auto/widgets/effects/qgraphicseffect/BLACKLIST @@ -1,3 +1,2 @@ [prepareGeometryChangeInvalidateCache] -opensuse -opensuse-leap +opensuse-42.3 diff --git a/tests/auto/widgets/graphicsview/qgraphicsitem/qgraphicsitem.pro b/tests/auto/widgets/graphicsview/qgraphicsitem/qgraphicsitem.pro index ae6de48195..16818a98f9 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsitem/qgraphicsitem.pro +++ b/tests/auto/widgets/graphicsview/qgraphicsitem/qgraphicsitem.pro @@ -5,4 +5,4 @@ QT += core-private gui-private SOURCES += tst_qgraphicsitem.cpp DEFINES += QT_NO_CAST_TO_ASCII -win32:!winrt: LIBS += -luser32 +win32:!winrt: QMAKE_USE += user32 diff --git a/tests/auto/widgets/graphicsview/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/widgets/graphicsview/qgraphicsitem/tst_qgraphicsitem.cpp index 670dc0b808..af0dd9b0f0 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsitem/tst_qgraphicsitem.cpp @@ -272,6 +272,9 @@ class tst_QGraphicsItem : public QObject { Q_OBJECT +public: + static void initMain(); + private slots: void construction(); void constructionWithParent(); @@ -474,6 +477,14 @@ private: QTouchDevice *m_touchDevice = nullptr; }; +void tst_QGraphicsItem::initMain() +{ +#ifdef Q_OS_WIN + // Ensure minimum size constraints of framed windows on High DPI screens + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif +} + void tst_QGraphicsItem::construction() { for (int i = 0; i < 7; ++i) { @@ -4440,15 +4451,19 @@ protected: break; case QGraphicsItem::ItemPositionHasChanged: break; +#if QT_DEPRECATED_SINCE(5, 14) case QGraphicsItem::ItemMatrixChange: { +#if QT_DEPRECATED_SINCE(5, 13) QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED QVariant variant; variant.setValue<QMatrix>(matrix()); oldValues << variant; QT_WARNING_POP +#endif } break; +#endif case QGraphicsItem::ItemTransformChange: { QVariant variant; variant.setValue<QTransform>(transform()); @@ -4566,6 +4581,7 @@ void tst_QGraphicsItem::itemChange() QCOMPARE(tester.oldValues.last(), QVariant(true)); QCOMPARE(tester.isEnabled(), true); } +#if QT_DEPRECATED_SINCE(5, 13) { QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED // QDesktopWidget::screen() @@ -4585,6 +4601,7 @@ QT_WARNING_DISABLE_DEPRECATED // QDesktopWidget::screen() QCOMPARE(tester.matrix(), QMatrix().rotate(90)); QT_WARNING_POP } +#endif { tester.resetTransform(); ++changeCount; @@ -8397,7 +8414,7 @@ void tst_QGraphicsItem::focusProxy() QString err; QTextStream stream(&err); stream << "QGraphicsItem::setFocusProxy: " - << (void*)item << " is already in the focus proxy chain" << flush; + << (void*)item << " is already in the focus proxy chain" << Qt::flush; QTest::ignoreMessage(QtWarningMsg, err.toLatin1().constData()); item2->setFocusProxy(item); // fails QCOMPARE(item->focusProxy(), (QGraphicsItem *)item2); @@ -10960,7 +10977,7 @@ static QList<QTouchEvent::TouchPoint> tp.setStartScreenPos(screenPos); tp.setLastScreenPos(screenPos); tp.setEllipseDiameters(ellipseDiameters); - const QSizeF screenSize = QApplication::desktop()->screenGeometry(&view).size(); + const QSizeF screenSize = view.screen()->geometry().size(); tp.setNormalizedPos(QPointF(screenPos.x() / screenSize.width(), screenPos.y() / screenSize.height())); return QList<QTouchEvent::TouchPoint>() << tp; } diff --git a/tests/auto/widgets/graphicsview/qgraphicsitemanimation/tst_qgraphicsitemanimation.cpp b/tests/auto/widgets/graphicsview/qgraphicsitemanimation/tst_qgraphicsitemanimation.cpp index dfb2752ee0..ed79904ed8 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsitemanimation/tst_qgraphicsitemanimation.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsitemanimation/tst_qgraphicsitemanimation.cpp @@ -54,9 +54,9 @@ void tst_QGraphicsItemAnimation::construction() QCOMPARE(animation.posAt(0), QPointF()); QCOMPARE(animation.posAt(0.5), QPointF()); QCOMPARE(animation.posAt(1), QPointF()); - QCOMPARE(animation.matrixAt(0), QMatrix()); - QCOMPARE(animation.matrixAt(0.5), QMatrix()); - QCOMPARE(animation.matrixAt(1), QMatrix()); + QCOMPARE(animation.transformAt(0), QTransform()); + QCOMPARE(animation.transformAt(0.5), QTransform()); + QCOMPARE(animation.transformAt(1), QTransform()); QCOMPARE(animation.rotationAt(0), qreal(0.0)); QCOMPARE(animation.rotationAt(0.5), qreal(0.0)); QCOMPARE(animation.rotationAt(1), qreal(0.0)); diff --git a/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp b/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp index 4a301337ef..a437b05479 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp @@ -330,7 +330,7 @@ public: { // Make sure QGraphicsProxyWidget::paint does not modify the render hints set on the painter. painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform - | QPainter::NonCosmeticDefaultPen | QPainter::TextAntialiasing); + | QPainter::TextAntialiasing); const QPainter::RenderHints oldRenderHints = painter->renderHints(); QGraphicsProxyWidget::paint(painter, option, widget); QCOMPARE(painter->renderHints(), oldRenderHints); @@ -463,14 +463,13 @@ void tst_QGraphicsProxyWidget::setWidget() QCOMPARE(proxy->focusPolicy(), Qt::WheelFocus); QVERIFY(proxy->acceptDrops()); QCOMPARE(proxy->acceptHoverEvents(), true); // to get widget enter events - int left, top, right, bottom; - widget->getContentsMargins(&left, &top, &right, &bottom); + const QMarginsF margins = QMarginsF{widget->contentsMargins()}; qreal rleft, rtop, rright, rbottom; proxy->getContentsMargins(&rleft, &rtop, &rright, &rbottom); - QCOMPARE((qreal)left, rleft); - QCOMPARE((qreal)top, rtop); - QCOMPARE((qreal)right, rright); - QCOMPARE((qreal)bottom, rbottom); + QCOMPARE(margins.left(), rleft); + QCOMPARE(margins.top(), rtop); + QCOMPARE(margins.right(), rright); + QCOMPARE(margins.bottom(), rbottom); } else { // proxy shouldn't mess with the widget if it can't insert it. QCOMPARE(proxy->widget(), nullptr); @@ -2769,9 +2768,6 @@ void tst_QGraphicsProxyWidget::windowOpacity() // disabled on platforms without alpha channel support in QPixmap (e.g., // X11 without XRender). int paints = 0; -#if 0 // Used to be included in Qt4 for Q_WS_X11 - paints = !X11->use_xrender; -#endif QTRY_COMPARE(eventSpy.counts[QEvent::UpdateRequest], 0); QTRY_COMPARE(eventSpy.counts[QEvent::Paint], paints); diff --git a/tests/auto/widgets/graphicsview/qgraphicsscene/BLACKLIST b/tests/auto/widgets/graphicsview/qgraphicsscene/BLACKLIST index b8b427b3dd..c3797c9d57 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsscene/BLACKLIST +++ b/tests/auto/widgets/graphicsview/qgraphicsscene/BLACKLIST @@ -1,13 +1,5 @@ [isActive] opensuse-42.3 ci -[removeFullyTransparentItem] -osx-10.12 [tabFocus_sceneWithNestedFocusWidgets] -opensuse -opensuse-leap -[inputMethod] -opensuse -opensuse-leap -[hoverEvents_parentChild] -ubuntu +opensuse-42.3 diff --git a/tests/auto/widgets/graphicsview/qgraphicsscene/qgraphicsscene.pro b/tests/auto/widgets/graphicsview/qgraphicsscene/qgraphicsscene.pro index 351cecd92e..2f648a2212 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsscene/qgraphicsscene.pro +++ b/tests/auto/widgets/graphicsview/qgraphicsscene/qgraphicsscene.pro @@ -4,7 +4,7 @@ QT += widgets widgets-private testlib QT += core-private gui-private SOURCES += tst_qgraphicsscene.cpp RESOURCES += images.qrc -win32:!winrt: LIBS += -luser32 +win32:!winrt: QMAKE_USE += user32 DEFINES += SRCDIR=\\\"$$PWD\\\" DEFINES += QT_NO_CAST_TO_ASCII diff --git a/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp b/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp index 4f8741a5aa..4d24814724 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. @@ -26,11 +26,24 @@ ** ****************************************************************************/ +#include <QtWidgets/QApplication> +#include <QtWidgets/QDial> +#include <QtWidgets/QLabel> +#include <QtWidgets/QLineEdit> +#include <QtWidgets/QGraphicsView> +#include <QtWidgets/QGraphicsScene> +#include <QtWidgets/QGraphicsPixmapItem> +#include <QtWidgets/QStyle> +#include <QtWidgets/QStyleFactory> +#include <QtWidgets/QVBoxLayout> + +#include <QtGui/QScreen> #include <QtTest/QtTest> -#include <QtGui> -#include <QtWidgets> +#include <QtCore/QDebug> +#include <QtCore/QLoggingCategory> + #include <private/qgraphicsscene_p.h> #include <private/qgraphicssceneindex_p.h> #include <math.h> @@ -39,7 +52,7 @@ #include <private/qinputmethod_p.h> #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) -#include <windows.h> +#include <QtCore/qt_windows.h> #define Q_CHECK_PAINTEVENTS \ if (::SwitchDesktop(::GetThreadDesktop(::GetCurrentThreadId())) == 0) \ QSKIP("The Graphics View doesn't get the paint events"); @@ -51,6 +64,7 @@ Q_DECLARE_METATYPE(Qt::FocusReason) Q_DECLARE_METATYPE(QPainterPath) Q_DECLARE_METATYPE(Qt::AspectRatioMode) Q_DECLARE_METATYPE(Qt::ItemSelectionMode) +Q_DECLARE_METATYPE(QGraphicsItem::GraphicsItemFlags) static const int randomX[] = {276, 40, 250, 864, -56, 426, 855, 825, 184, 955, -798, -804, 773, 282, 489, 686, 780, -220, 50, 749, -856, -205, 81, 492, -819, 518, @@ -95,14 +109,16 @@ static const int randomY[] = {603, 70, -318, 843, 450, -637, 199, -527, 407, 964 -588, 864, 234, 225, -303, 493, 246, 153, 338, -378, 377, -819, 140, 136, 467, -849, -326, -533, 166, 252, -994, -699, 904, -566, 621, -752}; +Q_LOGGING_CATEGORY(lcTests, "qt.widgets.tests") + class HoverItem : public QGraphicsRectItem { public: HoverItem() - : QGraphicsRectItem(QRectF(-10, -10, 20, 20)), isHovered(false) + : QGraphicsRectItem(QRectF(-10, -10, 20, 20)) { setAcceptHoverEvents(true); } - bool isHovered; + bool isHovered = false; protected: void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) @@ -128,13 +144,13 @@ class EventSpy : public QGraphicsWidget Q_OBJECT public: EventSpy(QObject *watched, QEvent::Type type) - : _count(0), spied(type) + : spied(type) { watched->installEventFilter(this); } EventSpy(QGraphicsScene *scene, QGraphicsItem *watched, QEvent::Type type) - : _count(0), spied(type) + : spied(type) { scene->addItem(this); watched->installSceneEventFilter(this); @@ -143,7 +159,7 @@ public: int count() const { return _count; } protected: - bool eventFilter(QObject *watched, QEvent *event) + bool eventFilter(QObject *watched, QEvent *event) override { Q_UNUSED(watched); if (event->type() == spied) @@ -151,7 +167,7 @@ protected: return false; } - bool sceneEventFilter(QGraphicsItem *watched, QEvent *event) + bool sceneEventFilter(QGraphicsItem *watched, QEvent *event) override { Q_UNUSED(watched); if (event->type() == spied) @@ -159,13 +175,17 @@ protected: return false; } - int _count; - QEvent::Type spied; + int _count = 0; + const QEvent::Type spied; }; class tst_QGraphicsScene : public QObject { Q_OBJECT +public: + tst_QGraphicsScene(); + static void initMain() { QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling); } + public slots: void cleanup(); @@ -268,13 +288,26 @@ private slots: void taskQTBUG_15977_renderWithDeviceCoordinateCache(); void taskQTBUG_16401_focusItem(); void taskQTBUG_42915_focusNextPrevChild(); + +private: + QRect m_availableGeometry = QGuiApplication::primaryScreen()->availableGeometry(); + QSize m_testSize; }; +tst_QGraphicsScene::tst_QGraphicsScene() +{ + const int testSize = qMax(200, m_availableGeometry.width() / 10); + m_testSize.setWidth(testSize); + m_testSize.setHeight(testSize); +} + void tst_QGraphicsScene::cleanup() { // ensure not even skipped tests with custom input context leave it dangling - QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); - inputMethodPrivate->testContext = 0; + QInputMethodPrivate *inputMethodPrivate = + QInputMethodPrivate::get(QGuiApplication::inputMethod()); + inputMethodPrivate->testContext = nullptr; + QTRY_VERIFY(QApplication::topLevelWidgets().isEmpty()); } void tst_QGraphicsScene::construction() @@ -287,7 +320,7 @@ void tst_QGraphicsScene::construction() QVERIFY(scene.items(QPolygonF()).isEmpty()); QVERIFY(scene.items(QPainterPath()).isEmpty()); QTest::ignoreMessage(QtWarningMsg, "QGraphicsScene::collidingItems: cannot find collisions for null item"); - QVERIFY(scene.collidingItems(0).isEmpty()); + QVERIFY(scene.collidingItems(nullptr).isEmpty()); QVERIFY(scene.items(QPointF()).isEmpty()); QVERIFY(scene.selectedItems().isEmpty()); QVERIFY(!scene.focusItem()); @@ -301,7 +334,7 @@ static inline const QGraphicsItem *itemAt(const QGraphicsScene &scene, qreal x, void tst_QGraphicsScene::sceneRect() { QGraphicsScene scene; - QSignalSpy sceneRectChanged(&scene, SIGNAL(sceneRectChanged(QRectF))); + QSignalSpy sceneRectChanged(&scene, &QGraphicsScene::sceneRectChanged); QCOMPARE(scene.sceneRect(), QRectF()); QCOMPARE(sceneRectChanged.count(), 0); @@ -435,9 +468,9 @@ void tst_QGraphicsScene::items() scene.removeItem(items.at(5)); delete items.at(5); - QVERIFY(!scene.items().contains(0)); + QVERIFY(!scene.items().contains(nullptr)); delete items.at(7); - QVERIFY(!scene.items().contains(0)); + QVERIFY(!scene.items().contains(nullptr)); } { QGraphicsScene scene; @@ -516,7 +549,7 @@ void tst_QGraphicsScene::itemsBoundingRect() QGraphicsScene scene; - foreach (QRectF rect, rects) { + for (const auto &rect : qAsConst(rects)) { QPainterPath path; path.addRect(rect); QGraphicsPathItem *item = scene.addPath(path); @@ -581,7 +614,7 @@ void tst_QGraphicsScene::items_QPointF() int n = 0; QList<QGraphicsItem *> addedItems; - foreach(QRectF rect, items) { + for (const auto &rect : qAsConst(items)) { QPainterPath path; path.addRect(0, 0, rect.width(), rect.height()); @@ -593,7 +626,8 @@ void tst_QGraphicsScene::items_QPointF() } QList<int> itemIndexes; - foreach (QGraphicsItem *item, scene.items(point)) + const auto &actualItemsAtPoint = scene.items(point); + for (QGraphicsItem *item : actualItemsAtPoint) itemIndexes << addedItems.indexOf(item); QCOMPARE(itemIndexes, itemsAtPoint); @@ -912,12 +946,11 @@ void tst_QGraphicsScene::items_QPainterPath_2() class CustomView : public QGraphicsView { public: - CustomView() : repaints(0) - { } + using QGraphicsView::QGraphicsView; - int repaints; + int repaints = 0; protected: - void paintEvent(QPaintEvent *event) + void paintEvent(QPaintEvent *event) override { ++repaints; QGraphicsView::paintEvent(event); @@ -927,7 +960,7 @@ protected: void tst_QGraphicsScene::selectionChanged() { QGraphicsScene scene(0, 0, 1000, 1000); - QSignalSpy spy(&scene, SIGNAL(selectionChanged())); + QSignalSpy spy(&scene, &QGraphicsScene::selectionChanged); QCOMPARE(spy.count(), 0); QPainterPath path; @@ -997,7 +1030,7 @@ void tst_QGraphicsScene::selectionChanged() void tst_QGraphicsScene::selectionChanged2() { QGraphicsScene scene; - QSignalSpy spy(&scene, SIGNAL(selectionChanged())); + QSignalSpy spy(&scene, &QGraphicsScene::selectionChanged); QGraphicsItem *item1 = scene.addRect(0, 0, 100, 100); QGraphicsItem *item2 = scene.addRect(100, 100, 100, 100); @@ -1009,13 +1042,13 @@ void tst_QGraphicsScene::selectionChanged2() QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress); event.setScenePos(QPointF(50, 50)); event.setButton(Qt::LeftButton); - qApp->sendEvent(&scene, &event); + QCoreApplication::sendEvent(&scene, &event); } { QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseRelease); event.setScenePos(QPointF(50, 50)); event.setButton(Qt::LeftButton); - qApp->sendEvent(&scene, &event); + QCoreApplication::sendEvent(&scene, &event); } QVERIFY(item1->isSelected()); QVERIFY(!item2->isSelected()); @@ -1024,13 +1057,13 @@ void tst_QGraphicsScene::selectionChanged2() QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress); event.setScenePos(QPointF(150, 150)); event.setButton(Qt::LeftButton); - qApp->sendEvent(&scene, &event); + QCoreApplication::sendEvent(&scene, &event); } { QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseRelease); event.setScenePos(QPointF(150, 150)); event.setButton(Qt::LeftButton); - qApp->sendEvent(&scene, &event); + QCoreApplication::sendEvent(&scene, &event); } QVERIFY(!item1->isSelected()); QVERIFY(item2->isSelected()); @@ -1040,7 +1073,7 @@ void tst_QGraphicsScene::selectionChanged2() event.setScenePos(QPointF(50, 50)); event.setButton(Qt::LeftButton); event.setModifiers(Qt::ControlModifier); - qApp->sendEvent(&scene, &event); + QCoreApplication::sendEvent(&scene, &event); } QVERIFY(!item1->isSelected()); QVERIFY(item2->isSelected()); @@ -1049,7 +1082,7 @@ void tst_QGraphicsScene::selectionChanged2() QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseRelease); event.setScenePos(QPointF(50, 50)); event.setButton(Qt::LeftButton); - qApp->sendEvent(&scene, &event); + QCoreApplication::sendEvent(&scene, &event); } QVERIFY(item1->isSelected()); QVERIFY(!item2->isSelected()); @@ -1065,10 +1098,12 @@ void tst_QGraphicsScene::addItem() QGraphicsScene scene; CustomView view; + view.setWindowTitle(QTest::currentTestFunction()); view.setScene(&scene); + view.resize(m_testSize); view.show(); QVERIFY(QTest::qWaitForWindowExposed(&view)); - qApp->processEvents(); + QCoreApplication::processEvents(); view.repaints = 0; scene.addItem(path); @@ -1115,14 +1150,14 @@ void tst_QGraphicsScene::addEllipse() QCOMPARE(ellipse->pen(), QPen(Qt::red)); QCOMPARE(ellipse->brush(), QBrush(Qt::blue)); QCOMPARE(ellipse->rect(), QRectF(-10, -10, 20, 20)); - QCOMPARE(itemAt(scene, 0, 0), (QGraphicsItem *)ellipse); + QCOMPARE(itemAt(scene, 0, 0), ellipse); QVERIFY(scene.items(QPointF(-10, -10)).isEmpty()); - QCOMPARE(itemAt(scene, -9.9, 0), (QGraphicsItem *)ellipse); + QCOMPARE(itemAt(scene, -9.9, 0), ellipse); QVERIFY(scene.items(QPointF(-10, 10)).isEmpty()); - QCOMPARE(itemAt(scene, 0, -9.9), (QGraphicsItem *)ellipse); - QCOMPARE(itemAt(scene, 0, 9.9), (QGraphicsItem *)ellipse); + QCOMPARE(itemAt(scene, 0, -9.9), ellipse); + QCOMPARE(itemAt(scene, 0, 9.9), ellipse); QVERIFY(scene.items(QPointF(10, -10)).isEmpty()); - QCOMPARE(itemAt(scene, 9.9, 0), (QGraphicsItem *)ellipse); + QCOMPARE(itemAt(scene, 9.9, 0), ellipse); QVERIFY(scene.items(QPointF(10, 10)).isEmpty()); } @@ -1136,15 +1171,15 @@ void tst_QGraphicsScene::addLine() QCOMPARE(line->pos(), QPointF()); QCOMPARE(line->pen(), pen); QCOMPARE(line->line(), QLineF(-10, -10, 20, 20)); - QCOMPARE(itemAt(scene, 0, 0), (QGraphicsItem *)line); - QCOMPARE(itemAt(scene, -10, -10), (QGraphicsItem *)line); + QCOMPARE(itemAt(scene, 0, 0), line); + QCOMPARE(itemAt(scene, -10, -10), line); QVERIFY(scene.items(QPointF(-9.9, 0)).isEmpty()); QVERIFY(scene.items(QPointF(-10, 10)).isEmpty()); QVERIFY(scene.items(QPointF(0, -9.9)).isEmpty()); QVERIFY(scene.items(QPointF(0, 9.9)).isEmpty()); QVERIFY(scene.items(QPointF(10, -10)).isEmpty()); QVERIFY(scene.items(QPointF(9.9, 0)).isEmpty()); - QCOMPARE(itemAt(scene, 10, 10), (QGraphicsItem *)line); + QCOMPARE(itemAt(scene, 10, 10), line); } void tst_QGraphicsScene::addPath() @@ -1162,16 +1197,16 @@ void tst_QGraphicsScene::addPath() path->setPen(QPen(Qt::red, 0)); - QCOMPARE(itemAt(scene, 0, 0), (QGraphicsItem *)path); - QCOMPARE(itemAt(scene, -9.9, 0), (QGraphicsItem *)path); - QCOMPARE(itemAt(scene, 9.9, 0), (QGraphicsItem *)path); - QCOMPARE(itemAt(scene, 0, -9.9), (QGraphicsItem *)path); - QCOMPARE(itemAt(scene, 0, 9.9), (QGraphicsItem *)path); - QCOMPARE(itemAt(scene, 0, 30), (QGraphicsItem *)path); - QCOMPARE(itemAt(scene, -9.9, 30), (QGraphicsItem *)path); - QCOMPARE(itemAt(scene, 9.9, 30), (QGraphicsItem *)path); - QCOMPARE(itemAt(scene, 0, 20.1), (QGraphicsItem *)path); - QCOMPARE(itemAt(scene, 0, 39.9), (QGraphicsItem *)path); + QCOMPARE(itemAt(scene, 0, 0), path); + QCOMPARE(itemAt(scene, -9.9, 0), path); + QCOMPARE(itemAt(scene, 9.9, 0), path); + QCOMPARE(itemAt(scene, 0, -9.9), path); + QCOMPARE(itemAt(scene, 0, 9.9), path); + QCOMPARE(itemAt(scene, 0, 30), path); + QCOMPARE(itemAt(scene, -9.9, 30), path); + QCOMPARE(itemAt(scene, 9.9, 30), path); + QCOMPARE(itemAt(scene, 0, 20.1), path); + QCOMPARE(itemAt(scene, 0, 39.9), path); QVERIFY(scene.items(QPointF(-10, -10)).isEmpty()); QVERIFY(scene.items(QPointF(10, -10)).isEmpty()); QVERIFY(scene.items(QPointF(-10, 10)).isEmpty()); @@ -1193,10 +1228,10 @@ void tst_QGraphicsScene::addPixmap() QCOMPARE(pixmap->pos(), QPointF()); QCOMPARE(pixmap->pixmap(), pix); - QCOMPARE(itemAt(scene, 0, 0), (QGraphicsItem *)pixmap); - QCOMPARE(itemAt(scene, pix.width() - 1, 0), (QGraphicsItem *)pixmap); - QCOMPARE(itemAt(scene, 0, pix.height() - 1), (QGraphicsItem *)pixmap); - QCOMPARE(itemAt(scene, pix.width() - 1, pix.height() - 1), (QGraphicsItem *)pixmap); + QCOMPARE(itemAt(scene, 0, 0), pixmap); + QCOMPARE(itemAt(scene, pix.width() - 1, 0), pixmap); + QCOMPARE(itemAt(scene, 0, pix.height() - 1), pixmap); + QCOMPARE(itemAt(scene, pix.width() - 1, pix.height() - 1), pixmap); QVERIFY(scene.items(QPointF(-1, -1)).isEmpty()); QVERIFY(scene.items(QPointF(pix.width() - 1, -1)).isEmpty()); @@ -1218,14 +1253,14 @@ void tst_QGraphicsScene::addRect() rect->setPen(QPen(Qt::red, 0)); - QCOMPARE(itemAt(scene, 0, 0), (QGraphicsItem *)rect); - QCOMPARE(itemAt(scene, -10, -10), (QGraphicsItem *)rect); - QCOMPARE(itemAt(scene, -9.9, 0), (QGraphicsItem *)rect); + QCOMPARE(itemAt(scene, 0, 0),rect); + QCOMPARE(itemAt(scene, -10, -10), rect); + QCOMPARE(itemAt(scene, -9.9, 0), rect); QVERIFY(scene.items(QPointF(-10, 10)).isEmpty()); - QCOMPARE(itemAt(scene, 0, -9.9), (QGraphicsItem *)rect); - QCOMPARE(itemAt(scene, 0, 9.9), (QGraphicsItem *)rect); + QCOMPARE(itemAt(scene, 0, -9.9), rect); + QCOMPARE(itemAt(scene, 0, 9.9), rect); QVERIFY(scene.items(QPointF(10, -10)).isEmpty()); - QCOMPARE(itemAt(scene, 9.9, 0), (QGraphicsItem *)rect); + QCOMPARE(itemAt(scene, 9.9, 0), rect); QVERIFY(scene.items(QPointF(10, 10)).isEmpty()); } @@ -1271,6 +1306,7 @@ void tst_QGraphicsScene::removeItem() scene.setSceneRect(-50, -50, 100, 100); QGraphicsView view(&scene); + view.setWindowTitle(QTest::currentTestFunction()); view.setFixedSize(150, 150); view.show(); QApplication::setActiveWindow(&view); @@ -1342,7 +1378,7 @@ void tst_QGraphicsScene::focusItem() class FocusItem : public QGraphicsTextItem { protected: - void focusOutEvent(QFocusEvent *) + void focusOutEvent(QFocusEvent *) override { QVERIFY(!scene()->focusItem()); } @@ -1359,14 +1395,14 @@ void tst_QGraphicsScene::focusItemLostFocus() scene.addItem(item); item->setFocus(); - QCOMPARE(scene.focusItem(), (QGraphicsItem *)item); + QCOMPARE(scene.focusItem(), item); item->clearFocus(); } class ClearTestItem : public QGraphicsRectItem { public: - ClearTestItem(QGraphicsItem *parent = 0) : QGraphicsRectItem(parent) {} + using QGraphicsRectItem::QGraphicsRectItem; ~ClearTestItem() { qDeleteAll(items); } QList<QGraphicsItem *> items; }; @@ -1389,7 +1425,7 @@ void tst_QGraphicsScene::clear() scene.setItemIndexMethod(QGraphicsScene::NoIndex); scene.addItem(firstItem); scene.addItem(secondItem); - QCOMPARE(scene.items().at(0), (QGraphicsItem*)firstItem); + QCOMPARE(scene.items().at(0), firstItem); QCOMPARE(scene.items().at(1), secondItem); ClearTestItem *thirdItem = new ClearTestItem(firstItem); @@ -1441,7 +1477,7 @@ void tst_QGraphicsScene::setFocusItem() QVERIFY(item->hasFocus()); QVERIFY(!item2->hasFocus()); - scene.setFocusItem(0); + scene.setFocusItem(nullptr); QVERIFY(!item->hasFocus()); QVERIFY(!item2->hasFocus()); @@ -1562,26 +1598,26 @@ void tst_QGraphicsScene::hoverEvents_siblings() Q_CHECK_PAINTEVENTS QGraphicsScene scene; - QGraphicsItem *lastItem = 0; + QGraphicsItem *lastItem = nullptr; QList<HoverItem *> items; for (int i = 0; i < 15; ++i) { - QGraphicsItem *item = new HoverItem; + auto item = new HoverItem; scene.addItem(item); - items << (HoverItem *)item; - if (lastItem) { + items << item; + if (lastItem) item->setPos(lastItem->pos() + QPointF(sin(i / 3.0) * 17, cos(i / 3.0) * 17)); - } item->setZValue(i); lastItem = item; } QGraphicsView view(&scene); + view.setWindowTitle(QTest::currentTestFunction()); view.setRenderHint(QPainter::Antialiasing, true); view.setMinimumSize(400, 300); view.rotate(10); view.scale(1.7, 1.7); view.show(); - qApp->setActiveWindow(&view); + QApplication::setActiveWindow(&view); view.activateWindow(); QVERIFY(QTest::qWaitForWindowActive(&view)); @@ -1604,8 +1640,8 @@ void tst_QGraphicsScene::hoverEvents_siblings() mouseEvent.setScenePos(items.at(i)->mapToScene(0, 0)); QApplication::sendEvent(&scene, &mouseEvent); - qApp->processEvents(); // this posts updates from the scene to the view - qApp->processEvents(); // which trigger a repaint here + QCoreApplication::processEvents(); // this posts updates from the scene to the view + QCoreApplication::processEvents(); // which trigger a repaint here QTRY_VERIFY(items.at(i)->isHovered); if (j && i > 0) @@ -1621,8 +1657,8 @@ void tst_QGraphicsScene::hoverEvents_siblings() mouseEvent.setScenePos(QPointF(-1000, -1000)); QApplication::sendEvent(&scene, &mouseEvent); - qApp->processEvents(); // this posts updates from the scene to the view - qApp->processEvents(); // which trigger a repaint here + QCoreApplication::processEvents(); // this posts updates from the scene to the view + QCoreApplication::processEvents(); // which trigger a repaint here } } @@ -1631,12 +1667,12 @@ void tst_QGraphicsScene::hoverEvents_parentChild() Q_CHECK_PAINTEVENTS QGraphicsScene scene; - QGraphicsItem *lastItem = 0; + QGraphicsItem *lastItem = nullptr; QList<HoverItem *> items; for (int i = 0; i < 15; ++i) { - QGraphicsItem *item = new HoverItem; + auto item = new HoverItem; scene.addItem(item); - items << (HoverItem *)item; + items << item; if (lastItem) { item->setParentItem(lastItem); item->setPos(sin(i / 3.0) * 17, cos(i / 3.0) * 17); @@ -1645,12 +1681,13 @@ void tst_QGraphicsScene::hoverEvents_parentChild() } QGraphicsView view(&scene); + view.setWindowTitle(QTest::currentTestFunction()); view.setRenderHint(QPainter::Antialiasing, true); view.setMinimumSize(400, 300); view.rotate(10); view.scale(1.7, 1.7); view.show(); - qApp->setActiveWindow(&view); + QApplication::setActiveWindow(&view); QVERIFY(QTest::qWaitForWindowActive(&view)); QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseMove); @@ -1669,8 +1706,8 @@ void tst_QGraphicsScene::hoverEvents_parentChild() mouseEvent.setScenePos(items.at(i)->mapToScene(0, 0)); QApplication::sendEvent(&scene, &mouseEvent); - qApp->processEvents(); // this posts updates from the scene to the view - qApp->processEvents(); // which trigger a repaint here + QCoreApplication::processEvents(); // this posts updates from the scene to the view + QCoreApplication::processEvents(); // which trigger a repaint here QTRY_VERIFY(items.at(i)->isHovered); if (i < 14) @@ -1683,8 +1720,8 @@ void tst_QGraphicsScene::hoverEvents_parentChild() mouseEvent.setScenePos(QPointF(-1000, -1000)); QApplication::sendEvent(&scene, &mouseEvent); - qApp->processEvents(); // this posts updates from the scene to the view - qApp->processEvents(); // which trigger a repaint here + QCoreApplication::processEvents(); // this posts updates from the scene to the view + QCoreApplication::processEvents(); // which trigger a repaint here } } @@ -1712,23 +1749,23 @@ void tst_QGraphicsScene::createItemGroup() // All items in children1 are children of parent1 QGraphicsItem *parent1 = scene.addRect(QRectF(-10, -10, 20, 20)); - foreach (QGraphicsItem *item, children1) + for (QGraphicsItem *item : qAsConst(children1)) item->setParentItem(parent1); QGraphicsItemGroup *group = scene.createItemGroup(children1); QCOMPARE(group->parentItem(), parent1); - QCOMPARE(children1.first()->parentItem(), (QGraphicsItem *)group); + QCOMPARE(children1.first()->parentItem(), group); scene.destroyItemGroup(group); QCOMPARE(children1.first()->parentItem(), parent1); group = scene.createItemGroup(children1); QCOMPARE(group->parentItem(), parent1); - QCOMPARE(children1.first()->parentItem(), (QGraphicsItem *)group); + QCOMPARE(children1.first()->parentItem(), group); scene.destroyItemGroup(group); QCOMPARE(children1.first()->parentItem(), parent1); // All items in children2 are children of parent2 QGraphicsItem *parent2 = scene.addRect(QRectF(-10, -10, 20, 20)); - foreach (QGraphicsItem *item, children2) + for (QGraphicsItem *item : qAsConst(children2)) item->setParentItem(parent2); // Now make parent2 a child of parent1, so all children2 are also children @@ -1738,21 +1775,21 @@ void tst_QGraphicsScene::createItemGroup() // The children2 group should still have parent2 as their common ancestor. group = scene.createItemGroup(children2); QCOMPARE(group->parentItem(), parent2); - QCOMPARE(children2.first()->parentItem(), (QGraphicsItem *)group); + QCOMPARE(children2.first()->parentItem(), group); scene.destroyItemGroup(group); QCOMPARE(children2.first()->parentItem(), parent2); // But the set of both children2 and children1 share only parent1. group = scene.createItemGroup(children2 + children1); QCOMPARE(group->parentItem(), parent1); - QCOMPARE(children1.first()->parentItem(), (QGraphicsItem *)group); - QCOMPARE(children2.first()->parentItem(), (QGraphicsItem *)group); + QCOMPARE(children1.first()->parentItem(), group); + QCOMPARE(children2.first()->parentItem(), group); scene.destroyItemGroup(group); QCOMPARE(children1.first()->parentItem(), parent1); QCOMPARE(children2.first()->parentItem(), parent1); // Fixup the parent-child chain - foreach (QGraphicsItem *item, children2) + for (QGraphicsItem *item : qAsConst(children2)) item->setParentItem(parent2); // These share no common parent @@ -1762,7 +1799,7 @@ void tst_QGraphicsScene::createItemGroup() // Make children3 children of parent3 QGraphicsItem *parent3 = scene.addRect(QRectF(-10, -10, 20, 20)); - foreach (QGraphicsItem *item, children3) + for (QGraphicsItem *item : qAsConst(children3)) item->setParentItem(parent3); // These should have parent3 as a parent @@ -1794,15 +1831,14 @@ void tst_QGraphicsScene::createItemGroup() class EventTester : public QGraphicsEllipseItem { public: - EventTester() - : QGraphicsEllipseItem(QRectF(-10, -10, 20, 20)), ignoreMouse(false) + EventTester() : QGraphicsEllipseItem(QRectF(-10, -10, 20, 20)) { } - bool ignoreMouse; - QList<QEvent::Type> eventTypes; + bool ignoreMouse = false; + QVector<QEvent::Type> eventTypes; protected: - bool sceneEvent(QEvent *event) + bool sceneEvent(QEvent *event) override { eventTypes << QEvent::Type(event->type()); switch (event->type()) { @@ -1813,6 +1849,7 @@ protected: event->ignore(); return true; } + break; default: break; } @@ -1867,7 +1904,7 @@ void tst_QGraphicsScene::mouseEventPropagation() QCOMPARE(c->eventTypes.size(), 0); QCOMPARE(b->eventTypes.size(), 0); QCOMPARE(a->eventTypes.size(), 0); - QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)d); + QCOMPARE(scene.mouseGrabberItem(), d); // Send a move QApplication::sendEvent(&scene, &moveEvent); @@ -1876,7 +1913,7 @@ void tst_QGraphicsScene::mouseEventPropagation() QCOMPARE(c->eventTypes.size(), 0); QCOMPARE(b->eventTypes.size(), 0); QCOMPARE(a->eventTypes.size(), 0); - QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)d); + QCOMPARE(scene.mouseGrabberItem(), d); // Send a release QApplication::sendEvent(&scene, &releaseEvent); @@ -1898,7 +1935,7 @@ void tst_QGraphicsScene::mouseEventPropagation() QCOMPARE(c->eventTypes.at(1), QEvent::GraphicsSceneMousePress); QCOMPARE(b->eventTypes.size(), 0); QCOMPARE(a->eventTypes.size(), 0); - QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)c); + QCOMPARE(scene.mouseGrabberItem(), c); // Send another press, with a button that isn't actually accepted QApplication::sendEvent(&scene, &pressEvent); @@ -1908,7 +1945,7 @@ void tst_QGraphicsScene::mouseEventPropagation() QCOMPARE(c->eventTypes.at(2), QEvent::GraphicsSceneMousePress); QCOMPARE(b->eventTypes.size(), 0); QCOMPARE(a->eventTypes.size(), 0); - QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)c); + QCOMPARE(scene.mouseGrabberItem(), c); // Send a move QApplication::sendEvent(&scene, &moveEvent); @@ -1917,7 +1954,7 @@ void tst_QGraphicsScene::mouseEventPropagation() QCOMPARE(c->eventTypes.at(3), QEvent::GraphicsSceneMouseMove); QCOMPARE(b->eventTypes.size(), 0); QCOMPARE(a->eventTypes.size(), 0); - QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)c); + QCOMPARE(scene.mouseGrabberItem(), c); // Send a release QApplication::sendEvent(&scene, &releaseEvent); @@ -1950,7 +1987,7 @@ void tst_QGraphicsScene::mouseEventPropagation() QCOMPARE(c->eventTypes.at(7), QEvent::GraphicsSceneMousePress); QCOMPARE(b->eventTypes.size(), 0); QCOMPARE(a->eventTypes.size(), 0); - QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)c); + QCOMPARE(scene.mouseGrabberItem(), c); // Clicking outside the items removes the mouse grabber } @@ -1999,7 +2036,7 @@ void tst_QGraphicsScene::mouseEventPropagation_ignore() QCOMPARE(d->eventTypes.at(0), QEvent::GrabMouse); QCOMPARE(d->eventTypes.at(1), QEvent::GraphicsSceneMousePress); QCOMPARE(d->eventTypes.at(2), QEvent::UngrabMouse); - QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)a); + QCOMPARE(scene.mouseGrabberItem(), a); a->ignoreMouse = true; @@ -2115,7 +2152,7 @@ public: QVector<QPointF> mouseMovePoints; protected: - void mouseMoveEvent(QGraphicsSceneMouseEvent *event) + void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override { mouseMovePoints << event->scenePos(); } @@ -2140,22 +2177,17 @@ void tst_QGraphicsScene::mouseEventPropagation_mouseMove() class DndTester : public QGraphicsEllipseItem { public: - DndTester(const QRectF &rect) - : QGraphicsEllipseItem(rect), lastEvent(0), - ignoresDragEnter(false), ignoresDragMove(false) - - { - } + using QGraphicsEllipseItem::QGraphicsEllipseItem; ~DndTester() { delete lastEvent; } - QGraphicsSceneDragDropEvent *lastEvent; + QGraphicsSceneDragDropEvent *lastEvent = nullptr; QList<QEvent::Type> eventList; - bool ignoresDragEnter; - bool ignoresDragMove; + bool ignoresDragEnter = false; + bool ignoresDragMove = false; protected: void dragEnterEvent(QGraphicsSceneDragDropEvent *event) @@ -2218,21 +2250,21 @@ void tst_QGraphicsScene::dragAndDrop_simple() QMimeData mimeData; // Initial drag enter for the scene - QDragEnterEvent dragEnter(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragEnterEvent dragEnter(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragEnter); QVERIFY(dragEnter.isAccepted()); QCOMPARE(dragEnter.dropAction(), Qt::CopyAction); { // Move outside the item - QDragMoveEvent dragMove(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(!dragMove.isAccepted()); QCOMPARE(dragMove.dropAction(), Qt::CopyAction); } { // Move inside the item without setAcceptDrops - QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(!dragMove.isAccepted()); QCOMPARE(dragMove.dropAction(), Qt::CopyAction); @@ -2241,7 +2273,7 @@ void tst_QGraphicsScene::dragAndDrop_simple() item->setAcceptDrops(true); { // Move inside the item with setAcceptDrops - QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(dragMove.isAccepted()); QCOMPARE(dragMove.dropAction(), Qt::IgnoreAction); @@ -2255,7 +2287,7 @@ void tst_QGraphicsScene::dragAndDrop_simple() } { // Another move inside the item - QDragMoveEvent dragMove(view.mapFromScene(item->mapToScene(5, 5)), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(view.mapFromScene(item->mapToScene(5, 5)), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(dragMove.isAccepted()); QCOMPARE(dragMove.dropAction(), Qt::IgnoreAction); @@ -2268,7 +2300,7 @@ void tst_QGraphicsScene::dragAndDrop_simple() } { // Move outside the item - QDragMoveEvent dragMove(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(!dragMove.isAccepted()); QCOMPARE(dragMove.dropAction(), Qt::CopyAction); @@ -2281,7 +2313,7 @@ void tst_QGraphicsScene::dragAndDrop_simple() } { // Move inside the item again - QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(dragMove.isAccepted()); QCOMPARE(dragMove.dropAction(), Qt::IgnoreAction); @@ -2295,7 +2327,7 @@ void tst_QGraphicsScene::dragAndDrop_simple() } { // Drop inside the item - QDropEvent drop(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDropEvent drop(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &drop); QVERIFY(drop.isAccepted()); QCOMPARE(drop.dropAction(), Qt::CopyAction); @@ -2322,13 +2354,13 @@ void tst_QGraphicsScene::dragAndDrop_disabledOrInvisible() QMimeData mimeData; // Initial drag enter for the scene - QDragEnterEvent dragEnter(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragEnterEvent dragEnter(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragEnter); QVERIFY(dragEnter.isAccepted()); QCOMPARE(dragEnter.dropAction(), Qt::CopyAction); { // Move inside the item - QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(dragMove.isAccepted()); QCOMPARE(dragMove.dropAction(), Qt::IgnoreAction); @@ -2338,7 +2370,7 @@ void tst_QGraphicsScene::dragAndDrop_disabledOrInvisible() } { // Move outside the item - QDragMoveEvent dragMove(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(!dragMove.isAccepted()); QCOMPARE(dragMove.dropAction(), Qt::CopyAction); @@ -2353,7 +2385,7 @@ void tst_QGraphicsScene::dragAndDrop_disabledOrInvisible() { // Move inside the item - QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(!dragMove.isAccepted()); QCOMPARE(dragMove.dropAction(), Qt::CopyAction); @@ -2369,7 +2401,7 @@ void tst_QGraphicsScene::dragAndDrop_disabledOrInvisible() { // Move inside the item - QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(!dragMove.isAccepted()); QCOMPARE(dragMove.dropAction(), Qt::CopyAction); @@ -2378,7 +2410,7 @@ void tst_QGraphicsScene::dragAndDrop_disabledOrInvisible() } // Dummy drop event to keep the Mac from crashing. - QDropEvent dropEvent(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDropEvent dropEvent(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dropEvent); } @@ -2405,14 +2437,14 @@ void tst_QGraphicsScene::dragAndDrop_propagate() QMimeData mimeData; // Initial drag enter for the scene - QDragEnterEvent dragEnter(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragEnterEvent dragEnter(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragEnter); QVERIFY(dragEnter.isAccepted()); QCOMPARE(dragEnter.dropAction(), Qt::CopyAction); { // Move outside the items - QDragMoveEvent dragMove(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(!dragMove.isAccepted()); QCOMPARE(dragMove.dropAction(), Qt::CopyAction); @@ -2421,7 +2453,7 @@ void tst_QGraphicsScene::dragAndDrop_propagate() } { // Move inside item1 - QDragMoveEvent dragMove(view.mapFromScene(-5, -5), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(view.mapFromScene(-5, -5), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(dragMove.isAccepted()); QCOMPARE(dragMove.dropAction(), Qt::IgnoreAction); @@ -2432,7 +2464,7 @@ void tst_QGraphicsScene::dragAndDrop_propagate() { // Move into the intersection item1-item2 - QDragMoveEvent dragMove(view.mapFromScene(5, 5), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(view.mapFromScene(5, 5), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(!dragMove.isAccepted()); // move does not propagate, (ignoresDragMove = true) QCOMPARE(item1->eventList.size(), 3); @@ -2443,7 +2475,7 @@ void tst_QGraphicsScene::dragAndDrop_propagate() } { // Move into the item2 - QDragMoveEvent dragMove(view.mapFromScene(15, 15), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(view.mapFromScene(15, 15), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(!dragMove.isAccepted()); QCOMPARE(dragMove.dropAction(), Qt::CopyAction); @@ -2453,7 +2485,7 @@ void tst_QGraphicsScene::dragAndDrop_propagate() } { // Move inside item1 - QDragMoveEvent dragMove(view.mapFromScene(-5, -5), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(view.mapFromScene(-5, -5), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(dragMove.isAccepted()); QCOMPARE(dragMove.dropAction(), Qt::IgnoreAction); @@ -2467,7 +2499,7 @@ void tst_QGraphicsScene::dragAndDrop_propagate() { item2->ignoresDragEnter = true; // Move into the intersection item1-item2 - QDragMoveEvent dragMove(view.mapFromScene(5, 5), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(view.mapFromScene(5, 5), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(dragMove.isAccepted()); // dragEnter propagates down to item1, which then accepts the move event. QCOMPARE(dragMove.dropAction(), Qt::IgnoreAction); @@ -2480,7 +2512,7 @@ void tst_QGraphicsScene::dragAndDrop_propagate() { item2->ignoresDragEnter = false; // Drop on the intersection item1-item2 - QDropEvent drop(view.mapFromScene(5, 5), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDropEvent drop(view.mapFromScene(5, 5), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &drop); QVERIFY(drop.isAccepted()); QCOMPARE(drop.dropAction(), Qt::CopyAction); @@ -2491,7 +2523,7 @@ void tst_QGraphicsScene::dragAndDrop_propagate() } // Dummy drop event to keep the Mac from crashing. - QDropEvent dropEvent(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDropEvent dropEvent(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dropEvent); } #endif @@ -2580,6 +2612,8 @@ void tst_QGraphicsScene::render() pix.fill(Qt::blue); QGraphicsView view; + view.setWindowTitle(QTest::currentTestFunction()); + view.resize(m_testSize); QGraphicsScene scene(&view); scene.addEllipse(QRectF(-10, -10, 20, 20), QPen(Qt::black, 0), QBrush(Qt::white)); scene.addEllipse(QRectF(-2, -7, 4, 4), QPen(Qt::black, 0), QBrush(Qt::yellow))->setZValue(1); @@ -2642,6 +2676,7 @@ void tst_QGraphicsScene::render() gridLayout->addWidget(newLabel, 2, 0); QWidget widget; + widget.setWindowTitle(QTest::currentTestFunction()); widget.setLayout(gridLayout); widget.show(); @@ -2660,33 +2695,32 @@ void tst_QGraphicsScene::renderItemsWithNegativeWidthOrHeight() #if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) || defined(Q_OS_WINRT) QSKIP("Test only works on platforms with resizable windows"); #endif - - QGraphicsScene scene(0, 0, 150, 150); + QGraphicsScene scene(0, 0, m_testSize.width(), m_testSize.height()); // Add item with negative width. - QGraphicsRectItem *item1 = new QGraphicsRectItem(0, 0, -150, 50); + QGraphicsRectItem *item1 = new QGraphicsRectItem(0, 0, -m_testSize.width(), 50); item1->setBrush(Qt::red); - item1->setPos(150, 50); + item1->setPos(m_testSize.width(), 50); scene.addItem(item1); // Add item with negative height. - QGraphicsRectItem *item2 = new QGraphicsRectItem(0, 0, 50, -150); + QGraphicsRectItem *item2 = new QGraphicsRectItem(0, 0, 50, -m_testSize.height()); item2->setBrush(Qt::blue); - item2->setPos(50, 150); + item2->setPos(50, m_testSize.height()); scene.addItem(item2); QGraphicsView view(&scene); + view.setWindowTitle(QTest::currentTestFunction()); view.setFrameStyle(QFrame::NoFrame); - view.resize(150, 150); view.show(); - QCOMPARE(view.viewport()->size(), QSize(150, 150)); + QTRY_COMPARE(view.viewport()->size(), m_testSize); QImage expected(view.viewport()->size(), QImage::Format_RGB32); view.viewport()->render(&expected); // Make sure the scene background is the same as the viewport background. scene.setBackgroundBrush(view.viewport()->palette().brush(view.viewport()->backgroundRole())); - QImage actual(150, 150, QImage::Format_RGB32); + QImage actual(m_testSize, QImage::Format_RGB32); QPainter painter(&actual); scene.render(&painter); painter.end(); @@ -2710,6 +2744,8 @@ void tst_QGraphicsScene::contextMenuEvent() QVERIFY(scene.hasFocus()); QGraphicsView view(&scene); + view.setWindowTitle(QTest::currentTestFunction()); + view.resize(m_testSize); view.show(); view.activateWindow(); QVERIFY(QTest::qWaitForWindowActive(&view)); @@ -2726,11 +2762,11 @@ void tst_QGraphicsScene::contextMenuEvent() class ContextMenuItem : public QGraphicsRectItem { public: - ContextMenuItem() : QGraphicsRectItem(0, 0, 100, 100) + ContextMenuItem(const QSize &s) : QGraphicsRectItem(0, 0, s.width(), s.height()) { setBrush(Qt::red); } protected: - void contextMenuEvent(QGraphicsSceneContextMenuEvent *) + void contextMenuEvent(QGraphicsSceneContextMenuEvent *) override { /* just accept */ } }; @@ -2740,26 +2776,30 @@ void tst_QGraphicsScene::contextMenuEvent_ItemIgnoresTransformations() QSKIP("Test fails on some Android devices (QTBUG-44430)"); #endif - QGraphicsScene scene(0, 0, 200, 200); - ContextMenuItem *item = new ContextMenuItem; + QGraphicsScene scene(0, 0, m_testSize.width(), m_testSize.height()); + const QSize itemSize = m_testSize / 2; + ContextMenuItem *item = new ContextMenuItem(itemSize); item->setFlag(QGraphicsItem::ItemIgnoresTransformations); scene.addItem(item); QWidget topLevel; + topLevel.setWindowTitle(QTest::currentTestFunction()); + topLevel.resize(m_testSize); QGraphicsView view(&scene, &topLevel); - view.resize(200, 200); topLevel.show(); QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + + { - QPoint pos(50, 50); + QPoint pos(itemSize.width() / 2, itemSize.height() / 2); QContextMenuEvent event(QContextMenuEvent::Keyboard, pos, view.viewport()->mapToGlobal(pos)); event.ignore(); QApplication::sendEvent(view.viewport(), &event); QVERIFY(event.isAccepted()); } { - QPoint pos(150, 150); + QPoint pos(itemSize.width() * 3 / 2, itemSize.height() * 3 / 2); QContextMenuEvent event(QContextMenuEvent::Keyboard, pos, view.viewport()->mapToGlobal(pos)); event.ignore(); QApplication::sendEvent(view.viewport(), &event); @@ -2767,14 +2807,14 @@ void tst_QGraphicsScene::contextMenuEvent_ItemIgnoresTransformations() } view.scale(1.5, 1.5); { - QPoint pos(25, 25); + QPoint pos(itemSize.width() / 4, itemSize.height() / 4); QContextMenuEvent event(QContextMenuEvent::Keyboard, pos, view.viewport()->mapToGlobal(pos)); event.ignore(); QApplication::sendEvent(view.viewport(), &event); QVERIFY(event.isAccepted()); } { - QPoint pos(55, 55); + QPoint pos(itemSize.width() / 2 + 5, itemSize.height() / 2 + 5); QContextMenuEvent event(QContextMenuEvent::Keyboard, pos, view.viewport()->mapToGlobal(pos)); event.ignore(); QApplication::sendEvent(view.viewport(), &event); @@ -2790,14 +2830,14 @@ void tst_QGraphicsScene::update() QGraphicsRectItem *rect = new QGraphicsRectItem(0, 0, 100, 100); rect->setPen(QPen(Qt::black, 0)); scene.addItem(rect); - qApp->processEvents(); + QCoreApplication::processEvents(); rect->setPos(-100, -100); // This function forces indexing itemAt(scene, 0, 0); qRegisterMetaType<QList<QRectF> >("QList<QRectF>"); - QSignalSpy spy(&scene, SIGNAL(changed(QList<QRectF>))); + QSignalSpy spy(&scene, &QGraphicsScene::changed); // We update the scene. scene.update(); @@ -2806,12 +2846,13 @@ void tst_QGraphicsScene::update() itemAt(scene, 0, 0); // This will process the pending update - QApplication::instance()->processEvents(); + QCoreApplication::processEvents(); // Check that the update region is correct QCOMPARE(spy.count(), 1); QRectF region; - foreach (QRectF rectF, qvariant_cast<QList<QRectF> >(spy.at(0).at(0))) + const auto &rects = qvariant_cast<QList<QRectF> >(spy.at(0).at(0)); + for (const auto &rectF : rects) region |= rectF; QCOMPARE(region, QRectF(-100, -100, 200, 200)); } @@ -2821,9 +2862,11 @@ void tst_QGraphicsScene::update2() QGraphicsScene scene; scene.setSceneRect(-200, -200, 200, 200); CustomView view; + view.setWindowTitle(QTest::currentTestFunction()); + view.resize(m_testSize); view.setScene(&scene); view.show(); - qApp->setActiveWindow(&view); + QApplication::setActiveWindow(&view); QVERIFY(QTest::qWaitForWindowActive(&view)); QTRY_VERIFY(view.repaints >= 1); view.repaints = 0; @@ -2831,13 +2874,13 @@ void tst_QGraphicsScene::update2() // Make sure QGraphicsScene::update only requires one event-loop iteration // before the view is updated. scene.update(); - qApp->processEvents(); + QCoreApplication::processEvents(); QTRY_COMPARE(view.repaints, 1); view.repaints = 0; // The same for partial scene updates. scene.update(QRectF(-100, -100, 100, 100)); - qApp->processEvents(); + QCoreApplication::processEvents(); QCOMPARE(view.repaints, 1); } @@ -2853,7 +2896,7 @@ void tst_QGraphicsScene::views() QCOMPARE(scene.views().size(), 2); QVERIFY(scene.views().contains(&view1)); - view.setScene(0); + view.setScene(nullptr); QCOMPARE(scene.views().size(), 1); QCOMPARE(scene.views().at(0), &view1); @@ -2871,12 +2914,12 @@ void tst_QGraphicsScene::views() class CustomScene : public QGraphicsScene { public: - CustomScene() : gotTimerEvent(false) + CustomScene() { startTimer(10); } - bool gotTimerEvent; + bool gotTimerEvent = false; protected: - void timerEvent(QTimerEvent *) + void timerEvent(QTimerEvent *) override { gotTimerEvent = true; } @@ -2893,7 +2936,7 @@ void tst_QGraphicsScene::testEvent() class DisabledItemTester : public QGraphicsRectItem { public: - DisabledItemTester(const QRectF &rect, QGraphicsItem *parent = 0) + DisabledItemTester(const QRectF &rect, QGraphicsItem *parent = nullptr) : QGraphicsRectItem(rect, parent) { } @@ -2901,13 +2944,13 @@ public: QList<QEvent::Type> receivedSceneEventFilters; protected: - bool sceneEventFilter(QGraphicsItem *watched, QEvent *event) + bool sceneEventFilter(QGraphicsItem *watched, QEvent *event) override { receivedSceneEventFilters << event->type(); return QGraphicsRectItem::sceneEventFilter(watched, event); } - bool sceneEvent(QEvent *event) + bool sceneEvent(QEvent *event) override { receivedSceneEvents << event->type(); return QGraphicsRectItem::sceneEvent(event); @@ -2965,11 +3008,9 @@ void tst_QGraphicsScene::eventsToDisabledItems() class ExposedPixmapItem : public QGraphicsPixmapItem { public: - ExposedPixmapItem(QGraphicsItem *item = 0) - : QGraphicsPixmapItem(item) - { } + using QGraphicsPixmapItem::QGraphicsPixmapItem; - void paint(QPainter *, const QStyleOptionGraphicsItem *option, QWidget *) + void paint(QPainter *, const QStyleOptionGraphicsItem *option, QWidget *) override { exposed = option->exposedRect; } @@ -3013,8 +3054,9 @@ void tst_QGraphicsScene::tabFocus_emptyScene() QWidget widget; widget.setLayout(layout); + widget.setWindowTitle(QTest::currentTestFunction()); widget.show(); - qApp->setActiveWindow(&widget); + QApplication::setActiveWindow(&widget); widget.activateWindow(); QVERIFY(QTest::qWaitForWindowActive(&widget)); @@ -3060,9 +3102,10 @@ void tst_QGraphicsScene::tabFocus_sceneWithFocusableItems() layout->addWidget(dial2); QWidget widget; + widget.setWindowTitle(QTest::currentTestFunction()); widget.setLayout(layout); widget.show(); - qApp->setActiveWindow(&widget); + QApplication::setActiveWindow(&widget); widget.activateWindow(); QVERIFY(QTest::qWaitForWindowActive(&widget)); @@ -3112,18 +3155,18 @@ void tst_QGraphicsScene::tabFocus_sceneWithFocusableItems() QVERIFY(!view->viewport()->hasFocus()); QVERIFY(!scene.hasFocus()); QVERIFY(!item->hasFocus()); - QCOMPARE(scene.focusItem(), static_cast<QGraphicsItem *>(item)); + QCOMPARE(scene.focusItem(), item); // Check that the correct item regains focus. widget.show(); - qApp->setActiveWindow(&widget); + QApplication::setActiveWindow(&widget); widget.activateWindow(); QVERIFY(QTest::qWaitForWindowActive(&widget)); QVERIFY(view->hasFocus()); QTRY_VERIFY(scene.isActive()); QVERIFY(view->viewport()->hasFocus()); QVERIFY(scene.hasFocus()); - QCOMPARE(scene.focusItem(), static_cast<QGraphicsItem *>(item)); + QCOMPARE(scene.focusItem(), item); QVERIFY(item->hasFocus()); } @@ -3131,14 +3174,13 @@ class FocusWidget : public QGraphicsWidget { Q_OBJECT public: - FocusWidget(QGraphicsItem *parent = 0) - : QGraphicsWidget(parent), tabs(0), backTabs(0) + FocusWidget(QGraphicsItem *parent = nullptr) : QGraphicsWidget(parent) { setFocusPolicy(Qt::StrongFocus); resize(100, 100); } - void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) override { if (option->state & QStyle::State_HasFocus) { painter->fillRect(rect(), Qt::blue); @@ -3152,11 +3194,11 @@ public: } } - int tabs; - int backTabs; + int tabs = 0; + int backTabs = 0; protected: - bool sceneEvent(QEvent *event) + bool sceneEvent(QEvent *event) override { if (event->type() == QEvent::KeyPress) { QKeyEvent *k = static_cast<QKeyEvent *>(event); @@ -3168,9 +3210,9 @@ protected: return QGraphicsWidget::sceneEvent(event); } - void focusInEvent(QFocusEvent *) + void focusInEvent(QFocusEvent *) override { update(); } - void focusOutEvent(QFocusEvent *) + void focusOutEvent(QFocusEvent *) override { update(); } }; @@ -3195,9 +3237,10 @@ void tst_QGraphicsScene::tabFocus_sceneWithFocusWidgets() layout->addWidget(dial2); QWidget widget; + widget.setWindowTitle(QTest::currentTestFunction()); widget.setLayout(layout); widget.show(); - qApp->setActiveWindow(&widget); + QApplication::setActiveWindow(&widget); widget.activateWindow(); QVERIFY(QTest::qWaitForWindowActive(&widget)); @@ -3236,7 +3279,7 @@ void tst_QGraphicsScene::tabFocus_sceneWithFocusWidgets() widget.hide(); QTest::qWait(15); widget.show(); - qApp->setActiveWindow(&widget); + QApplication::setActiveWindow(&widget); widget.activateWindow(); QVERIFY(QTest::qWaitForWindowActive(&widget)); QTRY_VERIFY(widget1->hasFocus()); @@ -3279,9 +3322,10 @@ void tst_QGraphicsScene::tabFocus_sceneWithNestedFocusWidgets() layout->addWidget(dial2); QWidget widget; + widget.setWindowTitle(QTest::currentTestFunction()); widget.setLayout(layout); widget.show(); - qApp->setActiveWindow(&widget); + QApplication::setActiveWindow(&widget); widget.activateWindow(); QVERIFY(QTest::qWaitForWindowActive(&widget)); @@ -3366,7 +3410,7 @@ void tst_QGraphicsScene::tabFocus_sceneWithNestedFocusWidgets() widget.hide(); QTest::qWait(12); widget.show(); - qApp->setActiveWindow(&widget); + QApplication::setActiveWindow(&widget); widget.activateWindow(); QVERIFY(QTest::qWaitForWindowActive(&widget)); QTRY_VERIFY(widget1->hasFocus()); @@ -3390,11 +3434,11 @@ void tst_QGraphicsScene::style() QCOMPARE(sceneSpy.count(), 1); QCOMPARE(proxySpy.count(), 1); QCOMPARE(editSpy.count(), 1); - QCOMPARE(scene.style(), (QStyle *)windowsStyle); - QCOMPARE(proxy->style(), (QStyle *)windowsStyle); - QCOMPARE(edit->style(), (QStyle *)windowsStyle); + QCOMPARE(scene.style(), windowsStyle.data()); + QCOMPARE(proxy->style(), windowsStyle.data()); + QCOMPARE(edit->style(), windowsStyle.data()); - scene.setStyle(0); + scene.setStyle(nullptr); QCOMPARE(sceneSpy.count(), 2); QCOMPARE(proxySpy.count(), 2); QCOMPARE(editSpy.count(), 2); @@ -3411,11 +3455,12 @@ void tst_QGraphicsScene::task139710_bspTreeCrash() for (int i = 0; i < 2; ++i) { // trigger delayed item indexing - qApp->processEvents(); + QCoreApplication::processEvents(); scene.setSceneRect(0, 0, 10000, 10000); // delete all items in the scene - pointers are now likely to be recycled - foreach (QGraphicsItem *item, scene.items()) { + const auto &items = scene.items(); + for (QGraphicsItem *item : items) { scene.removeItem(item); delete item; } @@ -3427,7 +3472,7 @@ void tst_QGraphicsScene::task139710_bspTreeCrash() } // trigger delayed item indexing for the first 1000 items - qApp->processEvents(); + QCoreApplication::processEvents(); // add 1000 more items - the BSP tree is now resized for (int i = 0; i < 1000; ++i) { @@ -3437,7 +3482,8 @@ void tst_QGraphicsScene::task139710_bspTreeCrash() // get items from the BSP tree and use them. there was junk in the tree // the second time this happened. - foreach (QGraphicsItem *item, scene.items(QRectF(0, 0, 1000, 1000))) + const auto &itemsWithin = scene.items(QRectF(0, 0, 1000, 1000)); + for (QGraphicsItem *item : itemsWithin) item->moveBy(0, 0); } } @@ -3446,7 +3492,7 @@ void tst_QGraphicsScene::task139782_containsItemBoundingRect() { // The item in question has a scene bounding rect of (10, 10, 50, 50) QGraphicsScene scene(0.0, 0.0, 200.0, 200.0); - QGraphicsRectItem *item = new QGraphicsRectItem(0.0, 0.0, 50.0, 50.0, 0); + QGraphicsRectItem *item = new QGraphicsRectItem(0.0, 0.0, 50.0, 50.0, nullptr); scene.addItem(item); item->setPos(10.0, 10.0); @@ -3476,7 +3522,8 @@ void tst_QGraphicsScene::task160653_selectionChanged() QGraphicsScene scene(0, 0, 100, 100); scene.addItem(new QGraphicsRectItem(0, 0, 20, 20)); scene.addItem(new QGraphicsRectItem(30, 30, 20, 20)); - foreach (QGraphicsItem *item, scene.items()) { + const auto &items = scene.items(); + for (QGraphicsItem *item : items) { item->setFlags( item->flags() | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable); item->setSelected(true); @@ -3484,12 +3531,14 @@ void tst_QGraphicsScene::task160653_selectionChanged() QVERIFY(scene.items().size() > 1); QCOMPARE(scene.items().size(), scene.selectedItems().size()); - QSignalSpy spy(&scene, SIGNAL(selectionChanged())); + QSignalSpy spy(&scene, &QGraphicsScene::selectionChanged); QGraphicsView view(&scene); + view.setWindowTitle(QTest::currentTestFunction()); + view.resize(m_testSize); view.show(); QVERIFY(QTest::qWaitForWindowActive(&view)); QTest::mouseClick( - view.viewport(), Qt::LeftButton, 0, view.mapFromScene(scene.items().first()->scenePos())); + view.viewport(), Qt::LeftButton, {}, view.mapFromScene(scene.items().first()->scenePos())); QCOMPARE(spy.count(), 1); } @@ -3574,17 +3623,21 @@ void tst_QGraphicsScene::sorting() scene.addItem(t_1); - foreach (QGraphicsItem *item, scene.items()) + const auto &items = scene.items(); + for (QGraphicsItem *item : items) item->setFlag(QGraphicsItem::ItemIsSelectable); // QGraphicsView view(&scene); // view.setDragMode(QGraphicsView::RubberBandDrag); // view.show(); - qDebug() << "items: {"; - foreach (QGraphicsItem *item, scene.items(QRectF(32, 31, 4, 55))) - qDebug() << "\t" << item->data(0).toString(); - qDebug() << "}"; + if (lcTests().isDebugEnabled()) { + qCDebug(lcTests) << "items: {"; + const auto &itemsWithin = scene.items(QRectF(32, 31, 4, 55)); + for (QGraphicsItem *item : itemsWithin) + qCDebug(lcTests).nospace() << '\t' << item->data(0).toString(); + qCDebug(lcTests) << '}'; + } QCOMPARE(scene.items(QRectF(32, 31, 4, 55)), QList<QGraphicsItem *>() @@ -3664,11 +3717,11 @@ void tst_QGraphicsScene::changedSignal() QFETCH(bool, withView); QGraphicsScene scene; ChangedListener cl; - connect(&scene, SIGNAL(changed(QList<QRectF>)), &cl, SLOT(changed(QList<QRectF>))); + connect(&scene, &QGraphicsScene::changed, &cl, &ChangedListener::changed); - QGraphicsView *view = 0; + QScopedPointer<QGraphicsView> view; if (withView) - view = new QGraphicsView(&scene); + view.reset(new QGraphicsView(&scene)); QGraphicsRectItem *rect = new QGraphicsRectItem(0, 0, 10, 10); rect->setPen(QPen(Qt::black, 0)); @@ -3682,14 +3735,11 @@ void tst_QGraphicsScene::changedSignal() rect->setPos(20, 0); QCOMPARE(cl.changes.size(), 1); - qApp->processEvents(); + QCoreApplication::processEvents(); QCOMPARE(cl.changes.size(), 2); QCOMPARE(cl.changes.at(1).size(), 2); QCOMPARE(scene.sceneRect(), QRectF(0, 0, 30, 10)); - - if (withView) - delete view; } void tst_QGraphicsScene::stickyFocus_data() @@ -3716,7 +3766,7 @@ void tst_QGraphicsScene::stickyFocus() QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress); event.setScenePos(QPointF(-10, -10)); // outside item event.setButton(Qt::LeftButton); - qApp->sendEvent(&scene, &event); + QCoreApplication::sendEvent(&scene, &event); QCOMPARE(text->hasFocus(), sticky); } @@ -3734,43 +3784,51 @@ void tst_QGraphicsScene::sendEvent() void tst_QGraphicsScene::inputMethod_data() { - QTest::addColumn<int>("flags"); + QTest::addColumn<QGraphicsItem::GraphicsItemFlags>("flags"); QTest::addColumn<bool>("callFocusItem"); - QTest::newRow("0") << 0 << false; - QTest::newRow("1") << (int)QGraphicsItem::ItemAcceptsInputMethod << false; - QTest::newRow("2") << (int)QGraphicsItem::ItemIsFocusable << false; + QTest::newRow("0") << QGraphicsItem::GraphicsItemFlags() << false; + QTest::newRow("1") << QGraphicsItem::GraphicsItemFlags(QGraphicsItem::ItemAcceptsInputMethod) << false; + QTest::newRow("2") << QGraphicsItem::GraphicsItemFlags(QGraphicsItem::ItemIsFocusable) << false; QTest::newRow("3") << - (int)(QGraphicsItem::ItemAcceptsInputMethod|QGraphicsItem::ItemIsFocusable) << true; + (QGraphicsItem::ItemAcceptsInputMethod|QGraphicsItem::ItemIsFocusable) << true; } class InputMethodTester : public QGraphicsRectItem { - void inputMethodEvent(QInputMethodEvent *) { ++eventCalls; } - QVariant inputMethodQuery(Qt::InputMethodQuery) const { ++queryCalls; return QVariant(); } + void inputMethodEvent(QInputMethodEvent *) override { ++eventCalls; } + QVariant inputMethodQuery(Qt::InputMethodQuery) const override + { + ++queryCalls; + return QVariant(); + } + public: - int eventCalls; - mutable int queryCalls; + int eventCalls = 0; + mutable int queryCalls = 0; }; void tst_QGraphicsScene::inputMethod() { PlatformInputContext inputContext; - QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); + QInputMethodPrivate *inputMethodPrivate = + QInputMethodPrivate::get(QGuiApplication::inputMethod()); inputMethodPrivate->testContext = &inputContext; - QFETCH(int, flags); + QFETCH(QGraphicsItem::GraphicsItemFlags, flags); QFETCH(bool, callFocusItem); InputMethodTester *item = new InputMethodTester; - item->setFlags((QGraphicsItem::GraphicsItemFlags)flags); + item->setFlags(flags); QGraphicsScene scene; QGraphicsView view(&scene); + view.resize(m_testSize); view.show(); + view.setWindowTitle(QTest::currentTestFunction()); QApplication::setActiveWindow(&view); view.setFocus(); QVERIFY(QTest::qWaitForWindowActive(&view)); - QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view)); + QCOMPARE(QApplication::activeWindow(), &view); inputContext.m_resetCallCount = 0; inputContext.m_commitCallCount = 0; @@ -3782,25 +3840,25 @@ void tst_QGraphicsScene::inputMethod() QCOMPARE(inputContext.m_resetCallCount, 0); item->eventCalls = 0; - qApp->sendEvent(&scene, &event); + QCoreApplication::sendEvent(&scene, &event); QCOMPARE(item->eventCalls, callFocusItem ? 1 : 0); item->queryCalls = 0; - scene.inputMethodQuery((Qt::InputMethodQuery)0); + scene.inputMethodQuery(Qt::InputMethodQuery(0)); QCOMPARE(item->queryCalls, callFocusItem ? 1 : 0); - scene.setFocusItem(0); + scene.setFocusItem(nullptr); // the input context is reset twice, once because an item has lost focus and again because // the Qt::WA_InputMethodEnabled flag is cleared because no item has focus. QCOMPARE(inputContext.m_resetCallCount + inputContext.m_commitCallCount, callFocusItem ? 2 : 0); QCOMPARE(item->queryCalls, callFocusItem ? 1 : 0); // verify that value is unaffected item->eventCalls = 0; - qApp->sendEvent(&scene, &event); + QCoreApplication::sendEvent(&scene, &event); QCOMPARE(item->eventCalls, 0); item->queryCalls = 0; - scene.inputMethodQuery((Qt::InputMethodQuery)0); + scene.inputMethodQuery(Qt::InputMethodQuery(0)); QCOMPARE(item->queryCalls, 0); } @@ -3824,18 +3882,18 @@ void tst_QGraphicsScene::dispatchHoverOnPress() me.setButtons(Qt::LeftButton); QGraphicsSceneMouseEvent me2(QEvent::GraphicsSceneMouseRelease); me2.setButton(Qt::LeftButton); - qApp->sendEvent(&scene, &me); - qApp->sendEvent(&scene, &me2); - QCOMPARE(tester1->eventTypes, QList<QEvent::Type>() + QCoreApplication::sendEvent(&scene, &me); + QCoreApplication::sendEvent(&scene, &me2); + QCOMPARE(tester1->eventTypes, QVector<QEvent::Type>() << QEvent::GraphicsSceneHoverEnter << QEvent::GraphicsSceneHoverMove << QEvent::GrabMouse << QEvent::GraphicsSceneMousePress << QEvent::UngrabMouse); tester1->eventTypes.clear(); - qApp->sendEvent(&scene, &me); - qApp->sendEvent(&scene, &me2); - QCOMPARE(tester1->eventTypes, QList<QEvent::Type>() + QCoreApplication::sendEvent(&scene, &me); + QCoreApplication::sendEvent(&scene, &me2); + QCOMPARE(tester1->eventTypes, QVector<QEvent::Type>() << QEvent::GraphicsSceneHoverMove << QEvent::GrabMouse << QEvent::GraphicsSceneMousePress @@ -3850,21 +3908,21 @@ void tst_QGraphicsScene::dispatchHoverOnPress() me2.setScenePos(QPointF(30, 30)); me2.setButton(Qt::LeftButton); tester1->eventTypes.clear(); - qApp->sendEvent(&scene, &me); - qApp->sendEvent(&scene, &me2); - qDebug() << tester1->eventTypes; - QCOMPARE(tester1->eventTypes, QList<QEvent::Type>() + QCoreApplication::sendEvent(&scene, &me); + QCoreApplication::sendEvent(&scene, &me2); + qCDebug(lcTests) << tester1->eventTypes; + QCOMPARE(tester1->eventTypes, QVector<QEvent::Type>() << QEvent::GraphicsSceneHoverLeave); - QCOMPARE(tester2->eventTypes, QList<QEvent::Type>() + QCOMPARE(tester2->eventTypes, QVector<QEvent::Type>() << QEvent::GraphicsSceneHoverEnter << QEvent::GraphicsSceneHoverMove << QEvent::GrabMouse << QEvent::GraphicsSceneMousePress << QEvent::UngrabMouse); tester2->eventTypes.clear(); - qApp->sendEvent(&scene, &me); - qApp->sendEvent(&scene, &me2); - QCOMPARE(tester2->eventTypes, QList<QEvent::Type>() + QCoreApplication::sendEvent(&scene, &me); + QCoreApplication::sendEvent(&scene, &me2); + QCOMPARE(tester2->eventTypes, QVector<QEvent::Type>() << QEvent::GraphicsSceneHoverMove << QEvent::GrabMouse << QEvent::GraphicsSceneMousePress @@ -3913,7 +3971,7 @@ void tst_QGraphicsScene::initialFocus() if (activeScene) { QEvent windowActivate(QEvent::WindowActivate); - qApp->sendEvent(&scene, &windowActivate); + QCoreApplication::sendEvent(&scene, &windowActivate); scene.setFocus(); } @@ -3921,7 +3979,7 @@ void tst_QGraphicsScene::initialFocus() if (!activeScene) { QEvent windowActivate(QEvent::WindowActivate); - qApp->sendEvent(&scene, &windowActivate); + QCoreApplication::sendEvent(&scene, &windowActivate); scene.setFocus(); } @@ -3931,14 +3989,13 @@ void tst_QGraphicsScene::initialFocus() class PolishItem : public QGraphicsTextItem { public: - PolishItem(QGraphicsItem *parent = 0) - : QGraphicsTextItem(parent), polished(false), deleteChildrenInPolish(true), addChildrenInPolish(false) { } + using QGraphicsTextItem::QGraphicsTextItem; - bool polished; - bool deleteChildrenInPolish; - bool addChildrenInPolish; + bool polished = false; + bool deleteChildrenInPolish = true; + bool addChildrenInPolish = false; protected: - QVariant itemChange(GraphicsItemChange change, const QVariant& value) + QVariant itemChange(GraphicsItemChange change, const QVariant& value) override { if (change == ItemVisibleChange) { polished = true; @@ -3977,19 +4034,19 @@ void tst_QGraphicsScene::polishItems2() // Wait for the polish event to be delivered. QVERIFY(!item->polished); - QApplication::sendPostedEvents(&scene, QEvent::MetaCall); + QCoreApplication::sendPostedEvents(&scene, QEvent::MetaCall); QVERIFY(item->polished); // We deleted the children we added above, but we also // added 10 new children. These should be polished in the next // event loop iteration. - QList<QGraphicsItem *> children = item->childItems(); + const QList<QGraphicsItem *> children = item->childItems(); QCOMPARE(children.count(), 10); - foreach (QGraphicsItem *child, children) + for (QGraphicsItem *child : children) QVERIFY(!static_cast<PolishItem *>(child)->polished); - QApplication::sendPostedEvents(&scene, QEvent::MetaCall); - foreach (QGraphicsItem *child, children) + QCoreApplication::sendPostedEvents(&scene, QEvent::MetaCall); + for (QGraphicsItem *child : children) QVERIFY(static_cast<PolishItem *>(child)->polished); } @@ -4006,6 +4063,8 @@ void tst_QGraphicsScene::isActive() { QWidget toplevel1; + toplevel1.setWindowTitle(QTest::currentTestFunction()); + toplevel1.resize(m_testSize); QHBoxLayout *layout = new QHBoxLayout; toplevel1.setLayout(layout); QGraphicsView *view1 = new QGraphicsView(&scene1); @@ -4071,8 +4130,9 @@ void tst_QGraphicsScene::isActive() { - const QRect availableGeometry = QGuiApplication::primaryScreen()->availableGeometry(); QWidget toplevel2; + toplevel2.setWindowTitle(QTest::currentTestFunction()); + toplevel2.resize(m_testSize); QHBoxLayout *layout = new QHBoxLayout; toplevel2.setLayout(layout); QGraphicsView *view1 = new QGraphicsView(&scene1); @@ -4085,7 +4145,7 @@ void tst_QGraphicsScene::isActive() QVERIFY(!scene1.hasFocus()); QVERIFY(!scene2.hasFocus()); - toplevel2.move(availableGeometry.topLeft() + QPoint(50, 50)); + toplevel2.move(m_availableGeometry.topLeft() + QPoint(50, 50)); toplevel2.show(); QApplication::setActiveWindow(&toplevel2); QVERIFY(QTest::qWaitForWindowActive(&toplevel2)); @@ -4134,12 +4194,13 @@ void tst_QGraphicsScene::isActive() QVERIFY(!scene2.hasFocus()); QGraphicsView topLevelView; - topLevelView.move(availableGeometry.topLeft() + QPoint(500, 50)); + topLevelView.move(toplevel2.geometry().topRight() + QPoint(100, 50)); + topLevelView.resize(m_testSize); topLevelView.show(); QApplication::setActiveWindow(&topLevelView); topLevelView.setFocus(); QVERIFY(QTest::qWaitForWindowActive(&topLevelView)); - QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&topLevelView)); + QCOMPARE(QApplication::activeWindow(), &topLevelView); QVERIFY(!scene1.isActive()); QVERIFY(!scene2.isActive()); @@ -4180,6 +4241,7 @@ void tst_QGraphicsScene::isActive() { QWidget toplevel3; + toplevel3.resize(m_testSize); QHBoxLayout *layout = new QHBoxLayout; toplevel3.setLayout(layout); QGraphicsView *view1 = new QGraphicsView(&scene1); @@ -4209,7 +4271,7 @@ void tst_QGraphicsScene::isActive() QVERIFY(scene1.hasFocus()); QVERIFY(!scene2.hasFocus()); - view1->setParent(0); + view1->setParent(nullptr); QVERIFY(!scene1.isActive()); QVERIFY(scene2.isActive()); QVERIFY(!scene1.hasFocus()); @@ -4241,7 +4303,7 @@ void tst_QGraphicsScene::siblingIndexAlwaysValid() scene.addItem(parent2); //Then we make the child a top level - child->setParentItem(0); + child->setParentItem(nullptr); //This is trigerred by a repaint... QGraphicsScenePrivate::get(&scene)->index->estimateTopLevelItems(QRectF(), Qt::AscendingOrder); @@ -4257,6 +4319,8 @@ void tst_QGraphicsScene::siblingIndexAlwaysValid() scene2.setItemIndexMethod(QGraphicsScene::NoIndex); QGraphicsView view2(&scene2); + view2.setWindowTitle(QTest::currentTestFunction()); + view2.resize(m_testSize); // first add the blue rect QGraphicsRectItem* const item1 = new QGraphicsRectItem(QRect( 10, 10, 10, 10 )); @@ -4300,9 +4364,11 @@ void tst_QGraphicsScene::removeFullyTransparentItem() child->setParentItem(parent); CustomView view; + view.setWindowTitle(QTest::currentTestFunction()); + view.resize(m_testSize); view.setScene(&scene); view.show(); - qApp->setActiveWindow(&view); + QApplication::setActiveWindow(&view); QVERIFY(QTest::qWaitForWindowActive(&view)); QCoreApplication::processEvents(); // Process all queued paint events @@ -4351,33 +4417,35 @@ void tst_QGraphicsScene::taskQTBUG_5904_crashWithDeviceCoordinateCache() void tst_QGraphicsScene::taskQT657_paintIntoCacheWithTransparentParts() { // Test using DeviceCoordinateCache and opaque item - QWidget *w = new QWidget(); + QScopedPointer<QWidget> w(new QWidget); w->setPalette(QColor(0, 0, 255)); w->setGeometry(0, 0, 50, 50); QGraphicsScene *scene = new QGraphicsScene(); - CustomView *view = new CustomView; - view->setScene(scene); + CustomView view; + view.resize(m_testSize); + view.setWindowTitle(QTest::currentTestFunction()); + view.setScene(scene); - QGraphicsProxyWidget *proxy = scene->addWidget(w); + QGraphicsProxyWidget *proxy = scene->addWidget(w.data()); proxy->setCacheMode(QGraphicsItem::DeviceCoordinateCache); proxy->setTransform(QTransform().rotate(15), true); - view->show(); - QVERIFY(QTest::qWaitForWindowExposed(view)); - view->repaints = 0; + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + view.repaints = 0; proxy->update(10, 10, 10, 10); - QTRY_VERIFY(view->repaints > 0); + QTRY_VERIFY(view.repaints > 0); QPixmap pix; QGraphicsItemPrivate* itemp = QGraphicsItemPrivate::get(proxy); - QTRY_VERIFY(QPixmapCache::find(itemp->extraItemCache()->deviceData.value(view->viewport()).key, &pix)); + QTRY_VERIFY(QPixmapCache::find(itemp->extraItemCache()->deviceData.value(view.viewport()).key, &pix)); QTransform t = proxy->sceneTransform(); // Map from scene coordinates to pixmap coordinates. // X origin in the pixmap is the most-left point // of the item's boundingRect in the scene. - qreal adjust = t.mapRect(proxy->boundingRect().toRect()).left(); + const int adjust = t.mapRect(proxy->boundingRect().toRect()).left(); QRect rect = t.mapRect(QRect(10, 10, 10, 10)).adjusted(-adjust, 0, -adjust + 1, 1); QPixmap subpix = pix.copy(rect); @@ -4386,8 +4454,6 @@ void tst_QGraphicsScene::taskQT657_paintIntoCacheWithTransparentParts() for(int j = 0; j < im.height(); j++) QCOMPARE(qAlpha(im.pixel(i, j)), 255); } - - delete w; } void tst_QGraphicsScene::taskQTBUG_7863_paintIntoCacheWithTransparentParts() @@ -4401,28 +4467,30 @@ void tst_QGraphicsScene::taskQTBUG_7863_paintIntoCacheWithTransparentParts() rectItem->setParentItem(backItem); QGraphicsScene *scene = new QGraphicsScene(); - CustomView *view = new CustomView; - view->setScene(scene); + CustomView view; + view.resize(m_testSize); + view.setWindowTitle(QTest::currentTestFunction()); + view.setScene(scene); scene->addItem(backItem); rectItem->setCacheMode(QGraphicsItem::DeviceCoordinateCache); backItem->setTransform(QTransform().rotate(15), true); - view->show(); - QVERIFY(QTest::qWaitForWindowExposed(view)); - view->repaints = 0; + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + view.repaints = 0; rectItem->update(10, 10, 10, 10); - QTRY_VERIFY(view->repaints > 0); + QTRY_VERIFY(view.repaints > 0); QPixmap pix; QGraphicsItemPrivate* itemp = QGraphicsItemPrivate::get(rectItem); - QTRY_VERIFY(QPixmapCache::find(itemp->extraItemCache()->deviceData.value(view->viewport()).key, &pix)); + QTRY_VERIFY(QPixmapCache::find(itemp->extraItemCache()->deviceData.value(view.viewport()).key, &pix)); QTransform t = rectItem->sceneTransform(); // Map from scene coordinates to pixmap coordinates. // X origin in the pixmap is the most-left point // of the item's boundingRect in the scene. - qreal adjust = t.mapRect(rectItem->boundingRect().toRect()).left(); + const int adjust = t.mapRect(rectItem->boundingRect().toRect()).left(); QRect rect = t.mapRect(QRect(10, 10, 10, 10)).adjusted(-adjust, 0, -adjust + 1, 1); QPixmap subpix = pix.copy(rect); @@ -4432,8 +4500,6 @@ void tst_QGraphicsScene::taskQTBUG_7863_paintIntoCacheWithTransparentParts() QCOMPARE(qAlpha(im.pixel(i, j)), 125); } } - - delete view; } // Test using ItemCoordinateCache and opaque item @@ -4442,18 +4508,20 @@ void tst_QGraphicsScene::taskQTBUG_7863_paintIntoCacheWithTransparentParts() rectItem->setBrush(QColor(0, 0, 255)); QGraphicsScene *scene = new QGraphicsScene(); - CustomView *view = new CustomView; - view->setScene(scene); + CustomView view; + view.setWindowTitle(QTest::currentTestFunction()); + view.resize(m_testSize); + view.setScene(scene); scene->addItem(rectItem); rectItem->setCacheMode(QGraphicsItem::ItemCoordinateCache); rectItem->setTransform(QTransform().rotate(15), true); - view->show(); - QVERIFY(QTest::qWaitForWindowExposed(view)); - view->repaints = 0; + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + view.repaints = 0; rectItem->update(10, 10, 10, 10); - QTRY_VERIFY(view->repaints > 0); + QTRY_VERIFY(view.repaints > 0); QPixmap pix; QGraphicsItemPrivate* itemp = QGraphicsItemPrivate::get(rectItem); @@ -4463,7 +4531,7 @@ void tst_QGraphicsScene::taskQTBUG_7863_paintIntoCacheWithTransparentParts() // Map from scene coordinates to pixmap coordinates. // X origin in the pixmap is the most-left point // of the item's boundingRect in the scene. - qreal adjust = t.mapRect(rectItem->boundingRect().toRect()).left(); + const int adjust = t.mapRect(rectItem->boundingRect().toRect()).left(); QRect rect = t.mapRect(QRect(10, 10, 10, 10)).adjusted(-adjust, 0, -adjust + 1, 1); QPixmap subpix = pix.copy(rect); @@ -4472,8 +4540,6 @@ void tst_QGraphicsScene::taskQTBUG_7863_paintIntoCacheWithTransparentParts() for(int j = 0; j < im.height(); j++) QCOMPARE(qAlpha(im.pixel(i, j)), 255); } - - delete view; } // Test using ItemCoordinateCache and semi-transparent item @@ -4482,18 +4548,20 @@ void tst_QGraphicsScene::taskQTBUG_7863_paintIntoCacheWithTransparentParts() rectItem->setBrush(QColor(0, 0, 255, 125)); QGraphicsScene *scene = new QGraphicsScene(); - CustomView *view = new CustomView; - view->setScene(scene); + CustomView view; + view.setWindowTitle(QTest::currentTestFunction()); + view.resize(m_testSize); + view.setScene(scene); scene->addItem(rectItem); rectItem->setCacheMode(QGraphicsItem::ItemCoordinateCache); rectItem->setTransform(QTransform().rotate(15), true); - view->show(); - QVERIFY(QTest::qWaitForWindowExposed(view)); - view->repaints = 0; + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + view.repaints = 0; rectItem->update(10, 10, 10, 10); - QTRY_VERIFY(view->repaints > 0); + QTRY_VERIFY(view.repaints > 0); QPixmap pix; QGraphicsItemPrivate* itemp = QGraphicsItemPrivate::get(rectItem); @@ -4503,7 +4571,7 @@ void tst_QGraphicsScene::taskQTBUG_7863_paintIntoCacheWithTransparentParts() // Map from scene coordinates to pixmap coordinates. // X origin in the pixmap is the most-left point // of the item's boundingRect in the scene. - qreal adjust = t.mapRect(rectItem->boundingRect().toRect()).left(); + const int adjust = int(t.mapRect(rectItem->boundingRect().toRect()).left()); QRect rect = t.mapRect(QRect(10, 10, 10, 10)).adjusted(-adjust, 0, -adjust + 1, 1); QPixmap subpix = pix.copy(rect); @@ -4512,8 +4580,6 @@ void tst_QGraphicsScene::taskQTBUG_7863_paintIntoCacheWithTransparentParts() for(int j = 0; j < im.height(); j++) QCOMPARE(qAlpha(im.pixel(i, j)), 125); } - - delete view; } } @@ -4544,7 +4610,7 @@ void tst_QGraphicsScene::zeroScale() QGraphicsView view(&scene); ChangedListener cl; - connect(&scene, SIGNAL(changed(QList<QRectF>)), &cl, SLOT(changed(QList<QRectF>))); + connect(&scene, &QGraphicsScene::changed, &cl, &ChangedListener::changed); QGraphicsRectItem *rect1 = new QGraphicsRectItem(0, 0, 0.0000001, 0.00000001); scene.addItem(rect1); @@ -4567,13 +4633,13 @@ void tst_QGraphicsScene::focusItemChangedSignal() qRegisterMetaType<Qt::FocusReason>("Qt::FocusReason"); QGraphicsScene scene; - QSignalSpy spy(&scene, SIGNAL(focusItemChanged(QGraphicsItem *, QGraphicsItem *, Qt::FocusReason))); + QSignalSpy spy(&scene, &QGraphicsScene::focusItemChanged); QVERIFY(spy.isValid()); QCOMPARE(spy.count(), 0); scene.setFocus(); QCOMPARE(spy.count(), 0); QEvent activateEvent(QEvent::WindowActivate); - qApp->sendEvent(&scene, &activateEvent); + QCoreApplication::sendEvent(&scene, &activateEvent); QCOMPARE(spy.count(), 0); QGraphicsRectItem *topLevelItem1 = new QGraphicsRectItem; @@ -4590,7 +4656,7 @@ void tst_QGraphicsScene::focusItemChangedSignal() QCOMPARE(spy.count(), 1); QList<QVariant> arguments = spy.takeFirst(); QCOMPARE(arguments.size(), 3); - QCOMPARE(qvariant_cast<QGraphicsItem *>(arguments.at(0)), (QGraphicsItem *)topLevelItem2); + QCOMPARE(qvariant_cast<QGraphicsItem *>(arguments.at(0)), topLevelItem2); QCOMPARE(qvariant_cast<QGraphicsItem *>(arguments.at(1)), nullptr); QCOMPARE(qvariant_cast<Qt::FocusReason>(arguments.at(2)), Qt::OtherFocusReason); QVERIFY(topLevelItem2->hasFocus()); @@ -4600,14 +4666,14 @@ void tst_QGraphicsScene::focusItemChangedSignal() arguments = spy.takeFirst(); QCOMPARE(arguments.size(), 3); QCOMPARE(qvariant_cast<QGraphicsItem *>(arguments.at(0)), nullptr); - QCOMPARE(qvariant_cast<QGraphicsItem *>(arguments.at(1)), (QGraphicsItem *)topLevelItem2); + QCOMPARE(qvariant_cast<QGraphicsItem *>(arguments.at(1)), topLevelItem2); QCOMPARE(qvariant_cast<Qt::FocusReason>(arguments.at(2)), Qt::OtherFocusReason); scene.setFocus(Qt::MenuBarFocusReason); QCOMPARE(spy.count(), 1); arguments = spy.takeFirst(); QCOMPARE(arguments.size(), 3); - QCOMPARE(qvariant_cast<QGraphicsItem *>(arguments.at(0)), (QGraphicsItem *)topLevelItem2); + QCOMPARE(qvariant_cast<QGraphicsItem *>(arguments.at(0)), topLevelItem2); QCOMPARE(qvariant_cast<QGraphicsItem *>(arguments.at(1)), nullptr); QCOMPARE(qvariant_cast<Qt::FocusReason>(arguments.at(2)), Qt::MenuBarFocusReason); @@ -4615,15 +4681,15 @@ void tst_QGraphicsScene::focusItemChangedSignal() topLevelItem1->setFocus(Qt::TabFocusReason); arguments = spy.takeFirst(); QCOMPARE(arguments.size(), 3); - QCOMPARE(qvariant_cast<QGraphicsItem *>(arguments.at(0)), (QGraphicsItem *)topLevelItem1); - QCOMPARE(qvariant_cast<QGraphicsItem *>(arguments.at(1)), (QGraphicsItem *)topLevelItem2); + QCOMPARE(qvariant_cast<QGraphicsItem *>(arguments.at(0)), topLevelItem1); + QCOMPARE(qvariant_cast<QGraphicsItem *>(arguments.at(1)), topLevelItem2); QCOMPARE(qvariant_cast<Qt::FocusReason>(arguments.at(2)), Qt::TabFocusReason); topLevelItem2->setFocus(Qt::TabFocusReason); arguments = spy.takeFirst(); QCOMPARE(arguments.size(), 3); - QCOMPARE(qvariant_cast<QGraphicsItem *>(arguments.at(0)), (QGraphicsItem *)topLevelItem2); - QCOMPARE(qvariant_cast<QGraphicsItem *>(arguments.at(1)), (QGraphicsItem *)topLevelItem1); + QCOMPARE(qvariant_cast<QGraphicsItem *>(arguments.at(0)), topLevelItem2); + QCOMPARE(qvariant_cast<QGraphicsItem *>(arguments.at(1)), topLevelItem1); QCOMPARE(qvariant_cast<Qt::FocusReason>(arguments.at(2)), Qt::TabFocusReason); } @@ -4631,10 +4697,10 @@ void tst_QGraphicsScene::focusItemChangedSignal() // when the scene activation changes) breaks quite a few tests so leave this fix // for some future release. See QTBUG-28346. QEvent deactivateEvent(QEvent::WindowDeactivate); - qApp->sendEvent(&scene, &deactivateEvent); + QCoreApplication::sendEvent(&scene, &deactivateEvent); QEXPECT_FAIL("", "QTBUG-28346", Continue); QCOMPARE(spy.count(), 1); - qApp->sendEvent(&scene, &activateEvent); + QCoreApplication::sendEvent(&scene, &activateEvent); QEXPECT_FAIL("", "QTBUG-28346", Continue); QCOMPARE(spy.count(), 1); @@ -4645,8 +4711,8 @@ void tst_QGraphicsScene::focusItemChangedSignal() QCOMPARE(spy.count(), 1); arguments = spy.takeFirst(); QCOMPARE(arguments.size(), 3); - QCOMPARE(qvariant_cast<QGraphicsItem *>(arguments.at(0)), (QGraphicsItem *)panel1); - QCOMPARE(qvariant_cast<QGraphicsItem *>(arguments.at(1)), (QGraphicsItem *)topLevelItem2); + QCOMPARE(qvariant_cast<QGraphicsItem *>(arguments.at(0)), panel1); + QCOMPARE(qvariant_cast<QGraphicsItem *>(arguments.at(1)), topLevelItem2); QCOMPARE(qvariant_cast<Qt::FocusReason>(arguments.at(2)), Qt::ActiveWindowFocusReason); QGraphicsRectItem *panel2 = new QGraphicsRectItem; @@ -4659,16 +4725,16 @@ void tst_QGraphicsScene::focusItemChangedSignal() QCOMPARE(spy.count(), 1); arguments = spy.takeFirst(); QCOMPARE(arguments.size(), 3); - QCOMPARE(qvariant_cast<QGraphicsItem *>(arguments.at(0)), (QGraphicsItem *)panel2); - QCOMPARE(qvariant_cast<QGraphicsItem *>(arguments.at(1)), (QGraphicsItem *)panel1); + QCOMPARE(qvariant_cast<QGraphicsItem *>(arguments.at(0)), panel2); + QCOMPARE(qvariant_cast<QGraphicsItem *>(arguments.at(1)), panel1); QCOMPARE(qvariant_cast<Qt::FocusReason>(arguments.at(2)), Qt::ActiveWindowFocusReason); scene.setActivePanel(panel1); QCOMPARE(spy.count(), 1); arguments = spy.takeFirst(); QCOMPARE(arguments.size(), 3); - QCOMPARE(qvariant_cast<QGraphicsItem *>(arguments.at(0)), (QGraphicsItem *)panel1); - QCOMPARE(qvariant_cast<QGraphicsItem *>(arguments.at(1)), (QGraphicsItem *)panel2); + QCOMPARE(qvariant_cast<QGraphicsItem *>(arguments.at(0)), panel1); + QCOMPARE(qvariant_cast<QGraphicsItem *>(arguments.at(1)), panel2); QCOMPARE(qvariant_cast<Qt::FocusReason>(arguments.at(2)), Qt::ActiveWindowFocusReason); } @@ -4677,14 +4743,15 @@ void tst_QGraphicsScene::focusItemChangedSignal() class ItemCountsPaintCalls : public QGraphicsRectItem { public: - ItemCountsPaintCalls(const QRectF & rect, QGraphicsItem *parent = 0) - : QGraphicsRectItem(rect, parent), repaints(0) {} - void paint ( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0 ) + using QGraphicsRectItem::QGraphicsRectItem; + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, + QWidget *widget = nullptr) override { QGraphicsRectItem::paint(painter, option, widget); ++repaints; } - int repaints; + int repaints = 0; }; void tst_QGraphicsScene::minimumRenderSize() @@ -4698,10 +4765,12 @@ void tst_QGraphicsScene::minimumRenderSize() scene.addItem(bigParent); CustomView view; + view.setWindowTitle(QTest::currentTestFunction()); + view.resize(m_testSize); view.setScene(&scene); view.show(); QVERIFY(QTest::qWaitForWindowExposed(&view)); - qApp->processEvents(); + QCoreApplication::processEvents(); // Initially, everything should be repainted the same number of times int viewRepaints = 0; @@ -4714,7 +4783,7 @@ void tst_QGraphicsScene::minimumRenderSize() // Setting a minimum render size should cause a repaint scene.setMinimumRenderSize(0.5); - qApp->processEvents(); + QCoreApplication::processEvents(); QTRY_VERIFY(view.repaints > viewRepaints); viewRepaints = view.repaints; @@ -4725,7 +4794,7 @@ void tst_QGraphicsScene::minimumRenderSize() // Scaling should cause a repaint of big items only. view.scale(0.1, 0.1); - qApp->processEvents(); + QCoreApplication::processEvents(); QTRY_VERIFY(view.repaints > viewRepaints); viewRepaints = view.repaints; @@ -4736,7 +4805,7 @@ void tst_QGraphicsScene::minimumRenderSize() // Scaling further should cause even fewer items to be repainted view.scale(0.1, 0.1); // Stacks with previous scale - qApp->processEvents(); + QCoreApplication::processEvents(); QTRY_VERIFY(view.repaints > viewRepaints); viewRepaints = view.repaints; @@ -4750,6 +4819,8 @@ void tst_QGraphicsScene::focusOnTouch() { QGraphicsScene scene; QGraphicsView view(&scene); + view.setWindowTitle(QTest::currentTestFunction()); + view.resize(m_testSize); scene.setSceneRect(0, 0, 100, 100); QGraphicsRectItem *rect = scene.addRect(0, 0, 100, 100); rect->setFlag(QGraphicsItem::ItemIsFocusable, true); @@ -4807,6 +4878,7 @@ void tst_QGraphicsScene::taskQTBUG_16401_focusItem() { QGraphicsScene scene; QGraphicsView view(&scene); + view.resize(m_testSize); QGraphicsRectItem *rect = scene.addRect(0, 0, 100, 100); rect->setFlag(QGraphicsItem::ItemIsFocusable); @@ -4837,6 +4909,8 @@ void tst_QGraphicsScene::taskQTBUG_42915_focusNextPrevChild() { QGraphicsScene scene; QGraphicsView view(&scene); + view.setWindowTitle(QTest::currentTestFunction()); + view.resize(m_testSize); scene.setSceneRect(1, 1, 198, 198); view.setFocus(); diff --git a/tests/auto/widgets/graphicsview/qgraphicsview/BLACKLIST b/tests/auto/widgets/graphicsview/qgraphicsview/BLACKLIST index ee13a37212..9b76ea02ff 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsview/BLACKLIST +++ b/tests/auto/widgets/graphicsview/qgraphicsview/BLACKLIST @@ -1,20 +1,16 @@ [task255529_transformationAnchorMouseAndViewportMargins] -xcb +opensuse-leap [cursor] -xcb +opensuse-leap [cursor2] -xcb -windows -[rubberBandExtendSelection] -xcb -[rotated_rubberBand] -xcb +ubuntu-16.04 [sendEvent] -xcb -[forwardMousePress] -xcb +ubuntu-16.04 +opensuse-42.3 [resizeAnchor] -xcb +opensuse-leap +rhel-7.6 +ubuntu [update2] opensuse-42.3 [itemsInRect_cosmeticAdjust] diff --git a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp index 1442219bea..e21b1b889a 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp @@ -352,8 +352,8 @@ void tst_QGraphicsView::renderHints() view.setScene(&scene); - view.setRenderHints(QPainter::TextAntialiasing | QPainter::Antialiasing | QPainter::NonCosmeticDefaultPen); - QCOMPARE(view.renderHints(), QPainter::TextAntialiasing | QPainter::Antialiasing | QPainter::NonCosmeticDefaultPen); + view.setRenderHints(QPainter::TextAntialiasing | QPainter::Antialiasing); + QCOMPARE(view.renderHints(), QPainter::TextAntialiasing | QPainter::Antialiasing); QCOMPARE(item->hints, 0); view.show(); @@ -361,8 +361,8 @@ void tst_QGraphicsView::renderHints() view.repaint(); QTRY_COMPARE(item->hints, view.renderHints()); - view.setRenderHints(QPainter::Antialiasing | QPainter::NonCosmeticDefaultPen); - QCOMPARE(view.renderHints(), QPainter::Antialiasing | QPainter::NonCosmeticDefaultPen); + view.setRenderHints(QPainter::Antialiasing); + QCOMPARE(view.renderHints(), QPainter::Antialiasing); view.repaint(); QTRY_COMPARE(item->hints, view.renderHints()); @@ -2219,7 +2219,7 @@ void tst_QGraphicsView::wheelEvent() { QWheelEvent event(view.mapFromScene(widget->boundingRect().center()), view.mapToGlobal(view.mapFromScene(widget->boundingRect().center())), - 120, 0, 0, Qt::Horizontal); + QPoint(), QPoint(120, 0), Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false); QApplication::sendEvent(view.viewport(), &event); QCOMPARE(scene.orientation, Qt::Horizontal); } @@ -2228,7 +2228,7 @@ void tst_QGraphicsView::wheelEvent() { QWheelEvent event(view.mapFromScene(widget->boundingRect().center()), view.mapToGlobal(view.mapFromScene(widget->boundingRect().center())), - 120, 0, 0, Qt::Vertical); + QPoint(), QPoint(0, 120), Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false); QApplication::sendEvent(view.viewport(), &event); QCOMPARE(scene.orientation, Qt::Vertical); } @@ -2526,9 +2526,8 @@ void tst_QGraphicsView::viewportUpdateMode2() view.setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate); view.setScene(&dummyScene); view.ensurePolished(); // make sure we get the right content margins - int left, top, right, bottom; - view.getContentsMargins(&left, &top, &right, &bottom); - view.resize(200 + left + right, 200 + top + bottom); + const QMargins margins = view.contentsMargins(); + view.resize(200 + margins.left() + margins.right(), 200 + margins.top() + margins.bottom()); toplevel.show(); qApp->setActiveWindow(&toplevel); QVERIFY(QTest::qWaitForWindowExposed(&toplevel)); @@ -2611,11 +2610,6 @@ void tst_QGraphicsView::optimizationFlags() QGraphicsView view; QVERIFY(!view.optimizationFlags()); - view.setOptimizationFlag(QGraphicsView::DontClipPainter); - QVERIFY(view.optimizationFlags() & QGraphicsView::DontClipPainter); - view.setOptimizationFlag(QGraphicsView::DontClipPainter, false); - QVERIFY(!view.optimizationFlags()); - view.setOptimizationFlag(QGraphicsView::DontSavePainterState); QVERIFY(view.optimizationFlags() & QGraphicsView::DontSavePainterState); view.setOptimizationFlag(QGraphicsView::DontSavePainterState, false); @@ -2626,10 +2620,8 @@ void tst_QGraphicsView::optimizationFlags() view.setOptimizationFlag(QGraphicsView::DontAdjustForAntialiasing, false); QVERIFY(!view.optimizationFlags()); - view.setOptimizationFlags(QGraphicsView::DontAdjustForAntialiasing - | QGraphicsView::DontClipPainter); - QCOMPARE(view.optimizationFlags(), QGraphicsView::OptimizationFlags(QGraphicsView::DontAdjustForAntialiasing - | QGraphicsView::DontClipPainter)); + view.setOptimizationFlags(QGraphicsView::DontAdjustForAntialiasing); + QCOMPARE(view.optimizationFlags(), QGraphicsView::OptimizationFlags(QGraphicsView::DontAdjustForAntialiasing)); } class MessUpPainterItem : public QGraphicsRectItem @@ -4043,9 +4035,8 @@ void tst_QGraphicsView::update() CustomView view(0, &toplevel); view.setScene(&dummyScene); view.ensurePolished(); // must ensure polished to get content margins right - int left, top, right, bottom; - view.getContentsMargins(&left, &top, &right, &bottom); - view.resize(200 + left + right, 200 + top + bottom); + const QMargins margins = view.contentsMargins(); + view.resize(200 + margins.left() + margins.right(), 200 + margins.top() + margins.bottom()); toplevel.show(); QVERIFY(QTest::qWaitForWindowExposed(&toplevel)); @@ -4857,7 +4848,7 @@ void tst_QGraphicsView::QTBUG_16063_microFocusRect() scene.setFocusItem(item); view.setFocus(); - QRectF mfv = view.inputMethodQuery(Qt::ImMicroFocus).toRectF(); + QRectF mfv = view.inputMethodQuery(Qt::ImCursorRectangle).toRectF(); QCOMPARE(mfv, IMItem::mf.translated(-view.mapToScene(view.sceneRect().toRect()).boundingRect().topLeft())); } diff --git a/tests/auto/widgets/graphicsview/qgraphicswidget/tst_qgraphicswidget.cpp b/tests/auto/widgets/graphicsview/qgraphicswidget/tst_qgraphicswidget.cpp index 85b42e54fe..d3477be986 100644 --- a/tests/auto/widgets/graphicsview/qgraphicswidget/tst_qgraphicswidget.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicswidget/tst_qgraphicswidget.cpp @@ -2905,7 +2905,7 @@ public: Q_UNUSED(widget); qreal w = rect().width(); QRectF box(0, 0, w, 2400/w); - painter->drawRoundRect(box); + painter->drawRoundedRect(box, 25, 25, Qt::RelativeSize); painter->drawLine(box.topLeft(), box.bottomRight()); painter->drawLine(box.bottomLeft(), box.topRight()); } diff --git a/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp b/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp index 6f7dca86eb..bcfc477733 100644 --- a/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp +++ b/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp @@ -1024,9 +1024,6 @@ void tst_QAbstractItemView::setItemDelegate() centerOnScreen(&v); moveCursorAway(&v); v.show(); -#if 0 // Used to be included in Qt4 for Q_WS_X11 - QCursor::setPos(v.geometry().center()); -#endif QApplication::setActiveWindow(&v); QVERIFY(QTest::qWaitForWindowActive(&v)); diff --git a/tests/auto/widgets/itemviews/qcolumnview/BLACKLIST b/tests/auto/widgets/itemviews/qcolumnview/BLACKLIST deleted file mode 100644 index bda01c700c..0000000000 --- a/tests/auto/widgets/itemviews/qcolumnview/BLACKLIST +++ /dev/null @@ -1,2 +0,0 @@ -[scrollTo:reverse] -osx diff --git a/tests/auto/widgets/itemviews/qheaderview/BLACKLIST b/tests/auto/widgets/itemviews/qheaderview/BLACKLIST index efb813f7d2..4eceaae0d3 100644 --- a/tests/auto/widgets/itemviews/qheaderview/BLACKLIST +++ b/tests/auto/widgets/itemviews/qheaderview/BLACKLIST @@ -1,3 +1,2 @@ [stretchAndRestoreLastSection] -opensuse opensuse-leap diff --git a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp index 1b3e1e1f34..0b120985ee 100644 --- a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp +++ b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp @@ -85,8 +85,8 @@ class XResetModel : public QStandardItemModel blockSignals(true); bool r = QStandardItemModel::removeRows(row, count, parent); blockSignals(false); - emit beginResetModel(); - emit endResetModel(); + beginResetModel(); + endResetModel(); return r; } virtual bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) @@ -94,8 +94,8 @@ class XResetModel : public QStandardItemModel blockSignals(true); bool r = QStandardItemModel::insertRows(row, count, parent); blockSignals(false); - emit beginResetModel(); - emit endResetModel(); + beginResetModel(); + endResetModel(); return r; } }; @@ -106,6 +106,7 @@ class tst_QHeaderView : public QObject public: tst_QHeaderView(); + static void initMain(); private slots: void initTestCase(); @@ -215,6 +216,7 @@ private slots: void QTBUG14242_hideSectionAutoSize(); void QTBUG50171_visualRegionForSwappedItems(); void QTBUG53221_assertShiftHiddenRow(); + void QTBUG75615_sizeHintWithStylesheet(); void ensureNoIndexAtLength(); void offsetConsistent(); @@ -265,6 +267,14 @@ protected: QElapsedTimer timer; }; +void tst_QHeaderView::initMain() +{ +#ifdef Q_OS_WIN + // Ensure minimum size constraints of framed windows on High DPI screens + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif +} + class QtTestModel: public QAbstractTableModel { @@ -2597,6 +2607,26 @@ void tst_QHeaderView::QTBUG53221_assertShiftHiddenRow() QCOMPARE(tableView.verticalHeader()->isSectionHidden(2), true); } +void tst_QHeaderView::QTBUG75615_sizeHintWithStylesheet() +{ + QTableView tableView; + QStandardItemModel model(1, 1); + tableView.setModel(&model); + tableView.show(); + + const auto headerView = tableView.horizontalHeader(); + const auto oldSizeHint = headerView->sizeHint(); + QVERIFY(oldSizeHint.isValid()); + + tableView.setStyleSheet("QTableView QHeaderView::section { height: 100px;}"); + QCOMPARE(headerView->sizeHint().width(), oldSizeHint.width()); + QCOMPARE(headerView->sizeHint().height(), 100); + + tableView.setStyleSheet("QTableView QHeaderView::section { width: 100px;}"); + QCOMPARE(headerView->sizeHint().height(), oldSizeHint.height()); + QCOMPARE(headerView->sizeHint().width(), 100); +} + void protected_QHeaderView::testVisualRegionForSelection() { QRegion r = visualRegionForSelection(QItemSelection(model()->index(1, 0), model()->index(1, 2))); diff --git a/tests/auto/widgets/itemviews/qitemdelegate/qitemdelegate.pro b/tests/auto/widgets/itemviews/qitemdelegate/qitemdelegate.pro index 10cd1dcc54..916694fd0f 100644 --- a/tests/auto/widgets/itemviews/qitemdelegate/qitemdelegate.pro +++ b/tests/auto/widgets/itemviews/qitemdelegate/qitemdelegate.pro @@ -3,4 +3,4 @@ TARGET = tst_qitemdelegate QT += widgets widgets-private testlib SOURCES += tst_qitemdelegate.cpp -win32:!winrt: LIBS += -luser32 +win32:!winrt: QMAKE_USE += user32 diff --git a/tests/auto/widgets/itemviews/qlistview/qlistview.pro b/tests/auto/widgets/itemviews/qlistview/qlistview.pro index 75f45ab432..c3e19adc81 100644 --- a/tests/auto/widgets/itemviews/qlistview/qlistview.pro +++ b/tests/auto/widgets/itemviews/qlistview/qlistview.pro @@ -2,4 +2,4 @@ CONFIG += testcase TARGET = tst_qlistview QT += widgets gui-private widgets-private core-private testlib testlib-private SOURCES += tst_qlistview.cpp -win32:!winrt: LIBS += -luser32 +win32:!winrt: QMAKE_USE += user32 diff --git a/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp b/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp index 0b828b8484..3a60b3b7c6 100644 --- a/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp +++ b/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp @@ -2516,9 +2516,9 @@ void tst_QListView::horizontalScrollingByVerticalWheelEvents() QPoint globalPos = lv.geometry().center(); QPoint pos = lv.viewport()->geometry().center(); - QWheelEvent wheelDownEvent(pos, globalPos, QPoint(0, 0), QPoint(0, -120), -120, Qt::Vertical, 0, 0); - QWheelEvent wheelUpEvent(pos, globalPos, QPoint(0, 0), QPoint(0, 120), 120, Qt::Vertical, 0, 0); - QWheelEvent wheelLeftDownEvent(pos, globalPos, QPoint(0, 0), QPoint(120, -120), -120, Qt::Vertical, 0, 0); + QWheelEvent wheelDownEvent(pos, globalPos, QPoint(0, 0), QPoint(0, -120), Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false); + QWheelEvent wheelUpEvent(pos, globalPos, QPoint(0, 0), QPoint(0, 120), Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false); + QWheelEvent wheelLeftDownEvent(pos, globalPos, QPoint(0, 0), QPoint(120, -120), Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false); int hValue = lv.horizontalScrollBar()->value(); QApplication::sendEvent(lv.viewport(), &wheelDownEvent); diff --git a/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp b/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp index 91088aeeca..fe2ede4183 100644 --- a/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp +++ b/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp @@ -1525,11 +1525,11 @@ void tst_QListWidget::itemData() item.setData(Qt::DisplayRole, QString("0")); QCOMPARE(widget.currentRoles, QVector<int>({Qt::DisplayRole, Qt::EditRole})); item.setData(Qt::CheckStateRole, Qt::PartiallyChecked); - QCOMPARE(widget.currentRoles, {Qt::CheckStateRole}); + QCOMPARE(widget.currentRoles, QVector<int>{Qt::CheckStateRole}); for (int i = 0; i < 4; ++i) { item.setData(Qt::UserRole + i, QString::number(i + 1)); - QCOMPARE(widget.currentRoles, {Qt::UserRole + i}); + QCOMPARE(widget.currentRoles, QVector<int>{Qt::UserRole + i}); } QMap<int, QVariant> flags = widget.model()->itemData(widget.model()->index(0, 0)); QCOMPARE(flags.count(), 6); diff --git a/tests/auto/widgets/itemviews/qtableview/BLACKLIST b/tests/auto/widgets/itemviews/qtableview/BLACKLIST index be90475a6f..9648cef3de 100644 --- a/tests/auto/widgets/itemviews/qtableview/BLACKLIST +++ b/tests/auto/widgets/itemviews/qtableview/BLACKLIST @@ -1,4 +1,3 @@ [moveCursorBiggerJump] osx -[columnViewportPosition] -winrt # QTBUG-72853 + diff --git a/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp b/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp index c8eecd3693..3e0d2539b4 100644 --- a/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp +++ b/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp @@ -26,16 +26,24 @@ ** ****************************************************************************/ - -#include <QtGui/QtGui> -#include <QtWidgets/QtWidgets> +#include <QIdentityProxyModel> +#include <QLabel> +#include <QLineEdit> +#include <QScrollBar> +#include <QSignalSpy> +#include <QSortFilterProxyModel> +#include <QStandardItemModel> +#include <QStringListModel> +#include <QStyledItemDelegate> +#include <QTableView> +#include <QTest> +#include <private/qapplication_p.h> #include <private/qtablewidget_p.h> -#include <QtTest/QtTest> -#include "private/qapplication_p.h" - -#include <algorithm> +#include <private/qtesthelpers_p.h> +#if QT_CONFIG(textmarkdownwriter) +#include <private/qtextmarkdownwriter_p.h> +#endif -#include <QtTest/private/qtesthelpers_p.h> using namespace QTestPrivate; @@ -46,14 +54,241 @@ using namespace QTestPrivate; #define VERIFY_SPANS_CONSISTENCY(TEST_VIEW_) (void)false #endif -typedef QList<int> IntList; +Q_DECLARE_METATYPE(Qt::Key); +Q_DECLARE_METATYPE(Qt::KeyboardModifier); +Q_DECLARE_METATYPE(QItemSelectionModel::SelectionFlag); +using BoolList = QVector<bool>; +using IntList = QVector<int>; +using KeyList = QVector<Qt::Key>; +using SpanList = QVector<QRect>; + +class QtTestTableModel: public QAbstractTableModel +{ + Q_OBJECT + +signals: + void invalidIndexEncountered() const; + +public slots: + bool submit() override { ++submit_count; return QAbstractTableModel::submit(); } + +public: + QtTestTableModel(int rows = 0, int columns = 0, QObject *parent = nullptr) + : QAbstractTableModel(parent), row_count(rows), column_count(columns) + {} + + int rowCount(const QModelIndex& = QModelIndex()) const override + { + return row_count; + } + + int columnCount(const QModelIndex& = QModelIndex()) const override + { + return column_count; + } + + bool isEditable(const QModelIndex &) const { return true; } + + Qt::ItemFlags flags(const QModelIndex &index) const override + { + Qt::ItemFlags index_flags = QAbstractTableModel::flags(index); + if (disabled_rows.contains(index.row()) + || disabled_columns.contains(index.column())) + index_flags &= ~Qt::ItemIsEnabled; + return index_flags; + } + + void disableRow(int row) + { + disabled_rows.insert(row); + } + + void enableRow(int row) + { + disabled_rows.remove(row); + } + + void disableColumn(int column) + { + disabled_columns.insert(column); + } + + void enableColumn(int column) + { + disabled_columns.remove(column); + } + + QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override + { + if (!idx.isValid() || idx.row() >= row_count || idx.column() >= column_count) { + qWarning() << "Invalid modelIndex [%d,%d,%p]" << idx; + emit invalidIndexEncountered(); + return QVariant(); + } + + if (role == Qt::DisplayRole || role == Qt::EditRole) { + return QLatin1Char('[') + QString::number(idx.row()) + QLatin1Char(',') + + QString::number(idx.column()) + QLatin1String(",0]"); + } -typedef QList<bool> BoolList; + return QVariant(); + } + + bool insertRows(int start, int count, const QModelIndex &parent = QModelIndex()) override + { + if (start < 0 || start > row_count) + return false; + + beginInsertRows(parent, start, start + count - 1); + row_count += count; + endInsertRows(); + return true; + } + + bool removeRows(int start, int count, const QModelIndex &parent = QModelIndex()) override + { + if (start < 0 || start >= row_count || row_count < count) + return false; + + beginRemoveRows(parent, start, start + count - 1); + row_count -= count; + endRemoveRows(); + return true; + } + + void removeLastRow() + { + beginRemoveRows(QModelIndex(), row_count - 1, row_count - 1); + --row_count; + endRemoveRows(); + } + + void removeAllRows() + { + beginRemoveRows(QModelIndex(), 0, row_count - 1); + row_count = 0; + endRemoveRows(); + } + + bool insertColumns(int start, int count, const QModelIndex &parent = QModelIndex()) override + { + if (start < 0 || start > column_count) + return false; + + beginInsertColumns(parent, start, start + count - 1); + column_count += count; + endInsertColumns(); + return true; + } + + bool removeColumns(int start, int count, const QModelIndex &parent = QModelIndex()) override + { + if (start < 0 || start >= column_count || column_count < count) + return false; + + beginRemoveColumns(parent, start, start + count - 1); + column_count -= count; + endRemoveColumns(); + return true; + } + + void removeLastColumn() + { + beginRemoveColumns(QModelIndex(), column_count - 1, column_count - 1); + --column_count; + endRemoveColumns(); + } + + void removeAllColumns() + { + beginRemoveColumns(QModelIndex(), 0, column_count - 1); + column_count = 0; + endRemoveColumns(); + } + + bool canFetchMore(const QModelIndex &) const override + { + return can_fetch_more; + } + + void fetchMore(const QModelIndex &) override + { + ++fetch_more_count; + } + + QSet<int> disabled_rows; + QSet<int> disabled_columns; + int row_count; + int column_count; + int submit_count = 0; + int fetch_more_count = 0; + bool can_fetch_more = false; +}; + +class QtTestTableView : public QTableView +{ + Q_OBJECT +public: + using QTableView::QTableView; + + void setModel(QAbstractItemModel *model) override + { + QTableView::setModel(model); + connect(selectionModel(), &QItemSelectionModel::currentChanged, + this, &QtTestTableView::slotCurrentChanged); + connect(selectionModel(), &QItemSelectionModel::selectionChanged, + this, &QtTestTableView::itemSelectionChanged); + // Allow small sections in this test, since this test was made before we correctly enforced minimum sizes. + horizontalHeader()->setMinimumSectionSize(0); + verticalHeader()->setMinimumSectionSize(0); + } + + using QTableView::moveCursor; + using QTableView::isIndexHidden; + using QTableView::setSelection; + using QTableView::selectedIndexes; + using QTableView::sizeHintForRow; + using QTableView::viewOptions; + + bool checkSignalOrder = false; +public slots: + void slotCurrentChanged(QModelIndex, QModelIndex) { + hasCurrentChanged++; + if (checkSignalOrder) + QVERIFY(hasCurrentChanged > hasSelectionChanged); + } + + void itemSelectionChanged(QItemSelection , QItemSelection ) { + hasSelectionChanged++; + if (checkSignalOrder) + QVERIFY(hasCurrentChanged >= hasSelectionChanged); + } +private: + int hasCurrentChanged = 0; + int hasSelectionChanged = 0; + + friend class tst_QTableView; + friend struct QMetaTypeId<QtTestTableView::CursorAction>; +}; +Q_DECLARE_METATYPE(QtTestTableView::CursorAction); + +class QtTestItemDelegate : public QStyledItemDelegate +{ +public: + QSize sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const override + { + return hint; + } + + QSize hint; +}; class tst_QTableView : public QObject { Q_OBJECT +private: + using CursorActionList = QVector<QtTestTableView::CursorAction>; private slots: void getSetCheck(); @@ -183,6 +418,7 @@ private slots: void taskQTBUG_10169_sizeHintForRow(); void taskQTBUG_30653_doItemsLayout(); void taskQTBUG_50171_selectRowAfterSwapColumns(); + void deselectRow(); #if QT_CONFIG(wheelevent) void mouseWheel_data(); @@ -196,6 +432,10 @@ private slots: void viewOptions(); void taskQTBUG_7232_AllowUserToControlSingleStep(); + +#if QT_CONFIG(textmarkdownwriter) + void markdownWriter(); +#endif }; // Testing get/set functions @@ -229,14 +469,14 @@ void tst_QTableView::getSetCheck() QHeaderView *var1 = new QHeaderView(Qt::Horizontal); obj1.setHorizontalHeader(var1); QCOMPARE(var1, obj1.horizontalHeader()); - obj1.setHorizontalHeader((QHeaderView *)0); + obj1.setHorizontalHeader(nullptr); QCOMPARE(var1, obj1.horizontalHeader()); delete var1; QHeaderView *var2 = new QHeaderView(Qt::Vertical); obj1.setVerticalHeader(var2); QCOMPARE(var2, obj1.verticalHeader()); - obj1.setVerticalHeader((QHeaderView *)0); + obj1.setVerticalHeader(nullptr); QCOMPARE(var2, obj1.verticalHeader()); delete var2; @@ -244,283 +484,12 @@ void tst_QTableView::getSetCheck() obj1.setCornerButtonEnabled(false); QCOMPARE(obj1.isCornerButtonEnabled(), false); } - -class QtTestTableModel: public QAbstractTableModel -{ - Q_OBJECT - -signals: - void invalidIndexEncountered() const; - -public slots: - bool submit() { ++submit_count; return QAbstractTableModel::submit(); } - -public: - QtTestTableModel(int rows = 0, int columns = 0, QObject *parent = 0) - : QAbstractTableModel(parent), - row_count(rows), - column_count(columns), - submit_count(0), - can_fetch_more(false), - fetch_more_count(0), - disabled_rows(), - disabled_columns() {} - - int rowCount(const QModelIndex& = QModelIndex()) const { return row_count; } - int columnCount(const QModelIndex& = QModelIndex()) const { return column_count; } - bool isEditable(const QModelIndex &) const { return true; } - - Qt::ItemFlags flags(const QModelIndex &index) const - { - Qt::ItemFlags index_flags = QAbstractTableModel::flags(index); - if (disabled_rows.contains(index.row()) - || disabled_columns.contains(index.column())) - index_flags &= ~Qt::ItemIsEnabled; - return index_flags; - } - - void disableRow(int row) - { - disabled_rows.insert(row); - } - - void enableRow(int row) - { - disabled_rows.remove(row); - } - - void disableColumn(int column) - { - disabled_columns.insert(column); - } - - void enableColumn(int column) - { - disabled_columns.remove(column); - } - - QVariant data(const QModelIndex &idx, int role) const - { - if (!idx.isValid() || idx.row() >= row_count || idx.column() >= column_count) { - qWarning() << "Invalid modelIndex [%d,%d,%p]" << idx; - emit invalidIndexEncountered(); - return QVariant(); - } - - if (role == Qt::DisplayRole || role == Qt::EditRole) { - return QLatin1Char('[') + QString::number(idx.row()) + QLatin1Char(',') - + QString::number(idx.column()) + QLatin1String(",0]"); - } - - return QVariant(); - } - - bool insertRows(int start, int count, const QModelIndex &parent = QModelIndex()) - { - if (start < 0 || start > row_count) - return false; - - beginInsertRows(parent, start, start + count - 1); - row_count += count; - endInsertRows(); - return true; - } - - bool removeRows(int start, int count, const QModelIndex &parent = QModelIndex()) - { - if (start < 0 || start >= row_count || row_count < count) - return false; - - beginRemoveRows(parent, start, start + count - 1); - row_count -= count; - endRemoveRows(); - return true; - } - - void removeLastRow() - { - beginRemoveRows(QModelIndex(), row_count - 1, row_count - 1); - --row_count; - endRemoveRows(); - } - - void removeAllRows() - { - beginRemoveRows(QModelIndex(), 0, row_count - 1); - row_count = 0; - endRemoveRows(); - } - - bool insertColumns(int start, int count, const QModelIndex &parent = QModelIndex()) - { - if (start < 0 || start > column_count) - return false; - - beginInsertColumns(parent, start, start + count - 1); - column_count += count; - endInsertColumns(); - return true; - } - - bool removeColumns(int start, int count, const QModelIndex &parent = QModelIndex()) - { - if (start < 0 || start >= column_count || column_count < count) - return false; - - beginRemoveColumns(parent, start, start + count - 1); - column_count -= count; - endRemoveColumns(); - return true; - } - - void removeLastColumn() - { - beginRemoveColumns(QModelIndex(), column_count - 1, column_count - 1); - --column_count; - endRemoveColumns(); - } - - void removeAllColumns() - { - beginRemoveColumns(QModelIndex(), 0, column_count - 1); - column_count = 0; - endRemoveColumns(); - } - - bool canFetchMore(const QModelIndex &) const - { - return can_fetch_more; - } - - void fetchMore(const QModelIndex &) - { - ++fetch_more_count; - } - - void reset() - { - beginResetModel(); - endResetModel(); - } - - int row_count; - int column_count; - int submit_count; - bool can_fetch_more; - int fetch_more_count; - QSet<int> disabled_rows; - QSet<int> disabled_columns; -}; - -class QtTestTableView : public QTableView -{ -Q_OBJECT - -public: - QtTestTableView(QWidget *parent = 0) : QTableView(parent), checkSignalOrder(false), hasCurrentChanged(0), hasSelectionChanged(0) {} - - void setModel(QAbstractItemModel *model) - { - QTableView::setModel(model); - connect(selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), - this, SLOT(slotCurrentChanged(QModelIndex,QModelIndex))); - connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), - this, SLOT(itemSelectionChanged(QItemSelection,QItemSelection))); - // Allow small sections in this test, since this test was made before we correctly enforced minimum sizes. - horizontalHeader()->setMinimumSectionSize(0); - verticalHeader()->setMinimumSectionSize(0); - } - - // enum CursorAction and moveCursor() are protected in QTableView. - enum CursorAction { - MoveUp = QAbstractItemView::MoveUp, - MoveDown = QAbstractItemView::MoveDown, - MoveLeft = QAbstractItemView::MoveLeft, - MoveRight = QAbstractItemView::MoveRight, - MoveHome = QAbstractItemView::MoveHome, - MoveEnd = QAbstractItemView::MoveEnd, - MovePageUp = QAbstractItemView::MovePageUp, - MovePageDown = QAbstractItemView::MovePageDown, - MoveNext = QAbstractItemView::MoveNext, - MovePrevious = QAbstractItemView::MovePrevious - }; - - QModelIndex doMoveCursor(QtTestTableView::CursorAction cursorAction, - Qt::KeyboardModifiers modifiers) - { - return QTableView::moveCursor((QAbstractItemView::CursorAction)cursorAction, modifiers); - } - - int columnWidthHint(int column) const - { - return sizeHintForColumn(column); - } - - int rowHeightHint(int row) const - { - return sizeHintForRow(row); - } - - bool isIndexHidden(const QModelIndex &index) const - { - return QTableView::isIndexHidden(index); - } - - void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command) - { - QTableView::setSelection(rect, command); - } - - QModelIndexList selectedIndexes() const - { - return QTableView::selectedIndexes(); - } - - int sizeHintForRow(int row) const - { - return QTableView::sizeHintForRow(row); - } - - QStyleOptionViewItem viewOptions() const { - return QTableView::viewOptions(); - } - - bool checkSignalOrder; -public slots: - void slotCurrentChanged(QModelIndex, QModelIndex) { - hasCurrentChanged++; - if (checkSignalOrder) - QVERIFY(hasCurrentChanged > hasSelectionChanged); - } - - void itemSelectionChanged(QItemSelection , QItemSelection ) { - hasSelectionChanged++; - if (checkSignalOrder) - QVERIFY(hasCurrentChanged >= hasSelectionChanged); - } -private: - int hasCurrentChanged; - int hasSelectionChanged; - -}; - -class QtTestItemDelegate : public QItemDelegate -{ -public: - QSize sizeHint(const QStyleOptionViewItem&, const QModelIndex&) const - { - return hint; - } - - QSize hint; -}; - void tst_QTableView::noDelegate() { QtTestTableModel model(3, 3); QTableView view; view.setModel(&model); - view.setItemDelegate(0); + view.setItemDelegate(nullptr); view.show(); } @@ -534,7 +503,7 @@ void tst_QTableView::emptyModel() { QtTestTableModel model; QTableView view; - QSignalSpy spy(&model, SIGNAL(invalidIndexEncountered())); + QSignalSpy spy(&model, &QtTestTableModel::invalidIndexEncountered); view.setModel(&model); view.show(); QCOMPARE(spy.count(), 0); @@ -555,7 +524,7 @@ void tst_QTableView::removeRows() QFETCH(int, columnCount); QtTestTableModel model(rowCount, columnCount); - QSignalSpy spy(&model, SIGNAL(invalidIndexEncountered())); + QSignalSpy spy(&model, &QtTestTableModel::invalidIndexEncountered); QTableView view; view.setModel(&model); @@ -583,7 +552,7 @@ void tst_QTableView::removeColumns() QFETCH(int, columnCount); QtTestTableModel model(rowCount, columnCount); - QSignalSpy spy(&model, SIGNAL(invalidIndexEncountered())); + QSignalSpy spy(&model, &QtTestTableModel::invalidIndexEncountered); QTableView view; view.setModel(&model); @@ -601,58 +570,18 @@ void tst_QTableView::keyboardNavigation_data() QTest::addColumn<int>("rowCount"); QTest::addColumn<int>("columnCount"); QTest::addColumn<bool>("tabKeyNavigation"); - QTest::addColumn<IntList>("keyPresses"); - - QTest::newRow("16x16 model") << 16 << 16 << true - << (IntList() - << Qt::Key_Up - << Qt::Key_Up - << Qt::Key_Right - << Qt::Key_Right - << Qt::Key_Up - << Qt::Key_Left - << Qt::Key_Left - << Qt::Key_Up - << Qt::Key_Down - << Qt::Key_Up - << Qt::Key_Up - << Qt::Key_Up - << Qt::Key_Up - << Qt::Key_Up - << Qt::Key_Up - << Qt::Key_Left - << Qt::Key_Left - << Qt::Key_Up - << Qt::Key_Down - << Qt::Key_Down - << Qt::Key_Tab - << Qt::Key_Backtab); - - - QTest::newRow("no tab") << 8 << 8 << false - << (IntList() - << Qt::Key_Up - << Qt::Key_Up - << Qt::Key_Right - << Qt::Key_Right - << Qt::Key_Up - << Qt::Key_Left - << Qt::Key_Left - << Qt::Key_Up - << Qt::Key_Down - << Qt::Key_Up - << Qt::Key_Up - << Qt::Key_Up - << Qt::Key_Up - << Qt::Key_Up - << Qt::Key_Up - << Qt::Key_Left - << Qt::Key_Left - << Qt::Key_Up - << Qt::Key_Down - << Qt::Key_Down - << Qt::Key_Tab - << Qt::Key_Backtab); + QTest::addColumn<KeyList>("keyPresses"); + + const KeyList keyList { + Qt::Key_Up, Qt::Key_Up, Qt::Key_Right, Qt::Key_Right, + Qt::Key_Up, Qt::Key_Left, Qt::Key_Left, Qt::Key_Up, + Qt::Key_Down, Qt::Key_Up, Qt::Key_Up, Qt::Key_Up, + Qt::Key_Up, Qt::Key_Up, Qt::Key_Up, Qt::Key_Left, + Qt::Key_Left, Qt::Key_Up, Qt::Key_Down, Qt::Key_Down, + Qt::Key_Tab, Qt::Key_Backtab}; + + QTest::newRow("16x16 model") << 16 << 16 << true << keyList; + QTest::newRow("no tab") << 8 << 8 << false << keyList; } void tst_QTableView::keyboardNavigation() @@ -660,7 +589,7 @@ void tst_QTableView::keyboardNavigation() QFETCH(int, rowCount); QFETCH(int, columnCount); QFETCH(bool, tabKeyNavigation); - QFETCH(IntList, keyPresses); + QFETCH(const KeyList, keyPresses); QtTestTableModel model(rowCount, columnCount); QTableView view; @@ -671,14 +600,12 @@ void tst_QTableView::keyboardNavigation() view.setCurrentIndex(index); view.show(); - qApp->setActiveWindow(&view); + QApplication::setActiveWindow(&view); QVERIFY(QTest::qWaitForWindowActive(&view)); int row = rowCount - 1; int column = columnCount - 1; - for (int i = 0; i < keyPresses.count(); ++i) { - - Qt::Key key = (Qt::Key)keyPresses.at(i); + for (Qt::Key key : keyPresses) { switch (key) { case Qt::Key_Up: @@ -778,8 +705,8 @@ void tst_QTableView::moveCursor_data() QTest::addColumn<int>("startRow"); QTest::addColumn<int>("startColumn"); - QTest::addColumn<int>("cursorMoveAction"); - QTest::addColumn<int>("modifier"); + QTest::addColumn<QtTestTableView::CursorAction>("cursorMoveAction"); + QTest::addColumn<Qt::KeyboardModifier>("modifier"); QTest::addColumn<int>("expectedRow"); QTest::addColumn<int>("expectedColumn"); @@ -790,346 +717,346 @@ void tst_QTableView::moveCursor_data() QTest::newRow("MoveRight (0,0)") << 4 << 4 << -1 << -1 << 0 << 0 - << int(QtTestTableView::MoveRight) << int(Qt::NoModifier) + << QtTestTableView::MoveRight << Qt::NoModifier << 0 << 1 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveRight (3,0)") << 4 << 4 << -1 << -1 << 3 << 0 - << int(QtTestTableView::MoveRight) << int(Qt::NoModifier) + << QtTestTableView::MoveRight << Qt::NoModifier << 3 << 1 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveRight (3,3)") << 4 << 4 << -1 << -1 << 3 << 3 - << int(QtTestTableView::MoveRight) << int(Qt::NoModifier) + << QtTestTableView::MoveRight << Qt::NoModifier << 3 << 3 << IntPair(0,0) << IntPair(0,0); // ### QTest::newRow("MoveRight, hidden column 1 (0,0)") << 4 << 4 << -1 << 1 << 0 << 0 - << int(QtTestTableView::MoveRight) << int(Qt::NoModifier) + << QtTestTableView::MoveRight << Qt::NoModifier << 0 << 2 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveRight, hidden column 3 (0,2)") << 4 << 4 << -1 << 3 << 0 << 2 - << int(QtTestTableView::MoveRight) << int(Qt::NoModifier) + << QtTestTableView::MoveRight << Qt::NoModifier << 0 << 2 << IntPair(0,0) << IntPair(0,0); // ### // MoveNext should in addition wrap QTest::newRow("MoveNext (0,0)") << 4 << 4 << -1 << -1 << 0 << 0 - << int(QtTestTableView::MoveNext) << int(Qt::NoModifier) + << QtTestTableView::MoveNext << Qt::NoModifier << 0 << 1 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveNext (0,2)") << 4 << 4 << -1 << -1 << 0 << 2 - << int(QtTestTableView::MoveNext) << int(Qt::NoModifier) + << QtTestTableView::MoveNext << Qt::NoModifier << 0 << 3 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveNext, wrap (0,3)") << 4 << 4 << -1 << -1 << 0 << 3 - << int(QtTestTableView::MoveNext) << int(Qt::NoModifier) + << QtTestTableView::MoveNext << Qt::NoModifier << 1 << 0 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveNext, wrap (3,3)") << 4 << 4 << -1 << -1 << 3 << 3 - << int(QtTestTableView::MoveNext) << int(Qt::NoModifier) + << QtTestTableView::MoveNext << Qt::NoModifier << 0 << 0 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveNext, hidden column 1 (0,0)") << 4 << 4 << -1 << 1 << 0 << 0 - << int(QtTestTableView::MoveNext) << int(Qt::NoModifier) + << QtTestTableView::MoveNext << Qt::NoModifier << 0 << 2 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveNext, wrap, hidden column 3 (0,2)") << 4 << 4 << -1 << 3 << 0 << 2 - << int(QtTestTableView::MoveNext) << int(Qt::NoModifier) + << QtTestTableView::MoveNext << Qt::NoModifier << 1 << 0 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveNext, wrap, hidden column 3 (3,2)") << 4 << 4 << -1 << 3 << 3 << 2 - << int(QtTestTableView::MoveNext) << int(Qt::NoModifier) + << QtTestTableView::MoveNext << Qt::NoModifier << 0 << 0 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveNext, wrapy, wrapx, hidden column 3, hidden row 3 (2,2)") << 4 << 4 << 3 << 3 << 2 << 2 - << int(QtTestTableView::MoveNext) << int(Qt::NoModifier) + << QtTestTableView::MoveNext << Qt::NoModifier << 0 << 0 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveNext, wrap, hidden column 2, moved column from 3 to 0. (0,2)") << 4 << 4 << -1 << 2 << 0 << 2 - << int(QtTestTableView::MoveNext) << int(Qt::NoModifier) + << QtTestTableView::MoveNext << Qt::NoModifier << 1 << 3 << IntPair(0,0) << IntPair(3,0); // MoveLeft QTest::newRow("MoveLeft (0,0)") << 4 << 4 << -1 << -1 << 0 << 0 - << int(QtTestTableView::MoveLeft) << int(Qt::NoModifier) + << QtTestTableView::MoveLeft << Qt::NoModifier << 0 << 0 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveLeft (0,3)") << 4 << 4 << -1 << -1 << 0 << 3 - << int(QtTestTableView::MoveLeft) << int(Qt::NoModifier) + << QtTestTableView::MoveLeft << Qt::NoModifier << 0 << 2 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveLeft (1,0)") << 4 << 4 << -1 << -1 << 1 << 0 - << int(QtTestTableView::MoveLeft) << int(Qt::NoModifier) + << QtTestTableView::MoveLeft << Qt::NoModifier << 1 << 0 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveLeft, hidden column 0 (0,2)") << 4 << 4 << -1 << 1 << 0 << 2 - << int(QtTestTableView::MoveLeft) << int(Qt::NoModifier) + << QtTestTableView::MoveLeft << Qt::NoModifier << 0 << 0 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveLeft, hidden column 0 (0,1)") << 4 << 4 << -1 << 0 << 0 << 1 - << int(QtTestTableView::MoveLeft) << int(Qt::NoModifier) + << QtTestTableView::MoveLeft << Qt::NoModifier << 0 << 1 << IntPair(0,0) << IntPair(0,0); // MovePrevious should in addition wrap QTest::newRow("MovePrevious (0,3)") << 4 << 4 << -1 << -1 << 0 << 3 - << int(QtTestTableView::MovePrevious) << int(Qt::NoModifier) + << QtTestTableView::MovePrevious << Qt::NoModifier << 0 << 2 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MovePrevious (0,1)") << 4 << 4 << -1 << -1 << 0 << 1 - << int(QtTestTableView::MovePrevious) << int(Qt::NoModifier) + << QtTestTableView::MovePrevious << Qt::NoModifier << 0 << 0 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MovePrevious, wrap (1,0)") << 4 << 4 << -1 << -1 << 1 << 0 - << int(QtTestTableView::MovePrevious) << int(Qt::NoModifier) + << QtTestTableView::MovePrevious << Qt::NoModifier << 0 << 3 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MovePrevious, wrap, (0,0)") << 4 << 4 << -1 << -1 << 0 << 0 - << int(QtTestTableView::MovePrevious) << int(Qt::NoModifier) + << QtTestTableView::MovePrevious << Qt::NoModifier << 3 << 3 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MovePrevious, hidden column 1 (0,2)") << 4 << 4 << -1 << 1 << 0 << 2 - << int(QtTestTableView::MovePrevious) << int(Qt::NoModifier) + << QtTestTableView::MovePrevious << Qt::NoModifier << 0 << 0 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MovePrevious, wrap, hidden column 3 (0,2)") << 4 << 4 << -1 << 3 << 0 << 2 - << int(QtTestTableView::MovePrevious) << int(Qt::NoModifier) + << QtTestTableView::MovePrevious << Qt::NoModifier << 0 << 1 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MovePrevious, wrapy, hidden column 0 (0,1)") << 4 << 4 << -1 << 0 << 0 << 1 - << int(QtTestTableView::MovePrevious) << int(Qt::NoModifier) + << QtTestTableView::MovePrevious << Qt::NoModifier << 3 << 3 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MovePrevious, wrap, hidden column 0, hidden row 0 (1,1)") << 4 << 4 << 0 << 0 << 1 << 1 - << int(QtTestTableView::MovePrevious) << int(Qt::NoModifier) + << QtTestTableView::MovePrevious << Qt::NoModifier << 3 << 3 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MovePrevious, wrap, hidden column 1, moved column from 0 to 3. (1,2)") << 4 << 4 << -1 << 1 << 1 << 2 - << int(QtTestTableView::MovePrevious) << int(Qt::NoModifier) + << QtTestTableView::MovePrevious << Qt::NoModifier << 0 << 0 << IntPair(0,0) << IntPair(0,3); // MoveDown QTest::newRow("MoveDown (0,0)") << 4 << 4 << -1 << -1 << 0 << 0 - << int(QtTestTableView::MoveDown) << int(Qt::NoModifier) + << QtTestTableView::MoveDown << Qt::NoModifier << 1 << 0 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveDown (3,0)") << 4 << 4 << -1 << -1 << 3 << 0 - << int(QtTestTableView::MoveDown) << int(Qt::NoModifier) + << QtTestTableView::MoveDown << Qt::NoModifier << 3 << 0 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveDown (3,3)") << 4 << 4 << -1 << -1 << 3 << 3 - << int(QtTestTableView::MoveDown) << int(Qt::NoModifier) + << QtTestTableView::MoveDown << Qt::NoModifier << 3 << 3 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveDown, hidden row 1 (0,0)") << 4 << 4 << 1 << -1 << 0 << 0 - << int(QtTestTableView::MoveDown) << int(Qt::NoModifier) + << QtTestTableView::MoveDown << Qt::NoModifier << 2 << 0 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveDown, hidden row 3 (2,0)") << 4 << 4 << 3 << -1 << 2 << 0 - << int(QtTestTableView::MoveDown) << int(Qt::NoModifier) + << QtTestTableView::MoveDown << Qt::NoModifier << 2 << 0 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveDown, hidden row 0 hidden column 0 (0,0)") << 4 << 4 << 0 << 0 << 0 << 0 - << int(QtTestTableView::MoveDown) << int(Qt::NoModifier) + << QtTestTableView::MoveDown << Qt::NoModifier << 1 << 1 << IntPair(0,0) << IntPair(0,0); // MoveUp QTest::newRow("MoveUp (0,0)") << 4 << 4 << -1 << -1 << 0 << 0 - << int(QtTestTableView::MoveUp) << int(Qt::NoModifier) + << QtTestTableView::MoveUp << Qt::NoModifier << 0 << 0 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveUp (3, 0)") << 4 << 4 << -1 << -1 << 3 << 0 - << int(QtTestTableView::MoveUp) << int(Qt::NoModifier) + << QtTestTableView::MoveUp << Qt::NoModifier << 2 << 0 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveUp (0,1)") << 4 << 4 << -1 << -1 << 0 << 1 - << int(QtTestTableView::MoveUp) << int(Qt::NoModifier) + << QtTestTableView::MoveUp << Qt::NoModifier << 0 << 1 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveUp, hidden row 1 (2,0)") << 4 << 4 << 1 << -1 << 2 << 0 - << int(QtTestTableView::MoveUp) << int(Qt::NoModifier) + << QtTestTableView::MoveUp << Qt::NoModifier << 0 << 0 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveUp, hidden row (1,0)") << 4 << 4 << 0 << -1 << 1 << 0 - << int(QtTestTableView::MoveUp) << int(Qt::NoModifier) + << QtTestTableView::MoveUp << Qt::NoModifier << 1 << 0 << IntPair(0,0) << IntPair(0,0); // MoveHome QTest::newRow("MoveHome (0,0)") << 4 << 4 << -1 << -1 << 0 << 0 - << int(QtTestTableView::MoveHome) << int(Qt::NoModifier) + << QtTestTableView::MoveHome << Qt::NoModifier << 0 << 0 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveHome (3,3)") << 4 << 4 << -1 << -1 << 3 << 3 - << int(QtTestTableView::MoveHome) << int(Qt::NoModifier) + << QtTestTableView::MoveHome << Qt::NoModifier << 3 << 0 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveHome, hidden column 0 (3,3)") << 4 << 4 << -1 << 0 << 3 << 3 - << int(QtTestTableView::MoveHome) << int(Qt::NoModifier) + << QtTestTableView::MoveHome << Qt::NoModifier << 3 << 1 << IntPair(0,0) << IntPair(0,0); // Use Ctrl modifier QTest::newRow("MoveHome + Ctrl (0,0)") << 4 << 4 << -1 << -1 << 0 << 0 - << int(QtTestTableView::MoveHome) << int(Qt::ControlModifier) + << QtTestTableView::MoveHome << Qt::ControlModifier << 0 << 0 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveHome + Ctrl (3,3)") << 4 << 4 << -1 << -1 << 3 << 3 - << int(QtTestTableView::MoveHome) << int(Qt::ControlModifier) + << QtTestTableView::MoveHome << Qt::ControlModifier << 0 << 0 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveHome + Ctrl, hidden column 0, hidden row 0 (3,3)") << 4 << 4 << 0 << 0 << 3 << 3 - << int(QtTestTableView::MoveHome) << int(Qt::ControlModifier) + << QtTestTableView::MoveHome << Qt::ControlModifier << 1 << 1 << IntPair(0,0) << IntPair(0,0); // MoveEnd QTest::newRow("MoveEnd (0,0)") << 4 << 4 << -1 << -1 << 0 << 0 - << int(QtTestTableView::MoveEnd) << int(Qt::NoModifier) + << QtTestTableView::MoveEnd << Qt::NoModifier << 0 << 3 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveEnd (3,3)") << 4 << 4 << -1 << -1 << 3 << 3 - << int(QtTestTableView::MoveEnd) << int(Qt::NoModifier) + << QtTestTableView::MoveEnd << Qt::NoModifier << 3 << 3 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveEnd, hidden column (0,0)") << 4 << 4 << -1 << 3 << 0 << 0 - << int(QtTestTableView::MoveEnd) << int(Qt::NoModifier) + << QtTestTableView::MoveEnd << Qt::NoModifier << 0<< 2 << IntPair(0,0) << IntPair(0,0); // Use Ctrl modifier QTest::newRow("MoveEnd + Ctrl (0,0)") << 4 << 4 << -1 << -1 << 0 << 0 - << int(QtTestTableView::MoveEnd) << int(Qt::ControlModifier) + << QtTestTableView::MoveEnd << Qt::ControlModifier << 3 << 3 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveEnd + Ctrl (3,3)") << 4 << 4 << -1 << -1 << 3 << 3 - << int(QtTestTableView::MoveEnd) << int(Qt::ControlModifier) + << QtTestTableView::MoveEnd << Qt::ControlModifier << 3 << 3 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveEnd + Ctrl, hidden column 3 (0,0)") << 4 << 4 << -1 << 3 << 0 << 0 - << int(QtTestTableView::MoveEnd) << int(Qt::ControlModifier) + << QtTestTableView::MoveEnd << Qt::ControlModifier << 3 << 2 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MoveEnd + Ctrl, hidden column 3, hidden row 3 (0,0)") << 4 << 4 << 3 << 3 << 0 << 0 - << int(QtTestTableView::MoveEnd) << int(Qt::ControlModifier) + << QtTestTableView::MoveEnd << Qt::ControlModifier << 2 << 2 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MovePageUp (0,0)") << 4 << 4 << -1 << -1 << 0 << 0 - << int(QtTestTableView::MovePageUp) << 0 + << QtTestTableView::MovePageUp << Qt::NoModifier << 0 << 0 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MovePageUp (3,3)") << 4 << 4 << -1 << -1 << 3 << 3 - << int(QtTestTableView::MovePageUp) << 0 + << QtTestTableView::MovePageUp << Qt::NoModifier << 0 << 3 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MovePageDown (3, 3)") << 4 << 4 << -1 << -1 << 3 << 3 - << int(QtTestTableView::MovePageDown) << 0 + << QtTestTableView::MovePageDown << Qt::NoModifier << 3 << 3 << IntPair(0,0) << IntPair(0,0); QTest::newRow("MovePageDown (0, 3)") << 4 << 4 << -1 << -1 << 0 << 3 - << int(QtTestTableView::MovePageDown) << 0 + << QtTestTableView::MovePageDown << Qt::NoModifier << 3 << 3 << IntPair(0,0) << IntPair(0,0); } @@ -1141,8 +1068,8 @@ void tst_QTableView::moveCursor() QFETCH(int, hideColumn); QFETCH(int, startRow); QFETCH(int, startColumn); - QFETCH(int, cursorMoveAction); - QFETCH(int, modifier); + QFETCH(QtTestTableView::CursorAction, cursorMoveAction); + QFETCH(Qt::KeyboardModifier, modifier); QFETCH(int, expectedRow); QFETCH(int, expectedColumn); QFETCH(IntPair, moveRow); @@ -1167,8 +1094,7 @@ void tst_QTableView::moveCursor() QModelIndex index = model.index(startRow, startColumn); view.setCurrentIndex(index); - QModelIndex newIndex = view.doMoveCursor((QtTestTableView::CursorAction)cursorMoveAction, - (Qt::KeyboardModifiers)modifier); + QModelIndex newIndex = view.moveCursor(cursorMoveAction, modifier); // expected fails, task 119433 if(newIndex.row() == -1) return; @@ -1186,7 +1112,7 @@ void tst_QTableView::moveCursorStrikesBack_data() QTest::addColumn<int>("startRow"); QTest::addColumn<int>("startColumn"); - QTest::addColumn<IntList>("cursorMoveActions"); + QTest::addColumn<CursorActionList>("cursorMoveActions"); QTest::addColumn<int>("expectedRow"); QTest::addColumn<int>("expectedColumn"); @@ -1194,70 +1120,84 @@ void tst_QTableView::moveCursorStrikesBack_data() << IntList() << (IntList() << 6) << QRect() - << 0 << 5 << (IntList() << int(QtTestTableView::MoveNext)) + << 0 << 5 + << CursorActionList{QtTestTableView::MoveNext} << 1 << 0; QTest::newRow("Last column disabled 2. Task QTBUG-3878") << -1 << -1 << IntList() << (IntList() << 6) << QRect() - << 1 << 0 << (IntList() << int(QtTestTableView::MovePrevious)) + << 1 << 0 + << CursorActionList{QtTestTableView::MovePrevious} << 0 << 5; QTest::newRow("Span, anchor column hidden") << -1 << 1 << IntList() << IntList() << QRect(1, 2, 2, 3) - << 2 << 0 << (IntList() << int(QtTestTableView::MoveNext)) + << 2 << 0 + << CursorActionList{QtTestTableView::MoveNext} << 2 << 1; QTest::newRow("Span, anchor column disabled") << -1 << -1 << IntList() << (IntList() << 1) << QRect(1, 2, 2, 3) - << 2 << 0 << (IntList() << int(QtTestTableView::MoveNext)) + << 2 << 0 + << CursorActionList{QtTestTableView::MoveNext} << 2 << 1; QTest::newRow("Span, anchor row hidden") << 2 << -1 << IntList() << IntList() << QRect(1, 2, 2, 3) - << 1 << 2 << (IntList() << int(QtTestTableView::MoveDown)) + << 1 << 2 + << CursorActionList{QtTestTableView::MoveDown} << 2 << 1; QTest::newRow("Span, anchor row disabled") << -1 << -1 << (IntList() << 2) << IntList() << QRect(1, 2, 2, 3) - << 1 << 2 << (IntList() << int(QtTestTableView::MoveDown)) + << 1 << 2 + << CursorActionList{QtTestTableView::MoveDown} << 2 << 1; QTest::newRow("Move through span right") << -1 << -1 << IntList() << IntList() << QRect(1, 2, 2, 3) - << 3 << 0 << (IntList() << int(QtTestTableView::MoveRight) << int(QtTestTableView::MoveRight)) + << 3 << 0 + << CursorActionList{QtTestTableView::MoveRight, + QtTestTableView::MoveRight} << 3 << 3; QTest::newRow("Move through span left") << -1 << -1 << IntList() << IntList() << QRect(1, 2, 2, 3) - << 3 << 3 << (IntList() << int(QtTestTableView::MoveLeft) << int(QtTestTableView::MoveLeft)) + << 3 << 3 + << CursorActionList{QtTestTableView::MoveLeft, + QtTestTableView::MoveLeft} << 3 << 0; QTest::newRow("Move through span down") << -1 << -1 << IntList() << IntList() << QRect(1, 2, 2, 3) - << 1 << 2 << (IntList() << int(QtTestTableView::MoveDown) << int(QtTestTableView::MoveDown)) + << 1 << 2 + << CursorActionList{QtTestTableView::MoveDown, + QtTestTableView::MoveDown} << 5 << 2; QTest::newRow("Move through span up") << -1 << -1 << IntList() << IntList() << QRect(1, 2, 2, 3) - << 5 << 2 << (IntList() << int(QtTestTableView::MoveUp) << int(QtTestTableView::MoveUp)) + << 5 << 2 + << CursorActionList{QtTestTableView::MoveUp, + QtTestTableView::MoveUp} << 1 << 2; IntList fullList; @@ -1268,42 +1208,48 @@ void tst_QTableView::moveCursorStrikesBack_data() << fullList << fullList << QRect() - << 1 << 0 << (IntList() << int(QtTestTableView::MoveNext)) + << 1 << 0 + << CursorActionList{QtTestTableView::MoveNext} << -1 << -1; QTest::newRow("All disabled, wrap backwards. => invalid index") << -1 << -1 << fullList << fullList << QRect() - << 1 << 0 << (IntList() << int(QtTestTableView::MovePrevious)) + << 1 << 0 + << CursorActionList{QtTestTableView::MovePrevious} << -1 << -1; QTest::newRow("Last column disabled, MoveEnd. QTBUG-72400") << -1 << -1 << IntList() << (IntList() << 6) << QRect() - << 0 << 0 << (IntList() << int(QtTestTableView::MoveEnd)) + << 0 << 0 + << CursorActionList{QtTestTableView::MoveEnd} << 0 << 5; QTest::newRow("First column disabled, MoveHome. QTBUG-72400") << -1 << -1 << IntList() << (IntList() << 0) << QRect() - << 0 << 6 << (IntList() << int(QtTestTableView::MoveHome)) + << 0 << 6 + << CursorActionList{QtTestTableView::MoveHome} << 0 << 1; QTest::newRow("First row disabled, MovePageUp. QTBUG-72400") << -1 << -1 << (IntList() << 0) << IntList() << QRect() - << 2 << 0 << (IntList() << int(QtTestTableView::MovePageUp)) + << 2 << 0 + << CursorActionList{QtTestTableView::MovePageUp} << 1 << 0; QTest::newRow("Last row disabled, MovePageDown. QTBUG-72400") << -1 << -1 << (IntList() << 6) << IntList() << QRect() - << 4 << 0 << (IntList() << int(QtTestTableView::MovePageDown)) + << 4 << 0 + << CursorActionList{QtTestTableView::MovePageDown} << 5 << 0; } @@ -1311,13 +1257,13 @@ void tst_QTableView::moveCursorStrikesBack() { QFETCH(int, hideRow); QFETCH(int, hideColumn); - QFETCH(IntList, disableRows); - QFETCH(IntList, disableColumns); + QFETCH(const IntList, disableRows); + QFETCH(const IntList, disableColumns); QFETCH(QRect, span); QFETCH(int, startRow); QFETCH(int, startColumn); - QFETCH(IntList, cursorMoveActions); + QFETCH(const CursorActionList, cursorMoveActions); QFETCH(int, expectedRow); QFETCH(int, expectedColumn); @@ -1337,15 +1283,15 @@ void tst_QTableView::moveCursorStrikesBack() QModelIndex index = model.index(startRow, startColumn); view.setCurrentIndex(index); - foreach (int row, disableRows) + for (int row : disableRows) model.disableRow(row); - foreach (int column, disableColumns) + for (int column : disableColumns) model.disableColumn(column); int newRow = -1; int newColumn = -1; - foreach (int cursorMoveAction, cursorMoveActions) { - QModelIndex newIndex = view.doMoveCursor((QtTestTableView::CursorAction)cursorMoveAction, 0); + for (auto cursorMoveAction : cursorMoveActions) { + QModelIndex newIndex = view.moveCursor(cursorMoveAction, nullptr); view.setCurrentIndex(newIndex); newRow = newIndex.row(); newColumn = newIndex.column(); @@ -1516,7 +1462,7 @@ void tst_QTableView::selection_data() QTest::addColumn<int>("y"); QTest::addColumn<int>("width"); QTest::addColumn<int>("height"); - QTest::addColumn<int>("command"); + QTest::addColumn<QItemSelectionModel::SelectionFlag>("command"); QTest::addColumn<int>("selectedCount"); // ### make this more detailed QTest::newRow("no span, no hidden, no moved, 3x3 select") @@ -1528,7 +1474,7 @@ void tst_QTableView::selection_data() << -1 << -1 // move col << 40 << 40 // cell size << 20 << 20 << 80 << 80 // rect - << int(QItemSelectionModel::Select) // command + << QItemSelectionModel::Select // command << 9; // selected count QTest::newRow("row span, no hidden, no moved, 3x3 select") @@ -1540,7 +1486,7 @@ void tst_QTableView::selection_data() << -1 << -1 // move col << 40 << 40 // cell size << 20 << 20 << 80 << 80 // rect - << int(QItemSelectionModel::Select) // command + << QItemSelectionModel::Select // command << 8; // selected count QTest::newRow("col span, no hidden, no moved, 3x3 select") @@ -1552,7 +1498,7 @@ void tst_QTableView::selection_data() << -1 << -1 // move col << 40 << 40 // cell size << 20 << 20 << 80 << 80 // rect - << int(QItemSelectionModel::Select) // command + << QItemSelectionModel::Select // command << 8; // selected count QTest::newRow("no span, row hidden, no moved, 3x3 select") @@ -1564,7 +1510,7 @@ void tst_QTableView::selection_data() << -1 << -1 // move col << 40 << 40 // cell size << 20 << 20 << 80 << 80 // rect - << int(QItemSelectionModel::Select) // command + << QItemSelectionModel::Select // command << 9; // selected count QTest::newRow("no span, col hidden, no moved, 3x3 select") @@ -1576,7 +1522,7 @@ void tst_QTableView::selection_data() << -1 << -1 // move col << 40 << 40 // cell size << 20 << 20 << 80 << 80 // rect - << int(QItemSelectionModel::Select) // command + << QItemSelectionModel::Select // command << 9; // selected count QTest::newRow("no span, no hidden, row moved, 3x3 select") @@ -1588,7 +1534,7 @@ void tst_QTableView::selection_data() << -1 << -1 // move col << 40 << 40 // cell size << 20 << 20 << 80 << 80 // rect - << int(QItemSelectionModel::Select) // command + << QItemSelectionModel::Select // command << 9; // selected count QTest::newRow("no span, no hidden, col moved, 3x3 select") @@ -1600,7 +1546,7 @@ void tst_QTableView::selection_data() << 1 << 3 // move col << 40 << 40 // cell size << 20 << 20 << 80 << 80 // rect - << int(QItemSelectionModel::Select) // command + << QItemSelectionModel::Select // command << 9; // selected count } @@ -1624,7 +1570,7 @@ void tst_QTableView::selection() QFETCH(int, y); QFETCH(int, width); QFETCH(int, height); - QFETCH(int, command); + QFETCH(QItemSelectionModel::SelectionFlag, command); QFETCH(int, selectedCount); QtTestTableModel model(rowCount, columnCount); @@ -1646,8 +1592,7 @@ void tst_QTableView::selection() for (int c = 0; c < columnCount; ++c) view.setColumnWidth(c, columnWidth); - view.setSelection(QRect(x, y, width, height), - QItemSelectionModel::SelectionFlags(command)); + view.setSelection(QRect(x, y, width, height), command); QCOMPARE(view.selectedIndexes().count(), selectedCount); } @@ -1657,92 +1602,92 @@ void tst_QTableView::selectRow_data() QTest::addColumn<int>("rowCount"); QTest::addColumn<int>("columnCount"); QTest::addColumn<int>("row"); - QTest::addColumn<int>("mode"); - QTest::addColumn<int>("behavior"); + QTest::addColumn<QAbstractItemView::SelectionMode>("mode"); + QTest::addColumn<QAbstractItemView::SelectionBehavior>("behavior"); QTest::addColumn<int>("selectedItems"); QTest::newRow("SingleSelection and SelectItems") << 10 << 10 << 0 - << (int)QAbstractItemView::SingleSelection - << (int)QAbstractItemView::SelectItems + << QAbstractItemView::SingleSelection + << QAbstractItemView::SelectItems << 0; QTest::newRow("SingleSelection and SelectRows") << 10 << 10 << 0 - << (int)QAbstractItemView::SingleSelection - << (int)QAbstractItemView::SelectRows + << QAbstractItemView::SingleSelection + << QAbstractItemView::SelectRows << 10; QTest::newRow("SingleSelection and SelectColumns") << 10 << 10 << 0 - << (int)QAbstractItemView::SingleSelection - << (int)QAbstractItemView::SelectColumns + << QAbstractItemView::SingleSelection + << QAbstractItemView::SelectColumns << 0; QTest::newRow("MultiSelection and SelectItems") << 10 << 10 << 0 - << (int)QAbstractItemView::MultiSelection - << (int)QAbstractItemView::SelectItems + << QAbstractItemView::MultiSelection + << QAbstractItemView::SelectItems << 10; QTest::newRow("MultiSelection and SelectRows") << 10 << 10 << 0 - << (int)QAbstractItemView::MultiSelection - << (int)QAbstractItemView::SelectRows + << QAbstractItemView::MultiSelection + << QAbstractItemView::SelectRows << 10; QTest::newRow("MultiSelection and SelectColumns") << 10 << 10 << 0 - << (int)QAbstractItemView::MultiSelection - << (int)QAbstractItemView::SelectColumns + << QAbstractItemView::MultiSelection + << QAbstractItemView::SelectColumns << 0; QTest::newRow("ExtendedSelection and SelectItems") << 10 << 10 << 0 - << (int)QAbstractItemView::ExtendedSelection - << (int)QAbstractItemView::SelectItems + << QAbstractItemView::ExtendedSelection + << QAbstractItemView::SelectItems << 10; QTest::newRow("ExtendedSelection and SelectRows") << 10 << 10 << 0 - << (int)QAbstractItemView::ExtendedSelection - << (int)QAbstractItemView::SelectRows + << QAbstractItemView::ExtendedSelection + << QAbstractItemView::SelectRows << 10; QTest::newRow("ExtendedSelection and SelectColumns") << 10 << 10 << 0 - << (int)QAbstractItemView::ExtendedSelection - << (int)QAbstractItemView::SelectColumns + << QAbstractItemView::ExtendedSelection + << QAbstractItemView::SelectColumns << 0; QTest::newRow("ContiguousSelection and SelectItems") << 10 << 10 << 0 - << (int)QAbstractItemView::ContiguousSelection - << (int)QAbstractItemView::SelectItems + << QAbstractItemView::ContiguousSelection + << QAbstractItemView::SelectItems << 10; QTest::newRow("ContiguousSelection and SelectRows") << 10 << 10 << 0 - << (int)QAbstractItemView::ContiguousSelection - << (int)QAbstractItemView::SelectRows + << QAbstractItemView::ContiguousSelection + << QAbstractItemView::SelectRows << 10; QTest::newRow("ContiguousSelection and SelectColumns") << 10 << 10 << 0 - << (int)QAbstractItemView::ContiguousSelection - << (int)QAbstractItemView::SelectColumns + << QAbstractItemView::ContiguousSelection + << QAbstractItemView::SelectColumns << 0; } @@ -1751,16 +1696,16 @@ void tst_QTableView::selectRow() QFETCH(int, rowCount); QFETCH(int, columnCount); QFETCH(int, row); - QFETCH(int, mode); - QFETCH(int, behavior); + QFETCH(QAbstractItemView::SelectionMode, mode); + QFETCH(QAbstractItemView::SelectionBehavior, behavior); QFETCH(int, selectedItems); QtTestTableModel model(rowCount, columnCount); QTableView view; view.setModel(&model); - view.setSelectionMode((QAbstractItemView::SelectionMode)mode); - view.setSelectionBehavior((QAbstractItemView::SelectionBehavior)behavior); + view.setSelectionMode(mode); + view.setSelectionBehavior(behavior); QCOMPARE(view.selectionModel()->selectedIndexes().count(), 0); @@ -1778,92 +1723,92 @@ void tst_QTableView::selectColumn_data() QTest::addColumn<int>("rowCount"); QTest::addColumn<int>("columnCount"); QTest::addColumn<int>("column"); - QTest::addColumn<int>("mode"); - QTest::addColumn<int>("behavior"); + QTest::addColumn<QAbstractItemView::SelectionMode>("mode"); + QTest::addColumn<QAbstractItemView::SelectionBehavior>("behavior"); QTest::addColumn<int>("selectedItems"); QTest::newRow("SingleSelection and SelectItems") << 10 << 10 << 0 - << (int)QAbstractItemView::SingleSelection - << (int)QAbstractItemView::SelectItems + << QAbstractItemView::SingleSelection + << QAbstractItemView::SelectItems << 0; QTest::newRow("SingleSelection and SelectRows") << 10 << 10 << 0 - << (int)QAbstractItemView::SingleSelection - << (int)QAbstractItemView::SelectRows + << QAbstractItemView::SingleSelection + << QAbstractItemView::SelectRows << 0; QTest::newRow("SingleSelection and SelectColumns") << 10 << 10 << 0 - << (int)QAbstractItemView::SingleSelection - << (int)QAbstractItemView::SelectColumns + << QAbstractItemView::SingleSelection + << QAbstractItemView::SelectColumns << 10; QTest::newRow("MultiSelection and SelectItems") << 10 << 10 << 0 - << (int)QAbstractItemView::MultiSelection - << (int)QAbstractItemView::SelectItems + << QAbstractItemView::MultiSelection + << QAbstractItemView::SelectItems << 10; QTest::newRow("MultiSelection and SelectRows") << 10 << 10 << 0 - << (int)QAbstractItemView::MultiSelection - << (int)QAbstractItemView::SelectRows + << QAbstractItemView::MultiSelection + << QAbstractItemView::SelectRows << 0; QTest::newRow("MultiSelection and SelectColumns") << 10 << 10 << 0 - << (int)QAbstractItemView::MultiSelection - << (int)QAbstractItemView::SelectColumns + << QAbstractItemView::MultiSelection + << QAbstractItemView::SelectColumns << 10; QTest::newRow("ExtendedSelection and SelectItems") << 10 << 10 << 0 - << (int)QAbstractItemView::ExtendedSelection - << (int)QAbstractItemView::SelectItems + << QAbstractItemView::ExtendedSelection + << QAbstractItemView::SelectItems << 10; QTest::newRow("ExtendedSelection and SelectRows") << 10 << 10 << 0 - << (int)QAbstractItemView::ExtendedSelection - << (int)QAbstractItemView::SelectRows + << QAbstractItemView::ExtendedSelection + << QAbstractItemView::SelectRows << 0; QTest::newRow("ExtendedSelection and SelectColumns") << 10 << 10 << 0 - << (int)QAbstractItemView::ExtendedSelection - << (int)QAbstractItemView::SelectColumns + << QAbstractItemView::ExtendedSelection + << QAbstractItemView::SelectColumns << 10; QTest::newRow("ContiguousSelection and SelectItems") << 10 << 10 << 0 - << (int)QAbstractItemView::ContiguousSelection - << (int)QAbstractItemView::SelectItems + << QAbstractItemView::ContiguousSelection + << QAbstractItemView::SelectItems << 10; QTest::newRow("ContiguousSelection and SelectRows") << 10 << 10 << 0 - << (int)QAbstractItemView::ContiguousSelection - << (int)QAbstractItemView::SelectRows + << QAbstractItemView::ContiguousSelection + << QAbstractItemView::SelectRows << 0; QTest::newRow("ContiguousSelection and SelectColumns") << 10 << 10 << 0 - << (int)QAbstractItemView::ContiguousSelection - << (int)QAbstractItemView::SelectColumns + << QAbstractItemView::ContiguousSelection + << QAbstractItemView::SelectColumns << 10; } @@ -1872,16 +1817,16 @@ void tst_QTableView::selectColumn() QFETCH(int, rowCount); QFETCH(int, columnCount); QFETCH(int, column); - QFETCH(int, mode); - QFETCH(int, behavior); + QFETCH(QAbstractItemView::SelectionMode, mode); + QFETCH(QAbstractItemView::SelectionBehavior, behavior); QFETCH(int, selectedItems); QtTestTableModel model(rowCount, columnCount); QTableView view; view.setModel(&model); - view.setSelectionMode((QAbstractItemView::SelectionMode)mode); - view.setSelectionBehavior((QAbstractItemView::SelectionBehavior)behavior); + view.setSelectionMode(mode); + view.setSelectionBehavior(behavior); QCOMPARE(view.selectionModel()->selectedIndexes().count(), 0); @@ -1981,9 +1926,9 @@ void tst_QTableView::selectall_data() << 100; // selected count } -void QTest__keySequence(QWidget* widget, QKeySequence ks) +void QTest__keySequence(QWidget* widget, const QKeySequence &ks) { - for (int i=0; i<ks.count(); ++i) + for (int i = 0; i < ks.count(); ++i) { Qt::Key key = Qt::Key(ks[i] & ~Qt::KeyboardModifierMask); Qt::KeyboardModifiers modifiers = Qt::KeyboardModifiers(ks[i] & Qt::KeyboardModifierMask); @@ -2221,7 +2166,7 @@ void tst_QTableView::resizeRowsToContents() QFETCH(int, cellHeight); QFETCH(int, rowHeight); QFETCH(int, columnWidth); - Q_UNUSED(columnWidth); + Q_UNUSED(columnWidth) QtTestTableModel model(rowCount, columnCount); QtTestTableView view; @@ -2233,13 +2178,12 @@ void tst_QTableView::resizeRowsToContents() delegate.hint = QSize(cellWidth, cellHeight); - QSignalSpy resizedSpy(view.verticalHeader(), SIGNAL(sectionResized(int,int,int))); + QSignalSpy resizedSpy(view.verticalHeader(), &QHeaderView::sectionResized); view.resizeRowsToContents(); QCOMPARE(resizedSpy.count(), model.rowCount()); - for (int r = 0; r < model.rowCount(); ++r) { + for (int r = 0; r < model.rowCount(); ++r) QCOMPARE(view.rowHeight(r), rowHeight); - } } void tst_QTableView::resizeColumnsToContents_data() @@ -2268,7 +2212,7 @@ void tst_QTableView::resizeColumnsToContents() QFETCH(int, cellHeight); QFETCH(int, rowHeight); QFETCH(int, columnWidth); - Q_UNUSED(rowHeight); + Q_UNUSED(rowHeight) QtTestTableModel model(rowCount, columnCount); QtTestTableView view; @@ -2280,7 +2224,7 @@ void tst_QTableView::resizeColumnsToContents() delegate.hint = QSize(cellWidth, cellHeight); - QSignalSpy resizedSpy(view.horizontalHeader(), SIGNAL(sectionResized(int,int,int))); + QSignalSpy resizedSpy(view.horizontalHeader(), &QHeaderView::sectionResized); view.resizeColumnsToContents(); QCOMPARE(resizedSpy.count(), model.columnCount()); @@ -2293,51 +2237,51 @@ void tst_QTableView::rowViewportPosition_data() QTest::addColumn<int>("rowCount"); QTest::addColumn<int>("rowHeight"); QTest::addColumn<int>("row"); - QTest::addColumn<int>("verticalScrollMode"); + QTest::addColumn<QAbstractItemView::ScrollMode>("verticalScrollMode"); QTest::addColumn<int>("verticalScrollValue"); QTest::addColumn<int>("rowViewportPosition"); QTest::newRow("row 0, scroll per item 0") - << 10 << 40 << 0 << int(QAbstractItemView::ScrollPerItem) << 0 << 0; + << 10 << 40 << 0 << QAbstractItemView::ScrollPerItem << 0 << 0; QTest::newRow("row 1, scroll per item, 0") - << 10 << 40 << 1 << int(QAbstractItemView::ScrollPerItem) << 0 << 1 * 40; + << 10 << 40 << 1 << QAbstractItemView::ScrollPerItem << 0 << 1 * 40; QTest::newRow("row 1, scroll per item, 1") - << 10 << 40 << 1 << int(QAbstractItemView::ScrollPerItem) << 1 << 0; + << 10 << 40 << 1 << QAbstractItemView::ScrollPerItem << 1 << 0; QTest::newRow("row 5, scroll per item, 0") - << 10 << 40 << 5 << int(QAbstractItemView::ScrollPerItem) << 0 << 5 * 40; + << 10 << 40 << 5 << QAbstractItemView::ScrollPerItem << 0 << 5 * 40; QTest::newRow("row 5, scroll per item, 5") - << 10 << 40 << 5 << int(QAbstractItemView::ScrollPerItem) << 5 << 0; + << 10 << 40 << 5 << QAbstractItemView::ScrollPerItem << 5 << 0; QTest::newRow("row 9, scroll per item, 0") - << 10 << 40 << 9 << int(QAbstractItemView::ScrollPerItem) << 0 << 9 * 40; + << 10 << 40 << 9 << QAbstractItemView::ScrollPerItem << 0 << 9 * 40; QTest::newRow("row 9, scroll per item, 5") - << 10 << 40 << 9 << int(QAbstractItemView::ScrollPerItem) << 5 << 4 * 40; + << 10 << 40 << 9 << QAbstractItemView::ScrollPerItem << 5 << 4 * 40; QTest::newRow("row 0, scroll per pixel 0") - << 10 << 40 << 0 << int(QAbstractItemView::ScrollPerPixel) << 0 << 0; + << 10 << 40 << 0 << QAbstractItemView::ScrollPerPixel << 0 << 0; QTest::newRow("row 1, scroll per pixel, 0") - << 10 << 40 << 1 << int(QAbstractItemView::ScrollPerPixel) << 0 << 1 * 40; + << 10 << 40 << 1 << QAbstractItemView::ScrollPerPixel << 0 << 1 * 40; QTest::newRow("row 1, scroll per pixel, 1") - << 10 << 40 << 1 << int(QAbstractItemView::ScrollPerPixel) << 1 * 40 << 0; + << 10 << 40 << 1 << QAbstractItemView::ScrollPerPixel << 1 * 40 << 0; QTest::newRow("row 5, scroll per pixel, 0") - << 10 << 40 << 5 << int(QAbstractItemView::ScrollPerPixel) << 0 << 5 * 40; + << 10 << 40 << 5 << QAbstractItemView::ScrollPerPixel << 0 << 5 * 40; QTest::newRow("row 5, scroll per pixel, 5") - << 10 << 40 << 5 << int(QAbstractItemView::ScrollPerPixel) << 5 * 40 << 0; + << 10 << 40 << 5 << QAbstractItemView::ScrollPerPixel << 5 * 40 << 0; QTest::newRow("row 9, scroll per pixel, 0") - << 10 << 40 << 9 << int(QAbstractItemView::ScrollPerPixel) << 0 << 9 * 40; + << 10 << 40 << 9 << QAbstractItemView::ScrollPerPixel << 0 << 9 * 40; QTest::newRow("row 9, scroll per pixel, 5") - << 10 << 40 << 9 << int(QAbstractItemView::ScrollPerPixel) << 5 * 40 << 4 * 40; + << 10 << 40 << 9 << QAbstractItemView::ScrollPerPixel << 5 * 40 << 4 * 40; } void tst_QTableView::rowViewportPosition() @@ -2345,7 +2289,7 @@ void tst_QTableView::rowViewportPosition() QFETCH(int, rowCount); QFETCH(int, rowHeight); QFETCH(int, row); - QFETCH(int, verticalScrollMode); + QFETCH(QAbstractItemView::ScrollMode, verticalScrollMode); QFETCH(int, verticalScrollValue); QFETCH(int, rowViewportPosition); @@ -2359,7 +2303,7 @@ void tst_QTableView::rowViewportPosition() for (int r = 0; r < rowCount; ++r) view.setRowHeight(r, rowHeight); - view.setVerticalScrollMode((QAbstractItemView::ScrollMode)verticalScrollMode); + view.setVerticalScrollMode(verticalScrollMode); view.verticalScrollBar()->setValue(verticalScrollValue); #ifdef Q_OS_WINRT @@ -2464,51 +2408,51 @@ void tst_QTableView::columnViewportPosition_data() QTest::addColumn<int>("columnCount"); QTest::addColumn<int>("columnWidth"); QTest::addColumn<int>("column"); - QTest::addColumn<int>("horizontalScrollMode"); + QTest::addColumn<QAbstractItemView::ScrollMode>("horizontalScrollMode"); QTest::addColumn<int>("horizontalScrollValue"); QTest::addColumn<int>("columnViewportPosition"); QTest::newRow("column 0, scroll per item 0") - << 10 << 40 << 0 << int(QAbstractItemView::ScrollPerItem) << 0 << 0; + << 10 << 40 << 0 << QAbstractItemView::ScrollPerItem << 0 << 0; QTest::newRow("column 1, scroll per item, 0") - << 10 << 40 << 1 << int(QAbstractItemView::ScrollPerItem) << 0 << 1 * 40; + << 10 << 40 << 1 << QAbstractItemView::ScrollPerItem << 0 << 1 * 40; QTest::newRow("column 1, scroll per item, 1") - << 10 << 40 << 1 << int(QAbstractItemView::ScrollPerItem) << 1 << 0; + << 10 << 40 << 1 << QAbstractItemView::ScrollPerItem << 1 << 0; QTest::newRow("column 5, scroll per item, 0") - << 10 << 40 << 5 << int(QAbstractItemView::ScrollPerItem) << 0 << 5 * 40; + << 10 << 40 << 5 << QAbstractItemView::ScrollPerItem << 0 << 5 * 40; QTest::newRow("column 5, scroll per item, 5") - << 10 << 40 << 5 << int(QAbstractItemView::ScrollPerItem) << 5 << 0; + << 10 << 40 << 5 << QAbstractItemView::ScrollPerItem << 5 << 0; QTest::newRow("column 9, scroll per item, 0") - << 10 << 40 << 9 << int(QAbstractItemView::ScrollPerItem) << 0 << 9 * 40; + << 10 << 40 << 9 << QAbstractItemView::ScrollPerItem << 0 << 9 * 40; QTest::newRow("column 9, scroll per item, 5") - << 10 << 40 << 9 << int(QAbstractItemView::ScrollPerItem) << 5 << 4 * 40; + << 10 << 40 << 9 << QAbstractItemView::ScrollPerItem << 5 << 4 * 40; QTest::newRow("column 0, scroll per pixel 0") - << 10 << 40 << 0 << int(QAbstractItemView::ScrollPerPixel) << 0 << 0; + << 10 << 40 << 0 << QAbstractItemView::ScrollPerPixel << 0 << 0; QTest::newRow("column 1, scroll per pixel 0") - << 10 << 40 << 1 << int(QAbstractItemView::ScrollPerPixel) << 0 << 1 * 40; + << 10 << 40 << 1 << QAbstractItemView::ScrollPerPixel << 0 << 1 * 40; QTest::newRow("column 1, scroll per pixel 1") - << 10 << 40 << 1 << int(QAbstractItemView::ScrollPerPixel) << 1 * 40 << 0; + << 10 << 40 << 1 << QAbstractItemView::ScrollPerPixel << 1 * 40 << 0; QTest::newRow("column 5, scroll per pixel 0") - << 10 << 40 << 5 << int(QAbstractItemView::ScrollPerPixel) << 0 << 5 * 40; + << 10 << 40 << 5 << QAbstractItemView::ScrollPerPixel << 0 << 5 * 40; QTest::newRow("column 5, scroll per pixel 5") - << 10 << 40 << 5 << int(QAbstractItemView::ScrollPerPixel) << 5 * 40 << 0; + << 10 << 40 << 5 << QAbstractItemView::ScrollPerPixel << 5 * 40 << 0; QTest::newRow("column 9, scroll per pixel 0") - << 10 << 40 << 9 << int(QAbstractItemView::ScrollPerPixel) << 0 << 9 * 40; + << 10 << 40 << 9 << QAbstractItemView::ScrollPerPixel << 0 << 9 * 40; QTest::newRow("column 9, scroll per pixel 5") - << 10 << 40 << 9 << int(QAbstractItemView::ScrollPerPixel) << 5 * 40 << 4 * 40; + << 10 << 40 << 9 << QAbstractItemView::ScrollPerPixel << 5 * 40 << 4 * 40; } void tst_QTableView::columnViewportPosition() @@ -2516,7 +2460,7 @@ void tst_QTableView::columnViewportPosition() QFETCH(int, columnCount); QFETCH(int, columnWidth); QFETCH(int, column); - QFETCH(int, horizontalScrollMode); + QFETCH(QAbstractItemView::ScrollMode, horizontalScrollMode); QFETCH(int, horizontalScrollValue); QFETCH(int, columnViewportPosition); @@ -2530,7 +2474,7 @@ void tst_QTableView::columnViewportPosition() for (int c = 0; c < columnCount; ++c) view.setColumnWidth(c, columnWidth); - view.setHorizontalScrollMode((QAbstractItemView::ScrollMode)horizontalScrollMode); + view.setHorizontalScrollMode(horizontalScrollMode); view.horizontalScrollBar()->setValue(horizontalScrollValue); #ifdef Q_OS_WINRT @@ -2730,8 +2674,8 @@ void tst_QTableView::sortingEnabled() void tst_QTableView::scrollTo_data() { - QTest::addColumn<int>("verticalScrollMode"); - QTest::addColumn<int>("horizontalScrollMode"); + QTest::addColumn<QAbstractItemView::ScrollMode>("verticalScrollMode"); + QTest::addColumn<QAbstractItemView::ScrollMode>("horizontalScrollMode"); QTest::addColumn<int>("rowCount"); QTest::addColumn<int>("columnCount"); QTest::addColumn<int>("rowHeight"); @@ -2744,51 +2688,51 @@ void tst_QTableView::scrollTo_data() QTest::addColumn<int>("columnSpan"); QTest::addColumn<int>("horizontalScroll"); QTest::addColumn<int>("verticalScroll"); - QTest::addColumn<int>("scrollHint"); + QTest::addColumn<QAbstractItemView::ScrollHint>("scrollHint"); QTest::addColumn<int>("expectedHorizontalScroll"); QTest::addColumn<int>("expectedVerticalScroll"); QTest::newRow("no hidden, no span, no scroll, per item") - << (int)QAbstractItemView::ScrollPerItem - << (int)QAbstractItemView::ScrollPerItem + << QAbstractItemView::ScrollPerItem + << QAbstractItemView::ScrollPerItem << 10 << 10 // table << 80 << 80 // size << -1 << -1 // hide << 0 << 0 // cell << 1 << 1 // span << 0 << 0 // scroll - << (int)QAbstractItemView::PositionAtTop + << QAbstractItemView::PositionAtTop << 0 << 0; // expected QTest::newRow("no hidden, no span, no scroll, per pixel") - << (int)QAbstractItemView::ScrollPerPixel - << (int)QAbstractItemView::ScrollPerPixel + << QAbstractItemView::ScrollPerPixel + << QAbstractItemView::ScrollPerPixel << 10 << 10 // table << 80 << 80 // size << -1 << -1 // hide << 0 << 0 // cell << 1 << 1 // span << 0 << 0 // scroll - << (int)QAbstractItemView::PositionAtTop + << QAbstractItemView::PositionAtTop << 0 << 0; // expected QTest::newRow("hidden, no span, no scroll, per item") - << (int)QAbstractItemView::ScrollPerItem - << (int)QAbstractItemView::ScrollPerItem + << QAbstractItemView::ScrollPerItem + << QAbstractItemView::ScrollPerItem << 10 << 10 // table << 80 << 80 // size << 3 << 3 // hide << 5 << 5 // cell << 1 << 1 // span << 0 << 0 // scroll - << (int)QAbstractItemView::PositionAtTop + << QAbstractItemView::PositionAtTop << 4 << 4; // expected } void tst_QTableView::scrollTo() { - QFETCH(int, horizontalScrollMode); - QFETCH(int, verticalScrollMode); + QFETCH(QAbstractItemView::ScrollMode, horizontalScrollMode); + QFETCH(QAbstractItemView::ScrollMode, verticalScrollMode); QFETCH(int, rowCount); QFETCH(int, columnCount); QFETCH(int, rowHeight); @@ -2801,7 +2745,7 @@ void tst_QTableView::scrollTo() QFETCH(int, columnSpan); QFETCH(int, horizontalScroll); QFETCH(int, verticalScroll); - QFETCH(int, scrollHint); + QFETCH(QAbstractItemView::ScrollHint, scrollHint); QFETCH(int, expectedHorizontalScroll); QFETCH(int, expectedVerticalScroll); @@ -2821,8 +2765,8 @@ void tst_QTableView::scrollTo() view.setSpan(row, column, rowSpan, columnSpan); view.hideRow(hiddenRow); view.hideColumn(hiddenColumn); - view.setHorizontalScrollMode((QAbstractItemView::ScrollMode)horizontalScrollMode); - view.setVerticalScrollMode((QAbstractItemView::ScrollMode)verticalScrollMode); + view.setHorizontalScrollMode(horizontalScrollMode); + view.setVerticalScrollMode(verticalScrollMode); for (int r = 0; r < rowCount; ++r) view.setRowHeight(r, rowHeight); @@ -2834,7 +2778,7 @@ void tst_QTableView::scrollTo() QModelIndex index = model.index(row, column); QVERIFY(index.isValid()); - view.scrollTo(index, (QAbstractItemView::ScrollHint)scrollHint); + view.scrollTo(index, scrollHint); QTRY_COMPARE(view.verticalScrollBar()->value(), expectedVerticalScroll); QTRY_COMPARE(view.horizontalScrollBar()->value(), expectedHorizontalScroll); } @@ -3139,8 +3083,6 @@ void tst_QTableView::span() VERIFY_SPANS_CONSISTENCY(&view); } -typedef QVector<QRect> SpanList; - void tst_QTableView::spans_data() { QTest::addColumn<int>("rows"); @@ -3268,7 +3210,7 @@ void tst_QTableView::spans() { QFETCH(int, rows); QFETCH(int, columns); - QFETCH(SpanList, spans); + QFETCH(const SpanList, spans); QFETCH(bool, hideRowLastRowOfFirstSpan); QFETCH(QPoint, pos); QFETCH(int, expectedRowSpan); @@ -3280,10 +3222,8 @@ void tst_QTableView::spans() view.setModel(&model); view.show(); - for (int i = 0; i < spans.count(); ++i) { - QRect sp = spans.at(i); + for (const auto &sp : spans) view.setSpan(sp.x(), sp.y(), sp.width(), sp.height()); - } if (hideRowLastRowOfFirstSpan) { view.setRowHidden(spans.at(0).bottom(), true); @@ -3377,32 +3317,34 @@ void tst_QTableView::spansAfterRowRemoval() QtTestTableView view; view.setModel(&model); - QList<QRect> spans; - spans << QRect(0, 1, 1, 2) - << QRect(1, 2, 1, 2) - << QRect(2, 2, 1, 5) - << QRect(2, 8, 1, 2) - << QRect(3, 4, 1, 2) - << QRect(4, 4, 1, 4) - << QRect(5, 6, 1, 3) - << QRect(6, 7, 1, 3); - foreach (QRect span, spans) + static const QRect spans[] = { + {0, 1, 1, 2}, + {1, 2, 1, 2}, + {2, 2, 1, 5}, + {2, 8, 1, 2}, + {3, 4, 1, 2}, + {4, 4, 1, 4}, + {5, 6, 1, 3}, + {6, 7, 1, 3} + }; + for (const QRect &span : spans) view.setSpan(span.top(), span.left(), span.height(), span.width()); view.show(); QVERIFY(QTest::qWaitForWindowActive(&view)); view.model()->removeRows(3, 3); - QList<QRect> expectedSpans; - expectedSpans << QRect(0, 1, 1, 2) - << QRect(1, 2, 1, 1) - << QRect(2, 2, 1, 2) - << QRect(2, 5, 1, 2) - << QRect(3, 4, 1, 1) - << QRect(4, 3, 1, 2) - << QRect(5, 3, 1, 3) - << QRect(6, 4, 1, 3); - foreach (QRect span, expectedSpans) { + static const QRect expectedSpans[] = { + {0, 1, 1, 2}, + {1, 2, 1, 1}, + {2, 2, 1, 2}, + {2, 5, 1, 2}, + {3, 4, 1, 1}, + {4, 3, 1, 2}, + {5, 3, 1, 3}, + {6, 4, 1, 3} + }; + for (const QRect &span : expectedSpans) { QCOMPARE(view.columnSpan(span.top(), span.left()), span.width()); QCOMPARE(view.rowSpan(span.top(), span.left()), span.height()); } @@ -3417,32 +3359,34 @@ void tst_QTableView::spansAfterColumnRemoval() view.setModel(&model); // Same set as above just swapping columns and rows. - QList<QRect> spans; - spans << QRect(0, 1, 1, 2) - << QRect(1, 2, 1, 2) - << QRect(2, 2, 1, 5) - << QRect(2, 8, 1, 2) - << QRect(3, 4, 1, 2) - << QRect(4, 4, 1, 4) - << QRect(5, 6, 1, 3) - << QRect(6, 7, 1, 3); - foreach (QRect span, spans) - view.setSpan(span.left(), span.top(), span.width(), span.height()); + static const QRect spans[] = { + {0, 1, 1, 2}, + {1, 2, 1, 2}, + {2, 2, 1, 5}, + {2, 8, 1, 2}, + {3, 4, 1, 2}, + {4, 4, 1, 4}, + {5, 6, 1, 3}, + {6, 7, 1, 3} + }; + for (const QRect &span : spans) + view.setSpan(span.left(), span.top(), span.width(), span.height()); view.show(); QVERIFY(QTest::qWaitForWindowActive(&view)); view.model()->removeColumns(3, 3); - QList<QRect> expectedSpans; - expectedSpans << QRect(0, 1, 1, 2) - << QRect(1, 2, 1, 1) - << QRect(2, 2, 1, 2) - << QRect(2, 5, 1, 2) - << QRect(3, 4, 1, 1) - << QRect(4, 3, 1, 2) - << QRect(5, 3, 1, 3) - << QRect(6, 4, 1, 3); - foreach (QRect span, expectedSpans) { + static const QRect expectedSpans[] = { + {0, 1, 1, 2}, + {1, 2, 1, 1}, + {2, 2, 1, 2}, + {2, 5, 1, 2}, + {3, 4, 1, 1}, + {4, 3, 1, 2}, + {5, 3, 1, 3}, + {6, 4, 1, 3} + }; + for (const QRect &span : expectedSpans) { QCOMPARE(view.columnSpan(span.left(), span.top()), span.height()); QCOMPARE(view.rowSpan(span.left(), span.top()), span.width()); } @@ -3450,12 +3394,10 @@ void tst_QTableView::spansAfterColumnRemoval() VERIFY_SPANS_CONSISTENCY(&view); } -Q_DECLARE_METATYPE(Qt::Key) - void tst_QTableView::editSpanFromDirections_data() { - QTest::addColumn<QList<Qt::Key> >("keyPresses"); - QTest::addColumn<QSharedPointer<QStandardItemModel> >("model"); + QTest::addColumn<KeyList>("keyPresses"); + QTest::addColumn<QSharedPointer<QStandardItemModel>>("model"); QTest::addColumn<int>("row"); QTest::addColumn<int>("column"); QTest::addColumn<int>("rowSpan"); @@ -3474,8 +3416,7 @@ void tst_QTableView::editSpanFromDirections_data() +---+---+ | | ^ | +---+---+ */ - QList<Qt::Key> keyPresses; - keyPresses << Qt::Key_Right << Qt::Key_PageDown << Qt::Key_Up; + KeyList keyPresses {Qt::Key_Right, Qt::Key_PageDown, Qt::Key_Up}; QSharedPointer<QStandardItemModel> model(new QStandardItemModel(4, 2)); QTest::newRow("row span, bottom up") << keyPresses << model << 1 << 1 << 2 << 1 << model->index(2, 1) << model->index(1, 1); @@ -3489,8 +3430,7 @@ void tst_QTableView::editSpanFromDirections_data() +---+---+ | | | +---+---+ */ - keyPresses.clear(); - keyPresses << Qt::Key_Right << Qt::Key_Down; + keyPresses = {Qt::Key_Right, Qt::Key_Down}; model = QSharedPointer<QStandardItemModel>::create(4, 2); QTest::newRow("row span, top down") << keyPresses << model << 1 << 1 << 2 << 1 << model->index(1, 1) << model->index(1, 1); @@ -3502,8 +3442,7 @@ void tst_QTableView::editSpanFromDirections_data() +---+ +---+ | | | | +---+---+---+ */ - keyPresses.clear(); - keyPresses << Qt::Key_End << Qt::Key_Down << Qt::Key_Left; + keyPresses = {Qt::Key_End, Qt::Key_Down, Qt::Key_Left}; model = QSharedPointer<QStandardItemModel>::create(3, 3); QTest::newRow("row span, right to left") << keyPresses << model << 1 << 1 << 2 << 1 << model->index(1, 1) << model->index(1, 1); @@ -3515,8 +3454,7 @@ void tst_QTableView::editSpanFromDirections_data() +---+ +---+ | > | c | | +---+---+---+ */ - keyPresses.clear(); - keyPresses << Qt::Key_PageDown << Qt::Key_Right; + keyPresses = {Qt::Key_PageDown, Qt::Key_Right}; model = QSharedPointer<QStandardItemModel>::create(3, 3); QTest::newRow("row span, left to right") << keyPresses << model << 1 << 1 << 2 << 1 << model->index(2, 1) << model->index(1, 1); @@ -3528,8 +3466,7 @@ void tst_QTableView::editSpanFromDirections_data() +---+---+---+ | ^ | | | +---+---+---+ */ - keyPresses.clear(); - keyPresses << Qt::Key_PageDown << Qt::Key_Up; + keyPresses = {Qt::Key_PageDown, Qt::Key_Up}; model = QSharedPointer<QStandardItemModel>::create(3, 3); QTest::newRow("col span, bottom up") << keyPresses << model << 1 << 0 << 1 << 3 << model->index(1, 0) << model->index(1, 0); @@ -3541,8 +3478,7 @@ void tst_QTableView::editSpanFromDirections_data() +---+---+---+ | | ^ | | +---+---+---+ */ - keyPresses.clear(); - keyPresses << Qt::Key_PageDown << Qt::Key_Right << Qt::Key_Up; + keyPresses = {Qt::Key_PageDown, Qt::Key_Right, Qt::Key_Up}; model = QSharedPointer<QStandardItemModel>::create(3, 3); QTest::newRow("col span, bottom up #2") << keyPresses << model << 1 << 0 << 1 << 3 << model->index(1, 1) << model->index(1, 0); @@ -3554,8 +3490,7 @@ void tst_QTableView::editSpanFromDirections_data() +---+---+---+ | | | | +---+---+---+ */ - keyPresses.clear(); - keyPresses << Qt::Key_End << Qt::Key_Down; + keyPresses = {Qt::Key_End, Qt::Key_Down}; model = QSharedPointer<QStandardItemModel>::create(3, 3); QTest::newRow("col span, top down") << keyPresses << model << 1 << 0 << 1 << 3 << model->index(1, 2) << model->index(1, 0); @@ -3564,12 +3499,10 @@ void tst_QTableView::editSpanFromDirections_data() class TableViewWithCursorExposed : public QTableView { public: - TableViewWithCursorExposed() : - QTableView() { - } + using QTableView::QTableView; -public: - QModelIndex visualCursorIndex() { + QModelIndex visualCursorIndex() + { QTableViewPrivate *d = static_cast<QTableViewPrivate*>(qt_widget_private(this)); return d->model->index(d->visualCursor.y(), d->visualCursor.x()); } @@ -3577,7 +3510,7 @@ public: void tst_QTableView::editSpanFromDirections() { - QFETCH(QList<Qt::Key>, keyPresses); + QFETCH(const KeyList, keyPresses); QFETCH(QSharedPointer<QStandardItemModel>, model); QFETCH(int, row); QFETCH(int, column); @@ -3595,9 +3528,8 @@ void tst_QTableView::editSpanFromDirections() view.show(); QVERIFY(QTest::qWaitForWindowActive(&view)); - foreach (Qt::Key key, keyPresses) { + for (Qt::Key key : keyPresses) QTest::keyClick(&view, key); - } QCOMPARE(view.visualCursorIndex(), expectedVisualCursorIndex); QCOMPARE(view.selectionModel()->currentIndex(), expectedEditedIndex); @@ -3606,21 +3538,21 @@ void tst_QTableView::editSpanFromDirections() QTRY_COMPARE(view.model()->data(expectedEditedIndex).toString(), QLatin1String("x")); } -class Model : public QAbstractTableModel { - -Q_OBJECT - +class Model : public QAbstractTableModel +{ + Q_OBJECT public: - Model(QObject * parent = 0) : QAbstractTableModel(parent) { - } + using QAbstractTableModel::QAbstractTableModel; - int rowCount(const QModelIndex &) const { + int rowCount(const QModelIndex &) const override + { return rows; } - int columnCount(const QModelIndex &) const { + int columnCount(const QModelIndex &) const override + { return columns; } - QVariant data(const QModelIndex &, int) const + QVariant data(const QModelIndex &, int) const override { return QVariant(); } @@ -3630,8 +3562,8 @@ public: endResetModel(); } - int rows; - int columns; + int rows = 0; + int columns = 0; }; void tst_QTableView::checkHeaderReset() @@ -3655,7 +3587,7 @@ void tst_QTableView::checkHeaderMinSize() //viewport. QTableView view; QStringListModel m; - m.setStringList( QStringList() << QLatin1String("one cell is enough")); + m.setStringList({QLatin1String("one cell is enough")}); view.setModel(&m); //setting the minimum height on the horizontal header @@ -3686,31 +3618,29 @@ void tst_QTableView::resizeToContents() table2.verticalHeader()->setVisible(false); - for(int i = 0;i<table.columnCount();i++) { + for (int i = 0; i < table.columnCount(); i++) table.resizeColumnToContents(i); - } - for(int i = 0;i<table.rowCount();i++) { + for (int i = 0; i < table.rowCount(); i++) table.resizeRowToContents(i); - } table2.resizeColumnsToContents(); table2.resizeRowsToContents(); table3.resizeColumnsToContents(); table3.resizeRowsToContents(); //now let's check the row/col sizes - for(int i = 0;i<table.columnCount();i++) { - QCOMPARE( table.columnWidth(i), table2.columnWidth(i)); - QCOMPARE( table2.columnWidth(i), table3.columnWidth(i)); + for (int i = 0; i < table.columnCount(); i++) { + QCOMPARE(table.columnWidth(i), table2.columnWidth(i)); + QCOMPARE(table2.columnWidth(i), table3.columnWidth(i)); } - for(int i = 0;i<table.rowCount();i++) { - QCOMPARE( table.rowHeight(i), table2.rowHeight(i)); - QCOMPARE( table2.rowHeight(i), table3.rowHeight(i)); + for (int i = 0; i < table.rowCount(); i++) { + QCOMPARE(table.rowHeight(i), table2.rowHeight(i)); + QCOMPARE(table2.rowHeight(i), table3.rowHeight(i)); } } QT_BEGIN_NAMESPACE -extern bool Q_GUI_EXPORT qt_tab_all_widgets(); // qapplication.cpp +extern bool Q_WIDGETS_EXPORT qt_tab_all_widgets(); // qapplication.cpp QT_END_NAMESPACE void tst_QTableView::tabFocus() @@ -3740,57 +3670,57 @@ void tst_QTableView::tabFocus() for (int i = 0; i < 2; ++i) { // tab to view - QTest::keyPress(qApp->focusWidget(), Qt::Key_Tab); + QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab); QTRY_VERIFY(!window.hasFocus()); QVERIFY(view->hasFocus()); QVERIFY(!edit->hasFocus()); // tab to edit - QTest::keyPress(qApp->focusWidget(), Qt::Key_Tab); + QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab); QTRY_VERIFY(edit->hasFocus()); QVERIFY(!window.hasFocus()); QVERIFY(!view->hasFocus()); } // backtab to view - QTest::keyPress(qApp->focusWidget(), Qt::Key_Backtab); + QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab); QTRY_VERIFY(view->hasFocus()); QVERIFY(!window.hasFocus()); QVERIFY(!edit->hasFocus()); // backtab to edit - QTest::keyPress(qApp->focusWidget(), Qt::Key_Backtab); + QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab); QTRY_VERIFY(edit->hasFocus()); QVERIFY(!window.hasFocus()); QVERIFY(!view->hasFocus()); - QStandardItemModel *model = new QStandardItemModel; - view->setModel(model); + QStandardItemModel model; + view->setModel(&model); // backtab to view - QTest::keyPress(qApp->focusWidget(), Qt::Key_Backtab); + QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab); QTRY_VERIFY(view->hasFocus()); QVERIFY(!window.hasFocus()); QVERIFY(!edit->hasFocus()); // backtab to edit - QTest::keyPress(qApp->focusWidget(), Qt::Key_Backtab); + QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab); QTRY_VERIFY(edit->hasFocus()); QVERIFY(!window.hasFocus()); QVERIFY(!view->hasFocus()); - model->insertRow(0, new QStandardItem("Hei")); - model->insertRow(0, new QStandardItem("Hei")); - model->insertRow(0, new QStandardItem("Hei")); + model.insertRow(0, new QStandardItem("Hei")); + model.insertRow(0, new QStandardItem("Hei")); + model.insertRow(0, new QStandardItem("Hei")); // backtab to view - QTest::keyPress(qApp->focusWidget(), Qt::Key_Backtab); + QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab); QTRY_VERIFY(view->hasFocus()); QVERIFY(!window.hasFocus()); QVERIFY(!edit->hasFocus()); // backtab to edit doesn't work - QTest::keyPress(qApp->focusWidget(), Qt::Key_Backtab); + QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab); QVERIFY(!window.hasFocus()); QVERIFY(view->hasFocus()); QVERIFY(!edit->hasFocus()); @@ -3798,41 +3728,38 @@ void tst_QTableView::tabFocus() view->setTabKeyNavigation(false); // backtab to edit - QTest::keyPress(qApp->focusWidget(), Qt::Key_Backtab); + QTest::keyPress(QApplication::focusWidget(), Qt::Key_Backtab); QTRY_VERIFY(edit->hasFocus()); QVERIFY(!window.hasFocus()); QVERIFY(!view->hasFocus()); - QTest::keyPress(qApp->focusWidget(), Qt::Key_Tab); + QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab); QTRY_VERIFY(view->hasFocus()); - QTest::keyPress(qApp->focusWidget(), Qt::Key_Tab); + QTest::keyPress(QApplication::focusWidget(), Qt::Key_Tab); QTRY_VERIFY(edit->hasFocus()); - - delete model; } class BigModel : public QAbstractTableModel { Q_OBJECT public: - virtual QVariant data(const QModelIndex &index, - int role = Qt::DisplayRole) const + QVariant data(const QModelIndex &index, + int role = Qt::DisplayRole) const override { if (role == Qt::DisplayRole) return QString::number(index.column()) + QLatin1String(" - ") + QString::number(index.row()); return QVariant(); } - - int rowCount(const QModelIndex & parent = QModelIndex()) const + int rowCount(const QModelIndex &parent = QModelIndex()) const override { - Q_UNUSED(parent); + Q_UNUSED(parent) return 10000000; } - int columnCount(const QModelIndex & parent = QModelIndex()) const + int columnCount(const QModelIndex &parent = QModelIndex()) const override { - Q_UNUSED(parent); + Q_UNUSED(parent) return 20000000; } }; @@ -3861,7 +3788,7 @@ void tst_QTableView::selectionSignal() view.resize(200, 200); view.show(); QVERIFY(QTest::qWaitForWindowExposed(&view)); - QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.visualRect(model.index(2, 0)).center()); + QTest::mouseClick(view.viewport(), Qt::LeftButton, {}, view.visualRect(model.index(2, 0)).center()); } void tst_QTableView::setCurrentIndex() @@ -3887,14 +3814,14 @@ void tst_QTableView::setCurrentIndex() class task173773_EventFilter : public QObject { - int paintEventCount_; + int paintEventCount_ = 0; public: - task173773_EventFilter() : paintEventCount_(0) {} + using QObject::QObject; int paintEventCount() const { return paintEventCount_; } private: - bool eventFilter(QObject *obj, QEvent *e) + bool eventFilter(QObject *obj, QEvent *e) override { - Q_UNUSED(obj); + Q_UNUSED(obj) if (e->type() == QEvent::Paint) ++paintEventCount_; return false; @@ -4023,25 +3950,25 @@ void tst_QTableView::task248688_autoScrollNavigation() #if QT_CONFIG(wheelevent) void tst_QTableView::mouseWheel_data() { - QTest::addColumn<int>("scrollMode"); + QTest::addColumn<QAbstractItemView::ScrollMode>("scrollMode"); QTest::addColumn<int>("delta"); QTest::addColumn<int>("horizontalPositon"); QTest::addColumn<int>("verticalPosition"); QTest::newRow("scroll up per item") - << int(QAbstractItemView::ScrollPerItem) << 120 - << 10 - qApp->wheelScrollLines() << 10 - qApp->wheelScrollLines(); + << QAbstractItemView::ScrollPerItem << 120 + << 10 - QApplication::wheelScrollLines() << 10 - QApplication::wheelScrollLines(); QTest::newRow("scroll down per item") - << int(QAbstractItemView::ScrollPerItem) << -120 - << 10 + qApp->wheelScrollLines() << 10 + qApp->wheelScrollLines(); + << QAbstractItemView::ScrollPerItem << -120 + << 10 + QApplication::wheelScrollLines() << 10 + QApplication::wheelScrollLines(); QTest::newRow("scroll down per pixel") - << int(QAbstractItemView::ScrollPerPixel) << -120 - << 10 + qApp->wheelScrollLines() * 91 << 10 + qApp->wheelScrollLines() * 46; + << QAbstractItemView::ScrollPerPixel << -120 + << 10 + QApplication::wheelScrollLines() * 91 << 10 + QApplication::wheelScrollLines() * 46; } void tst_QTableView::mouseWheel() { - QFETCH(int, scrollMode); + QFETCH(QAbstractItemView::ScrollMode, scrollMode); QFETCH(int, delta); QFETCH(int, horizontalPositon); QFETCH(int, verticalPosition); @@ -4061,14 +3988,16 @@ void tst_QTableView::mouseWheel() for (int c = 0; c < 100; ++c) view.setColumnWidth(c, 100); - view.setHorizontalScrollMode((QAbstractItemView::ScrollMode)scrollMode); - view.setVerticalScrollMode((QAbstractItemView::ScrollMode)scrollMode); + view.setHorizontalScrollMode(scrollMode); + view.setVerticalScrollMode(scrollMode); view.horizontalScrollBar()->setValue(10); view.verticalScrollBar()->setValue(10); QPoint pos = view.viewport()->geometry().center(); - QWheelEvent verticalEvent(pos, delta, 0, 0, Qt::Vertical); - QWheelEvent horizontalEvent(pos, delta, 0, 0, Qt::Horizontal); + QWheelEvent verticalEvent(pos, view.mapToGlobal(pos), QPoint(), QPoint(0, delta), + Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false); + QWheelEvent horizontalEvent(pos, view.mapToGlobal(pos), QPoint(), QPoint(delta, 0), + Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false); QApplication::sendEvent(view.viewport(), &horizontalEvent); QVERIFY(qAbs(view.horizontalScrollBar()->value() - horizontalPositon) < 15); QApplication::sendEvent(view.viewport(), &verticalEvent); @@ -4159,15 +4088,15 @@ void tst_QTableView::task191545_dragSelectRows() QWidget *vHeaderVp = vHeader->viewport(); QPoint rowPos(cellRect.center()); QMouseEvent rowPressEvent(QEvent::MouseButtonPress, rowPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier); - qApp->sendEvent(vHeaderVp, &rowPressEvent); + QCoreApplication::sendEvent(vHeaderVp, &rowPressEvent); for (int i = 0; i < 4; ++i) { rowPos.setY(rowPos.y() + cellRect.height()); QMouseEvent moveEvent(QEvent::MouseMove, rowPos, Qt::NoButton, Qt::LeftButton, Qt::ControlModifier); - qApp->sendEvent(vHeaderVp, &moveEvent); + QCoreApplication::sendEvent(vHeaderVp, &moveEvent); } QMouseEvent rowReleaseEvent(QEvent::MouseButtonRelease, rowPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier); - qApp->sendEvent(vHeaderVp, &rowReleaseEvent); + QCoreApplication::sendEvent(vHeaderVp, &rowReleaseEvent); for (int i = 0; i < 4; ++i) { QModelIndex index = model.index(3 + i, 0, table.rootIndex()); @@ -4181,15 +4110,15 @@ void tst_QTableView::task191545_dragSelectRows() QWidget *hHeaderVp = hHeader->viewport(); QPoint colPos((cellRect.left() + cellRect.right()) / 2, 5); QMouseEvent colPressEvent(QEvent::MouseButtonPress, colPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier); - qApp->sendEvent(hHeaderVp, &colPressEvent); + QCoreApplication::sendEvent(hHeaderVp, &colPressEvent); for (int i = 0; i < 4; ++i) { colPos.setX(colPos.x() + cellRect.width()); QMouseEvent moveEvent(QEvent::MouseMove, colPos, Qt::NoButton, Qt::LeftButton, Qt::ControlModifier); - qApp->sendEvent(hHeaderVp, &moveEvent); + QCoreApplication::sendEvent(hHeaderVp, &moveEvent); } QMouseEvent colReleaseEvent(QEvent::MouseButtonRelease, colPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier); - qApp->sendEvent(hHeaderVp, &colReleaseEvent); + QCoreApplication::sendEvent(hHeaderVp, &colReleaseEvent); for (int i = 0; i < 4; ++i) { QModelIndex index = model.index(0, 3 + i, table.rootIndex()); @@ -4202,22 +4131,23 @@ void tst_QTableView::task191545_dragSelectRows() QWidget *tableVp = table.viewport(); QPoint cellPos = cellRect.center(); QMouseEvent cellPressEvent(QEvent::MouseButtonPress, cellPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier); - qApp->sendEvent(tableVp, &cellPressEvent); + QCoreApplication::sendEvent(tableVp, &cellPressEvent); for (int i = 0; i < 6; ++i) { cellPos.setX(cellPos.x() + cellRect.width()); cellPos.setY(cellPos.y() + cellRect.height()); QMouseEvent moveEvent(QEvent::MouseMove, cellPos, Qt::NoButton, Qt::LeftButton, Qt::ControlModifier); - qApp->sendEvent(tableVp, &moveEvent); + QCoreApplication::sendEvent(tableVp, &moveEvent); } QMouseEvent cellReleaseEvent(QEvent::MouseButtonRelease, cellPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier); - qApp->sendEvent(tableVp, &cellReleaseEvent); + QCoreApplication::sendEvent(tableVp, &cellReleaseEvent); - for (int i = 0; i < 6; ++i) + for (int i = 0; i < 6; ++i) { for (int j = 0; j < 6; ++j) { QModelIndex index = model.index(2 + i, 2 + j, table.rootIndex()); QVERIFY(table.selectionModel()->isSelected(index)); } + } } { @@ -4225,23 +4155,24 @@ void tst_QTableView::task191545_dragSelectRows() QWidget *tableVp = table.viewport(); QPoint cellPos = cellRect.center(); QMouseEvent cellPressEvent(QEvent::MouseButtonPress, cellPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier); - qApp->sendEvent(tableVp, &cellPressEvent); + QCoreApplication::sendEvent(tableVp, &cellPressEvent); for (int i = 0; i < 6; ++i) { cellPos.setX(cellPos.x() + cellRect.width()); cellPos.setY(cellPos.y() + cellRect.height()); QMouseEvent moveEvent(QEvent::MouseMove, cellPos, Qt::NoButton, Qt::LeftButton, Qt::ControlModifier); - qApp->sendEvent(tableVp, &moveEvent); + QCoreApplication::sendEvent(tableVp, &moveEvent); } QMouseEvent cellReleaseEvent(QEvent::MouseButtonRelease, cellPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier); - qApp->sendEvent(tableVp, &cellReleaseEvent); + QCoreApplication::sendEvent(tableVp, &cellReleaseEvent); QTest::qWait(200); - for (int i = 0; i < 6; ++i) + for (int i = 0; i < 6; ++i) { for (int j = 0; j < 6; ++j) { QModelIndex index = model.index(3 + i, 3 + j, table.rootIndex()); QVERIFY(!table.selectionModel()->isSelected(index)); } + } } } @@ -4319,8 +4250,6 @@ void tst_QTableView::taskQTBUG_4516_clickOnRichTextLabel() QTest::mouseClick(&label, Qt::LeftButton); QCOMPARE(view.currentIndex(), model.index(1,1)); - - } @@ -4353,21 +4282,23 @@ void tst_QTableView::taskQTBUG_5237_wheelEventOnHeader() int sbValueBefore = view.verticalScrollBar()->value(); QHeaderView *header = view.verticalHeader(); QTest::mouseMove(header); - QWheelEvent wheelEvent(header->geometry().center(), -720, 0, 0); + QPoint pos = header->geometry().center(); + QWheelEvent wheelEvent(pos, header->viewport()->mapToGlobal(pos), QPoint(), QPoint(0, -720), + Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false); QApplication::sendEvent(header->viewport(), &wheelEvent); int sbValueAfter = view.verticalScrollBar()->value(); QVERIFY(sbValueBefore != sbValueAfter); } #endif -class TestTableView : public QTableView { -Q_OBJECT +class TestTableView : public QTableView +{ + Q_OBJECT public: - TestTableView(QWidget *parent = 0) : QTableView(parent) + TestTableView(QWidget *parent = nullptr) : QTableView(parent) { - connect(this, SIGNAL(entered(QModelIndex)), this, SLOT(openEditor(QModelIndex))); + connect(this, &QTableView::entered, this, &TestTableView::openPersistentEditor); } - ~TestTableView(){} public slots: void onDataChanged() { @@ -4375,9 +4306,6 @@ public slots: setRowHidden(i, model()->data(model()->index(i, 0)).toBool()); } } - - void openEditor(const QModelIndex& index) - { openPersistentEditor(index); } }; @@ -4385,15 +4313,13 @@ void tst_QTableView::taskQTBUG_8585_crashForNoGoodReason() { QStandardItemModel model; model.insertColumn(0, QModelIndex()); - for(int i = 0; i < 20; i++) - { + for (int i = 0; i < 20; i++) model.insertRow(i); - } TestTableView w; w.setMouseTracking(true); w.setModel(&model); - connect(&model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), &w, SLOT(onDataChanged())); + connect(&model, &QStandardItemModel::dataChanged, &w, &TestTableView::onDataChanged); w.show(); QVERIFY(QTest::qWaitForWindowExposed(&w)); for (int i = 0; i < 10; i++) @@ -4407,10 +4333,7 @@ void tst_QTableView::taskQTBUG_8585_crashForNoGoodReason() class TableView7774 : public QTableView { public: - QRegion visualRegionForSelection(const QItemSelection &selection) const - { - return QTableView::visualRegionForSelection(selection); - } + using QTableView::visualRegionForSelection; }; void tst_QTableView::taskQTBUG_7774_RtoLVisualRegionForSelection() @@ -4570,5 +4493,58 @@ void tst_QTableView::taskQTBUG_50171_selectRowAfterSwapColumns() } } +class DeselectTableWidget : public QTableWidget +{ +public: + using QTableWidget::QTableWidget; + QItemSelectionModel::SelectionFlags selectionCommand(const QModelIndex &, + const QEvent * = nullptr) const override + { + return QItemSelectionModel::Toggle; + } +}; + +void tst_QTableView::deselectRow() +{ + DeselectTableWidget tw(20, 20); + tw.show(); + QVERIFY(QTest::qWaitForWindowExposed(&tw)); + tw.hideColumn(0); + QVERIFY(tw.isColumnHidden(0)); + tw.selectRow(1); + QVERIFY(tw.selectionModel()->isRowSelected(1, QModelIndex())); + tw.selectRow(1); + // QTBUG-79092 - deselection was not possible when column 0 was hidden + QVERIFY(!tw.selectionModel()->isRowSelected(1, QModelIndex())); +} + +// This has nothing to do with QTableView, but it's convenient to reuse the QtTestTableModel +#if QT_CONFIG(textmarkdownwriter) + +// #define DEBUG_WRITE_OUTPUT + +void tst_QTableView::markdownWriter() +{ + QtTestTableModel model(2, 3); + QString md; + { + QTextStream stream(&md); + QTextMarkdownWriter writer(stream, QTextDocument::MarkdownDialectGitHub); + writer.writeTable(&model); + } + +#ifdef DEBUG_WRITE_OUTPUT + { + QFile out("/tmp/table.md"); + out.open(QFile::WriteOnly); + out.write(md.toUtf8()); + out.close(); + } +#endif + + QCOMPARE(md, QString::fromLatin1("|1 |2 |3 |\n|-------|-------|-------|\n|[0,0,0]|[0,1,0]|[0,2,0]|\n|[1,0,0]|[1,1,0]|[1,2,0]|\n")); +} +#endif + QTEST_MAIN(tst_QTableView) #include "tst_qtableview.moc" diff --git a/tests/auto/widgets/itemviews/qtablewidget/tst_qtablewidget.cpp b/tests/auto/widgets/itemviews/qtablewidget/tst_qtablewidget.cpp index c2de5c2761..f640996690 100644 --- a/tests/auto/widgets/itemviews/qtablewidget/tst_qtablewidget.cpp +++ b/tests/auto/widgets/itemviews/qtablewidget/tst_qtablewidget.cpp @@ -26,15 +26,12 @@ ** ****************************************************************************/ - -#include <QtTest/QtTest> -#include <qeventloop.h> -#include <qlist.h> -#include <qpair.h> -#include <qheaderview.h> -#include <qlineedit.h> - -#include <qtablewidget.h> +#include <QHeaderView> +#include <QLineEdit> +#include <QMimeData> +#include <QSignalSpy> +#include <QTableWidget> +#include <QTest> class QObjectTableItem : public QObject, public QTableWidgetItem { @@ -46,11 +43,10 @@ class tst_QTableWidget : public QObject Q_OBJECT public: - tst_QTableWidget(); + using QObject::QObject; private slots: void initTestCase(); - void cleanupTestCase(); void init(); void getSetCheck(); void clear(); @@ -97,12 +93,12 @@ private slots: #endif private: - QTableWidget *testWidget; + std::unique_ptr<QTableWidget> testWidget; }; -typedef QPair<int, int> IntPair; -typedef QList<int> IntList; -typedef QList<IntPair> IntIntList; +using IntPair = QPair<int, int>; +using IntList = QVector<int>; +using IntIntList = QVector<IntPair>; Q_DECLARE_METATYPE(QTableWidgetSelectionRange) @@ -143,45 +139,36 @@ void tst_QTableWidget::getSetCheck() obj1.setItem(3, 3, new QTableWidgetItem("3,3")); obj1.setCurrentItem(var3); QCOMPARE(var3, obj1.currentItem()); - obj1.setCurrentItem((QTableWidgetItem *)0); - QCOMPARE((QTableWidgetItem *)0, obj1.currentItem()); - obj1.setItem(0, 0, 0); - QCOMPARE((QTableWidgetItem *)0, obj1.item(0, 0)); + obj1.setCurrentItem(nullptr); + QCOMPARE(obj1.currentItem(), nullptr); + obj1.setItem(0, 0, nullptr); + QCOMPARE(obj1.item(0, 0), nullptr); // const QTableWidgetItem * QTableWidget::itemPrototype() // void QTableWidget::setItemPrototype(const QTableWidgetItem *) const QTableWidgetItem *var4 = new QTableWidgetItem; obj1.setItemPrototype(var4); QCOMPARE(var4, obj1.itemPrototype()); - obj1.setItemPrototype((QTableWidgetItem *)0); - QCOMPARE((const QTableWidgetItem *)0, obj1.itemPrototype()); -} - -tst_QTableWidget::tst_QTableWidget(): testWidget(0) -{ + obj1.setItemPrototype(nullptr); + QCOMPARE(obj1.itemPrototype(), nullptr); } void tst_QTableWidget::initTestCase() { - testWidget = new QTableWidget(); + testWidget.reset(new QTableWidget); testWidget->show(); QApplication::setKeyboardInputInterval(100); } -void tst_QTableWidget::cleanupTestCase() -{ - delete testWidget; -} - void tst_QTableWidget::init() { testWidget->clear(); testWidget->setRowCount(5); testWidget->setColumnCount(5); - for (int row=0; row < testWidget->rowCount(); ++row) + for (int row = 0; row < testWidget->rowCount(); ++row) testWidget->showRow(row); - for (int column=0; column < testWidget->columnCount(); ++column) + for (int column = 0; column < testWidget->columnCount(); ++column) testWidget->showColumn(column); } @@ -319,13 +306,15 @@ void tst_QTableWidget::item() QCOMPARE(testWidget->rowCount(), rowCount); QCOMPARE(testWidget->columnCount(), columnCount); - for (int r = 0; r < testWidget->rowCount(); ++r) + for (int r = 0; r < testWidget->rowCount(); ++r) { for (int c = 0; c < testWidget->columnCount(); ++c) testWidget->setItem(r, c, new QTableWidgetItem(QString::number(r * c + c))); + } - for (int r = 0; r < testWidget->rowCount(); ++r) + for (int r = 0; r < testWidget->rowCount(); ++r) { for (int c = 0; c < testWidget->columnCount(); ++c) QCOMPARE(testWidget->item(r, c)->text(), QString::number(r * c + c)); + } QTableWidgetItem *item = testWidget->item(row, column); QCOMPARE(!!item, expectItem); @@ -361,15 +350,17 @@ void tst_QTableWidget::takeItem() QCOMPARE(testWidget->rowCount(), rowCount); QCOMPARE(testWidget->columnCount(), columnCount); - for (int r = 0; r < testWidget->rowCount(); ++r) + for (int r = 0; r < testWidget->rowCount(); ++r) { for (int c = 0; c < testWidget->columnCount(); ++c) testWidget->setItem(r, c, new QTableWidgetItem(QString::number(r * c + c))); + } - for (int r = 0; r < testWidget->rowCount(); ++r) + for (int r = 0; r < testWidget->rowCount(); ++r) { for (int c = 0; c < testWidget->columnCount(); ++c) QCOMPARE(testWidget->item(r, c)->text(), QString::number(r * c + c)); + } - QSignalSpy spy(testWidget, &QTableWidget::cellChanged); + QSignalSpy spy(testWidget.get(), &QTableWidget::cellChanged); QTableWidgetItem *item = testWidget->takeItem(row, column); QCOMPARE(!!item, expectItem); if (expectItem) { @@ -516,11 +507,11 @@ void tst_QTableWidget::selectedItems() { QFETCH(int, rowCount); QFETCH(int, columnCount); - QFETCH(IntIntList, createItems); - QFETCH(IntList, hiddenRows); - QFETCH(IntList, hiddenColumns); - QFETCH(QTableWidgetSelectionRange, selectionRange); - QFETCH(IntIntList, expectedItems); + QFETCH(const IntIntList, createItems); + QFETCH(const IntList, hiddenRows); + QFETCH(const IntList, hiddenColumns); + QFETCH(const QTableWidgetSelectionRange, selectionRange); + QFETCH(const IntIntList, expectedItems); // set dimensions and test they are ok testWidget->setRowCount(rowCount); @@ -529,15 +520,15 @@ void tst_QTableWidget::selectedItems() QCOMPARE(testWidget->columnCount(), columnCount); // create and set items - foreach (IntPair intPair, createItems) { + for (const auto &intPair : createItems) { testWidget->setItem(intPair.first, intPair.second, new QTableWidgetItem(QString("Item %1 %2") .arg(intPair.first).arg(intPair.second))); } // hide rows/columns - foreach (int row, hiddenRows) + for (int row : hiddenRows) testWidget->setRowHidden(row, true); - foreach (int column, hiddenColumns) + for (int column : hiddenColumns) testWidget->setColumnHidden(column, true); // make sure we don't have any previous selections hanging around @@ -557,31 +548,18 @@ void tst_QTableWidget::selectedItems() } // check that the correct number of items and the expected items are there - QList<QTableWidgetItem *> selectedItems = testWidget->selectedItems(); + const QList<QTableWidgetItem *> selectedItems = testWidget->selectedItems(); QCOMPARE(selectedItems.count(), expectedItems.count()); - foreach (IntPair intPair, expectedItems) + for (const auto &intPair : expectedItems) QVERIFY(selectedItems.contains(testWidget->item(intPair.first, intPair.second))); // check that setItemSelected agrees with selectedItems - for (int row = 0; row<testWidget->rowCount(); ++row) { - bool hidden = false; - foreach (int hiddenRow, hiddenRows){ - if(hiddenRow == row){ - hidden = true; - break; - } - } - if (hidden) + for (int row = 0; row < testWidget->rowCount(); ++row) { + if (hiddenRows.contains(row)) continue; - for (int column = 0; column<testWidget->columnCount(); ++column) { - foreach (int hiddenColumn, hiddenColumns){ - if(hiddenColumn == column){ - hidden = true; - break; - } - } - if (hidden) + for (int column = 0; column < testWidget->columnCount(); ++column) { + if (hiddenColumns.contains(column)) continue; QTableWidgetItem *item = testWidget->item(row, column); @@ -621,11 +599,13 @@ void tst_QTableWidget::removeRow() QCOMPARE(testWidget->columnCount(), columnCount); // fill table with items - for (int r = 0; r < rowCount; ++r) - for (int c = 0; c < columnCount; ++c) + for (int r = 0; r < rowCount; ++r) { + const QString rRow = QString::number(r) + QLatin1Char(':'); + for (int c = 0; c < columnCount; ++c) { testWidget->setItem(r, c, - new QTableWidgetItem( - QString::number(r) + ":" + QString::number(c))); + new QTableWidgetItem(rRow + QString::number(c))); + } + } // remove and compare the results testWidget->removeRow(row); @@ -633,14 +613,18 @@ void tst_QTableWidget::removeRow() QCOMPARE(testWidget->columnCount(), expectedColumnCount); // check if the correct items were removed - for (int r = 0; r < expectedRowCount; ++r) - for (int c = 0; c < expectedColumnCount; ++c) + for (int r = 0; r < expectedRowCount; ++r) { + const QString rRow = QString::number(r < row ? r : r + 1) + + QLatin1Char(':'); + for (int c = 0; c < expectedColumnCount; ++c) { if (r < row) QCOMPARE(testWidget->item(r, c)->text(), - QString::number(r) + ":" + QString::number(c)); + rRow + QString::number(c)); else QCOMPARE(testWidget->item(r, c)->text(), - QString::number(r + 1) + ":" + QString::number(c)); + rRow + QString::number(c)); + } + } } void tst_QTableWidget::removeColumn_data() @@ -673,11 +657,14 @@ void tst_QTableWidget::removeColumn() QCOMPARE(testWidget->columnCount(), columnCount); // fill table with items - for (int r = 0; r < rowCount; ++r) - for (int c = 0; c < columnCount; ++c) + for (int r = 0; r < rowCount; ++r) { + const QString rStr = QString::number(r) + QLatin1Char(':'); + for (int c = 0; c < columnCount; ++c) { testWidget->setItem(r, c, new QTableWidgetItem( - QString::number(r) + ":" + QString::number(c))); + rStr + QString::number(c))); + } + } // remove and compare the results testWidget->removeColumn(column); @@ -686,14 +673,17 @@ void tst_QTableWidget::removeColumn() // check if the correct items were removed - for (int r = 0; r < expectedRowCount; ++r) - for (int c = 0; c < expectedColumnCount; ++c) + for (int r = 0; r < expectedRowCount; ++r) { + const QString rStr = QString::number(r) + QLatin1Char(':'); + for (int c = 0; c < expectedColumnCount; ++c) { if (c < column) QCOMPARE(testWidget->item(r, c)->text(), - QString::number(r) + ":" + QString::number(c)); + rStr + QString::number(c)); else QCOMPARE(testWidget->item(r, c)->text(), - QString::number(r) + ":" + QString::number(c + 1)); + rStr + QString::number(c + 1)); + } + } } void tst_QTableWidget::insertRow_data() @@ -819,7 +809,7 @@ void tst_QTableWidget::itemOwnership() item = new QObjectTableItem(); testWidget->setItem(0, 0, item); delete item; - QCOMPARE(testWidget->item(0, 0), (QTableWidgetItem *)0); + QCOMPARE(testWidget->item(0, 0), nullptr); //delete vertical headeritem from outside headerItem = new QObjectTableItem(); @@ -887,7 +877,7 @@ void tst_QTableWidget::sortItems_data() { QTest::addColumn<int>("rowCount"); QTest::addColumn<int>("columnCount"); - QTest::addColumn<int>("sortOrder"); + QTest::addColumn<Qt::SortOrder>("sortOrder"); QTest::addColumn<int>("sortColumn"); QTest::addColumn<QStringList>("initial"); QTest::addColumn<QStringList>("expected"); @@ -897,7 +887,7 @@ void tst_QTableWidget::sortItems_data() QTest::newRow("ascending") << 4 << 5 - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << 0 << (QStringList() << "0" << "a" << "o" << "8" << "k" @@ -915,7 +905,7 @@ void tst_QTableWidget::sortItems_data() QTest::newRow("descending") << 4 << 5 - << static_cast<int>(Qt::DescendingOrder) + << Qt::DescendingOrder << 0 << (QStringList() << "0" << "a" << "o" << "8" << "k" @@ -933,154 +923,151 @@ void tst_QTableWidget::sortItems_data() QTest::newRow("empty table") << 4 << 5 - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << 0 << (QStringList() - << 0 << 0 << 0 << 0 << 0 - << 0 << 0 << 0 << 0 << 0 - << 0 << 0 << 0 << 0 << 0 - << 0 << 0 << 0 << 0 << 0) + << QString() << QString() << QString() << QString() << QString() + << QString() << QString() << QString() << QString() << QString() + << QString() << QString() << QString() << QString() << QString() + << QString() << QString() << QString() << QString() << QString()) << (QStringList() - << 0 << 0 << 0 << 0 << 0 - << 0 << 0 << 0 << 0 << 0 - << 0 << 0 << 0 << 0 << 0 - << 0 << 0 << 0 << 0 << 0) + << QString() << QString() << QString() << QString() << QString() + << QString() << QString() << QString() << QString() << QString() + << QString() << QString() << QString() << QString() << QString() + << QString() << QString() << QString() << QString() << QString()) << IntList() << IntList() << IntList(); - QTest::newRow("half-empty table") << 4 << 5 - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << 0 << (QStringList() - << "0" << 0 << 0 << 0 << 0 - << "3" << "d" << 0 << 0 << 0 - << "2" << "c" << 0 << 0 << 0 - << 0 << 0 << 0 << 0 << 0) + << "0" << QString() << QString() << QString() << QString() + << "3" << "d" << QString() << QString() << QString() + << "2" << "c" << QString() << QString() << QString() + << QString() << QString() << QString() << QString() << QString()) << (QStringList() - << "0" << 0 << 0 << 0 << 0 - << "2" << "c" << 0 << 0 << 0 - << "3" << "d" << 0 << 0 << 0 - << 0 << 0 << 0 << 0 << 0) + << "0" << QString() << QString() << QString() << QString() + << "2" << "c" << QString() << QString() << QString() + << "3" << "d" << QString() << QString() << QString() + << QString() << QString() << QString() << QString() << QString()) << (IntList() << 0 << 2 << 1) << IntList() << IntList(); QTest::newRow("empty column, should not sort.") << 4 << 5 - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << 3 << (QStringList() - << "0" << 0 << 0 << 0 << 0 - << "3" << "d" << 0 << 0 << 0 - << "2" << "c" << 0 << 0 << 0 - << 0 << 0 << 0 << 0 << 0) + << "0" << QString() << QString() << QString() << QString() + << "3" << "d" << QString() << QString() << QString() + << "2" << "c" << QString() << QString() << QString() + << QString() << QString() << QString() << QString() << QString()) << (QStringList() - << "0" << 0 << 0 << 0 << 0 - << "3" << "d" << 0 << 0 << 0 - << "2" << "c" << 0 << 0 << 0 - << 0 << 0 << 0 << 0 << 0) + << "0" << QString() << QString() << QString() << QString() + << "3" << "d" << QString() << QString() << QString() + << "2" << "c" << QString() << QString() << QString() + << QString() << QString() << QString() << QString() << QString()) << IntList() << IntList() << IntList(); QTest::newRow("descending with null cell, the null cell should be placed at the bottom") << 4 << 5 - << static_cast<int>(Qt::DescendingOrder) + << Qt::DescendingOrder << 0 << (QStringList() - << "0" << "a" << "o" << "8" << "k" - << "3" << "d" << "k" << "o" << "6" - << "2" << "c" << "9" << "y" << "8" - << 0 << "b" << "7" << "3" << "u") + << "0" << "a" << "o" << "8" << "k" + << "3" << "d" << "k" << "o" << "6" + << "2" << "c" << "9" << "y" << "8" + << QString() << "b" << "7" << "3" << "u") << (QStringList() - << "3" << "d" << "k" << "o" << "6" - << "2" << "c" << "9" << "y" << "8" - << "0" << "a" << "o" << "8" << "k" - << 0 << "b" << "7" << "3" << "u") + << "3" << "d" << "k" << "o" << "6" + << "2" << "c" << "9" << "y" << "8" + << "0" << "a" << "o" << "8" << "k" + << QString() << "b" << "7" << "3" << "u") << (IntList() << 2 << 0 << 1) << IntList() << IntList(); QTest::newRow("ascending with null cell, the null cell should be placed at the bottom") << 4 << 5 - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << 0 << (QStringList() - << "0" << "a" << "o" << "8" << "k" - << "3" << "d" << "k" << "o" << "6" - << "2" << "c" << "9" << "y" << "8" - << 0 << "b" << "7" << "3" << "u") + << "0" << "a" << "o" << "8" << "k" + << "3" << "d" << "k" << "o" << "6" + << "2" << "c" << "9" << "y" << "8" + << QString() << "b" << "7" << "3" << "u") << (QStringList() - << "0" << "a" << "o" << "8" << "k" - << "2" << "c" << "9" << "y" << "8" - << "3" << "d" << "k" << "o" << "6" - << 0 << "b" << "7" << "3" << "u") + << "0" << "a" << "o" << "8" << "k" + << "2" << "c" << "9" << "y" << "8" + << "3" << "d" << "k" << "o" << "6" + << QString() << "b" << "7" << "3" << "u") << (IntList() << 0 << 2 << 1) << IntList() << IntList(); QTest::newRow("ascending with null cells, the null cells should be placed at the bottom") << 4 << 5 - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << 0 << (QStringList() - << "3" << "d" << "k" << "o" << "6" - << "0" << "a" << "o" << "8" << "k" - << 0 << "c" << "9" << "y" << "8" - << 0 << "b" << "7" << "3" << "u") + << "3" << "d" << "k" << "o" << "6" + << "0" << "a" << "o" << "8" << "k" + << QString() << "c" << "9" << "y" << "8" + << QString() << "b" << "7" << "3" << "u") << (QStringList() - << "0" << "a" << "o" << "8" << "k" - << "3" << "d" << "k" << "o" << "6" - << 0 << "c" << "9" << "y" << "8" - << 0 << "b" << "7" << "3" << "u") + << "0" << "a" << "o" << "8" << "k" + << "3" << "d" << "k" << "o" << "6" + << QString() << "c" << "9" << "y" << "8" + << QString() << "b" << "7" << "3" << "u") << (IntList() << 1 << 0) << IntList() << IntList(); QTest::newRow("ascending... Check a bug in PersistentIndexes") << 4 << 5 - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << 0 << (QStringList() << "3" << "c" << "9" << "y" << "8" << "2" << "b" << "7" << "3" << "u" << "4" << "d" << "k" << "o" << "6" - << "1" << "a" << "o" << "8" << "k" - ) + << "1" << "a" << "o" << "8" << "k") << (QStringList() << "1" << "a" << "o" << "8" << "k" << "2" << "b" << "7" << "3" << "u" << "3" << "c" << "9" << "y" << "8" - << "4" << "d" << "k" << "o" << "6" - ) + << "4" << "d" << "k" << "o" << "6") << (IntList() << 2 << 1 << 3 << 0) << IntList() << IntList(); QTest::newRow("ascending with some null cells inbetween") << 4 << 5 - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << 0 << (QStringList() - << 0 << "a" << "o" << "8" << "k" - << "2" << "c" << "9" << "y" << "8" - << 0 << "d" << "k" << "o" << "6" - << "1" << "b" << "7" << "3" << "u") + << QString() << "a" << "o" << "8" << "k" + << "2" << "c" << "9" << "y" << "8" + << QString() << "d" << "k" << "o" << "6" + << "1" << "b" << "7" << "3" << "u") << (QStringList() - << "1" << "b" << "7" << "3" << "u" - << "2" << "c" << "9" << "y" << "8" - << 0 << "a" << "o" << "8" << "k" - << 0 << "d" << "k" << "o" << "6") + << "1" << "b" << "7" << "3" << "u" + << "2" << "c" << "9" << "y" << "8" + << QString() << "a" << "o" << "8" << "k" + << QString() << "d" << "k" << "o" << "6") << (IntList() << 1 << 0) << IntList() << IntList(); QTest::newRow("ascending hidden") << 4 << 5 - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << 0 << (QStringList() << "0" << "a" << "o" << "8" << "k" @@ -1098,7 +1085,7 @@ void tst_QTableWidget::sortItems_data() QTest::newRow("descending hidden") << 4 << 5 - << static_cast<int>(Qt::DescendingOrder) + << Qt::DescendingOrder << 0 << (QStringList() << "0" << "a" << "o" << "8" << "k" @@ -1119,7 +1106,7 @@ void tst_QTableWidget::sortItems() { QFETCH(int, rowCount); QFETCH(int, columnCount); - QFETCH(int, sortOrder); + QFETCH(Qt::SortOrder, sortOrder); QFETCH(int, sortColumn); QFETCH(QStringList, initial); QFETCH(QStringList, expected); @@ -1131,13 +1118,13 @@ void tst_QTableWidget::sortItems() testWidget->setColumnCount(columnCount); QAbstractItemModel *model = testWidget->model(); - QList<QPersistentModelIndex> persistent; + QVector<QPersistentModelIndex> persistent; int ti = 0; for (int r = 0; r < rowCount; ++r) { for (int c = 0; c < columnCount; ++c) { - QString str = initial.at(ti++); - if (!str.isNull()) { + QString str = initial.at(ti++); + if (!str.isEmpty()) { testWidget->setItem(r, c, new QTableWidgetItem(str)); } } @@ -1150,7 +1137,7 @@ void tst_QTableWidget::sortItems() QCOMPARE(testWidget->verticalHeader()->hiddenSectionCount(), initialHidden.count()); - testWidget->sortItems(sortColumn, static_cast<Qt::SortOrder>(sortOrder)); + testWidget->sortItems(sortColumn, sortOrder); int te = 0; for (int i = 0; i < rows.count(); ++i) { @@ -1175,7 +1162,7 @@ void tst_QTableWidget::setItemWithSorting_data() { QTest::addColumn<int>("rowCount"); QTest::addColumn<int>("columnCount"); - QTest::addColumn<int>("sortOrder"); + QTest::addColumn<Qt::SortOrder>("sortOrder"); QTest::addColumn<int>("sortColumn"); QTest::addColumn<QStringList>("initialValues"); QTest::addColumn<int>("row"); @@ -1187,7 +1174,7 @@ void tst_QTableWidget::setItemWithSorting_data() QTest::newRow("2x1 no change (ascending)") << 2 << 1 - << static_cast<int>(Qt::AscendingOrder) << 0 + << Qt::AscendingOrder << 0 << (QStringList() << "0" << "1") << 1 << 0 << "2" << (QStringList() << "0" << "2") @@ -1195,7 +1182,7 @@ void tst_QTableWidget::setItemWithSorting_data() << false; QTest::newRow("2x1 no change (descending)") << 2 << 1 - << static_cast<int>(Qt::DescendingOrder) << 0 + << Qt::DescendingOrder << 0 << (QStringList() << "1" << "0") << 0 << 0 << "2" << (QStringList() << "2" << "0") @@ -1203,7 +1190,7 @@ void tst_QTableWidget::setItemWithSorting_data() << false; QTest::newRow("2x1 reorder (ascending)") << 2 << 1 - << static_cast<int>(Qt::AscendingOrder) << 0 + << Qt::AscendingOrder << 0 << (QStringList() << "0" << "1") << 0 << 0 << "2" << (QStringList() << "1" << "2") @@ -1211,7 +1198,7 @@ void tst_QTableWidget::setItemWithSorting_data() << true; QTest::newRow("2x1 reorder (descending)") << 2 << 1 - << static_cast<int>(Qt::DescendingOrder) << 0 + << Qt::DescendingOrder << 0 << (QStringList() << "1" << "0") << 1 << 0 << "2" << (QStringList() << "2" << "1") @@ -1219,7 +1206,7 @@ void tst_QTableWidget::setItemWithSorting_data() << true; QTest::newRow("2x2 no change (ascending)") << 2 << 2 - << static_cast<int>(Qt::AscendingOrder) << 0 + << Qt::AscendingOrder << 0 << (QStringList() << "0" << "00" << "1" << "11") @@ -1231,7 +1218,7 @@ void tst_QTableWidget::setItemWithSorting_data() << false; QTest::newRow("2x2 reorder (ascending)") << 2 << 2 - << static_cast<int>(Qt::AscendingOrder) << 0 + << Qt::AscendingOrder << 0 << (QStringList() << "0" << "00" << "1" << "11") @@ -1243,7 +1230,7 @@ void tst_QTableWidget::setItemWithSorting_data() << true; QTest::newRow("2x2 reorder (ascending, sortColumn = 1)") << 2 << 2 - << static_cast<int>(Qt::AscendingOrder) << 1 + << Qt::AscendingOrder << 1 << (QStringList() << "00" << "0" << "11" << "1") @@ -1255,7 +1242,7 @@ void tst_QTableWidget::setItemWithSorting_data() << true; QTest::newRow("2x2 no change (column != sortColumn)") << 2 << 2 - << static_cast<int>(Qt::AscendingOrder) << 1 + << Qt::AscendingOrder << 1 << (QStringList() << "00" << "0" << "11" << "1") @@ -1267,7 +1254,7 @@ void tst_QTableWidget::setItemWithSorting_data() << false; QTest::newRow("8x4 reorder (ascending, sortColumn = 3)") << 8 << 4 - << static_cast<int>(Qt::AscendingOrder) << 3 + << Qt::AscendingOrder << 3 << (QStringList() << "q" << "v" << "u" << "0" << "e" << "j" << "i" << "10" @@ -1293,9 +1280,13 @@ void tst_QTableWidget::setItemWithSorting_data() void tst_QTableWidget::setItemWithSorting() { + static int dummy1 = qRegisterMetaType<QList<QPersistentModelIndex>>(); + static int dummy2 = qRegisterMetaType<QAbstractItemModel::LayoutChangeHint>(); + Q_UNUSED(dummy1); + Q_UNUSED(dummy2); QFETCH(int, rowCount); QFETCH(int, columnCount); - QFETCH(int, sortOrder); + QFETCH(Qt::SortOrder, sortOrder); QFETCH(int, sortColumn); QFETCH(QStringList, initialValues); QFETCH(int, row); @@ -1309,7 +1300,7 @@ void tst_QTableWidget::setItemWithSorting() QTableWidget w(rowCount, columnCount); QAbstractItemModel *model = w.model(); - QList<QPersistentModelIndex> persistent; + QVector<QPersistentModelIndex> persistent; int ti = 0; for (int r = 0; r < rowCount; ++r) { @@ -1320,11 +1311,11 @@ void tst_QTableWidget::setItemWithSorting() persistent << model->index(r, sortColumn); } - w.sortItems(sortColumn, static_cast<Qt::SortOrder>(sortOrder)); + w.sortItems(sortColumn, sortOrder); w.setSortingEnabled(true); - QSignalSpy dataChangedSpy(model, SIGNAL(dataChanged(QModelIndex,QModelIndex))); - QSignalSpy layoutChangedSpy(model, SIGNAL(layoutChanged())); + QSignalSpy dataChangedSpy(model, &QAbstractItemModel::dataChanged); + QSignalSpy layoutChangedSpy(model, &QAbstractItemModel::layoutChanged); if (i == 0) { // set a new item @@ -1376,18 +1367,18 @@ public: void tst_QTableWidget::itemData() { QTableWidgetDataChanged widget(2, 2); - widget.setItem(0, 0, new QTableWidgetItem()); + widget.setItem(0, 0, new QTableWidgetItem); QTableWidgetItem *item = widget.item(0, 0); QVERIFY(item); item->setFlags(item->flags() | Qt::ItemIsEditable); item->setData(Qt::DisplayRole, QString("0")); QCOMPARE(widget.currentRoles, QVector<int>({Qt::DisplayRole, Qt::EditRole})); item->setData(Qt::CheckStateRole, Qt::PartiallyChecked); - QCOMPARE(widget.currentRoles, {Qt::CheckStateRole}); + QCOMPARE(widget.currentRoles, QVector<int>{Qt::CheckStateRole}); for (int i = 0; i < 4; ++i) { item->setData(Qt::UserRole + i, QString::number(i + 1)); - QCOMPARE(widget.currentRoles, {Qt::UserRole + i}); + QCOMPARE(widget.currentRoles, QVector<int>{Qt::UserRole + i}); } QMap<int, QVariant> flags = widget.model()->itemData(widget.model()->index(0, 0)); QCOMPARE(flags.count(), 6); @@ -1399,7 +1390,7 @@ void tst_QTableWidget::setItemData() { QTableWidgetDataChanged table(10, 10); table.setSortingEnabled(false); - QSignalSpy dataChangedSpy(table.model(), SIGNAL(dataChanged(QModelIndex,QModelIndex))); + QSignalSpy dataChangedSpy(table.model(), &QAbstractItemModel::dataChanged); QTableWidgetItem *item = new QTableWidgetItem; table.setItem(0, 0, item); @@ -1432,11 +1423,11 @@ void tst_QTableWidget::cellWidget() QTableWidget table(10, 10); QWidget widget; - QCOMPARE(table.cellWidget(5, 5), static_cast<QWidget*>(0)); + QCOMPARE(table.cellWidget(5, 5), nullptr); table.setCellWidget(5, 5, &widget); QCOMPARE(table.cellWidget(5, 5), &widget); table.removeCellWidget(5, 5); - QCOMPARE(table.cellWidget(5, 5), static_cast<QWidget*>(0)); + QCOMPARE(table.cellWidget(5, 5), nullptr); } void tst_QTableWidget::cellWidgetGeometry() @@ -1463,27 +1454,29 @@ void tst_QTableWidget::cellWidgetGeometry() void tst_QTableWidget::sizeHint_data() { - QTest::addColumn<int>("scrollBarPolicy"); + QTest::addColumn<Qt::ScrollBarPolicy>("scrollBarPolicy"); QTest::addColumn<QSize>("viewSize"); - QTest::newRow("ScrollBarAlwaysOn") << static_cast<int>(Qt::ScrollBarAlwaysOn) << QSize(); - QTest::newRow("ScrollBarAlwaysOff") << static_cast<int>(Qt::ScrollBarAlwaysOff) << QSize(); + QTest::newRow("ScrollBarAlwaysOn") << Qt::ScrollBarAlwaysOn << QSize(); + QTest::newRow("ScrollBarAlwaysOff") << Qt::ScrollBarAlwaysOff << QSize(); // make sure the scrollbars are shown by resizing the view to 40x40 - QTest::newRow("ScrollBarAsNeeded (40x40)") << static_cast<int>(Qt::ScrollBarAsNeeded) << QSize(40, 40); - QTest::newRow("ScrollBarAsNeeded (1000x1000)") << static_cast<int>(Qt::ScrollBarAsNeeded) << QSize(1000, 1000); + QTest::newRow("ScrollBarAsNeeded (40x40)") << Qt::ScrollBarAsNeeded << QSize(40, 40); + QTest::newRow("ScrollBarAsNeeded (1000x1000)") << Qt::ScrollBarAsNeeded << QSize(1000, 1000); } void tst_QTableWidget::sizeHint() { - QFETCH(int, scrollBarPolicy); + QFETCH(Qt::ScrollBarPolicy, scrollBarPolicy); QFETCH(QSize, viewSize); QTableWidget view(2, 2); view.setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); - view.setVerticalScrollBarPolicy(static_cast<Qt::ScrollBarPolicy>(scrollBarPolicy)); - view.setHorizontalScrollBarPolicy(static_cast<Qt::ScrollBarPolicy>(scrollBarPolicy)); - for (int r = 0 ; r < view.rowCount(); ++r) + view.setVerticalScrollBarPolicy(scrollBarPolicy); + view.setHorizontalScrollBarPolicy(scrollBarPolicy); + for (int r = 0 ; r < view.rowCount(); ++r) { + const QString rStr = QString::number(r) + QLatin1Char('/'); for (int c = 0 ; c < view.columnCount(); ++c) - view.setItem(r, c, new QTableWidgetItem(QString("%1/%2").arg(r).arg(c))); + view.setItem(r, c, new QTableWidgetItem(rStr + QString::number(c))); + } view.show(); QVERIFY(QTest::qWaitForWindowExposed(&view)); @@ -1520,7 +1513,7 @@ void tst_QTableWidget::task231094() if (y == 1) twi->setFlags(Qt::ItemIsEnabled); else - twi->setFlags(0); + twi->setFlags({}); tw.setItem(y, x, twi); } } @@ -1558,15 +1551,15 @@ void tst_QTableWidget::task262056_sortDuplicate() testWidget->setColumnCount(2); testWidget->setRowCount(8); testWidget->setSortingEnabled(true); - QStringList items = (QStringList() << "AAA" << "BBB" << "CCC" << "CCC" << "DDD"\ - << "EEE" << "FFF" << "GGG"); - for (int i = 0; i<8; i++ ) { + const QStringList items({"AAA", "BBB", "CCC", "CCC", "DDD", + "EEE", "FFF", "GGG"}); + for (int i = 0; i < 8; i++ ) { QTableWidgetItem *twi = new QTableWidgetItem(items.at(i)); - testWidget->setItem(i,0,twi); - testWidget->setItem(i,1,new QTableWidgetItem(QLatin1String("item ") + QString::number(i))); + testWidget->setItem(i, 0, twi); + testWidget->setItem(i, 1, new QTableWidgetItem(QLatin1String("item ") + QString::number(i))); } testWidget->sortItems(0, Qt::AscendingOrder); - QSignalSpy layoutChangedSpy(testWidget->model(), SIGNAL(layoutChanged())); + QSignalSpy layoutChangedSpy(testWidget->model(), &QAbstractItemModel::layoutChanged); testWidget->item(3,0)->setBackground(Qt::red); QCOMPARE(layoutChangedSpy.count(),0); @@ -1586,18 +1579,14 @@ void tst_QTableWidget::itemWithHeaderItems() QTableWidgetItem *item1_0 = new QTableWidgetItem(QTableWidgetItem::UserType); table.setItem(1, 0, item1_0); - QCOMPARE(table.item(0, 1), static_cast<QTableWidgetItem *>(0)); + QCOMPARE(table.item(0, 1), nullptr); } class TestTableWidget : public QTableWidget { Q_OBJECT public: - TestTableWidget(int rows, int columns, QWidget *parent = 0) - : QTableWidget(rows, columns, parent) - { - } - + using QTableWidget::QTableWidget; using QTableWidget::mimeData; using QTableWidget::indexFromItem; using QTableWidget::keyPressEvent; @@ -1661,18 +1650,19 @@ void tst_QTableWidget::selectedRowAfterSorting() { TestTableWidget table(3,3); table.setSelectionBehavior(QAbstractItemView::SelectRows); - for (int r = 0; r < 3; r++) + for (int r = 0; r < 3; r++) { for (int c = 0; c < 3; c++) - table.setItem(r,c,new QTableWidgetItem(QStringLiteral("0"))); + table.setItem(r, c, new QTableWidgetItem(QStringLiteral("0"))); + } QHeaderView *localHorizontalHeader = table.horizontalHeader(); localHorizontalHeader->setSortIndicator(1,Qt::DescendingOrder); table.setProperty("sortingEnabled",true); table.selectRow(1); table.item(1,1)->setText("9"); QCOMPARE(table.selectedItems().count(),3); - foreach (QTableWidgetItem *item, table.selectedItems()) { - QCOMPARE(item->row(),0); - } + const auto selectedItems = table.selectedItems(); + for (QTableWidgetItem *item : selectedItems) + QCOMPARE(item->row(), 0); } void tst_QTableWidget::search() @@ -1717,10 +1707,11 @@ void tst_QTableWidget::search() #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) void tst_QTableWidget::clearItemData() { - QTableWidget table(3,3); - for (int r = 0; r < 3; r++) + QTableWidget table(3, 3); + for (int r = 0; r < 3; r++) { for (int c = 0; c < 3; c++) - table.setItem(r,c,new QTableWidgetItem(QStringLiteral("0"))); + table.setItem(r, c, new QTableWidgetItem(QStringLiteral("0"))); + } QSignalSpy dataChangeSpy(table.model(), &QAbstractItemModel::dataChanged); QVERIFY(dataChangeSpy.isValid()); QVERIFY(!table.model()->clearItemData(QModelIndex())); diff --git a/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp b/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp index 2a1163ec66..44195d3b25 100644 --- a/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp +++ b/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp @@ -27,13 +27,28 @@ ****************************************************************************/ #include "../../../../shared/fakedirmodel.h" -#include <qabstractitemview.h> -#include <QtTest/QtTest> -#include <QtGui/QtGui> -#include <QtWidgets/QtWidgets> -#include <private/qtreeview_p.h> -#include <QtTest/private/qtesthelpers_p.h> +#include <QDesktopWidget> +#include <QHeaderView> +#include <QLabel> +#include <QLineEdit> +#include <QMainWindow> +#include <QProxyStyle> +#include <QPushButton> +#include <QScrollBar> +#include <QSignalSpy> +#include <QSortFilterProxyModel> +#include <QStatusBar> +#include <QStringListModel> +#include <QStyledItemDelegate> +#include <QTextEdit> +#include <QTimer> +#include <QToolButton> +#include <QTreeWidget> +#include <QTest> +#include <QVBoxLayout> +#include <private/qtreeview_p.h> +#include <private/qtesthelpers_p.h> using namespace QTestPrivate; @@ -43,6 +58,7 @@ Q_DECLARE_METATYPE(QAbstractItemView::DragDropMode) Q_DECLARE_METATYPE(QAbstractItemView::EditTriggers) Q_DECLARE_METATYPE(QAbstractItemView::EditTrigger) +using IntBounds = std::numeric_limits<int>; static void initStandardTreeModel(QStandardItemModel *model) { QStandardItem *item; @@ -206,18 +222,11 @@ private slots: class QtTestModel: public QAbstractItemModel { + Q_OBJECT public: - QtTestModel(QObject *parent = 0): QAbstractItemModel(parent), - fetched(false), rows(0), cols(0), levels(INT_MAX), wrongIndex(false) { init(); } - - QtTestModel(int _rows, int _cols, QObject *parent = 0): QAbstractItemModel(parent), - fetched(false), rows(_rows), cols(_cols), levels(INT_MAX), wrongIndex(false) { init(); } - - void init() - { - decorationsEnabled = false; - statusTipsEnabled = false; - } + QtTestModel(int _rows, int _cols, QObject *parent = nullptr) + : QAbstractItemModel(parent), rows(_rows), cols(_cols) + {} inline qint32 level(const QModelIndex &index) const { @@ -264,7 +273,7 @@ public: if (row < 0 || column < 0 || (level(parent) > levels) || column >= cols || row >= rows) { return QModelIndex(); } - QModelIndex i = createIndex(row, column, level(parent) + 1); + QModelIndex i = createIndex(row, column, quintptr(level(parent) + 1)); parentHash[i] = parent; return i; } @@ -361,13 +370,14 @@ public: decorationsEnabled = enable; } - mutable bool fetched; - bool decorationsEnabled; - bool statusTipsEnabled; - int rows, cols; - int levels; - mutable bool wrongIndex; mutable QMap<QModelIndex,QModelIndex> parentHash; + int rows = 0; + int cols = 0; + int levels = IntBounds::max(); + mutable bool wrongIndex = false; + mutable bool fetched = false; + bool decorationsEnabled = false; + bool statusTipsEnabled = false; }; // Testing get/set functions @@ -377,14 +387,15 @@ void tst_QTreeView::getSetCheck() // int QTreeView::indentation() // void QTreeView::setIndentation(int) - const int styledIndentation = obj1.style()->pixelMetric(QStyle::PM_TreeViewIndentation, 0, &obj1); + const int styledIndentation = obj1.style()->pixelMetric( + QStyle::PM_TreeViewIndentation, nullptr, &obj1); QCOMPARE(obj1.indentation(), styledIndentation); obj1.setIndentation(0); QCOMPARE(obj1.indentation(), 0); - obj1.setIndentation(INT_MIN); - QCOMPARE(obj1.indentation(), INT_MIN); - obj1.setIndentation(INT_MAX); - QCOMPARE(obj1.indentation(), INT_MAX); + obj1.setIndentation(IntBounds::min()); + QCOMPARE(obj1.indentation(), IntBounds::min()); + obj1.setIndentation(IntBounds::max()); + QCOMPARE(obj1.indentation(), IntBounds::max()); // bool QTreeView::rootIsDecorated() // void QTreeView::setRootIsDecorated(bool) @@ -477,7 +488,8 @@ void tst_QTreeView::construction() QCOMPARE(view.sizeHintForRow(1), -1); QVERIFY(!view.tabKeyNavigation()); QCOMPARE(view.textElideMode(), Qt::ElideRight); - QCOMPARE(static_cast<int>(view.verticalScrollMode()), view.style()->styleHint(QStyle::SH_ItemView_ScrollMode, 0, &view)); + QCOMPARE(static_cast<int>(view.verticalScrollMode()), + view.style()->styleHint(QStyle::SH_ItemView_ScrollMode, nullptr, &view)); QCOMPARE(view.visualRect(QModelIndex()), QRect()); // QTreeView properties @@ -493,8 +505,8 @@ void tst_QTreeView::construction() QCOMPARE(view.columnWidth(0), 0); QCOMPARE(view.columnWidth(1), 0); QVERIFY(view.header()); - const int styledIndentation = view.style()->pixelMetric(QStyle::PM_TreeViewIndentation, 0, &view); - QCOMPARE(view.indentation(), styledIndentation); + QCOMPARE(view.indentation(), + view.style()->pixelMetric(QStyle::PM_TreeViewIndentation, nullptr, &view)); QCOMPARE(view.indexAbove(QModelIndex()), QModelIndex()); QCOMPARE(view.indexBelow(QModelIndex()), QModelIndex()); QVERIFY(!view.isAnimated()); @@ -781,17 +793,17 @@ void tst_QTreeView::editTriggers() break; case QAbstractItemView::DoubleClicked: // Doubleclick the center of the current cell - QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, + QTest::mouseClick(view.viewport(), Qt::LeftButton, {}, view.visualRect(view.model()->index(0, 0)).center()); - QTest::mouseDClick(view.viewport(), Qt::LeftButton, 0, + QTest::mouseDClick(view.viewport(), Qt::LeftButton, {}, view.visualRect(view.model()->index(0, 0)).center()); break; case QAbstractItemView::SelectedClicked: // Click the center of the current cell view.selectionModel()->select(view.model()->index(0, 0), QItemSelectionModel::Select); - QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, + QTest::mouseClick(view.viewport(), Qt::LeftButton, {}, view.visualRect(view.model()->index(0, 0)).center()); - QTest::qWait(int(QApplication::doubleClickInterval() * 1.5)); + QTest::qWait(qRound(QApplication::doubleClickInterval() * 1.5)); break; case QAbstractItemView::EditKeyPressed: view.setFocus(); @@ -808,7 +820,7 @@ void tst_QTreeView::editTriggers() } // Check if we got an editor - QTRY_COMPARE(view.findChild<QLineEdit *>(QString()) != 0, editorOpened); + QTRY_COMPARE(view.findChild<QLineEdit *>(QString()) != nullptr, editorOpened); } void tst_QTreeView::hasAutoScroll() @@ -860,11 +872,11 @@ void tst_QTreeView::horizontalScrollMode() class RepaintTreeView : public QTreeView { public: - RepaintTreeView() : repainted(false) { } - bool repainted; + using QTreeView::QTreeView; + bool repainted = false; protected: - void paintEvent(QPaintEvent *event) + void paintEvent(QPaintEvent *event) override { repainted = true; QTreeView::paintEvent(event); } }; @@ -902,8 +914,7 @@ void tst_QTreeView::iconSize() void tst_QTreeView::indexAt() { - QtTestModel model; - model.rows = model.cols = 5; + QtTestModel model(5, 5); QTreeView view; QCOMPARE(view.indexAt(QPoint()), QModelIndex()); @@ -985,21 +996,21 @@ void tst_QTreeView::indexWidget() void tst_QTreeView::itemDelegate() { QPointer<QAbstractItemDelegate> oldDelegate; - QPointer<QItemDelegate> otherItemDelegate; + QPointer<QStyledItemDelegate> otherItemDelegate; { QTreeView view; QVERIFY(qobject_cast<QStyledItemDelegate *>(view.itemDelegate())); QPointer<QAbstractItemDelegate> oldDelegate = view.itemDelegate(); - otherItemDelegate = new QItemDelegate; + otherItemDelegate = new QStyledItemDelegate; view.setItemDelegate(otherItemDelegate); QVERIFY(!otherItemDelegate->parent()); QVERIFY(oldDelegate); - QCOMPARE(view.itemDelegate(), (QAbstractItemDelegate *)otherItemDelegate); + QCOMPARE(view.itemDelegate(), otherItemDelegate); - view.setItemDelegate(0); + view.setItemDelegate(nullptr); QVERIFY(!view.itemDelegate()); // <- view does its own drawing? QVERIFY(otherItemDelegate); } @@ -1038,29 +1049,29 @@ void tst_QTreeView::itemDelegateForColumnOrRow() QCOMPARE(view.itemDelegate(QModelIndex()), defaultDelegate); QCOMPARE(view.itemDelegate(view.model()->index(0, 0)), defaultDelegate); - QPointer<QAbstractItemDelegate> rowDelegate = new QItemDelegate; + QPointer<QAbstractItemDelegate> rowDelegate = new QStyledItemDelegate; view.setItemDelegateForRow(0, rowDelegate); QVERIFY(!rowDelegate->parent()); - QCOMPARE(view.itemDelegateForRow(0), (QAbstractItemDelegate *)rowDelegate); - QCOMPARE(view.itemDelegate(view.model()->index(0, 0)), (QAbstractItemDelegate *)rowDelegate); - QCOMPARE(view.itemDelegate(view.model()->index(0, 1)), (QAbstractItemDelegate *)rowDelegate); + QCOMPARE(view.itemDelegateForRow(0), rowDelegate); + QCOMPARE(view.itemDelegate(view.model()->index(0, 0)), rowDelegate); + QCOMPARE(view.itemDelegate(view.model()->index(0, 1)), rowDelegate); QCOMPARE(view.itemDelegate(view.model()->index(1, 0)), defaultDelegate); QCOMPARE(view.itemDelegate(view.model()->index(1, 1)), defaultDelegate); - QPointer<QAbstractItemDelegate> columnDelegate = new QItemDelegate; + QPointer<QAbstractItemDelegate> columnDelegate = new QStyledItemDelegate; view.setItemDelegateForColumn(1, columnDelegate); QVERIFY(!columnDelegate->parent()); - QCOMPARE(view.itemDelegateForColumn(1), (QAbstractItemDelegate *)columnDelegate); - QCOMPARE(view.itemDelegate(view.model()->index(0, 0)), (QAbstractItemDelegate *)rowDelegate); - QCOMPARE(view.itemDelegate(view.model()->index(0, 1)), (QAbstractItemDelegate *)rowDelegate); // row wins + QCOMPARE(view.itemDelegateForColumn(1), columnDelegate); + QCOMPARE(view.itemDelegate(view.model()->index(0, 0)), rowDelegate); + QCOMPARE(view.itemDelegate(view.model()->index(0, 1)), rowDelegate); // row wins QCOMPARE(view.itemDelegate(view.model()->index(1, 0)), defaultDelegate); - QCOMPARE(view.itemDelegate(view.model()->index(1, 1)), (QAbstractItemDelegate *)columnDelegate); + QCOMPARE(view.itemDelegate(view.model()->index(1, 1)), columnDelegate); - view.setItemDelegateForRow(0, 0); + view.setItemDelegateForRow(0, nullptr); QVERIFY(!view.itemDelegateForRow(0)); QVERIFY(rowDelegate); // <- wasn't deleted - view.setItemDelegateForColumn(1, 0); + view.setItemDelegateForColumn(1, nullptr); QVERIFY(!view.itemDelegateForColumn(1)); QVERIFY(columnDelegate); // <- wasn't deleted @@ -1130,12 +1141,9 @@ void tst_QTreeView::keyboardSearch() QTest::qWait(QApplication::keyboardInputInterval() * 2); model.clear(); view.setCurrentIndex(QModelIndex()); - QList<QStandardItem *> items = { new QStandardItem("Andreas"), new QStandardItem("Alicia") }; - model.appendRow(items); - items = { new QStandardItem("Baldrian"), new QStandardItem("Belinda") }; - model.appendRow(items); - items = { new QStandardItem("Cecilie"), new QStandardItem("Claire") }; - model.appendRow(items); + model.appendRow({ new QStandardItem("Andreas"), new QStandardItem("Alicia") }); + model.appendRow({ new QStandardItem("Baldrian"), new QStandardItem("Belinda") }); + model.appendRow({ new QStandardItem("Cecilie"), new QStandardItem("Claire") }); QVERIFY(!view.selectionModel()->hasSelection()); QVERIFY(!view.selectionModel()->isSelected(model.index(0, 0))); @@ -1166,8 +1174,7 @@ void tst_QTreeView::keyboardSearch() QCOMPARE(view.currentIndex(), model.index(1, 1)); // Test that it wraps round - items = { new QStandardItem("Andy"), new QStandardItem("Adele") }; - model.appendRow(items); + model.appendRow({ new QStandardItem("Andy"), new QStandardItem("Adele") }); QTest::qWait(QApplication::keyboardInputInterval() * 2); view.keyboardSearch(QLatin1String("A")); QVERIFY(view.selectionModel()->isSelected(model.index(3, 1))); @@ -1202,17 +1209,16 @@ void tst_QTreeView::keyboardSearch() void tst_QTreeView::keyboardSearchMultiColumn() { QTreeView view; - QStandardItemModel model(4, 2); model.setItem(0, 0, new QStandardItem("1")); model.setItem(0, 1, new QStandardItem("green")); - model.setItem(1, 0, new QStandardItem("bad")); model.setItem(1, 1, new QStandardItem("eggs")); - model.setItem(2, 0, new QStandardItem("moof")); model.setItem(2, 1, new QStandardItem("and")); - model.setItem(3, 0, new QStandardItem("elf")); model.setItem(3, 1, new QStandardItem("ham")); + model.setItem(1, 0, new QStandardItem("bad")); model.setItem(1, 1, new QStandardItem("eggs")); + model.setItem(2, 0, new QStandardItem("moof")); model.setItem(2, 1, new QStandardItem("and")); + model.setItem(3, 0, new QStandardItem("elf")); model.setItem(3, 1, new QStandardItem("ham")); view.setModel(&model); view.show(); - qApp->setActiveWindow(&view); + QApplication::setActiveWindow(&view); QVERIFY(QTest::qWaitForWindowActive(&view)); view.setCurrentIndex(model.index(0, 1)); @@ -1240,22 +1246,22 @@ void tst_QTreeView::setModel() for (int x = 0; x < 2; ++x) { QtTestModel *model = new QtTestModel(10, 8); QAbstractItemModel *oldModel = view.model(); - QSignalSpy modelDestroyedSpy(oldModel ? oldModel : model, SIGNAL(destroyed())); + QSignalSpy modelDestroyedSpy(oldModel ? oldModel : model, &QObject::destroyed); // set the same model twice for (int i = 0; i < 2; ++i) { QItemSelectionModel *oldSelectionModel = view.selectionModel(); QItemSelectionModel *dummy = new QItemSelectionModel(model); QSignalSpy selectionModelDestroyedSpy( - oldSelectionModel ? oldSelectionModel : dummy, SIGNAL(destroyed())); + oldSelectionModel ? oldSelectionModel : dummy, &QObject::destroyed); view.setModel(model); // QCOMPARE(selectionModelDestroyedSpy.count(), (x == 0 || i == 1) ? 0 : 1); - QCOMPARE(view.model(), (QAbstractItemModel *)model); - QCOMPARE(view.header()->model(), (QAbstractItemModel *)model); + QCOMPARE(view.model(), model); + QCOMPARE(view.header()->model(), model); QCOMPARE(view.selectionModel() != oldSelectionModel, (i == 0)); } QTRY_COMPARE(modelDestroyedSpy.count(), 0); - view.setModel(0); + view.setModel(nullptr); QCOMPARE(view.model(), nullptr); // ### shouldn't selectionModel also be 0 now? // QCOMPARE(view.selectionModel(), nullptr); @@ -1278,7 +1284,7 @@ void tst_QTreeView::openPersistentEditor() view.closePersistentEditor(view.model()->index(0, 0)); QVERIFY(!view.viewport()->findChild<QLineEdit *>()->isVisible()); - qApp->sendPostedEvents(0, QEvent::DeferredDelete); + QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); QVERIFY(!view.viewport()->findChild<QLineEdit *>()); } @@ -1300,21 +1306,20 @@ void tst_QTreeView::rootIndex() void tst_QTreeView::setHeader() { QTreeView view; - QVERIFY(view.header() != 0); + QVERIFY(view.header() != nullptr); QCOMPARE(view.header()->orientation(), Qt::Horizontal); - QCOMPARE(view.header()->parent(), (QObject *)&view); + QCOMPARE(view.header()->parent(), &view); for (int x = 0; x < 2; ++x) { - QSignalSpy destroyedSpy(view.header(), SIGNAL(destroyed())); + QSignalSpy destroyedSpy(view.header(), &QObject::destroyed); Qt::Orientation orient = x ? Qt::Vertical : Qt::Horizontal; QHeaderView *head = new QHeaderView(orient); view.setHeader(head); QCOMPARE(destroyedSpy.count(), 1); - QCOMPARE(head->parent(), (QObject *)&view); + QCOMPARE(head->parent(), &view); QCOMPARE(view.header(), head); view.setHeader(head); QCOMPARE(view.header(), head); - // Itemviews in Qt < 4.2 have asserts for this. Qt >= 4.2 should handle this gracefully - view.setHeader((QHeaderView *)0); + view.setHeader(nullptr); QCOMPARE(view.header(), head); } } @@ -1328,13 +1333,13 @@ void tst_QTreeView::columnHidden() for (int c = 0; c < model.columnCount(); ++c) QCOMPARE(view.isColumnHidden(c), false); // hide even columns - for (int c = 0; c < model.columnCount(); c+=2) + for (int c = 0; c < model.columnCount(); c += 2) view.setColumnHidden(c, true); for (int c = 0; c < model.columnCount(); ++c) QCOMPARE(view.isColumnHidden(c), (c & 1) == 0); view.update(); // hide odd columns too - for (int c = 1; c < model.columnCount(); c+=2) + for (int c = 1; c < model.columnCount(); c += 2) view.setColumnHidden(c, true); for (int c = 0; c < model.columnCount(); ++c) QCOMPARE(view.isColumnHidden(c), true); @@ -1418,7 +1423,7 @@ void tst_QTreeView::noDelegate() QtTestModel model(10, 7); QTreeView view; view.setModel(&model); - view.setItemDelegate(0); + view.setItemDelegate(nullptr); QCOMPARE(view.itemDelegate(), nullptr); } @@ -1427,11 +1432,13 @@ void tst_QTreeView::noModel() QTreeView view; view.show(); view.setRowHidden(0, QModelIndex(), true); + // no model -> not able to hide a row + QVERIFY(!view.isRowHidden(0, QModelIndex())); } void tst_QTreeView::emptyModel() { - QtTestModel model; + QtTestModel model(0, 0); QTreeView view; view.setModel(&model); view.show(); @@ -1486,7 +1493,7 @@ void tst_QTreeView::limitedExpand() QTreeView view; view.setModel(&model); - QSignalSpy spy(&view, SIGNAL(expanded(QModelIndex))); + QSignalSpy spy(&view, &QTreeView::expanded); QVERIFY(spy.isValid()); view.expand(model.index(0, 0)); @@ -1500,7 +1507,7 @@ void tst_QTreeView::limitedExpand() QTreeView view; view.setModel(&model); - QSignalSpy spy(&view, SIGNAL(expanded(QModelIndex))); + QSignalSpy spy(&view, &QTreeView::expanded); QVERIFY(spy.isValid()); view.expand(model.index(0, 0)); @@ -1515,7 +1522,6 @@ void tst_QTreeView::expandAndCollapse_data() QTest::addColumn<bool>("animationEnabled"); QTest::newRow("normal") << false; QTest::newRow("animated") << true; - } void tst_QTreeView::expandAndCollapse() @@ -1533,8 +1539,8 @@ void tst_QTreeView::expandAndCollapse() QModelIndex a = model.index(0, 0, QModelIndex()); QModelIndex b = model.index(0, 0, a); - QSignalSpy expandedSpy(&view, SIGNAL(expanded(QModelIndex))); - QSignalSpy collapsedSpy(&view, SIGNAL(collapsed(QModelIndex))); + QSignalSpy expandedSpy(&view, &QTreeView::expanded); + QSignalSpy collapsedSpy(&view, &QTreeView::collapsed); QVariantList args; for (int y = 0; y < 2; ++y) { @@ -1744,7 +1750,7 @@ void tst_QTreeView::expandAndCollapseAll() void tst_QTreeView::expandWithNoChildren() { QTreeView tree; - QStandardItemModel model(1,1); + QStandardItemModel model(1, 1); tree.setModel(&model); tree.setAnimated(true); tree.doItemsLayout(); @@ -1765,14 +1771,15 @@ void tst_QTreeView::keyboardNavigation() view.setModel(&model); view.show(); - QVector<Qt::Key> keymoves; - keymoves << Qt::Key_Down << Qt::Key_Right << Qt::Key_Right << Qt::Key_Right - << Qt::Key_Down << Qt::Key_Down << Qt::Key_Down << Qt::Key_Down - << Qt::Key_Right << Qt::Key_Right << Qt::Key_Right - << Qt::Key_Left << Qt::Key_Up << Qt::Key_Left << Qt::Key_Left - << Qt::Key_Up << Qt::Key_Down << Qt::Key_Up << Qt::Key_Up - << Qt::Key_Up << Qt::Key_Up << Qt::Key_Up << Qt::Key_Up - << Qt::Key_Left << Qt::Key_Left << Qt::Key_Up << Qt::Key_Down; + const auto keymoves = { + Qt::Key_Down, Qt::Key_Right, Qt::Key_Right, Qt::Key_Right, + Qt::Key_Down, Qt::Key_Down, Qt::Key_Down, Qt::Key_Down, + Qt::Key_Right, Qt::Key_Right, Qt::Key_Right, + Qt::Key_Left, Qt::Key_Up, Qt::Key_Left, Qt::Key_Left, + Qt::Key_Up, Qt::Key_Down, Qt::Key_Up, Qt::Key_Up, + Qt::Key_Up, Qt::Key_Up, Qt::Key_Up, Qt::Key_Up, + Qt::Key_Left, Qt::Key_Left, Qt::Key_Up, Qt::Key_Down + }; int row = 0; int column = 0; @@ -1780,8 +1787,7 @@ void tst_QTreeView::keyboardNavigation() view.setCurrentIndex(index); QCOMPARE(view.currentIndex(), index); - for (int i = 0; i < keymoves.size(); ++i) { - Qt::Key key = keymoves.at(i); + for (Qt::Key key : keymoves) { QTest::keyClick(&view, key); switch (key) { @@ -1838,10 +1844,10 @@ void tst_QTreeView::keyboardNavigation() class Dmodel : public QtTestModel { + Q_OBJECT public: - Dmodel() : QtTestModel(10, 10){} - - int columnCount(const QModelIndex &parent) const + using QtTestModel::QtTestModel; + int columnCount(const QModelIndex &parent) const override { if (parent.row() == 5) return 1; @@ -1851,7 +1857,7 @@ public: void tst_QTreeView::headerSections() { - Dmodel model; + Dmodel model(10, 10); QTreeView view; QHeaderView *header = view.header(); @@ -1895,7 +1901,8 @@ void tst_QTreeView::moveCursor() view.setColumnHidden(0, true); QVERIFY(view.isColumnHidden(0)); view.show(); - qApp->setActiveWindow(&view); + QApplication::setActiveWindow(&view); + QVERIFY(QTest::qWaitForWindowActive(&view)); //here the first visible index should be selected //because the view got the focus @@ -1938,73 +1945,60 @@ void tst_QTreeView::moveCursor() QCOMPARE(view.currentIndex(), expected); } -class TestDelegate : public QItemDelegate +class TestDelegate : public QStyledItemDelegate { + Q_OBJECT public: - TestDelegate(QObject *parent) : QItemDelegate(parent) {} - QSize sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const { return QSize(200, 50); } + using QStyledItemDelegate::QStyledItemDelegate; + QSize sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const override + { return QSize(200, 50); } }; -typedef QList<QPoint> PointList; +typedef QVector<QPoint> PointList; void tst_QTreeView::setSelection_data() { QTest::addColumn<QRect>("selectionRect"); - QTest::addColumn<int>("selectionMode"); - QTest::addColumn<int>("selectionCommand"); + QTest::addColumn<QAbstractItemView::SelectionMode>("selectionMode"); + QTest::addColumn<QItemSelectionModel::SelectionFlags>("selectionCommand"); QTest::addColumn<PointList>("expectedItems"); QTest::addColumn<int>("verticalOffset"); - QTest::newRow("(0,0,50,20),rows") << QRect(0,0,50,20) - << int(QAbstractItemView::SingleSelection) - << int(QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows) - << (PointList() - << QPoint(0,0) << QPoint(1,0) << QPoint(2,0) << QPoint(3,0) << QPoint(4,0) - ) - << 0; - - QTest::newRow("(0,0,50,90),rows") << QRect(0,0,50,90) - << int(QAbstractItemView::ExtendedSelection) - << int(QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows) - << (PointList() - << QPoint(0,0) << QPoint(1,0) << QPoint(2,0) << QPoint(3,0) << QPoint(4,0) - << QPoint(0,1) << QPoint(1,1) << QPoint(2,1) << QPoint(3,1) << QPoint(4,1) - ) - << 0; - - QTest::newRow("(50,0,0,90),rows,invalid rect") << QRect(QPoint(50, 0), QPoint(0, 90)) - << int(QAbstractItemView::ExtendedSelection) - << int(QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows) - << (PointList() - << QPoint(0,0) << QPoint(1,0) << QPoint(2,0) << QPoint(3,0) << QPoint(4,0) - << QPoint(0,1) << QPoint(1,1) << QPoint(2,1) << QPoint(3,1) << QPoint(4,1) - ) - << 0; - - QTest::newRow("(0,-20,20,50),rows") << QRect(0,-20,20,50) - << int(QAbstractItemView::ExtendedSelection) - << int(QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows) - << (PointList() - << QPoint(0,0) << QPoint(1,0) << QPoint(2,0) << QPoint(3,0) << QPoint(4,0) - << QPoint(0,1) << QPoint(1,1) << QPoint(2,1) << QPoint(3,1) << QPoint(4,1) - ) - << 1; - QTest::newRow("(0,-50,20,90),rows") << QRect(0,-50,20,90) - << int(QAbstractItemView::ExtendedSelection) - << int(QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows) - << (PointList() - << QPoint(0,0) << QPoint(1,0) << QPoint(2,0) << QPoint(3,0) << QPoint(4,0) - << QPoint(0,1) << QPoint(1,1) << QPoint(2,1) << QPoint(3,1) << QPoint(4,1) - ) - << 1; - + const PointList pl1{QPoint(0, 0), QPoint(1, 0), QPoint(2, 0), QPoint(3, 0), QPoint(4, 0)}; + const PointList pl2{QPoint(0, 0), QPoint(1, 0), QPoint(2, 0), QPoint(3, 0), QPoint(4, 0), + QPoint(0, 1), QPoint(1, 1), QPoint(2, 1), QPoint(3, 1), QPoint(4, 1)}; + const QItemSelectionModel::SelectionFlags selFlags(QItemSelectionModel::ClearAndSelect | + QItemSelectionModel::Rows); + QTest::newRow("(0,0,50,20),rows") + << QRect(0, 0, 50, 20) + << QAbstractItemView::SingleSelection + << selFlags << pl1 << 0; + + QTest::newRow("(0,0,50,90),rows") + << QRect(0, 0, 50, 90) + << QAbstractItemView::ExtendedSelection + << selFlags << pl2 << 0; + + QTest::newRow("(50,0,0,90),rows,invalid rect") + << QRect(QPoint(50, 0), QPoint(0, 90)) + << QAbstractItemView::ExtendedSelection + << selFlags << pl2 << 0; + + QTest::newRow("(0,-20,20,50),rows") + << QRect(0, -20, 20, 50) + << QAbstractItemView::ExtendedSelection + << selFlags << pl2 << 1; + QTest::newRow("(0,-50,20,90),rows") + << QRect(0, -50, 20, 90) + << QAbstractItemView::ExtendedSelection + << selFlags << pl2 << 1; } void tst_QTreeView::setSelection() { QFETCH(QRect, selectionRect); - QFETCH(int, selectionMode); - QFETCH(int, selectionCommand); + QFETCH(QAbstractItemView::SelectionMode, selectionMode); + QFETCH(QItemSelectionModel::SelectionFlags, selectionCommand); QFETCH(PointList, expectedItems); QFETCH(int, verticalOffset); @@ -2016,25 +2010,23 @@ void tst_QTreeView::setSelection() view.show(); view.setRootIsDecorated(false); view.setItemDelegate(new TestDelegate(&view)); - view.setSelectionMode(QAbstractItemView::SelectionMode(selectionMode)); + view.setSelectionMode(selectionMode); view.setModel(&model); view.setUniformRowHeights(true); view.setVerticalScrollMode(QAbstractItemView::ScrollPerItem); view.scrollTo(model.index(verticalOffset, 0), QAbstractItemView::PositionAtTop); - view.setSelection(selectionRect, QItemSelectionModel::SelectionFlags(selectionCommand)); + view.setSelection(selectionRect, selectionCommand); QItemSelectionModel *selectionModel = view.selectionModel(); QVERIFY(selectionModel); - QModelIndexList selectedIndexes = selectionModel->selectedIndexes(); + const QModelIndexList selectedIndexes = selectionModel->selectedIndexes(); #ifdef Q_OS_WINRT QEXPECT_FAIL("(0,-20,20,50),rows", "Fails on WinRT - QTBUG-68297", Abort); QEXPECT_FAIL("(0,-50,20,90),rows", "Fails on WinRT - QTBUG-68297", Abort); #endif QCOMPARE(selectedIndexes.count(), expectedItems.count()); - for (int i = 0; i < selectedIndexes.count(); ++i) { - QModelIndex idx = selectedIndexes.at(i); + for (const QModelIndex &idx : selectedIndexes) QVERIFY(expectedItems.contains(QPoint(idx.column(), idx.row()))); - } } void tst_QTreeView::indexAbove() @@ -2134,7 +2126,7 @@ void tst_QTreeView::clicked() QModelIndex index = view.indexAt(p); if (!index.isValid()) continue; - QSignalSpy spy(&view, SIGNAL(clicked(QModelIndex))); + QSignalSpy spy(&view, &QTreeView::clicked); QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, p); QTRY_COMPARE(spy.count(), 1); } @@ -2149,9 +2141,9 @@ void tst_QTreeView::mouseDoubleClick() for (int i = 0; i < model.rowCount(); i++) { QModelIndex index = model.index(i, 0, QModelIndex()); model.insertRows(0, 20, index); - model.insertColumns(0,2,index); + model.insertColumns(0, 2,index); for (int i1 = 0; i1 < model.rowCount(index); i1++) { - (void)model.index(i1, 0, index); + QVERIFY(model.index(i1, 0, index).isValid()); } } @@ -2159,8 +2151,8 @@ void tst_QTreeView::mouseDoubleClick() view.setModel(&model); // make sure the viewport height is smaller than the contents height. - view.resize(200,200); - view.move(0,0); + view.resize(200, 200); + view.move(0, 0); view.show(); QModelIndex index = model.index(0, 0, QModelIndex()); view.setCurrentIndex(index); @@ -2170,9 +2162,8 @@ void tst_QTreeView::mouseDoubleClick() view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); // Make sure all items are collapsed - for (int i = 0; i < model.rowCount(QModelIndex()); i++) { - view.setExpanded(model.index(i,0, QModelIndex()), false); - } + for (int i = 0; i < model.rowCount(QModelIndex()); i++) + view.setExpanded(model.index(i, 0, QModelIndex()), false); int maximum = view.verticalScrollBar()->maximum(); @@ -2210,14 +2201,13 @@ void tst_QTreeView::rowsAboutToBeRemoved() view.setCurrentIndex(index); view.setExpanded(model.index(0,0, QModelIndex()), true); - for (int i = 0; i < model.rowCount(QModelIndex()); i++) { - view.setExpanded(model.index(i,0, QModelIndex()), true); - } + for (int i = 0; i < model.rowCount(QModelIndex()); i++) + view.setExpanded(model.index(i, 0, QModelIndex()), true); - QSignalSpy spy1(&model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int))); + QSignalSpy spy1(&model, &QAbstractItemModel::rowsAboutToBeRemoved); model.removeRows(1,1); - QCOMPARE(int(view.state()), 0); + QCOMPARE((view.state()), 0); // Should not be 5 (or any other number for that sake :) QCOMPARE(spy1.count(), 1); @@ -2241,8 +2231,7 @@ void tst_QTreeView::headerSections_unhideSection() void tst_QTreeView::columnAt() { - QtTestModel model; - model.rows = model.cols = 10; + QtTestModel model(10, 10); QTreeView view; view.resize(500,500); view.setModel(&model); @@ -2256,8 +2245,7 @@ void tst_QTreeView::scrollTo() #define CHECK_VISIBLE(ROW,COL) QVERIFY(QRect(QPoint(),view.viewport()->size()).contains(\ view.visualRect(model.index((ROW),(COL),QModelIndex())))) - QtTestModel model; - model.rows = model.cols = 100; + QtTestModel model(100, 100); QTreeView view; view.setUniformRowHeights(true); view.scrollTo(QModelIndex(), QTreeView::PositionAtTop); @@ -2268,19 +2256,18 @@ void tst_QTreeView::scrollTo() // ### create a data function for this test view.scrollTo(QModelIndex()); - view.scrollTo(model.index(0,0,QModelIndex())); - view.scrollTo(model.index(0,0,QModelIndex()), QTreeView::PositionAtTop); - view.scrollTo(model.index(0,0,QModelIndex()), QTreeView::PositionAtBottom); - - // + view.scrollTo(model.index(0, 0, QModelIndex())); + view.scrollTo(model.index(0, 0, QModelIndex()), QTreeView::PositionAtTop); + view.scrollTo(model.index(0, 0, QModelIndex()), QTreeView::PositionAtBottom); view.show(); view.setVerticalScrollMode(QAbstractItemView::ScrollPerItem); //some styles change that in Polish - view.resize(300, 200); + + QVERIFY(QTest::qWaitForWindowExposed(&view)); //view.verticalScrollBar()->setValue(0); - view.scrollTo(model.index(0,0,QModelIndex())); + view.scrollTo(model.index(0, 0, QModelIndex())); CHECK_VISIBLE(0,0); QCOMPARE(view.verticalScrollBar()->value(), 0); @@ -2305,22 +2292,23 @@ void tst_QTreeView::rowsAboutToBeRemoved_move() QTreeView view; view.setModel(&model); QModelIndex indexThatWantsToLiveButWillDieDieITellYou; - QModelIndex parent = model.index(2, 0 ); + QModelIndex parent = model.index(2, 0); view.expand(parent); for (int i = 0; i < 6; ++i) { model.insertRows(0, 1, parent); model.insertColumns(0, 1, parent); QModelIndex index = model.index(0, 0, parent); view.expand(index); - if ( i == 3 ) + if (i == 3) indexThatWantsToLiveButWillDieDieITellYou = index; model.setData(index, i); parent = index; } view.resize(600,800); view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); view.doItemsLayout(); - static_cast<QTreeView *>(&view)->executeDelayedItemsLayout(); + view.executeDelayedItemsLayout(); parent = indexThatWantsToLiveButWillDieDieITellYou.parent(); QCOMPARE(view.isExpanded(indexThatWantsToLiveButWillDieDieITellYou), true); QCOMPARE(parent.isValid(), true); @@ -2354,7 +2342,8 @@ void tst_QTreeView::resizeColumnToContents() QTreeView view; view.setModel(&model); view.show(); - qApp->processEvents(); //must have this, or else it will not scroll + QVERIFY(QTest::qWaitForWindowExposed(&view)); + view.scrollToBottom(); view.resizeColumnToContents(0); int oldColumnSize = view.header()->sectionSize(0); @@ -2365,11 +2354,12 @@ void tst_QTreeView::resizeColumnToContents() void tst_QTreeView::insertAfterSelect() { - QtTestModel model; - model.rows = model.cols = 10; + QtTestModel model(10, 10); QTreeView view; view.setModel(&model); view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + QModelIndex firstIndex = model.index(0, 0, QModelIndex()); QVERIFY(firstIndex.isValid()); int itemOffset = view.visualRect(firstIndex).width() / 2; @@ -2382,11 +2372,12 @@ void tst_QTreeView::insertAfterSelect() void tst_QTreeView::removeAfterSelect() { - QtTestModel model; - model.rows = model.cols = 10; + QtTestModel model(10, 10); QTreeView view; view.setModel(&model); view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + QModelIndex firstIndex = model.index(0, 0, QModelIndex()); QVERIFY(firstIndex.isValid()); int itemOffset = view.visualRect(firstIndex).width() / 2; @@ -2399,17 +2390,17 @@ void tst_QTreeView::removeAfterSelect() void tst_QTreeView::hiddenItems() { - QtTestModel model; - model.rows = model.cols = 10; + QtTestModel model(10, 10); QTreeView view; view.setModel(&model); view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); QModelIndex firstIndex = model.index(1, 0, QModelIndex()); QVERIFY(firstIndex.isValid()); if (model.canFetchMore(firstIndex)) model.fetchMore(firstIndex); - for (int i=0; i < model.rowCount(firstIndex); i++) + for (int i = 0; i < model.rowCount(firstIndex); i++) view.setRowHidden(i , firstIndex, true ); int itemOffset = view.visualRect(firstIndex).width() / 2; @@ -2419,18 +2410,18 @@ void tst_QTreeView::hiddenItems() QTest::mouseDClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, p); QCOMPARE(view.isExpanded(firstIndex), false); - p.setX( 5 ); + p.setX(5); QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, p); QCOMPARE(view.isExpanded(firstIndex), false); } void tst_QTreeView::spanningItems() { - QtTestModel model; - model.rows = model.cols = 10; + QtTestModel model(10, 10); QTreeView view; view.setModel(&model); view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); int itemWidth = view.header()->sectionSize(0); int itemHeight = view.visualRect(model.index(0, 0, QModelIndex())).height(); @@ -2470,7 +2461,7 @@ void tst_QTreeView::spanningItems() void tst_QTreeView::selectionOrderTest() { - QVERIFY(((QItemSelectionModel*)sender())->currentIndex().row() != -1); + QVERIFY(static_cast<QItemSelectionModel*>(sender())->currentIndex().row() != -1); } void tst_QTreeView::selection() @@ -2489,12 +2480,11 @@ void tst_QTreeView::selection() treeView.setSelectionBehavior(QAbstractItemView::SelectRows); treeView.setSelectionMode(QAbstractItemView::ExtendedSelection); - connect(treeView.selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), - this, SLOT(selectionOrderTest())); - - treeView.show(); + connect(treeView.selectionModel(), &QItemSelectionModel::selectionChanged, + this, &tst_QTreeView::selectionOrderTest); - QTest::mousePress(treeView.viewport(), Qt::LeftButton, 0, treeView.visualRect(m.index(1, 0)).center()); + QTest::mousePress(treeView.viewport(), Qt::LeftButton, {}, + treeView.visualRect(m.index(1, 0)).center()); QTest::keyPress(treeView.viewport(), Qt::Key_Down); auto selectedRows = treeView.selectionModel()->selectedRows(); QCOMPARE(selectedRows.size(), 1); @@ -2509,23 +2499,21 @@ void tst_QTreeView::selection() void tst_QTreeView::selectionWithHiddenItems() { QStandardItemModel model; - for (int i = 0; i < model.rowCount(); ++i) - model.setData(model.index(i,0), QLatin1String("row ") + QString::number(i)); QStandardItem item0("row 0"); QStandardItem item1("row 1"); QStandardItem item2("row 2"); QStandardItem item3("row 3"); - model.appendColumn( QList<QStandardItem*>() << &item0 << &item1 << &item2 << &item3); + model.appendColumn({&item0, &item1, &item2, &item3}); QStandardItem child("child"); - item1.appendRow( &child); + item1.appendRow(&child); QTreeView view; view.setModel(&model); view.setSelectionMode(QAbstractItemView::ExtendedSelection); view.show(); - qApp->processEvents(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); //child should not be selected as it is hidden (its parent is not expanded) view.selectAll(); @@ -2548,12 +2536,11 @@ void tst_QTreeView::selectionWithHiddenItems() //we hide the node with a child (there should then be 3 items selected in 2 ranges) view.setRowHidden(1, QModelIndex(), true); QVERIFY(view.isExpanded(item1.index())); - qApp->processEvents(); view.selectAll(); QCOMPARE(view.selectionModel()->selection().count(), 2); QCOMPARE(view.selectionModel()->selectedRows().count(), 3); - QVERIFY( !view.selectionModel()->isSelected(model.indexFromItem(&item1))); - QVERIFY( !view.selectionModel()->isSelected(model.indexFromItem(&child))); + QVERIFY(!view.selectionModel()->isSelected(model.indexFromItem(&item1))); + QVERIFY(!view.selectionModel()->isSelected(model.indexFromItem(&child))); view.setRowHidden(1, QModelIndex(), false); QVERIFY(view.isExpanded(item1.index())); @@ -2561,7 +2548,6 @@ void tst_QTreeView::selectionWithHiddenItems() //we hide a node without children (there should then be 4 items selected in 3 ranges) view.setRowHidden(2, QModelIndex(), true); - qApp->processEvents(); QVERIFY(view.isExpanded(item1.index())); view.selectAll(); QVERIFY(view.isExpanded(item1.index())); @@ -2575,7 +2561,7 @@ void tst_QTreeView::selectionWithHiddenItems() void tst_QTreeView::selectAll() { - QStandardItemModel model(4,4); + QStandardItemModel model(4, 4); QTreeView view2; view2.setModel(&model); view2.setSelectionMode(QAbstractItemView::ExtendedSelection); @@ -2619,7 +2605,8 @@ void tst_QTreeView::extendedSelection() view.setModel(&model); view.setSelectionMode(QAbstractItemView::ExtendedSelection); topLevel.show(); - QTest::mousePress(view.viewport(), Qt::LeftButton, 0, mousePressPos); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + QTest::mousePress(view.viewport(), Qt::LeftButton, {}, mousePressPos); QCOMPARE(view.selectionModel()->selectedIndexes().count(), selectedCount); } @@ -2627,21 +2614,22 @@ void tst_QTreeView::rowSizeHint() { //tests whether the correct visible columns are taken into account when //calculating the height of a line - QStandardItemModel model(1,3); - model.setData( model.index(0,0), QSize(20,40), Qt::SizeHintRole); - model.setData( model.index(0,1), QSize(20,10), Qt::SizeHintRole); - model.setData( model.index(0,2), QSize(20,10), Qt::SizeHintRole); + QStandardItemModel model(1, 3); + model.setData(model.index(0, 0), QSize(20, 40), Qt::SizeHintRole); + model.setData(model.index(0, 1), QSize(20, 10), Qt::SizeHintRole); + model.setData(model.index(0, 2), QSize(20, 10), Qt::SizeHintRole); QTreeView view; view.setModel(&model); view.header()->moveSection(1, 0); //the 2nd column goes to the 1st place view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); //it must be 40 since the tallest item that defines the height of a line - QCOMPARE( view.visualRect(model.index(0,0)).height(), 40); - QCOMPARE( view.visualRect(model.index(0,1)).height(), 40); - QCOMPARE( view.visualRect(model.index(0,2)).height(), 40); + QCOMPARE(view.visualRect(model.index(0,0)).height(), 40); + QCOMPARE(view.visualRect(model.index(0,1)).height(), 40); + QCOMPARE(view.visualRect(model.index(0,2)).height(), 40); } @@ -2651,7 +2639,7 @@ void tst_QTreeView::rowSizeHint() void tst_QTreeView::setSortingEnabledTopLevel() { QTreeView view; - QStandardItemModel model(1,1); + QStandardItemModel model(1, 1); view.setModel(&model); const int size = view.header()->sectionSize(0); view.setSortingEnabled(true); @@ -2665,7 +2653,7 @@ void tst_QTreeView::setSortingEnabledChild() QMainWindow win; QTreeView view; // two columns to not get in trouble with stretchLastSection - QStandardItemModel model(1,2); + QStandardItemModel model(1, 2); view.setModel(&model); view.header()->setDefaultSectionSize(92); win.setCentralWidget(&view); @@ -2690,16 +2678,18 @@ void tst_QTreeView::headerHidden() class TestTreeViewStyle : public QProxyStyle { + Q_OBJECT public: - TestTreeViewStyle() : indentation(20) {} - int pixelMetric(PixelMetric metric, const QStyleOption *option = 0, const QWidget *widget = 0) const override + using QProxyStyle::QProxyStyle; + int pixelMetric(PixelMetric metric, const QStyleOption *option = nullptr, + const QWidget *widget = nullptr) const override { if (metric == QStyle::PM_TreeViewIndentation) return indentation; else return QProxyStyle::pixelMetric(metric, option, widget); } - int indentation; + int indentation = 20; }; void tst_QTreeView::indentation() @@ -2745,7 +2735,7 @@ void tst_QTreeView::removeAndInsertExpandedCol0() model.insertColumns(0, 1); view.show(); - qApp->processEvents(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); } void tst_QTreeView::disabledButCheckable() @@ -2782,7 +2772,7 @@ void tst_QTreeView::sortByColumn() { QFETCH(bool, sortingEnabled); QTreeView view; - QStandardItemModel model(4,2); + QStandardItemModel model(4, 2); QSortFilterProxyModel sfpm; // default QStandardItemModel does not support 'unsorted' state sfpm.setSourceModel(&model); model.setItem(0, 0, new QStandardItem("b")); @@ -2825,11 +2815,13 @@ void tst_QTreeView::sortByColumn() */ class EvilModel: public QAbstractItemModel { - + Q_OBJECT public: - class Node { + class Node + { public: - Node(Node *p = 0, int level = 0) : parent(p), isDead(false) { + Node(Node *p = nullptr, int level = 0) : parent(p) + { populate(level); } ~Node() @@ -2838,20 +2830,23 @@ public: qDeleteAll(deadChildren.begin(), deadChildren.end()); } - void populate(int level = 0) { - if (level < 4) + void populate(int level = 0) + { + if (level < 4) { for (int i = 0; i < 5; ++i) children.append(new Node(this, level + 1)); + } } - void kill() { + void kill() + { for (int i = children.count() -1; i >= 0; --i) { children.at(i)->kill(); - if (parent == 0) { + if (parent == nullptr) { deadChildren.append(children.at(i)); children.removeAt(i); } } - if (parent == 0) { + if (parent == nullptr) { if (!children.isEmpty()) qFatal("%s: children should be empty when parent is null", Q_FUNC_INFO); populate(); @@ -2860,17 +2855,16 @@ public: } } - QList<Node*> children; - QList<Node*> deadChildren; + QVector<Node *> children; + QVector<Node *> deadChildren; Node *parent; - bool isDead; + bool isDead = false; }; Node *root; - EvilModel(QObject *parent = 0): QAbstractItemModel(parent), root(new Node) - { - } + EvilModel(QObject *parent = nullptr): QAbstractItemModel(parent), root(new Node) + {} ~EvilModel() { delete root; @@ -2880,7 +2874,7 @@ public: { emit layoutAboutToBeChanged(); QModelIndexList oldList = persistentIndexList(); - QList<QStack<int> > oldListPath; + QVector<QStack<int>> oldListPath; for (int i = 0; i < oldList.count(); ++i) { QModelIndex idx = oldList.at(i); QStack<int> path; @@ -2893,12 +2887,10 @@ public: root->kill(); QModelIndexList newList; - for (int i = 0; i < oldListPath.count(); ++i) { - QStack<int> path = oldListPath[i]; + for (auto path : qAsConst(oldListPath)) { QModelIndex idx; - while(!path.isEmpty()) { + while (!path.isEmpty()) idx = index(path.pop(), 0, idx); - } newList.append(idx); } @@ -2906,7 +2898,8 @@ public: emit layoutChanged(); } - int rowCount(const QModelIndex& parent = QModelIndex()) const { + int rowCount(const QModelIndex &parent = QModelIndex()) const override + { Node *parentNode = root; if (parent.isValid()) { parentNode = static_cast<Node*>(parent.internalPointer()); @@ -2915,13 +2908,12 @@ public: } return parentNode->children.count(); } - int columnCount(const QModelIndex& parent = QModelIndex()) const { - if (parent.column() > 0) - return 0; - return 1; + int columnCount(const QModelIndex &parent = QModelIndex()) const override + { + return parent.column() > 0 ? 0 : 1; } - QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override { Node *grandparentNode = static_cast<Node*>(parent.internalPointer()); Node *parentNode = root; @@ -2935,7 +2927,7 @@ public: return createIndex(row, column, parentNode); } - QModelIndex parent(const QModelIndex &index) const + QModelIndex parent(const QModelIndex &index) const override { Node *parent = static_cast<Node*>(index.internalPointer()); Node *grandparent = parent->parent; @@ -2944,7 +2936,7 @@ public: return createIndex(grandparent->children.indexOf(parent), 0, grandparent); } - QVariant data(const QModelIndex &idx, int role) const + QVariant data(const QModelIndex &idx, int role) const override { if (idx.isValid() && role == Qt::DisplayRole) { Node *parentNode = root; @@ -2987,7 +2979,6 @@ void tst_QTreeView::evilModel() view.setRowHidden(0, firstLevel, true); model.change(); - return; view.setFirstColumnSpanned(1, QModelIndex(), true); model.change(); @@ -3167,7 +3158,7 @@ void tst_QTreeView::filterProxyModelCrash() QTreeView view; view.setModel(&proxy); view.show(); - QTest::qWait(30); + QVERIFY(QTest::qWaitForWindowExposed(&view)); proxy.invalidate(); view.verticalScrollBar()->setValue(15); QTest::qWait(20); @@ -3190,7 +3181,7 @@ void tst_QTreeView::renderToPixmap() QStandardItemModel model; model.appendRow(new QStandardItem("Spanning")); - model.appendRow(QList<QStandardItem*>() << new QStandardItem("Not") << new QStandardItem("Spanning")); + model.appendRow({ new QStandardItem("Not"), new QStandardItem("Spanning") }); view.setModel(&model); view.setFirstColumnSpanned(0, QModelIndex(), true); @@ -3211,57 +3202,60 @@ void tst_QTreeView::styleOptionViewItem() { class MyDelegate : public QStyledItemDelegate { - static QString posToString(QStyleOptionViewItem::ViewItemPosition pos) { + static QString posToString(QStyleOptionViewItem::ViewItemPosition pos) + { static const char* s_pos[] = { "Invalid", "Beginning", "Middle", "End", "OnlyOne" }; return s_pos[pos]; } public: - MyDelegate() - : QStyledItemDelegate(), - count(0), - allCollapsed(false) - {} - - void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const - { - QStyleOptionViewItem opt(option); - initStyleOption(&opt, index); + using QStyledItemDelegate::QStyledItemDelegate; + void paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const override + { + QStyleOptionViewItem opt(option); + initStyleOption(&opt, index); - QVERIFY(!opt.text.isEmpty()); - QCOMPARE(opt.index, index); - //qDebug() << index << opt.text; + QVERIFY(!opt.text.isEmpty()); + QCOMPARE(opt.index, index); + //qDebug() << index << opt.text; - if (allCollapsed) - QCOMPARE(!(opt.features & QStyleOptionViewItem::Alternate), !(index.row() % 2)); - QCOMPARE(!(opt.features & QStyleOptionViewItem::HasCheckIndicator), !opt.text.contains("Checkable")); + if (allCollapsed) { + QCOMPARE(!opt.features.testFlag(QStyleOptionViewItem::Alternate), + !(index.row() % 2)); + } + QCOMPARE(!opt.features.testFlag(QStyleOptionViewItem::HasCheckIndicator), + !opt.text.contains("Checkable")); - if (opt.text.contains("Beginning")) - QCOMPARE(posToString(opt.viewItemPosition), posToString(QStyleOptionViewItem::Beginning)); + const QString posStr(posToString(opt.viewItemPosition)); + if (opt.text.contains("Beginning")) + QCOMPARE(posStr, posToString(QStyleOptionViewItem::Beginning)); - if (opt.text.contains("Middle")) - QCOMPARE(posToString(opt.viewItemPosition), posToString(QStyleOptionViewItem::Middle)); + if (opt.text.contains("Middle")) + QCOMPARE(posStr, posToString(QStyleOptionViewItem::Middle)); - if (opt.text.contains("End")) - QCOMPARE(posToString(opt.viewItemPosition), posToString(QStyleOptionViewItem::End)); + if (opt.text.contains("End")) + QCOMPARE(posStr, posToString(QStyleOptionViewItem::End)); - if (opt.text.contains("OnlyOne")) - QCOMPARE(posToString(opt.viewItemPosition), posToString(QStyleOptionViewItem::OnlyOne)); + if (opt.text.contains("OnlyOne")) + QCOMPARE(posStr, posToString(QStyleOptionViewItem::OnlyOne)); - if (opt.text.contains("Checked")) - QCOMPARE(opt.checkState, Qt::Checked); - else - QCOMPARE(opt.checkState, Qt::Unchecked); + if (opt.text.contains("Checked")) + QCOMPARE(opt.checkState, Qt::Checked); + else + QCOMPARE(opt.checkState, Qt::Unchecked); - QCOMPARE(!(opt.state & QStyle::State_Children) , !opt.text.contains("HasChildren")); - QCOMPARE(!!(opt.state & QStyle::State_Sibling) , !opt.text.contains("Last")); + QCOMPARE(!opt.state.testFlag(QStyle::State_Children), + !opt.text.contains("HasChildren")); + QCOMPARE(opt.state.testFlag(QStyle::State_Sibling), + !opt.text.contains("Last")); - QVERIFY(!opt.text.contains("Assert")); + QVERIFY(!opt.text.contains("Assert")); - QStyledItemDelegate::paint(painter, option, index); - count++; - } - mutable int count; - bool allCollapsed; + QStyledItemDelegate::paint(painter, option, index); + count++; + } + mutable int count = 0; + bool allCollapsed = false; }; QTreeView view; @@ -3269,39 +3263,68 @@ void tst_QTreeView::styleOptionViewItem() view.setModel(&model); MyDelegate delegate; view.setItemDelegate(&delegate); - model.appendRow(QList<QStandardItem*>() - << new QStandardItem("Beginning") << new QStandardItem("Hidden") << new QStandardItem("Middle") << new QStandardItem("Middle") << new QStandardItem("End") ); + model.appendRow({ new QStandardItem("Beginning"), + new QStandardItem("Hidden"), + new QStandardItem("Middle"), + new QStandardItem("Middle"), + new QStandardItem("End") }); QStandardItem *par1 = new QStandardItem("Beginning HasChildren"); - model.appendRow(QList<QStandardItem*>() - << par1 << new QStandardItem("Hidden") << new QStandardItem("Middle HasChildren") << new QStandardItem("Middle HasChildren") << new QStandardItem("End HasChildren") ); - model.appendRow(QList<QStandardItem*>() - << new QStandardItem("OnlyOne") << new QStandardItem("Hidden") << new QStandardItem("Assert") << new QStandardItem("Assert") << new QStandardItem("Assert") ); + model.appendRow({ par1, + new QStandardItem("Hidden"), + new QStandardItem("Middle HasChildren"), + new QStandardItem("Middle HasChildren"), + new QStandardItem("End HasChildren") }); + model.appendRow({ new QStandardItem("OnlyOne"), + new QStandardItem("Hidden"), + new QStandardItem("Assert"), + new QStandardItem("Assert"), + new QStandardItem("Assert") }); QStandardItem *checkable = new QStandardItem("Checkable"); checkable->setCheckable(true); QStandardItem *checked = new QStandardItem("Checkable Checked"); checked->setCheckable(true); checked->setCheckState(Qt::Checked); - model.appendRow(QList<QStandardItem*>() - << new QStandardItem("Beginning") << new QStandardItem("Hidden") << checkable << checked << new QStandardItem("End") ); - model.appendRow(QList<QStandardItem*>() - << new QStandardItem("Beginning Last") << new QStandardItem("Hidden") << new QStandardItem("Middle Last") << new QStandardItem("Middle Last") << new QStandardItem("End Last") ); - - par1->appendRow(QList<QStandardItem*>() - << new QStandardItem("Beginning") << new QStandardItem("Hidden") << new QStandardItem("Middle") << new QStandardItem("Middle") << new QStandardItem("End") ); + model.appendRow({ new QStandardItem("Beginning"), + new QStandardItem("Hidden"), + checkable, checked, + new QStandardItem("End") }); + model.appendRow({ new QStandardItem("Beginning Last"), + new QStandardItem("Hidden"), + new QStandardItem("Middle Last"), + new QStandardItem("Middle Last"), + new QStandardItem("End Last") }); + par1->appendRow({ new QStandardItem("Beginning"), + new QStandardItem("Hidden"), + new QStandardItem("Middle"), + new QStandardItem("Middle"), + new QStandardItem("End") }); QStandardItem *par2 = new QStandardItem("Beginning HasChildren"); - par1->appendRow(QList<QStandardItem*>() - << par2 << new QStandardItem("Hidden") << new QStandardItem("Middle HasChildren") << new QStandardItem("Middle HasChildren") << new QStandardItem("End HasChildren") ); - par2->appendRow(QList<QStandardItem*>() - << new QStandardItem("Beginning Last") << new QStandardItem("Hidden") << new QStandardItem("Middle Last") << new QStandardItem("Middle Last") << new QStandardItem("End Last") ); - + par1->appendRow({ par2, + new QStandardItem("Hidden"), + new QStandardItem("Middle HasChildren"), + new QStandardItem("Middle HasChildren"), + new QStandardItem("End HasChildren") }); + par2->appendRow({ new QStandardItem("Beginning Last"), + new QStandardItem("Hidden"), + new QStandardItem("Middle Last"), + new QStandardItem("Middle Last"), + new QStandardItem("End Last") }); QStandardItem *par3 = new QStandardItem("Beginning Last"); - par1->appendRow(QList<QStandardItem*>() - << par3 << new QStandardItem("Hidden") << new QStandardItem("Middle Last") << new QStandardItem("Middle Last") << new QStandardItem("End Last") ); - par3->appendRow(QList<QStandardItem*>() - << new QStandardItem("Assert") << new QStandardItem("Hidden") << new QStandardItem("Assert") << new QStandardItem("Assert") << new QStandardItem("Asser") ); + par1->appendRow({ par3, new QStandardItem("Hidden"), + new QStandardItem("Middle Last"), + new QStandardItem("Middle Last"), + new QStandardItem("End Last") }); + par3->appendRow({ new QStandardItem("Assert"), + new QStandardItem("Hidden"), + new QStandardItem("Assert"), + new QStandardItem("Assert"), + new QStandardItem("Asser") }); view.setRowHidden(0, par3->index(), true); - par1->appendRow(QList<QStandardItem*>() - << new QStandardItem("Assert") << new QStandardItem("Hidden") << new QStandardItem("Assert") << new QStandardItem("Assert") << new QStandardItem("Asser") ); + par1->appendRow({ new QStandardItem("Assert"), + new QStandardItem("Hidden"), + new QStandardItem("Assert"), + new QStandardItem("Assert"), + new QStandardItem("Asser") }); view.setRowHidden(3, par1->index(), true); view.setColumnHidden(1, true); @@ -3331,16 +3354,14 @@ void tst_QTreeView::styleOptionViewItem() delegate.count = 0; delegate.allCollapsed = true; view.showMaximized(); - QApplication::processEvents(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); QTRY_VERIFY(delegate.count >= 13); delegate.count = 0; delegate.allCollapsed = false; view.expandAll(); - QApplication::processEvents(); QTRY_VERIFY(delegate.count >= 13); delegate.count = 0; view.collapse(par2->index()); - QApplication::processEvents(); QTRY_VERIFY(delegate.count >= 4); // test that the rendering of drag pixmap sets the correct options too (QTBUG-15834) @@ -3360,96 +3381,73 @@ void tst_QTreeView::styleOptionViewItem() delegate.count = 0; QStandardItemModel model2; QStandardItem *item0 = new QStandardItem("OnlyOne Last"); - model2.appendRow(QList<QStandardItem*>() << item0); + model2.appendRow(item0); view.setModel(&model2); - QApplication::processEvents(); QTRY_VERIFY(delegate.count >= 1); - QApplication::processEvents(); QStandardItem *item00 = new QStandardItem("OnlyOne Last"); - item0->appendRow(QList<QStandardItem*>() << item00); + item0->appendRow(item00); item0->setText("OnlyOne Last HasChildren"); - QApplication::processEvents(); delegate.count = 0; view.expandAll(); - QApplication::processEvents(); QTRY_VERIFY(delegate.count >= 2); - QApplication::processEvents(); QStandardItem *item1 = new QStandardItem("OnlyOne Last"); delegate.count = 0; item0->setText("OnlyOne HasChildren"); - model2.appendRow(QList<QStandardItem*>() << item1); - QApplication::processEvents(); + model2.appendRow(item1); QTRY_VERIFY(delegate.count >= 3); - QApplication::processEvents(); QStandardItem *item01 = new QStandardItem("OnlyOne Last"); delegate.count = 0; item00->setText("OnlyOne"); - item0->appendRow(QList<QStandardItem*>() << item01); - QApplication::processEvents(); + item0->appendRow(item01); QTRY_VERIFY(delegate.count >= 4); - QApplication::processEvents(); QStandardItem *item000 = new QStandardItem("OnlyOne Last"); delegate.count = 0; item00->setText("OnlyOne HasChildren"); - item00->appendRow(QList<QStandardItem*>() << item000); - QApplication::processEvents(); + item00->appendRow(item000); QTRY_VERIFY(delegate.count >= 5); - QApplication::processEvents(); delegate.count = 0; item0->removeRow(0); - QApplication::processEvents(); QTRY_VERIFY(delegate.count >= 3); - QApplication::processEvents(); item00 = new QStandardItem("OnlyOne"); - item0->insertRow(0, QList<QStandardItem*>() << item00); - QApplication::processEvents(); + item0->insertRow(0, item00); + delegate.count = 0; view.expandAll(); - QApplication::processEvents(); QTRY_VERIFY(delegate.count >= 4); - QApplication::processEvents(); delegate.count = 0; item0->removeRow(1); item00->setText("OnlyOne Last"); - QApplication::processEvents(); QTRY_VERIFY(delegate.count >= 3); - QApplication::processEvents(); delegate.count = 0; item0->removeRow(0); item0->setText("OnlyOne"); - QApplication::processEvents(); QTRY_VERIFY(delegate.count >= 2); - QApplication::processEvents(); //with hidden items item0->setText("OnlyOne HasChildren"); item00 = new QStandardItem("OnlyOne"); - item0->appendRow(QList<QStandardItem*>() << item00); + item0->appendRow(item00); item01 = new QStandardItem("Assert"); - item0->appendRow(QList<QStandardItem*>() << item01); + item0->appendRow(item01); view.setRowHidden(1, item0->index(), true); view.expandAll(); QStandardItem *item02 = new QStandardItem("OnlyOne Last"); - item0->appendRow(QList<QStandardItem*>() << item02); + item0->appendRow(item02); delegate.count = 0; - QApplication::processEvents(); QTRY_VERIFY(delegate.count >= 4); - QApplication::processEvents(); item0->removeRow(2); item00->setText("OnlyOne Last"); delegate.count = 0; - QApplication::processEvents(); QTRY_VERIFY(delegate.count >= 3); - QApplication::processEvents(); item00->setText("OnlyOne"); item0->insertRow(2, new QStandardItem("OnlyOne Last")); @@ -3457,13 +3455,11 @@ void tst_QTreeView::styleOptionViewItem() item0->removeRow(0); delegate.count = 0; QTRY_VERIFY(delegate.count >= 2); - QApplication::processEvents(); item0->removeRow(1); item0->setText("OnlyOne"); delegate.count = 0; QTRY_VERIFY(delegate.count >= 2); - QApplication::processEvents(); } } @@ -3471,10 +3467,10 @@ class task174627_TreeView : public QTreeView { Q_OBJECT protected slots: - void currentChanged(const QModelIndex ¤t, const QModelIndex &) - { emit currentChanged(current); } + void currentChanged(const QModelIndex ¤t, const QModelIndex &) override + { emit signalCurrentChanged(current); } signals: - void currentChanged(const QModelIndex &); + void signalCurrentChanged(const QModelIndex &); }; void tst_QTreeView::task174627_moveLeftToRoot() @@ -3490,7 +3486,7 @@ void tst_QTreeView::task174627_moveLeftToRoot() view.setRootIndex(item1->index()); view.setCurrentIndex(item2->index()); - QSignalSpy spy(&view, SIGNAL(currentChanged(QModelIndex))); + QSignalSpy spy(&view, &task174627_TreeView::signalCurrentChanged); QTest::keyClick(&view, Qt::Key_Left); QCOMPARE(spy.count(), 0); } @@ -3503,9 +3499,9 @@ void tst_QTreeView::task171902_expandWith1stColHidden() subitem("subitem"), subitem2("subitem"), subsubitem("subsubitem"), subsubitem2("subsubitem"); - model.appendRow( QList<QStandardItem *>() << &root << &root2); - root.appendRow( QList<QStandardItem *>() << &subitem << &subitem2); - subitem.appendRow( QList<QStandardItem *>() << &subsubitem << &subsubitem2); + model.appendRow({ &root, &root2 }); + root.appendRow({ &subitem, &subitem2 }); + subitem.appendRow({ &subsubitem, &subsubitem2 }); QTreeView view; view.setModel(&model); @@ -3523,18 +3519,18 @@ void tst_QTreeView::task171902_expandWith1stColHidden() void tst_QTreeView::task203696_hidingColumnsAndRowsn() { QTreeView view; - QStandardItemModel *model = new QStandardItemModel(0, 3, &view); + QStandardItemModel model(0, 3); for (int i = 0; i < 3; ++i) { const QString prefix = QLatin1String("row ") + QString::number(i) + QLatin1String(" col "); - model->insertRow(model->rowCount()); - for (int j = 0; j < model->columnCount(); ++j) - model->setData(model->index(i, j), prefix + QString::number(j)); + model.insertRow(model.rowCount()); + for (int j = 0; j < model.columnCount(); ++j) + model.setData(model.index(i, j), prefix + QString::number(j)); } - view.setModel(model); + view.setModel(&model); view.show(); view.setColumnHidden(0, true); view.setRowHidden(0, QModelIndex(), true); - QCOMPARE(view.indexAt(QPoint(0, 0)), model->index(1, 1)); + QCOMPARE(view.indexAt(QPoint(0, 0)), model.index(1, 1)); } @@ -3547,27 +3543,23 @@ void tst_QTreeView::addRowsWhileSectionsAreHidden() view.show(); QVERIFY(QTest::qWaitForWindowActive(&view)); - int i; - for (i = 0; i < 3; ++i) + for (int i = 0; i < 3; ++i) { model->insertRow(model->rowCount()); const QString prefix = QLatin1String("row ") + QString::number(i) + QLatin1String(" col "); - for (int j = 0; j < model->columnCount(); ++j) { + for (int j = 0; j < model->columnCount(); ++j) model->setData(model->index(i, j), prefix + QString::number(j)); - } } - int col; - for (col = 0; col < pass; ++col) + for (int col = 0; col < pass; ++col) view.setColumnHidden(col, true); - for (i = 3; i < 6; ++i) + for (int i = 3; i < 6; ++i) { model->insertRow(model->rowCount()); const QString prefix = QLatin1String("row ") + QString::number(i) + QLatin1String(" col "); - for (int j = 0; j < model->columnCount(); ++j) { + for (int j = 0; j < model->columnCount(); ++j) model->setData(model->index(i, j), prefix + QString::number(j)); - } } - for (col = 0; col < pass; ++col) + for (int col = 0; col < pass; ++col) view.setColumnHidden(col, false); auto allVisualRectsValid = [](QTreeView *view, QStandardItemModel *model) { @@ -3585,24 +3577,25 @@ void tst_QTreeView::addRowsWhileSectionsAreHidden() void tst_QTreeView::task216717_updateChildren() { - class Tree : public QTreeWidget { + class Tree : public QTreeWidget + { protected: - void paintEvent(QPaintEvent *e) + void paintEvent(QPaintEvent *e) override { QTreeWidget::paintEvent(e); - refreshed=true; + refreshed = true; } public: - bool refreshed; + bool refreshed = false; } tree; tree.show(); QVERIFY(QTest::qWaitForWindowExposed(&tree)); tree.refreshed = false; - QTreeWidgetItem *parent = new QTreeWidgetItem(QStringList() << "parent"); + QTreeWidgetItem *parent = new QTreeWidgetItem({ "parent" }); tree.addTopLevelItem(parent); QTRY_VERIFY(tree.refreshed); tree.refreshed = false; - parent->addChild(new QTreeWidgetItem(QStringList() << "child")); + parent->addChild(new QTreeWidgetItem({ "child" })); QTRY_VERIFY(tree.refreshed); } @@ -3611,13 +3604,14 @@ void tst_QTreeView::task220298_selectColumns() { //this is a very simple 3x3 model where the internalId of the index are different for each cell class Model : public QAbstractTableModel - { public: - virtual int columnCount ( const QModelIndex & parent = QModelIndex() ) const + { + public: + int columnCount(const QModelIndex & parent = QModelIndex()) const override { return parent.isValid() ? 0 : 3; } - virtual int rowCount ( const QModelIndex & parent = QModelIndex() ) const + int rowCount(const QModelIndex & parent = QModelIndex()) const override { return parent.isValid() ? 0 : 3; } - virtual QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const + QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override { if (role == Qt::DisplayRole) { return QVariant(QString::number(index.column()) + QLatin1Char('-') @@ -3626,18 +3620,21 @@ void tst_QTreeView::task220298_selectColumns() return QVariant(); } - virtual QModelIndex index ( int row, int column, const QModelIndex & parent = QModelIndex() ) const + QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const override { - return hasIndex(row, column, parent) ? createIndex(row, column, column*10+row) : QModelIndex(); + return hasIndex(row, column, parent) ? createIndex(row, column, quintptr(column * 10 + row)) : QModelIndex(); } }; - class TreeView : public QTreeView { public: QModelIndexList selectedIndexes () const { return QTreeView::selectedIndexes(); } } view; + class TreeView : public QTreeView { + public: + using QTreeView::selectedIndexes; + } view; Model model; view.setModel(&model); view.show(); QVERIFY(QTest::qWaitForWindowActive(&view)); - QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, + QTest::mouseClick(view.viewport(), Qt::LeftButton, {}, view.visualRect(view.model()->index(1, 1)).center()); QTRY_VERIFY(view.selectedIndexes().contains(view.model()->index(1, 2))); QVERIFY(view.selectedIndexes().contains(view.model()->index(1, 1))); @@ -3653,8 +3650,8 @@ void tst_QTreeView::task224091_appendColumns() QTreeView *treeView = new QTreeView(topLevel); treeView->setModel(model); topLevel->show(); - treeView->resize(50,50); - qApp->setActiveWindow(topLevel); + treeView->resize(50, 50); + QApplication::setActiveWindow(topLevel); QVERIFY(QTest::qWaitForWindowActive(topLevel)); QVERIFY(!treeView->verticalScrollBar()->isVisible()); @@ -3705,9 +3702,8 @@ void tst_QTreeView::task211293_removeRootIndex() view.setCurrentIndex(model.indexFromItem(E11314)); view.setExpanded(model.indexFromItem(E11314), true); view.show(); - qApp->processEvents(); - model.removeRows(0, 1); - qApp->processEvents(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + QVERIFY(model.removeRows(0, 1)); } void tst_QTreeView::task225539_deleteModel() @@ -3716,8 +3712,8 @@ void tst_QTreeView::task225539_deleteModel() treeView.show(); QStandardItemModel *model = new QStandardItemModel(&treeView); - QStandardItem* parentItem = model->invisibleRootItem(); - QStandardItem* item = new QStandardItem(QString("item")); + QStandardItem *parentItem = model->invisibleRootItem(); + QStandardItem *item = new QStandardItem(QString("item")); parentItem->appendRow(item); treeView.setModel(model); @@ -3767,7 +3763,7 @@ void tst_QTreeView::task230123_setItemsExpandable() QTest::keyClick(&tree, Qt::Key_Right); QVERIFY(root.isExpanded()); - const bool navToChild = tree.style()->styleHint(QStyle::SH_ItemView_ArrowKeysNavigateIntoChildren, 0, &tree); + const bool navToChild = tree.style()->styleHint(QStyle::SH_ItemView_ArrowKeysNavigateIntoChildren, nullptr, &tree); QTest::keyClick(&tree, Qt::Key_Right); QCOMPARE(tree.currentItem(), navToChild ? &child : &root); @@ -3784,13 +3780,13 @@ void tst_QTreeView::task230123_setItemsExpandable() void tst_QTreeView::task202039_closePersistentEditor() { - QStandardItemModel model(1,1); + QStandardItemModel model(1, 1); QTreeView view; view.setModel(&model); QModelIndex current = model.index(0,0); - QTest::mousePress(view.viewport(), Qt::LeftButton, 0, view.visualRect(current).center()); - QTest::mouseDClick(view.viewport(), Qt::LeftButton, 0, view.visualRect(current).center()); + QTest::mousePress(view.viewport(), Qt::LeftButton, {}, view.visualRect(current).center()); + QTest::mouseDClick(view.viewport(), Qt::LeftButton, {}, view.visualRect(current).center()); QCOMPARE(view.currentIndex(), current); QVERIFY(view.indexWidget(current)); @@ -3799,8 +3795,8 @@ void tst_QTreeView::task202039_closePersistentEditor() //here was the bug: closing the persistent editor would not reset the state //and it was impossible to go into editinon again - QTest::mousePress(view.viewport(), Qt::LeftButton, 0, view.visualRect(current).center()); - QTest::mouseDClick(view.viewport(), Qt::LeftButton, 0, view.visualRect(current).center()); + QTest::mousePress(view.viewport(), Qt::LeftButton, {}, view.visualRect(current).center()); + QTest::mouseDClick(view.viewport(), Qt::LeftButton, {}, view.visualRect(current).center()); QCOMPARE(view.currentIndex(), current); QVERIFY(view.indexWidget(current)); } @@ -3824,13 +3820,12 @@ void tst_QTreeView::task238873_avoidAutoReopening() view.expandAll(); QVERIFY(QTest::qWaitForWindowActive(&view)); - QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.visualRect(child.index()).center()); + QTest::mouseClick(view.viewport(), Qt::LeftButton, {}, view.visualRect(child.index()).center()); QTRY_COMPARE(view.currentIndex(), child.index()); view.setExpanded(item1.index(), false); - QTest::qWait(500); //enough to trigger the delayedAutoScroll timer - QVERIFY(!view.isExpanded(item1.index())); + QTRY_VERIFY(!view.isExpanded(item1.index())); } void tst_QTreeView::task244304_clickOnDecoration() @@ -3841,39 +3836,38 @@ void tst_QTreeView::task244304_clickOnDecoration() QStandardItem item00("row 0"); item0.appendRow(&item00); QStandardItem item1("row 1"); - model.appendColumn(QList<QStandardItem*>() << &item0 << &item1); + model.appendColumn({ &item0, &item1 }); view.setModel(&model); QVERIFY(!view.currentIndex().isValid()); QRect rect = view.visualRect(item0.index()); //we click on the decoration - QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, rect.topLeft()+QPoint(-rect.left()/2,rect.height()/2)); + QTest::mouseClick(view.viewport(), Qt::LeftButton, {}, + rect.topLeft() + QPoint(-rect.left() / 2, rect.height() / 2)); QVERIFY(!view.currentIndex().isValid()); QVERIFY(view.isExpanded(item0.index())); rect = view.visualRect(item1.index()); //the item has no decoration, it should get selected - QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, rect.topLeft()+QPoint(-rect.left()/2,rect.height()/2)); + QTest::mouseClick(view.viewport(), Qt::LeftButton, {}, + rect.topLeft() + QPoint(-rect.left() / 2, rect.height() / 2)); QCOMPARE(view.currentIndex(), item1.index()); } void tst_QTreeView::task246536_scrollbarsNotWorking() { - struct MyObject : public QObject + class MyObject : public QObject { - MyObject() : count(0) - { - } - - bool eventFilter(QObject*, QEvent *e) + public: + using QObject::QObject; + bool eventFilter(QObject*, QEvent *e) override { if (e->type() == QEvent::Paint) count++; return false; } - - int count; + int count = 0; }; QTreeView tree; MyObject o; @@ -3883,11 +3877,11 @@ void tst_QTreeView::task246536_scrollbarsNotWorking() tree.show(); QVERIFY(QTest::qWaitForWindowExposed(&tree)); QList<QStandardItem *> items; - for(int i=0; i<100; ++i){ + for (int i = 0; i < 100; ++i) items << new QStandardItem(QLatin1String("item ") + QString::number(i)); - } + o.count = 0; model.invisibleRootItem()->appendColumn(items); - QTest::qWait(100); + QTRY_VERIFY(o.count > 0); o.count = 0; tree.verticalScrollBar()->setValue(50); QTRY_VERIFY(o.count > 0); @@ -3915,12 +3909,12 @@ void tst_QTreeView::task239271_addRowsWithFirstColumnHidden() class MyDelegate : public QStyledItemDelegate { public: - void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const + void paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const override { paintedIndexes << index; QStyledItemDelegate::paint(painter, option, index); } - mutable QSet<QModelIndex> paintedIndexes; }; @@ -3953,15 +3947,15 @@ void tst_QTreeView::task254234_proxySort() //based on tst_QTreeView::sortByColumn // it used not to work when setting the source of a proxy after enabling sorting QTreeView view; - QStandardItemModel model(4,2); - model.setItem(0,0,new QStandardItem("b")); - model.setItem(1,0,new QStandardItem("d")); - model.setItem(2,0,new QStandardItem("c")); - model.setItem(3,0,new QStandardItem("a")); - model.setItem(0,1,new QStandardItem("e")); - model.setItem(1,1,new QStandardItem("g")); - model.setItem(2,1,new QStandardItem("h")); - model.setItem(3,1,new QStandardItem("f")); + QStandardItemModel model(4, 2); + model.setItem(0, 0, new QStandardItem("b")); + model.setItem(1, 0, new QStandardItem("d")); + model.setItem(2, 0, new QStandardItem("c")); + model.setItem(3, 0, new QStandardItem("a")); + model.setItem(0, 1, new QStandardItem("e")); + model.setItem(1, 1, new QStandardItem("g")); + model.setItem(2, 1, new QStandardItem("h")); + model.setItem(3, 1, new QStandardItem("f")); view.sortByColumn(1, Qt::DescendingOrder); view.setSortingEnabled(true); @@ -3971,8 +3965,8 @@ void tst_QTreeView::task254234_proxySort() view.setModel(&proxy); proxy.setSourceModel(&model); QCOMPARE(view.header()->sortIndicatorSection(), 1); - QCOMPARE(view.model()->data(view.model()->index(0,1)).toString(), QString::fromLatin1("h")); - QCOMPARE(view.model()->data(view.model()->index(1,1)).toString(), QString::fromLatin1("g")); + QCOMPARE(view.model()->data(view.model()->index(0, 1)).toString(), QString::fromLatin1("h")); + QCOMPARE(view.model()->data(view.model()->index(1, 1)).toString(), QString::fromLatin1("g")); } class TreeView : public QTreeView @@ -3984,7 +3978,8 @@ public slots: //let's select the last item QModelIndex idx = model()->index(0, 0); selectionModel()->select(QItemSelection(idx, idx), QItemSelectionModel::Select); - disconnect(selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(handleSelectionChanged())); + disconnect(selectionModel(), &QItemSelectionModel::selectionChanged, + this, &TreeView::handleSelectionChanged); } }; @@ -3993,12 +3988,14 @@ void tst_QTreeView::task248022_changeSelection() //we check that changing the selection between the mouse press and the mouse release //works correctly TreeView view; - QStringList list = QStringList() << "1" << "2"; + const QStringList list({"1", "2"}); QStringListModel model(list); view.setSelectionMode(QAbstractItemView::ExtendedSelection); view.setModel(&model); - view.connect(view.selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(handleSelectionChanged())); - QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.visualRect(model.index(1)).center()); + connect(view.selectionModel(), &QItemSelectionModel::selectionChanged, + &view, &TreeView::handleSelectionChanged); + QTest::mouseClick(view.viewport(), Qt::LeftButton, {}, + view.visualRect(model.index(1)).center()); QCOMPARE(view.selectionModel()->selectedIndexes().count(), list.count()); } @@ -4012,8 +4009,9 @@ void tst_QTreeView::task245654_changeModelAndExpandAll() model->appendRow(top); view.setModel(model.data()); view.expandAll(); - QApplication::processEvents(); - QVERIFY(view.isExpanded(top->index())); + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + QTRY_VERIFY(view.isExpanded(top->index())); //now let's try to delete the model //then repopulate and expand again @@ -4024,9 +4022,7 @@ void tst_QTreeView::task245654_changeModelAndExpandAll() model->appendRow(top); view.setModel(model.data()); view.expandAll(); - QApplication::processEvents(); - QVERIFY(view.isExpanded(top->index())); - + QTRY_VERIFY(view.isExpanded(top->index())); } void tst_QTreeView::doubleClickedWithSpans() @@ -4042,10 +4038,10 @@ void tst_QTreeView::doubleClickedWithSpans() QPoint p(10, 10); QCOMPARE(view.indexAt(p), model.index(0, 0)); - QSignalSpy spy(&view, SIGNAL(doubleClicked(QModelIndex))); - QTest::mousePress(view.viewport(), Qt::LeftButton, 0, p); - QTest::mouseDClick(view.viewport(), Qt::LeftButton, 0, p); - QTest::mouseRelease(view.viewport(), Qt::LeftButton, 0, p); + QSignalSpy spy(&view, &QAbstractItemView::doubleClicked); + QTest::mousePress(view.viewport(), Qt::LeftButton, {}, p); + QTest::mouseDClick(view.viewport(), Qt::LeftButton, {}, p); + QTest::mouseRelease(view.viewport(), Qt::LeftButton, {}, p); QCOMPARE(spy.count(), 1); //let's click on the 2nd column @@ -4053,10 +4049,10 @@ void tst_QTreeView::doubleClickedWithSpans() QCOMPARE(view.indexAt(p), model.index(0, 0)); //end the previous edition - QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p); - QTest::mousePress(view.viewport(), Qt::LeftButton, 0, p); - QTest::mouseDClick(view.viewport(), Qt::LeftButton, 0, p); - QTest::mouseRelease(view.viewport(), Qt::LeftButton, 0, p); + QTest::mouseClick(view.viewport(), Qt::LeftButton, {}, p); + QTest::mousePress(view.viewport(), Qt::LeftButton, {}, p); + QTest::mouseDClick(view.viewport(), Qt::LeftButton, {}, p); + QTest::mouseRelease(view.viewport(), Qt::LeftButton, {}, p); QTRY_COMPARE(spy.count(), 2); } @@ -4069,7 +4065,8 @@ void tst_QTreeView::taskQTBUG_6450_selectAllWith1stColumnHidden() const int nrRows = 10; for (int i = 0; i < nrRows; ++i) { const QString text = QLatin1String("item: ") + QString::number(i); - items.append(new QTreeWidgetItem((QTreeWidget*)0, QStringList(text))); + items.append(new QTreeWidgetItem(static_cast<QTreeWidget *>(nullptr), + QStringList(text))); items.last()->setText(1, QString("is an item")); } tree.insertTopLevelItems(0, items); @@ -4086,15 +4083,15 @@ class TreeViewQTBUG_9216 : public QTreeView { Q_OBJECT public: - void paintEvent(QPaintEvent *event) + void paintEvent(QPaintEvent *event) override { if (doCompare) QCOMPARE(event->rect(), viewport()->rect()); QTreeView::paintEvent(event); painted++; } - int painted; - bool doCompare; + int painted = 0; + bool doCompare = false; }; void tst_QTreeView::taskQTBUG_9216_setSizeAndUniformRowHeightsWrongRepaint() @@ -4128,7 +4125,7 @@ void tst_QTreeView::keyboardNavigationWithDisabled() QStandardItemModel model(90, 0); for (int i = 0; i < 90; i ++) { model.setItem(i, new QStandardItem(QString::number(i))); - model.item(i)->setEnabled(i%6 == 0); + model.item(i)->setEnabled(i % 6 == 0); } view.setModel(&model); @@ -4179,6 +4176,7 @@ void tst_QTreeView::keyboardNavigationWithDisabled() class RemoveColumnOne : public QSortFilterProxyModel { + Q_OBJECT public: bool filterAcceptsColumn(int source_column, const QModelIndex &) const override { @@ -4200,9 +4198,9 @@ void tst_QTreeView::saveRestoreState() { QStandardItemModel model; for (int i = 0; i < 100; i++) { - QList<QStandardItem *> items; - items << new QStandardItem(QLatin1String("item ") + QString::number(i)) << new QStandardItem(QStringLiteral("hidden by proxy")) << new QStandardItem(QStringLiteral("hidden by user")); - model.appendRow(items); + model.appendRow({new QStandardItem(QStringLiteral("item ") + QString::number(i)), + new QStandardItem(QStringLiteral("hidden by proxy")), + new QStandardItem(QStringLiteral("hidden by user")) }); } QCOMPARE(model.columnCount(), 3); @@ -4233,32 +4231,29 @@ class Model_11466 : public QAbstractItemModel { Q_OBJECT public: - Model_11466(QObject * /* parent */) : - m_block(false) + Model_11466(QObject *parent = nullptr) : QAbstractItemModel(parent) + , m_selectionModel(new QItemSelectionModel(this, this)) { - // set up the model to have two top level items and a few others - m_selectionModel = new QItemSelectionModel(this, this); // owned by this - - connect(m_selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)), - this, SLOT(slotCurrentChanged(QModelIndex,QModelIndex))); - }; + connect(m_selectionModel, &QItemSelectionModel::currentChanged, + this, &Model_11466::slotCurrentChanged); + } - int rowCount(const QModelIndex &parent) const + int rowCount(const QModelIndex &parent) const override { if (parent.isValid()) return (parent.internalId() == 0) ? 4 : 0; return 2; // two top level items } - int columnCount(const QModelIndex & /* parent */) const + int columnCount(const QModelIndex & /* parent */) const override { return 2; } - QVariant data(const QModelIndex &index, int role) const + QVariant data(const QModelIndex &index, int role) const override { if (role == Qt::DisplayRole && index.isValid()) { - qint64 parentRowPlusOne = index.internalId(); + qint64 parentRowPlusOne = qint64(index.internalId()); QString str; QTextStream stream(&str); if (parentRowPlusOne > 0) @@ -4270,10 +4265,10 @@ public: return QVariant(); } - QModelIndex parent(const QModelIndex &index) const + QModelIndex parent(const QModelIndex &index) const override { if (index.isValid()) { - qint64 parentRowPlusOne = index.internalId(); + qint64 parentRowPlusOne = qint64(index.internalId()); if (parentRowPlusOne > 0) { int row = static_cast<int>(parentRowPlusOne - 1); return createIndex(row, 0); @@ -4294,9 +4289,9 @@ public: delete oldModel; } - QModelIndex index(int row, int column, const QModelIndex &parent) const + QModelIndex index(int row, int column, const QModelIndex &parent) const override { - return createIndex(row, column, parent.isValid() ? (quintptr)(parent.row() + 1) : (quintptr)0); + return createIndex(row, column, parent.isValid() ? quintptr(parent.row() + 1) : quintptr(0)); } public slots: @@ -4333,7 +4328,7 @@ public slots: } private: - bool m_block; + bool m_block = false; QItemSelectionModel *m_selectionModel; }; @@ -4388,9 +4383,9 @@ void tst_QTreeView::taskQTBUG_25333_adjustViewOptionsForIndex() QStandardItem *data3 = new QStandardItem("Data3"); // Create a treeview - model.appendRow(QList<QStandardItem*>() << item1 << data1 ); - model.appendRow(QList<QStandardItem*>() << item2 << data2 ); - model.appendRow(QList<QStandardItem*>() << item3 << data3 ); + model.appendRow({ item1, data1 }); + model.appendRow({ item2, data2 }); + model.appendRow({ item3, data3 }); view.setModel(&model); @@ -4414,6 +4409,9 @@ void tst_QTreeView::taskQTBUG_25333_adjustViewOptionsForIndex() void tst_QTreeView::taskQTBUG_18539_emitLayoutChanged() { + qRegisterMetaType<QList<QPersistentModelIndex>>(); + qRegisterMetaType<QAbstractItemModel::LayoutChangeHint>(); + QTreeView view; QStandardItem* item = new QStandardItem("Orig"); @@ -4430,14 +4428,14 @@ void tst_QTreeView::taskQTBUG_18539_emitLayoutChanged() replacementItem->setChild(0, 0, replacementChild); - QSignalSpy beforeSpy(&model, SIGNAL(layoutAboutToBeChanged())); - QSignalSpy afterSpy(&model, SIGNAL(layoutChanged())); + QSignalSpy beforeSpy(&model, &QAbstractItemModel::layoutAboutToBeChanged); + QSignalSpy afterSpy(&model, &QAbstractItemModel::layoutChanged); - QSignalSpy beforeRISpy(&model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int))); - QSignalSpy afterRISpy(&model, SIGNAL(rowsInserted(QModelIndex,int,int))); + QSignalSpy beforeRISpy(&model, &QAbstractItemModel::rowsAboutToBeInserted); + QSignalSpy afterRISpy(&model, &QAbstractItemModel::rowsInserted); - QSignalSpy beforeRRSpy(&model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int))); - QSignalSpy afterRRSpy(&model, SIGNAL(rowsRemoved(QModelIndex,int,int))); + QSignalSpy beforeRRSpy(&model, &QAbstractItemModel::rowsAboutToBeRemoved); + QSignalSpy afterRRSpy(&model, &QAbstractItemModel::rowsRemoved); model.setItem(0, 0, replacementItem); @@ -4460,7 +4458,7 @@ void tst_QTreeView::taskQTBUG_8176_emitOnExpandAll() new QTreeWidgetItem(item2, QStringList(QString("item 4"))); QTreeWidgetItem *item5 = new QTreeWidgetItem(&tw, QStringList(QString("item 5"))); new QTreeWidgetItem(item5, QStringList(QString("item 6"))); - QSignalSpy spy(&tw, SIGNAL(expanded(const QModelIndex&))); + QSignalSpy spy(&tw, &QTreeView::expanded); // expand all tw.expandAll(); @@ -4473,7 +4471,7 @@ void tst_QTreeView::taskQTBUG_8176_emitOnExpandAll() QCOMPARE(spy.size(), 5); // collapse all - QSignalSpy spy2(&tw, SIGNAL(collapsed(const QModelIndex&))); + QSignalSpy spy2(&tw, &QTreeView::collapsed); tw.collapseAll(); QCOMPARE(spy2.size(), 6); tw.expandAll(); @@ -4496,14 +4494,13 @@ void tst_QTreeView::testInitialFocus() { QTreeWidget treeWidget; treeWidget.setColumnCount(5); - new QTreeWidgetItem(&treeWidget, QStringList(QString("1;2;3;4;5").split(QLatin1Char(';')))); + new QTreeWidgetItem(&treeWidget, QString("1;2;3;4;5").split(QLatin1Char(';'))); treeWidget.setTreePosition(2); treeWidget.header()->hideSection(0); // make sure we skip hidden section(s) treeWidget.header()->swapSections(1, 2); // make sure that we look for first visual index (and not first logical) treeWidget.show(); QVERIFY(QTest::qWaitForWindowExposed(&treeWidget)); - QApplication::processEvents(); - QCOMPARE(treeWidget.currentIndex().column(), 2); + QTRY_COMPARE(treeWidget.currentIndex().column(), 2); } #if QT_CONFIG(animation) @@ -4534,9 +4531,8 @@ void tst_QTreeView::quickExpandCollapse() tree.collapse(rootIndex); QCOMPARE(tree.state(), QTreeView::AnimatingState); - QTest::qWait(500); //the animation lasts for 250ms max so 500 should be enough - - QCOMPARE(tree.state(), initialState); + //the animation lasts for 250ms max so 5000 (default) should be enough + QTRY_COMPARE(tree.state(), initialState); } #endif // animation @@ -4576,7 +4572,7 @@ class Qtbug45697TestWidget : public QWidget public: static const int columnCount = 3; - explicit Qtbug45697TestWidget(); + explicit Qtbug45697TestWidget(QWidget *parent = nullptr); int timerTick() const { return m_timerTick; } public slots: @@ -4586,14 +4582,13 @@ private: QTreeView *m_treeView; QStandardItemModel *m_model; QSortFilterProxyModel *m_sortFilterProxyModel; - int m_timerTick; + int m_timerTick = 0; }; -Qtbug45697TestWidget::Qtbug45697TestWidget() - : m_treeView(new QTreeView(this)) +Qtbug45697TestWidget::Qtbug45697TestWidget(QWidget *parent) + : QWidget(parent), m_treeView(new QTreeView(this)) , m_model(new QStandardItemModel(0, Qtbug45697TestWidget::columnCount, this)) , m_sortFilterProxyModel(new QSortFilterProxyModel(this)) - , m_timerTick(0) { QVBoxLayout *vBoxLayout = new QVBoxLayout(this); vBoxLayout->addWidget(m_treeView); @@ -4611,7 +4606,7 @@ Qtbug45697TestWidget::Qtbug45697TestWidget() m_treeView->setModel(m_sortFilterProxyModel); QHeaderView *headerView = m_treeView->header(); - for (int s = 1, lastSection = headerView->count() - 1; s < lastSection; ++s ) + for (int s = 1, lastSection = headerView->count() - 1; s < lastSection; ++s) headerView->setSectionResizeMode(s, QHeaderView::ResizeToContents); QTimer *timer = new QTimer(this); @@ -4697,9 +4692,8 @@ void tst_QTreeView::statusTip() { QFETCH(bool, intermediateParent); QMainWindow mw; - QtTestModel model; + QtTestModel model(5, 5); model.statusTipsEnabled = true; - model.rows = model.cols = 5; QTreeView *view = new QTreeView; view->setModel(&model); view->viewport()->setMouseTracking(true); @@ -4717,7 +4711,7 @@ void tst_QTreeView::statusTip() mw.setGeometry(QRect(QPoint(QApplication::desktop()->geometry().center() - QPoint(250, 250)), QSize(500, 500))); mw.show(); - qApp->setActiveWindow(&mw); + QApplication::setActiveWindow(&mw); QVERIFY(QTest::qWaitForWindowActive(&mw)); // Ensure it is moved away first and then moved to the relevant section QTest::mouseMove(mw.windowHandle(), view->mapTo(&mw, view->rect().bottomLeft() + QPoint(20, 20))); @@ -4736,8 +4730,9 @@ void tst_QTreeView::statusTip() class FetchMoreModel : public QStandardItemModel { + Q_OBJECT public: - FetchMoreModel() : QStandardItemModel(), canFetchReady(false) + FetchMoreModel(QObject *parent = nullptr) : QStandardItemModel(parent) { for (int i = 0; i < 20; ++i) { QStandardItem *item = new QStandardItem("Row"); @@ -4757,9 +4752,9 @@ public: { QStandardItem *item = itemFromIndex(parent); for (int i = 0; i < 19; ++i) - item->appendRow(new QStandardItem(QString("New Child %1").arg(i))); + item->appendRow(new QStandardItem(QStringLiteral("New Child ") + QString::number(i))); } - bool canFetchReady; + bool canFetchReady = false; }; void tst_QTreeView::fetchMoreOnScroll() @@ -4865,12 +4860,12 @@ void tst_QTreeView::taskQTBUG_61476() const QRect rect = priv->itemDecorationRect(mi); const QPoint pos = rect.center(); - QTest::mousePress(tv.viewport(), Qt::LeftButton, 0, pos); - if (tv.style()->styleHint(QStyle::SH_ListViewExpand_SelectMouseType, 0, &tv) == + QTest::mousePress(tv.viewport(), Qt::LeftButton, {}, pos); + if (tv.style()->styleHint(QStyle::SH_ListViewExpand_SelectMouseType, nullptr, &tv) == QEvent::MouseButtonPress) QTRY_VERIFY(!tv.isExpanded(mi)); - QTest::mouseRelease(tv.viewport(), Qt::LeftButton, 0, pos); + QTest::mouseRelease(tv.viewport(), Qt::LeftButton, nullptr, pos); QTRY_VERIFY(!tv.isExpanded(mi)); QCOMPARE(lastTopLevel->checkState(), Qt::Checked); } diff --git a/tests/auto/widgets/itemviews/qtreewidget/tst_qtreewidget.cpp b/tests/auto/widgets/itemviews/qtreewidget/tst_qtreewidget.cpp index 33d4f3bf91..6b8beccbdc 100644 --- a/tests/auto/widgets/itemviews/qtreewidget/tst_qtreewidget.cpp +++ b/tests/auto/widgets/itemviews/qtreewidget/tst_qtreewidget.cpp @@ -27,36 +27,22 @@ ****************************************************************************/ -#include <QtTest/QtTest> -#include <qtreewidget.h> -#include <qtreewidgetitemiterator.h> -#include <qapplication.h> -#include <qeventloop.h> -#include <qdebug.h> -#include <qheaderview.h> -#include <qlineedit.h> +#include <QApplication> +#include <QHeaderView> +#include <QLineEdit> #include <QScrollBar> +#include <QSignalSpy> #include <QStyledItemDelegate> - -class CustomTreeWidget : public QTreeWidget -{ - Q_OBJECT -public: - QModelIndex indexFromItem(QTreeWidgetItem *item, int column = 0) const - { return QTreeWidget::indexFromItem(item, column); } - - QMimeData * mimeData(const QList<QTreeWidgetItem*> items) const - { return QTreeWidget::mimeData(items); } -}; +#include <QTreeWidget> +#include <QTreeWidgetItemIterator> +#include <QTest> class tst_QTreeWidget : public QObject { Q_OBJECT public: - tst_QTreeWidget(); - ~tst_QTreeWidget(); - + tst_QTreeWidget() = default; public slots: void initTestCase(); @@ -173,8 +159,25 @@ public slots: void itemSelectionChanged(); void emitDataChanged(); +public: + class PublicTreeWidget : public QTreeWidget + { + public: + using QTreeWidget::indexFromItem; + using QTreeWidget::mimeData; + using QTreeWidget::sizeHintForColumn; + void deleteCurrent() { delete currentItem(); } + }; + + class PublicTreeItem : public QTreeWidgetItem + { + public: + using QTreeWidgetItem::QTreeWidgetItem; + using QTreeWidgetItem::emitDataChanged; + }; + private: - CustomTreeWidget *testWidget; + PublicTreeWidget *testWidget = nullptr; }; // Testing get/set functions @@ -186,7 +189,7 @@ void tst_QTreeWidget::getSetCheck() obj1.setColumnCount(0); QCOMPARE(obj1.columnCount(), 0); - obj1.setColumnCount(INT_MIN); + obj1.setColumnCount(std::numeric_limits<int>::min()); QCOMPARE(obj1.columnCount(), 0); //obj1.setColumnCount(INT_MAX); @@ -202,7 +205,7 @@ void tst_QTreeWidget::getSetCheck() obj1.setHeaderItem(var2); QCOMPARE(obj1.headerItem(), var2); - obj1.setHeaderItem((QTreeWidgetItem *)0); + obj1.setHeaderItem(nullptr); // QCOMPARE(obj1.headerItem(), nullptr); // QTreeWidgetItem * QTreeWidget::currentItem() @@ -211,36 +214,28 @@ void tst_QTreeWidget::getSetCheck() obj1.setCurrentItem(var3); QCOMPARE(obj1.currentItem(), var3); - obj1.setCurrentItem((QTreeWidgetItem *)0); + obj1.setCurrentItem(nullptr); QCOMPARE(obj1.currentItem(), nullptr); } -typedef QList<int> IntList; -typedef QList<IntList> ListIntList; +using IntList = QVector<int>; +using ListIntList = QVector<IntList>; +using PersistentModelIndexVec = QVector<QPersistentModelIndex>; +using TreeItem = QTreeWidgetItem; +using TreeItemList = QVector<TreeItem*>; Q_DECLARE_METATYPE(Qt::Orientation) - -typedef QTreeWidgetItem TreeItem; -typedef QList<TreeItem*> TreeItemList; - Q_DECLARE_METATYPE(QTreeWidgetItem*) Q_DECLARE_METATYPE(TreeItemList) -tst_QTreeWidget::tst_QTreeWidget(): testWidget(0) -{ -} - -tst_QTreeWidget::~tst_QTreeWidget() -{ -} - void tst_QTreeWidget::initTestCase() { - qMetaTypeId<QModelIndex>(); qMetaTypeId<Qt::Orientation>(); qRegisterMetaType<QTreeWidgetItem*>("QTreeWidgetItem*"); + qRegisterMetaType<QList<QPersistentModelIndex>>("QList<QPersistentModelIndex>"); + qRegisterMetaType<QAbstractItemModel::LayoutChangeHint>("QAbstractItemModel::LayoutChangeHint"); - testWidget = new CustomTreeWidget(); + testWidget = new PublicTreeWidget(); testWidget->show(); QVERIFY(QTest::qWaitForWindowExposed(testWidget)); } @@ -261,18 +256,19 @@ void tst_QTreeWidget::cleanup() { } -TreeItem *operator<<(TreeItem *parent, const TreeItemList &children) { - for (int i = 0; i < children.count(); ++i) - parent->addChild(children.at(i)); +TreeItem *operator<<(TreeItem *parent, const TreeItemList &children) +{ + for (TreeItem *child : children) + parent->addChild(child); return parent; } static void populate(QTreeWidget *widget, const TreeItemList &topLevelItems, - TreeItem *headerItem = 0) + TreeItem *headerItem = nullptr) { widget->clear(); widget->setHeaderItem(headerItem); - foreach (TreeItem *item, topLevelItems) + for (TreeItem *item : topLevelItems) widget->addTopLevelItem(item); } @@ -282,12 +278,12 @@ void tst_QTreeWidget::addTopLevelItem() QCOMPARE(tree.topLevelItemCount(), 0); // try to add 0 - tree.addTopLevelItem(0); + tree.addTopLevelItem(nullptr); QCOMPARE(tree.topLevelItemCount(), 0); - QCOMPARE(tree.indexOfTopLevelItem(0), -1); + QCOMPARE(tree.indexOfTopLevelItem(nullptr), -1); // add one at a time - QList<TreeItem*> tops; + QList<TreeItem *> tops; for (int i = 0; i < 10; ++i) { TreeItem *ti = new TreeItem(); QCOMPARE(tree.indexOfTopLevelItem(ti), -1); @@ -362,19 +358,19 @@ void tst_QTreeWidget::currentItem_data() QTest::newRow("only top-level items, 2 columns") << (TreeItemList() - << new TreeItem(QStringList() << "a" << "b") - << new TreeItem(QStringList() << "c" << "d")); + << new TreeItem({"a", "b"}) + << new TreeItem({"c", "d"})); TreeItemList lst; - lst << (new TreeItem(QStringList() << "a" << "b") + lst << (new TreeItem({"a", "b"}) << (TreeItemList() - << new TreeItem(QStringList() << "c" << "d") - << new TreeItem(QStringList() << "c" << "d") + << new TreeItem({"c", "d"}) + << new TreeItem({"c", "d"}) ) ) - << (new TreeItem(QStringList() << "e" << "f") + << (new TreeItem({"e", "f"}) << (TreeItemList() - << new TreeItem(QStringList() << "g" << "h") - << new TreeItem(QStringList() << "g" << "h") + << new TreeItem({"g", "h"}) + << new TreeItem({"g", "h"}) ) ); QTest::newRow("hierarchy, 2 columns") << lst; @@ -386,15 +382,15 @@ void tst_QTreeWidget::currentItem() QTreeWidget tree; tree.show(); - populate(&tree, topLevelItems, new TreeItem(QStringList() << "1" << "2")); - QTreeWidgetItem *previous = 0; + populate(&tree, topLevelItems, new TreeItem({"1", "2"})); + QTreeWidgetItem *previous = nullptr; for (int x = 0; x < 2; ++x) { tree.setSelectionBehavior(x ? QAbstractItemView::SelectItems : QAbstractItemView::SelectRows); QSignalSpy currentItemChangedSpy( - &tree, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*))); + &tree, &QTreeWidget::currentItemChanged); QSignalSpy itemSelectionChangedSpy( - &tree, SIGNAL(itemSelectionChanged())); + &tree, &QTreeWidget::itemSelectionChanged); QTreeWidgetItemIterator it(&tree); // do all items @@ -468,8 +464,7 @@ void tst_QTreeWidget::editItem() tree.show(); QVERIFY(QTest::qWaitForWindowActive(&tree)); - QSignalSpy itemChangedSpy( - &tree, SIGNAL(itemChanged(QTreeWidgetItem*,int))); + QSignalSpy itemChangedSpy(&tree, &QTreeWidget::itemChanged); QTreeWidgetItemIterator it(&tree); while (QTreeWidgetItem *item = (*it++)) { @@ -477,18 +472,18 @@ void tst_QTreeWidget::editItem() if (!(item->flags() & Qt::ItemIsEditable)) QTest::ignoreMessage(QtWarningMsg, "edit: editing failed"); tree.editItem(item, col); - QApplication::instance()->processEvents(); - QApplication::instance()->processEvents(); + QCoreApplication::processEvents(); + QCoreApplication::processEvents(); QLineEdit *editor = tree.findChild<QLineEdit*>(); if (editor) { QVERIFY(item->flags() & Qt::ItemIsEditable); QCOMPARE(editor->selectedText(), editor->text()); QTest::keyClick(editor, Qt::Key_A); QTest::keyClick(editor, Qt::Key_Enter); - QApplication::instance()->processEvents(); + QCoreApplication::processEvents(); QCOMPARE(itemChangedSpy.count(), 1); QVariantList args = itemChangedSpy.takeFirst(); - QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item); + QCOMPARE(qvariant_cast<QTreeWidgetItem *>(args.at(0)), item); QCOMPARE(qvariant_cast<int>(args.at(1)), col); } else { QVERIFY(!(item->flags() & Qt::ItemIsEditable)); @@ -522,10 +517,10 @@ void tst_QTreeWidget::takeItem() QFETCH(bool, topLevel); QFETCH(bool, outOfBounds); - for (int i=0; i<3; ++i) { + for (int i = 0; i < 3; ++i) { QTreeWidgetItem *top = new QTreeWidgetItem(testWidget); top->setText(0, QStringLiteral("top") + QString::number(i)); - for (int j=0; j<3; ++j) { + for (int j = 0; j < 3; ++j) { QTreeWidgetItem *child = new QTreeWidgetItem(top); child->setText(0, QStringLiteral("child") + QString::number(j)); } @@ -635,27 +630,23 @@ void tst_QTreeWidget::setItemHidden() parent->setHidden(true); parent->setHidden(false); QVERIFY(!parent->isHidden()); - - } void tst_QTreeWidget::setItemHidden2() { // From Task 78587 - QStringList hl; - hl << "ID" << "Desc"; + const QStringList hl({"ID", "Desc"}); testWidget->setColumnCount(hl.count()); testWidget->setHeaderLabels(hl); testWidget->setSortingEnabled(true); QTreeWidgetItem *top = new QTreeWidgetItem(testWidget); - QTreeWidgetItem *leaf = 0; top->setText(0, "ItemList"); for (int i = 1; i <= 4; i++) { - leaf = new QTreeWidgetItem(top); - leaf->setText(0, QString::asprintf("%d", i)); - leaf->setText(1, QString::asprintf("Item %d", i)); + auto leaf = new QTreeWidgetItem(top); + leaf->setText(0, QString::number(i)); + leaf->setText(1, QStringLiteral("Item %1").arg(i)); } if (testWidget->topLevelItemCount() > 0) { @@ -666,11 +657,10 @@ void tst_QTreeWidget::setItemHidden2() if (testWidget->topLevelItemCount() > 0) { top = testWidget->topLevelItem(0); for (int i = 0; i < top->childCount(); i++) { - leaf = top->child(i); + auto leaf = top->child(i); if (leaf->text(0).toInt() % 2 == 0) { - if (!leaf->isHidden()) { + if (!leaf->isHidden()) leaf->setHidden(true); - } } } } @@ -799,25 +789,25 @@ void tst_QTreeWidget::selectedItems() QFETCH(int, topLevel); QFETCH(int, children); QFETCH(bool, closeTopLevel); - QFETCH(ListIntList, selectedItems); - QFETCH(ListIntList, hiddenItems); - QFETCH(ListIntList, expectedItems); + QFETCH(const ListIntList, selectedItems); + QFETCH(const ListIntList, hiddenItems); + QFETCH(const ListIntList, expectedItems); // create items - for (int t=0; t<topLevel; ++t) { + for (int t = 0; t < topLevel; ++t) { QTreeWidgetItem *top = new QTreeWidgetItem(testWidget); const QString topS = QLatin1String("top") + QString::number(t); top->setText(0, topS); - for (int c=0; c<children; ++c) { + for (int c = 0; c < children; ++c) { QTreeWidgetItem *child = new QTreeWidgetItem(top); child->setText(0, topS + QLatin1String("child") + QString::number(c)); } } // set selected - foreach (IntList itemPath, selectedItems) { - QTreeWidgetItem *item = 0; - foreach(int index, itemPath) { + for (const auto &itemPath : selectedItems) { + QTreeWidgetItem *item = nullptr; + for (int index : itemPath) { if (!item) item = testWidget->topLevelItem(index); else @@ -827,9 +817,9 @@ void tst_QTreeWidget::selectedItems() } // hide rows - foreach (IntList itemPath, hiddenItems) { - QTreeWidgetItem *item = 0; - foreach(int index, itemPath) { + for (const auto &itemPath : hiddenItems) { + QTreeWidgetItem *item = nullptr; + for (int index : itemPath) { if (!item) item = testWidget->topLevelItem(index); else @@ -839,7 +829,7 @@ void tst_QTreeWidget::selectedItems() } // open/close toplevel - for (int i=0; i<testWidget->topLevelItemCount(); ++i) { + for (int i = 0; i < testWidget->topLevelItemCount(); ++i) { if (closeTopLevel) testWidget->collapseItem(testWidget->topLevelItem(i)); else @@ -847,26 +837,26 @@ void tst_QTreeWidget::selectedItems() } // check selectedItems - QList<QTreeWidgetItem*> sel = testWidget->selectedItems(); + const auto sel = testWidget->selectedItems(); QCOMPARE(sel.count(), expectedItems.count()); - foreach (IntList itemPath, expectedItems) { - QTreeWidgetItem *item = 0; - foreach(int index, itemPath) { + for (const auto &itemPath : expectedItems) { + QTreeWidgetItem *item = nullptr; + for (int index : itemPath) { if (!item) item = testWidget->topLevelItem(index); else item = item->child(index); } if (item) - QVERIFY(sel.contains(item)); + QVERIFY(sel.contains(item)); } // compare isSelected - for (int t=0; t<testWidget->topLevelItemCount(); ++t) { + for (int t = 0; t < testWidget->topLevelItemCount(); ++t) { QTreeWidgetItem *top = testWidget->topLevelItem(t); if (top->isSelected() && !top->isHidden()) QVERIFY(sel.contains(top)); - for (int c=0; c<top->childCount(); ++c) { + for (int c = 0; c < top->childCount(); ++c) { QTreeWidgetItem *child = top->child(c); if (child->isSelected() && !child->isHidden()) QVERIFY(sel.contains(child)); @@ -883,9 +873,9 @@ QT_WARNING_POP #endif // unselect - foreach (IntList itemPath, selectedItems) { - QTreeWidgetItem *item = 0; - foreach(int index, itemPath) { + for (const auto &itemPath : selectedItems) { + QTreeWidgetItem *item = nullptr; + for (int index : itemPath) { if (!item) item = testWidget->topLevelItem(index); else @@ -903,7 +893,7 @@ void tst_QTreeWidget::itemAssignment() QTreeWidgetItem *parent = new QTreeWidgetItem(&grandParent); parent->setText(0, "foo"); parent->setText(1, "bar"); - for (int i=0; i<5; ++i) { + for (int i = 0; i < 5; ++i) { QTreeWidgetItem *child = new QTreeWidgetItem(parent); child->setText(0, "bingo"); child->setText(1, "bango"); @@ -919,7 +909,7 @@ void tst_QTreeWidget::itemAssignment() QTreeWidgetItem item(testWidget); item.setText(0, "baz"); QVERIFY(!item.parent()); - QCOMPARE(item.treeWidget(), static_cast<QTreeWidget *>(testWidget)); + QCOMPARE(item.treeWidget(), testWidget); QCOMPARE(item.columnCount(), 1); QCOMPARE(item.text(0), QString("baz")); QCOMPARE(item.childCount(), 0); @@ -959,16 +949,16 @@ void tst_QTreeWidget::clone() QFETCH(int, column); QFETCH(int, topLevelIndex); QFETCH(int, childIndex); - QFETCH(QStringList, topLevelText); - QFETCH(QStringList, childText); + QFETCH(const QStringList, topLevelText); + QFETCH(const QStringList, childText); QFETCH(bool, cloneChild); - for (int i = 0; i < topLevelText.count(); ++i) { + for (const QString &tl : topLevelText) { QTreeWidgetItem *item = new QTreeWidgetItem(testWidget); - item->setText(column, topLevelText.at(i)); - for (int j = 0; j < childText.count(); ++j) { + item->setText(column, tl); + for (const QString &cl : childText) { QTreeWidgetItem *child = new QTreeWidgetItem(item); - child->setText(column, childText.at(j)); + child->setText(column, cl); } } @@ -984,7 +974,7 @@ void tst_QTreeWidget::clone() QVERIFY(copiedChild != originalChild); QCOMPARE(copiedChild->text(column), originalChild->text(column)); QCOMPARE(copiedChild->childCount(), originalChild->childCount()); - QCOMPARE(copiedChild->parent(), cloneChild ? 0 : copy); + QCOMPARE(copiedChild->parent(), cloneChild ? nullptr : copy); QVERIFY(!copiedChild->treeWidget()); if (cloneChild) delete copiedChild; @@ -1109,18 +1099,18 @@ void tst_QTreeWidget::findItems_data() void tst_QTreeWidget::findItems() { QFETCH(int, column); - QFETCH(QStringList, topLevelText); - QFETCH(QStringList, childText); + QFETCH(const QStringList, topLevelText); + QFETCH(const QStringList, childText); QFETCH(QString, pattern); QFETCH(int, resultCount); - QFETCH(QStringList, resultText); + QFETCH(const QStringList, resultText); - for (int i = 0; i < topLevelText.count(); ++i) { + for (const QString &tl : topLevelText) { QTreeWidgetItem *item = new QTreeWidgetItem(testWidget); - item->setText(column, topLevelText.at(i)); - for (int j = 0; j < childText.count(); ++j) { + item->setText(column, tl); + for (const QString &cl : childText) { QTreeWidgetItem *child = new QTreeWidgetItem(item); - child->setText(column, childText.at(j)); + child->setText(column, cl); } } @@ -1152,7 +1142,7 @@ void tst_QTreeWidget::findItemsInColumn() void tst_QTreeWidget::sortItems_data() { QTest::addColumn<int>("column"); - QTest::addColumn<int>("order"); + QTest::addColumn<Qt::SortOrder>("order"); QTest::addColumn<QStringList>("topLevelText"); QTest::addColumn<QStringList>("childText"); QTest::addColumn<QStringList>("topLevelResult"); @@ -1162,7 +1152,7 @@ void tst_QTreeWidget::sortItems_data() QTest::newRow("ascending order") << 0 - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << (QStringList() << "c" << "d" << "a" << "b") << (QStringList() << "e" << "h" << "g" << "f") << (QStringList() << "a" << "b" << "c" << "d") @@ -1172,7 +1162,7 @@ void tst_QTreeWidget::sortItems_data() QTest::newRow("descending order") << 0 - << static_cast<int>(Qt::DescendingOrder) + << Qt::DescendingOrder << (QStringList() << "c" << "d" << "a" << "b") << (QStringList() << "e" << "h" << "g" << "f") << (QStringList() << "d" << "c" << "b" << "a") @@ -1184,7 +1174,7 @@ void tst_QTreeWidget::sortItems_data() void tst_QTreeWidget::sortItems() { QFETCH(int, column); - QFETCH(int, order); + QFETCH(Qt::SortOrder, order); QFETCH(QStringList, topLevelText); QFETCH(QStringList, childText); QFETCH(QStringList, topLevelResult); @@ -1193,28 +1183,24 @@ void tst_QTreeWidget::sortItems() QFETCH(IntList, expectedChildRows); testWidget->setSortingEnabled(false); - for (int i = 0; i < topLevelText.count(); ++i) { + for (const QString &tl : topLevelText) { QTreeWidgetItem *item = new QTreeWidgetItem(testWidget); - item->setText(column, topLevelText.at(i)); - for (int j = 0; j < childText.count(); ++j) { + item->setText(column, tl); + for (const QString &cl : childText) { QTreeWidgetItem *child = new QTreeWidgetItem(item); - child->setText(column, childText.at(j)); + child->setText(column, cl); } } QAbstractItemModel *model = testWidget->model(); - QList<QPersistentModelIndex> tops; - for (int r = 0; r < model->rowCount(QModelIndex()); ++r) { - QPersistentModelIndex p = model->index(r, 0, QModelIndex()); - tops << p; - } - QList<QPersistentModelIndex> children; - for (int s = 0; s < model->rowCount(tops.first()); ++s) { - QPersistentModelIndex c = model->index(s, 0, tops.first()); - children << c; - } - - testWidget->sortItems(column, static_cast<Qt::SortOrder>(order)); + PersistentModelIndexVec tops; + for (int r = 0; r < model->rowCount(QModelIndex()); ++r) + tops.push_back(model->index(r, 0, QModelIndex())); + PersistentModelIndexVec children; + for (int s = 0; s < model->rowCount(tops.constFirst()); ++s) + children.push_back(model->index(s, 0, tops.constFirst())); + + testWidget->sortItems(column, order); QCOMPARE(testWidget->sortColumn(), column); for (int k = 0; k < topLevelResult.count(); ++k) { @@ -1382,8 +1368,8 @@ void tst_QTreeWidget::insertTopLevelItems_data() QTest::addColumn<int>("insertChildIndex"); QTest::addColumn<int>("expectedChildIndex"); - QStringList initial = (QStringList() << "foo" << "bar"); - QStringList insert = (QStringList() << "baz"); + const QStringList initial{ "foo", "bar" }; + const QStringList insert{ "baz" }; QTest::newRow("Insert at count") << initial << insert << initial.count() << initial.count() @@ -1434,7 +1420,7 @@ void tst_QTreeWidget::insertTopLevelItems() delete topsy; } else { QTreeWidgetItem *item = testWidget->topLevelItem(expectedTopLevelIndex); - QVERIFY(item != 0); + QVERIFY(item != nullptr); QCOMPARE(item->text(0), insertText.at(0)); QCOMPARE(testWidget->indexOfTopLevelItem(item), expectedTopLevelIndex); } @@ -1442,7 +1428,7 @@ void tst_QTreeWidget::insertTopLevelItems() { // test adding more children QTreeWidgetItem *topLevel = testWidget->topLevelItem(0); - QVERIFY(topLevel != 0); + QVERIFY(topLevel != nullptr); QTreeWidgetItem *child = new QTreeWidgetItem(QStringList(insertText.at(0))); topLevel->insertChild(insertChildIndex, child); if (expectedChildIndex == -1) { @@ -1450,7 +1436,7 @@ void tst_QTreeWidget::insertTopLevelItems() delete child; } else { QTreeWidgetItem *item = topLevel->child(expectedChildIndex); - QVERIFY(item != 0); + QVERIFY(item != nullptr); QCOMPARE(item->text(0), insertText.at(0)); } } @@ -1486,37 +1472,33 @@ void tst_QTreeWidget::keyboardNavigation() fillTreeWidget(testWidget, rows); - QVector<Qt::Key> keymoves; - keymoves << Qt::Key_Down << Qt::Key_Right << Qt::Key_Left - << Qt::Key_Down << Qt::Key_Down << Qt::Key_Down << Qt::Key_Down - << Qt::Key_Right - << Qt::Key_Up << Qt::Key_Left << Qt::Key_Left - << Qt::Key_Up << Qt::Key_Down << Qt::Key_Up << Qt::Key_Up - << Qt::Key_Up << Qt::Key_Up << Qt::Key_Up << Qt::Key_Up - << Qt::Key_Down << Qt::Key_Right << Qt::Key_Down << Qt::Key_Down - << Qt::Key_Down << Qt::Key_Right << Qt::Key_Down << Qt::Key_Down - << Qt::Key_Left << Qt::Key_Left << Qt::Key_Up << Qt::Key_Down - << Qt::Key_Up << Qt::Key_Up << Qt::Key_Up << Qt::Key_Left - << Qt::Key_Down << Qt::Key_Right << Qt::Key_Right << Qt::Key_Right - << Qt::Key_Left << Qt::Key_Left << Qt::Key_Right << Qt::Key_Left; - - int row = 0; + const QVector<Qt::Key> keymoves { + Qt::Key_Down, Qt::Key_Right, Qt::Key_Left, + Qt::Key_Down, Qt::Key_Down, Qt::Key_Down, Qt::Key_Down, + Qt::Key_Right, + Qt::Key_Up, Qt::Key_Left, Qt::Key_Left, + Qt::Key_Up, Qt::Key_Down, Qt::Key_Up, Qt::Key_Up, + Qt::Key_Up, Qt::Key_Up, Qt::Key_Up, Qt::Key_Up, + Qt::Key_Down, Qt::Key_Right, Qt::Key_Down, Qt::Key_Down, + Qt::Key_Down, Qt::Key_Right, Qt::Key_Down, Qt::Key_Down, + Qt::Key_Left, Qt::Key_Left, Qt::Key_Up, Qt::Key_Down, + Qt::Key_Up, Qt::Key_Up, Qt::Key_Up, Qt::Key_Left, + Qt::Key_Down, Qt::Key_Right, Qt::Key_Right, Qt::Key_Right, + Qt::Key_Left, Qt::Key_Left, Qt::Key_Right, Qt::Key_Left + }; + + int row = 0; QTreeWidgetItem *item = testWidget->topLevelItem(0); testWidget->setCurrentItem(item); QCOMPARE(testWidget->currentItem(), item); - QApplication::instance()->processEvents(); + QCoreApplication::processEvents(); QScrollBar *scrollBar = testWidget->horizontalScrollBar(); - bool checkScroll = false; - for (int i = 0; i < keymoves.size(); ++i) { - Qt::Key key = keymoves.at(i); + for (const Qt::Key key : keymoves) { int valueBeforeClick = scrollBar->value(); - if (valueBeforeClick >= scrollBar->singleStep()) - checkScroll = true; - else - checkScroll = false; + const bool checkScroll = (valueBeforeClick >= scrollBar->singleStep()); QTest::keyClick(testWidget, key); - QApplication::instance()->processEvents(); + QCoreApplication::processEvents(); switch (key) { case Qt::Key_Up: @@ -1611,15 +1593,15 @@ void tst_QTreeWidget::scrollToItem() // Check if all parent nodes of the item found are expanded. // Reported in task #78761 QTreeWidgetItem *search = nullptr; - for (int i=0; i<2; ++i) { + for (int i = 0; i < 2; ++i) { QTreeWidgetItem *bar = new QTreeWidgetItem(testWidget); bar->setText(0, QString::number(i)); - for (int j=0; j<2; ++j) { + for (int j = 0; j < 2; ++j) { QTreeWidgetItem *foo = new QTreeWidgetItem(bar); foo->setText(0, bar->text(0) + QString::number(j)); - for (int k=0; k<2; ++k) { + for (int k = 0; k < 2; ++k) { search = new QTreeWidgetItem(foo); search->setText(0, foo->text(0) + QString::number(k)); } @@ -1639,8 +1621,7 @@ void tst_QTreeWidget::scrollToItem() // From task #85413 void tst_QTreeWidget::setSortingEnabled() { - QStringList hl; - hl << "ID"; + const QStringList hl{ "ID" }; testWidget->setColumnCount(hl.count()); testWidget->setHeaderLabels(hl); @@ -1682,14 +1663,14 @@ void tst_QTreeWidget::addChild() { QTreeWidget tree; for (int x = 0; x < 2; ++x) { - QTreeWidget *view = x ? &tree : static_cast<QTreeWidget*>(0); - QTreeWidgetItem *item = new QTreeWidgetItem((QTreeWidget*)view); + QTreeWidget *view = x ? &tree : static_cast<QTreeWidget*>(nullptr); + QTreeWidgetItem *item = new QTreeWidgetItem(view); QCOMPARE(item->childCount(), 0); // try to add 0 - item->addChild(0); + item->addChild(nullptr); QCOMPARE(item->childCount(), 0); - QCOMPARE(item->indexOfChild(0), -1); + QCOMPARE(item->indexOfChild(nullptr), -1); // add one at a time QList<QTreeWidgetItem*> children; @@ -1762,11 +1743,11 @@ void tst_QTreeWidget::setData() testWidget->setHeaderItem(headerItem); QSignalSpy headerDataChangedSpy( - testWidget->model(), SIGNAL(headerDataChanged(Qt::Orientation,int,int))); + testWidget->model(), &QAbstractItemModel::headerDataChanged); QSignalSpy dataChangedSpy( - testWidget->model(), SIGNAL(dataChanged(QModelIndex,QModelIndex))); + testWidget->model(), &QAbstractItemModel::dataChanged); QSignalSpy itemChangedSpy( - testWidget, SIGNAL(itemChanged(QTreeWidgetItem*,int))); + testWidget, &QTreeWidget::itemChanged); headerItem->setText(0, "test"); QCOMPARE(dataChangedSpy.count(), 0); QCOMPARE(headerDataChangedSpy.count(), 1); @@ -1777,7 +1758,7 @@ void tst_QTreeWidget::setData() { QSignalSpy itemChangedSpy( - testWidget, SIGNAL(itemChanged(QTreeWidgetItem*,int))); + testWidget, &QTreeWidget::itemChanged); QTreeWidgetItem *item = new QTreeWidgetItem(); testWidget->addTopLevelItem(item); for (int x = 0; x < 2; ++x) { @@ -1999,10 +1980,10 @@ void tst_QTreeWidget::itemData() item.setData(0, Qt::DisplayRole, QString("0")); QCOMPARE(widget.currentRoles, QVector<int>({Qt::DisplayRole, Qt::EditRole})); item.setData(0, Qt::CheckStateRole, Qt::PartiallyChecked); - QCOMPARE(widget.currentRoles, {Qt::CheckStateRole}); + QCOMPARE(widget.currentRoles, QVector<int>{Qt::CheckStateRole}); for (int i = 0; i < 4; ++i) { item.setData(0, Qt::UserRole + i, QString::number(i + 1)); - QCOMPARE(widget.currentRoles, {Qt::UserRole + i}); + QCOMPARE(widget.currentRoles, QVector<int>{Qt::UserRole + i}); } QMap<int, QVariant> flags = widget.model()->itemData(widget.model()->index(0, 0)); QCOMPARE(flags.count(), 6); @@ -2069,7 +2050,7 @@ void tst_QTreeWidget::setHeaderLabels() void tst_QTreeWidget::setHeaderItem() { - testWidget->setHeaderItem(0); + testWidget->setHeaderItem(nullptr); QTreeWidgetItem *headerItem = new QTreeWidgetItem(); testWidget->setColumnCount(0); @@ -2118,7 +2099,7 @@ void tst_QTreeWidget::itemWidget() QFETCH(TreeItemList, topLevelItems); QTreeWidget tree; - populate(&tree, topLevelItems, new TreeItem(QStringList() << "1" << "2")); + populate(&tree, topLevelItems, new TreeItem({"1", "2"})); tree.show(); for (int x = 0; x < 2; ++x) { @@ -2126,18 +2107,18 @@ void tst_QTreeWidget::itemWidget() while (QTreeWidgetItem *item = (*it++)) { for (int col = 0; col < item->columnCount(); ++col) { if (x == 0) { - QCOMPARE(tree.itemWidget(item, col), static_cast<QWidget*>(0)); + QCOMPARE(tree.itemWidget(item, col), nullptr); QWidget *editor = new QLineEdit(); tree.setItemWidget(item, col, editor); QCOMPARE(tree.itemWidget(item, col), editor); tree.removeItemWidget(item, col); - QCOMPARE(tree.itemWidget(item, col), static_cast<QWidget*>(0)); + QCOMPARE(tree.itemWidget(item, col), nullptr); } else { // ### should you really be able to open a persistent // editor for an item that isn't editable?? tree.openPersistentEditor(item, col); QWidget *editor = tree.findChild<QLineEdit*>(); - QVERIFY(editor != 0); + QVERIFY(editor != nullptr); tree.closePersistentEditor(item, col); } } @@ -2147,50 +2128,50 @@ void tst_QTreeWidget::itemWidget() void tst_QTreeWidget::insertItemsWithSorting_data() { - QTest::addColumn<int>("sortOrder"); + QTest::addColumn<Qt::SortOrder>("sortOrder"); QTest::addColumn<QStringList>("initialItems"); QTest::addColumn<QStringList>("insertItems"); QTest::addColumn<QStringList>("expectedItems"); QTest::addColumn<IntList>("expectedRows"); QTest::newRow("() + (a) = (a)") - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << QStringList() << (QStringList() << "a") << (QStringList() << "a") << IntList(); QTest::newRow("() + (c, b, a) = (a, b, c)") - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << QStringList() << (QStringList() << "c" << "b" << "a") << (QStringList() << "a" << "b" << "c") << IntList(); QTest::newRow("() + (a, b, c) = (c, b, a)") - << static_cast<int>(Qt::DescendingOrder) + << Qt::DescendingOrder << QStringList() << (QStringList() << "a" << "b" << "c") << (QStringList() << "c" << "b" << "a") << IntList(); QTest::newRow("(a) + (b) = (a, b)") - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << QStringList("a") << (QStringList() << "b") << (QStringList() << "a" << "b") << (IntList() << 0); QTest::newRow("(a) + (b) = (b, a)") - << static_cast<int>(Qt::DescendingOrder) + << Qt::DescendingOrder << QStringList("a") << (QStringList() << "b") << (QStringList() << "b" << "a") << (IntList() << 1); QTest::newRow("(a, c, b) + (d) = (a, b, c, d)") - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << (QStringList() << "a" << "c" << "b") << (QStringList() << "d") << (QStringList() << "a" << "b" << "c" << "d") << (IntList() << 0 << 1 << 2); QTest::newRow("(b, c, a) + (d) = (d, c, b, a)") - << static_cast<int>(Qt::DescendingOrder) + << Qt::DescendingOrder << (QStringList() << "b" << "c" << "a") << (QStringList() << "d") << (QStringList() << "d" << "c" << "b" << "a") @@ -2200,38 +2181,38 @@ void tst_QTreeWidget::insertItemsWithSorting_data() IntList reverseRows; QStringList ascendingItems; QStringList reverseItems; - for (int i = 'a'; i <= 'z'; ++i) { + for (char i = 'a'; i <= 'z'; ++i) { ascendingItems << QString(1, QLatin1Char(i)); reverseItems << QString(1, QLatin1Char('z' - i + 'a')); ascendingRows << i - 'a'; reverseRows << 'z' - i + 'a'; } QTest::newRow("() + (sorted items) = (sorted items)") - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << QStringList() << ascendingItems << ascendingItems << IntList(); QTest::newRow("(sorted items) + () = (sorted items)") - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << ascendingItems << QStringList() << ascendingItems << ascendingRows; QTest::newRow("() + (ascending items) = (reverse items)") - << static_cast<int>(Qt::DescendingOrder) + << Qt::DescendingOrder << QStringList() << ascendingItems << reverseItems << IntList(); QTest::newRow("(reverse items) + () = (ascending items)") - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << reverseItems << QStringList() << ascendingItems << ascendingRows; QTest::newRow("(reverse items) + () = (reverse items)") - << static_cast<int>(Qt::DescendingOrder) + << Qt::DescendingOrder << reverseItems << QStringList() << reverseItems @@ -2241,57 +2222,57 @@ void tst_QTreeWidget::insertItemsWithSorting_data() void tst_QTreeWidget::insertItemsWithSorting() { - QFETCH(int, sortOrder); - QFETCH(QStringList, initialItems); - QFETCH(QStringList, insertItems); - QFETCH(QStringList, expectedItems); + QFETCH(Qt::SortOrder, sortOrder); + QFETCH(const QStringList, initialItems); + QFETCH(const QStringList, insertItems); + QFETCH(const QStringList, expectedItems); QFETCH(IntList, expectedRows); for (int method = 0; method < 5; ++method) { QTreeWidget w; w.setSortingEnabled(true); - w.sortItems(0, static_cast<Qt::SortOrder>(sortOrder)); - for (int i = 0; i < initialItems.count(); ++i) - w.addTopLevelItem(new QTreeWidgetItem(QStringList() << initialItems.at(i))); + w.sortItems(0, sortOrder); + for (const QString &initialItem : initialItems) + w.addTopLevelItem(new QTreeWidgetItem({initialItem})); QAbstractItemModel *model = w.model(); - QList<QPersistentModelIndex> persistent; + PersistentModelIndexVec persistent; for (int j = 0; j < model->rowCount(QModelIndex()); ++j) persistent << model->index(j, 0, QModelIndex()); switch (method) { case 0: // insert using item constructor - for (int i = 0; i < insertItems.size(); ++i) - new QTreeWidgetItem(&w, QStringList() << insertItems.at(i)); + for (const QString &txt : insertItems) + new QTreeWidgetItem(&w, { txt }); break; case 1: { // insert using insertTopLevelItems() QList<QTreeWidgetItem*> lst; - for (int i = 0; i < insertItems.size(); ++i) - lst << new QTreeWidgetItem(QStringList() << insertItems.at(i)); + for (const QString &txt : insertItems) + lst << new QTreeWidgetItem({ txt }); w.insertTopLevelItems(0, lst); break; } case 2: // insert using insertTopLevelItem() - for (int i = 0; i < insertItems.size(); ++i) - w.insertTopLevelItem(0, new QTreeWidgetItem(QStringList() << insertItems.at(i))); + for (const QString &txt : insertItems) + w.insertTopLevelItem(0, new QTreeWidgetItem({ txt })); break; case 3: { // insert using addTopLevelItems() QList<QTreeWidgetItem*> lst; - for (int i = 0; i < insertItems.size(); ++i) - lst << new QTreeWidgetItem(QStringList() << insertItems.at(i)); + for (const QString &txt : insertItems) + lst << new QTreeWidgetItem({ txt }); w.addTopLevelItems(lst); break; } case 4: // insert using addTopLevelItem() - for (int i = 0; i < insertItems.size(); ++i) - w.addTopLevelItem(new QTreeWidgetItem(QStringList() << insertItems.at(i))); + for (const QString &txt : insertItems) + w.addTopLevelItem(new QTreeWidgetItem({ txt })); break; } QCOMPARE(w.topLevelItemCount(), expectedItems.count()); @@ -2305,8 +2286,8 @@ void tst_QTreeWidget::insertItemsWithSorting() void tst_QTreeWidget::insertExpandedItemsWithSorting_data() { - QTest::addColumn<QStringList>("parentText"); - QTest::addColumn<QStringList>("childText"); + QTest::addColumn<QStringList>("parentTexts"); + QTest::addColumn<QStringList>("childTexts"); QTest::addColumn<QStringList>("parentResult"); QTest::addColumn<QStringList>("childResult"); QTest::newRow("test 1") @@ -2319,36 +2300,36 @@ void tst_QTreeWidget::insertExpandedItemsWithSorting_data() // From Task 134978 void tst_QTreeWidget::insertExpandedItemsWithSorting() { - QFETCH(QStringList, parentText); - QFETCH(QStringList, childText); - QFETCH(QStringList, parentResult); - QFETCH(QStringList, childResult); + QFETCH(const QStringList, parentTexts); + QFETCH(const QStringList, childTexts); + QFETCH(const QStringList, parentResult); + QFETCH(const QStringList, childResult); // create a tree with autosorting enabled - CustomTreeWidget tree; + PublicTreeWidget tree; tree.setSortingEnabled(true); // insert expanded items in unsorted order - QList<QTreeWidgetItem *> items; - for (int i = 0; i < parentText.count(); ++i) { - QTreeWidgetItem *parent = new QTreeWidgetItem(&tree, QStringList(parentText.at(i))); + QVector<QTreeWidgetItem *> items; + for (const QString &text : parentTexts) { + QTreeWidgetItem *parent = new QTreeWidgetItem(&tree, {text}); parent->setExpanded(true); QVERIFY(parent->isExpanded()); items << parent; - for (int j = 0; j < childText.count(); ++j) { - QTreeWidgetItem *child = new QTreeWidgetItem(parent, QStringList(childText.at(j))); + for (const QString &text : childTexts) { + QTreeWidgetItem *child = new QTreeWidgetItem(parent, {text}); items << child; } - QCOMPARE(parent->childCount(), childText.count()); + QCOMPARE(parent->childCount(), childTexts.count()); QVERIFY(parent->isExpanded()); } - QCOMPARE(tree.model()->rowCount(), parentText.count()); + QCOMPARE(tree.model()->rowCount(), parentTexts.count()); // verify that the items are still expanded - foreach (QTreeWidgetItem *item, items) { + for (const QTreeWidgetItem *item : qAsConst(items)) { if (item->childCount() > 0) QVERIFY(item->isExpanded()); - QModelIndex idx = tree.indexFromItem(const_cast<QTreeWidgetItem *>(item)); + QModelIndex idx = tree.indexFromItem(item); QVERIFY(idx.isValid()); //QRect rect = tree.visualRect(idx); //QVERIFY(rect.isValid()); @@ -2357,16 +2338,12 @@ void tst_QTreeWidget::insertExpandedItemsWithSorting() // verify that the tree is sorted QAbstractItemModel *model = tree.model(); - QList<QPersistentModelIndex> parents; - for (int i = 0; i < model->rowCount(QModelIndex()); ++i) { - QPersistentModelIndex parent = model->index(i, 0, QModelIndex()); - parents << parent; - } - QList<QPersistentModelIndex> children; - for (int i = 0; i < model->rowCount(parents.first()); ++i) { - QPersistentModelIndex child = model->index(i, 0, parents.first()); - children << child; - } + PersistentModelIndexVec parents; + for (int i = 0; i < model->rowCount(QModelIndex()); ++i) + parents.push_back(model->index(i, 0, QModelIndex())); + PersistentModelIndexVec children; + for (int i = 0; i < model->rowCount(parents.constFirst()); ++i) + children.push_back(model->index(i, 0, parents.constFirst())); for (int i = 0; i < parentResult.count(); ++i) { QTreeWidgetItem *item = tree.topLevelItem(i); QCOMPARE(item->text(0), parentResult.at(i)); @@ -2377,7 +2354,7 @@ void tst_QTreeWidget::insertExpandedItemsWithSorting() void tst_QTreeWidget::changeDataWithSorting_data() { - QTest::addColumn<int>("sortOrder"); + QTest::addColumn<Qt::SortOrder>("sortOrder"); QTest::addColumn<QStringList>("initialItems"); QTest::addColumn<int>("itemIndex"); QTest::addColumn<QString>("newValue"); @@ -2386,49 +2363,49 @@ void tst_QTreeWidget::changeDataWithSorting_data() QTest::addColumn<bool>("reorderingExpected"); QTest::newRow("change a to b in (a)") - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << (QStringList() << "a") << 0 << "b" << (QStringList() << "b") << (IntList() << 0) << false; QTest::newRow("change a to b in (a, c)") - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << (QStringList() << "a" << "c") << 0 << "b" << (QStringList() << "b" << "c") << (IntList() << 0 << 1) << false; QTest::newRow("change a to c in (a, b)") - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << (QStringList() << "a" << "b") << 0 << "c" << (QStringList() << "b" << "c") << (IntList() << 1 << 0) << true; QTest::newRow("change c to a in (c, b)") - << static_cast<int>(Qt::DescendingOrder) + << Qt::DescendingOrder << (QStringList() << "c" << "b") << 0 << "a" << (QStringList() << "b" << "a") << (IntList() << 1 << 0) << true; QTest::newRow("change e to i in (a, c, e, g)") - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << (QStringList() << "a" << "c" << "e" << "g") << 2 << "i" << (QStringList() << "a" << "c" << "g" << "i") << (IntList() << 0 << 1 << 3 << 2) << true; QTest::newRow("change e to a in (c, e, g, i)") - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << (QStringList() << "c" << "e" << "g" << "i") << 1 << "a" << (QStringList() << "a" << "c" << "g" << "i") << (IntList() << 1 << 0 << 2 << 3) << true; QTest::newRow("change e to f in (c, e, g, i)") - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << (QStringList() << "c" << "e" << "g" << "i") << 1 << "f" << (QStringList() << "c" << "f" << "g" << "i") @@ -2438,35 +2415,35 @@ void tst_QTreeWidget::changeDataWithSorting_data() void tst_QTreeWidget::changeDataWithSorting() { - QFETCH(int, sortOrder); - QFETCH(QStringList, initialItems); + QFETCH(Qt::SortOrder, sortOrder); + QFETCH(const QStringList, initialItems); QFETCH(int, itemIndex); - QFETCH(QString, newValue); - QFETCH(QStringList, expectedItems); - QFETCH(IntList, expectedRows); + QFETCH(const QString, newValue); + QFETCH(const QStringList, expectedItems); + QFETCH(const IntList, expectedRows); QFETCH(bool, reorderingExpected); QTreeWidget w; w.setSortingEnabled(true); - w.sortItems(0, static_cast<Qt::SortOrder>(sortOrder)); - for (int i = 0; i < initialItems.count(); ++i) - w.addTopLevelItem(new QTreeWidgetItem(QStringList() << initialItems.at(i))); + w.sortItems(0, sortOrder); + for (const QString &str : initialItems) + w.addTopLevelItem(new QTreeWidgetItem({ str })); QAbstractItemModel *model = w.model(); - QList<QPersistentModelIndex> persistent; + PersistentModelIndexVec persistent; for (int j = 0; j < model->rowCount(QModelIndex()); ++j) persistent << model->index(j, 0, QModelIndex()); - QSignalSpy dataChangedSpy(model, SIGNAL(dataChanged(QModelIndex,QModelIndex))); - QSignalSpy layoutChangedSpy(model, SIGNAL(layoutChanged())); + QSignalSpy dataChangedSpy(model, &QAbstractItemModel::dataChanged); + QSignalSpy layoutChangedSpy(model, &QAbstractItemModel::layoutChanged); QTreeWidgetItem *item = w.topLevelItem(itemIndex); item->setText(0, newValue); for (int i = 0; i < expectedItems.count(); ++i) { QCOMPARE(w.topLevelItem(i)->text(0), expectedItems.at(i)); - for (int j = 0; j < persistent.count(); ++j) { - if (persistent.at(j).row() == i) // the same toplevel row - QCOMPARE(persistent.at(j).internalPointer(), (void *)w.topLevelItem(i)); + for (const QPersistentModelIndex &p : qAsConst(persistent)) { + if (p.row() == i) // the same toplevel row + QCOMPARE(p.internalPointer(), static_cast<void *>(w.topLevelItem(i))); } } @@ -2479,7 +2456,7 @@ void tst_QTreeWidget::changeDataWithSorting() void tst_QTreeWidget::changeDataWithStableSorting_data() { - QTest::addColumn<int>("sortOrder"); + QTest::addColumn<Qt::SortOrder>("sortOrder"); QTest::addColumn<QStringList>("initialItems"); QTest::addColumn<int>("itemIndex"); QTest::addColumn<QString>("newValue"); @@ -2489,7 +2466,7 @@ void tst_QTreeWidget::changeDataWithStableSorting_data() QTest::addColumn<bool>("forceChange"); QTest::newRow("change a to c in (a, c, c, c, e)") - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << (QStringList() << "a" << "c" << "c" << "c" << "e") << 0 << "c" << (QStringList() << "c" << "c" << "c" << "c" << "e") @@ -2497,7 +2474,7 @@ void tst_QTreeWidget::changeDataWithStableSorting_data() << false << false; QTest::newRow("change e to c in (a, c, c, c, e)") - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << (QStringList() << "a" << "c" << "c" << "c" << "e") << 4 << "c" << (QStringList() << "a" << "c" << "c" << "c" << "c") @@ -2505,7 +2482,7 @@ void tst_QTreeWidget::changeDataWithStableSorting_data() << false << false; QTest::newRow("change 1st c to c in (a, c, c, c, e)") - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << (QStringList() << "a" << "c" << "c" << "c" << "e") << 1 << "c" << (QStringList() << "a" << "c" << "c" << "c" << "e") @@ -2513,7 +2490,7 @@ void tst_QTreeWidget::changeDataWithStableSorting_data() << false << true; QTest::newRow("change 2nd c to c in (a, c, c, c, e)") - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << (QStringList() << "a" << "c" << "c" << "c" << "e") << 2 << "c" << (QStringList() << "a" << "c" << "c" << "c" << "e") @@ -2521,7 +2498,7 @@ void tst_QTreeWidget::changeDataWithStableSorting_data() << false << true; QTest::newRow("change 3rd c to c in (a, c, c, c, e)") - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << (QStringList() << "a" << "c" << "c" << "c" << "e") << 3 << "c" << (QStringList() << "a" << "c" << "c" << "c" << "e") @@ -2529,7 +2506,7 @@ void tst_QTreeWidget::changeDataWithStableSorting_data() << false << true; QTest::newRow("change 1st c to c in (e, c, c, c, a)") - << static_cast<int>(Qt::DescendingOrder) + << Qt::DescendingOrder << (QStringList() << "e" << "c" << "c" << "c" << "a") << 1 << "c" << (QStringList() << "e" << "c" << "c" << "c" << "a") @@ -2537,7 +2514,7 @@ void tst_QTreeWidget::changeDataWithStableSorting_data() << false << true; QTest::newRow("change 2nd c to c in (e, c, c, c, a)") - << static_cast<int>(Qt::DescendingOrder) + << Qt::DescendingOrder << (QStringList() << "e" << "c" << "c" << "c" << "a") << 2 << "c" << (QStringList() << "e" << "c" << "c" << "c" << "a") @@ -2545,7 +2522,7 @@ void tst_QTreeWidget::changeDataWithStableSorting_data() << false << true; QTest::newRow("change 3rd c to c in (e, c, c, c, a)") - << static_cast<int>(Qt::DescendingOrder) + << Qt::DescendingOrder << (QStringList() << "e" << "c" << "c" << "c" << "a") << 3 << "c" << (QStringList() << "e" << "c" << "c" << "c" << "a") @@ -2553,7 +2530,7 @@ void tst_QTreeWidget::changeDataWithStableSorting_data() << false << true; QTest::newRow("change 1st c to b in (a, c, c, c, e)") - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << (QStringList() << "a" << "c" << "c" << "c" << "e") << 1 << "b" << (QStringList() << "a" << "b" << "c" << "c" << "e") @@ -2561,7 +2538,7 @@ void tst_QTreeWidget::changeDataWithStableSorting_data() << false << false; QTest::newRow("change 2nd c to b in (a, c, c, c, e)") - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << (QStringList() << "a" << "c" << "c" << "c" << "e") << 2 << "b" << (QStringList() << "a" << "b" << "c" << "c" << "e") @@ -2569,7 +2546,7 @@ void tst_QTreeWidget::changeDataWithStableSorting_data() << true << false; QTest::newRow("change 3rd c to b in (a, c, c, c, e)") - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << (QStringList() << "a" << "c" << "c" << "c" << "e") << 3 << "b" << (QStringList() << "a" << "b" << "c" << "c" << "e") @@ -2577,7 +2554,7 @@ void tst_QTreeWidget::changeDataWithStableSorting_data() << true << false; QTest::newRow("change 1st c to d in (a, c, c, c, e)") - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << (QStringList() << "a" << "c" << "c" << "c" << "e") << 1 << "d" << (QStringList() << "a" << "c" << "c" << "d" << "e") @@ -2585,7 +2562,7 @@ void tst_QTreeWidget::changeDataWithStableSorting_data() << true << false; QTest::newRow("change 2nd c to d in (a, c, c, c, e)") - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << (QStringList() << "a" << "c" << "c" << "c" << "e") << 2 << "d" << (QStringList() << "a" << "c" << "c" << "d" << "e") @@ -2593,7 +2570,7 @@ void tst_QTreeWidget::changeDataWithStableSorting_data() << true << false; QTest::newRow("change 3rd c to d in (a, c, c, c, e)") - << static_cast<int>(Qt::AscendingOrder) + << Qt::AscendingOrder << (QStringList() << "a" << "c" << "c" << "c" << "e") << 3 << "d" << (QStringList() << "a" << "c" << "c" << "d" << "e") @@ -2604,47 +2581,38 @@ void tst_QTreeWidget::changeDataWithStableSorting_data() void tst_QTreeWidget::changeDataWithStableSorting() { - QFETCH(int, sortOrder); - QFETCH(QStringList, initialItems); + QFETCH(Qt::SortOrder, sortOrder); + QFETCH(const QStringList, initialItems); QFETCH(int, itemIndex); - QFETCH(QString, newValue); - QFETCH(QStringList, expectedItems); - QFETCH(IntList, expectedRows); + QFETCH(const QString, newValue); + QFETCH(const QStringList, expectedItems); + QFETCH(const IntList, expectedRows); QFETCH(bool, reorderingExpected); QFETCH(bool, forceChange); - class StableItem : public QTreeWidgetItem - { - public: - StableItem(const QStringList &strings) : QTreeWidgetItem(strings, QTreeWidgetItem::UserType) {} - void forceChangeData() { - emitDataChanged(); - } - }; - QTreeWidget w; w.setSortingEnabled(true); - w.sortItems(0, static_cast<Qt::SortOrder>(sortOrder)); - for (int i = 0; i < initialItems.count(); ++i) - w.addTopLevelItem(new StableItem(QStringList() << initialItems.at(i))); + w.sortItems(0, sortOrder); + for (const QString &str : initialItems) + w.addTopLevelItem(new PublicTreeItem({ str })); QAbstractItemModel *model = w.model(); - QList<QPersistentModelIndex> persistent; + PersistentModelIndexVec persistent; for (int j = 0; j < model->rowCount(QModelIndex()); ++j) persistent << model->index(j, 0, QModelIndex()); - QSignalSpy dataChangedSpy(model, SIGNAL(dataChanged(QModelIndex,QModelIndex))); - QSignalSpy layoutChangedSpy(model, SIGNAL(layoutChanged())); + QSignalSpy dataChangedSpy(model, &QAbstractItemModel::dataChanged); + QSignalSpy layoutChangedSpy(model, &QAbstractItemModel::layoutChanged); - StableItem *item = static_cast<StableItem *>(w.topLevelItem(itemIndex)); + auto *item = static_cast<PublicTreeItem *>(w.topLevelItem(itemIndex)); item->setText(0, newValue); if (forceChange) - item->forceChangeData(); + item->emitDataChanged(); for (int i = 0; i < expectedItems.count(); ++i) { QCOMPARE(w.topLevelItem(i)->text(0), expectedItems.at(i)); - for (int j = 0; j < persistent.count(); ++j) { - if (persistent.at(j).row() == i) // the same toplevel row - QCOMPARE(persistent.at(j).internalPointer(), (void *)w.topLevelItem(i)); + for (const QPersistentModelIndex &p : qAsConst(persistent)) { + if (p.row() == i) // the same toplevel row + QCOMPARE(p.internalPointer(), static_cast<void *>(w.topLevelItem(i))); } } @@ -2657,24 +2625,24 @@ void tst_QTreeWidget::changeDataWithStableSorting() void tst_QTreeWidget::sizeHint_data() { - QTest::addColumn<int>("scrollBarPolicy"); + QTest::addColumn<Qt::ScrollBarPolicy>("scrollBarPolicy"); QTest::addColumn<QSize>("viewSize"); - QTest::newRow("ScrollBarAlwaysOn") << static_cast<int>(Qt::ScrollBarAlwaysOn) << QSize(); - QTest::newRow("ScrollBarAlwaysOff") << static_cast<int>(Qt::ScrollBarAlwaysOff) << QSize(); + QTest::newRow("ScrollBarAlwaysOn") << Qt::ScrollBarAlwaysOn << QSize(); + QTest::newRow("ScrollBarAlwaysOff") << Qt::ScrollBarAlwaysOff << QSize(); // make sure the scrollbars are shown by resizing the view to 40x40 - QTest::newRow("ScrollBarAsNeeded (40x40)") << static_cast<int>(Qt::ScrollBarAsNeeded) << QSize(40, 40); - QTest::newRow("ScrollBarAsNeeded (1000x1000)") << static_cast<int>(Qt::ScrollBarAsNeeded) << QSize(1000, 1000); + QTest::newRow("ScrollBarAsNeeded (40x40)") << Qt::ScrollBarAsNeeded << QSize(40, 40); + QTest::newRow("ScrollBarAsNeeded (1000x1000)") << Qt::ScrollBarAsNeeded << QSize(1000, 1000); } void tst_QTreeWidget::sizeHint() { - QFETCH(int, scrollBarPolicy); + QFETCH(Qt::ScrollBarPolicy, scrollBarPolicy); QFETCH(QSize, viewSize); QTreeWidget view; view.setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); - view.setVerticalScrollBarPolicy(static_cast<Qt::ScrollBarPolicy>(scrollBarPolicy)); - view.setHorizontalScrollBarPolicy(static_cast<Qt::ScrollBarPolicy>(scrollBarPolicy)); + view.setVerticalScrollBarPolicy(scrollBarPolicy); + view.setHorizontalScrollBarPolicy(scrollBarPolicy); view.setColumnCount(2); for (int i = 0 ; i < view.columnCount(); ++i) view.addTopLevelItem(new QTreeWidgetItem(QStringList{"foo","bar"})); @@ -2726,36 +2694,36 @@ void tst_QTreeWidget::itemOperatorLessThan() void tst_QTreeWidget::sortedIndexOfChild_data() { - QTest::addColumn<int>("sortOrder"); + QTest::addColumn<Qt::SortOrder>("sortOrder"); QTest::addColumn<QStringList>("itemTexts"); - QTest::addColumn<QList<int> >("expectedIndexes"); + QTest::addColumn<IntList>("expectedIndexes"); QTest::newRow("three ascending") - << int(Qt::AscendingOrder) - << (QStringList() << "A" << "B" << "C") - << (QList<int>() << 0 << 1 << 2); + << Qt::AscendingOrder + << (QStringList{"A", "B", "C"}) + << (IntList{0, 1, 2}); QTest::newRow("three descending") - << int(Qt::DescendingOrder) - << (QStringList() << "A" << "B" << "C") - << (QList<int>() << 2 << 1 << 0); + << Qt::DescendingOrder + << (QStringList{"A", "B", "C"}) + << (IntList{2, 1, 0}); } void tst_QTreeWidget::sortedIndexOfChild() { - QFETCH(int, sortOrder); - QFETCH(QStringList, itemTexts); - QFETCH(QList<int>, expectedIndexes); + QFETCH(Qt::SortOrder, sortOrder); + QFETCH(const QStringList, itemTexts); + QFETCH(const IntList, expectedIndexes); QTreeWidget tw; - QList<QTreeWidgetItem*> itms; - QTreeWidgetItem *top = new QTreeWidgetItem(&tw, QStringList() << "top"); + QVector<QTreeWidgetItem *> itms; + auto *top = new QTreeWidgetItem(&tw, {"top"}); - for (int i = 0; i < itemTexts.count(); ++i) - itms << new QTreeWidgetItem(top, QStringList() << itemTexts.at(i)); + for (const QString &str : itemTexts) + itms << new QTreeWidgetItem(top, {str}); - tw.sortItems(0, (Qt::SortOrder)sortOrder); + tw.sortItems(0, sortOrder); tw.expandAll(); QCOMPARE(itms.count(), expectedIndexes.count()); @@ -2773,8 +2741,8 @@ void tst_QTreeWidget::expandAndCallapse() for (int j = 0; j < 10; ++j) new QTreeWidgetItem(p, QStringList(QString::number(j))); } - QSignalSpy spy0(&tw, SIGNAL(itemExpanded(QTreeWidgetItem*))); - QSignalSpy spy1(&tw, SIGNAL(itemCollapsed(QTreeWidgetItem*))); + QSignalSpy spy0(&tw, &QTreeWidget::itemExpanded); + QSignalSpy spy1(&tw, &QTreeWidget::itemCollapsed); tw.expandItem(p); @@ -2909,20 +2877,12 @@ void tst_QTreeWidget::removeSelectedItem() QCOMPARE(selModel->isSelected(w->model()->index(0,0)), false); } -class AnotherTreeWidget : public QTreeWidget -{ - Q_OBJECT -public: - AnotherTreeWidget(QWidget *parent = 0) : QTreeWidget(parent) {} - void deleteCurrent() { if (currentItem()) delete currentItem(); } -}; - void tst_QTreeWidget::removeCurrentItem() { - AnotherTreeWidget widget; - QObject::connect(widget.selectionModel(), - SIGNAL(currentChanged(QModelIndex,QModelIndex)), - &widget, SLOT(clear())); + PublicTreeWidget widget; + connect(widget.selectionModel(), + &QItemSelectionModel::currentChanged, + &widget, &PublicTreeWidget::clear); QTreeWidgetItem *item = new QTreeWidgetItem(&widget); widget.setCurrentItem(item); widget.deleteCurrent(); @@ -2930,9 +2890,9 @@ void tst_QTreeWidget::removeCurrentItem() void tst_QTreeWidget::removeCurrentItem_task186451() { - AnotherTreeWidget widget; - QTreeWidgetItem *item = new QTreeWidgetItem(&widget, QStringList() << "1"); - QTreeWidgetItem *item2 = new QTreeWidgetItem(&widget, QStringList() << "2"); + PublicTreeWidget widget; + QTreeWidgetItem *item = new QTreeWidgetItem(&widget, {"1"}); + QTreeWidgetItem *item2 = new QTreeWidgetItem(&widget, {"2"}); widget.setCurrentItem(item); widget.deleteCurrent(); @@ -2940,19 +2900,6 @@ void tst_QTreeWidget::removeCurrentItem_task186451() QCOMPARE(item2, widget.currentItem()); } - -class TreeWidget : QTreeWidget { - -public: - QModelIndex indexFromItem(QTreeWidgetItem *item, int column = 0) const { - return QTreeWidget::indexFromItem(item, column); - } - QTreeWidgetItem *itemFromIndex(const QModelIndex &index) const { - return QTreeWidget::itemFromIndex(index); - } -}; - - void tst_QTreeWidget::randomExpand() { QTreeWidget tree; @@ -2970,9 +2917,8 @@ void tst_QTreeWidget::randomExpand() \- item4 */ - QTreeWidgetItem *newItem1 = 0; for (int i = 0; i < 100; i++) { - newItem1 = new QTreeWidgetItem(&tree, item1); + auto newItem1 = new QTreeWidgetItem(&tree, item1); newItem1->setExpanded(true); QCOMPARE(newItem1->isExpanded(), true); @@ -2982,35 +2928,34 @@ void tst_QTreeWidget::randomExpand() QCOMPARE(newItem1->isExpanded(), true); } - } void tst_QTreeWidget::crashTest() { - QTreeWidget *tree = new QTreeWidget(); - tree->setColumnCount(1); - tree->show(); + QTreeWidget tree; + tree.setColumnCount(1); + tree.show(); - QTreeWidgetItem *item1 = new QTreeWidgetItem(tree); + QTreeWidgetItem *item1 = new QTreeWidgetItem(&tree); item1->setText(0, "item1"); item1->setExpanded(true); QTreeWidgetItem *item2 = new QTreeWidgetItem(item1); item2->setText(0, "item2"); - QTreeWidgetItem *item3 = new QTreeWidgetItem(tree, item1); + QTreeWidgetItem *item3 = new QTreeWidgetItem(&tree, item1); item3->setText(0, "item3"); item3->setExpanded(true); QTreeWidgetItem *item4 = new QTreeWidgetItem(item3); item4->setText(0, "item4"); - QTreeWidgetItem *item5 = new QTreeWidgetItem(tree, item3); + QTreeWidgetItem *item5 = new QTreeWidgetItem(&tree, item3); item5->setText(0, "item5"); item5->setExpanded(true); QTreeWidgetItem *item6 = new QTreeWidgetItem(item5); item6->setText(0, "item6"); for (int i = 0; i < 1000; i++) { - QTreeWidgetItem *newItem1 = new QTreeWidgetItem(tree, item1); + QTreeWidgetItem *newItem1 = new QTreeWidgetItem(&tree, item1); newItem1->setText(0, "newItem"); QTreeWidgetItem *newItem2 = new QTreeWidgetItem(newItem1); newItem2->setText(0, "subItem1"); @@ -3019,23 +2964,23 @@ void tst_QTreeWidget::crashTest() delete item3; item3 = newItem1; } - QApplication::instance()->processEvents(); - - delete tree; + QCoreApplication::processEvents(); } class CrashWidget : public QTreeWidget { public: - CrashWidget(QWidget *parent = 0) : QTreeWidget(parent), i(0) { + CrashWidget(QWidget *parent = nullptr) : QTreeWidget(parent) + { setSortingEnabled(true); timerId = startTimer(10); } - int i; + int i = 0; protected: - void timerEvent(QTimerEvent * event) { + void timerEvent(QTimerEvent * event) override + { if (event->timerId() == timerId) { - QTreeWidgetItem *newItem = new QTreeWidgetItem((QStringList() << QString::number(i++))); + auto newItem = new QTreeWidgetItem({QString::number(i++)}); m_list.append(newItem); insertTopLevelItem(0, newItem); while (m_list.count() > 10) @@ -3045,7 +2990,7 @@ protected: } private: int timerId; - QList<QTreeWidgetItem*> m_list; + QVector<QTreeWidgetItem*> m_list; }; void tst_QTreeWidget::sortAndSelect() @@ -3068,12 +3013,13 @@ void tst_QTreeWidget::defaultRowSizes() const QScopedPointer<QTreeWidget> tw(new QTreeWidget); tw->setIconSize(QSize(50, 50)); tw->setColumnCount(6); - for (int i=0; i<10; ++i) { + for (int i = 0; i < 10; ++i) { auto it = new QTreeWidgetItem(tw.data()); - for (int j=0; j<tw->columnCount() - 1; ++j) { + for (int j = 0; j < tw->columnCount() - 1; ++j) it->setText(j, "This is a test"); - } - QPixmap icon = tw->style()->standardPixmap((QStyle::StandardPixmap)(i + QStyle::SP_TitleBarMenuButton)); + auto sp = static_cast<QStyle::StandardPixmap>(i + QStyle::SP_TitleBarMenuButton); + QPixmap icon = tw->style()->standardPixmap(sp); + if (icon.isNull()) QSKIP("No pixmap found on current style, skipping this test."); it->setIcon(tw->columnCount() - 1, @@ -3089,8 +3035,8 @@ void tst_QTreeWidget::defaultRowSizes() void tst_QTreeWidget::task191552_rtl() { - Qt::LayoutDirection oldDir = qApp->layoutDirection(); - qApp->setLayoutDirection(Qt::RightToLeft); + Qt::LayoutDirection oldDir = QGuiApplication::layoutDirection(); + QGuiApplication::setLayoutDirection(Qt::RightToLeft); QTreeWidget tw; tw.setColumnCount(1); @@ -3111,7 +3057,7 @@ void tst_QTreeWidget::task191552_rtl() QTest::mouseClick(tw.viewport(), Qt::LeftButton, Qt::NoModifier, checkRect.center()); QCOMPARE(item->checkState(0), Qt::Unchecked); - qApp->setLayoutDirection(oldDir); + QGuiApplication::setLayoutDirection(oldDir); } void tst_QTreeWidget::task203673_selection() @@ -3210,7 +3156,7 @@ void tst_QTreeWidget::task253109_itemHeight() QTreeWidgetItem item(&treeWidget); class MyWidget : public QWidget { - virtual QSize sizeHint() const { return QSize(200,100); } + QSize sizeHint() const override { return QSize(200, 100); } } w; treeWidget.setItemWidget(&item, 0, &w); @@ -3230,24 +3176,23 @@ void tst_QTreeWidget::task206367_duplication() treeWidget.setHeaderHidden(true); treeWidget.setSortingEnabled(true); - QTreeWidgetItem* rootItem = new QTreeWidgetItem( &treeWidget, QStringList("root") ); + QTreeWidgetItem* rootItem = new QTreeWidgetItem(&treeWidget, QStringList("root")); for (int nFile = 0; nFile < 2; nFile++ ) { - QTreeWidgetItem* itemFile = new QTreeWidgetItem(rootItem, QStringList(QString::number(nFile))); + QTreeWidgetItem* itemFile = new QTreeWidgetItem(rootItem, {QString::number(nFile)}); for (int nRecord = 0; nRecord < 2; nRecord++) - new QTreeWidgetItem(itemFile , QStringList(QString::number(nRecord))); + new QTreeWidgetItem(itemFile, {QString::number(nRecord)}); itemFile->setExpanded(true); } rootItem->setExpanded(true); //there should be enough room for 2x2 items. If there is a scrollbar, it means the items are duplicated QTRY_VERIFY(!treeWidget.verticalScrollBar()->isVisible()); - } void tst_QTreeWidget::itemSelectionChanged() { QVERIFY(testWidget); - if(testWidget->topLevelItem(0)) + if (testWidget->topLevelItem(0)) QVERIFY(testWidget->topLevelItem(0)->isSelected()); } @@ -3255,14 +3200,18 @@ void tst_QTreeWidget::selectionOrder() { testWidget->setColumnCount(1); QList<QTreeWidgetItem *> items; - for (int i = 0; i < 10; ++i) - items.append(new QTreeWidgetItem((QTreeWidget*)0, QStringList(QLatin1String("item: ") + QString::number(i)))); + for (int i = 0; i < 10; ++i) { + items.append(new QTreeWidgetItem(static_cast<QTreeWidget *>(nullptr), + {QStringLiteral("item: %1").arg(i)})); + } testWidget->insertTopLevelItems(0, items); - QModelIndex idx = testWidget->indexFromItem(items[0]); - connect(testWidget, SIGNAL(itemSelectionChanged()), this, SLOT(itemSelectionChanged())); + QModelIndex idx = testWidget->indexFromItem(items.at(0)); + connect(testWidget, &QTreeWidget::itemSelectionChanged, + this, &tst_QTreeWidget::itemSelectionChanged); testWidget->selectionModel()->select(idx, QItemSelectionModel::SelectCurrent); - disconnect(testWidget, SIGNAL(itemSelectionChanged()), this, SLOT(itemSelectionChanged())); + disconnect(testWidget, &QTreeWidget::itemSelectionChanged, + this, &tst_QTreeWidget::itemSelectionChanged); } void tst_QTreeWidget::setSelectionModel() @@ -3271,7 +3220,7 @@ void tst_QTreeWidget::setSelectionModel() for(int i = 0; i < 3; ++i) new QTreeWidgetItem(&tree, QStringList(QString::number(i))); QItemSelectionModel selection(tree.model()); - selection.select(tree.model()->index(1,0), QItemSelectionModel::Select); + selection.select(tree.model()->index(1, 0), QItemSelectionModel::Select); tree.setSelectionModel(&selection); QCOMPARE(tree.topLevelItem(1)->isSelected(), true); } @@ -3301,9 +3250,9 @@ void tst_QTreeWidget::task217309() void tst_QTreeWidget::nonEditableTristate() { // A tree with checkable items, the parent is tristate - QTreeWidget *tree = new QTreeWidget; - QTreeWidgetItem *item = new QTreeWidgetItem(); - tree->insertTopLevelItem(0, item); + QTreeWidget tree; + QTreeWidgetItem *item = new QTreeWidgetItem; + tree.insertTopLevelItem(0, item); item->setFlags(item->flags() | Qt::ItemIsAutoTristate); item->setCheckState(0, Qt::Unchecked); QTreeWidgetItem *subitem1 = new QTreeWidgetItem(item); @@ -3311,53 +3260,46 @@ void tst_QTreeWidget::nonEditableTristate() QTreeWidgetItem *subitem2 = new QTreeWidgetItem(item); subitem2->setCheckState(0, Qt::Unchecked); QCOMPARE(int(item->checkState(0)), int(Qt::Unchecked)); - tree->show(); + tree.show(); + QVERIFY(QTest::qWaitForWindowExposed(&tree)); // Test clicking on the parent item, it should become Checked (not PartiallyChecked) QStyleOptionViewItem option; - option.rect = tree->visualRect(tree->model()->index(0, 0)); + option.rect = tree.visualRect(tree.model()->index(0, 0)); option.state |= QStyle::State_Enabled; option.features |= QStyleOptionViewItem::HasCheckIndicator | QStyleOptionViewItem::HasDisplay; option.checkState = item->checkState(0); - const int checkMargin = qApp->style()->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, 0) + 1; - QPoint pos = qApp->style()->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &option, 0).center() + QPoint(checkMargin, 0); - QTest::mouseClick(tree->viewport(), Qt::LeftButton, Qt::NoModifier, pos); - QCOMPARE(int(item->checkState(0)), int(Qt::Checked)); + auto appStyle = QApplication::style(); + const int checkMargin = appStyle->pixelMetric( + QStyle::PM_FocusFrameHMargin, nullptr, nullptr) + 1; + QPoint pos = appStyle->subElementRect( + QStyle::SE_ItemViewItemCheckIndicator, &option, nullptr).center(); + pos.rx() += checkMargin; + QTest::mouseClick(tree.viewport(), Qt::LeftButton, Qt::NoModifier, pos); + QCOMPARE(item->checkState(0), Qt::Checked); // Click again, it should become Unchecked. - QTest::mouseClick(tree->viewport(), Qt::LeftButton, Qt::NoModifier, pos); - QCOMPARE(int(item->checkState(0)), int(Qt::Unchecked)); - - delete tree; + QTest::mouseClick(tree.viewport(), Qt::LeftButton, Qt::NoModifier, pos); + QCOMPARE(item->checkState(0), Qt::Unchecked); } -class TreeWidgetItem : public QTreeWidgetItem -{ - -public: - void _emitDataChanged() { emitDataChanged(); } - -}; - void tst_QTreeWidget::emitDataChanged() { - - QTreeWidget *tree = new QTreeWidget; - QSignalSpy spy(tree, SIGNAL(itemChanged(QTreeWidgetItem*,int))); - TreeWidgetItem *item = new TreeWidgetItem(); - tree->insertTopLevelItem(0, item); - item->_emitDataChanged(); + QTreeWidget tree; + QSignalSpy spy(&tree, &QTreeWidget::itemChanged); + auto item = new PublicTreeItem; + tree.insertTopLevelItem(0, item); + item->emitDataChanged(); QCOMPARE(spy.count(), 1); - } void tst_QTreeWidget::setCurrentItemExpandsParent() { QTreeWidget w; w.setColumnCount(1); - QTreeWidgetItem *i1 = new QTreeWidgetItem(&w, QStringList() << "parent"); - QTreeWidgetItem *i2 = new QTreeWidgetItem(i1, QStringList() << "child"); + QTreeWidgetItem *i1 = new QTreeWidgetItem(&w, {"parent"}); + QTreeWidgetItem *i2 = new QTreeWidgetItem(i1, {"child"}); QVERIFY(!i2->isExpanded()); QVERIFY(!w.currentItem()); w.setCurrentItem(i2); @@ -3373,13 +3315,13 @@ void tst_QTreeWidget::task239150_editorWidth() QStyleOptionFrame opt; opt.init(&tree); const int minWidth = tree.style()->sizeFromContents(QStyle::CT_LineEdit, &opt, QSize(0, 0). - expandedTo(QApplication::globalStrut()), 0).width(); + expandedTo(QApplication::globalStrut()), nullptr).width(); { QTreeWidgetItem item; item.setFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled ); tree.addTopLevelItem(&item); - QVERIFY(tree.itemWidget(&item, 0) == 0); + QVERIFY(tree.itemWidget(&item, 0) == nullptr); tree.editItem(&item); QVERIFY(tree.itemWidget(&item, 0)); QVERIFY(tree.itemWidget(&item, 0)->width() >= minWidth); @@ -3391,7 +3333,7 @@ void tst_QTreeWidget::task239150_editorWidth() item.setText(0, "foooooooooooooooooooooooo"); item.setFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled ); tree.addTopLevelItem(&item); - QVERIFY(tree.itemWidget(&item, 0) == 0); + QVERIFY(tree.itemWidget(&item, 0) == nullptr); tree.editItem(&item); QVERIFY(tree.itemWidget(&item, 0)); QVERIFY(tree.itemWidget(&item, 0)->width() >= minWidth + tree.fontMetrics().horizontalAdvance(item.text(0))); @@ -3408,23 +3350,21 @@ void tst_QTreeWidget::setTextUpdate() class MyItemDelegate : public QStyledItemDelegate { public: - MyItemDelegate() : numPaints(0) { } - void paint(QPainter *painter, - const QStyleOptionViewItem &option, const QModelIndex &index) const + using QStyledItemDelegate::QStyledItemDelegate; + void paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const override { numPaints++; QStyledItemDelegate::paint(painter, option, index); } - mutable int numPaints; + mutable int numPaints = 0; } delegate; treeWidget.setItemDelegate(&delegate); treeWidget.show(); QVERIFY(QTest::qWaitForWindowExposed(&treeWidget)); - QStringList strList; - strList << "variable1" << "0"; - QTreeWidgetItem *item = new QTreeWidgetItem(strList); + QTreeWidgetItem *item = new QTreeWidgetItem({ "variable1", "0" }); treeWidget.insertTopLevelItem(0, item); QTRY_VERIFY(delegate.numPaints > 0); delegate.numPaints = 0; @@ -3435,7 +3375,7 @@ void tst_QTreeWidget::setTextUpdate() void tst_QTreeWidget::taskQTBUG2844_visualItemRect() { - CustomTreeWidget tree; + PublicTreeWidget tree; tree.resize(150, 100); tree.setColumnCount(3); QTreeWidgetItem item(&tree); @@ -3457,15 +3397,17 @@ void tst_QTreeWidget::setChildIndicatorPolicy() class MyItemDelegate : public QStyledItemDelegate { public: - MyItemDelegate() : numPaints(0), expectChildren(false) { } - void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const + using QStyledItemDelegate::QStyledItemDelegate; + void paint(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const override { numPaints++; QCOMPARE(!(option.state & QStyle::State_Children), !expectChildren); QStyledItemDelegate::paint(painter, option, index); } - mutable int numPaints; - bool expectChildren; + mutable int numPaints = 0; + bool expectChildren = false; } delegate; treeWidget.setItemDelegate(&delegate); @@ -3503,19 +3445,15 @@ void tst_QTreeWidget::setChildIndicatorPolicy() // The test passes simply if it doesn't crash. void tst_QTreeWidget::taskQTBUG_34717_collapseAtBottom() { - struct PublicTreeWidget: public QTreeWidget - { - inline int sizeHintForColumn(int column) const { return QTreeWidget::sizeHintForColumn(column); } - }; PublicTreeWidget treeWidget; treeWidget.header()->setSectionResizeMode(QHeaderView::ResizeToContents); treeWidget.setColumnCount(2); - QTreeWidgetItem *mainItem = new QTreeWidgetItem(&treeWidget, QStringList() << "Root"); + QTreeWidgetItem *mainItem = new QTreeWidgetItem(&treeWidget, { "Root" }); for (int i = 0; i < 200; ++i) { - QTreeWidgetItem *item = new QTreeWidgetItem(mainItem, QStringList(QString("Item"))); - new QTreeWidgetItem(item, QStringList() << "Child" << "1"); - new QTreeWidgetItem(item, QStringList() << "Child" << "2"); - new QTreeWidgetItem(item, QStringList() << "Child" << "3"); + QTreeWidgetItem *item = new QTreeWidgetItem(mainItem, { "Item" }); + new QTreeWidgetItem(item, { "Child", "1" }); + new QTreeWidgetItem(item, { "Child", "2" }); + new QTreeWidgetItem(item, { "Child", "3" }); } treeWidget.show(); treeWidget.expandAll(); @@ -3545,11 +3483,8 @@ void tst_QTreeWidget::task20345_sortChildren() tw.setSortingEnabled(true); tw.show(); - QTreeWidgetItem *rootItem = 0; - QTreeWidgetItem *childItem = 0; - - rootItem = new QTreeWidgetItem(&tw, QStringList("a")); - childItem = new QTreeWidgetItem(rootItem); + auto rootItem = new QTreeWidgetItem(&tw, QStringList("a")); + auto childItem = new QTreeWidgetItem(rootItem); childItem->setText(1, "3"); childItem = new QTreeWidgetItem(rootItem); childItem->setText(1, "1"); @@ -3558,10 +3493,10 @@ void tst_QTreeWidget::task20345_sortChildren() tw.setCurrentItem(tw.topLevelItem(0)); - QTreeWidgetItem * curItem = tw.currentItem(); + QTreeWidgetItem *curItem = tw.currentItem(); int childCount = curItem->childCount() + 1; - QTreeWidgetItem * newItem = new QTreeWidgetItem(curItem); + QTreeWidgetItem *newItem = new QTreeWidgetItem(curItem); newItem->setText(1, QString::number(childCount)); rootItem->sortChildren(1, Qt::AscendingOrder); QVERIFY(1); @@ -3569,7 +3504,7 @@ void tst_QTreeWidget::task20345_sortChildren() void tst_QTreeWidget::getMimeDataWithInvalidItem() { - CustomTreeWidget w; + PublicTreeWidget w; QTest::ignoreMessage(QtWarningMsg, "QTreeWidget::mimeData: Null-item passed"); QMimeData *md = w.mimeData(QList<QTreeWidgetItem*>() << nullptr); QVERIFY(!md); diff --git a/tests/auto/widgets/itemviews/qtreewidgetitemiterator/tst_qtreewidgetitemiterator.cpp b/tests/auto/widgets/itemviews/qtreewidgetitemiterator/tst_qtreewidgetitemiterator.cpp index 76ca148d3f..68d149fc6e 100644 --- a/tests/auto/widgets/itemviews/qtreewidgetitemiterator/tst_qtreewidgetitemiterator.cpp +++ b/tests/auto/widgets/itemviews/qtreewidgetitemiterator/tst_qtreewidgetitemiterator.cpp @@ -27,20 +27,19 @@ ****************************************************************************/ -#include <QtTest/QtTest> +#include <QTreeWidget> +#include <QTreeWidgetItemIterator> +#include <QTest> -#include <qtreewidget.h> -#include <qtreewidgetitemiterator.h> -#include <qapplication.h> -#include <qeventloop.h> -#include <qdebug.h> +Q_DECLARE_METATYPE(QTreeWidgetItemIterator::IteratorFlag) +Q_DECLARE_METATYPE(QTreeWidgetItemIterator::IteratorFlags) class tst_QTreeWidgetItemIterator : public QObject { Q_OBJECT public: - tst_QTreeWidgetItemIterator(); + using QObject::QObject; private slots: void initTestCase(); @@ -65,13 +64,9 @@ private slots: void initializeIterator(); void sortingEnabled(); private: - QTreeWidget *testWidget; + QTreeWidget *testWidget = nullptr; }; -tst_QTreeWidgetItemIterator::tst_QTreeWidgetItemIterator(): testWidget(0) -{ -} - void tst_QTreeWidgetItemIterator::initTestCase() { testWidget = new QTreeWidget(); @@ -90,7 +85,7 @@ void tst_QTreeWidgetItemIterator::initTestCase() * |Qt::ItemIsDropEnabled * */ - for (int i=0; i <= 16; ++i) { + for (int i = 0; i <= 16; ++i) { QTreeWidgetItem *top = new QTreeWidgetItem(testWidget); const QString topS = QLatin1String("top") + QString::number(i); top->setText(0, topS); @@ -111,9 +106,7 @@ void tst_QTreeWidgetItemIterator::initTestCase() case 9: top->setFlags(Qt::ItemIsEnabled);break; case 10: top->setFlags(Qt::ItemIsEnabled);break; - case 11: - top->setFlags(0); - break; + case 11: top->setFlags({});break; case 12: top->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable);break; case 13: top->setFlags(Qt::ItemIsEnabled);break; @@ -142,7 +135,7 @@ void tst_QTreeWidgetItemIterator::initTestCase() case 9: child->setFlags(Qt::ItemIsEnabled);break; case 10: child->setFlags(Qt::ItemIsEnabled);break; - case 11: child->setFlags(0);break; + case 11: child->setFlags({});break; case 12: child->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable);break; case 13: child->setFlags(Qt::ItemIsEnabled);break; @@ -188,10 +181,10 @@ void tst_QTreeWidgetItemIterator::iteratorflags_data() NotEditable = 0x00020000 */ QTest::addColumn<int>("start"); - QTest::addColumn<int>("iteratorflags"); + QTest::addColumn<QTreeWidgetItemIterator::IteratorFlags>("iteratorflags"); QTest::addColumn<QStringList>("matches"); - QTest::newRow("Match all") << 0 << (int)QTreeWidgetItemIterator::All + QTest::newRow("Match all") << 0 << QTreeWidgetItemIterator::IteratorFlags(QTreeWidgetItemIterator::All) << (QStringList() << "top0" << "top0,child0" << "top0,child1" << "top0,child2" << "top0,child3" << "top0,child4" << "top0,child5" << "top0,child6" << "top0,child7" @@ -279,7 +272,7 @@ void tst_QTreeWidgetItemIterator::iteratorflags_data() << "top16,child12" << "top16,child13" << "top16,child14" << "top16,child15" << "top16,child16"); - QTest::newRow("Match hidden") << 0 << (int)QTreeWidgetItemIterator::Hidden + QTest::newRow("Match hidden") << 0 << QTreeWidgetItemIterator::IteratorFlags(QTreeWidgetItemIterator::Hidden) << (QStringList() << "top0" << "top0,child0" // fails due to hidden row << "top1,child0" @@ -299,7 +292,7 @@ void tst_QTreeWidgetItemIterator::iteratorflags_data() << "top15,child0" << "top16,child0"); - QTest::newRow("Match not hidden") << 0 << (int)QTreeWidgetItemIterator::NotHidden + QTest::newRow("Match not hidden") << 0 << QTreeWidgetItemIterator::IteratorFlags(QTreeWidgetItemIterator::NotHidden) << (QStringList() << "top0,child1" << "top0,child2" << "top0,child3" << "top0,child4" << "top0,child5" << "top0,child6" << "top0,child7" @@ -387,7 +380,7 @@ void tst_QTreeWidgetItemIterator::iteratorflags_data() << "top16,child12" << "top16,child13" << "top16,child14" << "top16,child15" << "top16,child16"); - QTest::newRow("Match selected") << 0 << (int)QTreeWidgetItemIterator::Selected + QTest::newRow("Match selected") << 0 << QTreeWidgetItemIterator::IteratorFlags(QTreeWidgetItemIterator::Selected) << (QStringList() << "top0,child2" << "top1,child2" @@ -407,7 +400,7 @@ void tst_QTreeWidgetItemIterator::iteratorflags_data() << "top15,child2" << "top16,child2"); - QTest::newRow("Match selectable") << 0 << (int)QTreeWidgetItemIterator::Selectable + QTest::newRow("Match selectable") << 0 << QTreeWidgetItemIterator::IteratorFlags(QTreeWidgetItemIterator::Selectable) << (QStringList() << "top0" << "top0,child0" << "top0,child1" << "top0,child2" << "top0,child3" << "top0,child4" @@ -479,7 +472,7 @@ void tst_QTreeWidgetItemIterator::iteratorflags_data() << "top16,child16"); - QTest::newRow("Match DragEnabled") << 0 << (int)QTreeWidgetItemIterator::DragEnabled + QTest::newRow("Match DragEnabled") << 0 << QTreeWidgetItemIterator::IteratorFlags(QTreeWidgetItemIterator::DragEnabled) << (QStringList() << "top0" << "top0,child0" << "top0,child1" << "top0,child2" << "top0,child3" << "top0,child6" @@ -550,7 +543,7 @@ void tst_QTreeWidgetItemIterator::iteratorflags_data() << "top16,child14" << "top16,child15" << "top16,child16"); - QTest::newRow("Match DragDisabled") << 0 << (int)QTreeWidgetItemIterator::DragDisabled + QTest::newRow("Match DragDisabled") << 0 << QTreeWidgetItemIterator::IteratorFlags(QTreeWidgetItemIterator::DragDisabled) << (QStringList() /* top0 */ @@ -623,7 +616,7 @@ void tst_QTreeWidgetItemIterator::iteratorflags_data() << "top16,child13" ); - QTest::newRow("Match DropEnabled") << 0 << (int)QTreeWidgetItemIterator::DropEnabled + QTest::newRow("Match DropEnabled") << 0 << QTreeWidgetItemIterator::IteratorFlags(QTreeWidgetItemIterator::DropEnabled) << (QStringList() << "top0" << "top0,child0" << "top0,child1" << "top0,child2" << "top0,child3" << "top0,child8" @@ -694,12 +687,12 @@ void tst_QTreeWidgetItemIterator::iteratorflags_data() << "top16,child14" << "top16,child15" << "top16,child16"); - QTest::newRow("Match HasChildren") << 0 << (int)QTreeWidgetItemIterator::HasChildren + QTest::newRow("Match HasChildren") << 0 << QTreeWidgetItemIterator::IteratorFlags(QTreeWidgetItemIterator::HasChildren) << (QStringList() << "top0" << "top1" << "top2" << "top3" << "top4" << "top5" << "top6" << "top7" << "top8" << "top9" << "top10" << "top11" << "top12" << "top13" << "top14" << "top15" << "top16"); - QTest::newRow("Match Checked") << 0 << (int)QTreeWidgetItemIterator::Checked + QTest::newRow("Match Checked") << 0 << QTreeWidgetItemIterator::IteratorFlags(QTreeWidgetItemIterator::Checked) << (QStringList() << "top0,child14" << "top0,child16" << "top1,child14" << "top1,child16" @@ -721,7 +714,7 @@ void tst_QTreeWidgetItemIterator::iteratorflags_data() << "top16" << "top16,child14" << "top16,child16"); - QTest::newRow("Match NotChecked") << 0 << (int)QTreeWidgetItemIterator::NotChecked + QTest::newRow("Match NotChecked") << 0 << QTreeWidgetItemIterator::IteratorFlags(QTreeWidgetItemIterator::NotChecked) << (QStringList() << "top0" << "top0,child0" << "top0,child1" << "top0,child2" << "top0,child3" << "top0,child4" << "top0,child5" << "top0,child6" << "top0,child7" @@ -810,7 +803,7 @@ void tst_QTreeWidgetItemIterator::iteratorflags_data() - QTest::newRow("Match Disabled") << 0 << (int)QTreeWidgetItemIterator::Disabled + QTest::newRow("Match Disabled") << 0 << QTreeWidgetItemIterator::IteratorFlags(QTreeWidgetItemIterator::Disabled) << (QStringList() << "top0,child11" << "top1,child11" @@ -848,7 +841,7 @@ void tst_QTreeWidgetItemIterator::iteratorflags_data() << "top15,child11" << "top16,child11"); - QTest::newRow("Match Editable") << 0 << (int)QTreeWidgetItemIterator::Editable + QTest::newRow("Match Editable") << 0 << QTreeWidgetItemIterator::IteratorFlags(QTreeWidgetItemIterator::Editable) << (QStringList() << "top0,child12" << "top1,child12" @@ -869,34 +862,34 @@ void tst_QTreeWidgetItemIterator::iteratorflags_data() << "top15,child12" << "top16,child12"); - QTest::newRow("Match mutually exclusive Hidden|NotHidden") << 0 << (int)(QTreeWidgetItemIterator::Hidden|QTreeWidgetItemIterator::NotHidden) + QTest::newRow("Match mutually exclusive Hidden|NotHidden") << 0 << (QTreeWidgetItemIterator::Hidden|QTreeWidgetItemIterator::NotHidden) << QStringList(); - QTest::newRow("Match mutually exclusive Selected|Unselected") << 0 << (int)(QTreeWidgetItemIterator::Selected|QTreeWidgetItemIterator::Unselected) + QTest::newRow("Match mutually exclusive Selected|Unselected") << 0 << (QTreeWidgetItemIterator::Selected|QTreeWidgetItemIterator::Unselected) << QStringList(); - QTest::newRow("Match mutually exclusive Selectable|NotSelectable") << 0 << (int)(QTreeWidgetItemIterator::Selectable|QTreeWidgetItemIterator::NotSelectable) + QTest::newRow("Match mutually exclusive Selectable|NotSelectable") << 0 << (QTreeWidgetItemIterator::Selectable|QTreeWidgetItemIterator::NotSelectable) << QStringList(); - QTest::newRow("Match mutually exclusive DragEnabled|DragDisabled") << 0 << (int)(QTreeWidgetItemIterator::DragEnabled|QTreeWidgetItemIterator::DragDisabled) + QTest::newRow("Match mutually exclusive DragEnabled|DragDisabled") << 0 << (QTreeWidgetItemIterator::DragEnabled|QTreeWidgetItemIterator::DragDisabled) << QStringList(); - QTest::newRow("Match mutually exclusive DropEnabled|DropDisabled") << 0 << (int)(QTreeWidgetItemIterator::DropEnabled|QTreeWidgetItemIterator::DropDisabled) + QTest::newRow("Match mutually exclusive DropEnabled|DropDisabled") << 0 << (QTreeWidgetItemIterator::DropEnabled|QTreeWidgetItemIterator::DropDisabled) << QStringList(); - QTest::newRow("Match mutually exclusive HasChildren|NoChildren") << 0 << (int)(QTreeWidgetItemIterator::HasChildren|QTreeWidgetItemIterator::NoChildren) + QTest::newRow("Match mutually exclusive HasChildren|NoChildren") << 0 << (QTreeWidgetItemIterator::HasChildren|QTreeWidgetItemIterator::NoChildren) << QStringList(); - QTest::newRow("Match mutually exclusive Checked|NotChecked") << 0 << (int)(QTreeWidgetItemIterator::Checked|QTreeWidgetItemIterator::NotChecked) + QTest::newRow("Match mutually exclusive Checked|NotChecked") << 0 << (QTreeWidgetItemIterator::Checked|QTreeWidgetItemIterator::NotChecked) << QStringList(); - QTest::newRow("Match mutually exclusive Disabled|Enabled") << 0 << (int)(QTreeWidgetItemIterator::Disabled|QTreeWidgetItemIterator::Enabled) + QTest::newRow("Match mutually exclusive Disabled|Enabled") << 0 << (QTreeWidgetItemIterator::Disabled|QTreeWidgetItemIterator::Enabled) << QStringList(); - QTest::newRow("Match mutually exclusive Editable|NotEditable") << 0 << (int)(QTreeWidgetItemIterator::Editable|QTreeWidgetItemIterator::NotEditable) + QTest::newRow("Match mutually exclusive Editable|NotEditable") << 0 << (QTreeWidgetItemIterator::Editable|QTreeWidgetItemIterator::NotEditable) << QStringList(); } void tst_QTreeWidgetItemIterator::iteratorflags() { QFETCH(int, start); - QFETCH(int, iteratorflags); + QFETCH(QTreeWidgetItemIterator::IteratorFlags, iteratorflags); QFETCH(QStringList, matches); - QTreeWidgetItemIterator it(testWidget, QTreeWidgetItemIterator::IteratorFlags(iteratorflags)); - it+=start; + QTreeWidgetItemIterator it(testWidget, iteratorflags); + it += start; int iMatch = 0; while (*it && iMatch < matches.count()) { QTreeWidgetItem *item = *it; @@ -953,26 +946,26 @@ void tst_QTreeWidgetItemIterator::plus_eq_data() { QTest::addColumn<int>("start"); QTest::addColumn<int>("addition"); - QTest::addColumn<int>("iteratorflags"); + QTest::addColumn<QTreeWidgetItemIterator::IteratorFlag>("iteratorflags"); QTest::addColumn<QString>("expecteditem"); - QTest::newRow("+=0") << 0 << 0 << (int)QTreeWidgetItemIterator::All << QString("top0"); - QTest::newRow("+=1") << 0 << 1 << (int)QTreeWidgetItemIterator::All << QString("top0,child0"); - QTest::newRow("+=2") << 0 << 2 << (int)QTreeWidgetItemIterator::All << QString("top0,child1"); - QTest::newRow("+=(-1)") << 1 << -1 << (int)QTreeWidgetItemIterator::All << QString("top0"); - QTest::newRow("+=(-2)") << 3 << -2 << (int)QTreeWidgetItemIterator::All << QString("top0,child0"); + QTest::newRow("+=0") << 0 << 0 << QTreeWidgetItemIterator::All << QString("top0"); + QTest::newRow("+=1") << 0 << 1 << QTreeWidgetItemIterator::All << QString("top0,child0"); + QTest::newRow("+=2") << 0 << 2 << QTreeWidgetItemIterator::All << QString("top0,child1"); + QTest::newRow("+=(-1)") << 1 << -1 << QTreeWidgetItemIterator::All << QString("top0"); + QTest::newRow("+=(-2)") << 3 << -2 << QTreeWidgetItemIterator::All << QString("top0,child0"); } void tst_QTreeWidgetItemIterator::plus_eq() { QFETCH(int, start); QFETCH(int, addition); - QFETCH(int, iteratorflags); + QFETCH(QTreeWidgetItemIterator::IteratorFlag, iteratorflags); QFETCH(QString, expecteditem); - QTreeWidgetItemIterator it(testWidget, QTreeWidgetItemIterator::IteratorFlags(iteratorflags)); - it+=start; - it+=addition; + QTreeWidgetItemIterator it(testWidget, iteratorflags); + it += start; + it += addition; QTreeWidgetItem *item = *it; QVERIFY(item); @@ -984,28 +977,28 @@ void tst_QTreeWidgetItemIterator::minus_eq_data() { QTest::addColumn<int>("start"); QTest::addColumn<int>("subtraction"); - QTest::addColumn<int>("iteratorflags"); + QTest::addColumn<QTreeWidgetItemIterator::IteratorFlag>("iteratorflags"); QTest::addColumn<QString>("expecteditem"); - QTest::newRow("0-=0") << 0 << 0 << (int)QTreeWidgetItemIterator::All << QString("top0"); - QTest::newRow("2-=1") << 2 << 1 << (int)QTreeWidgetItemIterator::All << QString("top0,child0"); - QTest::newRow("4-=2") << 4 << 2 << (int)QTreeWidgetItemIterator::All << QString("top0,child1"); - QTest::newRow("0-=(-1)") << 0 << -1 << (int)QTreeWidgetItemIterator::All << QString("top0,child0"); - QTest::newRow("0-=(-2)") << 0 << -2 << (int)QTreeWidgetItemIterator::All << QString("top0,child1"); - QTest::newRow("18-=1") << 18 << 1 << (int)QTreeWidgetItemIterator::All << QString("top0,child16"); - QTest::newRow("1-=1") << 1 << 1 << (int)QTreeWidgetItemIterator::All << QString("top0"); + QTest::newRow("0-=0") << 0 << 0 << QTreeWidgetItemIterator::All << QString("top0"); + QTest::newRow("2-=1") << 2 << 1 << QTreeWidgetItemIterator::All << QString("top0,child0"); + QTest::newRow("4-=2") << 4 << 2 << QTreeWidgetItemIterator::All << QString("top0,child1"); + QTest::newRow("0-=(-1)") << 0 << -1 << QTreeWidgetItemIterator::All << QString("top0,child0"); + QTest::newRow("0-=(-2)") << 0 << -2 << QTreeWidgetItemIterator::All << QString("top0,child1"); + QTest::newRow("18-=1") << 18 << 1 << QTreeWidgetItemIterator::All << QString("top0,child16"); + QTest::newRow("1-=1") << 1 << 1 << QTreeWidgetItemIterator::All << QString("top0"); } void tst_QTreeWidgetItemIterator::minus_eq() { QFETCH(int, start); QFETCH(int, subtraction); - QFETCH(int, iteratorflags); + QFETCH(QTreeWidgetItemIterator::IteratorFlag, iteratorflags); QFETCH(QString, expecteditem); - QTreeWidgetItemIterator it(testWidget, QTreeWidgetItemIterator::IteratorFlags(iteratorflags)); - it+=start; - it-=subtraction; + QTreeWidgetItemIterator it(testWidget, iteratorflags); + it += start; + it -= subtraction; QTreeWidgetItem *item = *it; // should be the first one QVERIFY(item); @@ -1017,41 +1010,41 @@ void tst_QTreeWidgetItemIterator::updateIfModifiedFromWidget_data() QTest::addColumn<int>("topLevelItems"); QTest::addColumn<int>("childItems"); QTest::addColumn<int>("grandChildItems"); - QTest::addColumn<int>("iteratorflags"); + QTest::addColumn<QTreeWidgetItemIterator::IteratorFlag>("iteratorflags"); QTest::addColumn<int>("removeindex"); QTest::addColumn<int>("expecteditemindex"); QTest::addColumn<QString>("expecteditemvalue"); QTest::addColumn<QString>("expectedUpdatedCurrent"); QTest::addColumn<int>("expecteditemIsNull"); - QTest::newRow("Remove 3, check 1") << 3 << 3 << 0 << (int)QTreeWidgetItemIterator::All + QTest::newRow("Remove 3, check 1") << 3 << 3 << 0 << QTreeWidgetItemIterator::All << 3 << 1 << QString("top0,child0") << QString("top1") << 0; - QTest::newRow("Remove 1, check 0") << 3 << 3 << 0 << (int)QTreeWidgetItemIterator::All + QTest::newRow("Remove 1, check 0") << 3 << 3 << 0 << QTreeWidgetItemIterator::All << 1 << 0 << QString("top0") << QString("top0,child1") << 0; - QTest::newRow("Remove 2, check 2") << 3 << 3 << 0 << (int)QTreeWidgetItemIterator::All + QTest::newRow("Remove 2, check 2") << 3 << 3 << 0 << QTreeWidgetItemIterator::All << 2 << 2 << QString("top0,child2") << QString("top0,child2") << 0; - QTest::newRow("Remove 0, check 0") << 3 << 3 << 3 << (int)QTreeWidgetItemIterator::All + QTest::newRow("Remove 0, check 0") << 3 << 3 << 3 << QTreeWidgetItemIterator::All << 0 << 0 << QString("top1") << QString("top1") << 0; - QTest::newRow("Remove top1, check top1") << 3 << 3 << 3 << (int)QTreeWidgetItemIterator::All + QTest::newRow("Remove top1, check top1") << 3 << 3 << 3 << QTreeWidgetItemIterator::All << 13 << 13 << QString("top2") << QString("top2") << 0; - QTest::newRow("Remove top0, check top1") << 3 << 3 << 3 << (int)QTreeWidgetItemIterator::All + QTest::newRow("Remove top0, check top1") << 3 << 3 << 3 << QTreeWidgetItemIterator::All << 0 << 13 << QString("top1") << QString("top1") << 0; - QTest::newRow("Remove (top0,child1), check (top0,child1)") << 3 << 3 << 3 << (int)QTreeWidgetItemIterator::All + QTest::newRow("Remove (top0,child1), check (top0,child1)") << 3 << 3 << 3 << QTreeWidgetItemIterator::All << 5 << 5 << QString("top0,child2") << QString("top0,child2") << 0; - QTest::newRow("Remove (t0,c0) check (t0,c0)") << 3 << 3 << 3 << (int)QTreeWidgetItemIterator::All + QTest::newRow("Remove (t0,c0) check (t0,c0)") << 3 << 3 << 3 << QTreeWidgetItemIterator::All << 1 << 1 << QString("top0,child1") << QString("top0,child1") << 0; - QTest::newRow("Remove (t0,c1) check (t0,c1)") << 3 << 3 << 3 << (int)QTreeWidgetItemIterator::All + QTest::newRow("Remove (t0,c1) check (t0,c1)") << 3 << 3 << 3 << QTreeWidgetItemIterator::All << 5 << 5 << QString("top0,child2") << QString("top0,child2") << 0; - QTest::newRow("Remove (t0) check (t0,c1)") << 3 << 3 << 0 << (int)QTreeWidgetItemIterator::All + QTest::newRow("Remove (t0) check (t0,c1)") << 3 << 3 << 0 << QTreeWidgetItemIterator::All << 0 << 4 << QString("top1") << QString("top1") << 0; - QTest::newRow("Remove (t0) check (t0,c0,g1)") << 3 << 3 << 3 << (int)QTreeWidgetItemIterator::All + QTest::newRow("Remove (t0) check (t0,c0,g1)") << 3 << 3 << 3 << QTreeWidgetItemIterator::All << 0 << 3 << QString("top1") << QString("top1") << 0; - QTest::newRow("Remove (top2), check if top2 is null") << 3 << 3 << 3 << (int)QTreeWidgetItemIterator::All + QTest::newRow("Remove (top2), check if top2 is null") << 3 << 3 << 3 << QTreeWidgetItemIterator::All << 2*13 << 2*13 << QString() << QString() << 1; QTest::newRow("Remove last item, check if iterator::current returns 0") - << 3 << 0 << 0 << (int)QTreeWidgetItemIterator::All << 2 << 2 << QString() << QString() << 1; + << 3 << 0 << 0 << QTreeWidgetItemIterator::All << 2 << 2 << QString() << QString() << 1; QTest::newRow("remove 1, iterator points to 3, should move to 1") - << 3 << 3 << 3 << (int)QTreeWidgetItemIterator::All << 1 << 3 << QString("top0,child1") << QString("top0,child1") << 0; + << 3 << 3 << 3 << QTreeWidgetItemIterator::All << 1 << 3 << QString("top0,child1") << QString("top0,child1") << 0; } static void populate3Levels(QTreeWidget &tw, int topLevelItems, int childItems, int grandChildItems) @@ -1077,7 +1070,7 @@ void tst_QTreeWidgetItemIterator::updateIfModifiedFromWidget() QFETCH(int, topLevelItems); QFETCH(int, childItems); QFETCH(int, grandChildItems); - QFETCH(int, iteratorflags); + QFETCH(QTreeWidgetItemIterator::IteratorFlag, iteratorflags); QFETCH(int, removeindex); QFETCH(int, expecteditemindex); QFETCH(QString, expecteditemvalue); @@ -1089,12 +1082,11 @@ void tst_QTreeWidgetItemIterator::updateIfModifiedFromWidget() tw.setColumnCount(2); populate3Levels(tw, topLevelItems, childItems, grandChildItems); - QTreeWidgetItemIterator it(&tw, QTreeWidgetItemIterator::IteratorFlags(iteratorflags)); + QTreeWidgetItemIterator it(&tw, iteratorflags); it+=expecteditemindex; - QTreeWidgetItem *item = 0; QTreeWidgetItemIterator itRemove(&tw, QTreeWidgetItemIterator::IteratorFlags(iteratorflags)); itRemove+=removeindex; - item = *itRemove; + QTreeWidgetItem *item = *itRemove; QVERIFY(item); delete item; item = *it; @@ -1104,11 +1096,10 @@ void tst_QTreeWidgetItemIterator::updateIfModifiedFromWidget() QVERIFY(item); QCOMPARE(item->text(0), expecteditemvalue); item = *itRemove; - if (expectedUpdatedCurrent.isNull()) { + if (expectedUpdatedCurrent.isNull()) QVERIFY(!item); - } else { + else QCOMPARE(item->text(0), expectedUpdatedCurrent); - } } } @@ -1152,38 +1143,36 @@ void tst_QTreeWidgetItemIterator::updateIteratorAfterDeletedItem_and_ContinueIte QTreeWidgetItemIterator it(&tw, QTreeWidgetItemIterator::All); it += iterator_initial_index; - QTreeWidgetItem *item = 0; QTreeWidgetItemIterator itRemove(&tw, QTreeWidgetItemIterator::All); itRemove+=removeindex; - item = *itRemove; + QTreeWidgetItem *item = *itRemove; QVERIFY(item); delete item; it+=iterator_advance_after_removal; - if (iterator_new_value.isNull()) { + if (iterator_new_value.isNull()) QCOMPARE((*it), nullptr); - } else { + else QCOMPARE((*it)->text(0), iterator_new_value); - } } void tst_QTreeWidgetItemIterator::constructIteratorWithItem_data() { QTest::addColumn<int>("indextoitem"); - QTest::addColumn<int>("iteratorflags"); + QTest::addColumn<QTreeWidgetItemIterator::IteratorFlag>("iteratorflags"); QTest::addColumn<QString>("expecteditem"); - QTest::newRow("index 0") << 0 << 0 << QString("top0"); - QTest::newRow("index 1") << 1 << 0 << QString("top0,child0"); - QTest::newRow("index 2") << 2 << 0 << QString("top0,child1"); - QTest::newRow("index 30") << 30 << 0 << QString("top1,child11"); - QTest::newRow("305 (last item)") << 305 << 0 << QString("top16,child16"); - QTest::newRow("index 0, advance to next matching node") << 0 << (int)QTreeWidgetItemIterator::NotHidden << QString("top0,child1"); + QTest::newRow("index 0") << 0 << QTreeWidgetItemIterator::All << QString("top0"); + QTest::newRow("index 1") << 1 << QTreeWidgetItemIterator::All << QString("top0,child0"); + QTest::newRow("index 2") << 2 << QTreeWidgetItemIterator::All << QString("top0,child1"); + QTest::newRow("index 30") << 30 << QTreeWidgetItemIterator::All << QString("top1,child11"); + QTest::newRow("305 (last item)") << 305 << QTreeWidgetItemIterator::All << QString("top16,child16"); + QTest::newRow("index 0, advance to next matching node") << 0 << QTreeWidgetItemIterator::NotHidden << QString("top0,child1"); } void tst_QTreeWidgetItemIterator::constructIteratorWithItem() { QFETCH(int, indextoitem); - QFETCH(int, iteratorflags); + QFETCH(QTreeWidgetItemIterator::IteratorFlag, iteratorflags); QFETCH(QString, expecteditem); QTreeWidgetItemIterator it(testWidget); diff --git a/tests/auto/widgets/kernel/kernel.pro b/tests/auto/widgets/kernel/kernel.pro index 73fd934502..af85a2bd13 100644 --- a/tests/auto/widgets/kernel/kernel.pro +++ b/tests/auto/widgets/kernel/kernel.pro @@ -22,5 +22,3 @@ SUBDIRS=\ darwin:SUBDIRS -= \ # Uses native recognizers qgesturerecognizer \ - -SUBDIRS -= qsound diff --git a/tests/auto/widgets/kernel/qaction/tst_qaction.cpp b/tests/auto/widgets/kernel/qaction/tst_qaction.cpp index 3d68e42baf..0d62c2cd4b 100644 --- a/tests/auto/widgets/kernel/qaction/tst_qaction.cpp +++ b/tests/auto/widgets/kernel/qaction/tst_qaction.cpp @@ -70,7 +70,7 @@ private slots: void shortcutFromKeyEvent(); // QTBUG-48325 private: - int m_lastEventType; + QEvent::Type m_lastEventType; const int m_keyboardScheme; QAction *m_lastAction; }; @@ -82,7 +82,7 @@ tst_QAction::tst_QAction() void tst_QAction::init() { - m_lastEventType = 0; + m_lastEventType = QEvent::None; m_lastAction = nullptr; } @@ -94,23 +94,23 @@ void tst_QAction::cleanup() // Testing get/set functions void tst_QAction::getSetCheck() { - QAction obj1(0); + QAction obj1(nullptr); // QActionGroup * QAction::actionGroup() // void QAction::setActionGroup(QActionGroup *) - QActionGroup *var1 = new QActionGroup(0); + QActionGroup *var1 = new QActionGroup(nullptr); obj1.setActionGroup(var1); QCOMPARE(var1, obj1.actionGroup()); - obj1.setActionGroup((QActionGroup *)0); - QCOMPARE((QActionGroup *)0, obj1.actionGroup()); + obj1.setActionGroup(nullptr); + QCOMPARE(obj1.actionGroup(), nullptr); delete var1; // QMenu * QAction::menu() // void QAction::setMenu(QMenu *) - QMenu *var2 = new QMenu(0); + QMenu *var2 = new QMenu(nullptr); obj1.setMenu(var2); QCOMPARE(var2, obj1.menu()); - obj1.setMenu((QMenu *)0); - QCOMPARE((QMenu *)0, obj1.menu()); + obj1.setMenu(nullptr); + QCOMPARE(obj1.menu(), nullptr); delete var2; QCOMPARE(obj1.priority(), QAction::NormalPriority); @@ -148,7 +148,7 @@ void tst_QAction::setText() { QFETCH(QString, text); - QAction action(0); + QAction action(nullptr); action.setText(text); QCOMPARE(action.text(), text); @@ -161,7 +161,7 @@ void tst_QAction::setIconText() { QFETCH(QString, iconText); - QAction action(0); + QAction action(nullptr); action.setIconText(iconText); QCOMPARE(action.iconText(), iconText); @@ -171,7 +171,7 @@ void tst_QAction::setIconText() void tst_QAction::setUnknownFont() // QTBUG-42728 { - QAction action(0); + QAction action(nullptr); QFont font("DoesNotExist", 11); action.setFont(font); @@ -182,17 +182,17 @@ void tst_QAction::setUnknownFont() // QTBUG-42728 void tst_QAction::updateState(QActionEvent *e) { if (!e) { - m_lastEventType = 0; - m_lastAction = 0; + m_lastEventType = QEvent::None; + m_lastAction = nullptr; } else { - m_lastEventType = (int)e->type(); + m_lastEventType = e->type(); m_lastAction = e->action(); } } void tst_QAction::actionEvent() { - QAction a(0); + QAction a(nullptr); a.setText("action text"); // add action @@ -202,33 +202,33 @@ void tst_QAction::actionEvent() testWidget.addAction(&a); qApp->processEvents(); - QCOMPARE(m_lastEventType, (int)QEvent::ActionAdded); + QCOMPARE(m_lastEventType, QEvent::ActionAdded); QCOMPARE(m_lastAction, &a); // change action a.setText("new action text"); qApp->processEvents(); - QCOMPARE(m_lastEventType, (int)QEvent::ActionChanged); + QCOMPARE(m_lastEventType, QEvent::ActionChanged); QCOMPARE(m_lastAction, &a); // remove action testWidget.removeAction(&a); qApp->processEvents(); - QCOMPARE(m_lastEventType, (int)QEvent::ActionRemoved); + QCOMPARE(m_lastEventType, QEvent::ActionRemoved); QCOMPARE(m_lastAction, &a); } //basic testing of standard keys void tst_QAction::setStandardKeys() { - QAction act(0); + QAction act(nullptr); act.setShortcut(QKeySequence("CTRL+L")); QList<QKeySequence> list; act.setShortcuts(list); act.setShortcuts(QKeySequence::Copy); - QCOMPARE(act.shortcut(), act.shortcuts().first()); + QCOMPARE(act.shortcut(), act.shortcuts().constFirst()); QList<QKeySequence> expected; const QKeySequence ctrlC = QKeySequence(QStringLiteral("CTRL+C")); @@ -263,7 +263,7 @@ void tst_QAction::alternateShortcuts() QList<QKeySequence> shlist = QList<QKeySequence>() << QKeySequence("CTRL+P") << QKeySequence("CTRL+A"); act.setShortcuts(shlist); - QSignalSpy spy(&act, SIGNAL(triggered())); + QSignalSpy spy(&act, &QAction::triggered); act.setAutoRepeat(true); QTest::keyClick(&testWidget, Qt::Key_A, Qt::ControlModifier); @@ -322,7 +322,7 @@ void tst_QAction::enabledVisibleInteraction() testWidget.show(); QApplication::setActiveWindow(&testWidget); - QAction act(0); + QAction act(nullptr); // check defaults QVERIFY(act.isEnabled()); QVERIFY(act.isVisible()); @@ -370,7 +370,7 @@ void tst_QAction::task229128TriggeredSignalWithoutActiongroup() { // test without a group const QScopedPointer<QAction> actionWithoutGroup(new QAction("Test", nullptr)); - QSignalSpy spyWithoutGroup(actionWithoutGroup.data(), SIGNAL(triggered(bool))); + QSignalSpy spyWithoutGroup(actionWithoutGroup.data(), QOverload<bool>::of(&QAction::triggered)); QCOMPARE(spyWithoutGroup.count(), 0); actionWithoutGroup->trigger(); // signal should be emitted @@ -388,7 +388,7 @@ void tst_QAction::task229128TriggeredSignalWithoutActiongroup() void tst_QAction::task229128TriggeredSignalWhenInActiongroup() { - QActionGroup ag(0); + QActionGroup ag(nullptr); QAction *action = new QAction("Test", &ag); QAction *checkedAction = new QAction("Test 2", &ag); ag.addAction(action); @@ -397,8 +397,8 @@ void tst_QAction::task229128TriggeredSignalWhenInActiongroup() checkedAction->setCheckable(true); checkedAction->setChecked(true); - QSignalSpy actionSpy(checkedAction, SIGNAL(triggered(bool))); - QSignalSpy actionGroupSpy(&ag, SIGNAL(triggered(QAction*))); + QSignalSpy actionSpy(checkedAction, QOverload<bool>::of(&QAction::triggered)); + QSignalSpy actionGroupSpy(&ag, QOverload<QAction*>::of(&QActionGroup::triggered)); QCOMPARE(actionGroupSpy.count(), 0); QCOMPARE(actionSpy.count(), 0); checkedAction->trigger(); @@ -513,10 +513,10 @@ void tst_QAction::disableShortcutsWithBlockedWidgets() class ShortcutOverrideWidget : public QWidget { public: - ShortcutOverrideWidget(QWidget *parent = 0) : QWidget(parent), shortcutOverrideCount(0) {} - int shortcutOverrideCount; + using QWidget::QWidget; + int shortcutOverrideCount = 0; protected: - bool event(QEvent *e) + bool event(QEvent *e) override { if (e->type() == QEvent::ShortcutOverride) ++shortcutOverrideCount; diff --git a/tests/auto/widgets/kernel/qactiongroup/tst_qactiongroup.cpp b/tests/auto/widgets/kernel/qactiongroup/tst_qactiongroup.cpp index 52ca10d31f..524040d003 100644 --- a/tests/auto/widgets/kernel/qactiongroup/tst_qactiongroup.cpp +++ b/tests/auto/widgets/kernel/qactiongroup/tst_qactiongroup.cpp @@ -41,6 +41,7 @@ private slots: void enabledPropagation(); void visiblePropagation(); void exclusive(); + void exclusiveOptional(); void separators(); void testActionInTwoQActionGroup(); void unCheckCurrentAction(); @@ -48,11 +49,11 @@ private slots: void tst_QActionGroup::enabledPropagation() { - QActionGroup testActionGroup( 0 ); + QActionGroup testActionGroup(nullptr); QAction* childAction = new QAction( &testActionGroup ); QAction* anotherChildAction = new QAction( &testActionGroup ); - QAction* freeAction = new QAction(0); + QAction* freeAction = new QAction(nullptr); QVERIFY( testActionGroup.isEnabled() ); QVERIFY( childAction->isEnabled() ); @@ -87,11 +88,11 @@ void tst_QActionGroup::enabledPropagation() void tst_QActionGroup::visiblePropagation() { - QActionGroup testActionGroup( 0 ); + QActionGroup testActionGroup(nullptr); QAction* childAction = new QAction( &testActionGroup ); QAction* anotherChildAction = new QAction( &testActionGroup ); - QAction* freeAction = new QAction(0); + QAction* freeAction = new QAction(nullptr); QVERIFY( testActionGroup.isVisible() ); QVERIFY( childAction->isVisible() ); @@ -124,7 +125,7 @@ void tst_QActionGroup::visiblePropagation() void tst_QActionGroup::exclusive() { - QActionGroup group(0); + QActionGroup group(nullptr); group.setExclusive(false); QVERIFY( !group.isExclusive() ); @@ -151,6 +152,52 @@ void tst_QActionGroup::exclusive() QVERIFY( !actThree->isChecked() ); } +void tst_QActionGroup::exclusiveOptional() +{ + QActionGroup group(0); + group.setExclusive(true); + QVERIFY( group.isExclusive() ); + + QAction* actOne = new QAction( &group ); + actOne->setCheckable( true ); + QAction* actTwo = new QAction( &group ); + actTwo->setCheckable( true ); + QAction* actThree = new QAction( &group ); + actThree->setCheckable( true ); + + QVERIFY( !actOne->isChecked() ); + QVERIFY( !actTwo->isChecked() ); + QVERIFY( !actThree->isChecked() ); + + actOne->trigger(); + QVERIFY( actOne->isChecked() ); + QVERIFY( !actTwo->isChecked() ); + QVERIFY( !actThree->isChecked() ); + + actOne->trigger(); + QVERIFY( actOne->isChecked() ); + QVERIFY( !actTwo->isChecked() ); + QVERIFY( !actThree->isChecked() ); + + group.setExclusionPolicy( QActionGroup::ExclusionPolicy::ExclusiveOptional ); + QVERIFY( group.isExclusive() ); + + actOne->trigger(); + QVERIFY( !actOne->isChecked() ); + QVERIFY( !actTwo->isChecked() ); + QVERIFY( !actThree->isChecked() ); + + actTwo->trigger(); + QVERIFY( !actOne->isChecked() ); + QVERIFY( actTwo->isChecked() ); + QVERIFY( !actThree->isChecked() ); + + actTwo->trigger(); + QVERIFY( !actOne->isChecked() ); + QVERIFY( !actTwo->isChecked() ); + QVERIFY( !actThree->isChecked() ); +} + void tst_QActionGroup::separators() { QMainWindow mw; @@ -166,26 +213,24 @@ void tst_QActionGroup::separators() separator->setSeparator(true); actGroup.addAction(separator); - QListIterator<QAction*> it(actGroup.actions()); - while (it.hasNext()) - menu.addAction(it.next()); + menu.addActions(actGroup.actions()); - QCOMPARE((int)menu.actions().size(), 2); + QCOMPARE(menu.actions().size(), 2); - it = QListIterator<QAction*>(actGroup.actions()); - while (it.hasNext()) - menu.removeAction(it.next()); + const auto removeActions = [&menu](const QList<QAction *> &actions) { + for (QAction *action : actions) + menu.removeAction(action); + }; + removeActions(actGroup.actions()); - QCOMPARE((int)menu.actions().size(), 0); + QCOMPARE(menu.actions().size(), 0); action = new QAction(&actGroup); action->setText("test two"); - it = QListIterator<QAction*>(actGroup.actions()); - while (it.hasNext()) - menu.addAction(it.next()); + menu.addActions(actGroup.actions()); - QCOMPARE((int)menu.actions().size(), 3); + QCOMPARE(menu.actions().size(), 3); } void tst_QActionGroup::testActionInTwoQActionGroup() @@ -205,7 +250,7 @@ void tst_QActionGroup::testActionInTwoQActionGroup() void tst_QActionGroup::unCheckCurrentAction() { - QActionGroup group(0); + QActionGroup group(nullptr); QAction action1(&group) ,action2(&group); action1.setCheckable(true); action2.setCheckable(true); diff --git a/tests/auto/widgets/kernel/qapplication/BLACKLIST b/tests/auto/widgets/kernel/qapplication/BLACKLIST index d7de7bf16e..c68c7d6b14 100644 --- a/tests/auto/widgets/kernel/qapplication/BLACKLIST +++ b/tests/auto/widgets/kernel/qapplication/BLACKLIST @@ -1,4 +1,3 @@ [touchEventPropagation] # QTBUG-66745 -opensuse opensuse-leap diff --git a/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp index 7ee085b81c..367a5767c4 100644 --- a/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp +++ b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp @@ -890,7 +890,9 @@ void tst_QApplication::libraryPaths() QStringList actual = QApplication::libraryPaths(); actual.sort(); - QStringList expected = QSet<QString>::fromList((QStringList() << testDir << appDirPath)).toList(); + QStringList expected; + expected << testDir << appDirPath; + expected = QSet<QString>(expected.constBegin(), expected.constEnd()).values(); expected.sort(); QVERIFY2(isPathListIncluded(actual, expected), @@ -907,7 +909,9 @@ void tst_QApplication::libraryPaths() QStringList actual = QApplication::libraryPaths(); actual.sort(); - QStringList expected = QSet<QString>::fromList((QStringList() << installPathPlugins << appDirPath)).toList(); + QStringList expected; + expected << installPathPlugins << appDirPath; + expected = QSet<QString>(expected.constBegin(), expected.constEnd()).values(); expected.sort(); #ifdef Q_OS_WINRT diff --git a/tests/auto/widgets/kernel/qboxlayout/tst_qboxlayout.cpp b/tests/auto/widgets/kernel/qboxlayout/tst_qboxlayout.cpp index b2650d1f32..00bde3cb25 100644 --- a/tests/auto/widgets/kernel/qboxlayout/tst_qboxlayout.cpp +++ b/tests/auto/widgets/kernel/qboxlayout/tst_qboxlayout.cpp @@ -47,6 +47,7 @@ private slots: void sizeConstraints(); void setGeometry(); void setStyleShouldChangeSpacing(); + void widgetSurplus(); void testLayoutEngine_data(); void testLayoutEngine(); @@ -193,7 +194,7 @@ void tst_QBoxLayout::setGeometry() setFrameless(&toplevel); QWidget w(&toplevel); QVBoxLayout *lay = new QVBoxLayout; - lay->setMargin(0); + lay->setContentsMargins(0, 0, 0, 0); lay->setSpacing(0); QHBoxLayout *lay2 = new QHBoxLayout; QDial *dial = new QDial; @@ -236,6 +237,69 @@ void tst_QBoxLayout::setStyleShouldChangeSpacing() QTRY_COMPARE(spacing(), 10); } +class MarginEatingStyle : public QProxyStyle +{ +public: + MarginEatingStyle() : QProxyStyle(QStyleFactory::create("windows")) + { + } + + virtual QRect subElementRect(SubElement sr, const QStyleOption *opt, + const QWidget *widget) const + { + QRect rect = opt->rect; + switch (sr) { + case SE_GroupBoxLayoutItem: + // this is a simplifed version of what the macOS style does + rect.setTop(rect.top() + 20); + rect.setLeft(rect.left() + 20); + rect.setRight(rect.right() - 20); + rect.setBottom(rect.bottom() - 20); + break; + default: + return QProxyStyle::subElementRect(sr, opt, widget); + } + + return rect; + } +}; + +void tst_QBoxLayout::widgetSurplus() +{ + // Test case for QTBUG-67608 - a style requests space in the margin + + QDialog window; + QScopedPointer<MarginEatingStyle> marginEater(new MarginEatingStyle); + QVBoxLayout *vbox = new QVBoxLayout(&window); + vbox->setContentsMargins(0, 0, 0, 0); + vbox->setSpacing(0); + + QLabel *hiddenLabel = new QLabel(tr("Invisible label")); + hiddenLabel->setVisible(false); + + QGroupBox *groupBox = new QGroupBox(tr("Groupbox Title")); + groupBox->setStyle(marginEater.data()); + groupBox->setObjectName("Test group box"); + QPushButton *button1 = new QPushButton(tr("Button 1")); + QPushButton *button2 = new QPushButton(tr("Button 2")); + QVBoxLayout *groupLayout = new QVBoxLayout; + groupLayout->addWidget(button1); + groupLayout->addWidget(button2); + groupBox->setLayout(groupLayout); + + QLabel *label = new QLabel(tr("Visible label")); + + vbox->addWidget(hiddenLabel); + vbox->addWidget(groupBox); + vbox->addWidget(label); + window.setLayout(vbox); + + window.show(); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + QCOMPARE(groupBox->y(), 0); + QCOMPARE(groupBox->x(), 0); +} + void tst_QBoxLayout::taskQTBUG_7103_minMaxWidthNotRespected() { QLabel *label = new QLabel("Qt uses standard C++, but makes extensive use of the C pre-processor to enrich the language. Qt can also be used in several other programming languages via language bindings. It runs on all major platforms, and has extensive internationalization support. Non-GUI features include SQL database access, XML parsing, thread management, network support and a unified cross-platform API for file handling."); @@ -507,6 +571,10 @@ void tst_QBoxLayout::replaceWidget() QCOMPARE(boxLayout->indexOf(replaceFrom), 1); QCOMPARE(boxLayout->indexOf(replaceTo), -1); + QCOMPARE(boxLayout->count(), 3); + boxLayout->replaceWidget(replaceFrom, replaceFrom); + QCOMPARE(boxLayout->count(), 3); + delete boxLayout->replaceWidget(replaceFrom, replaceTo); QCOMPARE(boxLayout->indexOf(replaceFrom), -1); diff --git a/tests/auto/widgets/kernel/qdesktopwidget/tst_qdesktopwidget.cpp b/tests/auto/widgets/kernel/qdesktopwidget/tst_qdesktopwidget.cpp index 90776dfcb2..a29e8408a3 100644 --- a/tests/auto/widgets/kernel/qdesktopwidget/tst_qdesktopwidget.cpp +++ b/tests/auto/widgets/kernel/qdesktopwidget/tst_qdesktopwidget.cpp @@ -42,10 +42,12 @@ class tst_QDesktopWidget : public QObject private slots: void cleanup(); +#if QT_DEPRECATED_SINCE(5, 11) void numScreens(); void primaryScreen(); - void screenNumberForQWidget(); void screenNumberForQPoint(); +#endif + void screenNumberForQWidget(); void availableGeometry(); void screenGeometry(); void topLevels(); @@ -56,6 +58,7 @@ void tst_QDesktopWidget::cleanup() QVERIFY(QApplication::topLevelWidgets().isEmpty()); } +#if QT_DEPRECATED_SINCE(5, 11) void tst_QDesktopWidget::numScreens() { QDesktopWidget desktop; @@ -68,14 +71,17 @@ void tst_QDesktopWidget::primaryScreen() QVERIFY(desktop.primaryScreen() >= 0); QVERIFY(desktop.primaryScreen() < desktop.numScreens()); } +#endif void tst_QDesktopWidget::availableGeometry() { QDesktopWidget desktop; QTest::ignoreMessage(QtWarningMsg, "QDesktopWidget::availableGeometry(): Attempt " "to get the available geometry of a null widget"); - desktop.availableGeometry((QWidget *)0); + QRect r = desktop.availableGeometry(nullptr); + QVERIFY(r.isNull()); +#if QT_DEPRECATED_SINCE(5, 11) QRect total; QRect available; @@ -90,13 +96,14 @@ void tst_QDesktopWidget::availableGeometry() QVERIFY(total.contains(available)); QCOMPARE(desktop.availableGeometry(desktop.primaryScreen()), available); QCOMPARE(desktop.screenGeometry(desktop.primaryScreen()), total); +#endif } void tst_QDesktopWidget::screenNumberForQWidget() { QDesktopWidget desktop; - QCOMPARE(desktop.screenNumber(0), 0); + QCOMPARE(desktop.screenNumber(nullptr), 0); QWidget widget; widget.show(); @@ -105,9 +112,10 @@ void tst_QDesktopWidget::screenNumberForQWidget() int widgetScreen = desktop.screenNumber(&widget); QVERIFY(widgetScreen > -1); - QVERIFY(widgetScreen < desktop.numScreens()); + QVERIFY(widgetScreen < QGuiApplication::screens().size()); } +#if QT_DEPRECATED_SINCE(5, 11) void tst_QDesktopWidget::screenNumberForQPoint() { // make sure QDesktopWidget::screenNumber(QPoint) returns the correct screen @@ -131,25 +139,28 @@ void tst_QDesktopWidget::screenNumberForQPoint() screen = desktopWidget->screenNumber(allScreens.bottomRight() + QPoint(1, 1)); QVERIFY(screen >= 0 && screen < desktopWidget->numScreens()); } +#endif void tst_QDesktopWidget::screenGeometry() { QDesktopWidget *desktopWidget = QApplication::desktop(); QTest::ignoreMessage(QtWarningMsg, "QDesktopWidget::screenGeometry(): Attempt " "to get the screen geometry of a null widget"); - QRect r = desktopWidget->screenGeometry((QWidget *)0); + QRect r = desktopWidget->screenGeometry(nullptr); QVERIFY(r.isNull()); QWidget widget; widget.show(); QVERIFY(QTest::qWaitForWindowExposed(&widget)); r = desktopWidget->screenGeometry(&widget); +#if QT_DEPRECATED_SINCE(5, 11) QRect total; QRect available; for (int i = 0; i < desktopWidget->screenCount(); ++i) { total = desktopWidget->screenGeometry(i); available = desktopWidget->availableGeometry(i); } +#endif } void tst_QDesktopWidget::topLevels() diff --git a/tests/auto/widgets/kernel/qformlayout/qformlayout.pro b/tests/auto/widgets/kernel/qformlayout/qformlayout.pro index 617183fee6..0766b50f68 100644 --- a/tests/auto/widgets/kernel/qformlayout/qformlayout.pro +++ b/tests/auto/widgets/kernel/qformlayout/qformlayout.pro @@ -1,4 +1,4 @@ CONFIG += testcase TARGET = tst_qformlayout -QT += widgets testlib testlib-private +QT += widgets widgets-private testlib testlib-private SOURCES += tst_qformlayout.cpp diff --git a/tests/auto/widgets/kernel/qformlayout/tst_qformlayout.cpp b/tests/auto/widgets/kernel/qformlayout/tst_qformlayout.cpp index cff3dad35e..c6760000f4 100644 --- a/tests/auto/widgets/kernel/qformlayout/tst_qformlayout.cpp +++ b/tests/auto/widgets/kernel/qformlayout/tst_qformlayout.cpp @@ -38,6 +38,9 @@ #include <QtWidgets/QLabel> #include <QtWidgets/QLineEdit> #include <QtWidgets/QPushButton> + +#include <private/qdialog_p.h> + #include <QStyleFactory> #include <QSharedPointer> @@ -52,7 +55,7 @@ using namespace QTestPrivate; Q_CONSTEXPR QFormLayout::ItemRole invalidRole = QFormLayout::ItemRole(3); struct QFormLayoutTakeRowResultHolder { - QFormLayoutTakeRowResultHolder(QFormLayout::TakeRowResult result) Q_DECL_NOTHROW + QFormLayoutTakeRowResultHolder(QFormLayout::TakeRowResult result) noexcept : labelItem(result.labelItem), fieldItem(result.fieldItem) { @@ -66,20 +69,20 @@ struct QFormLayoutTakeRowResultHolder { if (fieldItem) disposer.setItem(0, QFormLayout::FieldRole, fieldItem); } - QFormLayoutTakeRowResultHolder(QFormLayoutTakeRowResultHolder &&other) Q_DECL_NOTHROW + QFormLayoutTakeRowResultHolder(QFormLayoutTakeRowResultHolder &&other) noexcept : labelItem(other.labelItem), fieldItem(other.fieldItem) { other.labelItem = nullptr; other.fieldItem = nullptr; } - QFormLayoutTakeRowResultHolder &operator=(QFormLayoutTakeRowResultHolder &&other) Q_DECL_NOTHROW + QFormLayoutTakeRowResultHolder &operator=(QFormLayoutTakeRowResultHolder &&other) noexcept { swap(other); return *this; } - void swap(QFormLayoutTakeRowResultHolder &other) Q_DECL_NOTHROW + void swap(QFormLayoutTakeRowResultHolder &other) noexcept { qSwap(labelItem, other.labelItem); qSwap(fieldItem, other.fieldItem); @@ -1196,22 +1199,20 @@ void tst_QFormLayout::layoutAlone() void tst_QFormLayout::taskQTBUG_27420_takeAtShouldUnparentLayout() { QSharedPointer<QFormLayout> outer(new QFormLayout); - QPointer<QFormLayout> inner = new QFormLayout; + QAutoPointer<QFormLayout> holder{new QFormLayout}; + auto inner = holder.get(); outer->addRow(inner); QCOMPARE(outer->count(), 1); QCOMPARE(inner->parent(), outer.data()); QLayoutItem *item = outer->takeAt(0); - QCOMPARE(item->layout(), inner.data()); + QCOMPARE(item->layout(), inner); QVERIFY(!item->layout()->parent()); outer.reset(); - if (inner) - delete item; // success: a taken item/layout should not be deleted when the old parent is deleted - else - QVERIFY(!inner.isNull()); + QVERIFY(holder); // a taken item/layout should not be deleted when the old parent is deleted } void tst_QFormLayout::taskQTBUG_40609_addingWidgetToItsOwnLayout(){ diff --git a/tests/auto/widgets/kernel/qgridlayout/tst_qgridlayout.cpp b/tests/auto/widgets/kernel/qgridlayout/tst_qgridlayout.cpp index 5e0327319b..1d63d140fb 100644 --- a/tests/auto/widgets/kernel/qgridlayout/tst_qgridlayout.cpp +++ b/tests/auto/widgets/kernel/qgridlayout/tst_qgridlayout.cpp @@ -219,9 +219,9 @@ void tst_QGridLayout::badDistributionBug() QDialog dialog; Ui::SortDialog ui; ui.setupUi(&dialog); - ui.gridLayout->setMargin(0); + ui.gridLayout->setContentsMargins(0, 0, 0, 0); ui.gridLayout->setSpacing(0); - ui.vboxLayout->setMargin(0); + ui.vboxLayout->setContentsMargins(0, 0, 0, 0); ui.vboxLayout->setSpacing(0); ui.okButton->setFixedHeight(20); ui.moreButton->setFixedHeight(20); @@ -237,7 +237,7 @@ void tst_QGridLayout::setMinAndMaxSize() QWidget widget; setFrameless(&widget); QGridLayout layout(&widget); - layout.setMargin(0); + layout.setContentsMargins(0, 0, 0, 0); layout.setSpacing(0); layout.setSizeConstraint(QLayout::SetMinAndMaxSize); widget.show(); @@ -396,7 +396,7 @@ void tst_QGridLayout::spacingAndSpacers() QWidget widget; setFrameless(&widget); QGridLayout layout(&widget); - layout.setMargin(0); + layout.setContentsMargins(0, 0, 0, 0); layout.setSpacing(0); widget.show(); @@ -1541,7 +1541,7 @@ void tst_QGridLayout::spacerWithSpacing() QWidget window; QGridLayout layout(&window); layout.setSpacing(1); - layout.setMargin(0); + layout.setContentsMargins(0, 0, 0, 0); populate(&layout, 0, i); populate(&layout, 1, j); populate(&layout, 2, k); @@ -1651,7 +1651,7 @@ void tst_QGridLayout::taskQTBUG_52357_spacingWhenItemIsHidden() QWidget widget; setFrameless(&widget); QGridLayout layout(&widget); - layout.setMargin(0); + layout.setContentsMargins(0, 0, 0, 0); layout.setSpacing(5); QPushButton button1; layout.addWidget(&button1, 0, 0); diff --git a/tests/auto/widgets/kernel/qlayout/tst_qlayout.cpp b/tests/auto/widgets/kernel/qlayout/tst_qlayout.cpp index 936f581d89..140a367afe 100644 --- a/tests/auto/widgets/kernel/qlayout/tst_qlayout.cpp +++ b/tests/auto/widgets/kernel/qlayout/tst_qlayout.cpp @@ -308,7 +308,7 @@ void tst_QLayout::controlTypes2() { QWidget main; QVBoxLayout *const layout = new QVBoxLayout(&main); - layout->setMargin(0); + layout->setContentsMargins(0, 0, 0, 0); QComboBox *combo = new QComboBox(&main); layout->addWidget(combo); QCOMPARE(layout->controlTypes(), QSizePolicy::ComboBox); @@ -319,7 +319,7 @@ void tst_QLayout::adjustSizeShouldMakeSureLayoutIsActivated() QWidget main; QVBoxLayout *const layout = new QVBoxLayout(&main); - layout->setMargin(0); + layout->setContentsMargins(0, 0, 0, 0); SizeHinterFrame *frame = new SizeHinterFrame(QSize(200, 10), QSize(200, 8)); frame->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); layout->addWidget(frame); diff --git a/tests/auto/widgets/kernel/qshortcut/tst_qshortcut.cpp b/tests/auto/widgets/kernel/qshortcut/tst_qshortcut.cpp index 53753e195a..84120c70e9 100644 --- a/tests/auto/widgets/kernel/qshortcut/tst_qshortcut.cpp +++ b/tests/auto/widgets/kernel/qshortcut/tst_qshortcut.cpp @@ -41,7 +41,6 @@ #include <qshortcut.h> #include <qscreen.h> -class AccelForm; QT_BEGIN_NAMESPACE class QMainWindow; class QTextEdit; @@ -51,15 +50,14 @@ class tst_QShortcut : public QObject { Q_OBJECT public: - tst_QShortcut(); - virtual ~tst_QShortcut(); - enum Action { SetupAccel, TestAccel, - ClearAll - } currentAction; + ClearAll, + TestEnd + }; + Q_ENUM(Action) enum Widget { NoWidget, @@ -70,8 +68,8 @@ public: TriggerSlot5, TriggerSlot6, TriggerSlot7, - SendKeyEvent }; + Q_ENUM(Widget) enum Result { NoResult, @@ -84,7 +82,8 @@ public: Slot7Triggered, SentKeyEvent, Ambiguous - } currentResult; + } currentResult = NoResult; + Q_ENUM(Result) public slots: void slotTrig1() { currentResult = Slot1Triggered; } @@ -101,16 +100,9 @@ public slots: void ambigSlot5() { currentResult = Ambiguous; ambigResult = Slot5Triggered; } void ambigSlot6() { currentResult = Ambiguous; ambigResult = Slot6Triggered; } void ambigSlot7() { currentResult = Ambiguous; ambigResult = Slot7Triggered; } - void statusMessage( const QString& message ) { sbText = message; } - void shortcutDestroyed(QObject* obj); - void sendKeyEvent() { sendKeyEvents(edit, Qt::CTRL + Qt::Key_B, 0); currentResult = SentKeyEvent; } - -public slots: - void initTestCase(); - void cleanupTestCase(); - void cleanup() { QCOMPARE(QApplication::topLevelWidgets().size(), 1); } private slots: + void cleanup(); void number_data(); void number(); void text_data(); @@ -129,29 +121,19 @@ protected: static Qt::KeyboardModifiers toButtons( int key ); void defElements(); - void clearAllShortcuts(); - QShortcut *setupShortcut(int testWidget, const QKeySequence &ks); - QShortcut *setupShortcut(int testWidget, const QString &txt, int k1 = 0, int k2 = 0, int k3 = 0, int k4 = 0); - - QShortcut *setupShortcut(QWidget *parent, const char *name, int testWidget, const QString &txt, int k1 = 0, int k2 = 0, int k3 = 0, int k4 = 0); - QShortcut *setupShortcut(QWidget *parent, const char *name, int testWidget, const QKeySequence &ks, Qt::ShortcutContext context = Qt::WindowShortcut); + QShortcut *setupShortcut(QWidget *parent, const QString &name, const QKeySequence &ks, + Qt::ShortcutContext context = Qt::WindowShortcut); + QShortcut *setupShortcut(QWidget *parent, const QString &name, Widget testWidget, + const QKeySequence &ks, Qt::ShortcutContext context = Qt::WindowShortcut); - void sendKeyEvents(QWidget *w, int k1, QChar c1 = 0, int k2 = 0, QChar c2 = 0, int k3 = 0, QChar c3 = 0, int k4 = 0, QChar c4 = 0); - void sendKeyEvents(int k1, QChar c1 = 0, int k2 = 0, QChar c2 = 0, int k3 = 0, QChar c3 = 0, int k4 = 0, QChar c4 = 0); + static void sendKeyEvents(QWidget *w, int k1, QChar c1 = 0, int k2 = 0, QChar c2 = 0, + int k3 = 0, QChar c3 = 0, int k4 = 0, QChar c4 = 0); void testElement(); - QMainWindow *mainW; - QList<QShortcut*> shortcuts; - QTextEdit *edit; - QString sbText; Result ambigResult; }; -Q_DECLARE_METATYPE(tst_QShortcut::Widget); -Q_DECLARE_METATYPE(tst_QShortcut::Result); -Q_DECLARE_METATYPE(tst_QShortcut::Action); - class TestEdit : public QTextEdit { Q_OBJECT @@ -163,7 +145,8 @@ public: } protected: - bool event(QEvent *e) { + bool event(QEvent *e) override + { // Make testedit allow any Ctrl+Key as shortcut if (e->type() == QEvent::ShortcutOverride) { QKeyEvent *ke = static_cast<QKeyEvent*>(e); @@ -196,33 +179,28 @@ protected: } }; -tst_QShortcut::tst_QShortcut(): mainW( 0 ) +class MainWindow : public QMainWindow { -} +public: + MainWindow(); -tst_QShortcut::~tst_QShortcut() -{ - clearAllShortcuts(); -} + TestEdit *testEdit() const { return m_testEdit; } -void tst_QShortcut::initTestCase() +private: + TestEdit *m_testEdit; +}; + +MainWindow::MainWindow() { - currentResult = NoResult; - mainW = new QMainWindow(0); - mainW->setWindowFlags(Qt::X11BypassWindowManagerHint); - edit = new TestEdit(mainW, "test_edit"); - mainW->setFixedSize( 200, 200 ); - mainW->setCentralWidget( edit ); - mainW->show(); - mainW->activateWindow(); - QVERIFY(QTest::qWaitForWindowActive(mainW)); - connect( mainW->statusBar(), SIGNAL(messageChanged(QString)), - this, SLOT(statusMessage(QString)) ); + setWindowFlags(Qt::X11BypassWindowManagerHint); + m_testEdit = new TestEdit(this, "test_edit"); + setCentralWidget(m_testEdit); + setFixedSize(200, 200); } -void tst_QShortcut::cleanupTestCase() +void tst_QShortcut::cleanup() { - delete mainW; + QVERIFY(QApplication::topLevelWidgets().size() <= 1); // The data driven tests keep a widget around } Qt::KeyboardModifiers tst_QShortcut::toButtons( int key ) @@ -277,7 +255,7 @@ void tst_QShortcut::number_data() defElements(); // Clear all - QTest::newRow("N00 - clear") << ClearAll << NoWidget <<QString("")<<0<<0<<0<<0<<0<<0<<0<<0<<NoResult; + QTest::newRow("N00 - clear") << ClearAll << NoWidget <<QString()<<0<<0<<0<<0<<0<<0<<0<<0<<NoResult; //=========================================== // [Shift + key] on non-shift shortcuts testing @@ -289,15 +267,15 @@ void tst_QShortcut::number_data() Shift + Qt::Key_Plus on Qt::Key_Pluss Qt::Key_Plus on Qt::Key_Pluss */ - QTest::newRow("N001 - slot1") << SetupAccel << TriggerSlot1 << QString("") << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N001 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; //commented out because the behaviour changed, those tests should be updated - //QTest::newRow("N001:Shift + M - [M]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("N001:M - [M]") << TestAccel << NoWidget << QString("") << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("N001 - slot2") << SetupAccel << TriggerSlot2 << QString("") << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + //QTest::newRow("N001:Shift + M - [M]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N001:M - [M]") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N001 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; //commented out because the behaviour changed, those tests should be updated - //QTest::newRow("N001:Shift++ [+]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; - QTest::newRow("N001:+ [+]") << TestAccel << NoWidget << QString("") << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; - QTest::newRow("N001 - clear") << ClearAll << NoWidget << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all + //QTest::newRow("N001:Shift++ [+]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("N001:+ [+]") << TestAccel << NoWidget << QString() << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("N001 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all /* Testing Single Sequences Shift + Qt::Key_M on Shift + Qt::Key_M @@ -305,32 +283,32 @@ void tst_QShortcut::number_data() Shift + Qt::Key_Plus on Shift + Qt::Key_Pluss Qt::Key_Plus on Shift + Qt::Key_Pluss */ - QTest::newRow("N002 - slot1") << SetupAccel << TriggerSlot1 << QString("") << int(Qt::SHIFT + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("N002:Shift+M - [Shift+M]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("N002:M - [Shift+M]") << TestAccel << NoWidget << QString("") << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("N002 - slot2") << SetupAccel << TriggerSlot2 << QString("") << int(Qt::SHIFT + Qt::Key_Plus) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("N002:Shift++ [Shift++]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; - QTest::newRow("N002:+ [Shift++]") << TestAccel << NoWidget << QString("") << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("N002 - clear") << ClearAll << NoWidget << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all + QTest::newRow("N002 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::SHIFT + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N002:Shift+M - [Shift+M]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N002:M - [Shift+M]") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N002 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::SHIFT + Qt::Key_Plus) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N002:Shift++ [Shift++]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("N002:+ [Shift++]") << TestAccel << NoWidget << QString() << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N002 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all /* Testing Single Sequences Shift + Qt::Key_F1 on Qt::Key_F1 Qt::Key_F1 on Qt::Key_F1 */ - QTest::newRow("N003 - slot1") << SetupAccel << TriggerSlot1 << QString("") << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N003 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; //commented out because the behaviour changed, those tests should be updated - //QTest::newRow("N003:Shift+F1 - [F1]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("N003:F1 - [F1]") << TestAccel << NoWidget << QString("") << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("N003 - clear") << ClearAll << NoWidget << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all + //QTest::newRow("N003:Shift+F1 - [F1]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N003:F1 - [F1]") << TestAccel << NoWidget << QString() << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N003 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all /* Testing Single Sequences Shift + Qt::Key_F1 on Shift + Qt::Key_F1 Qt::Key_F1 on Shift + Qt::Key_F1 */ - QTest::newRow("N004 - slot1") << SetupAccel << TriggerSlot1 << QString("") << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("N004:Shift+F1 - [Shift+F1]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("N004:F1 - [Shift+F1]") << TestAccel << NoWidget << QString("") << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("N004 - clear") << ClearAll << NoWidget << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all + QTest::newRow("N004 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N004:Shift+F1 - [Shift+F1]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N004:F1 - [Shift+F1]") << TestAccel << NoWidget << QString() << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N004 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all /* Testing Single Sequences Qt::Key_Tab on Qt::Key_Tab @@ -338,14 +316,14 @@ void tst_QShortcut::number_data() Qt::Key_Backtab on Qt::Key_Tab Shift + Qt::Key_Backtab on Qt::Key_Tab */ - QTest::newRow("N005a - slot1") << SetupAccel << TriggerSlot1 << QString("") << int(Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("N005a:Tab - [Tab]") << TestAccel << NoWidget << QString("") << int(Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N005a - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N005a:Tab - [Tab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; //commented out because the behaviour changed, those tests should be updated - //QTest::newRow("N005a:Shift+Tab - [Tab]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + //QTest::newRow("N005a:Shift+Tab - [Tab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; // (Shift+)BackTab != Tab, but Shift+BackTab == Shift+Tab - QTest::newRow("N005a:Backtab - [Tab]") << TestAccel << NoWidget << QString("") << int(Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("N005a:Shift+Backtab - [Tab]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("N005a - clear") << ClearAll << NoWidget << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all + QTest::newRow("N005a:Backtab - [Tab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N005a:Shift+Backtab - [Tab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N005a - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all /* Testing Single Sequences Qt::Key_Tab on Shift + Qt::Key_Tab @@ -353,12 +331,12 @@ void tst_QShortcut::number_data() Qt::Key_Backtab on Shift + Qt::Key_Tab Shift + Qt::Key_Backtab on Shift + Qt::Key_Tab */ - QTest::newRow("N005b - slot1") << SetupAccel << TriggerSlot1 << QString("") << int(Qt::SHIFT + Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("N005b:Tab - [Shift+Tab]") << TestAccel << NoWidget << QString("") << int(Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("N005b:Shift+Tab - [Shift+Tab]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("N005b:BackTab - [Shift+Tab]") << TestAccel << NoWidget << QString("") << int(Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("N005b:Shift+BackTab - [Shift+Tab]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("N005b - clear") << ClearAll << NoWidget << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all + QTest::newRow("N005b - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::SHIFT + Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N005b:Tab - [Shift+Tab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N005b:Shift+Tab - [Shift+Tab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N005b:BackTab - [Shift+Tab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N005b:Shift+BackTab - [Shift+Tab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N005b - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all /* Testing Single Sequences Qt::Key_Tab on Qt::Key_Backtab @@ -366,15 +344,15 @@ void tst_QShortcut::number_data() Qt::Key_Backtab on Qt::Key_Backtab Shift + Qt::Key_Backtab on Qt::Key_Backtab */ - QTest::newRow("N006a - slot1") << SetupAccel << TriggerSlot1 << QString("") << int(Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("N006a:Tab - [BackTab]") << TestAccel << NoWidget << QString("") << int(Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N006a - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N006a:Tab - [BackTab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // This should work, since platform dependent code will transform the // Shift+Tab into a Shift+BackTab, which should trigger the shortcut - QTest::newRow("N006a:Shift+Tab - [BackTab]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; //XFAIL - QTest::newRow("N006a:BackTab - [BackTab]") << TestAccel << NoWidget << QString("") << int(Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N006a:Shift+Tab - [BackTab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; //XFAIL + QTest::newRow("N006a:BackTab - [BackTab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; //commented out because the behaviour changed, those tests should be updated - //QTest::newRow("N006a:Shift+BackTab - [BackTab]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("N006a - clear") << ClearAll << NoWidget<< QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all + //QTest::newRow("N006a:Shift+BackTab - [BackTab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N006a - clear") << ClearAll << NoWidget<< QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all /* Testing Single Sequences Qt::Key_Tab on Shift + Qt::Key_Backtab @@ -382,12 +360,12 @@ void tst_QShortcut::number_data() Qt::Key_Backtab on Shift + Qt::Key_Backtab Shift + Qt::Key_Backtab on Shift + Qt::Key_Backtab */ - QTest::newRow("N006b - slot1") << SetupAccel << TriggerSlot1 << QString("") << int(Qt::SHIFT + Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("N006b:Tab - [Shift+BackTab]") << TestAccel << NoWidget << QString("") << int(Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("N006b:Shift+Tab - [Shift+BackTab]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("N006b:BackTab - [Shift+BackTab]") << TestAccel << NoWidget << QString("") << int(Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("N006b:Shift+BackTab - [Shift+BackTab]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; //XFAIL - QTest::newRow("N006b - clear") << ClearAll << NoWidget << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all + QTest::newRow("N006b - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::SHIFT + Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N006b:Tab - [Shift+BackTab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N006b:Shift+Tab - [Shift+BackTab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N006b:BackTab - [Shift+BackTab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N006b:Shift+BackTab - [Shift+BackTab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; //XFAIL + QTest::newRow("N006b - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all //=========================================== // [Shift + key] and [key] on shortcuts with @@ -398,11 +376,11 @@ void tst_QShortcut::number_data() Qt::Key_F1 Shift + Qt::Key_F1 */ - QTest::newRow("N007 - slot1") << SetupAccel << TriggerSlot1 << QString("") << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("N007 - slot2") << SetupAccel << TriggerSlot2 << QString("") << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("N007:F1") << TestAccel << NoWidget << QString("") << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("N007:Shift + F1") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; - QTest::newRow("N007 - clear") << ClearAll << NoWidget << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all + QTest::newRow("N007 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N007 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N007:F1") << TestAccel << NoWidget << QString() << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N007:Shift + F1") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("N007 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all /* Testing Single Sequences Qt::Key_M @@ -410,51 +388,51 @@ void tst_QShortcut::number_data() Ctrl + Qt::Key_M Alt + Qt::Key_M */ - QTest::newRow("N01 - slot1") << SetupAccel << TriggerSlot1 << QString("") << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("N02 - slot2") << SetupAccel << TriggerSlot2 << QString("") << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("N03 - slot1") << SetupAccel << TriggerSlot1 << QString("") << int(Qt::CTRL + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("N04 - slot2") << SetupAccel << TriggerSlot2 << QString("") << int(Qt::ALT + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("N:Qt::Key_M") << TestAccel << NoWidget << QString("") << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("N:Shift+Qt::Key_M") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; - QTest::newRow("N:Ctrl+Qt::Key_M") << TestAccel << NoWidget << QString("") << int(Qt::CTRL + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("N:Alt+Qt::Key_M") << TestAccel << NoWidget << QString("") << int(Qt::ALT + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("N01 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N02 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N03 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::CTRL + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N04 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::ALT + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N:Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N:Shift+Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("N:Ctrl+Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::CTRL + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N:Alt+Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::ALT + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; /* Testing Single Sequence Ambiguity Qt::Key_M on shortcut2 */ - QTest::newRow("N05 - slot2") << SetupAccel << TriggerSlot2 << QString("") << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("N:Qt::Key_M on slot") << TestAccel << NoWidget << QString("") << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Ambiguous; - QTest::newRow("N05 - clear") << ClearAll << NoWidget << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all + QTest::newRow("N05 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N:Qt::Key_M on slot") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Ambiguous; + QTest::newRow("N05 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all /* Testing Single Specialkeys Qt::Key_aring Qt::Key_Aring Qt::UNICODE_ACCEL + Qt::Key_K */ - QTest::newRow("N06 - slot1") << SetupAccel << TriggerSlot1 << QString("") << int(Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("N07 - slot2") << SetupAccel << TriggerSlot2 << QString("") << int(Qt::SHIFT+Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("N08 - slot2") << SetupAccel << TriggerSlot1 << QString("") << int(Qt::UNICODE_ACCEL + Qt::Key_K) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N06 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N07 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::SHIFT+Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N08 - slot2") << SetupAccel << TriggerSlot1 << QString() << int(Qt::UNICODE_ACCEL + Qt::Key_K) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("N:Qt::Key_aring") << TestAccel << NoWidget << QString("") << int(Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("N:Qt::Key_Aring") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT+Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; - QTest::newRow("N:Qt::Key_aring - Text Form") << TestAccel << NoWidget << QString("") << 0 << 0xC5 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("N:Qt::Key_Aring - Text Form") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT+0) << 0xC5 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; - QTest::newRow("N:Qt::UNICODE_ACCEL + Qt::Key_K")<< TestAccel << NoWidget << QString("") << int(Qt::UNICODE_ACCEL + Qt::Key_K) << int('k') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("N09 - clear") << ClearAll << NoWidget << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all + QTest::newRow("N:Qt::Key_aring") << TestAccel << NoWidget << QString() << int(Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N:Qt::Key_Aring") << TestAccel << NoWidget << QString() << int(Qt::SHIFT+Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("N:Qt::Key_aring - Text Form") << TestAccel << NoWidget << QString() << 0 << 0xC5 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N:Qt::Key_Aring - Text Form") << TestAccel << NoWidget << QString() << int(Qt::SHIFT+0) << 0xC5 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("N:Qt::UNICODE_ACCEL + Qt::Key_K")<< TestAccel << NoWidget << QString() << int(Qt::UNICODE_ACCEL + Qt::Key_K) << int('k') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N09 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all /* Testing Multiple Sequences Qt::Key_M Qt::Key_I, Qt::Key_M Shift+Qt::Key_I, Qt::Key_M */ - QTest::newRow("N10 - slot1") << SetupAccel << TriggerSlot1 << QString("") << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("N11 - slot2") << SetupAccel << TriggerSlot2 << QString("") << int(Qt::Key_I) << 0 << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("N12 - slot1") << SetupAccel << TriggerSlot1 << QString("") << int(Qt::SHIFT + Qt::Key_I) << 0 << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << NoResult; - - QTest::newRow("N:Qt::Key_M (2)") << TestAccel << NoWidget << QString("") << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("N:Qt::Key_I, Qt::Key_M") << TestAccel << NoWidget << QString("") << int(Qt::Key_I) << int('i') << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << Slot2Triggered; - QTest::newRow("N:Shift+Qt::Key_I, Qt::Key_M") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_I) << int('I') << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("N13 - clear") << ClearAll << NoWidget << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all + QTest::newRow("N10 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N11 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::Key_I) << 0 << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N12 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::SHIFT + Qt::Key_I) << 0 << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << NoResult; + + QTest::newRow("N:Qt::Key_M (2)") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N:Qt::Key_I, Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::Key_I) << int('i') << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("N:Shift+Qt::Key_I, Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_I) << int('I') << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N:end") << TestEnd << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; } // ------------------------------------------------------------------ @@ -464,7 +442,7 @@ void tst_QShortcut::text_data() { defElements(); // Clear all - QTest::newRow("T00 - clear") << ClearAll << NoWidget <<QString("")<<0<<0<<0<<0<<0<<0<<0<<0<< NoResult; + QTest::newRow("T00 - clear") << ClearAll << NoWidget <<QString()<<0<<0<<0<<0<<0<<0<<0<<0<< NoResult; //=========================================== // [Shift + key] on non-shift shortcuts testing @@ -478,13 +456,13 @@ void tst_QShortcut::text_data() */ QTest::newRow("T001 - slot1") << SetupAccel << TriggerSlot1 << QString("M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; //commented out because the behaviour changed, those tests should be updated - //QTest::newRow("T001:Shift+M - [M]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("T001:M - [M]") << TestAccel << NoWidget << QString("") << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + //QTest::newRow("T001:Shift+M - [M]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T001:M - [M]") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; QTest::newRow("T001 - slot2") << SetupAccel << TriggerSlot2 << QString("+") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; //commented out because the behaviour changed, those tests should be updated - //QTest::newRow("T001:Shift++ [+]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; - QTest::newRow("T001:+ [+]") << TestAccel << NoWidget << QString("") << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; - QTest::newRow("T001 - clear") << ClearAll << NoWidget << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all + //QTest::newRow("T001:Shift++ [+]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("T001:+ [+]") << TestAccel << NoWidget << QString() << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("T001 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all /* Testing Single Sequences Shift + Qt::Key_M on Shift + Qt::Key_M @@ -495,12 +473,12 @@ void tst_QShortcut::text_data() Ctrl + Qt::Key_Plus on Ctrl + Qt::Key_Pluss */ QTest::newRow("T002 - slot1") << SetupAccel << TriggerSlot1 << QString("Shift+M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("T002:Shift+M - [Shift+M]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("T002:M - [Shift+M]") << TestAccel << NoWidget << QString("") << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("T002:Shift+M - [Shift+M]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T002:M - [Shift+M]") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; QTest::newRow("T002 - slot2") << SetupAccel << TriggerSlot2 << QString("Shift++") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("T002:Shift++ [Shift++]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; - QTest::newRow("T002:+ [Shift++]") << TestAccel << NoWidget << QString("") << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("T002 - clear") << ClearAll << NoWidget << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all + QTest::newRow("T002:Shift++ [Shift++]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("T002:+ [Shift++]") << TestAccel << NoWidget << QString() << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("T002 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all /* Testing Single Sequences Shift + Ctrl + Qt::Key_Plus on Ctrl + Qt::Key_Plus @@ -509,10 +487,10 @@ void tst_QShortcut::text_data() */ QTest::newRow("T002b - slot1") << SetupAccel << TriggerSlot1 << QString("Ctrl++") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; //commented out because the behaviour changed, those tests should be updated - //QTest::newRow("T002b:Shift+Ctrl++ [Ctrl++]")<< TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::CTRL + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("T002b:Ctrl++ [Ctrl++]") << TestAccel << NoWidget << QString("") << int(Qt::CTRL + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("T002b:+ [Ctrl++]") << TestAccel << NoWidget << QString("") << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("T002b - clear") << ClearAll << NoWidget << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all + //QTest::newRow("T002b:Shift+Ctrl++ [Ctrl++]")<< TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::CTRL + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T002b:Ctrl++ [Ctrl++]") << TestAccel << NoWidget << QString() << int(Qt::CTRL + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T002b:+ [Ctrl++]") << TestAccel << NoWidget << QString() << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("T002b - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all /* Testing Single Sequences Shift + Qt::Key_F1 on Qt::Key_F1 @@ -520,18 +498,18 @@ void tst_QShortcut::text_data() */ QTest::newRow("T003 - slot1") << SetupAccel << TriggerSlot1 << QString("F1") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; //commented out because the behaviour changed, those tests should be updated - //QTest::newRow("T003:Shift+F1 - [F1]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("T003:F1 - [F1]") << TestAccel << NoWidget << QString("") << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("T003 - clear") << ClearAll << NoWidget << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all + //QTest::newRow("T003:Shift+F1 - [F1]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T003:F1 - [F1]") << TestAccel << NoWidget << QString() << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T003 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all /* Testing Single Sequences Shift + Qt::Key_F1 on Shift + Qt::Key_F1 Qt::Key_F1 on Shift + Qt::Key_F1 */ QTest::newRow("T004 - slot1") << SetupAccel << TriggerSlot1 << QString("Shift+F1") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("T004:Shift+F1 - [Shift+F1]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("T004:F1 - [Shift+F1]") << TestAccel << NoWidget << QString("") << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("T004 - clear") << ClearAll << NoWidget << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all + QTest::newRow("T004:Shift+F1 - [Shift+F1]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T004:F1 - [Shift+F1]") << TestAccel << NoWidget << QString() << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("T004 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all //=========================================== // [Shift + key] and [key] on shortcuts with @@ -544,9 +522,9 @@ void tst_QShortcut::text_data() */ QTest::newRow("T007 - slot1") << SetupAccel << TriggerSlot1 << QString("F1") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; QTest::newRow("T007 - slot2") << SetupAccel << TriggerSlot2 << QString("Shift+F1") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("T007:F1") << TestAccel << NoWidget << QString("") << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("T007:Shift + F1") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; - QTest::newRow("T007 - clear") << ClearAll << NoWidget << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all + QTest::newRow("T007:F1") << TestAccel << NoWidget << QString() << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T007:Shift + F1") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("T007 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all /* Testing Single Sequences Qt::Key_M @@ -559,17 +537,17 @@ void tst_QShortcut::text_data() QTest::newRow("T03 - slot1") << SetupAccel << TriggerSlot1 << QString("Ctrl+M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; QTest::newRow("T04 - slot2") << SetupAccel << TriggerSlot2 << QString("Alt+M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("T:Qt::Key_M") << TestAccel << NoWidget << QString("") << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("T:Shift + Qt::Key_M") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; - QTest::newRow("T:Ctrl + Qt::Key_M") << TestAccel << NoWidget << QString("") << int(Qt::CTRL + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("T:Alt + Qt::Key_M") << TestAccel << NoWidget << QString("") << int(Qt::ALT + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("T:Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T:Shift + Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("T:Ctrl + Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::CTRL + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T:Alt + Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::ALT + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; /* Testing Single Sequence Ambiguity Qt::Key_M on shortcut2 */ QTest::newRow("T05 - slot2") << SetupAccel << TriggerSlot2 << QString("M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("T:Qt::Key_M on TriggerSlot2") << TestAccel << NoWidget << QString("") << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Ambiguous; - QTest::newRow("T06 - clear") << ClearAll << NoWidget << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all + QTest::newRow("T:Qt::Key_M on TriggerSlot2") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Ambiguous; + QTest::newRow("T06 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all /* Testing Single Specialkeys Qt::Key_aring @@ -580,12 +558,12 @@ void tst_QShortcut::text_data() QTest::newRow("T06 - slot1") << SetupAccel << TriggerSlot1 << QString::fromLatin1("\x0C5")<< 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; QTest::newRow("T07 - slot2") << SetupAccel << TriggerSlot2 << QString::fromLatin1("Shift+\x0C5")<< 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; QTest::newRow("T08 - slot2") << SetupAccel << TriggerSlot1 << QString("K") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("T:Qt::Key_aring") << TestAccel << NoWidget << QString("") << int(Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("T:Qt::Key_Aring") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT+Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; - QTest::newRow("T:Qt::Key_aring - Text Form") << TestAccel << NoWidget << QString("") << 0 << 0xC5 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("T:Qt::Key_Aring - Text Form") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT+0) << 0xC5 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; - QTest::newRow("T:Qt::UNICODE_ACCEL + Qt::Key_K")<< TestAccel << NoWidget << QString("") << int(Qt::UNICODE_ACCEL + Qt::Key_K) << int('k') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("T09 - clear") << ClearAll << NoWidget << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all + QTest::newRow("T:Qt::Key_aring") << TestAccel << NoWidget << QString() << int(Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T:Qt::Key_Aring") << TestAccel << NoWidget << QString() << int(Qt::SHIFT+Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("T:Qt::Key_aring - Text Form") << TestAccel << NoWidget << QString() << 0 << 0xC5 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T:Qt::Key_Aring - Text Form") << TestAccel << NoWidget << QString() << int(Qt::SHIFT+0) << 0xC5 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("T:Qt::UNICODE_ACCEL + Qt::Key_K")<< TestAccel << NoWidget << QString() << int(Qt::UNICODE_ACCEL + Qt::Key_K) << int('k') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T09 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all /* Testing Multiple Sequences Qt::Key_M @@ -595,10 +573,38 @@ void tst_QShortcut::text_data() QTest::newRow("T10 - slot1") << SetupAccel << TriggerSlot1 << QString("M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; QTest::newRow("T11 - slot2") << SetupAccel << TriggerSlot2 << QString("I, M")<< 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; QTest::newRow("T12 - slot1") << SetupAccel << TriggerSlot1 << QString("Shift+I, M")<< 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; - QTest::newRow("T:Qt::Key_M (2)") << TestAccel << NoWidget << QString("") << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("T:Qt::Key_I, Qt::Key_M") << TestAccel << NoWidget << QString("") << int(Qt::Key_I) << int('i') << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << Slot2Triggered; - QTest::newRow("T:Shift+Qt::Key_I, Qt::Key_M") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_I) << int('I') << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << Slot1Triggered; - QTest::newRow("T13 - clear") << ClearAll << NoWidget << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all + QTest::newRow("T:Qt::Key_M (2)") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T:Qt::Key_I, Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::Key_I) << int('i') << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("T:Shift+Qt::Key_I, Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_I) << int('I') << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T:end") << TestEnd << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; +} + +class ButtonWidget : public QWidget +{ +public: + ButtonWidget(); + + QPushButton *pushButton1() const { return m_pb1; } + QPushButton *pushButton2() const { return m_pb2; } + +private: + QPushButton *m_pb1; + QPushButton *m_pb2; +}; + +ButtonWidget::ButtonWidget() +{ + // Setup two identical shortcuts on different pushbuttons + QString name = QLatin1String("pushbutton-1"); + m_pb1 = new QPushButton(name, this); + m_pb1->setObjectName(name); + name = QLatin1String("pushbutton-2"); + m_pb2 = new QPushButton(name, this); + m_pb2->setObjectName(name); + auto hLayout = new QHBoxLayout(this); + hLayout->addWidget(m_pb1); + hLayout->addWidget(m_pb2); + hLayout->addStretch(); } // ------------------------------------------------------------------ @@ -606,9 +612,11 @@ void tst_QShortcut::text_data() // ------------------------------------------------------------------ void tst_QShortcut::disabledItems() { - clearAllShortcuts(); - mainW->activateWindow(); - QVERIFY(QTest::qWaitForWindowActive(mainW)); + ButtonWidget mainW; + mainW.setWindowTitle(QTest::currentTestFunction()); + mainW.show(); + mainW.activateWindow(); + QVERIFY(QTest::qWaitForWindowActive(&mainW)); /* Testing Disabled Shortcuts Qt::Key_M on slot1 @@ -618,27 +626,27 @@ void tst_QShortcut::disabledItems() */ // Setup two identical shortcuts on different pushbuttons - QPushButton pb1(mainW); - QPushButton pb2(mainW); - pb1.setObjectName("pushbutton-1"); - pb2.setObjectName("pushbutton-2"); - pb1.show(); // Must be show for QShortcutMap::correctSubWindow to trigger - pb2.show(); - - QShortcut *cut1 = setupShortcut(&pb1, "shortcut1-pb1", TriggerSlot1, "M"); - QShortcut *cut2 = setupShortcut(&pb1, "shortcut2-pb1", TriggerSlot1, "Shift+M"); - QShortcut *cut3 = setupShortcut(&pb2, "shortcut3-pb2", TriggerSlot2, "M"); - QShortcut *cut4 = setupShortcut(&pb2, "shortcut4-pb2", TriggerSlot2, "Shift+M"); + auto pb1 = mainW.pushButton1(); + auto pb2 = mainW.pushButton2(); + const int shiftM = Qt::SHIFT + Qt::Key_M; + QShortcut *cut1 = setupShortcut(pb1, "shortcut1-pb1", TriggerSlot1, + QKeySequence(Qt::Key_M)); + QShortcut *cut2 = setupShortcut(pb1, "shortcut2-pb1", TriggerSlot1, + QKeySequence(shiftM)); + QShortcut *cut3 = setupShortcut(pb2, "shortcut3-pb2", TriggerSlot2, + QKeySequence(Qt::Key_M)); + QShortcut *cut4 = setupShortcut(pb2, "shortcut4-pb2", TriggerSlot2, + QKeySequence(shiftM)); cut3->setEnabled(false); cut4->setEnabled(false); currentResult = NoResult; - sendKeyEvents(Qt::Key_M, 'm'); + sendKeyEvents(&mainW, Qt::Key_M, 'm'); QCOMPARE(currentResult, Slot1Triggered); currentResult = NoResult; - sendKeyEvents(Qt::SHIFT+Qt::Key_M, 'M'); + sendKeyEvents(&mainW, shiftM, 'M'); QCOMPARE(currentResult, Slot1Triggered); cut2->setEnabled(false); @@ -651,11 +659,11 @@ void tst_QShortcut::disabledItems() Shift + Qt::Key_M on slot2 */ currentResult = NoResult; - sendKeyEvents( Qt::Key_M, 'm' ); + sendKeyEvents(&mainW, Qt::Key_M, 'm' ); QCOMPARE( currentResult, Slot1Triggered ); currentResult = NoResult; - sendKeyEvents( Qt::SHIFT+Qt::Key_M, 'M' ); + sendKeyEvents(&mainW, shiftM, 'M' ); QCOMPARE( currentResult, Slot2Triggered ); @@ -663,67 +671,34 @@ void tst_QShortcut::disabledItems() Qt::Key_F5 on slot1 Shift + Qt::Key_F5 on slot2 (disabled) */ - clearAllShortcuts(); - cut1 = setupShortcut(&pb1, "shortcut1-pb1", TriggerSlot1, "F5"); - cut4 = setupShortcut(&pb2, "shortcut4-pb2", TriggerSlot2, "Shift+F5"); - - cut1->setKey(QKeySequence("F5")); - cut4->setKey(QKeySequence("Shift+F5")); + qDeleteAll(mainW.findChildren<QShortcut *>()); + const int shiftF5 = Qt::SHIFT + Qt::Key_F5; + cut1 = setupShortcut(pb1, "shortcut1-pb1", TriggerSlot1, QKeySequence(Qt::Key_F5)); + cut4 = setupShortcut(pb2, "shortcut4-pb2", TriggerSlot2, QKeySequence(shiftF5)); cut1->setEnabled(true); cut4->setEnabled(false); currentResult = NoResult; - sendKeyEvents( Qt::Key_F5, 0 ); + sendKeyEvents(&mainW, Qt::Key_F5, 0 ); QCOMPARE( currentResult, Slot1Triggered ); currentResult = NoResult; - sendKeyEvents( Qt::SHIFT+Qt::Key_F5, 0 ); - QCOMPARE( currentResult, NoResult ); - -#if 0 - qFatal("Not testing statusbar text feedback yet, since not implemented"); - /* Testing Disabled Accel, and the corresponding statusbar feedback - Ctrl + Qt::Key_K, Ctrl + Qt::Key_L on slot1 - Ctrl + Qt::Key_K, Ctrl + Qt::Key_M on slot2 (disabled) - */ - cut1->setKey(QKeySequence("Ctrl+K, Ctrl+L")); - cut4->setKey(QKeySequence("Ctrl+K, Ctrl+M")); - - cut1->setEnabled(true); - cut4->setEnabled(false); - - currentResult = NoResult; - sendKeyEvents( Qt::CTRL+Qt::Key_K, 0 ); - sendKeyEvents( Qt::CTRL+Qt::Key_Q, 0 ); - QCOMPARE( currentResult, NoResult ); - if (over_330) - QCOMPARE( sbText, QString("Ctrl+K, Ctrl+Q not defined") ); - - currentResult = NoResult; - sendKeyEvents( Qt::CTRL+Qt::Key_K, 0 ); - sendKeyEvents( Qt::CTRL+Qt::Key_M, 0 ); + sendKeyEvents(&mainW, shiftF5, 0 ); QCOMPARE( currentResult, NoResult ); - if (over_330) - QCOMPARE( sbText, QString() ); - - currentResult = NoResult; - sendKeyEvents( Qt::CTRL+Qt::Key_K, 0 ); - sendKeyEvents( Qt::CTRL+Qt::Key_L, 0 ); - QCOMPARE( currentResult, Slot1Triggered ); - if (over_330) - QCOMPARE( sbText, QString() ); -#endif - clearAllShortcuts(); - cut1 = 0; - cut4 = 0; } // ------------------------------------------------------------------ // Ambiguous Elements ----------------------------------------------- // ------------------------------------------------------------------ void tst_QShortcut::ambiguousRotation() { - clearAllShortcuts(); + MainWindow mainW; + const QString name = QLatin1String(QTest::currentTestFunction()); + mainW.setWindowTitle(name); + mainW.show(); + mainW.activateWindow(); + QVERIFY(QTest::qWaitForWindowActive(&mainW)); + /* Testing Shortcut rotation scheme Ctrl + Qt::Key_A on slot1 (disabled) Ctrl + Qt::Key_A on slot2 (disabled) @@ -733,13 +708,15 @@ void tst_QShortcut::ambiguousRotation() Ctrl + Qt::Key_A on slot6 Ctrl + Qt::Key_A on slot7 (disabled) */ - QShortcut *cut1 = setupShortcut(TriggerSlot1, "Ctrl+A"); - QShortcut *cut2 = setupShortcut(TriggerSlot2, "Ctrl+A"); - QShortcut *cut3 = setupShortcut(TriggerSlot3, "Ctrl+A"); - QShortcut *cut4 = setupShortcut(TriggerSlot4, "Ctrl+A"); - QShortcut *cut5 = setupShortcut(TriggerSlot5, "Ctrl+A"); - QShortcut *cut6 = setupShortcut(TriggerSlot6, "Ctrl+A"); - QShortcut *cut7 = setupShortcut(TriggerSlot7, "Ctrl+A"); + const int ctrlA = Qt::CTRL + Qt::Key_A; + QKeySequence ctrlA_Sequence(ctrlA); + QShortcut *cut1 = setupShortcut(&mainW, name, TriggerSlot1, ctrlA_Sequence); + QShortcut *cut2 = setupShortcut(&mainW, name, TriggerSlot2, ctrlA_Sequence); + QShortcut *cut3 = setupShortcut(&mainW, name, TriggerSlot3, ctrlA_Sequence); + QShortcut *cut4 = setupShortcut(&mainW, name, TriggerSlot4, ctrlA_Sequence); + QShortcut *cut5 = setupShortcut(&mainW, name, TriggerSlot5, ctrlA_Sequence); + QShortcut *cut6 = setupShortcut(&mainW, name, TriggerSlot6, ctrlA_Sequence); + QShortcut *cut7 = setupShortcut(&mainW, name, TriggerSlot7, ctrlA_Sequence); cut1->setEnabled(false); cut2->setEnabled(false); @@ -753,37 +730,37 @@ void tst_QShortcut::ambiguousRotation() // Continue... currentResult = NoResult; ambigResult = NoResult; - sendKeyEvents(Qt::CTRL+Qt::Key_A); + sendKeyEvents(&mainW, ctrlA); QCOMPARE(currentResult, Ambiguous); QCOMPARE(ambigResult, Slot3Triggered); currentResult = NoResult; ambigResult = NoResult; - sendKeyEvents(Qt::CTRL+Qt::Key_A); + sendKeyEvents(&mainW, ctrlA); QCOMPARE(currentResult, Ambiguous); QCOMPARE(ambigResult, Slot4Triggered); currentResult = NoResult; ambigResult = NoResult; - sendKeyEvents(Qt::CTRL+Qt::Key_A); + sendKeyEvents(&mainW, ctrlA); QCOMPARE(currentResult, Ambiguous); QCOMPARE(ambigResult, Slot6Triggered); currentResult = NoResult; ambigResult = NoResult; - sendKeyEvents(Qt::CTRL+Qt::Key_A); + sendKeyEvents(&mainW, ctrlA); QCOMPARE(currentResult, Ambiguous); QCOMPARE(ambigResult, Slot3Triggered); currentResult = NoResult; ambigResult = NoResult; - sendKeyEvents(Qt::CTRL+Qt::Key_A); + sendKeyEvents(&mainW, ctrlA); QCOMPARE(currentResult, Ambiguous); QCOMPARE(ambigResult, Slot4Triggered); currentResult = NoResult; ambigResult = NoResult; - sendKeyEvents(Qt::CTRL+Qt::Key_A); + sendKeyEvents(&mainW, ctrlA); QCOMPARE(currentResult, Ambiguous); QCOMPARE(ambigResult, Slot6Triggered); @@ -808,94 +785,87 @@ void tst_QShortcut::ambiguousRotation() currentResult = NoResult; ambigResult = NoResult; - sendKeyEvents(Qt::CTRL+Qt::Key_A); + sendKeyEvents(&mainW, ctrlA); QCOMPARE(currentResult, Ambiguous); QCOMPARE(ambigResult, Slot1Triggered); currentResult = NoResult; ambigResult = NoResult; - sendKeyEvents(Qt::CTRL+Qt::Key_A); + sendKeyEvents(&mainW, ctrlA); QCOMPARE(currentResult, Ambiguous); QCOMPARE(ambigResult, Slot2Triggered); currentResult = NoResult; ambigResult = NoResult; - sendKeyEvents(Qt::CTRL+Qt::Key_A); + sendKeyEvents(&mainW, ctrlA); QCOMPARE(currentResult, Ambiguous); QCOMPARE(ambigResult, Slot5Triggered); currentResult = NoResult; ambigResult = NoResult; - sendKeyEvents(Qt::CTRL+Qt::Key_A); + sendKeyEvents(&mainW, ctrlA); QCOMPARE(currentResult, Ambiguous); QCOMPARE(ambigResult, Slot7Triggered); currentResult = NoResult; ambigResult = NoResult; - sendKeyEvents(Qt::CTRL+Qt::Key_A); + sendKeyEvents(&mainW, ctrlA); QCOMPARE(currentResult, Ambiguous); QCOMPARE(ambigResult, Slot1Triggered); currentResult = NoResult; ambigResult = NoResult; - sendKeyEvents(Qt::CTRL+Qt::Key_A); + sendKeyEvents(&mainW, ctrlA); QCOMPARE(currentResult, Ambiguous); QCOMPARE(ambigResult, Slot2Triggered); currentResult = NoResult; ambigResult = NoResult; - sendKeyEvents(Qt::CTRL+Qt::Key_A); + sendKeyEvents(&mainW, ctrlA); QCOMPARE(currentResult, Ambiguous); QCOMPARE(ambigResult, Slot5Triggered); currentResult = NoResult; ambigResult = NoResult; - sendKeyEvents(Qt::CTRL+Qt::Key_A); + sendKeyEvents(&mainW, ctrlA); QCOMPARE(currentResult, Ambiguous); QCOMPARE(ambigResult, Slot7Triggered); - - clearAllShortcuts(); - cut1 = 0; cut2 = 0; - cut3 = 0; cut4 = 0; - cut5 = 0; cut6 = 0; - cut7 = 0; } void tst_QShortcut::ambiguousItems() { - clearAllShortcuts(); + ButtonWidget mainW; + mainW.setWindowTitle(QTest::currentTestFunction()); + mainW.show(); + mainW.activateWindow(); + QVERIFY(QTest::qWaitForWindowActive(&mainW)); + /* Testing Ambiguous Shortcuts Qt::Key_M on Pushbutton 1 Qt::Key_M on Pushbutton 2 */ // Setup two identical shortcuts on different pushbuttons - QPushButton pb1(mainW); - QPushButton pb2(mainW); - pb1.setObjectName("pushbutton-1"); - pb2.setObjectName("pushbutton-2"); - pb1.show(); // Must be show for QShortcutMap::correctSubWindow to trigger - pb2.show(); + auto pb1 = mainW.pushButton1(); + auto pb2 = mainW.pushButton2(); - setupShortcut(&pb1, "shortcut1-pb1", TriggerSlot1, "M"); - setupShortcut(&pb1, "shortcut2-pb2", TriggerSlot2, "M"); + setupShortcut(pb1, "shortcut1-pb1", TriggerSlot1, QKeySequence(Qt::Key_M)); + setupShortcut(pb2, "shortcut2-pb2", TriggerSlot2, QKeySequence(Qt::Key_M)); currentResult = NoResult; - sendKeyEvents( Qt::Key_M, 'm' ); + sendKeyEvents(&mainW, Qt::Key_M, 'm' ); QCOMPARE( currentResult, Ambiguous ); QCOMPARE( ambigResult, Slot1Triggered ); currentResult = NoResult; - sendKeyEvents( Qt::Key_M, 'm' ); + sendKeyEvents(&mainW, Qt::Key_M, 'm' ); QCOMPARE( currentResult, Ambiguous ); QCOMPARE( ambigResult, Slot2Triggered ); currentResult = NoResult; - sendKeyEvents( Qt::Key_M, 'm' ); + sendKeyEvents(&mainW, Qt::Key_M, 'm' ); QCOMPARE( currentResult, Ambiguous ); QCOMPARE( ambigResult, Slot1Triggered ); - - clearAllShortcuts(); } @@ -904,32 +874,31 @@ void tst_QShortcut::ambiguousItems() // ------------------------------------------------------------------ void tst_QShortcut::unicodeCompare() { - clearAllShortcuts(); + ButtonWidget mainW; + mainW.setWindowTitle(QTest::currentTestFunction()); + mainW.show(); + mainW.activateWindow(); + QVERIFY(QTest::qWaitForWindowActive(&mainW)); + /* Testing Unicode/non-Unicode Shortcuts Qt::Key_M on Pushbutton 1 Qt::Key_M on Pushbutton 2 */ - QPushButton pb1(mainW); - QPushButton pb2(mainW); - pb1.setObjectName("pushbutton-1"); - pb2.setObjectName("pushbutton-2"); - pb1.show(); // Must be show for QShortcutMap::correctSubWindow to trigger - pb2.show(); + auto pb1 = mainW.pushButton1(); + auto pb2 = mainW.pushButton2(); QKeySequence ks1("Ctrl+M"); // Unicode QKeySequence ks2(Qt::CTRL+Qt::Key_M); // non-Unicode - setupShortcut(&pb1, "shortcut1-pb1", TriggerSlot1, ks1); - setupShortcut(&pb1, "shortcut2-pb2", TriggerSlot2, ks2); + setupShortcut(pb1, "shortcut1-pb1", TriggerSlot1, ks1); + setupShortcut(pb2, "shortcut2-pb2", TriggerSlot2, ks2); currentResult = NoResult; - sendKeyEvents( Qt::CTRL+Qt::Key_M, 0 ); + sendKeyEvents(&mainW, Qt::CTRL + Qt::Key_M, 0); QCOMPARE( currentResult, Ambiguous ); // They _are_ ambiguous, so the QKeySequence operator== // should indicate the same QVERIFY( ks1 == ks2 ); QVERIFY( !(ks1 != ks2) ); - - clearAllShortcuts(); } // ------------------------------------------------------------------ @@ -937,25 +906,29 @@ void tst_QShortcut::unicodeCompare() // ------------------------------------------------------------------ void tst_QShortcut::keypressConsumption() { - clearAllShortcuts(); - edit->clear(); - QCOMPARE(edit->toPlainText().size(), 0); + MainWindow mainW; + mainW.setWindowTitle(QTest::currentTestFunction()); + mainW.show(); + mainW.activateWindow(); + QVERIFY(QTest::qWaitForWindowActive(&mainW)); + auto edit = mainW.testEdit(); - QShortcut *cut1 = setupShortcut(edit, "shortcut1-line", TriggerSlot1, "Ctrl+I, A"); - QShortcut *cut2 = setupShortcut(edit, "shortcut1-line", TriggerSlot2, "Ctrl+I, B"); + const int ctrlI = Qt::CTRL + Qt::Key_I; + QShortcut *cut1 = setupShortcut(edit, "shortcut1-line", TriggerSlot1, QKeySequence(ctrlI, Qt::Key_A)); + QShortcut *cut2 = setupShortcut(edit, "shortcut1-line", TriggerSlot2, QKeySequence(ctrlI, Qt::Key_B)); currentResult = NoResult; ambigResult = NoResult; - sendKeyEvents(edit, Qt::CTRL + Qt::Key_I, 0); // Send key to edit + sendKeyEvents(edit, ctrlI, 0); // Send key to edit QCOMPARE( currentResult, NoResult ); QCOMPARE( ambigResult, NoResult ); - QCOMPARE(edit->toPlainText(), QString("")); + QCOMPARE(edit->toPlainText(), QString()); // Make sure next keypress is eaten (failing multiple keysequence) sendKeyEvents(edit, Qt::Key_C, 'c'); // Send key to edit QCOMPARE( currentResult, NoResult ); QCOMPARE( ambigResult, NoResult ); - QCOMPARE(edit->toPlainText(), QString("")); + QCOMPARE(edit->toPlainText(), QString()); // Next keypress should be normal sendKeyEvents(edit, Qt::Key_C, 'c'); // Send key to edit @@ -983,11 +956,15 @@ void tst_QShortcut::keypressConsumption() QCOMPARE( ambigResult, NoResult ); QVERIFY(edit->toPlainText().endsWith("<Ctrl+I>a")); - clearAllShortcuts(); + qDeleteAll(mainW.findChildren<QShortcut *>()); edit->clear(); QCOMPARE(edit->toPlainText().size(), 0); - setupShortcut(edit, "first", SendKeyEvent, "Ctrl+A"); + auto cut = setupShortcut(edit, QLatin1String("first"), QKeySequence(Qt::CTRL + Qt::Key_A)); + connect(cut, &QShortcut::activated, edit, [this, edit] () { + this->sendKeyEvents(edit, Qt::CTRL + Qt::Key_B, 0); + this->currentResult = tst_QShortcut::SentKeyEvent; + }); // Verify reentrancy when a non-shortcut is triggered as part // of shortcut processing. @@ -996,7 +973,7 @@ void tst_QShortcut::keypressConsumption() sendKeyEvents(edit, Qt::CTRL + Qt::Key_A, 0); QCOMPARE(currentResult, SentKeyEvent); QCOMPARE(ambigResult, NoResult); - QCOMPARE(edit->toPlainText(), QString(QString("<Ctrl+B>"))); + QCOMPARE(edit->toPlainText(), QLatin1String("<Ctrl+B>")); } // ------------------------------------------------------------------ @@ -1004,12 +981,17 @@ void tst_QShortcut::keypressConsumption() // ------------------------------------------------------------------ void tst_QShortcut::context() { - clearAllShortcuts(); + const QString name = QLatin1String(QTest::currentTestFunction()); + MainWindow mainW; + mainW.setWindowTitle(name + QLatin1String("_Helper")); + mainW.show(); + auto edit = mainW.testEdit(); QWidget myBox; - TestEdit *other1 = new TestEdit(&myBox, "test_edit_other1"); - TestEdit *other2 = new TestEdit(&myBox, "test_edit_other2"); - QHBoxLayout *layout = new QHBoxLayout(&myBox); + myBox.setWindowTitle(name); + auto other1 = new TestEdit(&myBox, "test_edit_other1"); + auto other2 = new TestEdit(&myBox, "test_edit_other2"); + auto layout = new QHBoxLayout(&myBox); layout->addWidget(other1); layout->addWidget(other2); myBox.show(); @@ -1034,8 +1016,8 @@ void tst_QShortcut::context() // Focus on 'other1' edit, so Active Window context should trigger other1->activateWindow(); // <--- QApplication::setActiveWindow(other1); - QCOMPARE(qApp->activeWindow(), other1->window()); - QCOMPARE(qApp->focusWidget(), (QWidget *)other1); + QCOMPARE(QApplication::activeWindow(), other1->window()); + QCOMPARE(QApplication::focusWidget(), static_cast<QWidget *>(other1)); currentResult = NoResult; ambigResult = NoResult; @@ -1043,13 +1025,13 @@ void tst_QShortcut::context() other1->clear(); other2->clear(); - QCOMPARE(qApp->focusWidget(), (QWidget *)other1); + QCOMPARE(QApplication::focusWidget(), static_cast<QWidget *>(other1)); sendKeyEvents(other1, Qt::ALT+Qt::Key_1); QCOMPARE(currentResult, Slot1Triggered); QCOMPARE(ambigResult, NoResult); - QCOMPARE(edit->toPlainText(), QString("")); - QCOMPARE(other1->toPlainText(), QString("")); - QCOMPARE(other2->toPlainText(), QString("")); + QCOMPARE(edit->toPlainText(), QString()); + QCOMPARE(other1->toPlainText(), QString()); + QCOMPARE(other2->toPlainText(), QString()); // ..but not Focus context on 'other2'.. currentResult = NoResult; @@ -1061,9 +1043,9 @@ void tst_QShortcut::context() sendKeyEvents(other1, Qt::ALT+Qt::Key_2); QCOMPARE(currentResult, NoResult); QCOMPARE(ambigResult, NoResult); - QCOMPARE(edit->toPlainText(), QString("")); + QCOMPARE(edit->toPlainText(), QString()); QCOMPARE(other1->toPlainText(), QString("<Alt+2>")); - QCOMPARE(other2->toPlainText(), QString("")); + QCOMPARE(other2->toPlainText(), QString()); // ..however, application global context on 'edit' should.. currentResult = NoResult; @@ -1075,15 +1057,15 @@ void tst_QShortcut::context() sendKeyEvents(other1, Qt::ALT+Qt::Key_3); QCOMPARE(currentResult, Slot3Triggered); QCOMPARE(ambigResult, NoResult); - QCOMPARE(edit->toPlainText(), QString("")); - QCOMPARE(other1->toPlainText(), QString("")); - QCOMPARE(other2->toPlainText(), QString("")); + QCOMPARE(edit->toPlainText(), QString()); + QCOMPARE(other1->toPlainText(), QString()); + QCOMPARE(other2->toPlainText(), QString()); // Changing focus to 'other2' should make the Focus context there work other2->activateWindow(); other2->setFocus(); // ### - QTRY_COMPARE(qApp->activeWindow(), other2->window()); - QCOMPARE(qApp->focusWidget(), (QWidget *)other2); + QTRY_COMPARE(QApplication::activeWindow(), other2->window()); + QCOMPARE(QApplication::focusWidget(), static_cast<QWidget *>(other2)); currentResult = NoResult; ambigResult = NoResult; @@ -1094,20 +1076,18 @@ void tst_QShortcut::context() sendKeyEvents(other2, Qt::ALT+Qt::Key_2); QCOMPARE(currentResult, Slot2Triggered); QCOMPARE(ambigResult, NoResult); - QCOMPARE(edit->toPlainText(), QString("")); - QCOMPARE(other1->toPlainText(), QString("")); - QCOMPARE(other2->toPlainText(), QString("")); - - clearAllShortcuts(); + QCOMPARE(edit->toPlainText(), QString()); + QCOMPARE(other1->toPlainText(), QString()); + QCOMPARE(other2->toPlainText(), QString()); } // QTBUG-38986, do not generate duplicated QEvent::ShortcutOverride in event processing. class OverrideCountingWidget : public QWidget { public: - OverrideCountingWidget(QWidget *parent = 0) : QWidget(parent), overrideCount(0) {} + using QWidget::QWidget; - int overrideCount; + int overrideCount = 0; bool event(QEvent *e) override { @@ -1131,95 +1111,55 @@ void tst_QShortcut::duplicatedShortcutOverride() QCOMPARE(w.overrideCount, 1); } -// ------------------------------------------------------------------ -// Element Testing helper functions --------------------------------- -// ------------------------------------------------------------------ -void tst_QShortcut::clearAllShortcuts() -{ - QList<QShortcut *> shortcutsCpy = shortcuts; - qDeleteAll(shortcutsCpy); - shortcuts.clear(); -} - -QShortcut *tst_QShortcut::setupShortcut(int testWidget, const QKeySequence &ks) -{ - return setupShortcut(mainW, QTest::currentDataTag() ? QTest::currentDataTag() : "", testWidget, ks); -} - -QShortcut *tst_QShortcut::setupShortcut(int testWidget, const QString &txt, int k1, int k2, int k3, int k4) -{ - return setupShortcut(mainW, QTest::currentDataTag() ? QTest::currentDataTag() : "", testWidget, - (txt.isEmpty() ? QKeySequence(k1, k2, k3, k4) : QKeySequence(txt))); -} - -QShortcut *tst_QShortcut::setupShortcut(QWidget *parent, const char *name, int testWidget, const QString &txt, int k1, int k2, int k3, int k4) +QShortcut *tst_QShortcut::setupShortcut(QWidget *parent, const QString &name, const QKeySequence &ks, Qt::ShortcutContext context) { - return setupShortcut(parent, name, testWidget, - (txt.isEmpty() ? QKeySequence(k1, k2, k3, k4) : QKeySequence(txt))); + // Set up shortcut for next test + auto cut = new QShortcut(ks, parent, nullptr, nullptr, context); + cut->setObjectName(name); + return cut; } -QShortcut *tst_QShortcut::setupShortcut(QWidget *parent, const char *name, int testWidget, +QShortcut *tst_QShortcut::setupShortcut(QWidget *parent, const QString &name, Widget testWidget, const QKeySequence &ks, Qt::ShortcutContext context) { // Set up shortcut for next test - QShortcut *cut = new QShortcut(QKeySequence(), parent, 0, 0, context); - cut->setObjectName(name); - cut->setKey(ks); + auto cut = setupShortcut(parent, name, ks, context); - const char *normal = 0; - const char *ambig = 0; - switch(testWidget) - { + switch (testWidget) { case TriggerSlot1: - normal = SLOT(slotTrig1()); - ambig = SLOT(ambigSlot1()); + connect(cut, &QShortcut::activated, this, &tst_QShortcut::slotTrig1); + connect(cut, &QShortcut::activatedAmbiguously, this, &tst_QShortcut::ambigSlot1); break; case TriggerSlot2: - normal = SLOT(slotTrig2()); - ambig = SLOT(ambigSlot2()); + connect(cut, &QShortcut::activated, this, &tst_QShortcut::slotTrig2); + connect(cut, &QShortcut::activatedAmbiguously, this, &tst_QShortcut::ambigSlot2); break; case TriggerSlot3: - normal = SLOT(slotTrig3()); - ambig = SLOT(ambigSlot3()); + connect(cut, &QShortcut::activated, this, &tst_QShortcut::slotTrig3); + connect(cut, &QShortcut::activatedAmbiguously, this, &tst_QShortcut::ambigSlot3); break; case TriggerSlot4: - normal = SLOT(slotTrig4()); - ambig = SLOT(ambigSlot4()); + connect(cut, &QShortcut::activated, this, &tst_QShortcut::slotTrig4); + connect(cut, &QShortcut::activatedAmbiguously, this, &tst_QShortcut::ambigSlot4); break; case TriggerSlot5: - normal = SLOT(slotTrig5()); - ambig = SLOT(ambigSlot5()); + connect(cut, &QShortcut::activated, this, &tst_QShortcut::slotTrig5); + connect(cut, &QShortcut::activatedAmbiguously, this, &tst_QShortcut::ambigSlot5); break; case TriggerSlot6: - normal = SLOT(slotTrig6()); - ambig = SLOT(ambigSlot6()); + connect(cut, &QShortcut::activated, this, &tst_QShortcut::slotTrig6); + connect(cut, &QShortcut::activatedAmbiguously, this, &tst_QShortcut::ambigSlot6); break; case TriggerSlot7: - normal = SLOT(slotTrig7()); - ambig = SLOT(ambigSlot7()); + connect(cut, &QShortcut::activated, this, &tst_QShortcut::slotTrig7); + connect(cut, &QShortcut::activatedAmbiguously, this, &tst_QShortcut::ambigSlot7); + break; + case NoWidget: break; - case SendKeyEvent: - normal = SLOT(sendKeyEvent()); } - connect(cut, SIGNAL(activated()), this, normal); - if (ambig) - connect(cut, SIGNAL(activatedAmbiguously()), this, ambig); - connect(cut, SIGNAL(destroyed(QObject*)), this, SLOT(shortcutDestroyed(QObject*))); - shortcuts.append(cut); return cut; } -void tst_QShortcut::shortcutDestroyed(QObject* obj) -{ - shortcuts.erase(std::remove(shortcuts.begin(), shortcuts.end(), obj), - shortcuts.end()); -} - -void tst_QShortcut::sendKeyEvents(int k1, QChar c1, int k2, QChar c2, int k3, QChar c3, int k4, QChar c4) -{ - sendKeyEvents(mainW, k1, c1, k2, c2, k3, c3, k4, c4); -} - void tst_QShortcut::sendKeyEvents(QWidget *w, int k1, QChar c1, int k2, QChar c2, int k3, QChar c3, int k4, QChar c4) { Qt::KeyboardModifiers b1 = toButtons( k1 ); @@ -1259,6 +1199,8 @@ void tst_QShortcut::sendKeyEvents(QWidget *w, int k1, QChar c1, int k2, QChar c2 void tst_QShortcut::testElement() { + static QScopedPointer<MainWindow> mainW; + currentResult = NoResult; QFETCH(tst_QShortcut::Action, action); QFETCH(tst_QShortcut::Widget, testWidget); @@ -1273,13 +1215,29 @@ void tst_QShortcut::testElement() QFETCH(int, c4); QFETCH(tst_QShortcut::Result, result); - if (action == ClearAll) { - clearAllShortcuts(); - } else if (action == SetupAccel) { - setupShortcut(testWidget, txt, k1, k2, k3, k4); - } else { - sendKeyEvents(k1, c1, k2, c2, k3, c3, k4, c4); - QCOMPARE((int)currentResult, (int)result); + if (mainW.isNull()) { + mainW.reset(new MainWindow); + mainW->setWindowTitle(QTest::currentTestFunction()); + mainW->show(); + mainW->activateWindow(); + QVERIFY(QTest::qWaitForWindowActive(mainW.data())); + } + + switch (action) { + case ClearAll: + qDeleteAll(mainW->findChildren<QShortcut *>()); + break; + case SetupAccel: + setupShortcut(mainW.data(), txt, testWidget, txt.isEmpty() + ? QKeySequence(k1, k2, k3, k4) : QKeySequence::fromString(txt)); + break; + case TestAccel: + sendKeyEvents(mainW.data(), k1, c1, k2, c2, k3, c3, k4, c4); + QCOMPARE(currentResult, result); + break; + case TestEnd: + mainW.reset(); + break; } } diff --git a/tests/auto/widgets/kernel/qwidget/BLACKLIST b/tests/auto/widgets/kernel/qwidget/BLACKLIST index 03bec4286b..26f9ce1b85 100644 --- a/tests/auto/widgets/kernel/qwidget/BLACKLIST +++ b/tests/auto/widgets/kernel/qwidget/BLACKLIST @@ -2,30 +2,31 @@ [normalGeometry] ubuntu-16.04 [saveRestoreGeometry] -xcb +opensuse-leap +ubuntu-16.04 b2qt +opensuse-42.3 [restoreVersion1Geometry] -osx -[updateWhileMinimized] ubuntu-16.04 +[updateWhileMinimized] ubuntu-18.04 rhel-7.4 +ubuntu-16.04 rhel-7.6 -osx [focusProxyAndInputMethods] -linux +rhel-7.6 +opensuse-leap +ubuntu [raise] -# QTBUG-68175 -opensuse opensuse-leap -[setWindowGeometry] -osx -[windowMoveResize] -osx +# QTBUG-68175 +opensuse-42.3 [childEvents] osx ci [renderInvisible] -osx +osx-10.12 +osx-10.11 +osx-10.14 [optimizedResizeMove] osx [optimizedResize_topLevel] @@ -40,12 +41,11 @@ opensuse opensuse-leap [moveInResizeEvent] ubuntu-16.04 -[moveChild:right] -osx -[activateWindow] -osx-10.12 ci [multipleToplevelFocusCheck] -linux +rhel-7.6 +opensuse-leap +ubuntu [windowState] # QTBUG-75270 winrt + diff --git a/tests/auto/widgets/kernel/qwidget/qwidget.pro b/tests/auto/widgets/kernel/qwidget/qwidget.pro index c1908af2a2..d3fbd6d0d9 100644 --- a/tests/auto/widgets/kernel/qwidget/qwidget.pro +++ b/tests/auto/widgets/kernel/qwidget/qwidget.pro @@ -16,4 +16,4 @@ mac { OBJECTIVE_SOURCES += tst_qwidget_mac_helpers.mm } -win32:!winrt: LIBS += -luser32 -lgdi32 +win32:!winrt: QMAKE_USE += user32 gdi32 diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index a95d6e76b3..40377eb946 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -46,6 +46,7 @@ #include <qstylefactory.h> #include <qdesktopwidget.h> #include <private/qwidget_p.h> +#include <private/qwidgetrepaintmanager_p.h> #include <private/qapplication_p.h> #include <private/qhighdpiscaling_p.h> #include <qcalendarwidget.h> @@ -54,6 +55,7 @@ #include <qrandom.h> #include <qtoolbar.h> #include <qtoolbutton.h> +#include <QtCore/qoperatingsystemversion.h> #include <QtGui/qpaintengine.h> #include <QtGui/qbackingstore.h> #include <QtGui/qguiapplication.h> @@ -1137,6 +1139,7 @@ void tst_QWidget::visible() QVERIFY( !childWidget->isVisible() ); testWidget->show(); + QVERIFY(testWidget->screen()); QVERIFY( testWidget->isVisible() ); QVERIFY( childWidget->isVisible() ); @@ -2527,8 +2530,8 @@ void tst_QWidget::showMinimizedKeepsFocus() { if (m_platform == QStringLiteral("xcb")) QSKIP("QTBUG-26424"); - if (m_platform == QStringLiteral("wayland")) - QSKIP("Wayland: This fails. Figure out why."); + if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation)) + QSKIP("Window activation is not supported."); if (m_platform == QStringLiteral("offscreen")) QSKIP("Platform offscreen does not support showMinimized()"); @@ -2739,8 +2742,8 @@ void tst_QWidget::icon() void tst_QWidget::hideWhenFocusWidgetIsChild() { - if (m_platform == QStringLiteral("wayland")) - QSKIP("Wayland: This fails. Figure out why."); + if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation)) + QSKIP("Window activation is not supported."); QScopedPointer<QWidget> testWidget(new QWidget); testWidget->setWindowTitle(__FUNCTION__); @@ -5380,7 +5383,7 @@ void tst_QWidget::moveChild() parent.setStyle(style.data()); ColorWidget child(&parent, Qt::Widget, Qt::blue); - parent.setGeometry(QRect(QPoint(QApplication::desktop()->availableGeometry(&parent).topLeft()) + QPoint(50, 50), + parent.setGeometry(QRect(parent.screen()->availableGeometry().topLeft() + QPoint(50, 50), QSize(200, 200))); child.setGeometry(25, 25, 50, 50); #ifndef QT_NO_CURSOR // Try to make sure the cursor is not in a taskbar area to prevent tooltips or window highlighting @@ -5427,8 +5430,7 @@ void tst_QWidget::showAndMoveChild() const QScopedPointer<QStyle> style(QStyleFactory::create(QLatin1String("Windows"))); parent.setStyle(style.data()); - QDesktopWidget desktop; - QRect desktopDimensions = desktop.availableGeometry(&parent); + QRect desktopDimensions = parent.screen()->availableGeometry(); desktopDimensions = desktopDimensions.adjusted(64, 64, -64, -64); #ifndef QT_NO_CURSOR // Try to make sure the cursor is not in a taskbar area to prevent tooltips or window highlighting @@ -5541,8 +5543,8 @@ void tst_QWidget::multipleToplevelFocusCheck() QSKIP("QTBUG-52974"); #endif - if (m_platform == QStringLiteral("wayland")) - QSKIP("Wayland: This fails. Figure out why."); + if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation)) + QSKIP("Window activation is not supported"); else if (m_platform == QStringLiteral("winrt")) QSKIP("Winrt: Sometimes crashes in QTextLayout. - QTBUG-68297"); TopLevelFocusCheck w1; @@ -6256,7 +6258,11 @@ public: return false; } +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + bool nativeEvent(const QByteArray &eventType, void *message, qintptr *) override +#else bool nativeEvent(const QByteArray &eventType, void *message, long *) override +#endif { if (isMapNotify(eventType, message)) gotExpectedMapNotify = true; @@ -6264,7 +6270,11 @@ public: } // QAbstractNativeEventFilter interface +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + bool nativeEventFilter(const QByteArray &eventType, void *message, qintptr *) override +#else bool nativeEventFilter(const QByteArray &eventType, void *message, long *) override +#endif { if (isMapNotify(eventType, message)) gotExpectedGlobalEvent = true; @@ -7095,7 +7105,7 @@ void tst_QWidget::renderWithPainter() // Make sure QWidget::render does not modify the render hints set on the painter. painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform - | QPainter::NonCosmeticDefaultPen | QPainter::TextAntialiasing); + | QPainter::TextAntialiasing); QPainter::RenderHints oldRenderHints = painter.renderHints(); widget.render(&painter); QCOMPARE(painter.renderHints(), oldRenderHints); @@ -7693,13 +7703,11 @@ void tst_QWidget::moveWindowInShowEvent() void tst_QWidget::repaintWhenChildDeleted() { #ifdef Q_OS_WIN - if (QSysInfo::WindowsVersion & QSysInfo::WV_VISTA) { - QTest::qWait(1000); - } + QTest::qWait(1000); #endif ColorWidget w(nullptr, Qt::FramelessWindowHint, Qt::red); w.setWindowTitle(QLatin1String(QTest::currentTestFunction())); - QPoint startPoint = QApplication::desktop()->availableGeometry(&w).topLeft(); + QPoint startPoint = w.screen()->availableGeometry().topLeft(); startPoint.rx() += 50; startPoint.ry() += 50; w.setGeometry(QRect(startPoint, QSize(100, 100))); @@ -7724,7 +7732,7 @@ void tst_QWidget::hideOpaqueChildWhileHidden() { ColorWidget w(nullptr, Qt::FramelessWindowHint, Qt::red); w.setWindowTitle(QLatin1String(QTest::currentTestFunction())); - QPoint startPoint = QApplication::desktop()->availableGeometry(&w).topLeft(); + QPoint startPoint = w.screen()->availableGeometry().topLeft(); startPoint.rx() += 50; startPoint.ry() += 50; w.setGeometry(QRect(startPoint, QSize(100, 100))); @@ -8064,7 +8072,7 @@ public: sp.setHeightForWidth(hfwLayout); QVBoxLayout *vbox = new QVBoxLayout; - vbox->setMargin(0); + vbox->setContentsMargins(0, 0, 0, 0); vbox->addWidget(new ASWidget(sizeHint + QSize(30, 20), sp, false, false)); setLayout(vbox); } @@ -8892,13 +8900,13 @@ void tst_QWidget::translucentWidget() #ifdef Q_OS_WIN QWidget *desktopWidget = QApplication::desktop()->screen(0); - if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA) - widgetSnapshot = grabWindow(desktopWidget->windowHandle(), labelPos.x(), labelPos.y(), label.width(), label.height()); - else + widgetSnapshot = grabWindow(desktopWidget->windowHandle(), labelPos.x(), labelPos.y(), label.width(), label.height()); +#else + widgetSnapshot = label.grab(QRect(QPoint(0, 0), label.size())); #endif - widgetSnapshot = label.grab(QRect(QPoint(0, 0), label.size())); const QImage actual = widgetSnapshot.toImage().convertToFormat(QImage::Format_RGB32); - const QImage expected = pm.toImage().scaled(label.devicePixelRatioF() * pm.size()); + QImage expected = pm.toImage().scaled(label.devicePixelRatioF() * pm.size()); + expected.setDevicePixelRatio(label.devicePixelRatioF()); if (m_platform == QStringLiteral("winrt")) QEXPECT_FAIL("", "WinRT: This fails. QTBUG-68297.", Abort); QCOMPARE(actual.size(),expected.size()); @@ -9555,7 +9563,7 @@ void tst_QWidget::destroyBackingStore() QTRY_VERIFY(w.numPaintEvents > 0); w.reset(); w.update(); - qt_widget_private(&w)->topData()->backingStoreTracker.create(&w); + qt_widget_private(&w)->topData()->repaintManager.reset(new QWidgetRepaintManager(&w)); w.update(); QApplication::processEvents(); @@ -9570,14 +9578,14 @@ void tst_QWidget::destroyBackingStore() #endif // QT_BUILD_INTERNAL // Helper function -QWidgetBackingStore* backingStore(QWidget &widget) +QWidgetRepaintManager* repaintManager(QWidget &widget) { - QWidgetBackingStore *backingStore = nullptr; + QWidgetRepaintManager *repaintManager = nullptr; #ifdef QT_BUILD_INTERNAL if (QTLWExtra *topExtra = qt_widget_private(&widget)->maybeTopData()) - backingStore = topExtra->backingStoreTracker.data(); + repaintManager = topExtra->repaintManager.get(); #endif - return backingStore; + return repaintManager; } // Tables of 5000 elements do not make sense on Windows Mobile. @@ -9592,8 +9600,7 @@ void tst_QWidget::rectOutsideCoordinatesLimit_task144779() palette.setColor(QPalette::Window, Qt::red); main.setPalette(palette); - QDesktopWidget desktop; - QRect desktopDimensions = desktop.availableGeometry(&main); + QRect desktopDimensions = main.screen()->availableGeometry(); QSize mainSize(400, 400); mainSize = mainSize.boundedTo(desktopDimensions.size()); main.resize(mainSize); @@ -9674,8 +9681,8 @@ void tst_QWidget::setGraphicsEffect() void tst_QWidget::activateWindow() { - if (m_platform == QStringLiteral("wayland")) - QSKIP("Wayland: This fails. Figure out why."); + if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation)) + QSKIP("Window activation is not supported."); // Test case for QTBUG-26711 @@ -9743,8 +9750,8 @@ void tst_QWidget::openModal_taskQTBUG_5804() void tst_QWidget::focusProxyAndInputMethods() { - if (m_platform == QStringLiteral("wayland")) - QSKIP("Wayland: This fails. Figure out why."); + if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation)) + QSKIP("Window activation is not supported."); QScopedPointer<QWidget> toplevel(new QWidget(nullptr, Qt::X11BypassWindowManagerHint)); toplevel->setWindowTitle(QLatin1String(QTest::currentTestFunction())); toplevel->resize(200, 200); @@ -9775,12 +9782,12 @@ class scrollWidgetWBS : public QWidget public: void deleteBackingStore() { - static_cast<QWidgetPrivate*>(d_ptr.data())->topData()->backingStoreTracker.destroy(); + static_cast<QWidgetPrivate*>(d_ptr.data())->topData()->repaintManager.reset(nullptr); } void enableBackingStore() { - if (!static_cast<QWidgetPrivate*>(d_ptr.data())->maybeBackingStore()) { - static_cast<QWidgetPrivate*>(d_ptr.data())->topData()->backingStoreTracker.create(this); + if (!static_cast<QWidgetPrivate*>(d_ptr.data())->maybeRepaintManager()) { + static_cast<QWidgetPrivate*>(d_ptr.data())->topData()->repaintManager.reset(new QWidgetRepaintManager(this)); static_cast<QWidgetPrivate*>(d_ptr.data())->invalidateBackingStore(this->rect()); repaint(); } @@ -10111,7 +10118,7 @@ void tst_QWidget::grabMouse() w.setObjectName(QLatin1String("tst_qwidget_grabMouse")); w.setWindowTitle(w.objectName()); QLayout *layout = new QVBoxLayout(&w); - layout->setMargin(50); + layout->setContentsMargins(50, 50, 50, 50); GrabLoggerWidget *grabber = new GrabLoggerWidget(&log, &w); const QString grabberObjectName = QLatin1String("tst_qwidget_grabMouse_grabber"); grabber->setObjectName(grabberObjectName); diff --git a/tests/auto/widgets/kernel/qwidget_window/BLACKLIST b/tests/auto/widgets/kernel/qwidget_window/BLACKLIST index 934f2e8025..39d7b695f6 100644 --- a/tests/auto/widgets/kernel/qwidget_window/BLACKLIST +++ b/tests/auto/widgets/kernel/qwidget_window/BLACKLIST @@ -2,7 +2,7 @@ # QTBUG-66345 opensuse-42.3 ubuntu-16.04 -ubuntu-18.04 [setWindowState] ubuntu-18.04 -rhel +rhel-7.6 + diff --git a/tests/auto/widgets/styles/qstyle/images/mac/button.png b/tests/auto/widgets/styles/qstyle/images/mac/button.png Binary files differdeleted file mode 100644 index 7b11325e87..0000000000 --- a/tests/auto/widgets/styles/qstyle/images/mac/button.png +++ /dev/null diff --git a/tests/auto/widgets/styles/qstyle/images/mac/combobox.png b/tests/auto/widgets/styles/qstyle/images/mac/combobox.png Binary files differdeleted file mode 100644 index ded0b11f29..0000000000 --- a/tests/auto/widgets/styles/qstyle/images/mac/combobox.png +++ /dev/null diff --git a/tests/auto/widgets/styles/qstyle/images/mac/lineedit.png b/tests/auto/widgets/styles/qstyle/images/mac/lineedit.png Binary files differdeleted file mode 100644 index 8d2861b65b..0000000000 --- a/tests/auto/widgets/styles/qstyle/images/mac/lineedit.png +++ /dev/null diff --git a/tests/auto/widgets/styles/qstyle/images/mac/mdi.png b/tests/auto/widgets/styles/qstyle/images/mac/mdi.png Binary files differdeleted file mode 100644 index 8c09ae4338..0000000000 --- a/tests/auto/widgets/styles/qstyle/images/mac/mdi.png +++ /dev/null diff --git a/tests/auto/widgets/styles/qstyle/images/mac/menu.png b/tests/auto/widgets/styles/qstyle/images/mac/menu.png Binary files differdeleted file mode 100644 index 5dd9111d69..0000000000 --- a/tests/auto/widgets/styles/qstyle/images/mac/menu.png +++ /dev/null diff --git a/tests/auto/widgets/styles/qstyle/images/mac/radiobutton.png b/tests/auto/widgets/styles/qstyle/images/mac/radiobutton.png Binary files differdeleted file mode 100644 index 8828e220a2..0000000000 --- a/tests/auto/widgets/styles/qstyle/images/mac/radiobutton.png +++ /dev/null diff --git a/tests/auto/widgets/styles/qstyle/images/mac/slider.png b/tests/auto/widgets/styles/qstyle/images/mac/slider.png Binary files differdeleted file mode 100644 index fc65035631..0000000000 --- a/tests/auto/widgets/styles/qstyle/images/mac/slider.png +++ /dev/null diff --git a/tests/auto/widgets/styles/qstyle/images/mac/spinbox.png b/tests/auto/widgets/styles/qstyle/images/mac/spinbox.png Binary files differdeleted file mode 100644 index ee88441ecb..0000000000 --- a/tests/auto/widgets/styles/qstyle/images/mac/spinbox.png +++ /dev/null diff --git a/tests/auto/widgets/styles/qstyle/images/vista/button.png b/tests/auto/widgets/styles/qstyle/images/vista/button.png Binary files differdeleted file mode 100644 index a6c45276ca..0000000000 --- a/tests/auto/widgets/styles/qstyle/images/vista/button.png +++ /dev/null diff --git a/tests/auto/widgets/styles/qstyle/images/vista/combobox.png b/tests/auto/widgets/styles/qstyle/images/vista/combobox.png Binary files differdeleted file mode 100644 index 9b82f64d32..0000000000 --- a/tests/auto/widgets/styles/qstyle/images/vista/combobox.png +++ /dev/null diff --git a/tests/auto/widgets/styles/qstyle/images/vista/lineedit.png b/tests/auto/widgets/styles/qstyle/images/vista/lineedit.png Binary files differdeleted file mode 100644 index b2c6ac1ae4..0000000000 --- a/tests/auto/widgets/styles/qstyle/images/vista/lineedit.png +++ /dev/null diff --git a/tests/auto/widgets/styles/qstyle/images/vista/menu.png b/tests/auto/widgets/styles/qstyle/images/vista/menu.png Binary files differdeleted file mode 100644 index b114099cc3..0000000000 --- a/tests/auto/widgets/styles/qstyle/images/vista/menu.png +++ /dev/null diff --git a/tests/auto/widgets/styles/qstyle/images/vista/radiobutton.png b/tests/auto/widgets/styles/qstyle/images/vista/radiobutton.png Binary files differdeleted file mode 100644 index c8aa7864df..0000000000 --- a/tests/auto/widgets/styles/qstyle/images/vista/radiobutton.png +++ /dev/null diff --git a/tests/auto/widgets/styles/qstyle/images/vista/slider.png b/tests/auto/widgets/styles/qstyle/images/vista/slider.png Binary files differdeleted file mode 100644 index 7c156ded9d..0000000000 --- a/tests/auto/widgets/styles/qstyle/images/vista/slider.png +++ /dev/null diff --git a/tests/auto/widgets/styles/qstyle/images/vista/spinbox.png b/tests/auto/widgets/styles/qstyle/images/vista/spinbox.png Binary files differdeleted file mode 100644 index b8d0823ab2..0000000000 --- a/tests/auto/widgets/styles/qstyle/images/vista/spinbox.png +++ /dev/null diff --git a/tests/auto/widgets/styles/qstyle/qstyle.pro b/tests/auto/widgets/styles/qstyle/qstyle.pro index 9ad0940245..4dc0525c49 100644 --- a/tests/auto/widgets/styles/qstyle/qstyle.pro +++ b/tests/auto/widgets/styles/qstyle/qstyle.pro @@ -2,8 +2,3 @@ CONFIG += testcase TARGET = tst_qstyle QT += widgets testlib testlib-private SOURCES += tst_qstyle.cpp - -android:!android-embedded { - RESOURCES += \ - testdata.qrc -} diff --git a/tests/auto/widgets/styles/qstyle/testdata.qrc b/tests/auto/widgets/styles/qstyle/testdata.qrc deleted file mode 100644 index 29bb46726e..0000000000 --- a/tests/auto/widgets/styles/qstyle/testdata.qrc +++ /dev/null @@ -1,19 +0,0 @@ -<RCC> - <qresource prefix="/"> - <file>images/mac/button.png</file> - <file>images/mac/combobox.png</file> - <file>images/mac/lineedit.png</file> - <file>images/mac/mdi.png</file> - <file>images/mac/menu.png</file> - <file>images/mac/radiobutton.png</file> - <file>images/mac/slider.png</file> - <file>images/mac/spinbox.png</file> - <file>images/vista/button.png</file> - <file>images/vista/combobox.png</file> - <file>images/vista/lineedit.png</file> - <file>images/vista/menu.png</file> - <file>images/vista/radiobutton.png</file> - <file>images/vista/slider.png</file> - <file>images/vista/spinbox.png</file> - </qresource> -</RCC> diff --git a/tests/auto/widgets/styles/qstyle/tst_qstyle.cpp b/tests/auto/widgets/styles/qstyle/tst_qstyle.cpp index a552c91928..ae084310b1 100644 --- a/tests/auto/widgets/styles/qstyle/tst_qstyle.cpp +++ b/tests/auto/widgets/styles/qstyle/tst_qstyle.cpp @@ -73,7 +73,6 @@ public: private: bool testAllFunctions(QStyle *); bool testScrollBarSubControls(); - void testPainting(QStyle *style, const QString &platform); private slots: void drawItemPixmap(); void init(); @@ -333,138 +332,15 @@ void tst_QStyle::testWindowsStyle() delete wstyle; } -void writeImage(const QString &fileName, QImage image) -{ - QImageWriter imageWriter(fileName); - imageWriter.setFormat("png"); - qDebug() << "result " << imageWriter.write(image); -} - -QImage readImage(const QString &fileName) -{ - QImageReader reader(fileName); - return reader.read(); -} - - #if defined(Q_OS_WIN) && !defined(QT_NO_STYLE_WINDOWSVISTA) && !defined(Q_OS_WINRT) void tst_QStyle::testWindowsVistaStyle() { QStyle *vistastyle = QStyleFactory::create("WindowsVista"); QVERIFY(testAllFunctions(vistastyle)); - - if (QSysInfo::WindowsVersion == QSysInfo::WV_VISTA) - testPainting(vistastyle, "vista"); delete vistastyle; } #endif -void comparePixmap(const QString &filename, const QPixmap &pixmap) -{ - QImage oldFile = readImage(filename); - QPixmap oldPixmap = QPixmap::fromImage(oldFile); - if (!oldFile.isNull()) - QCOMPARE(pixmap, oldPixmap); - else - writeImage(filename, pixmap.toImage()); -} - -void tst_QStyle::testPainting(QStyle *style, const QString &platform) -{ -qDebug("TEST PAINTING"); - //Test Menu - QString fileName = "images/" + platform + "/menu.png"; - QMenu menu; - menu.setStyle(style); - menu.show(); - menu.addAction(new QAction("Test 1", &menu)); - menu.addAction(new QAction("Test 2", &menu)); - QPixmap pixmap = menu.grab(); - comparePixmap(fileName, pixmap); - - //Push button - fileName = "images/" + platform + "/button.png"; - QPushButton button("OK"); - button.setStyle(style); - button.show(); - pixmap = button.grab(); - button.hide(); - comparePixmap(fileName, pixmap); - - //Push button - fileName = "images/" + platform + "/radiobutton.png"; - QRadioButton radiobutton("Check"); - radiobutton.setStyle(style); - radiobutton.show(); - pixmap = radiobutton.grab(); - radiobutton.hide(); - comparePixmap(fileName, pixmap); - - //Combo box - fileName = "images/" + platform + "/combobox.png"; - QComboBox combobox; - combobox.setStyle(style); - combobox.addItem("Test 1"); - combobox.addItem("Test 2"); - combobox.show(); - pixmap = combobox.grab(); - combobox.hide(); - comparePixmap(fileName, pixmap); - - //Spin box - fileName = "images/" + platform + "/spinbox.png"; - QDoubleSpinBox spinbox; - spinbox.setLocale(QLocale(QLocale::English, QLocale::UnitedStates)); - spinbox.setStyle(style); - spinbox.show(); - pixmap = spinbox.grab(); - spinbox.hide(); - comparePixmap(fileName, pixmap); - QLocale::setDefault(QLocale::system()); - - //Slider - fileName = "images/" + platform + "/slider.png"; - QSlider slider; - slider.setStyle(style); - slider.show(); - pixmap = slider.grab(); - slider.hide(); - comparePixmap(fileName, pixmap); - - //Line edit - fileName = "images/" + platform + "/lineedit.png"; - QLineEdit lineedit("Test text"); - lineedit.setStyle(style); - lineedit.show(); - pixmap = lineedit.grab(); - lineedit.hide(); - comparePixmap(fileName, pixmap); - - //MDI - fileName = "images/" + platform + "/mdi.png"; - QMdiArea mdiArea; - mdiArea.addSubWindow(new QWidget(&mdiArea)); - mdiArea.resize(200, 200); - mdiArea.setStyle(style); - mdiArea.show(); - pixmap = mdiArea.grab(); - mdiArea.hide(); - comparePixmap(fileName, pixmap); - - // QToolButton - fileName = "images/" + platform + "/toolbutton.png"; - QToolButton tb; - tb.setToolButtonStyle(Qt::ToolButtonTextUnderIcon); - tb.setText("AaQqPpXx"); - tb.setIcon(style->standardPixmap(QStyle::SP_DirHomeIcon)); - tb.setStyle(style); - tb.show(); - pixmap = tb.grab(); - tb.hide(); - comparePixmap(fileName, pixmap); - -} - #ifdef Q_OS_MAC void tst_QStyle::testMacStyle() { diff --git a/tests/auto/widgets/util/qcompleter/BLACKLIST b/tests/auto/widgets/util/qcompleter/BLACKLIST index fdc424b6ac..367270fdf2 100644 --- a/tests/auto/widgets/util/qcompleter/BLACKLIST +++ b/tests/auto/widgets/util/qcompleter/BLACKLIST @@ -1,2 +1,6 @@ [QTBUG_14292_filesystem] -linux +ubuntu-16.04 +opensuse-leap +rhel-7.4 +rhel-6.6 +opensuse-42.3 diff --git a/tests/auto/widgets/util/qcompleter/tst_qcompleter.cpp b/tests/auto/widgets/util/qcompleter/tst_qcompleter.cpp index 5a51f15008..27ae41fc4f 100644 --- a/tests/auto/widgets/util/qcompleter/tst_qcompleter.cpp +++ b/tests/auto/widgets/util/qcompleter/tst_qcompleter.cpp @@ -1765,7 +1765,7 @@ void tst_QCompleter::QTBUG_52028_tabAutoCompletes() auto le = new QLineEdit; w.layout()->addWidget(le); - const auto pos = QApplication::desktop()->availableGeometry(&w).topLeft() + QPoint(200,200); + const auto pos = w.screen()->availableGeometry().topLeft() + QPoint(200,200); w.move(pos); w.show(); QApplication::setActiveWindow(&w); @@ -1806,7 +1806,7 @@ void tst_QCompleter::QTBUG_51889_activatedSentTwice() w.layout()->addWidget(new QLineEdit); - const auto pos = QApplication::desktop()->availableGeometry(&w).topLeft() + QPoint(200,200); + const auto pos = w.screen()->availableGeometry().topLeft() + QPoint(200,200); w.move(pos); w.show(); QApplication::setActiveWindow(&w); diff --git a/tests/auto/widgets/widgets/qabstractscrollarea/tst_qabstractscrollarea.cpp b/tests/auto/widgets/widgets/qabstractscrollarea/tst_qabstractscrollarea.cpp index 007825d39c..a17a9f6c33 100644 --- a/tests/auto/widgets/widgets/qabstractscrollarea/tst_qabstractscrollarea.cpp +++ b/tests/auto/widgets/widgets/qabstractscrollarea/tst_qabstractscrollarea.cpp @@ -124,13 +124,19 @@ void tst_QAbstractScrollArea::scrollBarWidgets() QCOMPARE(area.scrollBarWidgets(Qt::AlignTop), QWidgetList()); QCOMPARE(area.scrollBarWidgets(Qt::AlignBottom), w2List); + auto sort = [](const QWidgetList l) { + QWidgetList list = l; + std::sort(list.begin(), list.end()); + return list; + }; + // two widgets at Bottom. area.addScrollBarWidget(w3, Qt::AlignBottom); - QCOMPARE(area.scrollBarWidgets(all).toSet(), allList.toSet()); + QCOMPARE(sort(area.scrollBarWidgets(all)), sort(allList)); QCOMPARE(area.scrollBarWidgets(Qt::AlignLeft), w1List); QCOMPARE(area.scrollBarWidgets(Qt::AlignRight), QWidgetList()); QCOMPARE(area.scrollBarWidgets(Qt::AlignTop), QWidgetList()); - QCOMPARE(area.scrollBarWidgets(Qt::AlignBottom).toSet(), (w2List + w3List).toSet()); + QCOMPARE(sort(area.scrollBarWidgets(Qt::AlignBottom)), sort(w2List + w3List)); //delete delete w1; diff --git a/tests/auto/widgets/widgets/qabstractslider/tst_qabstractslider.cpp b/tests/auto/widgets/widgets/qabstractslider/tst_qabstractslider.cpp index 1a0d7a9289..f77efe036a 100644 --- a/tests/auto/widgets/widgets/qabstractslider/tst_qabstractslider.cpp +++ b/tests/auto/widgets/widgets/qabstractslider/tst_qabstractslider.cpp @@ -33,7 +33,7 @@ #include <QSlider> #include <QStyle> #include <QStyleOption> -#include <QTime> +#include <QElapsedTimer> #include <QDebug> #include <QtTest/private/qtesthelpers_p.h> @@ -91,7 +91,7 @@ private slots: void connectedSliders(); private: - void waitUntilTimeElapsed(const QTime& t, int ms); + void waitUntilTimeElapsed(const QElapsedTimer &t, int ms); QWidget *topLevel; Slider *slider; @@ -1662,8 +1662,12 @@ void tst_QAbstractSlider::wheelEvent() slider->setOrientation(sliderOrientation); Qt::KeyboardModifier k = withModifiers ? Qt::ControlModifier : Qt::NoModifier; - QWheelEvent event(slider->rect().bottomRight() + distanceFromBottomRight, WHEEL_DELTA * deltaMultiple, - Qt::NoButton, k, wheelOrientation); + + const QPoint wheelPoint = slider->rect().bottomRight() + distanceFromBottomRight; + const QPoint angleDelta(wheelOrientation == Qt::Horizontal ? WHEEL_DELTA * deltaMultiple : 0, + wheelOrientation == Qt::Vertical ? WHEEL_DELTA * deltaMultiple : 0); + QWheelEvent event(wheelPoint, slider->mapToGlobal(wheelPoint), QPoint(), angleDelta, + Qt::NoButton, k, Qt::NoScrollPhase, false); QVERIFY(applicationInstance->sendEvent(slider,&event)); #ifdef Q_OS_MAC QEXPECT_FAIL("Normal data page", "QTBUG-23679", Continue); @@ -1674,8 +1678,8 @@ void tst_QAbstractSlider::wheelEvent() slider->setSliderPosition(initialSliderPosition); k = withModifiers ? Qt::ShiftModifier : Qt::NoModifier; - event = QWheelEvent(slider->rect().bottomRight() + distanceFromBottomRight, WHEEL_DELTA * deltaMultiple, - Qt::NoButton, k, wheelOrientation); + event = QWheelEvent(wheelPoint, slider->mapToGlobal(wheelPoint), QPoint(), angleDelta, + Qt::NoButton, k, Qt::NoScrollPhase, false); QSignalSpy spy1(slider, SIGNAL(actionTriggered(int))); QSignalSpy spy2(slider, SIGNAL(valueChanged(int))); QVERIFY(applicationInstance->sendEvent(slider,&event)); @@ -1715,16 +1719,16 @@ void tst_QAbstractSlider::fineGrainedWheelEvent() slider->setSliderPosition(0); const int singleStepDelta = invertedControls ? (-WHEEL_DELTA / 3) : (WHEEL_DELTA / 3); - - QWheelEvent eventDown(slider->rect().bottomRight(), singleStepDelta / 2, - Qt::NoButton, Qt::NoModifier, Qt::Vertical); + const QPoint wheelPoint = slider->rect().bottomRight(); + QWheelEvent eventDown(wheelPoint, slider->mapToGlobal(wheelPoint), QPoint(), QPoint(0, singleStepDelta / 2), + Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false); QVERIFY(applicationInstance->sendEvent(slider,&eventDown)); QCOMPARE(slider->sliderPosition(), 0); QVERIFY(applicationInstance->sendEvent(slider,&eventDown)); QCOMPARE(slider->sliderPosition(), 1); - QWheelEvent eventUp(slider->rect().bottomRight(), -singleStepDelta / 2, - Qt::NoButton, Qt::NoModifier, Qt::Vertical); + QWheelEvent eventUp(wheelPoint, slider->mapToGlobal(wheelPoint), QPoint(), QPoint(0, -singleStepDelta / 2), + Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false); QVERIFY(applicationInstance->sendEvent(slider,&eventUp)); QCOMPARE(slider->sliderPosition(), 1); QVERIFY(applicationInstance->sendEvent(slider,&eventUp)); @@ -2053,11 +2057,11 @@ void tst_QAbstractSlider::setValue() QVERIFY(sliderMovedTimeStamp < valueChangedTimeStamp); } -void tst_QAbstractSlider::waitUntilTimeElapsed(const QTime& t, int ms) +void tst_QAbstractSlider::waitUntilTimeElapsed(const QElapsedTimer &t, int ms) { const int eps = 80; while (t.elapsed() < ms + eps) - QTest::qWait(qMax(ms - t.elapsed() + eps, 25)); + QTest::qWait(qMax(int(ms - t.elapsed() + eps), 25)); } void tst_QAbstractSlider::setRepeatAction() @@ -2073,7 +2077,7 @@ void tst_QAbstractSlider::setRepeatAction() QCOMPARE(spy.count(), 0); QCOMPARE(slider->value(), 55); - QTime t; + QElapsedTimer t; t.start(); QTest::qWait(300); QCOMPARE(spy.count(), 0); diff --git a/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp b/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp index a576770811..b7869a0653 100644 --- a/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp +++ b/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp @@ -34,7 +34,6 @@ #include <qpa/qplatformtheme.h> #include <qfontcombobox.h> -#include <qdesktopwidget.h> #include <qapplication.h> #include <qpushbutton.h> #include <qdialog.h> @@ -254,12 +253,22 @@ void tst_QComboBox::getSetCheck() obj1.setMaxCount(INT_MAX); QCOMPARE(INT_MAX, obj1.maxCount()); + // QCompleter *QComboBox::completer() + // void QComboBox::setCompleter(QCompleter *) + obj1.setCompleter(nullptr); + QCOMPARE(nullptr, obj1.completer()); + QCompleter completer; + obj1.setCompleter(&completer); + QVERIFY(obj1.completer() == nullptr); // no QLineEdit is set + +#if QT_DEPRECATED_SINCE(5, 13) // bool QComboBox::autoCompletion() // void QComboBox::setAutoCompletion(bool) obj1.setAutoCompletion(false); QCOMPARE(false, obj1.autoCompletion()); obj1.setAutoCompletion(true); QCOMPARE(true, obj1.autoCompletion()); +#endif // bool QComboBox::duplicatesEnabled() // void QComboBox::setDuplicatesEnabled(bool) @@ -317,6 +326,9 @@ void tst_QComboBox::getSetCheck() QCOMPARE(var8, obj1.lineEdit()); // delete var8; // No delete, since QComboBox takes ownership + // After setting a line edit, completer() should not return nullptr anymore + QVERIFY(obj1.completer() != nullptr); + // const QValidator * QComboBox::validator() // void QComboBox::setValidator(const QValidator *) QIntValidator *var9 = new QIntValidator(0); @@ -777,7 +789,9 @@ void tst_QComboBox::virtualAutocompletion() QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); QComboBox *testWidget = topLevel.comboBox(); testWidget->clear(); +#if QT_DEPRECATED_SINCE(5, 13) testWidget->setAutoCompletion(true); +#endif testWidget->addItem("Foo"); testWidget->addItem("Bar"); testWidget->addItem("Boat"); @@ -837,7 +851,9 @@ void tst_QComboBox::autoCompletionCaseSensitivity() QCOMPARE(qApp->focusWidget(), (QWidget *)testWidget); testWidget->clear(); +#if QT_DEPRECATED_SINCE(5, 13) testWidget->setAutoCompletion(true); +#endif testWidget->addItem("Cow"); testWidget->addItem("irrelevant1"); testWidget->addItem("aww"); @@ -2102,7 +2118,9 @@ void tst_QComboBox::mouseWheel() box.setEditable(i==0?false:true); box.setCurrentIndex(startIndex); - QWheelEvent event = QWheelEvent(box.rect().bottomRight() , WHEEL_DELTA * wheelDirection, Qt::NoButton, Qt::NoModifier); + const QPoint wheelPoint = box.rect().bottomRight(); + QWheelEvent event(wheelPoint, box.mapToGlobal(wheelPoint), QPoint(), QPoint(0, WHEEL_DELTA * wheelDirection), + Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false); QVERIFY(applicationInstance->sendEvent(&box,&event)); QCOMPARE(box.currentIndex(), expectedIndex); @@ -2131,7 +2149,9 @@ void tst_QComboBox::popupWheelHandling() comboBox->showPopup(); QTRY_VERIFY(comboBox->view() && comboBox->view()->isVisible()); const QPoint popupPos = comboBox->view()->pos(); - QWheelEvent event(QPointF(10, 10), WHEEL_DELTA, Qt::NoButton, Qt::NoModifier); + const QPoint wheelPoint(10, 10); + QWheelEvent event(wheelPoint, scrollArea.mapToGlobal(wheelPoint), QPoint(), QPoint(0, WHEEL_DELTA), + Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false); QVERIFY(QCoreApplication::sendEvent(scrollArea.windowHandle(), &event)); QCoreApplication::processEvents(); QVERIFY(comboBox->view()->isVisible()); @@ -2191,15 +2211,13 @@ void tst_QComboBox::itemListPosition() QFontComboBox combo(&topLevel); layout->addWidget(&combo); - //the code to get the available screen space is copied from QComboBox code - const int scrNumber = QApplication::desktop()->screenNumber(&combo); bool useFullScreenForPopupMenu = false; if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) useFullScreenForPopupMenu = theme->themeHint(QPlatformTheme::UseFullScreenForPopupMenu).toBool(); const QRect screen = useFullScreenForPopupMenu ? - QApplication::screens().at(scrNumber)->geometry() : - QApplication::screens().at(scrNumber)->availableGeometry(); + combo.screen()->geometry() : + combo.screen()->availableGeometry(); topLevel.move(screen.width() - topLevel.sizeHint().width() - 10, 0); //puts the combo to the top-right corner @@ -2419,8 +2437,7 @@ void tst_QComboBox::task248169_popupWithMinimalSize() #if defined QT_BUILD_INTERNAL QFrame *container = comboBox.findChild<QComboBoxPrivateContainer *>(); QVERIFY(container); - QDesktopWidget desktop; - QTRY_VERIFY(desktop.screenGeometry(container).contains(container->geometry())); + QTRY_VERIFY(container->screen()->geometry().contains(container->geometry())); #endif } @@ -3050,7 +3067,9 @@ void tst_QComboBox::task_QTBUG_31146_popupCompletion() { QComboBox comboBox; comboBox.setEditable(true); +#if QT_DEPRECATED_SINCE(5, 13) comboBox.setAutoCompletion(true); +#endif comboBox.setInsertPolicy(QComboBox::NoInsert); comboBox.completer()->setCaseSensitivity(Qt::CaseInsensitive); comboBox.completer()->setCompletionMode(QCompleter::PopupCompletion); diff --git a/tests/auto/widgets/widgets/qdatetimeedit/tst_qdatetimeedit.cpp b/tests/auto/widgets/widgets/qdatetimeedit/tst_qdatetimeedit.cpp index b5ef454b14..26b4b7d020 100644 --- a/tests/auto/widgets/widgets/qdatetimeedit/tst_qdatetimeedit.cpp +++ b/tests/auto/widgets/widgets/qdatetimeedit/tst_qdatetimeedit.cpp @@ -307,19 +307,19 @@ static QLatin1String modifierToName(Qt::KeyboardModifier modifier) { switch (modifier) { case Qt::NoModifier: - return QLatin1Literal("No"); + return QLatin1String("No"); break; case Qt::ControlModifier: - return QLatin1Literal("Ctrl"); + return QLatin1String("Ctrl"); break; case Qt::ShiftModifier: - return QLatin1Literal("Shift"); + return QLatin1String("Shift"); break; case Qt::AltModifier: - return QLatin1Literal("Alt"); + return QLatin1String("Alt"); break; case Qt::MetaModifier: - return QLatin1Literal("Meta"); + return QLatin1String("Meta"); break; default: qFatal("Unexpected keyboard modifier"); @@ -331,25 +331,24 @@ static QLatin1String sectionToName(const QDateTimeEdit::Section section) { switch (section) { case QDateTimeEdit::SecondSection: - return QLatin1Literal("Second"); + return QLatin1String("Second"); case QDateTimeEdit::MinuteSection: - return QLatin1Literal("Minute"); + return QLatin1String("Minute"); case QDateTimeEdit::HourSection: - return QLatin1Literal("Hours"); + return QLatin1String("Hours"); case QDateTimeEdit::DaySection: - return QLatin1Literal("Day"); + return QLatin1String("Day"); case QDateTimeEdit::MonthSection: - return QLatin1Literal("Month"); + return QLatin1String("Month"); case QDateTimeEdit::YearSection: - return QLatin1Literal("Year"); + return QLatin1String("Year"); default: qFatal("Unexpected section"); return QLatin1String(); } } -static QDate stepDate(const QDate& startDate, const QDateTimeEdit::Section section, - const int steps) +static QDate stepDate(QDate startDate, const QDateTimeEdit::Section section, const int steps) { switch (section) { case QDateTimeEdit::DaySection: @@ -364,8 +363,7 @@ static QDate stepDate(const QDate& startDate, const QDateTimeEdit::Section secti } } -static QTime stepTime(const QTime& startTime, const QDateTimeEdit::Section section, - const int steps) +static QTime stepTime(QTime startTime, const QDateTimeEdit::Section section, const int steps) { switch (section) { case QDateTimeEdit::SecondSection: @@ -3141,7 +3139,6 @@ void tst_QDateTimeEdit::wheelEvent_data() { #if QT_CONFIG(wheelevent) QTest::addColumn<QPoint>("angleDelta"); - QTest::addColumn<int>("qt4Delta"); QTest::addColumn<int>("stepModifier"); QTest::addColumn<Qt::KeyboardModifiers>("modifiers"); QTest::addColumn<Qt::MouseEventSource>("source"); @@ -3217,16 +3214,16 @@ void tst_QDateTimeEdit::wheelEvent_data() QLatin1String sourceName; switch (source) { case Qt::MouseEventNotSynthesized: - sourceName = QLatin1Literal("NotSynthesized"); + sourceName = QLatin1String("NotSynthesized"); break; case Qt::MouseEventSynthesizedBySystem: - sourceName = QLatin1Literal("SynthesizedBySystem"); + sourceName = QLatin1String("SynthesizedBySystem"); break; case Qt::MouseEventSynthesizedByQt: - sourceName = QLatin1Literal("SynthesizedByQt"); + sourceName = QLatin1String("SynthesizedByQt"); break; case Qt::MouseEventSynthesizedByApplication: - sourceName = QLatin1Literal("SynthesizedByApplication"); + sourceName = QLatin1String("SynthesizedByApplication"); break; default: qFatal("Unexpected wheel event source"); @@ -3255,7 +3252,6 @@ void tst_QDateTimeEdit::wheelEvent_data() modifierName.latin1(), sourceName.latin1()) << angleDelta - << units << static_cast<int>(stepModifier) << modifiers << source @@ -3277,7 +3273,6 @@ void tst_QDateTimeEdit::wheelEvent() { #if QT_CONFIG(wheelevent) QFETCH(QPoint, angleDelta); - QFETCH(int, qt4Delta); QFETCH(int, stepModifier); QFETCH(Qt::KeyboardModifiers, modifiers); QFETCH(Qt::MouseEventSource, source); @@ -3294,9 +3289,8 @@ void tst_QDateTimeEdit::wheelEvent() style->stepModifier = static_cast<Qt::KeyboardModifier>(stepModifier); edit.setStyle(style.data()); - QWheelEvent event(QPointF(), QPointF(), QPoint(), angleDelta, qt4Delta, - Qt::Vertical, Qt::NoButton, modifiers, Qt::NoScrollPhase, - source); + QWheelEvent event(QPointF(), QPointF(), QPoint(), angleDelta, + Qt::NoButton, modifiers, Qt::NoScrollPhase, false, source); QCOMPARE(edit.date(), startDate); for (QDate expected : expectedDates) { @@ -3454,7 +3448,7 @@ void tst_QDateTimeEdit::timeSpec() } QVERIFY(edit.minimumTime() != min.time()); QVERIFY(edit.minimumDateTime().timeSpec() != min.timeSpec()); - QCOMPARE(edit.minimumDateTime().toTime_t(), min.toTime_t()); + QCOMPARE(edit.minimumDateTime().toSecsSinceEpoch(), min.toSecsSinceEpoch()); } else { QSKIP("Not tested in the GMT timezone"); } diff --git a/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp b/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp index f8ce6a2c0a..625116654d 100644 --- a/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp +++ b/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp @@ -670,7 +670,11 @@ void tst_QDockWidget::dockLocationChanged() spy.clear(); dw.setFloating(true); - QTest::qWait(100); + QTRY_COMPARE(spy.count(), 1); + QCOMPARE(qvariant_cast<Qt::DockWidgetArea>(spy.at(0).at(0)), + Qt::NoDockWidgetArea); + spy.clear(); + dw.setFloating(false); QTRY_COMPARE(spy.count(), 1); QCOMPARE(qvariant_cast<Qt::DockWidgetArea>(spy.at(0).at(0)), diff --git a/tests/auto/widgets/widgets/qdoublespinbox/BLACKLIST b/tests/auto/widgets/widgets/qdoublespinbox/BLACKLIST index c1b6c9693e..8f5648d0f9 100644 --- a/tests/auto/widgets/widgets/qdoublespinbox/BLACKLIST +++ b/tests/auto/widgets/widgets/qdoublespinbox/BLACKLIST @@ -1,2 +1,4 @@ [editingFinished] -* +osx-10.12 +osx-10.14 +osx-10.13 diff --git a/tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp b/tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp index 954ee6471d..c760d9cc99 100644 --- a/tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp +++ b/tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp @@ -221,19 +221,19 @@ static QLatin1String modifierToName(Qt::KeyboardModifier modifier) { switch (modifier) { case Qt::NoModifier: - return QLatin1Literal("No"); + return QLatin1String("No"); break; case Qt::ControlModifier: - return QLatin1Literal("Ctrl"); + return QLatin1String("Ctrl"); break; case Qt::ShiftModifier: - return QLatin1Literal("Shift"); + return QLatin1String("Shift"); break; case Qt::AltModifier: - return QLatin1Literal("Alt"); + return QLatin1String("Alt"); break; case Qt::MetaModifier: - return QLatin1Literal("Meta"); + return QLatin1String("Meta"); break; default: qFatal("Unexpected keyboard modifier"); @@ -1377,7 +1377,6 @@ void tst_QDoubleSpinBox::wheelEvents_data() { #if QT_CONFIG(wheelevent) QTest::addColumn<QPoint>("angleDelta"); - QTest::addColumn<int>("qt4Delta"); QTest::addColumn<int>("stepModifier"); QTest::addColumn<Qt::KeyboardModifiers>("modifier"); QTest::addColumn<Qt::MouseEventSource>("source"); @@ -1448,16 +1447,16 @@ void tst_QDoubleSpinBox::wheelEvents_data() QLatin1String sourceName; switch (source) { case Qt::MouseEventNotSynthesized: - sourceName = QLatin1Literal("NotSynthesized"); + sourceName = QLatin1String("NotSynthesized"); break; case Qt::MouseEventSynthesizedBySystem: - sourceName = QLatin1Literal("SynthesizedBySystem"); + sourceName = QLatin1String("SynthesizedBySystem"); break; case Qt::MouseEventSynthesizedByQt: - sourceName = QLatin1Literal("SynthesizedByQt"); + sourceName = QLatin1String("SynthesizedByQt"); break; case Qt::MouseEventSynthesizedByApplication: - sourceName = QLatin1Literal("SynthesizedByApplication"); + sourceName = QLatin1String("SynthesizedByApplication"); break; default: qFatal("Unexpected wheel event source"); @@ -1476,7 +1475,6 @@ void tst_QDoubleSpinBox::wheelEvents_data() modifierName.latin1(), sourceName.latin1()) << angleDelta - << units << static_cast<int>(stepModifier) << modifiers << source @@ -1496,7 +1494,6 @@ void tst_QDoubleSpinBox::wheelEvents() { #if QT_CONFIG(wheelevent) QFETCH(QPoint, angleDelta); - QFETCH(int, qt4Delta); QFETCH(int, stepModifier); QFETCH(Qt::KeyboardModifiers, modifier); QFETCH(Qt::MouseEventSource, source); @@ -1512,9 +1509,8 @@ void tst_QDoubleSpinBox::wheelEvents() style->stepModifier = static_cast<Qt::KeyboardModifier>(stepModifier); spinBox.setStyle(style.data()); - QWheelEvent event(QPointF(), QPointF(), QPoint(), angleDelta, qt4Delta, - Qt::Vertical, Qt::NoButton, modifier, Qt::NoScrollPhase, - source); + QWheelEvent event(QPointF(), QPointF(), QPoint(), angleDelta, + Qt::NoButton, modifier, Qt::NoScrollPhase, false, source); for (int expected : expectedValues) { qApp->sendEvent(&spinBox, &event); QCOMPARE(spinBox.value(), expected); diff --git a/tests/auto/widgets/widgets/qfontcombobox/tst_qfontcombobox.cpp b/tests/auto/widgets/widgets/qfontcombobox/tst_qfontcombobox.cpp index 1813e5ad5f..5392d36ae0 100644 --- a/tests/auto/widgets/widgets/qfontcombobox/tst_qfontcombobox.cpp +++ b/tests/auto/widgets/widgets/qfontcombobox/tst_qfontcombobox.cpp @@ -108,7 +108,7 @@ void tst_QFontComboBox::currentFont() QFont oldCurrentFont = box.currentFont(); box.setCurrentFont(currentFont); - QRegExp foundry(" \\[.*\\]"); + QRegularExpression foundry(" \\[.*\\]"); if (!box.currentFont().family().contains(foundry)) { QCOMPARE(box.currentFont(), currentFont); } diff --git a/tests/auto/widgets/widgets/qframe/tst_qframe.cpp b/tests/auto/widgets/widgets/qframe/tst_qframe.cpp index 432f4474c5..05f9cd2e4a 100644 --- a/tests/auto/widgets/widgets/qframe/tst_qframe.cpp +++ b/tests/auto/widgets/widgets/qframe/tst_qframe.cpp @@ -37,6 +37,10 @@ class tst_QFrame : public QObject { Q_OBJECT + +public: + static void initMain() { QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling); } + private slots: void testDefaults(); void testInitStyleOption_data(); diff --git a/tests/auto/widgets/widgets/qgroupbox/tst_qgroupbox.cpp b/tests/auto/widgets/widgets/qgroupbox/tst_qgroupbox.cpp index 420ef56106..1b477fbbd0 100644 --- a/tests/auto/widgets/widgets/qgroupbox/tst_qgroupbox.cpp +++ b/tests/auto/widgets/widgets/qgroupbox/tst_qgroupbox.cpp @@ -295,6 +295,12 @@ void tst_QGroupBox::enabledChildPropagation() QVERIFY(!childWidget->isEnabled()); dialog = new QDialog(&testWidget); QVERIFY(dialog->isEnabled()); + + // children that are enabled after adding should still be disabled before + // they are shown + childWidget->setEnabled(true); + testWidget.show(); + QVERIFY(!childWidget->isEnabled()); } void tst_QGroupBox::sizeHint() diff --git a/tests/auto/widgets/widgets/qlabel/tst_qlabel.cpp b/tests/auto/widgets/widgets/qlabel/tst_qlabel.cpp index 34862f6810..f599ac73c6 100644 --- a/tests/auto/widgets/widgets/qlabel/tst_qlabel.cpp +++ b/tests/auto/widgets/widgets/qlabel/tst_qlabel.cpp @@ -461,7 +461,7 @@ void tst_QLabel::unicodeText() QVBoxLayout *layout = new QVBoxLayout(); QLabel *label = new QLabel(text, &frame); layout->addWidget(label); - layout->setMargin(8); + layout->setContentsMargins(8, 8, 8, 8); frame.setLayout(layout); frame.show(); QVERIFY(QTest::qWaitForWindowExposed(&frame)); diff --git a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp index 27cc385df4..0cfbc651ad 100644 --- a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp +++ b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp @@ -3530,6 +3530,13 @@ void tst_QLineEdit::textMargin() centerOnScreen(&tlw); tlw.show(); + const QMargins margins = testWidget.textMargins(); + QCOMPARE(left, margins.left()); + QCOMPARE(top, margins.top()); + QCOMPARE(right, margins.right()); + QCOMPARE(bottom, margins.bottom()); + +#if QT_DEPRECATED_SINCE(5, 14) int l; int t; int r; @@ -3539,6 +3546,7 @@ void tst_QLineEdit::textMargin() QCOMPARE(top, t); QCOMPARE(right, r); QCOMPARE(bottom, b); +#endif QTest::mouseClick(&testWidget, Qt::LeftButton, 0, mousePressPos); QTRY_COMPARE(testWidget.cursorPosition(), cursorPosition); @@ -3615,6 +3623,14 @@ void tst_QLineEdit::task174640_editingFinished() le2->setFocus(); QTRY_VERIFY(le2->hasFocus()); + // editingFinished will not be emitted anew because no editing happened + QCOMPARE(editingFinishedSpy.count(), 0); + + le1->setFocus(); + QTRY_VERIFY(le1->hasFocus()); + QTest::keyPress(le1, Qt::Key_Plus); + le2->setFocus(); + QTRY_VERIFY(le2->hasFocus()); QCOMPARE(editingFinishedSpy.count(), 1); editingFinishedSpy.clear(); @@ -3632,6 +3648,8 @@ void tst_QLineEdit::task174640_editingFinished() delete testMenu1; QCOMPARE(editingFinishedSpy.count(), 0); QTRY_VERIFY(le1->hasFocus()); + // Ensure le1 has been edited + QTest::keyPress(le1, Qt::Key_Plus); QMenu *testMenu2 = new QMenu(le2); testMenu2->addAction("foo2"); @@ -3986,7 +4004,7 @@ void tst_QLineEdit::QTBUG7174_inputMaskCursorBlink() edit.setFocus(); edit.setText(QLatin1String("AAAA")); edit.show(); - QRect cursorRect = edit.inputMethodQuery(Qt::ImMicroFocus).toRect(); + QRect cursorRect = edit.inputMethodQuery(Qt::ImCursorRectangle).toRect(); QVERIFY(QTest::qWaitForWindowExposed(&edit)); edit.updateRegion = QRegion(); QTest::qWait(QApplication::cursorFlashTime()); diff --git a/tests/auto/widgets/widgets/qmdiarea/BLACKLIST b/tests/auto/widgets/widgets/qmdiarea/BLACKLIST index b1c8d7dfde..1dd876ea97 100644 --- a/tests/auto/widgets/widgets/qmdiarea/BLACKLIST +++ b/tests/auto/widgets/widgets/qmdiarea/BLACKLIST @@ -1,7 +1,16 @@ -[updateScrollBars] -osx [tileSubWindows] -osx -xcb +ubuntu-16.04 +rhel-7.6 +opensuse-leap +osx-10.11 +osx-10.13 +ubuntu-18.04 +osx-10.14 +rhel-7.4 +osx-10.12 +opensuse-42.3 [resizeTimer] -osx +osx-10.12 +osx-10.14 +osx-10.13 + diff --git a/tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp b/tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp index 67b79e3faf..6d38dc262f 100644 --- a/tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp +++ b/tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp @@ -333,6 +333,7 @@ void tst_QMdiArea::subWindowActivated() for ( i = 0; i < count; ++i ) { QWidget *widget = new QWidget(workspace, 0); widget->setAttribute(Qt::WA_DeleteOnClose); + widget->setFocus(); workspace->addSubWindow(widget)->show(); widget->show(); qApp->processEvents(); @@ -478,9 +479,6 @@ void tst_QMdiArea::subWindowActivated2() // Check that we only emit _one_ signal and the active window // is unchanged after hide/show. mdiArea.hide(); -#if 0 // Used to be included in Qt4 for Q_WS_X11 - qt_x11_wait_for_window_manager(&mdiArea); -#endif QTest::qWait(100); QTRY_COMPARE(spy.count(), 1); QVERIFY(!mdiArea.activeSubWindow()); @@ -879,7 +877,7 @@ void tst_QMdiArea::minimumSizeHint() { QMdiArea workspace; workspace.show(); - QSize expectedSize(workspace.style()->pixelMetric(QStyle::PM_MDIMinimizedWidth), + QSize expectedSize(workspace.style()->pixelMetric(QStyle::PM_MdiSubWindowMinimizedWidth), workspace.style()->pixelMetric(QStyle::PM_TitleBarHeight)); qApp->processEvents(); QAbstractScrollArea dummyScrollArea; diff --git a/tests/auto/widgets/widgets/qmdisubwindow/BLACKLIST b/tests/auto/widgets/widgets/qmdisubwindow/BLACKLIST deleted file mode 100644 index 26d1776b0d..0000000000 --- a/tests/auto/widgets/widgets/qmdisubwindow/BLACKLIST +++ /dev/null @@ -1,2 +0,0 @@ -[setOpaqueResizeAndMove] -osx-10.12 diff --git a/tests/auto/widgets/widgets/qmdisubwindow/tst_qmdisubwindow.cpp b/tests/auto/widgets/widgets/qmdisubwindow/tst_qmdisubwindow.cpp index 2b59a227b3..3ee9c72209 100644 --- a/tests/auto/widgets/widgets/qmdisubwindow/tst_qmdisubwindow.cpp +++ b/tests/auto/widgets/widgets/qmdisubwindow/tst_qmdisubwindow.cpp @@ -52,9 +52,7 @@ #include <QVector> QT_BEGIN_NAMESPACE -#if 1 // Used to be excluded in Qt4 for Q_WS_WIN extern bool qt_tab_all_widgets(); -#endif QT_END_NAMESPACE static inline bool tabAllWidgets() @@ -613,7 +611,7 @@ void tst_QMdiSubWindow::showShaded() // Calculate mouse position for bottom right corner and simulate a // vertical resize with the mouse. - int offset = window->style()->pixelMetric(QStyle::PM_MDIFrameWidth) / 2; + int offset = window->style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth) / 2; QPoint mousePosition(window->width() - qMax(offset, 2), window->height() - qMax(offset, 2)); QWidget *mouseReceiver = nullptr; #ifdef Q_OS_MAC @@ -759,7 +757,7 @@ void tst_QMdiSubWindow::setOpaqueResizeAndMove() QTRY_COMPARE(priv->resizeTimerId, -1); // Enter resize mode. - int offset = window->style()->pixelMetric(QStyle::PM_MDIFrameWidth) / 2; + int offset = window->style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth) / 2; QPoint mousePosition(mouseReceiver->width() - qMax(offset, 2), mouseReceiver->height() - qMax(offset, 2)); sendMouseMove(mouseReceiver, mousePosition, Qt::NoButton); sendMousePress(mouseReceiver, mousePosition); @@ -1762,7 +1760,8 @@ void tst_QMdiSubWindow::fixedMinMaxSize() int minimizedHeight = subWindow->style()->pixelMetric(QStyle::PM_TitleBarHeight, &options); if (!subWindow->style()->styleHint(QStyle::SH_TitleBar_NoBorder, &options, subWindow)) minimizedHeight += 8; - int minimizedWidth = subWindow->style()->pixelMetric(QStyle::PM_MDIMinimizedWidth, &options); + int minimizedWidth = subWindow->style()->pixelMetric(QStyle::PM_MdiSubWindowMinimizedWidth, + &options); const QSize minimizedSize = QSize(minimizedWidth, minimizedHeight); // Even though the sub window has a minimum size set, it should be possible diff --git a/tests/auto/widgets/widgets/qmenu/BLACKLIST b/tests/auto/widgets/widgets/qmenu/BLACKLIST index bac14ea225..ad6d2f340c 100644 --- a/tests/auto/widgets/widgets/qmenu/BLACKLIST +++ b/tests/auto/widgets/widgets/qmenu/BLACKLIST @@ -1,13 +1,13 @@ [task258920_mouseBorder] -osx -[submenuTearOffDontClose] -osx-10.12 ci +osx-10.14 +osx-10.13 [layoutDirection] +osx-10.12 +osx-10.13 # Fails when enabling synchronous expose events QTBUG-62092 -osx ci [pushButtonPopulateOnAboutToShow] -osx +osx-10.13 [tearOff] -osx +osx-10.14 [activeSubMenuPosition] winrt diff --git a/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp b/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp index 3bfbe754ef..9c40c0bd57 100644 --- a/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp +++ b/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp @@ -610,7 +610,7 @@ void tst_QMenu::widgetActionFocus() static QMenu *getTornOffMenu() { - foreach (QWidget *w, QApplication::allWidgets()) { + for (QWidget *w : QApplication::allWidgets()) { if (w->isVisible() && w->inherits("QTornOffMenu")) return static_cast<QMenu *>(w); } @@ -948,30 +948,28 @@ void tst_QMenu::menuSizeHint() { QMenu menu; //this is a list of arbitrary strings so that we check the geometry - QStringList list = QStringList() << "trer" << "ezrfgtgvqd" << "sdgzgzerzerzer" << "eerzertz" << "er"; - foreach (QString str, list) + for (auto str : {"trer", "ezrfgtgvqd", "sdgzgzerzerzer", "eerzertz", "er"}) menu.addAction(str); - int left, top, right, bottom; - menu.getContentsMargins(&left, &top, &right, &bottom); + const QMargins cm = menu.contentsMargins(); const int panelWidth = menu.style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, &menu); const int hmargin = menu.style()->pixelMetric(QStyle::PM_MenuHMargin, 0, &menu), vmargin = menu.style()->pixelMetric(QStyle::PM_MenuVMargin, 0, &menu); int maxWidth =0; QRect result; - foreach (QAction *action, menu.actions()) { + for (QAction *action : menu.actions()) { maxWidth = qMax(maxWidth, menu.actionGeometry(action).width()); result |= menu.actionGeometry(action); - QCOMPARE(result.x(), left + hmargin + panelWidth); - QCOMPARE(result.y(), top + vmargin + panelWidth); + QCOMPARE(result.x(), cm.left() + hmargin + panelWidth); + QCOMPARE(result.y(), cm.top() + vmargin + panelWidth); } QStyleOption opt(0); opt.rect = menu.rect(); opt.state = QStyle::State_None; - QSize resSize = QSize(result.x(), result.y()) + result.size() + QSize(hmargin + right + panelWidth, vmargin + top + panelWidth); + QSize resSize = QSize(result.x(), result.y()) + result.size() + QSize(hmargin + cm.right() + panelWidth, vmargin + cm.top() + panelWidth); resSize = menu.style()->sizeFromContents(QStyle::CT_Menu, &opt, resSize.expandedTo(QApplication::globalStrut()), &menu); @@ -1572,8 +1570,7 @@ void tst_QMenu::menuSize_Scrolling() int hmargin = style()->pixelMetric(QStyle::PM_MenuHMargin, nullptr, this); int fw = style()->pixelMetric(QStyle::PM_MenuPanelWidth, nullptr, this); - int leftMargin, topMargin, rightMargin, bottomMargin; - getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin); + const QMargins cm = contentsMargins(); QRect lastItem = actionGeometry(actions().at(actions().length() - 1)); QSize s = size(); #ifdef Q_OS_WINRT @@ -1586,7 +1583,7 @@ void tst_QMenu::menuSize_Scrolling() return; } - QCOMPARE( s.width(), lastItem.right() + fw + hmargin + rightMargin + 1); + QCOMPARE( s.width(), lastItem.right() + fw + hmargin + cm.right() + 1); QMenu::showEvent(e); } diff --git a/tests/auto/widgets/widgets/qmenubar/BLACKLIST b/tests/auto/widgets/widgets/qmenubar/BLACKLIST index f897797f00..c9e15e531c 100644 --- a/tests/auto/widgets/widgets/qmenubar/BLACKLIST +++ b/tests/auto/widgets/widgets/qmenubar/BLACKLIST @@ -3,6 +3,6 @@ ubuntu-16.04 #QTBUG-66255 ubuntu-18.04 [activatedCount] -* +opensuse-42.3 [QTBUG_65488_hiddenActionTriggered] winrt diff --git a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp index cb829c81a6..417d6e3124 100644 --- a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp +++ b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp @@ -34,7 +34,6 @@ #include <qstyle.h> #include <qproxystyle.h> #include <qstylefactory.h> -#include <qdesktopwidget.h> #include <qaction.h> #include <qstyleoption.h> #include <QVBoxLayout> @@ -113,10 +112,7 @@ private slots: void check_escKey(); #endif -#ifndef Q_OS_WINCE void allowActiveAndDisabled(); -#endif - void taskQTBUG56860_focus(); void check_endKey(); void check_homeKey(); @@ -1152,8 +1148,8 @@ void tst_QMenuBar::check_menuPosition() Menu menu; menu.setTitle("&menu"); - QRect availRect = QApplication::desktop()->availableGeometry(&w); - QRect screenRect = QApplication::desktop()->screenGeometry(&w); + QRect availRect = w.screen()->availableGeometry(); + QRect screenRect = w.screen()->geometry(); while(menu.sizeHint().height() < (screenRect.height()*2/3)) { menu.addAction("item"); diff --git a/tests/auto/widgets/widgets/qopenglwidget/BLACKLIST b/tests/auto/widgets/widgets/qopenglwidget/BLACKLIST index b67c8354e8..b281eca3bf 100644 --- a/tests/auto/widgets/widgets/qopenglwidget/BLACKLIST +++ b/tests/auto/widgets/widgets/qopenglwidget/BLACKLIST @@ -1,5 +1,3 @@ -[clearAndGrab] -ubuntu - [stackWidgetOpaqueChildIsVisible] -windows +windows-10 msvc-2017 + diff --git a/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp b/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp index 21c9f41646..76f8ebc804 100644 --- a/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp +++ b/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp @@ -49,6 +49,9 @@ class tst_QOpenGLWidget : public QObject { Q_OBJECT +public: + static void initMain() { QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling); } + private slots: void initTestCase(); void create(); diff --git a/tests/auto/widgets/widgets/qprogressbar/tst_qprogressbar.cpp b/tests/auto/widgets/widgets/qprogressbar/tst_qprogressbar.cpp index df5ff9d448..f2f9cfc009 100644 --- a/tests/auto/widgets/widgets/qprogressbar/tst_qprogressbar.cpp +++ b/tests/auto/widgets/widgets/qprogressbar/tst_qprogressbar.cpp @@ -171,11 +171,8 @@ void tst_QProgressBar::format() bar.setFormat("%v of %m (%p%)"); qApp->processEvents(); -#ifndef Q_OS_MAC +#if !defined(Q_OS_MACOS) && !defined(Q_OS_WIN) // Animated scroll bars get paint events all the time -#ifdef Q_OS_WIN - if (QSysInfo::WindowsVersion < QSysInfo::WV_VISTA) -#endif QVERIFY(!bar.repainted); #endif diff --git a/tests/auto/widgets/widgets/qscrollarea/tst_qscrollarea.cpp b/tests/auto/widgets/widgets/qscrollarea/tst_qscrollarea.cpp index d1923e4bb0..9f08bd337b 100644 --- a/tests/auto/widgets/widgets/qscrollarea/tst_qscrollarea.cpp +++ b/tests/auto/widgets/widgets/qscrollarea/tst_qscrollarea.cpp @@ -87,7 +87,7 @@ public: protected: QVariant inputMethodQuery(Qt::InputMethodQuery query) const { - if (query == Qt::ImMicroFocus) + if (query == Qt::ImCursorRectangle) return QRect(width() / 2, height() / 2, 5, 5); return QWidget::inputMethodQuery(query); } @@ -110,7 +110,7 @@ void tst_QScrollArea::ensureMicroFocusVisible_Task_167838() parent->resize(300, 300); scrollArea.setWidget(parent); scrollArea.ensureWidgetVisible(child, 10, 10); - QRect microFocus = child->inputMethodQuery(Qt::ImMicroFocus).toRect(); + QRect microFocus = child->inputMethodQuery(Qt::ImCursorRectangle).toRect(); QPoint p = child->mapTo(scrollArea.viewport(), microFocus.topLeft()); microFocus.translate(p - microFocus.topLeft()); QVERIFY(scrollArea.viewport()->rect().contains(microFocus)); diff --git a/tests/auto/widgets/widgets/qscrollbar/BLACKLIST b/tests/auto/widgets/widgets/qscrollbar/BLACKLIST deleted file mode 100644 index 277ae4d260..0000000000 --- a/tests/auto/widgets/widgets/qscrollbar/BLACKLIST +++ /dev/null @@ -1,3 +0,0 @@ -#QTBUG-66321 -[QTBUG_42871] -macos diff --git a/tests/auto/widgets/widgets/qscrollbar/tst_qscrollbar.cpp b/tests/auto/widgets/widgets/qscrollbar/tst_qscrollbar.cpp index 278f5cdd68..339ff293f4 100644 --- a/tests/auto/widgets/widgets/qscrollbar/tst_qscrollbar.cpp +++ b/tests/auto/widgets/widgets/qscrollbar/tst_qscrollbar.cpp @@ -151,8 +151,11 @@ void tst_QScrollBar::QTBUG_27308() testWidget.setValue(testWidget.minimum()); testWidget.setEnabled(false); - QWheelEvent event(testWidget.rect().center(), - -WHEEL_DELTA, Qt::NoButton, Qt::NoModifier, testWidget.orientation()); + const QPoint wheelPoint = testWidget.rect().center(); + const QPoint angleDelta(testWidget.orientation() == Qt::Horizontal ? -WHEEL_DELTA : 0, + testWidget.orientation() == Qt::Vertical ? -WHEEL_DELTA : 0); + QWheelEvent event(wheelPoint, testWidget.mapToGlobal(wheelPoint), QPoint(), angleDelta, + Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false); qApp->sendEvent(&testWidget, &event); QCOMPARE(testWidget.value(), testWidget.minimum()); } diff --git a/tests/auto/widgets/widgets/qspinbox/BLACKLIST b/tests/auto/widgets/widgets/qspinbox/BLACKLIST index a38511bfb4..96a7732165 100644 --- a/tests/auto/widgets/widgets/qspinbox/BLACKLIST +++ b/tests/auto/widgets/widgets/qspinbox/BLACKLIST @@ -1,3 +1,2 @@ [stepModifierPressAndHold] -opensuse ci # QTBUG-69492 -opensuse-leap ci +opensuse-42.3 diff --git a/tests/auto/widgets/widgets/qspinbox/tst_qspinbox.cpp b/tests/auto/widgets/widgets/qspinbox/tst_qspinbox.cpp index 52d7dad7cf..d75e701d1c 100644 --- a/tests/auto/widgets/widgets/qspinbox/tst_qspinbox.cpp +++ b/tests/auto/widgets/widgets/qspinbox/tst_qspinbox.cpp @@ -206,7 +206,7 @@ private slots: void stepModifierPressAndHold_data(); void stepModifierPressAndHold(); public slots: - void valueChangedHelper(const QString &); + void textChangedHelper(const QString &); void valueChangedHelper(int); private: QStringList actualTexts; @@ -222,19 +222,19 @@ static QLatin1String modifierToName(Qt::KeyboardModifier modifier) { switch (modifier) { case Qt::NoModifier: - return QLatin1Literal("No"); + return QLatin1String("No"); break; case Qt::ControlModifier: - return QLatin1Literal("Ctrl"); + return QLatin1String("Ctrl"); break; case Qt::ShiftModifier: - return QLatin1Literal("Shift"); + return QLatin1String("Shift"); break; case Qt::AltModifier: - return QLatin1Literal("Alt"); + return QLatin1String("Alt"); break; case Qt::MetaModifier: - return QLatin1Literal("Meta"); + return QLatin1String("Meta"); break; default: qFatal("Unexpected keyboard modifier"); @@ -490,7 +490,7 @@ void tst_QSpinBox::setPrefixSuffix() } } -void tst_QSpinBox::valueChangedHelper(const QString &text) +void tst_QSpinBox::textChangedHelper(const QString &text) { actualTexts << text; } @@ -568,7 +568,7 @@ void tst_QSpinBox::setTracking() QSpinBox spin(0); spin.setKeyboardTracking(tracking); spin.show(); - connect(&spin, SIGNAL(valueChanged(QString)), this, SLOT(valueChangedHelper(QString))); + connect(&spin, &QSpinBox::textChanged, this, &tst_QSpinBox::textChangedHelper); keys.simulate(&spin); QCOMPARE(actualTexts, texts); @@ -1331,7 +1331,6 @@ void tst_QSpinBox::wheelEvents_data() { #if QT_CONFIG(wheelevent) QTest::addColumn<QPoint>("angleDelta"); - QTest::addColumn<int>("qt4Delta"); QTest::addColumn<int>("stepModifier"); QTest::addColumn<Qt::KeyboardModifiers>("modifier"); QTest::addColumn<Qt::MouseEventSource>("source"); @@ -1402,16 +1401,16 @@ void tst_QSpinBox::wheelEvents_data() QLatin1String sourceName; switch (source) { case Qt::MouseEventNotSynthesized: - sourceName = QLatin1Literal("NotSynthesized"); + sourceName = QLatin1String("NotSynthesized"); break; case Qt::MouseEventSynthesizedBySystem: - sourceName = QLatin1Literal("SynthesizedBySystem"); + sourceName = QLatin1String("SynthesizedBySystem"); break; case Qt::MouseEventSynthesizedByQt: - sourceName = QLatin1Literal("SynthesizedByQt"); + sourceName = QLatin1String("SynthesizedByQt"); break; case Qt::MouseEventSynthesizedByApplication: - sourceName = QLatin1Literal("SynthesizedByApplication"); + sourceName = QLatin1String("SynthesizedByApplication"); break; default: qFatal("Unexpected wheel event source"); @@ -1430,7 +1429,6 @@ void tst_QSpinBox::wheelEvents_data() modifierName.latin1(), sourceName.latin1()) << angleDelta - << units << static_cast<int>(stepModifier) << modifiers << source @@ -1450,7 +1448,6 @@ void tst_QSpinBox::wheelEvents() { #if QT_CONFIG(wheelevent) QFETCH(QPoint, angleDelta); - QFETCH(int, qt4Delta); QFETCH(int, stepModifier); QFETCH(Qt::KeyboardModifiers, modifier); QFETCH(Qt::MouseEventSource, source); @@ -1466,9 +1463,8 @@ void tst_QSpinBox::wheelEvents() style->stepModifier = static_cast<Qt::KeyboardModifier>(stepModifier); spinBox.setStyle(style.data()); - QWheelEvent event(QPointF(), QPointF(), QPoint(), angleDelta, qt4Delta, - Qt::Vertical, Qt::NoButton, modifier, Qt::NoScrollPhase, - source); + QWheelEvent event(QPointF(), QPointF(), QPoint(), angleDelta, + Qt::NoButton, modifier, Qt::NoScrollPhase, false, source); for (int expected : expectedValues) { qApp->sendEvent(&spinBox, &event); QCOMPARE(spinBox.value(), expected); diff --git a/tests/auto/widgets/widgets/qsplitter/tst_qsplitter.cpp b/tests/auto/widgets/widgets/qsplitter/tst_qsplitter.cpp index 8b45ac20b7..cbeb77a25e 100644 --- a/tests/auto/widgets/widgets/qsplitter/tst_qsplitter.cpp +++ b/tests/auto/widgets/widgets/qsplitter/tst_qsplitter.cpp @@ -599,7 +599,7 @@ void tst_QSplitter::testShowHide() QWidget widget(&topLevel); widget.resize(400 + split->handleWidth(), 200); QVBoxLayout *lay=new QVBoxLayout(&widget); - lay->setMargin(0); + lay->setContentsMargins(0, 0, 0, 0); lay->setSpacing(0); split->addWidget(new QWidget); split->addWidget(new QWidget); diff --git a/tests/auto/widgets/widgets/qtabwidget/qtabwidget.pro b/tests/auto/widgets/widgets/qtabwidget/qtabwidget.pro index 6523209c32..b61cc8fa13 100644 --- a/tests/auto/widgets/widgets/qtabwidget/qtabwidget.pro +++ b/tests/auto/widgets/widgets/qtabwidget/qtabwidget.pro @@ -8,4 +8,4 @@ INCLUDEPATH += ../ HEADERS += SOURCES += tst_qtabwidget.cpp -win32:!winrt: LIBS += -luser32 +win32:!winrt: QMAKE_USE += user32 diff --git a/tests/auto/widgets/widgets/qtabwidget/tst_qtabwidget.cpp b/tests/auto/widgets/widgets/qtabwidget/tst_qtabwidget.cpp index cbf5196bb9..feade7d443 100644 --- a/tests/auto/widgets/widgets/qtabwidget/tst_qtabwidget.cpp +++ b/tests/auto/widgets/widgets/qtabwidget/tst_qtabwidget.cpp @@ -620,7 +620,7 @@ void tst_QTabWidget::heightForWidth() QWidget *window = new QWidget; QVBoxLayout *lay = new QVBoxLayout(window); - lay->setMargin(0); + lay->setContentsMargins(0, 0, 0, 0); lay->setSpacing(0); QTabWidget *tabWid = new QTabWidget(window); QWidget *w = new QWidget; @@ -637,7 +637,7 @@ void tst_QTabWidget::heightForWidth() ); label->setWordWrap(true); lay2->addWidget(label); - lay2->setMargin(0); + lay2->setContentsMargins(0, 0, 0, 0); lay->addWidget(tabWid); int h = window->heightForWidth(160); diff --git a/tests/auto/widgets/widgets/qtextbrowser/heading.html b/tests/auto/widgets/widgets/qtextbrowser/heading.html new file mode 100644 index 0000000000..8b23807f65 --- /dev/null +++ b/tests/auto/widgets/widgets/qtextbrowser/heading.html @@ -0,0 +1,2 @@ +<h3>this is a heading</h3> +<p>this is a paragraph</p> diff --git a/tests/auto/widgets/widgets/qtextbrowser/markdown.md b/tests/auto/widgets/widgets/qtextbrowser/markdown.md new file mode 100644 index 0000000000..be56aef234 --- /dev/null +++ b/tests/auto/widgets/widgets/qtextbrowser/markdown.md @@ -0,0 +1,2 @@ +### this is a heading +this is a paragraph diff --git a/tests/auto/widgets/widgets/qtextbrowser/markdown.really b/tests/auto/widgets/widgets/qtextbrowser/markdown.really new file mode 100644 index 0000000000..be56aef234 --- /dev/null +++ b/tests/auto/widgets/widgets/qtextbrowser/markdown.really @@ -0,0 +1,2 @@ +### this is a heading +this is a paragraph diff --git a/tests/auto/widgets/widgets/qtextbrowser/qtextbrowser.pro b/tests/auto/widgets/widgets/qtextbrowser/qtextbrowser.pro index 9680ffd871..dfdcf26497 100644 --- a/tests/auto/widgets/widgets/qtextbrowser/qtextbrowser.pro +++ b/tests/auto/widgets/widgets/qtextbrowser/qtextbrowser.pro @@ -4,6 +4,6 @@ SOURCES += tst_qtextbrowser.cpp QT += widgets testlib -TESTDATA += *.html subdir/* +TESTDATA += *.html *.md markdown.really subdir/* builtin_testdata: DEFINES += BUILTIN_TESTDATA diff --git a/tests/auto/widgets/widgets/qtextbrowser/quotesAndFractions.md b/tests/auto/widgets/widgets/qtextbrowser/quotesAndFractions.md new file mode 100644 index 0000000000..6bad9cb95b --- /dev/null +++ b/tests/auto/widgets/widgets/qtextbrowser/quotesAndFractions.md @@ -0,0 +1 @@ +you’ll hope to see âquotesâž ï¹ 1½ â…” ¼ â…— â…š â… some “vulgar†fractions (pardon my «French») diff --git a/tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp b/tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp index 8a1b228c71..27bf0ce7be 100644 --- a/tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp +++ b/tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. @@ -38,7 +38,7 @@ class TestBrowser : public QTextBrowser { public: - inline TestBrowser() : htmlLoadAttempts(0) { + inline TestBrowser() { show(); QApplication::setActiveWindow(this); activateWindow(); @@ -47,11 +47,12 @@ public: QVERIFY(hasFocus()); } - virtual QVariant loadResource(int type, const QUrl &name); + QVariant loadResource(int type, const QUrl &name) override; - int htmlLoadAttempts; + int htmlLoadAttempts = 0; QUrl lastResource; QUrl sourceInsideLoadResource; + QUrl baseInsideLoadResource; }; QVariant TestBrowser::loadResource(int type, const QUrl &name) @@ -60,6 +61,7 @@ QVariant TestBrowser::loadResource(int type, const QUrl &name) htmlLoadAttempts++; lastResource = name; sourceInsideLoadResource = source(); + baseInsideLoadResource = document()->baseUrl(); return QTextBrowser::loadResource(type, name); } @@ -90,6 +92,10 @@ private slots: void focusIndicator(); void focusHistory(); void urlEncoding(); + void sourceType_data(); + void sourceType(); + void unicode_data(); + void unicode(); private: TestBrowser *browser; @@ -108,7 +114,7 @@ void tst_QTextBrowser::init() void tst_QTextBrowser::cleanup() { delete browser; - browser = 0; + browser = nullptr; } void tst_QTextBrowser::noReloadOnAnchorJump() @@ -428,11 +434,18 @@ void tst_QTextBrowser::sourceInsideLoadResource() #ifdef Q_OS_WINRT QSKIP("Paths cannot be compared if applications are sandboxed."); #endif - QUrl url = QUrl::fromLocalFile("pagewithimage.html"); + QUrl url = QUrl::fromLocalFile("pagewithimage.html"); // "file://pagewithimage.html" browser->setSource(url); QCOMPARE(browser->lastResource, QUrl::fromLocalFile(QDir::current().filePath("foobar.png"))); + // baseUrl was not set because the source URL was a relative one + QCOMPARE(browser->baseInsideLoadResource, QUrl()); QEXPECT_FAIL("", "This is currently not supported", Continue); QCOMPARE(browser->sourceInsideLoadResource.toString(), url.toString()); + url = QUrl::fromLocalFile(QDir::current().filePath("pagewithimage.html")); // "file:///home/user/path/to/pagewithimage.html" + browser->setSource(url); + QCOMPARE(browser->lastResource, QUrl::fromLocalFile(QDir::current().filePath("foobar.png"))); + // baseUrl has the full path, and that's where relative-path resources come from + QCOMPARE(browser->baseInsideLoadResource, QUrl::fromLocalFile(QDir::currentPath() + QLatin1Char('/'))); } void tst_QTextBrowser::textInteractionFlags_vs_readOnly() @@ -669,5 +682,72 @@ void tst_QTextBrowser::urlEncoding() delete browser; } +void tst_QTextBrowser::sourceType_data() +{ + QTest::addColumn<QString>("sourceFile"); + QTest::addColumn<QTextDocument::ResourceType>("sourceType"); + QTest::addColumn<int>("expectedMaxHeadingLevel"); + QTest::addColumn<QTextDocument::ResourceType>("expectedSourceType"); + +#if QT_CONFIG(textmarkdownreader) + const int maxMdHeadingLevel = 3; + const QTextDocument::ResourceType mdExpectedType = QTextDocument::MarkdownResource; +#else + // If Qt doesn't support markdown, and we read a MD document anyway, it won't have any H3's. + const int maxMdHeadingLevel = 0; + const QTextDocument::ResourceType mdExpectedType = QTextDocument::HtmlResource; +#endif + QTest::newRow("markdown detected") << "markdown.md" << QTextDocument::UnknownResource << maxMdHeadingLevel << mdExpectedType; + QTest::newRow("markdown specified") << "markdown.really" << QTextDocument::MarkdownResource << maxMdHeadingLevel << mdExpectedType; + QTest::newRow("markdown not identified") << "markdown.really" << QTextDocument::UnknownResource << 0 << QTextDocument::HtmlResource; + QTest::newRow("html detected") << "heading.html" << QTextDocument::UnknownResource << 3 << QTextDocument::HtmlResource; + QTest::newRow("html specified") << "heading.html" << QTextDocument::HtmlResource << 3 << QTextDocument::HtmlResource; +} + +void tst_QTextBrowser::sourceType() +{ + QFETCH(QString, sourceFile); + QFETCH(QTextDocument::ResourceType, sourceType); + QFETCH(int, expectedMaxHeadingLevel); + QFETCH(QTextDocument::ResourceType, expectedSourceType); + if (sourceType == QTextDocument::UnknownResource) + // verify that the property setter works, with its default parameter for sourceType + browser->setProperty("source", QUrl::fromLocalFile(QFINDTESTDATA(sourceFile))); + else + browser->setSource(QUrl::fromLocalFile(QFINDTESTDATA(sourceFile)), sourceType); + QCOMPARE(browser->sourceType(), expectedSourceType); + QTextFrame::iterator iterator = browser->document()->rootFrame()->begin(); + int maxHeadingLevel = -1; + while (!iterator.atEnd()) + maxHeadingLevel = qMax(iterator++.currentBlock().blockFormat().intProperty(QTextFormat::HeadingLevel), maxHeadingLevel); + QCOMPARE(maxHeadingLevel, expectedMaxHeadingLevel); +} + +void tst_QTextBrowser::unicode_data() +{ + QTest::addColumn<QString>("sourceFile"); + QTest::addColumn<QTextDocument::ResourceType>("sourceType"); + QTest::addColumn<QString>("expectedText"); + +#if QT_CONFIG(textmarkdownreader) + QTest::newRow("markdown with quotes and fractions") << "quotesAndFractions.md" << QTextDocument::MarkdownResource << + "you\u2019ll hope to see \u275Dquotes\u275E \uFE601\u00BD \u2154 \u00BC \u2157 \u215A \u215D some \u201Cvulgar\u201D fractions (pardon my \u00ABFrench\u00BB)"; +#endif +} + +void tst_QTextBrowser::unicode() +{ + QFETCH(QString, sourceFile); + QFETCH(QTextDocument::ResourceType, sourceType); + QFETCH(QString, expectedText); + browser->setSource(QUrl::fromLocalFile(QFINDTESTDATA(sourceFile)), sourceType); + QTextFrame::iterator iterator = browser->document()->rootFrame()->begin(); + while (!iterator.atEnd()) { + QString blockText = iterator++.currentBlock().text(); + if (!blockText.isEmpty()) + QCOMPARE(blockText, expectedText); + } +} + QTEST_MAIN(tst_QTextBrowser) #include "tst_qtextbrowser.moc" diff --git a/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp b/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp index 3669935823..b31e230893 100644 --- a/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp +++ b/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp @@ -160,6 +160,7 @@ private slots: void selectionChanged(); #ifndef QT_NO_CLIPBOARD void copyPasteBackgroundImage(); + void copyPasteForegroundImage(); #endif void setText(); void cursorRect(); @@ -1904,6 +1905,36 @@ void tst_QTextEdit::copyPasteBackgroundImage() ba.texture().cacheKey() == bb.texture().cacheKey()); QFile::remove(QLatin1String("foo.png")); } + +void tst_QTextEdit::copyPasteForegroundImage() +{ + ed->clear(); + + QPixmap pix(20, 20); + pix.fill(Qt::blue); + + QTextCharFormat fmt; + { + QBrush textureBrush; + { + textureBrush.setTexture(pix); + } + textureBrush.setStyle(Qt::TexturePattern); + fmt.setForeground(textureBrush); + } + ed->textCursor().insertText("Foobar", fmt); + + ed->moveCursor(QTextCursor::Start); + ed->moveCursor(QTextCursor::End, QTextCursor::KeepAnchor); + + ed->copy(); + ed->clear(); + ed->paste(); + + QBrush brush = ed->textCursor().charFormat().foreground(); + QCOMPARE(brush.style(), Qt::TexturePattern); + QCOMPARE(brush.texture().cacheKey(), pix.cacheKey()); +} #endif void tst_QTextEdit::setText() @@ -1947,8 +1978,23 @@ void tst_QTextEdit::fullWidthSelection_data() #endif #ifdef QT_BUILD_INTERNAL + +// With the fix for QTBUG-78318 scaling of documentMargin is added. The testing framework +// forces qt_defaultDpi() to always return 96 DPI. For systems where the actual DPI differs +// (typically 72 DPI) this would now cause scaling of the documentMargin when +// drawing QTextEdit into QImage. In order to avoid the need of multiple reference PNGs +// for comparison we disable the Qt::AA_Use96Dpi attribute for these tests. + +struct ForceSystemDpiHelper { + ForceSystemDpiHelper() { QCoreApplication::setAttribute(Qt::AA_Use96Dpi, false); } + ~ForceSystemDpiHelper() { QCoreApplication::setAttribute(Qt::AA_Use96Dpi, old); } + bool old = QCoreApplication::testAttribute(Qt::AA_Use96Dpi); +}; + void tst_QTextEdit::fullWidthSelection() { + ForceSystemDpiHelper useSystemDpi; + QFETCH(int, cursorFrom); QFETCH(int, cursorTo); QFETCH(QString, imageFileName); @@ -2017,6 +2063,8 @@ void tst_QTextEdit::fullWidthSelection() #ifdef QT_BUILD_INTERNAL void tst_QTextEdit::fullWidthSelection2() { + ForceSystemDpiHelper useSystemDpi; + QPalette myPalette; myPalette.setColor(QPalette::All, QPalette::HighlightedText, QColor(0,0,0,0)); myPalette.setColor(QPalette::All, QPalette::Highlight, QColor(239,221,85)); @@ -2638,12 +2686,14 @@ void tst_QTextEdit::wheelEvent() ed.setReadOnly(true); float defaultFontSize = ed.font().pointSizeF(); - QWheelEvent wheelUp(QPointF(), QPointF(), QPoint(), QPoint(0, 120), 120, Qt::Vertical, Qt::NoButton, Qt::ControlModifier); + QWheelEvent wheelUp(QPointF(), QPointF(), QPoint(), QPoint(0, 120), + Qt::NoButton, Qt::ControlModifier, Qt::NoScrollPhase, Qt::MouseEventNotSynthesized); ed.wheelEvent(&wheelUp); QCOMPARE(defaultFontSize + 1, ed.font().pointSizeF()); - QWheelEvent wheelHalfDown(QPointF(), QPointF(), QPoint(), QPoint(0, -60), -60, Qt::Vertical, Qt::NoButton, Qt::ControlModifier); + QWheelEvent wheelHalfDown(QPointF(), QPointF(), QPoint(), QPoint(0, -60), + Qt::NoButton, Qt::ControlModifier, Qt::NoScrollPhase, Qt::MouseEventNotSynthesized); ed.wheelEvent(&wheelHalfDown); QCOMPARE(defaultFontSize + 0.5, ed.font().pointSizeF()); diff --git a/tests/auto/widgets/widgets/qtoolbutton/BLACKLIST b/tests/auto/widgets/widgets/qtoolbutton/BLACKLIST index df4fda196f..52ba36562f 100644 --- a/tests/auto/widgets/widgets/qtoolbutton/BLACKLIST +++ b/tests/auto/widgets/widgets/qtoolbutton/BLACKLIST @@ -1,2 +1,2 @@ [task176137_autoRepeatOfAction] -osx ci +osx-10.13 diff --git a/tests/auto/xml/sax/qxmlinputsource/tst_qxmlinputsource.cpp b/tests/auto/xml/sax/qxmlinputsource/tst_qxmlinputsource.cpp index 752e39c23f..d40c8c2fd6 100644 --- a/tests/auto/xml/sax/qxmlinputsource/tst_qxmlinputsource.cpp +++ b/tests/auto/xml/sax/qxmlinputsource/tst_qxmlinputsource.cpp @@ -34,6 +34,7 @@ #include <QTcpServer> #include <QTcpSocket> #include <QTimer> +#include <QElapsedTimer> #include <QtDebug> #include <QtTest/QtTest> #include <QXmlDefaultHandler> @@ -259,7 +260,7 @@ public: // Delibrately wait a maximum of 10 seconds for the sake // of the test, so it doesn't unduly hang const int waitTime = qMax(10000, msecs); - QTime t; + QElapsedTimer t; t.start(); while (t.elapsed() < waitTime) { QCoreApplication::processEvents(); diff --git a/tests/auto/xml/sax/qxmlsimplereader/parser/main.cpp b/tests/auto/xml/sax/qxmlsimplereader/parser/main.cpp index 15f10232bd..b5d9fea315 100644 --- a/tests/auto/xml/sax/qxmlsimplereader/parser/main.cpp +++ b/tests/auto/xml/sax/qxmlsimplereader/parser/main.cpp @@ -72,7 +72,7 @@ int main(int argc, const char *argv[]) QFile in_file(file_name); if (!in_file.open(QIODevice::ReadOnly)) { - qerr << "Could not open " << file_name << ": " << strerror(errno) << endl; + qerr << "Could not open " << file_name << ": " << strerror(errno) << Qt::endl; return 1; } @@ -87,7 +87,7 @@ int main(int argc, const char *argv[]) } else { _out_file.setFileName(out_file_name); if (!_out_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { - qerr << "Could not open " << out_file_name << ": " << strerror(errno) << endl; + qerr << "Could not open " << out_file_name << ": " << strerror(errno) << Qt::endl; return 1; } _out_stream.setDevice(&_out_file); diff --git a/tests/auto/xml/sax/qxmlsimplereader/parser/parser.cpp b/tests/auto/xml/sax/qxmlsimplereader/parser/parser.cpp index 17351883c3..556603a681 100644 --- a/tests/auto/xml/sax/qxmlsimplereader/parser/parser.cpp +++ b/tests/auto/xml/sax/qxmlsimplereader/parser/parser.cpp @@ -28,7 +28,7 @@ #include <qxml.h> -#include <qregexp.h> +#include <qregularexpression.h> #include "parser.h" @@ -139,11 +139,11 @@ bool ContentHandler::startElement(const QString &namespaceURI, QString ContentHandler::escapeStr(const QString &s) { QString result = s; - result.replace(QRegExp("\""), "\\\""); - result.replace(QRegExp("\\"), "\\\\"); - result.replace(QRegExp("\n"), "\\n"); - result.replace(QRegExp("\r"), "\\r"); - result.replace(QRegExp("\t"), "\\t"); + result.replace(QRegularExpression("\""), "\\\""); + result.replace(QRegularExpression("\\"), "\\\\"); + result.replace(QRegularExpression("\n"), "\\n"); + result.replace(QRegularExpression("\r"), "\\r"); + result.replace(QRegularExpression("\t"), "\\t"); return result; } diff --git a/tests/auto/xml/sax/qxmlsimplereader/xmldocs/valid/sa/089.xml.bak b/tests/auto/xml/sax/qxmlsimplereader/xmldocs/valid/sa/089.xml.bak deleted file mode 100644 index 2d80c8f3fb..0000000000 --- a/tests/auto/xml/sax/qxmlsimplereader/xmldocs/valid/sa/089.xml.bak +++ /dev/null @@ -1,5 +0,0 @@ -<!DOCTYPE doc [
-<!ENTITY e "𐀀􏿽">
-<!ELEMENT doc (#PCDATA)>
-]>
-<doc>&e;</doc>
diff --git a/tests/baselineserver/shared/baselineprotocol.cpp b/tests/baselineserver/shared/baselineprotocol.cpp index c9f9cd9bd2..aa496d6c54 100644 --- a/tests/baselineserver/shared/baselineprotocol.cpp +++ b/tests/baselineserver/shared/baselineprotocol.cpp @@ -38,6 +38,7 @@ #include <QDir> #include <QTime> #include <QPointer> +#include <QRegExp> const QString PI_Project(QLS("Project")); const QString PI_TestCase(QLS("TestCase")); @@ -291,7 +292,8 @@ void ImageItem::writeImageToStream(QDataStream &out) const out << quint8('Q') << quint8(image.format()); out << quint8(QSysInfo::ByteOrder) << quint8(0); // pad to multiple of 4 bytes out << quint32(image.width()) << quint32(image.height()) << quint32(image.bytesPerLine()); - out << qCompress((const uchar *)image.constBits(), image.byteCount()); + out << qCompress(reinterpret_cast<const uchar *>(image.constBits()), + int(image.sizeInBytes())); //# can be followed by colormap for formats that use it } diff --git a/tests/benchmarks/corelib/corelib.pro b/tests/benchmarks/corelib/corelib.pro index b5781ad49e..010abd7751 100644 --- a/tests/benchmarks/corelib/corelib.pro +++ b/tests/benchmarks/corelib/corelib.pro @@ -4,7 +4,9 @@ SUBDIRS = \ json \ mimetypes \ kernel \ + text \ thread \ + time \ tools \ codecs \ plugin diff --git a/tests/benchmarks/corelib/io/qdiriterator/main.cpp b/tests/benchmarks/corelib/io/qdiriterator/main.cpp index e71daccf7d..eae752d99a 100644 --- a/tests/benchmarks/corelib/io/qdiriterator/main.cpp +++ b/tests/benchmarks/corelib/io/qdiriterator/main.cpp @@ -78,24 +78,22 @@ void tst_qdiriterator::data() } #ifdef Q_OS_WIN -static int posix_helper(const wchar_t *dirpath) +static int posix_helper(const wchar_t *dirpath, size_t length) { int count = 0; HANDLE hSearch; WIN32_FIND_DATA fd; - const size_t origDirPathLength = wcslen(dirpath); - wchar_t appendedPath[MAX_PATH]; - wcscpy(appendedPath, dirpath); - wcscat(appendedPath, L"\\*"); + Q_ASSERT(MAX_PATH > length + 3); + wcsncpy(appendedPath, dirpath, length); + wcscpy(appendedPath + length, L"\\*"); #ifndef Q_OS_WINRT hSearch = FindFirstFile(appendedPath, &fd); #else hSearch = FindFirstFileEx(appendedPath, FindExInfoStandard, &fd, FindExSearchNameMatch, NULL, FIND_FIRST_EX_LARGE_FETCH); #endif - appendedPath[origDirPathLength] = 0; if (hSearch == INVALID_HANDLE_VALUE) { qWarning("FindFirstFile failed"); @@ -107,10 +105,12 @@ static int posix_helper(const wchar_t *dirpath) !(fd.cFileName[0] == L'.' && fd.cFileName[1] == L'.' && fd.cFileName[2] == 0)) { if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - wcscat(appendedPath, L"\\"); - wcscat(appendedPath, fd.cFileName); - count += posix_helper(appendedPath); - appendedPath[origDirPathLength] = 0; + // newLength will "point" to where we put a * earlier, so we overwrite that. + size_t newLength = length + 1; // "+ 1" for directory separator + Q_ASSERT(newLength + wcslen(fd.cFileName) + 1 < MAX_PATH); // "+ 1" for null-terminator + wcscpy(appendedPath + newLength, fd.cFileName); + newLength += wcslen(fd.cFileName); + count += posix_helper(appendedPath, newLength); } else { ++count; @@ -164,8 +164,8 @@ void tst_qdiriterator::posix() QBENCHMARK { #ifdef Q_OS_WIN wchar_t wPath[MAX_PATH]; - path.toWCharArray(wPath); - count = posix_helper(wPath); + const int end = path.toWCharArray(wPath); + count = posix_helper(wPath, end); #else count = posix_helper(dirpath.constData()); #endif diff --git a/tests/benchmarks/corelib/io/qdiriterator/qfilesystemiterator.cpp b/tests/benchmarks/corelib/io/qdiriterator/qfilesystemiterator.cpp index d68264b78f..6ee8b4e93b 100644 --- a/tests/benchmarks/corelib/io/qdiriterator/qfilesystemiterator.cpp +++ b/tests/benchmarks/corelib/io/qdiriterator/qfilesystemiterator.cpp @@ -218,8 +218,9 @@ void QFileSystemIteratorPrivate::pushSubDirectory(const QByteArray &path) #ifdef Q_OS_WIN wchar_t szSearchPath[MAX_PATH]; - QString::fromLatin1(path).toWCharArray(szSearchPath); - wcscat(szSearchPath, L"\\*"); + const int end = QString::fromLatin1(path + "\\*").toWCharArray(szSearchPath); + Q_ASSERT(end < MAX_PATH); + szSearchPath[end] = L'\0'; #ifndef Q_OS_WINRT HANDLE dir = FindFirstFile(szSearchPath, &m_fileSearchResult); #else diff --git a/tests/benchmarks/corelib/kernel/kernel.pro b/tests/benchmarks/corelib/kernel/kernel.pro index 02eeeaa254..92f7174419 100644 --- a/tests/benchmarks/corelib/kernel/kernel.pro +++ b/tests/benchmarks/corelib/kernel/kernel.pro @@ -5,7 +5,8 @@ SUBDIRS = \ qmetatype \ qobject \ qvariant \ - qcoreapplication + qcoreapplication \ + qtimer_vs_qmetaobject !qtHaveModule(widgets): SUBDIRS -= \ qmetaobject \ diff --git a/tests/benchmarks/corelib/kernel/qtimer_vs_qmetaobject/tst_qtimer_vs_qmetaobject.cpp b/tests/benchmarks/corelib/kernel/qtimer_vs_qmetaobject/tst_qtimer_vs_qmetaobject.cpp index 66a29780f0..6af5b8d586 100644 --- a/tests/benchmarks/corelib/kernel/qtimer_vs_qmetaobject/tst_qtimer_vs_qmetaobject.cpp +++ b/tests/benchmarks/corelib/kernel/qtimer_vs_qmetaobject/tst_qtimer_vs_qmetaobject.cpp @@ -28,6 +28,7 @@ #include <QtCore> #include <QtTest/QtTest> +#include <QThread> #define INVOKE_COUNT 10000 @@ -35,8 +36,10 @@ class qtimer_vs_qmetaobject : public QObject { Q_OBJECT private slots: - void testZeroTimerSingleShot(); - void testQueuedInvokeMethod(); + void bench(); + void bench_data(); + void benchBackgroundThread(); + void benchBackgroundThread_data() { bench_data(); } }; class InvokeCounter : public QObject { @@ -47,36 +50,89 @@ public slots: void invokeSlot() { count++; if (count == INVOKE_COUNT) - QTestEventLoop::instance().exitLoop(); + emit allInvoked(); } +signals: + void allInvoked(); protected: int count; }; -void qtimer_vs_qmetaobject::testZeroTimerSingleShot() +void qtimer_vs_qmetaobject::bench() { + QFETCH(int, type); + + std::function<void(InvokeCounter*)> invoke; + if (type == 0) { + invoke = [](InvokeCounter* invokeCounter) { + QTimer::singleShot(0, invokeCounter, SLOT(invokeSlot())); + }; + } else if (type == 1) { + invoke = [](InvokeCounter* invokeCounter) { + QTimer::singleShot(0, invokeCounter, &InvokeCounter::invokeSlot); + }; + } else if (type == 2) { + invoke = [](InvokeCounter* invokeCounter) { + QTimer::singleShot(0, invokeCounter, [invokeCounter]() { + invokeCounter->invokeSlot(); + }); + }; + } else if (type == 3) { + invoke = [](InvokeCounter* invokeCounter) { + QTimer::singleShot(0, [invokeCounter]() { + invokeCounter->invokeSlot(); + }); + }; + } else if (type == 4) { + invoke = [](InvokeCounter* invokeCounter) { + QMetaObject::invokeMethod(invokeCounter, "invokeSlot", Qt::QueuedConnection); + }; + } else if (type == 5) { + invoke = [](InvokeCounter* invokeCounter) { + QMetaObject::invokeMethod(invokeCounter, &InvokeCounter::invokeSlot, Qt::QueuedConnection); + }; + } else if (type == 6) { + invoke = [](InvokeCounter* invokeCounter) { + QMetaObject::invokeMethod(invokeCounter, [invokeCounter]() { + invokeCounter->invokeSlot(); + }, Qt::QueuedConnection); + }; + } else { + QFAIL("unhandled data tag"); + } + QBENCHMARK { InvokeCounter invokeCounter; + QSignalSpy spy(&invokeCounter, &InvokeCounter::allInvoked); for(int i = 0; i < INVOKE_COUNT; ++i) { - QTimer::singleShot(0, &invokeCounter, SLOT(invokeSlot())); + invoke(&invokeCounter); } - QTestEventLoop::instance().enterLoop(10); - QVERIFY(!QTestEventLoop::instance().timeout()); + QVERIFY(spy.wait(10000)); } } -void qtimer_vs_qmetaobject::testQueuedInvokeMethod() +void qtimer_vs_qmetaobject::bench_data() { - QBENCHMARK { - InvokeCounter invokeCounter; - for(int i = 0; i < INVOKE_COUNT; ++i) { - QMetaObject::invokeMethod(&invokeCounter, "invokeSlot", Qt::QueuedConnection); - } - QTestEventLoop::instance().enterLoop(10); - QVERIFY(!QTestEventLoop::instance().timeout()); - } + QTest::addColumn<int>("type"); + QTest::addRow("singleShot_slot") << 0; + QTest::addRow("singleShot_pmf") << 1; + QTest::addRow("singleShot_functor") << 2; + QTest::addRow("singleShot_functor_noctx") << 3; + QTest::addRow("invokeMethod_string") << 4; + QTest::addRow("invokeMethod_pmf") << 5; + QTest::addRow("invokeMethod_functor") << 6; } +void qtimer_vs_qmetaobject::benchBackgroundThread() +{ +#if !QT_CONFIG(cxx11_future) + QSKIP("This test requires QThread::create"); +#else + QScopedPointer<QThread> thread(QThread::create([this]() { bench(); })); + thread->start(); + QVERIFY(thread->wait()); +#endif +} QTEST_MAIN(qtimer_vs_qmetaobject) diff --git a/tests/benchmarks/corelib/tools/qbytearray/main.cpp b/tests/benchmarks/corelib/text/qbytearray/main.cpp index e421e7436b..e421e7436b 100644 --- a/tests/benchmarks/corelib/tools/qbytearray/main.cpp +++ b/tests/benchmarks/corelib/text/qbytearray/main.cpp diff --git a/tests/benchmarks/corelib/tools/qbytearray/qbytearray.pro b/tests/benchmarks/corelib/text/qbytearray/qbytearray.pro index cf28b0247f..cf28b0247f 100644 --- a/tests/benchmarks/corelib/tools/qbytearray/qbytearray.pro +++ b/tests/benchmarks/corelib/text/qbytearray/qbytearray.pro diff --git a/tests/benchmarks/corelib/tools/qchar/main.cpp b/tests/benchmarks/corelib/text/qchar/main.cpp index 4dcf86786d..4dcf86786d 100644 --- a/tests/benchmarks/corelib/tools/qchar/main.cpp +++ b/tests/benchmarks/corelib/text/qchar/main.cpp diff --git a/tests/benchmarks/corelib/tools/qchar/qchar.pro b/tests/benchmarks/corelib/text/qchar/qchar.pro index 80a9861f48..80a9861f48 100644 --- a/tests/benchmarks/corelib/tools/qchar/qchar.pro +++ b/tests/benchmarks/corelib/text/qchar/qchar.pro diff --git a/tests/benchmarks/corelib/tools/qlocale/main.cpp b/tests/benchmarks/corelib/text/qlocale/main.cpp index 38d94af143..38d94af143 100644 --- a/tests/benchmarks/corelib/tools/qlocale/main.cpp +++ b/tests/benchmarks/corelib/text/qlocale/main.cpp diff --git a/tests/benchmarks/corelib/tools/qlocale/qlocale.pro b/tests/benchmarks/corelib/text/qlocale/qlocale.pro index e56bbe0341..e56bbe0341 100644 --- a/tests/benchmarks/corelib/tools/qlocale/qlocale.pro +++ b/tests/benchmarks/corelib/text/qlocale/qlocale.pro diff --git a/tests/benchmarks/corelib/tools/qregexp/main.cpp b/tests/benchmarks/corelib/text/qregexp/main.cpp index 798b23f2b0..798b23f2b0 100644 --- a/tests/benchmarks/corelib/tools/qregexp/main.cpp +++ b/tests/benchmarks/corelib/text/qregexp/main.cpp diff --git a/tests/benchmarks/corelib/tools/qregexp/qregexp.pro b/tests/benchmarks/corelib/text/qregexp/qregexp.pro index f64ae781a2..f64ae781a2 100644 --- a/tests/benchmarks/corelib/tools/qregexp/qregexp.pro +++ b/tests/benchmarks/corelib/text/qregexp/qregexp.pro diff --git a/tests/benchmarks/corelib/tools/qregexp/qregexp.qrc b/tests/benchmarks/corelib/text/qregexp/qregexp.qrc index a7fe13c035..a7fe13c035 100644 --- a/tests/benchmarks/corelib/tools/qregexp/qregexp.qrc +++ b/tests/benchmarks/corelib/text/qregexp/qregexp.qrc diff --git a/tests/benchmarks/corelib/tools/qstring/main.cpp b/tests/benchmarks/corelib/text/qstring/main.cpp index 826a843c10..826a843c10 100644 --- a/tests/benchmarks/corelib/tools/qstring/main.cpp +++ b/tests/benchmarks/corelib/text/qstring/main.cpp diff --git a/tests/benchmarks/corelib/tools/qstring/qstring.pro b/tests/benchmarks/corelib/text/qstring/qstring.pro index 9f5e34b915..9f5e34b915 100644 --- a/tests/benchmarks/corelib/tools/qstring/qstring.pro +++ b/tests/benchmarks/corelib/text/qstring/qstring.pro diff --git a/tests/benchmarks/corelib/tools/qstringbuilder/main.cpp b/tests/benchmarks/corelib/text/qstringbuilder/main.cpp index d0dfe3b1a7..0de6d33846 100644 --- a/tests/benchmarks/corelib/tools/qstringbuilder/main.cpp +++ b/tests/benchmarks/corelib/text/qstringbuilder/main.cpp @@ -401,7 +401,7 @@ private slots: } private: - const QLatin1Literal l1literal; + const QLatin1String l1literal; const QLatin1String l1string; const QByteArray ba; const QString string; diff --git a/tests/benchmarks/corelib/tools/qstringbuilder/qstringbuilder.pro b/tests/benchmarks/corelib/text/qstringbuilder/qstringbuilder.pro index fa4cbe3c13..fa4cbe3c13 100644 --- a/tests/benchmarks/corelib/tools/qstringbuilder/qstringbuilder.pro +++ b/tests/benchmarks/corelib/text/qstringbuilder/qstringbuilder.pro diff --git a/tests/benchmarks/corelib/tools/qstringlist/.gitignore b/tests/benchmarks/corelib/text/qstringlist/.gitignore index 3e0cdc952f..3e0cdc952f 100644 --- a/tests/benchmarks/corelib/tools/qstringlist/.gitignore +++ b/tests/benchmarks/corelib/text/qstringlist/.gitignore diff --git a/tests/benchmarks/corelib/tools/qstringlist/main.cpp b/tests/benchmarks/corelib/text/qstringlist/main.cpp index ae355a8b89..ae355a8b89 100644 --- a/tests/benchmarks/corelib/tools/qstringlist/main.cpp +++ b/tests/benchmarks/corelib/text/qstringlist/main.cpp diff --git a/tests/benchmarks/corelib/tools/qstringlist/qstringlist.pro b/tests/benchmarks/corelib/text/qstringlist/qstringlist.pro index 5803e7da0e..5803e7da0e 100644 --- a/tests/benchmarks/corelib/tools/qstringlist/qstringlist.pro +++ b/tests/benchmarks/corelib/text/qstringlist/qstringlist.pro diff --git a/tests/benchmarks/corelib/text/text.pro b/tests/benchmarks/corelib/text/text.pro new file mode 100644 index 0000000000..a2397b37fe --- /dev/null +++ b/tests/benchmarks/corelib/text/text.pro @@ -0,0 +1,9 @@ +TEMPLATE = subdirs +SUBDIRS = \ + qbytearray \ + qchar \ + qlocale \ + qstringbuilder \ + qstringlist + +*g++*: SUBDIRS += qstring diff --git a/tests/benchmarks/corelib/thread/qreadwritelock/qreadwritelock.pro b/tests/benchmarks/corelib/thread/qreadwritelock/qreadwritelock.pro index 86102adecd..a1827d0276 100644 --- a/tests/benchmarks/corelib/thread/qreadwritelock/qreadwritelock.pro +++ b/tests/benchmarks/corelib/thread/qreadwritelock/qreadwritelock.pro @@ -1,6 +1,7 @@ TEMPLATE = app TARGET = tst_bench_qreadwritelock -QT = core testlib +QT = core-private testlib SOURCES += tst_qreadwritelock.cpp CONFIG += c++14 # for std::shared_timed_mutex +CONFIG += c++1z # for std::shared_mutex diff --git a/tests/benchmarks/corelib/thread/qreadwritelock/tst_qreadwritelock.cpp b/tests/benchmarks/corelib/thread/qreadwritelock/tst_qreadwritelock.cpp index fcf600a059..1d47d98657 100644 --- a/tests/benchmarks/corelib/thread/qreadwritelock/tst_qreadwritelock.cpp +++ b/tests/benchmarks/corelib/thread/qreadwritelock/tst_qreadwritelock.cpp @@ -28,12 +28,14 @@ #include <QtCore/QtCore> #include <QtTest/QtTest> +#include <QtCore/private/qmemory_p.h> #include <mutex> #if QT_HAS_INCLUDE(<shared_mutex>) #if __cplusplus > 201103L #include <shared_mutex> #endif #endif +#include <vector> // Wrapers that take pointers instead of reference to have the same interface as Qt template <typename T> @@ -63,6 +65,8 @@ private slots: void uncontended(); void readOnly_data(); void readOnly(); + void writeOnly_data(); + void writeOnly(); // void readWrite(); }; @@ -106,6 +110,14 @@ void tst_QReadWriteLock::uncontended_data() << FunctionPtrHolder(testUncontended<QReadWriteLock, QWriteLocker>); QTest::newRow("std::mutex") << FunctionPtrHolder( testUncontended<std::mutex, LockerWrapper<std::unique_lock<std::mutex>>>); +#ifdef __cpp_lib_shared_mutex + QTest::newRow("std::shared_mutex, read") << FunctionPtrHolder( + testUncontended<std::shared_mutex, + LockerWrapper<std::shared_lock<std::shared_mutex>>>); + QTest::newRow("std::shared_mutex, write") << FunctionPtrHolder( + testUncontended<std::shared_mutex, + LockerWrapper<std::unique_lock<std::shared_mutex>>>); +#endif #if defined __cpp_lib_shared_timed_mutex QTest::newRow("std::shared_timed_mutex, read") << FunctionPtrHolder( testUncontended<std::shared_timed_mutex, @@ -130,7 +142,7 @@ void testReadOnly() struct Thread : QThread { Mutex *lock; - void run() + void run() override { for (int i = 0; i < Iterations; ++i) { QString s = QString::number(i); // Do something outside the lock @@ -140,21 +152,20 @@ void testReadOnly() } }; Mutex lock; - QVector<QThread *> threads; + std::vector<std::unique_ptr<Thread>> threads; for (int i = 0; i < threadCount; ++i) { - auto t = new Thread; + auto t = qt_make_unique<Thread>(); t->lock = &lock; - threads.append(t); + threads.push_back(std::move(t)); } QBENCHMARK { - for (auto t : threads) { + for (auto &t : threads) { t->start(); } - for (auto t : threads) { + for (auto &t : threads) { t->wait(); } } - qDeleteAll(threads); } void tst_QReadWriteLock::readOnly_data() @@ -166,6 +177,11 @@ void tst_QReadWriteLock::readOnly_data() QTest::newRow("QReadWriteLock") << FunctionPtrHolder(testReadOnly<QReadWriteLock, QReadLocker>); QTest::newRow("std::mutex") << FunctionPtrHolder( testReadOnly<std::mutex, LockerWrapper<std::unique_lock<std::mutex>>>); +#ifdef __cpp_lib_shared_mutex + QTest::newRow("std::shared_mutex") << FunctionPtrHolder( + testReadOnly<std::shared_mutex, + LockerWrapper<std::shared_lock<std::shared_mutex>>>); +#endif #if defined __cpp_lib_shared_timed_mutex QTest::newRow("std::shared_timed_mutex") << FunctionPtrHolder( testReadOnly<std::shared_timed_mutex, @@ -179,5 +195,66 @@ void tst_QReadWriteLock::readOnly() holder.value(); } +static QString global_string; + +template <typename Mutex, typename Locker> +void testWriteOnly() +{ + struct Thread : QThread + { + Mutex *lock; + void run() override + { + for (int i = 0; i < Iterations; ++i) { + QString s = QString::number(i); // Do something outside the lock + Locker locker(lock); + global_string = s; + } + } + }; + Mutex lock; + std::vector<std::unique_ptr<Thread>> threads; + for (int i = 0; i < threadCount; ++i) { + auto t = qt_make_unique<Thread>(); + t->lock = &lock; + threads.push_back(std::move(t)); + } + QBENCHMARK { + for (auto &t : threads) { + t->start(); + } + for (auto &t : threads) { + t->wait(); + } + } +} + +void tst_QReadWriteLock::writeOnly_data() +{ + QTest::addColumn<FunctionPtrHolder>("holder"); + + // QTest::newRow("nothing") << FunctionPtrHolder(testWriteOnly<int, FakeLock>); + QTest::newRow("QMutex") << FunctionPtrHolder(testWriteOnly<QMutex, QMutexLocker>); + QTest::newRow("QReadWriteLock") << FunctionPtrHolder(testWriteOnly<QReadWriteLock, QWriteLocker>); + QTest::newRow("std::mutex") << FunctionPtrHolder( + testWriteOnly<std::mutex, LockerWrapper<std::unique_lock<std::mutex>>>); +#ifdef __cpp_lib_shared_mutex + QTest::newRow("std::shared_mutex") << FunctionPtrHolder( + testWriteOnly<std::shared_mutex, + LockerWrapper<std::unique_lock<std::shared_mutex>>>); +#endif +#if defined __cpp_lib_shared_timed_mutex + QTest::newRow("std::shared_timed_mutex") << FunctionPtrHolder( + testWriteOnly<std::shared_timed_mutex, + LockerWrapper<std::unique_lock<std::shared_timed_mutex>>>); +#endif +} + +void tst_QReadWriteLock::writeOnly() +{ + QFETCH(FunctionPtrHolder, holder); + holder.value(); +} + QTEST_MAIN(tst_QReadWriteLock) #include "tst_qreadwritelock.moc" diff --git a/tests/benchmarks/corelib/time/qdate/qdate.pro b/tests/benchmarks/corelib/time/qdate/qdate.pro new file mode 100644 index 0000000000..a655917135 --- /dev/null +++ b/tests/benchmarks/corelib/time/qdate/qdate.pro @@ -0,0 +1,4 @@ +TARGET = tst_bench_qdate +QT = core testlib + +SOURCES += tst_bench_qdate.cpp diff --git a/tests/benchmarks/corelib/time/qdate/tst_bench_qdate.cpp b/tests/benchmarks/corelib/time/qdate/tst_bench_qdate.cpp new file mode 100644 index 0000000000..10c013c080 --- /dev/null +++ b/tests/benchmarks/corelib/time/qdate/tst_bench_qdate.cpp @@ -0,0 +1,213 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QDate> +#include <QTest> +#include <QVector> + +class tst_QDate : public QObject +{ + Q_OBJECT + + enum : qint64 + { + JULIAN_DAY_2010 = 2455198, + JULIAN_DAY_2011 = 2455563, + JULIAN_DAY_2020 = 2458850, + }; + + static QVector<QDate> daily(qint64 start, qint64 end); + static QVector<QDate> yearly(qint32 first, qint32 last); + +private Q_SLOTS: + void create(); + void year(); + void month(); + void day(); + void dayOfWeek(); + void dayOfYear(); + void monthLengths(); // isValid() and daysInMonth() + void daysInYear(); + void isLeapYear(); + void getSetDate(); + void addDays(); + void addMonths(); + void addYears(); +}; + +QVector<QDate> tst_QDate::daily(qint64 start, qint64 end) +{ + QVector<QDate> list; + list.reserve(end - start); + for (qint64 jd = start; jd < end; ++jd) + list.append(QDate::fromJulianDay(jd)); + return list; +} + +QVector<QDate> tst_QDate::yearly(qint32 first, qint32 last) +{ + QVector<QDate> list; + list.reserve(last + 1 - first); + for (qint32 year = first; year <= last; ++year) + list.append(QDate(year, 3, 21)); + return list; +} + +void tst_QDate::create() +{ + QDate test; + QBENCHMARK { + for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) + test = QDate::fromJulianDay(jd); + } + Q_UNUSED(test); +} + +void tst_QDate::year() +{ + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (const QDate &test : list) + test.year(); + } +} + +void tst_QDate::month() +{ + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (const QDate &test : list) + test.month(); + } +} + +void tst_QDate::day() +{ + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (const QDate &test : list) + test.day(); + } +} + +void tst_QDate::dayOfWeek() +{ + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (const QDate &test : list) + test.dayOfWeek(); + } +} + +void tst_QDate::dayOfYear() +{ + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (const QDate &test : list) + test.dayOfYear(); + } +} + +void tst_QDate::monthLengths() +{ + bool check = true; + QBENCHMARK { + for (int year = 1900; year <= 2100; year++) { + for (int month = 1; month <= 12; month++) + check = QDate::isValid(year, month, QDate(year, month, 1).daysInMonth()); + } + } + Q_UNUSED(check); +} + +void tst_QDate::daysInYear() +{ + const auto list = yearly(1601, 2401); + QBENCHMARK { + for (const QDate date : list) + date.daysInYear(); + } +} + +void tst_QDate::isLeapYear() +{ + QBENCHMARK { + for (qint32 year = 1601; year <= 2401; year++) + QDate::isLeapYear(year); + } +} + +void tst_QDate::getSetDate() +{ + QDate store; + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (const auto test : list) { + int year, month, day; + test.getDate(&year, &month, &day); + store.setDate(year, month, day); + } + } + Q_UNUSED(store); +} + +void tst_QDate::addDays() +{ + QDate store; + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (const auto test : list) + store = test.addDays(17); + } + Q_UNUSED(store); +} + +void tst_QDate::addMonths() +{ + QDate store; + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (const auto test : list) + store = test.addMonths(17); + } + Q_UNUSED(store); +} + +void tst_QDate::addYears() +{ + QDate store; + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (const auto test : list) + store = test.addYears(17); + } + Q_UNUSED(store); +} + +QTEST_MAIN(tst_QDate) +#include "tst_bench_qdate.moc" diff --git a/tests/benchmarks/corelib/time/qdatetime/main.cpp b/tests/benchmarks/corelib/time/qdatetime/main.cpp new file mode 100644 index 0000000000..740e08cc46 --- /dev/null +++ b/tests/benchmarks/corelib/time/qdatetime/main.cpp @@ -0,0 +1,574 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QDateTime> +#include <QTimeZone> +#include <QTest> +#include <QVector> +#include <qdebug.h> + +class tst_QDateTime : public QObject +{ + Q_OBJECT + + enum : qint64 + { + SECS_PER_DAY = 86400, + MSECS_PER_DAY = 86400000, + JULIAN_DAY_1950 = 2433283, + JULIAN_DAY_1960 = 2436935, + JULIAN_DAY_1970 = 2440588, // Epoch + JULIAN_DAY_2010 = 2455198, + JULIAN_DAY_2011 = 2455563, + JULIAN_DAY_2020 = 2458850, + JULIAN_DAY_2050 = 2469808, + JULIAN_DAY_2060 = 2473460 + }; + + static QVector<QDateTime> daily(qint64 start, qint64 end); + static QVector<QDateTime> norse(qint64 start, qint64 end); + +private Q_SLOTS: + void create(); + void isNull(); + void isValid(); + void date(); + void time(); + void timeSpec(); + void offsetFromUtc(); + void timeZoneAbbreviation(); + void toMSecsSinceEpoch(); + void toMSecsSinceEpoch1950(); + void toMSecsSinceEpoch2050(); + void toMSecsSinceEpochTz(); + void toMSecsSinceEpoch1950Tz(); + void toMSecsSinceEpoch2050Tz(); + void setDate(); + void setTime(); + void setTimeSpec(); + void setOffsetFromUtc(); + void setMSecsSinceEpoch(); + void setMSecsSinceEpochTz(); + void toString(); + void toStringTextFormat(); + void toStringIsoFormat(); + void addDays(); + void addDaysTz(); + void addMSecs(); + void addMSecsTz(); + void toTimeSpec(); + void toOffsetFromUtc(); + void daysTo(); + void msecsTo(); + void equivalent(); + void equivalentUtc(); + void lessThan(); + void lessThanUtc(); + void currentDateTime(); + void currentDate(); + void currentTime(); + void currentDateTimeUtc(); + void currentMSecsSinceEpoch(); + void fromString(); + void fromStringText(); + void fromStringIso(); + void fromMSecsSinceEpoch(); + void fromMSecsSinceEpochUtc(); + void fromMSecsSinceEpochTz(); +}; + +QVector<QDateTime> tst_QDateTime::daily(qint64 start, qint64 end) +{ + QVector<QDateTime> list; + list.reserve(end - start); + for (int jd = start; jd < end; ++jd) + list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0))); + return list; +} + +QVector<QDateTime> tst_QDateTime::norse(qint64 start, qint64 end) +{ + const QTimeZone cet("Europe/Oslo"); + QVector<QDateTime> list; + list.reserve(end - start); + for (int jd = start; jd < end; ++jd) + list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0), cet)); + return list; +} + +void tst_QDateTime::create() +{ + QBENCHMARK { + for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) { + QDateTime test(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0)); + Q_UNUSED(test) + } + } +} + +void tst_QDateTime::isNull() +{ + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (const QDateTime &test : list) + test.isNull(); + } +} + +void tst_QDateTime::isValid() +{ + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (const QDateTime &test : list) + test.isValid(); + } +} + +void tst_QDateTime::date() +{ + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (const QDateTime &test : list) + test.date(); + } +} + +void tst_QDateTime::time() +{ + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (const QDateTime &test : list) + test.time(); + } +} + +void tst_QDateTime::timeSpec() +{ + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (const QDateTime &test : list) + test.timeSpec(); + } +} + +void tst_QDateTime::offsetFromUtc() +{ + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (const QDateTime &test : list) + test.offsetFromUtc(); + } +} + +void tst_QDateTime::timeZoneAbbreviation() +{ + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (const QDateTime &test : list) + test.timeZoneAbbreviation(); + } +} + +void tst_QDateTime::toMSecsSinceEpoch() +{ + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (const QDateTime &test : list) + test.toMSecsSinceEpoch(); + } +} + +void tst_QDateTime::toMSecsSinceEpoch1950() +{ + const auto list = daily(JULIAN_DAY_1950, JULIAN_DAY_1960); + QBENCHMARK { + for (const QDateTime &test : list) + test.toMSecsSinceEpoch(); + } +} + +void tst_QDateTime::toMSecsSinceEpoch2050() +{ + const auto list = daily(JULIAN_DAY_2050, JULIAN_DAY_2060); + QBENCHMARK { + for (const QDateTime &test : list) + test.toMSecsSinceEpoch(); + } +} + +void tst_QDateTime::toMSecsSinceEpochTz() +{ + qint64 result; + const auto list = norse(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (const QDateTime &test : list) + result = test.toMSecsSinceEpoch(); + } + Q_UNUSED(result); +} + +void tst_QDateTime::toMSecsSinceEpoch1950Tz() +{ + qint64 result; + const auto list = norse(JULIAN_DAY_1950, JULIAN_DAY_1960); + QBENCHMARK { + for (const QDateTime &test : list) + result = test.toMSecsSinceEpoch(); + } + Q_UNUSED(result); +} + +void tst_QDateTime::toMSecsSinceEpoch2050Tz() +{ + qint64 result; + const auto list = norse(JULIAN_DAY_2050, JULIAN_DAY_2060); + QBENCHMARK { + for (const QDateTime &test : list) + result = test.toMSecsSinceEpoch(); + } + Q_UNUSED(result); +} + +void tst_QDateTime::setDate() +{ + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (QDateTime test : list) + test.setDate(QDate::fromJulianDay(JULIAN_DAY_2010)); + } +} + +void tst_QDateTime::setTime() +{ + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (QDateTime test : list) + test.setTime(QTime(12, 0, 0)); + } +} + +void tst_QDateTime::setTimeSpec() +{ + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (QDateTime test : list) + test.setTimeSpec(Qt::UTC); + } +} + +void tst_QDateTime::setOffsetFromUtc() +{ + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (QDateTime test : list) + test.setOffsetFromUtc(3600); + } +} + +void tst_QDateTime::setMSecsSinceEpoch() +{ + qint64 msecs = qint64(JULIAN_DAY_2010 - JULIAN_DAY_1970 + 180) * MSECS_PER_DAY; + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (QDateTime test : list) + test.setMSecsSinceEpoch(msecs); + } +} + +void tst_QDateTime::setMSecsSinceEpochTz() +{ + const qint64 msecs = qint64(JULIAN_DAY_2010 - JULIAN_DAY_1970 + 180) * MSECS_PER_DAY; + const auto list = norse(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (QDateTime test : list) + test.setMSecsSinceEpoch(msecs); + } +} + +void tst_QDateTime::toString() +{ + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2011); + QBENCHMARK { + for (const QDateTime &test : list) + test.toString(QStringLiteral("yyy-MM-dd hh:mm:ss.zzz t")); + } +} + +void tst_QDateTime::toStringTextFormat() +{ + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2011); + QBENCHMARK { + for (const QDateTime &test : list) + test.toString(Qt::TextDate); + } +} + +void tst_QDateTime::toStringIsoFormat() +{ + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2011); + QBENCHMARK { + for (const QDateTime &test : list) + test.toString(Qt::ISODate); + } +} + +void tst_QDateTime::addDays() +{ + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QDateTime next; + QBENCHMARK { + for (const QDateTime &test : list) + next = test.addDays(1); + } + Q_UNUSED(next); +} + +void tst_QDateTime::addDaysTz() +{ + const auto list = norse(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (const QDateTime &test : list) + QDateTime result = test.addDays(1); + } +} + +void tst_QDateTime::addMSecs() +{ + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QDateTime next; + QBENCHMARK { + for (const QDateTime &test : list) + next = test.addMSecs(1); + } + Q_UNUSED(next); +} + +void tst_QDateTime::addMSecsTz() +{ + const auto list = norse(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (const QDateTime &test : list) + QDateTime result = test.addMSecs(1); + } +} + +void tst_QDateTime::toTimeSpec() +{ + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (const QDateTime &test : list) + test.toTimeSpec(Qt::UTC); + } +} + +void tst_QDateTime::toOffsetFromUtc() +{ + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (const QDateTime &test : list) + test.toOffsetFromUtc(3600); + } +} + +void tst_QDateTime::daysTo() +{ + const QDateTime other = QDateTime::fromMSecsSinceEpoch( + qint64(JULIAN_DAY_2010 - JULIAN_DAY_1970) * MSECS_PER_DAY); + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (const QDateTime &test : list) + test.daysTo(other); + } +} + +void tst_QDateTime::msecsTo() +{ + const QDateTime other = QDateTime::fromMSecsSinceEpoch( + qint64(JULIAN_DAY_2010 - JULIAN_DAY_1970) * MSECS_PER_DAY); + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (const QDateTime &test : list) + test.msecsTo(other); + } +} + +void tst_QDateTime::equivalent() +{ + bool result; + const QDateTime other = QDateTime::fromMSecsSinceEpoch( + qint64(JULIAN_DAY_2010 - JULIAN_DAY_1970) * MSECS_PER_DAY); + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (const QDateTime &test : list) + result = (test == other); + } + Q_UNUSED(result) +} + +void tst_QDateTime::equivalentUtc() +{ + bool result = false; + const QDateTime other = QDateTime::fromMSecsSinceEpoch( + qint64(JULIAN_DAY_2010 - JULIAN_DAY_1970) * MSECS_PER_DAY, Qt::UTC); + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (const QDateTime &test : list) + result = (test == other); + } + Q_UNUSED(result) +} + +void tst_QDateTime::lessThan() +{ + bool result = false; + const QDateTime other = QDateTime::fromMSecsSinceEpoch( + qint64(JULIAN_DAY_2010 - JULIAN_DAY_1970) * MSECS_PER_DAY); + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (const QDateTime &test : list) + result = (test < other); + } + Q_UNUSED(result) +} + +void tst_QDateTime::lessThanUtc() +{ + bool result = false; + const QDateTime other = QDateTime::fromMSecsSinceEpoch( + qint64(JULIAN_DAY_2010 - JULIAN_DAY_1970) * MSECS_PER_DAY, Qt::UTC); + const auto list = daily(JULIAN_DAY_2010, JULIAN_DAY_2020); + QBENCHMARK { + for (const QDateTime &test : list) + result = (test < other); + } + Q_UNUSED(result) +} + +void tst_QDateTime::currentDateTime() +{ + QBENCHMARK { + for (int i = 0; i < 1000; ++i) + QDateTime::currentDateTime(); + } +} + +void tst_QDateTime::currentDate() +{ + QBENCHMARK { + for (int i = 0; i < 1000; ++i) + QDate::currentDate(); + } +} + +void tst_QDateTime::currentTime() +{ + QBENCHMARK { + for (int i = 0; i < 1000; ++i) + QTime::currentTime(); + } +} + +void tst_QDateTime::currentDateTimeUtc() +{ + QBENCHMARK { + for (int i = 0; i < 1000; ++i) + QDateTime::currentDateTimeUtc(); + } +} + +void tst_QDateTime::currentMSecsSinceEpoch() +{ + QBENCHMARK { + for (int i = 0; i < 1000; ++i) + QDateTime::currentMSecsSinceEpoch(); + } +} + +void tst_QDateTime::fromString() +{ + QString format = "yyyy-MM-dd hh:mm:ss.zzz"; + QString input = "2010-01-01 13:12:11.999"; + QVERIFY(QDateTime::fromString(input, format).isValid()); + QBENCHMARK { + for (int i = 0; i < 1000; ++i) + QDateTime::fromString(input, format); + } +} + +void tst_QDateTime::fromStringText() +{ + QString input = "Wed Jan 2 01:02:03.000 2013 GMT"; + QBENCHMARK { + for (int i = 0; i < 1000; ++i) + QDateTime::fromString(input, Qt::TextDate); + } +} + +void tst_QDateTime::fromStringIso() +{ + QString input = "2010-01-01T13:28:34.999Z"; + QBENCHMARK { + for (int i = 0; i < 1000; ++i) + QDateTime::fromString(input, Qt::ISODate); + } +} + +void tst_QDateTime::fromMSecsSinceEpoch() +{ + const int start = JULIAN_DAY_2010 - JULIAN_DAY_1970; + const int end = JULIAN_DAY_2020 - JULIAN_DAY_1970; + QBENCHMARK { + for (int jd = start; jd < end; ++jd) + QDateTime::fromMSecsSinceEpoch(jd * MSECS_PER_DAY, Qt::LocalTime); + } +} + +void tst_QDateTime::fromMSecsSinceEpochUtc() +{ + const int start = JULIAN_DAY_2010 - JULIAN_DAY_1970; + const int end = JULIAN_DAY_2020 - JULIAN_DAY_1970; + QBENCHMARK { + for (int jd = start; jd < end; ++jd) + QDateTime::fromMSecsSinceEpoch(jd * MSECS_PER_DAY, Qt::UTC); + } +} + +void tst_QDateTime::fromMSecsSinceEpochTz() +{ + const int start = JULIAN_DAY_2010 - JULIAN_DAY_1970; + const int end = JULIAN_DAY_2020 - JULIAN_DAY_1970; + const QTimeZone cet("Europe/Oslo"); + QBENCHMARK { + for (int jd = start; jd < end; ++jd) + QDateTime test = QDateTime::fromMSecsSinceEpoch(jd * MSECS_PER_DAY, cet); + } +} + +QTEST_MAIN(tst_QDateTime) + +#include "main.moc" diff --git a/tests/benchmarks/corelib/tools/qdatetime/qdatetime.pro b/tests/benchmarks/corelib/time/qdatetime/qdatetime.pro index a85e7346c6..a85e7346c6 100644 --- a/tests/benchmarks/corelib/tools/qdatetime/qdatetime.pro +++ b/tests/benchmarks/corelib/time/qdatetime/qdatetime.pro diff --git a/tests/benchmarks/corelib/tools/qtimezone/main.cpp b/tests/benchmarks/corelib/time/qtimezone/main.cpp index 65455a7261..65455a7261 100644 --- a/tests/benchmarks/corelib/tools/qtimezone/main.cpp +++ b/tests/benchmarks/corelib/time/qtimezone/main.cpp diff --git a/tests/benchmarks/corelib/tools/qtimezone/qtimezone.pro b/tests/benchmarks/corelib/time/qtimezone/qtimezone.pro index d0531b568b..d0531b568b 100644 --- a/tests/benchmarks/corelib/tools/qtimezone/qtimezone.pro +++ b/tests/benchmarks/corelib/time/qtimezone/qtimezone.pro diff --git a/tests/benchmarks/corelib/time/time.pro b/tests/benchmarks/corelib/time/time.pro new file mode 100644 index 0000000000..b5184845d9 --- /dev/null +++ b/tests/benchmarks/corelib/time/time.pro @@ -0,0 +1,5 @@ +TEMPLATE = subdirs +SUBDIRS = \ + qdate \ + qdatetime \ + qtimezone diff --git a/tests/benchmarks/corelib/tools/qdatetime/main.cpp b/tests/benchmarks/corelib/tools/qdatetime/main.cpp deleted file mode 100644 index 2c1e3d97ae..0000000000 --- a/tests/benchmarks/corelib/tools/qdatetime/main.cpp +++ /dev/null @@ -1,604 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QDateTime> -#include <QTimeZone> -#include <QTest> -#include <qdebug.h> - -class tst_QDateTime : public QObject -{ - Q_OBJECT - - enum -#if defined(Q_COMPILER_CLASS_ENUM) || (defined(Q_CC_MSVC) && _MSC_VER >= 1700) - : qint64 -#endif - { - SECS_PER_DAY = 86400, - MSECS_PER_DAY = 86400000, - JULIAN_DAY_1950 = 2433283, - JULIAN_DAY_1960 = 2436935, - JULIAN_DAY_2010 = 2455198, - JULIAN_DAY_2011 = 2455563, - JULIAN_DAY_2020 = 2458850, - JULIAN_DAY_2050 = 2469808, - JULIAN_DAY_2060 = 2473460 - }; - -private Q_SLOTS: - void create(); - void isNull(); - void isValid(); - void date(); - void time(); - void timeSpec(); - void offsetFromUtc(); - void timeZoneAbbreviation(); - void toMSecsSinceEpoch(); - void toMSecsSinceEpoch1950(); - void toMSecsSinceEpoch2050(); - void toMSecsSinceEpochTz(); - void toMSecsSinceEpoch1950Tz(); - void toMSecsSinceEpoch2050Tz(); - void setDate(); - void setTime(); - void setTimeSpec(); - void setOffsetFromUtc(); - void setMSecsSinceEpoch(); - void setMSecsSinceEpochTz(); - void toString(); - void toStringTextFormat(); - void toStringIsoFormat(); - void addDays(); - void addDaysTz(); - void addMSecs(); - void addMSecsTz(); - void toTimeSpec(); - void toOffsetFromUtc(); - void daysTo(); - void msecsTo(); - void equivalent(); - void equivalentUtc(); - void lessThan(); - void lessThanUtc(); - void currentDateTime(); - void currentDate(); - void currentTime(); - void currentDateTimeUtc(); - void currentMSecsSinceEpoch(); - void fromString(); - void fromStringText(); - void fromStringIso(); - void fromMSecsSinceEpoch(); - void fromMSecsSinceEpochUtc(); - void fromMSecsSinceEpochTz(); -}; - -void tst_QDateTime::create() -{ - QBENCHMARK { - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) { - QDateTime test(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0)); - Q_UNUSED(test) - } - } -} - -void tst_QDateTime::isNull() -{ - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0))); - QBENCHMARK { - foreach (const QDateTime &test, list) - test.isNull(); - } -} - -void tst_QDateTime::isValid() -{ - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0))); - QBENCHMARK { - foreach (const QDateTime &test, list) - test.isValid(); - } -} - -void tst_QDateTime::date() -{ - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0))); - QBENCHMARK { - foreach (const QDateTime &test, list) - test.date(); - } -} - -void tst_QDateTime::time() -{ - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0))); - QBENCHMARK { - foreach (const QDateTime &test, list) - test.time(); - } -} - -void tst_QDateTime::timeSpec() -{ - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0))); - QBENCHMARK { - foreach (const QDateTime &test, list) - test.timeSpec(); - } -} - -void tst_QDateTime::offsetFromUtc() -{ - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0))); - QBENCHMARK { - foreach (const QDateTime &test, list) - test.offsetFromUtc(); - } -} - -void tst_QDateTime::timeZoneAbbreviation() -{ - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0))); - QBENCHMARK { - foreach (const QDateTime &test, list) - test.timeZoneAbbreviation(); - } -} - -void tst_QDateTime::toMSecsSinceEpoch() -{ - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0))); - QBENCHMARK { - foreach (const QDateTime &test, list) - test.toMSecsSinceEpoch(); - } -} - -void tst_QDateTime::toMSecsSinceEpoch1950() -{ - QList<QDateTime> list; - for (int jd = JULIAN_DAY_1950; jd < JULIAN_DAY_1960; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0))); - QBENCHMARK { - foreach (const QDateTime &test, list) - test.toMSecsSinceEpoch(); - } -} - -void tst_QDateTime::toMSecsSinceEpoch2050() -{ - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2050; jd < JULIAN_DAY_2060; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0))); - QBENCHMARK { - foreach (const QDateTime &test, list) - test.toMSecsSinceEpoch(); - } -} - -void tst_QDateTime::toMSecsSinceEpochTz() -{ - QTimeZone cet = QTimeZone("Europe/Oslo"); - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0), cet)); - QBENCHMARK { - foreach (const QDateTime &test, list) - qint64 result = test.toMSecsSinceEpoch(); - } -} - -void tst_QDateTime::toMSecsSinceEpoch1950Tz() -{ - QTimeZone cet = QTimeZone("Europe/Oslo"); - QList<QDateTime> list; - for (int jd = JULIAN_DAY_1950; jd < JULIAN_DAY_1960; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0), cet)); - QBENCHMARK { - foreach (const QDateTime &test, list) - qint64 result = test.toMSecsSinceEpoch(); - } -} - -void tst_QDateTime::toMSecsSinceEpoch2050Tz() -{ - QTimeZone cet = QTimeZone("Europe/Oslo"); - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2050; jd < JULIAN_DAY_2060; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0), cet)); - QBENCHMARK { - foreach (const QDateTime &test, list) - qint64 result = test.toMSecsSinceEpoch(); - } -} - -void tst_QDateTime::setDate() -{ - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0))); - QBENCHMARK { - foreach (QDateTime test, list) - test.setDate(QDate::fromJulianDay(JULIAN_DAY_2010)); - } -} - -void tst_QDateTime::setTime() -{ - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0))); - QBENCHMARK { - foreach (QDateTime test, list) - test.setTime(QTime(12, 0, 0)); - } -} - -void tst_QDateTime::setTimeSpec() -{ - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0))); - QBENCHMARK { - foreach (QDateTime test, list) - test.setTimeSpec(Qt::UTC); - } -} - -void tst_QDateTime::setOffsetFromUtc() -{ - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0))); - QBENCHMARK { - foreach (QDateTime test, list) - test.setOffsetFromUtc(3600); - } -} - -void tst_QDateTime::setMSecsSinceEpoch() -{ - qint64 msecs = qint64(JULIAN_DAY_2010 + 180) * MSECS_PER_DAY; - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0))); - QBENCHMARK { - foreach (QDateTime test, list) - test.setMSecsSinceEpoch(msecs); - } -} - -void tst_QDateTime::setMSecsSinceEpochTz() -{ - QTimeZone cet = QTimeZone("Europe/Oslo"); - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0), cet)); - QBENCHMARK { - foreach (QDateTime test, list) - test.setMSecsSinceEpoch((JULIAN_DAY_2010 + 180) * MSECS_PER_DAY); - } -} - -void tst_QDateTime::toString() -{ - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2011; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0))); - QBENCHMARK { - foreach (const QDateTime &test, list) - test.toString(QStringLiteral("yyy-MM-dd hh:mm:ss.zzz t")); - } -} - -void tst_QDateTime::toStringTextFormat() -{ - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2011; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0))); - QBENCHMARK { - foreach (const QDateTime &test, list) - test.toString(Qt::TextDate); - } -} - -void tst_QDateTime::toStringIsoFormat() -{ - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2011; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0))); - QBENCHMARK { - foreach (const QDateTime &test, list) - test.toString(Qt::ISODate); - } -} - -void tst_QDateTime::addDays() -{ - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0))); - QBENCHMARK { - foreach (const QDateTime &test, list) - test.addDays(1); - } -} - -void tst_QDateTime::addDaysTz() -{ - QTimeZone cet = QTimeZone("Europe/Oslo"); - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0), cet)); - QBENCHMARK { - foreach (const QDateTime &test, list) - QDateTime result = test.addDays(1); - } -} - -void tst_QDateTime::addMSecs() -{ - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0))); - QBENCHMARK { - foreach (const QDateTime &test, list) - test.addMSecs(1); - } -} - -void tst_QDateTime::addMSecsTz() -{ - QTimeZone cet = QTimeZone("Europe/Oslo"); - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0), cet)); - QBENCHMARK { - foreach (const QDateTime &test, list) - QDateTime result = test.addMSecs(1); - } -} - -void tst_QDateTime::toTimeSpec() -{ - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0))); - QBENCHMARK { - foreach (const QDateTime &test, list) - test.toTimeSpec(Qt::UTC); - } -} - -void tst_QDateTime::toOffsetFromUtc() -{ - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0))); - QBENCHMARK { - foreach (const QDateTime &test, list) - test.toOffsetFromUtc(3600); - } -} - -void tst_QDateTime::daysTo() -{ - QDateTime other = QDateTime::fromMSecsSinceEpoch(qint64(JULIAN_DAY_2010) * MSECS_PER_DAY); - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0))); - QBENCHMARK { - foreach (const QDateTime &test, list) - test.daysTo(other); - } -} - -void tst_QDateTime::msecsTo() -{ - QDateTime other = QDateTime::fromMSecsSinceEpoch(qint64(JULIAN_DAY_2010) * MSECS_PER_DAY); - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0))); - QBENCHMARK { - foreach (const QDateTime &test, list) - test.msecsTo(other); - } -} - -void tst_QDateTime::equivalent() -{ - bool result; - QDateTime other = QDateTime::fromMSecsSinceEpoch(qint64(JULIAN_DAY_2010) * MSECS_PER_DAY); - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0))); - QBENCHMARK { - foreach (const QDateTime &test, list) - result = (test == other); - } - Q_UNUSED(result) -} - -void tst_QDateTime::equivalentUtc() -{ - bool result = false; - QDateTime other = QDateTime::fromMSecsSinceEpoch(qint64(JULIAN_DAY_2010) * MSECS_PER_DAY, Qt::UTC); - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0))); - QBENCHMARK { - foreach (const QDateTime &test, list) - result = (test == other); - } - Q_UNUSED(result) -} - -void tst_QDateTime::lessThan() -{ - bool result = false; - QDateTime other = QDateTime::fromMSecsSinceEpoch(qint64(JULIAN_DAY_2010) * MSECS_PER_DAY); - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0))); - QBENCHMARK { - foreach (const QDateTime &test, list) - result = (test < other); - } - Q_UNUSED(result) -} - -void tst_QDateTime::lessThanUtc() -{ - bool result = false; - QDateTime other = QDateTime::fromMSecsSinceEpoch(qint64(JULIAN_DAY_2010) * MSECS_PER_DAY, Qt::UTC); - QList<QDateTime> list; - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - list.append(QDateTime(QDate::fromJulianDay(jd), QTime::fromMSecsSinceStartOfDay(0))); - QBENCHMARK { - foreach (const QDateTime &test, list) - result = (test < other); - } - Q_UNUSED(result) -} - -void tst_QDateTime::currentDateTime() -{ - QBENCHMARK { - for (int i = 0; i < 1000; ++i) - QDateTime::currentDateTime(); - } -} - -void tst_QDateTime::currentDate() -{ - QBENCHMARK { - for (int i = 0; i < 1000; ++i) - QDate::currentDate(); - } -} - -void tst_QDateTime::currentTime() -{ - QBENCHMARK { - for (int i = 0; i < 1000; ++i) - QTime::currentTime(); - } -} - -void tst_QDateTime::currentDateTimeUtc() -{ - QBENCHMARK { - for (int i = 0; i < 1000; ++i) - QDateTime::currentDateTimeUtc(); - } -} - -void tst_QDateTime::currentMSecsSinceEpoch() -{ - QBENCHMARK { - for (int i = 0; i < 1000; ++i) - QDateTime::currentMSecsSinceEpoch(); - } -} - -void tst_QDateTime::fromString() -{ - QString format = "yyyy-MM-dd hh:mm:ss.zzz"; - QString input = "2010-01-01 13:12:11.999"; - QVERIFY(QDateTime::fromString(input, format).isValid()); - QBENCHMARK { - for (int i = 0; i < 1000; ++i) - QDateTime::fromString(input, format); - } -} - -void tst_QDateTime::fromStringText() -{ - QString input = "Wed Jan 2 01:02:03.000 2013 GMT"; - QBENCHMARK { - for (int i = 0; i < 1000; ++i) - QDateTime::fromString(input, Qt::TextDate); - } -} - -void tst_QDateTime::fromStringIso() -{ - QString input = "2010-01-01T13:28:34.999Z"; - QBENCHMARK { - for (int i = 0; i < 1000; ++i) - QDateTime::fromString(input, Qt::ISODate); - } -} - -void tst_QDateTime::fromMSecsSinceEpoch() -{ - QBENCHMARK { - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - QDateTime::fromMSecsSinceEpoch(jd * MSECS_PER_DAY, Qt::LocalTime); - } -} - -void tst_QDateTime::fromMSecsSinceEpochUtc() -{ - QBENCHMARK { - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - QDateTime::fromMSecsSinceEpoch(jd * MSECS_PER_DAY, Qt::UTC); - } -} - -void tst_QDateTime::fromMSecsSinceEpochTz() -{ - QTimeZone cet = QTimeZone("Europe/Oslo"); - QBENCHMARK { - for (int jd = JULIAN_DAY_2010; jd < JULIAN_DAY_2020; ++jd) - QDateTime test = QDateTime::fromMSecsSinceEpoch(jd * MSECS_PER_DAY, cet); - } -} - -QTEST_MAIN(tst_QDateTime) - -#include "main.moc" diff --git a/tests/benchmarks/corelib/tools/qhash/paths_small_data.txt b/tests/benchmarks/corelib/tools/qhash/paths_small_data.txt index d5acd28820..662285296f 100644 --- a/tests/benchmarks/corelib/tools/qhash/paths_small_data.txt +++ b/tests/benchmarks/corelib/tools/qhash/paths_small_data.txt @@ -47,13 +47,38 @@ ./codecs/.obj/debug-shared ./.pch ./.pch/debug-shared +./text +./text/text.pro +./text/qregexp +./text/qregexp/qregexp.qrc +./text/qregexp/main.cpp +./text/qregexp/Makefile +./text/qregexp/qregexp.pro +./text/qstringbuilder +./text/qstringbuilder/main.cpp +./text/qstringbuilder/Makefile +./text/qstringbuilder/qstringbuilder.pro +./text/qstring +./text/qstring/generatelist.pl +./text/qstring/data.h +./text/qstring/qstring.pro +./text/qstring/main.cpp +./text/qstring/data.cpp +./text/qstring/Makefile +./text/qstring/utf-8.txt +./text/qstringlist +./text/qstringlist/qstringlist.pro +./text/qstringlist/main.cpp +./text/qstringlist/.gitignore +./text/qstringlist/Makefile +./text/qbytearray +./text/qbytearray/qbytearray.pro +./text/qbytearray/main.cpp +./text/qbytearray/Makefile +./text/.pch +./text/.pch/debug-shared ./tools ./tools/tools.pro -./tools/qregexp -./tools/qregexp/qregexp.qrc -./tools/qregexp/main.cpp -./tools/qregexp/Makefile -./tools/qregexp/qregexp.pro ./tools/qvector ./tools/qvector/tst_vector ./tools/qvector/.pch @@ -72,31 +97,10 @@ ./tools/qvector/qvector.pro ./tools/.pch ./tools/.pch/debug-shared -./tools/qstringbuilder -./tools/qstringbuilder/main.cpp -./tools/qstringbuilder/Makefile -./tools/qstringbuilder/qstringbuilder.pro ./tools/containers-sequential ./tools/containers-sequential/containers-sequential.pro ./tools/containers-sequential/main.cpp ./tools/containers-sequential/Makefile -./tools/qstring -./tools/qstring/generatelist.pl -./tools/qstring/data.h -./tools/qstring/qstring.pro -./tools/qstring/main.cpp -./tools/qstring/data.cpp -./tools/qstring/Makefile -./tools/qstring/utf-8.txt -./tools/qstringlist -./tools/qstringlist/qstringlist.pro -./tools/qstringlist/main.cpp -./tools/qstringlist/.gitignore -./tools/qstringlist/Makefile -./tools/qbytearray -./tools/qbytearray/qbytearray.pro -./tools/qbytearray/main.cpp -./tools/qbytearray/Makefile ./tools/containers-associative ./tools/containers-associative/containers-associative.pro ./tools/containers-associative/main.cpp diff --git a/tests/benchmarks/corelib/tools/qvector/qrawvector.h b/tests/benchmarks/corelib/tools/qvector/qrawvector.h index c7173b5b8d..16a911c63a 100644 --- a/tests/benchmarks/corelib/tools/qvector/qrawvector.h +++ b/tests/benchmarks/corelib/tools/qvector/qrawvector.h @@ -32,7 +32,6 @@ #include <QtCore/qiterator.h> #include <QtCore/qdebug.h> #include <QtCore/qatomic.h> -#include <QtCore/qalgorithms.h> #include <QtCore/qlist.h> #include <QtCore/private/qtools_p.h> @@ -263,9 +262,9 @@ public: //static QRawVector<T> fromList(const QList<T> &list); static inline QRawVector<T> fromStdVector(const std::vector<T> &vector) - { QRawVector<T> tmp; qCopy(vector.begin(), vector.end(), std::back_inserter(tmp)); return tmp; } + { QRawVector<T> tmp; std::copy(vector.begin(), vector.end(), std::back_inserter(tmp)); return tmp; } inline std::vector<T> toStdVector() const - { std::vector<T> tmp; qCopy(constBegin(), constEnd(), std::back_inserter(tmp)); return tmp; } + { std::vector<T> tmp; std::copy(constBegin(), constEnd(), std::back_inserter(tmp)); return tmp; } private: T *allocate(int alloc); @@ -568,7 +567,7 @@ typename QRawVector<T>::iterator QRawVector<T>::erase(iterator abegin, iterator int l = int(aend - m_begin); int n = l - f; if (QTypeInfo<T>::isComplex) { - qCopy(m_begin + l, m_begin + m_size, m_begin + f); + std::copy(m_begin + l, m_begin + m_size, m_begin + f); T *i = m_begin + m_size; T *b = m_begin + m_size - n; while (i != b) { diff --git a/tests/benchmarks/corelib/tools/tools.pro b/tests/benchmarks/corelib/tools/tools.pro index ca9c0a6f89..b4ee0520a6 100644 --- a/tests/benchmarks/corelib/tools/tools.pro +++ b/tests/benchmarks/corelib/tools/tools.pro @@ -2,21 +2,12 @@ TEMPLATE = subdirs SUBDIRS = \ containers-associative \ containers-sequential \ - qbytearray \ qcontiguouscache \ qcryptographichash \ - qdatetime \ qlist \ - qlocale \ qmap \ qrect \ qringbuffer \ qstack \ - qstring \ - qstringbuilder \ - qstringlist \ - qtimezone \ qvector \ qalgorithms - -!*g++*: SUBDIRS -= qstring diff --git a/tests/benchmarks/gui/image/qimageconversion/tst_qimageconversion.cpp b/tests/benchmarks/gui/image/qimageconversion/tst_qimageconversion.cpp index 605df100ee..b8afb3bc05 100644 --- a/tests/benchmarks/gui/image/qimageconversion/tst_qimageconversion.cpp +++ b/tests/benchmarks/gui/image/qimageconversion/tst_qimageconversion.cpp @@ -183,6 +183,7 @@ void tst_QImageConversion::convertRgb32_data() QTest::newRow("rgb32 -> rgb30") << rgb32 << QImage::Format_RGB30; QTest::newRow("rgb32 -> a2bgr30") << rgb32 << QImage::Format_A2BGR30_Premultiplied; QTest::newRow("rgb32 -> rgb888") << rgb32 << QImage::Format_RGB888; + QTest::newRow("rgb32 -> bgr888") << rgb32 << QImage::Format_BGR888; QTest::newRow("rgb32 -> rgb666") << rgb32 << QImage::Format_RGB666; QTest::newRow("rgb32 -> rgb555") << rgb32 << QImage::Format_RGB555; QTest::newRow("rgb32 -> argb8565pm") << rgb32 << QImage::Format_ARGB8565_Premultiplied; @@ -196,6 +197,7 @@ void tst_QImageConversion::convertRgb32_data() QTest::newRow("argb32 -> rgb30") << argb32 << QImage::Format_RGB30; QTest::newRow("argb32 -> a2bgr30") << argb32 << QImage::Format_A2BGR30_Premultiplied; QTest::newRow("argb32 -> rgb888") << argb32 << QImage::Format_RGB888; + QTest::newRow("argb32 -> bgr888") << argb32 << QImage::Format_BGR888; QTest::newRow("argb32 -> rgb666") << argb32 << QImage::Format_RGB666; QTest::newRow("argb32 -> argb8565pm") << argb32 << QImage::Format_ARGB8565_Premultiplied; QTest::newRow("argb32 -> argb4444pm") << argb32 << QImage::Format_ARGB4444_Premultiplied; @@ -212,6 +214,7 @@ void tst_QImageConversion::convertRgb32_data() QTest::newRow("argb32pm -> rgb30") << argb32pm << QImage::Format_RGB30; QTest::newRow("argb32pm -> a2bgr30") << argb32pm << QImage::Format_A2BGR30_Premultiplied; QTest::newRow("argb32pm -> rgb888") << argb32pm << QImage::Format_RGB888; + QTest::newRow("argb32pm -> bgr888") << argb32pm << QImage::Format_BGR888; QTest::newRow("argb32pm -> rgb666") << argb32pm << QImage::Format_RGB666; QTest::newRow("argb32pm -> argb8565pm") << argb32pm << QImage::Format_ARGB8565_Premultiplied; QTest::newRow("argb32pm -> argb4444pm") << argb32pm << QImage::Format_ARGB4444_Premultiplied; @@ -242,6 +245,8 @@ void tst_QImageConversion::convertGeneric_data() QImage rgb666 = rgb32.convertToFormat(QImage::Format_RGB666); QImage argb4444 = argb32.convertToFormat(QImage::Format_ARGB4444_Premultiplied); QImage rgba64pm = argb32.convertToFormat(QImage::Format_RGBA64_Premultiplied); + QImage rgb888 = rgb32.convertToFormat(QImage::Format_RGB888); + QImage bgr888 = rgb32.convertToFormat(QImage::Format_BGR888); QTest::newRow("indexed8 -> rgb32") << i8 << QImage::Format_RGB32; QTest::newRow("indexed8 -> argb32") << i8 << QImage::Format_ARGB32; @@ -299,6 +304,20 @@ void tst_QImageConversion::convertGeneric_data() QTest::newRow("rgba64pm -> rgb30") << rgba64pm << QImage::Format_RGB30; QTest::newRow("rgba64pm -> a2bgr30") << rgba64pm << QImage::Format_A2BGR30_Premultiplied; QTest::newRow("rgba64pm -> rgba64") << rgba64pm << QImage::Format_RGBA64; + + QTest::newRow("rgb888 -> rgb32") << rgb888 << QImage::Format_RGB32; + QTest::newRow("rgb888 -> argb32") << rgb888 << QImage::Format_ARGB32; + QTest::newRow("rgb888 -> argb32pm") << rgb888 << QImage::Format_ARGB32_Premultiplied; + QTest::newRow("rgb888 -> rgbx8888") << rgb888 << QImage::Format_RGBX8888; + QTest::newRow("rgb888 -> rgba8888pm") << rgb888 << QImage::Format_RGBA8888_Premultiplied; + QTest::newRow("rgb888 -> bgr888") << rgb888 << QImage::Format_BGR888; + + QTest::newRow("bgr888 -> rgb32") << bgr888 << QImage::Format_RGB32; + QTest::newRow("bgr888 -> argb32") << bgr888 << QImage::Format_ARGB32; + QTest::newRow("bgr888 -> argb32pm") << bgr888 << QImage::Format_ARGB32_Premultiplied; + QTest::newRow("bgr888 -> rgbx8888") << bgr888 << QImage::Format_RGBX8888; + QTest::newRow("bgr888 -> rgba8888pm") << bgr888 << QImage::Format_RGBA8888_Premultiplied; + QTest::newRow("bgr888 -> rgb888") << bgr888 << QImage::Format_RGB888; } void tst_QImageConversion::convertGeneric() @@ -323,6 +342,8 @@ void tst_QImageConversion::convertGenericInplace_data() QImage argb6666 = argb32.convertToFormat(QImage::Format_ARGB6666_Premultiplied); QImage argb4444 = argb32.convertToFormat(QImage::Format_ARGB4444_Premultiplied); QImage rgb16 = argb32.convertToFormat(QImage::Format_RGB16); + QImage rgb30 = argb32.convertToFormat(QImage::Format_RGB30); + QImage rgb888 = argb32.convertToFormat(QImage::Format_RGB888); QTest::newRow("argb32 -> argb32pm -> argb32") << argb32 << QImage::Format_ARGB32_Premultiplied; QTest::newRow("argb32 -> rgb32 -> argb32") << argb32 << QImage::Format_RGB32; @@ -349,6 +370,9 @@ void tst_QImageConversion::convertGenericInplace_data() QTest::newRow("rgb16 -> rgb555 -> rgb16") << rgb16 << QImage::Format_RGB555; QTest::newRow("rgb16 -> rgb444 -> rgb16") << rgb16 << QImage::Format_RGB444; QTest::newRow("rgb16 -> argb4444pm -> rgb16") << rgb16 << QImage::Format_ARGB4444_Premultiplied; + + QTest::newRow("rgb30 -> bgr30 -> rgb30") << rgb30 << QImage::Format_BGR30; + QTest::newRow("rgb888 -> bgr888 -> rgb888") << rgb888 << QImage::Format_BGR888; } void tst_QImageConversion::convertGenericInplace() @@ -357,10 +381,10 @@ void tst_QImageConversion::convertGenericInplace() QFETCH(QImage::Format, outputFormat); QImage::Format inputFormat = inputImage.format(); - QImage tmpImage = qMove(inputImage); + QImage tmpImage = std::move(inputImage); QBENCHMARK { - tmpImage = (qMove(tmpImage).convertToFormat(outputFormat)).convertToFormat(inputFormat); + tmpImage = (std::move(tmpImage).convertToFormat(outputFormat)).convertToFormat(inputFormat); } } diff --git a/tests/benchmarks/gui/image/qimagereader/qimagereader.pro b/tests/benchmarks/gui/image/qimagereader/qimagereader.pro index 29f7f6b16e..3454cf1474 100644 --- a/tests/benchmarks/gui/image/qimagereader/qimagereader.pro +++ b/tests/benchmarks/gui/image/qimagereader/qimagereader.pro @@ -8,3 +8,5 @@ SOURCES += tst_qimagereader.cpp qtConfig(gif): DEFINES += QTEST_HAVE_GIF qtConfig(jpeg): DEFINES += QTEST_HAVE_JPEG + +TESTDATA += images/* diff --git a/tests/benchmarks/gui/image/qimagereader/tst_qimagereader.cpp b/tests/benchmarks/gui/image/qimagereader/tst_qimagereader.cpp index d81d5bb01a..48e838148f 100644 --- a/tests/benchmarks/gui/image/qimagereader/tst_qimagereader.cpp +++ b/tests/benchmarks/gui/image/qimagereader/tst_qimagereader.cpp @@ -51,6 +51,7 @@ public: virtual ~tst_QImageReader(); public slots: + void initTestCase(); void init(); void cleanup(); @@ -69,6 +70,7 @@ private slots: private: QList< QPair<QString, QByteArray> > images; // filename, format + QString prefix; }; tst_QImageReader::tst_QImageReader() @@ -102,6 +104,13 @@ tst_QImageReader::~tst_QImageReader() { } +void tst_QImageReader::initTestCase() +{ + prefix = QFINDTESTDATA("images/"); + if (prefix.isEmpty()) + QFAIL("Can't find images directory!"); +} + void tst_QImageReader::init() { } @@ -128,7 +137,7 @@ void tst_QImageReader::readImage() QFETCH(QByteArray, format); QBENCHMARK { - QImageReader io("images/" + fileName, format); + QImageReader io(prefix + fileName, format); QImage image = io.read(); QVERIFY(!image.isNull()); } @@ -159,7 +168,7 @@ void tst_QImageReader::setScaledSize() QFETCH(QByteArray, format); QBENCHMARK { - QImageReader reader("images/" + fileName, format); + QImageReader reader(prefix + fileName, format); reader.setScaledSize(newSize); QImage image = reader.read(); QCOMPARE(image.size(), newSize); @@ -186,7 +195,7 @@ void tst_QImageReader::setClipRect() QFETCH(QByteArray, format); QBENCHMARK { - QImageReader reader("images/" + fileName, format); + QImageReader reader(prefix + fileName, format); reader.setClipRect(newRect); QImage image = reader.read(); QCOMPARE(image.rect(), newRect); @@ -205,7 +214,7 @@ void tst_QImageReader::setScaledClipRect() QFETCH(QByteArray, format); QBENCHMARK { - QImageReader reader("images/" + fileName, format); + QImageReader reader(prefix + fileName, format); reader.setScaledSize(QSize(300, 300)); reader.setScaledClipRect(newRect); QImage image = reader.read(); diff --git a/tests/benchmarks/gui/image/qpixmapcache/tst_qpixmapcache.cpp b/tests/benchmarks/gui/image/qpixmapcache/tst_qpixmapcache.cpp index d4be85b5ad..2ded426cdd 100644 --- a/tests/benchmarks/gui/image/qpixmapcache/tst_qpixmapcache.cpp +++ b/tests/benchmarks/gui/image/qpixmapcache/tst_qpixmapcache.cpp @@ -106,7 +106,7 @@ void tst_QPixmapCache::find() if (cacheType) { QBENCHMARK { for (int i = 0 ; i <= 10000 ; i++) - QPixmapCache::find(QString::asprintf("my-key-%d", i), p); + QPixmapCache::find(QString::asprintf("my-key-%d", i), &p); } } else { QBENCHMARK { @@ -155,7 +155,7 @@ void tst_QPixmapCache::styleUseCaseComplexKey() QPixmapCache::insert(QString::asprintf("%s-%d-%d-%d-%d-%d-%d", QString("my-progressbar-%1").arg(i).toLatin1().constData(), 5, 3, 0, 358, 100, 200), p); for (int i = 0 ; i <= 10000 ; i++) - QPixmapCache::find(QString::asprintf("%s-%d-%d-%d-%d-%d-%d", QString("my-progressbar-%1").arg(i).toLatin1().constData(), 5, 3, 0, 358, 100, 200), p); + QPixmapCache::find(QString::asprintf("%s-%d-%d-%d-%d-%d-%d", QString("my-progressbar-%1").arg(i).toLatin1().constData(), 5, 3, 0, 358, 100, 200), &p); } } else { QHash<styleStruct, QPixmapCache::Key> hash; diff --git a/tests/benchmarks/gui/painting/qtransform/tst_qtransform.cpp b/tests/benchmarks/gui/painting/qtransform/tst_qtransform.cpp index d7a7f383ac..12e85d4842 100644 --- a/tests/benchmarks/gui/painting/qtransform/tst_qtransform.cpp +++ b/tests/benchmarks/gui/painting/qtransform/tst_qtransform.cpp @@ -167,9 +167,7 @@ void tst_QTransform::func##_data() \ { \ QTest::addColumn<QTransform>("transform"); \ QMap<const char *, QTransform> x = generateTransforms(); \ - QMapIterator<const char *, QTransform> it(x); \ - while (it.hasNext()) { \ - it.next(); \ + for (auto it = x.begin(), end = x.end(); it != end; ++it) { \ QTest::newRow(it.key()) << it.value(); \ } \ } @@ -180,14 +178,10 @@ void tst_QTransform::func##_data() \ QTest::addColumn<QTransform>("x1"); \ QTest::addColumn<QTransform>("x2"); \ QMap<const char *, QTransform> x = generateTransforms(); \ - QMapIterator<const char *, QTransform> it(x); \ - while (it.hasNext()) { \ - it.next(); \ + for (auto it = x.cbegin(), end = x.cend(); it != end; ++it) { \ const char *key1 = it.key(); \ QTransform x1 = it.value(); \ - QMapIterator<const char *, QTransform> it2(x); \ - while (it2.hasNext()) { \ - it2.next(); \ + for (auto it2 = x.cbegin(), end = x.cend(); it2 != end; ++it2) { \ QTest::newRow(QString("%1 + %2").arg(key1).arg(it2.key()).toLatin1().constData()) \ << x1 << it2.value(); \ } \ diff --git a/tests/benchmarks/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/benchmarks/network/access/qnetworkreply/tst_qnetworkreply.cpp index b2f4cbd7ba..c182ef7ebf 100644 --- a/tests/benchmarks/network/access/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/benchmarks/network/access/qnetworkreply/tst_qnetworkreply.cpp @@ -908,7 +908,7 @@ void tst_qnetworkreply::httpsRequestChain() qint64 average = (elapsed / count); - qSort(helper.timeList); + std::sort(helper.timeList.begin(), helper.timeList.end()); qint64 median = helper.timeList.at(5); qDebug() << "Total:" << elapsed << " Average:" << average << " Median:" << median; diff --git a/tests/benchmarks/opengl/main.cpp b/tests/benchmarks/opengl/main.cpp index 5008f1592b..0886c0e55b 100644 --- a/tests/benchmarks/opengl/main.cpp +++ b/tests/benchmarks/opengl/main.cpp @@ -76,7 +76,6 @@ void OpenGLBench::initTestCase() QPainter p(pb); p.setRenderHint(QPainter::Antialiasing); - p.setRenderHint(QPainter::HighQualityAntialiasing); p.drawImage(0, 0, QImage(256, 256, QImage::Format_ARGB32_Premultiplied)); } @@ -120,7 +119,6 @@ void OpenGLBench::imageDrawing() QPainter p(pb); p.setRenderHint(QPainter::SmoothPixmapTransform, smoothPixmapTransform); p.setRenderHint(QPainter::Antialiasing, highQualityAntialiasing); - p.setRenderHint(QPainter::HighQualityAntialiasing, highQualityAntialiasing); QBENCHMARK { if (pixmap) { @@ -182,7 +180,6 @@ void OpenGLBench::pathDrawing() dummy.addRect(-1, -1, 2, 2); QPainter p(pb); p.setRenderHint(QPainter::Antialiasing, highQualityAntialiasing); - p.setRenderHint(QPainter::HighQualityAntialiasing, highQualityAntialiasing); p.translate(pb->width() / 2, pb->height() / 2); p.rotate(30); p.drawPath(dummy); @@ -196,7 +193,6 @@ void OpenGLBench::pathDrawing() QBENCHMARK { p.setRenderHint(QPainter::Antialiasing, highQualityAntialiasing); - p.setRenderHint(QPainter::HighQualityAntialiasing, highQualityAntialiasing); p.rotate(0.01); p.drawPath(path); @@ -227,7 +223,6 @@ void OpenGLBench::startupCost() QGLPixelBuffer buffer(512, 512); QPainter p(&buffer); p.setRenderHint(QPainter::Antialiasing, highQualityAntialiasing); - p.setRenderHint(QPainter::HighQualityAntialiasing, highQualityAntialiasing); p.translate(buffer.width() / 2, buffer.height() / 2); p.drawPath(path); diff --git a/tests/benchmarks/widgets/graphicsview/functional/GraphicsViewBenchmark/widgets/mainview.cpp b/tests/benchmarks/widgets/graphicsview/functional/GraphicsViewBenchmark/widgets/mainview.cpp index c8ccb60dbb..8f7736010d 100644 --- a/tests/benchmarks/widgets/graphicsview/functional/GraphicsViewBenchmark/widgets/mainview.cpp +++ b/tests/benchmarks/widgets/graphicsview/functional/GraphicsViewBenchmark/widgets/mainview.cpp @@ -270,7 +270,6 @@ void MainView::construct() // Turn off automatic background setAttribute(Qt::WA_OpaquePaintEvent); - setAttribute(Qt::WA_NoBackground); setAttribute(Qt::WA_NoSystemBackground); setAutoFillBackground(false); diff --git a/tests/benchmarks/widgets/graphicsview/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp b/tests/benchmarks/widgets/graphicsview/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp index b15aad04cd..e0c5a7f683 100644 --- a/tests/benchmarks/widgets/graphicsview/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp +++ b/tests/benchmarks/widgets/graphicsview/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp @@ -60,7 +60,7 @@ public: { Q_UNUSED(option); Q_UNUSED(widget); - painter->drawRoundRect(rect()); + painter->drawRoundedRect(rect(), 25, 25, Qt::RelativeSize); painter->drawLine(rect().topLeft(), rect().bottomRight()); painter->drawLine(rect().bottomLeft(), rect().topRight()); } diff --git a/tests/benchmarks/widgets/graphicsview/qgraphicslayout/tst_qgraphicslayout.cpp b/tests/benchmarks/widgets/graphicsview/qgraphicslayout/tst_qgraphicslayout.cpp index 5c97d7f738..caf5455a80 100644 --- a/tests/benchmarks/widgets/graphicsview/qgraphicslayout/tst_qgraphicslayout.cpp +++ b/tests/benchmarks/widgets/graphicsview/qgraphicslayout/tst_qgraphicslayout.cpp @@ -53,7 +53,7 @@ public: { Q_UNUSED(option); Q_UNUSED(widget); - painter->drawRoundRect(rect()); + painter->drawRoundedRect(rect(), 25, 25, Qt::RelativeSize); painter->drawLine(rect().topLeft(), rect().bottomRight()); painter->drawLine(rect().bottomLeft(), rect().topRight()); } diff --git a/tests/benchmarks/widgets/graphicsview/qgraphicsview/benchapps/chipTest/chip.cpp b/tests/benchmarks/widgets/graphicsview/qgraphicsview/benchapps/chipTest/chip.cpp index 57ab62b1c3..2277ae0f14 100644 --- a/tests/benchmarks/widgets/graphicsview/qgraphicsview/benchapps/chipTest/chip.cpp +++ b/tests/benchmarks/widgets/graphicsview/qgraphicsview/benchapps/chipTest/chip.cpp @@ -38,7 +38,7 @@ Chip::Chip(const QColor &color, int x, int y) setZValue((x + y) % 2); setFlags(ItemIsSelectable | ItemIsMovable); - setAcceptsHoverEvents(true); + setAcceptHoverEvents(true); } QRectF Chip::boundingRect() const diff --git a/tests/benchmarks/widgets/graphicsview/qgraphicsview/benchapps/chipTest/view.cpp b/tests/benchmarks/widgets/graphicsview/qgraphicsview/benchapps/chipTest/view.cpp index de4e9e5ad7..6e0ac445a6 100644 --- a/tests/benchmarks/widgets/graphicsview/qgraphicsview/benchapps/chipTest/view.cpp +++ b/tests/benchmarks/widgets/graphicsview/qgraphicsview/benchapps/chipTest/view.cpp @@ -30,12 +30,7 @@ #include <QtGui> -#if 0 // Used to be included in Qt4 for Q_WS_WIN -#define CALLGRIND_START_INSTRUMENTATION {} -#define CALLGRIND_STOP_INSTRUMENTATION {} -#else #include "valgrind/callgrind.h" -#endif #ifndef QT_NO_OPENGL #include <QtOpenGL> diff --git a/tests/benchmarks/widgets/graphicsview/qgraphicsview/benchapps/moveItems/main.cpp b/tests/benchmarks/widgets/graphicsview/qgraphicsview/benchapps/moveItems/main.cpp index e0cc0f8eb4..140278b8f6 100644 --- a/tests/benchmarks/widgets/graphicsview/qgraphicsview/benchapps/moveItems/main.cpp +++ b/tests/benchmarks/widgets/graphicsview/qgraphicsview/benchapps/moveItems/main.cpp @@ -27,16 +27,7 @@ ****************************************************************************/ #include <QtGui> -#if 0 // Used to be included in Qt4 for Q_WS_WIN -#define CALLGRIND_START_INSTRUMENTATION {} -#define CALLGRIND_STOP_INSTRUMENTATION {} -#else #include "valgrind/callgrind.h" -#endif - -#if 0 // Used to be included in Qt4 for Q_WS_X11 -extern void qt_x11_wait_for_window_manager(QWidget *); -#endif class View : public QGraphicsView { @@ -89,9 +80,6 @@ int main(int argc, char *argv[]) View view(&scene, item); view.resize(300, 300); view.show(); -#if 0 // Used to be included in Qt4 for Q_WS_X11 - qt_x11_wait_for_window_manager(&view); -#endif return app.exec(); } diff --git a/tests/benchmarks/widgets/graphicsview/qgraphicsview/benchapps/scrolltest/main.cpp b/tests/benchmarks/widgets/graphicsview/qgraphicsview/benchapps/scrolltest/main.cpp index 1fbb229cd8..566d16ca51 100644 --- a/tests/benchmarks/widgets/graphicsview/qgraphicsview/benchapps/scrolltest/main.cpp +++ b/tests/benchmarks/widgets/graphicsview/qgraphicsview/benchapps/scrolltest/main.cpp @@ -27,12 +27,7 @@ ****************************************************************************/ #include <QtGui> -#if 0 // Used to be included in Qt4 for Q_WS_WIN -#define CALLGRIND_START_INSTRUMENTATION {} -#define CALLGRIND_STOP_INSTRUMENTATION {} -#else #include "valgrind/callgrind.h" -#endif class ItemMover : public QObject { diff --git a/tests/benchmarks/widgets/graphicsview/qgraphicsview/chiptester/chip.cpp b/tests/benchmarks/widgets/graphicsview/qgraphicsview/chiptester/chip.cpp index cf82282bfe..21eb622f15 100644 --- a/tests/benchmarks/widgets/graphicsview/qgraphicsview/chiptester/chip.cpp +++ b/tests/benchmarks/widgets/graphicsview/qgraphicsview/chiptester/chip.cpp @@ -57,9 +57,9 @@ void Chip::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWid { Q_UNUSED(widget); - QColor fillColor = (option->state & QStyle::State_Selected) ? color.dark(150) : color; + QColor fillColor = (option->state & QStyle::State_Selected) ? color.darker(150) : color; if (option->state & QStyle::State_MouseOver) - fillColor = fillColor.light(125); + fillColor = fillColor.lighter(125); if (option->levelOfDetail < 0.2) { if (option->levelOfDetail < 0.125) { @@ -82,7 +82,7 @@ void Chip::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWid pen.setWidth(width); QBrush b = painter->brush(); - painter->setBrush(QBrush(fillColor.dark(option->state & QStyle::State_Sunken ? 120 : 100))); + painter->setBrush(QBrush(fillColor.darker(option->state & QStyle::State_Sunken ? 120 : 100))); painter->drawRect(QRect(14, 14, 79, 39)); painter->setBrush(b); diff --git a/tests/libfuzzer/corelib/serialization/qxmlstream/qxmlstreamreader/readnext/main.cpp b/tests/libfuzzer/corelib/serialization/qxmlstream/qxmlstreamreader/readnext/main.cpp index 5a60c78cb5..7b73e6e952 100644 --- a/tests/libfuzzer/corelib/serialization/qxmlstream/qxmlstreamreader/readnext/main.cpp +++ b/tests/libfuzzer/corelib/serialization/qxmlstream/qxmlstreamreader/readnext/main.cpp @@ -29,7 +29,7 @@ #include <QXmlStreamReader> extern "C" int LLVMFuzzerTestOneInput(const char *Data, size_t Size) { - QXmlStreamReader reader(QByteArray(Data, Size)); + QXmlStreamReader reader(QByteArray::fromRawData(Data, Size)); while (!reader.atEnd()) reader.readNext(); return 0; diff --git a/tests/libfuzzer/gui/iccparser/iccparser.pro b/tests/libfuzzer/gui/iccparser/iccparser.pro new file mode 100644 index 0000000000..bf4037eae7 --- /dev/null +++ b/tests/libfuzzer/gui/iccparser/iccparser.pro @@ -0,0 +1,3 @@ +QT += gui +SOURCES += main.cpp +LIBS += -fsanitize=fuzzer diff --git a/tests/libfuzzer/gui/iccparser/main.cpp b/tests/libfuzzer/gui/iccparser/main.cpp new file mode 100644 index 0000000000..1db43d2e25 --- /dev/null +++ b/tests/libfuzzer/gui/iccparser/main.cpp @@ -0,0 +1,37 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QGuiApplication> +#include <QColorSpace> + +extern "C" int LLVMFuzzerTestOneInput(const char *data, size_t size) { + static int c = 0; + static QGuiApplication a(c, nullptr); + QColorSpace cs = QColorSpace::fromIccProfile(QByteArray::fromRawData(data, size)); + return 0; +} diff --git a/tests/libfuzzer/gui/text/qtextdocument/setHtml/main.cpp b/tests/libfuzzer/gui/text/qtextdocument/setHtml/main.cpp index c9b33d0f88..51fa3c9e0f 100644 --- a/tests/libfuzzer/gui/text/qtextdocument/setHtml/main.cpp +++ b/tests/libfuzzer/gui/text/qtextdocument/setHtml/main.cpp @@ -32,6 +32,6 @@ extern "C" int LLVMFuzzerTestOneInput(const char *Data, size_t Size) { static int c = 0; static QApplication a(c, nullptr); - QTextDocument().setHtml(QByteArray(Data, Size)); + QTextDocument().setHtml(QByteArray::fromRawData(Data, Size)); return 0; } diff --git a/tests/libfuzzer/gui/text/qtextdocument/setMarkdown/main.cpp b/tests/libfuzzer/gui/text/qtextdocument/setMarkdown/main.cpp new file mode 100644 index 0000000000..66ddf738f2 --- /dev/null +++ b/tests/libfuzzer/gui/text/qtextdocument/setMarkdown/main.cpp @@ -0,0 +1,34 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QTextDocument> + +extern "C" int LLVMFuzzerTestOneInput(const char *Data, size_t Size) { + QTextDocument().setMarkdown(QByteArray::fromRawData(Data, Size)); + return 0; +} diff --git a/tests/libfuzzer/gui/text/qtextdocument/setMarkdown/setMarkdown.pro b/tests/libfuzzer/gui/text/qtextdocument/setMarkdown/setMarkdown.pro new file mode 100644 index 0000000000..4a2dfa51b9 --- /dev/null +++ b/tests/libfuzzer/gui/text/qtextdocument/setMarkdown/setMarkdown.pro @@ -0,0 +1,4 @@ +CONFIG += console +CONFIG -= app_bundle +SOURCES += main.cpp +LIBS += -fsanitize=fuzzer diff --git a/tests/libfuzzer/gui/text/qtextlayout/beginLayout/beginLayout.pro b/tests/libfuzzer/gui/text/qtextlayout/beginLayout/beginLayout.pro new file mode 100644 index 0000000000..c9b14f6caf --- /dev/null +++ b/tests/libfuzzer/gui/text/qtextlayout/beginLayout/beginLayout.pro @@ -0,0 +1,3 @@ +QT += widgets +SOURCES += main.cpp +LIBS += -fsanitize=fuzzer diff --git a/tests/libfuzzer/gui/text/qtextlayout/beginLayout/main.cpp b/tests/libfuzzer/gui/text/qtextlayout/beginLayout/main.cpp new file mode 100644 index 0000000000..dfb9559241 --- /dev/null +++ b/tests/libfuzzer/gui/text/qtextlayout/beginLayout/main.cpp @@ -0,0 +1,36 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QTextLayout> + +extern "C" int LLVMFuzzerTestOneInput(const char *Data, size_t Size) { + QTextLayout tl(QByteArray::fromRawData(Data, Size)); + tl.beginLayout(); + tl.endLayout(); + return 0; +} diff --git a/tests/manual/diaglib/diaglib.pri b/tests/manual/diaglib/diaglib.pri index 9f10167136..b57ee75841 100644 --- a/tests/manual/diaglib/diaglib.pri +++ b/tests/manual/diaglib/diaglib.pri @@ -12,7 +12,7 @@ HEADERS += \ win32:!winrt: { SOURCES += $$PWD/nativewindowdump_win.cpp - LIBS *= -luser32 + QMAKE_USE += user32 } else { SOURCES += $$PWD/nativewindowdump.cpp } diff --git a/tests/manual/diaglib/textdump.cpp b/tests/manual/diaglib/textdump.cpp index 8bb899783b..383ec4edb0 100644 --- a/tests/manual/diaglib/textdump.cpp +++ b/tests/manual/diaglib/textdump.cpp @@ -44,6 +44,9 @@ static const EnumLookup specialCharactersEnumLookup[] = #if QT_VERSION >= 0x050000 {QChar::Tabulation, "Tabulation"}, {QChar::LineFeed, "LineFeed"}, +# if QT_VERSION >= 0x050e00 + {QChar::FormFeed, "FormFeed"}, +# endif {QChar::CarriageReturn, "CarriageReturn"}, {QChar::Space, "Space"}, #endif diff --git a/tests/manual/dialogs/printdialogpanel.cpp b/tests/manual/dialogs/printdialogpanel.cpp index 8d64d2f6a6..b7447e3d64 100644 --- a/tests/manual/dialogs/printdialogpanel.cpp +++ b/tests/manual/dialogs/printdialogpanel.cpp @@ -710,8 +710,7 @@ void PrintDialogPanel::showPreviewDialog() applySettings(m_printer.data()); PrintPreviewDialog dialog(m_printer.data(), this); #if QT_VERSION >= 0x050000 - const int screenNumber = QApplication::desktop()->screenNumber(this); - const QSize availableSize = QGuiApplication::screens().at(screenNumber)->availableSize(); + const QSize availableSize = screen()->availableSize(); #else const QSize availableSize = QApplication::desktop()->availableGeometry().size(); #endif diff --git a/tests/manual/highdpi/dragwidget.cpp b/tests/manual/highdpi/dragwidget.cpp index 46a8ea8090..11bbc1d127 100644 --- a/tests/manual/highdpi/dragwidget.cpp +++ b/tests/manual/highdpi/dragwidget.cpp @@ -110,7 +110,7 @@ void DragWidget::dropEvent(QDropEvent *event) { if (event->mimeData()->hasText()) { const QMimeData *mime = event->mimeData(); - QStringList pieces = mime->text().split(QRegExp("\\s+"), + QStringList pieces = mime->text().split(QRegularExpression("\\s+"), QString::SkipEmptyParts); QPoint position = event->pos(); QPoint hotSpot; diff --git a/tests/manual/highdpi/highdpi.pro b/tests/manual/highdpi/highdpi.pro index 9db083cd82..2de8ed3bb5 100644 --- a/tests/manual/highdpi/highdpi.pro +++ b/tests/manual/highdpi/highdpi.pro @@ -15,3 +15,4 @@ HEADERS += \ RESOURCES += \ highdpi.qrc +DEFINES += HAVE_SCREEN_BASE_DPI diff --git a/tests/manual/highdpi/main.cpp b/tests/manual/highdpi/main.cpp index bb01ab785d..51a7026e85 100644 --- a/tests/manual/highdpi/main.cpp +++ b/tests/manual/highdpi/main.cpp @@ -37,10 +37,12 @@ #include <QPushButton> #include <QButtonGroup> #include <QLineEdit> +#include <QPlainTextEdit> #include <QScrollBar> #include <QSlider> #include <QSpinBox> #include <QTabBar> +#include <QTextBrowser> #include <QIcon> #include <QPainter> #include <QWindow> @@ -55,9 +57,16 @@ #include <QCommandLineOption> #include <QDebug> #include <private/qhighdpiscaling_p.h> +#include <qpa/qplatformscreen.h> #include "dragwidget.h" +static QTextStream &operator<<(QTextStream &str, const QRect &r) +{ + str << r.width() << 'x' << r.height() << forcesign << r.x() << r.y() << noforcesign; + return str; +} + class DemoContainerBase { public: @@ -1176,6 +1185,85 @@ public: } }; +class MetricsTest : public QWidget +{ + QPlainTextEdit *m_textEdit; + +public: + MetricsTest() + { + qDebug() << R"( +MetricsTest +Relevant environment variables are: +QT_FONT_DPI=N +QT_SCALE_FACTOR=n +QT_ENABLE_HIGHDPI_SCALING=0|1 +QT_USE_PHYSICAL_DPI=0|1 +QT_SCREEN_SCALE_FACTORS=N;N;N or QT_SCREEN_SCALE_FACTORS=name:N +QT_SCALE_FACTOR_ROUNDING_POLICY=Round|Ceil|Floor|RoundPreferFloor|PassThrough +QT_DPI_ADJUSTMENT_POLICY=AdjustDpi|DontAdjustDpi|AdjustUpOnly)"; + + resize(480, 360); + + QVBoxLayout *layout = new QVBoxLayout(); + setLayout(layout); + + m_textEdit = new QPlainTextEdit; + m_textEdit->setReadOnly(true); + layout->addWidget(m_textEdit); + } + + void updateMetrics() + { + QString text; + QTextStream str(&text); + + auto currentScreen = windowHandle()->screen(); + const auto screens = QGuiApplication::screens(); + for (int i = 0, size = screens.size(); i < size; ++i) { + auto screen = screens.at(i); + auto platformScreen = screen->handle(); + str << "Screen #" << i << " \"" << screen->name() << '"'; + if (screen == currentScreen) + str << " [current]"; + if (screen == QGuiApplication::primaryScreen()) + str << " [primary]"; + str << "\n screen geometry: " << screen->geometry() + << "\n platform screen geometry: " << platformScreen->geometry() + << "\n platform screen logicalDpi: " << platformScreen->logicalDpi().first; + +#ifdef HAVE_SCREEN_BASE_DPI + str << "\n platform screen logicalBaseDpi: " << platformScreen->logicalBaseDpi().first; +#endif + str << "\n platform screen devicePixelRatio: " <<platformScreen->devicePixelRatio() + << "\n platform screen physicalDpi: " << screen->physicalDotsPerInch() + << "\n\n"; + } + + str << "widget devicePixelRatio: " << this->devicePixelRatioF() + << "\nwidget logicalDpi: " << this->logicalDpiX() + << "\n\nQT_FONT_DPI: " << qgetenv("QT_FONT_DPI") + << "\nQT_SCALE_FACTOR: " << qgetenv("QT_SCALE_FACTOR") + << "\nQT_ENABLE_HIGHDPI_SCALING: " << qgetenv("QT_ENABLE_HIGHDPI_SCALING") + << "\nQT_SCREEN_SCALE_FACTORS: " << qgetenv("QT_SCREEN_SCALE_FACTORS") + << "\nQT_USE_PHYSICAL_DPI: " << qgetenv("QT_USE_PHYSICAL_DPI") + << "\nQT_SCALE_FACTOR_ROUNDING_POLICY: " << qgetenv("QT_SCALE_FACTOR_ROUNDING_POLICY") + << "\nQT_DPI_ADJUSTMENT_POLICY: " << qgetenv("QT_DPI_ADJUSTMENT_POLICY") + << '\n'; + + m_textEdit->setPlainText(text); + } + + void paintEvent(QPaintEvent *ev) + { + // We get a paint event on screen change, so this is a convenient place + // to update the metrics, at the possible risk of doing something else + // than painting in a paint event. + updateMetrics(); + QWidget::paintEvent(ev); + } +}; + int main(int argc, char **argv) { QApplication app(argc, argv); @@ -1212,6 +1300,7 @@ int main(int argc, char **argv) demoList << new DemoContainer<ScreenDisplayer>("screens", "Test screen and window positioning"); demoList << new DemoContainer<PhysicalSizeTest>("physicalsize", "Test manual highdpi support using physicalDotsPerInch"); demoList << new DemoContainer<GraphicsViewCaching>("graphicsview", "Test QGraphicsView caching"); + demoList << new DemoContainer<MetricsTest>("metrics", "Show display metrics"); foreach (DemoContainerBase *demo, demoList) parser.addOption(demo->option()); diff --git a/tests/manual/keypadnavigation/main.cpp b/tests/manual/keypadnavigation/main.cpp index 67986a9cc9..dad4376514 100644 --- a/tests/manual/keypadnavigation/main.cpp +++ b/tests/manual/keypadnavigation/main.cpp @@ -33,7 +33,6 @@ #include <QFontDialog> #include <QInputDialog> #include <QMessageBox> -#include <QSignalMapper> #include "ui_keypadnavigation.h" class KeypadNavigation : public QMainWindow @@ -48,7 +47,7 @@ public: ui->setupUi(this); const struct { - QObject *action; + QAction *action; QWidget *page; } layoutMappings[] = { {ui->m_actionLayoutVerticalSimple, ui->m_pageVerticalSimple}, @@ -58,15 +57,16 @@ public: {ui->m_actionLayoutChaos, ui->m_pageChaos}, {ui->m_actionLayoutDialogs, ui->m_pageDialogs} }; - for (int i = 0; i < int(sizeof layoutMappings / sizeof layoutMappings[0]); ++i) { - connect(layoutMappings[i].action, SIGNAL(triggered()), &m_layoutSignalMapper, SLOT(map())); - m_layoutSignalMapper.setMapping(layoutMappings[i].action, layoutMappings[i].page); + for (auto layoutMapping : layoutMappings) { + const auto page = layoutMapping.page; + connect(layoutMapping.action, &QAction::triggered, ui->m_stackWidget, + [this, page]() + { ui->m_stackWidget->setCurrentWidget(page); }); } - connect(&m_layoutSignalMapper, SIGNAL(mapped(QWidget*)), ui->m_stackWidget, SLOT(setCurrentWidget(QWidget*))); #ifdef QT_KEYPAD_NAVIGATION const struct { - QObject *action; + QAction *action; Qt::NavigationMode mode; } modeMappings[] = { {ui->m_actionModeNone, Qt::NavigationModeNone}, @@ -75,17 +75,17 @@ public: {ui->m_actionModeCursorAuto, Qt::NavigationModeCursorAuto}, {ui->m_actionModeCursorForceVisible, Qt::NavigationModeCursorForceVisible} }; - for (int i = 0; i < int(sizeof modeMappings / sizeof modeMappings[0]); ++i) { - connect(modeMappings[i].action, SIGNAL(triggered()), &m_modeSignalMapper, SLOT(map())); - m_modeSignalMapper.setMapping(modeMappings[i].action, int(modeMappings[i].mode)); + for (auto modeMapping : modeMappings) { + const auto mode = modeMapping.mode; + connect(modeMapping.action, &QAction::triggered, this, + [this, mode]() { setNavigationMode(mode); }); } - connect(&m_modeSignalMapper, SIGNAL(mapped(int)), SLOT(setNavigationMode(int))); #else // QT_KEYPAD_NAVIGATION ui->m_menuNavigation_mode->deleteLater(); #endif // QT_KEYPAD_NAVIGATION const struct { - QObject *button; + QPushButton *button; Dialog dialog; } openDialogMappings[] = { {ui->m_buttonGetOpenFileName, DialogGetOpenFileName}, @@ -97,11 +97,11 @@ public: {ui->m_buttonAboutQt, DialogAboutQt}, {ui->m_buttonGetItem, DialogGetItem} }; - for (int i = 0; i < int(sizeof openDialogMappings / sizeof openDialogMappings[0]); ++i) { - connect(openDialogMappings[i].button, SIGNAL(clicked()), &m_dialogSignalMapper, SLOT(map())); - m_dialogSignalMapper.setMapping(openDialogMappings[i].button, int(openDialogMappings[i].dialog)); + for (auto openDialogMapping : openDialogMappings) { + const auto dialog = openDialogMapping.dialog; + connect(openDialogMapping.button, &QPushButton::clicked, this, + [this, dialog]() { openDialog(dialog); }); } - connect(&m_dialogSignalMapper, SIGNAL(mapped(int)), SLOT(openDialog(int))); } ~KeypadNavigation() @@ -162,11 +162,6 @@ private: }; Ui_KeypadNavigation *ui; - QSignalMapper m_layoutSignalMapper; -#ifdef QT_KEYPAD_NAVIGATION - QSignalMapper m_modeSignalMapper; -#endif // QT_KEYPAD_NAVIGATION - QSignalMapper m_dialogSignalMapper; }; int main(int argc, char *argv[]) diff --git a/tests/manual/lance/main.cpp b/tests/manual/lance/main.cpp index 7f5af2d908..6dc5e2076a 100644 --- a/tests/manual/lance/main.cpp +++ b/tests/manual/lance/main.cpp @@ -334,20 +334,7 @@ int main(int argc, char **argv) checkers_background = false; } } else { -#if 0 // Used to be included in Qt4 for Q_WS_WIN - QString input = QString::fromLocal8Bit(argv[i]); - if (input.indexOf('*') >= 0) { - QFileInfo info(input); - QDir dir = info.dir(); - QFileInfoList infos = dir.entryInfoList(QStringList(info.fileName())); - for (int ii=0; ii<infos.size(); ++ii) - files.append(infos.at(ii).absoluteFilePath()); - } else { - files.append(input); - } -#else files.append(QString(argv[i])); -#endif } } scaledWidth = int(width * scalefactor); diff --git a/tests/manual/lance/widgets.h b/tests/manual/lance/widgets.h index 46c55f4c16..09b2c3e667 100644 --- a/tests/manual/lance/widgets.h +++ b/tests/manual/lance/widgets.h @@ -43,7 +43,6 @@ #include <QFileDialog> #include <QTextStream> #include <QPaintEngine> -#include <QSignalMapper> #include <QAction> #include <QDebug> diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro index ab00a5ef60..42f9878e44 100644 --- a/tests/manual/manual.pro +++ b/tests/manual/manual.pro @@ -23,6 +23,7 @@ qimagereader \ qlayout \ qlocale \ qmimedatabase \ +qnetconmonitor \ qnetworkaccessmanager/qget \ qnetworkconfigurationmanager \ qnetworkconfiguration \ @@ -34,6 +35,7 @@ qsslsocket \ qsysinfo \ qtabletevent \ qtexteditlist \ +qtexttableborders \ qtbug-8933 \ qtbug-52641 \ qtouchevent \ @@ -53,7 +55,8 @@ shortcuts \ dialogs \ windowtransparency \ unc \ -qtabbar +qtabbar \ +rhi !qtConfig(openssl): SUBDIRS -= qssloptions diff --git a/tests/manual/markdown/html2md.cpp b/tests/manual/markdown/html2md.cpp new file mode 100644 index 0000000000..19d6ff06af --- /dev/null +++ b/tests/manual/markdown/html2md.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** + ** + ** Copyright (C) 2019 The Qt Company Ltd. + ** Contact: https://www.qt.io/licensing/ + ** + ** This file is part of the test suite of the Qt Toolkit. + ** + ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ + ** Commercial License Usage + ** Licensees holding valid commercial Qt licenses may use this file in + ** accordance with the commercial license agreement provided with the + ** Software or, alternatively, in accordance with the terms contained in + ** a written agreement between you and The Qt Company. For licensing terms + ** and conditions see https://www.qt.io/terms-conditions. For further + ** information use the contact form at https://www.qt.io/contact-us. + ** + ** GNU General Public License Usage + ** Alternatively, this file may be used under the terms of the GNU + ** General Public License version 3 as published by the Free Software + ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT + ** included in the packaging of this file. Please review the following + ** information to ensure the GNU General Public License requirements will + ** be met: https://www.gnu.org/licenses/gpl-3.0.html. + ** + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + +#include <QCommandLineParser> +#include <QDebug> +#include <QFile> +#include <QGuiApplication> +#include <QTextDocument> + +int main(int argc, char **argv) +{ + QGuiApplication app(argc, argv); + QGuiApplication::setApplicationVersion(QT_VERSION_STR); + QCommandLineParser parser; + parser.setApplicationDescription("Converts the Qt-supported subset of HTML to Markdown."); + parser.addHelpOption(); + parser.addVersionOption(); + parser.addPositionalArgument(QGuiApplication::translate("main", "input"), + QGuiApplication::translate("main", "input file")); + parser.addPositionalArgument(QGuiApplication::translate("main", "output"), + QGuiApplication::translate("main", "output file")); + parser.process(app); + if (parser.positionalArguments().count() != 2) + parser.showHelp(1); + + QFile inFile(parser.positionalArguments().first()); + if (!inFile.open(QIODevice::ReadOnly)) { + qFatal("failed to open %s for reading", parser.positionalArguments().first().toLocal8Bit().data()); + exit(2); + } + QFile outFile(parser.positionalArguments().at(1)); + if (!outFile.open(QIODevice::WriteOnly)) { + qFatal("failed to open %s for writing", parser.positionalArguments().at(1).toLocal8Bit().data()); + exit(2); + } + QTextDocument doc; + doc.setHtml(QString::fromUtf8(inFile.readAll())); + outFile.write(doc.toMarkdown().toUtf8()); +} diff --git a/tests/manual/markdown/html2md.pro b/tests/manual/markdown/html2md.pro new file mode 100644 index 0000000000..4d6254e5a0 --- /dev/null +++ b/tests/manual/markdown/html2md.pro @@ -0,0 +1,6 @@ +TEMPLATE = app +TARGET = html2md +INCLUDEPATH += . +#QT += gui-private +SOURCES += html2md.cpp + diff --git a/tests/manual/qcursor/qcursorhighdpi/main.cpp b/tests/manual/qcursor/qcursorhighdpi/main.cpp index 4a7646c39d..e70be333fd 100644 --- a/tests/manual/qcursor/qcursorhighdpi/main.cpp +++ b/tests/manual/qcursor/qcursorhighdpi/main.cpp @@ -183,7 +183,7 @@ private: void DraggableLabel::mousePressEvent(QMouseEvent *) { QMimeData *mimeData = new QMimeData; - mimeData->setImageData(qVariantFromValue(m_pixmap)); + mimeData->setImageData(QVariant::fromValue(m_pixmap)); QDrag *drag = new QDrag(this); QPixmap pixmap = m_pixmap; if (QApplication::keyboardModifiers() & Qt::ShiftModifier) { @@ -218,7 +218,7 @@ protected: VerticalRuler::VerticalRuler(QWidget *parent) : QWidget(parent) { - const int screenWidth = QApplication::desktop()->screenGeometry(this).width(); + const int screenWidth = screen()->geometry().width(); setFixedWidth(screenWidth / 48); // 1920 pixel monitor ->40 } @@ -356,15 +356,12 @@ int main(int argc, char *argv[]) QApplication app(argc, argv); MainWindowPtrList windows; - - QDesktopWidget *desktopWidget = app.desktop(); - const int lastScreen = arguments.contains("-p") ? 0 // Primary screen only - : desktopWidget->screenCount() - 1; // All screens + : QGuiApplication::screens().size() - 1; // All screens for (int s = lastScreen; s >= 0; --s) { - MainWindowPtr window(new MainWindow(desktopWidget->screen(s))); - const QPoint pos = desktopWidget->screenGeometry(s).center() - QPoint(200, 100); + MainWindowPtr window(new MainWindow()); + const QPoint pos = QGuiApplication::screens().at(s)->geometry().center() - QPoint(200, 100); window->move(pos); windows.append(window); window->show(); diff --git a/tests/manual/qdesktopwidget/main.cpp b/tests/manual/qdesktopwidget/main.cpp index f4c82c5f72..978dc62b0e 100644 --- a/tests/manual/qdesktopwidget/main.cpp +++ b/tests/manual/qdesktopwidget/main.cpp @@ -34,6 +34,7 @@ class DesktopView : public QGraphicsView { +#if QT_DEPRECATED_SINCE(5, 11) Q_OBJECT public: DesktopView() @@ -195,6 +196,7 @@ private: QGraphicsScene *scene; QGraphicsRectItem *that; QPoint thatRoot; +#endif }; #include "main.moc" diff --git a/tests/manual/qgraphicslayout/flicker/window.h b/tests/manual/qgraphicslayout/flicker/window.h index 22a53585d1..c49b82704e 100644 --- a/tests/manual/qgraphicslayout/flicker/window.h +++ b/tests/manual/qgraphicslayout/flicker/window.h @@ -107,7 +107,7 @@ public: Q_UNUSED(option); Q_UNUSED(widget); painter->setBrush(m_brush); - painter->drawRoundRect(rect()); + painter->drawRoundedRect(rect(), 25, 25, Qt::RelativeSize); painter->drawLine(rect().topLeft(), rect().bottomRight()); painter->drawLine(rect().bottomLeft(), rect().topRight()); } diff --git a/tests/manual/qnetconmonitor/qnetconmonitor.pro b/tests/manual/qnetconmonitor/qnetconmonitor.pro new file mode 100644 index 0000000000..dda88c4cd7 --- /dev/null +++ b/tests/manual/qnetconmonitor/qnetconmonitor.pro @@ -0,0 +1,4 @@ +TEMPLATE = app +QT = network-private testlib +CONFIG += console +SOURCES += tst_qnetconmonitor.cpp diff --git a/tests/manual/qnetconmonitor/tst_qnetconmonitor.cpp b/tests/manual/qnetconmonitor/tst_qnetconmonitor.cpp new file mode 100644 index 0000000000..92daee3348 --- /dev/null +++ b/tests/manual/qnetconmonitor/tst_qnetconmonitor.cpp @@ -0,0 +1,220 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qcoreapplication.h> +#include <QtCore/qdeadlinetimer.h> + +#include <QtNetwork/qhostinfo.h> +#include <QtNetwork/private/qnetconmonitor_p.h> + +#include <QtTest/qsignalspy.h> + +void testDetectDisconnection(); +void testDetectRouteDisrupted(); + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + + if (!QNetworkStatusMonitor::isEnabled()) { + qWarning("QNetworkStatusMonitor is not enabled for this platform!"); + return 0; + } + + while (true) { + + QByteArray indent(" "); + { + QTextStream writer(stdout); + writer << "Manual test for QNetwork{Status|Connection}Monitor\n" + << "The tests are grouped by what they test. Run them in any order\n" + << "- QNetworkStatusMonitor tests:\n" + << indent << "c" << indent << "Test connection and disconnection detection.\n" + << "- QNetworkConnectionMonitor tests:\n" + << indent << "r" << indent << "Test detection of disruption of route to target.\n" + << "- General\n" + << indent << "q" << indent << "Quit the test.\n" + << "> "; + } + + auto getCommand = []() { + char ch; + QTextStream reader(stdin); + reader >> ch; + return ch; + }; + + switch (getCommand()) { + case 'c': + testDetectDisconnection(); + break; + case 'r': + testDetectRouteDisrupted(); + break; + case 'q': + return 0; + } + } + Q_UNREACHABLE(); + return 0; +} + +bool ensureNetworkAccessible(QNetworkStatusMonitor &status, QTextStream &writer) +{ + if (!status.isNetworkAccessible()) { + writer << "Network currently not accessible, please make sure you have an internet " + "connection. Will wait for a connection for 20 seconds.\n"; + writer.flush(); + QDeadlineTimer timer{ 20 * 1000 }; + while (!timer.hasExpired() && !status.isNetworkAccessible()) + QCoreApplication::processEvents(); + if (!status.isNetworkAccessible()) { + writer << "Error: No network in 20 seconds, ending now!\n"; + return false; + } + writer << "Network successfully connected, thanks!\n"; + } + return true; +} + +void testDetectDisconnection() +{ + QTextStream writer(stdout); + QNetworkStatusMonitor status; + + if (!status.start()) { + writer << "Error: Failed to start"; + return; + } + + if (!ensureNetworkAccessible(status, writer)) + return; + + QSignalSpy onlineStateSpy(&status, &QNetworkStatusMonitor::onlineStateChanged); + + writer << "Please disconnect from the internet within 20 seconds\n"; + writer.flush(); + QDeadlineTimer timer{ 20 * 1000 }; + while (!timer.hasExpired() && status.isNetworkAccessible()) + QCoreApplication::processEvents(); + if (status.isNetworkAccessible()) { + writer << "Error: Still connected after 20 seconds, ending now!\n"; + return; + } + if (onlineStateSpy.count() == 0) { + writer << "Error: There was a disconnection but there was no signal emitted!\n"; + return; + } + // Get the final parameter of the final signal emission and make sure it is false. + if (onlineStateSpy.last().last().toBool()) { + writer << "Error: There was a disconnection but the latest signal emitted says we are online!\n"; + return; + } + writer << "Success, connection loss was detected!\n"; +} + +void testDetectRouteDisrupted() +{ + QTextStream writer(stdout); + + { + QNetworkStatusMonitor status; + if (!status.start()) { + writer << "Error: Failed to start"; + return; + } + if (!ensureNetworkAccessible(status, writer)) + return; + } + + QNetworkConnectionMonitor connection; + + auto readLineFromStdin = []() -> QString { + QTextStream in(stdin); + return in.readLine(); + }; + + writer << "Type your local IP address: "; + writer.flush(); + const QHostAddress local{ readLineFromStdin() }; + if (local.isNull()) { + writer << "Error: The address is invalid!\n"; + return; + } + + const QHostAddress defaultAddress{ QString::fromLatin1("1.1.1.1") }; + QHostAddress remote; + do { + writer << "Type a remote IP address [" << defaultAddress.toString() << "]: "; + writer.flush(); + QString address = readLineFromStdin(); + if (address.isEmpty()) { + remote = defaultAddress; + } else { + QHostAddress remoteTemp{ address }; + if (remoteTemp.isNull()) { + writer << "Invalid address\n"; + } else { + remote = remoteTemp; + } + } + } while (remote.isNull()); + + if (!connection.setTargets(local, remote)) { + writer << "Error: Failed to set the targets!\n"; + return; + } + if (!connection.isReachable()) { + writer << "Error: Target is not reachable!\n"; + return; + } + if (!connection.startMonitoring()) { + writer << "Error: Failed to start monitoring!\n"; + return; + } + + QSignalSpy reachabilitySpy(&connection, &QNetworkConnectionMonitor::reachabilityChanged); + + writer << "QNetworkConnectionMonitor might assume the target is initially reachable.\n" + "If it is not reachable then this test might not work correctly.\n" + "Please disrupt the connection between your machine and the target within 20 " + "seconds\n"; + writer.flush(); + reachabilitySpy.wait(20 * 1000); + if (reachabilitySpy.count() == 0) { + writer << "Error: There was a disconnection but there was no signal emitted!\n"; + return; + } + // Get the final parameter of the final signal emission and make sure it is false. + if (reachabilitySpy.last().last().toBool()) { + writer << "Error: There was a disconnection but the latest signal emitted says the target is " + "reachable!\n"; + return; + } + writer << "Success, connection disruption was detected!\n"; +} diff --git a/tests/manual/qscreen/main.cpp b/tests/manual/qscreen/main.cpp index 6fba872b12..0728d66bf9 100644 --- a/tests/manual/qscreen/main.cpp +++ b/tests/manual/qscreen/main.cpp @@ -61,8 +61,10 @@ public: QLatin1String("Left-click to test QGuiApplication::topLevelAt(click pos)\nRight-click to ungrab\n") : QLatin1String("Left-click to grab mouse\n"); if (!m_cursorPos.isNull()) { + const auto screen = QGuiApplication::screenAt(m_cursorPos); + const auto screenNum = screen ? QGuiApplication::screens().indexOf(screen) : 0; txt += QString(QLatin1String("Current mouse position: %1, %2 on screen %3\n")) - .arg(m_cursorPos.x()).arg(m_cursorPos.y()).arg(QApplication::desktop()->screenNumber(m_cursorPos)); + .arg(m_cursorPos.x()).arg(m_cursorPos.y()).arg(screenNum); if (QGuiApplication::mouseButtons() & Qt::LeftButton) { QWindow *win = QGuiApplication::topLevelAt(m_cursorPos); txt += QString(QLatin1String("Top-level window found? %1\n")) @@ -234,6 +236,7 @@ void screenAdded(QScreen* screen) QList<QScreen *> screens = QGuiApplication::screens(); int screenNumber = screens.indexOf(screen); Q_ASSERT(screenNumber >= 0); + // ### Qt 6: Find a replacement for QDesktopWidget::screen() w->setParent(qApp->desktop()->screen(screenNumber)); w->show(); diff --git a/tests/manual/qtexttableborders/main.cpp b/tests/manual/qtexttableborders/main.cpp new file mode 100644 index 0000000000..a8fdf7becc --- /dev/null +++ b/tests/manual/qtexttableborders/main.cpp @@ -0,0 +1,39 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "widget.h" +#include <QApplication> + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + Widget w; + w.show(); + + return a.exec(); +} diff --git a/tests/manual/qtexttableborders/qtexttableborders.pro b/tests/manual/qtexttableborders/qtexttableborders.pro new file mode 100644 index 0000000000..7e454f978d --- /dev/null +++ b/tests/manual/qtexttableborders/qtexttableborders.pro @@ -0,0 +1,10 @@ +#This project can be used to verify QTBUG-36152 case. +QT += core gui printsupport +CONFIG += c++11 +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets +TARGET = qtexttableborders +TEMPLATE = app +SOURCES += main.cpp widget.cpp +HEADERS += widget.h +FORMS += widget.ui +RESOURCES += resources.qrc diff --git a/tests/manual/qtexttableborders/resources.qrc b/tests/manual/qtexttableborders/resources.qrc new file mode 100644 index 0000000000..a7000a73e3 --- /dev/null +++ b/tests/manual/qtexttableborders/resources.qrc @@ -0,0 +1,6 @@ +<RCC> + <qresource prefix="/"> + <file>table-border-test-header.html</file> + <file>table-border-test.html</file> + </qresource> +</RCC> diff --git a/tests/manual/qtexttableborders/table-border-test-header.html b/tests/manual/qtexttableborders/table-border-test-header.html new file mode 100644 index 0000000000..cb29d0a41d --- /dev/null +++ b/tests/manual/qtexttableborders/table-border-test-header.html @@ -0,0 +1,129 @@ +<html> + <body> + + <h2>Printable table with repeated header</h2> + + <p> + Please print (to PDF, save the trees) this table and compare this to the + print results of Chrome/Firefox. + <ul> + <li>Firefox fails to render the first repeated header correctly + <li>Chrome fails to render the Cell B top edge (should be red, except the first row after header + <li>Qt: Could do slightly better with the last row on each page (although both Firefox and Chrome don't work perfect here as well) + </ul> + </p> + + <table border=1 bordercolor="#aaaaaa" style="border-collapse:collapse"> + <thead> + <tr> + <th style="border-bottom: 1px solid blue">Header A</th> + <th style="border-bottom: 4px solid blue">Header B</th> + </tr> + </thead> + <tbody> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + <tr><td>Cell A</td><td style="border-top: 1px solid red">Cell B</td></tr> + </tbody> + </table> + + </body> +</html> diff --git a/tests/manual/qtexttableborders/table-border-test.html b/tests/manual/qtexttableborders/table-border-test.html new file mode 100644 index 0000000000..0339f80d0f --- /dev/null +++ b/tests/manual/qtexttableborders/table-border-test.html @@ -0,0 +1,171 @@ +<html> + <body> + + <h1>Working Test Cases</h1> + + <h2>border-collapse: separate</h2> + + <h3>TC-A1: table no border</h3> + <table> + <tbody> + <tr> + <td>Cell 1A</td> + <td>Cell 1B</td> + </tr> + </tbody> + </table> + + <h3>TC-A2: table attribute controlled border (1px, red)</h3> + <table border=1 bordercolor="red"> + <tbody> + <tr> + <td>Cell 1A</td> + <td>Cell 1B</td> + </tr> + </tbody> + </table> + + <h3>TC-A3: table attribute controlled border (4px, blue)</h3> + <table border=4 bordercolor="blue"> + <tbody> + <tr> + <td>Cell 1A</td> + <td>Cell 1B</td> + </tr> + </tbody> + </table> + Note: Real browsers render the inner cells border with 1px, but QTextDocument's rendering has always been like this. + + <h2>border-collapse: collapse</h2> + + <h3>TC-B1: table no border</h3> + <table style="border-collapse: collapse"> + <tbody> + <tr> + <td>Cell 1A</td> + <td>Cell 1B</td> + </tr> + </tbody> + </table> + + <h3>TC-B2: table attribute + css controlled grid (outer border 1px)</h3> + <table border=1 bordercolor="red" style="border-collapse: collapse"> + <tbody> + <tr> + <td>Cell 1A</td> + <td>Cell 1B</td> + </tr> + </tbody> + </table> + + <h3>TC-B3: table attribute + css controlled grid (outer border 4px)</h3> + <table border=4 bordercolor="red" style="border-collapse: collapse"> + <tbody> + <tr> + <td>Cell 1A</td> + <td>Cell 1B</td> + </tr> + </tbody> + </table> + + <h3>TC-B4: table attribute + css controlled grid (one cell with custom edge)</h3> + <table border=4 bordercolor="red" style="border-collapse: collapse"> + <tbody> + <tr> + <td>Cell 1A</td> + <td style="border-right: 8px solid green">Cell 1B (border-right: 8px solid green)</td> + </tr> + </tbody> + </table> + + <h3>TC-B5: table with single decorated cell</h3> + <table style="border-collapse: collapse"> + <tbody> + <tr> + <td>Cell 1A</td> + <td style="border: 2px solid red">Cell 1B (border: 2px solid red)</td> + </tr> + </tbody> + </table> + + <h3>cells with competing rules</h3> + + <h4>TC-C1: vertical edge (pink, 6px) wins over horizontal edge (red|blue, 6px)</h4> + <table border=1 bordercolor="#999999" style="border-collapse: collapse"> + <tbody> + <tr> + <td style="border-right: 4px solid green; border-bottom: 6px solid red">Cell 1A</td> + <td style="border-left: 6px solid pink; border-bottom: 6px solid blue">Cell 2B</td> + </tr> + </tbody> + </table> + + <h4>TC-C2: vertical edge (pink, 6px) loses over horizontal edge (red|blue, 8px)</h4> + <table border=1 bordercolor="#999999" style="border-collapse: collapse"> + <tbody> + <tr> + <td style="border-right: 4px solid green; border-bottom: 8px solid red">Cell 1A</td> + <td style="border-left: 6px solid pink; border-bottom: 8px solid blue">Cell 2B</td> + </tr> + </tbody> + </table> + + <h4>TC-C3: cells with span and competing rules</h4> + <table border=1 bordercolor="#999999" style="border-collapse: collapse"> + <tbody> + <tr> + <td colspan=2 style="border-bottom: 4px solid red">Cell 1A/B spans over two columns (border-bottom: red)</td> + </tr> + <tr> + <td style="border-top: 1px solid green">Cell 2A (border-top loses -> red)</td> + <td style="border-top: 10px solid green">Cell 2B (border-top wins -> green)</td> + </tr> + </tbody> + </table> + + <h1>Non-Working Test Cases</h1> + + <h2>border-collapse: separate</h2> + + <h3>TC-X1: table css border (red via style)</h3> + <table style="border: 1px solid red"> + <tbody> + <tr> + <td>Cell 1A</td> + <td>Cell 1B</td> + </tr> + </tbody> + </table> + + <h2>border-collapse: collapse</h2> + + <h3>TC-X2: tr css border</h3> + <table border=1 style="border-collapse: collapse"> + <tbody> + <tr style="border-bottom: 2px solid red"> + <td>Cell 1A (border-bottom should be red)</td> + <td>Cell 1B (border-bottom should be red)</td> + </tr> + <tr style="border-left: 2px solid red"> + <td>Cell 2A (border-left should be red)</td> + <td>Cell 2B</td> + </tr> + </tbody> + </table> + + <h3>TC-X3: cells with competing rules and colspan</h3> + <table border=1 bordercolor="#999999" style="border-collapse: collapse"> + <tbody> + <tr> + <td colspan=2 style="border-bottom: 4px solid red; border-right: 15px solid pink">Cell 1A/B spans over two columns (border-bottom: red, border-right pink)</td> + </tr> + <tr> + <td style="border-top: 1px solid green">Cell 2A (border-top loses -> red)</td> + <td style="border-top: 10px solid green">Cell 2B (border-top wins -> green)</td> + </tr> + </tbody> + </table> + This is currently not 100% correct but admittedly a constructed corner case (and Chrome failes here, too). + + </body> +</html> diff --git a/tests/manual/qtexttableborders/widget.cpp b/tests/manual/qtexttableborders/widget.cpp new file mode 100644 index 0000000000..21d958ce81 --- /dev/null +++ b/tests/manual/qtexttableborders/widget.cpp @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "widget.h" +#include "ui_widget.h" + +#include <QScrollBar> +#include <QFile> +#include <QDir> +#include <QTemporaryFile> + +#ifndef QT_NO_DESKTOPSERVICES +#include <QDesktopServices> +#endif + +#ifndef QT_NO_PRINTER +#include <QPrinter> +#include <QPrintDialog> +#include <QPrintPreviewDialog> +#endif + +// This manual test allows checking the QTextTable border logic (QTBUG-36152) + +Widget::Widget(QWidget *parent) : + QWidget(parent), + ui(new Ui::Widget) +{ + ui->setupUi(this); + resize(1400, 800); + + connect(ui->docComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &Widget::onDocumentSelected); + connect(ui->printButton, &QPushButton::clicked, this, &Widget::onPrint); + connect(ui->previewButton, &QPushButton::clicked, this, &Widget::onPreview); + connect(ui->openBrowserButton, &QPushButton::clicked, this, &Widget::onOpenBrowser); + + connect(ui->sourceEdit, &QTextEdit::textChanged, this, + [this]() { + // make this a world class HTML IDE + auto pos = ui->htmlEdit->verticalScrollBar()->value(); + ui->htmlEdit->setHtml(ui->sourceEdit->toPlainText()); + ui->htmlEdit->verticalScrollBar()->setValue(pos); + }); + + ui->docComboBox->addItem(tr("Table Border Test"), ":/table-border-test.html"); + ui->docComboBox->addItem(tr("Table Border Header Test"), ":/table-border-test-header.html"); + + ui->docComboBox->setCurrentIndex(0); +} + +Widget::~Widget() +{ + delete ui; +} + +void Widget::onDocumentSelected() +{ + QString url = ui->docComboBox->itemData(ui->docComboBox->currentIndex()).toString(); + QFile f(url); + if (f.open(QFile::ReadOnly)) { + ui->sourceEdit->setPlainText(QString::fromUtf8(f.readAll())); + // preview HTML is set via textChanged signal + } +} + +void Widget::onPrint() +{ +#ifndef QT_NO_PRINTER + QPrinter printer(QPrinter::HighResolution); + QPrintDialog dlg(&printer, this); + if (ui->htmlEdit->textCursor().hasSelection()) + dlg.addEnabledOption(QAbstractPrintDialog::PrintSelection); + dlg.setWindowTitle(tr("Print Document")); + if (dlg.exec() == QDialog::Accepted) { + ui->htmlEdit->print(&printer); + } +#endif +} + +void Widget::onPreview() +{ +#ifndef QT_NO_PRINTER + QPrinter printer(QPrinter::HighResolution); + QPrintPreviewDialog preview(&printer, this); + connect(&preview, &QPrintPreviewDialog::paintRequested, ui->htmlEdit, &QTextEdit::print); + preview.exec(); +#endif +} + +void Widget::onOpenBrowser() +{ + // write the current html to a temp file and open the system browser +#ifndef QT_NO_DESKTOPSERVICES + auto tf = new QTemporaryFile(QDir::tempPath() + "/XXXXXX.html", this); + if (tf->open()) { + tf->write(ui->sourceEdit->toPlainText().toUtf8()); + tf->close(); + QDesktopServices::openUrl(QUrl::fromLocalFile(tf->fileName())); + } +#endif +} diff --git a/tests/manual/qtexttableborders/widget.h b/tests/manual/qtexttableborders/widget.h new file mode 100644 index 0000000000..9cf459e1cd --- /dev/null +++ b/tests/manual/qtexttableborders/widget.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WIDGET_H +#define WIDGET_H + +#include <QWidget> + +namespace Ui { +class Widget; +} + +class Widget : public QWidget +{ + Q_OBJECT + +public: + explicit Widget(QWidget *parent = nullptr); + ~Widget(); + +private slots: + void onDocumentSelected(); + void onPrint(); + void onPreview(); + void onOpenBrowser(); + +private: + Ui::Widget *ui; +}; + +#endif // WIDGET_H diff --git a/tests/manual/qtexttableborders/widget.ui b/tests/manual/qtexttableborders/widget.ui new file mode 100644 index 0000000000..95c23be69e --- /dev/null +++ b/tests/manual/qtexttableborders/widget.ui @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Widget</class> + <widget class="QWidget" name="Widget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>606</width> + <height>522</height> + </rect> + </property> + <property name="windowTitle"> + <string>QTextTable Border Manual Test</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QComboBox" name="docComboBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="printButton"> + <property name="text"> + <string>Print</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="previewButton"> + <property name="text"> + <string>Preview</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="openBrowserButton"> + <property name="text"> + <string>Open Browser</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QSplitter" name="splitter"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <widget class="QTextEdit" name="htmlEdit"/> + <widget class="QTextEdit" name="sourceEdit"/> + </widget> + </item> + </layout> + </widget> + <layoutdefault spacing="6" margin="11"/> + <tabstops> + <tabstop>docComboBox</tabstop> + <tabstop>printButton</tabstop> + <tabstop>previewButton</tabstop> + <tabstop>openBrowserButton</tabstop> + <tabstop>htmlEdit</tabstop> + </tabstops> + <resources/> + <connections/> +</ui> diff --git a/tests/manual/rhi/compressedtexture_bc1/compressedtexture_bc1.cpp b/tests/manual/rhi/compressedtexture_bc1/compressedtexture_bc1.cpp new file mode 100644 index 0000000000..af454c2487 --- /dev/null +++ b/tests/manual/rhi/compressedtexture_bc1/compressedtexture_bc1.cpp @@ -0,0 +1,200 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "../shared/examplefw.h" +#include "../shared/cube.h" +#include "../shared/dds_bc1.h" + +struct { + QRhiBuffer *vbuf = nullptr; + bool vbufReady = false; + QRhiBuffer *ubuf = nullptr; + QRhiTexture *tex = nullptr; + QRhiSampler *sampler = nullptr; + QRhiShaderResourceBindings *srb = nullptr; + QRhiGraphicsPipeline *ps = nullptr; + + float rotation = 0; + + QByteArrayList compressedData; +} d; + +void Window::customInit() +{ + if (!m_r->isTextureFormatSupported(QRhiTexture::BC1)) + qFatal("This backend does not support BC1"); + + d.vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(cube)); + d.vbuf->build(); + d.vbufReady = false; + + d.ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 68); + d.ubuf->build(); + + QSize imageSize; + d.compressedData = loadBC1(QLatin1String(":/qt256_bc1_9mips.dds"), &imageSize); + qDebug() << d.compressedData.count() << imageSize << m_r->mipLevelsForSize(imageSize); + + d.tex = m_r->newTexture(QRhiTexture::BC1, imageSize, 1, QRhiTexture::MipMapped); + d.tex->build(); + + d.sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::Linear, + QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge); + d.sampler->build(); + + d.srb = m_r->newShaderResourceBindings(); + d.srb->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf), + QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.tex, d.sampler) + }); + d.srb->build(); + + d.ps = m_r->newGraphicsPipeline(); + + d.ps->setDepthTest(true); + d.ps->setDepthWrite(true); + d.ps->setDepthOp(QRhiGraphicsPipeline::Less); + + d.ps->setCullMode(QRhiGraphicsPipeline::Back); + d.ps->setFrontFace(QRhiGraphicsPipeline::CCW); + + const QShader vs = getShader(QLatin1String(":/texture.vert.qsb")); + if (!vs.isValid()) + qFatal("Failed to load shader pack (vertex)"); + const QShader fs = getShader(QLatin1String(":/texture.frag.qsb")); + if (!fs.isValid()) + qFatal("Failed to load shader pack (fragment)"); + + d.ps->setShaderStages({ + { QRhiShaderStage::Vertex, vs }, + { QRhiShaderStage::Fragment, fs } + }); + + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ + { 3 * sizeof(float) }, + { 2 * sizeof(float) } + }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float3, 0 }, + { 1, 1, QRhiVertexInputAttribute::Float2, 0 } + }); + + d.ps->setVertexInputLayout(inputLayout); + d.ps->setShaderResourceBindings(d.srb); + d.ps->setRenderPassDescriptor(m_rp); + + d.ps->build(); +} + +void Window::customRelease() +{ + delete d.ps; + d.ps = nullptr; + + delete d.srb; + d.srb = nullptr; + + delete d.ubuf; + d.ubuf = nullptr; + + delete d.vbuf; + d.vbuf = nullptr; + + delete d.sampler; + d.sampler = nullptr; + + delete d.tex; + d.tex = nullptr; +} + +void Window::customRender() +{ + QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch(); + if (!d.vbufReady) { + d.vbufReady = true; + u->uploadStaticBuffer(d.vbuf, cube); + qint32 flip = 0; + u->updateDynamicBuffer(d.ubuf, 64, 4, &flip); + } + if (!d.compressedData.isEmpty()) { + QVarLengthArray<QRhiTextureUploadEntry, 16> descEntries; + for (int i = 0; i < d.compressedData.count(); ++i) { + QRhiTextureSubresourceUploadDescription image(d.compressedData[i].constData(), d.compressedData[i].size()); + descEntries.append({ 0, i, image }); + } + QRhiTextureUploadDescription desc; + desc.setEntries(descEntries.cbegin(), descEntries.cend()); + u->uploadTexture(d.tex, desc); + d.compressedData.clear(); + } + d.rotation += 1.0f; + QMatrix4x4 mvp = m_proj; + mvp.scale(0.5f); + mvp.rotate(d.rotation, 0, 1, 0); + u->updateDynamicBuffer(d.ubuf, 0, 64, mvp.constData()); + + QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer(); + const QSize outputSizeInPixels = m_sc->currentPixelSize(); + + cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }, u); + + cb->setGraphicsPipeline(d.ps); + cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) }); + cb->setShaderResources(); + const QRhiCommandBuffer::VertexInput vbufBindings[] = { + { d.vbuf, 0 }, + { d.vbuf, 36 * 3 * sizeof(float) } + }; + cb->setVertexInput(0, 2, vbufBindings); + cb->draw(36); + + cb->endPass(); +} diff --git a/tests/manual/rhi/compressedtexture_bc1/compressedtexture_bc1.pro b/tests/manual/rhi/compressedtexture_bc1/compressedtexture_bc1.pro new file mode 100644 index 0000000000..d185aa6b9a --- /dev/null +++ b/tests/manual/rhi/compressedtexture_bc1/compressedtexture_bc1.pro @@ -0,0 +1,8 @@ +TEMPLATE = app + +QT += gui-private + +SOURCES = \ + compressedtexture_bc1.cpp + +RESOURCES = compressedtexture_bc1.qrc diff --git a/tests/manual/rhi/compressedtexture_bc1/compressedtexture_bc1.qrc b/tests/manual/rhi/compressedtexture_bc1/compressedtexture_bc1.qrc new file mode 100644 index 0000000000..a83259a7d3 --- /dev/null +++ b/tests/manual/rhi/compressedtexture_bc1/compressedtexture_bc1.qrc @@ -0,0 +1,7 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file alias="qt256_bc1_9mips.dds">../shared/qt256_bc1_9mips.dds</file> + <file alias="texture.vert.qsb">../shared/texture.vert.qsb</file> + <file alias="texture.frag.qsb">../shared/texture.frag.qsb</file> +</qresource> +</RCC> diff --git a/tests/manual/rhi/compressedtexture_bc1_subupload/compressedtexture_bc1_subupload.cpp b/tests/manual/rhi/compressedtexture_bc1_subupload/compressedtexture_bc1_subupload.cpp new file mode 100644 index 0000000000..4931c8eaa1 --- /dev/null +++ b/tests/manual/rhi/compressedtexture_bc1_subupload/compressedtexture_bc1_subupload.cpp @@ -0,0 +1,213 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "../shared/examplefw.h" +#include "../shared/cube.h" +#include "../shared/dds_bc1.h" + +struct { + QRhiBuffer *vbuf = nullptr; + bool vbufReady = false; + QRhiBuffer *ubuf = nullptr; + QRhiTexture *tex = nullptr; + QRhiSampler *sampler = nullptr; + QRhiShaderResourceBindings *srb = nullptr; + QRhiGraphicsPipeline *ps = nullptr; + + float rotation = 0; + + QByteArrayList compressedData; + QByteArrayList compressedData2; +} d; + +void Window::customInit() +{ + if (!m_r->isTextureFormatSupported(QRhiTexture::BC1)) + qFatal("This backend does not support BC1"); + + d.vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(cube)); + d.vbuf->build(); + d.vbufReady = false; + + d.ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 68); + d.ubuf->build(); + + QSize imageSize; + d.compressedData = loadBC1(QLatin1String(":/qt256_bc1_9mips.dds"), &imageSize); + Q_ASSERT(imageSize == QSize(256, 256)); + + d.tex = m_r->newTexture(QRhiTexture::BC1, imageSize); + d.tex->build(); + + d.compressedData2 = loadBC1(QLatin1String(":/bwqt224_64_nomips.dds"), &imageSize); + Q_ASSERT(imageSize == QSize(224, 64)); + + d.sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None, // no mipmapping here + QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge); + d.sampler->build(); + + d.srb = m_r->newShaderResourceBindings(); + d.srb->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf), + QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.tex, d.sampler) + }); + d.srb->build(); + + d.ps = m_r->newGraphicsPipeline(); + + d.ps->setDepthTest(true); + d.ps->setDepthWrite(true); + d.ps->setDepthOp(QRhiGraphicsPipeline::Less); + + d.ps->setCullMode(QRhiGraphicsPipeline::Back); + d.ps->setFrontFace(QRhiGraphicsPipeline::CCW); + + const QShader vs = getShader(QLatin1String(":/texture.vert.qsb")); + if (!vs.isValid()) + qFatal("Failed to load shader pack (vertex)"); + const QShader fs = getShader(QLatin1String(":/texture.frag.qsb")); + if (!fs.isValid()) + qFatal("Failed to load shader pack (fragment)"); + + d.ps->setShaderStages({ + { QRhiShaderStage::Vertex, vs }, + { QRhiShaderStage::Fragment, fs } + }); + + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ + { 3 * sizeof(float) }, + { 2 * sizeof(float) } + }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float3, 0 }, + { 1, 1, QRhiVertexInputAttribute::Float2, 0 } + }); + + d.ps->setVertexInputLayout(inputLayout); + d.ps->setShaderResourceBindings(d.srb); + d.ps->setRenderPassDescriptor(m_rp); + + d.ps->build(); +} + +void Window::customRelease() +{ + delete d.ps; + d.ps = nullptr; + + delete d.srb; + d.srb = nullptr; + + delete d.ubuf; + d.ubuf = nullptr; + + delete d.vbuf; + d.vbuf = nullptr; + + delete d.sampler; + d.sampler = nullptr; + + delete d.tex; + d.tex = nullptr; +} + +void Window::customRender() +{ + QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch(); + if (!d.vbufReady) { + d.vbufReady = true; + u->uploadStaticBuffer(d.vbuf, cube); + qint32 flip = 0; + u->updateDynamicBuffer(d.ubuf, 64, 4, &flip); + } + if (!d.compressedData.isEmpty()) { + { + QRhiTextureUploadDescription desc({ 0, 0, { d.compressedData[0].constData(), d.compressedData[0].size() } }); + u->uploadTexture(d.tex, desc); + d.compressedData.clear(); + } + + // now exercise uploading a smaller compressed image into the same texture + { + QRhiTextureSubresourceUploadDescription image(d.compressedData2[0].constData(), d.compressedData2[0].size()); + // positions and sizes must be multiples of 4 here (for BC1) + image.setDestinationTopLeft(QPoint(16, 32)); + // the image is smaller than the subresource size (224x64 vs + // 256x256) so the size must be specified manually + image.setSourceSize(QSize(224, 64)); + QRhiTextureUploadDescription desc({ 0, 0, image }); + u->uploadTexture(d.tex, desc); + d.compressedData2.clear(); + } + } + d.rotation += 1.0f; + QMatrix4x4 mvp = m_proj; + mvp.scale(0.5f); + mvp.rotate(d.rotation, 0, 1, 0); + u->updateDynamicBuffer(d.ubuf, 0, 64, mvp.constData()); + + QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer(); + const QSize outputSizeInPixels = m_sc->currentPixelSize(); + + cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }, u); + + cb->setGraphicsPipeline(d.ps); + cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) }); + cb->setShaderResources(); + const QRhiCommandBuffer::VertexInput vbufBindings[] = { + { d.vbuf, 0 }, + { d.vbuf, 36 * 3 * sizeof(float) } + }; + cb->setVertexInput(0, 2, vbufBindings); + cb->draw(36); + + cb->endPass(); +} diff --git a/tests/manual/rhi/compressedtexture_bc1_subupload/compressedtexture_bc1_subupload.pro b/tests/manual/rhi/compressedtexture_bc1_subupload/compressedtexture_bc1_subupload.pro new file mode 100644 index 0000000000..a1184fc754 --- /dev/null +++ b/tests/manual/rhi/compressedtexture_bc1_subupload/compressedtexture_bc1_subupload.pro @@ -0,0 +1,8 @@ +TEMPLATE = app + +QT += gui-private + +SOURCES = \ + compressedtexture_bc1_subupload.cpp + +RESOURCES = compressedtexture_bc1_subupload.qrc diff --git a/tests/manual/rhi/compressedtexture_bc1_subupload/compressedtexture_bc1_subupload.qrc b/tests/manual/rhi/compressedtexture_bc1_subupload/compressedtexture_bc1_subupload.qrc new file mode 100644 index 0000000000..859a0a79f6 --- /dev/null +++ b/tests/manual/rhi/compressedtexture_bc1_subupload/compressedtexture_bc1_subupload.qrc @@ -0,0 +1,8 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file alias="qt256_bc1_9mips.dds">../shared/qt256_bc1_9mips.dds</file> + <file alias="bwqt224_64_nomips.dds">../shared/bwqt224_64_nomips.dds</file> + <file alias="texture.vert.qsb">../shared/texture.vert.qsb</file> + <file alias="texture.frag.qsb">../shared/texture.frag.qsb</file> +</qresource> +</RCC> diff --git a/tests/manual/rhi/computebuffer/buffer.comp b/tests/manual/rhi/computebuffer/buffer.comp new file mode 100644 index 0000000000..a0d0350e37 --- /dev/null +++ b/tests/manual/rhi/computebuffer/buffer.comp @@ -0,0 +1,41 @@ +#version 440 + +layout (local_size_x = 256) in; + +struct Data +{ + vec2 pos; + float dir; +}; + +layout(std140, binding = 0) buffer StorageBuffer +{ + Data d[]; +} buf; + +layout(std140, binding = 1) uniform UniformBuffer +{ + float step; + uint count; +} ubuf; + +void main() +{ + uint index = gl_GlobalInvocationID.x; + if (index < ubuf.count) { + vec2 p = buf.d[index].pos; + float dir = buf.d[index].dir; + + p.x += dir * ubuf.step * 0.01; + if (p.x > 1.0) { + p.x = 1.0; + buf.d[index].dir *= -1.0; + } + if (p.x < -1.0) { + p.x = -1.0; + buf.d[index].dir *= -1.0; + } + + buf.d[index].pos = p; + } +} diff --git a/tests/manual/rhi/computebuffer/buffer.comp.qsb b/tests/manual/rhi/computebuffer/buffer.comp.qsb Binary files differnew file mode 100644 index 0000000000..b1a666f185 --- /dev/null +++ b/tests/manual/rhi/computebuffer/buffer.comp.qsb diff --git a/tests/manual/rhi/computebuffer/buildshaders.bat b/tests/manual/rhi/computebuffer/buildshaders.bat new file mode 100755 index 0000000000..2768273b70 --- /dev/null +++ b/tests/manual/rhi/computebuffer/buildshaders.bat @@ -0,0 +1,3 @@ +qsb --glsl "310 es,430" --hlsl 50 --msl 12 buffer.comp -o buffer.comp.qsb +qsb --glsl "310 es,430" --hlsl 50 --msl 12 main.vert -o main.vert.qsb +qsb --glsl "310 es,430" --hlsl 50 --msl 12 main.frag -o main.frag.qsb diff --git a/tests/manual/rhi/computebuffer/computebuffer.cpp b/tests/manual/rhi/computebuffer/computebuffer.cpp new file mode 100644 index 0000000000..c991a11438 --- /dev/null +++ b/tests/manual/rhi/computebuffer/computebuffer.cpp @@ -0,0 +1,205 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "../shared/examplefw.h" +#include <QRandomGenerator> + +// Compute shader example. Writes to a storage buffer from a compute shader, +// then uses the same buffer as vertex buffer in the vertex stage. This would +// be typical when implementing particles for example. Here we just simply move +// the positions back and forth along the X axis. + +// Note that the example relies on gl_PointSize which is not supported +// everywhere. So in some cases the points will be of size 1. + +struct { + QVector<QRhiResource *> releasePool; + QRhiBuffer *sbuf = nullptr; + QRhiBuffer *computeUniBuf = nullptr; + QRhiShaderResourceBindings *computeBindings = nullptr; + QRhiComputePipeline *computePipeline = nullptr; + QRhiShaderResourceBindings *graphicsBindings = nullptr; + QRhiGraphicsPipeline *graphicsPipeline = nullptr; + QRhiResourceUpdateBatch *initialUpdates = nullptr; + float step = 0.2f; +} d; + +// these struct must match the std140 packing rules +struct Data { + float pos[2]; + float dir; + quint32 pad[1]; +}; +struct ComputeUBuf { + float step; + quint32 count; +}; + +const int DATA_COUNT = 256 * 128; + +const int COMPUTE_UBUF_SIZE = 8; + +void Window::customInit() +{ + if (!m_r->isFeatureSupported(QRhi::Compute)) + qFatal("Compute is not supported"); + + if (!m_r->isFeatureSupported(QRhi::VertexShaderPointSize)) + qWarning("Point sizes other than 1 not supported"); + + // compute pass + + d.sbuf = m_r->newBuffer(QRhiBuffer::Immutable, + QRhiBuffer::StorageBuffer | QRhiBuffer::VertexBuffer, + sizeof(Data) * DATA_COUNT); + d.sbuf->build(); + d.releasePool << d.sbuf; + + d.computeUniBuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, COMPUTE_UBUF_SIZE); + d.computeUniBuf->build(); + d.releasePool << d.computeUniBuf; + + d.initialUpdates = m_r->nextResourceUpdateBatch(); + + QByteArray data; + data.resize(sizeof(Data) * DATA_COUNT); + Data *p = reinterpret_cast<Data *>(data.data()); + QRandomGenerator *rgen = QRandomGenerator::global(); + for (int i = 0; i < DATA_COUNT; ++i) { + p->pos[0] = rgen->bounded(1000) / 500.0f - 1.0f; + p->pos[1] = rgen->bounded(1000) / 500.0f - 1.0f; + p->dir = rgen->bounded(2) ? 1 : -1; + ++p; + } + d.initialUpdates->uploadStaticBuffer(d.sbuf, data.constData()); + + ComputeUBuf ud; + ud.step = d.step; + ud.count = DATA_COUNT; + d.initialUpdates->updateDynamicBuffer(d.computeUniBuf, 0, COMPUTE_UBUF_SIZE, &ud); + + d.computeBindings = m_r->newShaderResourceBindings(); + d.computeBindings->setBindings({ + QRhiShaderResourceBinding::bufferLoadStore(0, QRhiShaderResourceBinding::ComputeStage, d.sbuf), + QRhiShaderResourceBinding::uniformBuffer(1, QRhiShaderResourceBinding::ComputeStage, d.computeUniBuf) + }); + d.computeBindings->build(); + d.releasePool << d.computeBindings; + + d.computePipeline = m_r->newComputePipeline(); + d.computePipeline->setShaderResourceBindings(d.computeBindings); + d.computePipeline->setShaderStage({ QRhiShaderStage::Compute, getShader(QLatin1String(":/buffer.comp.qsb")) }); + d.computePipeline->build(); + d.releasePool << d.computePipeline; + + // graphics pass + + d.graphicsBindings = m_r->newShaderResourceBindings(); + d.graphicsBindings->build(); + d.releasePool << d.graphicsBindings; + + d.graphicsPipeline = m_r->newGraphicsPipeline(); + d.graphicsPipeline->setTopology(QRhiGraphicsPipeline::Points); + d.graphicsPipeline->setShaderStages({ + { QRhiShaderStage::Vertex, getShader(QLatin1String(":/main.vert.qsb")) }, + { QRhiShaderStage::Fragment, getShader(QLatin1String(":/main.frag.qsb")) } + }); + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ + { 2 * sizeof(float) } + }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float2, 0 }, + }); + d.graphicsPipeline->setVertexInputLayout(inputLayout); + d.graphicsPipeline->setShaderResourceBindings(d.graphicsBindings); + d.graphicsPipeline->setRenderPassDescriptor(m_rp); + d.graphicsPipeline->build(); + d.releasePool << d.graphicsPipeline; +} + +void Window::customRelease() +{ + qDeleteAll(d.releasePool); + d.releasePool.clear(); +} + +void Window::customRender() +{ + const QSize outputSizeInPixels = m_sc->currentPixelSize(); + QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer(); + QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch(); + if (d.initialUpdates) { + u->merge(d.initialUpdates); + d.initialUpdates->release(); + d.initialUpdates = nullptr; + } + +#if 0 + u->updateDynamicBuffer(d.computeUniBuf, 0, sizeof(float), &d.step); + d.step += 0.01f; +#endif + + // compute pass + cb->beginComputePass(u); + cb->setComputePipeline(d.computePipeline); + cb->setShaderResources(); + cb->dispatch(DATA_COUNT / 256, 1, 1); + cb->endComputePass(); + + // graphics pass + cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }); + cb->setGraphicsPipeline(d.graphicsPipeline); + cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) }); + QRhiCommandBuffer::VertexInput vbufBinding(d.sbuf, 0); + cb->setVertexInput(0, 1, &vbufBinding); + cb->draw(DATA_COUNT); + cb->endPass(); +} diff --git a/tests/manual/rhi/computebuffer/computebuffer.pro b/tests/manual/rhi/computebuffer/computebuffer.pro new file mode 100644 index 0000000000..ab3c8001f1 --- /dev/null +++ b/tests/manual/rhi/computebuffer/computebuffer.pro @@ -0,0 +1,8 @@ +TEMPLATE = app + +QT += gui-private + +SOURCES = \ + computebuffer.cpp + +RESOURCES = computebuffer.qrc diff --git a/tests/manual/rhi/computebuffer/computebuffer.qrc b/tests/manual/rhi/computebuffer/computebuffer.qrc new file mode 100644 index 0000000000..d9e877a15d --- /dev/null +++ b/tests/manual/rhi/computebuffer/computebuffer.qrc @@ -0,0 +1,7 @@ +<!DOCTYPE RCC><RCC version="1.0"> + <qresource> + <file>buffer.comp.qsb</file> + <file>main.vert.qsb</file> + <file>main.frag.qsb</file> +</qresource> +</RCC> diff --git a/tests/manual/rhi/computebuffer/main.frag b/tests/manual/rhi/computebuffer/main.frag new file mode 100644 index 0000000000..4785a404d3 --- /dev/null +++ b/tests/manual/rhi/computebuffer/main.frag @@ -0,0 +1,8 @@ +#version 440 + +layout(location = 0) out vec4 fragColor; + +void main() +{ + fragColor = vec4(1.0); +} diff --git a/tests/manual/rhi/computebuffer/main.frag.qsb b/tests/manual/rhi/computebuffer/main.frag.qsb Binary files differnew file mode 100644 index 0000000000..f05da411e5 --- /dev/null +++ b/tests/manual/rhi/computebuffer/main.frag.qsb diff --git a/tests/manual/rhi/computebuffer/main.vert b/tests/manual/rhi/computebuffer/main.vert new file mode 100644 index 0000000000..5dfb778d2e --- /dev/null +++ b/tests/manual/rhi/computebuffer/main.vert @@ -0,0 +1,11 @@ +#version 440 + +layout(location = 0) in vec4 position; + +out gl_PerVertex { vec4 gl_Position; float gl_PointSize; }; + +void main() +{ + gl_PointSize = 4.0; // required with Vulkan when drawing points + gl_Position = position; +} diff --git a/tests/manual/rhi/computebuffer/main.vert.qsb b/tests/manual/rhi/computebuffer/main.vert.qsb Binary files differnew file mode 100644 index 0000000000..944645ffbf --- /dev/null +++ b/tests/manual/rhi/computebuffer/main.vert.qsb diff --git a/tests/manual/rhi/computeimage/buildshaders.bat b/tests/manual/rhi/computeimage/buildshaders.bat new file mode 100755 index 0000000000..41a324d2b2 --- /dev/null +++ b/tests/manual/rhi/computeimage/buildshaders.bat @@ -0,0 +1 @@ +qsb --glsl "310 es,430" --hlsl 50 --msl 12 image.comp -o image.comp.qsb diff --git a/tests/manual/rhi/computeimage/computeimage.cpp b/tests/manual/rhi/computeimage/computeimage.cpp new file mode 100644 index 0000000000..a6c860f8ee --- /dev/null +++ b/tests/manual/rhi/computeimage/computeimage.cpp @@ -0,0 +1,228 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "../shared/examplefw.h" + +// Compute shader example with image load/store. The texture sampled in the +// fragment shader is generated by the compute shader. + +struct { + QVector<QRhiResource *> releasePool; + + QRhiTexture *texIn = nullptr; + QRhiTexture *texOut = nullptr; + QRhiBuffer *computeUBuf = nullptr; + QRhiShaderResourceBindings *computeBindings = nullptr; + QRhiComputePipeline *computePipeline = nullptr; + + QRhiBuffer *vbuf = nullptr; + QRhiBuffer *ibuf = nullptr; + QRhiBuffer *ubuf = nullptr; + QRhiSampler *sampler = nullptr; + QRhiShaderResourceBindings *srb = nullptr; + QRhiGraphicsPipeline *ps = nullptr; + + QRhiResourceUpdateBatch *initialUpdates = nullptr; + QSize imageSize; + QMatrix4x4 winProj; + float factor = 1.0f; +} d; + +static float quadVertexData[] = +{ // Y up, CCW + -0.5f, 0.5f, 0.0f, 0.0f, + -0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, 0.5f, 1.0f, 0.0f +}; + +static quint16 quadIndexData[] = +{ + 0, 1, 2, 0, 2, 3 +}; + +void Window::customInit() +{ + if (!m_r->isFeatureSupported(QRhi::Compute)) + qFatal("Compute is not supported"); + + d.initialUpdates = m_r->nextResourceUpdateBatch(); + + // compute pass + + const QImage image = QImage(QLatin1String(":/qt256.png")).convertToFormat(QImage::Format_RGBA8888); + d.imageSize = image.size(); + d.texIn = m_r->newTexture(QRhiTexture::RGBA8, d.imageSize, 1, QRhiTexture::UsedWithLoadStore); + d.texIn->build(); + d.releasePool << d.texIn; + + d.texOut = m_r->newTexture(QRhiTexture::RGBA8, d.imageSize, 1, QRhiTexture::UsedWithLoadStore); + d.texOut->build(); + d.releasePool << d.texOut; + + d.initialUpdates->uploadTexture(d.texIn, image); + + d.computeUBuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 4); + d.computeUBuf->build(); + d.releasePool << d.computeUBuf; + + d.computeBindings = m_r->newShaderResourceBindings(); + d.computeBindings->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::ComputeStage, d.computeUBuf), + QRhiShaderResourceBinding::imageLoad(1, QRhiShaderResourceBinding::ComputeStage, d.texIn, 0), + QRhiShaderResourceBinding::imageStore(2, QRhiShaderResourceBinding::ComputeStage, d.texOut, 0) + }); + d.computeBindings->build(); + d.releasePool << d.computeBindings; + + d.computePipeline = m_r->newComputePipeline(); + d.computePipeline->setShaderResourceBindings(d.computeBindings); + d.computePipeline->setShaderStage({ QRhiShaderStage::Compute, getShader(QLatin1String(":/image.comp.qsb")) }); + d.computePipeline->build(); + d.releasePool << d.computePipeline; + + // graphics pass + + d.vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(quadVertexData)); + d.vbuf->build(); + d.releasePool << d.vbuf; + + d.initialUpdates->uploadStaticBuffer(d.vbuf, quadVertexData); + + d.ibuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::IndexBuffer, sizeof(quadIndexData)); + d.ibuf->build(); + d.releasePool << d.ibuf; + + d.initialUpdates->uploadStaticBuffer(d.ibuf, quadIndexData); + + d.ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 68); + d.ubuf->build(); + d.releasePool << d.ubuf; + + qint32 flip = 0; // regardless of isYUpInFramebuffer() since the input is not flipped so the end result is good for GL too + d.initialUpdates->updateDynamicBuffer(d.ubuf, 64, 4, &flip); + + d.sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None, + QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge); + d.releasePool << d.sampler; + d.sampler->build(); + + d.srb = m_r->newShaderResourceBindings(); + d.releasePool << d.srb; + d.srb->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf), + QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.texOut, d.sampler) + }); + d.srb->build(); + + d.ps = m_r->newGraphicsPipeline(); + d.releasePool << d.ps; + d.ps->setShaderStages({ + { QRhiShaderStage::Vertex, getShader(QLatin1String(":/texture.vert.qsb")) }, + { QRhiShaderStage::Fragment, getShader(QLatin1String(":/texture.frag.qsb")) } + }); + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ + { 4 * sizeof(float) } + }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float2, 0 }, + { 0, 1, QRhiVertexInputAttribute::Float2, 2 * sizeof(float) } + }); + d.ps->setVertexInputLayout(inputLayout); + d.ps->setShaderResourceBindings(d.srb); + d.ps->setRenderPassDescriptor(m_rp); + d.ps->build(); +} + +void Window::customRelease() +{ + qDeleteAll(d.releasePool); + d.releasePool.clear(); +} + +void Window::customRender() +{ + const QSize outputSizeInPixels = m_sc->currentPixelSize(); + QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer(); + QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch(); + if (d.initialUpdates) { + u->merge(d.initialUpdates); + d.initialUpdates->release(); + d.initialUpdates = nullptr; + } + + if (d.winProj != m_proj) { + d.winProj = m_proj; + QMatrix4x4 mvp = m_proj; + mvp.scale(2.5f); + u->updateDynamicBuffer(d.ubuf, 0, 64, mvp.constData()); + } + + u->updateDynamicBuffer(d.computeUBuf, 0, 4, &d.factor); + d.factor += 0.1f; + if (d.factor >= 50.0f) + d.factor = 1.0f; + + cb->beginComputePass(u); + cb->setComputePipeline(d.computePipeline); + cb->setShaderResources(); + cb->dispatch(d.imageSize.width() / 16, d.imageSize.height() / 16, 1); + cb->endComputePass(); + + cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }); + cb->setGraphicsPipeline(d.ps); + cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) }); + cb->setShaderResources(); + QRhiCommandBuffer::VertexInput vbufBinding(d.vbuf, 0); + cb->setVertexInput(0, 1, &vbufBinding, d.ibuf, 0, QRhiCommandBuffer::IndexUInt16); + cb->drawIndexed(6); + cb->endPass(); +} diff --git a/tests/manual/rhi/computeimage/computeimage.pro b/tests/manual/rhi/computeimage/computeimage.pro new file mode 100644 index 0000000000..291a4e91b1 --- /dev/null +++ b/tests/manual/rhi/computeimage/computeimage.pro @@ -0,0 +1,8 @@ +TEMPLATE = app + +QT += gui-private + +SOURCES = \ + computeimage.cpp + +RESOURCES = computeimage.qrc diff --git a/tests/manual/rhi/computeimage/computeimage.qrc b/tests/manual/rhi/computeimage/computeimage.qrc new file mode 100644 index 0000000000..5299e1ae22 --- /dev/null +++ b/tests/manual/rhi/computeimage/computeimage.qrc @@ -0,0 +1,8 @@ +<!DOCTYPE RCC><RCC version="1.0"> + <qresource> + <file>image.comp.qsb</file> + <file alias="texture.vert.qsb">../shared/texture.vert.qsb</file> + <file alias="texture.frag.qsb">../shared/texture.frag.qsb</file> + <file alias="qt256.png">../shared/qt256.png</file> +</qresource> +</RCC> diff --git a/tests/manual/rhi/computeimage/image.comp b/tests/manual/rhi/computeimage/image.comp new file mode 100644 index 0000000000..9826ed7c6c --- /dev/null +++ b/tests/manual/rhi/computeimage/image.comp @@ -0,0 +1,20 @@ +#version 440 + +layout (local_size_x = 16, local_size_y = 16) in; + +layout(std140, binding = 0) uniform UniformBuffer +{ + float factor; +} ubuf; + +layout (binding = 1, rgba8) uniform readonly image2D texIn; +layout (binding = 2, rgba8) uniform writeonly image2D texOut; + +void main() +{ + ivec2 pos = ivec2(gl_GlobalInvocationID.xy); + ivec2 d = ivec2(1, 1); + vec4 diff = imageLoad(texIn, pos + d) - imageLoad(texIn, pos - d); + float c = (diff.x + diff.y + diff.z) / ubuf.factor + 0.5f; + imageStore(texOut, pos, vec4(c, c, c, 1.0)); +} diff --git a/tests/manual/rhi/computeimage/image.comp.qsb b/tests/manual/rhi/computeimage/image.comp.qsb Binary files differnew file mode 100644 index 0000000000..725629f7ab --- /dev/null +++ b/tests/manual/rhi/computeimage/image.comp.qsb diff --git a/tests/manual/rhi/cubemap/buildshaders.bat b/tests/manual/rhi/cubemap/buildshaders.bat new file mode 100644 index 0000000000..ebf673875d --- /dev/null +++ b/tests/manual/rhi/cubemap/buildshaders.bat @@ -0,0 +1,2 @@ +qsb --glsl "100 es,120" --hlsl 50 --msl 12 -c cubemap.vert -o cubemap.vert.qsb +qsb --glsl "100 es,120" --hlsl 50 --msl 12 -c cubemap.frag -o cubemap.frag.qsb diff --git a/tests/manual/rhi/cubemap/c.png b/tests/manual/rhi/cubemap/c.png Binary files differnew file mode 100644 index 0000000000..7b00455e53 --- /dev/null +++ b/tests/manual/rhi/cubemap/c.png diff --git a/tests/manual/rhi/cubemap/cubemap.cpp b/tests/manual/rhi/cubemap/cubemap.cpp new file mode 100644 index 0000000000..fe6ac9762e --- /dev/null +++ b/tests/manual/rhi/cubemap/cubemap.cpp @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "../shared/examplefw.h" +#include "../shared/cube.h" + +struct { + QVector<QRhiResource *> releasePool; + QRhiBuffer *vbuf = nullptr; + QRhiBuffer *ubuf = nullptr; + QRhiTexture *tex = nullptr; + QRhiSampler *sampler = nullptr; + QRhiShaderResourceBindings *srb = nullptr; + QRhiGraphicsPipeline *ps = nullptr; + QRhiResourceUpdateBatch *initialUpdates = nullptr; +} d; + +void Window::customInit() +{ + d.vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(cube)); + d.vbuf->build(); + d.releasePool << d.vbuf; + + d.ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64); + d.ubuf->build(); + d.releasePool << d.ubuf; + + const QSize cubeMapSize(512, 512); + d.tex = m_r->newTexture(QRhiTexture::RGBA8, cubeMapSize, 1, QRhiTexture::CubeMap); + d.releasePool << d.tex; + d.tex->build(); + + d.initialUpdates = m_r->nextResourceUpdateBatch(); + d.initialUpdates->uploadStaticBuffer(d.vbuf, cube); + + QImage img = QImage(":/c.png").mirrored().convertToFormat(QImage::Format_RGBA8888); + // just use the same image for all faces for now + QRhiTextureSubresourceUploadDescription subresDesc(img); + QRhiTextureUploadDescription desc({ + { 0, 0, subresDesc }, // +X + { 1, 0, subresDesc }, // -X + { 2, 0, subresDesc }, // +Y + { 3, 0, subresDesc }, // -Y + { 4, 0, subresDesc }, // +Z + { 5, 0, subresDesc } // -Z + }); + d.initialUpdates->uploadTexture(d.tex, desc); + + d.sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None, + QRhiSampler::Repeat, QRhiSampler::Repeat); + d.releasePool << d.sampler; + d.sampler->build(); + + d.srb = m_r->newShaderResourceBindings(); + d.releasePool << d.srb; + d.srb->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf), + QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.tex, d.sampler) + }); + d.srb->build(); + + d.ps = m_r->newGraphicsPipeline(); + d.releasePool << d.ps; + + d.ps->setDepthTest(true); + d.ps->setDepthWrite(true); + d.ps->setDepthOp(QRhiGraphicsPipeline::LessOrEqual); + + d.ps->setCullMode(QRhiGraphicsPipeline::Front); // we are inside the cube so cull front, not back + d.ps->setFrontFace(QRhiGraphicsPipeline::CCW); // front is ccw in the cube data + + QShader vs = getShader(QLatin1String(":/cubemap.vert.qsb")); + Q_ASSERT(vs.isValid()); + QShader fs = getShader(QLatin1String(":/cubemap.frag.qsb")); + Q_ASSERT(fs.isValid()); + d.ps->setShaderStages({ + { QRhiShaderStage::Vertex, vs }, + { QRhiShaderStage::Fragment, fs } + }); + + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ + { 3 * sizeof(float) } + }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float3, 0 } + }); + + d.ps->setVertexInputLayout(inputLayout); + d.ps->setShaderResourceBindings(d.srb); + d.ps->setRenderPassDescriptor(m_rp); + + d.ps->build(); +} + +void Window::customRelease() +{ + qDeleteAll(d.releasePool); + d.releasePool.clear(); +} + +void Window::customRender() +{ + const QSize outputSizeInPixels = m_sc->currentPixelSize(); + QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer(); + QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch(); + + if (d.initialUpdates) { + u->merge(d.initialUpdates); + d.initialUpdates->release(); + d.initialUpdates = nullptr; + } + + QMatrix4x4 mvp = m_r->clipSpaceCorrMatrix(); + mvp.perspective(90.0f, outputSizeInPixels.width() / (float) outputSizeInPixels.height(), 0.01f, 1000.0f); + // cube vertices go from -1..1 + mvp.scale(10); + static float rx = 0; + mvp.rotate(rx, 1, 0, 0); + rx += 0.5f; + // no translation + u->updateDynamicBuffer(d.ubuf, 0, 64, mvp.constData()); + + cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }, u); + cb->setGraphicsPipeline(d.ps); + cb->setViewport(QRhiViewport(0, 0, outputSizeInPixels.width(), outputSizeInPixels.height())); + cb->setShaderResources(); + const QRhiCommandBuffer::VertexInput vbufBinding(d.vbuf, 0); + cb->setVertexInput(0, 1, &vbufBinding); + cb->draw(36); + cb->endPass(); +} diff --git a/tests/manual/rhi/cubemap/cubemap.frag b/tests/manual/rhi/cubemap/cubemap.frag new file mode 100644 index 0000000000..13a365ed0c --- /dev/null +++ b/tests/manual/rhi/cubemap/cubemap.frag @@ -0,0 +1,10 @@ +#version 440 + +layout(location = 0) in vec3 v_coord; +layout(location = 0) out vec4 fragColor; +layout(binding = 1) uniform samplerCube tex; + +void main() +{ + fragColor = vec4(texture(tex, v_coord).rgb, 1.0); +} diff --git a/tests/manual/rhi/cubemap/cubemap.frag.qsb b/tests/manual/rhi/cubemap/cubemap.frag.qsb Binary files differnew file mode 100644 index 0000000000..d7cc025554 --- /dev/null +++ b/tests/manual/rhi/cubemap/cubemap.frag.qsb diff --git a/tests/manual/rhi/cubemap/cubemap.pro b/tests/manual/rhi/cubemap/cubemap.pro new file mode 100644 index 0000000000..61910ffe20 --- /dev/null +++ b/tests/manual/rhi/cubemap/cubemap.pro @@ -0,0 +1,8 @@ +TEMPLATE = app + +QT += gui-private + +SOURCES = \ + cubemap.cpp + +RESOURCES = cubemap.qrc diff --git a/tests/manual/rhi/cubemap/cubemap.qrc b/tests/manual/rhi/cubemap/cubemap.qrc new file mode 100644 index 0000000000..bacd15446c --- /dev/null +++ b/tests/manual/rhi/cubemap/cubemap.qrc @@ -0,0 +1,7 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file>cubemap.vert.qsb</file> + <file>cubemap.frag.qsb</file> + <file>c.png</file> +</qresource> +</RCC> diff --git a/tests/manual/rhi/cubemap/cubemap.vert b/tests/manual/rhi/cubemap/cubemap.vert new file mode 100644 index 0000000000..65216dd6b0 --- /dev/null +++ b/tests/manual/rhi/cubemap/cubemap.vert @@ -0,0 +1,15 @@ +#version 440 + +layout(location = 0) in vec4 position; +layout(location = 0) out vec3 v_coord; +layout(std140, binding = 0) uniform buf { + mat4 mvp; +} ubuf; + +out gl_PerVertex { vec4 gl_Position; }; + +void main() +{ + v_coord = position.xyz; + gl_Position = ubuf.mvp * position; +} diff --git a/tests/manual/rhi/cubemap/cubemap.vert.qsb b/tests/manual/rhi/cubemap/cubemap.vert.qsb Binary files differnew file mode 100644 index 0000000000..fae136337c --- /dev/null +++ b/tests/manual/rhi/cubemap/cubemap.vert.qsb diff --git a/tests/manual/rhi/cubemap_scissor/cubemap_scissor.cpp b/tests/manual/rhi/cubemap_scissor/cubemap_scissor.cpp new file mode 100644 index 0000000000..25a7c64c8a --- /dev/null +++ b/tests/manual/rhi/cubemap_scissor/cubemap_scissor.cpp @@ -0,0 +1,241 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// This is a test for scissoring. Based on the cubemap test (because there the +// rendering covers the entire viewport which is what we need here). The +// scissor rectangle moves first up, then down, then from the center to the +// left and then to right. The important part is to ensure that the behavior +// identical between all backends, especially when the rectangle is partly or +// fully off window. + +#include "../shared/examplefw.h" +#include "../shared/cube.h" + +struct { + QVector<QRhiResource *> releasePool; + QRhiBuffer *vbuf = nullptr; + QRhiBuffer *ubuf = nullptr; + QRhiTexture *tex = nullptr; + QRhiSampler *sampler = nullptr; + QRhiShaderResourceBindings *srb = nullptr; + QRhiGraphicsPipeline *ps = nullptr; + QRhiResourceUpdateBatch *initialUpdates = nullptr; + + QPoint scissorBottomLeft; + QSize scissorSize; + int scissorAnimState = 0; + QSize outputSize; +} d; + +void Window::customInit() +{ + d.vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(cube)); + d.vbuf->build(); + d.releasePool << d.vbuf; + + d.ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64); + d.ubuf->build(); + d.releasePool << d.ubuf; + + const QSize cubeMapSize(512, 512); + d.tex = m_r->newTexture(QRhiTexture::RGBA8, cubeMapSize, 1, QRhiTexture::CubeMap); + d.releasePool << d.tex; + d.tex->build(); + + d.initialUpdates = m_r->nextResourceUpdateBatch(); + d.initialUpdates->uploadStaticBuffer(d.vbuf, cube); + + QImage img = QImage(":/c.png").mirrored().convertToFormat(QImage::Format_RGBA8888); + // just use the same image for all faces for now + QRhiTextureSubresourceUploadDescription subresDesc(img); + QRhiTextureUploadDescription desc({ + { 0, 0, subresDesc }, // +X + { 1, 0, subresDesc }, // -X + { 2, 0, subresDesc }, // +Y + { 3, 0, subresDesc }, // -Y + { 4, 0, subresDesc }, // +Z + { 5, 0, subresDesc } // -Z + }); + d.initialUpdates->uploadTexture(d.tex, desc); + + d.sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None, + QRhiSampler::Repeat, QRhiSampler::Repeat); + d.releasePool << d.sampler; + d.sampler->build(); + + d.srb = m_r->newShaderResourceBindings(); + d.releasePool << d.srb; + d.srb->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf), + QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.tex, d.sampler) + }); + d.srb->build(); + + d.ps = m_r->newGraphicsPipeline(); + d.releasePool << d.ps; + + d.ps->setFlags(QRhiGraphicsPipeline::UsesScissor); + + d.ps->setDepthTest(true); + d.ps->setDepthWrite(true); + d.ps->setDepthOp(QRhiGraphicsPipeline::LessOrEqual); + + d.ps->setCullMode(QRhiGraphicsPipeline::Front); // we are inside the cube so cull front, not back + d.ps->setFrontFace(QRhiGraphicsPipeline::CCW); // front is ccw in the cube data + + QShader vs = getShader(QLatin1String(":/cubemap.vert.qsb")); + Q_ASSERT(vs.isValid()); + QShader fs = getShader(QLatin1String(":/cubemap.frag.qsb")); + Q_ASSERT(fs.isValid()); + d.ps->setShaderStages({ + { QRhiShaderStage::Vertex, vs }, + { QRhiShaderStage::Fragment, fs } + }); + + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ + { 3 * sizeof(float) } + }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float3, 0 } + }); + + d.ps->setVertexInputLayout(inputLayout); + d.ps->setShaderResourceBindings(d.srb); + d.ps->setRenderPassDescriptor(m_rp); + + d.ps->build(); + + d.scissorAnimState = 0; +} + +void Window::customRelease() +{ + qDeleteAll(d.releasePool); + d.releasePool.clear(); +} + +static void advanceScissor() +{ + switch (d.scissorAnimState) { + case 1: // up + d.scissorBottomLeft.setX(d.outputSize.width() / 4); + d.scissorBottomLeft.ry() += 1; + if (d.scissorBottomLeft.y() > d.outputSize.height() + 100) + d.scissorAnimState = 2; + break; + case 2: // down + d.scissorBottomLeft.ry() -= 1; + if (d.scissorBottomLeft.y() < -d.scissorSize.height() - 100) + d.scissorAnimState = 3; + break; + case 3: // left + d.scissorBottomLeft.setY(d.outputSize.height() / 4); + d.scissorBottomLeft.rx() += 1; + if (d.scissorBottomLeft.x() > d.outputSize.width() + 100) + d.scissorAnimState = 4; + break; + case 4: // right + d.scissorBottomLeft.rx() -= 1; + if (d.scissorBottomLeft.x() < -d.scissorSize.width() - 100) + d.scissorAnimState = 1; + break; + } + + qDebug() << "scissor bottom-left" << d.scissorBottomLeft << "size" << d.scissorSize; +} + +void Window::customRender() +{ + const QSize outputSizeInPixels = m_sc->currentPixelSize(); + QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer(); + QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch(); + + if (d.initialUpdates) { + u->merge(d.initialUpdates); + d.initialUpdates->release(); + d.initialUpdates = nullptr; + } + + d.outputSize = outputSizeInPixels; + if (d.scissorAnimState == 0) { + d.scissorBottomLeft = QPoint(outputSizeInPixels.width() / 4, 0); + d.scissorSize = QSize(outputSizeInPixels.width() / 2, outputSizeInPixels.height() / 2); + d.scissorAnimState = 1; + } + + QMatrix4x4 mvp = m_r->clipSpaceCorrMatrix(); + mvp.perspective(90.0f, outputSizeInPixels.width() / (float) outputSizeInPixels.height(), 0.01f, 1000.0f); + // cube vertices go from -1..1 + mvp.scale(10); + static float rx = 0; + mvp.rotate(rx, 1, 0, 0); + rx += 0.5f; + // no translation + u->updateDynamicBuffer(d.ubuf, 0, 64, mvp.constData()); + + cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }, u); + cb->setGraphicsPipeline(d.ps); + cb->setViewport(QRhiViewport(0, 0, outputSizeInPixels.width(), outputSizeInPixels.height())); + + // Apply a scissor rectangle that moves around on the screen, also + // exercising the out of screen (negative x or y) case. + cb->setScissor(QRhiScissor(d.scissorBottomLeft.x(), d.scissorBottomLeft.y(), + d.scissorSize.width(), d.scissorSize.height())); + + cb->setShaderResources(); + + const QRhiCommandBuffer::VertexInput vbufBinding(d.vbuf, 0); + cb->setVertexInput(0, 1, &vbufBinding); + cb->draw(36); + cb->endPass(); + + advanceScissor(); +} diff --git a/tests/manual/rhi/cubemap_scissor/cubemap_scissor.pro b/tests/manual/rhi/cubemap_scissor/cubemap_scissor.pro new file mode 100644 index 0000000000..1f02bda87a --- /dev/null +++ b/tests/manual/rhi/cubemap_scissor/cubemap_scissor.pro @@ -0,0 +1,8 @@ +TEMPLATE = app + +QT += gui-private + +SOURCES = \ + cubemap_scissor.cpp + +RESOURCES = cubemap_scissor.qrc diff --git a/tests/manual/rhi/cubemap_scissor/cubemap_scissor.qrc b/tests/manual/rhi/cubemap_scissor/cubemap_scissor.qrc new file mode 100644 index 0000000000..8a0ae17dc8 --- /dev/null +++ b/tests/manual/rhi/cubemap_scissor/cubemap_scissor.qrc @@ -0,0 +1,7 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file alias="cubemap.vert.qsb">../cubemap/cubemap.vert.qsb</file> + <file alias="cubemap.frag.qsb">../cubemap/cubemap.frag.qsb</file> + <file alias="c.png">../cubemap/c.png</file> +</qresource> +</RCC> diff --git a/tests/manual/rhi/floattexture/floattexture.cpp b/tests/manual/rhi/floattexture/floattexture.cpp new file mode 100644 index 0000000000..0d24860c78 --- /dev/null +++ b/tests/manual/rhi/floattexture/floattexture.cpp @@ -0,0 +1,328 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "../shared/examplefw.h" +#include <qmath.h> + +QByteArray loadHdr(const QString &fn, QSize *size) +{ + QFile f(fn); + if (!f.open(QIODevice::ReadOnly)) { + qWarning("Failed to open %s", qPrintable(fn)); + return QByteArray(); + } + + char sig[256]; + f.read(sig, 11); + if (strncmp(sig, "#?RADIANCE\n", 11)) + return QByteArray(); + + QByteArray buf = f.readAll(); + const char *p = buf.constData(); + const char *pEnd = p + buf.size(); + + // Process lines until the empty one. + QByteArray line; + while (p < pEnd) { + char c = *p++; + if (c == '\n') { + if (line.isEmpty()) + break; + if (line.startsWith(QByteArrayLiteral("FORMAT="))) { + const QByteArray format = line.mid(7).trimmed(); + if (format != QByteArrayLiteral("32-bit_rle_rgbe")) { + qWarning("HDR format '%s' is not supported", format.constData()); + return QByteArray(); + } + } + line.clear(); + } else { + line.append(c); + } + } + if (p == pEnd) { + qWarning("Malformed HDR image data at property strings"); + return QByteArray(); + } + + // Get the resolution string. + while (p < pEnd) { + char c = *p++; + if (c == '\n') + break; + line.append(c); + } + if (p == pEnd) { + qWarning("Malformed HDR image data at resolution string"); + return QByteArray(); + } + + int w = 0, h = 0; + // We only care about the standard orientation. + if (!sscanf(line.constData(), "-Y %d +X %d", &h, &w)) { + qWarning("Unsupported HDR resolution string '%s'", line.constData()); + return QByteArray(); + } + if (w <= 0 || h <= 0) { + qWarning("Invalid HDR resolution"); + return QByteArray(); + } + + // output is RGBA32F + const int blockSize = 4 * sizeof(float); + QByteArray data; + data.resize(w * h * blockSize); + + typedef unsigned char RGBE[4]; + RGBE *scanline = new RGBE[w]; + + for (int y = 0; y < h; ++y) { + if (pEnd - p < 4) { + qWarning("Unexpected end of HDR data"); + delete[] scanline; + return QByteArray(); + } + + scanline[0][0] = *p++; + scanline[0][1] = *p++; + scanline[0][2] = *p++; + scanline[0][3] = *p++; + + if (scanline[0][0] == 2 && scanline[0][1] == 2 && scanline[0][2] < 128) { + // new rle, the first pixel was a dummy + for (int channel = 0; channel < 4; ++channel) { + for (int x = 0; x < w && p < pEnd; ) { + unsigned char c = *p++; + if (c > 128) { // run + if (p < pEnd) { + int repCount = c & 127; + c = *p++; + while (repCount--) + scanline[x++][channel] = c; + } + } else { // not a run + while (c-- && p < pEnd) + scanline[x++][channel] = *p++; + } + } + } + } else { + // old rle + scanline[0][0] = 2; + int bitshift = 0; + int x = 1; + while (x < w && pEnd - p >= 4) { + scanline[x][0] = *p++; + scanline[x][1] = *p++; + scanline[x][2] = *p++; + scanline[x][3] = *p++; + + if (scanline[x][0] == 1 && scanline[x][1] == 1 && scanline[x][2] == 1) { // run + int repCount = scanline[x][3] << bitshift; + while (repCount--) { + memcpy(scanline[x], scanline[x - 1], 4); + ++x; + } + bitshift += 8; + } else { // not a run + ++x; + bitshift = 0; + } + } + } + + // adjust for -Y orientation + float *fp = reinterpret_cast<float *>(data.data() + (h - 1 - y) * blockSize * w); + for (int x = 0; x < w; ++x) { + float d = qPow(2.0f, float(scanline[x][3]) - 128.0f); + // r, g, b, a + *fp++ = scanline[x][0] / 256.0f * d; + *fp++ = scanline[x][1] / 256.0f * d; + *fp++ = scanline[x][2] / 256.0f * d; + *fp++ = 1.0f; + } + } + + delete[] scanline; + + if (size) + *size = QSize(w, h); + + return data; +} + +static float vertexData[] = +{ // Y up, CCW + -0.5f, 0.5f, 0.0f, 0.0f, + -0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, 0.5f, 1.0f, 0.0f +}; + +static quint16 indexData[] = +{ + 0, 1, 2, 0, 2, 3 +}; + +struct { + QVector<QRhiResource *> releasePool; + QRhiBuffer *vbuf = nullptr; + QRhiBuffer *ibuf = nullptr; + QRhiBuffer *ubuf = nullptr; + QRhiTexture *tex = nullptr; + QRhiSampler *sampler = nullptr; + QRhiShaderResourceBindings *srb = nullptr; + QRhiGraphicsPipeline *ps = nullptr; + QRhiResourceUpdateBatch *initialUpdates = nullptr; + QMatrix4x4 winProj; +} d; + +void Window::customInit() +{ + if (!m_r->isTextureFormatSupported(QRhiTexture::RGBA32F)) + qWarning("RGBA32F texture format is not supported"); + + QSize size; + QByteArray floatData = loadHdr(QLatin1String(":/OpenfootageNET_fieldairport-512.hdr"), &size); + Q_ASSERT(!floatData.isEmpty()); + qDebug() << size; + + d.vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData)); + d.vbuf->build(); + d.releasePool << d.vbuf; + + d.ibuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::IndexBuffer, sizeof(indexData)); + d.ibuf->build(); + d.releasePool << d.ibuf; + + d.ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 68); + d.ubuf->build(); + d.releasePool << d.ubuf; + + d.tex = m_r->newTexture(QRhiTexture::RGBA32F, size); + d.releasePool << d.tex; + d.tex->build(); + + d.sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None, + QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge); + d.releasePool << d.sampler; + d.sampler->build(); + + d.srb = m_r->newShaderResourceBindings(); + d.releasePool << d.srb; + d.srb->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf), + QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.tex, d.sampler) + }); + d.srb->build(); + + d.ps = m_r->newGraphicsPipeline(); + d.releasePool << d.ps; + d.ps->setShaderStages({ + { QRhiShaderStage::Vertex, getShader(QLatin1String(":/texture.vert.qsb")) }, + { QRhiShaderStage::Fragment, getShader(QLatin1String(":/texture.frag.qsb")) } + }); + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ + { 4 * sizeof(float) } + }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float2, 0 }, + { 0, 1, QRhiVertexInputAttribute::Float2, 2 * sizeof(float) } + }); + d.ps->setVertexInputLayout(inputLayout); + d.ps->setShaderResourceBindings(d.srb); + d.ps->setRenderPassDescriptor(m_rp); + d.ps->build(); + + d.initialUpdates = m_r->nextResourceUpdateBatch(); + d.initialUpdates->uploadStaticBuffer(d.vbuf, vertexData); + d.initialUpdates->uploadStaticBuffer(d.ibuf, indexData); + + qint32 flip = 1; + d.initialUpdates->updateDynamicBuffer(d.ubuf, 64, 4, &flip); + + QRhiTextureUploadDescription desc({ 0, 0, { floatData.constData(), floatData.size() } }); + d.initialUpdates->uploadTexture(d.tex, desc); +} + +void Window::customRelease() +{ + qDeleteAll(d.releasePool); + d.releasePool.clear(); +} + +void Window::customRender() +{ + QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer(); + QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch(); + if (d.initialUpdates) { + u->merge(d.initialUpdates); + d.initialUpdates->release(); + d.initialUpdates = nullptr; + } + + if (d.winProj != m_proj) { + d.winProj = m_proj; + QMatrix4x4 mvp = m_proj; + mvp.scale(2.5f); + u->updateDynamicBuffer(d.ubuf, 0, 64, mvp.constData()); + } + + const QSize outputSizeInPixels = m_sc->currentPixelSize(); + cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }, u); + cb->setGraphicsPipeline(d.ps); + cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) }); + cb->setShaderResources(); + const QRhiCommandBuffer::VertexInput vbufBinding(d.vbuf, 0); + cb->setVertexInput(0, 1, &vbufBinding, d.ibuf, 0, QRhiCommandBuffer::IndexUInt16); + cb->drawIndexed(6); + cb->endPass(); +} diff --git a/tests/manual/rhi/floattexture/floattexture.pro b/tests/manual/rhi/floattexture/floattexture.pro new file mode 100644 index 0000000000..e566da2b94 --- /dev/null +++ b/tests/manual/rhi/floattexture/floattexture.pro @@ -0,0 +1,8 @@ +TEMPLATE = app + +QT += gui-private + +SOURCES = \ + floattexture.cpp + +RESOURCES = floattexture.qrc diff --git a/tests/manual/rhi/floattexture/floattexture.qrc b/tests/manual/rhi/floattexture/floattexture.qrc new file mode 100644 index 0000000000..fefb56b910 --- /dev/null +++ b/tests/manual/rhi/floattexture/floattexture.qrc @@ -0,0 +1,7 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file alias="texture.vert.qsb">../shared/texture.vert.qsb</file> + <file alias="texture.frag.qsb">../shared/texture.frag.qsb</file> + <file alias="OpenfootageNET_fieldairport-512.hdr">../shared/OpenfootageNET_fieldairport-512.hdr</file> +</qresource> +</RCC> diff --git a/tests/manual/rhi/hellominimalcrossgfxtriangle/hellominimalcrossgfxtriangle.cpp b/tests/manual/rhi/hellominimalcrossgfxtriangle/hellominimalcrossgfxtriangle.cpp new file mode 100644 index 0000000000..ea1fefc308 --- /dev/null +++ b/tests/manual/rhi/hellominimalcrossgfxtriangle/hellominimalcrossgfxtriangle.cpp @@ -0,0 +1,550 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// This is a compact, minimal, single-file demo of deciding the backend at +// runtime while using the exact same shaders and rendering code without any +// branching whatsoever once the QWindow is up and the RHI is initialized. + +#include <QGuiApplication> +#include <QCommandLineParser> +#include <QWindow> +#include <QPlatformSurfaceEvent> +#include <QElapsedTimer> + +#include <QtGui/private/qshader_p.h> +#include <QFile> + +#include <QtGui/private/qrhinull_p.h> + +#ifndef QT_NO_OPENGL +#include <QtGui/private/qrhigles2_p.h> +#include <QOffscreenSurface> +#endif + +#if QT_CONFIG(vulkan) +#include <QLoggingCategory> +#include <QtGui/private/qrhivulkan_p.h> +#endif + +#ifdef Q_OS_WIN +#include <QtGui/private/qrhid3d11_p.h> +#endif + +#ifdef Q_OS_DARWIN +#include <QtGui/private/qrhimetal_p.h> +#endif + +static float vertexData[] = { + // Y up (note clipSpaceCorrMatrix in m_proj), CCW + 0.0f, 0.5f, 1.0f, 0.0f, 0.0f, + -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, + 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, +}; + +static QShader getShader(const QString &name) +{ + QFile f(name); + if (f.open(QIODevice::ReadOnly)) + return QShader::fromSerialized(f.readAll()); + + return QShader(); +} + +enum GraphicsApi +{ + OpenGL, + Vulkan, + D3D11, + Metal, + Null +}; + +static GraphicsApi graphicsApi; + +static QString graphicsApiName() +{ + switch (graphicsApi) { + case OpenGL: + return QLatin1String("OpenGL 2.x"); + case Vulkan: + return QLatin1String("Vulkan"); + case D3D11: + return QLatin1String("Direct3D 11"); + case Metal: + return QLatin1String("Metal"); + case Null: + return QLatin1String("Null"); + default: + break; + } + return QString(); +} + +class Window : public QWindow +{ +public: + Window(); + ~Window(); + + void init(); + void releaseResources(); + void resizeSwapChain(); + void releaseSwapChain(); + void render(); + + void exposeEvent(QExposeEvent *) override; + bool event(QEvent *) override; + +private: + bool m_running = false; + bool m_notExposed = false; + bool m_newlyExposed = false; + + QRhi *m_r = nullptr; + bool m_hasSwapChain = false; + QRhiSwapChain *m_sc = nullptr; + QRhiRenderBuffer *m_ds = nullptr; + QRhiRenderPassDescriptor *m_rp = nullptr; + QRhiBuffer *m_vbuf = nullptr; + bool m_vbufReady = false; + QRhiBuffer *m_ubuf = nullptr; + QRhiShaderResourceBindings *m_srb = nullptr; + QRhiGraphicsPipeline *m_ps = nullptr; + QVector<QRhiResource *> releasePool; + + QMatrix4x4 m_proj; + float m_rotation = 0; + float m_opacity = 1; + int m_opacityDir = -1; + + QElapsedTimer m_timer; + qint64 m_elapsedMs; + int m_elapsedCount; + +#ifndef QT_NO_OPENGL + QOffscreenSurface *m_fallbackSurface = nullptr; +#endif +}; + +Window::Window() +{ + // Tell the platform plugin what we want. + switch (graphicsApi) { + case OpenGL: +#if QT_CONFIG(opengl) + setSurfaceType(OpenGLSurface); + setFormat(QRhiGles2InitParams::adjustedFormat()); +#endif + break; + case Vulkan: + setSurfaceType(VulkanSurface); + break; + case D3D11: + setSurfaceType(OpenGLSurface); // not a typo + break; + case Metal: +#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) + setSurfaceType(MetalSurface); +#endif + break; + default: + break; + } +} + +Window::~Window() +{ + releaseResources(); +} + +void Window::exposeEvent(QExposeEvent *) +{ + // initialize and start rendering when the window becomes usable for graphics purposes + if (isExposed() && !m_running) { + m_running = true; + init(); + resizeSwapChain(); + } + + // stop pushing frames when not exposed (or size is 0) + if ((!isExposed() || (m_hasSwapChain && m_sc->surfacePixelSize().isEmpty())) && m_running) + m_notExposed = true; + + // continue when exposed again and the surface has a valid size. + // note that the surface size can be (0, 0) even though size() reports a valid one... + if (isExposed() && m_running && m_notExposed && !m_sc->surfacePixelSize().isEmpty()) { + m_notExposed = false; + m_newlyExposed = true; + } + + // always render a frame on exposeEvent() (when exposed) in order to update + // immediately on window resize. + if (isExposed() && !m_sc->surfacePixelSize().isEmpty()) + render(); +} + +bool Window::event(QEvent *e) +{ + switch (e->type()) { + case QEvent::UpdateRequest: + render(); + break; + + case QEvent::PlatformSurface: + // this is the proper time to tear down the swapchain (while the native window and surface are still around) + if (static_cast<QPlatformSurfaceEvent *>(e)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) + releaseSwapChain(); + break; + + default: + break; + } + + return QWindow::event(e); +} + +void Window::init() +{ + if (graphicsApi == Null) { + QRhiNullInitParams params; + m_r = QRhi::create(QRhi::Null, ¶ms); + } + +#ifndef QT_NO_OPENGL + if (graphicsApi == OpenGL) { + m_fallbackSurface = QRhiGles2InitParams::newFallbackSurface(); + QRhiGles2InitParams params; + params.fallbackSurface = m_fallbackSurface; + params.window = this; + m_r = QRhi::create(QRhi::OpenGLES2, ¶ms); + } +#endif + +#if QT_CONFIG(vulkan) + if (graphicsApi == Vulkan) { + QRhiVulkanInitParams params; + params.inst = vulkanInstance(); + params.window = this; + m_r = QRhi::create(QRhi::Vulkan, ¶ms); + } +#endif + +#ifdef Q_OS_WIN + if (graphicsApi == D3D11) { + QRhiD3D11InitParams params; + m_r = QRhi::create(QRhi::D3D11, ¶ms); + } +#endif + +#ifdef Q_OS_DARWIN + if (graphicsApi == Metal) { + QRhiMetalInitParams params; + m_r = QRhi::create(QRhi::Metal, ¶ms); + } +#endif + + if (!m_r) + qFatal("Failed to create RHI backend"); + + // now onto the backend-independent init + + m_sc = m_r->newSwapChain(); + // allow depth-stencil, although we do not actually enable depth test/write for the triangle + m_ds = m_r->newRenderBuffer(QRhiRenderBuffer::DepthStencil, + QSize(), // no need to set the size here, due to UsedWithSwapChainOnly + 1, + QRhiRenderBuffer::UsedWithSwapChainOnly); + releasePool << m_ds; + m_sc->setWindow(this); + m_sc->setDepthStencil(m_ds); + m_rp = m_sc->newCompatibleRenderPassDescriptor(); + releasePool << m_rp; + m_sc->setRenderPassDescriptor(m_rp); + + m_vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData)); + releasePool << m_vbuf; + m_vbuf->build(); + m_vbufReady = false; + + m_ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 68); + releasePool << m_ubuf; + m_ubuf->build(); + + m_srb = m_r->newShaderResourceBindings(); + releasePool << m_srb; + m_srb->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, m_ubuf) + }); + m_srb->build(); + + m_ps = m_r->newGraphicsPipeline(); + releasePool << m_ps; + + QRhiGraphicsPipeline::TargetBlend premulAlphaBlend; + premulAlphaBlend.enable = true; + m_ps->setTargetBlends({ premulAlphaBlend }); + + const QShader vs = getShader(QLatin1String(":/color.vert.qsb")); + if (!vs.isValid()) + qFatal("Failed to load shader pack (vertex)"); + const QShader fs = getShader(QLatin1String(":/color.frag.qsb")); + if (!fs.isValid()) + qFatal("Failed to load shader pack (fragment)"); + + m_ps->setShaderStages({ + { QRhiShaderStage::Vertex, vs }, + { QRhiShaderStage::Fragment, fs } + }); + + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ + { 5 * sizeof(float) } + }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float2, 0 }, + { 0, 1, QRhiVertexInputAttribute::Float3, 2 * sizeof(float) } + }); + + m_ps->setVertexInputLayout(inputLayout); + m_ps->setShaderResourceBindings(m_srb); + m_ps->setRenderPassDescriptor(m_rp); + + m_ps->build(); +} + +void Window::releaseResources() +{ + qDeleteAll(releasePool); + releasePool.clear(); + + delete m_sc; // native swapchain is likely released already + m_sc = nullptr; + + delete m_r; + +#ifndef QT_NO_OPENGL + delete m_fallbackSurface; +#endif +} + +void Window::resizeSwapChain() +{ + m_hasSwapChain = m_sc->buildOrResize(); // also handles m_ds + + m_elapsedMs = 0; + m_elapsedCount = 0; + + const QSize outputSize = m_sc->currentPixelSize(); + m_proj = m_r->clipSpaceCorrMatrix(); + m_proj.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 100.0f); + m_proj.translate(0, 0, -4); +} + +void Window::releaseSwapChain() +{ + if (m_hasSwapChain) { + m_hasSwapChain = false; + m_sc->release(); + } +} + +void Window::render() +{ + if (!m_hasSwapChain || m_notExposed) + return; + + // If the window got resized or got newly exposed, resize the swapchain. + // (the newly-exposed case is not actually required by some + // platforms/backends, but f.ex. Vulkan on Windows seems to need it) + if (m_sc->currentPixelSize() != m_sc->surfacePixelSize() || m_newlyExposed) { + resizeSwapChain(); + if (!m_hasSwapChain) + return; + m_newlyExposed = false; + } + + // Start a new frame. This is where we block when too far ahead of + // GPU/present, and that's what throttles the thread to the refresh rate. + // (except for OpenGL where it happens either in endFrame or somewhere else + // depending on the GL implementation) + QRhi::FrameOpResult r = m_r->beginFrame(m_sc); + if (r == QRhi::FrameOpSwapChainOutOfDate) { + resizeSwapChain(); + if (!m_hasSwapChain) + return; + r = m_r->beginFrame(m_sc); + } + if (r != QRhi::FrameOpSuccess) { + requestUpdate(); + return; + } + + if (m_elapsedCount) + m_elapsedMs += m_timer.elapsed(); + m_timer.restart(); + m_elapsedCount += 1; + if (m_elapsedMs >= 4000) { + qDebug("%f", m_elapsedCount / 4.0f); + m_elapsedMs = 0; + m_elapsedCount = 0; + } + + // Set up buffer updates. + QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch(); + if (!m_vbufReady) { + m_vbufReady = true; + u->uploadStaticBuffer(m_vbuf, vertexData); + } + m_rotation += 1.0f; + QMatrix4x4 mvp = m_proj; + mvp.rotate(m_rotation, 0, 1, 0); + u->updateDynamicBuffer(m_ubuf, 0, 64, mvp.constData()); + m_opacity += m_opacityDir * 0.005f; + if (m_opacity < 0.0f || m_opacity > 1.0f) { + m_opacityDir *= -1; + m_opacity = qBound(0.0f, m_opacity, 1.0f); + } + u->updateDynamicBuffer(m_ubuf, 64, 4, &m_opacity); + + QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer(); + const QSize outputSizeInPixels = m_sc->currentPixelSize(); + + // Apply buffer updates, clear, start the renderpass (where applicable). + cb->beginPass(m_sc->currentFrameRenderTarget(), QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f), { 1.0f, 0 }, u); + + cb->setGraphicsPipeline(m_ps); + cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) }); + cb->setShaderResources(); + + const QRhiCommandBuffer::VertexInput vbufBinding(m_vbuf, 0); + cb->setVertexInput(0, 1, &vbufBinding); + cb->draw(3); + + cb->endPass(); + + // Submit. + m_r->endFrame(m_sc); + + requestUpdate(); // render continuously, throttled by the presentation rate (due to beginFrame above) +} + +int main(int argc, char **argv) +{ + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QGuiApplication app(argc, argv); + + // Defaults. +#if defined(Q_OS_WIN) + graphicsApi = D3D11; +#elif defined(Q_OS_DARWIN) + graphicsApi = Metal; +#elif QT_CONFIG(vulkan) + graphicsApi = Vulkan; +#else + graphicsApi = OpenGL; +#endif + + // Allow overriding via the command line. + QCommandLineParser cmdLineParser; + cmdLineParser.addHelpOption(); + QCommandLineOption glOption({ "g", "opengl" }, QLatin1String("OpenGL (2.x)")); + cmdLineParser.addOption(glOption); + QCommandLineOption vkOption({ "v", "vulkan" }, QLatin1String("Vulkan")); + cmdLineParser.addOption(vkOption); + QCommandLineOption d3dOption({ "d", "d3d11" }, QLatin1String("Direct3D 11")); + cmdLineParser.addOption(d3dOption); + QCommandLineOption mtlOption({ "m", "metal" }, QLatin1String("Metal")); + cmdLineParser.addOption(mtlOption); + QCommandLineOption nullOption({ "n", "null" }, QLatin1String("Null")); + cmdLineParser.addOption(nullOption); + cmdLineParser.process(app); + if (cmdLineParser.isSet(glOption)) + graphicsApi = OpenGL; + if (cmdLineParser.isSet(vkOption)) + graphicsApi = Vulkan; + if (cmdLineParser.isSet(d3dOption)) + graphicsApi = D3D11; + if (cmdLineParser.isSet(mtlOption)) + graphicsApi = Metal; + if (cmdLineParser.isSet(nullOption)) + graphicsApi = Null; + + // Vulkan setup. +#if QT_CONFIG(vulkan) + QVulkanInstance inst; + if (graphicsApi == Vulkan) { + if (!inst.create()) { + qWarning("Failed to create Vulkan instance, switching to OpenGL"); + graphicsApi = OpenGL; + } + } +#endif + + // Create and show the window. + Window w; +#if QT_CONFIG(vulkan) + if (graphicsApi == Vulkan) + w.setVulkanInstance(&inst); +#endif + w.resize(1280, 720); + w.setTitle(graphicsApiName()); + w.show(); + + // Window::event() will not get invoked when the + // PlatformSurfaceAboutToBeDestroyed event is sent during the QWindow + // destruction. That happens only when exiting via app::quit() instead of + // the more common QWindow::close(). Take care of it: if the + // QPlatformWindow is still around (there was no close() yet), get rid of + // the swapchain while it's not too late. + if (w.handle()) + w.releaseSwapChain(); + + return app.exec(); +} diff --git a/tests/manual/rhi/hellominimalcrossgfxtriangle/hellominimalcrossgfxtriangle.pro b/tests/manual/rhi/hellominimalcrossgfxtriangle/hellominimalcrossgfxtriangle.pro new file mode 100644 index 0000000000..eeef33ff6a --- /dev/null +++ b/tests/manual/rhi/hellominimalcrossgfxtriangle/hellominimalcrossgfxtriangle.pro @@ -0,0 +1,8 @@ +TEMPLATE = app + +QT += gui-private + +SOURCES = \ + hellominimalcrossgfxtriangle.cpp + +RESOURCES = hellominimalcrossgfxtriangle.qrc diff --git a/tests/manual/rhi/hellominimalcrossgfxtriangle/hellominimalcrossgfxtriangle.qrc b/tests/manual/rhi/hellominimalcrossgfxtriangle/hellominimalcrossgfxtriangle.qrc new file mode 100644 index 0000000000..8cec4fa9ec --- /dev/null +++ b/tests/manual/rhi/hellominimalcrossgfxtriangle/hellominimalcrossgfxtriangle.qrc @@ -0,0 +1,6 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file alias="color.vert.qsb">../shared/color.vert.qsb</file> + <file alias="color.frag.qsb">../shared/color.frag.qsb</file> +</qresource> +</RCC> diff --git a/tests/manual/rhi/instancing/buildshaders.bat b/tests/manual/rhi/instancing/buildshaders.bat new file mode 100644 index 0000000000..9053a1c54a --- /dev/null +++ b/tests/manual/rhi/instancing/buildshaders.bat @@ -0,0 +1,2 @@ +qsb --glsl "330,300 es" --hlsl 50 --msl 12 inst.vert -o inst.vert.qsb +qsb --glsl "330,300 es" --hlsl 50 --msl 12 inst.frag -o inst.frag.qsb diff --git a/tests/manual/rhi/instancing/inst.frag b/tests/manual/rhi/instancing/inst.frag new file mode 100644 index 0000000000..719fd79ff5 --- /dev/null +++ b/tests/manual/rhi/instancing/inst.frag @@ -0,0 +1,9 @@ +#version 440 + +layout(location = 0) in vec3 vColor; +layout(location = 0) out vec4 fragColor; + +void main() +{ + fragColor = vec4(vColor, 1.0); +} diff --git a/tests/manual/rhi/instancing/inst.frag.qsb b/tests/manual/rhi/instancing/inst.frag.qsb Binary files differnew file mode 100644 index 0000000000..f19a2f0a71 --- /dev/null +++ b/tests/manual/rhi/instancing/inst.frag.qsb diff --git a/tests/manual/rhi/instancing/inst.vert b/tests/manual/rhi/instancing/inst.vert new file mode 100644 index 0000000000..3e1b117d58 --- /dev/null +++ b/tests/manual/rhi/instancing/inst.vert @@ -0,0 +1,25 @@ +#version 440 + +layout(location = 0) in vec4 position; + +// Instanced attributes to variate the translation and color of the cube +layout(location = 1) in vec3 instTranslate; +layout(location = 2) in vec3 instColor; + +layout(location = 0) out vec3 vColor; + +out gl_PerVertex { vec4 gl_Position; }; + +layout(std140, binding = 0) uniform buf { + mat4 mvp; +} ubuf; + +void main() +{ + vColor = instColor; + mat4 t = mat4(1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + instTranslate.x, instTranslate.y, instTranslate.z, 1); + gl_Position = ubuf.mvp * t * position; +} diff --git a/tests/manual/rhi/instancing/inst.vert.qsb b/tests/manual/rhi/instancing/inst.vert.qsb Binary files differnew file mode 100644 index 0000000000..de05eae80f --- /dev/null +++ b/tests/manual/rhi/instancing/inst.vert.qsb diff --git a/tests/manual/rhi/instancing/instancing.cpp b/tests/manual/rhi/instancing/instancing.cpp new file mode 100644 index 0000000000..bdafbd81bc --- /dev/null +++ b/tests/manual/rhi/instancing/instancing.cpp @@ -0,0 +1,175 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "../shared/examplefw.h" +#include "../shared/cube.h" +#include <QRandomGenerator> + +// Instanced draw example. When running with OpenGL, at least 3.3 or ES 3.0 is +// needed. + +const int INSTANCE_COUNT = 1024; + +struct { + QVector<QRhiResource *> releasePool; + + QRhiBuffer *vbuf = nullptr; + QRhiBuffer *instBuf = nullptr; + QRhiBuffer *ubuf = nullptr; + QRhiShaderResourceBindings *srb = nullptr; + QRhiGraphicsPipeline *ps = nullptr; + + QRhiResourceUpdateBatch *initialUpdates = nullptr; + QMatrix4x4 winProj; +} d; + +void Window::customInit() +{ + if (!m_r->isFeatureSupported(QRhi::Instancing)) + qFatal("Instanced drawing is not supported"); + + d.initialUpdates = m_r->nextResourceUpdateBatch(); + + d.vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(cube)); + d.vbuf->build(); + d.releasePool << d.vbuf; + + d.initialUpdates->uploadStaticBuffer(d.vbuf, cube); + + // translation + color (vec3 + vec3), interleaved, for each instance + d.instBuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, INSTANCE_COUNT * 6 * sizeof(float)); + d.instBuf->build(); + d.releasePool << d.instBuf; + + d.ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64 + 12); + d.ubuf->build(); + d.releasePool << d.ubuf; + + d.srb = m_r->newShaderResourceBindings(); + d.releasePool << d.srb; + d.srb->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage, d.ubuf) + }); + d.srb->build(); + + d.ps = m_r->newGraphicsPipeline(); + d.releasePool << d.ps; + d.ps->setShaderStages({ + { QRhiShaderStage::Vertex, getShader(QLatin1String(":/inst.vert.qsb")) }, + { QRhiShaderStage::Fragment, getShader(QLatin1String(":/inst.frag.qsb")) } + }); + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ + { 3 * sizeof(float) }, // cube vertices + { 6 * sizeof(float), QRhiVertexInputBinding::PerInstance } // per-instance translation and color + }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float3, 0 }, // position + { 1, 1, QRhiVertexInputAttribute::Float3, 0 }, // instTranslate + { 1, 2, QRhiVertexInputAttribute::Float3, 3 * sizeof(float) } // instColor + }); + d.ps->setVertexInputLayout(inputLayout); + d.ps->setShaderResourceBindings(d.srb); + d.ps->setRenderPassDescriptor(m_rp); + d.ps->build(); + + QByteArray instData; + instData.resize(INSTANCE_COUNT * 6 * sizeof(float)); + float *p = reinterpret_cast<float *>(instData.data()); + QRandomGenerator *rgen = QRandomGenerator::global(); + for (int i = 0; i < INSTANCE_COUNT; ++i) { + // translation + *p++ = rgen->bounded(8000) / 100.0f - 40.0f; + *p++ = rgen->bounded(8000) / 100.0f - 40.0f; + *p++ = 0.0f; + // color + *p++ = i / float(INSTANCE_COUNT); + *p++ = 0.0f; + *p++ = 0.0f; + } + d.initialUpdates->uploadStaticBuffer(d.instBuf, instData.constData()); +} + +void Window::customRelease() +{ + qDeleteAll(d.releasePool); + d.releasePool.clear(); +} + +void Window::customRender() +{ + const QSize outputSizeInPixels = m_sc->currentPixelSize(); + QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer(); + QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch(); + if (d.initialUpdates) { + u->merge(d.initialUpdates); + d.initialUpdates->release(); + d.initialUpdates = nullptr; + } + + if (d.winProj != m_proj) { + d.winProj = m_proj; + QMatrix4x4 mvp = m_proj; + mvp.scale(0.05f); + u->updateDynamicBuffer(d.ubuf, 0, 64, mvp.constData()); + } + + cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }, u); + cb->setGraphicsPipeline(d.ps); + cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) }); + cb->setShaderResources(); + const QRhiCommandBuffer::VertexInput vbufBinding[] = { + { d.vbuf, 0 }, + { d.instBuf, 0 } + }; + cb->setVertexInput(0, 2, vbufBinding); + cb->draw(36, INSTANCE_COUNT); + cb->endPass(); +} diff --git a/tests/manual/rhi/instancing/instancing.pro b/tests/manual/rhi/instancing/instancing.pro new file mode 100644 index 0000000000..416c79f28a --- /dev/null +++ b/tests/manual/rhi/instancing/instancing.pro @@ -0,0 +1,8 @@ +TEMPLATE = app + +QT += gui-private + +SOURCES = \ + instancing.cpp + +RESOURCES = instancing.qrc diff --git a/tests/manual/rhi/instancing/instancing.qrc b/tests/manual/rhi/instancing/instancing.qrc new file mode 100644 index 0000000000..db21a9d8aa --- /dev/null +++ b/tests/manual/rhi/instancing/instancing.qrc @@ -0,0 +1,6 @@ +<!DOCTYPE RCC><RCC version="1.0"> + <qresource> + <file>inst.vert.qsb</file> + <file>inst.frag.qsb</file> +</qresource> +</RCC> diff --git a/tests/manual/rhi/mrt/buildshaders.bat b/tests/manual/rhi/mrt/buildshaders.bat new file mode 100644 index 0000000000..75741448b1 --- /dev/null +++ b/tests/manual/rhi/mrt/buildshaders.bat @@ -0,0 +1,2 @@ +qsb --glsl "100 es,120" --hlsl 50 --msl 12 -c mrt.vert -o mrt.vert.qsb +qsb --glsl "100 es,120" --hlsl 50 --msl 12 -c mrt.frag -o mrt.frag.qsb diff --git a/tests/manual/rhi/mrt/mrt.cpp b/tests/manual/rhi/mrt/mrt.cpp new file mode 100644 index 0000000000..dfec5bb1d1 --- /dev/null +++ b/tests/manual/rhi/mrt/mrt.cpp @@ -0,0 +1,294 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "../shared/examplefw.h" + +// Exercises MRT, by attaching 4 textures to a single QRhiTextureRenderTarget. +// The fragment shader outputs to all four targets. +// The textures are then used to render 4 quads, so their contents can be confirmed. + +const int ATTCOUNT = 4; + +static float quadVertexData[] = +{ // Y up, CCW + -0.5f, 0.5f, 0.0f, 0.0f, + -0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, 0.5f, 1.0f, 0.0f +}; + +static quint16 quadIndexData[] = +{ + 0, 1, 2, 0, 2, 3 +}; + +static float triangleData[] = +{ // Y up, CCW + 0.0f, 0.5f, 1.0f, 0.0f, 0.0f, + -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, + 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, +}; + +struct { + QVector<QRhiResource *> releasePool; + QRhiBuffer *vbuf = nullptr; + QRhiBuffer *ibuf = nullptr; + QRhiBuffer *ubuf = nullptr; + QRhiTextureRenderTarget *rt = nullptr; + QRhiRenderPassDescriptor *rtRp = nullptr; + QRhiSampler *sampler = nullptr; + QRhiGraphicsPipeline *ps = nullptr; + QRhiResourceUpdateBatch *initialUpdates = nullptr; + QMatrix4x4 winProj; + struct PerColorBuffer { + QRhiTexture *tex = nullptr; + QRhiShaderResourceBindings *srb = nullptr; + }; + PerColorBuffer colData[ATTCOUNT]; + + QRhiBuffer *triUbuf = nullptr; + QRhiShaderResourceBindings *triSrb = nullptr; + QRhiGraphicsPipeline *triPs = nullptr; + float triRot = 0; + QMatrix4x4 triBaseMvp; +} d; + +void Window::customInit() +{ + qDebug("Max color attachments: %d", m_r->resourceLimit(QRhi::MaxColorAttachments)); + if (m_r->resourceLimit(QRhi::MaxColorAttachments) < 4) + qWarning("MRT is not supported"); + + d.vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(quadVertexData) + sizeof(triangleData)); + d.vbuf->build(); + d.releasePool << d.vbuf; + + d.ibuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::IndexBuffer, sizeof(quadIndexData)); + d.ibuf->build(); + d.releasePool << d.ibuf; + + const int oneRoundedUniformBlockSize = m_r->ubufAligned(68); + d.ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, oneRoundedUniformBlockSize * ATTCOUNT); + d.ubuf->build(); + d.releasePool << d.ubuf; + + d.sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None, + QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge); + d.releasePool << d.sampler; + d.sampler->build(); + + for (int i = 0; i < ATTCOUNT; ++i) { + QRhiTexture *tex = m_r->newTexture(QRhiTexture::RGBA8, QSize(512, 512), 1, QRhiTexture::RenderTarget); + d.releasePool << tex; + tex->build(); + + QRhiShaderResourceBindings *srb = m_r->newShaderResourceBindings(); + d.releasePool << srb; + srb->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, + d.ubuf, i * oneRoundedUniformBlockSize, 68), + QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, tex, d.sampler) + }); + srb->build(); + + d.colData[i].tex = tex; + d.colData[i].srb = srb; + } + + QRhiTextureRenderTargetDescription rtDesc; + QRhiColorAttachment att[ATTCOUNT]; + for (int i = 0; i < ATTCOUNT; ++i) + att[i] = QRhiColorAttachment(d.colData[i].tex); + rtDesc.setColorAttachments(att, att + ATTCOUNT); + d.rt = m_r->newTextureRenderTarget(rtDesc); + d.releasePool << d.rt; + d.rtRp = d.rt->newCompatibleRenderPassDescriptor(); + d.releasePool << d.rtRp; + d.rt->setRenderPassDescriptor(d.rtRp); + d.rt->build(); + + d.ps = m_r->newGraphicsPipeline(); + d.releasePool << d.ps; + d.ps->setShaderStages({ + { QRhiShaderStage::Vertex, getShader(QLatin1String(":/texture.vert.qsb")) }, + { QRhiShaderStage::Fragment, getShader(QLatin1String(":/texture.frag.qsb")) } + }); + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ + { 4 * sizeof(float) } + }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float2, 0 }, + { 0, 1, QRhiVertexInputAttribute::Float2, 2 * sizeof(float) } + }); + d.ps->setVertexInputLayout(inputLayout); + d.ps->setShaderResourceBindings(d.colData[0].srb); // all of them are layout-compatible + d.ps->setRenderPassDescriptor(m_rp); + d.ps->build(); + + d.initialUpdates = m_r->nextResourceUpdateBatch(); + d.initialUpdates->uploadStaticBuffer(d.vbuf, 0, sizeof(quadVertexData), quadVertexData); + d.initialUpdates->uploadStaticBuffer(d.vbuf, sizeof(quadVertexData), sizeof(triangleData), triangleData); + d.initialUpdates->uploadStaticBuffer(d.ibuf, quadIndexData); + + qint32 flip = m_r->isYUpInFramebuffer() ? 1 : 0; + for (int i = 0; i < ATTCOUNT; ++i) + d.initialUpdates->updateDynamicBuffer(d.ubuf, i * oneRoundedUniformBlockSize + 64, 4, &flip); + + // triangle + d.triUbuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 68); + d.releasePool << d.triUbuf; + d.triUbuf->build(); + + d.triSrb = m_r->newShaderResourceBindings(); + d.releasePool << d.triSrb; + d.triSrb->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.triUbuf) + }); + d.triSrb->build(); + + d.triPs = m_r->newGraphicsPipeline(); + d.releasePool << d.triPs; + d.triPs->setShaderStages({ + { QRhiShaderStage::Vertex, getShader(QLatin1String(":/mrt.vert.qsb")) }, + { QRhiShaderStage::Fragment, getShader(QLatin1String(":/mrt.frag.qsb")) } + }); + + QRhiGraphicsPipeline::TargetBlend blends[ATTCOUNT]; // defaults to blending == false + d.triPs->setTargetBlends(blends, blends + ATTCOUNT); + + inputLayout.setBindings({ + { 5 * sizeof(float) } + }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float2, 0 }, + { 0, 1, QRhiVertexInputAttribute::Float3, 2 * sizeof(float) } + }); + d.triPs->setVertexInputLayout(inputLayout); + d.triPs->setShaderResourceBindings(d.triSrb); + d.triPs->setRenderPassDescriptor(d.rtRp); + d.triPs->build(); + + d.triBaseMvp = m_r->clipSpaceCorrMatrix(); + d.triBaseMvp.perspective(45.0f, d.rt->pixelSize().width() / float(d.rt->pixelSize().height()), 0.01f, 1000.0f); + d.triBaseMvp.translate(0, 0, -2); + float opacity = 1.0f; + d.initialUpdates->updateDynamicBuffer(d.triUbuf, 64, 4, &opacity); +} + +void Window::customRelease() +{ + qDeleteAll(d.releasePool); + d.releasePool.clear(); +} + +void Window::customRender() +{ + QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer(); + QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch(); + if (d.initialUpdates) { + u->merge(d.initialUpdates); + d.initialUpdates->release(); + d.initialUpdates = nullptr; + } + + QMatrix4x4 triMvp = d.triBaseMvp; + triMvp.rotate(d.triRot, 0, 1, 0); + d.triRot += 1; + u->updateDynamicBuffer(d.triUbuf, 0, 64, triMvp.constData()); + + cb->beginPass(d.rt, QColor::fromRgbF(0.5f, 0.2f, 0.0f, 1.0f), { 1.0f, 0 }, u); + cb->setGraphicsPipeline(d.triPs); + cb->setViewport({ 0, 0, float(d.rt->pixelSize().width()), float(d.rt->pixelSize().height()) }); + cb->setShaderResources(); + QRhiCommandBuffer::VertexInput vbufBinding(d.vbuf, sizeof(quadVertexData)); + cb->setVertexInput(0, 1, &vbufBinding); + cb->draw(3); + cb->endPass(); + + u = m_r->nextResourceUpdateBatch(); + if (d.winProj != m_proj) { + d.winProj = m_proj; + const int oneRoundedUniformBlockSize = m_r->ubufAligned(68); + for (int i = 0; i < ATTCOUNT; ++i) { + QMatrix4x4 mvp = m_proj; + switch (i) { + case 0: + mvp.translate(-2.0f, 0, 0); + break; + case 1: + mvp.translate(-0.8f, 0, 0); + break; + case 2: + mvp.translate(0.4f, 0, 0); + break; + case 3: + mvp.translate(1.6f, 0, 0); + break; + default: + Q_UNREACHABLE(); + break; + } + u->updateDynamicBuffer(d.ubuf, i * oneRoundedUniformBlockSize, 64, mvp.constData()); + } + } + + const QSize outputSizeInPixels = m_sc->currentPixelSize(); + cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }, u); + cb->setGraphicsPipeline(d.ps); + cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) }); + vbufBinding.second = 0; + cb->setVertexInput(0, 1, &vbufBinding, d.ibuf, 0, QRhiCommandBuffer::IndexUInt16); + for (int i = 0; i < ATTCOUNT; ++i) { + cb->setShaderResources(d.colData[i].srb); + cb->drawIndexed(6); + } + cb->endPass(); +} diff --git a/tests/manual/rhi/mrt/mrt.frag b/tests/manual/rhi/mrt/mrt.frag new file mode 100644 index 0000000000..9166b552b9 --- /dev/null +++ b/tests/manual/rhi/mrt/mrt.frag @@ -0,0 +1,22 @@ +#version 440 + +layout(location = 0) in vec3 v_color; + +layout(location = 0) out vec4 c0; +layout(location = 1) out vec4 c1; +layout(location = 2) out vec4 c2; +layout(location = 3) out vec4 c3; + +layout(std140, binding = 0) uniform buf { + mat4 mvp; + float opacity; +} ubuf; + +void main() +{ + vec4 c = vec4(v_color * ubuf.opacity, ubuf.opacity); + c0 = vec4(c.r, 0, 0, c.a); + c1 = vec4(0, c.g, 0, c.a); + c2 = vec4(0, 0, c.b, c.a); + c3 = c; +} diff --git a/tests/manual/rhi/mrt/mrt.frag.qsb b/tests/manual/rhi/mrt/mrt.frag.qsb Binary files differnew file mode 100644 index 0000000000..389b6affa3 --- /dev/null +++ b/tests/manual/rhi/mrt/mrt.frag.qsb diff --git a/tests/manual/rhi/mrt/mrt.pro b/tests/manual/rhi/mrt/mrt.pro new file mode 100644 index 0000000000..7cde425488 --- /dev/null +++ b/tests/manual/rhi/mrt/mrt.pro @@ -0,0 +1,8 @@ +TEMPLATE = app + +QT += gui-private + +SOURCES = \ + mrt.cpp + +RESOURCES = mrt.qrc diff --git a/tests/manual/rhi/mrt/mrt.qrc b/tests/manual/rhi/mrt/mrt.qrc new file mode 100644 index 0000000000..275f476013 --- /dev/null +++ b/tests/manual/rhi/mrt/mrt.qrc @@ -0,0 +1,8 @@ +<!DOCTYPE RCC><RCC version="1.0"> + <qresource> + <file>mrt.vert.qsb</file> + <file>mrt.frag.qsb</file> + <file alias="texture.vert.qsb">../shared/texture.vert.qsb</file> + <file alias="texture.frag.qsb">../shared/texture.frag.qsb</file> +</qresource> +</RCC> diff --git a/tests/manual/rhi/mrt/mrt.vert b/tests/manual/rhi/mrt/mrt.vert new file mode 100644 index 0000000000..43af543f44 --- /dev/null +++ b/tests/manual/rhi/mrt/mrt.vert @@ -0,0 +1,19 @@ +#version 440 + +layout(location = 0) in vec4 position; +layout(location = 1) in vec3 color; + +layout(location = 0) out vec3 v_color; + +layout(std140, binding = 0) uniform buf { + mat4 mvp; + float opacity; +} ubuf; + +out gl_PerVertex { vec4 gl_Position; }; + +void main() +{ + v_color = color; + gl_Position = ubuf.mvp * position; +} diff --git a/tests/manual/rhi/mrt/mrt.vert.qsb b/tests/manual/rhi/mrt/mrt.vert.qsb Binary files differnew file mode 100644 index 0000000000..ff8c0e50bb --- /dev/null +++ b/tests/manual/rhi/mrt/mrt.vert.qsb diff --git a/tests/manual/rhi/msaarenderbuffer/msaarenderbuffer.cpp b/tests/manual/rhi/msaarenderbuffer/msaarenderbuffer.cpp new file mode 100644 index 0000000000..27dabb2276 --- /dev/null +++ b/tests/manual/rhi/msaarenderbuffer/msaarenderbuffer.cpp @@ -0,0 +1,259 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "../shared/examplefw.h" + +// Uses a multisample renderbuffer (whatever that may be on a given backend) to +// render to and then resolves the samples into a non-multisample texture. + +static float vertexData[] = +{ // Y up, CCW + -0.5f, 0.5f, 0.0f, 0.0f, + -0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, 0.5f, 1.0f, 0.0f +}; + +static quint16 indexData[] = +{ + 0, 1, 2, 0, 2, 3 +}; + +static float triangleData[] = +{ // Y up, CCW + 0.0f, 0.5f, 1.0f, 0.0f, 0.0f, + -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, + 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, +}; + +struct { + QVector<QRhiResource *> releasePool; + QRhiBuffer *vbuf = nullptr; + QRhiBuffer *ibuf = nullptr; + QRhiBuffer *ubuf = nullptr; + QRhiRenderBuffer *rb = nullptr; + QRhiTextureRenderTarget *rt = nullptr; + QRhiRenderPassDescriptor *rtRp = nullptr; + QRhiTexture *tex = nullptr; + QRhiSampler *sampler = nullptr; + QRhiBuffer *triUbuf = nullptr; + QRhiShaderResourceBindings *triSrb = nullptr; + QRhiGraphicsPipeline *triPs = nullptr; + QRhiShaderResourceBindings *srb = nullptr; + QRhiGraphicsPipeline *ps = nullptr; + QRhiResourceUpdateBatch *initialUpdates = nullptr; + QMatrix4x4 triBaseMvp; + float triRot = 0; + QMatrix4x4 winProj; +} d; + +void Window::customInit() +{ + d.vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData) + sizeof(triangleData)); + d.vbuf->build(); + d.releasePool << d.vbuf; + + d.ibuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::IndexBuffer, sizeof(indexData)); + d.ibuf->build(); + d.releasePool << d.ibuf; + + d.ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 68); + d.ubuf->build(); + d.releasePool << d.ubuf; + + d.rb = m_r->newRenderBuffer(QRhiRenderBuffer::Color, QSize(512, 512), 4); // 4x MSAA + d.rb->build(); + d.releasePool << d.rb; + + // the non-msaa texture that will be the destination in the resolve + d.tex = m_r->newTexture(QRhiTexture::RGBA8, d.rb->pixelSize(), 1, QRhiTexture::RenderTarget); + d.releasePool << d.tex; + d.tex->build(); + + // rb is multisample, instead of writing out the msaa data into it, + // resolve into d.tex at the end of each render pass + QRhiTextureRenderTargetDescription rtDesc; + QRhiColorAttachment rtAtt(d.rb); + rtAtt.setResolveTexture(d.tex); + rtDesc.setColorAttachments({ rtAtt }); + + d.rt = m_r->newTextureRenderTarget(rtDesc); + d.releasePool << d.rt; + d.rtRp = d.rt->newCompatibleRenderPassDescriptor(); + d.releasePool << d.rtRp; + d.rt->setRenderPassDescriptor(d.rtRp); + d.rt->build(); + + d.triUbuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 68); + d.releasePool << d.triUbuf; + d.triUbuf->build(); + + d.triSrb = m_r->newShaderResourceBindings(); + d.releasePool << d.triSrb; + d.triSrb->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.triUbuf) + }); + d.triSrb->build(); + + d.triPs = m_r->newGraphicsPipeline(); + d.releasePool << d.triPs; + d.triPs->setSampleCount(4); // must match the render target + d.triPs->setShaderStages({ + { QRhiShaderStage::Vertex, getShader(QLatin1String(":/color.vert.qsb")) }, + { QRhiShaderStage::Fragment, getShader(QLatin1String(":/color.frag.qsb")) } + }); + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ + { 5 * sizeof(float) } + }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float2, 0 }, + { 0, 1, QRhiVertexInputAttribute::Float3, 2 * sizeof(float) } + }); + d.triPs->setVertexInputLayout(inputLayout); + d.triPs->setShaderResourceBindings(d.triSrb); + d.triPs->setRenderPassDescriptor(d.rtRp); + d.triPs->build(); + + d.sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None, + QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge); + d.releasePool << d.sampler; + d.sampler->build(); + + d.srb = m_r->newShaderResourceBindings(); + d.releasePool << d.srb; + d.srb->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf), + QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.tex, d.sampler) + }); + d.srb->build(); + + d.ps = m_r->newGraphicsPipeline(); + d.releasePool << d.ps; + d.ps->setShaderStages({ + { QRhiShaderStage::Vertex, getShader(QLatin1String(":/texture.vert.qsb")) }, + { QRhiShaderStage::Fragment, getShader(QLatin1String(":/texture.frag.qsb")) } + }); + inputLayout.setBindings({ + { 4 * sizeof(float) } + }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float2, 0 }, + { 0, 1, QRhiVertexInputAttribute::Float2, 2 * sizeof(float) } + }); + d.ps->setVertexInputLayout(inputLayout); + d.ps->setShaderResourceBindings(d.srb); + d.ps->setRenderPassDescriptor(m_rp); + d.ps->build(); + + d.initialUpdates = m_r->nextResourceUpdateBatch(); + d.initialUpdates->uploadStaticBuffer(d.vbuf, 0, sizeof(vertexData), vertexData); + d.initialUpdates->uploadStaticBuffer(d.vbuf, sizeof(vertexData), sizeof(triangleData), triangleData); + d.initialUpdates->uploadStaticBuffer(d.ibuf, indexData); + + d.triBaseMvp = m_r->clipSpaceCorrMatrix(); + d.triBaseMvp.perspective(45.0f, d.rb->pixelSize().width() / float(d.rb->pixelSize().height()), 0.01f, 1000.0f); + d.triBaseMvp.translate(0, 0, -2); + float opacity = 1.0f; + d.initialUpdates->updateDynamicBuffer(d.triUbuf, 64, 4, &opacity); + + qint32 flip = m_r->isYUpInFramebuffer() ? 1 : 0; + d.initialUpdates->updateDynamicBuffer(d.ubuf, 64, 4, &flip); +} + +void Window::customRelease() +{ + qDeleteAll(d.releasePool); + d.releasePool.clear(); +} + +void Window::customRender() +{ + QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer(); + QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch(); + if (d.initialUpdates) { + u->merge(d.initialUpdates); + d.initialUpdates->release(); + d.initialUpdates = nullptr; + } + + QMatrix4x4 triMvp = d.triBaseMvp; + triMvp.rotate(d.triRot, 0, 1, 0); + d.triRot += 1; + u->updateDynamicBuffer(d.triUbuf, 0, 64, triMvp.constData()); + + if (d.winProj != m_proj) { + d.winProj = m_proj; + QMatrix4x4 mvp = m_proj; + mvp.scale(2.5f); + u->updateDynamicBuffer(d.ubuf, 0, 64, mvp.constData()); + } + + // offscreen (triangle, msaa) + cb->beginPass(d.rt, QColor::fromRgbF(0.5f, 0.2f, 0.0f, 1.0f), { 1.0f, 0 }, u); + cb->setGraphicsPipeline(d.triPs); + cb->setViewport({ 0, 0, float(d.rb->pixelSize().width()), float(d.rb->pixelSize().height()) }); + cb->setShaderResources(); + QRhiCommandBuffer::VertexInput vbufBinding(d.vbuf, sizeof(vertexData)); + cb->setVertexInput(0, 1, &vbufBinding); + cb->draw(3); + cb->endPass(); + + // onscreen (quad) + const QSize outputSizeInPixels = m_sc->currentPixelSize(); + cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }); + cb->setGraphicsPipeline(d.ps); + cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) }); + cb->setShaderResources(); + vbufBinding.second = 0; + cb->setVertexInput(0, 1, &vbufBinding, d.ibuf, 0, QRhiCommandBuffer::IndexUInt16); + cb->drawIndexed(6); + cb->endPass(); +} diff --git a/tests/manual/rhi/msaarenderbuffer/msaarenderbuffer.pro b/tests/manual/rhi/msaarenderbuffer/msaarenderbuffer.pro new file mode 100644 index 0000000000..4b31e39e7d --- /dev/null +++ b/tests/manual/rhi/msaarenderbuffer/msaarenderbuffer.pro @@ -0,0 +1,8 @@ +TEMPLATE = app + +QT += gui-private + +SOURCES = \ + msaarenderbuffer.cpp + +RESOURCES = msaarenderbuffer.qrc diff --git a/tests/manual/rhi/msaarenderbuffer/msaarenderbuffer.qrc b/tests/manual/rhi/msaarenderbuffer/msaarenderbuffer.qrc new file mode 100644 index 0000000000..c7a2380a42 --- /dev/null +++ b/tests/manual/rhi/msaarenderbuffer/msaarenderbuffer.qrc @@ -0,0 +1,8 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file alias="color.vert.qsb">../shared/color.vert.qsb</file> + <file alias="color.frag.qsb">../shared/color.frag.qsb</file> + <file alias="texture.vert.qsb">../shared/texture.vert.qsb</file> + <file alias="texture.frag.qsb">../shared/texture.frag.qsb</file> +</qresource> +</RCC> diff --git a/tests/manual/rhi/msaatexture/msaatexture.cpp b/tests/manual/rhi/msaatexture/msaatexture.cpp new file mode 100644 index 0000000000..2fb466c8d6 --- /dev/null +++ b/tests/manual/rhi/msaatexture/msaatexture.cpp @@ -0,0 +1,329 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "../shared/examplefw.h" + +// Renders into a non-multisample and a multisample (4x) texture, and then uses +// those textures to draw two quads. Note that this uses an MSAA sampler in the +// shader, not resolves. Not supported on the GL(ES) backend atm. + +static float vertexData[] = +{ // Y up, CCW + -0.5f, 0.5f, 0.0f, 0.0f, + -0.5f, -0.5f, 0.0f, 1.0f, + 0.5f, -0.5f, 1.0f, 1.0f, + 0.5f, 0.5f, 1.0f, 0.0f +}; + +static quint16 indexData[] = +{ + 0, 1, 2, 0, 2, 3 +}; + +static float triangleData[] = +{ // Y up, CCW + 0.0f, 0.5f, 1.0f, 0.0f, 0.0f, + -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, + 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, +}; + +const int UBUFSZ = 68; + +struct { + QVector<QRhiResource *> releasePool; + QRhiBuffer *vbuf = nullptr; + QRhiBuffer *ibuf = nullptr; + QRhiBuffer *ubuf = nullptr; + QRhiTexture *tex = nullptr; + QRhiTexture *msaaTex = nullptr; + QRhiSampler *sampler = nullptr; + QRhiShaderResourceBindings *srbLeft = nullptr; + QRhiShaderResourceBindings *srbRight = nullptr; + QRhiGraphicsPipeline *psLeft = nullptr; + QRhiGraphicsPipeline *psRight = nullptr; + QRhiResourceUpdateBatch *initialUpdates = nullptr; + int rightOfs; + QMatrix4x4 winProj; + QMatrix4x4 triBaseMvp; + float triRot = 0; + + QRhiShaderResourceBindings *triSrb = nullptr; + QRhiGraphicsPipeline *msaaTriPs = nullptr; + QRhiGraphicsPipeline *triPs = nullptr; + QRhiBuffer *triUbuf = nullptr; + QRhiTextureRenderTarget *msaaRt = nullptr; + QRhiRenderPassDescriptor *msaaRtRp = nullptr; + QRhiTextureRenderTarget *rt = nullptr; + QRhiRenderPassDescriptor *rtRp = nullptr; +} d; + +//#define NO_MSAA + +void Window::customInit() +{ + if (!m_r->isFeatureSupported(QRhi::MultisampleTexture)) + qFatal("Multisample textures not supported by this backend"); + + d.vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData) + sizeof(triangleData)); + d.releasePool << d.vbuf; + d.vbuf->build(); + + d.ibuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::IndexBuffer, sizeof(indexData)); + d.releasePool << d.ibuf; + d.ibuf->build(); + + d.rightOfs = m_r->ubufAligned(UBUFSZ); + d.ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, d.rightOfs + UBUFSZ); + d.releasePool << d.ubuf; + d.ubuf->build(); + + d.tex = m_r->newTexture(QRhiTexture::RGBA8, QSize(512, 512), 1, QRhiTexture::RenderTarget); + d.releasePool << d.tex; + d.tex->build(); +#ifndef NO_MSAA + d.msaaTex = m_r->newTexture(QRhiTexture::RGBA8, QSize(512, 512), 4, QRhiTexture::RenderTarget); +#else + d.msaaTex = m_r->newTexture(QRhiTexture::RGBA8, QSize(512, 512), 1, QRhiTexture::RenderTarget); +#endif + d.releasePool << d.msaaTex; + d.msaaTex->build(); + + d.initialUpdates = m_r->nextResourceUpdateBatch(); + d.initialUpdates->uploadStaticBuffer(d.vbuf, 0, sizeof(vertexData), vertexData); + d.initialUpdates->uploadStaticBuffer(d.vbuf, sizeof(vertexData), sizeof(triangleData), triangleData); + d.initialUpdates->uploadStaticBuffer(d.ibuf, indexData); + + d.sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None, + QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge); + d.releasePool << d.sampler; + d.sampler->build(); + + d.srbLeft = m_r->newShaderResourceBindings(); + d.releasePool << d.srbLeft; + d.srbLeft->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf, 0, UBUFSZ), + QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.tex, d.sampler) + }); + d.srbLeft->build(); + + d.srbRight = m_r->newShaderResourceBindings(); + d.releasePool << d.srbRight; + d.srbRight->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf, d.rightOfs, UBUFSZ), + QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.msaaTex, d.sampler) + }); + d.srbRight->build(); + + d.psLeft = m_r->newGraphicsPipeline(); + d.releasePool << d.psLeft; + d.psLeft->setShaderStages({ + { QRhiShaderStage::Vertex, getShader(QLatin1String(":/texture.vert.qsb")) }, + { QRhiShaderStage::Fragment, getShader(QLatin1String(":/texture.frag.qsb")) } + }); + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ { 4 * sizeof(float) } }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float2, 0 }, + { 0, 1, QRhiVertexInputAttribute::Float2, 2 * sizeof(float) } + }); + d.psLeft->setVertexInputLayout(inputLayout); + d.psLeft->setShaderResourceBindings(d.srbLeft); + d.psLeft->setRenderPassDescriptor(m_rp); + d.psLeft->build(); + + d.psRight = m_r->newGraphicsPipeline(); + d.releasePool << d.psRight; + d.psRight->setShaderStages({ + { QRhiShaderStage::Vertex, getShader(QLatin1String(":/texture.vert.qsb")) }, +#ifndef NO_MSAA + { QRhiShaderStage::Fragment, getShader(QLatin1String(":/texture_ms4.frag.qsb")) } +#else + { QRhiShaderStage::Fragment, getShader(QLatin1String(":/texture.frag.qsb")) } +#endif + }); + d.psRight->setVertexInputLayout(d.psLeft->vertexInputLayout()); + d.psRight->setShaderResourceBindings(d.srbRight); + d.psRight->setRenderPassDescriptor(m_rp); + d.psRight->build(); + + // set up the offscreen triangle that goes into tex and msaaTex + d.triUbuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 68); + d.releasePool << d.triUbuf; + d.triUbuf->build(); + d.triSrb = m_r->newShaderResourceBindings(); + d.releasePool << d.triSrb; + d.triSrb->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.triUbuf) + }); + d.triSrb->build(); + d.rt = m_r->newTextureRenderTarget({ d.tex }); + d.releasePool << d.rt; + d.rtRp = d.rt->newCompatibleRenderPassDescriptor(); + d.releasePool << d.rtRp; + d.rt->setRenderPassDescriptor(d.rtRp); + d.rt->build(); + d.msaaRt = m_r->newTextureRenderTarget({ d.msaaTex }); + d.releasePool << d.msaaRt; + d.msaaRtRp = d.msaaRt->newCompatibleRenderPassDescriptor(); + d.releasePool << d.msaaRtRp; + d.msaaRt->setRenderPassDescriptor(d.msaaRtRp); + d.msaaRt->build(); + d.triPs = m_r->newGraphicsPipeline(); + d.releasePool << d.triPs; + d.triPs->setSampleCount(1); + d.triPs->setShaderStages({ + { QRhiShaderStage::Vertex, getShader(QLatin1String(":/color.vert.qsb")) }, + { QRhiShaderStage::Fragment, getShader(QLatin1String(":/color.frag.qsb")) } + }); + inputLayout.setBindings({ + { 5 * sizeof(float) } + }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float2, 0 }, + { 0, 1, QRhiVertexInputAttribute::Float3, 2 * sizeof(float) } + }); + d.triPs->setVertexInputLayout(inputLayout); + d.triPs->setShaderResourceBindings(d.triSrb); + d.triPs->setRenderPassDescriptor(d.rtRp); + d.triPs->build(); + d.msaaTriPs = m_r->newGraphicsPipeline(); + d.releasePool << d.msaaTriPs; +#ifndef NO_MSAA + d.msaaTriPs->setSampleCount(4); +#else + d.msaaTriPs->setSampleCount(1); +#endif + d.msaaTriPs->setShaderStages(d.triPs->cbeginShaderStages(), d.triPs->cendShaderStages()); + d.msaaTriPs->setVertexInputLayout(d.triPs->vertexInputLayout()); + d.msaaTriPs->setShaderResourceBindings(d.triSrb); + d.msaaTriPs->setRenderPassDescriptor(d.msaaRtRp); + d.msaaTriPs->build(); +} + +void Window::customRelease() +{ + qDeleteAll(d.releasePool); + d.releasePool.clear(); +} + +void Window::customRender() +{ + QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer(); + QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch(); + if (d.initialUpdates) { + u->merge(d.initialUpdates); + d.initialUpdates->release(); + d.initialUpdates = nullptr; + + // onscreen ubuf + qint32 flip = m_r->isYUpInFramebuffer() ? 1 : 0; + u->updateDynamicBuffer(d.ubuf, 64, 4, &flip); + u->updateDynamicBuffer(d.ubuf, d.rightOfs + 64, 4, &flip); + + // offscreen ubuf + d.triBaseMvp = m_r->clipSpaceCorrMatrix(); + d.triBaseMvp.perspective(45.0f, d.msaaTex->pixelSize().width() / float(d.msaaTex->pixelSize().height()), 0.01f, 1000.0f); + d.triBaseMvp.translate(0, 0, -2); + float opacity = 1.0f; + u->updateDynamicBuffer(d.triUbuf, 64, 4, &opacity); + } + + if (d.winProj != m_proj) { + // onscreen buf, window size dependent + d.winProj = m_proj; + QMatrix4x4 mvp = m_proj; + mvp.scale(2); + mvp.translate(-0.8f, 0, 0); + u->updateDynamicBuffer(d.ubuf, 0, 64, mvp.constData()); + mvp.translate(1.6f, 0, 0); + u->updateDynamicBuffer(d.ubuf, d.rightOfs, 64, mvp.constData()); + } + + // offscreen buf, apply the rotation on every frame + QMatrix4x4 triMvp = d.triBaseMvp; + triMvp.rotate(d.triRot, 0, 1, 0); + d.triRot += 1; + u->updateDynamicBuffer(d.triUbuf, 0, 64, triMvp.constData()); + + cb->resourceUpdate(u); // could have passed u to beginPass but exercise this one too + + // offscreen + cb->beginPass(d.rt, QColor::fromRgbF(0.5f, 0.2f, 0.0f, 1.0f), { 1.0f, 0 }); + cb->setGraphicsPipeline(d.triPs); + cb->setViewport({ 0, 0, float(d.msaaTex->pixelSize().width()), float(d.msaaTex->pixelSize().height()) }); + cb->setShaderResources(); + QRhiCommandBuffer::VertexInput vbufBinding(d.vbuf, sizeof(vertexData)); + cb->setVertexInput(0, 1, &vbufBinding); + cb->draw(3); + cb->endPass(); + + // offscreen msaa + cb->beginPass(d.msaaRt, QColor::fromRgbF(0.5f, 0.2f, 0.0f, 1.0f), { 1.0f, 0 }); + cb->setGraphicsPipeline(d.msaaTriPs); + cb->setViewport({ 0, 0, float(d.msaaTex->pixelSize().width()), float(d.msaaTex->pixelSize().height()) }); + cb->setShaderResources(); + cb->setVertexInput(0, 1, &vbufBinding); + cb->draw(3); + cb->endPass(); + + // onscreen + const QSize outputSizeInPixels = m_sc->currentPixelSize(); + cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }); + cb->setGraphicsPipeline(d.psLeft); // showing the non-msaa version + cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) }); + cb->setShaderResources(); + vbufBinding.second = 0; + cb->setVertexInput(0, 1, &vbufBinding, d.ibuf, 0, QRhiCommandBuffer::IndexUInt16); + cb->drawIndexed(6); + cb->setGraphicsPipeline(d.psRight); // showing the msaa version, resolved in the shader + cb->setShaderResources(); + cb->drawIndexed(6); + cb->endPass(); +} diff --git a/tests/manual/rhi/msaatexture/msaatexture.pro b/tests/manual/rhi/msaatexture/msaatexture.pro new file mode 100644 index 0000000000..0467e4dc9d --- /dev/null +++ b/tests/manual/rhi/msaatexture/msaatexture.pro @@ -0,0 +1,8 @@ +TEMPLATE = app + +QT += gui-private + +SOURCES = \ + msaatexture.cpp + +RESOURCES = msaatexture.qrc diff --git a/tests/manual/rhi/msaatexture/msaatexture.qrc b/tests/manual/rhi/msaatexture/msaatexture.qrc new file mode 100644 index 0000000000..ecd968481c --- /dev/null +++ b/tests/manual/rhi/msaatexture/msaatexture.qrc @@ -0,0 +1,9 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file alias="color.vert.qsb">../shared/color.vert.qsb</file> + <file alias="color.frag.qsb">../shared/color.frag.qsb</file> + <file alias="texture.vert.qsb">../shared/texture.vert.qsb</file> + <file alias="texture.frag.qsb">../shared/texture.frag.qsb</file> + <file alias="texture_ms4.frag.qsb">../shared/texture_ms4.frag.qsb</file> +</qresource> +</RCC> diff --git a/tests/manual/rhi/multiwindow/multiwindow.cpp b/tests/manual/rhi/multiwindow/multiwindow.cpp new file mode 100644 index 0000000000..4d5de16a58 --- /dev/null +++ b/tests/manual/rhi/multiwindow/multiwindow.cpp @@ -0,0 +1,640 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QApplication> +#include <QWidget> +#include <QLabel> +#include <QPlainTextEdit> +#include <QPushButton> +#include <QCheckBox> +#include <QVBoxLayout> + +#include <QCommandLineParser> +#include <QWindow> +#include <QPlatformSurfaceEvent> +#include <QElapsedTimer> + +#include <QtGui/private/qshader_p.h> +#include <QFile> + +#ifndef QT_NO_OPENGL +#include <QtGui/private/qrhigles2_p.h> +#include <QOffscreenSurface> +#endif + +#if QT_CONFIG(vulkan) +#include <QLoggingCategory> +#include <QtGui/private/qrhivulkan_p.h> +#endif + +#ifdef Q_OS_WIN +#include <QtGui/private/qrhid3d11_p.h> +#endif + +#ifdef Q_OS_DARWIN +#include <QtGui/private/qrhimetal_p.h> +#endif + +enum GraphicsApi +{ + OpenGL, + Vulkan, + D3D11, + Metal +}; + +static GraphicsApi graphicsApi; + +static QString graphicsApiName() +{ + switch (graphicsApi) { + case OpenGL: + return QLatin1String("OpenGL 2.x"); + case Vulkan: + return QLatin1String("Vulkan"); + case D3D11: + return QLatin1String("Direct3D 11"); + case Metal: + return QLatin1String("Metal"); + default: + break; + } + return QString(); +} + +static struct { +#if QT_CONFIG(vulkan) + QVulkanInstance *instance = nullptr; +#endif + QRhi *r = nullptr; +#ifndef QT_NO_OPENGL + QOffscreenSurface *fallbackSurface = nullptr; +#endif +} r; + +void createRhi() +{ +#ifndef QT_NO_OPENGL + if (graphicsApi == OpenGL) { + r.fallbackSurface = QRhiGles2InitParams::newFallbackSurface(); + QRhiGles2InitParams params; + params.fallbackSurface = r.fallbackSurface; + //params.window = this; + r.r = QRhi::create(QRhi::OpenGLES2, ¶ms); + } +#endif + +#if QT_CONFIG(vulkan) + if (graphicsApi == Vulkan) { + QRhiVulkanInitParams params; + params.inst = r.instance; + //params.window = this; + r.r = QRhi::create(QRhi::Vulkan, ¶ms); + } +#endif + +#ifdef Q_OS_WIN + if (graphicsApi == D3D11) { + QRhiD3D11InitParams params; + params.enableDebugLayer = true; + r.r = QRhi::create(QRhi::D3D11, ¶ms); + } +#endif + +#ifdef Q_OS_DARWIN + if (graphicsApi == Metal) { + QRhiMetalInitParams params; + r.r = QRhi::create(QRhi::Metal, ¶ms); + } +#endif + + if (!r.r) + qFatal("Failed to create RHI backend"); +} + +void destroyRhi() +{ + delete r.r; + +#ifndef QT_NO_OPENGL + delete r.fallbackSurface; +#endif +} + +struct { + QVector<QWindow *> windows; + + QRhiBuffer *vbuf = nullptr; + QRhiBuffer *ubuf = nullptr; + QRhiShaderResourceBindings *srb = nullptr; + QRhiGraphicsPipeline *ps = nullptr; + QRhiResourceUpdateBatch *initialUpdates = nullptr; +} d; + +static float vertexData[] = { + 0.0f, 0.5f, 1.0f, 0.0f, 0.0f, + -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, + 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, +}; + +static QShader getShader(const QString &name) +{ + QFile f(name); + if (f.open(QIODevice::ReadOnly)) + return QShader::fromSerialized(f.readAll()); + + return QShader(); +} + +// can use just one rpd from whichever window comes first since they are +// actually compatible due to all windows using the same config (have +// depth-stencil, sample count 1, same format). this means the same pso can be +// reused too. +void ensureSharedResources(QRhiRenderPassDescriptor *rp) +{ + if (!d.vbuf) { + d.vbuf = r.r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData)); + d.vbuf->build(); + d.initialUpdates = r.r->nextResourceUpdateBatch(); + d.initialUpdates->uploadStaticBuffer(d.vbuf, vertexData); + } + + if (!d.ubuf) { + d.ubuf = r.r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 68); + d.ubuf->build(); + } + + if (!d.srb) { + d.srb = r.r->newShaderResourceBindings(); + d.srb->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf) + }); + d.srb->build(); + } + + if (!d.ps) { + d.ps = r.r->newGraphicsPipeline(); + + QRhiGraphicsPipeline::TargetBlend premulAlphaBlend; + premulAlphaBlend.enable = true; + d.ps->setTargetBlends({ premulAlphaBlend }); + + const QShader vs = getShader(QLatin1String(":/color.vert.qsb")); + if (!vs.isValid()) + qFatal("Failed to load shader pack (vertex)"); + const QShader fs = getShader(QLatin1String(":/color.frag.qsb")); + if (!fs.isValid()) + qFatal("Failed to load shader pack (fragment)"); + + d.ps->setShaderStages({ + { QRhiShaderStage::Vertex, vs }, + { QRhiShaderStage::Fragment, fs } + }); + + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ + { 5 * sizeof(float) } + }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float2, 0 }, + { 0, 1, QRhiVertexInputAttribute::Float3, 2 * sizeof(float) } + }); + + d.ps->setVertexInputLayout(inputLayout); + d.ps->setShaderResourceBindings(d.srb); + d.ps->setRenderPassDescriptor(rp); + + d.ps->build(); + } +} + +void destroySharedResources() +{ + delete d.ps; + d.ps = nullptr; + + delete d.srb; + d.srb = nullptr; + + delete d.vbuf; + d.vbuf = nullptr; + + delete d.ubuf; + d.ubuf = nullptr; +} + +class Window : public QWindow +{ +public: + Window(const QString &title, const QColor &bgColor, int axis, bool noVSync); + ~Window(); + +protected: + void init(); + void releaseResources(); + void resizeSwapChain(); + void releaseSwapChain(); + void render(); + + void exposeEvent(QExposeEvent *) override; + bool event(QEvent *) override; + + QColor m_bgColor; + int m_rotationAxis; + bool m_noVSync; + + bool m_running = false; + bool m_notExposed = false; + bool m_newlyExposed = false; + + QMatrix4x4 m_proj; + QVector<QRhiResource *> m_releasePool; + + bool m_hasSwapChain = false; + QRhiSwapChain *m_sc = nullptr; + QRhiRenderBuffer *m_ds = nullptr; + QRhiRenderPassDescriptor *m_rp = nullptr; + + float m_rotation = 0; + float m_opacity = 1; + int m_opacityDir = -1; +}; + +Window::Window(const QString &title, const QColor &bgColor, int axis, bool noVSync) + : m_bgColor(bgColor), + m_rotationAxis(axis), + m_noVSync(noVSync) +{ + switch (graphicsApi) { + case OpenGL: + { +#if QT_CONFIG(opengl) + setSurfaceType(OpenGLSurface); + QSurfaceFormat fmt = QRhiGles2InitParams::adjustedFormat(); // default + depth/stencil + fmt.setSwapInterval(noVSync ? 0 : 1); // + swap interval + setFormat(fmt); +#endif + } + break; + case Vulkan: +#if QT_CONFIG(vulkan) + setSurfaceType(VulkanSurface); + setVulkanInstance(r.instance); +#endif + break; + case D3D11: + setSurfaceType(OpenGLSurface); // not a typo + break; + case Metal: +#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) + setSurfaceType(MetalSurface); +#endif + break; + default: + break; + } + + resize(800, 600); + setTitle(title); +} + +Window::~Window() +{ + releaseResources(); +} + +void Window::exposeEvent(QExposeEvent *) +{ + // initialize and start rendering when the window becomes usable for graphics purposes + if (isExposed() && !m_running) { + m_running = true; + init(); + resizeSwapChain(); + } + + // stop pushing frames when not exposed (or size is 0) + if ((!isExposed() || (m_hasSwapChain && m_sc->surfacePixelSize().isEmpty())) && m_running) + m_notExposed = true; + + // continue when exposed again and the surface has a valid size. + // note that the surface size can be (0, 0) even though size() reports a valid one... + if (isExposed() && m_running && m_notExposed && !m_sc->surfacePixelSize().isEmpty()) { + m_notExposed = false; + m_newlyExposed = true; + } + + // always render a frame on exposeEvent() (when exposed) in order to update + // immediately on window resize. + if (isExposed() && !m_sc->surfacePixelSize().isEmpty()) + render(); +} + +bool Window::event(QEvent *e) +{ + switch (e->type()) { + case QEvent::UpdateRequest: + render(); + break; + + case QEvent::PlatformSurface: + // this is the proper time to tear down the swapchain (while the native window and surface are still around) + if (static_cast<QPlatformSurfaceEvent *>(e)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) + releaseSwapChain(); + break; + + default: + break; + } + + return QWindow::event(e); +} + +void Window::init() +{ + m_sc = r.r->newSwapChain(); + m_ds = r.r->newRenderBuffer(QRhiRenderBuffer::DepthStencil, + QSize(), + 1, + QRhiRenderBuffer::UsedWithSwapChainOnly); + m_releasePool << m_ds; + m_sc->setWindow(this); + m_sc->setDepthStencil(m_ds); + if (m_noVSync) + m_sc->setFlags(QRhiSwapChain::NoVSync); + + m_rp = m_sc->newCompatibleRenderPassDescriptor(); + m_releasePool << m_rp; + m_sc->setRenderPassDescriptor(m_rp); + + ensureSharedResources(m_rp); +} + +void Window::releaseResources() +{ + qDeleteAll(m_releasePool); + m_releasePool.clear(); + + delete m_sc; + m_sc = nullptr; +} + +void Window::resizeSwapChain() +{ + m_hasSwapChain = m_sc->buildOrResize(); + + const QSize outputSize = m_sc->currentPixelSize(); + m_proj = r.r->clipSpaceCorrMatrix(); + m_proj.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 1000.0f); + m_proj.translate(0, 0, -4); +} + +void Window::releaseSwapChain() +{ + if (m_hasSwapChain) { + m_hasSwapChain = false; + m_sc->release(); + } +} + +void Window::render() +{ + if (!m_hasSwapChain || m_notExposed) + return; + + // If the window got resized or got newly exposed, resize the swapchain. + // (the newly-exposed case is not actually required by some + // platforms/backends, but f.ex. Vulkan on Windows seems to need it) + if (m_sc->currentPixelSize() != m_sc->surfacePixelSize() || m_newlyExposed) { + resizeSwapChain(); + if (!m_hasSwapChain) + return; + m_newlyExposed = false; + } + + QRhi::FrameOpResult result = r.r->beginFrame(m_sc); + if (result == QRhi::FrameOpSwapChainOutOfDate) { + resizeSwapChain(); + if (!m_hasSwapChain) + return; + result = r.r->beginFrame(m_sc); + } + if (result != QRhi::FrameOpSuccess) { + requestUpdate(); + return; + } + + QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer(); + const QSize outputSizeInPixels = m_sc->currentPixelSize(); + + QRhiResourceUpdateBatch *u = r.r->nextResourceUpdateBatch(); + if (d.initialUpdates) { + u->merge(d.initialUpdates); + d.initialUpdates->release(); + d.initialUpdates = nullptr; + } + + m_rotation += 1.0f; + QMatrix4x4 mvp = m_proj; + mvp.rotate(m_rotation, m_rotationAxis == 0 ? 1 : 0, m_rotationAxis == 1 ? 1 : 0, m_rotationAxis == 2 ? 1 : 0); + u->updateDynamicBuffer(d.ubuf, 0, 64, mvp.constData()); + m_opacity += m_opacityDir * 0.005f; + if (m_opacity < 0.0f || m_opacity > 1.0f) { + m_opacityDir *= -1; + m_opacity = qBound(0.0f, m_opacity, 1.0f); + } + u->updateDynamicBuffer(d.ubuf, 64, 4, &m_opacity); + + cb->beginPass(m_sc->currentFrameRenderTarget(), + QColor::fromRgbF(float(m_bgColor.redF()), float(m_bgColor.greenF()), float(m_bgColor.blueF()), 1.0f), + { 1.0f, 0 }, + u); + + cb->setGraphicsPipeline(d.ps); + cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) }); + cb->setShaderResources(); + const QRhiCommandBuffer::VertexInput vbufBinding(d.vbuf, 0); + cb->setVertexInput(0, 1, &vbufBinding); + cb->draw(3); + + cb->endPass(); + + r.r->endFrame(m_sc); + + requestUpdate(); +} + +void createWindow(bool noVSync) +{ + static QColor colors[] = { Qt::red, Qt::green, Qt::blue, Qt::yellow, Qt::cyan, Qt::gray }; + const int n = d.windows.count(); + d.windows.append(new Window(QString::asprintf("Window #%d%s", n, noVSync ? " (no vsync)" : ""), colors[n % 6], n % 3, noVSync)); + d.windows.last()->show(); +} + +void closeWindow() +{ + delete d.windows.takeLast(); +} + +int main(int argc, char **argv) +{ + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QApplication app(argc, argv); + +#if defined(Q_OS_WIN) + graphicsApi = D3D11; +#elif defined(Q_OS_DARWIN) + graphicsApi = Metal; +#elif QT_CONFIG(vulkan) + graphicsApi = Vulkan; +#else + graphicsApi = OpenGL; +#endif + + QCommandLineParser cmdLineParser; + cmdLineParser.addHelpOption(); + QCommandLineOption glOption({ "g", "opengl" }, QLatin1String("OpenGL (2.x)")); + cmdLineParser.addOption(glOption); + QCommandLineOption vkOption({ "v", "vulkan" }, QLatin1String("Vulkan")); + cmdLineParser.addOption(vkOption); + QCommandLineOption d3dOption({ "d", "d3d11" }, QLatin1String("Direct3D 11")); + cmdLineParser.addOption(d3dOption); + QCommandLineOption mtlOption({ "m", "metal" }, QLatin1String("Metal")); + cmdLineParser.addOption(mtlOption); + cmdLineParser.process(app); + if (cmdLineParser.isSet(glOption)) + graphicsApi = OpenGL; + if (cmdLineParser.isSet(vkOption)) + graphicsApi = Vulkan; + if (cmdLineParser.isSet(d3dOption)) + graphicsApi = D3D11; + if (cmdLineParser.isSet(mtlOption)) + graphicsApi = Metal; + + qDebug("Selected graphics API is %s", qPrintable(graphicsApiName())); + qDebug("This is a multi-api example, use command line arguments to override:\n%s", qPrintable(cmdLineParser.helpText())); + +#if QT_CONFIG(vulkan) + r.instance = new QVulkanInstance; + if (graphicsApi == Vulkan) { +#ifndef Q_OS_ANDROID + r.instance->setLayers({ "VK_LAYER_LUNARG_standard_validation" }); +#else + r.instance->setLayers(QByteArrayList() + << "VK_LAYER_GOOGLE_threading" + << "VK_LAYER_LUNARG_parameter_validation" + << "VK_LAYER_LUNARG_object_tracker" + << "VK_LAYER_LUNARG_core_validation" + << "VK_LAYER_LUNARG_image" + << "VK_LAYER_LUNARG_swapchain" + << "VK_LAYER_GOOGLE_unique_objects"); +#endif + if (!r.instance->create()) { + qWarning("Failed to create Vulkan instance, switching to OpenGL"); + graphicsApi = OpenGL; + } + } +#endif + + createRhi(); + + int winCount = 0; + QWidget w; + w.resize(800, 600); + w.setWindowTitle(QCoreApplication::applicationName() + QLatin1String(" - ") + graphicsApiName()); + QVBoxLayout *layout = new QVBoxLayout(&w); + + QPlainTextEdit *info = new QPlainTextEdit( + QLatin1String("This application tests rendering with the same QRhi instance (and so the same Vulkan/Metal/D3D device or OpenGL context) " + "to multiple windows via multiple QRhiSwapChain objects, from the same one thread. Some resources are shared across all windows.\n" + "\nNote that the behavior may differ depending on the underlying graphics API implementation and the number of windows. " + "One challenge here is the vsync throttling: with the default vsync/fifo presentation mode the behavior may differ between " + "platforms, drivers, and APIs as we present different swapchains' images in a row on the same thread. As a potential solution, " + "setting NoVSync on the second, third, and later window swapchains is offered as an option.\n" + "\n\nUsing API: ") + graphicsApiName()); + info->setReadOnly(true); + layout->addWidget(info); + QLabel *label = new QLabel(QLatin1String("Window count: 0")); + layout->addWidget(label); + QCheckBox *vsCb = new QCheckBox(QLatin1String("Set NoVSync on all swapchains except the first")); + vsCb->setChecked(false); + layout->addWidget(vsCb); + QPushButton *btn = new QPushButton(QLatin1String("New window")); + QObject::connect(btn, &QPushButton::clicked, btn, [label, vsCb, &winCount] { + winCount += 1; + label->setText(QString::asprintf("Window count: %d", winCount)); + const bool noVSync = vsCb->isChecked() && winCount > 1; + createWindow(noVSync); + }); + layout->addWidget(btn); + btn = new QPushButton(QLatin1String("Close window")); + QObject::connect(btn, &QPushButton::clicked, btn, [label, &winCount] { + if (winCount > 0) { + winCount -= 1; + label->setText(QString::asprintf("Window count: %d", winCount)); + closeWindow(); + } + }); + layout->addWidget(btn); + w.show(); + + int result = app.exec(); + + qDeleteAll(d.windows); + + destroySharedResources(); + destroyRhi(); + +#if QT_CONFIG(vulkan) + delete r.instance; +#endif + + return result; +} diff --git a/tests/manual/rhi/multiwindow/multiwindow.pro b/tests/manual/rhi/multiwindow/multiwindow.pro new file mode 100644 index 0000000000..b9c3867bf8 --- /dev/null +++ b/tests/manual/rhi/multiwindow/multiwindow.pro @@ -0,0 +1,8 @@ +TEMPLATE = app + +QT += gui-private widgets + +SOURCES = \ + multiwindow.cpp + +RESOURCES = multiwindow.qrc diff --git a/tests/manual/rhi/multiwindow/multiwindow.qrc b/tests/manual/rhi/multiwindow/multiwindow.qrc new file mode 100644 index 0000000000..8cec4fa9ec --- /dev/null +++ b/tests/manual/rhi/multiwindow/multiwindow.qrc @@ -0,0 +1,6 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file alias="color.vert.qsb">../shared/color.vert.qsb</file> + <file alias="color.frag.qsb">../shared/color.frag.qsb</file> +</qresource> +</RCC> diff --git a/tests/manual/rhi/multiwindow_threaded/multiwindow_threaded.cpp b/tests/manual/rhi/multiwindow_threaded/multiwindow_threaded.cpp new file mode 100644 index 0000000000..37c6cd04c3 --- /dev/null +++ b/tests/manual/rhi/multiwindow_threaded/multiwindow_threaded.cpp @@ -0,0 +1,831 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QApplication> +#include <QWidget> +#include <QLabel> +#include <QPlainTextEdit> +#include <QPushButton> +#include <QCheckBox> +#include <QVBoxLayout> + +#include <QThread> +#include <QMutex> +#include <QWaitCondition> +#include <QQueue> +#include <QEvent> +#include <QCommandLineParser> +#include <QElapsedTimer> + +#include <QtGui/private/qshader_p.h> +#include <QFile> +#include <QtGui/private/qrhiprofiler_p.h> + +#ifndef QT_NO_OPENGL +#include <QtGui/private/qrhigles2_p.h> +#include <QOffscreenSurface> +#endif + +#if QT_CONFIG(vulkan) +#include <QLoggingCategory> +#include <QtGui/private/qrhivulkan_p.h> +#endif + +#ifdef Q_OS_WIN +#include <QtGui/private/qrhid3d11_p.h> +#endif + +#ifdef Q_OS_DARWIN +#include <QtGui/private/qrhimetal_p.h> +#endif + +#include "window.h" + +#include "../shared/cube.h" + +static QShader getShader(const QString &name) +{ + QFile f(name); + if (f.open(QIODevice::ReadOnly)) + return QShader::fromSerialized(f.readAll()); + + return QShader(); +} + +static GraphicsApi graphicsApi; + +static QString graphicsApiName() +{ + switch (graphicsApi) { + case OpenGL: + return QLatin1String("OpenGL 2.x"); + case Vulkan: + return QLatin1String("Vulkan"); + case D3D11: + return QLatin1String("Direct3D 11"); + case Metal: + return QLatin1String("Metal"); + default: + break; + } + return QString(); +} + +#if QT_CONFIG(vulkan) +QVulkanInstance *instance = nullptr; +#endif + +// Window (main thread) emit signals -> Renderer::send* (main thread) -> event queue (add on main, process on render thread) -> Renderer::renderEvent (render thread) + +// event queue is taken from the Qt Quick scenegraph as-is +// all this below is conceptually the same as the QSG threaded render loop +class RenderThreadEventQueue : public QQueue<QEvent *> +{ +public: + RenderThreadEventQueue() + : waiting(false) + { + } + + void addEvent(QEvent *e) { + mutex.lock(); + enqueue(e); + if (waiting) + condition.wakeOne(); + mutex.unlock(); + } + + QEvent *takeEvent(bool wait) { + mutex.lock(); + if (isEmpty() && wait) { + waiting = true; + condition.wait(&mutex); + waiting = false; + } + QEvent *e = dequeue(); + mutex.unlock(); + return e; + } + + bool hasMoreEvents() { + mutex.lock(); + bool has = !isEmpty(); + mutex.unlock(); + return has; + } + +private: + QMutex mutex; + QWaitCondition condition; + bool waiting; +}; + +struct Renderer; + +struct Thread : public QThread +{ + Thread(Renderer *renderer_) + : renderer(renderer_) + { + active = true; + start(); + } + void run() override; + + Renderer *renderer; + bool active; + RenderThreadEventQueue eventQueue; + bool sleeping = false; + bool stopEventProcessing = false; + bool pendingRender = false; + bool pendingRenderIsNewExpose = false; + // mutex and cond used to allow the main thread waiting until something completes on the render thread + QMutex mutex; + QWaitCondition cond; +}; + +class RenderThreadEvent : public QEvent +{ +public: + RenderThreadEvent(QEvent::Type type) : QEvent(type) { } +}; + +class InitEvent : public RenderThreadEvent +{ +public: + static const QEvent::Type TYPE = QEvent::Type(QEvent::User + 1); + InitEvent() : RenderThreadEvent(TYPE) + { } +}; + +class RequestRenderEvent : public RenderThreadEvent +{ +public: + static const QEvent::Type TYPE = QEvent::Type(QEvent::User + 2); + RequestRenderEvent(bool newlyExposed_) : RenderThreadEvent(TYPE), newlyExposed(newlyExposed_) + { } + bool newlyExposed; +}; + +class SurfaceCleanupEvent : public RenderThreadEvent +{ +public: + static const QEvent::Type TYPE = QEvent::Type(QEvent::User + 3); + SurfaceCleanupEvent() : RenderThreadEvent(TYPE) + { } +}; + +class CloseEvent : public RenderThreadEvent +{ +public: + static const QEvent::Type TYPE = QEvent::Type(QEvent::User + 4); + CloseEvent() : RenderThreadEvent(TYPE) + { } +}; + +class SyncSurfaceSizeEvent : public RenderThreadEvent +{ +public: + static const QEvent::Type TYPE = QEvent::Type(QEvent::User + 5); + SyncSurfaceSizeEvent() : RenderThreadEvent(TYPE) + { } +}; + +struct Renderer +{ + // ctor and dtor and send* are called main thread, rest on the render thread + + Renderer(QWindow *w, const QColor &bgColor, int rotationAxis); + ~Renderer(); + + void sendInit(); + void sendRender(bool newlyExposed); + void sendSurfaceGoingAway(); + void sendSyncSurfaceSize(); + + QWindow *window; + Thread *thread; + QRhi *r = nullptr; +#ifndef QT_NO_OPENGL + QOffscreenSurface *fallbackSurface = nullptr; +#endif + + void createRhi(); + void destroyRhi(); + void renderEvent(QEvent *e); + void init(); + void releaseSwapChain(); + void releaseResources(); + void render(bool newlyExposed, bool wakeBeforePresent); + + QColor m_bgColor; + int m_rotationAxis; + + QVector<QRhiResource *> m_releasePool; + bool m_hasSwapChain = false; + QRhiSwapChain *m_sc = nullptr; + QRhiRenderBuffer *m_ds = nullptr; + QRhiRenderPassDescriptor *m_rp = nullptr; + + QRhiBuffer *m_vbuf = nullptr; + QRhiBuffer *m_ubuf = nullptr; + QRhiTexture *m_tex = nullptr; + QRhiSampler *m_sampler = nullptr; + QRhiShaderResourceBindings *m_srb = nullptr; + QRhiGraphicsPipeline *m_ps = nullptr; + QRhiResourceUpdateBatch *m_initialUpdates = nullptr; + + QMatrix4x4 m_proj; + float m_rotation = 0; + int m_frameCount = 0; +}; + +void Thread::run() +{ + while (active) { +#ifdef Q_OS_DARWIN + QMacAutoReleasePool autoReleasePool; +#endif + + if (pendingRender) { + pendingRender = false; + renderer->render(pendingRenderIsNewExpose, false); + } + + while (eventQueue.hasMoreEvents()) { + QEvent *e = eventQueue.takeEvent(false); + renderer->renderEvent(e); + delete e; + } + + if (active && !pendingRender) { + sleeping = true; + stopEventProcessing = false; + while (!stopEventProcessing) { + QEvent *e = eventQueue.takeEvent(true); + renderer->renderEvent(e); + delete e; + } + sleeping = false; + } + } +} + +Renderer::Renderer(QWindow *w, const QColor &bgColor, int rotationAxis) + : window(w), + m_bgColor(bgColor), + m_rotationAxis(rotationAxis) +{ // main thread + thread = new Thread(this); + +#ifndef QT_NO_OPENGL + if (graphicsApi == OpenGL) + fallbackSurface = QRhiGles2InitParams::newFallbackSurface(); +#endif +} + +Renderer::~Renderer() +{ // main thread + thread->eventQueue.addEvent(new CloseEvent); + thread->wait(); + delete thread; + +#ifndef QT_NO_OPENGL + delete fallbackSurface; +#endif +} + +void Renderer::createRhi() +{ + if (r) + return; + + qDebug() << "renderer" << this << "creating rhi"; + QRhi::Flags rhiFlags = QRhi::EnableProfiling; + +#ifndef QT_NO_OPENGL + if (graphicsApi == OpenGL) { + QRhiGles2InitParams params; + params.fallbackSurface = fallbackSurface; + params.window = window; + r = QRhi::create(QRhi::OpenGLES2, ¶ms, rhiFlags); + } +#endif + +#if QT_CONFIG(vulkan) + if (graphicsApi == Vulkan) { + QRhiVulkanInitParams params; + params.inst = instance; + params.window = window; + r = QRhi::create(QRhi::Vulkan, ¶ms, rhiFlags); + } +#endif + +#ifdef Q_OS_WIN + if (graphicsApi == D3D11) { + QRhiD3D11InitParams params; + params.enableDebugLayer = true; + r = QRhi::create(QRhi::D3D11, ¶ms, rhiFlags); + } +#endif + +#ifdef Q_OS_DARWIN + if (graphicsApi == Metal) { + QRhiMetalInitParams params; + r = QRhi::create(QRhi::Metal, ¶ms, rhiFlags); + } +#endif + + if (!r) + qFatal("Failed to create RHI backend"); +} + +void Renderer::destroyRhi() +{ + qDebug() << "renderer" << this << "destroying rhi"; + delete r; + r = nullptr; +} + +void Renderer::renderEvent(QEvent *e) +{ + Q_ASSERT(QThread::currentThread() == thread); + + if (thread->sleeping) + thread->stopEventProcessing = true; + + switch (int(e->type())) { + case InitEvent::TYPE: + qDebug() << "renderer" << this << "for window" << window << "is initializing"; + createRhi(); + init(); + break; + case RequestRenderEvent::TYPE: + thread->pendingRender = true; + thread->pendingRenderIsNewExpose = static_cast<RequestRenderEvent *>(e)->newlyExposed; + break; + case SurfaceCleanupEvent::TYPE: // when the QWindow is closed, before QPlatformWindow goes away + thread->mutex.lock(); + qDebug() << "renderer" << this << "for window" << window << "is destroying swapchain"; + thread->pendingRender = false; + releaseSwapChain(); + thread->cond.wakeOne(); + thread->mutex.unlock(); + break; + case CloseEvent::TYPE: // when destroying the window+renderer (NB not the same as hitting X on the window, that's just QWindow close) + qDebug() << "renderer" << this << "for window" << window << "is shutting down"; + thread->pendingRender = false; + thread->active = false; + thread->stopEventProcessing = true; + releaseResources(); + destroyRhi(); + break; + case SyncSurfaceSizeEvent::TYPE: + thread->mutex.lock(); + thread->pendingRender = false; + render(false, true); + break; + default: + break; + } +} + +void Renderer::init() +{ + m_sc = r->newSwapChain(); + m_ds = r->newRenderBuffer(QRhiRenderBuffer::DepthStencil, + QSize(), + 1, + QRhiRenderBuffer::UsedWithSwapChainOnly); + m_releasePool << m_ds; + m_sc->setWindow(window); + m_sc->setDepthStencil(m_ds); + m_rp = m_sc->newCompatibleRenderPassDescriptor(); + m_releasePool << m_rp; + m_sc->setRenderPassDescriptor(m_rp); + + m_vbuf = r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(cube)); + m_releasePool << m_vbuf; + m_vbuf->build(); + + m_ubuf = r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64 + 4); + m_releasePool << m_ubuf; + m_ubuf->build(); + + QImage image = QImage(QLatin1String(":/qt256.png")).convertToFormat(QImage::Format_RGBA8888); + m_tex = r->newTexture(QRhiTexture::RGBA8, image.size()); + m_releasePool << m_tex; + m_tex->build(); + + m_sampler = r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None, + QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge); + m_releasePool << m_sampler; + m_sampler->build(); + + m_srb = r->newShaderResourceBindings(); + m_releasePool << m_srb; + m_srb->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, m_ubuf), + QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, m_tex, m_sampler) + }); + m_srb->build(); + + m_ps = r->newGraphicsPipeline(); + m_releasePool << m_ps; + + m_ps->setDepthTest(true); + m_ps->setDepthWrite(true); + m_ps->setDepthOp(QRhiGraphicsPipeline::Less); + + m_ps->setCullMode(QRhiGraphicsPipeline::Back); + m_ps->setFrontFace(QRhiGraphicsPipeline::CCW); + + m_ps->setShaderStages({ + { QRhiShaderStage::Vertex, getShader(QLatin1String(":/texture.vert.qsb")) }, + { QRhiShaderStage::Fragment, getShader(QLatin1String(":/texture.frag.qsb")) } + }); + + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ + { 3 * sizeof(float) }, + { 2 * sizeof(float) } + }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float3, 0 }, + { 1, 1, QRhiVertexInputAttribute::Float2, 0 } + }); + + m_ps->setVertexInputLayout(inputLayout); + m_ps->setShaderResourceBindings(m_srb); + m_ps->setRenderPassDescriptor(m_rp); + + m_ps->build(); + + m_initialUpdates = r->nextResourceUpdateBatch(); + + m_initialUpdates->uploadStaticBuffer(m_vbuf, cube); + + qint32 flip = 0; + m_initialUpdates->updateDynamicBuffer(m_ubuf, 64, 4, &flip); + + m_initialUpdates->uploadTexture(m_tex, image); +} + +void Renderer::releaseSwapChain() +{ + if (m_hasSwapChain) { + m_hasSwapChain = false; + m_sc->release(); + } +} + +void Renderer::releaseResources() +{ + qDeleteAll(m_releasePool); + m_releasePool.clear(); + + delete m_sc; + m_sc = nullptr; +} + +void Renderer::render(bool newlyExposed, bool wakeBeforePresent) +{ + // This function handles both resizing and rendering. Resizes have some + // complications due to the threaded model (check exposeEvent and + // sendSyncSurfaceSize) but don't have to worry about that in here. + + auto buildOrResizeSwapChain = [this] { + qDebug() << "renderer" << this << "build or resize swapchain for window" << window; + m_hasSwapChain = m_sc->buildOrResize(); + const QSize outputSize = m_sc->currentPixelSize(); + qDebug() << " size is" << outputSize; + m_proj = r->clipSpaceCorrMatrix(); + m_proj.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 100.0f); + m_proj.translate(0, 0, -4); + }; + + auto wakeUpIfNeeded = [wakeBeforePresent, this] { + // make sure the main/gui thread is not blocked when issuing the Present (or equivalent) + if (wakeBeforePresent) { + thread->cond.wakeOne(); + thread->mutex.unlock(); + } + }; + + const QSize surfaceSize = m_sc->surfacePixelSize(); + if (surfaceSize.isEmpty()) { + wakeUpIfNeeded(); + return; + } + + if (newlyExposed || m_sc->currentPixelSize() != surfaceSize) + buildOrResizeSwapChain(); + + if (!m_hasSwapChain) { + wakeUpIfNeeded(); + return; + } + + QRhi::FrameOpResult result = r->beginFrame(m_sc); + if (result == QRhi::FrameOpSwapChainOutOfDate) { + buildOrResizeSwapChain(); + if (!m_hasSwapChain) { + wakeUpIfNeeded(); + return; + } + result = r->beginFrame(m_sc); + } + if (result != QRhi::FrameOpSuccess) { + wakeUpIfNeeded(); + return; + } + + QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer(); + const QSize outputSize = m_sc->currentPixelSize(); + + QRhiResourceUpdateBatch *u = r->nextResourceUpdateBatch(); + if (m_initialUpdates) { + u->merge(m_initialUpdates); + m_initialUpdates->release(); + m_initialUpdates = nullptr; + } + + m_rotation += 1.0f; + QMatrix4x4 mvp = m_proj; + mvp.scale(0.5f); + mvp.rotate(m_rotation, m_rotationAxis == 0 ? 1 : 0, m_rotationAxis == 1 ? 1 : 0, m_rotationAxis == 2 ? 1 : 0); + u->updateDynamicBuffer(m_ubuf, 0, 64, mvp.constData()); + + cb->beginPass(m_sc->currentFrameRenderTarget(), + QColor::fromRgbF(float(m_bgColor.redF()), float(m_bgColor.greenF()), float(m_bgColor.blueF()), 1.0f), + { 1.0f, 0 }, + u); + + cb->setGraphicsPipeline(m_ps); + cb->setViewport(QRhiViewport(0, 0, outputSize.width(), outputSize.height())); + cb->setShaderResources(); + const QRhiCommandBuffer::VertexInput vbufBindings[] = { + { m_vbuf, 0 }, + { m_vbuf, 36 * 3 * sizeof(float) } + }; + cb->setVertexInput(0, 2, vbufBindings); + cb->draw(36); + + cb->endPass(); + + wakeUpIfNeeded(); + + r->endFrame(m_sc); + + m_frameCount += 1; + if ((m_frameCount % 300) == 0) { + const QRhiProfiler::CpuTime ff = r->profiler()->frameToFrameTimes(m_sc); + const QRhiProfiler::CpuTime be = r->profiler()->frameBuildTimes(m_sc); + const QRhiProfiler::GpuTime gp = r->profiler()->gpuFrameTimes(m_sc); + if (r->isFeatureSupported(QRhi::Timestamps)) { + qDebug("[renderer %p] frame-to-frame: min %lld max %lld avg %f. " + "frame build: min %lld max %lld avg %f. " + "gpu frame time: min %f max %f avg %f", + this, + ff.minTime, ff.maxTime, ff.avgTime, + be.minTime, be.maxTime, be.avgTime, + gp.minTime, gp.maxTime, gp.avgTime); + } else { + qDebug("[renderer %p] frame-to-frame: min %lld max %lld avg %f. " + "frame build: min %lld max %lld avg %f. ", + this, + ff.minTime, ff.maxTime, ff.avgTime, + be.minTime, be.maxTime, be.avgTime); + } + } +} + +void Renderer::sendInit() +{ // main thread + InitEvent *e = new InitEvent; + thread->eventQueue.addEvent(e); +} + +void Renderer::sendRender(bool newlyExposed) +{ // main thread + RequestRenderEvent *e = new RequestRenderEvent(newlyExposed); + thread->eventQueue.addEvent(e); +} + +void Renderer::sendSurfaceGoingAway() +{ // main thread + SurfaceCleanupEvent *e = new SurfaceCleanupEvent; + + // cannot let this thread to proceed with tearing down the native window + // before the render thread completes the swapchain release + thread->mutex.lock(); + + thread->eventQueue.addEvent(e); + + thread->cond.wait(&thread->mutex); + thread->mutex.unlock(); +} + +void Renderer::sendSyncSurfaceSize() +{ // main thread + SyncSurfaceSizeEvent *e = new SyncSurfaceSizeEvent; + // must block to prevent surface size mess. the render thread will do a + // full rendering round before it unlocks which is good since it can thus + // pick up and the surface (window) size atomically. + thread->mutex.lock(); + thread->eventQueue.addEvent(e); + thread->cond.wait(&thread->mutex); + thread->mutex.unlock(); +} + +struct WindowAndRenderer +{ + QWindow *window; + Renderer *renderer; +}; + +QVector<WindowAndRenderer> windows; + +void createWindow() +{ + static QColor colors[] = { Qt::red, Qt::green, Qt::blue, Qt::yellow, Qt::cyan, Qt::gray }; + const int n = windows.count(); + Window *w = new Window(QString::asprintf("Window+Thread #%d (%s)", n, qPrintable(graphicsApiName())), graphicsApi); + Renderer *renderer = new Renderer(w, colors[n % 6], n % 3);; + QObject::connect(w, &Window::initRequested, w, [renderer] { + renderer->sendInit(); + }); + QObject::connect(w, &Window::renderRequested, w, [w, renderer](bool newlyExposed) { + renderer->sendRender(newlyExposed); + w->requestUpdate(); + }); + QObject::connect(w, &Window::surfaceGoingAway, w, [renderer] { + renderer->sendSurfaceGoingAway(); + }); + QObject::connect(w, &Window::syncSurfaceSizeRequested, w, [renderer] { + renderer->sendSyncSurfaceSize(); + }); + windows.append({ w, renderer }); + w->show(); +} + +void closeWindow() +{ + WindowAndRenderer wr = windows.takeLast(); + delete wr.renderer; + delete wr.window; +} + +int main(int argc, char **argv) +{ + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QApplication app(argc, argv); + +#if defined(Q_OS_WIN) + graphicsApi = D3D11; +#elif defined(Q_OS_DARWIN) + graphicsApi = Metal; +#elif QT_CONFIG(vulkan) + graphicsApi = Vulkan; +#else + graphicsApi = OpenGL; +#endif + + QCommandLineParser cmdLineParser; + cmdLineParser.addHelpOption(); + QCommandLineOption glOption({ "g", "opengl" }, QLatin1String("OpenGL (2.x)")); + cmdLineParser.addOption(glOption); + QCommandLineOption vkOption({ "v", "vulkan" }, QLatin1String("Vulkan")); + cmdLineParser.addOption(vkOption); + QCommandLineOption d3dOption({ "d", "d3d11" }, QLatin1String("Direct3D 11")); + cmdLineParser.addOption(d3dOption); + QCommandLineOption mtlOption({ "m", "metal" }, QLatin1String("Metal")); + cmdLineParser.addOption(mtlOption); + cmdLineParser.process(app); + if (cmdLineParser.isSet(glOption)) + graphicsApi = OpenGL; + if (cmdLineParser.isSet(vkOption)) + graphicsApi = Vulkan; + if (cmdLineParser.isSet(d3dOption)) + graphicsApi = D3D11; + if (cmdLineParser.isSet(mtlOption)) + graphicsApi = Metal; + + qDebug("Selected graphics API is %s", qPrintable(graphicsApiName())); + qDebug("This is a multi-api example, use command line arguments to override:\n%s", qPrintable(cmdLineParser.helpText())); + +#if QT_CONFIG(vulkan) + instance = new QVulkanInstance; + if (graphicsApi == Vulkan) { +#ifndef Q_OS_ANDROID + instance->setLayers({ "VK_LAYER_LUNARG_standard_validation" }); +#else + instance->setLayers(QByteArrayList() + << "VK_LAYER_GOOGLE_threading" + << "VK_LAYER_LUNARG_parameter_validation" + << "VK_LAYER_LUNARG_object_tracker" + << "VK_LAYER_LUNARG_core_validation" + << "VK_LAYER_LUNARG_image" + << "VK_LAYER_LUNARG_swapchain" + << "VK_LAYER_GOOGLE_unique_objects"); +#endif + if (!instance->create()) { + qWarning("Failed to create Vulkan instance, switching to OpenGL"); + graphicsApi = OpenGL; + } + } +#endif + + int winCount = 0; + QWidget w; + w.resize(800, 600); + w.setWindowTitle(QCoreApplication::applicationName() + QLatin1String(" - ") + graphicsApiName()); + QVBoxLayout *layout = new QVBoxLayout(&w); + + QPlainTextEdit *info = new QPlainTextEdit( + QLatin1String("This application tests rendering on a separate thread per window, with dedicated QRhi instances and resources. " + "\n\nThis is the same concept as the Qt Quick Scenegraph's threaded render loop. This should allow rendering to the different windows " + "without unintentionally throttling each other's threads." + "\n\nUsing API: ") + graphicsApiName()); + info->setReadOnly(true); + layout->addWidget(info); + QLabel *label = new QLabel(QLatin1String("Window and thread count: 0")); + layout->addWidget(label); + QPushButton *btn = new QPushButton(QLatin1String("New window")); + QObject::connect(btn, &QPushButton::clicked, btn, [label, &winCount] { + winCount += 1; + label->setText(QString::asprintf("Window count: %d", winCount)); + createWindow(); + }); + layout->addWidget(btn); + btn = new QPushButton(QLatin1String("Close window")); + QObject::connect(btn, &QPushButton::clicked, btn, [label, &winCount] { + if (winCount > 0) { + winCount -= 1; + label->setText(QString::asprintf("Window count: %d", winCount)); + closeWindow(); + } + }); + layout->addWidget(btn); + w.show(); + + int result = app.exec(); + + for (const WindowAndRenderer &wr : windows) { + delete wr.renderer; + delete wr.window; + } + +#if QT_CONFIG(vulkan) + delete instance; +#endif + + return result; +} diff --git a/tests/manual/rhi/multiwindow_threaded/multiwindow_threaded.pro b/tests/manual/rhi/multiwindow_threaded/multiwindow_threaded.pro new file mode 100644 index 0000000000..0b78518b9b --- /dev/null +++ b/tests/manual/rhi/multiwindow_threaded/multiwindow_threaded.pro @@ -0,0 +1,12 @@ +TEMPLATE = app + +QT += gui-private widgets + +SOURCES = \ + multiwindow_threaded.cpp \ + window.cpp + +HEADERS = \ + window.h + +RESOURCES = multiwindow_threaded.qrc diff --git a/tests/manual/rhi/multiwindow_threaded/multiwindow_threaded.qrc b/tests/manual/rhi/multiwindow_threaded/multiwindow_threaded.qrc new file mode 100644 index 0000000000..742b2b77af --- /dev/null +++ b/tests/manual/rhi/multiwindow_threaded/multiwindow_threaded.qrc @@ -0,0 +1,7 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file alias="qt256.png">../shared/qt256.png</file> + <file alias="texture.vert.qsb">../shared/texture.vert.qsb</file> + <file alias="texture.frag.qsb">../shared/texture.frag.qsb</file> +</qresource> +</RCC> diff --git a/tests/manual/rhi/multiwindow_threaded/window.cpp b/tests/manual/rhi/multiwindow_threaded/window.cpp new file mode 100644 index 0000000000..aa7b479047 --- /dev/null +++ b/tests/manual/rhi/multiwindow_threaded/window.cpp @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "window.h" +#include <QPlatformSurfaceEvent> + +#ifndef QT_NO_OPENGL +#include <QtGui/private/qrhigles2_p.h> +#endif + +#if QT_CONFIG(vulkan) +extern QVulkanInstance *instance; +#endif + +Window::Window(const QString &title, GraphicsApi api) +{ + switch (api) { + case OpenGL: +#if QT_CONFIG(opengl) + setSurfaceType(OpenGLSurface); + setFormat(QRhiGles2InitParams::adjustedFormat()); +#endif + break; + case Vulkan: +#if QT_CONFIG(vulkan) + setSurfaceType(VulkanSurface); + setVulkanInstance(instance); +#endif + break; + case D3D11: + setSurfaceType(OpenGLSurface); // not a typo + break; + case Metal: +#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) + setSurfaceType(MetalSurface); +#endif + break; + default: + break; + } + + resize(800, 600); + setTitle(title); +} + +Window::~Window() +{ +} + +void Window::exposeEvent(QExposeEvent *) +{ + if (isExposed()) { + if (!m_running) { + // initialize and start rendering when the window becomes usable for graphics purposes + m_running = true; + m_notExposed = false; + emit initRequested(); + emit renderRequested(true); + } else { + // continue when exposed again + if (m_notExposed) { + m_notExposed = false; + emit renderRequested(true); + } else { + // resize generates exposes - this is very important here (unlike in a single-threaded renderer) + emit syncSurfaceSizeRequested(); + } + } + } else { + // stop pushing frames when not exposed (on some platforms this is essential, optional on others) + if (m_running) + m_notExposed = true; + } +} + +bool Window::event(QEvent *e) +{ + switch (e->type()) { + case QEvent::UpdateRequest: + if (!m_notExposed) + emit renderRequested(false); + break; + + case QEvent::PlatformSurface: + // this is the proper time to tear down the swapchain (while the native window and surface are still around) + if (static_cast<QPlatformSurfaceEvent *>(e)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) + emit surfaceGoingAway(); + break; + + default: + break; + } + + return QWindow::event(e); +} diff --git a/tests/manual/rhi/multiwindow_threaded/window.h b/tests/manual/rhi/multiwindow_threaded/window.h new file mode 100644 index 0000000000..7810858d0a --- /dev/null +++ b/tests/manual/rhi/multiwindow_threaded/window.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WINDOW_H +#define WINDOW_H + +#include <QWindow> + +enum GraphicsApi +{ + OpenGL, + Vulkan, + D3D11, + Metal +}; + +class Window : public QWindow +{ + Q_OBJECT + +public: + Window(const QString &title, GraphicsApi api); + ~Window(); + + void exposeEvent(QExposeEvent *) override; + bool event(QEvent *) override; + +signals: + void initRequested(); + void renderRequested(bool newlyExposed); + void surfaceGoingAway(); + void syncSurfaceSizeRequested(); + +protected: + bool m_running = false; + bool m_notExposed = true; +}; + +#endif diff --git a/tests/manual/rhi/offscreen/offscreen.cpp b/tests/manual/rhi/offscreen/offscreen.cpp new file mode 100644 index 0000000000..79e50d3dd4 --- /dev/null +++ b/tests/manual/rhi/offscreen/offscreen.cpp @@ -0,0 +1,366 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QGuiApplication> +#include <QImage> +#include <QFileInfo> +#include <QFile> +#include <QLoggingCategory> +#include <QCommandLineParser> +#include <QtGui/private/qshader_p.h> + +#include <QtGui/private/qrhinull_p.h> + +#ifndef QT_NO_OPENGL +#include <QtGui/private/qrhigles2_p.h> +#include <QOffscreenSurface> +#endif + +#if QT_CONFIG(vulkan) +#include <QLoggingCategory> +#include <QtGui/private/qrhivulkan_p.h> +#endif + +#ifdef Q_OS_WIN +#include <QtGui/private/qrhid3d11_p.h> +#endif + +#ifdef Q_OS_DARWIN +#include <QtGui/private/qrhimetal_p.h> +#endif + +//#define TEST_FINISH + +static float vertexData[] = { // Y up (note m_proj), CCW + 0.0f, 0.5f, 1.0f, 0.0f, 0.0f, + -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, + 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, +}; + +static QShader getShader(const QString &name) +{ + QFile f(name); + if (f.open(QIODevice::ReadOnly)) + return QShader::fromSerialized(f.readAll()); + + return QShader(); +} + +enum GraphicsApi +{ + OpenGL, + Vulkan, + D3D11, + Metal, + Null +}; + +GraphicsApi graphicsApi; + +QString graphicsApiName() +{ + switch (graphicsApi) { + case OpenGL: + return QLatin1String("OpenGL 2.x"); + case Vulkan: + return QLatin1String("Vulkan"); + case D3D11: + return QLatin1String("Direct3D 11"); + case Metal: + return QLatin1String("Metal"); + case Null: + return QLatin1String("Null"); + default: + break; + } + return QString(); +} + +int main(int argc, char **argv) +{ + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QGuiApplication app(argc, argv); + +#if defined(Q_OS_WIN) + graphicsApi = D3D11; +#elif defined(Q_OS_DARWIN) + graphicsApi = Metal; +#elif QT_CONFIG(vulkan) + graphicsApi = Vulkan; +#else + graphicsApi = OpenGL; +#endif + + QCommandLineParser cmdLineParser; + cmdLineParser.addHelpOption(); + QCommandLineOption glOption({ "g", "opengl" }, QLatin1String("OpenGL (2.x)")); + cmdLineParser.addOption(glOption); + QCommandLineOption vkOption({ "v", "vulkan" }, QLatin1String("Vulkan")); + cmdLineParser.addOption(vkOption); + QCommandLineOption d3dOption({ "d", "d3d11" }, QLatin1String("Direct3D 11")); + cmdLineParser.addOption(d3dOption); + QCommandLineOption mtlOption({ "m", "metal" }, QLatin1String("Metal")); + cmdLineParser.addOption(mtlOption); + QCommandLineOption nullOption({ "n", "null" }, QLatin1String("Null")); + cmdLineParser.addOption(nullOption); + cmdLineParser.process(app); + if (cmdLineParser.isSet(glOption)) + graphicsApi = OpenGL; + if (cmdLineParser.isSet(vkOption)) + graphicsApi = Vulkan; + if (cmdLineParser.isSet(d3dOption)) + graphicsApi = D3D11; + if (cmdLineParser.isSet(mtlOption)) + graphicsApi = Metal; + if (cmdLineParser.isSet(nullOption)) + graphicsApi = Null; + + qDebug("Selected graphics API is %s", qPrintable(graphicsApiName())); + qDebug("This is a multi-api example, use command line arguments to override:\n%s", qPrintable(cmdLineParser.helpText())); + + QRhi *r = nullptr; + + if (graphicsApi == Null) { + QRhiNullInitParams params; + r = QRhi::create(QRhi::Null, ¶ms); + } + +#if QT_CONFIG(vulkan) + QVulkanInstance inst; + if (graphicsApi == Vulkan) { + QLoggingCategory::setFilterRules(QStringLiteral("qt.vulkan=true")); +#ifndef Q_OS_ANDROID + inst.setLayers(QByteArrayList() << "VK_LAYER_LUNARG_standard_validation"); +#else + inst.setLayers(QByteArrayList() + << "VK_LAYER_GOOGLE_threading" + << "VK_LAYER_LUNARG_parameter_validation" + << "VK_LAYER_LUNARG_object_tracker" + << "VK_LAYER_LUNARG_core_validation" + << "VK_LAYER_LUNARG_image" + << "VK_LAYER_LUNARG_swapchain" + << "VK_LAYER_GOOGLE_unique_objects"); +#endif + if (inst.create()) { + QRhiVulkanInitParams params; + params.inst = &inst; + r = QRhi::create(QRhi::Vulkan, ¶ms); + } else { + qWarning("Failed to create Vulkan instance, switching to OpenGL"); + graphicsApi = OpenGL; + } + } +#endif + +#ifndef QT_NO_OPENGL + QScopedPointer<QOffscreenSurface> offscreenSurface; + if (graphicsApi == OpenGL) { + offscreenSurface.reset(QRhiGles2InitParams::newFallbackSurface()); + QRhiGles2InitParams params; + params.fallbackSurface = offscreenSurface.data(); + r = QRhi::create(QRhi::OpenGLES2, ¶ms); + } +#endif + +#ifdef Q_OS_WIN + if (graphicsApi == D3D11) { + QRhiD3D11InitParams params; + params.enableDebugLayer = true; + r = QRhi::create(QRhi::D3D11, ¶ms); + } +#endif + +#ifdef Q_OS_DARWIN + if (graphicsApi == Metal) { + QRhiMetalInitParams params; + r = QRhi::create(QRhi::Metal, ¶ms); + } +#endif + + if (!r) + qFatal("Failed to initialize RHI"); + + QRhiTexture *tex = r->newTexture(QRhiTexture::RGBA8, QSize(1280, 720), 1, QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource); + tex->build(); + QRhiTextureRenderTarget *rt = r->newTextureRenderTarget({ tex }); + QRhiRenderPassDescriptor *rp = rt->newCompatibleRenderPassDescriptor(); + rt->setRenderPassDescriptor(rp); + rt->build(); + + QMatrix4x4 proj = r->clipSpaceCorrMatrix(); + proj.perspective(45.0f, 1280 / 720.f, 0.01f, 1000.0f); + proj.translate(0, 0, -4); + + QRhiBuffer *vbuf = r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData)); + vbuf->build(); + + QRhiBuffer *ubuf = r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 68); + ubuf->build(); + + QRhiShaderResourceBindings *srb = r->newShaderResourceBindings(); + srb->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, ubuf) + }); + srb->build(); + + QRhiGraphicsPipeline *ps = r->newGraphicsPipeline(); + + QRhiGraphicsPipeline::TargetBlend premulAlphaBlend; + premulAlphaBlend.enable = true; + ps->setTargetBlends({ premulAlphaBlend }); + + const QShader vs = getShader(QLatin1String(":/color.vert.qsb")); + if (!vs.isValid()) + qFatal("Failed to load shader pack (vertex)"); + const QShader fs = getShader(QLatin1String(":/color.frag.qsb")); + if (!fs.isValid()) + qFatal("Failed to load shader pack (fragment)"); + + ps->setShaderStages({ + { QRhiShaderStage::Vertex, vs }, + { QRhiShaderStage::Fragment, fs } + }); + + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ + { 5 * sizeof(float) } + }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float2, 0 }, + { 0, 1, QRhiVertexInputAttribute::Float3, 2 * sizeof(float) } + }); + + ps->setVertexInputLayout(inputLayout); + ps->setShaderResourceBindings(srb); + ps->setRenderPassDescriptor(rp); + ps->build(); + + int frame = 0; + for (; frame < 20; ++frame) { + QRhiCommandBuffer *cb; + if (r->beginOffscreenFrame(&cb) != QRhi::FrameOpSuccess) + break; + + qDebug("Generating offscreen frame %d", frame); + QRhiResourceUpdateBatch *u = r->nextResourceUpdateBatch(); + if (frame == 0) + u->uploadStaticBuffer(vbuf, vertexData); + + static float rotation = 0.0f; + QMatrix4x4 mvp = proj; + mvp.rotate(rotation, 0, 1, 0); + u->updateDynamicBuffer(ubuf, 0, 64, mvp.constData()); + rotation += 5.0f; + static float opacity = 1.0f; + static int opacityDir= 1; + u->updateDynamicBuffer(ubuf, 64, 4, &opacity); + opacity += opacityDir * 0.005f; + if (opacity < 0.0f || opacity > 1.0f) { + opacityDir *= -1; + opacity = qBound(0.0f, opacity, 1.0f); + } + + cb->beginPass(rt, QColor::fromRgbF(0.0f, 1.0f, 0.0f, 1.0f), { 1, 0 }, u); + cb->setGraphicsPipeline(ps); + cb->setViewport({ 0, 0, 1280, 720 }); + cb->setShaderResources(); + const QRhiCommandBuffer::VertexInput vbufBinding(vbuf, 0); + cb->setVertexInput(0, 1, &vbufBinding); + cb->draw(3); + + u = r->nextResourceUpdateBatch(); + QRhiReadbackDescription rb(tex); + QRhiReadbackResult rbResult; + rbResult.completed = [frame] { qDebug(" - readback %d completed", frame); }; + u->readBackTexture(rb, &rbResult); + + cb->endPass(u); + + qDebug("Submit and wait"); +#ifdef TEST_FINISH + r->finish(); +#else + r->endOffscreenFrame(); +#endif + // The data should be ready either because endOffscreenFrame() waits + // for completion or because finish() did. + if (!rbResult.data.isEmpty()) { + const uchar *p = reinterpret_cast<const uchar *>(rbResult.data.constData()); + QImage image(p, rbResult.pixelSize.width(), rbResult.pixelSize.height(), QImage::Format_RGBA8888); + QString fn = QString::asprintf("frame%d.png", frame); + fn = QFileInfo(fn).absoluteFilePath(); + qDebug("Saving into %s", qPrintable(fn)); + if (r->isYUpInFramebuffer()) + image.mirrored().save(fn); + else + image.save(fn); + } else { + qWarning("Readback failed!"); + } +#ifdef TEST_FINISH + r->endOffscreenFrame(); +#endif + } + + delete ps; + delete srb; + delete ubuf; + delete vbuf; + + delete rt; + delete rp; + delete tex; + + delete r; + + qDebug("\nRendered and read back %d frames using %s", frame, qPrintable(graphicsApiName())); + + return 0; +} diff --git a/tests/manual/rhi/offscreen/offscreen.pro b/tests/manual/rhi/offscreen/offscreen.pro new file mode 100644 index 0000000000..ae040a4b6c --- /dev/null +++ b/tests/manual/rhi/offscreen/offscreen.pro @@ -0,0 +1,9 @@ +TEMPLATE = app +CONFIG += console + +QT += gui-private + +SOURCES = \ + offscreen.cpp + +RESOURCES = offscreen.qrc diff --git a/tests/manual/rhi/offscreen/offscreen.qrc b/tests/manual/rhi/offscreen/offscreen.qrc new file mode 100644 index 0000000000..8cec4fa9ec --- /dev/null +++ b/tests/manual/rhi/offscreen/offscreen.qrc @@ -0,0 +1,6 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file alias="color.vert.qsb">../shared/color.vert.qsb</file> + <file alias="color.frag.qsb">../shared/color.frag.qsb</file> +</qresource> +</RCC> diff --git a/tests/manual/rhi/qrhiprof/qrhiprof.cpp b/tests/manual/rhi/qrhiprof/qrhiprof.cpp new file mode 100644 index 0000000000..7e3027a951 --- /dev/null +++ b/tests/manual/rhi/qrhiprof/qrhiprof.cpp @@ -0,0 +1,671 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Simple QRhiProfiler receiver app. Start it and then in a QRhi-based +// application connect with a QTcpSocket to 127.0.0.1:30667 and set that as the +// QRhiProfiler's device. + +#include <QTcpServer> +#include <QTcpSocket> +#include <QApplication> +#include <QWidget> +#include <QVBoxLayout> +#include <QGroupBox> +#include <QTextEdit> +#include <QLabel> +#include <QTime> +#include <QtGui/private/qrhiprofiler_p.h> + +const int MIN_KNOWN_OP = 1; +const int MAX_KNOWN_OP = 18; + +class Parser : public QObject +{ + Q_OBJECT + +public: + void feed(const QByteArray &line); + + struct Event { + QRhiProfiler::StreamOp op; + qint64 timestamp; + quint64 resource; + QByteArray resourceName; + + struct Param { + enum ValueType { + Int64, + Float + }; + QByteArray key; + ValueType valueType; + union { + qint64 intValue; + float floatValue; + }; + }; + + QVector<Param> params; + + const Param *param(const char *key) const { + auto it = std::find_if(params.cbegin(), params.cend(), [key](const Param &p) { + return !strcmp(p.key.constData(), key); + }); + return it == params.cend() ? nullptr : &*it; + } + }; + +signals: + void eventReceived(const Event &e); +}; + +void Parser::feed(const QByteArray &line) +{ + const QList<QByteArray> elems = line.split(','); + if (elems.count() < 4) { + qWarning("Malformed line '%s'", line.constData()); + return; + } + bool ok = false; + const int op = elems[0].toInt(&ok); + if (!ok) { + qWarning("Invalid op %s", elems[0].constData()); + return; + } + if (op < MIN_KNOWN_OP || op > MAX_KNOWN_OP) { + qWarning("Unknown op %d", op); + return; + } + + Event e; + e.op = QRhiProfiler::StreamOp(op); + e.timestamp = elems[1].toLongLong(); + e.resource = elems[2].toULongLong(); + e.resourceName = elems[3]; + + const int elemCount = elems.count(); + for (int i = 4; i < elemCount; i += 2) { + if (i + 1 < elemCount && !elems[i].isEmpty() && !elems[i + 1].isEmpty()) { + QByteArray key = elems[i]; + if (key.startsWith('F')) { + key = key.mid(1); + bool ok = false; + const float value = elems[i + 1].toFloat(&ok); + if (!ok) { + qWarning("Failed to parse float %s in line '%s'", elems[i + 1].constData(), line.constData()); + continue; + } + Event::Param param; + param.key = key; + param.valueType = Event::Param::Float; + param.floatValue = value; + e.params.append(param); + } else { + const qint64 value = elems[i + 1].toLongLong(); + Event::Param param; + param.key = key; + param.valueType = Event::Param::Int64; + param.intValue = value; + e.params.append(param); + } + } + } + + emit eventReceived(e); +} + +class Tracker : public QObject +{ + Q_OBJECT + +public slots: + void handleEvent(const Parser::Event &e); + +signals: + void buffersTouched(); + void texturesTouched(); + void swapchainsTouched(); + void frameTimeTouched(); + void gpuFrameTimeTouched(); + void gpuMemAllocStatsTouched(); + +public: + Tracker() { + reset(); + } + + static const int MAX_STAGING_SLOTS = 3; + + struct Buffer { + Buffer() + { + memset(stagingExtraSize, 0, sizeof(stagingExtraSize)); + } + quint64 lastTimestamp; + QByteArray resourceName; + qint64 effectiveSize = 0; + int backingGpuBufCount = 1; + qint64 stagingExtraSize[MAX_STAGING_SLOTS]; + }; + QHash<qint64, Buffer> m_buffers; + qint64 m_totalBufferApproxByteSize; + qint64 m_peakBufferApproxByteSize; + qint64 m_totalStagingBufferApproxByteSize; + qint64 m_peakStagingBufferApproxByteSize; + + struct Texture { + Texture() + { + memset(stagingExtraSize, 0, sizeof(stagingExtraSize)); + } + quint64 lastTimestamp; + QByteArray resourceName; + qint64 approxByteSize = 0; + bool ownsNativeResource = true; + qint64 stagingExtraSize[MAX_STAGING_SLOTS]; + }; + QHash<qint64, Texture> m_textures; + qint64 m_totalTextureApproxByteSize; + qint64 m_peakTextureApproxByteSize; + qint64 m_totalTextureStagingBufferApproxByteSize; + qint64 m_peakTextureStagingBufferApproxByteSize; + + struct SwapChain { + quint64 lastTimestamp; + QByteArray resourceName; + qint64 approxByteSize = 0; + }; + QHash<qint64, SwapChain> m_swapchains; + qint64 m_totalSwapChainApproxByteSize; + qint64 m_peakSwapChainApproxByteSize; + + struct FrameTime { + qint64 framesSinceResize = 0; + int minDelta = 0; + int maxDelta = 0; + float avgDelta = 0; + }; + FrameTime m_lastFrameTime; + + struct GpuFrameTime { + float minTime = 0; + float maxTime = 0; + float avgTime = 0; + }; + GpuFrameTime m_lastGpuFrameTime; + + struct GpuMemAllocStats { + qint64 realAllocCount; + qint64 subAllocCount; + qint64 totalSize; + qint64 unusedSize; + }; + GpuMemAllocStats m_lastGpuMemAllocStats; + + void reset() { + m_buffers.clear(); + m_textures.clear(); + m_totalBufferApproxByteSize = 0; + m_peakBufferApproxByteSize = 0; + m_totalStagingBufferApproxByteSize = 0; + m_peakStagingBufferApproxByteSize = 0; + m_totalTextureApproxByteSize = 0; + m_peakTextureApproxByteSize = 0; + m_totalTextureStagingBufferApproxByteSize = 0; + m_peakTextureStagingBufferApproxByteSize = 0; + m_totalSwapChainApproxByteSize = 0; + m_peakSwapChainApproxByteSize = 0; + m_lastFrameTime = FrameTime(); + m_lastGpuFrameTime = GpuFrameTime(); + m_lastGpuMemAllocStats = GpuMemAllocStats(); + emit buffersTouched(); + emit texturesTouched(); + emit swapchainsTouched(); + emit frameTimeTouched(); + emit gpuFrameTimeTouched(); + emit gpuMemAllocStatsTouched(); + } +}; + +Q_DECLARE_TYPEINFO(Tracker::Buffer, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(Tracker::Texture, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(Tracker::FrameTime, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(Tracker::GpuFrameTime, Q_MOVABLE_TYPE); + +void Tracker::handleEvent(const Parser::Event &e) +{ + switch (e.op) { + case QRhiProfiler::NewBuffer: + { + Buffer b; + b.lastTimestamp = e.timestamp; + b.resourceName = e.resourceName; + // type,0,usage,1,logical_size,84,effective_size,84,backing_gpu_buf_count,1,backing_cpu_buf_count,0 + for (const Parser::Event::Param &p : e.params) { + if (p.key == QByteArrayLiteral("effective_size")) + b.effectiveSize = p.intValue; + else if (p.key == QByteArrayLiteral("backing_gpu_buf_count")) + b.backingGpuBufCount = p.intValue; + } + m_totalBufferApproxByteSize += b.effectiveSize * b.backingGpuBufCount; + m_peakBufferApproxByteSize = qMax(m_peakBufferApproxByteSize, m_totalBufferApproxByteSize); + m_buffers.insert(e.resource, b); + emit buffersTouched(); + } + break; + case QRhiProfiler::ReleaseBuffer: + { + auto it = m_buffers.find(e.resource); + if (it != m_buffers.end()) { + m_totalBufferApproxByteSize -= it->effectiveSize * it->backingGpuBufCount; + m_buffers.erase(it); + emit buffersTouched(); + } + } + break; + + case QRhiProfiler::NewBufferStagingArea: + { + qint64 slot = -1; + qint64 size = 0; + for (const Parser::Event::Param &p : e.params) { + if (p.key == QByteArrayLiteral("slot")) + slot = p.intValue; + else if (p.key == QByteArrayLiteral("size")) + size = p.intValue; + } + if (slot >= 0 && slot < MAX_STAGING_SLOTS) { + auto it = m_buffers.find(e.resource); + if (it != m_buffers.end()) { + it->stagingExtraSize[slot] = size; + m_totalStagingBufferApproxByteSize += size; + m_peakStagingBufferApproxByteSize = qMax(m_peakStagingBufferApproxByteSize, m_totalStagingBufferApproxByteSize); + emit buffersTouched(); + } + } + } + break; + case QRhiProfiler::ReleaseBufferStagingArea: + { + qint64 slot = -1; + for (const Parser::Event::Param &p : e.params) { + if (p.key == QByteArrayLiteral("slot")) + slot = p.intValue; + } + if (slot >= 0 && slot < MAX_STAGING_SLOTS) { + auto it = m_buffers.find(e.resource); + if (it != m_buffers.end()) { + m_totalStagingBufferApproxByteSize -= it->stagingExtraSize[slot]; + it->stagingExtraSize[slot] = 0; + emit buffersTouched(); + } + } + } + break; + + case QRhiProfiler::NewTexture: + { + Texture t; + t.lastTimestamp = e.timestamp; + t.resourceName = e.resourceName; + // width,256,height,256,format,1,owns_native_resource,1,mip_count,9,layer_count,1,effective_sample_count,1,approx_byte_size,349524 + for (const Parser::Event::Param &p : e.params) { + if (p.key == QByteArrayLiteral("approx_byte_size")) + t.approxByteSize = p.intValue; + else if (p.key == QByteArrayLiteral("owns_native_resource")) + t.ownsNativeResource = p.intValue; + } + if (t.ownsNativeResource) { + m_totalTextureApproxByteSize += t.approxByteSize; + m_peakTextureApproxByteSize = qMax(m_peakTextureApproxByteSize, m_totalTextureApproxByteSize); + } + m_textures.insert(e.resource, t); + emit texturesTouched(); + } + break; + case QRhiProfiler::ReleaseTexture: + { + auto it = m_textures.find(e.resource); + if (it != m_textures.end()) { + if (it->ownsNativeResource) + m_totalTextureApproxByteSize -= it->approxByteSize; + m_textures.erase(it); + emit texturesTouched(); + } + } + break; + + case QRhiProfiler::NewTextureStagingArea: + { + qint64 slot = -1; + qint64 size = 0; + for (const Parser::Event::Param &p : e.params) { + if (p.key == QByteArrayLiteral("slot")) + slot = p.intValue; + else if (p.key == QByteArrayLiteral("size")) + size = p.intValue; + } + if (slot >= 0 && slot < MAX_STAGING_SLOTS) { + auto it = m_textures.find(e.resource); + if (it != m_textures.end()) { + it->stagingExtraSize[slot] = size; + m_totalTextureStagingBufferApproxByteSize += size; + m_peakTextureStagingBufferApproxByteSize = qMax(m_peakTextureStagingBufferApproxByteSize, m_totalTextureStagingBufferApproxByteSize); + emit texturesTouched(); + } + } + } + break; + case QRhiProfiler::ReleaseTextureStagingArea: + { + qint64 slot = -1; + for (const Parser::Event::Param &p : e.params) { + if (p.key == QByteArrayLiteral("slot")) + slot = p.intValue; + } + if (slot >= 0 && slot < MAX_STAGING_SLOTS) { + auto it = m_textures.find(e.resource); + if (it != m_textures.end()) { + m_totalTextureStagingBufferApproxByteSize -= it->stagingExtraSize[slot]; + it->stagingExtraSize[slot] = 0; + emit texturesTouched(); + } + } + } + break; + + case QRhiProfiler::ResizeSwapChain: + { + auto it = m_swapchains.find(e.resource); + if (it != m_swapchains.end()) + m_totalSwapChainApproxByteSize -= it->approxByteSize; + + SwapChain s; + s.lastTimestamp = e.timestamp; + s.resourceName = e.resourceName; + // width,1280,height,720,buffer_count,2,msaa_buffer_count,0,effective_sample_count,1,approx_total_byte_size,7372800 + for (const Parser::Event::Param &p : e.params) { + if (p.key == QByteArrayLiteral("approx_total_byte_size")) + s.approxByteSize = p.intValue; + } + m_totalSwapChainApproxByteSize += s.approxByteSize; + m_peakSwapChainApproxByteSize = qMax(m_peakSwapChainApproxByteSize, m_totalSwapChainApproxByteSize); + m_swapchains.insert(e.resource, s); + emit swapchainsTouched(); + } + break; + case QRhiProfiler::ReleaseSwapChain: + { + auto it = m_swapchains.find(e.resource); + if (it != m_swapchains.end()) { + m_totalSwapChainApproxByteSize -= it->approxByteSize; + m_swapchains.erase(it); + emit swapchainsTouched(); + } + } + break; + + case QRhiProfiler::GpuFrameTime: + { + // Fmin_ms_gpu_frame_time,0.15488,Fmax_ms_gpu_frame_time,0.494592,Favg_ms_gpu_frame_time,0.33462 + for (const Parser::Event::Param &p : e.params) { + if (p.key == QByteArrayLiteral("min_ms_gpu_frame_time")) + m_lastGpuFrameTime.minTime = p.floatValue; + else if (p.key == QByteArrayLiteral("max_ms_gpu_frame_time")) + m_lastGpuFrameTime.maxTime = p.floatValue; + else if (p.key == QByteArrayLiteral("avg_ms_gpu_frame_time")) + m_lastGpuFrameTime.avgTime = p.floatValue; + } + emit gpuFrameTimeTouched(); + } + break; + case QRhiProfiler::FrameToFrameTime: + { + // frames_since_resize,121,min_ms_frame_delta,9,max_ms_frame_delta,33,Favg_ms_frame_delta,16.1167 + for (const Parser::Event::Param &p : e.params) { + if (p.key == QByteArrayLiteral("frames_since_resize")) + m_lastFrameTime.framesSinceResize = p.intValue; + else if (p.key == QByteArrayLiteral("min_ms_frame_delta")) + m_lastFrameTime.minDelta = p.intValue; + else if (p.key == QByteArrayLiteral("max_ms_frame_delta")) + m_lastFrameTime.maxDelta = p.intValue; + else if (p.key == QByteArrayLiteral("avg_ms_frame_delta")) + m_lastFrameTime.avgDelta = p.floatValue; + } + emit frameTimeTouched(); + } + break; + + case QRhiProfiler::GpuMemAllocStats: + { + // real_alloc_count,2,sub_alloc_count,154,total_size,10752,unused_size,50320896 + for (const Parser::Event::Param &p : e.params) { + if (p.key == QByteArrayLiteral("real_alloc_count")) + m_lastGpuMemAllocStats.realAllocCount = p.intValue; + else if (p.key == QByteArrayLiteral("sub_alloc_count")) + m_lastGpuMemAllocStats.subAllocCount = p.intValue; + else if (p.key == QByteArrayLiteral("total_size")) + m_lastGpuMemAllocStats.totalSize = p.intValue; + else if (p.key == QByteArrayLiteral("unused_size")) + m_lastGpuMemAllocStats.unusedSize = p.intValue; + } + emit gpuMemAllocStatsTouched(); + } + break; + + default: + break; + } +} + +class Server : public QTcpServer +{ + Q_OBJECT + +protected: + void incomingConnection(qintptr socketDescriptor) override; + +signals: + void clientConnected(); + void clientDisconnected(); + void receiveStarted(); + void lineReceived(const QByteArray &line); + +private: + bool m_valid = false; + QTcpSocket m_socket; + QByteArray m_buf; +}; + +void Server::incomingConnection(qintptr socketDescriptor) +{ + if (m_valid) + return; + + m_socket.setSocketDescriptor(socketDescriptor); + m_valid = true; + emit clientConnected(); + connect(&m_socket, &QAbstractSocket::readyRead, this, [this] { + bool receiveStartedSent = false; + m_buf += m_socket.readAll(); + while (m_buf.contains('\n')) { + const int lfpos = m_buf.indexOf('\n'); + const QByteArray line = m_buf.left(lfpos).trimmed(); + m_buf = m_buf.mid(lfpos + 1); + if (!receiveStartedSent) { + receiveStartedSent = true; + emit receiveStarted(); + } + emit lineReceived(line); + } + }); + connect(&m_socket, &QAbstractSocket::disconnected, this, [this] { + if (m_valid) { + m_valid = false; + emit clientDisconnected(); + } + }); +} + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + + Tracker tracker; + Parser parser; + QObject::connect(&parser, &Parser::eventReceived, &tracker, &Tracker::handleEvent); + + Server server; + if (!server.listen(QHostAddress::Any, 30667)) + qFatal("Failed to start server: %s", qPrintable(server.errorString())); + + QVBoxLayout *layout = new QVBoxLayout; + + QLabel *infoLabel = new QLabel(QLatin1String("<i>Launch a Qt Quick application with QSG_RHI_PROFILE=1 and QSG_RHI_PROFILE_HOST set to the IP address.<br>" + "(resource memory usage reporting works best with the Vulkan backend)</i>")); + layout->addWidget(infoLabel); + + QGroupBox *groupBox = new QGroupBox(QLatin1String("RHI statistics")); + QVBoxLayout *groupLayout = new QVBoxLayout; + + QLabel *buffersLabel = new QLabel; + QObject::connect(&tracker, &Tracker::buffersTouched, buffersLabel, [buffersLabel, &tracker] { + const QString msg = QString::asprintf("%d buffers with ca. %lld bytes of current memory (sub)allocations (peak %lld) + %lld bytes of known staging buffers (peak %lld)", + tracker.m_buffers.count(), + tracker.m_totalBufferApproxByteSize, tracker.m_peakBufferApproxByteSize, + tracker.m_totalStagingBufferApproxByteSize, tracker.m_peakStagingBufferApproxByteSize); + buffersLabel->setText(msg); + }); + groupLayout->addWidget(buffersLabel); + + QLabel *texturesLabel = new QLabel; + QObject::connect(&tracker, &Tracker::texturesTouched, texturesLabel, [texturesLabel, &tracker] { + const QString msg = QString::asprintf("%d textures with ca. %lld bytes of current memory (sub)allocations (peak %lld) + %lld bytes of known staging buffers (peak %lld)", + tracker.m_textures.count(), + tracker.m_totalTextureApproxByteSize, tracker.m_peakTextureApproxByteSize, + tracker.m_totalTextureStagingBufferApproxByteSize, tracker.m_peakTextureStagingBufferApproxByteSize); + texturesLabel->setText(msg); + }); + groupLayout->addWidget(texturesLabel); + + QLabel *swapchainsLabel = new QLabel; + QObject::connect(&tracker, &Tracker::swapchainsTouched, swapchainsLabel, [swapchainsLabel, &tracker] { + const QString msg = QString::asprintf("Estimated total swapchain color buffer size is %lld bytes (peak %lld)", + tracker.m_totalSwapChainApproxByteSize, tracker.m_peakSwapChainApproxByteSize); + swapchainsLabel->setText(msg); + }); + groupLayout->addWidget(swapchainsLabel); + + QLabel *frameTimeLabel = new QLabel; + QObject::connect(&tracker, &Tracker::frameTimeTouched, frameTimeLabel, [frameTimeLabel, &tracker] { + const QString msg = QString::asprintf("Frames since resize %lld Frame delta min %d ms max %d ms avg %f ms", + tracker.m_lastFrameTime.framesSinceResize, + tracker.m_lastFrameTime.minDelta, + tracker.m_lastFrameTime.maxDelta, + tracker.m_lastFrameTime.avgDelta); + frameTimeLabel->setText(msg); + }); + groupLayout->addWidget(frameTimeLabel); + + QLabel *gpuFrameTimeLabel = new QLabel; + QObject::connect(&tracker, &Tracker::gpuFrameTimeTouched, gpuFrameTimeLabel, [gpuFrameTimeLabel, &tracker] { + const QString msg = QString::asprintf("GPU frame time min %f ms max %f ms avg %f ms", + tracker.m_lastGpuFrameTime.minTime, + tracker.m_lastGpuFrameTime.maxTime, + tracker.m_lastGpuFrameTime.avgTime); + gpuFrameTimeLabel->setText(msg); + }); + groupLayout->addWidget(gpuFrameTimeLabel); + + QLabel *gpuMemAllocStatsLabel = new QLabel; + QObject::connect(&tracker, &Tracker::gpuMemAllocStatsTouched, gpuMemAllocStatsLabel, [gpuMemAllocStatsLabel, &tracker] { + const QString msg = QString::asprintf("GPU memory allocator status: %lld real allocations %lld sub-allocations %lld total bytes %lld unused bytes", + tracker.m_lastGpuMemAllocStats.realAllocCount, + tracker.m_lastGpuMemAllocStats.subAllocCount, + tracker.m_lastGpuMemAllocStats.totalSize, + tracker.m_lastGpuMemAllocStats.unusedSize); + gpuMemAllocStatsLabel->setText(msg); + }); + groupLayout->addWidget(gpuMemAllocStatsLabel); + + groupBox->setLayout(groupLayout); + layout->addWidget(groupBox); + + QTextEdit *rawLog = new QTextEdit; + rawLog->setReadOnly(true); + layout->addWidget(rawLog); + + QObject::connect(&server, &Server::clientConnected, rawLog, [rawLog] { + rawLog->append(QLatin1String("\nCONNECTED\n")); + }); + QObject::connect(&server, &Server::clientDisconnected, rawLog, [rawLog, &tracker] { + rawLog->append(QLatin1String("\nDISCONNECTED\n")); + tracker.reset(); + }); + QObject::connect(&server, &Server::receiveStarted, rawLog, [rawLog] { + rawLog->setFontItalic(true); + rawLog->append(QLatin1String("[") + QTime::currentTime().toString() + QLatin1String("]")); + rawLog->setFontItalic(false); + }); + + QObject::connect(&server, &Server::lineReceived, rawLog, [rawLog, &parser](const QByteArray &line) { + rawLog->append(QString::fromUtf8(line)); + parser.feed(line); + }); + + QWidget w; + w.resize(800, 600); + w.setLayout(layout); + w.show(); + + return app.exec(); +} + +#include "qrhiprof.moc" diff --git a/tests/manual/rhi/qrhiprof/qrhiprof.pro b/tests/manual/rhi/qrhiprof/qrhiprof.pro new file mode 100644 index 0000000000..2939dd7ce2 --- /dev/null +++ b/tests/manual/rhi/qrhiprof/qrhiprof.pro @@ -0,0 +1,6 @@ +TEMPLATE = app + +QT += network widgets gui-private + +SOURCES = \ + qrhiprof.cpp diff --git a/tests/manual/rhi/rhi.pro b/tests/manual/rhi/rhi.pro new file mode 100644 index 0000000000..4768ee1c6d --- /dev/null +++ b/tests/manual/rhi/rhi.pro @@ -0,0 +1,26 @@ +TEMPLATE = subdirs + +SUBDIRS += \ + hellominimalcrossgfxtriangle \ + compressedtexture_bc1 \ + compressedtexture_bc1_subupload \ + texuploads \ + msaatexture \ + msaarenderbuffer \ + cubemap \ + cubemap_scissor \ + multiwindow \ + multiwindow_threaded \ + triquadcube \ + offscreen \ + floattexture \ + mrt \ + shadowmap \ + computebuffer \ + computeimage \ + instancing + +qtConfig(widgets) { + SUBDIRS += \ + qrhiprof +} diff --git a/tests/manual/rhi/shadowmap/buildshaders.bat b/tests/manual/rhi/shadowmap/buildshaders.bat new file mode 100644 index 0000000000..7b84cc0952 --- /dev/null +++ b/tests/manual/rhi/shadowmap/buildshaders.bat @@ -0,0 +1,4 @@ +qsb --glsl "120,300 es" --hlsl 50 --msl 12 -c shadowmap.vert -o shadowmap.vert.qsb +qsb --glsl "120,300 es" --hlsl 50 --msl 12 -c shadowmap.frag -o shadowmap.frag.qsb +qsb --glsl "120,300 es" --hlsl 50 --msl 12 -c main.vert -o main.vert.qsb +qsb --glsl "120,300 es" --hlsl 50 --msl 12 -c main.frag -o main.frag.qsb diff --git a/tests/manual/rhi/shadowmap/buildshaders.sh b/tests/manual/rhi/shadowmap/buildshaders.sh new file mode 100755 index 0000000000..8991bb074a --- /dev/null +++ b/tests/manual/rhi/shadowmap/buildshaders.sh @@ -0,0 +1,5 @@ +#!/bin/sh +qsb --glsl "120,300 es" --hlsl 50 --msl 12 shadowmap.vert -o shadowmap.vert.qsb +qsb --glsl "120,300 es" --hlsl 50 --msl 12 shadowmap.frag -o shadowmap.frag.qsb +qsb --glsl "120,300 es" --hlsl 50 --msl 12 main.vert -o main.vert.qsb +qsb --glsl "120,300 es" --hlsl 50 --msl 12 main.frag -o main.frag.qsb diff --git a/tests/manual/rhi/shadowmap/main.frag b/tests/manual/rhi/shadowmap/main.frag new file mode 100644 index 0000000000..8fefe2bb42 --- /dev/null +++ b/tests/manual/rhi/shadowmap/main.frag @@ -0,0 +1,30 @@ +#version 440 + +layout(location = 0) in vec4 vLCVertPos; + +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2DShadow shadowMap; + +layout(std140, binding = 0) uniform buf { + mat4 mvp; + mat4 lightMvp; + mat4 shadowBias; + int useShadow; +} ubuf; + +void main() +{ + vec4 adjustedLcVertPos = vLCVertPos; + adjustedLcVertPos.z -= 0.0001; // bias to avoid acne + + // no textureProj, that seems to end up not doing the perspective divide for z (?) + vec3 v = adjustedLcVertPos.xyz / adjustedLcVertPos.w; + float sc = texture(shadowMap, v); // sampler is comparison enabled so compares to z + + float shadowFactor = 0.2; + if (sc > 0 || ubuf.useShadow == 0) + shadowFactor = 1.0; + + fragColor = vec4(0.5, 0.3 + ubuf.useShadow * 0.2, 0.7, 1.0) * shadowFactor; +} diff --git a/tests/manual/rhi/shadowmap/main.frag.qsb b/tests/manual/rhi/shadowmap/main.frag.qsb Binary files differnew file mode 100644 index 0000000000..3001908b85 --- /dev/null +++ b/tests/manual/rhi/shadowmap/main.frag.qsb diff --git a/tests/manual/rhi/shadowmap/main.vert b/tests/manual/rhi/shadowmap/main.vert new file mode 100644 index 0000000000..9d6cade634 --- /dev/null +++ b/tests/manual/rhi/shadowmap/main.vert @@ -0,0 +1,20 @@ +#version 440 + +layout(location = 0) in vec4 position; + +layout(std140, binding = 0) uniform buf { + mat4 mvp; + mat4 lightMvp; + mat4 shadowBias; + int useShadow; +} ubuf; + +out gl_PerVertex { vec4 gl_Position; }; + +layout(location = 0) out vec4 vLCVertPos; + +void main() +{ + vLCVertPos = ubuf.shadowBias * ubuf.lightMvp * position; + gl_Position = ubuf.mvp * position; +} diff --git a/tests/manual/rhi/shadowmap/main.vert.qsb b/tests/manual/rhi/shadowmap/main.vert.qsb Binary files differnew file mode 100644 index 0000000000..8b81a93c00 --- /dev/null +++ b/tests/manual/rhi/shadowmap/main.vert.qsb diff --git a/tests/manual/rhi/shadowmap/shadowmap.cpp b/tests/manual/rhi/shadowmap/shadowmap.cpp new file mode 100644 index 0000000000..424a8b3783 --- /dev/null +++ b/tests/manual/rhi/shadowmap/shadowmap.cpp @@ -0,0 +1,304 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "../shared/examplefw.h" +#include "../shared/cube.h" + +// Depth texture / shadow sampler / shadow map example. +// Not available on GLES 2.0. + +static float quadVertexData[] = +{ // Y up, CCW, x-y-z + -0.5f, 0.5f, 0.0f, + -0.5f, -0.5f, 0.0f, + 0.5f, -0.5f, 0.0f, + 0.5f, 0.5f, 0.0f, +}; + +static quint16 quadIndexData[] = +{ + 0, 1, 2, 0, 2, 3 +}; + +struct { + QVector<QRhiResource *> releasePool; + QRhiBuffer *vbuf = nullptr; + QRhiBuffer *ibuf = nullptr; + QRhiBuffer *ubuf = nullptr; + QRhiSampler *shadowSampler = nullptr; + QRhiShaderResourceBindings *srb = nullptr; + QRhiGraphicsPipeline *ps = nullptr; + QRhiResourceUpdateBatch *initialUpdates = nullptr; + QMatrix4x4 winProj; + float cubeRot = 0; + + QRhiTextureRenderTarget *rt = nullptr; + QRhiRenderPassDescriptor *rtRp = nullptr; + QRhiTexture *shadowMap = nullptr; + QRhiShaderResourceBindings *shadowSrb = nullptr; + QRhiGraphicsPipeline *shadowPs = nullptr; +} d; + +const int UBLOCK_SIZE = 64 * 3 + 4; +const int SHADOW_UBLOCK_SIZE = 64 * 1; +const int UBUF_SLOTS = 4; // 2 objects * 2 passes with different cameras + +void Window::customInit() +{ + if (!m_r->isTextureFormatSupported(QRhiTexture::D32F)) + qFatal("Depth texture is not supported"); + + d.vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(quadVertexData) + sizeof(cube)); + d.vbuf->build(); + d.releasePool << d.vbuf; + + d.ibuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::IndexBuffer, sizeof(quadIndexData)); + d.ibuf->build(); + d.releasePool << d.ibuf; + + const int oneRoundedUniformBlockSize = m_r->ubufAligned(UBLOCK_SIZE); + d.ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, UBUF_SLOTS * oneRoundedUniformBlockSize); + d.ubuf->build(); + d.releasePool << d.ubuf; + + d.shadowMap = m_r->newTexture(QRhiTexture::D32F, QSize(1024, 1024), 1, QRhiTexture::RenderTarget); + d.releasePool << d.shadowMap; + d.shadowMap->build(); + + d.shadowSampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None, + QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge); + d.releasePool << d.shadowSampler; + d.shadowSampler->setTextureCompareOp(QRhiSampler::Less); + d.shadowSampler->build(); + + d.srb = m_r->newShaderResourceBindings(); + d.releasePool << d.srb; + const QRhiShaderResourceBinding::StageFlags stages = QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage; + d.srb->setBindings({ QRhiShaderResourceBinding::uniformBufferWithDynamicOffset(0, stages, d.ubuf, UBLOCK_SIZE), + QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.shadowMap, d.shadowSampler) }); + d.srb->build(); + + d.ps = m_r->newGraphicsPipeline(); + d.releasePool << d.ps; + d.ps->setShaderStages({ + { QRhiShaderStage::Vertex, getShader(QLatin1String(":/main.vert.qsb")) }, + { QRhiShaderStage::Fragment, getShader(QLatin1String(":/main.frag.qsb")) } + }); + d.ps->setDepthTest(true); + d.ps->setDepthWrite(true); + // fits both the quad and cube vertex data + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ + { 3 * sizeof(float) } + }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float3, 0 }, + }); + d.ps->setVertexInputLayout(inputLayout); + d.ps->setShaderResourceBindings(d.srb); + d.ps->setRenderPassDescriptor(m_rp); + d.ps->build(); + + d.initialUpdates = m_r->nextResourceUpdateBatch(); + d.initialUpdates->uploadStaticBuffer(d.vbuf, 0, sizeof(quadVertexData), quadVertexData); + d.initialUpdates->uploadStaticBuffer(d.vbuf, sizeof(quadVertexData), sizeof(cube), cube); + d.initialUpdates->uploadStaticBuffer(d.ibuf, quadIndexData); + + QRhiTextureRenderTargetDescription rtDesc; + rtDesc.setDepthTexture(d.shadowMap); + d.rt = m_r->newTextureRenderTarget(rtDesc); + d.releasePool << d.rt; + d.rtRp = d.rt->newCompatibleRenderPassDescriptor(); + d.releasePool << d.rtRp; + d.rt->setRenderPassDescriptor(d.rtRp); + d.rt->build(); + + d.shadowSrb = m_r->newShaderResourceBindings(); + d.releasePool << d.shadowSrb; + d.shadowSrb->setBindings({ QRhiShaderResourceBinding::uniformBufferWithDynamicOffset(0, stages, d.ubuf, SHADOW_UBLOCK_SIZE) }); + d.shadowSrb->build(); + + d.shadowPs = m_r->newGraphicsPipeline(); + d.releasePool << d.shadowPs; + d.shadowPs->setShaderStages({ + { QRhiShaderStage::Vertex, getShader(QLatin1String(":/shadowmap.vert.qsb")) }, + { QRhiShaderStage::Fragment, getShader(QLatin1String(":/shadowmap.frag.qsb")) } + }); + d.shadowPs->setDepthTest(true); + d.shadowPs->setDepthWrite(true); + inputLayout.setBindings({ + { 3 * sizeof(float) } + }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float3, 0 } + }); + d.shadowPs->setVertexInputLayout(inputLayout); + d.shadowPs->setShaderResourceBindings(d.shadowSrb); + d.shadowPs->setRenderPassDescriptor(d.rtRp); + d.shadowPs->build(); +} + +void Window::customRelease() +{ + qDeleteAll(d.releasePool); + d.releasePool.clear(); +} + +static void enqueueScene(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb, int oneRoundedUniformBlockSize, int firstUbufSlot) +{ + QRhiCommandBuffer::DynamicOffset ubufOffset(0, quint32(firstUbufSlot * oneRoundedUniformBlockSize)); + // draw the ground (the quad) + cb->setShaderResources(srb, 1, &ubufOffset); + QRhiCommandBuffer::VertexInput vbufBinding(d.vbuf, 0); + cb->setVertexInput(0, 1, &vbufBinding, d.ibuf, 0, QRhiCommandBuffer::IndexUInt16); + cb->drawIndexed(6); + + // Draw the object (the cube). Both vertex and uniform data are in the same + // buffer, right after the quad's. + ubufOffset.second += oneRoundedUniformBlockSize; + cb->setShaderResources(srb, 1, &ubufOffset); + vbufBinding.second = sizeof(quadVertexData); + cb->setVertexInput(0, 1, &vbufBinding); + cb->draw(36); +} + +void Window::customRender() +{ + const QSize outputSizeInPixels = m_sc->currentPixelSize(); + QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer(); + QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch(); + if (d.initialUpdates) { + u->merge(d.initialUpdates); + d.initialUpdates->release(); + d.initialUpdates = nullptr; + } + + const int oneRoundedUniformBlockSize = m_r->ubufAligned(UBLOCK_SIZE); + + QMatrix4x4 shadowBias; + // fill it in column-major order to keep our sanity (ctor would take row-major) + float *sbp = shadowBias.data(); + if (m_r->isClipDepthZeroToOne()) { + // convert x, y [-1, 1] -> [0, 1] + *sbp++ = 0.5f; *sbp++ = 0.0f; *sbp++ = 0.0f; *sbp++ = 0.0f; + *sbp++ = 0.0f; *sbp++ = m_r->isYUpInNDC() ? -0.5f : 0.5f; *sbp++ = 0.0f; *sbp++ = 0.0f; + *sbp++ = 0.0f; *sbp++ = 0.0f; *sbp++ = 1.0f; *sbp++ = 0.0f; + *sbp++ = 0.5f; *sbp++ = 0.5f; *sbp++ = 0.0f; *sbp++ = 1.0f; + } else { + // convert x, y, z [-1, 1] -> [0, 1] + *sbp++ = 0.5f; *sbp++ = 0.0f; *sbp++ = 0.0f; *sbp++ = 0.0f; + *sbp++ = 0.0f; *sbp++ = 0.5f; *sbp++ = 0.0f; *sbp++ = 0.0f; + *sbp++ = 0.0f; *sbp++ = 0.0f; *sbp++ = 0.5f; *sbp++ = 0.0f; + *sbp++ = 0.5f; *sbp++ = 0.5f; *sbp++ = 0.5f; *sbp++ = 1.0f; + } + + const QVector3D lightPos(5, 10, 10); + QMatrix4x4 lightViewProj = m_r->clipSpaceCorrMatrix(); + lightViewProj.perspective(45.0f, 1, 0.1f, 100.0f); + lightViewProj.lookAt(lightPos, QVector3D(0, 0, 0), QVector3D(0, 1, 0)); + + // uniform data for the ground + if (d.winProj != m_proj) { + d.winProj = m_proj; + + QMatrix4x4 m; + m.scale(4.0f); + m.rotate(-60, 1, 0, 0); + + // for the main pass + const QMatrix4x4 mvp = m_proj * m; // m_proj is in fact projection * view + u->updateDynamicBuffer(d.ubuf, 0, 64, mvp.constData()); + const QMatrix4x4 shadowMvp = lightViewProj * m; + u->updateDynamicBuffer(d.ubuf, 64, 64, shadowMvp.constData()); + u->updateDynamicBuffer(d.ubuf, 128, 64, shadowBias.constData()); + qint32 useShadows = 1; + u->updateDynamicBuffer(d.ubuf, 192, 4, &useShadows); + + // for the shadow pass + u->updateDynamicBuffer(d.ubuf, 2 * oneRoundedUniformBlockSize, 64, shadowMvp.constData()); + } + + // uniform data for the rotating cube + QMatrix4x4 m; + m.translate(0, 0.5f, 2); + m.scale(0.2f); + m.rotate(d.cubeRot, 0, 1, 0); + m.rotate(45, 1, 0, 0); + d.cubeRot += 1; + + // for the main pass + const QMatrix4x4 mvp = m_proj * m; + u->updateDynamicBuffer(d.ubuf, oneRoundedUniformBlockSize, 64, mvp.constData()); + const QMatrix4x4 shadowMvp = lightViewProj * m; + u->updateDynamicBuffer(d.ubuf, oneRoundedUniformBlockSize + 64, 64, shadowMvp.constData()); + u->updateDynamicBuffer(d.ubuf, oneRoundedUniformBlockSize + 128, 64, shadowBias.constData()); + qint32 useShadows = 0; + u->updateDynamicBuffer(d.ubuf, oneRoundedUniformBlockSize + 192, 4, &useShadows); + + // for the shadow pass + u->updateDynamicBuffer(d.ubuf, 3 * oneRoundedUniformBlockSize, 64, shadowMvp.constData()); + + cb->resourceUpdate(u); + + // shadow pass + const QSize shadowMapSize = d.shadowMap->pixelSize(); + cb->beginPass(d.rt, QColor(), { 1.0f, 0 }); + cb->setGraphicsPipeline(d.shadowPs); + cb->setViewport({ 0, 0, float(shadowMapSize.width()), float(shadowMapSize.height()) }); + enqueueScene(cb, d.shadowSrb, oneRoundedUniformBlockSize, 2); + cb->endPass(); + + // main pass + cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }); + cb->setGraphicsPipeline(d.ps); + cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) }); + enqueueScene(cb, d.srb, oneRoundedUniformBlockSize, 0); + cb->endPass(); +} diff --git a/tests/manual/rhi/shadowmap/shadowmap.frag b/tests/manual/rhi/shadowmap/shadowmap.frag new file mode 100644 index 0000000000..fa868f31a2 --- /dev/null +++ b/tests/manual/rhi/shadowmap/shadowmap.frag @@ -0,0 +1,5 @@ +#version 440 + +void main() +{ +} diff --git a/tests/manual/rhi/shadowmap/shadowmap.frag.qsb b/tests/manual/rhi/shadowmap/shadowmap.frag.qsb Binary files differnew file mode 100644 index 0000000000..3cad114cf4 --- /dev/null +++ b/tests/manual/rhi/shadowmap/shadowmap.frag.qsb diff --git a/tests/manual/rhi/shadowmap/shadowmap.pro b/tests/manual/rhi/shadowmap/shadowmap.pro new file mode 100644 index 0000000000..baf740927c --- /dev/null +++ b/tests/manual/rhi/shadowmap/shadowmap.pro @@ -0,0 +1,8 @@ +TEMPLATE = app + +QT += gui-private + +SOURCES = \ + shadowmap.cpp + +RESOURCES = shadowmap.qrc diff --git a/tests/manual/rhi/shadowmap/shadowmap.qrc b/tests/manual/rhi/shadowmap/shadowmap.qrc new file mode 100644 index 0000000000..8256d5ca25 --- /dev/null +++ b/tests/manual/rhi/shadowmap/shadowmap.qrc @@ -0,0 +1,8 @@ +<!DOCTYPE RCC><RCC version="1.0"> + <qresource> + <file>shadowmap.vert.qsb</file> + <file>shadowmap.frag.qsb</file> + <file>main.vert.qsb</file> + <file>main.frag.qsb</file> +</qresource> +</RCC> diff --git a/tests/manual/rhi/shadowmap/shadowmap.vert b/tests/manual/rhi/shadowmap/shadowmap.vert new file mode 100644 index 0000000000..72b5370aec --- /dev/null +++ b/tests/manual/rhi/shadowmap/shadowmap.vert @@ -0,0 +1,14 @@ +#version 440 + +layout(location = 0) in vec4 position; + +layout(std140, binding = 0) uniform buf { + mat4 mvp; +} ubuf; + +out gl_PerVertex { vec4 gl_Position; }; + +void main() +{ + gl_Position = ubuf.mvp * position; +} diff --git a/tests/manual/rhi/shadowmap/shadowmap.vert.qsb b/tests/manual/rhi/shadowmap/shadowmap.vert.qsb Binary files differnew file mode 100644 index 0000000000..37a5e6ecbf --- /dev/null +++ b/tests/manual/rhi/shadowmap/shadowmap.vert.qsb diff --git a/tests/manual/rhi/shared/OpenfootageNET_fieldairport-512.hdr b/tests/manual/rhi/shared/OpenfootageNET_fieldairport-512.hdr Binary files differnew file mode 100644 index 0000000000..abdebdb74b --- /dev/null +++ b/tests/manual/rhi/shared/OpenfootageNET_fieldairport-512.hdr diff --git a/tests/manual/rhi/shared/buildshaders.bat b/tests/manual/rhi/shared/buildshaders.bat new file mode 100644 index 0000000000..dde5f7b3d2 --- /dev/null +++ b/tests/manual/rhi/shared/buildshaders.bat @@ -0,0 +1,5 @@ +qsb --glsl "100 es,120" --hlsl 50 --msl 12 -c color.vert -o color.vert.qsb +qsb --glsl "100 es,120" --hlsl 50 --msl 12 -c color.frag -o color.frag.qsb +qsb --glsl "100 es,120" --hlsl 50 --msl 12 -c texture.vert -o texture.vert.qsb +qsb --glsl "100 es,120" --hlsl 50 --msl 12 -c texture.frag -o texture.frag.qsb +qsb --hlsl 50 --msl 12 -c texture_ms4.frag -o texture_ms4.frag.qsb diff --git a/tests/manual/rhi/shared/bwqt224_64.png b/tests/manual/rhi/shared/bwqt224_64.png Binary files differnew file mode 100644 index 0000000000..8020cbb2a8 --- /dev/null +++ b/tests/manual/rhi/shared/bwqt224_64.png diff --git a/tests/manual/rhi/shared/bwqt224_64_nomips.dds b/tests/manual/rhi/shared/bwqt224_64_nomips.dds Binary files differnew file mode 100644 index 0000000000..393cfec9db --- /dev/null +++ b/tests/manual/rhi/shared/bwqt224_64_nomips.dds diff --git a/tests/manual/rhi/shared/color.frag b/tests/manual/rhi/shared/color.frag new file mode 100644 index 0000000000..bb94a5a605 --- /dev/null +++ b/tests/manual/rhi/shared/color.frag @@ -0,0 +1,15 @@ +#version 440 + +layout(location = 0) in vec3 v_color; + +layout(location = 0) out vec4 fragColor; + +layout(std140, binding = 0) uniform buf { + mat4 mvp; + float opacity; +} ubuf; + +void main() +{ + fragColor = vec4(v_color * ubuf.opacity, ubuf.opacity); +} diff --git a/tests/manual/rhi/shared/color.frag.qsb b/tests/manual/rhi/shared/color.frag.qsb Binary files differnew file mode 100644 index 0000000000..3a965682eb --- /dev/null +++ b/tests/manual/rhi/shared/color.frag.qsb diff --git a/tests/manual/rhi/shared/color.vert b/tests/manual/rhi/shared/color.vert new file mode 100644 index 0000000000..43af543f44 --- /dev/null +++ b/tests/manual/rhi/shared/color.vert @@ -0,0 +1,19 @@ +#version 440 + +layout(location = 0) in vec4 position; +layout(location = 1) in vec3 color; + +layout(location = 0) out vec3 v_color; + +layout(std140, binding = 0) uniform buf { + mat4 mvp; + float opacity; +} ubuf; + +out gl_PerVertex { vec4 gl_Position; }; + +void main() +{ + v_color = color; + gl_Position = ubuf.mvp * position; +} diff --git a/tests/manual/rhi/shared/color.vert.qsb b/tests/manual/rhi/shared/color.vert.qsb Binary files differnew file mode 100644 index 0000000000..e34eae79a0 --- /dev/null +++ b/tests/manual/rhi/shared/color.vert.qsb diff --git a/tests/manual/rhi/shared/cube.h b/tests/manual/rhi/shared/cube.h new file mode 100644 index 0000000000..252e80c56c --- /dev/null +++ b/tests/manual/rhi/shared/cube.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2015-2016 The Khronos Group Inc. + * Copyright (c) 2015-2016 Valve Corporation + * Copyright (c) 2015-2016 LunarG, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Author: Chia-I Wu <olv@lunarg.com> + * Author: Courtney Goeltzenleuchter <courtney@LunarG.com> + * Author: Ian Elliott <ian@LunarG.com> + * Author: Ian Elliott <ianelliott@google.com> + * Author: Jon Ashburn <jon@lunarg.com> + * Author: Gwan-gyeong Mun <elongbug@gmail.com> + * Author: Tony Barbour <tony@LunarG.com> + * Author: Bill Hollings <bill.hollings@brenwill.com> + */ + +#ifndef CUBE_H +#define CUBE_H + +// clang-format off +static const float cube[] = { + -1.0f,-1.0f,-1.0f, // -X side + -1.0f,-1.0f, 1.0f, + -1.0f, 1.0f, 1.0f, + -1.0f, 1.0f, 1.0f, + -1.0f, 1.0f,-1.0f, + -1.0f,-1.0f,-1.0f, + + -1.0f,-1.0f,-1.0f, // -Z side + 1.0f, 1.0f,-1.0f, + 1.0f,-1.0f,-1.0f, + -1.0f,-1.0f,-1.0f, + -1.0f, 1.0f,-1.0f, + 1.0f, 1.0f,-1.0f, + + -1.0f,-1.0f,-1.0f, // -Y side + 1.0f,-1.0f,-1.0f, + 1.0f,-1.0f, 1.0f, + -1.0f,-1.0f,-1.0f, + 1.0f,-1.0f, 1.0f, + -1.0f,-1.0f, 1.0f, + + -1.0f, 1.0f,-1.0f, // +Y side + -1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + -1.0f, 1.0f,-1.0f, + 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f,-1.0f, + + 1.0f, 1.0f,-1.0f, // +X side + 1.0f, 1.0f, 1.0f, + 1.0f,-1.0f, 1.0f, + 1.0f,-1.0f, 1.0f, + 1.0f,-1.0f,-1.0f, + 1.0f, 1.0f,-1.0f, + + -1.0f, 1.0f, 1.0f, // +Z side + -1.0f,-1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + -1.0f,-1.0f, 1.0f, + 1.0f,-1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + + 0.0f, 1.0f, // -X side + 1.0f, 1.0f, + 1.0f, 0.0f, + 1.0f, 0.0f, + 0.0f, 0.0f, + 0.0f, 1.0f, + + 1.0f, 1.0f, // -Z side + 0.0f, 0.0f, + 0.0f, 1.0f, + 1.0f, 1.0f, + 1.0f, 0.0f, + 0.0f, 0.0f, + + 1.0f, 0.0f, // -Y side + 1.0f, 1.0f, + 0.0f, 1.0f, + 1.0f, 0.0f, + 0.0f, 1.0f, + 0.0f, 0.0f, + + 1.0f, 0.0f, // +Y side + 0.0f, 0.0f, + 0.0f, 1.0f, + 1.0f, 0.0f, + 0.0f, 1.0f, + 1.0f, 1.0f, + + 1.0f, 0.0f, // +X side + 0.0f, 0.0f, + 0.0f, 1.0f, + 0.0f, 1.0f, + 1.0f, 1.0f, + 1.0f, 0.0f, + + 0.0f, 0.0f, // +Z side + 0.0f, 1.0f, + 1.0f, 0.0f, + 0.0f, 1.0f, + 1.0f, 1.0f, + 1.0f, 0.0f, +}; +// clang-format on + +#endif diff --git a/tests/manual/rhi/shared/dds_bc1.h b/tests/manual/rhi/shared/dds_bc1.h new file mode 100644 index 0000000000..3c98a94cfc --- /dev/null +++ b/tests/manual/rhi/shared/dds_bc1.h @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +static const quint32 DDS_MAGIC = 0x20534444; // 'DDS ' +static const quint32 DDS_FOURCC = 4; + +#define FOURCC(c0, c1, c2, c3) ((c0) | ((c1) << 8) | ((c2) << 16) | ((c3 << 24))) + +struct DDS_PIXELFORMAT { + quint32 size; + quint32 flags; + quint32 fourCC; + quint32 rgbBitCount; + quint32 rBitMask; + quint32 gBitMask; + quint32 bBitMask; + quint32 aBitMask; +}; + +struct DDS_HEADER { + quint32 size; + quint32 flags; + quint32 height; + quint32 width; + quint32 pitch; + quint32 depth; + quint32 mipMapCount; + quint32 reserved1[11]; + DDS_PIXELFORMAT pixelFormat; + quint32 caps; + quint32 caps2; + quint32 caps3; + quint32 caps4; + quint32 reserved2; +}; + +static quint32 bc1size(const QSize &size) +{ + static const quint32 blockSize = 8; // 8 bytes for BC1 + const quint32 bytesPerLine = qMax<quint32>(1, (size.width() + 3) / 4) * blockSize; + const quint32 ySize = qMax<quint32>(1, (size.height() + 3) / 4); + return bytesPerLine * ySize; +} + +static QByteArrayList loadBC1(const QString &filename, QSize *size) +{ + QFile f(filename); + if (!f.open(QIODevice::ReadOnly)) { + qWarning("Failed to open %s", qPrintable(filename)); + return QByteArrayList(); + } + + quint32 magic = 0; + f.read(reinterpret_cast<char *>(&magic), sizeof(magic)); + if (magic != DDS_MAGIC) { + qWarning("%s is not a DDS file", qPrintable(filename)); + return QByteArrayList(); + } + DDS_HEADER header; + f.read(reinterpret_cast<char *>(&header), sizeof(header)); + if (header.size != sizeof(DDS_HEADER)) { + qWarning("Invalid DDS header size"); + return QByteArrayList(); + } + if (header.pixelFormat.size != sizeof(DDS_PIXELFORMAT)) { + qWarning("Invalid DDS pixel format size"); + return QByteArrayList(); + } + if (!(header.pixelFormat.flags & DDS_FOURCC)) { + qWarning("Invalid DDS pixel format"); + return QByteArrayList(); + } + if (header.pixelFormat.fourCC != FOURCC('D', 'X', 'T', '1')) { + qWarning("Only DXT1 (BC1) is supported"); + return QByteArrayList(); + } + + QByteArrayList data; + QSize sz(header.width, header.height); + for (quint32 level = 0; level < header.mipMapCount; ++level) { + data.append(f.read(bc1size(sz))); + sz.setWidth(qMax(1, sz.width() / 2)); + sz.setHeight(qMax(1, sz.height() / 2)); + } + + if (size) + *size = QSize(header.width, header.height); + + return data; +} diff --git a/tests/manual/rhi/shared/examplefw.h b/tests/manual/rhi/shared/examplefw.h new file mode 100644 index 0000000000..d28bbea0a8 --- /dev/null +++ b/tests/manual/rhi/shared/examplefw.h @@ -0,0 +1,583 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Adapted from hellominimalcrossgfxtriangle with the frame rendering stripped out. +// Include this file and implement Window::customInit, release and render. +// Debug/validation layer is enabled for D3D and Vulkan. + +#include <QGuiApplication> +#include <QCommandLineParser> +#include <QWindow> +#include <QPlatformSurfaceEvent> +#include <QElapsedTimer> +#include <QTimer> +#include <QLoggingCategory> + +#include <QtGui/private/qshader_p.h> +#include <QFile> +#include <QtGui/private/qrhiprofiler_p.h> +#include <QtGui/private/qrhinull_p.h> + +#ifndef QT_NO_OPENGL +#include <QtGui/private/qrhigles2_p.h> +#include <QOffscreenSurface> +#endif + +#if QT_CONFIG(vulkan) +#include <QtGui/private/qrhivulkan_p.h> +#endif + +#ifdef Q_OS_WIN +#include <QtGui/private/qrhid3d11_p.h> +#endif + +#ifdef Q_OS_DARWIN +#include <QtGui/private/qrhimetal_p.h> +#endif + +QShader getShader(const QString &name) +{ + QFile f(name); + if (f.open(QIODevice::ReadOnly)) + return QShader::fromSerialized(f.readAll()); + + return QShader(); +} + +enum GraphicsApi +{ + Null, + OpenGL, + Vulkan, + D3D11, + Metal +}; + +GraphicsApi graphicsApi; + +QString graphicsApiName() +{ + switch (graphicsApi) { + case Null: + return QLatin1String("Null (no output)"); + case OpenGL: + return QLatin1String("OpenGL 2.x"); + case Vulkan: + return QLatin1String("Vulkan"); + case D3D11: + return QLatin1String("Direct3D 11"); + case Metal: + return QLatin1String("Metal"); + default: + break; + } + return QString(); +} + +QRhi::Flags rhiFlags = QRhi::EnableDebugMarkers; +int sampleCount = 1; +QRhiSwapChain::Flags scFlags = 0; +QRhi::BeginFrameFlags beginFrameFlags = 0; +QRhi::EndFrameFlags endFrameFlags = 0; +int framesUntilTdr = -1; +bool transparentBackground = false; + +class Window : public QWindow +{ +public: + Window(); + ~Window(); + +protected: + void init(); + void releaseResources(); + void resizeSwapChain(); + void releaseSwapChain(); + void render(); + + void customInit(); + void customRelease(); + void customRender(); + + void exposeEvent(QExposeEvent *) override; + bool event(QEvent *) override; + + bool m_running = false; + bool m_notExposed = false; + bool m_newlyExposed = false; + + QRhi *m_r = nullptr; + bool m_hasSwapChain = false; + QRhiSwapChain *m_sc = nullptr; + QRhiRenderBuffer *m_ds = nullptr; + QRhiRenderPassDescriptor *m_rp = nullptr; + + QMatrix4x4 m_proj; + + QElapsedTimer m_timer; + int m_frameCount; + +#ifndef QT_NO_OPENGL + QOffscreenSurface *m_fallbackSurface = nullptr; +#endif + + QColor m_clearColor; + + friend int main(int, char**); +}; + +Window::Window() +{ + // Tell the platform plugin what we want. + switch (graphicsApi) { + case OpenGL: +#if QT_CONFIG(opengl) + setSurfaceType(OpenGLSurface); + setFormat(QRhiGles2InitParams::adjustedFormat()); +#endif + break; + case Vulkan: + setSurfaceType(VulkanSurface); + break; + case D3D11: + setSurfaceType(OpenGLSurface); // not a typo + break; + case Metal: +#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) + setSurfaceType(MetalSurface); +#endif + break; + default: + break; + } + + m_clearColor = transparentBackground ? Qt::transparent : QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f); +} + +Window::~Window() +{ + releaseResources(); +} + +void Window::exposeEvent(QExposeEvent *) +{ + // initialize and start rendering when the window becomes usable for graphics purposes + if (isExposed() && !m_running) { + m_running = true; + init(); + resizeSwapChain(); + } + + const QSize surfaceSize = m_hasSwapChain ? m_sc->surfacePixelSize() : QSize(); + + // stop pushing frames when not exposed (or size is 0) + if ((!isExposed() || (m_hasSwapChain && surfaceSize.isEmpty())) && m_running) + m_notExposed = true; + + // continue when exposed again and the surface has a valid size. + // note that the surface size can be (0, 0) even though size() reports a valid one... + if (isExposed() && m_running && m_notExposed && !surfaceSize.isEmpty()) { + m_notExposed = false; + m_newlyExposed = true; + } + + // always render a frame on exposeEvent() (when exposed) in order to update + // immediately on window resize. + if (isExposed() && !surfaceSize.isEmpty()) + render(); +} + +bool Window::event(QEvent *e) +{ + switch (e->type()) { + case QEvent::UpdateRequest: + render(); + break; + + case QEvent::PlatformSurface: + // this is the proper time to tear down the swapchain (while the native window and surface are still around) + if (static_cast<QPlatformSurfaceEvent *>(e)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) + releaseSwapChain(); + break; + + default: + break; + } + + return QWindow::event(e); +} + +void Window::init() +{ + if (graphicsApi == Null) { + QRhiNullInitParams params; + m_r = QRhi::create(QRhi::Null, ¶ms, rhiFlags); + } + +#ifndef QT_NO_OPENGL + if (graphicsApi == OpenGL) { + m_fallbackSurface = QRhiGles2InitParams::newFallbackSurface(); + QRhiGles2InitParams params; + params.fallbackSurface = m_fallbackSurface; + params.window = this; + m_r = QRhi::create(QRhi::OpenGLES2, ¶ms, rhiFlags); + } +#endif + +#if QT_CONFIG(vulkan) + if (graphicsApi == Vulkan) { + QRhiVulkanInitParams params; + params.inst = vulkanInstance(); + params.window = this; + m_r = QRhi::create(QRhi::Vulkan, ¶ms, rhiFlags); + } +#endif + +#ifdef Q_OS_WIN + if (graphicsApi == D3D11) { + QRhiD3D11InitParams params; + params.enableDebugLayer = true; + if (framesUntilTdr > 0) { + params.framesUntilKillingDeviceViaTdr = framesUntilTdr; + params.repeatDeviceKill = true; + } + m_r = QRhi::create(QRhi::D3D11, ¶ms, rhiFlags); + } +#endif + +#ifdef Q_OS_DARWIN + if (graphicsApi == Metal) { + QRhiMetalInitParams params; + m_r = QRhi::create(QRhi::Metal, ¶ms, rhiFlags); + } +#endif + + if (!m_r) + qFatal("Failed to create RHI backend"); + + // now onto the backend-independent init + + m_sc = m_r->newSwapChain(); + // allow depth-stencil, although we do not actually enable depth test/write for the triangle + m_ds = m_r->newRenderBuffer(QRhiRenderBuffer::DepthStencil, + QSize(), // no need to set the size here, due to UsedWithSwapChainOnly + sampleCount, + QRhiRenderBuffer::UsedWithSwapChainOnly); + m_sc->setWindow(this); + m_sc->setDepthStencil(m_ds); + m_sc->setSampleCount(sampleCount); + m_sc->setFlags(scFlags); + m_rp = m_sc->newCompatibleRenderPassDescriptor(); + m_sc->setRenderPassDescriptor(m_rp); + + customInit(); +} + +void Window::releaseResources() +{ + customRelease(); + + delete m_rp; + m_rp = nullptr; + + delete m_ds; + m_ds = nullptr; + + delete m_sc; + m_sc = nullptr; + + delete m_r; + m_r = nullptr; + +#ifndef QT_NO_OPENGL + delete m_fallbackSurface; + m_fallbackSurface = nullptr; +#endif +} + +void Window::resizeSwapChain() +{ + m_hasSwapChain = m_sc->buildOrResize(); // also handles m_ds + + m_frameCount = 0; + m_timer.restart(); + + const QSize outputSize = m_sc->currentPixelSize(); + m_proj = m_r->clipSpaceCorrMatrix(); + m_proj.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 1000.0f); + m_proj.translate(0, 0, -4); +} + +void Window::releaseSwapChain() +{ + if (m_hasSwapChain) { + m_hasSwapChain = false; + m_sc->release(); + } +} + +void Window::render() +{ + if (!m_hasSwapChain || m_notExposed) + return; + + // If the window got resized or got newly exposed, resize the swapchain. + // (the newly-exposed case is not actually required by some + // platforms/backends, but f.ex. Vulkan on Windows seems to need it) + if (m_sc->currentPixelSize() != m_sc->surfacePixelSize() || m_newlyExposed) { + resizeSwapChain(); + if (!m_hasSwapChain) + return; + m_newlyExposed = false; + } + + // Start a new frame. This is where we block when too far ahead of + // GPU/present, and that's what throttles the thread to the refresh rate. + // (except for OpenGL where it happens either in endFrame or somewhere else + // depending on the GL implementation) + QRhi::FrameOpResult r = m_r->beginFrame(m_sc, beginFrameFlags); + if (r == QRhi::FrameOpSwapChainOutOfDate) { + resizeSwapChain(); + if (!m_hasSwapChain) + return; + r = m_r->beginFrame(m_sc); + } + if (r != QRhi::FrameOpSuccess) { + requestUpdate(); + return; + } + + m_frameCount += 1; + if (m_timer.elapsed() > 1000) { + if (rhiFlags.testFlag(QRhi::EnableProfiling)) { + const QRhiProfiler::CpuTime ff = m_r->profiler()->frameToFrameTimes(m_sc); + const QRhiProfiler::CpuTime be = m_r->profiler()->frameBuildTimes(m_sc); + const QRhiProfiler::GpuTime gp = m_r->profiler()->gpuFrameTimes(m_sc); + if (m_r->isFeatureSupported(QRhi::Timestamps)) { + qDebug("ca. %d fps. " + "frame-to-frame: min %lld max %lld avg %f. " + "frame build: min %lld max %lld avg %f. " + "gpu frame time: min %f max %f avg %f", + m_frameCount, + ff.minTime, ff.maxTime, ff.avgTime, + be.minTime, be.maxTime, be.avgTime, + gp.minTime, gp.maxTime, gp.avgTime); + } else { + qDebug("ca. %d fps. " + "frame-to-frame: min %lld max %lld avg %f. " + "frame build: min %lld max %lld avg %f. ", + m_frameCount, + ff.minTime, ff.maxTime, ff.avgTime, + be.minTime, be.maxTime, be.avgTime); + } + } else { + qDebug("ca. %d fps", m_frameCount); + } + + m_timer.restart(); + m_frameCount = 0; + } + + customRender(); + + m_r->endFrame(m_sc, endFrameFlags); + + if (!scFlags.testFlag(QRhiSwapChain::NoVSync)) + requestUpdate(); + else // try prevent all delays when NoVSync + QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest)); +} + +int main(int argc, char **argv) +{ + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QGuiApplication app(argc, argv); + + QLoggingCategory::setFilterRules(QLatin1String("qt.rhi.*=true")); + + // Defaults. +#if defined(Q_OS_WIN) + graphicsApi = D3D11; +#elif defined(Q_OS_DARWIN) + graphicsApi = Metal; +#elif QT_CONFIG(vulkan) + graphicsApi = Vulkan; +#else + graphicsApi = OpenGL; +#endif + + // Allow overriding via the command line. + QCommandLineParser cmdLineParser; + cmdLineParser.addHelpOption(); + QCommandLineOption nullOption({ "n", "null" }, QLatin1String("Null")); + cmdLineParser.addOption(nullOption); + QCommandLineOption glOption({ "g", "opengl" }, QLatin1String("OpenGL (2.x)")); + cmdLineParser.addOption(glOption); + QCommandLineOption vkOption({ "v", "vulkan" }, QLatin1String("Vulkan")); + cmdLineParser.addOption(vkOption); + QCommandLineOption d3dOption({ "d", "d3d11" }, QLatin1String("Direct3D 11")); + cmdLineParser.addOption(d3dOption); + QCommandLineOption mtlOption({ "m", "metal" }, QLatin1String("Metal")); + cmdLineParser.addOption(mtlOption); + // Testing cleanup both with QWindow::close() (hitting X or Alt-F4) and + // QCoreApplication::quit() (e.g. what a menu widget would do) is important. + // Use this parameter for the latter. + QCommandLineOption sdOption({ "s", "self-destruct" }, QLatin1String("Self-destruct after 5 seconds.")); + cmdLineParser.addOption(sdOption); + // Attempt testing device lost situations on D3D at least. + QCommandLineOption tdrOption(QLatin1String("curse"), QLatin1String("Curse the graphics device. " + "(generate a device reset every <count> frames when on D3D11)"), + QLatin1String("count")); + cmdLineParser.addOption(tdrOption); + // Allow testing preferring the software adapter (D3D). + QCommandLineOption swOption(QLatin1String("software"), QLatin1String("Prefer a software renderer when choosing the adapter. " + "Only applicable with some APIs and platforms.")); + cmdLineParser.addOption(swOption); + // Allow testing having a semi-transparent window. + QCommandLineOption transparentOption(QLatin1String("transparent"), QLatin1String("Make background transparent")); + cmdLineParser.addOption(transparentOption); + + cmdLineParser.process(app); + if (cmdLineParser.isSet(nullOption)) + graphicsApi = Null; + if (cmdLineParser.isSet(glOption)) + graphicsApi = OpenGL; + if (cmdLineParser.isSet(vkOption)) + graphicsApi = Vulkan; + if (cmdLineParser.isSet(d3dOption)) + graphicsApi = D3D11; + if (cmdLineParser.isSet(mtlOption)) + graphicsApi = Metal; + + qDebug("Selected graphics API is %s", qPrintable(graphicsApiName())); + qDebug("This is a multi-api example, use command line arguments to override:\n%s", qPrintable(cmdLineParser.helpText())); + + if (cmdLineParser.isSet(transparentOption)) { + transparentBackground = true; + scFlags |= QRhiSwapChain::SurfaceHasPreMulAlpha; + } + +#ifdef EXAMPLEFW_PREINIT + void preInit(); + preInit(); +#endif + + // OpenGL specifics. + QSurfaceFormat fmt; + fmt.setDepthBufferSize(24); + fmt.setStencilBufferSize(8); + if (sampleCount > 1) + fmt.setSamples(sampleCount); + if (scFlags.testFlag(QRhiSwapChain::NoVSync)) + fmt.setSwapInterval(0); + if (scFlags.testFlag(QRhiSwapChain::sRGB)) + fmt.setColorSpace(QSurfaceFormat::sRGBColorSpace); + // Exception: The alpha size is not necessarily OpenGL specific. + if (transparentBackground) + fmt.setAlphaBufferSize(8); + QSurfaceFormat::setDefaultFormat(fmt); + + // Vulkan setup. +#if QT_CONFIG(vulkan) + QVulkanInstance inst; + if (graphicsApi == Vulkan) { +#ifndef Q_OS_ANDROID + inst.setLayers(QByteArrayList() << "VK_LAYER_LUNARG_standard_validation"); +#else + inst.setLayers(QByteArrayList() + << "VK_LAYER_GOOGLE_threading" + << "VK_LAYER_LUNARG_parameter_validation" + << "VK_LAYER_LUNARG_object_tracker" + << "VK_LAYER_LUNARG_core_validation" + << "VK_LAYER_LUNARG_image" + << "VK_LAYER_LUNARG_swapchain" + << "VK_LAYER_GOOGLE_unique_objects"); +#endif + inst.setExtensions(QByteArrayList() + << "VK_KHR_get_physical_device_properties2"); + if (!inst.create()) { + qWarning("Failed to create Vulkan instance, switching to OpenGL"); + graphicsApi = OpenGL; + } + } +#endif + + if (cmdLineParser.isSet(tdrOption)) + framesUntilTdr = cmdLineParser.value(tdrOption).toInt(); + + if (cmdLineParser.isSet(swOption)) + rhiFlags |= QRhi::PreferSoftwareRenderer; + + // Create and show the window. + Window w; +#if QT_CONFIG(vulkan) + if (graphicsApi == Vulkan) + w.setVulkanInstance(&inst); +#endif + w.resize(1280, 720); + w.setTitle(QCoreApplication::applicationName() + QLatin1String(" - ") + graphicsApiName()); + w.show(); + + if (cmdLineParser.isSet(sdOption)) + QTimer::singleShot(5000, qGuiApp, SLOT(quit())); + + int ret = app.exec(); + + // Window::event() will not get invoked when the + // PlatformSurfaceAboutToBeDestroyed event is sent during the QWindow + // destruction. That happens only when exiting via app::quit() instead of + // the more common QWindow::close(). Take care of it: if the + // QPlatformWindow is still around (there was no close() yet), get rid of + // the swapchain while it's not too late. + if (w.handle()) + w.releaseSwapChain(); + + return ret; +} diff --git a/tests/manual/rhi/shared/qt256.png b/tests/manual/rhi/shared/qt256.png Binary files differnew file mode 100644 index 0000000000..30c621c9c6 --- /dev/null +++ b/tests/manual/rhi/shared/qt256.png diff --git a/tests/manual/rhi/shared/qt256_bc1_9mips.dds b/tests/manual/rhi/shared/qt256_bc1_9mips.dds Binary files differnew file mode 100644 index 0000000000..734a5d184f --- /dev/null +++ b/tests/manual/rhi/shared/qt256_bc1_9mips.dds diff --git a/tests/manual/rhi/shared/texture.frag b/tests/manual/rhi/shared/texture.frag new file mode 100644 index 0000000000..5405444c68 --- /dev/null +++ b/tests/manual/rhi/shared/texture.frag @@ -0,0 +1,18 @@ +#version 440 + +layout(location = 0) in vec2 v_texcoord; + +layout(location = 0) out vec4 fragColor; + +layout(std140, binding = 0) uniform buf { + mat4 mvp; + int flip; +} ubuf; + +layout(binding = 1) uniform sampler2D tex; + +void main() +{ + vec4 c = texture(tex, v_texcoord); + fragColor = vec4(c.rgb * c.a, c.a); +} diff --git a/tests/manual/rhi/shared/texture.frag.qsb b/tests/manual/rhi/shared/texture.frag.qsb Binary files differnew file mode 100644 index 0000000000..31bcd7105e --- /dev/null +++ b/tests/manual/rhi/shared/texture.frag.qsb diff --git a/tests/manual/rhi/shared/texture.vert b/tests/manual/rhi/shared/texture.vert new file mode 100644 index 0000000000..ad7e783dfb --- /dev/null +++ b/tests/manual/rhi/shared/texture.vert @@ -0,0 +1,21 @@ +#version 440 + +layout(location = 0) in vec4 position; +layout(location = 1) in vec2 texcoord; + +layout(location = 0) out vec2 v_texcoord; + +layout(std140, binding = 0) uniform buf { + mat4 mvp; + int flip; +} ubuf; + +out gl_PerVertex { vec4 gl_Position; }; + +void main() +{ + v_texcoord = vec2(texcoord.x, texcoord.y); + if (ubuf.flip != 0) + v_texcoord.y = 1.0 - v_texcoord.y; + gl_Position = ubuf.mvp * position; +} diff --git a/tests/manual/rhi/shared/texture.vert.qsb b/tests/manual/rhi/shared/texture.vert.qsb Binary files differnew file mode 100644 index 0000000000..1b9e52890d --- /dev/null +++ b/tests/manual/rhi/shared/texture.vert.qsb diff --git a/tests/manual/rhi/shared/texture_ms4.frag b/tests/manual/rhi/shared/texture_ms4.frag new file mode 100644 index 0000000000..d4f2bd3654 --- /dev/null +++ b/tests/manual/rhi/shared/texture_ms4.frag @@ -0,0 +1,20 @@ +#version 440 + +layout(location = 0) in vec2 v_texcoord; + +layout(location = 0) out vec4 fragColor; + +layout(std140, binding = 0) uniform buf { + mat4 mvp; + int flip; +} ubuf; + +layout(binding = 1) uniform sampler2DMS tex; + +void main() +{ + ivec2 tc = ivec2(floor(vec2(textureSize(tex)) * v_texcoord)); + vec4 c = texelFetch(tex, tc, 0) + texelFetch(tex, tc, 1) + texelFetch(tex, tc, 2) + texelFetch(tex, tc, 3); + c /= 4.0; + fragColor = vec4(c.rgb * c.a, c.a); +} diff --git a/tests/manual/rhi/shared/texture_ms4.frag.qsb b/tests/manual/rhi/shared/texture_ms4.frag.qsb Binary files differnew file mode 100644 index 0000000000..7f187ce7f0 --- /dev/null +++ b/tests/manual/rhi/shared/texture_ms4.frag.qsb diff --git a/tests/manual/rhi/texuploads/texuploads.cpp b/tests/manual/rhi/texuploads/texuploads.cpp new file mode 100644 index 0000000000..4c10a6b965 --- /dev/null +++ b/tests/manual/rhi/texuploads/texuploads.cpp @@ -0,0 +1,313 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "../shared/examplefw.h" +#include "../shared/cube.h" +#include <QPainter> + +struct { + QRhiBuffer *vbuf = nullptr; + QRhiBuffer *ubuf = nullptr; + QRhiTexture *tex = nullptr; + QRhiSampler *sampler = nullptr; + QRhiShaderResourceBindings *srb = nullptr; + QRhiGraphicsPipeline *ps = nullptr; + QVector<QRhiResource *> releasePool; + + float rotation = 0; + QRhiResourceUpdateBatch *initialUpdates = nullptr; + int frameCount = 0; + QImage customImage; + QRhiTexture *newTex = nullptr; + QRhiTexture *importedTex = nullptr; + int testStage = 0; + + QRhiShaderResourceBinding bindings[2]; +} d; + +void Window::customInit() +{ + d.vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(cube)); + d.releasePool << d.vbuf; + d.vbuf->build(); + + d.ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 68); + d.releasePool << d.ubuf; + d.ubuf->build(); + + QImage baseImage(QLatin1String(":/qt256.png")); + d.tex = m_r->newTexture(QRhiTexture::RGBA8, baseImage.size(), 1, QRhiTexture::UsedAsTransferSource); + d.releasePool << d.tex; + d.tex->build(); + + // As an alternative to what some of the other examples do, prepare an + // update batch right here instead of relying on vbufReady and similar flags. + d.initialUpdates = m_r->nextResourceUpdateBatch(); + d.initialUpdates->uploadStaticBuffer(d.vbuf, cube); + qint32 flip = 0; + d.initialUpdates->updateDynamicBuffer(d.ubuf, 64, 4, &flip); + d.initialUpdates->uploadTexture(d.tex, baseImage); + + d.sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None, + QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge); + d.releasePool << d.sampler; + d.sampler->build(); + + d.srb = m_r->newShaderResourceBindings(); + d.releasePool << d.srb; + + d.bindings[0] = QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf); + d.bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.tex, d.sampler); + d.srb->setBindings(d.bindings, d.bindings + 2); + d.srb->build(); + + d.ps = m_r->newGraphicsPipeline(); + d.releasePool << d.ps; + + d.ps->setDepthTest(true); + d.ps->setDepthWrite(true); + d.ps->setDepthOp(QRhiGraphicsPipeline::Less); + + d.ps->setCullMode(QRhiGraphicsPipeline::Back); + d.ps->setFrontFace(QRhiGraphicsPipeline::CCW); + + const QShader vs = getShader(QLatin1String(":/texture.vert.qsb")); + if (!vs.isValid()) + qFatal("Failed to load shader pack (vertex)"); + const QShader fs = getShader(QLatin1String(":/texture.frag.qsb")); + if (!fs.isValid()) + qFatal("Failed to load shader pack (fragment)"); + + d.ps->setShaderStages({ + { QRhiShaderStage::Vertex, vs }, + { QRhiShaderStage::Fragment, fs } + }); + + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ + { 3 * sizeof(float) }, + { 2 * sizeof(float) } + }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float3, 0 }, + { 1, 1, QRhiVertexInputAttribute::Float2, 0 } + }); + + d.ps->setVertexInputLayout(inputLayout); + d.ps->setShaderResourceBindings(d.srb); + d.ps->setRenderPassDescriptor(m_rp); + + d.ps->build(); + + d.customImage = QImage(128, 64, QImage::Format_RGBA8888); + d.customImage.fill(Qt::red); + QPainter painter(&d.customImage); + // the text may look different on different platforms, so no guarantee the + // output on the screen will be identical everywhere + painter.drawText(5, 25, "Hello world"); + painter.end(); +} + +void Window::customRelease() +{ + qDeleteAll(d.releasePool); + d.releasePool.clear(); +} + +void Window::customRender() +{ + QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch(); + + // take the initial set of updates, if this is the first frame + if (d.initialUpdates) { + u->merge(d.initialUpdates); + d.initialUpdates->release(); + d.initialUpdates = nullptr; + } + + d.rotation += 1.0f; + QMatrix4x4 mvp = m_proj; + mvp.scale(0.5f); + mvp.rotate(d.rotation, 0, 1, 0); + u->updateDynamicBuffer(d.ubuf, 0, 64, mvp.constData()); + + if (d.frameCount > 0 && (d.frameCount % 100) == 0) { + d.testStage += 1; + qDebug("testStage = %d", d.testStage); + + // Partially change the texture. + if (d.testStage == 1) { + QRhiTextureSubresourceUploadDescription mipDesc(d.customImage); + // The image here is smaller than the original. Use a non-zero position + // to make it more interesting. + mipDesc.setDestinationTopLeft(QPoint(100, 20)); + QRhiTextureUploadDescription desc({ 0, 0, mipDesc }); + u->uploadTexture(d.tex, desc); + } + + // Exercise image copying. + if (d.testStage == 2) { + const QSize sz = d.tex->pixelSize(); + d.newTex = m_r->newTexture(QRhiTexture::RGBA8, sz); + d.releasePool << d.newTex; + d.newTex->build(); + + QImage empty(sz.width(), sz.height(), QImage::Format_RGBA8888); + empty.fill(Qt::blue); + u->uploadTexture(d.newTex, empty); + + // Copy the left-half of tex to the right-half of newTex, while + // leaving the left-half of newTex blue. Keep a 20 pixel gap at + // the top. + QRhiTextureCopyDescription desc; + desc.setSourceTopLeft(QPoint(0, 20)); + desc.setPixelSize(QSize(sz.width() / 2, sz.height() - 20)); + desc.setDestinationTopLeft(QPoint(sz.width() / 2, 20)); + u->copyTexture(d.newTex, d.tex, desc); + + // Now replace d.tex with d.newTex as the shader resource. + d.bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.newTex, d.sampler); + d.srb->setBindings(d.bindings, d.bindings + 2); + // "rebuild", whatever that means for a given backend. This srb is + // already live as the ps in the setGraphicsPipeline references it, + // but that's fine. Changes will be picked up automatically. + d.srb->build(); + } + + // Exercise simple, full texture copy. + if (d.testStage == 4) + u->copyTexture(d.newTex, d.tex); + + // Now again upload customImage but this time only a part of it. + if (d.testStage == 5) { + QRhiTextureSubresourceUploadDescription mipDesc(d.customImage); + mipDesc.setDestinationTopLeft(QPoint(10, 120)); + mipDesc.setSourceSize(QSize(50, 40)); + mipDesc.setSourceTopLeft(QPoint(20, 10)); + QRhiTextureUploadDescription desc({ 0, 0, mipDesc }); + u->uploadTexture(d.newTex, desc); + } + + // Exercise texture object export/import. + if (d.testStage == 6) { + const QRhiNativeHandles *h = d.tex->nativeHandles(); + if (h) { +#ifdef Q_OS_DARWIN + if (graphicsApi == Metal) { + qDebug() << "Metal texture: " << static_cast<const QRhiMetalTextureNativeHandles *>(h)->texture; + // Now could cast to id<MTLTexture> and do something with + // it, keeping in mind that copy operations are only done + // in beginPass, while rendering into a texture may only + // have proper results in current_frame + 2, or after a + // finish(). The QRhiTexture still owns the native object. + } +#endif + // omit for other backends, the idea is the same + + d.importedTex = m_r->newTexture(QRhiTexture::RGBA8, d.tex->pixelSize()); + d.releasePool << d.importedTex; + if (!d.importedTex->buildFrom(h)) + qWarning("Texture import failed"); + + // now d.tex and d.importedTex use the same MTLTexture + // underneath (owned by d.tex) + + // switch to showing d.importedTex + d.bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.importedTex, d.sampler); + d.srb->setBindings(d.bindings, d.bindings + 2); + d.srb->build(); + } else { + qWarning("Accessing native texture object is not supported"); + } + } + + // Exercise uploading uncompressed data without a QImage. + if (d.testStage == 7) { + d.bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.newTex, d.sampler); + d.srb->setBindings(d.bindings, d.bindings + 2); + d.srb->build(); + + const QSize sz(221, 139); + QByteArray data; + data.resize(sz.width() * sz.height() * 4); + for (int y = 0; y < sz.height(); ++y) { + uchar *p = reinterpret_cast<uchar *>(data.data()) + y * sz.width() * 4; + for (int x = 0; x < sz.width(); ++x) { + *p++ = 0; *p++ = 0; *p++ = y * (255 / sz.height()); + *p++ = 255; + } + } + QRhiTextureSubresourceUploadDescription mipDesc(data.constData(), data.size()); + mipDesc.setSourceSize(sz); + mipDesc.setDestinationTopLeft(QPoint(5, 25)); + QRhiTextureUploadDescription desc({ 0, 0, mipDesc }); + u->uploadTexture(d.newTex, desc); + } + } + + QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer(); + const QSize outputSizeInPixels = m_sc->currentPixelSize(); + + cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }, u); + + cb->setGraphicsPipeline(d.ps); + cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) }); + cb->setShaderResources(); + const QRhiCommandBuffer::VertexInput vbufBindings[] = { + { d.vbuf, 0 }, + { d.vbuf, 36 * 3 * sizeof(float) } + }; + cb->setVertexInput(0, 2, vbufBindings); + cb->draw(36); + + cb->endPass(); + + d.frameCount += 1; +} diff --git a/tests/manual/rhi/texuploads/texuploads.pro b/tests/manual/rhi/texuploads/texuploads.pro new file mode 100644 index 0000000000..64f204fb32 --- /dev/null +++ b/tests/manual/rhi/texuploads/texuploads.pro @@ -0,0 +1,8 @@ +TEMPLATE = app + +QT += gui-private + +SOURCES = \ + texuploads.cpp + +RESOURCES = texuploads.qrc diff --git a/tests/manual/rhi/texuploads/texuploads.qrc b/tests/manual/rhi/texuploads/texuploads.qrc new file mode 100644 index 0000000000..742b2b77af --- /dev/null +++ b/tests/manual/rhi/texuploads/texuploads.qrc @@ -0,0 +1,7 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file alias="qt256.png">../shared/qt256.png</file> + <file alias="texture.vert.qsb">../shared/texture.vert.qsb</file> + <file alias="texture.frag.qsb">../shared/texture.frag.qsb</file> +</qresource> +</RCC> diff --git a/tests/manual/rhi/triquadcube/quadrenderer.cpp b/tests/manual/rhi/triquadcube/quadrenderer.cpp new file mode 100644 index 0000000000..6137fb1b9a --- /dev/null +++ b/tests/manual/rhi/triquadcube/quadrenderer.cpp @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "quadrenderer.h" +#include <QFile> +#include <QtGui/private/qshader_p.h> + +// Renders a quad using indexed drawing. No QRhiGraphicsPipeline is created, it +// expects to reuse the one created by TriangleRenderer. A separate +// QRhiShaderResourceBindings is still needed, this will override the one the +// QRhiGraphicsPipeline references. + +static float vertexData[] = +{ // Y up (note m_proj), CCW + -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, + -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, + 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, + 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f +}; + +static quint16 indexData[] = +{ + 0, 1, 2, 0, 2, 3 +}; + +void QuadRenderer::initResources(QRhiRenderPassDescriptor *) +{ + m_vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData)); + m_vbuf->build(); + m_vbufReady = false; + + m_ibuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::IndexBuffer, sizeof(indexData)); + m_ibuf->build(); + + m_ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 68); + m_ubuf->build(); + + m_srb = m_r->newShaderResourceBindings(); + m_srb->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, m_ubuf) + }); + m_srb->build(); +} + +void QuadRenderer::setPipeline(QRhiGraphicsPipeline *ps) +{ + m_ps = ps; +} + +void QuadRenderer::resize(const QSize &pixelSize) +{ + m_proj = m_r->clipSpaceCorrMatrix(); + m_proj.perspective(45.0f, pixelSize.width() / (float) pixelSize.height(), 0.01f, 100.0f); + m_proj.translate(0, 0, -4); +} + +void QuadRenderer::releaseResources() +{ + delete m_srb; + m_srb = nullptr; + + delete m_ubuf; + m_ubuf = nullptr; + + delete m_ibuf; + m_ibuf = nullptr; + + delete m_vbuf; + m_vbuf = nullptr; +} + +void QuadRenderer::queueResourceUpdates(QRhiResourceUpdateBatch *resourceUpdates) +{ + if (!m_vbufReady) { + m_vbufReady = true; + resourceUpdates->uploadStaticBuffer(m_vbuf, vertexData); + resourceUpdates->uploadStaticBuffer(m_ibuf, indexData); + } + + m_rotation += 1.0f; + QMatrix4x4 mvp = m_proj; + mvp.translate(m_translation); + mvp.rotate(m_rotation, 0, 1, 0); + resourceUpdates->updateDynamicBuffer(m_ubuf, 0, 64, mvp.constData()); + + if (!m_opacityReady) { + m_opacityReady = true; + const float opacity = 1.0f; + resourceUpdates->updateDynamicBuffer(m_ubuf, 64, 4, &opacity); + } +} + +void QuadRenderer::queueDraw(QRhiCommandBuffer *cb, const QSize &/*outputSizeInPixels*/) +{ + cb->setGraphicsPipeline(m_ps); + //cb->setViewport(QRhiViewport(0, 0, outputSizeInPixels.width(), outputSizeInPixels.height())); + cb->setShaderResources(m_srb); + const QRhiCommandBuffer::VertexInput vbufBinding(m_vbuf, 0); + cb->setVertexInput(0, 1, &vbufBinding, m_ibuf, 0, QRhiCommandBuffer::IndexUInt16); + cb->drawIndexed(6); +} diff --git a/tests/manual/rhi/triquadcube/quadrenderer.h b/tests/manual/rhi/triquadcube/quadrenderer.h new file mode 100644 index 0000000000..79d5b8209d --- /dev/null +++ b/tests/manual/rhi/triquadcube/quadrenderer.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QUADRENDERER_H +#define QUADRENDERER_H + +#include <QtGui/private/qrhi_p.h> + +class QuadRenderer +{ +public: + void setRhi(QRhi *r) { m_r = r; } + void setSampleCount(int samples) { m_sampleCount = samples; } + int sampleCount() const { return m_sampleCount; } + void setTranslation(const QVector3D &v) { m_translation = v; } + void initResources(QRhiRenderPassDescriptor *rp); + void releaseResources(); + void setPipeline(QRhiGraphicsPipeline *ps); + void resize(const QSize &pixelSize); + void queueResourceUpdates(QRhiResourceUpdateBatch *resourceUpdates); + void queueDraw(QRhiCommandBuffer *cb, const QSize &outputSizeInPixels); + +private: + QRhi *m_r; + + QRhiBuffer *m_vbuf = nullptr; + bool m_vbufReady = false; + QRhiBuffer *m_ibuf = nullptr; + bool m_opacityReady = false; + QRhiBuffer *m_ubuf = nullptr; + QRhiGraphicsPipeline *m_ps = nullptr; + QRhiShaderResourceBindings *m_srb = nullptr; + + QVector3D m_translation; + QMatrix4x4 m_proj; + float m_rotation = 0; + int m_sampleCount = 1; // no MSAA by default +}; + +#endif diff --git a/tests/manual/rhi/triquadcube/texturedcuberenderer.cpp b/tests/manual/rhi/triquadcube/texturedcuberenderer.cpp new file mode 100644 index 0000000000..8c5845d4fc --- /dev/null +++ b/tests/manual/rhi/triquadcube/texturedcuberenderer.cpp @@ -0,0 +1,224 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "texturedcuberenderer.h" +#include <QFile> +#include <QtGui/private/qshader_p.h> + +#include "../shared/cube.h" + +const bool MIPMAP = true; +const bool AUTOGENMIPMAP = true; + +static QShader getShader(const QString &name) +{ + QFile f(name); + if (f.open(QIODevice::ReadOnly)) + return QShader::fromSerialized(f.readAll()); + + return QShader(); +} + +void TexturedCubeRenderer::initResources(QRhiRenderPassDescriptor *rp) +{ + m_vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(cube)); + m_vbuf->setName(QByteArrayLiteral("Cube vbuf (textured)")); + m_vbuf->build(); + m_vbufReady = false; + + m_ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64 + 4); + m_ubuf->setName(QByteArrayLiteral("Cube ubuf (textured)")); + m_ubuf->build(); + + m_image = QImage(QLatin1String(":/qt256.png")).convertToFormat(QImage::Format_RGBA8888); + QRhiTexture::Flags texFlags = 0; + if (MIPMAP) + texFlags |= QRhiTexture::MipMapped; + if (AUTOGENMIPMAP) + texFlags |= QRhiTexture::UsedWithGenerateMips; + m_tex = m_r->newTexture(QRhiTexture::RGBA8, QSize(m_image.width(), m_image.height()), 1, texFlags); + m_tex->setName(QByteArrayLiteral("Qt texture")); + m_tex->build(); + + m_sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, MIPMAP ? QRhiSampler::Linear : QRhiSampler::None, + QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge); + m_sampler->build(); + + m_srb = m_r->newShaderResourceBindings(); + m_srb->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, m_ubuf), + QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, m_tex, m_sampler) + }); + m_srb->build(); + + m_ps = m_r->newGraphicsPipeline(); + + // No blending but the texture has alpha which we do not want to write out. + // Be nice. (would not matter for an onscreen window but makes a difference + // when reading back and saving into image files f.ex.) + QRhiGraphicsPipeline::TargetBlend blend; + blend.colorWrite = QRhiGraphicsPipeline::R | QRhiGraphicsPipeline::G | QRhiGraphicsPipeline::B; + m_ps->setTargetBlends({ blend }); + + m_ps->setDepthTest(true); + m_ps->setDepthWrite(true); + m_ps->setDepthOp(QRhiGraphicsPipeline::Less); + + m_ps->setCullMode(QRhiGraphicsPipeline::Back); + m_ps->setFrontFace(QRhiGraphicsPipeline::CCW); + + m_ps->setSampleCount(m_sampleCount); + + QShader vs = getShader(QLatin1String(":/texture.vert.qsb")); + Q_ASSERT(vs.isValid()); + QShader fs = getShader(QLatin1String(":/texture.frag.qsb")); + Q_ASSERT(fs.isValid()); + m_ps->setShaderStages({ + { QRhiShaderStage::Vertex, vs }, + { QRhiShaderStage::Fragment, fs } + }); + + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ + { 3 * sizeof(float) }, + { 2 * sizeof(float) } + }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float3, 0 }, + { 1, 1, QRhiVertexInputAttribute::Float2, 0 } + }); + + m_ps->setVertexInputLayout(inputLayout); + m_ps->setShaderResourceBindings(m_srb); + m_ps->setRenderPassDescriptor(rp); + + m_ps->build(); +} + +void TexturedCubeRenderer::resize(const QSize &pixelSize) +{ + m_proj = m_r->clipSpaceCorrMatrix(); + m_proj.perspective(45.0f, pixelSize.width() / (float) pixelSize.height(), 0.01f, 100.0f); + m_proj.translate(0, 0, -4); +} + +void TexturedCubeRenderer::releaseResources() +{ + delete m_ps; + m_ps = nullptr; + + delete m_srb; + m_srb = nullptr; + + delete m_sampler; + m_sampler = nullptr; + + delete m_tex; + m_tex = nullptr; + + delete m_ubuf; + m_ubuf = nullptr; + + delete m_vbuf; + m_vbuf = nullptr; +} + +void TexturedCubeRenderer::queueResourceUpdates(QRhiResourceUpdateBatch *resourceUpdates) +{ + if (!m_vbufReady) { + m_vbufReady = true; + resourceUpdates->uploadStaticBuffer(m_vbuf, cube); + qint32 flip = 0; + resourceUpdates->updateDynamicBuffer(m_ubuf, 64, 4, &flip); + } + + if (!m_image.isNull()) { + if (MIPMAP) { + QVarLengthArray<QRhiTextureUploadEntry, 16> descEntries; + if (!AUTOGENMIPMAP) { + // the ghetto mipmap generator... + for (int i = 0, ie = m_r->mipLevelsForSize(m_image.size()); i != ie; ++i) { + QImage image = m_image.scaled(m_r->sizeForMipLevel(i, m_image.size())); + descEntries.append({ 0, i, image }); + } + } else { + descEntries.append({ 0, 0, m_image }); + } + QRhiTextureUploadDescription desc; + desc.setEntries(descEntries.cbegin(), descEntries.cend()); + resourceUpdates->uploadTexture(m_tex, desc); + if (AUTOGENMIPMAP) + resourceUpdates->generateMips(m_tex); + } else { + resourceUpdates->uploadTexture(m_tex, m_image); + } + m_image = QImage(); + } + + m_rotation += 1.0f; + QMatrix4x4 mvp = m_proj; + mvp.translate(m_translation); + mvp.scale(0.5f); + mvp.rotate(m_rotation, 0, 1, 0); + resourceUpdates->updateDynamicBuffer(m_ubuf, 0, 64, mvp.constData()); +} + +void TexturedCubeRenderer::queueDraw(QRhiCommandBuffer *cb, const QSize &outputSizeInPixels) +{ + cb->setGraphicsPipeline(m_ps); + cb->setViewport(QRhiViewport(0, 0, outputSizeInPixels.width(), outputSizeInPixels.height())); + cb->setShaderResources(); + const QRhiCommandBuffer::VertexInput vbufBindings[] = { + { m_vbuf, 0 }, + { m_vbuf, 36 * 3 * sizeof(float) } + }; + cb->setVertexInput(0, 2, vbufBindings); + cb->draw(36); +} diff --git a/tests/manual/rhi/triquadcube/texturedcuberenderer.h b/tests/manual/rhi/triquadcube/texturedcuberenderer.h new file mode 100644 index 0000000000..879f875209 --- /dev/null +++ b/tests/manual/rhi/triquadcube/texturedcuberenderer.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TEXTUREDCUBERENDERER_H +#define TEXTUREDCUBERENDERER_H + +#include <QtGui/private/qrhi_p.h> + +class TexturedCubeRenderer +{ +public: + void setRhi(QRhi *r) { m_r = r; } + void setSampleCount(int samples) { m_sampleCount = samples; } + void setTranslation(const QVector3D &v) { m_translation = v; } + void initResources(QRhiRenderPassDescriptor *rp); + void releaseResources(); + void resize(const QSize &pixelSize); + void queueResourceUpdates(QRhiResourceUpdateBatch *resourceUpdates); + void queueDraw(QRhiCommandBuffer *cb, const QSize &outputSizeInPixels); + +private: + QRhi *m_r; + + QRhiBuffer *m_vbuf = nullptr; + bool m_vbufReady = false; + QRhiBuffer *m_ubuf = nullptr; + QImage m_image; + QRhiTexture *m_tex = nullptr; + QRhiSampler *m_sampler = nullptr; + QRhiShaderResourceBindings *m_srb = nullptr; + QRhiGraphicsPipeline *m_ps = nullptr; + + QVector3D m_translation; + QMatrix4x4 m_proj; + float m_rotation = 0; + int m_sampleCount = 1; // no MSAA by default +}; + +#endif diff --git a/tests/manual/rhi/triquadcube/triangleoncuberenderer.cpp b/tests/manual/rhi/triquadcube/triangleoncuberenderer.cpp new file mode 100644 index 0000000000..250ae3a2ee --- /dev/null +++ b/tests/manual/rhi/triquadcube/triangleoncuberenderer.cpp @@ -0,0 +1,292 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "triangleoncuberenderer.h" +#include <QFile> +#include <QtGui/private/qshader_p.h> + +// toggle to test the preserved content (no clear) path +const bool IMAGE_UNDER_OFFSCREEN_RENDERING = false; +const bool UPLOAD_UNDERLAY_ON_EVERY_FRAME = false; + +const bool DS_ATT = false; // have a depth-stencil attachment for the offscreen pass + +const bool DEPTH_TEXTURE = false; // offscreen pass uses a depth texture (verify with renderdoc etc., ignore valid.layer about ps slot 0) +const bool MRT = false; // two textures, the second is just cleared as the shader does not write anything (valid.layer may warn but for testing that's ok) + +#include "../shared/cube.h" + +static QShader getShader(const QString &name) +{ + QFile f(name); + if (f.open(QIODevice::ReadOnly)) + return QShader::fromSerialized(f.readAll()); + + return QShader(); +} + +static const QSize OFFSCREEN_SIZE(512, 512); + +void TriangleOnCubeRenderer::initResources(QRhiRenderPassDescriptor *rp) +{ + m_vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(cube)); + m_vbuf->setName(QByteArrayLiteral("Cube vbuf (textured with offscreen)")); + m_vbuf->build(); + m_vbufReady = false; + + m_ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64 + 4); + m_ubuf->setName(QByteArrayLiteral("Cube ubuf (textured with offscreen)")); + m_ubuf->build(); + + if (IMAGE_UNDER_OFFSCREEN_RENDERING) { + m_image = QImage(QLatin1String(":/qt256.png")).scaled(OFFSCREEN_SIZE).convertToFormat(QImage::Format_RGBA8888); + if (m_r->isYUpInFramebuffer()) + m_image = m_image.mirrored(); // just cause we'll flip texcoord Y when y up so accommodate our static background image as well + } + + m_tex = m_r->newTexture(QRhiTexture::RGBA8, OFFSCREEN_SIZE, 1, QRhiTexture::RenderTarget); + m_tex->setName(QByteArrayLiteral("Texture for offscreen content")); + m_tex->build(); + + if (MRT) { + m_tex2 = m_r->newTexture(QRhiTexture::RGBA8, OFFSCREEN_SIZE, 1, QRhiTexture::RenderTarget); + m_tex2->build(); + } + + if (DS_ATT) { + m_offscreenTriangle.setDepthWrite(true); + m_ds = m_r->newRenderBuffer(QRhiRenderBuffer::DepthStencil, m_tex->pixelSize()); + m_ds->build(); + } + + if (DEPTH_TEXTURE) { + m_offscreenTriangle.setDepthWrite(true); + m_depthTex = m_r->newTexture(QRhiTexture::D32F, OFFSCREEN_SIZE, 1, QRhiTexture::RenderTarget); + m_depthTex->build(); + } + + m_sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None, QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge); + m_sampler->build(); + + m_srb = m_r->newShaderResourceBindings(); + m_srb->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, m_ubuf), + QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, m_tex, m_sampler) + }); + m_srb->build(); + + m_ps = m_r->newGraphicsPipeline(); + + m_ps->setDepthTest(true); + m_ps->setDepthWrite(true); + m_ps->setDepthOp(QRhiGraphicsPipeline::Less); + + m_ps->setCullMode(QRhiGraphicsPipeline::Back); + m_ps->setFrontFace(QRhiGraphicsPipeline::CCW); + + m_ps->setSampleCount(m_sampleCount); + + QShader vs = getShader(QLatin1String(":/texture.vert.qsb")); + Q_ASSERT(vs.isValid()); + QShader fs = getShader(QLatin1String(":/texture.frag.qsb")); + Q_ASSERT(fs.isValid()); + m_ps->setShaderStages({ + { QRhiShaderStage::Vertex, vs }, + { QRhiShaderStage::Fragment, fs } + }); + + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ + { 3 * sizeof(float) }, + { 2 * sizeof(float) } + }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float3, 0 }, + { 1, 1, QRhiVertexInputAttribute::Float2, 0 } + }); + + m_ps->setVertexInputLayout(inputLayout); + m_ps->setShaderResourceBindings(m_srb); + m_ps->setRenderPassDescriptor(rp); + + m_ps->build(); + + QRhiTextureRenderTarget::Flags rtFlags = 0; + if (IMAGE_UNDER_OFFSCREEN_RENDERING) + rtFlags |= QRhiTextureRenderTarget::PreserveColorContents; + + if (DEPTH_TEXTURE) { + QRhiTextureRenderTargetDescription desc; + desc.setDepthTexture(m_depthTex); + m_rt = m_r->newTextureRenderTarget(desc, rtFlags); + } else { + QRhiTextureRenderTargetDescription desc; + QRhiColorAttachment color0 { m_tex }; + if (DS_ATT) + desc.setDepthStencilBuffer(m_ds); + if (MRT) { + m_offscreenTriangle.setColorAttCount(2); + QRhiColorAttachment color1 { m_tex2 }; + desc.setColorAttachments({ color0, color1 }); + } else { + desc.setColorAttachments({ color0 }); + } + m_rt = m_r->newTextureRenderTarget(desc, rtFlags); + } + + m_rp = m_rt->newCompatibleRenderPassDescriptor(); + m_rt->setRenderPassDescriptor(m_rp); + + m_rt->build(); + + m_offscreenTriangle.setRhi(m_r); + m_offscreenTriangle.initResources(m_rp); + m_offscreenTriangle.setScale(2); + // m_tex and the offscreen triangle are never multisample +} + +void TriangleOnCubeRenderer::resize(const QSize &pixelSize) +{ + m_proj = m_r->clipSpaceCorrMatrix(); + m_proj.perspective(45.0f, pixelSize.width() / (float) pixelSize.height(), 0.01f, 100.0f); + m_proj.translate(0, 0, -4); + + m_offscreenTriangle.resize(pixelSize); +} + +void TriangleOnCubeRenderer::releaseResources() +{ + m_offscreenTriangle.releaseResources(); + + delete m_ps; + m_ps = nullptr; + + delete m_srb; + m_srb = nullptr; + + delete m_rt; + m_rt = nullptr; + + delete m_rp; + m_rp = nullptr; + + delete m_sampler; + m_sampler = nullptr; + + delete m_depthTex; + m_depthTex = nullptr; + + delete m_tex2; + m_tex2 = nullptr; + + delete m_tex; + m_tex = nullptr; + + delete m_ds; + m_ds = nullptr; + + delete m_ubuf; + m_ubuf = nullptr; + + delete m_vbuf; + m_vbuf = nullptr; +} + +void TriangleOnCubeRenderer::queueResourceUpdates(QRhiResourceUpdateBatch *resourceUpdates) +{ + if (!m_vbufReady) { + m_vbufReady = true; + resourceUpdates->uploadStaticBuffer(m_vbuf, cube); + qint32 flip = m_r->isYUpInFramebuffer() ? 1 : 0; + resourceUpdates->updateDynamicBuffer(m_ubuf, 64, 4, &flip); + } + + m_rotation += 1.0f; + QMatrix4x4 mvp = m_proj; + mvp.translate(m_translation); + mvp.scale(0.5f); + mvp.rotate(m_rotation, 1, 0, 0); + resourceUpdates->updateDynamicBuffer(m_ubuf, 0, 64, mvp.constData()); + + // ### +// if (DEPTH_TEXTURE) { +// // m_tex is basically undefined here, be nice and transition the layout properly at least +// resourceUpdates->prepareTextureForUse(m_tex, QRhiResourceUpdateBatch::TextureRead); +// } +} + +void TriangleOnCubeRenderer::queueOffscreenPass(QRhiCommandBuffer *cb) +{ + QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch(); + m_offscreenTriangle.queueResourceUpdates(u); + + if (IMAGE_UNDER_OFFSCREEN_RENDERING && !m_image.isNull()) { + u->uploadTexture(m_tex, m_image); + if (!UPLOAD_UNDERLAY_ON_EVERY_FRAME) + m_image = QImage(); + } + + cb->beginPass(m_rt, QColor::fromRgbF(0.0f, 0.4f, 0.7f, 1.0f), { 1.0f, 0 }, u); + m_offscreenTriangle.queueDraw(cb, OFFSCREEN_SIZE); + cb->endPass(); +} + +void TriangleOnCubeRenderer::queueDraw(QRhiCommandBuffer *cb, const QSize &outputSizeInPixels) +{ + cb->setGraphicsPipeline(m_ps); + cb->setViewport(QRhiViewport(0, 0, outputSizeInPixels.width(), outputSizeInPixels.height())); + cb->setShaderResources(); + const QRhiCommandBuffer::VertexInput vbufBindings[] = { + { m_vbuf, 0 }, + { m_vbuf, 36 * 3 * sizeof(float) } + }; + cb->setVertexInput(0, 2, vbufBindings); + cb->draw(36); +} diff --git a/tests/manual/rhi/triquadcube/triangleoncuberenderer.h b/tests/manual/rhi/triquadcube/triangleoncuberenderer.h new file mode 100644 index 0000000000..5a56bf6bd1 --- /dev/null +++ b/tests/manual/rhi/triquadcube/triangleoncuberenderer.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TRIANGLEONCUBERENDERER_H +#define TRIANGLEONCUBERENDERER_H + +#include "trianglerenderer.h" + +class TriangleOnCubeRenderer +{ +public: + void setRhi(QRhi *r) { m_r = r; } + void setSampleCount(int samples) { m_sampleCount = samples; } + void setTranslation(const QVector3D &v) { m_translation = v; } + void initResources(QRhiRenderPassDescriptor *rp); + void releaseResources(); + void resize(const QSize &pixelSize); + void queueResourceUpdates(QRhiResourceUpdateBatch *resourceUpdates); + void queueOffscreenPass(QRhiCommandBuffer *cb); + void queueDraw(QRhiCommandBuffer *cb, const QSize &outputSizeInPixels); + +private: + QRhi *m_r; + + QRhiBuffer *m_vbuf = nullptr; + bool m_vbufReady = false; + QRhiBuffer *m_ubuf = nullptr; + QRhiTexture *m_tex = nullptr; + QRhiRenderBuffer *m_ds = nullptr; + QRhiTexture *m_tex2 = nullptr; + QRhiTexture *m_depthTex = nullptr; + QRhiSampler *m_sampler = nullptr; + QRhiTextureRenderTarget *m_rt = nullptr; + QRhiRenderPassDescriptor *m_rp = nullptr; + QRhiShaderResourceBindings *m_srb = nullptr; + QRhiGraphicsPipeline *m_ps = nullptr; + + QVector3D m_translation; + QMatrix4x4 m_proj; + float m_rotation = 0; + int m_sampleCount = 1; // no MSAA by default + + TriangleRenderer m_offscreenTriangle; + + QImage m_image; +}; + +#endif diff --git a/tests/manual/rhi/triquadcube/trianglerenderer.cpp b/tests/manual/rhi/triquadcube/trianglerenderer.cpp new file mode 100644 index 0000000000..5d932aea52 --- /dev/null +++ b/tests/manual/rhi/triquadcube/trianglerenderer.cpp @@ -0,0 +1,202 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "trianglerenderer.h" +#include <QFile> +#include <QtGui/private/qshader_p.h> + +//#define VBUF_IS_DYNAMIC + +static float vertexData[] = { // Y up (note m_proj), CCW + 0.0f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, + -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, + 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f +}; + +static QShader getShader(const QString &name) +{ + QFile f(name); + if (f.open(QIODevice::ReadOnly)) + return QShader::fromSerialized(f.readAll()); + + return QShader(); +} + +void TriangleRenderer::initResources(QRhiRenderPassDescriptor *rp) +{ +#ifdef VBUF_IS_DYNAMIC + m_vbuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::VertexBuffer, sizeof(vertexData)); +#else + m_vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData)); +#endif + m_vbuf->setName(QByteArrayLiteral("Triangle vbuf")); + m_vbuf->build(); + m_vbufReady = false; + + m_ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 68); + m_ubuf->setName(QByteArrayLiteral("Triangle ubuf")); + m_ubuf->build(); + + m_srb = m_r->newShaderResourceBindings(); + m_srb->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, m_ubuf) + }); + m_srb->build(); + + m_ps = m_r->newGraphicsPipeline(); + + QRhiGraphicsPipeline::TargetBlend premulAlphaBlend; // convenient defaults... + premulAlphaBlend.enable = true; + QVarLengthArray<QRhiGraphicsPipeline::TargetBlend, 4> rtblends; + for (int i = 0; i < m_colorAttCount; ++i) + rtblends << premulAlphaBlend; + + m_ps->setTargetBlends(rtblends.cbegin(), rtblends.cend()); + m_ps->setSampleCount(m_sampleCount); + + if (m_depthWrite) { // TriangleOnCube may want to exercise this + m_ps->setDepthTest(true); + m_ps->setDepthOp(QRhiGraphicsPipeline::Always); + m_ps->setDepthWrite(true); + } + + QShader vs = getShader(QLatin1String(":/color.vert.qsb")); + Q_ASSERT(vs.isValid()); + QShader fs = getShader(QLatin1String(":/color.frag.qsb")); + Q_ASSERT(fs.isValid()); + m_ps->setShaderStages({ + { QRhiShaderStage::Vertex, vs }, + { QRhiShaderStage::Fragment, fs } + }); + + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ + { 7 * sizeof(float) } + }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float2, 0 }, + { 0, 1, QRhiVertexInputAttribute::Float3, 2 * sizeof(float) } + }); + + m_ps->setVertexInputLayout(inputLayout); + m_ps->setShaderResourceBindings(m_srb); + m_ps->setRenderPassDescriptor(rp); + + m_ps->build(); +} + +void TriangleRenderer::resize(const QSize &pixelSize) +{ + m_proj = m_r->clipSpaceCorrMatrix(); + m_proj.perspective(45.0f, pixelSize.width() / (float) pixelSize.height(), 0.01f, 100.0f); + m_proj.translate(0, 0, -4); +} + +void TriangleRenderer::releaseResources() +{ + delete m_ps; + m_ps = nullptr; + + delete m_srb; + m_srb = nullptr; + + delete m_ubuf; + m_ubuf = nullptr; + + delete m_vbuf; + m_vbuf = nullptr; +} + +void TriangleRenderer::queueResourceUpdates(QRhiResourceUpdateBatch *resourceUpdates) +{ +#if 0 + static int messWithBufferTrigger = 0; + // recreate the underlying VkBuffer every second frame + // to exercise setShaderResources' built-in smartness + if (!(messWithBufferTrigger & 1)) { + m_ubuf->release(); + m_ubuf->build(); + } + ++messWithBufferTrigger; +#endif + + if (!m_vbufReady) { + m_vbufReady = true; +#ifdef VBUF_IS_DYNAMIC + resourceUpdates->updateDynamicBuffer(m_vbuf, 0, m_vbuf->size(), vertexData); +#else + resourceUpdates->uploadStaticBuffer(m_vbuf, vertexData); +#endif + } + + m_rotation += 1.0f; + QMatrix4x4 mvp = m_proj; + mvp.translate(m_translation); + mvp.scale(m_scale); + mvp.rotate(m_rotation, 0, 1, 0); + resourceUpdates->updateDynamicBuffer(m_ubuf, 0, 64, mvp.constData()); + + m_opacity += m_opacityDir * 0.005f; + if (m_opacity < 0.0f || m_opacity > 1.0f) { + m_opacityDir *= -1; + m_opacity = qBound(0.0f, m_opacity, 1.0f); + } + resourceUpdates->updateDynamicBuffer(m_ubuf, 64, 4, &m_opacity); +} + +void TriangleRenderer::queueDraw(QRhiCommandBuffer *cb, const QSize &outputSizeInPixels) +{ + cb->setGraphicsPipeline(m_ps); + cb->setViewport(QRhiViewport(0, 0, outputSizeInPixels.width(), outputSizeInPixels.height())); + cb->setShaderResources(); + const QRhiCommandBuffer::VertexInput vbufBinding(m_vbuf, 0); + cb->setVertexInput(0, 1, &vbufBinding); + cb->draw(3); +} diff --git a/tests/manual/rhi/triquadcube/trianglerenderer.h b/tests/manual/rhi/triquadcube/trianglerenderer.h new file mode 100644 index 0000000000..53d6926a62 --- /dev/null +++ b/tests/manual/rhi/triquadcube/trianglerenderer.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TRIANGLERENDERER_H +#define TRIANGLERENDERER_H + +#include <QtGui/private/qrhi_p.h> + +class TriangleRenderer +{ +public: + void setRhi(QRhi *r) { m_r = r; } + void setSampleCount(int samples) { m_sampleCount = samples; } + int sampleCount() const { return m_sampleCount; } + void setTranslation(const QVector3D &v) { m_translation = v; } + void setScale(float f) { m_scale = f; } + void setDepthWrite(bool enable) { m_depthWrite = enable; } + void setColorAttCount(int count) { m_colorAttCount = count; } + QRhiGraphicsPipeline *pipeline() const { return m_ps; } + void initResources(QRhiRenderPassDescriptor *rp); + void releaseResources(); + void resize(const QSize &pixelSize); + void queueResourceUpdates(QRhiResourceUpdateBatch *resourceUpdates); + void queueDraw(QRhiCommandBuffer *cb, const QSize &outputSizeInPixels); + +private: + QRhi *m_r; + + QRhiBuffer *m_vbuf = nullptr; + bool m_vbufReady = false; + QRhiBuffer *m_ubuf = nullptr; + QRhiShaderResourceBindings *m_srb = nullptr; + QRhiGraphicsPipeline *m_ps = nullptr; + + QVector3D m_translation; + float m_scale = 1; + bool m_depthWrite = false; + int m_colorAttCount = 1; + QMatrix4x4 m_proj; + float m_rotation = 0; + float m_opacity = 1; + int m_opacityDir = -1; + int m_sampleCount = 1; // no MSAA by default +}; + +#endif diff --git a/tests/manual/rhi/triquadcube/triquadcube.cpp b/tests/manual/rhi/triquadcube/triquadcube.cpp new file mode 100644 index 0000000000..252ec63e21 --- /dev/null +++ b/tests/manual/rhi/triquadcube/triquadcube.cpp @@ -0,0 +1,281 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// An example exercising more than a single feature. Enables profiling +// (resource logging to a file) and inserts debug markers and sets some +// object names. Can also be used to test MSAA swapchains, swapchain image +// readback, requesting an sRGB swapchain, and some texture features. + +#define EXAMPLEFW_PREINIT +#include "../shared/examplefw.h" +#include "trianglerenderer.h" +#include "quadrenderer.h" +#include "texturedcuberenderer.h" +#include "triangleoncuberenderer.h" + +#include <QFileInfo> +#include <QFile> +#include <QtGui/private/qrhiprofiler_p.h> + +#define PROFILE_TO_FILE +//#define SKIP_PRESENT +//#define USE_MSAA +//#define USE_SRGB_SWAPCHAIN +//#define READBACK_SWAPCHAIN +//#define NO_VSYNC +//#define USE_MIN_SWAPCHAIN_BUFFERS +//#define DECLARE_EXT_CONTENTS + +struct { + TriangleRenderer triRenderer; + QuadRenderer quadRenderer; + TexturedCubeRenderer cubeRenderer; + TriangleOnCubeRenderer liveTexCubeRenderer; + bool onScreenOnly = false; + bool triangleOnly = false; + QSize lastOutputSize; + int frameCount = 0; + QFile profOut; +} d; + +void preInit() +{ +#ifdef PROFILE_TO_FILE + rhiFlags |= QRhi::EnableProfiling; + const QString profFn = QFileInfo(QLatin1String("rhiprof.txt")).absoluteFilePath(); + qDebug("Writing profiling output to %s", qPrintable(profFn)); + d.profOut.setFileName(profFn); + d.profOut.open(QIODevice::WriteOnly); +#endif + +#ifdef SKIP_PRESENT + endFrameFlags |= QRhi::SkipPresent; +#endif + +#ifdef USE_MSAA + sampleCount = 4; // enable 4x MSAA (except for the render-to-texture pass) +#endif + +#ifdef READBACK_SWAPCHAIN + scFlags |= QRhiSwapChain::UsedAsTransferSource; +#endif + +#ifdef USE_SRGB_SWAPCHAIN + scFlags |= QRhiSwapChain::sRGB; +#endif + +#ifdef NO_VSYNC + scFlags |= QRhiSwapChain::NoVSync; +#endif + +#ifdef USE_MIN_SWAPCHAIN_BUFFERS + scFlags |= QRhiSwapChain::MinimalBufferCount; +#endif + +#ifdef DECLARE_EXT_CONTENTS + beginFrameFlags |= QRhi::ExternalContentsInPass; +#endif + + // For OpenGL some of these are incorporated into the QSurfaceFormat by + // examplefw.h after returning from here as that is out of the RHI's control. +} + +void Window::customInit() +{ +#ifdef PROFILE_TO_FILE + m_r->profiler()->setDevice(&d.profOut); +#endif + + d.triRenderer.setRhi(m_r); + d.triRenderer.setSampleCount(sampleCount); + d.triRenderer.initResources(m_rp); + + if (!d.triangleOnly) { + d.triRenderer.setTranslation(QVector3D(0, 0.5f, 0)); + + d.quadRenderer.setRhi(m_r); + d.quadRenderer.setSampleCount(sampleCount); + d.quadRenderer.setPipeline(d.triRenderer.pipeline()); + d.quadRenderer.initResources(m_rp); + d.quadRenderer.setTranslation(QVector3D(1.5f, -0.5f, 0)); + + d.cubeRenderer.setRhi(m_r); + d.cubeRenderer.setSampleCount(sampleCount); + d.cubeRenderer.initResources(m_rp); + d.cubeRenderer.setTranslation(QVector3D(0, -0.5f, 0)); + } + + if (!d.onScreenOnly) { + d.liveTexCubeRenderer.setRhi(m_r); + d.liveTexCubeRenderer.setSampleCount(sampleCount); + d.liveTexCubeRenderer.initResources(m_rp); + d.liveTexCubeRenderer.setTranslation(QVector3D(-2.0f, 0, 0)); + } + + // Put the gpu mem allocator statistics to the profiling stream after doing + // all the init. (where applicable) + m_r->profiler()->addVMemAllocatorStats(); + + // Check some features/limits. + qDebug("isFeatureSupported(MultisampleTexture): %d", m_r->isFeatureSupported(QRhi::MultisampleTexture)); + qDebug("isFeatureSupported(MultisampleRenderBuffer): %d", m_r->isFeatureSupported(QRhi::MultisampleRenderBuffer)); + qDebug("isFeatureSupported(DebugMarkers): %d", m_r->isFeatureSupported(QRhi::DebugMarkers)); + qDebug("isFeatureSupported(Timestamps): %d", m_r->isFeatureSupported(QRhi::Timestamps)); + qDebug("isFeatureSupported(Instancing): %d", m_r->isFeatureSupported(QRhi::Instancing)); + qDebug("isFeatureSupported(CustomInstanceStepRate): %d", m_r->isFeatureSupported(QRhi::CustomInstanceStepRate)); + qDebug("isFeatureSupported(PrimitiveRestart): %d", m_r->isFeatureSupported(QRhi::PrimitiveRestart)); + qDebug("isFeatureSupported(NonDynamicUniformBuffers): %d", m_r->isFeatureSupported(QRhi::NonDynamicUniformBuffers)); + qDebug("isFeatureSupported(NonFourAlignedEffectiveIndexBufferOffset): %d", m_r->isFeatureSupported(QRhi::NonFourAlignedEffectiveIndexBufferOffset)); + qDebug("isFeatureSupported(NPOTTextureRepeat): %d", m_r->isFeatureSupported(QRhi::NPOTTextureRepeat)); + qDebug("isFeatureSupported(RedOrAlpha8IsRed): %d", m_r->isFeatureSupported(QRhi::RedOrAlpha8IsRed)); + qDebug("isFeatureSupported(ElementIndexUint): %d", m_r->isFeatureSupported(QRhi::ElementIndexUint)); + qDebug("isFeatureSupported(Compute): %d", m_r->isFeatureSupported(QRhi::Compute)); + qDebug("isFeatureSupported(WideLines): %d", m_r->isFeatureSupported(QRhi::WideLines)); + qDebug("isFeatureSupported(VertexShaderPointSize): %d", m_r->isFeatureSupported(QRhi::VertexShaderPointSize)); + qDebug("isFeatureSupported(BaseVertex): %d", m_r->isFeatureSupported(QRhi::BaseVertex)); + qDebug("isFeatureSupported(BaseInstance): %d", m_r->isFeatureSupported(QRhi::BaseInstance)); + qDebug("Min 2D texture width/height: %d", m_r->resourceLimit(QRhi::TextureSizeMin)); + qDebug("Max 2D texture width/height: %d", m_r->resourceLimit(QRhi::TextureSizeMax)); + qDebug("Max color attachment count: %d", m_r->resourceLimit(QRhi::MaxColorAttachments)); +} + +void Window::customRelease() +{ + d.triRenderer.releaseResources(); + + if (!d.triangleOnly) { + d.quadRenderer.releaseResources(); + d.cubeRenderer.releaseResources(); + } + + if (!d.onScreenOnly) + d.liveTexCubeRenderer.releaseResources(); +} + +void Window::customRender() +{ + const QSize outputSize = m_sc->currentPixelSize(); + QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer(); + + if (outputSize != d.lastOutputSize) { + d.triRenderer.resize(outputSize); + if (!d.triangleOnly) { + d.quadRenderer.resize(outputSize); + d.cubeRenderer.resize(outputSize); + } + if (!d.onScreenOnly) + d.liveTexCubeRenderer.resize(outputSize); + d.lastOutputSize = outputSize; + } + + if (!d.onScreenOnly) { + cb->debugMarkBegin("Offscreen triangle pass"); + d.liveTexCubeRenderer.queueOffscreenPass(cb); + cb->debugMarkEnd(); + } + + QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch(); + d.triRenderer.queueResourceUpdates(u); + if (!d.triangleOnly) { + d.quadRenderer.queueResourceUpdates(u); + d.cubeRenderer.queueResourceUpdates(u); + } + if (!d.onScreenOnly) + d.liveTexCubeRenderer.queueResourceUpdates(u); + + cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }, u); + cb->debugMarkBegin(QByteArrayLiteral("Triangle")); + d.triRenderer.queueDraw(cb, outputSize); + cb->debugMarkEnd(); + if (!d.triangleOnly) { + cb->debugMarkMsg(QByteArrayLiteral("More stuff")); + cb->debugMarkBegin(QByteArrayLiteral("Quad")); + d.quadRenderer.queueDraw(cb, outputSize); + cb->debugMarkEnd(); + cb->debugMarkBegin(QByteArrayLiteral("Cube")); + d.cubeRenderer.queueDraw(cb, outputSize); + cb->debugMarkEnd(); + } + if (!d.onScreenOnly) { + cb->debugMarkMsg(QByteArrayLiteral("Even more stuff")); + cb->debugMarkBegin(QByteArrayLiteral("Cube with offscreen triangle")); + d.liveTexCubeRenderer.queueDraw(cb, outputSize); + cb->debugMarkEnd(); + } + + QRhiResourceUpdateBatch *passEndUpdates = nullptr; +#ifdef READBACK_SWAPCHAIN + passEndUpdates = m_r->nextResourceUpdateBatch(); + QRhiReadbackDescription rb; // no texture given -> backbuffer + QRhiReadbackResult *rbResult = new QRhiReadbackResult; + int frameNo = d.frameCount; + rbResult->completed = [this, rbResult, frameNo] { + { + QImage::Format fmt = rbResult->format == QRhiTexture::BGRA8 ? QImage::Format_ARGB32_Premultiplied + : QImage::Format_RGBA8888_Premultiplied; + const uchar *p = reinterpret_cast<const uchar *>(rbResult->data.constData()); + QImage image(p, rbResult->pixelSize.width(), rbResult->pixelSize.height(), fmt); + QString fn = QString::asprintf("frame%d.png", frameNo); + fn = QFileInfo(fn).absoluteFilePath(); + qDebug("Saving into %s", qPrintable(fn)); + if (m_r->isYUpInFramebuffer()) + image.mirrored().save(fn); + else + image.save(fn); + } + delete rbResult; + }; + passEndUpdates->readBackTexture(rb, rbResult); +#endif + + cb->endPass(passEndUpdates); + + d.frameCount += 1; +} diff --git a/tests/manual/rhi/triquadcube/triquadcube.pro b/tests/manual/rhi/triquadcube/triquadcube.pro new file mode 100644 index 0000000000..0002b3cad1 --- /dev/null +++ b/tests/manual/rhi/triquadcube/triquadcube.pro @@ -0,0 +1,18 @@ +TEMPLATE = app + +QT += gui-private + +SOURCES = \ + triquadcube.cpp \ + trianglerenderer.cpp \ + quadrenderer.cpp \ + texturedcuberenderer.cpp \ + triangleoncuberenderer.cpp + +HEADERS = \ + trianglerenderer.h \ + quadrenderer.h \ + texturedcuberenderer.h \ + triangleoncuberenderer.h + +RESOURCES = triquadcube.qrc diff --git a/tests/manual/rhi/triquadcube/triquadcube.qrc b/tests/manual/rhi/triquadcube/triquadcube.qrc new file mode 100644 index 0000000000..41b72edc41 --- /dev/null +++ b/tests/manual/rhi/triquadcube/triquadcube.qrc @@ -0,0 +1,9 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file alias="color.vert.qsb">../shared/color.vert.qsb</file> + <file alias="color.frag.qsb">../shared/color.frag.qsb</file> + <file alias="texture.vert.qsb">../shared/texture.vert.qsb</file> + <file alias="texture.frag.qsb">../shared/texture.frag.qsb</file> + <file alias="qt256.png">../shared/qt256.png</file> +</qresource> +</RCC> diff --git a/tests/manual/socketengine/main.cpp b/tests/manual/socketengine/main.cpp index 0d491e7350..3e3e7e53e5 100644 --- a/tests/manual/socketengine/main.cpp +++ b/tests/manual/socketengine/main.cpp @@ -83,7 +83,7 @@ int main(int argc, char**argv) // disconnected exit(0); } - qFill(buf, buf + bufsize, 0); + std::fill(buf, buf + bufsize, 0); ret = socketEngine->read(buf, available); if (ret > 0) { printf("%s", buf); diff --git a/tests/manual/textrendering/glyphshaping/main.cpp b/tests/manual/textrendering/glyphshaping/main.cpp index c3acda953d..c1e49b3b7e 100644 --- a/tests/manual/textrendering/glyphshaping/main.cpp +++ b/tests/manual/textrendering/glyphshaping/main.cpp @@ -160,8 +160,6 @@ bool dumpHtml(const QString &pathName) QString platformName = QString::fromLatin1( #if defined(Q_OS_WIN) "Win32" -#elif 0 // Used to be included in Qt4 for Q_WS_X11 - "X11" #else "" #endif diff --git a/tests/shared/filesystem.h b/tests/shared/filesystem.h index 9f4527a992..0e7e6ba867 100644 --- a/tests/shared/filesystem.h +++ b/tests/shared/filesystem.h @@ -79,7 +79,7 @@ public: return file.isNull() ? qint64(-1) : file->write(relativeFileName.toUtf8()); } -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) +#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) static DWORD createNtfsJunction(QString target, QString linkName, QString *errorMessage) { typedef struct { diff --git a/tests/testserver/apache2/apache2.sh b/tests/testserver/apache2/apache2.sh index 4b0c74e2c4..d5075c7096 100755 --- a/tests/testserver/apache2/apache2.sh +++ b/tests/testserver/apache2/apache2.sh @@ -73,5 +73,8 @@ touch -d "2007-05-22 12:04:57 GMT" /home/$USER/www/htdocs/fluke.gif # Create 10MB file for use by tst_Q*::downloadBigFile and interruption tests: su $USER -c "/bin/dd if=/dev/zero of=~/www/htdocs/mediumfile bs=1 count=0 seek=10000000" +# Emulate test server's hierarchy: +su $USER -c "ln -s ~/www/htdocs/rfcs/rfc2616.html ~/www/htdocs/deflate/" + # enable service with installed configurations service apache2 restart diff --git a/tests/testserver/apache2/testdata/www/cgi-bin/httpcachetest_cachecontrol-expire.cgi b/tests/testserver/apache2/testdata/www/cgi-bin/httpcachetest_cachecontrol-expire.cgi new file mode 100755 index 0000000000..7dc506fc1e --- /dev/null +++ b/tests/testserver/apache2/testdata/www/cgi-bin/httpcachetest_cachecontrol-expire.cgi @@ -0,0 +1,7 @@ +#!/bin/bash +# cache control takes precedence over expires +echo "Cache-Control: max-age=-1" +echo "Expires: Mon, 30 Oct 2028 14:19:41 GMT" +echo "Content-type: text/html"; +echo "" +echo "Hello World!" diff --git a/tests/testserver/apache2/testdata/www/cgi-bin/httpcachetest_cachecontrol.cgi b/tests/testserver/apache2/testdata/www/cgi-bin/httpcachetest_cachecontrol.cgi new file mode 100755 index 0000000000..f2edfc161f --- /dev/null +++ b/tests/testserver/apache2/testdata/www/cgi-bin/httpcachetest_cachecontrol.cgi @@ -0,0 +1,13 @@ +#!/bin/bash +if [ ! -z ${HTTP_IF_MODIFIED_SINCE} ] ; then + echo "Status: 304" + echo "" + exit; +fi + +cc=`echo "${QUERY_STRING}" | sed -e s/%20/\ /g` +echo "Cache-Control: $cc" +echo "Last-Modified: Sat, 31 Oct 1981 06:00:00 GMT" +echo "Content-type: text/html"; +echo "" +echo "Hello World!" diff --git a/tests/testserver/apache2/testdata/www/cgi-bin/httpcachetest_cachecontrol200.cgi b/tests/testserver/apache2/testdata/www/cgi-bin/httpcachetest_cachecontrol200.cgi new file mode 100755 index 0000000000..e44d5ed570 --- /dev/null +++ b/tests/testserver/apache2/testdata/www/cgi-bin/httpcachetest_cachecontrol200.cgi @@ -0,0 +1,9 @@ +#!/bin/bash +cc=`echo "${QUERY_STRING}" | sed -e s/%20/\ /g` +echo "Status: 200" +echo "Cache-Control: $cc" +echo "Last-Modified: Sat, 31 Oct 1981 06:00:00 GMT" +echo "Content-type: text/html"; +echo "X-Script: $0" +echo "" +echo "Hello World!" diff --git a/tests/testserver/apache2/testdata/www/cgi-bin/httpcachetest_etag200.cgi b/tests/testserver/apache2/testdata/www/cgi-bin/httpcachetest_etag200.cgi new file mode 100755 index 0000000000..0966abfdd1 --- /dev/null +++ b/tests/testserver/apache2/testdata/www/cgi-bin/httpcachetest_etag200.cgi @@ -0,0 +1,5 @@ +#!/bin/bash +echo "ETag: foo" +echo "Content-type: text/html"; +echo "" +echo "Hello World!" diff --git a/tests/testserver/apache2/testdata/www/cgi-bin/httpcachetest_etag304.cgi b/tests/testserver/apache2/testdata/www/cgi-bin/httpcachetest_etag304.cgi new file mode 100755 index 0000000000..91a4b922bd --- /dev/null +++ b/tests/testserver/apache2/testdata/www/cgi-bin/httpcachetest_etag304.cgi @@ -0,0 +1,11 @@ +#!/bin/bash +if [ ! -z ${HTTP_IF_NONE_MATCH} ] ; then + echo "Status: 304" + echo "" + exit; +fi + +echo "ETag: foo" +echo "Content-type: text/html"; +echo "" +echo "Hello World!" diff --git a/tests/testserver/apache2/testdata/www/cgi-bin/httpcachetest_expires200.cgi b/tests/testserver/apache2/testdata/www/cgi-bin/httpcachetest_expires200.cgi new file mode 100755 index 0000000000..e18ebc86ad --- /dev/null +++ b/tests/testserver/apache2/testdata/www/cgi-bin/httpcachetest_expires200.cgi @@ -0,0 +1,5 @@ +#!/bin/bash +echo "Expires: Sat, 31 Oct 1981 6:00:00 GMT" +echo "Content-type: text/html"; +echo "" +echo "Hello World!" diff --git a/tests/testserver/apache2/testdata/www/cgi-bin/httpcachetest_expires304.cgi b/tests/testserver/apache2/testdata/www/cgi-bin/httpcachetest_expires304.cgi new file mode 100755 index 0000000000..1c7de1cd77 --- /dev/null +++ b/tests/testserver/apache2/testdata/www/cgi-bin/httpcachetest_expires304.cgi @@ -0,0 +1,11 @@ +#!/bin/bash +if [ ${HTTP_IF_MODIFIED_SINCE} == "Mon, 30 Oct 2028 14:19:41 GMT" ] ; then + echo "Status: 304" + echo "" + exit; +fi + +echo "Expires: Mon, 30 Oct 2028 14:19:41 GMT" +echo "Content-type: text/html"; +echo "" +echo "Hello World!" diff --git a/tests/testserver/apache2/testdata/www/cgi-bin/httpcachetest_lastModified200.cgi b/tests/testserver/apache2/testdata/www/cgi-bin/httpcachetest_lastModified200.cgi new file mode 100755 index 0000000000..5dc219b1e7 --- /dev/null +++ b/tests/testserver/apache2/testdata/www/cgi-bin/httpcachetest_lastModified200.cgi @@ -0,0 +1,5 @@ +#!/bin/bash +echo "Last-Modified: Sat, 31 Oct 1981 6:00:00 GMT" +echo "Content-type: text/html"; +echo "" +echo "Hello World!" diff --git a/tests/testserver/apache2/testdata/www/cgi-bin/httpcachetest_lastModified304.cgi b/tests/testserver/apache2/testdata/www/cgi-bin/httpcachetest_lastModified304.cgi new file mode 100755 index 0000000000..bdf23bed2f --- /dev/null +++ b/tests/testserver/apache2/testdata/www/cgi-bin/httpcachetest_lastModified304.cgi @@ -0,0 +1,11 @@ +#!/bin/bash +if [ ${HTTP_IF_MODIFIED_SINCE} == "Sat, 31 Oct 1981 06:00:00 GMT" ] ; then + echo "Status: 304" + echo "" + exit; +fi + +echo "Last-Modified: Sat, 31 Oct 1981 06:00:00 GMT" +echo "Content-type: text/html"; +echo "" +echo "Hello World!" diff --git a/tests/testserver/apache2/testdata/www/htdocs/rfcs/.gitattributes b/tests/testserver/apache2/testdata/www/htdocs/rfcs/.gitattributes new file mode 100644 index 0000000000..1d09ee726e --- /dev/null +++ b/tests/testserver/apache2/testdata/www/htdocs/rfcs/.gitattributes @@ -0,0 +1 @@ +rfc2616.html binary diff --git a/tests/testserver/apache2/testdata/www/htdocs/rfcs/rfc2616.html b/tests/testserver/apache2/testdata/www/htdocs/rfcs/rfc2616.html new file mode 100644 index 0000000000..0e3282fb8d --- /dev/null +++ b/tests/testserver/apache2/testdata/www/htdocs/rfcs/rfc2616.html @@ -0,0 +1,8380 @@ +<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> +<html><head><title>RFC 2616 (rfc2616) - Hypertext Transfer Protocol -- HTTP/1.1</title>
+
+
+
+<meta name="description" content="RFC 2616 - Hypertext Transfer Protocol -- HTTP/1.1">
+<meta name="obsoletes" content="RFC2068">
+<script language="JavaScript1.2">
+function erfc(s)
+{document.write("<A href=\"/rfccomment.php?rfcnum="+s+"\" target=\"_blank\" onclick=\"window.open('/rfccomment.php?rfcnum="+s+"','Popup','toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=680,height=530,left=30,top=43'); return false;\")>Comment on RFC "+s+"</A>\n");}
+//-->
+</script></head><body bgcolor="#ffffff" text="#000000">
+<p align="center"><img src="rfc2616_files/library.htm" alt="" align="middle" border="0" height="62" width="150"></p>
+<h1 align="center">RFC 2616 (RFC2616)</h1>
+<p align="center">Internet RFC/STD/FYI/BCP Archives</p>
+
+<div align="center">[ <a href="http://firefly.troll.no/rfcs/">RFC Index</a> | <a href="http://firefly.troll.no/rfcs/rfcsearch.html">RFC Search</a> | <a href="http://firefly.troll.no/faqs/">Usenet FAQs</a> | <a href="http://firefly.troll.no/contrib/">Web FAQs</a> | <a href="http://firefly.troll.no/docs/">Documents</a> | <a href="http://www.city-data.com/">Cities</a> ]
+<p>
+<strong>Alternate Formats:</strong>
+ <a href="http://firefly.troll.no/ftp/rfc/rfc2616.txt">rfc2616.txt</a> |
+ <a href="http://firefly.troll.no/ftp/rfc/rfc2616.ps">rfc2616.ps</a> |
+ <a href="http://firefly.troll.no/ftp/rfc/rfc2616.pdf">rfc2616.pdf</a></p></div>
+<p align="center"><script language="JavaScript"><!--
+erfc("2616");
+// --></script><a href="http://firefly.troll.no/rfccomment.php?rfcnum=2616" target="_blank" onclick="window.open('/rfccomment.php?rfcnum=2616','Popup','toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=680,height=530,left=30,top=43'); return false;" )="">Comment on RFC 2616</a>
+</p>
+<h3 align="center">RFC 2616 - Hypertext Transfer Protocol -- HTTP/1.1</h3>
+<hr noshade="noshade" size="2">
+<pre>
+Network Working Group R. Fielding
+Request for Comments: 2616 UC Irvine
+Obsoletes: 2068 J. Gettys
+Category: Standards Track Compaq/W3C
+ J. Mogul
+ Compaq
+ H. Frystyk
+ W3C/MIT
+ L. Masinter
+ Xerox
+ P. Leach
+ Microsoft
+ T. Berners-Lee
+ W3C/MIT
+ June 1999
+
+ Hypertext Transfer Protocol -- HTTP/1.1
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+Abstract
+
+ The Hypertext Transfer Protocol (HTTP) is an application-level
+ protocol for distributed, collaborative, hypermedia information
+ systems. It is a generic, stateless, protocol which can be used for
+ many tasks beyond its use for hypertext, such as name servers and
+ distributed object management systems, through extension of its
+ request methods, error codes and headers [47]. A feature of HTTP is
+ the typing and negotiation of data representation, allowing systems
+ to be built independently of the data being transferred.
+
+ HTTP has been in use by the World-Wide Web global information
+ initiative since 1990. This specification defines the protocol
+ referred to as "HTTP/1.1", and is an update to <a href="http://firefly.troll.no/rfcs/rfc2068.html">RFC 2068</a> [33].
+
+Table of Contents
+
+ 1 Introduction ...................................................7
+ 1.1 Purpose......................................................7
+ 1.2 Requirements .................................................8
+ 1.3 Terminology ..................................................8
+ 1.4 Overall Operation ...........................................12
+ 2 Notational Conventions and Generic Grammar ....................14
+ 2.1 Augmented BNF ...............................................14
+ 2.2 Basic Rules .................................................15
+ 3 Protocol Parameters ...........................................17
+ 3.1 HTTP Version ................................................17
+ 3.2 Uniform Resource Identifiers ................................18
+ 3.2.1 General Syntax ...........................................19
+ 3.2.2 http URL .................................................19
+ 3.2.3 URI Comparison ...........................................20
+ 3.3 Date/Time Formats ...........................................20
+ 3.3.1 Full Date ................................................20
+ 3.3.2 Delta Seconds ............................................21
+ 3.4 Character Sets ..............................................21
+ 3.4.1 Missing Charset ..........................................22
+ 3.5 Content Codings .............................................23
+ 3.6 Transfer Codings ............................................24
+ 3.6.1 Chunked Transfer Coding ..................................25
+ 3.7 Media Types .................................................26
+ 3.7.1 Canonicalization and Text Defaults .......................27
+ 3.7.2 Multipart Types ..........................................27
+ 3.8 Product Tokens ..............................................28
+ 3.9 Quality Values ..............................................29
+ 3.10 Language Tags ...............................................29
+ 3.11 Entity Tags .................................................30
+ 3.12 Range Units .................................................30
+ 4 HTTP Message ..................................................31
+ 4.1 Message Types ...............................................31
+ 4.2 Message Headers .............................................31
+ 4.3 Message Body ................................................32
+ 4.4 Message Length ..............................................33
+ 4.5 General Header Fields .......................................34
+ 5 Request .......................................................35
+ 5.1 Request-Line ................................................35
+ 5.1.1 Method ...................................................36
+ 5.1.2 Request-URI ..............................................36
+ 5.2 The Resource Identified by a Request ........................38
+ 5.3 Request Header Fields .......................................38
+ 6 Response ......................................................39
+ 6.1 Status-Line .................................................39
+ 6.1.1 Status Code and Reason Phrase ............................39
+ 6.2 Response Header Fields ......................................41
+
+ 7 Entity ........................................................42
+ 7.1 Entity Header Fields ........................................42
+ 7.2 Entity Body .................................................43
+ 7.2.1 Type .....................................................43
+ 7.2.2 Entity Length ............................................43
+ 8 Connections ...................................................44
+ 8.1 Persistent Connections ......................................44
+ 8.1.1 Purpose ..................................................44
+ 8.1.2 Overall Operation ........................................45
+ 8.1.3 Proxy Servers ............................................46
+ 8.1.4 Practical Considerations .................................46
+ 8.2 Message Transmission Requirements ...........................47
+ 8.2.1 Persistent Connections and Flow Control ..................47
+ 8.2.2 Monitoring Connections for Error Status Messages .........48
+ 8.2.3 Use of the 100 (Continue) Status .........................48
+ 8.2.4 Client Behavior if Server Prematurely Closes Connection ..50
+ 9 Method Definitions ............................................51
+ 9.1 Safe and Idempotent Methods .................................51
+ 9.1.1 Safe Methods .............................................51
+ 9.1.2 Idempotent Methods .......................................51
+ 9.2 OPTIONS .....................................................52
+ 9.3 GET .........................................................53
+ 9.4 HEAD ........................................................54
+ 9.5 POST ........................................................54
+ 9.6 PUT .........................................................55
+ 9.7 DELETE ......................................................56
+ 9.8 TRACE .......................................................56
+ 9.9 CONNECT .....................................................57
+ 10 Status Code Definitions ......................................57
+ 10.1 Informational 1xx ...........................................57
+ 10.1.1 100 Continue .............................................58
+ 10.1.2 101 Switching Protocols ..................................58
+ 10.2 Successful 2xx ..............................................58
+ 10.2.1 200 OK ...................................................58
+ 10.2.2 201 Created ..............................................59
+ 10.2.3 202 Accepted .............................................59
+ 10.2.4 203 Non-Authoritative Information ........................59
+ 10.2.5 204 No Content ...........................................60
+ 10.2.6 205 Reset Content ........................................60
+ 10.2.7 206 Partial Content ......................................60
+ 10.3 Redirection 3xx .............................................61
+ 10.3.1 300 Multiple Choices .....................................61
+ 10.3.2 301 Moved Permanently ....................................62
+ 10.3.3 302 Found ................................................62
+ 10.3.4 303 See Other ............................................63
+ 10.3.5 304 Not Modified .........................................63
+ 10.3.6 305 Use Proxy ............................................64
+ 10.3.7 306 (Unused) .............................................64
+
+ 10.3.8 307 Temporary Redirect ...................................65
+ 10.4 Client Error 4xx ............................................65
+ 10.4.1 400 Bad Request .........................................65
+ 10.4.2 401 Unauthorized ........................................66
+ 10.4.3 402 Payment Required ....................................66
+ 10.4.4 403 Forbidden ...........................................66
+ 10.4.5 404 Not Found ...........................................66
+ 10.4.6 405 Method Not Allowed ..................................66
+ 10.4.7 406 Not Acceptable ......................................67
+ 10.4.8 407 Proxy Authentication Required .......................67
+ 10.4.9 408 Request Timeout .....................................67
+ 10.4.10 409 Conflict ............................................67
+ 10.4.11 410 Gone ................................................68
+ 10.4.12 411 Length Required .....................................68
+ 10.4.13 412 Precondition Failed .................................68
+ 10.4.14 413 Request Entity Too Large ............................69
+ 10.4.15 414 Request-URI Too Long ................................69
+ 10.4.16 415 Unsupported Media Type ..............................69
+ 10.4.17 416 Requested Range Not Satisfiable .....................69
+ 10.4.18 417 Expectation Failed ..................................70
+ 10.5 Server Error 5xx ............................................70
+ 10.5.1 500 Internal Server Error ................................70
+ 10.5.2 501 Not Implemented ......................................70
+ 10.5.3 502 Bad Gateway ..........................................70
+ 10.5.4 503 Service Unavailable ..................................70
+ 10.5.5 504 Gateway Timeout ......................................71
+ 10.5.6 505 HTTP Version Not Supported ...........................71
+ 11 Access Authentication ........................................71
+ 12 Content Negotiation ..........................................71
+ 12.1 Server-driven Negotiation ...................................72
+ 12.2 Agent-driven Negotiation ....................................73
+ 12.3 Transparent Negotiation .....................................74
+ 13 Caching in HTTP ..............................................74
+ 13.1.1 Cache Correctness ........................................75
+ 13.1.2 Warnings .................................................76
+ 13.1.3 Cache-control Mechanisms .................................77
+ 13.1.4 Explicit User Agent Warnings .............................78
+ 13.1.5 Exceptions to the Rules and Warnings .....................78
+ 13.1.6 Client-controlled Behavior ...............................79
+ 13.2 Expiration Model ............................................79
+ 13.2.1 Server-Specified Expiration ..............................79
+ 13.2.2 Heuristic Expiration .....................................80
+ 13.2.3 Age Calculations .........................................80
+ 13.2.4 Expiration Calculations ..................................83
+ 13.2.5 Disambiguating Expiration Values .........................84
+ 13.2.6 Disambiguating Multiple Responses ........................84
+ 13.3 Validation Model ............................................85
+ 13.3.1 Last-Modified Dates ......................................86
+
+ 13.3.2 Entity Tag Cache Validators ..............................86
+ 13.3.3 Weak and Strong Validators ...............................86
+ 13.3.4 Rules for When to Use Entity Tags and Last-Modified Dates.89
+ 13.3.5 Non-validating Conditionals ..............................90
+ 13.4 Response Cacheability .......................................91
+ 13.5 Constructing Responses From Caches ..........................92
+ 13.5.1 End-to-end and Hop-by-hop Headers ........................92
+ 13.5.2 Non-modifiable Headers ...................................92
+ 13.5.3 Combining Headers ........................................94
+ 13.5.4 Combining Byte Ranges ....................................95
+ 13.6 Caching Negotiated Responses ................................95
+ 13.7 Shared and Non-Shared Caches ................................96
+ 13.8 Errors or Incomplete Response Cache Behavior ................97
+ 13.9 Side Effects of GET and HEAD ................................97
+ 13.10 Invalidation After Updates or Deletions ...................97
+ 13.11 Write-Through Mandatory ...................................98
+ 13.12 Cache Replacement .........................................99
+ 13.13 History Lists .............................................99
+ 14 Header Field Definitions ....................................100
+ 14.1 Accept .....................................................100
+ 14.2 Accept-Charset .............................................102
+ 14.3 Accept-Encoding ............................................102
+ 14.4 Accept-Language ............................................104
+ 14.5 Accept-Ranges ..............................................105
+ 14.6 Age ........................................................106
+ 14.7 Allow ......................................................106
+ 14.8 Authorization ..............................................107
+ 14.9 Cache-Control ..............................................108
+ 14.9.1 What is Cacheable .......................................109
+ 14.9.2 What May be Stored by Caches ............................110
+ 14.9.3 Modifications of the Basic Expiration Mechanism .........111
+ 14.9.4 Cache Revalidation and Reload Controls ..................113
+ 14.9.5 No-Transform Directive ..................................115
+ 14.9.6 Cache Control Extensions ................................116
+ 14.10 Connection ...............................................117
+ 14.11 Content-Encoding .........................................118
+ 14.12 Content-Language .........................................118
+ 14.13 Content-Length ...........................................119
+ 14.14 Content-Location .........................................120
+ 14.15 Content-MD5 ..............................................121
+ 14.16 Content-Range ............................................122
+ 14.17 Content-Type .............................................124
+ 14.18 Date .....................................................124
+ 14.18.1 Clockless Origin Server Operation ......................125
+ 14.19 ETag .....................................................126
+ 14.20 Expect ...................................................126
+ 14.21 Expires ..................................................127
+ 14.22 From .....................................................128
+
+ 14.23 Host .....................................................128
+ 14.24 If-Match .................................................129
+ 14.25 If-Modified-Since ........................................130
+ 14.26 If-None-Match ............................................132
+ 14.27 If-Range .................................................133
+ 14.28 If-Unmodified-Since ......................................134
+ 14.29 Last-Modified ............................................134
+ 14.30 Location .................................................135
+ 14.31 Max-Forwards .............................................136
+ 14.32 Pragma ...................................................136
+ 14.33 Proxy-Authenticate .......................................137
+ 14.34 Proxy-Authorization ......................................137
+ 14.35 Range ....................................................138
+ 14.35.1 Byte Ranges ...........................................138
+ 14.35.2 Range Retrieval Requests ..............................139
+ 14.36 Referer ..................................................140
+ 14.37 Retry-After ..............................................141
+ 14.38 Server ...................................................141
+ 14.39 TE .......................................................142
+ 14.40 Trailer ..................................................143
+ 14.41 Transfer-Encoding..........................................143
+ 14.42 Upgrade ..................................................144
+ 14.43 User-Agent ...............................................145
+ 14.44 Vary .....................................................145
+ 14.45 Via ......................................................146
+ 14.46 Warning ..................................................148
+ 14.47 WWW-Authenticate .........................................150
+ 15 Security Considerations .......................................150
+ 15.1 Personal Information....................................151
+ 15.1.1 Abuse of Server Log Information .........................151
+ 15.1.2 Transfer of Sensitive Information .......................151
+ 15.1.3 Encoding Sensitive Information in URI's .................152
+ 15.1.4 Privacy Issues Connected to Accept Headers ..............152
+ 15.2 Attacks Based On File and Path Names .......................153
+ 15.3 DNS Spoofing ...............................................154
+ 15.4 Location Headers and Spoofing ..............................154
+ 15.5 Content-Disposition Issues .................................154
+ 15.6 Authentication Credentials and Idle Clients ................155
+ 15.7 Proxies and Caching ........................................155
+ 15.7.1 Denial of Service Attacks on Proxies....................156
+ 16 Acknowledgments .............................................156
+ 17 References ..................................................158
+ 18 Authors' Addresses ..........................................162
+ 19 Appendices ..................................................164
+ 19.1 Internet Media Type message/http and application/http ......164
+ 19.2 Internet Media Type multipart/byteranges ...................165
+ 19.3 Tolerant Applications ......................................166
+ 19.4 Differences Between HTTP Entities and <a href="http://firefly.troll.no/rfcs/rfc2045.html">RFC 2045</a> Entities ....167
+
+ 19.4.1 MIME-Version ............................................167
+ 19.4.2 Conversion to Canonical Form ............................167
+ 19.4.3 Conversion of Date Formats ..............................168
+ 19.4.4 Introduction of Content-Encoding ........................168
+ 19.4.5 No Content-Transfer-Encoding ............................168
+ 19.4.6 Introduction of Transfer-Encoding .......................169
+ 19.4.7 MHTML and Line Length Limitations .......................169
+ 19.5 Additional Features ........................................169
+ 19.5.1 Content-Disposition .....................................170
+ 19.6 Compatibility with Previous Versions .......................170
+ 19.6.1 Changes from HTTP/1.0 ...................................171
+ 19.6.2 Compatibility with HTTP/1.0 Persistent Connections ......172
+ 19.6.3 Changes from <a href="http://firefly.troll.no/rfcs/rfc2068.html">RFC 2068</a> ...................................172
+ 20 Index .......................................................175
+ 21 Full Copyright Statement ....................................176
+
+1 Introduction
+
+1.1 Purpose
+
+ The Hypertext Transfer Protocol (HTTP) is an application-level
+ protocol for distributed, collaborative, hypermedia information
+ systems. HTTP has been in use by the World-Wide Web global
+ information initiative since 1990. The first version of HTTP,
+ referred to as HTTP/0.9, was a simple protocol for raw data transfer
+ across the Internet. HTTP/1.0, as defined by <a href="http://firefly.troll.no/rfcs/rfc1945.html">RFC 1945</a> [6], improved
+ the protocol by allowing messages to be in the format of MIME-like
+ messages, containing metainformation about the data transferred and
+ modifiers on the request/response semantics. However, HTTP/1.0 does
+ not sufficiently take into consideration the effects of hierarchical
+ proxies, caching, the need for persistent connections, or virtual
+ hosts. In addition, the proliferation of incompletely-implemented
+ applications calling themselves "HTTP/1.0" has necessitated a
+ protocol version change in order for two communicating applications
+ to determine each other's true capabilities.
+
+ This specification defines the protocol referred to as "HTTP/1.1".
+ This protocol includes more stringent requirements than HTTP/1.0 in
+ order to ensure reliable implementation of its features.
+
+ Practical information systems require more functionality than simple
+ retrieval, including search, front-end update, and annotation. HTTP
+ allows an open-ended set of methods and headers that indicate the
+ purpose of a request [47]. It builds on the discipline of reference
+ provided by the Uniform Resource Identifier (URI) [3], as a location
+ (URL) [4] or name (URN) [20], for indicating the resource to which a
+
+ method is to be applied. Messages are passed in a format similar to
+ that used by Internet mail [9] as defined by the Multipurpose
+ Internet Mail Extensions (MIME) [7].
+
+ HTTP is also used as a generic protocol for communication between
+ user agents and proxies/gateways to other Internet systems, including
+ those supported by the SMTP [16], NNTP [13], FTP [18], Gopher [2],
+ and WAIS [10] protocols. In this way, HTTP allows basic hypermedia
+ access to resources available from diverse applications.
+
+1.2 Requirements
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in <a href="http://firefly.troll.no/rfcs/rfc2119.html">RFC 2119</a> [34].
+
+ An implementation is not compliant if it fails to satisfy one or more
+ of the MUST or REQUIRED level requirements for the protocols it
+ implements. An implementation that satisfies all the MUST or REQUIRED
+ level and all the SHOULD level requirements for its protocols is said
+ to be "unconditionally compliant"; one that satisfies all the MUST
+ level requirements but not all the SHOULD level requirements for its
+ protocols is said to be "conditionally compliant."
+
+1.3 Terminology
+
+ This specification uses a number of terms to refer to the roles
+ played by participants in, and objects of, the HTTP communication.
+
+ connection
+ A transport layer virtual circuit established between two programs
+ for the purpose of communication.
+
+ message
+ The basic unit of HTTP communication, consisting of a structured
+ sequence of octets matching the syntax defined in section 4 and
+ transmitted via the connection.
+
+ request
+ An HTTP request message, as defined in section 5.
+
+ response
+ An HTTP response message, as defined in section 6.
+
+ resource
+ A network data object or service that can be identified by a URI,
+ as defined in section 3.2. Resources may be available in multiple
+ representations (e.g. multiple languages, data formats, size, and
+ resolutions) or vary in other ways.
+
+ entity
+ The information transferred as the payload of a request or
+ response. An entity consists of metainformation in the form of
+ entity-header fields and content in the form of an entity-body, as
+ described in section 7.
+
+ representation
+ An entity included with a response that is subject to content
+ negotiation, as described in section 12. There may exist multiple
+ representations associated with a particular response status.
+
+ content negotiation
+ The mechanism for selecting the appropriate representation when
+ servicing a request, as described in section 12. The
+ representation of entities in any response can be negotiated
+ (including error responses).
+
+ variant
+ A resource may have one, or more than one, representation(s)
+ associated with it at any given instant. Each of these
+ representations is termed a `varriant'. Use of the term `variant'
+ does not necessarily imply that the resource is subject to content
+ negotiation.
+
+ client
+ A program that establishes connections for the purpose of sending
+ requests.
+
+ user agent
+ The client which initiates a request. These are often browsers,
+ editors, spiders (web-traversing robots), or other end user tools.
+
+ server
+ An application program that accepts connections in order to
+ service requests by sending back responses. Any given program may
+ be capable of being both a client and a server; our use of these
+ terms refers only to the role being performed by the program for a
+ particular connection, rather than to the program's capabilities
+ in general. Likewise, any server may act as an origin server,
+ proxy, gateway, or tunnel, switching behavior based on the nature
+ of each request.
+
+ origin server
+ The server on which a given resource resides or is to be created.
+
+ proxy
+ An intermediary program which acts as both a server and a client
+ for the purpose of making requests on behalf of other clients.
+ Requests are serviced internally or by passing them on, with
+ possible translation, to other servers. A proxy MUST implement
+ both the client and server requirements of this specification. A
+ "transparent proxy" is a proxy that does not modify the request or
+ response beyond what is required for proxy authentication and
+ identification. A "non-transparent proxy" is a proxy that modifies
+ the request or response in order to provide some added service to
+ the user agent, such as group annotation services, media type
+ transformation, protocol reduction, or anonymity filtering. Except
+ where either transparent or non-transparent behavior is explicitly
+ stated, the HTTP proxy requirements apply to both types of
+ proxies.
+
+ gateway
+ A server which acts as an intermediary for some other server.
+ Unlike a proxy, a gateway receives requests as if it were the
+ origin server for the requested resource; the requesting client
+ may not be aware that it is communicating with a gateway.
+
+ tunnel
+ An intermediary program which is acting as a blind relay between
+ two connections. Once active, a tunnel is not considered a party
+ to the HTTP communication, though the tunnel may have been
+ initiated by an HTTP request. The tunnel ceases to exist when both
+ ends of the relayed connections are closed.
+
+ cache
+ A program's local store of response messages and the subsystem
+ that controls its message storage, retrieval, and deletion. A
+ cache stores cacheable responses in order to reduce the response
+ time and network bandwidth consumption on future, equivalent
+ requests. Any client or server may include a cache, though a cache
+ cannot be used by a server that is acting as a tunnel.
+
+ cacheable
+ A response is cacheable if a cache is allowed to store a copy of
+ the response message for use in answering subsequent requests. The
+ rules for determining the cacheability of HTTP responses are
+ defined in section 13. Even if a resource is cacheable, there may
+ be additional constraints on whether a cache can use the cached
+ copy for a particular request.
+
+ first-hand
+ A response is first-hand if it comes directly and without
+ unnecessary delay from the origin server, perhaps via one or more
+ proxies. A response is also first-hand if its validity has just
+ been checked directly with the origin server.
+
+ explicit expiration time
+ The time at which the origin server intends that an entity should
+ no longer be returned by a cache without further validation.
+
+ heuristic expiration time
+ An expiration time assigned by a cache when no explicit expiration
+ time is available.
+
+ age
+ The age of a response is the time since it was sent by, or
+ successfully validated with, the origin server.
+
+ freshness lifetime
+ The length of time between the generation of a response and its
+ expiration time.
+
+ fresh
+ A response is fresh if its age has not yet exceeded its freshness
+ lifetime.
+
+ stale
+ A response is stale if its age has passed its freshness lifetime.
+
+ semantically transparent
+ A cache behaves in a "semantically transparent" manner, with
+ respect to a particular response, when its use affects neither the
+ requesting client nor the origin server, except to improve
+ performance. When a cache is semantically transparent, the client
+ receives exactly the same response (except for hop-by-hop headers)
+ that it would have received had its request been handled directly
+ by the origin server.
+
+ validator
+ A protocol element (e.g., an entity tag or a Last-Modified time)
+ that is used to find out whether a cache entry is an equivalent
+ copy of an entity.
+
+ upstream/downstream
+ Upstream and downstream describe the flow of a message: all
+ messages flow from upstream to downstream.
+
+ inbound/outbound
+ Inbound and outbound refer to the request and response paths for
+ messages: "inbound" means "traveling toward the origin server",
+ and "outbound" means "traveling toward the user agent"
+
+1.4 Overall Operation
+
+ The HTTP protocol is a request/response protocol. A client sends a
+ request to the server in the form of a request method, URI, and
+ protocol version, followed by a MIME-like message containing request
+ modifiers, client information, and possible body content over a
+ connection with a server. The server responds with a status line,
+ including the message's protocol version and a success or error code,
+ followed by a MIME-like message containing server information, entity
+ metainformation, and possible entity-body content. The relationship
+ between HTTP and MIME is described in appendix 19.4.
+
+ Most HTTP communication is initiated by a user agent and consists of
+ a request to be applied to a resource on some origin server. In the
+ simplest case, this may be accomplished via a single connection (v)
+ between the user agent (UA) and the origin server (O).
+
+ request chain ------------------------>
+ UA -------------------v------------------- O
+ <----------------------- response chain
+
+ A more complicated situation occurs when one or more intermediaries
+ are present in the request/response chain. There are three common
+ forms of intermediary: proxy, gateway, and tunnel. A proxy is a
+ forwarding agent, receiving requests for a URI in its absolute form,
+ rewriting all or part of the message, and forwarding the reformatted
+ request toward the server identified by the URI. A gateway is a
+ receiving agent, acting as a layer above some other server(s) and, if
+ necessary, translating the requests to the underlying server's
+ protocol. A tunnel acts as a relay point between two connections
+ without changing the messages; tunnels are used when the
+ communication needs to pass through an intermediary (such as a
+ firewall) even when the intermediary cannot understand the contents
+ of the messages.
+
+ request chain -------------------------------------->
+ UA -----v----- A -----v----- B -----v----- C -----v----- O
+ <------------------------------------- response chain
+
+ The figure above shows three intermediaries (A, B, and C) between the
+ user agent and origin server. A request or response message that
+ travels the whole chain will pass through four separate connections.
+ This distinction is important because some HTTP communication options
+
+ may apply only to the connection with the nearest, non-tunnel
+ neighbor, only to the end-points of the chain, or to all connections
+ along the chain. Although the diagram is linear, each participant may
+ be engaged in multiple, simultaneous communications. For example, B
+ may be receiving requests from many clients other than A, and/or
+ forwarding requests to servers other than C, at the same time that it
+ is handling A's request.
+
+ Any party to the communication which is not acting as a tunnel may
+ employ an internal cache for handling requests. The effect of a cache
+ is that the request/response chain is shortened if one of the
+ participants along the chain has a cached response applicable to that
+ request. The following illustrates the resulting chain if B has a
+ cached copy of an earlier response from O (via C) for a request which
+ has not been cached by UA or A.
+
+ request chain ---------->
+ UA -----v----- A -----v----- B - - - - - - C - - - - - - O
+ <--------- response chain
+
+ Not all responses are usefully cacheable, and some requests may
+ contain modifiers which place special requirements on cache behavior.
+ HTTP requirements for cache behavior and cacheable responses are
+ defined in section 13.
+
+ In fact, there are a wide variety of architectures and configurations
+ of caches and proxies currently being experimented with or deployed
+ across the World Wide Web. These systems include national hierarchies
+ of proxy caches to save transoceanic bandwidth, systems that
+ broadcast or multicast cache entries, organizations that distribute
+ subsets of cached data via CD-ROM, and so on. HTTP systems are used
+ in corporate intranets over high-bandwidth links, and for access via
+ PDAs with low-power radio links and intermittent connectivity. The
+ goal of HTTP/1.1 is to support the wide diversity of configurations
+ already deployed while introducing protocol constructs that meet the
+ needs of those who build web applications that require high
+ reliability and, failing that, at least reliable indications of
+ failure.
+
+ HTTP communication usually takes place over TCP/IP connections. The
+ default port is TCP 80 [19], but other ports can be used. This does
+ not preclude HTTP from being implemented on top of any other protocol
+ on the Internet, or on other networks. HTTP only presumes a reliable
+ transport; any protocol that provides such guarantees can be used;
+ the mapping of the HTTP/1.1 request and response structures onto the
+ transport data units of the protocol in question is outside the scope
+ of this specification.
+
+ In HTTP/1.0, most implementations used a new connection for each
+ request/response exchange. In HTTP/1.1, a connection may be used for
+ one or more request/response exchanges, although connections may be
+ closed for a variety of reasons (see section 8.1).
+
+2 Notational Conventions and Generic Grammar
+
+2.1 Augmented BNF
+
+ All of the mechanisms specified in this document are described in
+ both prose and an augmented Backus-Naur Form (BNF) similar to that
+ used by <a href="http://firefly.troll.no/rfcs/rfc822.html">RFC 822</a> [9]. Implementors will need to be familiar with the
+ notation in order to understand this specification. The augmented BNF
+ includes the following constructs:
+
+ name = definition
+ The name of a rule is simply the name itself (without any
+ enclosing "<" and ">") and is separated from its definition by the
+ equal "=" character. White space is only significant in that
+ indentation of continuation lines is used to indicate a rule
+ definition that spans more than one line. Certain basic rules are
+ in uppercase, such as SP, LWS, HT, CRLF, DIGIT, ALPHA, etc. Angle
+ brackets are used within definitions whenever their presence will
+ facilitate discerning the use of rule names.
+
+ "literal"
+ Quotation marks surround literal text. Unless stated otherwise,
+ the text is case-insensitive.
+
+ rule1 | rule2
+ Elements separated by a bar ("|") are alternatives, e.g., "yes |
+ no" will accept yes or no.
+
+ (rule1 rule2)
+ Elements enclosed in parentheses are treated as a single element.
+ Thus, "(elem (foo | bar) elem)" allows the token sequences "elem
+ foo elem" and "elem bar elem".
+
+ *rule
+ The character "*" preceding an element indicates repetition. The
+ full form is "<n>*<m>element" indicating at least <n> and at most
+ <m> occurrences of element. Default values are 0 and infinity so
+ that "*(element)" allows any number, including zero; "1*element"
+ requires at least one; and "1*2element" allows one or two.
+
+ [rule]
+ Square brackets enclose optional elements; "[foo bar]" is
+ equivalent to "*1(foo bar)".
+
+ N rule
+ Specific repetition: "<n>(element)" is equivalent to
+ "<n>*<n>(element)"; that is, exactly <n> occurrences of (element).
+ Thus 2DIGIT is a 2-digit number, and 3ALPHA is a string of three
+ alphabetic characters.
+
+ #rule
+ A construct "#" is defined, similar to "*", for defining lists of
+ elements. The full form is "<n>#<m>element" indicating at least
+ <n> and at most <m> elements, each separated by one or more commas
+ (",") and OPTIONAL linear white space (LWS). This makes the usual
+ form of lists very easy; a rule such as
+ ( *LWS element *( *LWS "," *LWS element ))
+ can be shown as
+ 1#element
+ Wherever this construct is used, null elements are allowed, but do
+ not contribute to the count of elements present. That is,
+ "(element), , (element) " is permitted, but counts as only two
+ elements. Therefore, where at least one element is required, at
+ least one non-null element MUST be present. Default values are 0
+ and infinity so that "#element" allows any number, including zero;
+ "1#element" requires at least one; and "1#2element" allows one or
+ two.
+
+ ; comment
+ A semi-colon, set off some distance to the right of rule text,
+ starts a comment that continues to the end of line. This is a
+ simple way of including useful notes in parallel with the
+ specifications.
+
+ implied *LWS
+ The grammar described by this specification is word-based. Except
+ where noted otherwise, linear white space (LWS) can be included
+ between any two adjacent words (token or quoted-string), and
+ between adjacent words and separators, without changing the
+ interpretation of a field. At least one delimiter (LWS and/or
+
+ separators) MUST exist between any two tokens (for the definition
+ of "token" below), since they would otherwise be interpreted as a
+ single token.
+
+2.2 Basic Rules
+
+ The following rules are used throughout this specification to
+ describe basic parsing constructs. The US-ASCII coded character set
+ is defined by ANSI X3.4-1986 [21].
+
+ OCTET = <any 8-bit sequence of data>
+ CHAR = <any US-ASCII character (octets 0 - 127)>
+ UPALPHA = <any US-ASCII uppercase letter "A".."Z">
+ LOALPHA = <any US-ASCII lowercase letter "a".."z">
+ ALPHA = UPALPHA | LOALPHA
+ DIGIT = <any US-ASCII digit "0".."9">
+ CTL = <any US-ASCII control character
+ (octets 0 - 31) and DEL (127)>
+ CR = <US-ASCII CR, carriage return (13)>
+ LF = <US-ASCII LF, linefeed (10)>
+ SP = <US-ASCII SP, space (32)>
+ HT = <US-ASCII HT, horizontal-tab (9)>
+ <"> = <US-ASCII double-quote mark (34)>
+
+ HTTP/1.1 defines the sequence CR LF as the end-of-line marker for all
+ protocol elements except the entity-body (see appendix 19.3 for
+ tolerant applications). The end-of-line marker within an entity-body
+ is defined by its associated media type, as described in section 3.7.
+
+ CRLF = CR LF
+
+ HTTP/1.1 header field values can be folded onto multiple lines if the
+ continuation line begins with a space or horizontal tab. All linear
+ white space, including folding, has the same semantics as SP. A
+ recipient MAY replace any linear white space with a single SP before
+ interpreting the field value or forwarding the message downstream.
+
+ LWS = [CRLF] 1*( SP | HT )
+
+ The TEXT rule is only used for descriptive field contents and values
+ that are not intended to be interpreted by the message parser. Words
+ of *TEXT MAY contain characters from character sets other than ISO-
+ 8859-1 [22] only when encoded according to the rules of <a href="http://firefly.troll.no/rfcs/rfc2047.html">RFC 2047</a>
+ [14].
+
+ TEXT = <any OCTET except CTLs,
+ but including LWS>
+
+ A CRLF is allowed in the definition of TEXT only as part of a header
+ field continuation. It is expected that the folding LWS will be
+ replaced with a single SP before interpretation of the TEXT value.
+
+ Hexadecimal numeric characters are used in several protocol elements.
+
+ HEX = "A" | "B" | "C" | "D" | "E" | "F"
+ | "a" | "b" | "c" | "d" | "e" | "f" | DIGIT
+
+ Many HTTP/1.1 header field values consist of words separated by LWS
+ or special characters. These special characters MUST be in a quoted
+ string to be used within a parameter value (as defined in section
+ 3.6).
+
+ token = 1*<any CHAR except CTLs or separators>
+ separators = "(" | ")" | "<" | ">" | "@"
+ | "," | ";" | ":" | "\" | <">
+ | "/" | "[" | "]" | "?" | "="
+ | "{" | "}" | SP | HT
+
+ Comments can be included in some HTTP header fields by surrounding
+ the comment text with parentheses. Comments are only allowed in
+ fields containing "comment" as part of their field value definition.
+ In all other fields, parentheses are considered part of the field
+ value.
+
+ comment = "(" *( ctext | quoted-pair | comment ) ")"
+ ctext = <any TEXT excluding "(" and ")">
+
+ A string of text is parsed as a single word if it is quoted using
+ double-quote marks.
+
+ quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
+ qdtext = <any TEXT except <">>
+
+ The backslash character ("\") MAY be used as a single-character
+ quoting mechanism only within quoted-string and comment constructs.
+
+ quoted-pair = "\" CHAR
+
+3 Protocol Parameters
+
+3.1 HTTP Version
+
+ HTTP uses a "<major>.<minor>" numbering scheme to indicate versions
+ of the protocol. The protocol versioning policy is intended to allow
+ the sender to indicate the format of a message and its capacity for
+ understanding further HTTP communication, rather than the features
+ obtained via that communication. No change is made to the version
+ number for the addition of message components which do not affect
+ communication behavior or which only add to extensible field values.
+ The <minor> number is incremented when the changes made to the
+ protocol add features which do not change the general message parsing
+ algorithm, but which may add to the message semantics and imply
+ additional capabilities of the sender. The <major> number is
+ incremented when the format of a message within the protocol is
+ changed. See <a href="http://firefly.troll.no/rfcs/rfc2145.html">RFC 2145</a> [36] for a fuller explanation.
+
+ The version of an HTTP message is indicated by an HTTP-Version field
+ in the first line of the message.
+
+ HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT
+
+ Note that the major and minor numbers MUST be treated as separate
+ integers and that each MAY be incremented higher than a single digit.
+ Thus, HTTP/2.4 is a lower version than HTTP/2.13, which in turn is
+ lower than HTTP/12.3. Leading zeros MUST be ignored by recipients and
+ MUST NOT be sent.
+
+ An application that sends a request or response message that includes
+ HTTP-Version of "HTTP/1.1" MUST be at least conditionally compliant
+ with this specification. Applications that are at least conditionally
+ compliant with this specification SHOULD use an HTTP-Version of
+ "HTTP/1.1" in their messages, and MUST do so for any message that is
+ not compatible with HTTP/1.0. For more details on when to send
+ specific HTTP-Version values, see <a href="http://firefly.troll.no/rfcs/rfc2145.html">RFC 2145</a> [36].
+
+ The HTTP version of an application is the highest HTTP version for
+ which the application is at least conditionally compliant.
+
+ Proxy and gateway applications need to be careful when forwarding
+ messages in protocol versions different from that of the application.
+ Since the protocol version indicates the protocol capability of the
+ sender, a proxy/gateway MUST NOT send a message with a version
+ indicator which is greater than its actual version. If a higher
+ version request is received, the proxy/gateway MUST either downgrade
+ the request version, or respond with an error, or switch to tunnel
+ behavior.
+
+ Due to interoperability problems with HTTP/1.0 proxies discovered
+ since the publication of <a href="http://firefly.troll.no/rfcs/rfc2068.html">RFC 2068</a>[33], caching proxies MUST, gateways
+ MAY, and tunnels MUST NOT upgrade the request to the highest version
+ they support. The proxy/gateway's response to that request MUST be in
+ the same major version as the request.
+
+ Note: Converting between versions of HTTP may involve modification
+ of header fields required or forbidden by the versions involved.
+
+3.2 Uniform Resource Identifiers
+
+ URIs have been known by many names: WWW addresses, Universal Document
+ Identifiers, Universal Resource Identifiers [3], and finally the
+ combination of Uniform Resource Locators (URL) [4] and Names (URN)
+ [20]. As far as HTTP is concerned, Uniform Resource Identifiers are
+ simply formatted strings which identify--via name, location, or any
+ other characteristic--a resource.
+
+3.2.1 General Syntax
+
+ URIs in HTTP can be represented in absolute form or relative to some
+ known base URI [11], depending upon the context of their use. The two
+ forms are differentiated by the fact that absolute URIs always begin
+ with a scheme name followed by a colon. For definitive information on
+ URL syntax and semantics, see "Uniform Resource Identifiers (URI):
+ Generic Syntax and Semantics," <a href="http://firefly.troll.no/rfcs/rfc2396.html">RFC 2396</a> [42] (which replaces RFCs
+ 1738 [4] and <a href="http://firefly.troll.no/rfcs/rfc1808.html">RFC 1808</a> [11]). This specification adopts the
+ definitions of "URI-reference", "absoluteURI", "relativeURI", "port",
+ "host","abs_path", "rel_path", and "authority" from that
+ specification.
+
+ The HTTP protocol does not place any a priori limit on the length of
+ a URI. Servers MUST be able to handle the URI of any resource they
+ serve, and SHOULD be able to handle URIs of unbounded length if they
+ provide GET-based forms that could generate such URIs. A server
+ SHOULD return 414 (Request-URI Too Long) status if a URI is longer
+ than the server can handle (see section 10.4.15).
+
+ Note: Servers ought to be cautious about depending on URI lengths
+ above 255 bytes, because some older client or proxy
+ implementations might not properly support these lengths.
+
+3.2.2 http URL
+
+ The "http" scheme is used to locate network resources via the HTTP
+ protocol. This section defines the scheme-specific syntax and
+ semantics for http URLs.
+
+ http_URL = "http:" "//" host [ ":" port ] [ abs_path [ "?" query ]]
+
+ If the port is empty or not given, port 80 is assumed. The semantics
+ are that the identified resource is located at the server listening
+ for TCP connections on that port of that host, and the Request-URI
+ for the resource is abs_path (section 5.1.2). The use of IP addresses
+ in URLs SHOULD be avoided whenever possible (see <a href="http://firefly.troll.no/rfcs/rfc1900.html">RFC 1900</a> [24]). If
+ the abs_path is not present in the URL, it MUST be given as "/" when
+ used as a Request-URI for a resource (section 5.1.2). If a proxy
+ receives a host name which is not a fully qualified domain name, it
+ MAY add its domain to the host name it received. If a proxy receives
+ a fully qualified domain name, the proxy MUST NOT change the host
+ name.
+
+3.2.3 URI Comparison
+
+ When comparing two URIs to decide if they match or not, a client
+ SHOULD use a case-sensitive octet-by-octet comparison of the entire
+ URIs, with these exceptions:
+
+ - A port that is empty or not given is equivalent to the default
+ port for that URI-reference;
+
+ - Comparisons of host names MUST be case-insensitive;
+
+ - Comparisons of scheme names MUST be case-insensitive;
+
+ - An empty abs_path is equivalent to an abs_path of "/".
+
+ Characters other than those in the "reserved" and "unsafe" sets (see
+ <a href="http://firefly.troll.no/rfcs/rfc2396.html">RFC 2396</a> [42]) are equivalent to their ""%" HEX HEX" encoding.
+
+ For example, the following three URIs are equivalent:
+
+ <a href="http://abc.com/%7Esmith/home.html">http://abc.com:80/~smith/home.html</a>
+ <a href="http://abc.com/%7Esmith/home.html">http://ABC.com/%7Esmith/home.html</a>
+ <a href="http://firefly.troll.no/%3CA%20HREF=" ftp:="" abc.com="" %7esmith="" home.html="">/ABC.com:/%7esmith/home.html</a>">http:/<a href="ftp://abc.com/%7esmith/home.html%3C/A%3E">/ABC.com:/%7esmith/home.html</a>
+
+3.3 Date/Time Formats
+
+3.3.1 Full Date
+
+ HTTP applications have historically allowed three different formats
+ for the representation of date/time stamps:
+
+ Sun, 06 Nov 1994 08:49:37 GMT ; <a href="http://firefly.troll.no/rfcs/rfc822.html">RFC 822</a>, updated by <a href="http://firefly.troll.no/rfcs/rfc1123.html">RFC 1123</a>
+ Sunday, 06-Nov-94 08:49:37 GMT ; <a href="http://firefly.troll.no/rfcs/rfc850.html">RFC 850</a>, obsoleted by <a href="http://firefly.troll.no/rfcs/rfc1036.html">RFC 1036</a>
+ Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
+
+ The first format is preferred as an Internet standard and represents
+ a fixed-length subset of that defined by <a href="http://firefly.troll.no/rfcs/rfc1123.html">RFC 1123</a> [8] (an update to
+ <a href="http://firefly.troll.no/rfcs/rfc822.html">RFC 822</a> [9]). The second format is in common use, but is based on the
+ obsolete <a href="http://firefly.troll.no/rfcs/rfc850.html">RFC 850</a> [12] date format and lacks a four-digit year.
+ HTTP/1.1 clients and servers that parse the date value MUST accept
+ all three formats (for compatibility with HTTP/1.0), though they MUST
+ only generate the <a href="http://firefly.troll.no/rfcs/rfc1123.html">RFC 1123</a> format for representing HTTP-date values
+ in header fields. See section 19.3 for further information.
+
+ Note: Recipients of date values are encouraged to be robust in
+ accepting date values that may have been sent by non-HTTP
+ applications, as is sometimes the case when retrieving or posting
+ messages via proxies/gateways to SMTP or NNTP.
+
+ All HTTP date/time stamps MUST be represented in Greenwich Mean Time
+ (GMT), without exception. For the purposes of HTTP, GMT is exactly
+ equal to UTC (Coordinated Universal Time). This is indicated in the
+ first two formats by the inclusion of "GMT" as the three-letter
+ abbreviation for time zone, and MUST be assumed when reading the
+ asctime format. HTTP-date is case sensitive and MUST NOT include
+ additional LWS beyond that specifically included as SP in the
+ grammar.
+
+ HTTP-date = <a href="http://firefly.troll.no/rfcs/rfc1123.html">rfc1123</a>-date | <a href="http://firefly.troll.no/rfcs/rfc850.html">rfc850</a>-date | asctime-date
+ <a href="http://firefly.troll.no/rfcs/rfc1123.html">rfc1123</a>-date = wkday "," SP date1 SP time SP "GMT"
+ <a href="http://firefly.troll.no/rfcs/rfc850.html">rfc850</a>-date = weekday "," SP date2 SP time SP "GMT"
+ asctime-date = wkday SP date3 SP time SP 4DIGIT
+ date1 = 2DIGIT SP month SP 4DIGIT
+ ; day month year (e.g., 02 Jun 1982)
+ date2 = 2DIGIT "-" month "-" 2DIGIT
+ ; day-month-year (e.g., 02-Jun-82)
+ date3 = month SP ( 2DIGIT | ( SP 1DIGIT ))
+ ; month day (e.g., Jun 2)
+ time = 2DIGIT ":" 2DIGIT ":" 2DIGIT
+ ; 00:00:00 - 23:59:59
+ wkday = "Mon" | "Tue" | "Wed"
+ | "Thu" | "Fri" | "Sat" | "Sun"
+ weekday = "Monday" | "Tuesday" | "Wednesday"
+ | "Thursday" | "Friday" | "Saturday" | "Sunday"
+ month = "Jan" | "Feb" | "Mar" | "Apr"
+ | "May" | "Jun" | "Jul" | "Aug"
+ | "Sep" | "Oct" | "Nov" | "Dec"
+
+ Note: HTTP requirements for the date/time stamp format apply only
+ to their usage within the protocol stream. Clients and servers are
+ not required to use these formats for user presentation, request
+ logging, etc.
+
+3.3.2 Delta Seconds
+
+ Some HTTP header fields allow a time value to be specified as an
+ integer number of seconds, represented in decimal, after the time
+ that the message was received.
+
+ delta-seconds = 1*DIGIT
+
+3.4 Character Sets
+
+ HTTP uses the same definition of the term "character set" as that
+ described for MIME:
+
+ The term "character set" is used in this document to refer to a
+ method used with one or more tables to convert a sequence of octets
+ into a sequence of characters. Note that unconditional conversion in
+ the other direction is not required, in that not all characters may
+ be available in a given character set and a character set may provide
+ more than one sequence of octets to represent a particular character.
+ This definition is intended to allow various kinds of character
+ encoding, from simple single-table mappings such as US-ASCII to
+ complex table switching methods such as those that use ISO-2022's
+ techniques. However, the definition associated with a MIME character
+ set name MUST fully specify the mapping to be performed from octets
+ to characters. In particular, use of external profiling information
+ to determine the exact mapping is not permitted.
+
+ Note: This use of the term "character set" is more commonly
+ referred to as a "character encoding." However, since HTTP and
+ MIME share the same registry, it is important that the terminology
+ also be shared.
+
+ HTTP character sets are identified by case-insensitive tokens. The
+ complete set of tokens is defined by the IANA Character Set registry
+ [19].
+
+ charset = token
+
+ Although HTTP allows an arbitrary token to be used as a charset
+ value, any token that has a predefined value within the IANA
+ Character Set registry [19] MUST represent the character set defined
+ by that registry. Applications SHOULD limit their use of character
+ sets to those defined by the IANA registry.
+
+ Implementors should be aware of IETF character set requirements [38]
+ [41].
+
+3.4.1 Missing Charset
+
+ Some HTTP/1.0 software has interpreted a Content-Type header without
+ charset parameter incorrectly to mean "recipient should guess."
+ Senders wishing to defeat this behavior MAY include a charset
+ parameter even when the charset is ISO-8859-1 and SHOULD do so when
+ it is known that it will not confuse the recipient.
+
+ Unfortunately, some older HTTP/1.0 clients did not deal properly with
+ an explicit charset parameter. HTTP/1.1 recipients MUST respect the
+ charset label provided by the sender; and those user agents that have
+ a provision to "guess" a charset MUST use the charset from the
+
+ content-type field if they support that charset, rather than the
+ recipient's preference, when initially displaying a document. See
+ section 3.7.1.
+
+3.5 Content Codings
+
+ Content coding values indicate an encoding transformation that has
+ been or can be applied to an entity. Content codings are primarily
+ used to allow a document to be compressed or otherwise usefully
+ transformed without losing the identity of its underlying media type
+ and without loss of information. Frequently, the entity is stored in
+ coded form, transmitted directly, and only decoded by the recipient.
+
+ content-coding = token
+
+ All content-coding values are case-insensitive. HTTP/1.1 uses
+ content-coding values in the Accept-Encoding (section 14.3) and
+ Content-Encoding (section 14.11) header fields. Although the value
+ describes the content-coding, what is more important is that it
+ indicates what decoding mechanism will be required to remove the
+ encoding.
+
+ The Internet Assigned Numbers Authority (IANA) acts as a registry for
+ content-coding value tokens. Initially, the registry contains the
+ following tokens:
+
+ gzip An encoding format produced by the file compression program
+ "gzip" (GNU zip) as described in <a href="http://firefly.troll.no/rfcs/rfc1952.html">RFC 1952</a> [25]. This format is a
+ Lempel-Ziv coding (LZ77) with a 32 bit CRC.
+
+ compress
+ The encoding format produced by the common UNIX file compression
+ program "compress". This format is an adaptive Lempel-Ziv-Welch
+ coding (LZW).
+
+ Use of program names for the identification of encoding formats
+ is not desirable and is discouraged for future encodings. Their
+ use here is representative of historical practice, not good
+ design. For compatibility with previous implementations of HTTP,
+ applications SHOULD consider "x-gzip" and "x-compress" to be
+ equivalent to "gzip" and "compress" respectively.
+
+ deflate
+ The "zlib" format defined in <a href="http://firefly.troll.no/rfcs/rfc1950.html">RFC 1950</a> [31] in combination with
+ the "deflate" compression mechanism described in <a href="http://firefly.troll.no/rfcs/rfc1951.html">RFC 1951</a> [29].
+
+ identity
+ The default (identity) encoding; the use of no transformation
+ whatsoever. This content-coding is used only in the Accept-
+ Encoding header, and SHOULD NOT be used in the Content-Encoding
+ header.
+
+ New content-coding value tokens SHOULD be registered; to allow
+ interoperability between clients and servers, specifications of the
+ content coding algorithms needed to implement a new value SHOULD be
+ publicly available and adequate for independent implementation, and
+ conform to the purpose of content coding defined in this section.
+
+3.6 Transfer Codings
+
+ Transfer-coding values are used to indicate an encoding
+ transformation that has been, can be, or may need to be applied to an
+ entity-body in order to ensure "safe transport" through the network.
+ This differs from a content coding in that the transfer-coding is a
+ property of the message, not of the original entity.
+
+ transfer-coding = "chunked" | transfer-extension
+ transfer-extension = token *( ";" parameter )
+
+ Parameters are in the form of attribute/value pairs.
+
+ parameter = attribute "=" value
+ attribute = token
+ value = token | quoted-string
+
+ All transfer-coding values are case-insensitive. HTTP/1.1 uses
+ transfer-coding values in the TE header field (section 14.39) and in
+ the Transfer-Encoding header field (section 14.41).
+
+ Whenever a transfer-coding is applied to a message-body, the set of
+ transfer-codings MUST include "chunked", unless the message is
+ terminated by closing the connection. When the "chunked" transfer-
+ coding is used, it MUST be the last transfer-coding applied to the
+ message-body. The "chunked" transfer-coding MUST NOT be applied more
+ than once to a message-body. These rules allow the recipient to
+ determine the transfer-length of the message (section 4.4).
+
+ Transfer-codings are analogous to the Content-Transfer-Encoding
+ values of MIME [7], which were designed to enable safe transport of
+ binary data over a 7-bit transport service. However, safe transport
+ has a different focus for an 8bit-clean transfer protocol. In HTTP,
+ the only unsafe characteristic of message-bodies is the difficulty in
+ determining the exact body length (section 7.2.2), or the desire to
+ encrypt data over a shared transport.
+
+ The Internet Assigned Numbers Authority (IANA) acts as a registry for
+ transfer-coding value tokens. Initially, the registry contains the
+ following tokens: "chunked" (section 3.6.1), "identity" (section
+ 3.6.2), "gzip" (section 3.5), "compress" (section 3.5), and "deflate"
+ (section 3.5).
+
+ New transfer-coding value tokens SHOULD be registered in the same way
+ as new content-coding value tokens (section 3.5).
+
+ A server which receives an entity-body with a transfer-coding it does
+ not understand SHOULD return 501 (Unimplemented), and close the
+ connection. A server MUST NOT send transfer-codings to an HTTP/1.0
+ client.
+
+3.6.1 Chunked Transfer Coding
+
+ The chunked encoding modifies the body of a message in order to
+ transfer it as a series of chunks, each with its own size indicator,
+ followed by an OPTIONAL trailer containing entity-header fields. This
+ allows dynamically produced content to be transferred along with the
+ information necessary for the recipient to verify that it has
+ received the full message.
+
+ Chunked-Body = *chunk
+ last-chunk
+ trailer
+ CRLF
+
+ chunk = chunk-size [ chunk-extension ] CRLF
+ chunk-data CRLF
+ chunk-size = 1*HEX
+ last-chunk = 1*("0") [ chunk-extension ] CRLF
+
+ chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
+ chunk-ext-name = token
+ chunk-ext-val = token | quoted-string
+ chunk-data = chunk-size(OCTET)
+ trailer = *(entity-header CRLF)
+
+ The chunk-size field is a string of hex digits indicating the size of
+ the chunk. The chunked encoding is ended by any chunk whose size is
+ zero, followed by the trailer, which is terminated by an empty line.
+
+ The trailer allows the sender to include additional HTTP header
+ fields at the end of the message. The Trailer header field can be
+ used to indicate which header fields are included in a trailer (see
+ section 14.40).
+
+ A server using chunked transfer-coding in a response MUST NOT use the
+ trailer for any header fields unless at least one of the following is
+ true:
+
+ a)the request included a TE header field that indicates "trailers" is
+ acceptable in the transfer-coding of the response, as described in
+ section 14.39; or,
+
+ b)the server is the origin server for the response, the trailer
+ fields consist entirely of optional metadata, and the recipient
+ could use the message (in a manner acceptable to the origin server)
+ without receiving this metadata. In other words, the origin server
+ is willing to accept the possibility that the trailer fields might
+ be silently discarded along the path to the client.
+
+ This requirement prevents an interoperability failure when the
+ message is being received by an HTTP/1.1 (or later) proxy and
+ forwarded to an HTTP/1.0 recipient. It avoids a situation where
+ compliance with the protocol would have necessitated a possibly
+ infinite buffer on the proxy.
+
+ An example process for decoding a Chunked-Body is presented in
+ appendix 19.4.6.
+
+ All HTTP/1.1 applications MUST be able to receive and decode the
+ "chunked" transfer-coding, and MUST ignore chunk-extension extensions
+ they do not understand.
+
+3.7 Media Types
+
+ HTTP uses Internet Media Types [17] in the Content-Type (section
+ 14.17) and Accept (section 14.1) header fields in order to provide
+ open and extensible data typing and type negotiation.
+
+ media-type = type "/" subtype *( ";" parameter )
+ type = token
+ subtype = token
+
+ Parameters MAY follow the type/subtype in the form of attribute/value
+ pairs (as defined in section 3.6).
+
+ The type, subtype, and parameter attribute names are case-
+ insensitive. Parameter values might or might not be case-sensitive,
+ depending on the semantics of the parameter name. Linear white space
+ (LWS) MUST NOT be used between the type and subtype, nor between an
+ attribute and its value. The presence or absence of a parameter might
+ be significant to the processing of a media-type, depending on its
+ definition within the media type registry.
+
+ Note that some older HTTP applications do not recognize media type
+ parameters. When sending data to older HTTP applications,
+ implementations SHOULD only use media type parameters when they are
+ required by that type/subtype definition.
+
+ Media-type values are registered with the Internet Assigned Number
+ Authority (IANA [19]). The media type registration process is
+ outlined in <a href="http://firefly.troll.no/rfcs/rfc1590.html">RFC 1590</a> [17]. Use of non-registered media types is
+ discouraged.
+
+3.7.1 Canonicalization and Text Defaults
+
+ Internet media types are registered with a canonical form. An
+ entity-body transferred via HTTP messages MUST be represented in the
+ appropriate canonical form prior to its transmission except for
+ "text" types, as defined in the next paragraph.
+
+ When in canonical form, media subtypes of the "text" type use CRLF as
+ the text line break. HTTP relaxes this requirement and allows the
+ transport of text media with plain CR or LF alone representing a line
+ break when it is done consistently for an entire entity-body. HTTP
+ applications MUST accept CRLF, bare CR, and bare LF as being
+ representative of a line break in text media received via HTTP. In
+ addition, if the text is represented in a character set that does not
+ use octets 13 and 10 for CR and LF respectively, as is the case for
+ some multi-byte character sets, HTTP allows the use of whatever octet
+ sequences are defined by that character set to represent the
+ equivalent of CR and LF for line breaks. This flexibility regarding
+ line breaks applies only to text media in the entity-body; a bare CR
+ or LF MUST NOT be substituted for CRLF within any of the HTTP control
+ structures (such as header fields and multipart boundaries).
+
+ If an entity-body is encoded with a content-coding, the underlying
+ data MUST be in a form defined above prior to being encoded.
+
+ The "charset" parameter is used with some media types to define the
+ character set (section 3.4) of the data. When no explicit charset
+ parameter is provided by the sender, media subtypes of the "text"
+ type are defined to have a default charset value of "ISO-8859-1" when
+ received via HTTP. Data in character sets other than "ISO-8859-1" or
+ its subsets MUST be labeled with an appropriate charset value. See
+ section 3.4.1 for compatibility problems.
+
+3.7.2 Multipart Types
+
+ MIME provides for a number of "multipart" types -- encapsulations of
+ one or more entities within a single message-body. All multipart
+ types share a common syntax, as defined in section 5.1.1 of <a href="http://firefly.troll.no/rfcs/rfc2046.html">RFC 2046</a>
+
+ [40], and MUST include a boundary parameter as part of the media type
+ value. The message body is itself a protocol element and MUST
+ therefore use only CRLF to represent line breaks between body-parts.
+ Unlike in <a href="http://firefly.troll.no/rfcs/rfc2046.html">RFC 2046</a>, the epilogue of any multipart message MUST be
+ empty; HTTP applications MUST NOT transmit the epilogue (even if the
+ original multipart contains an epilogue). These restrictions exist in
+ order to preserve the self-delimiting nature of a multipart message-
+ body, wherein the "end" of the message-body is indicated by the
+ ending multipart boundary.
+
+ In general, HTTP treats a multipart message-body no differently than
+ any other media type: strictly as payload. The one exception is the
+ "multipart/byteranges" type (appendix 19.2) when it appears in a 206
+ (Partial Content) response, which will be interpreted by some HTTP
+ caching mechanisms as described in sections 13.5.4 and 14.16. In all
+ other cases, an HTTP user agent SHOULD follow the same or similar
+ behavior as a MIME user agent would upon receipt of a multipart type.
+ The MIME header fields within each body-part of a multipart message-
+ body do not have any significance to HTTP beyond that defined by
+ their MIME semantics.
+
+ In general, an HTTP user agent SHOULD follow the same or similar
+ behavior as a MIME user agent would upon receipt of a multipart type.
+ If an application receives an unrecognized multipart subtype, the
+ application MUST treat it as being equivalent to "multipart/mixed".
+
+ Note: The "multipart/form-data" type has been specifically defined
+ for carrying form data suitable for processing via the POST
+ request method, as described in <a href="http://firefly.troll.no/rfcs/rfc1867.html">RFC 1867</a> [15].
+
+3.8 Product Tokens
+
+ Product tokens are used to allow communicating applications to
+ identify themselves by software name and version. Most fields using
+ product tokens also allow sub-products which form a significant part
+ of the application to be listed, separated by white space. By
+ convention, the products are listed in order of their significance
+ for identifying the application.
+
+ product = token ["/" product-version]
+ product-version = token
+
+ Examples:
+
+ User-Agent: CERN-LineMode/2.15 libwww/2.17b3
+ Server: Apache/0.8.4
+
+ Product tokens SHOULD be short and to the point. They MUST NOT be
+ used for advertising or other non-essential information. Although any
+ token character MAY appear in a product-version, this token SHOULD
+ only be used for a version identifier (i.e., successive versions of
+ the same product SHOULD only differ in the product-version portion of
+ the product value).
+
+3.9 Quality Values
+
+ HTTP content negotiation (section 12) uses short "floating point"
+ numbers to indicate the relative importance ("weight") of various
+ negotiable parameters. A weight is normalized to a real number in
+ the range 0 through 1, where 0 is the minimum and 1 the maximum
+ value. If a parameter has a quality value of 0, then content with
+ this parameter is `not acceptable' for the client. HTTP/1.1
+ applications MUST NOT generate more than three digits after the
+ decimal point. User configuration of these values SHOULD also be
+ limited in this fashion.
+
+ qvalue = ( "0" [ "." 0*3DIGIT ] )
+ | ( "1" [ "." 0*3("0") ] )
+
+ "Quality values" is a misnomer, since these values merely represent
+ relative degradation in desired quality.
+
+3.10 Language Tags
+
+ A language tag identifies a natural language spoken, written, or
+ otherwise conveyed by human beings for communication of information
+ to other human beings. Computer languages are explicitly excluded.
+ HTTP uses language tags within the Accept-Language and Content-
+ Language fields.
+
+ The syntax and registry of HTTP language tags is the same as that
+ defined by <a href="http://firefly.troll.no/rfcs/rfc1766.html">RFC 1766</a> [1]. In summary, a language tag is composed of 1
+ or more parts: A primary language tag and a possibly empty series of
+ subtags:
+
+ language-tag = primary-tag *( "-" subtag )
+ primary-tag = 1*8ALPHA
+ subtag = 1*8ALPHA
+
+ White space is not allowed within the tag and all tags are case-
+ insensitive. The name space of language tags is administered by the
+ IANA. Example tags include:
+
+ en, en-US, en-cockney, i-cherokee, x-pig-latin
+
+ where any two-letter primary-tag is an ISO-639 language abbreviation
+ and any two-letter initial subtag is an ISO-3166 country code. (The
+ last three tags above are not registered tags; all but the last are
+ examples of tags which could be registered in future.)
+
+3.11 Entity Tags
+
+ Entity tags are used for comparing two or more entities from the same
+ requested resource. HTTP/1.1 uses entity tags in the ETag (section
+ 14.19), If-Match (section 14.24), If-None-Match (section 14.26), and
+ If-Range (section 14.27) header fields. The definition of how they
+ are used and compared as cache validators is in section 13.3.3. An
+ entity tag consists of an opaque quoted string, possibly prefixed by
+ a weakness indicator.
+
+ entity-tag = [ weak ] opaque-tag
+ weak = "W/"
+ opaque-tag = quoted-string
+
+ A "strong entity tag" MAY be shared by two entities of a resource
+ only if they are equivalent by octet equality.
+
+ A "weak entity tag," indicated by the "W/" prefix, MAY be shared by
+ two entities of a resource only if the entities are equivalent and
+ could be substituted for each other with no significant change in
+ semantics. A weak entity tag can only be used for weak comparison.
+
+ An entity tag MUST be unique across all versions of all entities
+ associated with a particular resource. A given entity tag value MAY
+ be used for entities obtained by requests on different URIs. The use
+ of the same entity tag value in conjunction with entities obtained by
+ requests on different URIs does not imply the equivalence of those
+ entities.
+
+3.12 Range Units
+
+ HTTP/1.1 allows a client to request that only part (a range of) the
+ response entity be included within the response. HTTP/1.1 uses range
+ units in the Range (section 14.35) and Content-Range (section 14.16)
+ header fields. An entity can be broken down into subranges according
+ to various structural units.
+
+ range-unit = bytes-unit | other-range-unit
+ bytes-unit = "bytes"
+ other-range-unit = token
+
+ The only range unit defined by HTTP/1.1 is "bytes". HTTP/1.1
+ implementations MAY ignore ranges specified using other units.
+
+ HTTP/1.1 has been designed to allow implementations of applications
+ that do not depend on knowledge of ranges.
+
+4 HTTP Message
+
+4.1 Message Types
+
+ HTTP messages consist of requests from client to server and responses
+ from server to client.
+
+ HTTP-message = Request | Response ; HTTP/1.1 messages
+
+ Request (section 5) and Response (section 6) messages use the generic
+ message format of <a href="http://firefly.troll.no/rfcs/rfc822.html">RFC 822</a> [9] for transferring entities (the payload
+ of the message). Both types of message consist of a start-line, zero
+ or more header fields (also known as "headers"), an empty line (i.e.,
+ a line with nothing preceding the CRLF) indicating the end of the
+ header fields, and possibly a message-body.
+
+ generic-message = start-line
+ *(message-header CRLF)
+ CRLF
+ [ message-body ]
+ start-line = Request-Line | Status-Line
+
+ In the interest of robustness, servers SHOULD ignore any empty
+ line(s) received where a Request-Line is expected. In other words, if
+ the server is reading the protocol stream at the beginning of a
+ message and receives a CRLF first, it should ignore the CRLF.
+
+ Certain buggy HTTP/1.0 client implementations generate extra CRLF's
+ after a POST request. To restate what is explicitly forbidden by the
+ BNF, an HTTP/1.1 client MUST NOT preface or follow a request with an
+ extra CRLF.
+
+4.2 Message Headers
+
+ HTTP header fields, which include general-header (section 4.5),
+ request-header (section 5.3), response-header (section 6.2), and
+ entity-header (section 7.1) fields, follow the same generic format as
+ that given in Section 3.1 of <a href="http://firefly.troll.no/rfcs/rfc822.html">RFC 822</a> [9]. Each header field consists
+ of a name followed by a colon (":") and the field value. Field names
+ are case-insensitive. The field value MAY be preceded by any amount
+ of LWS, though a single SP is preferred. Header fields can be
+ extended over multiple lines by preceding each extra line with at
+ least one SP or HT. Applications ought to follow "common form", where
+ one is known or indicated, when generating HTTP constructs, since
+ there might exist some implementations that fail to accept anything
+
+ beyond the common forms.
+
+ message-header = field-name ":" [ field-value ]
+ field-name = token
+ field-value = *( field-content | LWS )
+ field-content = <the OCTETs making up the field-value
+ and consisting of either *TEXT or combinations
+ of token, separators, and quoted-string>
+
+ The field-content does not include any leading or trailing LWS:
+ linear white space occurring before the first non-whitespace
+ character of the field-value or after the last non-whitespace
+ character of the field-value. Such leading or trailing LWS MAY be
+ removed without changing the semantics of the field value. Any LWS
+ that occurs between field-content MAY be replaced with a single SP
+ before interpreting the field value or forwarding the message
+ downstream.
+
+ The order in which header fields with differing field names are
+ received is not significant. However, it is "good practice" to send
+ general-header fields first, followed by request-header or response-
+ header fields, and ending with the entity-header fields.
+
+ Multiple message-header fields with the same field-name MAY be
+ present in a message if and only if the entire field-value for that
+ header field is defined as a comma-separated list [i.e., #(values)].
+ It MUST be possible to combine the multiple header fields into one
+ "field-name: field-value" pair, without changing the semantics of the
+ message, by appending each subsequent field-value to the first, each
+ separated by a comma. The order in which header fields with the same
+ field-name are received is therefore significant to the
+ interpretation of the combined field value, and thus a proxy MUST NOT
+ change the order of these field values when a message is forwarded.
+
+4.3 Message Body
+
+ The message-body (if any) of an HTTP message is used to carry the
+ entity-body associated with the request or response. The message-body
+ differs from the entity-body only when a transfer-coding has been
+ applied, as indicated by the Transfer-Encoding header field (section
+ 14.41).
+
+ message-body = entity-body
+ | <entity-body encoded as per Transfer-Encoding>
+
+ Transfer-Encoding MUST be used to indicate any transfer-codings
+ applied by an application to ensure safe and proper transfer of the
+ message. Transfer-Encoding is a property of the message, not of the
+
+ entity, and thus MAY be added or removed by any application along the
+ request/response chain. (However, section 3.6 places restrictions on
+ when certain transfer-codings may be used.)
+
+ The rules for when a message-body is allowed in a message differ for
+ requests and responses.
+
+ The presence of a message-body in a request is signaled by the
+ inclusion of a Content-Length or Transfer-Encoding header field in
+ the request's message-headers. A message-body MUST NOT be included in
+ a request if the specification of the request method (section 5.1.1)
+ does not allow sending an entity-body in requests. A server SHOULD
+ read and forward a message-body on any request; if the request method
+ does not include defined semantics for an entity-body, then the
+ message-body SHOULD be ignored when handling the request.
+
+ For response messages, whether or not a message-body is included with
+ a message is dependent on both the request method and the response
+ status code (section 6.1.1). All responses to the HEAD request method
+ MUST NOT include a message-body, even though the presence of entity-
+ header fields might lead one to believe they do. All 1xx
+ (informational), 204 (no content), and 304 (not modified) responses
+ MUST NOT include a message-body. All other responses do include a
+ message-body, although it MAY be of zero length.
+
+4.4 Message Length
+
+ The transfer-length of a message is the length of the message-body as
+ it appears in the message; that is, after any transfer-codings have
+ been applied. When a message-body is included with a message, the
+ transfer-length of that body is determined by one of the following
+ (in order of precedence):
+
+ 1.Any response message which "MUST NOT" include a message-body (such
+ as the 1xx, 204, and 304 responses and any response to a HEAD
+ request) is always terminated by the first empty line after the
+ header fields, regardless of the entity-header fields present in
+ the message.
+
+ 2.If a Transfer-Encoding header field (section 14.41) is present and
+ has any value other than "identity", then the transfer-length is
+ defined by use of the "chunked" transfer-coding (section 3.6),
+ unless the message is terminated by closing the connection.
+
+ 3.If a Content-Length header field (section 14.13) is present, its
+ decimal value in OCTETs represents both the entity-length and the
+ transfer-length. The Content-Length header field MUST NOT be sent
+ if these two lengths are different (i.e., if a Transfer-Encoding
+
+ header field is present). If a message is received with both a
+ Transfer-Encoding header field and a Content-Length header field,
+ the latter MUST be ignored.
+
+ 4.If the message uses the media type "multipart/byteranges", and the
+ ransfer-length is not otherwise specified, then this self-
+ elimiting media type defines the transfer-length. This media type
+ UST NOT be used unless the sender knows that the recipient can arse
+ it; the presence in a request of a Range header with ultiple byte-
+ range specifiers from a 1.1 client implies that the lient can parse
+ multipart/byteranges responses.
+
+ A range header might be forwarded by a 1.0 proxy that does not
+ understand multipart/byteranges; in this case the server MUST
+ delimit the message using methods defined in items 1,3 or 5 of
+ this section.
+
+ 5.By the server closing the connection. (Closing the connection
+ cannot be used to indicate the end of a request body, since that
+ would leave no possibility for the server to send back a response.)
+
+ For compatibility with HTTP/1.0 applications, HTTP/1.1 requests
+ containing a message-body MUST include a valid Content-Length header
+ field unless the server is known to be HTTP/1.1 compliant. If a
+ request contains a message-body and a Content-Length is not given,
+ the server SHOULD respond with 400 (bad request) if it cannot
+ determine the length of the message, or with 411 (length required) if
+ it wishes to insist on receiving a valid Content-Length.
+
+ All HTTP/1.1 applications that receive entities MUST accept the
+ "chunked" transfer-coding (section 3.6), thus allowing this mechanism
+ to be used for messages when the message length cannot be determined
+ in advance.
+
+ Messages MUST NOT include both a Content-Length header field and a
+ non-identity transfer-coding. If the message does include a non-
+ identity transfer-coding, the Content-Length MUST be ignored.
+
+ When a Content-Length is given in a message where a message-body is
+ allowed, its field value MUST exactly match the number of OCTETs in
+ the message-body. HTTP/1.1 user agents MUST notify the user when an
+ invalid length is received and detected.
+
+4.5 General Header Fields
+
+ There are a few header fields which have general applicability for
+ both request and response messages, but which do not apply to the
+ entity being transferred. These header fields apply only to the
+
+ message being transmitted.
+
+ general-header = Cache-Control ; Section 14.9
+ | Connection ; Section 14.10
+ | Date ; Section 14.18
+ | Pragma ; Section 14.32
+ | Trailer ; Section 14.40
+ | Transfer-Encoding ; Section 14.41
+ | Upgrade ; Section 14.42
+ | Via ; Section 14.45
+ | Warning ; Section 14.46
+
+ General-header field names can be extended reliably only in
+ combination with a change in the protocol version. However, new or
+ experimental header fields may be given the semantics of general
+ header fields if all parties in the communication recognize them to
+ be general-header fields. Unrecognized header fields are treated as
+ entity-header fields.
+
+5 Request
+
+ A request message from a client to a server includes, within the
+ first line of that message, the method to be applied to the resource,
+ the identifier of the resource, and the protocol version in use.
+
+ Request = Request-Line ; Section 5.1
+ *(( general-header ; Section 4.5
+ | request-header ; Section 5.3
+ | entity-header ) CRLF) ; Section 7.1
+ CRLF
+ [ message-body ] ; Section 4.3
+
+5.1 Request-Line
+
+ The Request-Line begins with a method token, followed by the
+ Request-URI and the protocol version, and ending with CRLF. The
+ elements are separated by SP characters. No CR or LF is allowed
+ except in the final CRLF sequence.
+
+ Request-Line = Method SP Request-URI SP HTTP-Version CRLF
+
+5.1.1 Method
+
+ The Method token indicates the method to be performed on the
+ resource identified by the Request-URI. The method is case-sensitive.
+
+ Method = "OPTIONS" ; Section 9.2
+ | "GET" ; Section 9.3
+ | "HEAD" ; Section 9.4
+ | "POST" ; Section 9.5
+ | "PUT" ; Section 9.6
+ | "DELETE" ; Section 9.7
+ | "TRACE" ; Section 9.8
+ | "CONNECT" ; Section 9.9
+ | extension-method
+ extension-method = token
+
+ The list of methods allowed by a resource can be specified in an
+ Allow header field (section 14.7). The return code of the response
+ always notifies the client whether a method is currently allowed on a
+ resource, since the set of allowed methods can change dynamically. An
+ origin server SHOULD return the status code 405 (Method Not Allowed)
+ if the method is known by the origin server but not allowed for the
+ requested resource, and 501 (Not Implemented) if the method is
+ unrecognized or not implemented by the origin server. The methods GET
+ and HEAD MUST be supported by all general-purpose servers. All other
+ methods are OPTIONAL; however, if the above methods are implemented,
+ they MUST be implemented with the same semantics as those specified
+ in section 9.
+
+5.1.2 Request-URI
+
+ The Request-URI is a Uniform Resource Identifier (section 3.2) and
+ identifies the resource upon which to apply the request.
+
+ Request-URI = "*" | absoluteURI | abs_path | authority
+
+ The four options for Request-URI are dependent on the nature of the
+ request. The asterisk "*" means that the request does not apply to a
+ particular resource, but to the server itself, and is only allowed
+ when the method used does not necessarily apply to a resource. One
+ example would be
+
+ OPTIONS * HTTP/1.1
+
+ The absoluteURI form is REQUIRED when the request is being made to a
+ proxy. The proxy is requested to forward the request or service it
+ from a valid cache, and return the response. Note that the proxy MAY
+ forward the request on to another proxy or directly to the server
+
+ specified by the absoluteURI. In order to avoid request loops, a
+ proxy MUST be able to recognize all of its server names, including
+ any aliases, local variations, and the numeric IP address. An example
+ Request-Line would be:
+
+ GET <a href="http://www.w3.org/pub/WWW/TheProject.html">http://www.w3.org/pub/WWW/TheProject.html</a> HTTP/1.1
+
+ To allow for transition to absoluteURIs in all requests in future
+ versions of HTTP, all HTTP/1.1 servers MUST accept the absoluteURI
+ form in requests, even though HTTP/1.1 clients will only generate
+ them in requests to proxies.
+
+ The authority form is only used by the CONNECT method (section 9.9).
+
+ The most common form of Request-URI is that used to identify a
+ resource on an origin server or gateway. In this case the absolute
+ path of the URI MUST be transmitted (see section 3.2.1, abs_path) as
+ the Request-URI, and the network location of the URI (authority) MUST
+ be transmitted in a Host header field. For example, a client wishing
+ to retrieve the resource above directly from the origin server would
+ create a TCP connection to port 80 of the host "www.w3.org" and send
+ the lines:
+
+ GET /pub/WWW/TheProject.html HTTP/1.1
+ Host: www.w3.org
+
+ followed by the remainder of the Request. Note that the absolute path
+ cannot be empty; if none is present in the original URI, it MUST be
+ given as "/" (the server root).
+
+ The Request-URI is transmitted in the format specified in section
+ 3.2.1. If the Request-URI is encoded using the "% HEX HEX" encoding
+ [42], the origin server MUST decode the Request-URI in order to
+ properly interpret the request. Servers SHOULD respond to invalid
+ Request-URIs with an appropriate status code.
+
+ A transparent proxy MUST NOT rewrite the "abs_path" part of the
+ received Request-URI when forwarding it to the next inbound server,
+ except as noted above to replace a null abs_path with "/".
+
+ Note: The "no rewrite" rule prevents the proxy from changing the
+ meaning of the request when the origin server is improperly using
+ a non-reserved URI character for a reserved purpose. Implementors
+ should be aware that some pre-HTTP/1.1 proxies have been known to
+ rewrite the Request-URI.
+
+5.2 The Resource Identified by a Request
+
+ The exact resource identified by an Internet request is determined by
+ examining both the Request-URI and the Host header field.
+
+ An origin server that does not allow resources to differ by the
+ requested host MAY ignore the Host header field value when
+ determining the resource identified by an HTTP/1.1 request. (But see
+ section 19.6.1.1 for other requirements on Host support in HTTP/1.1.)
+
+ An origin server that does differentiate resources based on the host
+ requested (sometimes referred to as virtual hosts or vanity host
+ names) MUST use the following rules for determining the requested
+ resource on an HTTP/1.1 request:
+
+ 1. If Request-URI is an absoluteURI, the host is part of the
+ Request-URI. Any Host header field value in the request MUST be
+ ignored.
+
+ 2. If the Request-URI is not an absoluteURI, and the request includes
+ a Host header field, the host is determined by the Host header
+ field value.
+
+ 3. If the host as determined by rule 1 or 2 is not a valid host on
+ the server, the response MUST be a 400 (Bad Request) error message.
+
+ Recipients of an HTTP/1.0 request that lacks a Host header field MAY
+ attempt to use heuristics (e.g., examination of the URI path for
+ something unique to a particular host) in order to determine what
+ exact resource is being requested.
+
+5.3 Request Header Fields
+
+ The request-header fields allow the client to pass additional
+ information about the request, and about the client itself, to the
+ server. These fields act as request modifiers, with semantics
+ equivalent to the parameters on a programming language method
+ invocation.
+
+ request-header = Accept ; Section 14.1
+ | Accept-Charset ; Section 14.2
+ | Accept-Encoding ; Section 14.3
+ | Accept-Language ; Section 14.4
+ | Authorization ; Section 14.8
+ | Expect ; Section 14.20
+ | From ; Section 14.22
+ | Host ; Section 14.23
+ | If-Match ; Section 14.24
+
+ | If-Modified-Since ; Section 14.25
+ | If-None-Match ; Section 14.26
+ | If-Range ; Section 14.27
+ | If-Unmodified-Since ; Section 14.28
+ | Max-Forwards ; Section 14.31
+ | Proxy-Authorization ; Section 14.34
+ | Range ; Section 14.35
+ | Referer ; Section 14.36
+ | TE ; Section 14.39
+ | User-Agent ; Section 14.43
+
+ Request-header field names can be extended reliably only in
+ combination with a change in the protocol version. However, new or
+ experimental header fields MAY be given the semantics of request-
+ header fields if all parties in the communication recognize them to
+ be request-header fields. Unrecognized header fields are treated as
+ entity-header fields.
+
+6 Response
+
+ After receiving and interpreting a request message, a server responds
+ with an HTTP response message.
+
+ Response = Status-Line ; Section 6.1
+ *(( general-header ; Section 4.5
+ | response-header ; Section 6.2
+ | entity-header ) CRLF) ; Section 7.1
+ CRLF
+ [ message-body ] ; Section 7.2
+
+6.1 Status-Line
+
+ The first line of a Response message is the Status-Line, consisting
+ of the protocol version followed by a numeric status code and its
+ associated textual phrase, with each element separated by SP
+ characters. No CR or LF is allowed except in the final CRLF sequence.
+
+ Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
+
+6.1.1 Status Code and Reason Phrase
+
+ The Status-Code element is a 3-digit integer result code of the
+ attempt to understand and satisfy the request. These codes are fully
+ defined in section 10. The Reason-Phrase is intended to give a short
+ textual description of the Status-Code. The Status-Code is intended
+ for use by automata and the Reason-Phrase is intended for the human
+ user. The client is not required to examine or display the Reason-
+ Phrase.
+
+ The first digit of the Status-Code defines the class of response. The
+ last two digits do not have any categorization role. There are 5
+ values for the first digit:
+
+ - 1xx: Informational - Request received, continuing process
+
+ - 2xx: Success - The action was successfully received,
+ understood, and accepted
+
+ - 3xx: Redirection - Further action must be taken in order to
+ complete the request
+
+ - 4xx: Client Error - The request contains bad syntax or cannot
+ be fulfilled
+
+ - 5xx: Server Error - The server failed to fulfill an apparently
+ valid request
+
+ The individual values of the numeric status codes defined for
+ HTTP/1.1, and an example set of corresponding Reason-Phrase's, are
+ presented below. The reason phrases listed here are only
+ recommendations -- they MAY be replaced by local equivalents without
+ affecting the protocol.
+
+ Status-Code =
+ "100" ; Section 10.1.1: Continue
+ | "101" ; Section 10.1.2: Switching Protocols
+ | "200" ; Section 10.2.1: OK
+ | "201" ; Section 10.2.2: Created
+ | "202" ; Section 10.2.3: Accepted
+ | "203" ; Section 10.2.4: Non-Authoritative Information
+ | "204" ; Section 10.2.5: No Content
+ | "205" ; Section 10.2.6: Reset Content
+ | "206" ; Section 10.2.7: Partial Content
+ | "300" ; Section 10.3.1: Multiple Choices
+ | "301" ; Section 10.3.2: Moved Permanently
+ | "302" ; Section 10.3.3: Found
+ | "303" ; Section 10.3.4: See Other
+ | "304" ; Section 10.3.5: Not Modified
+ | "305" ; Section 10.3.6: Use Proxy
+ | "307" ; Section 10.3.8: Temporary Redirect
+ | "400" ; Section 10.4.1: Bad Request
+ | "401" ; Section 10.4.2: Unauthorized
+ | "402" ; Section 10.4.3: Payment Required
+ | "403" ; Section 10.4.4: Forbidden
+ | "404" ; Section 10.4.5: Not Found
+ | "405" ; Section 10.4.6: Method Not Allowed
+ | "406" ; Section 10.4.7: Not Acceptable
+
+ | "407" ; Section 10.4.8: Proxy Authentication Required
+ | "408" ; Section 10.4.9: Request Time-out
+ | "409" ; Section 10.4.10: Conflict
+ | "410" ; Section 10.4.11: Gone
+ | "411" ; Section 10.4.12: Length Required
+ | "412" ; Section 10.4.13: Precondition Failed
+ | "413" ; Section 10.4.14: Request Entity Too Large
+ | "414" ; Section 10.4.15: Request-URI Too Large
+ | "415" ; Section 10.4.16: Unsupported Media Type
+ | "416" ; Section 10.4.17: Requested range not satisfiable
+ | "417" ; Section 10.4.18: Expectation Failed
+ | "500" ; Section 10.5.1: Internal Server Error
+ | "501" ; Section 10.5.2: Not Implemented
+ | "502" ; Section 10.5.3: Bad Gateway
+ | "503" ; Section 10.5.4: Service Unavailable
+ | "504" ; Section 10.5.5: Gateway Time-out
+ | "505" ; Section 10.5.6: HTTP Version not supported
+ | extension-code
+
+ extension-code = 3DIGIT
+ Reason-Phrase = *<TEXT, excluding CR, LF>
+
+ HTTP status codes are extensible. HTTP applications are not required
+ to understand the meaning of all registered status codes, though such
+ understanding is obviously desirable. However, applications MUST
+ understand the class of any status code, as indicated by the first
+ digit, and treat any unrecognized response as being equivalent to the
+ x00 status code of that class, with the exception that an
+ unrecognized response MUST NOT be cached. For example, if an
+ unrecognized status code of 431 is received by the client, it can
+ safely assume that there was something wrong with its request and
+ treat the response as if it had received a 400 status code. In such
+ cases, user agents SHOULD present to the user the entity returned
+ with the response, since that entity is likely to include human-
+ readable information which will explain the unusual status.
+
+6.2 Response Header Fields
+
+ The response-header fields allow the server to pass additional
+ information about the response which cannot be placed in the Status-
+ Line. These header fields give information about the server and about
+ further access to the resource identified by the Request-URI.
+
+ response-header = Accept-Ranges ; Section 14.5
+ | Age ; Section 14.6
+ | ETag ; Section 14.19
+ | Location ; Section 14.30
+ | Proxy-Authenticate ; Section 14.33
+
+ | Retry-After ; Section 14.37
+ | Server ; Section 14.38
+ | Vary ; Section 14.44
+ | WWW-Authenticate ; Section 14.47
+
+ Response-header field names can be extended reliably only in
+ combination with a change in the protocol version. However, new or
+ experimental header fields MAY be given the semantics of response-
+ header fields if all parties in the communication recognize them to
+ be response-header fields. Unrecognized header fields are treated as
+ entity-header fields.
+
+7 Entity
+
+ Request and Response messages MAY transfer an entity if not otherwise
+ restricted by the request method or response status code. An entity
+ consists of entity-header fields and an entity-body, although some
+ responses will only include the entity-headers.
+
+ In this section, both sender and recipient refer to either the client
+ or the server, depending on who sends and who receives the entity.
+
+7.1 Entity Header Fields
+
+ Entity-header fields define metainformation about the entity-body or,
+ if no body is present, about the resource identified by the request.
+ Some of this metainformation is OPTIONAL; some might be REQUIRED by
+ portions of this specification.
+
+ entity-header = Allow ; Section 14.7
+ | Content-Encoding ; Section 14.11
+ | Content-Language ; Section 14.12
+ | Content-Length ; Section 14.13
+ | Content-Location ; Section 14.14
+ | Content-MD5 ; Section 14.15
+ | Content-Range ; Section 14.16
+ | Content-Type ; Section 14.17
+ | Expires ; Section 14.21
+ | Last-Modified ; Section 14.29
+ | extension-header
+
+ extension-header = message-header
+
+ The extension-header mechanism allows additional entity-header fields
+ to be defined without changing the protocol, but these fields cannot
+ be assumed to be recognizable by the recipient. Unrecognized header
+ fields SHOULD be ignored by the recipient and MUST be forwarded by
+ transparent proxies.
+
+7.2 Entity Body
+
+ The entity-body (if any) sent with an HTTP request or response is in
+ a format and encoding defined by the entity-header fields.
+
+ entity-body = *OCTET
+
+ An entity-body is only present in a message when a message-body is
+ present, as described in section 4.3. The entity-body is obtained
+ from the message-body by decoding any Transfer-Encoding that might
+ have been applied to ensure safe and proper transfer of the message.
+
+7.2.1 Type
+
+ When an entity-body is included with a message, the data type of that
+ body is determined via the header fields Content-Type and Content-
+ Encoding. These define a two-layer, ordered encoding model:
+
+ entity-body := Content-Encoding( Content-Type( data ) )
+
+ Content-Type specifies the media type of the underlying data.
+ Content-Encoding may be used to indicate any additional content
+ codings applied to the data, usually for the purpose of data
+ compression, that are a property of the requested resource. There is
+ no default encoding.
+
+ Any HTTP/1.1 message containing an entity-body SHOULD include a
+ Content-Type header field defining the media type of that body. If
+ and only if the media type is not given by a Content-Type field, the
+ recipient MAY attempt to guess the media type via inspection of its
+ content and/or the name extension(s) of the URI used to identify the
+ resource. If the media type remains unknown, the recipient SHOULD
+ treat it as type "application/octet-stream".
+
+7.2.2 Entity Length
+
+ The entity-length of a message is the length of the message-body
+ before any transfer-codings have been applied. Section 4.4 defines
+ how the transfer-length of a message-body is determined.
+
+8 Connections
+
+8.1 Persistent Connections
+
+8.1.1 Purpose
+
+ Prior to persistent connections, a separate TCP connection was
+ established to fetch each URL, increasing the load on HTTP servers
+ and causing congestion on the Internet. The use of inline images and
+ other associated data often require a client to make multiple
+ requests of the same server in a short amount of time. Analysis of
+ these performance problems and results from a prototype
+ implementation are available [26] [30]. Implementation experience and
+ measurements of actual HTTP/1.1 (<a href="http://firefly.troll.no/rfcs/rfc2068.html">RFC 2068</a>) implementations show good
+ results [39]. Alternatives have also been explored, for example,
+ T/TCP [27].
+
+ Persistent HTTP connections have a number of advantages:
+
+ - By opening and closing fewer TCP connections, CPU time is saved
+ in routers and hosts (clients, servers, proxies, gateways,
+ tunnels, or caches), and memory used for TCP protocol control
+ blocks can be saved in hosts.
+
+ - HTTP requests and responses can be pipelined on a connection.
+ Pipelining allows a client to make multiple requests without
+ waiting for each response, allowing a single TCP connection to
+ be used much more efficiently, with much lower elapsed time.
+
+ - Network congestion is reduced by reducing the number of packets
+ caused by TCP opens, and by allowing TCP sufficient time to
+ determine the congestion state of the network.
+
+ - Latency on subsequent requests is reduced since there is no time
+ spent in TCP's connection opening handshake.
+
+ - HTTP can evolve more gracefully, since errors can be reported
+ without the penalty of closing the TCP connection. Clients using
+ future versions of HTTP might optimistically try a new feature,
+ but if communicating with an older server, retry with old
+ semantics after an error is reported.
+
+ HTTP implementations SHOULD implement persistent connections.
+
+8.1.2 Overall Operation
+
+ A significant difference between HTTP/1.1 and earlier versions of
+ HTTP is that persistent connections are the default behavior of any
+ HTTP connection. That is, unless otherwise indicated, the client
+ SHOULD assume that the server will maintain a persistent connection,
+ even after error responses from the server.
+
+ Persistent connections provide a mechanism by which a client and a
+ server can signal the close of a TCP connection. This signaling takes
+ place using the Connection header field (section 14.10). Once a close
+ has been signaled, the client MUST NOT send any more requests on that
+ connection.
+
+8.1.2.1 Negotiation
+
+ An HTTP/1.1 server MAY assume that a HTTP/1.1 client intends to
+ maintain a persistent connection unless a Connection header including
+ the connection-token "close" was sent in the request. If the server
+ chooses to close the connection immediately after sending the
+ response, it SHOULD send a Connection header including the
+ connection-token close.
+
+ An HTTP/1.1 client MAY expect a connection to remain open, but would
+ decide to keep it open based on whether the response from a server
+ contains a Connection header with the connection-token close. In case
+ the client does not want to maintain a connection for more than that
+ request, it SHOULD send a Connection header including the
+ connection-token close.
+
+ If either the client or the server sends the close token in the
+ Connection header, that request becomes the last one for the
+ connection.
+
+ Clients and servers SHOULD NOT assume that a persistent connection is
+ maintained for HTTP versions less than 1.1 unless it is explicitly
+ signaled. See section 19.6.2 for more information on backward
+ compatibility with HTTP/1.0 clients.
+
+ In order to remain persistent, all messages on the connection MUST
+ have a self-defined message length (i.e., one not defined by closure
+ of the connection), as described in section 4.4.
+
+8.1.2.2 Pipelining
+
+ A client that supports persistent connections MAY "pipeline" its
+ requests (i.e., send multiple requests without waiting for each
+ response). A server MUST send its responses to those requests in the
+ same order that the requests were received.
+
+ Clients which assume persistent connections and pipeline immediately
+ after connection establishment SHOULD be prepared to retry their
+ connection if the first pipelined attempt fails. If a client does
+ such a retry, it MUST NOT pipeline before it knows the connection is
+ persistent. Clients MUST also be prepared to resend their requests if
+ the server closes the connection before sending all of the
+ corresponding responses.
+
+ Clients SHOULD NOT pipeline requests using non-idempotent methods or
+ non-idempotent sequences of methods (see section 9.1.2). Otherwise, a
+ premature termination of the transport connection could lead to
+ indeterminate results. A client wishing to send a non-idempotent
+ request SHOULD wait to send that request until it has received the
+ response status for the previous request.
+
+8.1.3 Proxy Servers
+
+ It is especially important that proxies correctly implement the
+ properties of the Connection header field as specified in section
+ 14.10.
+
+ The proxy server MUST signal persistent connections separately with
+ its clients and the origin servers (or other proxy servers) that it
+ connects to. Each persistent connection applies to only one transport
+ link.
+
+ A proxy server MUST NOT establish a HTTP/1.1 persistent connection
+ with an HTTP/1.0 client (but see <a href="http://firefly.troll.no/rfcs/rfc2068.html">RFC 2068</a> [33] for information and
+ discussion of the problems with the Keep-Alive header implemented by
+ many HTTP/1.0 clients).
+
+8.1.4 Practical Considerations
+
+ Servers will usually have some time-out value beyond which they will
+ no longer maintain an inactive connection. Proxy servers might make
+ this a higher value since it is likely that the client will be making
+ more connections through the same server. The use of persistent
+ connections places no requirements on the length (or existence) of
+ this time-out for either the client or the server.
+
+ When a client or server wishes to time-out it SHOULD issue a graceful
+ close on the transport connection. Clients and servers SHOULD both
+ constantly watch for the other side of the transport close, and
+ respond to it as appropriate. If a client or server does not detect
+ the other side's close promptly it could cause unnecessary resource
+ drain on the network.
+
+ A client, server, or proxy MAY close the transport connection at any
+ time. For example, a client might have started to send a new request
+ at the same time that the server has decided to close the "idle"
+ connection. From the server's point of view, the connection is being
+ closed while it was idle, but from the client's point of view, a
+ request is in progress.
+
+ This means that clients, servers, and proxies MUST be able to recover
+ from asynchronous close events. Client software SHOULD reopen the
+ transport connection and retransmit the aborted sequence of requests
+ without user interaction so long as the request sequence is
+ idempotent (see section 9.1.2). Non-idempotent methods or sequences
+ MUST NOT be automatically retried, although user agents MAY offer a
+ human operator the choice of retrying the request(s). Confirmation by
+ user-agent software with semantic understanding of the application
+ MAY substitute for user confirmation. The automatic retry SHOULD NOT
+ be repeated if the second sequence of requests fails.
+
+ Servers SHOULD always respond to at least one request per connection,
+ if at all possible. Servers SHOULD NOT close a connection in the
+ middle of transmitting a response, unless a network or client failure
+ is suspected.
+
+ Clients that use persistent connections SHOULD limit the number of
+ simultaneous connections that they maintain to a given server. A
+ single-user client SHOULD NOT maintain more than 2 connections with
+ any server or proxy. A proxy SHOULD use up to 2*N connections to
+ another server or proxy, where N is the number of simultaneously
+ active users. These guidelines are intended to improve HTTP response
+ times and avoid congestion.
+
+8.2 Message Transmission Requirements
+
+8.2.1 Persistent Connections and Flow Control
+
+ HTTP/1.1 servers SHOULD maintain persistent connections and use TCP's
+ flow control mechanisms to resolve temporary overloads, rather than
+ terminating connections with the expectation that clients will retry.
+ The latter technique can exacerbate network congestion.
+
+8.2.2 Monitoring Connections for Error Status Messages
+
+ An HTTP/1.1 (or later) client sending a message-body SHOULD monitor
+ the network connection for an error status while it is transmitting
+ the request. If the client sees an error status, it SHOULD
+ immediately cease transmitting the body. If the body is being sent
+ using a "chunked" encoding (section 3.6), a zero length chunk and
+ empty trailer MAY be used to prematurely mark the end of the message.
+ If the body was preceded by a Content-Length header, the client MUST
+ close the connection.
+
+8.2.3 Use of the 100 (Continue) Status
+
+ The purpose of the 100 (Continue) status (see section 10.1.1) is to
+ allow a client that is sending a request message with a request body
+ to determine if the origin server is willing to accept the request
+ (based on the request headers) before the client sends the request
+ body. In some cases, it might either be inappropriate or highly
+ inefficient for the client to send the body if the server will reject
+ the message without looking at the body.
+
+ Requirements for HTTP/1.1 clients:
+
+ - If a client will wait for a 100 (Continue) response before
+ sending the request body, it MUST send an Expect request-header
+ field (section 14.20) with the "100-continue" expectation.
+
+ - A client MUST NOT send an Expect request-header field (section
+ 14.20) with the "100-continue" expectation if it does not intend
+ to send a request body.
+
+ Because of the presence of older implementations, the protocol allows
+ ambiguous situations in which a client may send "Expect: 100-
+ continue" without receiving either a 417 (Expectation Failed) status
+ or a 100 (Continue) status. Therefore, when a client sends this
+ header field to an origin server (possibly via a proxy) from which it
+ has never seen a 100 (Continue) status, the client SHOULD NOT wait
+ for an indefinite period before sending the request body.
+
+ Requirements for HTTP/1.1 origin servers:
+
+ - Upon receiving a request which includes an Expect request-header
+ field with the "100-continue" expectation, an origin server MUST
+ either respond with 100 (Continue) status and continue to read
+ from the input stream, or respond with a final status code. The
+ origin server MUST NOT wait for the request body before sending
+ the 100 (Continue) response. If it responds with a final status
+ code, it MAY close the transport connection or it MAY continue
+
+ to read and discard the rest of the request. It MUST NOT
+ perform the requested method if it returns a final status code.
+
+ - An origin server SHOULD NOT send a 100 (Continue) response if
+ the request message does not include an Expect request-header
+ field with the "100-continue" expectation, and MUST NOT send a
+ 100 (Continue) response if such a request comes from an HTTP/1.0
+ (or earlier) client. There is an exception to this rule: for
+ compatibility with <a href="http://firefly.troll.no/rfcs/rfc2068.html">RFC 2068</a>, a server MAY send a 100 (Continue)
+ status in response to an HTTP/1.1 PUT or POST request that does
+ not include an Expect request-header field with the "100-
+ continue" expectation. This exception, the purpose of which is
+ to minimize any client processing delays associated with an
+ undeclared wait for 100 (Continue) status, applies only to
+ HTTP/1.1 requests, and not to requests with any other HTTP-
+ version value.
+
+ - An origin server MAY omit a 100 (Continue) response if it has
+ already received some or all of the request body for the
+ corresponding request.
+
+ - An origin server that sends a 100 (Continue) response MUST
+ ultimately send a final status code, once the request body is
+ received and processed, unless it terminates the transport
+ connection prematurely.
+
+ - If an origin server receives a request that does not include an
+ Expect request-header field with the "100-continue" expectation,
+ the request includes a request body, and the server responds
+ with a final status code before reading the entire request body
+ from the transport connection, then the server SHOULD NOT close
+ the transport connection until it has read the entire request,
+ or until the client closes the connection. Otherwise, the client
+ might not reliably receive the response message. However, this
+ requirement is not be construed as preventing a server from
+ defending itself against denial-of-service attacks, or from
+ badly broken client implementations.
+
+ Requirements for HTTP/1.1 proxies:
+
+ - If a proxy receives a request that includes an Expect request-
+ header field with the "100-continue" expectation, and the proxy
+ either knows that the next-hop server complies with HTTP/1.1 or
+ higher, or does not know the HTTP version of the next-hop
+ server, it MUST forward the request, including the Expect header
+ field.
+
+ - If the proxy knows that the version of the next-hop server is
+ HTTP/1.0 or lower, it MUST NOT forward the request, and it MUST
+ respond with a 417 (Expectation Failed) status.
+
+ - Proxies SHOULD maintain a cache recording the HTTP version
+ numbers received from recently-referenced next-hop servers.
+
+ - A proxy MUST NOT forward a 100 (Continue) response if the
+ request message was received from an HTTP/1.0 (or earlier)
+ client and did not include an Expect request-header field with
+ the "100-continue" expectation. This requirement overrides the
+ general rule for forwarding of 1xx responses (see section 10.1).
+
+8.2.4 Client Behavior if Server Prematurely Closes Connection
+
+ If an HTTP/1.1 client sends a request which includes a request body,
+ but which does not include an Expect request-header field with the
+ "100-continue" expectation, and if the client is not directly
+ connected to an HTTP/1.1 origin server, and if the client sees the
+ connection close before receiving any status from the server, the
+ client SHOULD retry the request. If the client does retry this
+ request, it MAY use the following "binary exponential backoff"
+ algorithm to be assured of obtaining a reliable response:
+
+ 1. Initiate a new connection to the server
+
+ 2. Transmit the request-headers
+
+ 3. Initialize a variable R to the estimated round-trip time to the
+ server (e.g., based on the time it took to establish the
+ connection), or to a constant value of 5 seconds if the round-
+ trip time is not available.
+
+ 4. Compute T = R * (2**N), where N is the number of previous
+ retries of this request.
+
+ 5. Wait either for an error response from the server, or for T
+ seconds (whichever comes first)
+
+ 6. If no error response is received, after T seconds transmit the
+ body of the request.
+
+ 7. If client sees that the connection is closed prematurely,
+ repeat from step 1 until the request is accepted, an error
+ response is received, or the user becomes impatient and
+ terminates the retry process.
+
+ If at any point an error status is received, the client
+
+ - SHOULD NOT continue and
+
+ - SHOULD close the connection if it has not completed sending the
+ request message.
+
+9 Method Definitions
+
+ The set of common methods for HTTP/1.1 is defined below. Although
+ this set can be expanded, additional methods cannot be assumed to
+ share the same semantics for separately extended clients and servers.
+
+ The Host request-header field (section 14.23) MUST accompany all
+ HTTP/1.1 requests.
+
+9.1 Safe and Idempotent Methods
+
+9.1.1 Safe Methods
+
+ Implementors should be aware that the software represents the user in
+ their interactions over the Internet, and should be careful to allow
+ the user to be aware of any actions they might take which may have an
+ unexpected significance to themselves or others.
+
+ In particular, the convention has been established that the GET and
+ HEAD methods SHOULD NOT have the significance of taking an action
+ other than retrieval. These methods ought to be considered "safe".
+ This allows user agents to represent other methods, such as POST, PUT
+ and DELETE, in a special way, so that the user is made aware of the
+ fact that a possibly unsafe action is being requested.
+
+ Naturally, it is not possible to ensure that the server does not
+ generate side-effects as a result of performing a GET request; in
+ fact, some dynamic resources consider that a feature. The important
+ distinction here is that the user did not request the side-effects,
+ so therefore cannot be held accountable for them.
+
+9.1.2 Idempotent Methods
+
+ Methods can also have the property of "idempotence" in that (aside
+ from error or expiration issues) the side-effects of N > 0 identical
+ requests is the same as for a single request. The methods GET, HEAD,
+ PUT and DELETE share this property. Also, the methods OPTIONS and
+ TRACE SHOULD NOT have side effects, and so are inherently idempotent.
+
+ However, it is possible that a sequence of several requests is non-
+ idempotent, even if all of the methods executed in that sequence are
+ idempotent. (A sequence is idempotent if a single execution of the
+ entire sequence always yields a result that is not changed by a
+ reexecution of all, or part, of that sequence.) For example, a
+ sequence is non-idempotent if its result depends on a value that is
+ later modified in the same sequence.
+
+ A sequence that never has side effects is idempotent, by definition
+ (provided that no concurrent operations are being executed on the
+ same set of resources).
+
+9.2 OPTIONS
+
+ The OPTIONS method represents a request for information about the
+ communication options available on the request/response chain
+ identified by the Request-URI. This method allows the client to
+ determine the options and/or requirements associated with a resource,
+ or the capabilities of a server, without implying a resource action
+ or initiating a resource retrieval.
+
+ Responses to this method are not cacheable.
+
+ If the OPTIONS request includes an entity-body (as indicated by the
+ presence of Content-Length or Transfer-Encoding), then the media type
+ MUST be indicated by a Content-Type field. Although this
+ specification does not define any use for such a body, future
+ extensions to HTTP might use the OPTIONS body to make more detailed
+ queries on the server. A server that does not support such an
+ extension MAY discard the request body.
+
+ If the Request-URI is an asterisk ("*"), the OPTIONS request is
+ intended to apply to the server in general rather than to a specific
+ resource. Since a server's communication options typically depend on
+ the resource, the "*" request is only useful as a "ping" or "no-op"
+ type of method; it does nothing beyond allowing the client to test
+ the capabilities of the server. For example, this can be used to test
+ a proxy for HTTP/1.1 compliance (or lack thereof).
+
+ If the Request-URI is not an asterisk, the OPTIONS request applies
+ only to the options that are available when communicating with that
+ resource.
+
+ A 200 response SHOULD include any header fields that indicate
+ optional features implemented by the server and applicable to that
+ resource (e.g., Allow), possibly including extensions not defined by
+ this specification. The response body, if any, SHOULD also include
+ information about the communication options. The format for such a
+
+ body is not defined by this specification, but might be defined by
+ future extensions to HTTP. Content negotiation MAY be used to select
+ the appropriate response format. If no response body is included, the
+ response MUST include a Content-Length field with a field-value of
+ "0".
+
+ The Max-Forwards request-header field MAY be used to target a
+ specific proxy in the request chain. When a proxy receives an OPTIONS
+ request on an absoluteURI for which request forwarding is permitted,
+ the proxy MUST check for a Max-Forwards field. If the Max-Forwards
+ field-value is zero ("0"), the proxy MUST NOT forward the message;
+ instead, the proxy SHOULD respond with its own communication options.
+ If the Max-Forwards field-value is an integer greater than zero, the
+ proxy MUST decrement the field-value when it forwards the request. If
+ no Max-Forwards field is present in the request, then the forwarded
+ request MUST NOT include a Max-Forwards field.
+
+9.3 GET
+
+ The GET method means retrieve whatever information (in the form of an
+ entity) is identified by the Request-URI. If the Request-URI refers
+ to a data-producing process, it is the produced data which shall be
+ returned as the entity in the response and not the source text of the
+ process, unless that text happens to be the output of the process.
+
+ The semantics of the GET method change to a "conditional GET" if the
+ request message includes an If-Modified-Since, If-Unmodified-Since,
+ If-Match, If-None-Match, or If-Range header field. A conditional GET
+ method requests that the entity be transferred only under the
+ circumstances described by the conditional header field(s). The
+ conditional GET method is intended to reduce unnecessary network
+ usage by allowing cached entities to be refreshed without requiring
+ multiple requests or transferring data already held by the client.
+
+ The semantics of the GET method change to a "partial GET" if the
+ request message includes a Range header field. A partial GET requests
+ that only part of the entity be transferred, as described in section
+ 14.35. The partial GET method is intended to reduce unnecessary
+ network usage by allowing partially-retrieved entities to be
+ completed without transferring data already held by the client.
+
+ The response to a GET request is cacheable if and only if it meets
+ the requirements for HTTP caching described in section 13.
+
+ See section 15.1.3 for security considerations when used for forms.
+
+9.4 HEAD
+
+ The HEAD method is identical to GET except that the server MUST NOT
+ return a message-body in the response. The metainformation contained
+ in the HTTP headers in response to a HEAD request SHOULD be identical
+ to the information sent in response to a GET request. This method can
+ be used for obtaining metainformation about the entity implied by the
+ request without transferring the entity-body itself. This method is
+ often used for testing hypertext links for validity, accessibility,
+ and recent modification.
+
+ The response to a HEAD request MAY be cacheable in the sense that the
+ information contained in the response MAY be used to update a
+ previously cached entity from that resource. If the new field values
+ indicate that the cached entity differs from the current entity (as
+ would be indicated by a change in Content-Length, Content-MD5, ETag
+ or Last-Modified), then the cache MUST treat the cache entry as
+ stale.
+
+9.5 POST
+
+ The POST method is used to request that the origin server accept the
+ entity enclosed in the request as a new subordinate of the resource
+ identified by the Request-URI in the Request-Line. POST is designed
+ to allow a uniform method to cover the following functions:
+
+ - Annotation of existing resources;
+
+ - Posting a message to a bulletin board, newsgroup, mailing list,
+ or similar group of articles;
+
+ - Providing a block of data, such as the result of submitting a
+ form, to a data-handling process;
+
+ - Extending a database through an append operation.
+
+ The actual function performed by the POST method is determined by the
+ server and is usually dependent on the Request-URI. The posted entity
+ is subordinate to that URI in the same way that a file is subordinate
+ to a directory containing it, a news article is subordinate to a
+ newsgroup to which it is posted, or a record is subordinate to a
+ database.
+
+ The action performed by the POST method might not result in a
+ resource that can be identified by a URI. In this case, either 200
+ (OK) or 204 (No Content) is the appropriate response status,
+ depending on whether or not the response includes an entity that
+ describes the result.
+
+ If a resource has been created on the origin server, the response
+ SHOULD be 201 (Created) and contain an entity which describes the
+ status of the request and refers to the new resource, and a Location
+ header (see section 14.30).
+
+ Responses to this method are not cacheable, unless the response
+ includes appropriate Cache-Control or Expires header fields. However,
+ the 303 (See Other) response can be used to direct the user agent to
+ retrieve a cacheable resource.
+
+ POST requests MUST obey the message transmission requirements set out
+ in section 8.2.
+
+ See section 15.1.3 for security considerations.
+
+9.6 PUT
+
+ The PUT method requests that the enclosed entity be stored under the
+ supplied Request-URI. If the Request-URI refers to an already
+ existing resource, the enclosed entity SHOULD be considered as a
+ modified version of the one residing on the origin server. If the
+ Request-URI does not point to an existing resource, and that URI is
+ capable of being defined as a new resource by the requesting user
+ agent, the origin server can create the resource with that URI. If a
+ new resource is created, the origin server MUST inform the user agent
+ via the 201 (Created) response. If an existing resource is modified,
+ either the 200 (OK) or 204 (No Content) response codes SHOULD be sent
+ to indicate successful completion of the request. If the resource
+ could not be created or modified with the Request-URI, an appropriate
+ error response SHOULD be given that reflects the nature of the
+ problem. The recipient of the entity MUST NOT ignore any Content-*
+ (e.g. Content-Range) headers that it does not understand or implement
+ and MUST return a 501 (Not Implemented) response in such cases.
+
+ If the request passes through a cache and the Request-URI identifies
+ one or more currently cached entities, those entries SHOULD be
+ treated as stale. Responses to this method are not cacheable.
+
+ The fundamental difference between the POST and PUT requests is
+ reflected in the different meaning of the Request-URI. The URI in a
+ POST request identifies the resource that will handle the enclosed
+ entity. That resource might be a data-accepting process, a gateway to
+ some other protocol, or a separate entity that accepts annotations.
+ In contrast, the URI in a PUT request identifies the entity enclosed
+ with the request -- the user agent knows what URI is intended and the
+ server MUST NOT attempt to apply the request to some other resource.
+ If the server desires that the request be applied to a different URI,
+
+ it MUST send a 301 (Moved Permanently) response; the user agent MAY
+ then make its own decision regarding whether or not to redirect the
+ request.
+
+ A single resource MAY be identified by many different URIs. For
+ example, an article might have a URI for identifying "the current
+ version" which is separate from the URI identifying each particular
+ version. In this case, a PUT request on a general URI might result in
+ several other URIs being defined by the origin server.
+
+ HTTP/1.1 does not define how a PUT method affects the state of an
+ origin server.
+
+ PUT requests MUST obey the message transmission requirements set out
+ in section 8.2.
+
+ Unless otherwise specified for a particular entity-header, the
+ entity-headers in the PUT request SHOULD be applied to the resource
+ created or modified by the PUT.
+
+9.7 DELETE
+
+ The DELETE method requests that the origin server delete the resource
+ identified by the Request-URI. This method MAY be overridden by human
+ intervention (or other means) on the origin server. The client cannot
+ be guaranteed that the operation has been carried out, even if the
+ status code returned from the origin server indicates that the action
+ has been completed successfully. However, the server SHOULD NOT
+ indicate success unless, at the time the response is given, it
+ intends to delete the resource or move it to an inaccessible
+ location.
+
+ A successful response SHOULD be 200 (OK) if the response includes an
+ entity describing the status, 202 (Accepted) if the action has not
+ yet been enacted, or 204 (No Content) if the action has been enacted
+ but the response does not include an entity.
+
+ If the request passes through a cache and the Request-URI identifies
+ one or more currently cached entities, those entries SHOULD be
+ treated as stale. Responses to this method are not cacheable.
+
+9.8 TRACE
+
+ The TRACE method is used to invoke a remote, application-layer loop-
+ back of the request message. The final recipient of the request
+ SHOULD reflect the message received back to the client as the
+ entity-body of a 200 (OK) response. The final recipient is either the
+
+ origin server or the first proxy or gateway to receive a Max-Forwards
+ value of zero (0) in the request (see section 14.31). A TRACE request
+ MUST NOT include an entity.
+
+ TRACE allows the client to see what is being received at the other
+ end of the request chain and use that data for testing or diagnostic
+ information. The value of the Via header field (section 14.45) is of
+ particular interest, since it acts as a trace of the request chain.
+ Use of the Max-Forwards header field allows the client to limit the
+ length of the request chain, which is useful for testing a chain of
+ proxies forwarding messages in an infinite loop.
+
+ If the request is valid, the response SHOULD contain the entire
+ request message in the entity-body, with a Content-Type of
+ "message/http". Responses to this method MUST NOT be cached.
+
+9.9 CONNECT
+
+ This specification reserves the method name CONNECT for use with a
+ proxy that can dynamically switch to being a tunnel (e.g. SSL
+ tunneling [44]).
+
+10 Status Code Definitions
+
+ Each Status-Code is described below, including a description of which
+ method(s) it can follow and any metainformation required in the
+ response.
+
+10.1 Informational 1xx
+
+ This class of status code indicates a provisional response,
+ consisting only of the Status-Line and optional headers, and is
+ terminated by an empty line. There are no required headers for this
+ class of status code. Since HTTP/1.0 did not define any 1xx status
+ codes, servers MUST NOT send a 1xx response to an HTTP/1.0 client
+ except under experimental conditions.
+
+ A client MUST be prepared to accept one or more 1xx status responses
+ prior to a regular response, even if the client does not expect a 100
+ (Continue) status message. Unexpected 1xx status responses MAY be
+ ignored by a user agent.
+
+ Proxies MUST forward 1xx responses, unless the connection between the
+ proxy and its client has been closed, or unless the proxy itself
+ requested the generation of the 1xx response. (For example, if a
+
+ proxy adds a "Expect: 100-continue" field when it forwards a request,
+ then it need not forward the corresponding 100 (Continue)
+ response(s).)
+
+10.1.1 100 Continue
+
+ The client SHOULD continue with its request. This interim response is
+ used to inform the client that the initial part of the request has
+ been received and has not yet been rejected by the server. The client
+ SHOULD continue by sending the remainder of the request or, if the
+ request has already been completed, ignore this response. The server
+ MUST send a final response after the request has been completed. See
+ section 8.2.3 for detailed discussion of the use and handling of this
+ status code.
+
+10.1.2 101 Switching Protocols
+
+ The server understands and is willing to comply with the client's
+ request, via the Upgrade message header field (section 14.42), for a
+ change in the application protocol being used on this connection. The
+ server will switch protocols to those defined by the response's
+ Upgrade header field immediately after the empty line which
+ terminates the 101 response.
+
+ The protocol SHOULD be switched only when it is advantageous to do
+ so. For example, switching to a newer version of HTTP is advantageous
+ over older versions, and switching to a real-time, synchronous
+ protocol might be advantageous when delivering resources that use
+ such features.
+
+10.2 Successful 2xx
+
+ This class of status code indicates that the client's request was
+ successfully received, understood, and accepted.
+
+10.2.1 200 OK
+
+ The request has succeeded. The information returned with the response
+ is dependent on the method used in the request, for example:
+
+ GET an entity corresponding to the requested resource is sent in
+ the response;
+
+ HEAD the entity-header fields corresponding to the requested
+ resource are sent in the response without any message-body;
+
+ POST an entity describing or containing the result of the action;
+
+ TRACE an entity containing the request message as received by the
+ end server.
+
+10.2.2 201 Created
+
+ The request has been fulfilled and resulted in a new resource being
+ created. The newly created resource can be referenced by the URI(s)
+ returned in the entity of the response, with the most specific URI
+ for the resource given by a Location header field. The response
+ SHOULD include an entity containing a list of resource
+ characteristics and location(s) from which the user or user agent can
+ choose the one most appropriate. The entity format is specified by
+ the media type given in the Content-Type header field. The origin
+ server MUST create the resource before returning the 201 status code.
+ If the action cannot be carried out immediately, the server SHOULD
+ respond with 202 (Accepted) response instead.
+
+ A 201 response MAY contain an ETag response header field indicating
+ the current value of the entity tag for the requested variant just
+ created, see section 14.19.
+
+10.2.3 202 Accepted
+
+ The request has been accepted for processing, but the processing has
+ not been completed. The request might or might not eventually be
+ acted upon, as it might be disallowed when processing actually takes
+ place. There is no facility for re-sending a status code from an
+ asynchronous operation such as this.
+
+ The 202 response is intentionally non-committal. Its purpose is to
+ allow a server to accept a request for some other process (perhaps a
+ batch-oriented process that is only run once per day) without
+ requiring that the user agent's connection to the server persist
+ until the process is completed. The entity returned with this
+ response SHOULD include an indication of the request's current status
+ and either a pointer to a status monitor or some estimate of when the
+ user can expect the request to be fulfilled.
+
+10.2.4 203 Non-Authoritative Information
+
+ The returned metainformation in the entity-header is not the
+ definitive set as available from the origin server, but is gathered
+ from a local or a third-party copy. The set presented MAY be a subset
+ or superset of the original version. For example, including local
+ annotation information about the resource might result in a superset
+ of the metainformation known by the origin server. Use of this
+ response code is not required and is only appropriate when the
+ response would otherwise be 200 (OK).
+
+10.2.5 204 No Content
+
+ The server has fulfilled the request but does not need to return an
+ entity-body, and might want to return updated metainformation. The
+ response MAY include new or updated metainformation in the form of
+ entity-headers, which if present SHOULD be associated with the
+ requested variant.
+
+ If the client is a user agent, it SHOULD NOT change its document view
+ from that which caused the request to be sent. This response is
+ primarily intended to allow input for actions to take place without
+ causing a change to the user agent's active document view, although
+ any new or updated metainformation SHOULD be applied to the document
+ currently in the user agent's active view.
+
+ The 204 response MUST NOT include a message-body, and thus is always
+ terminated by the first empty line after the header fields.
+
+10.2.6 205 Reset Content
+
+ The server has fulfilled the request and the user agent SHOULD reset
+ the document view which caused the request to be sent. This response
+ is primarily intended to allow input for actions to take place via
+ user input, followed by a clearing of the form in which the input is
+ given so that the user can easily initiate another input action. The
+ response MUST NOT include an entity.
+
+10.2.7 206 Partial Content
+
+ The server has fulfilled the partial GET request for the resource.
+ The request MUST have included a Range header field (section 14.35)
+ indicating the desired range, and MAY have included an If-Range
+ header field (section 14.27) to make the request conditional.
+
+ The response MUST include the following header fields:
+
+ - Either a Content-Range header field (section 14.16) indicating
+ the range included with this response, or a multipart/byteranges
+ Content-Type including Content-Range fields for each part. If a
+ Content-Length header field is present in the response, its
+ value MUST match the actual number of OCTETs transmitted in the
+ message-body.
+
+ - Date
+
+ - ETag and/or Content-Location, if the header would have been sent
+ in a 200 response to the same request
+
+ - Expires, Cache-Control, and/or Vary, if the field-value might
+ differ from that sent in any previous response for the same
+ variant
+
+ If the 206 response is the result of an If-Range request that used a
+ strong cache validator (see section 13.3.3), the response SHOULD NOT
+ include other entity-headers. If the response is the result of an
+ If-Range request that used a weak validator, the response MUST NOT
+ include other entity-headers; this prevents inconsistencies between
+ cached entity-bodies and updated headers. Otherwise, the response
+ MUST include all of the entity-headers that would have been returned
+ with a 200 (OK) response to the same request.
+
+ A cache MUST NOT combine a 206 response with other previously cached
+ content if the ETag or Last-Modified headers do not match exactly,
+ see 13.5.4.
+
+ A cache that does not support the Range and Content-Range headers
+ MUST NOT cache 206 (Partial) responses.
+
+10.3 Redirection 3xx
+
+ This class of status code indicates that further action needs to be
+ taken by the user agent in order to fulfill the request. The action
+ required MAY be carried out by the user agent without interaction
+ with the user if and only if the method used in the second request is
+ GET or HEAD. A client SHOULD detect infinite redirection loops, since
+ such loops generate network traffic for each redirection.
+
+ Note: previous versions of this specification recommended a
+ maximum of five redirections. Content developers should be aware
+ that there might be clients that implement such a fixed
+ limitation.
+
+10.3.1 300 Multiple Choices
+
+ The requested resource corresponds to any one of a set of
+ representations, each with its own specific location, and agent-
+ driven negotiation information (section 12) is being provided so that
+ the user (or user agent) can select a preferred representation and
+ redirect its request to that location.
+
+ Unless it was a HEAD request, the response SHOULD include an entity
+ containing a list of resource characteristics and location(s) from
+ which the user or user agent can choose the one most appropriate. The
+ entity format is specified by the media type given in the Content-
+ Type header field. Depending upon the format and the capabilities of
+
+ the user agent, selection of the most appropriate choice MAY be
+ performed automatically. However, this specification does not define
+ any standard for such automatic selection.
+
+ If the server has a preferred choice of representation, it SHOULD
+ include the specific URI for that representation in the Location
+ field; user agents MAY use the Location field value for automatic
+ redirection. This response is cacheable unless indicated otherwise.
+
+10.3.2 301 Moved Permanently
+
+ The requested resource has been assigned a new permanent URI and any
+ future references to this resource SHOULD use one of the returned
+ URIs. Clients with link editing capabilities ought to automatically
+ re-link references to the Request-URI to one or more of the new
+ references returned by the server, where possible. This response is
+ cacheable unless indicated otherwise.
+
+ The new permanent URI SHOULD be given by the Location field in the
+ response. Unless the request method was HEAD, the entity of the
+ response SHOULD contain a short hypertext note with a hyperlink to
+ the new URI(s).
+
+ If the 301 status code is received in response to a request other
+ than GET or HEAD, the user agent MUST NOT automatically redirect the
+ request unless it can be confirmed by the user, since this might
+ change the conditions under which the request was issued.
+
+ Note: When automatically redirecting a POST request after
+ receiving a 301 status code, some existing HTTP/1.0 user agents
+ will erroneously change it into a GET request.
+
+10.3.3 302 Found
+
+ The requested resource resides temporarily under a different URI.
+ Since the redirection might be altered on occasion, the client SHOULD
+ continue to use the Request-URI for future requests. This response
+ is only cacheable if indicated by a Cache-Control or Expires header
+ field.
+
+ The temporary URI SHOULD be given by the Location field in the
+ response. Unless the request method was HEAD, the entity of the
+ response SHOULD contain a short hypertext note with a hyperlink to
+ the new URI(s).
+
+ If the 302 status code is received in response to a request other
+ than GET or HEAD, the user agent MUST NOT automatically redirect the
+ request unless it can be confirmed by the user, since this might
+ change the conditions under which the request was issued.
+
+ Note: <a href="http://firefly.troll.no/rfcs/rfc1945.html">RFC 1945</a> and <a href="http://firefly.troll.no/rfcs/rfc2068.html">RFC 2068</a> specify that the client is not allowed
+ to change the method on the redirected request. However, most
+ existing user agent implementations treat 302 as if it were a 303
+ response, performing a GET on the Location field-value regardless
+ of the original request method. The status codes 303 and 307 have
+ been added for servers that wish to make unambiguously clear which
+ kind of reaction is expected of the client.
+
+10.3.4 303 See Other
+
+ The response to the request can be found under a different URI and
+ SHOULD be retrieved using a GET method on that resource. This method
+ exists primarily to allow the output of a POST-activated script to
+ redirect the user agent to a selected resource. The new URI is not a
+ substitute reference for the originally requested resource. The 303
+ response MUST NOT be cached, but the response to the second
+ (redirected) request might be cacheable.
+
+ The different URI SHOULD be given by the Location field in the
+ response. Unless the request method was HEAD, the entity of the
+ response SHOULD contain a short hypertext note with a hyperlink to
+ the new URI(s).
+
+ Note: Many pre-HTTP/1.1 user agents do not understand the 303
+ status. When interoperability with such clients is a concern, the
+ 302 status code may be used instead, since most user agents react
+ to a 302 response as described here for 303.
+
+10.3.5 304 Not Modified
+
+ If the client has performed a conditional GET request and access is
+ allowed, but the document has not been modified, the server SHOULD
+ respond with this status code. The 304 response MUST NOT contain a
+ message-body, and thus is always terminated by the first empty line
+ after the header fields.
+
+ The response MUST include the following header fields:
+
+ - Date, unless its omission is required by section 14.18.1
+
+ If a clockless origin server obeys these rules, and proxies and
+ clients add their own Date to any response received without one (as
+ already specified by [<a href="http://firefly.troll.no/rfcs/rfc2068.html">RFC 2068</a>], section 14.19), caches will operate
+ correctly.
+
+ - ETag and/or Content-Location, if the header would have been sent
+ in a 200 response to the same request
+
+ - Expires, Cache-Control, and/or Vary, if the field-value might
+ differ from that sent in any previous response for the same
+ variant
+
+ If the conditional GET used a strong cache validator (see section
+ 13.3.3), the response SHOULD NOT include other entity-headers.
+ Otherwise (i.e., the conditional GET used a weak validator), the
+ response MUST NOT include other entity-headers; this prevents
+ inconsistencies between cached entity-bodies and updated headers.
+
+ If a 304 response indicates an entity not currently cached, then the
+ cache MUST disregard the response and repeat the request without the
+ conditional.
+
+ If a cache uses a received 304 response to update a cache entry, the
+ cache MUST update the entry to reflect any new field values given in
+ the response.
+
+10.3.6 305 Use Proxy
+
+ The requested resource MUST be accessed through the proxy given by
+ the Location field. The Location field gives the URI of the proxy.
+ The recipient is expected to repeat this single request via the
+ proxy. 305 responses MUST only be generated by origin servers.
+
+ Note: <a href="http://firefly.troll.no/rfcs/rfc2068.html">RFC 2068</a> was not clear that 305 was intended to redirect a
+ single request, and to be generated by origin servers only. Not
+ observing these limitations has significant security consequences.
+
+10.3.7 306 (Unused)
+
+ The 306 status code was used in a previous version of the
+ specification, is no longer used, and the code is reserved.
+
+10.3.8 307 Temporary Redirect
+
+ The requested resource resides temporarily under a different URI.
+ Since the redirection MAY be altered on occasion, the client SHOULD
+ continue to use the Request-URI for future requests. This response
+ is only cacheable if indicated by a Cache-Control or Expires header
+ field.
+
+ The temporary URI SHOULD be given by the Location field in the
+ response. Unless the request method was HEAD, the entity of the
+ response SHOULD contain a short hypertext note with a hyperlink to
+ the new URI(s) , since many pre-HTTP/1.1 user agents do not
+ understand the 307 status. Therefore, the note SHOULD contain the
+ information necessary for a user to repeat the original request on
+ the new URI.
+
+ If the 307 status code is received in response to a request other
+ than GET or HEAD, the user agent MUST NOT automatically redirect the
+ request unless it can be confirmed by the user, since this might
+ change the conditions under which the request was issued.
+
+10.4 Client Error 4xx
+
+ The 4xx class of status code is intended for cases in which the
+ client seems to have erred. Except when responding to a HEAD request,
+ the server SHOULD include an entity containing an explanation of the
+ error situation, and whether it is a temporary or permanent
+ condition. These status codes are applicable to any request method.
+ User agents SHOULD display any included entity to the user.
+
+ If the client is sending data, a server implementation using TCP
+ SHOULD be careful to ensure that the client acknowledges receipt of
+ the packet(s) containing the response, before the server closes the
+ input connection. If the client continues sending data to the server
+ after the close, the server's TCP stack will send a reset packet to
+ the client, which may erase the client's unacknowledged input buffers
+ before they can be read and interpreted by the HTTP application.
+
+10.4.1 400 Bad Request
+
+ The request could not be understood by the server due to malformed
+ syntax. The client SHOULD NOT repeat the request without
+ modifications.
+
+10.4.2 401 Unauthorized
+
+ The request requires user authentication. The response MUST include a
+ WWW-Authenticate header field (section 14.47) containing a challenge
+ applicable to the requested resource. The client MAY repeat the
+ request with a suitable Authorization header field (section 14.8). If
+ the request already included Authorization credentials, then the 401
+ response indicates that authorization has been refused for those
+ credentials. If the 401 response contains the same challenge as the
+ prior response, and the user agent has already attempted
+ authentication at least once, then the user SHOULD be presented the
+ entity that was given in the response, since that entity might
+ include relevant diagnostic information. HTTP access authentication
+ is explained in "HTTP Authentication: Basic and Digest Access
+ Authentication" [43].
+
+10.4.3 402 Payment Required
+
+ This code is reserved for future use.
+
+10.4.4 403 Forbidden
+
+ The server understood the request, but is refusing to fulfill it.
+ Authorization will not help and the request SHOULD NOT be repeated.
+ If the request method was not HEAD and the server wishes to make
+ public why the request has not been fulfilled, it SHOULD describe the
+ reason for the refusal in the entity. If the server does not wish to
+ make this information available to the client, the status code 404
+ (Not Found) can be used instead.
+
+10.4.5 404 Not Found
+
+ The server has not found anything matching the Request-URI. No
+ indication is given of whether the condition is temporary or
+ permanent. The 410 (Gone) status code SHOULD be used if the server
+ knows, through some internally configurable mechanism, that an old
+ resource is permanently unavailable and has no forwarding address.
+ This status code is commonly used when the server does not wish to
+ reveal exactly why the request has been refused, or when no other
+ response is applicable.
+
+10.4.6 405 Method Not Allowed
+
+ The method specified in the Request-Line is not allowed for the
+ resource identified by the Request-URI. The response MUST include an
+ Allow header containing a list of valid methods for the requested
+ resource.
+
+10.4.7 406 Not Acceptable
+
+ The resource identified by the request is only capable of generating
+ response entities which have content characteristics not acceptable
+ according to the accept headers sent in the request.
+
+ Unless it was a HEAD request, the response SHOULD include an entity
+ containing a list of available entity characteristics and location(s)
+ from which the user or user agent can choose the one most
+ appropriate. The entity format is specified by the media type given
+ in the Content-Type header field. Depending upon the format and the
+ capabilities of the user agent, selection of the most appropriate
+ choice MAY be performed automatically. However, this specification
+ does not define any standard for such automatic selection.
+
+ Note: HTTP/1.1 servers are allowed to return responses which are
+ not acceptable according to the accept headers sent in the
+ request. In some cases, this may even be preferable to sending a
+ 406 response. User agents are encouraged to inspect the headers of
+ an incoming response to determine if it is acceptable.
+
+ If the response could be unacceptable, a user agent SHOULD
+ temporarily stop receipt of more data and query the user for a
+ decision on further actions.
+
+10.4.8 407 Proxy Authentication Required
+
+ This code is similar to 401 (Unauthorized), but indicates that the
+ client must first authenticate itself with the proxy. The proxy MUST
+ return a Proxy-Authenticate header field (section 14.33) containing a
+ challenge applicable to the proxy for the requested resource. The
+ client MAY repeat the request with a suitable Proxy-Authorization
+ header field (section 14.34). HTTP access authentication is explained
+ in "HTTP Authentication: Basic and Digest Access Authentication"
+ [43].
+
+10.4.9 408 Request Timeout
+
+ The client did not produce a request within the time that the server
+ was prepared to wait. The client MAY repeat the request without
+ modifications at any later time.
+
+10.4.10 409 Conflict
+
+ The request could not be completed due to a conflict with the current
+ state of the resource. This code is only allowed in situations where
+ it is expected that the user might be able to resolve the conflict
+ and resubmit the request. The response body SHOULD include enough
+
+ information for the user to recognize the source of the conflict.
+ Ideally, the response entity would include enough information for the
+ user or user agent to fix the problem; however, that might not be
+ possible and is not required.
+
+ Conflicts are most likely to occur in response to a PUT request. For
+ example, if versioning were being used and the entity being PUT
+ included changes to a resource which conflict with those made by an
+ earlier (third-party) request, the server might use the 409 response
+ to indicate that it can't complete the request. In this case, the
+ response entity would likely contain a list of the differences
+ between the two versions in a format defined by the response
+ Content-Type.
+
+10.4.11 410 Gone
+
+ The requested resource is no longer available at the server and no
+ forwarding address is known. This condition is expected to be
+ considered permanent. Clients with link editing capabilities SHOULD
+ delete references to the Request-URI after user approval. If the
+ server does not know, or has no facility to determine, whether or not
+ the condition is permanent, the status code 404 (Not Found) SHOULD be
+ used instead. This response is cacheable unless indicated otherwise.
+
+ The 410 response is primarily intended to assist the task of web
+ maintenance by notifying the recipient that the resource is
+ intentionally unavailable and that the server owners desire that
+ remote links to that resource be removed. Such an event is common for
+ limited-time, promotional services and for resources belonging to
+ individuals no longer working at the server's site. It is not
+ necessary to mark all permanently unavailable resources as "gone" or
+ to keep the mark for any length of time -- that is left to the
+ discretion of the server owner.
+
+10.4.12 411 Length Required
+
+ The server refuses to accept the request without a defined Content-
+ Length. The client MAY repeat the request if it adds a valid
+ Content-Length header field containing the length of the message-body
+ in the request message.
+
+10.4.13 412 Precondition Failed
+
+ The precondition given in one or more of the request-header fields
+ evaluated to false when it was tested on the server. This response
+ code allows the client to place preconditions on the current resource
+ metainformation (header field data) and thus prevent the requested
+ method from being applied to a resource other than the one intended.
+
+10.4.14 413 Request Entity Too Large
+
+ The server is refusing to process a request because the request
+ entity is larger than the server is willing or able to process. The
+ server MAY close the connection to prevent the client from continuing
+ the request.
+
+ If the condition is temporary, the server SHOULD include a Retry-
+ After header field to indicate that it is temporary and after what
+ time the client MAY try again.
+
+10.4.15 414 Request-URI Too Long
+
+ The server is refusing to service the request because the Request-URI
+ is longer than the server is willing to interpret. This rare
+ condition is only likely to occur when a client has improperly
+ converted a POST request to a GET request with long query
+ information, when the client has descended into a URI "black hole" of
+ redirection (e.g., a redirected URI prefix that points to a suffix of
+ itself), or when the server is under attack by a client attempting to
+ exploit security holes present in some servers using fixed-length
+ buffers for reading or manipulating the Request-URI.
+
+10.4.16 415 Unsupported Media Type
+
+ The server is refusing to service the request because the entity of
+ the request is in a format not supported by the requested resource
+ for the requested method.
+
+10.4.17 416 Requested Range Not Satisfiable
+
+ A server SHOULD return a response with this status code if a request
+ included a Range request-header field (section 14.35), and none of
+ the range-specifier values in this field overlap the current extent
+ of the selected resource, and the request did not include an If-Range
+ request-header field. (For byte-ranges, this means that the first-
+ byte-pos of all of the byte-range-spec values were greater than the
+ current length of the selected resource.)
+
+ When this status code is returned for a byte-range request, the
+ response SHOULD include a Content-Range entity-header field
+ specifying the current length of the selected resource (see section
+ 14.16). This response MUST NOT use the multipart/byteranges content-
+ type.
+
+10.4.18 417 Expectation Failed
+
+ The expectation given in an Expect request-header field (see section
+ 14.20) could not be met by this server, or, if the server is a proxy,
+ the server has unambiguous evidence that the request could not be met
+ by the next-hop server.
+
+10.5 Server Error 5xx
+
+ Response status codes beginning with the digit "5" indicate cases in
+ which the server is aware that it has erred or is incapable of
+ performing the request. Except when responding to a HEAD request, the
+ server SHOULD include an entity containing an explanation of the
+ error situation, and whether it is a temporary or permanent
+ condition. User agents SHOULD display any included entity to the
+ user. These response codes are applicable to any request method.
+
+10.5.1 500 Internal Server Error
+
+ The server encountered an unexpected condition which prevented it
+ from fulfilling the request.
+
+10.5.2 501 Not Implemented
+
+ The server does not support the functionality required to fulfill the
+ request. This is the appropriate response when the server does not
+ recognize the request method and is not capable of supporting it for
+ any resource.
+
+10.5.3 502 Bad Gateway
+
+ The server, while acting as a gateway or proxy, received an invalid
+ response from the upstream server it accessed in attempting to
+ fulfill the request.
+
+10.5.4 503 Service Unavailable
+
+ The server is currently unable to handle the request due to a
+ temporary overloading or maintenance of the server. The implication
+ is that this is a temporary condition which will be alleviated after
+ some delay. If known, the length of the delay MAY be indicated in a
+ Retry-After header. If no Retry-After is given, the client SHOULD
+ handle the response as it would for a 500 response.
+
+ Note: The existence of the 503 status code does not imply that a
+ server must use it when becoming overloaded. Some servers may wish
+ to simply refuse the connection.
+
+10.5.5 504 Gateway Timeout
+
+ The server, while acting as a gateway or proxy, did not receive a
+ timely response from the upstream server specified by the URI (e.g.
+ HTTP, FTP, LDAP) or some other auxiliary server (e.g. DNS) it needed
+ to access in attempting to complete the request.
+
+ Note: Note to implementors: some deployed proxies are known to
+ return 400 or 500 when DNS lookups time out.
+
+10.5.6 505 HTTP Version Not Supported
+
+ The server does not support, or refuses to support, the HTTP protocol
+ version that was used in the request message. The server is
+ indicating that it is unable or unwilling to complete the request
+ using the same major version as the client, as described in section
+ 3.1, other than with this error message. The response SHOULD contain
+ an entity describing why that version is not supported and what other
+ protocols are supported by that server.
+
+11 Access Authentication
+
+ HTTP provides several OPTIONAL challenge-response authentication
+ mechanisms which can be used by a server to challenge a client
+ request and by a client to provide authentication information. The
+ general framework for access authentication, and the specification of
+ "basic" and "digest" authentication, are specified in "HTTP
+ Authentication: Basic and Digest Access Authentication" [43]. This
+ specification adopts the definitions of "challenge" and "credentials"
+ from that specification.
+
+12 Content Negotiation
+
+ Most HTTP responses include an entity which contains information for
+ interpretation by a human user. Naturally, it is desirable to supply
+ the user with the "best available" entity corresponding to the
+ request. Unfortunately for servers and caches, not all users have the
+ same preferences for what is "best," and not all user agents are
+ equally capable of rendering all entity types. For that reason, HTTP
+ has provisions for several mechanisms for "content negotiation" --
+ the process of selecting the best representation for a given response
+ when there are multiple representations available.
+
+ Note: This is not called "format negotiation" because the
+ alternate representations may be of the same media type, but use
+ different capabilities of that type, be in different languages,
+ etc.
+
+ Any response containing an entity-body MAY be subject to negotiation,
+ including error responses.
+
+ There are two kinds of content negotiation which are possible in
+ HTTP: server-driven and agent-driven negotiation. These two kinds of
+ negotiation are orthogonal and thus may be used separately or in
+ combination. One method of combination, referred to as transparent
+ negotiation, occurs when a cache uses the agent-driven negotiation
+ information provided by the origin server in order to provide
+ server-driven negotiation for subsequent requests.
+
+12.1 Server-driven Negotiation
+
+ If the selection of the best representation for a response is made by
+ an algorithm located at the server, it is called server-driven
+ negotiation. Selection is based on the available representations of
+ the response (the dimensions over which it can vary; e.g. language,
+ content-coding, etc.) and the contents of particular header fields in
+ the request message or on other information pertaining to the request
+ (such as the network address of the client).
+
+ Server-driven negotiation is advantageous when the algorithm for
+ selecting from among the available representations is difficult to
+ describe to the user agent, or when the server desires to send its
+ "best guess" to the client along with the first response (hoping to
+ avoid the round-trip delay of a subsequent request if the "best
+ guess" is good enough for the user). In order to improve the server's
+ guess, the user agent MAY include request header fields (Accept,
+ Accept-Language, Accept-Encoding, etc.) which describe its
+ preferences for such a response.
+
+ Server-driven negotiation has disadvantages:
+
+ 1. It is impossible for the server to accurately determine what
+ might be "best" for any given user, since that would require
+ complete knowledge of both the capabilities of the user agent
+ and the intended use for the response (e.g., does the user want
+ to view it on screen or print it on paper?).
+
+ 2. Having the user agent describe its capabilities in every
+ request can be both very inefficient (given that only a small
+ percentage of responses have multiple representations) and a
+ potential violation of the user's privacy.
+
+ 3. It complicates the implementation of an origin server and the
+ algorithms for generating responses to a request.
+
+ 4. It may limit a public cache's ability to use the same response
+ for multiple user's requests.
+
+ HTTP/1.1 includes the following request-header fields for enabling
+ server-driven negotiation through description of user agent
+ capabilities and user preferences: Accept (section 14.1), Accept-
+ Charset (section 14.2), Accept-Encoding (section 14.3), Accept-
+ Language (section 14.4), and User-Agent (section 14.43). However, an
+ origin server is not limited to these dimensions and MAY vary the
+ response based on any aspect of the request, including information
+ outside the request-header fields or within extension header fields
+ not defined by this specification.
+
+ The Vary header field can be used to express the parameters the
+ server uses to select a representation that is subject to server-
+ driven negotiation. See section 13.6 for use of the Vary header field
+ by caches and section 14.44 for use of the Vary header field by
+ servers.
+
+12.2 Agent-driven Negotiation
+
+ With agent-driven negotiation, selection of the best representation
+ for a response is performed by the user agent after receiving an
+ initial response from the origin server. Selection is based on a list
+ of the available representations of the response included within the
+ header fields or entity-body of the initial response, with each
+ representation identified by its own URI. Selection from among the
+ representations may be performed automatically (if the user agent is
+ capable of doing so) or manually by the user selecting from a
+ generated (possibly hypertext) menu.
+
+ Agent-driven negotiation is advantageous when the response would vary
+ over commonly-used dimensions (such as type, language, or encoding),
+ when the origin server is unable to determine a user agent's
+ capabilities from examining the request, and generally when public
+ caches are used to distribute server load and reduce network usage.
+
+ Agent-driven negotiation suffers from the disadvantage of needing a
+ second request to obtain the best alternate representation. This
+ second request is only efficient when caching is used. In addition,
+ this specification does not define any mechanism for supporting
+ automatic selection, though it also does not prevent any such
+ mechanism from being developed as an extension and used within
+ HTTP/1.1.
+
+ HTTP/1.1 defines the 300 (Multiple Choices) and 406 (Not Acceptable)
+ status codes for enabling agent-driven negotiation when the server is
+ unwilling or unable to provide a varying response using server-driven
+ negotiation.
+
+12.3 Transparent Negotiation
+
+ Transparent negotiation is a combination of both server-driven and
+ agent-driven negotiation. When a cache is supplied with a form of the
+ list of available representations of the response (as in agent-driven
+ negotiation) and the dimensions of variance are completely understood
+ by the cache, then the cache becomes capable of performing server-
+ driven negotiation on behalf of the origin server for subsequent
+ requests on that resource.
+
+ Transparent negotiation has the advantage of distributing the
+ negotiation work that would otherwise be required of the origin
+ server and also removing the second request delay of agent-driven
+ negotiation when the cache is able to correctly guess the right
+ response.
+
+ This specification does not define any mechanism for transparent
+ negotiation, though it also does not prevent any such mechanism from
+ being developed as an extension that could be used within HTTP/1.1.
+
+13 Caching in HTTP
+
+ HTTP is typically used for distributed information systems, where
+ performance can be improved by the use of response caches. The
+ HTTP/1.1 protocol includes a number of elements intended to make
+ caching work as well as possible. Because these elements are
+ inextricable from other aspects of the protocol, and because they
+ interact with each other, it is useful to describe the basic caching
+ design of HTTP separately from the detailed descriptions of methods,
+ headers, response codes, etc.
+
+ Caching would be useless if it did not significantly improve
+ performance. The goal of caching in HTTP/1.1 is to eliminate the need
+ to send requests in many cases, and to eliminate the need to send
+ full responses in many other cases. The former reduces the number of
+ network round-trips required for many operations; we use an
+ "expiration" mechanism for this purpose (see section 13.2). The
+ latter reduces network bandwidth requirements; we use a "validation"
+ mechanism for this purpose (see section 13.3).
+
+ Requirements for performance, availability, and disconnected
+ operation require us to be able to relax the goal of semantic
+ transparency. The HTTP/1.1 protocol allows origin servers, caches,
+
+ and clients to explicitly reduce transparency when necessary.
+ However, because non-transparent operation may confuse non-expert
+ users, and might be incompatible with certain server applications
+ (such as those for ordering merchandise), the protocol requires that
+ transparency be relaxed
+
+ - only by an explicit protocol-level request when relaxed by
+ client or origin server
+
+ - only with an explicit warning to the end user when relaxed by
+ cache or client
+
+ Therefore, the HTTP/1.1 protocol provides these important elements:
+
+ 1. Protocol features that provide full semantic transparency when
+ this is required by all parties.
+
+ 2. Protocol features that allow an origin server or user agent to
+ explicitly request and control non-transparent operation.
+
+ 3. Protocol features that allow a cache to attach warnings to
+ responses that do not preserve the requested approximation of
+ semantic transparency.
+
+ A basic principle is that it must be possible for the clients to
+ detect any potential relaxation of semantic transparency.
+
+ Note: The server, cache, or client implementor might be faced with
+ design decisions not explicitly discussed in this specification.
+ If a decision might affect semantic transparency, the implementor
+ ought to err on the side of maintaining transparency unless a
+ careful and complete analysis shows significant benefits in
+ breaking transparency.
+
+13.1.1 Cache Correctness
+
+ A correct cache MUST respond to a request with the most up-to-date
+ response held by the cache that is appropriate to the request (see
+ sections 13.2.5, 13.2.6, and 13.12) which meets one of the following
+ conditions:
+
+ 1. It has been checked for equivalence with what the origin server
+ would have returned by revalidating the response with the
+ origin server (section 13.3);
+
+ 2. It is "fresh enough" (see section 13.2). In the default case,
+ this means it meets the least restrictive freshness requirement
+ of the client, origin server, and cache (see section 14.9); if
+ the origin server so specifies, it is the freshness requirement
+ of the origin server alone.
+
+ If a stored response is not "fresh enough" by the most
+ restrictive freshness requirement of both the client and the
+ origin server, in carefully considered circumstances the cache
+ MAY still return the response with the appropriate Warning
+ header (see section 13.1.5 and 14.46), unless such a response
+ is prohibited (e.g., by a "no-store" cache-directive, or by a
+ "no-cache" cache-request-directive; see section 14.9).
+
+ 3. It is an appropriate 304 (Not Modified), 305 (Proxy Redirect),
+ or error (4xx or 5xx) response message.
+
+ If the cache can not communicate with the origin server, then a
+ correct cache SHOULD respond as above if the response can be
+ correctly served from the cache; if not it MUST return an error or
+ warning indicating that there was a communication failure.
+
+ If a cache receives a response (either an entire response, or a 304
+ (Not Modified) response) that it would normally forward to the
+ requesting client, and the received response is no longer fresh, the
+ cache SHOULD forward it to the requesting client without adding a new
+ Warning (but without removing any existing Warning headers). A cache
+ SHOULD NOT attempt to revalidate a response simply because that
+ response became stale in transit; this might lead to an infinite
+ loop. A user agent that receives a stale response without a Warning
+ MAY display a warning indication to the user.
+
+13.1.2 Warnings
+
+ Whenever a cache returns a response that is neither first-hand nor
+ "fresh enough" (in the sense of condition 2 in section 13.1.1), it
+ MUST attach a warning to that effect, using a Warning general-header.
+ The Warning header and the currently defined warnings are described
+ in section 14.46. The warning allows clients to take appropriate
+ action.
+
+ Warnings MAY be used for other purposes, both cache-related and
+ otherwise. The use of a warning, rather than an error status code,
+ distinguish these responses from true failures.
+
+ Warnings are assigned three digit warn-codes. The first digit
+ indicates whether the Warning MUST or MUST NOT be deleted from a
+ stored cache entry after a successful revalidation:
+
+ 1xx Warnings that describe the freshness or revalidation status of
+ the response, and so MUST be deleted after a successful
+ revalidation. 1XX warn-codes MAY be generated by a cache only when
+ validating a cached entry. It MUST NOT be generated by clients.
+
+ 2xx Warnings that describe some aspect of the entity body or entity
+ headers that is not rectified by a revalidation (for example, a
+ lossy compression of the entity bodies) and which MUST NOT be
+ deleted after a successful revalidation.
+
+ See section 14.46 for the definitions of the codes themselves.
+
+ HTTP/1.0 caches will cache all Warnings in responses, without
+ deleting the ones in the first category. Warnings in responses that
+ are passed to HTTP/1.0 caches carry an extra warning-date field,
+ which prevents a future HTTP/1.1 recipient from believing an
+ erroneously cached Warning.
+
+ Warnings also carry a warning text. The text MAY be in any
+ appropriate natural language (perhaps based on the client's Accept
+ headers), and include an OPTIONAL indication of what character set is
+ used.
+
+ Multiple warnings MAY be attached to a response (either by the origin
+ server or by a cache), including multiple warnings with the same code
+ number. For example, a server might provide the same warning with
+ texts in both English and Basque.
+
+ When multiple warnings are attached to a response, it might not be
+ practical or reasonable to display all of them to the user. This
+ version of HTTP does not specify strict priority rules for deciding
+ which warnings to display and in what order, but does suggest some
+ heuristics.
+
+13.1.3 Cache-control Mechanisms
+
+ The basic cache mechanisms in HTTP/1.1 (server-specified expiration
+ times and validators) are implicit directives to caches. In some
+ cases, a server or client might need to provide explicit directives
+ to the HTTP caches. We use the Cache-Control header for this purpose.
+
+ The Cache-Control header allows a client or server to transmit a
+ variety of directives in either requests or responses. These
+ directives typically override the default caching algorithms. As a
+ general rule, if there is any apparent conflict between header
+ values, the most restrictive interpretation is applied (that is, the
+ one that is most likely to preserve semantic transparency). However,
+
+ in some cases, cache-control directives are explicitly specified as
+ weakening the approximation of semantic transparency (for example,
+ "max-stale" or "public").
+
+ The cache-control directives are described in detail in section 14.9.
+
+13.1.4 Explicit User Agent Warnings
+
+ Many user agents make it possible for users to override the basic
+ caching mechanisms. For example, the user agent might allow the user
+ to specify that cached entities (even explicitly stale ones) are
+ never validated. Or the user agent might habitually add "Cache-
+ Control: max-stale=3600" to every request. The user agent SHOULD NOT
+ default to either non-transparent behavior, or behavior that results
+ in abnormally ineffective caching, but MAY be explicitly configured
+ to do so by an explicit action of the user.
+
+ If the user has overridden the basic caching mechanisms, the user
+ agent SHOULD explicitly indicate to the user whenever this results in
+ the display of information that might not meet the server's
+ transparency requirements (in particular, if the displayed entity is
+ known to be stale). Since the protocol normally allows the user agent
+ to determine if responses are stale or not, this indication need only
+ be displayed when this actually happens. The indication need not be a
+ dialog box; it could be an icon (for example, a picture of a rotting
+ fish) or some other indicator.
+
+ If the user has overridden the caching mechanisms in a way that would
+ abnormally reduce the effectiveness of caches, the user agent SHOULD
+ continually indicate this state to the user (for example, by a
+ display of a picture of currency in flames) so that the user does not
+ inadvertently consume excess resources or suffer from excessive
+ latency.
+
+13.1.5 Exceptions to the Rules and Warnings
+
+ In some cases, the operator of a cache MAY choose to configure it to
+ return stale responses even when not requested by clients. This
+ decision ought not be made lightly, but may be necessary for reasons
+ of availability or performance, especially when the cache is poorly
+ connected to the origin server. Whenever a cache returns a stale
+ response, it MUST mark it as such (using a Warning header) enabling
+ the client software to alert the user that there might be a potential
+ problem.
+
+ It also allows the user agent to take steps to obtain a first-hand or
+ fresh response. For this reason, a cache SHOULD NOT return a stale
+ response if the client explicitly requests a first-hand or fresh one,
+ unless it is impossible to comply for technical or policy reasons.
+
+13.1.6 Client-controlled Behavior
+
+ While the origin server (and to a lesser extent, intermediate caches,
+ by their contribution to the age of a response) are the primary
+ source of expiration information, in some cases the client might need
+ to control a cache's decision about whether to return a cached
+ response without validating it. Clients do this using several
+ directives of the Cache-Control header.
+
+ A client's request MAY specify the maximum age it is willing to
+ accept of an unvalidated response; specifying a value of zero forces
+ the cache(s) to revalidate all responses. A client MAY also specify
+ the minimum time remaining before a response expires. Both of these
+ options increase constraints on the behavior of caches, and so cannot
+ further relax the cache's approximation of semantic transparency.
+
+ A client MAY also specify that it will accept stale responses, up to
+ some maximum amount of staleness. This loosens the constraints on the
+ caches, and so might violate the origin server's specified
+ constraints on semantic transparency, but might be necessary to
+ support disconnected operation, or high availability in the face of
+ poor connectivity.
+
+13.2 Expiration Model
+
+13.2.1 Server-Specified Expiration
+
+ HTTP caching works best when caches can entirely avoid making
+ requests to the origin server. The primary mechanism for avoiding
+ requests is for an origin server to provide an explicit expiration
+ time in the future, indicating that a response MAY be used to satisfy
+ subsequent requests. In other words, a cache can return a fresh
+ response without first contacting the server.
+
+ Our expectation is that servers will assign future explicit
+ expiration times to responses in the belief that the entity is not
+ likely to change, in a semantically significant way, before the
+ expiration time is reached. This normally preserves semantic
+ transparency, as long as the server's expiration times are carefully
+ chosen.
+
+ The expiration mechanism applies only to responses taken from a cache
+ and not to first-hand responses forwarded immediately to the
+ requesting client.
+
+ If an origin server wishes to force a semantically transparent cache
+ to validate every request, it MAY assign an explicit expiration time
+ in the past. This means that the response is always stale, and so the
+ cache SHOULD validate it before using it for subsequent requests. See
+ section 14.9.4 for a more restrictive way to force revalidation.
+
+ If an origin server wishes to force any HTTP/1.1 cache, no matter how
+ it is configured, to validate every request, it SHOULD use the "must-
+ revalidate" cache-control directive (see section 14.9).
+
+ Servers specify explicit expiration times using either the Expires
+ header, or the max-age directive of the Cache-Control header.
+
+ An expiration time cannot be used to force a user agent to refresh
+ its display or reload a resource; its semantics apply only to caching
+ mechanisms, and such mechanisms need only check a resource's
+ expiration status when a new request for that resource is initiated.
+ See section 13.13 for an explanation of the difference between caches
+ and history mechanisms.
+
+13.2.2 Heuristic Expiration
+
+ Since origin servers do not always provide explicit expiration times,
+ HTTP caches typically assign heuristic expiration times, employing
+ algorithms that use other header values (such as the Last-Modified
+ time) to estimate a plausible expiration time. The HTTP/1.1
+ specification does not provide specific algorithms, but does impose
+ worst-case constraints on their results. Since heuristic expiration
+ times might compromise semantic transparency, they ought to used
+ cautiously, and we encourage origin servers to provide explicit
+ expiration times as much as possible.
+
+13.2.3 Age Calculations
+
+ In order to know if a cached entry is fresh, a cache needs to know if
+ its age exceeds its freshness lifetime. We discuss how to calculate
+ the latter in section 13.2.4; this section describes how to calculate
+ the age of a response or cache entry.
+
+ In this discussion, we use the term "now" to mean "the current value
+ of the clock at the host performing the calculation." Hosts that use
+ HTTP, but especially hosts running origin servers and caches, SHOULD
+ use NTP [28] or some similar protocol to synchronize their clocks to
+ a globally accurate time standard.
+
+ HTTP/1.1 requires origin servers to send a Date header, if possible,
+ with every response, giving the time at which the response was
+ generated (see section 14.18). We use the term "date_value" to denote
+ the value of the Date header, in a form appropriate for arithmetic
+ operations.
+
+ HTTP/1.1 uses the Age response-header to convey the estimated age of
+ the response message when obtained from a cache. The Age field value
+ is the cache's estimate of the amount of time since the response was
+ generated or revalidated by the origin server.
+
+ In essence, the Age value is the sum of the time that the response
+ has been resident in each of the caches along the path from the
+ origin server, plus the amount of time it has been in transit along
+ network paths.
+
+ We use the term "age_value" to denote the value of the Age header, in
+ a form appropriate for arithmetic operations.
+
+ A response's age can be calculated in two entirely independent ways:
+
+ 1. now minus date_value, if the local clock is reasonably well
+ synchronized to the origin server's clock. If the result is
+ negative, the result is replaced by zero.
+
+ 2. age_value, if all of the caches along the response path
+ implement HTTP/1.1.
+
+ Given that we have two independent ways to compute the age of a
+ response when it is received, we can combine these as
+
+ corrected_received_age = max(now - date_value, age_value)
+
+ and as long as we have either nearly synchronized clocks or all-
+ HTTP/1.1 paths, one gets a reliable (conservative) result.
+
+ Because of network-imposed delays, some significant interval might
+ pass between the time that a server generates a response and the time
+ it is received at the next outbound cache or client. If uncorrected,
+ this delay could result in improperly low ages.
+
+ Because the request that resulted in the returned Age value must have
+ been initiated prior to that Age value's generation, we can correct
+ for delays imposed by the network by recording the time at which the
+ request was initiated. Then, when an Age value is received, it MUST
+ be interpreted relative to the time the request was initiated, not
+
+ the time that the response was received. This algorithm results in
+ conservative behavior no matter how much delay is experienced. So, we
+ compute:
+
+ corrected_initial_age = corrected_received_age
+ + (now - request_time)
+
+ where "request_time" is the time (according to the local clock) when
+ the request that elicited this response was sent.
+
+ Summary of age calculation algorithm, when a cache receives a
+ response:
+
+ /*
+ * age_value
+ * is the value of Age: header received by the cache with
+ * this response.
+ * date_value
+ * is the value of the origin server's Date: header
+ * request_time
+ * is the (local) time when the cache made the request
+ * that resulted in this cached response
+ * response_time
+ * is the (local) time when the cache received the
+ * response
+ * now
+ * is the current (local) time
+ */
+
+ apparent_age = max(0, response_time - date_value);
+ corrected_received_age = max(apparent_age, age_value);
+ response_delay = response_time - request_time;
+ corrected_initial_age = corrected_received_age + response_delay;
+ resident_time = now - response_time;
+ current_age = corrected_initial_age + resident_time;
+
+ The current_age of a cache entry is calculated by adding the amount
+ of time (in seconds) since the cache entry was last validated by the
+ origin server to the corrected_initial_age. When a response is
+ generated from a cache entry, the cache MUST include a single Age
+ header field in the response with a value equal to the cache entry's
+ current_age.
+
+ The presence of an Age header field in a response implies that a
+ response is not first-hand. However, the converse is not true, since
+ the lack of an Age header field in a response does not imply that the
+
+ response is first-hand unless all caches along the request path are
+ compliant with HTTP/1.1 (i.e., older HTTP caches did not implement
+ the Age header field).
+
+13.2.4 Expiration Calculations
+
+ In order to decide whether a response is fresh or stale, we need to
+ compare its freshness lifetime to its age. The age is calculated as
+ described in section 13.2.3; this section describes how to calculate
+ the freshness lifetime, and to determine if a response has expired.
+ In the discussion below, the values can be represented in any form
+ appropriate for arithmetic operations.
+
+ We use the term "expires_value" to denote the value of the Expires
+ header. We use the term "max_age_value" to denote an appropriate
+ value of the number of seconds carried by the "max-age" directive of
+ the Cache-Control header in a response (see section 14.9.3).
+
+ The max-age directive takes priority over Expires, so if max-age is
+ present in a response, the calculation is simply:
+
+ freshness_lifetime = max_age_value
+
+ Otherwise, if Expires is present in the response, the calculation is:
+
+ freshness_lifetime = expires_value - date_value
+
+ Note that neither of these calculations is vulnerable to clock skew,
+ since all of the information comes from the origin server.
+
+ If none of Expires, Cache-Control: max-age, or Cache-Control: s-
+ maxage (see section 14.9.3) appears in the response, and the response
+ does not include other restrictions on caching, the cache MAY compute
+ a freshness lifetime using a heuristic. The cache MUST attach Warning
+ 113 to any response whose age is more than 24 hours if such warning
+ has not already been added.
+
+ Also, if the response does have a Last-Modified time, the heuristic
+ expiration value SHOULD be no more than some fraction of the interval
+ since that time. A typical setting of this fraction might be 10%.
+
+ The calculation to determine if a response has expired is quite
+ simple:
+
+ response_is_fresh = (freshness_lifetime > current_age)
+
+13.2.5 Disambiguating Expiration Values
+
+ Because expiration values are assigned optimistically, it is possible
+ for two caches to contain fresh values for the same resource that are
+ different.
+
+ If a client performing a retrieval receives a non-first-hand response
+ for a request that was already fresh in its own cache, and the Date
+ header in its existing cache entry is newer than the Date on the new
+ response, then the client MAY ignore the response. If so, it MAY
+ retry the request with a "Cache-Control: max-age=0" directive (see
+ section 14.9), to force a check with the origin server.
+
+ If a cache has two fresh responses for the same representation with
+ different validators, it MUST use the one with the more recent Date
+ header. This situation might arise because the cache is pooling
+ responses from other caches, or because a client has asked for a
+ reload or a revalidation of an apparently fresh cache entry.
+
+13.2.6 Disambiguating Multiple Responses
+
+ Because a client might be receiving responses via multiple paths, so
+ that some responses flow through one set of caches and other
+ responses flow through a different set of caches, a client might
+ receive responses in an order different from that in which the origin
+ server sent them. We would like the client to use the most recently
+ generated response, even if older responses are still apparently
+ fresh.
+
+ Neither the entity tag nor the expiration value can impose an
+ ordering on responses, since it is possible that a later response
+ intentionally carries an earlier expiration time. The Date values are
+ ordered to a granularity of one second.
+
+ When a client tries to revalidate a cache entry, and the response it
+ receives contains a Date header that appears to be older than the one
+ for the existing entry, then the client SHOULD repeat the request
+ unconditionally, and include
+
+ Cache-Control: max-age=0
+
+ to force any intermediate caches to validate their copies directly
+ with the origin server, or
+
+ Cache-Control: no-cache
+
+ to force any intermediate caches to obtain a new copy from the origin
+ server.
+
+ If the Date values are equal, then the client MAY use either response
+ (or MAY, if it is being extremely prudent, request a new response).
+ Servers MUST NOT depend on clients being able to choose
+ deterministically between responses generated during the same second,
+ if their expiration times overlap.
+
+13.3 Validation Model
+
+ When a cache has a stale entry that it would like to use as a
+ response to a client's request, it first has to check with the origin
+ server (or possibly an intermediate cache with a fresh response) to
+ see if its cached entry is still usable. We call this "validating"
+ the cache entry. Since we do not want to have to pay the overhead of
+ retransmitting the full response if the cached entry is good, and we
+ do not want to pay the overhead of an extra round trip if the cached
+ entry is invalid, the HTTP/1.1 protocol supports the use of
+ conditional methods.
+
+ The key protocol features for supporting conditional methods are
+ those concerned with "cache validators." When an origin server
+ generates a full response, it attaches some sort of validator to it,
+ which is kept with the cache entry. When a client (user agent or
+ proxy cache) makes a conditional request for a resource for which it
+ has a cache entry, it includes the associated validator in the
+ request.
+
+ The server then checks that validator against the current validator
+ for the entity, and, if they match (see section 13.3.3), it responds
+ with a special status code (usually, 304 (Not Modified)) and no
+ entity-body. Otherwise, it returns a full response (including
+ entity-body). Thus, we avoid transmitting the full response if the
+ validator matches, and we avoid an extra round trip if it does not
+ match.
+
+ In HTTP/1.1, a conditional request looks exactly the same as a normal
+ request for the same resource, except that it carries a special
+ header (which includes the validator) that implicitly turns the
+ method (usually, GET) into a conditional.
+
+ The protocol includes both positive and negative senses of cache-
+ validating conditions. That is, it is possible to request either that
+ a method be performed if and only if a validator matches or if and
+ only if no validators match.
+
+ Note: a response that lacks a validator may still be cached, and
+ served from cache until it expires, unless this is explicitly
+ prohibited by a cache-control directive. However, a cache cannot
+ do a conditional retrieval if it does not have a validator for the
+ entity, which means it will not be refreshable after it expires.
+
+13.3.1 Last-Modified Dates
+
+ The Last-Modified entity-header field value is often used as a cache
+ validator. In simple terms, a cache entry is considered to be valid
+ if the entity has not been modified since the Last-Modified value.
+
+13.3.2 Entity Tag Cache Validators
+
+ The ETag response-header field value, an entity tag, provides for an
+ "opaque" cache validator. This might allow more reliable validation
+ in situations where it is inconvenient to store modification dates,
+ where the one-second resolution of HTTP date values is not
+ sufficient, or where the origin server wishes to avoid certain
+ paradoxes that might arise from the use of modification dates.
+
+ Entity Tags are described in section 3.11. The headers used with
+ entity tags are described in sections 14.19, 14.24, 14.26 and 14.44.
+
+13.3.3 Weak and Strong Validators
+
+ Since both origin servers and caches will compare two validators to
+ decide if they represent the same or different entities, one normally
+ would expect that if the entity (the entity-body or any entity-
+ headers) changes in any way, then the associated validator would
+ change as well. If this is true, then we call this validator a
+ "strong validator."
+
+ However, there might be cases when a server prefers to change the
+ validator only on semantically significant changes, and not when
+ insignificant aspects of the entity change. A validator that does not
+ always change when the resource changes is a "weak validator."
+
+ Entity tags are normally "strong validators," but the protocol
+ provides a mechanism to tag an entity tag as "weak." One can think of
+ a strong validator as one that changes whenever the bits of an entity
+ changes, while a weak value changes whenever the meaning of an entity
+ changes. Alternatively, one can think of a strong validator as part
+ of an identifier for a specific entity, while a weak validator is
+ part of an identifier for a set of semantically equivalent entities.
+
+ Note: One example of a strong validator is an integer that is
+ incremented in stable storage every time an entity is changed.
+
+ An entity's modification time, if represented with one-second
+ resolution, could be a weak validator, since it is possible that
+ the resource might be modified twice during a single second.
+
+ Support for weak validators is optional. However, weak validators
+ allow for more efficient caching of equivalent objects; for
+ example, a hit counter on a site is probably good enough if it is
+ updated every few days or weeks, and any value during that period
+ is likely "good enough" to be equivalent.
+
+ A "use" of a validator is either when a client generates a request
+ and includes the validator in a validating header field, or when a
+ server compares two validators.
+
+ Strong validators are usable in any context. Weak validators are only
+ usable in contexts that do not depend on exact equality of an entity.
+ For example, either kind is usable for a conditional GET of a full
+ entity. However, only a strong validator is usable for a sub-range
+ retrieval, since otherwise the client might end up with an internally
+ inconsistent entity.
+
+ Clients MAY issue simple (non-subrange) GET requests with either weak
+ validators or strong validators. Clients MUST NOT use weak validators
+ in other forms of request.
+
+ The only function that the HTTP/1.1 protocol defines on validators is
+ comparison. There are two validator comparison functions, depending
+ on whether the comparison context allows the use of weak validators
+ or not:
+
+ - The strong comparison function: in order to be considered equal,
+ both validators MUST be identical in every way, and both MUST
+ NOT be weak.
+
+ - The weak comparison function: in order to be considered equal,
+ both validators MUST be identical in every way, but either or
+ both of them MAY be tagged as "weak" without affecting the
+ result.
+
+ An entity tag is strong unless it is explicitly tagged as weak.
+ Section 3.11 gives the syntax for entity tags.
+
+ A Last-Modified time, when used as a validator in a request, is
+ implicitly weak unless it is possible to deduce that it is strong,
+ using the following rules:
+
+ - The validator is being compared by an origin server to the
+ actual current validator for the entity and,
+
+ - That origin server reliably knows that the associated entity did
+ not change twice during the second covered by the presented
+ validator.
+
+ or
+
+ - The validator is about to be used by a client in an If-
+ Modified-Since or If-Unmodified-Since header, because the client
+ has a cache entry for the associated entity, and
+
+ - That cache entry includes a Date value, which gives the time
+ when the origin server sent the original response, and
+
+ - The presented Last-Modified time is at least 60 seconds before
+ the Date value.
+
+ or
+
+ - The validator is being compared by an intermediate cache to the
+ validator stored in its cache entry for the entity, and
+
+ - That cache entry includes a Date value, which gives the time
+ when the origin server sent the original response, and
+
+ - The presented Last-Modified time is at least 60 seconds before
+ the Date value.
+
+ This method relies on the fact that if two different responses were
+ sent by the origin server during the same second, but both had the
+ same Last-Modified time, then at least one of those responses would
+ have a Date value equal to its Last-Modified time. The arbitrary 60-
+ second limit guards against the possibility that the Date and Last-
+ Modified values are generated from different clocks, or at somewhat
+ different times during the preparation of the response. An
+ implementation MAY use a value larger than 60 seconds, if it is
+ believed that 60 seconds is too short.
+
+ If a client wishes to perform a sub-range retrieval on a value for
+ which it has only a Last-Modified time and no opaque validator, it
+ MAY do this only if the Last-Modified time is strong in the sense
+ described here.
+
+ A cache or origin server receiving a conditional request, other than
+ a full-body GET request, MUST use the strong comparison function to
+ evaluate the condition.
+
+ These rules allow HTTP/1.1 caches and clients to safely perform sub-
+ range retrievals on values that have been obtained from HTTP/1.0
+
+ servers.
+
+13.3.4 Rules for When to Use Entity Tags and Last-Modified Dates
+
+ We adopt a set of rules and recommendations for origin servers,
+ clients, and caches regarding when various validator types ought to
+ be used, and for what purposes.
+
+ HTTP/1.1 origin servers:
+
+ - SHOULD send an entity tag validator unless it is not feasible to
+ generate one.
+
+ - MAY send a weak entity tag instead of a strong entity tag, if
+ performance considerations support the use of weak entity tags,
+ or if it is unfeasible to send a strong entity tag.
+
+ - SHOULD send a Last-Modified value if it is feasible to send one,
+ unless the risk of a breakdown in semantic transparency that
+ could result from using this date in an If-Modified-Since header
+ would lead to serious problems.
+
+ In other words, the preferred behavior for an HTTP/1.1 origin server
+ is to send both a strong entity tag and a Last-Modified value.
+
+ In order to be legal, a strong entity tag MUST change whenever the
+ associated entity value changes in any way. A weak entity tag SHOULD
+ change whenever the associated entity changes in a semantically
+ significant way.
+
+ Note: in order to provide semantically transparent caching, an
+ origin server must avoid reusing a specific strong entity tag
+ value for two different entities, or reusing a specific weak
+ entity tag value for two semantically different entities. Cache
+ entries might persist for arbitrarily long periods, regardless of
+ expiration times, so it might be inappropriate to expect that a
+ cache will never again attempt to validate an entry using a
+ validator that it obtained at some point in the past.
+
+ HTTP/1.1 clients:
+
+ - If an entity tag has been provided by the origin server, MUST
+ use that entity tag in any cache-conditional request (using If-
+ Match or If-None-Match).
+
+ - If only a Last-Modified value has been provided by the origin
+ server, SHOULD use that value in non-subrange cache-conditional
+ requests (using If-Modified-Since).
+
+ - If only a Last-Modified value has been provided by an HTTP/1.0
+ origin server, MAY use that value in subrange cache-conditional
+ requests (using If-Unmodified-Since:). The user agent SHOULD
+ provide a way to disable this, in case of difficulty.
+
+ - If both an entity tag and a Last-Modified value have been
+ provided by the origin server, SHOULD use both validators in
+ cache-conditional requests. This allows both HTTP/1.0 and
+ HTTP/1.1 caches to respond appropriately.
+
+ An HTTP/1.1 origin server, upon receiving a conditional request that
+ includes both a Last-Modified date (e.g., in an If-Modified-Since or
+ If-Unmodified-Since header field) and one or more entity tags (e.g.,
+ in an If-Match, If-None-Match, or If-Range header field) as cache
+ validators, MUST NOT return a response status of 304 (Not Modified)
+ unless doing so is consistent with all of the conditional header
+ fields in the request.
+
+ An HTTP/1.1 caching proxy, upon receiving a conditional request that
+ includes both a Last-Modified date and one or more entity tags as
+ cache validators, MUST NOT return a locally cached response to the
+ client unless that cached response is consistent with all of the
+ conditional header fields in the request.
+
+ Note: The general principle behind these rules is that HTTP/1.1
+ servers and clients should transmit as much non-redundant
+ information as is available in their responses and requests.
+ HTTP/1.1 systems receiving this information will make the most
+ conservative assumptions about the validators they receive.
+
+ HTTP/1.0 clients and caches will ignore entity tags. Generally,
+ last-modified values received or used by these systems will
+ support transparent and efficient caching, and so HTTP/1.1 origin
+ servers should provide Last-Modified values. In those rare cases
+ where the use of a Last-Modified value as a validator by an
+ HTTP/1.0 system could result in a serious problem, then HTTP/1.1
+ origin servers should not provide one.
+
+13.3.5 Non-validating Conditionals
+
+ The principle behind entity tags is that only the service author
+ knows the semantics of a resource well enough to select an
+ appropriate cache validation mechanism, and the specification of any
+ validator comparison function more complex than byte-equality would
+ open up a can of worms. Thus, comparisons of any other headers
+ (except Last-Modified, for compatibility with HTTP/1.0) are never
+ used for purposes of validating a cache entry.
+
+13.4 Response Cacheability
+
+ Unless specifically constrained by a cache-control (section 14.9)
+ directive, a caching system MAY always store a successful response
+ (see section 13.8) as a cache entry, MAY return it without validation
+ if it is fresh, and MAY return it after successful validation. If
+ there is neither a cache validator nor an explicit expiration time
+ associated with a response, we do not expect it to be cached, but
+ certain caches MAY violate this expectation (for example, when little
+ or no network connectivity is available). A client can usually detect
+ that such a response was taken from a cache by comparing the Date
+ header to the current time.
+
+ Note: some HTTP/1.0 caches are known to violate this expectation
+ without providing any Warning.
+
+ However, in some cases it might be inappropriate for a cache to
+ retain an entity, or to return it in response to a subsequent
+ request. This might be because absolute semantic transparency is
+ deemed necessary by the service author, or because of security or
+ privacy considerations. Certain cache-control directives are
+ therefore provided so that the server can indicate that certain
+ resource entities, or portions thereof, are not to be cached
+ regardless of other considerations.
+
+ Note that section 14.8 normally prevents a shared cache from saving
+ and returning a response to a previous request if that request
+ included an Authorization header.
+
+ A response received with a status code of 200, 203, 206, 300, 301 or
+ 410 MAY be stored by a cache and used in reply to a subsequent
+ request, subject to the expiration mechanism, unless a cache-control
+ directive prohibits caching. However, a cache that does not support
+ the Range and Content-Range headers MUST NOT cache 206 (Partial
+ Content) responses.
+
+ A response received with any other status code (e.g. status codes 302
+ and 307) MUST NOT be returned in a reply to a subsequent request
+ unless there are cache-control directives or another header(s) that
+ explicitly allow it. For example, these include the following: an
+ Expires header (section 14.21); a "max-age", "s-maxage", "must-
+ revalidate", "proxy-revalidate", "public" or "private" cache-control
+ directive (section 14.9).
+
+13.5 Constructing Responses From Caches
+
+ The purpose of an HTTP cache is to store information received in
+ response to requests for use in responding to future requests. In
+ many cases, a cache simply returns the appropriate parts of a
+ response to the requester. However, if the cache holds a cache entry
+ based on a previous response, it might have to combine parts of a new
+ response with what is held in the cache entry.
+
+13.5.1 End-to-end and Hop-by-hop Headers
+
+ For the purpose of defining the behavior of caches and non-caching
+ proxies, we divide HTTP headers into two categories:
+
+ - End-to-end headers, which are transmitted to the ultimate
+ recipient of a request or response. End-to-end headers in
+ responses MUST be stored as part of a cache entry and MUST be
+ transmitted in any response formed from a cache entry.
+
+ - Hop-by-hop headers, which are meaningful only for a single
+ transport-level connection, and are not stored by caches or
+ forwarded by proxies.
+
+ The following HTTP/1.1 headers are hop-by-hop headers:
+
+ - Connection
+ - Keep-Alive
+ - Proxy-Authenticate
+ - Proxy-Authorization
+ - TE
+ - Trailers
+ - Transfer-Encoding
+ - Upgrade
+
+ All other headers defined by HTTP/1.1 are end-to-end headers.
+
+ Other hop-by-hop headers MUST be listed in a Connection header,
+ (section 14.10) to be introduced into HTTP/1.1 (or later).
+
+13.5.2 Non-modifiable Headers
+
+ Some features of the HTTP/1.1 protocol, such as Digest
+ Authentication, depend on the value of certain end-to-end headers. A
+ transparent proxy SHOULD NOT modify an end-to-end header unless the
+ definition of that header requires or specifically allows that.
+
+ A transparent proxy MUST NOT modify any of the following fields in a
+ request or response, and it MUST NOT add any of these fields if not
+ already present:
+
+ - Content-Location
+
+ - Content-MD5
+
+ - ETag
+
+ - Last-Modified
+
+ A transparent proxy MUST NOT modify any of the following fields in a
+ response:
+
+ - Expires
+
+ but it MAY add any of these fields if not already present. If an
+ Expires header is added, it MUST be given a field-value identical to
+ that of the Date header in that response.
+
+ A proxy MUST NOT modify or add any of the following fields in a
+ message that contains the no-transform cache-control directive, or in
+ any request:
+
+ - Content-Encoding
+
+ - Content-Range
+
+ - Content-Type
+
+ A non-transparent proxy MAY modify or add these fields to a message
+ that does not include no-transform, but if it does so, it MUST add a
+ Warning 214 (Transformation applied) if one does not already appear
+ in the message (see section 14.46).
+
+ Warning: unnecessary modification of end-to-end headers might
+ cause authentication failures if stronger authentication
+ mechanisms are introduced in later versions of HTTP. Such
+ authentication mechanisms MAY rely on the values of header fields
+ not listed here.
+
+ The Content-Length field of a request or response is added or deleted
+ according to the rules in section 4.4. A transparent proxy MUST
+ preserve the entity-length (section 7.2.2) of the entity-body,
+ although it MAY change the transfer-length (section 4.4).
+
+13.5.3 Combining Headers
+
+ When a cache makes a validating request to a server, and the server
+ provides a 304 (Not Modified) response or a 206 (Partial Content)
+ response, the cache then constructs a response to send to the
+ requesting client.
+
+ If the status code is 304 (Not Modified), the cache uses the entity-
+ body stored in the cache entry as the entity-body of this outgoing
+ response. If the status code is 206 (Partial Content) and the ETag or
+ Last-Modified headers match exactly, the cache MAY combine the
+ contents stored in the cache entry with the new contents received in
+ the response and use the result as the entity-body of this outgoing
+ response, (see 13.5.4).
+
+ The end-to-end headers stored in the cache entry are used for the
+ constructed response, except that
+
+ - any stored Warning headers with warn-code 1xx (see section
+ 14.46) MUST be deleted from the cache entry and the forwarded
+ response.
+
+ - any stored Warning headers with warn-code 2xx MUST be retained
+ in the cache entry and the forwarded response.
+
+ - any end-to-end headers provided in the 304 or 206 response MUST
+ replace the corresponding headers from the cache entry.
+
+ Unless the cache decides to remove the cache entry, it MUST also
+ replace the end-to-end headers stored with the cache entry with
+ corresponding headers received in the incoming response, except for
+ Warning headers as described immediately above. If a header field-
+ name in the incoming response matches more than one header in the
+ cache entry, all such old headers MUST be replaced.
+
+ In other words, the set of end-to-end headers received in the
+ incoming response overrides all corresponding end-to-end headers
+ stored with the cache entry (except for stored Warning headers with
+ warn-code 1xx, which are deleted even if not overridden).
+
+ Note: this rule allows an origin server to use a 304 (Not
+ Modified) or a 206 (Partial Content) response to update any header
+ associated with a previous response for the same entity or sub-
+ ranges thereof, although it might not always be meaningful or
+ correct to do so. This rule does not allow an origin server to use
+ a 304 (Not Modified) or a 206 (Partial Content) response to
+ entirely delete a header that it had provided with a previous
+ response.
+
+13.5.4 Combining Byte Ranges
+
+ A response might transfer only a subrange of the bytes of an entity-
+ body, either because the request included one or more Range
+ specifications, or because a connection was broken prematurely. After
+ several such transfers, a cache might have received several ranges of
+ the same entity-body.
+
+ If a cache has a stored non-empty set of subranges for an entity, and
+ an incoming response transfers another subrange, the cache MAY
+ combine the new subrange with the existing set if both the following
+ conditions are met:
+
+ - Both the incoming response and the cache entry have a cache
+ validator.
+
+ - The two cache validators match using the strong comparison
+ function (see section 13.3.3).
+
+ If either requirement is not met, the cache MUST use only the most
+ recent partial response (based on the Date values transmitted with
+ every response, and using the incoming response if these values are
+ equal or missing), and MUST discard the other partial information.
+
+13.6 Caching Negotiated Responses
+
+ Use of server-driven content negotiation (section 12.1), as indicated
+ by the presence of a Vary header field in a response, alters the
+ conditions and procedure by which a cache can use the response for
+ subsequent requests. See section 14.44 for use of the Vary header
+ field by servers.
+
+ A server SHOULD use the Vary header field to inform a cache of what
+ request-header fields were used to select among multiple
+ representations of a cacheable response subject to server-driven
+ negotiation. The set of header fields named by the Vary field value
+ is known as the "selecting" request-headers.
+
+ When the cache receives a subsequent request whose Request-URI
+ specifies one or more cache entries including a Vary header field,
+ the cache MUST NOT use such a cache entry to construct a response to
+ the new request unless all of the selecting request-headers present
+ in the new request match the corresponding stored request-headers in
+ the original request.
+
+ The selecting request-headers from two requests are defined to match
+ if and only if the selecting request-headers in the first request can
+ be transformed to the selecting request-headers in the second request
+
+ by adding or removing linear white space (LWS) at places where this
+ is allowed by the corresponding BNF, and/or combining multiple
+ message-header fields with the same field name following the rules
+ about message headers in section 4.2.
+
+ A Vary header field-value of "*" always fails to match and subsequent
+ requests on that resource can only be properly interpreted by the
+ origin server.
+
+ If the selecting request header fields for the cached entry do not
+ match the selecting request header fields of the new request, then
+ the cache MUST NOT use a cached entry to satisfy the request unless
+ it first relays the new request to the origin server in a conditional
+ request and the server responds with 304 (Not Modified), including an
+ entity tag or Content-Location that indicates the entity to be used.
+
+ If an entity tag was assigned to a cached representation, the
+ forwarded request SHOULD be conditional and include the entity tags
+ in an If-None-Match header field from all its cache entries for the
+ resource. This conveys to the server the set of entities currently
+ held by the cache, so that if any one of these entities matches the
+ requested entity, the server can use the ETag header field in its 304
+ (Not Modified) response to tell the cache which entry is appropriate.
+ If the entity-tag of the new response matches that of an existing
+ entry, the new response SHOULD be used to update the header fields of
+ the existing entry, and the result MUST be returned to the client.
+
+ If any of the existing cache entries contains only partial content
+ for the associated entity, its entity-tag SHOULD NOT be included in
+ the If-None-Match header field unless the request is for a range that
+ would be fully satisfied by that entry.
+
+ If a cache receives a successful response whose Content-Location
+ field matches that of an existing cache entry for the same Request-
+ ]URI, whose entity-tag differs from that of the existing entry, and
+ whose Date is more recent than that of the existing entry, the
+ existing entry SHOULD NOT be returned in response to future requests
+ and SHOULD be deleted from the cache.
+
+13.7 Shared and Non-Shared Caches
+
+ For reasons of security and privacy, it is necessary to make a
+ distinction between "shared" and "non-shared" caches. A non-shared
+ cache is one that is accessible only to a single user. Accessibility
+ in this case SHOULD be enforced by appropriate security mechanisms.
+ All other caches are considered to be "shared." Other sections of
+
+ this specification place certain constraints on the operation of
+ shared caches in order to prevent loss of privacy or failure of
+ access controls.
+
+13.8 Errors or Incomplete Response Cache Behavior
+
+ A cache that receives an incomplete response (for example, with fewer
+ bytes of data than specified in a Content-Length header) MAY store
+ the response. However, the cache MUST treat this as a partial
+ response. Partial responses MAY be combined as described in section
+ 13.5.4; the result might be a full response or might still be
+ partial. A cache MUST NOT return a partial response to a client
+ without explicitly marking it as such, using the 206 (Partial
+ Content) status code. A cache MUST NOT return a partial response
+ using a status code of 200 (OK).
+
+ If a cache receives a 5xx response while attempting to revalidate an
+ entry, it MAY either forward this response to the requesting client,
+ or act as if the server failed to respond. In the latter case, it MAY
+ return a previously received response unless the cached entry
+ includes the "must-revalidate" cache-control directive (see section
+ 14.9).
+
+13.9 Side Effects of GET and HEAD
+
+ Unless the origin server explicitly prohibits the caching of their
+ responses, the application of GET and HEAD methods to any resources
+ SHOULD NOT have side effects that would lead to erroneous behavior if
+ these responses are taken from a cache. They MAY still have side
+ effects, but a cache is not required to consider such side effects in
+ its caching decisions. Caches are always expected to observe an
+ origin server's explicit restrictions on caching.
+
+ We note one exception to this rule: since some applications have
+ traditionally used GETs and HEADs with query URLs (those containing a
+ "?" in the rel_path part) to perform operations with significant side
+ effects, caches MUST NOT treat responses to such URIs as fresh unless
+ the server provides an explicit expiration time. This specifically
+ means that responses from HTTP/1.0 servers for such URIs SHOULD NOT
+ be taken from a cache. See section 9.1.1 for related information.
+
+13.10 Invalidation After Updates or Deletions
+
+ The effect of certain methods performed on a resource at the origin
+ server might cause one or more existing cache entries to become non-
+ transparently invalid. That is, although they might continue to be
+ "fresh," they do not accurately reflect what the origin server would
+ return for a new request on that resource.
+
+ There is no way for the HTTP protocol to guarantee that all such
+ cache entries are marked invalid. For example, the request that
+ caused the change at the origin server might not have gone through
+ the proxy where a cache entry is stored. However, several rules help
+ reduce the likelihood of erroneous behavior.
+
+ In this section, the phrase "invalidate an entity" means that the
+ cache will either remove all instances of that entity from its
+ storage, or will mark these as "invalid" and in need of a mandatory
+ revalidation before they can be returned in response to a subsequent
+ request.
+
+ Some HTTP methods MUST cause a cache to invalidate an entity. This is
+ either the entity referred to by the Request-URI, or by the Location
+ or Content-Location headers (if present). These methods are:
+
+ - PUT
+
+ - DELETE
+
+ - POST
+
+ In order to prevent denial of service attacks, an invalidation based
+ on the URI in a Location or Content-Location header MUST only be
+ performed if the host part is the same as in the Request-URI.
+
+ A cache that passes through requests for methods it does not
+ understand SHOULD invalidate any entities referred to by the
+ Request-URI.
+
+13.11 Write-Through Mandatory
+
+ All methods that might be expected to cause modifications to the
+ origin server's resources MUST be written through to the origin
+ server. This currently includes all methods except for GET and HEAD.
+ A cache MUST NOT reply to such a request from a client before having
+ transmitted the request to the inbound server, and having received a
+ corresponding response from the inbound server. This does not prevent
+ a proxy cache from sending a 100 (Continue) response before the
+ inbound server has sent its final reply.
+
+ The alternative (known as "write-back" or "copy-back" caching) is not
+ allowed in HTTP/1.1, due to the difficulty of providing consistent
+ updates and the problems arising from server, cache, or network
+ failure prior to write-back.
+
+13.12 Cache Replacement
+
+ If a new cacheable (see sections 14.9.2, 13.2.5, 13.2.6 and 13.8)
+ response is received from a resource while any existing responses for
+ the same resource are cached, the cache SHOULD use the new response
+ to reply to the current request. It MAY insert it into cache storage
+ and MAY, if it meets all other requirements, use it to respond to any
+ future requests that would previously have caused the old response to
+ be returned. If it inserts the new response into cache storage the
+ rules in section 13.5.3 apply.
+
+ Note: a new response that has an older Date header value than
+ existing cached responses is not cacheable.
+
+13.13 History Lists
+
+ User agents often have history mechanisms, such as "Back" buttons and
+ history lists, which can be used to redisplay an entity retrieved
+ earlier in a session.
+
+ History mechanisms and caches are different. In particular history
+ mechanisms SHOULD NOT try to show a semantically transparent view of
+ the current state of a resource. Rather, a history mechanism is meant
+ to show exactly what the user saw at the time when the resource was
+ retrieved.
+
+ By default, an expiration time does not apply to history mechanisms.
+ If the entity is still in storage, a history mechanism SHOULD display
+ it even if the entity has expired, unless the user has specifically
+ configured the agent to refresh expired history documents.
+
+ This is not to be construed to prohibit the history mechanism from
+ telling the user that a view might be stale.
+
+ Note: if history list mechanisms unnecessarily prevent users from
+ viewing stale resources, this will tend to force service authors
+ to avoid using HTTP expiration controls and cache controls when
+ they would otherwise like to. Service authors may consider it
+ important that users not be presented with error messages or
+ warning messages when they use navigation controls (such as BACK)
+ to view previously fetched resources. Even though sometimes such
+ resources ought not to cached, or ought to expire quickly, user
+ interface considerations may force service authors to resort to
+ other means of preventing caching (e.g. "once-only" URLs) in order
+ not to suffer the effects of improperly functioning history
+ mechanisms.
+
+14 Header Field Definitions
+
+ This section defines the syntax and semantics of all standard
+ HTTP/1.1 header fields. For entity-header fields, both sender and
+ recipient refer to either the client or the server, depending on who
+ sends and who receives the entity.
+
+14.1 Accept
+
+ The Accept request-header field can be used to specify certain media
+ types which are acceptable for the response. Accept headers can be
+ used to indicate that the request is specifically limited to a small
+ set of desired types, as in the case of a request for an in-line
+ image.
+
+ Accept = "Accept" ":"
+ #( media-range [ accept-params ] )
+
+ media-range = ( "*/*"
+ | ( type "/" "*" )
+ | ( type "/" subtype )
+ ) *( ";" parameter )
+ accept-params = ";" "q" "=" qvalue *( accept-extension )
+ accept-extension = ";" token [ "=" ( token | quoted-string ) ]
+
+ The asterisk "*" character is used to group media types into ranges,
+ with "*/*" indicating all media types and "type/*" indicating all
+ subtypes of that type. The media-range MAY include media type
+ parameters that are applicable to that range.
+
+ Each media-range MAY be followed by one or more accept-params,
+ beginning with the "q" parameter for indicating a relative quality
+ factor. The first "q" parameter (if any) separates the media-range
+ parameter(s) from the accept-params. Quality factors allow the user
+ or user agent to indicate the relative degree of preference for that
+ media-range, using the qvalue scale from 0 to 1 (section 3.9). The
+ default value is q=1.
+
+ Note: Use of the "q" parameter name to separate media type
+ parameters from Accept extension parameters is due to historical
+ practice. Although this prevents any media type parameter named
+ "q" from being used with a media range, such an event is believed
+ to be unlikely given the lack of any "q" parameters in the IANA
+ media type registry and the rare usage of any media type
+ parameters in Accept. Future media types are discouraged from
+ registering any parameter named "q".
+
+ The example
+
+ Accept: audio/*; q=0.2, audio/basic
+
+ SHOULD be interpreted as "I prefer audio/basic, but send me any audio
+ type if it is the best available after an 80% mark-down in quality."
+
+ If no Accept header field is present, then it is assumed that the
+ client accepts all media types. If an Accept header field is present,
+ and if the server cannot send a response which is acceptable
+ according to the combined Accept field value, then the server SHOULD
+ send a 406 (not acceptable) response.
+
+ A more elaborate example is
+
+ Accept: text/plain; q=0.5, text/html,
+ text/x-dvi; q=0.8, text/x-c
+
+ Verbally, this would be interpreted as "text/html and text/x-c are
+ the preferred media types, but if they do not exist, then send the
+ text/x-dvi entity, and if that does not exist, send the text/plain
+ entity."
+
+ Media ranges can be overridden by more specific media ranges or
+ specific media types. If more than one media range applies to a given
+ type, the most specific reference has precedence. For example,
+
+ Accept: text/*, text/html, text/html;level=1, */*
+
+ have the following precedence:
+
+ 1) text/html;level=1
+ 2) text/html
+ 3) text/*
+ 4) */*
+
+ The media type quality factor associated with a given type is
+ determined by finding the media range with the highest precedence
+ which matches that type. For example,
+
+ Accept: text/*;q=0.3, text/html;q=0.7, text/html;level=1,
+ text/html;level=2;q=0.4, */*;q=0.5
+
+ would cause the following values to be associated:
+
+ text/html;level=1 = 1
+ text/html = 0.7
+ text/plain = 0.3
+
+ image/jpeg = 0.5
+ text/html;level=2 = 0.4
+ text/html;level=3 = 0.7
+
+ Note: A user agent might be provided with a default set of quality
+ values for certain media ranges. However, unless the user agent is
+ a closed system which cannot interact with other rendering agents,
+ this default set ought to be configurable by the user.
+
+14.2 Accept-Charset
+
+ The Accept-Charset request-header field can be used to indicate what
+ character sets are acceptable for the response. This field allows
+ clients capable of understanding more comprehensive or special-
+ purpose character sets to signal that capability to a server which is
+ capable of representing documents in those character sets.
+
+ Accept-Charset = "Accept-Charset" ":"
+ 1#( ( charset | "*" )[ ";" "q" "=" qvalue ] )
+
+ Character set values are described in section 3.4. Each charset MAY
+ be given an associated quality value which represents the user's
+ preference for that charset. The default value is q=1. An example is
+
+ Accept-Charset: iso-8859-5, unicode-1-1;q=0.8
+
+ The special value "*", if present in the Accept-Charset field,
+ matches every character set (including ISO-8859-1) which is not
+ mentioned elsewhere in the Accept-Charset field. If no "*" is present
+ in an Accept-Charset field, then all character sets not explicitly
+ mentioned get a quality value of 0, except for ISO-8859-1, which gets
+ a quality value of 1 if not explicitly mentioned.
+
+ If no Accept-Charset header is present, the default is that any
+ character set is acceptable. If an Accept-Charset header is present,
+ and if the server cannot send a response which is acceptable
+ according to the Accept-Charset header, then the server SHOULD send
+ an error response with the 406 (not acceptable) status code, though
+ the sending of an unacceptable response is also allowed.
+
+14.3 Accept-Encoding
+
+ The Accept-Encoding request-header field is similar to Accept, but
+ restricts the content-codings (section 3.5) that are acceptable in
+ the response.
+
+ Accept-Encoding = "Accept-Encoding" ":"
+
+ 1#( codings [ ";" "q" "=" qvalue ] )
+ codings = ( content-coding | "*" )
+
+ Examples of its use are:
+
+ Accept-Encoding: compress, gzip
+ Accept-Encoding:
+ Accept-Encoding: *
+ Accept-Encoding: compress;q=0.5, gzip;q=1.0
+ Accept-Encoding: gzip;q=1.0, identity; q=0.5, *;q=0
+
+ A server tests whether a content-coding is acceptable, according to
+ an Accept-Encoding field, using these rules:
+
+ 1. If the content-coding is one of the content-codings listed in
+ the Accept-Encoding field, then it is acceptable, unless it is
+ accompanied by a qvalue of 0. (As defined in section 3.9, a
+ qvalue of 0 means "not acceptable.")
+
+ 2. The special "*" symbol in an Accept-Encoding field matches any
+ available content-coding not explicitly listed in the header
+ field.
+
+ 3. If multiple content-codings are acceptable, then the acceptable
+ content-coding with the highest non-zero qvalue is preferred.
+
+ 4. The "identity" content-coding is always acceptable, unless
+ specifically refused because the Accept-Encoding field includes
+ "identity;q=0", or because the field includes "*;q=0" and does
+ not explicitly include the "identity" content-coding. If the
+ Accept-Encoding field-value is empty, then only the "identity"
+ encoding is acceptable.
+
+ If an Accept-Encoding field is present in a request, and if the
+ server cannot send a response which is acceptable according to the
+ Accept-Encoding header, then the server SHOULD send an error response
+ with the 406 (Not Acceptable) status code.
+
+ If no Accept-Encoding field is present in a request, the server MAY
+ assume that the client will accept any content coding. In this case,
+ if "identity" is one of the available content-codings, then the
+ server SHOULD use the "identity" content-coding, unless it has
+ additional information that a different content-coding is meaningful
+ to the client.
+
+ Note: If the request does not include an Accept-Encoding field,
+ and if the "identity" content-coding is unavailable, then
+ content-codings commonly understood by HTTP/1.0 clients (i.e.,
+
+ "gzip" and "compress") are preferred; some older clients
+ improperly display messages sent with other content-codings. The
+ server might also make this decision based on information about
+ the particular user-agent or client.
+
+ Note: Most HTTP/1.0 applications do not recognize or obey qvalues
+ associated with content-codings. This means that qvalues will not
+ work and are not permitted with x-gzip or x-compress.
+
+14.4 Accept-Language
+
+ The Accept-Language request-header field is similar to Accept, but
+ restricts the set of natural languages that are preferred as a
+ response to the request. Language tags are defined in section 3.10.
+
+ Accept-Language = "Accept-Language" ":"
+ 1#( language-range [ ";" "q" "=" qvalue ] )
+ language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )
+
+ Each language-range MAY be given an associated quality value which
+ represents an estimate of the user's preference for the languages
+ specified by that range. The quality value defaults to "q=1". For
+ example,
+
+ Accept-Language: da, en-gb;q=0.8, en;q=0.7
+
+ would mean: "I prefer Danish, but will accept British English and
+ other types of English." A language-range matches a language-tag if
+ it exactly equals the tag, or if it exactly equals a prefix of the
+ tag such that the first tag character following the prefix is "-".
+ The special range "*", if present in the Accept-Language field,
+ matches every tag not matched by any other range present in the
+ Accept-Language field.
+
+ Note: This use of a prefix matching rule does not imply that
+ language tags are assigned to languages in such a way that it is
+ always true that if a user understands a language with a certain
+ tag, then this user will also understand all languages with tags
+ for which this tag is a prefix. The prefix rule simply allows the
+ use of prefix tags if this is the case.
+
+ The language quality factor assigned to a language-tag by the
+ Accept-Language field is the quality value of the longest language-
+ range in the field that matches the language-tag. If no language-
+ range in the field matches the tag, the language quality factor
+ assigned is 0. If no Accept-Language header is present in the
+ request, the server
+
+ SHOULD assume that all languages are equally acceptable. If an
+ Accept-Language header is present, then all languages which are
+ assigned a quality factor greater than 0 are acceptable.
+
+ It might be contrary to the privacy expectations of the user to send
+ an Accept-Language header with the complete linguistic preferences of
+ the user in every request. For a discussion of this issue, see
+ section 15.1.4.
+
+ As intelligibility is highly dependent on the individual user, it is
+ recommended that client applications make the choice of linguistic
+ preference available to the user. If the choice is not made
+ available, then the Accept-Language header field MUST NOT be given in
+ the request.
+
+ Note: When making the choice of linguistic preference available to
+ the user, we remind implementors of the fact that users are not
+ familiar with the details of language matching as described above,
+ and should provide appropriate guidance. As an example, users
+ might assume that on selecting "en-gb", they will be served any
+ kind of English document if British English is not available. A
+ user agent might suggest in such a case to add "en" to get the
+ best matching behavior.
+
+14.5 Accept-Ranges
+
+ The Accept-Ranges response-header field allows the server to
+ indicate its acceptance of range requests for a resource:
+
+ Accept-Ranges = "Accept-Ranges" ":" acceptable-ranges
+ acceptable-ranges = 1#range-unit | "none"
+
+ Origin servers that accept byte-range requests MAY send
+
+ Accept-Ranges: bytes
+
+ but are not required to do so. Clients MAY generate byte-range
+ requests without having received this header for the resource
+ involved. Range units are defined in section 3.12.
+
+ Servers that do not accept any kind of range request for a
+ resource MAY send
+
+ Accept-Ranges: none
+
+ to advise the client not to attempt a range request.
+
+14.6 Age
+
+ The Age response-header field conveys the sender's estimate of the
+ amount of time since the response (or its revalidation) was
+ generated at the origin server. A cached response is "fresh" if
+ its age does not exceed its freshness lifetime. Age values are
+ calculated as specified in section 13.2.3.
+
+ Age = "Age" ":" age-value
+ age-value = delta-seconds
+
+ Age values are non-negative decimal integers, representing time in
+ seconds.
+
+ If a cache receives a value larger than the largest positive
+ integer it can represent, or if any of its age calculations
+ overflows, it MUST transmit an Age header with a value of
+ 2147483648 (2^31). An HTTP/1.1 server that includes a cache MUST
+ include an Age header field in every response generated from its
+ own cache. Caches SHOULD use an arithmetic type of at least 31
+ bits of range.
+
+14.7 Allow
+
+ The Allow entity-header field lists the set of methods supported
+ by the resource identified by the Request-URI. The purpose of this
+ field is strictly to inform the recipient of valid methods
+ associated with the resource. An Allow header field MUST be
+ present in a 405 (Method Not Allowed) response.
+
+ Allow = "Allow" ":" #Method
+
+ Example of use:
+
+ Allow: GET, HEAD, PUT
+
+ This field cannot prevent a client from trying other methods.
+ However, the indications given by the Allow header field value
+ SHOULD be followed. The actual set of allowed methods is defined
+ by the origin server at the time of each request.
+
+ The Allow header field MAY be provided with a PUT request to
+ recommend the methods to be supported by the new or modified
+ resource. The server is not required to support these methods and
+ SHOULD include an Allow header in the response giving the actual
+ supported methods.
+
+ A proxy MUST NOT modify the Allow header field even if it does not
+ understand all the methods specified, since the user agent might
+ have other means of communicating with the origin server.
+
+14.8 Authorization
+
+ A user agent that wishes to authenticate itself with a server--
+ usually, but not necessarily, after receiving a 401 response--does
+ so by including an Authorization request-header field with the
+ request. The Authorization field value consists of credentials
+ containing the authentication information of the user agent for
+ the realm of the resource being requested.
+
+ Authorization = "Authorization" ":" credentials
+
+ HTTP access authentication is described in "HTTP Authentication:
+ Basic and Digest Access Authentication" [43]. If a request is
+ authenticated and a realm specified, the same credentials SHOULD
+ be valid for all other requests within this realm (assuming that
+ the authentication scheme itself does not require otherwise, such
+ as credentials that vary according to a challenge value or using
+ synchronized clocks).
+
+ When a shared cache (see section 13.7) receives a request
+ containing an Authorization field, it MUST NOT return the
+ corresponding response as a reply to any other request, unless one
+ of the following specific exceptions holds:
+
+ 1. If the response includes the "s-maxage" cache-control
+ directive, the cache MAY use that response in replying to a
+ subsequent request. But (if the specified maximum age has
+ passed) a proxy cache MUST first revalidate it with the origin
+ server, using the request-headers from the new request to allow
+ the origin server to authenticate the new request. (This is the
+ defined behavior for s-maxage.) If the response includes "s-
+ maxage=0", the proxy MUST always revalidate it before re-using
+ it.
+
+ 2. If the response includes the "must-revalidate" cache-control
+ directive, the cache MAY use that response in replying to a
+ subsequent request. But if the response is stale, all caches
+ MUST first revalidate it with the origin server, using the
+ request-headers from the new request to allow the origin server
+ to authenticate the new request.
+
+ 3. If the response includes the "public" cache-control directive,
+ it MAY be returned in reply to any subsequent request.
+
+14.9 Cache-Control
+
+ The Cache-Control general-header field is used to specify directives
+ that MUST be obeyed by all caching mechanisms along the
+ request/response chain. The directives specify behavior intended to
+ prevent caches from adversely interfering with the request or
+ response. These directives typically override the default caching
+ algorithms. Cache directives are unidirectional in that the presence
+ of a directive in a request does not imply that the same directive is
+ to be given in the response.
+
+ Note that HTTP/1.0 caches might not implement Cache-Control and
+ might only implement Pragma: no-cache (see section 14.32).
+
+ Cache directives MUST be passed through by a proxy or gateway
+ application, regardless of their significance to that application,
+ since the directives might be applicable to all recipients along the
+ request/response chain. It is not possible to specify a cache-
+ directive for a specific cache.
+
+ Cache-Control = "Cache-Control" ":" 1#cache-directive
+
+ cache-directive = cache-request-directive
+ | cache-response-directive
+
+ cache-request-directive =
+ "no-cache" ; Section 14.9.1
+ | "no-store" ; Section 14.9.2
+ | "max-age" "=" delta-seconds ; Section 14.9.3, 14.9.4
+ | "max-stale" [ "=" delta-seconds ] ; Section 14.9.3
+ | "min-fresh" "=" delta-seconds ; Section 14.9.3
+ | "no-transform" ; Section 14.9.5
+ | "only-if-cached" ; Section 14.9.4
+ | cache-extension ; Section 14.9.6
+
+ cache-response-directive =
+ "public" ; Section 14.9.1
+ | "private" [ "=" <"> 1#field-name <"> ] ; Section 14.9.1
+ | "no-cache" [ "=" <"> 1#field-name <"> ]; Section 14.9.1
+ | "no-store" ; Section 14.9.2
+ | "no-transform" ; Section 14.9.5
+ | "must-revalidate" ; Section 14.9.4
+ | "proxy-revalidate" ; Section 14.9.4
+ | "max-age" "=" delta-seconds ; Section 14.9.3
+ | "s-maxage" "=" delta-seconds ; Section 14.9.3
+ | cache-extension ; Section 14.9.6
+
+ cache-extension = token [ "=" ( token | quoted-string ) ]
+
+ When a directive appears without any 1#field-name parameter, the
+ directive applies to the entire request or response. When such a
+ directive appears with a 1#field-name parameter, it applies only to
+ the named field or fields, and not to the rest of the request or
+ response. This mechanism supports extensibility; implementations of
+ future versions of the HTTP protocol might apply these directives to
+ header fields not defined in HTTP/1.1.
+
+ The cache-control directives can be broken down into these general
+ categories:
+
+ - Restrictions on what are cacheable; these may only be imposed by
+ the origin server.
+
+ - Restrictions on what may be stored by a cache; these may be
+ imposed by either the origin server or the user agent.
+
+ - Modifications of the basic expiration mechanism; these may be
+ imposed by either the origin server or the user agent.
+
+ - Controls over cache revalidation and reload; these may only be
+ imposed by a user agent.
+
+ - Control over transformation of entities.
+
+ - Extensions to the caching system.
+
+14.9.1 What is Cacheable
+
+ By default, a response is cacheable if the requirements of the
+ request method, request header fields, and the response status
+ indicate that it is cacheable. Section 13.4 summarizes these defaults
+ for cacheability. The following Cache-Control response directives
+ allow an origin server to override the default cacheability of a
+ response:
+
+ public
+ Indicates that the response MAY be cached by any cache, even if it
+ would normally be non-cacheable or cacheable only within a non-
+ shared cache. (See also Authorization, section 14.8, for
+ additional details.)
+
+ private
+ Indicates that all or part of the response message is intended for
+ a single user and MUST NOT be cached by a shared cache. This
+ allows an origin server to state that the specified parts of the
+
+ response are intended for only one user and are not a valid
+ response for requests by other users. A private (non-shared) cache
+ MAY cache the response.
+
+ Note: This usage of the word private only controls where the
+ response may be cached, and cannot ensure the privacy of the
+ message content.
+
+ no-cache
+ If the no-cache directive does not specify a field-name, then a
+ cache MUST NOT use the response to satisfy a subsequent request
+ without successful revalidation with the origin server. This
+ allows an origin server to prevent caching even by caches that
+ have been configured to return stale responses to client requests.
+
+ If the no-cache directive does specify one or more field-names,
+ then a cache MAY use the response to satisfy a subsequent request,
+ subject to any other restrictions on caching. However, the
+ specified field-name(s) MUST NOT be sent in the response to a
+ subsequent request without successful revalidation with the origin
+ server. This allows an origin server to prevent the re-use of
+ certain header fields in a response, while still allowing caching
+ of the rest of the response.
+
+ Note: Most HTTP/1.0 caches will not recognize or obey this
+ directive.
+
+14.9.2 What May be Stored by Caches
+
+ no-store
+ The purpose of the no-store directive is to prevent the
+ inadvertent release or retention of sensitive information (for
+ example, on backup tapes). The no-store directive applies to the
+ entire message, and MAY be sent either in a response or in a
+ request. If sent in a request, a cache MUST NOT store any part of
+ either this request or any response to it. If sent in a response,
+ a cache MUST NOT store any part of either this response or the
+ request that elicited it. This directive applies to both non-
+ shared and shared caches. "MUST NOT store" in this context means
+ that the cache MUST NOT intentionally store the information in
+ non-volatile storage, and MUST make a best-effort attempt to
+ remove the information from volatile storage as promptly as
+ possible after forwarding it.
+
+ Even when this directive is associated with a response, users
+ might explicitly store such a response outside of the caching
+ system (e.g., with a "Save As" dialog). History buffers MAY store
+ such responses as part of their normal operation.
+
+ The purpose of this directive is to meet the stated requirements
+ of certain users and service authors who are concerned about
+ accidental releases of information via unanticipated accesses to
+ cache data structures. While the use of this directive might
+ improve privacy in some cases, we caution that it is NOT in any
+ way a reliable or sufficient mechanism for ensuring privacy. In
+ particular, malicious or compromised caches might not recognize or
+ obey this directive, and communications networks might be
+ vulnerable to eavesdropping.
+
+14.9.3 Modifications of the Basic Expiration Mechanism
+
+ The expiration time of an entity MAY be specified by the origin
+ server using the Expires header (see section 14.21). Alternatively,
+ it MAY be specified using the max-age directive in a response. When
+ the max-age cache-control directive is present in a cached response,
+ the response is stale if its current age is greater than the age
+ value given (in seconds) at the time of a new request for that
+ resource. The max-age directive on a response implies that the
+ response is cacheable (i.e., "public") unless some other, more
+ restrictive cache directive is also present.
+
+ If a response includes both an Expires header and a max-age
+ directive, the max-age directive overrides the Expires header, even
+ if the Expires header is more restrictive. This rule allows an origin
+ server to provide, for a given response, a longer expiration time to
+ an HTTP/1.1 (or later) cache than to an HTTP/1.0 cache. This might be
+ useful if certain HTTP/1.0 caches improperly calculate ages or
+ expiration times, perhaps due to desynchronized clocks.
+
+ Many HTTP/1.0 cache implementations will treat an Expires value that
+ is less than or equal to the response Date value as being equivalent
+ to the Cache-Control response directive "no-cache". If an HTTP/1.1
+ cache receives such a response, and the response does not include a
+ Cache-Control header field, it SHOULD consider the response to be
+ non-cacheable in order to retain compatibility with HTTP/1.0 servers.
+
+ Note: An origin server might wish to use a relatively new HTTP
+ cache control feature, such as the "private" directive, on a
+ network including older caches that do not understand that
+ feature. The origin server will need to combine the new feature
+ with an Expires field whose value is less than or equal to the
+ Date value. This will prevent older caches from improperly
+ caching the response.
+
+ s-maxage
+ If a response includes an s-maxage directive, then for a shared
+ cache (but not for a private cache), the maximum age specified by
+ this directive overrides the maximum age specified by either the
+ max-age directive or the Expires header. The s-maxage directive
+ also implies the semantics of the proxy-revalidate directive (see
+ section 14.9.4), i.e., that the shared cache must not use the
+ entry after it becomes stale to respond to a subsequent request
+ without first revalidating it with the origin server. The s-
+ maxage directive is always ignored by a private cache.
+
+ Note that most older caches, not compliant with this specification,
+ do not implement any cache-control directives. An origin server
+ wishing to use a cache-control directive that restricts, but does not
+ prevent, caching by an HTTP/1.1-compliant cache MAY exploit the
+ requirement that the max-age directive overrides the Expires header,
+ and the fact that pre-HTTP/1.1-compliant caches do not observe the
+ max-age directive.
+
+ Other directives allow a user agent to modify the basic expiration
+ mechanism. These directives MAY be specified on a request:
+
+ max-age
+ Indicates that the client is willing to accept a response whose
+ age is no greater than the specified time in seconds. Unless max-
+ stale directive is also included, the client is not willing to
+ accept a stale response.
+
+ min-fresh
+ Indicates that the client is willing to accept a response whose
+ freshness lifetime is no less than its current age plus the
+ specified time in seconds. That is, the client wants a response
+ that will still be fresh for at least the specified number of
+ seconds.
+
+ max-stale
+ Indicates that the client is willing to accept a response that has
+ exceeded its expiration time. If max-stale is assigned a value,
+ then the client is willing to accept a response that has exceeded
+ its expiration time by no more than the specified number of
+ seconds. If no value is assigned to max-stale, then the client is
+ willing to accept a stale response of any age.
+
+ If a cache returns a stale response, either because of a max-stale
+ directive on a request, or because the cache is configured to
+ override the expiration time of a response, the cache MUST attach a
+ Warning header to the stale response, using Warning 110 (Response is
+ stale).
+
+ A cache MAY be configured to return stale responses without
+ validation, but only if this does not conflict with any "MUST"-level
+ requirements concerning cache validation (e.g., a "must-revalidate"
+ cache-control directive).
+
+ If both the new request and the cached entry include "max-age"
+ directives, then the lesser of the two values is used for determining
+ the freshness of the cached entry for that request.
+
+14.9.4 Cache Revalidation and Reload Controls
+
+ Sometimes a user agent might want or need to insist that a cache
+ revalidate its cache entry with the origin server (and not just with
+ the next cache along the path to the origin server), or to reload its
+ cache entry from the origin server. End-to-end revalidation might be
+ necessary if either the cache or the origin server has overestimated
+ the expiration time of the cached response. End-to-end reload may be
+ necessary if the cache entry has become corrupted for some reason.
+
+ End-to-end revalidation may be requested either when the client does
+ not have its own local cached copy, in which case we call it
+ "unspecified end-to-end revalidation", or when the client does have a
+ local cached copy, in which case we call it "specific end-to-end
+ revalidation."
+
+ The client can specify these three kinds of action using Cache-
+ Control request directives:
+
+ End-to-end reload
+ The request includes a "no-cache" cache-control directive or, for
+ compatibility with HTTP/1.0 clients, "Pragma: no-cache". Field
+ names MUST NOT be included with the no-cache directive in a
+ request. The server MUST NOT use a cached copy when responding to
+ such a request.
+
+ Specific end-to-end revalidation
+ The request includes a "max-age=0" cache-control directive, which
+ forces each cache along the path to the origin server to
+ revalidate its own entry, if any, with the next cache or server.
+ The initial request includes a cache-validating conditional with
+ the client's current validator.
+
+ Unspecified end-to-end revalidation
+ The request includes "max-age=0" cache-control directive, which
+ forces each cache along the path to the origin server to
+ revalidate its own entry, if any, with the next cache or server.
+ The initial request does not include a cache-validating
+
+ conditional; the first cache along the path (if any) that holds a
+ cache entry for this resource includes a cache-validating
+ conditional with its current validator.
+
+ max-age
+ When an intermediate cache is forced, by means of a max-age=0
+ directive, to revalidate its own cache entry, and the client has
+ supplied its own validator in the request, the supplied validator
+ might differ from the validator currently stored with the cache
+ entry. In this case, the cache MAY use either validator in making
+ its own request without affecting semantic transparency.
+
+ However, the choice of validator might affect performance. The
+ best approach is for the intermediate cache to use its own
+ validator when making its request. If the server replies with 304
+ (Not Modified), then the cache can return its now validated copy
+ to the client with a 200 (OK) response. If the server replies with
+ a new entity and cache validator, however, the intermediate cache
+ can compare the returned validator with the one provided in the
+ client's request, using the strong comparison function. If the
+ client's validator is equal to the origin server's, then the
+ intermediate cache simply returns 304 (Not Modified). Otherwise,
+ it returns the new entity with a 200 (OK) response.
+
+ If a request includes the no-cache directive, it SHOULD NOT
+ include min-fresh, max-stale, or max-age.
+
+ only-if-cached
+ In some cases, such as times of extremely poor network
+ connectivity, a client may want a cache to return only those
+ responses that it currently has stored, and not to reload or
+ revalidate with the origin server. To do this, the client may
+ include the only-if-cached directive in a request. If it receives
+ this directive, a cache SHOULD either respond using a cached entry
+ that is consistent with the other constraints of the request, or
+ respond with a 504 (Gateway Timeout) status. However, if a group
+ of caches is being operated as a unified system with good internal
+ connectivity, such a request MAY be forwarded within that group of
+ caches.
+
+ must-revalidate
+ Because a cache MAY be configured to ignore a server's specified
+ expiration time, and because a client request MAY include a max-
+ stale directive (which has a similar effect), the protocol also
+ includes a mechanism for the origin server to require revalidation
+ of a cache entry on any subsequent use. When the must-revalidate
+ directive is present in a response received by a cache, that cache
+ MUST NOT use the entry after it becomes stale to respond to a
+
+ subsequent request without first revalidating it with the origin
+ server. (I.e., the cache MUST do an end-to-end revalidation every
+ time, if, based solely on the origin server's Expires or max-age
+ value, the cached response is stale.)
+
+ The must-revalidate directive is necessary to support reliable
+ operation for certain protocol features. In all circumstances an
+ HTTP/1.1 cache MUST obey the must-revalidate directive; in
+ particular, if the cache cannot reach the origin server for any
+ reason, it MUST generate a 504 (Gateway Timeout) response.
+
+ Servers SHOULD send the must-revalidate directive if and only if
+ failure to revalidate a request on the entity could result in
+ incorrect operation, such as a silently unexecuted financial
+ transaction. Recipients MUST NOT take any automated action that
+ violates this directive, and MUST NOT automatically provide an
+ unvalidated copy of the entity if revalidation fails.
+
+ Although this is not recommended, user agents operating under
+ severe connectivity constraints MAY violate this directive but, if
+ so, MUST explicitly warn the user that an unvalidated response has
+ been provided. The warning MUST be provided on each unvalidated
+ access, and SHOULD require explicit user confirmation.
+
+ proxy-revalidate
+ The proxy-revalidate directive has the same meaning as the must-
+ revalidate directive, except that it does not apply to non-shared
+ user agent caches. It can be used on a response to an
+ authenticated request to permit the user's cache to store and
+ later return the response without needing to revalidate it (since
+ it has already been authenticated once by that user), while still
+ requiring proxies that service many users to revalidate each time
+ (in order to make sure that each user has been authenticated).
+ Note that such authenticated responses also need the public cache
+ control directive in order to allow them to be cached at all.
+
+14.9.5 No-Transform Directive
+
+ no-transform
+ Implementors of intermediate caches (proxies) have found it useful
+ to convert the media type of certain entity bodies. A non-
+ transparent proxy might, for example, convert between image
+ formats in order to save cache space or to reduce the amount of
+ traffic on a slow link.
+
+ Serious operational problems occur, however, when these
+ transformations are applied to entity bodies intended for certain
+ kinds of applications. For example, applications for medical
+
+ imaging, scientific data analysis and those using end-to-end
+ authentication, all depend on receiving an entity body that is bit
+ for bit identical to the original entity-body.
+
+ Therefore, if a message includes the no-transform directive, an
+ intermediate cache or proxy MUST NOT change those headers that are
+ listed in section 13.5.2 as being subject to the no-transform
+ directive. This implies that the cache or proxy MUST NOT change
+ any aspect of the entity-body that is specified by these headers,
+ including the value of the entity-body itself.
+
+14.9.6 Cache Control Extensions
+
+ The Cache-Control header field can be extended through the use of one
+ or more cache-extension tokens, each with an optional assigned value.
+ Informational extensions (those which do not require a change in
+ cache behavior) MAY be added without changing the semantics of other
+ directives. Behavioral extensions are designed to work by acting as
+ modifiers to the existing base of cache directives. Both the new
+ directive and the standard directive are supplied, such that
+ applications which do not understand the new directive will default
+ to the behavior specified by the standard directive, and those that
+ understand the new directive will recognize it as modifying the
+ requirements associated with the standard directive. In this way,
+ extensions to the cache-control directives can be made without
+ requiring changes to the base protocol.
+
+ This extension mechanism depends on an HTTP cache obeying all of the
+ cache-control directives defined for its native HTTP-version, obeying
+ certain extensions, and ignoring all directives that it does not
+ understand.
+
+ For example, consider a hypothetical new response directive called
+ community which acts as a modifier to the private directive. We
+ define this new directive to mean that, in addition to any non-shared
+ cache, any cache which is shared only by members of the community
+ named within its value may cache the response. An origin server
+ wishing to allow the UCI community to use an otherwise private
+ response in their shared cache(s) could do so by including
+
+ Cache-Control: private, community="UCI"
+
+ A cache seeing this header field will act correctly even if the cache
+ does not understand the community cache-extension, since it will also
+ see and understand the private directive and thus default to the safe
+ behavior.
+
+ Unrecognized cache-directives MUST be ignored; it is assumed that any
+ cache-directive likely to be unrecognized by an HTTP/1.1 cache will
+ be combined with standard directives (or the response's default
+ cacheability) such that the cache behavior will remain minimally
+ correct even if the cache does not understand the extension(s).
+
+14.10 Connection
+
+ The Connection general-header field allows the sender to specify
+ options that are desired for that particular connection and MUST NOT
+ be communicated by proxies over further connections.
+
+ The Connection header has the following grammar:
+
+ Connection = "Connection" ":" 1#(connection-token)
+ connection-token = token
+
+ HTTP/1.1 proxies MUST parse the Connection header field before a
+ message is forwarded and, for each connection-token in this field,
+ remove any header field(s) from the message with the same name as the
+ connection-token. Connection options are signaled by the presence of
+ a connection-token in the Connection header field, not by any
+ corresponding additional header field(s), since the additional header
+ field may not be sent if there are no parameters associated with that
+ connection option.
+
+ Message headers listed in the Connection header MUST NOT include
+ end-to-end headers, such as Cache-Control.
+
+ HTTP/1.1 defines the "close" connection option for the sender to
+ signal that the connection will be closed after completion of the
+ response. For example,
+
+ Connection: close
+
+ in either the request or the response header fields indicates that
+ the connection SHOULD NOT be considered `persistent' (section 8.1)
+ after the current request/response is complete.
+
+ HTTP/1.1 applications that do not support persistent connections MUST
+ include the "close" connection option in every message.
+
+ A system receiving an HTTP/1.0 (or lower-version) message that
+ includes a Connection header MUST, for each connection-token in this
+ field, remove and ignore any header field(s) from the message with
+ the same name as the connection-token. This protects against mistaken
+ forwarding of such header fields by pre-HTTP/1.1 proxies. See section
+ 19.6.2.
+
+14.11 Content-Encoding
+
+ The Content-Encoding entity-header field is used as a modifier to the
+ media-type. When present, its value indicates what additional content
+ codings have been applied to the entity-body, and thus what decoding
+ mechanisms must be applied in order to obtain the media-type
+ referenced by the Content-Type header field. Content-Encoding is
+ primarily used to allow a document to be compressed without losing
+ the identity of its underlying media type.
+
+ Content-Encoding = "Content-Encoding" ":" 1#content-coding
+
+ Content codings are defined in section 3.5. An example of its use is
+
+ Content-Encoding: gzip
+
+ The content-coding is a characteristic of the entity identified by
+ the Request-URI. Typically, the entity-body is stored with this
+ encoding and is only decoded before rendering or analogous usage.
+ However, a non-transparent proxy MAY modify the content-coding if the
+ new coding is known to be acceptable to the recipient, unless the
+ "no-transform" cache-control directive is present in the message.
+
+ If the content-coding of an entity is not "identity", then the
+ response MUST include a Content-Encoding entity-header (section
+ 14.11) that lists the non-identity content-coding(s) used.
+
+ If the content-coding of an entity in a request message is not
+ acceptable to the origin server, the server SHOULD respond with a
+ status code of 415 (Unsupported Media Type).
+
+ If multiple encodings have been applied to an entity, the content
+ codings MUST be listed in the order in which they were applied.
+ Additional information about the encoding parameters MAY be provided
+ by other entity-header fields not defined by this specification.
+
+14.12 Content-Language
+
+ The Content-Language entity-header field describes the natural
+ language(s) of the intended audience for the enclosed entity. Note
+ that this might not be equivalent to all the languages used within
+ the entity-body.
+
+ Content-Language = "Content-Language" ":" 1#language-tag
+
+ Language tags are defined in section 3.10. The primary purpose of
+ Content-Language is to allow a user to identify and differentiate
+ entities according to the user's own preferred language. Thus, if the
+ body content is intended only for a Danish-literate audience, the
+ appropriate field is
+
+ Content-Language: da
+
+ If no Content-Language is specified, the default is that the content
+ is intended for all language audiences. This might mean that the
+ sender does not consider it to be specific to any natural language,
+ or that the sender does not know for which language it is intended.
+
+ Multiple languages MAY be listed for content that is intended for
+ multiple audiences. For example, a rendition of the "Treaty of
+ Waitangi," presented simultaneously in the original Maori and English
+ versions, would call for
+
+ Content-Language: mi, en
+
+ However, just because multiple languages are present within an entity
+ does not mean that it is intended for multiple linguistic audiences.
+ An example would be a beginner's language primer, such as "A First
+ Lesson in Latin," which is clearly intended to be used by an
+ English-literate audience. In this case, the Content-Language would
+ properly only include "en".
+
+ Content-Language MAY be applied to any media type -- it is not
+ limited to textual documents.
+
+14.13 Content-Length
+
+ The Content-Length entity-header field indicates the size of the
+ entity-body, in decimal number of OCTETs, sent to the recipient or,
+ in the case of the HEAD method, the size of the entity-body that
+ would have been sent had the request been a GET.
+
+ Content-Length = "Content-Length" ":" 1*DIGIT
+
+ An example is
+
+ Content-Length: 3495
+
+ Applications SHOULD use this field to indicate the transfer-length of
+ the message-body, unless this is prohibited by the rules in section
+ 4.4.
+
+ Any Content-Length greater than or equal to zero is a valid value.
+ Section 4.4 describes how to determine the length of a message-body
+ if a Content-Length is not given.
+
+ Note that the meaning of this field is significantly different from
+ the corresponding definition in MIME, where it is an optional field
+ used within the "message/external-body" content-type. In HTTP, it
+ SHOULD be sent whenever the message's length can be determined prior
+ to being transferred, unless this is prohibited by the rules in
+ section 4.4.
+
+14.14 Content-Location
+
+ The Content-Location entity-header field MAY be used to supply the
+ resource location for the entity enclosed in the message when that
+ entity is accessible from a location separate from the requested
+ resource's URI. A server SHOULD provide a Content-Location for the
+ variant corresponding to the response entity; especially in the case
+ where a resource has multiple entities associated with it, and those
+ entities actually have separate locations by which they might be
+ individually accessed, the server SHOULD provide a Content-Location
+ for the particular variant which is returned.
+
+ Content-Location = "Content-Location" ":"
+ ( absoluteURI | relativeURI )
+
+ The value of Content-Location also defines the base URI for the
+ entity.
+
+ The Content-Location value is not a replacement for the original
+ requested URI; it is only a statement of the location of the resource
+ corresponding to this particular entity at the time of the request.
+ Future requests MAY specify the Content-Location URI as the request-
+ URI if the desire is to identify the source of that particular
+ entity.
+
+ A cache cannot assume that an entity with a Content-Location
+ different from the URI used to retrieve it can be used to respond to
+ later requests on that Content-Location URI. However, the Content-
+ Location can be used to differentiate between multiple entities
+ retrieved from a single requested resource, as described in section
+ 13.6.
+
+ If the Content-Location is a relative URI, the relative URI is
+ interpreted relative to the Request-URI.
+
+ The meaning of the Content-Location header in PUT or POST requests is
+ undefined; servers are free to ignore it in those cases.
+
+14.15 Content-MD5
+
+ The Content-MD5 entity-header field, as defined in <a href="http://firefly.troll.no/rfcs/rfc1864.html">RFC 1864</a> [23], is
+ an MD5 digest of the entity-body for the purpose of providing an
+ end-to-end message integrity check (MIC) of the entity-body. (Note: a
+ MIC is good for detecting accidental modification of the entity-body
+ in transit, but is not proof against malicious attacks.)
+
+ Content-MD5 = "Content-MD5" ":" md5-digest
+ md5-digest = <base64 of 128 bit MD5 digest as per <a href="http://firefly.troll.no/rfcs/rfc1864.html">RFC 1864</a>>
+
+ The Content-MD5 header field MAY be generated by an origin server or
+ client to function as an integrity check of the entity-body. Only
+ origin servers or clients MAY generate the Content-MD5 header field;
+ proxies and gateways MUST NOT generate it, as this would defeat its
+ value as an end-to-end integrity check. Any recipient of the entity-
+ body, including gateways and proxies, MAY check that the digest value
+ in this header field matches that of the entity-body as received.
+
+ The MD5 digest is computed based on the content of the entity-body,
+ including any content-coding that has been applied, but not including
+ any transfer-encoding applied to the message-body. If the message is
+ received with a transfer-encoding, that encoding MUST be removed
+ prior to checking the Content-MD5 value against the received entity.
+
+ This has the result that the digest is computed on the octets of the
+ entity-body exactly as, and in the order that, they would be sent if
+ no transfer-encoding were being applied.
+
+ HTTP extends <a href="http://firefly.troll.no/rfcs/rfc1864.html">RFC 1864</a> to permit the digest to be computed for MIME
+ composite media-types (e.g., multipart/* and message/rfc822), but
+ this does not change how the digest is computed as defined in the
+ preceding paragraph.
+
+ There are several consequences of this. The entity-body for composite
+ types MAY contain many body-parts, each with its own MIME and HTTP
+ headers (including Content-MD5, Content-Transfer-Encoding, and
+ Content-Encoding headers). If a body-part has a Content-Transfer-
+ Encoding or Content-Encoding header, it is assumed that the content
+ of the body-part has had the encoding applied, and the body-part is
+ included in the Content-MD5 digest as is -- i.e., after the
+ application. The Transfer-Encoding header field is not allowed within
+ body-parts.
+
+ Conversion of all line breaks to CRLF MUST NOT be done before
+ computing or checking the digest: the line break convention used in
+ the text actually transmitted MUST be left unaltered when computing
+ the digest.
+
+ Note: while the definition of Content-MD5 is exactly the same for
+ HTTP as in <a href="http://firefly.troll.no/rfcs/rfc1864.html">RFC 1864</a> for MIME entity-bodies, there are several ways
+ in which the application of Content-MD5 to HTTP entity-bodies
+ differs from its application to MIME entity-bodies. One is that
+ HTTP, unlike MIME, does not use Content-Transfer-Encoding, and
+ does use Transfer-Encoding and Content-Encoding. Another is that
+ HTTP more frequently uses binary content types than MIME, so it is
+ worth noting that, in such cases, the byte order used to compute
+ the digest is the transmission byte order defined for the type.
+ Lastly, HTTP allows transmission of text types with any of several
+ line break conventions and not just the canonical form using CRLF.
+
+14.16 Content-Range
+
+ The Content-Range entity-header is sent with a partial entity-body to
+ specify where in the full entity-body the partial body should be
+ applied. Range units are defined in section 3.12.
+
+ Content-Range = "Content-Range" ":" content-range-spec
+
+ content-range-spec = byte-content-range-spec
+ byte-content-range-spec = bytes-unit SP
+ byte-range-resp-spec "/"
+ ( instance-length | "*" )
+
+ byte-range-resp-spec = (first-byte-pos "-" last-byte-pos)
+ | "*"
+ instance-length = 1*DIGIT
+
+ The header SHOULD indicate the total length of the full entity-body,
+ unless this length is unknown or difficult to determine. The asterisk
+ "*" character means that the instance-length is unknown at the time
+ when the response was generated.
+
+ Unlike byte-ranges-specifier values (see section 14.35.1), a byte-
+ range-resp-spec MUST only specify one range, and MUST contain
+ absolute byte positions for both the first and last byte of the
+ range.
+
+ A byte-content-range-spec with a byte-range-resp-spec whose last-
+ byte-pos value is less than its first-byte-pos value, or whose
+ instance-length value is less than or equal to its last-byte-pos
+ value, is invalid. The recipient of an invalid byte-content-range-
+ spec MUST ignore it and any content transferred along with it.
+
+ A server sending a response with status code 416 (Requested range not
+ satisfiable) SHOULD include a Content-Range field with a byte-range-
+ resp-spec of "*". The instance-length specifies the current length of
+
+ the selected resource. A response with status code 206 (Partial
+ Content) MUST NOT include a Content-Range field with a byte-range-
+ resp-spec of "*".
+
+ Examples of byte-content-range-spec values, assuming that the entity
+ contains a total of 1234 bytes:
+
+ . The first 500 bytes:
+ bytes 0-499/1234
+
+ . The second 500 bytes:
+ bytes 500-999/1234
+
+ . All except for the first 500 bytes:
+ bytes 500-1233/1234
+
+ . The last 500 bytes:
+ bytes 734-1233/1234
+
+ When an HTTP message includes the content of a single range (for
+ example, a response to a request for a single range, or to a request
+ for a set of ranges that overlap without any holes), this content is
+ transmitted with a Content-Range header, and a Content-Length header
+ showing the number of bytes actually transferred. For example,
+
+ HTTP/1.1 206 Partial content
+ Date: Wed, 15 Nov 1995 06:25:24 GMT
+ Last-Modified: Wed, 15 Nov 1995 04:58:08 GMT
+ Content-Range: bytes 21010-47021/47022
+ Content-Length: 26012
+ Content-Type: image/gif
+
+ When an HTTP message includes the content of multiple ranges (for
+ example, a response to a request for multiple non-overlapping
+ ranges), these are transmitted as a multipart message. The multipart
+ media type used for this purpose is "multipart/byteranges" as defined
+ in appendix 19.2. See appendix 19.6.3 for a compatibility issue.
+
+ A response to a request for a single range MUST NOT be sent using the
+ multipart/byteranges media type. A response to a request for
+ multiple ranges, whose result is a single range, MAY be sent as a
+ multipart/byteranges media type with one part. A client that cannot
+ decode a multipart/byteranges message MUST NOT ask for multiple
+ byte-ranges in a single request.
+
+ When a client requests multiple byte-ranges in one request, the
+ server SHOULD return them in the order that they appeared in the
+ request.
+
+ If the server ignores a byte-range-spec because it is syntactically
+ invalid, the server SHOULD treat the request as if the invalid Range
+ header field did not exist. (Normally, this means return a 200
+ response containing the full entity).
+
+ If the server receives a request (other than one including an If-
+ Range request-header field) with an unsatisfiable Range request-
+ header field (that is, all of whose byte-range-spec values have a
+ first-byte-pos value greater than the current length of the selected
+ resource), it SHOULD return a response code of 416 (Requested range
+ not satisfiable) (section 10.4.17).
+
+ Note: clients cannot depend on servers to send a 416 (Requested
+ range not satisfiable) response instead of a 200 (OK) response for
+ an unsatisfiable Range request-header, since not all servers
+ implement this request-header.
+
+14.17 Content-Type
+
+ The Content-Type entity-header field indicates the media type of the
+ entity-body sent to the recipient or, in the case of the HEAD method,
+ the media type that would have been sent had the request been a GET.
+
+ Content-Type = "Content-Type" ":" media-type
+
+ Media types are defined in section 3.7. An example of the field is
+
+ Content-Type: text/html; charset=ISO-8859-4
+
+ Further discussion of methods for identifying the media type of an
+ entity is provided in section 7.2.1.
+
+14.18 Date
+
+ The Date general-header field represents the date and time at which
+ the message was originated, having the same semantics as orig-date in
+ <a href="http://firefly.troll.no/rfcs/rfc822.html">RFC 822</a>. The field value is an HTTP-date, as described in section
+ 3.3.1; it MUST be sent in <a href="http://firefly.troll.no/rfcs/rfc1123.html">RFC 1123</a> [8]-date format.
+
+ Date = "Date" ":" HTTP-date
+
+ An example is
+
+ Date: Tue, 15 Nov 1994 08:12:31 GMT
+
+ Origin servers MUST include a Date header field in all responses,
+ except in these cases:
+
+ 1. If the response status code is 100 (Continue) or 101 (Switching
+ Protocols), the response MAY include a Date header field, at
+ the server's option.
+
+ 2. If the response status code conveys a server error, e.g. 500
+ (Internal Server Error) or 503 (Service Unavailable), and it is
+ inconvenient or impossible to generate a valid Date.
+
+ 3. If the server does not have a clock that can provide a
+ reasonable approximation of the current time, its responses
+ MUST NOT include a Date header field. In this case, the rules
+ in section 14.18.1 MUST be followed.
+
+ A received message that does not have a Date header field MUST be
+ assigned one by the recipient if the message will be cached by that
+ recipient or gatewayed via a protocol which requires a Date. An HTTP
+ implementation without a clock MUST NOT cache responses without
+ revalidating them on every use. An HTTP cache, especially a shared
+ cache, SHOULD use a mechanism, such as NTP [28], to synchronize its
+ clock with a reliable external standard.
+
+ Clients SHOULD only send a Date header field in messages that include
+ an entity-body, as in the case of the PUT and POST requests, and even
+ then it is optional. A client without a clock MUST NOT send a Date
+ header field in a request.
+
+ The HTTP-date sent in a Date header SHOULD NOT represent a date and
+ time subsequent to the generation of the message. It SHOULD represent
+ the best available approximation of the date and time of message
+ generation, unless the implementation has no means of generating a
+ reasonably accurate date and time. In theory, the date ought to
+ represent the moment just before the entity is generated. In
+ practice, the date can be generated at any time during the message
+ origination without affecting its semantic value.
+
+14.18.1 Clockless Origin Server Operation
+
+ Some origin server implementations might not have a clock available.
+ An origin server without a clock MUST NOT assign Expires or Last-
+ Modified values to a response, unless these values were associated
+ with the resource by a system or user with a reliable clock. It MAY
+ assign an Expires value that is known, at or before server
+ configuration time, to be in the past (this allows "pre-expiration"
+ of responses without storing separate Expires values for each
+ resource).
+
+14.19 ETag
+
+ The ETag response-header field provides the current value of the
+ entity tag for the requested variant. The headers used with entity
+ tags are described in sections 14.24, 14.26 and 14.44. The entity tag
+ MAY be used for comparison with other entities from the same resource
+ (see section 13.3.3).
+
+ ETag = "ETag" ":" entity-tag
+
+ Examples:
+
+ ETag: "xyzzy"
+ ETag: W/"xyzzy"
+ ETag: ""
+
+14.20 Expect
+
+ The Expect request-header field is used to indicate that particular
+ server behaviors are required by the client.
+
+ Expect = "Expect" ":" 1#expectation
+
+ expectation = "100-continue" | expectation-extension
+ expectation-extension = token [ "=" ( token | quoted-string )
+ *expect-params ]
+ expect-params = ";" token [ "=" ( token | quoted-string ) ]
+
+ A server that does not understand or is unable to comply with any of
+ the expectation values in the Expect field of a request MUST respond
+ with appropriate error status. The server MUST respond with a 417
+ (Expectation Failed) status if any of the expectations cannot be met
+ or, if there are other problems with the request, some other 4xx
+ status.
+
+ This header field is defined with extensible syntax to allow for
+ future extensions. If a server receives a request containing an
+ Expect field that includes an expectation-extension that it does not
+ support, it MUST respond with a 417 (Expectation Failed) status.
+
+ Comparison of expectation values is case-insensitive for unquoted
+ tokens (including the 100-continue token), and is case-sensitive for
+ quoted-string expectation-extensions.
+
+ The Expect mechanism is hop-by-hop: that is, an HTTP/1.1 proxy MUST
+ return a 417 (Expectation Failed) status if it receives a request
+ with an expectation that it cannot meet. However, the Expect
+ request-header itself is end-to-end; it MUST be forwarded if the
+ request is forwarded.
+
+ Many older HTTP/1.0 and HTTP/1.1 applications do not understand the
+ Expect header.
+
+ See section 8.2.3 for the use of the 100 (continue) status.
+
+14.21 Expires
+
+ The Expires entity-header field gives the date/time after which the
+ response is considered stale. A stale cache entry may not normally be
+ returned by a cache (either a proxy cache or a user agent cache)
+ unless it is first validated with the origin server (or with an
+ intermediate cache that has a fresh copy of the entity). See section
+ 13.2 for further discussion of the expiration model.
+
+ The presence of an Expires field does not imply that the original
+ resource will change or cease to exist at, before, or after that
+ time.
+
+ The format is an absolute date and time as defined by HTTP-date in
+ section 3.3.1; it MUST be in <a href="http://firefly.troll.no/rfcs/rfc1123.html">RFC 1123</a> date format:
+
+ Expires = "Expires" ":" HTTP-date
+
+ An example of its use is
+
+ Expires: Thu, 01 Dec 1994 16:00:00 GMT
+
+ Note: if a response includes a Cache-Control field with the max-
+ age directive (see section 14.9.3), that directive overrides the
+ Expires field.
+
+ HTTP/1.1 clients and caches MUST treat other invalid date formats,
+ especially including the value "0", as in the past (i.e., "already
+ expired").
+
+ To mark a response as "already expired," an origin server sends an
+ Expires date that is equal to the Date header value. (See the rules
+ for expiration calculations in section 13.2.4.)
+
+ To mark a response as "never expires," an origin server sends an
+ Expires date approximately one year from the time the response is
+ sent. HTTP/1.1 servers SHOULD NOT send Expires dates more than one
+ year in the future.
+
+ The presence of an Expires header field with a date value of some
+ time in the future on a response that otherwise would by default be
+ non-cacheable indicates that the response is cacheable, unless
+ indicated otherwise by a Cache-Control header field (section 14.9).
+
+14.22 From
+
+ The From request-header field, if given, SHOULD contain an Internet
+ e-mail address for the human user who controls the requesting user
+ agent. The address SHOULD be machine-usable, as defined by "mailbox"
+ in <a href="http://firefly.troll.no/rfcs/rfc822.html">RFC 822</a> [9] as updated by <a href="http://firefly.troll.no/rfcs/rfc1123.html">RFC 1123</a> [8]:
+
+ From = "From" ":" mailbox
+
+ An example is:
+
+ From: <a href="mailto:webmaster@w3.org">webmaster@w3.org</a>
+
+ This header field MAY be used for logging purposes and as a means for
+ identifying the source of invalid or unwanted requests. It SHOULD NOT
+ be used as an insecure form of access protection. The interpretation
+ of this field is that the request is being performed on behalf of the
+ person given, who accepts responsibility for the method performed. In
+ particular, robot agents SHOULD include this header so that the
+ person responsible for running the robot can be contacted if problems
+ occur on the receiving end.
+
+ The Internet e-mail address in this field MAY be separate from the
+ Internet host which issued the request. For example, when a request
+ is passed through a proxy the original issuer's address SHOULD be
+ used.
+
+ The client SHOULD NOT send the From header field without the user's
+ approval, as it might conflict with the user's privacy interests or
+ their site's security policy. It is strongly recommended that the
+ user be able to disable, enable, and modify the value of this field
+ at any time prior to a request.
+
+14.23 Host
+
+ The Host request-header field specifies the Internet host and port
+ number of the resource being requested, as obtained from the original
+ URI given by the user or referring resource (generally an HTTP URL,
+
+ as described in section 3.2.2). The Host field value MUST represent
+ the naming authority of the origin server or gateway given by the
+ original URL. This allows the origin server or gateway to
+ differentiate between internally-ambiguous URLs, such as the root "/"
+ URL of a server for multiple host names on a single IP address.
+
+ Host = "Host" ":" host [ ":" port ] ; Section 3.2.2
+
+ A "host" without any trailing port information implies the default
+ port for the service requested (e.g., "80" for an HTTP URL). For
+ example, a request on the origin server for
+ <<a href="http://www.w3.org/pub/WWW/">http://www.w3.org/pub/WWW/</a>> would properly include:
+
+ GET /pub/WWW/ HTTP/1.1
+ Host: www.w3.org
+
+ A client MUST include a Host header field in all HTTP/1.1 request
+ messages . If the requested URI does not include an Internet host
+ name for the service being requested, then the Host header field MUST
+ be given with an empty value. An HTTP/1.1 proxy MUST ensure that any
+ request message it forwards does contain an appropriate Host header
+ field that identifies the service being requested by the proxy. All
+ Internet-based HTTP/1.1 servers MUST respond with a 400 (Bad Request)
+ status code to any HTTP/1.1 request message which lacks a Host header
+ field.
+
+ See sections 5.2 and 19.6.1.1 for other requirements relating to
+ Host.
+
+14.24 If-Match
+
+ The If-Match request-header field is used with a method to make it
+ conditional. A client that has one or more entities previously
+ obtained from the resource can verify that one of those entities is
+ current by including a list of their associated entity tags in the
+ If-Match header field. Entity tags are defined in section 3.11. The
+ purpose of this feature is to allow efficient updates of cached
+ information with a minimum amount of transaction overhead. It is also
+ used, on updating requests, to prevent inadvertent modification of
+ the wrong version of a resource. As a special case, the value "*"
+ matches any current entity of the resource.
+
+ If-Match = "If-Match" ":" ( "*" | 1#entity-tag )
+
+ If any of the entity tags match the entity tag of the entity that
+ would have been returned in the response to a similar GET request
+ (without the If-Match header) on that resource, or if "*" is given
+
+ and any current entity exists for that resource, then the server MAY
+ perform the requested method as if the If-Match header field did not
+ exist.
+
+ A server MUST use the strong comparison function (see section 13.3.3)
+ to compare the entity tags in If-Match.
+
+ If none of the entity tags match, or if "*" is given and no current
+ entity exists, the server MUST NOT perform the requested method, and
+ MUST return a 412 (Precondition Failed) response. This behavior is
+ most useful when the client wants to prevent an updating method, such
+ as PUT, from modifying a resource that has changed since the client
+ last retrieved it.
+
+ If the request would, without the If-Match header field, result in
+ anything other than a 2xx or 412 status, then the If-Match header
+ MUST be ignored.
+
+ The meaning of "If-Match: *" is that the method SHOULD be performed
+ if the representation selected by the origin server (or by a cache,
+ possibly using the Vary mechanism, see section 14.44) exists, and
+ MUST NOT be performed if the representation does not exist.
+
+ A request intended to update a resource (e.g., a PUT) MAY include an
+ If-Match header field to signal that the request method MUST NOT be
+ applied if the entity corresponding to the If-Match value (a single
+ entity tag) is no longer a representation of that resource. This
+ allows the user to indicate that they do not wish the request to be
+ successful if the resource has been changed without their knowledge.
+ Examples:
+
+ If-Match: "xyzzy"
+ If-Match: "xyzzy", "r2d2xxxx", "c3piozzzz"
+ If-Match: *
+
+ The result of a request having both an If-Match header field and
+ either an If-None-Match or an If-Modified-Since header fields is
+ undefined by this specification.
+
+14.25 If-Modified-Since
+
+ The If-Modified-Since request-header field is used with a method to
+ make it conditional: if the requested variant has not been modified
+ since the time specified in this field, an entity will not be
+ returned from the server; instead, a 304 (not modified) response will
+ be returned without any message-body.
+
+ If-Modified-Since = "If-Modified-Since" ":" HTTP-date
+
+ An example of the field is:
+
+ If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT
+
+ A GET method with an If-Modified-Since header and no Range header
+ requests that the identified entity be transferred only if it has
+ been modified since the date given by the If-Modified-Since header.
+ The algorithm for determining this includes the following cases:
+
+ a) If the request would normally result in anything other than a
+ 200 (OK) status, or if the passed If-Modified-Since date is
+ invalid, the response is exactly the same as for a normal GET.
+ A date which is later than the server's current time is
+ invalid.
+
+ b) If the variant has been modified since the If-Modified-Since
+ date, the response is exactly the same as for a normal GET.
+
+ c) If the variant has not been modified since a valid If-
+ Modified-Since date, the server SHOULD return a 304 (Not
+ Modified) response.
+
+ The purpose of this feature is to allow efficient updates of cached
+ information with a minimum amount of transaction overhead.
+
+ Note: The Range request-header field modifies the meaning of If-
+ Modified-Since; see section 14.35 for full details.
+
+ Note: If-Modified-Since times are interpreted by the server, whose
+ clock might not be synchronized with the client.
+
+ Note: When handling an If-Modified-Since header field, some
+ servers will use an exact date comparison function, rather than a
+ less-than function, for deciding whether to send a 304 (Not
+ Modified) response. To get best results when sending an If-
+ Modified-Since header field for cache validation, clients are
+ advised to use the exact date string received in a previous Last-
+ Modified header field whenever possible.
+
+ Note: If a client uses an arbitrary date in the If-Modified-Since
+ header instead of a date taken from the Last-Modified header for
+ the same request, the client should be aware of the fact that this
+ date is interpreted in the server's understanding of time. The
+ client should consider unsynchronized clocks and rounding problems
+ due to the different encodings of time between the client and
+ server. This includes the possibility of race conditions if the
+ document has changed between the time it was first requested and
+ the If-Modified-Since date of a subsequent request, and the
+
+ possibility of clock-skew-related problems if the If-Modified-
+ Since date is derived from the client's clock without correction
+ to the server's clock. Corrections for different time bases
+ between client and server are at best approximate due to network
+ latency.
+
+ The result of a request having both an If-Modified-Since header field
+ and either an If-Match or an If-Unmodified-Since header fields is
+ undefined by this specification.
+
+14.26 If-None-Match
+
+ The If-None-Match request-header field is used with a method to make
+ it conditional. A client that has one or more entities previously
+ obtained from the resource can verify that none of those entities is
+ current by including a list of their associated entity tags in the
+ If-None-Match header field. The purpose of this feature is to allow
+ efficient updates of cached information with a minimum amount of
+ transaction overhead. It is also used to prevent a method (e.g. PUT)
+ from inadvertently modifying an existing resource when the client
+ believes that the resource does not exist.
+
+ As a special case, the value "*" matches any current entity of the
+ resource.
+
+ If-None-Match = "If-None-Match" ":" ( "*" | 1#entity-tag )
+
+ If any of the entity tags match the entity tag of the entity that
+ would have been returned in the response to a similar GET request
+ (without the If-None-Match header) on that resource, or if "*" is
+ given and any current entity exists for that resource, then the
+ server MUST NOT perform the requested method, unless required to do
+ so because the resource's modification date fails to match that
+ supplied in an If-Modified-Since header field in the request.
+ Instead, if the request method was GET or HEAD, the server SHOULD
+ respond with a 304 (Not Modified) response, including the cache-
+ related header fields (particularly ETag) of one of the entities that
+ matched. For all other request methods, the server MUST respond with
+ a status of 412 (Precondition Failed).
+
+ See section 13.3.3 for rules on how to determine if two entities tags
+ match. The weak comparison function can only be used with GET or HEAD
+ requests.
+
+ If none of the entity tags match, then the server MAY perform the
+ requested method as if the If-None-Match header field did not exist,
+ but MUST also ignore any If-Modified-Since header field(s) in the
+ request. That is, if no entity tags match, then the server MUST NOT
+ return a 304 (Not Modified) response.
+
+ If the request would, without the If-None-Match header field, result
+ in anything other than a 2xx or 304 status, then the If-None-Match
+ header MUST be ignored. (See section 13.3.4 for a discussion of
+ server behavior when both If-Modified-Since and If-None-Match appear
+ in the same request.)
+
+ The meaning of "If-None-Match: *" is that the method MUST NOT be
+ performed if the representation selected by the origin server (or by
+ a cache, possibly using the Vary mechanism, see section 14.44)
+ exists, and SHOULD be performed if the representation does not exist.
+ This feature is intended to be useful in preventing races between PUT
+ operations.
+
+ Examples:
+
+ If-None-Match: "xyzzy"
+ If-None-Match: W/"xyzzy"
+ If-None-Match: "xyzzy", "r2d2xxxx", "c3piozzzz"
+ If-None-Match: W/"xyzzy", W/"r2d2xxxx", W/"c3piozzzz"
+ If-None-Match: *
+
+ The result of a request having both an If-None-Match header field and
+ either an If-Match or an If-Unmodified-Since header fields is
+ undefined by this specification.
+
+14.27 If-Range
+
+ If a client has a partial copy of an entity in its cache, and wishes
+ to have an up-to-date copy of the entire entity in its cache, it
+ could use the Range request-header with a conditional GET (using
+ either or both of If-Unmodified-Since and If-Match.) However, if the
+ condition fails because the entity has been modified, the client
+ would then have to make a second request to obtain the entire current
+ entity-body.
+
+ The If-Range header allows a client to "short-circuit" the second
+ request. Informally, its meaning is `if the entity is unchanged, send
+ me the part(s) that I am missing; otherwise, send me the entire new
+ entity'.
+
+ If-Range = "If-Range" ":" ( entity-tag | HTTP-date )
+
+ If the client has no entity tag for an entity, but does have a Last-
+ Modified date, it MAY use that date in an If-Range header. (The
+ server can distinguish between a valid HTTP-date and any form of
+ entity-tag by examining no more than two characters.) The If-Range
+ header SHOULD only be used together with a Range header, and MUST be
+ ignored if the request does not include a Range header, or if the
+ server does not support the sub-range operation.
+
+ If the entity tag given in the If-Range header matches the current
+ entity tag for the entity, then the server SHOULD provide the
+ specified sub-range of the entity using a 206 (Partial content)
+ response. If the entity tag does not match, then the server SHOULD
+ return the entire entity using a 200 (OK) response.
+
+14.28 If-Unmodified-Since
+
+ The If-Unmodified-Since request-header field is used with a method to
+ make it conditional. If the requested resource has not been modified
+ since the time specified in this field, the server SHOULD perform the
+ requested operation as if the If-Unmodified-Since header were not
+ present.
+
+ If the requested variant has been modified since the specified time,
+ the server MUST NOT perform the requested operation, and MUST return
+ a 412 (Precondition Failed).
+
+ If-Unmodified-Since = "If-Unmodified-Since" ":" HTTP-date
+
+ An example of the field is:
+
+ If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT
+
+ If the request normally (i.e., without the If-Unmodified-Since
+ header) would result in anything other than a 2xx or 412 status, the
+ If-Unmodified-Since header SHOULD be ignored.
+
+ If the specified date is invalid, the header is ignored.
+
+ The result of a request having both an If-Unmodified-Since header
+ field and either an If-None-Match or an If-Modified-Since header
+ fields is undefined by this specification.
+
+14.29 Last-Modified
+
+ The Last-Modified entity-header field indicates the date and time at
+ which the origin server believes the variant was last modified.
+
+ Last-Modified = "Last-Modified" ":" HTTP-date
+
+ An example of its use is
+
+ Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT
+
+ The exact meaning of this header field depends on the implementation
+ of the origin server and the nature of the original resource. For
+ files, it may be just the file system last-modified time. For
+ entities with dynamically included parts, it may be the most recent
+ of the set of last-modify times for its component parts. For database
+ gateways, it may be the last-update time stamp of the record. For
+ virtual objects, it may be the last time the internal state changed.
+
+ An origin server MUST NOT send a Last-Modified date which is later
+ than the server's time of message origination. In such cases, where
+ the resource's last modification would indicate some time in the
+ future, the server MUST replace that date with the message
+ origination date.
+
+ An origin server SHOULD obtain the Last-Modified value of the entity
+ as close as possible to the time that it generates the Date value of
+ its response. This allows a recipient to make an accurate assessment
+ of the entity's modification time, especially if the entity changes
+ near the time that the response is generated.
+
+ HTTP/1.1 servers SHOULD send Last-Modified whenever feasible.
+
+14.30 Location
+
+ The Location response-header field is used to redirect the recipient
+ to a location other than the Request-URI for completion of the
+ request or identification of a new resource. For 201 (Created)
+ responses, the Location is that of the new resource which was created
+ by the request. For 3xx responses, the location SHOULD indicate the
+ server's preferred URI for automatic redirection to the resource. The
+ field value consists of a single absolute URI.
+
+ Location = "Location" ":" absoluteURI
+
+ An example is:
+
+ Location: <a href="http://www.w3.org/pub/WWW/People.html">http://www.w3.org/pub/WWW/People.html</a>
+
+ Note: The Content-Location header field (section 14.14) differs
+ from Location in that the Content-Location identifies the original
+ location of the entity enclosed in the request. It is therefore
+ possible for a response to contain header fields for both Location
+ and Content-Location. Also see section 13.10 for cache
+ requirements of some methods.
+
+14.31 Max-Forwards
+
+ The Max-Forwards request-header field provides a mechanism with the
+ TRACE (section 9.8) and OPTIONS (section 9.2) methods to limit the
+ number of proxies or gateways that can forward the request to the
+ next inbound server. This can be useful when the client is attempting
+ to trace a request chain which appears to be failing or looping in
+ mid-chain.
+
+ Max-Forwards = "Max-Forwards" ":" 1*DIGIT
+
+ The Max-Forwards value is a decimal integer indicating the remaining
+ number of times this request message may be forwarded.
+
+ Each proxy or gateway recipient of a TRACE or OPTIONS request
+ containing a Max-Forwards header field MUST check and update its
+ value prior to forwarding the request. If the received value is zero
+ (0), the recipient MUST NOT forward the request; instead, it MUST
+ respond as the final recipient. If the received Max-Forwards value is
+ greater than zero, then the forwarded message MUST contain an updated
+ Max-Forwards field with a value decremented by one (1).
+
+ The Max-Forwards header field MAY be ignored for all other methods
+ defined by this specification and for any extension methods for which
+ it is not explicitly referred to as part of that method definition.
+
+14.32 Pragma
+
+ The Pragma general-header field is used to include implementation-
+ specific directives that might apply to any recipient along the
+ request/response chain. All pragma directives specify optional
+ behavior from the viewpoint of the protocol; however, some systems
+ MAY require that behavior be consistent with the directives.
+
+ Pragma = "Pragma" ":" 1#pragma-directive
+ pragma-directive = "no-cache" | extension-pragma
+ extension-pragma = token [ "=" ( token | quoted-string ) ]
+
+ When the no-cache directive is present in a request message, an
+ application SHOULD forward the request toward the origin server even
+ if it has a cached copy of what is being requested. This pragma
+ directive has the same semantics as the no-cache cache-directive (see
+ section 14.9) and is defined here for backward compatibility with
+ HTTP/1.0. Clients SHOULD include both header fields when a no-cache
+ request is sent to a server not known to be HTTP/1.1 compliant.
+
+ Pragma directives MUST be passed through by a proxy or gateway
+ application, regardless of their significance to that application,
+ since the directives might be applicable to all recipients along the
+ request/response chain. It is not possible to specify a pragma for a
+ specific recipient; however, any pragma directive not relevant to a
+ recipient SHOULD be ignored by that recipient.
+
+ HTTP/1.1 caches SHOULD treat "Pragma: no-cache" as if the client had
+ sent "Cache-Control: no-cache". No new Pragma directives will be
+ defined in HTTP.
+
+ Note: because the meaning of "Pragma: no-cache as a response
+ header field is not actually specified, it does not provide a
+ reliable replacement for "Cache-Control: no-cache" in a response
+
+14.33 Proxy-Authenticate
+
+ The Proxy-Authenticate response-header field MUST be included as part
+ of a 407 (Proxy Authentication Required) response. The field value
+ consists of a challenge that indicates the authentication scheme and
+ parameters applicable to the proxy for this Request-URI.
+
+ Proxy-Authenticate = "Proxy-Authenticate" ":" 1#challenge
+
+ The HTTP access authentication process is described in "HTTP
+ Authentication: Basic and Digest Access Authentication" [43]. Unlike
+ WWW-Authenticate, the Proxy-Authenticate header field applies only to
+ the current connection and SHOULD NOT be passed on to downstream
+ clients. However, an intermediate proxy might need to obtain its own
+ credentials by requesting them from the downstream client, which in
+ some circumstances will appear as if the proxy is forwarding the
+ Proxy-Authenticate header field.
+
+14.34 Proxy-Authorization
+
+ The Proxy-Authorization request-header field allows the client to
+ identify itself (or its user) to a proxy which requires
+ authentication. The Proxy-Authorization field value consists of
+ credentials containing the authentication information of the user
+ agent for the proxy and/or realm of the resource being requested.
+
+ Proxy-Authorization = "Proxy-Authorization" ":" credentials
+
+ The HTTP access authentication process is described in "HTTP
+ Authentication: Basic and Digest Access Authentication" [43] . Unlike
+ Authorization, the Proxy-Authorization header field applies only to
+ the next outbound proxy that demanded authentication using the Proxy-
+ Authenticate field. When multiple proxies are used in a chain, the
+
+ Proxy-Authorization header field is consumed by the first outbound
+ proxy that was expecting to receive credentials. A proxy MAY relay
+ the credentials from the client request to the next proxy if that is
+ the mechanism by which the proxies cooperatively authenticate a given
+ request.
+
+14.35 Range
+
+14.35.1 Byte Ranges
+
+ Since all HTTP entities are represented in HTTP messages as sequences
+ of bytes, the concept of a byte range is meaningful for any HTTP
+ entity. (However, not all clients and servers need to support byte-
+ range operations.)
+
+ Byte range specifications in HTTP apply to the sequence of bytes in
+ the entity-body (not necessarily the same as the message-body).
+
+ A byte range operation MAY specify a single range of bytes, or a set
+ of ranges within a single entity.
+
+ ranges-specifier = byte-ranges-specifier
+ byte-ranges-specifier = bytes-unit "=" byte-range-set
+ byte-range-set = 1#( byte-range-spec | suffix-byte-range-spec )
+ byte-range-spec = first-byte-pos "-" [last-byte-pos]
+ first-byte-pos = 1*DIGIT
+ last-byte-pos = 1*DIGIT
+
+ The first-byte-pos value in a byte-range-spec gives the byte-offset
+ of the first byte in a range. The last-byte-pos value gives the
+ byte-offset of the last byte in the range; that is, the byte
+ positions specified are inclusive. Byte offsets start at zero.
+
+ If the last-byte-pos value is present, it MUST be greater than or
+ equal to the first-byte-pos in that byte-range-spec, or the byte-
+ range-spec is syntactically invalid. The recipient of a byte-range-
+ set that includes one or more syntactically invalid byte-range-spec
+ values MUST ignore the header field that includes that byte-range-
+ set.
+
+ If the last-byte-pos value is absent, or if the value is greater than
+ or equal to the current length of the entity-body, last-byte-pos is
+ taken to be equal to one less than the current length of the entity-
+ body in bytes.
+
+ By its choice of last-byte-pos, a client can limit the number of
+ bytes retrieved without knowing the size of the entity.
+
+ suffix-byte-range-spec = "-" suffix-length
+ suffix-length = 1*DIGIT
+
+ A suffix-byte-range-spec is used to specify the suffix of the
+ entity-body, of a length given by the suffix-length value. (That is,
+ this form specifies the last N bytes of an entity-body.) If the
+ entity is shorter than the specified suffix-length, the entire
+ entity-body is used.
+
+ If a syntactically valid byte-range-set includes at least one byte-
+ range-spec whose first-byte-pos is less than the current length of
+ the entity-body, or at least one suffix-byte-range-spec with a non-
+ zero suffix-length, then the byte-range-set is satisfiable.
+ Otherwise, the byte-range-set is unsatisfiable. If the byte-range-set
+ is unsatisfiable, the server SHOULD return a response with a status
+ of 416 (Requested range not satisfiable). Otherwise, the server
+ SHOULD return a response with a status of 206 (Partial Content)
+ containing the satisfiable ranges of the entity-body.
+
+ Examples of byte-ranges-specifier values (assuming an entity-body of
+ length 10000):
+
+ - The first 500 bytes (byte offsets 0-499, inclusive): bytes=0-
+ 499
+
+ - The second 500 bytes (byte offsets 500-999, inclusive):
+ bytes=500-999
+
+ - The final 500 bytes (byte offsets 9500-9999, inclusive):
+ bytes=-500
+
+ - Or bytes=9500-
+
+ - The first and last bytes only (bytes 0 and 9999): bytes=0-0,-1
+
+ - Several legal but not canonical specifications of the second 500
+ bytes (byte offsets 500-999, inclusive):
+ bytes=500-600,601-999
+ bytes=500-700,601-999
+
+14.35.2 Range Retrieval Requests
+
+ HTTP retrieval requests using conditional or unconditional GET
+ methods MAY request one or more sub-ranges of the entity, instead of
+ the entire entity, using the Range request header, which applies to
+ the entity returned as the result of the request:
+
+ Range = "Range" ":" ranges-specifier
+
+ A server MAY ignore the Range header. However, HTTP/1.1 origin
+ servers and intermediate caches ought to support byte ranges when
+ possible, since Range supports efficient recovery from partially
+ failed transfers, and supports efficient partial retrieval of large
+ entities.
+
+ If the server supports the Range header and the specified range or
+ ranges are appropriate for the entity:
+
+ - The presence of a Range header in an unconditional GET modifies
+ what is returned if the GET is otherwise successful. In other
+ words, the response carries a status code of 206 (Partial
+ Content) instead of 200 (OK).
+
+ - The presence of a Range header in a conditional GET (a request
+ using one or both of If-Modified-Since and If-None-Match, or
+ one or both of If-Unmodified-Since and If-Match) modifies what
+ is returned if the GET is otherwise successful and the
+ condition is true. It does not affect the 304 (Not Modified)
+ response returned if the conditional is false.
+
+ In some cases, it might be more appropriate to use the If-Range
+ header (see section 14.27) in addition to the Range header.
+
+ If a proxy that supports ranges receives a Range request, forwards
+ the request to an inbound server, and receives an entire entity in
+ reply, it SHOULD only return the requested range to its client. It
+ SHOULD store the entire received response in its cache if that is
+ consistent with its cache allocation policies.
+
+14.36 Referer
+
+ The Referer[sic] request-header field allows the client to specify,
+ for the server's benefit, the address (URI) of the resource from
+ which the Request-URI was obtained (the "referrer", although the
+ header field is misspelled.) The Referer request-header allows a
+ server to generate lists of back-links to resources for interest,
+ logging, optimized caching, etc. It also allows obsolete or mistyped
+ links to be traced for maintenance. The Referer field MUST NOT be
+ sent if the Request-URI was obtained from a source that does not have
+ its own URI, such as input from the user keyboard.
+
+ Referer = "Referer" ":" ( absoluteURI | relativeURI )
+
+ Example:
+
+ Referer: <a href="http://www.w3.org/hypertext/DataSources/Overview.html">http://www.w3.org/hypertext/DataSources/Overview.html</a>
+
+ If the field value is a relative URI, it SHOULD be interpreted
+ relative to the Request-URI. The URI MUST NOT include a fragment. See
+ section 15.1.3 for security considerations.
+
+14.37 Retry-After
+
+ The Retry-After response-header field can be used with a 503 (Service
+ Unavailable) response to indicate how long the service is expected to
+ be unavailable to the requesting client. This field MAY also be used
+ with any 3xx (Redirection) response to indicate the minimum time the
+ user-agent is asked wait before issuing the redirected request. The
+ value of this field can be either an HTTP-date or an integer number
+ of seconds (in decimal) after the time of the response.
+
+ Retry-After = "Retry-After" ":" ( HTTP-date | delta-seconds )
+
+ Two examples of its use are
+
+ Retry-After: Fri, 31 Dec 1999 23:59:59 GMT
+ Retry-After: 120
+
+ In the latter example, the delay is 2 minutes.
+
+14.38 Server
+
+ The Server response-header field contains information about the
+ software used by the origin server to handle the request. The field
+ can contain multiple product tokens (section 3.8) and comments
+ identifying the server and any significant subproducts. The product
+ tokens are listed in order of their significance for identifying the
+ application.
+
+ Server = "Server" ":" 1*( product | comment )
+
+ Example:
+
+ Server: CERN/3.0 libwww/2.17
+
+ If the response is being forwarded through a proxy, the proxy
+ application MUST NOT modify the Server response-header. Instead, it
+ SHOULD include a Via field (as described in section 14.45).
+
+ Note: Revealing the specific software version of the server might
+ allow the server machine to become more vulnerable to attacks
+ against software that is known to contain security holes. Server
+ implementors are encouraged to make this field a configurable
+ option.
+
+14.39 TE
+
+ The TE request-header field indicates what extension transfer-codings
+ it is willing to accept in the response and whether or not it is
+ willing to accept trailer fields in a chunked transfer-coding. Its
+ value may consist of the keyword "trailers" and/or a comma-separated
+ list of extension transfer-coding names with optional accept
+ parameters (as described in section 3.6).
+
+ TE = "TE" ":" #( t-codings )
+ t-codings = "trailers" | ( transfer-extension [ accept-params ] )
+
+ The presence of the keyword "trailers" indicates that the client is
+ willing to accept trailer fields in a chunked transfer-coding, as
+ defined in section 3.6.1. This keyword is reserved for use with
+ transfer-coding values even though it does not itself represent a
+ transfer-coding.
+
+ Examples of its use are:
+
+ TE: deflate
+ TE:
+ TE: trailers, deflate;q=0.5
+
+ The TE header field only applies to the immediate connection.
+ Therefore, the keyword MUST be supplied within a Connection header
+ field (section 14.10) whenever TE is present in an HTTP/1.1 message.
+
+ A server tests whether a transfer-coding is acceptable, according to
+ a TE field, using these rules:
+
+ 1. The "chunked" transfer-coding is always acceptable. If the
+ keyword "trailers" is listed, the client indicates that it is
+ willing to accept trailer fields in the chunked response on
+ behalf of itself and any downstream clients. The implication is
+ that, if given, the client is stating that either all
+ downstream clients are willing to accept trailer fields in the
+ forwarded response, or that it will attempt to buffer the
+ response on behalf of downstream recipients.
+
+ Note: HTTP/1.1 does not define any means to limit the size of a
+ chunked response such that a client can be assured of buffering
+ the entire response.
+
+ 2. If the transfer-coding being tested is one of the transfer-
+ codings listed in the TE field, then it is acceptable unless it
+ is accompanied by a qvalue of 0. (As defined in section 3.9, a
+ qvalue of 0 means "not acceptable.")
+
+ 3. If multiple transfer-codings are acceptable, then the
+ acceptable transfer-coding with the highest non-zero qvalue is
+ preferred. The "chunked" transfer-coding always has a qvalue
+ of 1.
+
+ If the TE field-value is empty or if no TE field is present, the only
+ transfer-coding is "chunked". A message with no transfer-coding is
+ always acceptable.
+
+14.40 Trailer
+
+ The Trailer general field value indicates that the given set of
+ header fields is present in the trailer of a message encoded with
+ chunked transfer-coding.
+
+ Trailer = "Trailer" ":" 1#field-name
+
+ An HTTP/1.1 message SHOULD include a Trailer header field in a
+ message using chunked transfer-coding with a non-empty trailer. Doing
+ so allows the recipient to know which header fields to expect in the
+ trailer.
+
+ If no Trailer header field is present, the trailer SHOULD NOT include
+ any header fields. See section 3.6.1 for restrictions on the use of
+ trailer fields in a "chunked" transfer-coding.
+
+ Message header fields listed in the Trailer header field MUST NOT
+ include the following header fields:
+
+ . Transfer-Encoding
+
+ . Content-Length
+
+ . Trailer
+
+14.41 Transfer-Encoding
+
+ The Transfer-Encoding general-header field indicates what (if any)
+ type of transformation has been applied to the message body in order
+ to safely transfer it between the sender and the recipient. This
+ differs from the content-coding in that the transfer-coding is a
+ property of the message, not of the entity.
+
+ Transfer-Encoding = "Transfer-Encoding" ":" 1#transfer-coding
+
+ Transfer-codings are defined in section 3.6. An example is:
+
+ Transfer-Encoding: chunked
+
+ If multiple encodings have been applied to an entity, the transfer-
+ codings MUST be listed in the order in which they were applied.
+ Additional information about the encoding parameters MAY be provided
+ by other entity-header fields not defined by this specification.
+
+ Many older HTTP/1.0 applications do not understand the Transfer-
+ Encoding header.
+
+14.42 Upgrade
+
+ The Upgrade general-header allows the client to specify what
+ additional communication protocols it supports and would like to use
+ if the server finds it appropriate to switch protocols. The server
+ MUST use the Upgrade header field within a 101 (Switching Protocols)
+ response to indicate which protocol(s) are being switched.
+
+ Upgrade = "Upgrade" ":" 1#product
+
+ For example,
+
+ Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11
+
+ The Upgrade header field is intended to provide a simple mechanism
+ for transition from HTTP/1.1 to some other, incompatible protocol. It
+ does so by allowing the client to advertise its desire to use another
+ protocol, such as a later version of HTTP with a higher major version
+ number, even though the current request has been made using HTTP/1.1.
+ This eases the difficult transition between incompatible protocols by
+ allowing the client to initiate a request in the more commonly
+ supported protocol while indicating to the server that it would like
+ to use a "better" protocol if available (where "better" is determined
+ by the server, possibly according to the nature of the method and/or
+ resource being requested).
+
+ The Upgrade header field only applies to switching application-layer
+ protocols upon the existing transport-layer connection. Upgrade
+ cannot be used to insist on a protocol change; its acceptance and use
+ by the server is optional. The capabilities and nature of the
+ application-layer communication after the protocol change is entirely
+ dependent upon the new protocol chosen, although the first action
+ after changing the protocol MUST be a response to the initial HTTP
+ request containing the Upgrade header field.
+
+ The Upgrade header field only applies to the immediate connection.
+ Therefore, the upgrade keyword MUST be supplied within a Connection
+ header field (section 14.10) whenever Upgrade is present in an
+ HTTP/1.1 message.
+
+ The Upgrade header field cannot be used to indicate a switch to a
+ protocol on a different connection. For that purpose, it is more
+ appropriate to use a 301, 302, 303, or 305 redirection response.
+
+ This specification only defines the protocol name "HTTP" for use by
+ the family of Hypertext Transfer Protocols, as defined by the HTTP
+ version rules of section 3.1 and future updates to this
+ specification. Any token can be used as a protocol name; however, it
+ will only be useful if both the client and server associate the name
+ with the same protocol.
+
+14.43 User-Agent
+
+ The User-Agent request-header field contains information about the
+ user agent originating the request. This is for statistical purposes,
+ the tracing of protocol violations, and automated recognition of user
+ agents for the sake of tailoring responses to avoid particular user
+ agent limitations. User agents SHOULD include this field with
+ requests. The field can contain multiple product tokens (section 3.8)
+ and comments identifying the agent and any subproducts which form a
+ significant part of the user agent. By convention, the product tokens
+ are listed in order of their significance for identifying the
+ application.
+
+ User-Agent = "User-Agent" ":" 1*( product | comment )
+
+ Example:
+
+ User-Agent: CERN-LineMode/2.15 libwww/2.17b3
+
+14.44 Vary
+
+ The Vary field value indicates the set of request-header fields that
+ fully determines, while the response is fresh, whether a cache is
+ permitted to use the response to reply to a subsequent request
+ without revalidation. For uncacheable or stale responses, the Vary
+ field value advises the user agent about the criteria that were used
+ to select the representation. A Vary field value of "*" implies that
+ a cache cannot determine from the request headers of a subsequent
+ request whether this response is the appropriate representation. See
+ section 13.6 for use of the Vary header field by caches.
+
+ Vary = "Vary" ":" ( "*" | 1#field-name )
+
+ An HTTP/1.1 server SHOULD include a Vary header field with any
+ cacheable response that is subject to server-driven negotiation.
+ Doing so allows a cache to properly interpret future requests on that
+ resource and informs the user agent about the presence of negotiation
+
+ on that resource. A server MAY include a Vary header field with a
+ non-cacheable response that is subject to server-driven negotiation,
+ since this might provide the user agent with useful information about
+ the dimensions over which the response varies at the time of the
+ response.
+
+ A Vary field value consisting of a list of field-names signals that
+ the representation selected for the response is based on a selection
+ algorithm which considers ONLY the listed request-header field values
+ in selecting the most appropriate representation. A cache MAY assume
+ that the same selection will be made for future requests with the
+ same values for the listed field names, for the duration of time for
+ which the response is fresh.
+
+ The field-names given are not limited to the set of standard
+ request-header fields defined by this specification. Field names are
+ case-insensitive.
+
+ A Vary field value of "*" signals that unspecified parameters not
+ limited to the request-headers (e.g., the network address of the
+ client), play a role in the selection of the response representation.
+ The "*" value MUST NOT be generated by a proxy server; it may only be
+ generated by an origin server.
+
+14.45 Via
+
+ The Via general-header field MUST be used by gateways and proxies to
+ indicate the intermediate protocols and recipients between the user
+ agent and the server on requests, and between the origin server and
+ the client on responses. It is analogous to the "Received" field of
+ <a href="http://firefly.troll.no/rfcs/rfc822.html">RFC 822</a> [9] and is intended to be used for tracking message forwards,
+ avoiding request loops, and identifying the protocol capabilities of
+ all senders along the request/response chain.
+
+ Via = "Via" ":" 1#( received-protocol received-by [ comment ] )
+ received-protocol = [ protocol-name "/" ] protocol-version
+ protocol-name = token
+ protocol-version = token
+ received-by = ( host [ ":" port ] ) | pseudonym
+ pseudonym = token
+
+ The received-protocol indicates the protocol version of the message
+ received by the server or client along each segment of the
+ request/response chain. The received-protocol version is appended to
+ the Via field value when the message is forwarded so that information
+ about the protocol capabilities of upstream applications remains
+ visible to all recipients.
+
+ The protocol-name is optional if and only if it would be "HTTP". The
+ received-by field is normally the host and optional port number of a
+ recipient server or client that subsequently forwarded the message.
+ However, if the real host is considered to be sensitive information,
+ it MAY be replaced by a pseudonym. If the port is not given, it MAY
+ be assumed to be the default port of the received-protocol.
+
+ Multiple Via field values represents each proxy or gateway that has
+ forwarded the message. Each recipient MUST append its information
+ such that the end result is ordered according to the sequence of
+ forwarding applications.
+
+ Comments MAY be used in the Via header field to identify the software
+ of the recipient proxy or gateway, analogous to the User-Agent and
+ Server header fields. However, all comments in the Via field are
+ optional and MAY be removed by any recipient prior to forwarding the
+ message.
+
+ For example, a request message could be sent from an HTTP/1.0 user
+ agent to an internal proxy code-named "fred", which uses HTTP/1.1 to
+ forward the request to a public proxy at nowhere.com, which completes
+ the request by forwarding it to the origin server at www.ics.uci.edu.
+ The request received by www.ics.uci.edu would then have the following
+ Via header field:
+
+ Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1)
+
+ Proxies and gateways used as a portal through a network firewall
+ SHOULD NOT, by default, forward the names and ports of hosts within
+ the firewall region. This information SHOULD only be propagated if
+ explicitly enabled. If not enabled, the received-by host of any host
+ behind the firewall SHOULD be replaced by an appropriate pseudonym
+ for that host.
+
+ For organizations that have strong privacy requirements for hiding
+ internal structures, a proxy MAY combine an ordered subsequence of
+ Via header field entries with identical received-protocol values into
+ a single such entry. For example,
+
+ Via: 1.0 ricky, 1.1 ethel, 1.1 fred, 1.0 lucy
+
+ could be collapsed to
+
+ Via: 1.0 ricky, 1.1 mertz, 1.0 lucy
+
+ Applications SHOULD NOT combine multiple entries unless they are all
+ under the same organizational control and the hosts have already been
+ replaced by pseudonyms. Applications MUST NOT combine entries which
+ have different received-protocol values.
+
+14.46 Warning
+
+ The Warning general-header field is used to carry additional
+ information about the status or transformation of a message which
+ might not be reflected in the message. This information is typically
+ used to warn about a possible lack of semantic transparency from
+ caching operations or transformations applied to the entity body of
+ the message.
+
+ Warning headers are sent with responses using:
+
+ Warning = "Warning" ":" 1#warning-value
+
+ warning-value = warn-code SP warn-agent SP warn-text
+ [SP warn-date]
+
+ warn-code = 3DIGIT
+ warn-agent = ( host [ ":" port ] ) | pseudonym
+ ; the name or pseudonym of the server adding
+ ; the Warning header, for use in debugging
+ warn-text = quoted-string
+ warn-date = <"> HTTP-date <">
+
+ A response MAY carry more than one Warning header.
+
+ The warn-text SHOULD be in a natural language and character set that
+ is most likely to be intelligible to the human user receiving the
+ response. This decision MAY be based on any available knowledge, such
+ as the location of the cache or user, the Accept-Language field in a
+ request, the Content-Language field in a response, etc. The default
+ language is English and the default character set is ISO-8859-1.
+
+ If a character set other than ISO-8859-1 is used, it MUST be encoded
+ in the warn-text using the method described in <a href="http://firefly.troll.no/rfcs/rfc2047.html">RFC 2047</a> [14].
+
+ Warning headers can in general be applied to any message, however
+ some specific warn-codes are specific to caches and can only be
+ applied to response messages. New Warning headers SHOULD be added
+ after any existing Warning headers. A cache MUST NOT delete any
+ Warning header that it received with a message. However, if a cache
+ successfully validates a cache entry, it SHOULD remove any Warning
+ headers previously attached to that entry except as specified for
+
+ specific Warning codes. It MUST then add any Warning headers received
+ in the validating response. In other words, Warning headers are those
+ that would be attached to the most recent relevant response.
+
+ When multiple Warning headers are attached to a response, the user
+ agent ought to inform the user of as many of them as possible, in the
+ order that they appear in the response. If it is not possible to
+ inform the user of all of the warnings, the user agent SHOULD follow
+ these heuristics:
+
+ - Warnings that appear early in the response take priority over
+ those appearing later in the response.
+
+ - Warnings in the user's preferred character set take priority
+ over warnings in other character sets but with identical warn-
+ codes and warn-agents.
+
+ Systems that generate multiple Warning headers SHOULD order them with
+ this user agent behavior in mind.
+
+ Requirements for the behavior of caches with respect to Warnings are
+ stated in section 13.1.2.
+
+ This is a list of the currently-defined warn-codes, each with a
+ recommended warn-text in English, and a description of its meaning.
+
+ 110 Response is stale
+ MUST be included whenever the returned response is stale.
+
+ 111 Revalidation failed
+ MUST be included if a cache returns a stale response because an
+ attempt to revalidate the response failed, due to an inability to
+ reach the server.
+
+ 112 Disconnected operation
+ SHOULD be included if the cache is intentionally disconnected from
+ the rest of the network for a period of time.
+
+ 113 Heuristic expiration
+ MUST be included if the cache heuristically chose a freshness
+ lifetime greater than 24 hours and the response's age is greater
+ than 24 hours.
+
+ 199 Miscellaneous warning
+ The warning text MAY include arbitrary information to be presented
+ to a human user, or logged. A system receiving this warning MUST
+ NOT take any automated action, besides presenting the warning to
+ the user.
+
+ 214 Transformation applied
+ MUST be added by an intermediate cache or proxy if it applies any
+ transformation changing the content-coding (as specified in the
+ Content-Encoding header) or media-type (as specified in the
+ Content-Type header) of the response, or the entity-body of the
+ response, unless this Warning code already appears in the response.
+
+ 299 Miscellaneous persistent warning
+ The warning text MAY include arbitrary information to be presented
+ to a human user, or logged. A system receiving this warning MUST
+ NOT take any automated action.
+
+ If an implementation sends a message with one or more Warning headers
+ whose version is HTTP/1.0 or lower, then the sender MUST include in
+ each warning-value a warn-date that matches the date in the response.
+
+ If an implementation receives a message with a warning-value that
+ includes a warn-date, and that warn-date is different from the Date
+ value in the response, then that warning-value MUST be deleted from
+ the message before storing, forwarding, or using it. (This prevents
+ bad consequences of naive caching of Warning header fields.) If all
+ of the warning-values are deleted for this reason, the Warning header
+ MUST be deleted as well.
+
+14.47 WWW-Authenticate
+
+ The WWW-Authenticate response-header field MUST be included in 401
+ (Unauthorized) response messages. The field value consists of at
+ least one challenge that indicates the authentication scheme(s) and
+ parameters applicable to the Request-URI.
+
+ WWW-Authenticate = "WWW-Authenticate" ":" 1#challenge
+
+ The HTTP access authentication process is described in "HTTP
+ Authentication: Basic and Digest Access Authentication" [43]. User
+ agents are advised to take special care in parsing the WWW-
+ Authenticate field value as it might contain more than one challenge,
+ or if more than one WWW-Authenticate header field is provided, the
+ contents of a challenge itself can contain a comma-separated list of
+ authentication parameters.
+
+15 Security Considerations
+
+ This section is meant to inform application developers, information
+ providers, and users of the security limitations in HTTP/1.1 as
+ described by this document. The discussion does not include
+ definitive solutions to the problems revealed, though it does make
+ some suggestions for reducing security risks.
+
+15.1 Personal Information
+
+ HTTP clients are often privy to large amounts of personal information
+ (e.g. the user's name, location, mail address, passwords, encryption
+ keys, etc.), and SHOULD be very careful to prevent unintentional
+ leakage of this information via the HTTP protocol to other sources.
+ We very strongly recommend that a convenient interface be provided
+ for the user to control dissemination of such information, and that
+ designers and implementors be particularly careful in this area.
+ History shows that errors in this area often create serious security
+ and/or privacy problems and generate highly adverse publicity for the
+ implementor's company.
+
+15.1.1 Abuse of Server Log Information
+
+ A server is in the position to save personal data about a user's
+ requests which might identify their reading patterns or subjects of
+ interest. This information is clearly confidential in nature and its
+ handling can be constrained by law in certain countries. People using
+ the HTTP protocol to provide data are responsible for ensuring that
+ such material is not distributed without the permission of any
+ individuals that are identifiable by the published results.
+
+15.1.2 Transfer of Sensitive Information
+
+ Like any generic data transfer protocol, HTTP cannot regulate the
+ content of the data that is transferred, nor is there any a priori
+ method of determining the sensitivity of any particular piece of
+ information within the context of any given request. Therefore,
+ applications SHOULD supply as much control over this information as
+ possible to the provider of that information. Four header fields are
+ worth special mention in this context: Server, Via, Referer and From.
+
+ Revealing the specific software version of the server might allow the
+ server machine to become more vulnerable to attacks against software
+ that is known to contain security holes. Implementors SHOULD make the
+ Server header field a configurable option.
+
+ Proxies which serve as a portal through a network firewall SHOULD
+ take special precautions regarding the transfer of header information
+ that identifies the hosts behind the firewall. In particular, they
+ SHOULD remove, or replace with sanitized versions, any Via fields
+ generated behind the firewall.
+
+ The Referer header allows reading patterns to be studied and reverse
+ links drawn. Although it can be very useful, its power can be abused
+ if user details are not separated from the information contained in
+
+ the Referer. Even when the personal information has been removed, the
+ Referer header might indicate a private document's URI whose
+ publication would be inappropriate.
+
+ The information sent in the From field might conflict with the user's
+ privacy interests or their site's security policy, and hence it
+ SHOULD NOT be transmitted without the user being able to disable,
+ enable, and modify the contents of the field. The user MUST be able
+ to set the contents of this field within a user preference or
+ application defaults configuration.
+
+ We suggest, though do not require, that a convenient toggle interface
+ be provided for the user to enable or disable the sending of From and
+ Referer information.
+
+ The User-Agent (section 14.43) or Server (section 14.38) header
+ fields can sometimes be used to determine that a specific client or
+ server have a particular security hole which might be exploited.
+ Unfortunately, this same information is often used for other valuable
+ purposes for which HTTP currently has no better mechanism.
+
+15.1.3 Encoding Sensitive Information in URI's
+
+ Because the source of a link might be private information or might
+ reveal an otherwise private information source, it is strongly
+ recommended that the user be able to select whether or not the
+ Referer field is sent. For example, a browser client could have a
+ toggle switch for browsing openly/anonymously, which would
+ respectively enable/disable the sending of Referer and From
+ information.
+
+ Clients SHOULD NOT include a Referer header field in a (non-secure)
+ HTTP request if the referring page was transferred with a secure
+ protocol.
+
+ Authors of services which use the HTTP protocol SHOULD NOT use GET
+ based forms for the submission of sensitive data, because this will
+ cause this data to be encoded in the Request-URI. Many existing
+ servers, proxies, and user agents will log the request URI in some
+ place where it might be visible to third parties. Servers can use
+ POST-based form submission instead
+
+15.1.4 Privacy Issues Connected to Accept Headers
+
+ Accept request-headers can reveal information about the user to all
+ servers which are accessed. The Accept-Language header in particular
+ can reveal information the user would consider to be of a private
+ nature, because the understanding of particular languages is often
+
+ strongly correlated to the membership of a particular ethnic group.
+ User agents which offer the option to configure the contents of an
+ Accept-Language header to be sent in every request are strongly
+ encouraged to let the configuration process include a message which
+ makes the user aware of the loss of privacy involved.
+
+ An approach that limits the loss of privacy would be for a user agent
+ to omit the sending of Accept-Language headers by default, and to ask
+ the user whether or not to start sending Accept-Language headers to a
+ server if it detects, by looking for any Vary response-header fields
+ generated by the server, that such sending could improve the quality
+ of service.
+
+ Elaborate user-customized accept header fields sent in every request,
+ in particular if these include quality values, can be used by servers
+ as relatively reliable and long-lived user identifiers. Such user
+ identifiers would allow content providers to do click-trail tracking,
+ and would allow collaborating content providers to match cross-server
+ click-trails or form submissions of individual users. Note that for
+ many users not behind a proxy, the network address of the host
+ running the user agent will also serve as a long-lived user
+ identifier. In environments where proxies are used to enhance
+ privacy, user agents ought to be conservative in offering accept
+ header configuration options to end users. As an extreme privacy
+ measure, proxies could filter the accept headers in relayed requests.
+ General purpose user agents which provide a high degree of header
+ configurability SHOULD warn users about the loss of privacy which can
+ be involved.
+
+15.2 Attacks Based On File and Path Names
+
+ Implementations of HTTP origin servers SHOULD be careful to restrict
+ the documents returned by HTTP requests to be only those that were
+ intended by the server administrators. If an HTTP server translates
+ HTTP URIs directly into file system calls, the server MUST take
+ special care not to serve files that were not intended to be
+ delivered to HTTP clients. For example, UNIX, Microsoft Windows, and
+ other operating systems use ".." as a path component to indicate a
+ directory level above the current one. On such a system, an HTTP
+ server MUST disallow any such construct in the Request-URI if it
+ would otherwise allow access to a resource outside those intended to
+ be accessible via the HTTP server. Similarly, files intended for
+ reference only internally to the server (such as access control
+ files, configuration files, and script code) MUST be protected from
+ inappropriate retrieval, since they might contain sensitive
+ information. Experience has shown that minor bugs in such HTTP server
+ implementations have turned into security risks.
+
+15.3 DNS Spoofing
+
+ Clients using HTTP rely heavily on the Domain Name Service, and are
+ thus generally prone to security attacks based on the deliberate
+ mis-association of IP addresses and DNS names. Clients need to be
+ cautious in assuming the continuing validity of an IP number/DNS name
+ association.
+
+ In particular, HTTP clients SHOULD rely on their name resolver for
+ confirmation of an IP number/DNS name association, rather than
+ caching the result of previous host name lookups. Many platforms
+ already can cache host name lookups locally when appropriate, and
+ they SHOULD be configured to do so. It is proper for these lookups to
+ be cached, however, only when the TTL (Time To Live) information
+ reported by the name server makes it likely that the cached
+ information will remain useful.
+
+ If HTTP clients cache the results of host name lookups in order to
+ achieve a performance improvement, they MUST observe the TTL
+ information reported by DNS.
+
+ If HTTP clients do not observe this rule, they could be spoofed when
+ a previously-accessed server's IP address changes. As network
+ renumbering is expected to become increasingly common [24], the
+ possibility of this form of attack will grow. Observing this
+ requirement thus reduces this potential security vulnerability.
+
+ This requirement also improves the load-balancing behavior of clients
+ for replicated servers using the same DNS name and reduces the
+ likelihood of a user's experiencing failure in accessing sites which
+ use that strategy.
+
+15.4 Location Headers and Spoofing
+
+ If a single server supports multiple organizations that do not trust
+ one another, then it MUST check the values of Location and Content-
+ Location headers in responses that are generated under control of
+ said organizations to make sure that they do not attempt to
+ invalidate resources over which they have no authority.
+
+15.5 Content-Disposition Issues
+
+ <a href="http://firefly.troll.no/rfcs/rfc1806.html">RFC 1806</a> [35], from which the often implemented Content-Disposition
+ (see section 19.5.1) header in HTTP is derived, has a number of very
+ serious security considerations. Content-Disposition is not part of
+ the HTTP standard, but since it is widely implemented, we are
+ documenting its use and risks for implementors. See <a href="http://firefly.troll.no/rfcs/rfc2183.html">RFC 2183</a> [49]
+ (which updates <a href="http://firefly.troll.no/rfcs/rfc1806.html">RFC 1806</a>) for details.
+
+15.6 Authentication Credentials and Idle Clients
+
+ Existing HTTP clients and user agents typically retain authentication
+ information indefinitely. HTTP/1.1. does not provide a method for a
+ server to direct clients to discard these cached credentials. This is
+ a significant defect that requires further extensions to HTTP.
+ Circumstances under which credential caching can interfere with the
+ application's security model include but are not limited to:
+
+ - Clients which have been idle for an extended period following
+ which the server might wish to cause the client to reprompt the
+ user for credentials.
+
+ - Applications which include a session termination indication
+ (such as a `logout' or `commit' button on a page) after which
+ the server side of the application `knows' that there is no
+ further reason for the client to retain the credentials.
+
+ This is currently under separate study. There are a number of work-
+ arounds to parts of this problem, and we encourage the use of
+ password protection in screen savers, idle time-outs, and other
+ methods which mitigate the security problems inherent in this
+ problem. In particular, user agents which cache credentials are
+ encouraged to provide a readily accessible mechanism for discarding
+ cached credentials under user control.
+
+15.7 Proxies and Caching
+
+ By their very nature, HTTP proxies are men-in-the-middle, and
+ represent an opportunity for man-in-the-middle attacks. Compromise of
+ the systems on which the proxies run can result in serious security
+ and privacy problems. Proxies have access to security-related
+ information, personal information about individual users and
+ organizations, and proprietary information belonging to users and
+ content providers. A compromised proxy, or a proxy implemented or
+ configured without regard to security and privacy considerations,
+ might be used in the commission of a wide range of potential attacks.
+
+ Proxy operators should protect the systems on which proxies run as
+ they would protect any system that contains or transports sensitive
+ information. In particular, log information gathered at proxies often
+ contains highly sensitive personal information, and/or information
+ about organizations. Log information should be carefully guarded, and
+ appropriate guidelines for use developed and followed. (Section
+ 15.1.1).
+
+ Caching proxies provide additional potential vulnerabilities, since
+ the contents of the cache represent an attractive target for
+ malicious exploitation. Because cache contents persist after an HTTP
+ request is complete, an attack on the cache can reveal information
+ long after a user believes that the information has been removed from
+ the network. Therefore, cache contents should be protected as
+ sensitive information.
+
+ Proxy implementors should consider the privacy and security
+ implications of their design and coding decisions, and of the
+ configuration options they provide to proxy operators (especially the
+ default configuration).
+
+ Users of a proxy need to be aware that they are no trustworthier than
+ the people who run the proxy; HTTP itself cannot solve this problem.
+
+ The judicious use of cryptography, when appropriate, may suffice to
+ protect against a broad range of security and privacy attacks. Such
+ cryptography is beyond the scope of the HTTP/1.1 specification.
+
+15.7.1 Denial of Service Attacks on Proxies
+
+ They exist. They are hard to defend against. Research continues.
+ Beware.
+
+16 Acknowledgments
+
+ This specification makes heavy use of the augmented BNF and generic
+ constructs defined by David H. Crocker for <a href="http://firefly.troll.no/rfcs/rfc822.html">RFC 822</a> [9]. Similarly, it
+ reuses many of the definitions provided by Nathaniel Borenstein and
+ Ned Freed for MIME [7]. We hope that their inclusion in this
+ specification will help reduce past confusion over the relationship
+ between HTTP and Internet mail message formats.
+
+ The HTTP protocol has evolved considerably over the years. It has
+ benefited from a large and active developer community--the many
+ people who have participated on the www-talk mailing list--and it is
+ that community which has been most responsible for the success of
+ HTTP and of the World-Wide Web in general. Marc Andreessen, Robert
+ Cailliau, Daniel W. Connolly, Bob Denny, John Franks, Jean-Francois
+ Groff, Phillip M. Hallam-Baker, Hakon W. Lie, Ari Luotonen, Rob
+ McCool, Lou Montulli, Dave Raggett, Tony Sanders, and Marc
+ VanHeyningen deserve special recognition for their efforts in
+ defining early aspects of the protocol.
+
+ This document has benefited greatly from the comments of all those
+ participating in the HTTP-WG. In addition to those already mentioned,
+ the following individuals have contributed to this specification:
+
+ Gary Adams Ross Patterson
+ Harald Tveit Alvestrand Albert Lunde
+ Keith Ball John C. Mallery
+ Brian Behlendorf Jean-Philippe Martin-Flatin
+ Paul Burchard Mitra
+ Maurizio Codogno David Morris
+ Mike Cowlishaw Gavin Nicol
+ Roman Czyborra Bill Perry
+ Michael A. Dolan Jeffrey Perry
+ David J. Fiander Scott Powers
+ Alan Freier Owen Rees
+ Marc Hedlund Luigi Rizzo
+ Greg Herlihy David Robinson
+ Koen Holtman Marc Salomon
+ Alex Hopmann Rich Salz
+ Bob Jernigan Allan M. Schiffman
+ Shel Kaphan Jim Seidman
+ Rohit Khare Chuck Shotton
+ John Klensin Eric W. Sink
+ Martijn Koster Simon E. Spero
+ Alexei Kosut Richard N. Taylor
+ David M. Kristol Robert S. Thau
+ Daniel LaLiberte Bill (BearHeart) Weinman
+ Ben Laurie Francois Yergeau
+ Paul J. Leach Mary Ellen Zurko
+ Daniel DuBois Josh Cohen
+
+ Much of the content and presentation of the caching design is due to
+ suggestions and comments from individuals including: Shel Kaphan,
+ Paul Leach, Koen Holtman, David Morris, and Larry Masinter.
+
+ Most of the specification of ranges is based on work originally done
+ by Ari Luotonen and John Franks, with additional input from Steve
+ Zilles.
+
+ Thanks to the "cave men" of Palo Alto. You know who you are.
+
+ Jim Gettys (the current editor of this document) wishes particularly
+ to thank Roy Fielding, the previous editor of this document, along
+ with John Klensin, Jeff Mogul, Paul Leach, Dave Kristol, Koen
+ Holtman, John Franks, Josh Cohen, Alex Hopmann, Scott Lawrence, and
+ Larry Masinter for their help. And thanks go particularly to Jeff
+ Mogul and Scott Lawrence for performing the "MUST/MAY/SHOULD" audit.
+
+ The Apache Group, Anselm Baird-Smith, author of Jigsaw, and Henrik
+ Frystyk implemented <a href="http://firefly.troll.no/rfcs/rfc2068.html">RFC 2068</a> early, and we wish to thank them for the
+ discovery of many of the problems that this document attempts to
+ rectify.
+
+17 References
+
+ [1] Alvestrand, H., "Tags for the Identification of Languages", RFC
+ 1766, March 1995.
+
+ [2] Anklesaria, F., McCahill, M., Lindner, P., Johnson, D., Torrey,
+ D. and B. Alberti, "The Internet Gopher Protocol (a distributed
+ document search and retrieval protocol)", <a href="http://firefly.troll.no/rfcs/rfc1436.html">RFC 1436</a>, March 1993.
+
+ [3] Berners-Lee, T., "Universal Resource Identifiers in WWW", RFC
+ 1630, June 1994.
+
+ [4] Berners-Lee, T., Masinter, L. and M. McCahill, "Uniform Resource
+ Locators (URL)", <a href="http://firefly.troll.no/rfcs/rfc1738.html">RFC 1738</a>, December 1994.
+
+ [5] Berners-Lee, T. and D. Connolly, "Hypertext Markup Language -
+ 2.0", <a href="http://firefly.troll.no/rfcs/rfc1866.html">RFC 1866</a>, November 1995.
+
+ [6] Berners-Lee, T., Fielding, R. and H. Frystyk, "Hypertext Transfer
+ Protocol -- HTTP/1.0", <a href="http://firefly.troll.no/rfcs/rfc1945.html">RFC 1945</a>, May 1996.
+
+ [7] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part One: Format of Internet Message Bodies",
+ <a href="http://firefly.troll.no/rfcs/rfc2045.html">RFC 2045</a>, November 1996.
+
+ [8] Braden, R., "Requirements for Internet Hosts -- Communication
+ Layers", STD 3, <a href="http://firefly.troll.no/rfcs/rfc1123.html">RFC 1123</a>, October 1989.
+
+ [9] Crocker, D., "Standard for The Format of ARPA Internet Text
+ Messages", STD 11, <a href="http://firefly.troll.no/rfcs/rfc822.html">RFC 822</a>, August 1982.
+
+ [10] Davis, F., Kahle, B., Morris, H., Salem, J., Shen, T., Wang, R.,
+ Sui, J., and M. Grinbaum, "WAIS Interface Protocol Prototype
+ Functional Specification," (v1.5), Thinking Machines
+ Corporation, April 1990.
+
+ [11] Fielding, R., "Relative Uniform Resource Locators", <a href="http://firefly.troll.no/rfcs/rfc1808.html">RFC 1808</a>,
+ June 1995.
+
+ [12] Horton, M. and R. Adams, "Standard for Interchange of USENET
+ Messages", <a href="http://firefly.troll.no/rfcs/rfc1036.html">RFC 1036</a>, December 1987.
+
+ [13] Kantor, B. and P. Lapsley, "Network News Transfer Protocol", RFC
+ 977, February 1986.
+
+ [14] Moore, K., "MIME (Multipurpose Internet Mail Extensions) Part
+ Three: Message Header Extensions for Non-ASCII Text", <a href="http://firefly.troll.no/rfcs/rfc2047.html">RFC 2047</a>,
+ November 1996.
+
+ [15] Nebel, E. and L. Masinter, "Form-based File Upload in HTML", RFC
+ 1867, November 1995.
+
+ [16] Postel, J., "Simple Mail Transfer Protocol", STD 10, <a href="http://firefly.troll.no/rfcs/rfc821.html">RFC 821</a>,
+ August 1982.
+
+ [17] Postel, J., "Media Type Registration Procedure", <a href="http://firefly.troll.no/rfcs/rfc1590.html">RFC 1590</a>,
+ November 1996.
+
+ [18] Postel, J. and J. Reynolds, "File Transfer Protocol", STD 9, RFC
+ 959, October 1985.
+
+ [19] Reynolds, J. and J. Postel, "Assigned Numbers", STD 2, <a href="http://firefly.troll.no/rfcs/rfc1700.html">RFC 1700</a>,
+ October 1994.
+
+ [20] Sollins, K. and L. Masinter, "Functional Requirements for
+ Uniform Resource Names", <a href="http://firefly.troll.no/rfcs/rfc1737.html">RFC 1737</a>, December 1994.
+
+ [21] US-ASCII. Coded Character Set - 7-Bit American Standard Code for
+ Information Interchange. Standard ANSI X3.4-1986, ANSI, 1986.
+
+ [22] ISO-8859. International Standard -- Information Processing --
+ 8-bit Single-Byte Coded Graphic Character Sets --
+ Part 1: Latin alphabet No. 1, ISO-8859-1:1987.
+ Part 2: Latin alphabet No. 2, ISO-8859-2, 1987.
+ Part 3: Latin alphabet No. 3, ISO-8859-3, 1988.
+ Part 4: Latin alphabet No. 4, ISO-8859-4, 1988.
+ Part 5: Latin/Cyrillic alphabet, ISO-8859-5, 1988.
+ Part 6: Latin/Arabic alphabet, ISO-8859-6, 1987.
+ Part 7: Latin/Greek alphabet, ISO-8859-7, 1987.
+ Part 8: Latin/Hebrew alphabet, ISO-8859-8, 1988.
+ Part 9: Latin alphabet No. 5, ISO-8859-9, 1990.
+
+ [23] Meyers, J. and M. Rose, "The Content-MD5 Header Field", RFC
+ 1864, October 1995.
+
+ [24] Carpenter, B. and Y. Rekhter, "Renumbering Needs Work", RFC
+ 1900, February 1996.
+
+ [25] Deutsch, P., "GZIP file format specification version 4.3", RFC
+ 1952, May 1996.
+
+ [26] Venkata N. Padmanabhan, and Jeffrey C. Mogul. "Improving HTTP
+ Latency", Computer Networks and ISDN Systems, v. 28, pp. 25-35,
+ Dec. 1995. Slightly revised version of paper in Proc. 2nd
+ International WWW Conference '94: Mosaic and the Web, Oct. 1994,
+ which is available at
+ <a href="http://www.ncsa.uiuc.edu/SDG/IT94/Proceedings/DDay/mogul/HTTPLat">http://www.ncsa.uiuc.edu/SDG/IT94/Proceedings/DDay/mogul/HTTPLat</a>
+ ency.html.
+
+ [27] Joe Touch, John Heidemann, and Katia Obraczka. "Analysis of HTTP
+ Performance", <URL: <a href="http://www.isi.edu/touch/pubs/http-perf96/">http://www.isi.edu/touch/pubs/http-perf96/</a>>,
+ ISI Research Report ISI/RR-98-463, (original report dated Aug.
+ 1996), USC/Information Sciences Institute, August 1998.
+
+ [28] Mills, D., "Network Time Protocol (Version 3) Specification,
+ Implementation and Analysis", <a href="http://firefly.troll.no/rfcs/rfc1305.html">RFC 1305</a>, March 1992.
+
+ [29] Deutsch, P., "DEFLATE Compressed Data Format Specification
+ version 1.3", <a href="http://firefly.troll.no/rfcs/rfc1951.html">RFC 1951</a>, May 1996.
+
+ [30] S. Spero, "Analysis of HTTP Performance Problems,"
+ <a href="http://sunsite.unc.edu/mdma-release/http-prob.html">http://sunsite.unc.edu/mdma-release/http-prob.html</a>.
+
+ [31] Deutsch, P. and J. Gailly, "ZLIB Compressed Data Format
+ Specification version 3.3", <a href="http://firefly.troll.no/rfcs/rfc1950.html">RFC 1950</a>, May 1996.
+
+ [32] Franks, J., Hallam-Baker, P., Hostetler, J., Leach, P.,
+ Luotonen, A., Sink, E. and L. Stewart, "An Extension to HTTP:
+ Digest Access Authentication", <a href="http://firefly.troll.no/rfcs/rfc2069.html">RFC 2069</a>, January 1997.
+
+ [33] Fielding, R., Gettys, J., Mogul, J., Frystyk, H. and T.
+ Berners-Lee, "Hypertext Transfer Protocol -- HTTP/1.1", RFC
+ 2068, January 1997.
+
+ [34] Bradner, S., "Key words for use in RFCs to Indicate Requirement
+ Levels", BCP 14, <a href="http://firefly.troll.no/rfcs/rfc2119.html">RFC 2119</a>, March 1997.
+
+ [35] Troost, R. and Dorner, S., "Communicating Presentation
+ Information in Internet Messages: The Content-Disposition
+ Header", <a href="http://firefly.troll.no/rfcs/rfc1806.html">RFC 1806</a>, June 1995.
+
+ [36] Mogul, J., Fielding, R., Gettys, J. and H. Frystyk, "Use and
+ Interpretation of HTTP Version Numbers", <a href="http://firefly.troll.no/rfcs/rfc2145.html">RFC 2145</a>, May 1997.
+ [jg639]
+
+ [37] Palme, J., "Common Internet Message Headers", <a href="http://firefly.troll.no/rfcs/rfc2076.html">RFC 2076</a>, February
+ 1997. [jg640]
+
+ [38] Yergeau, F., "UTF-8, a transformation format of Unicode and
+ ISO-10646", <a href="http://firefly.troll.no/rfcs/rfc2279.html">RFC 2279</a>, January 1998. [jg641]
+
+ [39] Nielsen, H.F., Gettys, J., Baird-Smith, A., Prud'hommeaux, E.,
+ Lie, H., and C. Lilley. "Network Performance Effects of
+ HTTP/1.1, CSS1, and PNG," Proceedings of ACM SIGCOMM '97, Cannes
+ France, September 1997.[jg642]
+
+ [40] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part Two: Media Types", <a href="http://firefly.troll.no/rfcs/rfc2046.html">RFC 2046</a>, November
+ 1996. [jg643]
+
+ [41] Alvestrand, H., "IETF Policy on Character Sets and Languages",
+ BCP 18, <a href="http://firefly.troll.no/rfcs/rfc2277.html">RFC 2277</a>, January 1998. [jg644]
+
+ [42] Berners-Lee, T., Fielding, R. and L. Masinter, "Uniform Resource
+ Identifiers (URI): Generic Syntax and Semantics", <a href="http://firefly.troll.no/rfcs/rfc2396.html">RFC 2396</a>,
+ August 1998. [jg645]
+
+ [43] Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence, S.,
+ Leach, P., Luotonen, A., Sink, E. and L. Stewart, "HTTP
+ Authentication: Basic and Digest Access Authentication", RFC
+ 2617, June 1999. [jg646]
+
+ [44] Luotonen, A., "Tunneling TCP based protocols through Web proxy
+ servers," Work in Progress. [jg647]
+
+ [45] Palme, J. and A. Hopmann, "MIME E-mail Encapsulation of
+ Aggregate Documents, such as HTML (MHTML)", <a href="http://firefly.troll.no/rfcs/rfc2110.html">RFC 2110</a>, March
+ 1997.
+
+ [46] Bradner, S., "The Internet Standards Process -- Revision 3", BCP
+ 9, <a href="http://firefly.troll.no/rfcs/rfc2026.html">RFC 2026</a>, October 1996.
+
+ [47] Masinter, L., "Hyper Text Coffee Pot Control Protocol
+ (HTCPCP/1.0)", <a href="http://firefly.troll.no/rfcs/rfc2324.html">RFC 2324</a>, 1 April 1998.
+
+ [48] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part Five: Conformance Criteria and Examples",
+ <a href="http://firefly.troll.no/rfcs/rfc2049.html">RFC 2049</a>, November 1996.
+
+ [49] Troost, R., Dorner, S. and K. Moore, "Communicating Presentation
+ Information in Internet Messages: The Content-Disposition Header
+ Field", <a href="http://firefly.troll.no/rfcs/rfc2183.html">RFC 2183</a>, August 1997.
+
+18 Authors' Addresses
+
+ Roy T. Fielding
+ Information and Computer Science
+ University of California, Irvine
+ Irvine, CA 92697-3425, USA
+
+ Fax: +1 (949) 824-1715
+ EMail: <a href="mailto:fielding@ics.uci.edu">fielding@ics.uci.edu</a>
+
+ James Gettys
+ World Wide Web Consortium
+ MIT Laboratory for Computer Science
+ 545 Technology Square
+ Cambridge, MA 02139, USA
+
+ Fax: +1 (617) 258 8682
+ EMail: <a href="mailto:jg@w3.org">jg@w3.org</a>
+
+ Jeffrey C. Mogul
+ Western Research Laboratory
+ Compaq Computer Corporation
+ 250 University Avenue
+ Palo Alto, California, 94305, USA
+
+ EMail: <a href="mailto:mogul@wrl.dec.com">mogul@wrl.dec.com</a>
+
+ Henrik Frystyk Nielsen
+ World Wide Web Consortium
+ MIT Laboratory for Computer Science
+ 545 Technology Square
+ Cambridge, MA 02139, USA
+
+ Fax: +1 (617) 258 8682
+ EMail: <a href="mailto:frystyk@w3.org">frystyk@w3.org</a>
+
+ Larry Masinter
+ Xerox Corporation
+ 3333 Coyote Hill Road
+ Palo Alto, CA 94034, USA
+
+ EMail: <a href="mailto:masinter@parc.xerox.com">masinter@parc.xerox.com</a>
+
+ Paul J. Leach
+ Microsoft Corporation
+ 1 Microsoft Way
+ Redmond, WA 98052, USA
+
+ EMail: <a href="mailto:paulle@microsoft.com">paulle@microsoft.com</a>
+
+ Tim Berners-Lee
+ Director, World Wide Web Consortium
+ MIT Laboratory for Computer Science
+ 545 Technology Square
+ Cambridge, MA 02139, USA
+
+ Fax: +1 (617) 258 8682
+ EMail: <a href="mailto:timbl@w3.org">timbl@w3.org</a>
+
+19 Appendices
+
+19.1 Internet Media Type message/http and application/http
+
+ In addition to defining the HTTP/1.1 protocol, this document serves
+ as the specification for the Internet media type "message/http" and
+ "application/http". The message/http type can be used to enclose a
+ single HTTP request or response message, provided that it obeys the
+ MIME restrictions for all "message" types regarding line length and
+ encodings. The application/http type can be used to enclose a
+ pipeline of one or more HTTP request or response messages (not
+ intermixed). The following is to be registered with IANA [17].
+
+ Media Type name: message
+ Media subtype name: http
+ Required parameters: none
+ Optional parameters: version, msgtype
+ version: The HTTP-Version number of the enclosed message
+ (e.g., "1.1"). If not present, the version can be
+ determined from the first line of the body.
+ msgtype: The message type -- "request" or "response". If not
+ present, the type can be determined from the first
+ line of the body.
+ Encoding considerations: only "7bit", "8bit", or "binary" are
+ permitted
+ Security considerations: none
+
+ Media Type name: application
+ Media subtype name: http
+ Required parameters: none
+ Optional parameters: version, msgtype
+ version: The HTTP-Version number of the enclosed messages
+ (e.g., "1.1"). If not present, the version can be
+ determined from the first line of the body.
+ msgtype: The message type -- "request" or "response". If not
+ present, the type can be determined from the first
+ line of the body.
+ Encoding considerations: HTTP messages enclosed by this type
+ are in "binary" format; use of an appropriate
+ Content-Transfer-Encoding is required when
+ transmitted via E-mail.
+ Security considerations: none
+
+19.2 Internet Media Type multipart/byteranges
+
+ When an HTTP 206 (Partial Content) response message includes the
+ content of multiple ranges (a response to a request for multiple
+ non-overlapping ranges), these are transmitted as a multipart
+ message-body. The media type for this purpose is called
+ "multipart/byteranges".
+
+ The multipart/byteranges media type includes two or more parts, each
+ with its own Content-Type and Content-Range fields. The required
+ boundary parameter specifies the boundary string used to separate
+ each body-part.
+
+ Media Type name: multipart
+ Media subtype name: byteranges
+ Required parameters: boundary
+ Optional parameters: none
+ Encoding considerations: only "7bit", "8bit", or "binary" are
+ permitted
+ Security considerations: none
+
+ For example:
+
+ HTTP/1.1 206 Partial Content
+ Date: Wed, 15 Nov 1995 06:25:24 GMT
+ Last-Modified: Wed, 15 Nov 1995 04:58:08 GMT
+ Content-type: multipart/byteranges; boundary=THIS_STRING_SEPARATES
+
+ --THIS_STRING_SEPARATES
+ Content-type: application/pdf
+ Content-range: bytes 500-999/8000
+
+ ...the first range...
+ --THIS_STRING_SEPARATES
+ Content-type: application/pdf
+ Content-range: bytes 7000-7999/8000
+
+ ...the second range
+ --THIS_STRING_SEPARATES--
+
+ Notes:
+
+ 1) Additional CRLFs may precede the first boundary string in the
+ entity.
+
+ 2) Although <a href="http://firefly.troll.no/rfcs/rfc2046.html">RFC 2046</a> [40] permits the boundary string to be
+ quoted, some existing implementations handle a quoted boundary
+ string incorrectly.
+
+ 3) A number of browsers and servers were coded to an early draft
+ of the byteranges specification to use a media type of
+ multipart/x-byteranges, which is almost, but not quite
+ compatible with the version documented in HTTP/1.1.
+
+19.3 Tolerant Applications
+
+ Although this document specifies the requirements for the generation
+ of HTTP/1.1 messages, not all applications will be correct in their
+ implementation. We therefore recommend that operational applications
+ be tolerant of deviations whenever those deviations can be
+ interpreted unambiguously.
+
+ Clients SHOULD be tolerant in parsing the Status-Line and servers
+ tolerant when parsing the Request-Line. In particular, they SHOULD
+ accept any amount of SP or HT characters between fields, even though
+ only a single SP is required.
+
+ The line terminator for message-header fields is the sequence CRLF.
+ However, we recommend that applications, when parsing such headers,
+ recognize a single LF as a line terminator and ignore the leading CR.
+
+ The character set of an entity-body SHOULD be labeled as the lowest
+ common denominator of the character codes used within that body, with
+ the exception that not labeling the entity is preferred over labeling
+ the entity with the labels US-ASCII or ISO-8859-1. See section 3.7.1
+ and 3.4.1.
+
+ Additional rules for requirements on parsing and encoding of dates
+ and other potential problems with date encodings include:
+
+ - HTTP/1.1 clients and caches SHOULD assume that an <a href="http://firefly.troll.no/rfcs/rfc850.html">RFC-850</a> date
+ which appears to be more than 50 years in the future is in fact
+ in the past (this helps solve the "year 2000" problem).
+
+ - An HTTP/1.1 implementation MAY internally represent a parsed
+ Expires date as earlier than the proper value, but MUST NOT
+ internally represent a parsed Expires date as later than the
+ proper value.
+
+ - All expiration-related calculations MUST be done in GMT. The
+ local time zone MUST NOT influence the calculation or comparison
+ of an age or expiration time.
+
+ - If an HTTP header incorrectly carries a date value with a time
+ zone other than GMT, it MUST be converted into GMT using the
+ most conservative possible conversion.
+
+19.4 Differences Between HTTP Entities and <a href="http://firefly.troll.no/rfcs/rfc2045.html">RFC 2045</a> Entities
+
+ HTTP/1.1 uses many of the constructs defined for Internet Mail (RFC
+ 822 [9]) and the Multipurpose Internet Mail Extensions (MIME [7]) to
+ allow entities to be transmitted in an open variety of
+ representations and with extensible mechanisms. However, <a href="http://firefly.troll.no/rfcs/rfc2045.html">RFC 2045</a>
+ discusses mail, and HTTP has a few features that are different from
+ those described in <a href="http://firefly.troll.no/rfcs/rfc2045.html">RFC 2045</a>. These differences were carefully chosen
+ to optimize performance over binary connections, to allow greater
+ freedom in the use of new media types, to make date comparisons
+ easier, and to acknowledge the practice of some early HTTP servers
+ and clients.
+
+ This appendix describes specific areas where HTTP differs from RFC
+ 2045. Proxies and gateways to strict MIME environments SHOULD be
+ aware of these differences and provide the appropriate conversions
+ where necessary. Proxies and gateways from MIME environments to HTTP
+ also need to be aware of the differences because some conversions
+ might be required.
+
+19.4.1 MIME-Version
+
+ HTTP is not a MIME-compliant protocol. However, HTTP/1.1 messages MAY
+ include a single MIME-Version general-header field to indicate what
+ version of the MIME protocol was used to construct the message. Use
+ of the MIME-Version header field indicates that the message is in
+ full compliance with the MIME protocol (as defined in <a href="http://firefly.troll.no/rfcs/rfc2045.html">RFC 2045</a>[7]).
+ Proxies/gateways are responsible for ensuring full compliance (where
+ possible) when exporting HTTP messages to strict MIME environments.
+
+ MIME-Version = "MIME-Version" ":" 1*DIGIT "." 1*DIGIT
+
+ MIME version "1.0" is the default for use in HTTP/1.1. However,
+ HTTP/1.1 message parsing and semantics are defined by this document
+ and not the MIME specification.
+
+19.4.2 Conversion to Canonical Form
+
+ <a href="http://firefly.troll.no/rfcs/rfc2045.html">RFC 2045</a> [7] requires that an Internet mail entity be converted to
+ canonical form prior to being transferred, as described in section 4
+ of <a href="http://firefly.troll.no/rfcs/rfc2049.html">RFC 2049</a> [48]. Section 3.7.1 of this document describes the forms
+ allowed for subtypes of the "text" media type when transmitted over
+ HTTP. <a href="http://firefly.troll.no/rfcs/rfc2046.html">RFC 2046</a> requires that content with a type of "text" represent
+ line breaks as CRLF and forbids the use of CR or LF outside of line
+
+ break sequences. HTTP allows CRLF, bare CR, and bare LF to indicate a
+ line break within text content when a message is transmitted over
+ HTTP.
+
+ Where it is possible, a proxy or gateway from HTTP to a strict MIME
+ environment SHOULD translate all line breaks within the text media
+ types described in section 3.7.1 of this document to the <a href="http://firefly.troll.no/rfcs/rfc2049.html">RFC 2049</a>
+ canonical form of CRLF. Note, however, that this might be complicated
+ by the presence of a Content-Encoding and by the fact that HTTP
+ allows the use of some character sets which do not use octets 13 and
+ 10 to represent CR and LF, as is the case for some multi-byte
+ character sets.
+
+ Implementors should note that conversion will break any cryptographic
+ checksums applied to the original content unless the original content
+ is already in canonical form. Therefore, the canonical form is
+ recommended for any content that uses such checksums in HTTP.
+
+19.4.3 Conversion of Date Formats
+
+ HTTP/1.1 uses a restricted set of date formats (section 3.3.1) to
+ simplify the process of date comparison. Proxies and gateways from
+ other protocols SHOULD ensure that any Date header field present in a
+ message conforms to one of the HTTP/1.1 formats and rewrite the date
+ if necessary.
+
+19.4.4 Introduction of Content-Encoding
+
+ <a href="http://firefly.troll.no/rfcs/rfc2045.html">RFC 2045</a> does not include any concept equivalent to HTTP/1.1's
+ Content-Encoding header field. Since this acts as a modifier on the
+ media type, proxies and gateways from HTTP to MIME-compliant
+ protocols MUST either change the value of the Content-Type header
+ field or decode the entity-body before forwarding the message. (Some
+ experimental applications of Content-Type for Internet mail have used
+ a media-type parameter of ";conversions=<content-coding>" to perform
+ a function equivalent to Content-Encoding. However, this parameter is
+ not part of <a href="http://firefly.troll.no/rfcs/rfc2045.html">RFC 2045</a>.)
+
+19.4.5 No Content-Transfer-Encoding
+
+ HTTP does not use the Content-Transfer-Encoding (CTE) field of RFC
+ 2045. Proxies and gateways from MIME-compliant protocols to HTTP MUST
+ remove any non-identity CTE ("quoted-printable" or "base64") encoding
+ prior to delivering the response message to an HTTP client.
+
+ Proxies and gateways from HTTP to MIME-compliant protocols are
+ responsible for ensuring that the message is in the correct format
+ and encoding for safe transport on that protocol, where "safe
+
+ transport" is defined by the limitations of the protocol being used.
+ Such a proxy or gateway SHOULD label the data with an appropriate
+ Content-Transfer-Encoding if doing so will improve the likelihood of
+ safe transport over the destination protocol.
+
+19.4.6 Introduction of Transfer-Encoding
+
+ HTTP/1.1 introduces the Transfer-Encoding header field (section
+ 14.41). Proxies/gateways MUST remove any transfer-coding prior to
+ forwarding a message via a MIME-compliant protocol.
+
+ A process for decoding the "chunked" transfer-coding (section 3.6)
+ can be represented in pseudo-code as:
+
+ length := 0
+ read chunk-size, chunk-extension (if any) and CRLF
+ while (chunk-size > 0) {
+ read chunk-data and CRLF
+ append chunk-data to entity-body
+ length := length + chunk-size
+ read chunk-size and CRLF
+ }
+ read entity-header
+ while (entity-header not empty) {
+ append entity-header to existing header fields
+ read entity-header
+ }
+ Content-Length := length
+ Remove "chunked" from Transfer-Encoding
+
+19.4.7 MHTML and Line Length Limitations
+
+ HTTP implementations which share code with MHTML [45] implementations
+ need to be aware of MIME line length limitations. Since HTTP does not
+ have this limitation, HTTP does not fold long lines. MHTML messages
+ being transported by HTTP follow all conventions of MHTML, including
+ line length limitations and folding, canonicalization, etc., since
+ HTTP transports all message-bodies as payload (see section 3.7.2) and
+ does not interpret the content or any MIME header lines that might be
+ contained therein.
+
+19.5 Additional Features
+
+ <a href="http://firefly.troll.no/rfcs/rfc1945.html">RFC 1945</a> and <a href="http://firefly.troll.no/rfcs/rfc2068.html">RFC 2068</a> document protocol elements used by some
+ existing HTTP implementations, but not consistently and correctly
+ across most HTTP/1.1 applications. Implementors are advised to be
+ aware of these features, but cannot rely upon their presence in, or
+ interoperability with, other HTTP/1.1 applications. Some of these
+
+ describe proposed experimental features, and some describe features
+ that experimental deployment found lacking that are now addressed in
+ the base HTTP/1.1 specification.
+
+ A number of other headers, such as Content-Disposition and Title,
+ from SMTP and MIME are also often implemented (see <a href="http://firefly.troll.no/rfcs/rfc2076.html">RFC 2076</a> [37]).
+
+19.5.1 Content-Disposition
+
+ The Content-Disposition response-header field has been proposed as a
+ means for the origin server to suggest a default filename if the user
+ requests that the content is saved to a file. This usage is derived
+ from the definition of Content-Disposition in <a href="http://firefly.troll.no/rfcs/rfc1806.html">RFC 1806</a> [35].
+
+ content-disposition = "Content-Disposition" ":"
+ disposition-type *( ";" disposition-parm )
+ disposition-type = "attachment" | disp-extension-token
+ disposition-parm = filename-parm | disp-extension-parm
+ filename-parm = "filename" "=" quoted-string
+ disp-extension-token = token
+ disp-extension-parm = token "=" ( token | quoted-string )
+
+ An example is
+
+ Content-Disposition: attachment; filename="fname.ext"
+
+ The receiving user agent SHOULD NOT respect any directory path
+ information present in the filename-parm parameter, which is the only
+ parameter believed to apply to HTTP implementations at this time. The
+ filename SHOULD be treated as a terminal component only.
+
+ If this header is used in a response with the application/octet-
+ stream content-type, the implied suggestion is that the user agent
+ should not display the response, but directly enter a `save response
+ as...' dialog.
+
+ See section 15.5 for Content-Disposition security issues.
+
+19.6 Compatibility with Previous Versions
+
+ It is beyond the scope of a protocol specification to mandate
+ compliance with previous versions. HTTP/1.1 was deliberately
+ designed, however, to make supporting previous versions easy. It is
+ worth noting that, at the time of composing this specification
+ (1996), we would expect commercial HTTP/1.1 servers to:
+
+ - recognize the format of the Request-Line for HTTP/0.9, 1.0, and
+ 1.1 requests;
+
+ - understand any valid request in the format of HTTP/0.9, 1.0, or
+ 1.1;
+
+ - respond appropriately with a message in the same major version
+ used by the client.
+
+ And we would expect HTTP/1.1 clients to:
+
+ - recognize the format of the Status-Line for HTTP/1.0 and 1.1
+ responses;
+
+ - understand any valid response in the format of HTTP/0.9, 1.0, or
+ 1.1.
+
+ For most implementations of HTTP/1.0, each connection is established
+ by the client prior to the request and closed by the server after
+ sending the response. Some implementations implement the Keep-Alive
+ version of persistent connections described in section 19.7.1 of RFC
+ 2068 [33].
+
+19.6.1 Changes from HTTP/1.0
+
+ This section summarizes major differences between versions HTTP/1.0
+ and HTTP/1.1.
+
+19.6.1.1 Changes to Simplify Multi-homed Web Servers and Conserve IP
+ Addresses
+
+ The requirements that clients and servers support the Host request-
+ header, report an error if the Host request-header (section 14.23) is
+ missing from an HTTP/1.1 request, and accept absolute URIs (section
+ 5.1.2) are among the most important changes defined by this
+ specification.
+
+ Older HTTP/1.0 clients assumed a one-to-one relationship of IP
+ addresses and servers; there was no other established mechanism for
+ distinguishing the intended server of a request than the IP address
+ to which that request was directed. The changes outlined above will
+ allow the Internet, once older HTTP clients are no longer common, to
+ support multiple Web sites from a single IP address, greatly
+ simplifying large operational Web servers, where allocation of many
+ IP addresses to a single host has created serious problems. The
+ Internet will also be able to recover the IP addresses that have been
+ allocated for the sole purpose of allowing special-purpose domain
+ names to be used in root-level HTTP URLs. Given the rate of growth of
+ the Web, and the number of servers already deployed, it is extremely
+
+ important that all implementations of HTTP (including updates to
+ existing HTTP/1.0 applications) correctly implement these
+ requirements:
+
+ - Both clients and servers MUST support the Host request-header.
+
+ - A client that sends an HTTP/1.1 request MUST send a Host header.
+
+ - Servers MUST report a 400 (Bad Request) error if an HTTP/1.1
+ request does not include a Host request-header.
+
+ - Servers MUST accept absolute URIs.
+
+19.6.2 Compatibility with HTTP/1.0 Persistent Connections
+
+ Some clients and servers might wish to be compatible with some
+ previous implementations of persistent connections in HTTP/1.0
+ clients and servers. Persistent connections in HTTP/1.0 are
+ explicitly negotiated as they are not the default behavior. HTTP/1.0
+ experimental implementations of persistent connections are faulty,
+ and the new facilities in HTTP/1.1 are designed to rectify these
+ problems. The problem was that some existing 1.0 clients may be
+ sending Keep-Alive to a proxy server that doesn't understand
+ Connection, which would then erroneously forward it to the next
+ inbound server, which would establish the Keep-Alive connection and
+ result in a hung HTTP/1.0 proxy waiting for the close on the
+ response. The result is that HTTP/1.0 clients must be prevented from
+ using Keep-Alive when talking to proxies.
+
+ However, talking to proxies is the most important use of persistent
+ connections, so that prohibition is clearly unacceptable. Therefore,
+ we need some other mechanism for indicating a persistent connection
+ is desired, which is safe to use even when talking to an old proxy
+ that ignores Connection. Persistent connections are the default for
+ HTTP/1.1 messages; we introduce a new keyword (Connection: close) for
+ declaring non-persistence. See section 14.10.
+
+ The original HTTP/1.0 form of persistent connections (the Connection:
+ Keep-Alive and Keep-Alive header) is documented in <a href="http://firefly.troll.no/rfcs/rfc2068.html">RFC 2068</a>. [33]
+
+19.6.3 Changes from <a href="http://firefly.troll.no/rfcs/rfc2068.html">RFC 2068</a>
+
+ This specification has been carefully audited to correct and
+ disambiguate key word usage; <a href="http://firefly.troll.no/rfcs/rfc2068.html">RFC 2068</a> had many problems in respect to
+ the conventions laid out in <a href="http://firefly.troll.no/rfcs/rfc2119.html">RFC 2119</a> [34].
+
+ Clarified which error code should be used for inbound server failures
+ (e.g. DNS failures). (Section 10.5.5).
+
+ CREATE had a race that required an Etag be sent when a resource is
+ first created. (Section 10.2.2).
+
+ Content-Base was deleted from the specification: it was not
+ implemented widely, and there is no simple, safe way to introduce it
+ without a robust extension mechanism. In addition, it is used in a
+ similar, but not identical fashion in MHTML [45].
+
+ Transfer-coding and message lengths all interact in ways that
+ required fixing exactly when chunked encoding is used (to allow for
+ transfer encoding that may not be self delimiting); it was important
+ to straighten out exactly how message lengths are computed. (Sections
+ 3.6, 4.4, 7.2.2, 13.5.2, 14.13, 14.16)
+
+ A content-coding of "identity" was introduced, to solve problems
+ discovered in caching. (section 3.5)
+
+ Quality Values of zero should indicate that "I don't want something"
+ to allow clients to refuse a representation. (Section 3.9)
+
+ The use and interpretation of HTTP version numbers has been clarified
+ by <a href="http://firefly.troll.no/rfcs/rfc2145.html">RFC 2145</a>. Require proxies to upgrade requests to highest protocol
+ version they support to deal with problems discovered in HTTP/1.0
+ implementations (Section 3.1)
+
+ Charset wildcarding is introduced to avoid explosion of character set
+ names in accept headers. (Section 14.2)
+
+ A case was missed in the Cache-Control model of HTTP/1.1; s-maxage
+ was introduced to add this missing case. (Sections 13.4, 14.8, 14.9,
+ 14.9.3)
+
+ The Cache-Control: max-age directive was not properly defined for
+ responses. (Section 14.9.3)
+
+ There are situations where a server (especially a proxy) does not
+ know the full length of a response but is capable of serving a
+ byterange request. We therefore need a mechanism to allow byteranges
+ with a content-range not indicating the full length of the message.
+ (Section 14.16)
+
+ Range request responses would become very verbose if all meta-data
+ were always returned; by allowing the server to only send needed
+ headers in a 206 response, this problem can be avoided. (Section
+ 10.2.7, 13.5.3, and 14.27)
+
+ Fix problem with unsatisfiable range requests; there are two cases:
+ syntactic problems, and range doesn't exist in the document. The 416
+ status code was needed to resolve this ambiguity needed to indicate
+ an error for a byte range request that falls outside of the actual
+ contents of a document. (Section 10.4.17, 14.16)
+
+ Rewrite of message transmission requirements to make it much harder
+ for implementors to get it wrong, as the consequences of errors here
+ can have significant impact on the Internet, and to deal with the
+ following problems:
+
+ 1. Changing "HTTP/1.1 or later" to "HTTP/1.1", in contexts where
+ this was incorrectly placing a requirement on the behavior of
+ an implementation of a future version of HTTP/1.x
+
+ 2. Made it clear that user-agents should retry requests, not
+ "clients" in general.
+
+ 3. Converted requirements for clients to ignore unexpected 100
+ (Continue) responses, and for proxies to forward 100 responses,
+ into a general requirement for 1xx responses.
+
+ 4. Modified some TCP-specific language, to make it clearer that
+ non-TCP transports are possible for HTTP.
+
+ 5. Require that the origin server MUST NOT wait for the request
+ body before it sends a required 100 (Continue) response.
+
+ 6. Allow, rather than require, a server to omit 100 (Continue) if
+ it has already seen some of the request body.
+
+ 7. Allow servers to defend against denial-of-service attacks and
+ broken clients.
+
+ This change adds the Expect header and 417 status code. The message
+ transmission requirements fixes are in sections 8.2, 10.4.18,
+ 8.1.2.2, 13.11, and 14.20.
+
+ Proxies should be able to add Content-Length when appropriate.
+ (Section 13.5.2)
+
+ Clean up confusion between 403 and 404 responses. (Section 10.4.4,
+ 10.4.5, and 10.4.11)
+
+ Warnings could be cached incorrectly, or not updated appropriately.
+ (Section 13.1.2, 13.2.4, 13.5.2, 13.5.3, 14.9.3, and 14.46) Warning
+ also needed to be a general header, as PUT or other methods may have
+ need for it in requests.
+
+ Transfer-coding had significant problems, particularly with
+ interactions with chunked encoding. The solution is that transfer-
+ codings become as full fledged as content-codings. This involves
+ adding an IANA registry for transfer-codings (separate from content
+ codings), a new header field (TE) and enabling trailer headers in the
+ future. Transfer encoding is a major performance benefit, so it was
+ worth fixing [39]. TE also solves another, obscure, downward
+ interoperability problem that could have occurred due to interactions
+ between authentication trailers, chunked encoding and HTTP/1.0
+ clients.(Section 3.6, 3.6.1, and 14.39)
+
+ The PATCH, LINK, UNLINK methods were defined but not commonly
+ implemented in previous versions of this specification. See <a href="http://firefly.troll.no/rfcs/rfc2068.html">RFC 2068</a>
+ [33].
+
+ The Alternates, Content-Version, Derived-From, Link, URI, Public and
+ Content-Base header fields were defined in previous versions of this
+ specification, but not commonly implemented. See <a href="http://firefly.troll.no/rfcs/rfc2068.html">RFC 2068</a> [33].
+
+20 Index
+
+ Please see the PostScript version of this RFC for the INDEX.
+
+21. Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+</pre>
+<p align="center"><script language="JavaScript"><!--
+erfc("2616");
+// --></script><a href="http://firefly.troll.no/rfccomment.php?rfcnum=2616" target="_blank" onclick="window.open('/rfccomment.php?rfcnum=2616','Popup','toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=680,height=530,left=30,top=43'); return false;" )="">Comment on RFC 2616</a>
+</p>
+ <br>
+<div align="center">
+<center>
+<table border="0" cellpadding="4" cellspacing="4" width="100%">
+<tbody><tr><td bgcolor="#d6d6c0" width="100%">
+<p><font face="Arial">Comments about this RFC:</font></p>
+<ul>
+<li><font face="Arial"><a href="http://firefly.troll.no/qa/rfcc-869.html">RFC 2616: Very basic HTTP Server written in Emacs Lisp: http://www.chez.com/emarsden/downl...</a> by Alex Schröder (5/12/2004)</font></li>
+<li><font face="Arial"><a href="http://firefly.troll.no/qa/rfcc-539.html">RFC 2616: If someone has got sample code for a basic HTTP/1.1 Server please let me know......</a> by Mike (2/4/2004)</font></li>
+<li><font face="Arial"><a href="http://firefly.troll.no/qa/rfcc-486.html">RFC 2616: I am seeking ladies for nothing but sex that is all i want from the lady sorry...</a> by treblav (1/16/2004)</font></li>
+<li><font face="Arial"><a href="http://firefly.troll.no/qa/rfcc-2360.html">RFC 2616: Hello.
+
+ I have realized that point 8.1.4 of the RFC 2616 is a big threat to...</a> by Doolyo (8/20/2005)</font></li>
+<li><font face="Arial"><a href="http://firefly.troll.no/qa/rfcc-1522.html">RFC 2616: êêêöïïäììóì::::::@::@"""@:>c
+ :::@"$$%^^*^^*((((99(
+ <<>:"? </a> by óäöóöóöóö (12/16/2004)</font></li>
+<li><font face="Arial"><a href="http://firefly.troll.no/qa/rfcc-2147.html">RFC 2616: Man Such a big and boring doc.. thats why ppl shy away from RFC stuff. Make it...</a> by AnurgaM (6/15/2005)</font></li>
+<li><font face="Arial"><a href="http://firefly.troll.no/qa/rfcc-2277.html">RFC 2616: igeve uo 100 dolars
+
+ iwant password
+
+ farh51@hotmail.com </a> by farh (7/24/2005)</font></li>
+<li><font face="Arial"><a href="http://firefly.troll.no/qa/rfcc-2349.html">RFC 2616: I have realized that point 8.1.4 of this RFC is a big threat to the load speed...</a> by Doolyo (8/15/2005)</font></li>
+<li><font face="Arial"><a href="http://firefly.troll.no/qa/rfcc-1230.html">RFC 2616: Would it possible to extend the
+ protocol to allow another GET,
+ HEAD, POST,...</a> by CCaldwell (9/15/2004)</font></li>
+<li><font face="Arial"><a href="http://firefly.troll.no/qa/rfcc-692.html">RFC 2616: Wonder if he got his lady? </a> by SinJax (3/26/2004)</font></li>
+<li><font face="Arial"><a href="http://firefly.troll.no/qa/rfcc-2056.html">RFC 2616: it's for shareaza that the program go fasther </a> by sylle (5/24/2005)</font></li>
+<li><font face="Arial"><a href="http://firefly.troll.no/qa/rfcc-2526.html">RFC 2616: Only 2 simultaneous connections is a big threat to the load speed of HTML...</a> by Doolyo (9/30/2005)</font></li>
+<li><font face="Arial"><a href="http://firefly.troll.no/qa/rfcc-736.html">RFC 2616: yo to the southampton uni coursework massive </a> by anon (4/6/2004)</font></li>
+<li><font face="Arial"><a href="http://firefly.troll.no/qa/rfcc-1574.html">RFC 2616: If you know everything about HTTP this rfc will be helpful to you (as a recap...</a> by just a developer (1/5/2005)</font></li>
+<li><font face="Arial"><a href="http://firefly.troll.no/qa/rfcc-1111.html">RFC 2616: Please note that section 3.6.2, referenced in section 3.5 (page 25)
+ may most...</a> by Patrick Powell (8/12/2004)</font></li>
+<li><font face="Arial"><a href="http://firefly.troll.no/qa/rfcc-1354.html">RFC 2616: gtu87t 86t8o;koip]0-n df bhvfjkhfgfter6ecvgjlhhjuhjioy uftyei vn bk.jljpoi
+ =- ...</a> by jkl (10/20/2004)</font></li>
+<li><font face="Arial"><a href="http://firefly.troll.no/qa/rfcc-1973.html">RFC 2616: I HOPE KNOW MANY OF SOME RFC </a> by MARRY (5/5/2005)</font></li>
+</ul>
+</td></tr></tbody></table> <br></center></div>
+<div align="center">
+<table border="0" cellpadding="3" cellspacing="3" width="100%">
+<tbody><tr><td width="45%">
+<p align="left">Previous: <a href="http://firefly.troll.no/rfcs/rfc2615.html">RFC 2615 - PPP over SONET/SDH</a>
+</p></td><td width="10%"> </td><td width="45%">
+<p align="right">Next: <a href="http://firefly.troll.no/rfcs/rfc2617.html">RFC 2617 - HTTP Authentication: Basic and Digest Access Authentication</a>
+</p></td></tr></tbody></table></div><p align="right"> </p>
+<hr noshade="noshade" size="2">
+<div align="center">[ <a href="http://firefly.troll.no/rfcs/">RFC Index</a> | <a href="http://firefly.troll.no/rfcs/rfcsearch.html">RFC Search</a> | <a href="http://firefly.troll.no/faqs/">Usenet FAQs</a> | <a href="http://firefly.troll.no/contrib/">Web FAQs</a> | <a href="http://firefly.troll.no/docs/">Documents</a> | <a href="http://www.city-data.com/">Cities</a> ]
+<p>
+</p></div>
+ <a href="http://firefly.troll.no/ftp/rfc/rfc2616.pdf">rfc2616.pdf</a>
+<small>
+<address>
+<p align="center">
+
+</p>
+</address>
+</small>
+</body></html>
\ No newline at end of file diff --git a/tests/testserver/common/startup.sh b/tests/testserver/common/startup.sh index 74990a47f6..1386314e38 100755 --- a/tests/testserver/common/startup.sh +++ b/tests/testserver/common/startup.sh @@ -34,7 +34,7 @@ set -ex # export variables export USER=qt-test-server export PASS=password -export CONFIG=common/testdata +export CONFIG=service/testdata export TESTDATA=service/testdata # add users @@ -43,17 +43,4 @@ useradd -m -s /bin/bash $USER; echo "$USER:$PASS" | chpasswd # install configurations and test data su $USER -c "cp $CONFIG/system/passwords ~/" -# modules initialization (apache2.sh, ftp-proxy.sh ...) -for RUN_CMD -do $RUN_CMD -done - -# start multicast DNS service discovery (mDNS) -sed -i -e "s,#domain-name=local,domain-name=${test_domain:-test-net.qt.local}," \ - -e "s,#publish-aaaa-on-ipv4=yes,publish-aaaa-on-ipv4=no," \ - /etc/avahi/avahi-daemon.conf -service dbus restart -service avahi-daemon restart - -# keep-alive in docker detach mode -sleep infinity +./startup.sh "$@" diff --git a/tests/testserver/cyrus/cyrus.sh b/tests/testserver/cyrus/cyrus.sh new file mode 100755 index 0000000000..92c3bfa703 --- /dev/null +++ b/tests/testserver/cyrus/cyrus.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +############################################################################# +## +## Copyright (C) 2019 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:GPL$ +## Commercial License Usage +## Licensees holding valid commercial Qt licenses may use this file in +## accordance with the commercial license agreement provided with the +## Software or, alternatively, in accordance with the terms contained in +## a written agreement between you and The Qt Company. For licensing terms +## and conditions see https://www.qt.io/terms-conditions. For further +## information use the contact form at https://www.qt.io/contact-us. +## +## GNU General Public License Usage +## Alternatively, this file may be used under the terms of the GNU +## General Public License version 3 or (at your option) any later version +## approved by the KDE Free Qt Foundation. The licenses are as published by +## the Free Software Foundation and appearing in the file LICENSE.GPL3 +## included in the packaging of this file. Please review the following +## information to ensure the GNU General Public License requirements will +## be met: https://www.gnu.org/licenses/gpl-3.0.html. +## +## $QT_END_LICENSE$ +## +############################################################################# + +set -ex + +echo "tls_cert_file: /home/qt-test-server/ssl-certs/qt-test-server-cert.pem" >> /etc/imapd.conf +echo "tls_key_file: /home/qt-test-server/ssl-certs/private/qt-test-server-key.pem" >> /etc/imapd.conf +chmod +3 /home/qt-test-server/ssl-certs/private/ +mkdir -m 007 -p /run/cyrus/proc +sed -i 's/#imaps\t\tcmd="imapd/imaps\t\tcmd="imapd/' /etc/cyrus.conf + +service cyrus-imapd restart diff --git a/tests/testserver/docker-compose-bridge-network.yml b/tests/testserver/docker-compose-bridge-network.yml new file mode 100644 index 0000000000..2cabeee1dc --- /dev/null +++ b/tests/testserver/docker-compose-bridge-network.yml @@ -0,0 +1,157 @@ +version: '2.1' + +# The tag of images is used by docker compose file to launch the corresponding +# docker containers. The value of tag comes from the provisioning script +# (coin/provisioning/.../testserver/docker_testserver.sh). The script gets SHA-1 +# of each server context as the tag of docker images. If one of the server +# contexts gets changes, please make sure to update this compose file as well. +# You can run command 'docker images' to list all the tags of test server images. +# For example: +# REPOSITORY TAG +# qt-test-server-apache2 537fe302f61851d1663f41495230d8e3554a4a13 + +services: + apache2: + extends: + file: ${SHARED_DATA}/docker-compose-common.yml + service: ${SHARED_SERVICE} + container_name: qt-test-server-apache2 + hostname: ${HOST_NAME:-apache2} + build: + context: . + args: + provisioningImage: qt-test-server-apache2:537fe302f61851d1663f41495230d8e3554a4a13 + shareDir: ./common + serviceDir: ./apache2 + entrypoint: service/startup.sh + command: [service/ssl.sh, service/apache2.sh] + + squid: + extends: + file: ${SHARED_DATA}/docker-compose-common.yml + service: ${SHARED_SERVICE} + container_name: qt-test-server-squid + hostname: ${HOST_NAME:-squid} + depends_on: + - apache2 + external_links: + - apache2:apache2.${TEST_DOMAIN} + - cyrus:cyrus.${TEST_DOMAIN} + - iptables:iptables.${TEST_DOMAIN} + - vsftpd:vsftpd.${TEST_DOMAIN} + - echo:echo.${TEST_DOMAIN} + build: + context: . + args: + provisioningImage: qt-test-server-squid:9c32f41b19aca3d778733c4d8fb0ecc5955e893c + shareDir: ./common + serviceDir: ./squid + entrypoint: service/startup.sh + command: service/squid.sh + + vsftpd: + extends: + file: ${SHARED_DATA}/docker-compose-common.yml + service: ${SHARED_SERVICE} + container_name: qt-test-server-vsftpd + hostname: ${HOST_NAME:-vsftpd} + build: + context: . + args: + provisioningImage: qt-test-server-vsftpd:f3a9c8d793a77cc007c0e4e481bec01f9e3eeb7e + shareDir: ./common + serviceDir: ./vsftpd + entrypoint: service/startup.sh + command: service/vsftpd.sh + + ftp-proxy: + extends: + file: ${SHARED_DATA}/docker-compose-common.yml + service: ${SHARED_SERVICE} + container_name: qt-test-server-ftp-proxy + hostname: ${HOST_NAME:-ftp-proxy} + depends_on: + - vsftpd + external_links: + - vsftpd:vsftpd.${TEST_DOMAIN} + build: + context: . + args: + provisioningImage: qt-test-server-ftp-proxy:d7de8b28392d173db512a558ccc84ead8bece2ae + shareDir: ./common + serviceDir: ./ftp-proxy + entrypoint: service/startup.sh + command: service/ftp-proxy.sh + + danted: + extends: + file: ${SHARED_DATA}/docker-compose-common.yml + service: ${SHARED_SERVICE} + container_name: qt-test-server-danted + hostname: ${HOST_NAME:-danted} + depends_on: + - apache2 + - vsftpd + - ftp-proxy + external_links: + - apache2:apache2.${TEST_DOMAIN} + - vsftpd:vsftpd.${TEST_DOMAIN} + - ftp-proxy:ftp-proxy.${TEST_DOMAIN} + - cyrus:cyrus.${TEST_DOMAIN} + - echo:echo.${TEST_DOMAIN} + build: + context: . + args: + provisioningImage: qt-test-server-danted:35607f9b790524cf9690c7d12a9a401696b7b6b5 + shareDir: ./common + serviceDir: ./danted + entrypoint: service/startup.sh + command: service/danted.sh + + cyrus: + extends: + file: ${SHARED_DATA}/docker-compose-common.yml + service: ${SHARED_SERVICE} + container_name: qt-test-server-cyrus + hostname: ${HOST_NAME:-cyrus} + build: + context: . + args: + provisioningImage: qt-test-server-cyrus:c8d72754abc0e501afd624ce838e4df35505abc9 + shareDir: ./common + serviceDir: ./cyrus + entrypoint: service/startup.sh + command: [service/ssl.sh, service/cyrus.sh] + + iptables: + extends: + file: ${SHARED_DATA}/docker-compose-common.yml + service: ${SHARED_SERVICE} + container_name: qt-test-server-iptables + hostname: ${HOST_NAME:-iptables} + build: + context: . + args: + provisioningImage: qt-test-server-iptables:cb7a8bd6d28602085a88c8ced7d67e28e75781e2 + shareDir: ./common + serviceDir: ./iptables + entrypoint: service/startup.sh + command: service/iptables.sh + cap_add: + - NET_ADMIN + - NET_RAW + + echo: + extends: + file: ${SHARED_DATA}/docker-compose-common.yml + service: ${SHARED_SERVICE} + container_name: qt-test-server-echo + hostname: ${HOST_NAME:-echo} + build: + context: . + args: + provisioningImage: qt-test-server-echo:b29ad409e746a834c1055fd0f7a55fd5056da6ea + shareDir: ./common + serviceDir: ./echo + entrypoint: service/startup.sh + command: service/echo.sh diff --git a/tests/testserver/docker-compose-for-macOS.yml b/tests/testserver/docker-compose-for-macOS.yml deleted file mode 100644 index aa610dfb88..0000000000 --- a/tests/testserver/docker-compose-for-macOS.yml +++ /dev/null @@ -1,100 +0,0 @@ -version: '3.4' - -# The tag of images is used by docker compose file to launch the corresponding -# docker containers. The value of tag comes from the provisioning script -# (coin/provisioning/.../testserver/docker_testserver.sh). The script gets SHA-1 -# of each server context as the tag of docker images. If one of the server -# contexts gets changes, please make sure to update this compose file as well. -# You can run command 'docker images' to list all the tags of test server images. -# For example: -# REPOSITORY TAG -# qt-test-server-apache2 537fe302f61851d1663f41495230d8e3554a4a13 - -services: - apache2: - image: qt-test-server-apache2:537fe302f61851d1663f41495230d8e3554a4a13 - container_name: qt-test-server-apache2 - domainname: ${TEST_DOMAIN} - volumes: - - ./common:/common:ro - - ./apache2:/service:ro - entrypoint: common/startup.sh - command: [common/ssl.sh, service/apache2.sh] - network_mode: "host" - extra_hosts: - - "qt-test-server.${TEST_DOMAIN}:${MACHINE_IP}" - environment: - - test_domain=${TEST_DOMAIN} - - test_cert="qt-test-server-host-network-cacert.pem" - - squid: - image: qt-test-server-squid:9c32f41b19aca3d778733c4d8fb0ecc5955e893c - container_name: qt-test-server-squid - domainname: ${TEST_DOMAIN} - depends_on: - - apache2 - volumes: - - ./common:/common:ro - - ./squid:/service:ro - entrypoint: common/startup.sh - command: service/squid.sh - network_mode: "host" - extra_hosts: - - "qt-test-server.${TEST_DOMAIN}:${MACHINE_IP}" - environment: - - test_domain=${TEST_DOMAIN} - - vsftpd: - image: qt-test-server-vsftpd:f3a9c8d793a77cc007c0e4e481bec01f9e3eeb7e - container_name: qt-test-server-vsftpd - domainname: ${TEST_DOMAIN} - volumes: - - ./common:/common:ro - - ./vsftpd:/service:ro - entrypoint: common/startup.sh - command: service/vsftpd.sh - network_mode: "host" - extra_hosts: - - "qt-test-server.${TEST_DOMAIN}:${MACHINE_IP}" - environment: - - test_domain=${TEST_DOMAIN} - - ftp-proxy: - image: qt-test-server-ftp-proxy:d7de8b28392d173db512a558ccc84ead8bece2ae - container_name: qt-test-server-ftp-proxy - domainname: ${TEST_DOMAIN} - depends_on: - - vsftpd - volumes: - - ./common:/common:ro - - ./ftp-proxy:/service:ro - entrypoint: common/startup.sh - command: service/ftp-proxy.sh - network_mode: "host" - extra_hosts: - - "qt-test-server.${TEST_DOMAIN}:${MACHINE_IP}" - environment: - - test_domain=${TEST_DOMAIN} - - danted: - image: qt-test-server-danted:35607f9b790524cf9690c7d12a9a401696b7b6b5 - container_name: qt-test-server-danted - domainname: ${TEST_DOMAIN} - depends_on: - - apache2 - - vsftpd - - ftp-proxy - volumes: - - ./common:/common:ro - - ./danted:/service:ro - entrypoint: common/startup.sh - command: service/danted.sh - network_mode: "host" - extra_hosts: - - "qt-test-server.${TEST_DOMAIN}:${MACHINE_IP}" - environment: - - danted_internal=${MACHINE_IP} - - danted_external=${MACHINE_IP} - - danted_auth_internal=${MACHINE_IP} - - danted_auth_external=${MACHINE_IP} - - test_domain=${TEST_DOMAIN} diff --git a/tests/testserver/docker-compose-for-windows.yml b/tests/testserver/docker-compose-for-windows.yml deleted file mode 100644 index aa610dfb88..0000000000 --- a/tests/testserver/docker-compose-for-windows.yml +++ /dev/null @@ -1,100 +0,0 @@ -version: '3.4' - -# The tag of images is used by docker compose file to launch the corresponding -# docker containers. The value of tag comes from the provisioning script -# (coin/provisioning/.../testserver/docker_testserver.sh). The script gets SHA-1 -# of each server context as the tag of docker images. If one of the server -# contexts gets changes, please make sure to update this compose file as well. -# You can run command 'docker images' to list all the tags of test server images. -# For example: -# REPOSITORY TAG -# qt-test-server-apache2 537fe302f61851d1663f41495230d8e3554a4a13 - -services: - apache2: - image: qt-test-server-apache2:537fe302f61851d1663f41495230d8e3554a4a13 - container_name: qt-test-server-apache2 - domainname: ${TEST_DOMAIN} - volumes: - - ./common:/common:ro - - ./apache2:/service:ro - entrypoint: common/startup.sh - command: [common/ssl.sh, service/apache2.sh] - network_mode: "host" - extra_hosts: - - "qt-test-server.${TEST_DOMAIN}:${MACHINE_IP}" - environment: - - test_domain=${TEST_DOMAIN} - - test_cert="qt-test-server-host-network-cacert.pem" - - squid: - image: qt-test-server-squid:9c32f41b19aca3d778733c4d8fb0ecc5955e893c - container_name: qt-test-server-squid - domainname: ${TEST_DOMAIN} - depends_on: - - apache2 - volumes: - - ./common:/common:ro - - ./squid:/service:ro - entrypoint: common/startup.sh - command: service/squid.sh - network_mode: "host" - extra_hosts: - - "qt-test-server.${TEST_DOMAIN}:${MACHINE_IP}" - environment: - - test_domain=${TEST_DOMAIN} - - vsftpd: - image: qt-test-server-vsftpd:f3a9c8d793a77cc007c0e4e481bec01f9e3eeb7e - container_name: qt-test-server-vsftpd - domainname: ${TEST_DOMAIN} - volumes: - - ./common:/common:ro - - ./vsftpd:/service:ro - entrypoint: common/startup.sh - command: service/vsftpd.sh - network_mode: "host" - extra_hosts: - - "qt-test-server.${TEST_DOMAIN}:${MACHINE_IP}" - environment: - - test_domain=${TEST_DOMAIN} - - ftp-proxy: - image: qt-test-server-ftp-proxy:d7de8b28392d173db512a558ccc84ead8bece2ae - container_name: qt-test-server-ftp-proxy - domainname: ${TEST_DOMAIN} - depends_on: - - vsftpd - volumes: - - ./common:/common:ro - - ./ftp-proxy:/service:ro - entrypoint: common/startup.sh - command: service/ftp-proxy.sh - network_mode: "host" - extra_hosts: - - "qt-test-server.${TEST_DOMAIN}:${MACHINE_IP}" - environment: - - test_domain=${TEST_DOMAIN} - - danted: - image: qt-test-server-danted:35607f9b790524cf9690c7d12a9a401696b7b6b5 - container_name: qt-test-server-danted - domainname: ${TEST_DOMAIN} - depends_on: - - apache2 - - vsftpd - - ftp-proxy - volumes: - - ./common:/common:ro - - ./danted:/service:ro - entrypoint: common/startup.sh - command: service/danted.sh - network_mode: "host" - extra_hosts: - - "qt-test-server.${TEST_DOMAIN}:${MACHINE_IP}" - environment: - - danted_internal=${MACHINE_IP} - - danted_external=${MACHINE_IP} - - danted_auth_internal=${MACHINE_IP} - - danted_auth_external=${MACHINE_IP} - - test_domain=${TEST_DOMAIN} diff --git a/tests/testserver/docker-compose-host-network.yml b/tests/testserver/docker-compose-host-network.yml new file mode 100644 index 0000000000..4b2e1ebdab --- /dev/null +++ b/tests/testserver/docker-compose-host-network.yml @@ -0,0 +1,102 @@ +version: '2.1' + +# The tag of images is used by docker compose file to launch the corresponding +# docker containers. The value of tag comes from the provisioning script +# (coin/provisioning/.../testserver/docker_testserver.sh). The script gets SHA-1 +# of each server context as the tag of docker images. If one of the server +# contexts gets changes, please make sure to update this compose file as well. +# You can run command 'docker images' to list all the tags of test server images. +# For example: +# REPOSITORY TAG +# qt-test-server-apache2 537fe302f61851d1663f41495230d8e3554a4a13 + +services: + apache2: + extends: + file: ${SHARED_DATA}/docker-compose-common.yml + service: ${SHARED_SERVICE} + container_name: qt-test-server-apache2 + hostname: ${HOST_NAME:-apache2} + build: + context: . + args: + provisioningImage: qt-test-server-apache2:537fe302f61851d1663f41495230d8e3554a4a13 + shareDir: ./common + serviceDir: ./apache2 + entrypoint: service/startup.sh + command: [service/ssl.sh, service/apache2.sh] + environment: + - test_cert="qt-test-server-host-network-cacert.pem" + + squid: + extends: + file: ${SHARED_DATA}/docker-compose-common.yml + service: ${SHARED_SERVICE} + container_name: qt-test-server-squid + hostname: ${HOST_NAME:-squid} + depends_on: + - apache2 + build: + context: . + args: + provisioningImage: qt-test-server-squid:9c32f41b19aca3d778733c4d8fb0ecc5955e893c + shareDir: ./common + serviceDir: ./squid + entrypoint: service/startup.sh + command: service/squid.sh + + vsftpd: + extends: + file: ${SHARED_DATA}/docker-compose-common.yml + service: ${SHARED_SERVICE} + container_name: qt-test-server-vsftpd + hostname: ${HOST_NAME:-vsftpd} + build: + context: . + args: + provisioningImage: qt-test-server-vsftpd:f3a9c8d793a77cc007c0e4e481bec01f9e3eeb7e + shareDir: ./common + serviceDir: ./vsftpd + entrypoint: service/startup.sh + command: service/vsftpd.sh + + ftp-proxy: + extends: + file: ${SHARED_DATA}/docker-compose-common.yml + service: ${SHARED_SERVICE} + container_name: qt-test-server-ftp-proxy + hostname: ${HOST_NAME:-ftp-proxy} + depends_on: + - vsftpd + build: + context: . + args: + provisioningImage: qt-test-server-ftp-proxy:d7de8b28392d173db512a558ccc84ead8bece2ae + shareDir: ./common + serviceDir: ./ftp-proxy + entrypoint: service/startup.sh + command: service/ftp-proxy.sh + + danted: + extends: + file: ${SHARED_DATA}/docker-compose-common.yml + service: ${SHARED_SERVICE} + container_name: qt-test-server-danted + hostname: ${HOST_NAME:-danted} + depends_on: + - apache2 + - vsftpd + - ftp-proxy + build: + context: . + args: + provisioningImage: qt-test-server-danted:35607f9b790524cf9690c7d12a9a401696b7b6b5 + shareDir: ./common + serviceDir: ./danted + entrypoint: service/startup.sh + command: service/danted.sh + environment: + - danted_internal=${MACHINE_IP} + - danted_external=${MACHINE_IP} + - danted_auth_internal=${MACHINE_IP} + - danted_auth_external=${MACHINE_IP} diff --git a/tests/testserver/docker-compose.yml b/tests/testserver/docker-compose.yml deleted file mode 100644 index be65e5a26a..0000000000 --- a/tests/testserver/docker-compose.yml +++ /dev/null @@ -1,83 +0,0 @@ -version: '3.4' - -# The tag of images is used by docker compose file to launch the corresponding -# docker containers. The value of tag comes from the provisioning script -# (coin/provisioning/.../testserver/docker_testserver.sh). The script gets SHA-1 -# of each server context as the tag of docker images. If one of the server -# contexts gets changes, please make sure to update this compose file as well. -# You can run command 'docker images' to list all the tag of test server images. -# For example: -# REPOSITORY TAG -# qt-test-server-apache2 537fe302f61851d1663f41495230d8e3554a4a13 - -services: - apache2: - image: qt-test-server-apache2:537fe302f61851d1663f41495230d8e3554a4a13 - container_name: qt-test-server-apache2 - domainname: ${TEST_DOMAIN} - hostname: apache2 - volumes: - - ./common:/common:ro - - ./apache2:/service:ro - entrypoint: common/startup.sh - command: [common/ssl.sh, service/apache2.sh] - - squid: - image: qt-test-server-squid:9c32f41b19aca3d778733c4d8fb0ecc5955e893c - container_name: qt-test-server-squid - domainname: ${TEST_DOMAIN} - hostname: squid - depends_on: - - apache2 - external_links: - - apache2:apache2.${TEST_DOMAIN} - volumes: - - ./common:/common:ro - - ./squid:/service:ro - entrypoint: common/startup.sh - command: service/squid.sh - - vsftpd: - image: qt-test-server-vsftpd:f3a9c8d793a77cc007c0e4e481bec01f9e3eeb7e - container_name: qt-test-server-vsftpd - domainname: ${TEST_DOMAIN} - hostname: vsftpd - volumes: - - ./common:/common:ro - - ./vsftpd:/service:ro - entrypoint: common/startup.sh - command: service/vsftpd.sh - - ftp-proxy: - image: qt-test-server-ftp-proxy:d7de8b28392d173db512a558ccc84ead8bece2ae - container_name: qt-test-server-ftp-proxy - domainname: ${TEST_DOMAIN} - hostname: ftp-proxy - depends_on: - - vsftpd - external_links: - - vsftpd:vsftpd.${TEST_DOMAIN} - volumes: - - ./common:/common:ro - - ./ftp-proxy:/service:ro - entrypoint: common/startup.sh - command: service/ftp-proxy.sh - - danted: - image: qt-test-server-danted:35607f9b790524cf9690c7d12a9a401696b7b6b5 - container_name: qt-test-server-danted - domainname: ${TEST_DOMAIN} - hostname: danted - depends_on: - - apache2 - - vsftpd - - ftp-proxy - external_links: - - apache2:apache2.${TEST_DOMAIN} - - vsftpd:vsftpd.${TEST_DOMAIN} - - ftp-proxy:ftp-proxy.${TEST_DOMAIN} - volumes: - - ./common:/common:ro - - ./danted:/service:ro - entrypoint: common/startup.sh - command: service/danted.sh diff --git a/tests/testserver/echo/echo.sh b/tests/testserver/echo/echo.sh new file mode 100755 index 0000000000..f0da9627d5 --- /dev/null +++ b/tests/testserver/echo/echo.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +# Disabled by default, enable it. +sed -i 's/disable\t\t= yes/disable = no/' /etc/xinetd.d/echo +sed -i 's/disable\t\t= yes/disable = no/' /etc/xinetd.d/daytime + +service xinetd restart diff --git a/tests/testserver/ftp-proxy/ftp-proxy.sh b/tests/testserver/ftp-proxy/ftp-proxy.sh index 087a7b7bcc..e5b9631bbb 100755 --- a/tests/testserver/ftp-proxy/ftp-proxy.sh +++ b/tests/testserver/ftp-proxy/ftp-proxy.sh @@ -34,7 +34,9 @@ set -ex # package ftp-proxy # install configurations and test data -sed -i 's/# AllowMagicUser\tno/AllowMagicUser\tyes/' /etc/proxy-suite/ftp-proxy.conf +sed -i -e 's/# AllowMagicUser\tno/AllowMagicUser\tyes/' \ + -e 's/# ForkLimit\t\t40/ForkLimit\t\t2000/' \ + /etc/proxy-suite/ftp-proxy.conf # enable service with installed configurations ftp-proxy -d diff --git a/tests/testserver/iptables/iptables.sh b/tests/testserver/iptables/iptables.sh new file mode 100755 index 0000000000..9a48686d8b --- /dev/null +++ b/tests/testserver/iptables/iptables.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash + +############################################################################# +## +## Copyright (C) 2019 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:GPL$ +## Commercial License Usage +## Licensees holding valid commercial Qt licenses may use this file in +## accordance with the commercial license agreement provided with the +## Software or, alternatively, in accordance with the terms contained in +## a written agreement between you and The Qt Company. For licensing terms +## and conditions see https://www.qt.io/terms-conditions. For further +## information use the contact form at https://www.qt.io/contact-us. +## +## GNU General Public License Usage +## Alternatively, this file may be used under the terms of the GNU +## General Public License version 3 or (at your option) any later version +## approved by the KDE Free Qt Foundation. The licenses are as published by +## the Free Software Foundation and appearing in the file LICENSE.GPL3 +## included in the packaging of this file. Please review the following +## information to ensure the GNU General Public License requirements will +## be met: https://www.gnu.org/licenses/gpl-3.0.html. +## +## $QT_END_LICENSE$ +## +############################################################################# + +set -ex + +iptables -A INPUT -p tcp --destination-port 1357 -j DROP diff --git a/tests/testserver/vsftpd/testdata/vsftpd.conf b/tests/testserver/vsftpd/testdata/vsftpd.conf index 6bdb186c9f..e67cccefcc 100644 --- a/tests/testserver/vsftpd/testdata/vsftpd.conf +++ b/tests/testserver/vsftpd/testdata/vsftpd.conf @@ -101,6 +101,10 @@ userlist_enable=YES listen=YES tcp_wrappers=YES +# An internal setting used for testing the relative benefit of using the +# sendfile() system call on your platform. +use_sendfile=NO + # Enabling SFTP #ssl_enable=YES #allow_anon_ssl=YES diff --git a/tests/testserver/vsftpd/vsftpd.sh b/tests/testserver/vsftpd/vsftpd.sh index 14364f94c2..bd09ad3902 100755 --- a/tests/testserver/vsftpd/vsftpd.sh +++ b/tests/testserver/vsftpd/vsftpd.sh @@ -54,6 +54,10 @@ ln -s /home/$USER/ftp /var/ftp su $USER -c "mkdir -p ~/ftp/qtest/" su $USER -c "cp rfc3252.txt ~/ftp/qtest/"; rm rfc3252.txt +# tst_QNetworkReply::proxy_data() +su $USER -c "ln ~/ftp/qtest/rfc3252.txt ~/ftp/qtest/rfc3252" +su $USER -c "mkdir -p ~/ftp/qtest/nonASCII/" + # Duplicate rfc3252.txt 20 times for bigfile tests: su $USER -c "seq 20 | xargs -i cat ~/ftp/qtest/rfc3252.txt >> ~/ftp/qtest/bigfile" |