pax_global_header00006660000000000000000000000064142764327720014530gustar00rootroot0000000000000052 comment=345d5ba67f34a71548fb5d9a51b0a98ed1fcfe31 verdigris-1.3/000077500000000000000000000000001427643277200133715ustar00rootroot00000000000000verdigris-1.3/.appveyor.yml000066400000000000000000000020511427643277200160350ustar00rootroot00000000000000image: Visual Studio 2017 platform: x64 configuration: - Release environment: matrix: - QTDIR: C:\Qt\5.9\msvc2017_64 BUILD: qbs - QTDIR: C:\Qt\5.12\msvc2017_64 BUILD: qbs - QTDIR: C:\Qt\5.12\msvc2017_64 BUILD: qmake for: - matrix: only: - BUILD: qmake before_build: - set PATH=%QTDIR%\bin;%PATH% - call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" %PLATFORM% - qmake -r build_script: - nmake test_script: - nmake check - matrix: only: - BUILD: qbs install: - cinst qbs before_build: - set PATH=%QTDIR%\bin;%PATH% - call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" %PLATFORM% - qbs setup-toolchains --detect - qbs setup-qt --detect - qbs config --list profiles build_script: - qbs build --file verdigris.qbs --build-directory %TMP%\build test_script: - qbs build --file verdigris.qbs --build-directory %TMP%\build -p autotest-runner verdigris-1.3/.github/000077500000000000000000000000001427643277200147315ustar00rootroot00000000000000verdigris-1.3/.github/workflows/000077500000000000000000000000001427643277200167665ustar00rootroot00000000000000verdigris-1.3/.github/workflows/clang.yml000066400000000000000000000065331427643277200206040ustar00rootroot00000000000000name: Clang Tests on: [push, pull_request] jobs: osx-qmake: name: "OSX QMake Qt5 ${{ matrix.std_cpp }}" strategy: fail-fast: false matrix: include: - std_cpp: C++17 - std_cpp: C++14 runs-on: "macos-10.15" env: QMAKESPEC: macx-clang steps: - name: Install Qt run: | HOMEBREW_NO_AUTO_UPDATE=1 brew install qt5 brew link qt5 --force which qmake qmake --version - name: Git Checkout uses: actions/checkout@v2 - run: qmake -r "CONFIG+=${{ matrix.std_cpp }}" - run: make -j - run: make check docker-qbs: name: "Docker Qbs ${{ matrix.image }}" strategy: fail-fast: false matrix: include: - image: arbmind/qbs-clang-libstdcpp-qt:1.22.0-14-11-6.3.0 - image: arbmind/qbs-clang-libstdcpp-qt:1.21.0-13-10-6.2.4 - image: arbmind/qbs-clang13-qt515:latest - image: arbmind/qbs-clang8-qt512:1 runs-on: ubuntu-latest steps: - name: Git Checkout uses: actions/checkout@v2 - name: Build & Test run: >- docker run --rm -v ${GITHUB_WORKSPACE}:/build -w /build ${{ matrix.image }} build --file /build/verdigris.qbs --build-directory /tmp/build -p autotest-runner linux-qmake: name: "${{ matrix.host_system }} QMake Clang ${{ matrix.clang_version }} Qt ${{ matrix.qt_version }} ${{ matrix.std_cpp }}" strategy: fail-fast: false matrix: include: - host_system: ubuntu-20.04 clang_version: 12 qt_version: 6.3.0 qt_arch: gcc_64 std_cpp: C++20 - host_system: ubuntu-20.04 clang_version: 12 qt_version: 6.2.2 qt_arch: gcc_64 std_cpp: C++20 - host_system: ubuntu-20.04 clang_version: 11 qt_version: 6.0.0 qt_arch: gcc_64 std_cpp: C++17 - host_system: ubuntu-20.04 clang_version: 10 qt_version: 5.15.2 qt_arch: gcc_64 std_cpp: C++17 - host_system: ubuntu-18.04 clang_version: 9 qt_version: 5.12.3 qt_arch: gcc_64 std_cpp: C++14 runs-on: "${{ matrix.host_system }}" env: QMAKESPEC: linux-clang steps: - name: Cache Qt id: cache-qt uses: actions/cache@v1 with: path: ../Qt key: QtCache-${{ matrix.qt_version }}-${{ matrix.qt_arch }} - name: Install Qt uses: jurplel/install-qt-action@v2 with: version: "${{ matrix.qt_version }}" arch: "${{ matrix.qt_arch }}" cached: ${{ steps.cache-qt.outputs.cache-hit }} - name: Setup Clang run: | sudo apt-get update sudo apt-get install -y clang-${{ matrix.clang_version }} find /usr/bin -name "clang++*" echo $(which clang++) echo $(which clang++-${{ matrix.clang_version }}) sudo rm /usr/bin/clang++ sudo ln -s $(which clang++-${{ matrix.clang_version }}) /usr/bin/clang++ clang++ --version - name: Git Checkout uses: actions/checkout@v2 - run: qmake -r "CONFIG+=${{ matrix.std_cpp }}" - run: make -j - run: make check verdigris-1.3/.github/workflows/gcc.yml000066400000000000000000000050311427643277200202440ustar00rootroot00000000000000name: Gcc Tests on: [push, pull_request] jobs: docker-qbs: name: "Docker Qbs ${{ matrix.image }}" strategy: fail-fast: false matrix: include: - image: arbmind/qbs-gcc-qt:1.22.1-12-6.3.1 runs-on: ubuntu-latest steps: - name: Git Checkout uses: actions/checkout@v2 - name: Build & Test run: >- docker run --rm -v ${GITHUB_WORKSPACE}:/build -w /build ${{ matrix.image }} build --file /build/verdigris.qbs --build-directory /tmp/build -p autotest-runner linux-qmake: name: "${{ matrix.host_system }} QMake Gcc ${{ matrix.gcc_version }} Qt ${{ matrix.qt_version }} ${{ matrix.std_cpp }}" continue-on-error: ${{ matrix.experimental }} strategy: fail-fast: false matrix: include: - host_system: ubuntu-22.04 gcc_version: 11 qt_version: 6.3.0 qt_arch: gcc_64 std_cpp: C++17 experimental: false - host_system: ubuntu-20.04 gcc_version: 11 qt_version: 6.2.2 qt_arch: gcc_64 std_cpp: C++17 experimental: false - host_system: ubuntu-20.04 gcc_version: 10 qt_version: 6.0.0 qt_arch: gcc_64 std_cpp: C++17 experimental: false - host_system: ubuntu-20.04 gcc_version: 9 qt_version: 5.15.2 qt_arch: gcc_64 std_cpp: C++17 experimental: false runs-on: "${{ matrix.host_system }}" steps: - name: Cache Qt id: cache-qt uses: actions/cache@v1 with: path: ../Qt key: QtCache-${{ matrix.qt_version }}-${{ matrix.qt_arch }} - name: Install Qt uses: jurplel/install-qt-action@v2 with: version: "${{ matrix.qt_version }}" arch: "${{ matrix.qt_arch }}" cached: ${{ steps.cache-qt.outputs.cache-hit }} - name: Setup Gcc run: | sudo apt-get update sudo apt-get install -y g++-${{ matrix.gcc_version }} find /usr/bin -name "g++*" echo $(which g++) echo $(which g++-${{ matrix.gcc_version }}) sudo update-alternatives --install /usr/bin/g++ g++ $(which g++-${{ matrix.gcc_version }}) 90 g++ --version - name: Git Checkout uses: actions/checkout@v2 - run: qmake -r "CONFIG+=${{ matrix.std_cpp }}" - run: make -j - run: make check verdigris-1.3/.github/workflows/windows.yml000066400000000000000000000105501427643277200212040ustar00rootroot00000000000000name: Windows Tests on: [push, pull_request] jobs: windows-qbs: name: "${{ matrix.host_system }} Qbs Qt ${{ matrix.qt_version }} ${{ matrix.qt_arch }}" strategy: fail-fast: false matrix: include: - host_system: windows-2022 vcvars: C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat qt_version: "6.3.0" qt_arch: win64_msvc2019_64 - host_system: windows-2019 vcvars: C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat qt_version: "6.2.4" qt_arch: win64_msvc2019_64 - host_system: windows-2019 vcvars: C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat qt_version: "6.2.2" qt_arch: win64_msvc2019_64 - host_system: windows-2019 vcvars: C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat qt_version: "5.15.2" qt_arch: win64_msvc2019_64 - host_system: windows-2019 vcvars: C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat qt_version: "5.14.2" qt_arch: win64_msvc2015_64 - host_system: windows-2019 vcvars: C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat qt_version: "5.12.9" qt_arch: win64_msvc2017_64 - host_system: windows-2019 vcvars: C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat qt_version: "5.9.9" qt_arch: win64_msvc2017_64 runs-on: "${{ matrix.host_system }}" steps: - name: Cache Qt id: cache-qt uses: actions/cache@v1 with: path: ../Qt key: QtCache-${{ matrix.qt_version }}-${{ matrix.qt_arch }} - name: Install Qt uses: jurplel/install-qt-action@v2 with: version: "${{ matrix.qt_version }}" arch: "${{ matrix.qt_arch }}" cached: ${{ steps.cache-qt.outputs.cache-hit }} - name: Install Qbs run: choco install qbs - name: Setup Qbs run: | qbs setup-toolchains --type msvc $(cmd /c '"${{ matrix.vcvars }}" >nul & where cl') msvc qbs setup-qt $(cmd /c where qmake) qt qbs config profiles.qt.baseProfile msvc qbs config defaultProfile qt qbs config --list profiles - name: Git Checkout uses: actions/checkout@v2 - run: >- qbs build --file verdigris.qbs --build-directory ${env:RUNNER_TEMP}\build -p autotest-runner windows-qmake: name: "${{ matrix.host_system }} QMake Qt ${{ matrix.qt_version }} ${{ matrix.qt_arch }}" strategy: fail-fast: false matrix: include: - host_system: windows-2022 cl_version: "14.32" qt_version: "6.3.0" qt_arch: win64_msvc2019_64 - host_system: windows-2019 cl_version: "14.29" qt_version: "6.2.2" qt_arch: win64_msvc2019_64 - host_system: windows-2019 cl_version: "14.29" qt_version: "6.0.0" qt_arch: win64_msvc2019_64 - host_system: windows-2019 cl_version: "14.29" qt_version: "5.15.2" qt_arch: win64_msvc2019_64 - host_system: windows-2019 cl_version: "14.29" qt_version: "5.12.9" qt_arch: win64_msvc2017_64 runs-on: "${{ matrix.host_system }}" steps: - name: Cache Qt id: cache-qt uses: actions/cache@v1 with: path: ../Qt key: QtCache-${{ matrix.qt_version }}-${{ matrix.qt_arch }} - name: Install Qt uses: jurplel/install-qt-action@v2 with: version: "${{ matrix.qt_version }}" arch: "${{ matrix.qt_arch }}" cached: ${{ steps.cache-qt.outputs.cache-hit }} - name: Add msbuild to PATH uses: ilammy/msvc-dev-cmd@v1 with: toolset: '${{ matrix.cl_version }}' - name: Git Checkout uses: actions/checkout@v2 - run: qmake -r - run: nmake - run: nmake check verdigris-1.3/ChangeLog000066400000000000000000000031311427643277200151410ustar00rootroot00000000000000Version 1.3 (August 2022) * Add C++ API to allow meta programming your properties * Added Option to reduce macro spam a bit (W_NO_PROPERTY_MACRO) * Build with MSVC 2017, 2019, 2022 * Support from Qt 5.9 to 5.15 and Qt 6.0.0 to Qt 6.3.0 Version 1.2 (Juli 2019) * Added W_OBJECT_IMPL_INLINE / W_GADGET_IMPL_INLINE / W_NAMESPACE_IMPL_INLINE (#51) * Fix multiple-definition linker errors caused by W_NAMESPACE macro (#54) * Fix build with MSVC 2019 (#46) * Massive compile time improvements (#66) * Qbs project files (#63) * Tested with to Qt 5.13 Version 1.1 (September 2018) * Auto-detect the access specifier. (No need to add W_Access::Private or W_Access::Protected anymore) * Optimized compilation time for classes with many properties * Removed the need to set feature macro on MSVC * Don't make the staticMetaObject a constexpr as it breaks C++17 Q_GADGET declared in another translation unit (#38) * Workaround MSVC 2017 Update 7 compiler crash (#30) * Automatically mark the properties as FINAL for final classes (#40) * Added support for enum class in Q_ENUM * Added support enum alias (Qt 5.12 freature) Version 1.0 (February 2018) * Error out early without C++14 (#2) * Set Designable and Scriptable flags by default so it works with QML (#3) * Fix usage of Q_PRIVATE_PROPERTY (#5) * Added MSVC 2017 support (#6) * Support C++17 noexcept function part of the function signature (#9) * Added W_NAMESPACE/W_NAMESPACE_IMPL and W_ENUM_NS/W_FLAG_NS/W_CASSINFO_NS * Support for NOTIFY signal in parent class (Qt 5.10 feature) * Imported new tests from Qt 5.10 Initial Release (May 2016) verdigris-1.3/LICENSE.LGPLv3000066400000000000000000000170071427643277200154110ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright © 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this licensedocument, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, “this License” refers to version 3 of the GNU Lesser General Public License, and the “GNU GPL” refers to version 3 of the GNU General Public License. “The Library” refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An “Application” is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A “Combined Work” is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the “Linked Version”. The “Minimal Corresponding Source” for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The “Corresponding Application Code” for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. verdigris-1.3/README.md000066400000000000000000000153041427643277200146530ustar00rootroot00000000000000## About This (header-only) library can be used to create an application using Qt, without the need of the moc (MetaObject Compiler). It uses a different set of macro than Qt and templated constexpr code to generate the QMetaObject at compile-time. It is entirely binary compatible with Qt. Blog post presenting the project: https://woboq.com/blog/verdigris-qt-without-moc.html (2016) Blog post with some implementation details: https://woboq.com/blog/verdigris-implementation-tricks.html (2018) Browse code online: https://code.woboq.org/woboq/verdigris Github Actions: [![Clang Tests](https://github.com/woboq/verdigris/actions/workflows/clang.yml/badge.svg?branch=master)](https://github.com/woboq/verdigris/actions/workflows/clang.yml) [![Gcc Tests](https://github.com/woboq/verdigris/actions/workflows/gcc.yml/badge.svg?branch=master)](https://github.com/woboq/verdigris/actions/workflows/gcc.yml) [![Windows Tests](https://github.com/woboq/verdigris/actions/workflows/windows.yml/badge.svg?branch=master)](https://github.com/woboq/verdigris/actions/workflows/windows.yml) Appveyor: [![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/povubj5thvlsu6sy/branch/master?svg=true)](https://ci.appveyor.com/project/ogoffart/verdigris) ## Documentation For an introduction, see the [tutorial.cpp](https://code.woboq.org/woboq/verdigris/tutorial/tutorial.cpp.html). See also a more detailed documetation of the macros in the source code. ## Status Almost all features of Qt are working. The Qt test have been ported. Features that are not yet working: - Q_PLUGIN_METADATA: This would require compiling to the Qt's binary json. Out of scope for now. - QML_ELEMENT: This is a Qt6 feature that automatically registers the QObjects for QML. Out of scope for now. - BINDABLE: Needs to be backported to the current C++ and Qt requirements. - QMetaMethod::tag(): Not yet implemented, could be supported if needed, but is not really needed for anything. (not even tested by Qt's auto test) - Q_ENUM: Working, but requires to repeat the name of every enum value. Could be improved. **New features compared to Qt with moc:** - Support for templated QObject. - Support for QObject nested in another class. ## How to Use The library consist of only two headers files. You can either copy these header files in your project, or adjust the include paths so that the compiler finds them. You will find the headers in the 'src/' sub-directory. Also make sure to set your compiler in, at least, C++14 mode. With qmake, you can do that with `CONFIG += c++14`. Tested with Qt >= 5.9. Need a compiler that can do C++14 relaxed constexpr such as GCC 5.1 or Clang 3.5, or MSVC 2017 ### Translations When running `lupdate`, add the argument `-tr-function-alias Q_DECLARE_TR_FUNCTIONS+=W_OBJECT` to avoid the warning that your class are not using the Q_OBJECT macro. ### Correspondance Table This table show the correspondence between Qt macro and Verdigris macro: | Qt macro | Use the Verdigris macro instead | |----------------------------------------------|---------------------------------------------------| | `Q_OBJECT` | `W_OBJECT(MyClass)` ... `W_OBJECT_IMPL(MyClass)` | | `public slots: void mySlot(int x);` | `void mySlot(int x); W_SLOT(mySlot)` | | `signals: void mySignal(int x);` | `void mySignal(int x) W_SIGNAL(mySignal,x)` | | `Q_PROPERTY(int myProperty WRITE setProp READ getProp NOTIFY propChanged)` | `W_PROPERTY(int, myProperty WRITE setProp READ getProp NOTIFY propChanged)` | | `Q_GADGET` | `W_GADGET(MyClass)` ... `W_GADGET_IMPL(MyClass)` | | `Q_INVOKABLE void myFunction(int foo);` | `void myFunction(int foo); W_INVOKABLE(myFunction)` | `Q_INVOKABLE MyClass(int foo);` | `MyClass(int foo); W_CONSTRUCTOR(int)` | | `Q_CLASSINFO("foo", "bar")` | `W_CLASSINFO("foo", "bar")` | | `Q_DECLARE_INTERFACE(MyInterface, "my.interface")` ... `Q_INTERFACE(MyInterface)` | `Q_DECLARE_INTERFACE(MyInterface, "my.interface")` ... `W_INTERFACE(MyInterface)` | | `Q_NAMESPACE` | `W_NAMESPACE(MyNs)` ... `W_NAMESPACE_IMPL(MyNs)` | | Q_ENUM/Q_FLAG/Q_ENUM_NS/Q_FLAG_NS | W_ENUM/W_FLAG/W_ENUM_NS/W_FLAG_NS | ## Who uses Verdigris ? * [Ossia Score](https://ossia.io/), an interactive intermedia sequencer. ([github](https://github.com/OSSIA/score)) It uses Verdigris in productions. Verdigris allowed ossia score to use template with their QObject's, and solve some trouble with the build system. * [ISOTRONIC GmbH](https://isotronic.de/), a provider for visual inspection QA systems for automatic glass vial manufacturing, uses Verdigris in production: > The transition from standard Qt affected more than 100 source code files and was done in not much more than a day. The reason for the switch was to be able to use a build system that has no interface for Qt's MOC process. In the rare cases of questions or problems the Verdigris team was quick and competent in resolving the issues. After more than 6 months of real-world experience we are still very happy with that decision. * If you are using Verdigris and want to appear here, please open an issue, or a pull request ## Context The macros were inspired by [CopperSpice](http://www.copperspice.com/). The template code was based on previous work: https://woboq.com/blog/reflection-in-cpp-and-qt-moc.html Differences with CopperSpice: 1. Contrary to CopperSpice, this is not a fork of Qt, but just an alternative set of macro to define Qt objects and signals and slot in a way that is binary compatible with Qt, but does not require moc. This is to be used with the normal Qt. CopperSpice being an entire fork of Qt, it has more differences with Qt and is not kept up to date with all the new features coming in Qt. 2. The QMetaObject is built at compile time in the read only section (like what moc does). CopperSpice builds it at run-time when the library is loaded. So CopperSpice takes more memory and load slower. 3. With CopperSpice, you cannot declare your slot within the class definition. 4. CopperSpice uses `__LINE__` in its macro making it impossible to declare several things in one line or to declare objects or properties from macros. 5. The usability of some macro was (in our opinion) improved. 6. The additional Q_OBJECT_IMPL ## Licence Like Qt, this library is under the dual licence LGPLv3 and GPLv2. Being header-only, this removes many of the obligations of the LGPLv3. If you have any questions or remark please email info@woboq.com verdigris-1.3/benchmarks/000077500000000000000000000000001427643277200155065ustar00rootroot00000000000000verdigris-1.3/benchmarks/KitchenSink/000077500000000000000000000000001427643277200177205ustar00rootroot00000000000000verdigris-1.3/benchmarks/KitchenSink/README000066400000000000000000000015551427643277200206060ustar00rootroot00000000000000 The patch in this directory applies to the KitchenSink-1.2.1 from the CopperSpice project. http://www.copperspice.com/documentation-kitchensink.html The following changes were made: * Removed html_browser, web_viewer, musicplayer Because of dependency to webkit and phonon. * Ported to Qt5 by adding a .pro file, fixing a few compilations error notably in the includes (because does not include QtWidgets) * Added an #include to cs_abstraction.h which allow to convert CS_ macro to Qt one * Added support for verdigris in cs_abstraction. Build with Copperspice: (the $CS_HOME need to be set accordingly) ./configure && make Build with Qt5: qmake && make Build with Verdigris git ls-files -- src | xargs sed -i "/struct dummy { Q_OBJECT };/d" # Optional, to avoid moc run qmake DEFINES+=USE_VERDIGRIS INCLUDEPATH+=path/to/verdigris/src make verdigris-1.3/benchmarks/KitchenSink/kitchensink-verdigris.patch000066400000000000000000001433471427643277200252630ustar00rootroot00000000000000diff --git a/KitchenSink.pro b/KitchenSink.pro new file mode 100644 index 0000000..1b6ca5b --- /dev/null +++ b/KitchenSink.pro @@ -0,0 +1,114 @@ +###################################################################### +# Automatically generated by qmake (3.0) Sa. Mai 7 14:46:48 2016 +###################################################################### + +TEMPLATE = app +TARGET = KitchenSink +INCLUDEPATH += . + +# Input +HEADERS += src/aboutcs.h \ + src/analogclock.h \ + src/animated_tiles.h \ + src/calendar.h \ + src/colorpicker.h \ + src/dialogs.h \ + src/draglabel.h \ + src/draw.h \ + src/draw_area.h \ + src/fontpicker.h \ + src/fridgemag.h \ + src/glwidget.h \ + src/grabber.h \ + src/international.h \ + src/lighting.h \ + src/line_edit.h \ + src/listview.h \ + src/mandelbrot_thread.h \ + src/mandelbrot_widget.h \ + src/mdi.h \ + src/screenshot.h \ + src/script.h \ + src/sliders.h \ + src/stdpath.h \ + src/style_dw.h \ + src/style_edit.h \ + src/svg_view.h \ + src/svgtextobject.h \ + src/systray.h \ + src/tabdialog.h \ + src/tableview.h \ + src/tablewidget_view.h \ + src/treeview.h \ + src/util.h \ + src/videoplayer.h \ + src/videosurface.h \ + src/videowidget.h \ + src/xml.h \ + src/xmlpatterns.h \ + src/xmlsyntaxhighlighter.h +FORMS += forms/colorpicker.ui \ + forms/dialogs.ui \ + forms/fontpicker.ui \ + forms/international.ui \ + forms/line_edit.ui \ + forms/listview.ui \ + forms/mdi.ui \ + forms/script.ui \ + forms/stdpath.ui \ + forms/style_dw.ui \ + forms/style_edit.ui \ + forms/tabdialog.ui \ + forms/tablewidget_view.ui \ + forms/xml.ui \ + forms/xmlpatterns.ui +SOURCES += src/aboutcs.cpp \ + src/analogclock.cpp \ + src/animated_tiles.cpp \ + src/calendar.cpp \ + src/colorpicker.cpp \ + src/dialogs.cpp \ + src/draglabel.cpp \ + src/draw.cpp \ + src/draw_area.cpp \ + src/fontpicker.cpp \ + src/fridgemag.cpp \ + src/glwidget.cpp \ + src/grabber.cpp \ + src/international.cpp \ + src/lighting.cpp \ + src/line_edit.cpp \ + src/listview.cpp \ + src/mandelbrot_thread.cpp \ + src/mandelbrot_widget.cpp \ + src/mdi.cpp \ + src/screenshot.cpp \ + src/script.cpp \ + src/sliders.cpp \ + src/stdpath.cpp \ + src/style_dw.cpp \ + src/style_edit.cpp \ + src/svg_view.cpp \ + src/svgtextobject.cpp \ + src/systray.cpp \ + src/tabdialog.cpp \ + src/tableview.cpp \ + src/tablewidget_view.cpp \ + src/treeview.cpp \ + src/util.cpp \ + src/videoplayer.cpp \ + src/videosurface.cpp \ + src/videowidget.cpp \ + src/xml.cpp \ + src/xmlpatterns.cpp \ + src/xmlsyntaxhighlighter.cpp \ + src/main.cpp +RESOURCES += kitchensink.qrc +TRANSLATIONS += resources/qt_de.ts resources/qt_en.ts resources/qt_fr.ts + + +CONFIG += c++14 +QT += widgets opengl sql multimedia xml xmlpatterns script svg +DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 +DEFINES += USE_QT + diff --git a/bin/Makefile.am b/bin/Makefile.am index 906d7f9..406cb1c 100644 --- a/bin/Makefile.am +++ b/bin/Makefile.am @@ -10,7 +10,7 @@ gccpath=$(dir $(shell which $(word 1,$(CC)))) gcclibs=libgcc_s_*-1 libstdc++-6 libwinpthread-1 # list of CopperSpice libraries -cslibs=Core Gui Multimedia Network OpenGL Phonon Script Sql Svg WebKit Xml XmlPatterns +cslibs=Core Gui Multimedia Network OpenGL Phonon Script Sql Svg Xml XmlPatterns # Declarative (on hold) # location of includes @@ -154,7 +154,6 @@ KitchenSink_SOURCES = \ src/fontpicker.cpp \ src/glwidget.cpp \ src/grabber.cpp \ - src/html_viewer.cpp \ src/international.cpp \ src/lighting.cpp \ src/line_edit.cpp \ @@ -163,7 +162,6 @@ KitchenSink_SOURCES = \ src/mandelbrot_thread.cpp \ src/mandelbrot_widget.cpp \ src/mdi.cpp \ - src/musicplayer.cpp \ src/screenshot.cpp \ src/sliders.cpp \ src/script.cpp \ @@ -181,7 +179,6 @@ KitchenSink_SOURCES = \ src/videosurface.cpp \ src/videoplayer.cpp \ src/videowidget.cpp \ - src/web_browser.cpp \ src/xml.cpp \ src/xmlpatterns.cpp \ src/xmlsyntaxhighlighter.cpp @@ -198,12 +195,10 @@ noinst_HEADERS = \ src/draw.h \ src/draw_area.h \ src/fontpicker.h \ - src/html_viewer.h \ src/international.h \ src/line_edit.h \ src/listview.h \ src/mdi.h \ - src/musicplayer.h \ src/script.h \ src/stdpath.h \ src/sliders.h \ @@ -220,7 +215,6 @@ noinst_HEADERS = \ src/videoplayer.h \ src/videowidget.h \ src/videosurface.h \ - src/web_browser.h \ src/analogclock.h \ src/animated_tiles.h \ src/draglabel.h \ @@ -244,11 +238,9 @@ FORMS = \ forms/colorpicker.ui \ forms/fontpicker.ui \ forms/dialogs.ui \ - forms/html_viewer.ui \ forms/international.ui \ forms/line_edit.ui \ forms/listview.ui \ - forms/musicplayer.ui \ forms/stdpath.ui \ forms/style_dw.ui \ forms/style_edit.ui \ diff --git a/bin/Makefile.in b/bin/Makefile.in index f733a6d..07b7820 100644 --- a/bin/Makefile.in +++ b/bin/Makefile.in @@ -111,12 +111,11 @@ am_KitchenSink_OBJECTS = src/aboutcs.$(OBJEXT) \ src/draw.$(OBJEXT) src/draw_area.$(OBJEXT) \ src/fridgemag.$(OBJEXT) src/fontpicker.$(OBJEXT) \ src/glwidget.$(OBJEXT) src/grabber.$(OBJEXT) \ - src/html_viewer.$(OBJEXT) src/international.$(OBJEXT) \ src/lighting.$(OBJEXT) src/line_edit.$(OBJEXT) \ src/listview.$(OBJEXT) src/main.$(OBJEXT) \ src/mandelbrot_thread.$(OBJEXT) \ src/mandelbrot_widget.$(OBJEXT) src/mdi.$(OBJEXT) \ - src/musicplayer.$(OBJEXT) src/screenshot.$(OBJEXT) \ + src/screenshot.$(OBJEXT) \ src/sliders.$(OBJEXT) src/script.$(OBJEXT) \ src/stdpath.$(OBJEXT) src/style_edit.$(OBJEXT) \ src/style_dw.$(OBJEXT) src/svg_view.$(OBJEXT) \ @@ -125,7 +124,7 @@ am_KitchenSink_OBJECTS = src/aboutcs.$(OBJEXT) \ src/tabdialog.$(OBJEXT) src/treeview.$(OBJEXT) \ src/util.$(OBJEXT) src/videosurface.$(OBJEXT) \ src/videoplayer.$(OBJEXT) src/videowidget.$(OBJEXT) \ - src/web_browser.$(OBJEXT) src/xml.$(OBJEXT) \ + src/international.$(OBJEXT) src/xml.$(OBJEXT) \ src/xmlpatterns.$(OBJEXT) src/xmlsyntaxhighlighter.$(OBJEXT) nodist_KitchenSink_OBJECTS = qrc_kitchensink.$(OBJEXT) KitchenSink_OBJECTS = $(am_KitchenSink_OBJECTS) \ @@ -370,7 +369,7 @@ gccpath = $(dir $(shell which $(word 1,$(CC)))) gcclibs = libgcc_s_*-1 libstdc++-6 libwinpthread-1 # list of CopperSpice libraries -cslibs = Core Gui Multimedia Network OpenGL Phonon Script Sql Svg WebKit Xml XmlPatterns +cslibs = Core Gui Multimedia Network OpenGL Phonon Script Sql Svg Xml XmlPatterns @OSTYPE_WIN_TRUE@installdir = $(abs_top_builddir)/install @OSTYPE_DARWIN_TRUE@deployapp = $(deploydir)/$(bin_PROGRAMS).app/Contents @@ -391,7 +390,6 @@ KitchenSink_SOURCES = \ src/fontpicker.cpp \ src/glwidget.cpp \ src/grabber.cpp \ - src/html_viewer.cpp \ src/international.cpp \ src/lighting.cpp \ src/line_edit.cpp \ @@ -400,7 +398,6 @@ KitchenSink_SOURCES = \ src/mandelbrot_thread.cpp \ src/mandelbrot_widget.cpp \ src/mdi.cpp \ - src/musicplayer.cpp \ src/screenshot.cpp \ src/sliders.cpp \ src/script.cpp \ @@ -418,7 +415,6 @@ KitchenSink_SOURCES = \ src/videosurface.cpp \ src/videoplayer.cpp \ src/videowidget.cpp \ - src/web_browser.cpp \ src/xml.cpp \ src/xmlpatterns.cpp \ src/xmlsyntaxhighlighter.cpp @@ -435,12 +431,10 @@ noinst_HEADERS = \ src/draw.h \ src/draw_area.h \ src/fontpicker.h \ - src/html_viewer.h \ src/international.h \ src/line_edit.h \ src/listview.h \ src/mdi.h \ - src/musicplayer.h \ src/script.h \ src/stdpath.h \ src/sliders.h \ @@ -457,7 +451,6 @@ noinst_HEADERS = \ src/videoplayer.h \ src/videowidget.h \ src/videosurface.h \ - src/web_browser.h \ src/analogclock.h \ src/animated_tiles.h \ src/draglabel.h \ @@ -481,11 +474,9 @@ FORMS = \ forms/colorpicker.ui \ forms/fontpicker.ui \ forms/dialogs.ui \ - forms/html_viewer.ui \ forms/international.ui \ forms/line_edit.ui \ forms/listview.ui \ - forms/musicplayer.ui \ forms/stdpath.ui \ forms/style_dw.ui \ forms/style_edit.ui \ @@ -620,8 +611,6 @@ src/glwidget.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/grabber.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) -src/html_viewer.$(OBJEXT): src/$(am__dirstamp) \ - src/$(DEPDIR)/$(am__dirstamp) src/international.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/lighting.$(OBJEXT): src/$(am__dirstamp) \ @@ -636,8 +625,6 @@ src/mandelbrot_thread.$(OBJEXT): src/$(am__dirstamp) \ src/mandelbrot_widget.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/mdi.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) -src/musicplayer.$(OBJEXT): src/$(am__dirstamp) \ - src/$(DEPDIR)/$(am__dirstamp) src/screenshot.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/sliders.$(OBJEXT): src/$(am__dirstamp) \ @@ -671,8 +658,6 @@ src/videoplayer.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/videowidget.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) -src/web_browser.$(OBJEXT): src/$(am__dirstamp) \ - src/$(DEPDIR)/$(am__dirstamp) src/xml.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) src/xmlpatterns.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) @@ -704,7 +689,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/fridgemag.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/glwidget.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/grabber.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/html_viewer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/international.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/lighting.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/line_edit.Po@am__quote@ @@ -713,7 +697,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/mandelbrot_thread.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/mandelbrot_widget.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/mdi.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/musicplayer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/screenshot.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/script.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/sliders.Po@am__quote@ @@ -731,7 +714,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/videoplayer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/videosurface.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/videowidget.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/web_browser.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/xml.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/xmlpatterns.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/xmlsyntaxhighlighter.Po@am__quote@ diff --git a/src/aboutcs.cpp b/src/aboutcs.cpp index 5b6b74b..b3f7c95 100755 --- a/src/aboutcs.cpp +++ b/src/aboutcs.cpp @@ -63,8 +63,8 @@ AboutCS::AboutCS(QString route) closePB->setText("Close"); // - m_viewer = new QWebView; - m_viewer->setUrl(url); + // m_viewer = new QWebView; + // m_viewer->setUrl(url); // QHBoxLayout *buttonLayout = new QHBoxLayout; @@ -75,7 +75,7 @@ AboutCS::AboutCS(QString route) buttonLayout->addStretch(); QVBoxLayout *mainLayout = new QVBoxLayout; - mainLayout->addWidget(m_viewer); + //mainLayout->addWidget(m_viewer); mainLayout->addSpacing(10); mainLayout->addLayout(buttonLayout); setLayout(mainLayout); @@ -89,7 +89,7 @@ AboutCS::AboutCS(QString route) void AboutCS::actionHome() { QString url = "http://www.copperspice.com/kitchensink.html"; - m_viewer->setUrl(url); + //m_viewer->setUrl(url); } void AboutCS::actionClose() { @@ -100,3 +100,6 @@ QSize AboutCS::sizeHint() const { return QSize(800, 600); } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(AboutCS) +#endif diff --git a/src/aboutcs.h b/src/aboutcs.h index 6c795a9..423bae7 100755 --- a/src/aboutcs.h +++ b/src/aboutcs.h @@ -32,11 +32,15 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef ABOUTCS_H #define ABOUTCS_H -#include +//#include #include class AboutCS : public QWidget @@ -48,7 +52,7 @@ class AboutCS : public QWidget QSize sizeHint() const; private: - QWebView *m_viewer; + // QWebView *m_viewer; CS_SLOT_1(Private, void actionClose()) CS_SLOT_2(actionClose) diff --git a/src/analogclock.cpp b/src/analogclock.cpp index f85a4b4..b6d8edd 100755 --- a/src/analogclock.cpp +++ b/src/analogclock.cpp @@ -104,3 +104,6 @@ void AnalogClock::paintEvent(QPaintEvent *) } } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(AnalogClock) +#endif diff --git a/src/analogclock.h b/src/analogclock.h index 5352767..034fde6 100755 --- a/src/analogclock.h +++ b/src/analogclock.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef ANALOGCLOCK_H #define ANALOGCLOCK_H diff --git a/src/animated_tiles.cpp b/src/animated_tiles.cpp index c8248c2..3deb032 100755 --- a/src/animated_tiles.cpp +++ b/src/animated_tiles.cpp @@ -161,3 +161,12 @@ AnimatedTiles::AnimatedTiles(QWidget *parent) } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(AnimatedTiles) +#endif +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(Button) +#endif +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(Pixmap) +#endif diff --git a/src/animated_tiles.h b/src/animated_tiles.h index c44218a..89cfdb5 100755 --- a/src/animated_tiles.h +++ b/src/animated_tiles.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef ANIMATED_TILES_H #define ANIMATED_TILES_H @@ -66,8 +70,6 @@ class Pixmap : public QObject, public QGraphicsPixmapItem { CS_OBJECT_MULTIPLE(Pixmap, QObject) - CS_PROPERTY_READ(pos, pos) - CS_PROPERTY_WRITE(pos, ks_setPos) public: Pixmap(const QPixmap &pix) @@ -79,6 +81,15 @@ class Pixmap : public QObject, public QGraphicsPixmapItem // wrapper for overloaded method inline void ks_setPos(const QPointF &pos); +#if defined(USE_VERDIGRIS) + W_PROPERTY(QPointF, pos READ pos WRITE ks_setPos) +#elif defined(USE_QT) + Q_PROPERTY(QPointF pos READ pos WRITE ks_setPos) +#else + CS_PROPERTY_READ(pos, pos) + CS_PROPERTY_WRITE(pos, ks_setPos) +#endif + }; void Pixmap::ks_setPos(const QPointF &pos) diff --git a/src/calendar.cpp b/src/calendar.cpp index bedee4d..316166a 100755 --- a/src/calendar.cpp +++ b/src/calendar.cpp @@ -418,12 +418,15 @@ void Calendar::createTextFormatsGroupBox() QComboBox *Calendar::createColorComboBox() { QComboBox *comboBox = new QComboBox; - comboBox->addItem(tr("Black"), Qt::black); - comboBox->addItem(tr("Blue"), Qt::blue); - comboBox->addItem(tr("Green"), Qt::green); - comboBox->addItem(tr("Red"), Qt::darkRed); - comboBox->addItem(tr("Magenta"), Qt::magenta); - comboBox->addItem(tr("Yellow"), Qt::darkYellow); + comboBox->addItem(tr("Black"), QColor(Qt::black)); + comboBox->addItem(tr("Blue"), QColor(Qt::blue)); + comboBox->addItem(tr("Green"), QColor(Qt::green)); + comboBox->addItem(tr("Red"), QColor(Qt::darkRed)); + comboBox->addItem(tr("Magenta"), QColor(Qt::magenta)); + comboBox->addItem(tr("Yellow"), QColor(Qt::darkYellow)); return comboBox; } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(Calendar) +#endif diff --git a/src/calendar.h b/src/calendar.h index 37158af..445ceef 100755 --- a/src/calendar.h +++ b/src/calendar.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef CALENDAR_H #define CALENDAR_H diff --git a/src/colorpicker.cpp b/src/colorpicker.cpp index 558abaf..459a983 100755 --- a/src/colorpicker.cpp +++ b/src/colorpicker.cpp @@ -87,3 +87,6 @@ void ColorPicker::setColor() void ColorPicker::actionClose() { this->parentWidget()->close(); } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(ColorPicker) +#endif diff --git a/src/colorpicker.h b/src/colorpicker.h index ac1e1f2..6301fc4 100755 --- a/src/colorpicker.h +++ b/src/colorpicker.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef COLORPICKER_H #define COLORPICKER_H diff --git a/src/cs_abstraction.h b/src/cs_abstraction.h new file mode 100644 index 0000000..8ac3036 --- /dev/null +++ b/src/cs_abstraction.h @@ -0,0 +1,25 @@ +#pragma once + +#ifdef USE_VERDIGRIS + +#include + +#define CS_OBJECT(X) W_OBJECT(X) +#define CS_OBJECT_MULTIPLE(X,XX) W_OBJECT(X) +#define CS_SLOT_1(XX,...) __VA_ARGS__; +#define CS_SLOT_2(X) W_SLOT(X) +#define CS_SIGNAL_1(XX,...) __VA_ARGS__ +#define CS_SIGNAL_2(...) W_SIGNAL(__VA_ARGS__) +#define CS_INTERFACES(XX) Q_INTERFACES(XX) + +#elif defined(USE_QT) + +#define CS_OBJECT(X) Q_OBJECT +#define CS_OBJECT_MULTIPLE(X,XX) Q_OBJECT +#define CS_SLOT_1(XX,...) Q_SLOT __VA_ARGS__; +#define CS_SLOT_2(...) +#define CS_SIGNAL_1(XX,...) Q_SIGNAL __VA_ARGS__; +#define CS_SIGNAL_2(...) +#define CS_INTERFACES(XX) Q_INTERFACES(XX) + +#endif diff --git a/src/dialogs.cpp b/src/dialogs.cpp index 22f23a7..a2015a2 100755 --- a/src/dialogs.cpp +++ b/src/dialogs.cpp @@ -37,6 +37,9 @@ #include "ui_dialogs.h" #include +#include +#include +#include #define MESSAGE Dialogs::tr("

Message boxes have a caption, text, " \ "and any number of buttons, each with standard or custom text." \ @@ -246,3 +249,6 @@ void Dialogs::errorMessage() ui->error_lineEdit->setText(tr("If the box is unchecked, the message will not appear again.")); } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(Dialogs) +#endif diff --git a/src/dialogs.h b/src/dialogs.h index 5a05be3..c5f5606 100755 --- a/src/dialogs.h +++ b/src/dialogs.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef DIALOGS_H #define DIALOGS_H diff --git a/src/draglabel.h b/src/draglabel.h index 46be470..5ccee01 100755 --- a/src/draglabel.h +++ b/src/draglabel.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef DRAGLABEL_H #define DRAGLABEL_H diff --git a/src/draw.cpp b/src/draw.cpp index 04c14b3..ec2f9a8 100755 --- a/src/draw.cpp +++ b/src/draw.cpp @@ -37,6 +37,7 @@ #include "draw.h" #include +#include const int IdRole = Qt::UserRole; @@ -72,12 +73,12 @@ Draw::Draw() penWidthLabel->setBuddy(penWidthSpinBox); penStyleComboBox = new QComboBox; - penStyleComboBox->addItem(tr("Solid"), Qt::SolidLine); - penStyleComboBox->addItem(tr("Dash"), Qt::DashLine); - penStyleComboBox->addItem(tr("Dot"), Qt::DotLine); - penStyleComboBox->addItem(tr("Dash Dot"), Qt::DashDotLine); - penStyleComboBox->addItem(tr("Dash Dot Dot"), Qt::DashDotDotLine); - penStyleComboBox->addItem(tr("None"), Qt::NoPen); + penStyleComboBox->addItem(tr("Solid"), int(Qt::SolidLine)); + penStyleComboBox->addItem(tr("Dash"), int(Qt::DashLine)); + penStyleComboBox->addItem(tr("Dot"), int(Qt::DotLine)); + penStyleComboBox->addItem(tr("Dash Dot"), int(Qt::DashDotLine)); + penStyleComboBox->addItem(tr("Dash Dot Dot"), int(Qt::DashDotDotLine)); + penStyleComboBox->addItem(tr("None"), int(Qt::NoPen)); penStyleLabel = new QLabel(tr("&Pen Style:")); penStyleLabel->setBuddy(penStyleComboBox); @@ -99,25 +100,25 @@ Draw::Draw() penJoinLabel->setBuddy(penJoinComboBox); brushStyleComboBox = new QComboBox; - brushStyleComboBox->addItem(tr("Linear Gradient"), Qt::LinearGradientPattern); - brushStyleComboBox->addItem(tr("Radial Gradient"), Qt::RadialGradientPattern); - brushStyleComboBox->addItem(tr("Conical Gradient"), Qt::ConicalGradientPattern); - brushStyleComboBox->addItem(tr("Texture"), Qt::TexturePattern); - brushStyleComboBox->addItem(tr("Solid"), Qt::SolidPattern); - brushStyleComboBox->addItem(tr("Horizontal"), Qt::HorPattern); - brushStyleComboBox->addItem(tr("Vertical"), Qt::VerPattern); - brushStyleComboBox->addItem(tr("Cross"), Qt::CrossPattern); - brushStyleComboBox->addItem(tr("Backward Diagonal"), Qt::BDiagPattern); - brushStyleComboBox->addItem(tr("Forward Diagonal"), Qt::FDiagPattern); - brushStyleComboBox->addItem(tr("Diagonal Cross"), Qt::DiagCrossPattern); - brushStyleComboBox->addItem(tr("Dense 1"), Qt::Dense1Pattern); - brushStyleComboBox->addItem(tr("Dense 2"), Qt::Dense2Pattern); - brushStyleComboBox->addItem(tr("Dense 3"), Qt::Dense3Pattern); - brushStyleComboBox->addItem(tr("Dense 4"), Qt::Dense4Pattern); - brushStyleComboBox->addItem(tr("Dense 5"), Qt::Dense5Pattern); - brushStyleComboBox->addItem(tr("Dense 6"), Qt::Dense6Pattern); - brushStyleComboBox->addItem(tr("Dense 7"), Qt::Dense7Pattern); - brushStyleComboBox->addItem(tr("None"), Qt::NoBrush); + brushStyleComboBox->addItem(tr("Linear Gradient"), int(Qt::LinearGradientPattern)); + brushStyleComboBox->addItem(tr("Radial Gradient"), int(Qt::RadialGradientPattern)); + brushStyleComboBox->addItem(tr("Conical Gradient"), int(Qt::ConicalGradientPattern)); + brushStyleComboBox->addItem(tr("Texture"), int(Qt::TexturePattern)); + brushStyleComboBox->addItem(tr("Solid"), int(Qt::SolidPattern)); + brushStyleComboBox->addItem(tr("Horizontal"), int(Qt::HorPattern)); + brushStyleComboBox->addItem(tr("Vertical"), int(Qt::VerPattern)); + brushStyleComboBox->addItem(tr("Cross"), int(Qt::CrossPattern)); + brushStyleComboBox->addItem(tr("Backward Diagonal"),int(Qt::BDiagPattern)); + brushStyleComboBox->addItem(tr("Forward Diagonal"), int(Qt::FDiagPattern)); + brushStyleComboBox->addItem(tr("Diagonal Cross"), int(Qt::DiagCrossPattern)); + brushStyleComboBox->addItem(tr("Dense 1"), int(Qt::Dense1Pattern)); + brushStyleComboBox->addItem(tr("Dense 2"), int(Qt::Dense2Pattern)); + brushStyleComboBox->addItem(tr("Dense 3"), int(Qt::Dense3Pattern)); + brushStyleComboBox->addItem(tr("Dense 4"), int(Qt::Dense4Pattern)); + brushStyleComboBox->addItem(tr("Dense 5"), int(Qt::Dense5Pattern)); + brushStyleComboBox->addItem(tr("Dense 6"), int(Qt::Dense6Pattern)); + brushStyleComboBox->addItem(tr("Dense 7"), int(Qt::Dense7Pattern)); + brushStyleComboBox->addItem(tr("None"), int(Qt::NoBrush)); brushStyleLabel = new QLabel(tr("&Brush:")); brushStyleLabel->setBuddy(brushStyleComboBox); @@ -223,3 +224,6 @@ void Draw::brushChanged() } } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(Draw) +#endif diff --git a/src/draw.h b/src/draw.h index b5ddb80..a95d698 100755 --- a/src/draw.h +++ b/src/draw.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef DRAW_H #define DRAW_H diff --git a/src/draw_area.cpp b/src/draw_area.cpp index 489d201..86d7e54 100755 --- a/src/draw_area.cpp +++ b/src/draw_area.cpp @@ -36,6 +36,10 @@ #include "draw_area.h" #include +#ifdef W_REGISTER_ARGTYPE +W_REGISTER_ARGTYPE(DrawArea::Shape) +#endif + DrawArea::DrawArea(QWidget *parent) : QWidget(parent) { @@ -174,3 +178,6 @@ void DrawArea::paintEvent(QPaintEvent * /* event */) painter.drawRect(QRect(0, 0, width() - 1, height() - 1)); } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(DrawArea) +#endif diff --git a/src/draw_area.h b/src/draw_area.h index 7344317..028e9cc 100755 --- a/src/draw_area.h +++ b/src/draw_area.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef DRAWAREA_H #define DRAWAREA_H diff --git a/src/fontpicker.cpp b/src/fontpicker.cpp index 2c20078..120a958 100755 --- a/src/fontpicker.cpp +++ b/src/fontpicker.cpp @@ -79,3 +79,6 @@ void FontPicker::setFont() void FontPicker::actionClose() { this->parentWidget()->close(); } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(FontPicker) +#endif diff --git a/src/fontpicker.h b/src/fontpicker.h index 2d97316..390cfbf 100755 --- a/src/fontpicker.h +++ b/src/fontpicker.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef FONTPICKER_H #define FONTPICKER_H diff --git a/src/fridgemag.h b/src/fridgemag.h index 70a0354..ab14088 100755 --- a/src/fridgemag.h +++ b/src/fridgemag.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef FRIDGEMAG_H #define FRIDGEMAG_H diff --git a/src/glwidget.cpp b/src/glwidget.cpp index 4e5b0c0..00d3449 100755 --- a/src/glwidget.cpp +++ b/src/glwidget.cpp @@ -276,3 +276,6 @@ void GLWidget::normalizeAngle(int *angle) while (*angle > 360 * 16) *angle -= 360 * 16; } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(GLWidget) +#endif diff --git a/src/glwidget.h b/src/glwidget.h index a006c94..1a14cc7 100755 --- a/src/glwidget.h +++ b/src/glwidget.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef GLWIDGET_H #define GLWIDGET_H diff --git a/src/grabber.cpp b/src/grabber.cpp index d453659..425cdf3 100755 --- a/src/grabber.cpp +++ b/src/grabber.cpp @@ -209,3 +209,6 @@ QSize Grabber::sizeHint() const } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(Grabber) +#endif diff --git a/src/grabber.h b/src/grabber.h index bb62dfd..b9dece8 100755 --- a/src/grabber.h +++ b/src/grabber.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef GRABBER_H #define GRABBER_H diff --git a/src/international.cpp b/src/international.cpp index da33bde..2ec69a5 100755 --- a/src/international.cpp +++ b/src/international.cpp @@ -133,3 +133,6 @@ void International::actionClose() } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(International) +#endif diff --git a/src/international.h b/src/international.h index 05b8f88..e73e13c 100755 --- a/src/international.h +++ b/src/international.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef INTERNATIONAL_H #define INTERNATIONAL_H diff --git a/src/lighting.cpp b/src/lighting.cpp index a270358..47011d2 100755 --- a/src/lighting.cpp +++ b/src/lighting.cpp @@ -140,3 +140,6 @@ void Lighting::setupScene() void Lighting::resizeEvent(QResizeEvent */*event*/) { } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(Lighting) +#endif diff --git a/src/lighting.h b/src/lighting.h index 923f2eb..73047ed 100755 --- a/src/lighting.h +++ b/src/lighting.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef LIGHTING_H #define LIGHTING_H diff --git a/src/line_edit.cpp b/src/line_edit.cpp index 2e3743b..2d4552d 100755 --- a/src/line_edit.cpp +++ b/src/line_edit.cpp @@ -175,3 +175,6 @@ void LineEdit::readonlyChanged(int index) } } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(LineEdit) +#endif diff --git a/src/line_edit.h b/src/line_edit.h index b904f97..472f548 100755 --- a/src/line_edit.h +++ b/src/line_edit.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef LINEEDIT_H #define LINEEDIT_H diff --git a/src/listview.cpp b/src/listview.cpp index c655741..ef78089 100755 --- a/src/listview.cpp +++ b/src/listview.cpp @@ -117,3 +117,6 @@ void ListView::delRow() +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(ListView) +#endif diff --git a/src/listview.h b/src/listview.h index 7fd4f89..b4ff66b 100755 --- a/src/listview.h +++ b/src/listview.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef LISTVIEW_H #define LISTVIEW_H diff --git a/src/main.cpp b/src/main.cpp index 1301cfa..f5ee76f 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,7 +35,7 @@ #include "mdi.h" -#include +#include int main(int argc, char *argv[]) { diff --git a/src/mandelbrot_thread.cpp b/src/mandelbrot_thread.cpp index 51772af..93d4f68 100755 --- a/src/mandelbrot_thread.cpp +++ b/src/mandelbrot_thread.cpp @@ -191,3 +191,6 @@ uint Mandelbrot_Thread::rgbFromWaveLength(double wave) return qRgb(int(r * 255), int(g * 255), int(b * 255)); } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(Mandelbrot_Thread) +#endif diff --git a/src/mandelbrot_thread.h b/src/mandelbrot_thread.h index c887e43..18daf35 100755 --- a/src/mandelbrot_thread.h +++ b/src/mandelbrot_thread.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef MANDELBROT_THREAD_H #define MANDELBROT_THREAD_H diff --git a/src/mandelbrot_widget.cpp b/src/mandelbrot_widget.cpp index 5de0f59..e986b92 100755 --- a/src/mandelbrot_widget.cpp +++ b/src/mandelbrot_widget.cpp @@ -203,3 +203,6 @@ void Mandelbrot_Widget::zoom(double zoomFactor) thread.render(centerX, centerY, curScale, size()); } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(Mandelbrot_Widget) +#endif diff --git a/src/mandelbrot_widget.h b/src/mandelbrot_widget.h index e4d23e0..349cb3e 100755 --- a/src/mandelbrot_widget.h +++ b/src/mandelbrot_widget.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef MANDELBROT_WIDGET_H #define MANDELBROT_WIDGET_H diff --git a/src/mdi.cpp b/src/mdi.cpp index 018fbda..c7856aa 100755 --- a/src/mdi.cpp +++ b/src/mdi.cpp @@ -40,9 +40,9 @@ #include "dialogs.h" #include "draw.h" #include "fontpicker.h" -#include "html_viewer.h" +// #include "html_viewer.h" #include "international.h" -#include "musicplayer.h" +// #include "musicplayer.h" #include "line_edit.h" #include "listview.h" // #include "script.h" (QScript) @@ -56,7 +56,7 @@ #include "tablewidget_view.h" #include "treeview.h" #include "videoplayer.h" -#include "web_browser.h" +// #include "web_browser.h" #include "xml.h" #include "xmlpatterns.h" @@ -207,13 +207,13 @@ void Mdi::on_actionXmlPatterns_triggered() // audio & visual void Mdi::on_actionMusicPlayer_triggered() { - MusicPlayer *oDw = new MusicPlayer(); - - if ( oDw->loaded() ) { - addMdiChild(oDw); - } else { - delete oDw; - } +// MusicPlayer *oDw = new MusicPlayer(); +// +// if ( oDw->loaded() ) { +// addMdiChild(oDw); +// } else { +// delete oDw; +// } } void Mdi::on_actionVideoWidget_triggered() @@ -224,14 +224,14 @@ void Mdi::on_actionVideoWidget_triggered() void Mdi::on_actionHTML_Viewer_triggered() { - Html_Viewer *oDw = new Html_Viewer(); - addMdiChild(oDw); +// Html_Viewer *oDw = new Html_Viewer(); +// addMdiChild(oDw); } void Mdi::on_actionWebBrowser_triggered() { - WebBrowser *oDw = new WebBrowser(this); - addMdiChild(oDw); +// WebBrowser *oDw = new WebBrowser(this); +// addMdiChild(oDw); } @@ -386,3 +386,6 @@ void Mdi::on_actionAbout_triggered() msgB.exec(); } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(Mdi) +#endif diff --git a/src/mdi.h b/src/mdi.h index 7cea8de..2a5ed15 100755 --- a/src/mdi.h +++ b/src/mdi.h @@ -32,13 +32,17 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef MDI_H #define MDI_H #include "ui_mdi.h" -#include +#include class Mdi : public QMainWindow { diff --git a/src/screenshot.cpp b/src/screenshot.cpp index 1af228d..5e11a5a 100755 --- a/src/screenshot.cpp +++ b/src/screenshot.cpp @@ -36,6 +36,14 @@ #include "screenshot.h" #include +#include +#include +#include +#include +#include +#include +#include +#include Screenshot::Screenshot() { @@ -148,3 +156,6 @@ void Screenshot::updateScreenshotLabel() screenshotLabel->setPixmap(originalPixmap.scaled(screenshotLabel->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(Screenshot) +#endif diff --git a/src/screenshot.h b/src/screenshot.h index 578180c..794c59a 100755 --- a/src/screenshot.h +++ b/src/screenshot.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef SCREENSHOT_H #define SCREENSHOT_H diff --git a/src/script.cpp b/src/script.cpp index 11179c4..7d0ca18 100755 --- a/src/script.cpp +++ b/src/script.cpp @@ -150,3 +150,6 @@ void Script::actionClose() { this->parentWidget()->close(); } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(Script) +#endif diff --git a/src/script.h b/src/script.h index 26c4e75..9514a6f 100755 --- a/src/script.h +++ b/src/script.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef SCRIPT_H #define SCRIPT_H diff --git a/src/sliders.cpp b/src/sliders.cpp index 82d1f11..1e86401 100755 --- a/src/sliders.cpp +++ b/src/sliders.cpp @@ -36,6 +36,9 @@ #include "sliders.h" #include +#include +#include +#include Sliders::Sliders() : QWidget() @@ -160,3 +163,6 @@ void Sliders::rotateWidgets() m_rotableLayout->addWidget(m_rotableWidgets[i], 1, i); } } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(Sliders) +#endif diff --git a/src/sliders.h b/src/sliders.h index a606287..34e4109 100755 --- a/src/sliders.h +++ b/src/sliders.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef SLIDERS_H #define SLIDERS_H diff --git a/src/stdpath.cpp b/src/stdpath.cpp index 6ebffc8..f415528 100755 --- a/src/stdpath.cpp +++ b/src/stdpath.cpp @@ -175,3 +175,6 @@ void StdPath::locateAll() m_ui->locateAll->append(locationList.at(k)); } } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(StdPath) +#endif diff --git a/src/stdpath.h b/src/stdpath.h index 245a209..bbd47e4 100755 --- a/src/stdpath.h +++ b/src/stdpath.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef STDPATH_H #define STDPATH_H diff --git a/src/style_dw.cpp b/src/style_dw.cpp index ba5ed27..f272ffe 100755 --- a/src/style_dw.cpp +++ b/src/style_dw.cpp @@ -104,3 +104,6 @@ void Style_DW::styleEditClose() // marks the style_edit window closed m_style = NULL; } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(Style_DW) +#endif diff --git a/src/style_dw.h b/src/style_dw.h index fb7be43..730d020 100755 --- a/src/style_dw.h +++ b/src/style_dw.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef STYLE_DW_H #define STYLE_DW_H diff --git a/src/style_edit.cpp b/src/style_edit.cpp index 5b54eda..827355b 100755 --- a/src/style_edit.cpp +++ b/src/style_edit.cpp @@ -38,6 +38,7 @@ #include "style_dw.h" #include +#include const static QString qsPath = ":/resources/"; QString Style_Edit::qssName = "Shiny"; @@ -150,3 +151,6 @@ void Style_Edit::closeEvent(QCloseEvent *event) } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(Style_Edit) +#endif diff --git a/src/style_edit.h b/src/style_edit.h index 0b9b992..dc931c5 100755 --- a/src/style_edit.h +++ b/src/style_edit.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef STYLE_EDIT_H #define STYLE_EDIT_H diff --git a/src/svg_view.cpp b/src/svg_view.cpp index 3a96303..88cd43f 100755 --- a/src/svg_view.cpp +++ b/src/svg_view.cpp @@ -143,3 +143,6 @@ void Svg_View::actionClose() { this->parentWidget()->close(); } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(Svg_View) +#endif diff --git a/src/svg_view.h b/src/svg_view.h index 2ac13bc..e9fc962 100755 --- a/src/svg_view.h +++ b/src/svg_view.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef SVG_VIEW_H #define SVG_VIEW_H diff --git a/src/svgtextobject.cpp b/src/svgtextobject.cpp index fb703d9..1f38fdf 100755 --- a/src/svgtextobject.cpp +++ b/src/svgtextobject.cpp @@ -61,3 +61,6 @@ void SvgTextObject::drawObject(QPainter *painter, painter->drawImage(rect, bufferedImage); } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(SvgTextObject) +#endif diff --git a/src/svgtextobject.h b/src/svgtextobject.h index 96c29ee..0bb6a1c 100755 --- a/src/svgtextobject.h +++ b/src/svgtextobject.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef SVGTEXTOBJECT_H #define SVGTEXTOBJECT_H diff --git a/src/systray.cpp b/src/systray.cpp index 4862a86..7c25546 100755 --- a/src/systray.cpp +++ b/src/systray.cpp @@ -36,6 +36,12 @@ #include "systray.h" #include +#include +#include + +#ifdef W_REGISTER_ARGTYPE +W_REGISTER_ARGTYPE(QSystemTrayIcon::ActivationReason) +#endif const static QString sysPath = ":/resources/"; @@ -247,3 +253,6 @@ void SysTray::actionQuit() { } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(SysTray) +#endif diff --git a/src/systray.h b/src/systray.h index ac29603..80b2e01 100755 --- a/src/systray.h +++ b/src/systray.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef SYSTRAY_H #define SYSTRAY_H diff --git a/src/tabdialog.cpp b/src/tabdialog.cpp index 3c1f2d2..f545d6b 100755 --- a/src/tabdialog.cpp +++ b/src/tabdialog.cpp @@ -182,3 +182,6 @@ void TabDialog::actionRollYourOwn() void TabDialog::actionClose() { this->parentWidget()->close(); } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(TabDialog) +#endif diff --git a/src/tabdialog.h b/src/tabdialog.h index 20c2259..ee4bb83 100755 --- a/src/tabdialog.h +++ b/src/tabdialog.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef TABDIALOG_H #define TABDIALOG_H diff --git a/src/tableview.cpp b/src/tableview.cpp index e569552..c5bb12a 100755 --- a/src/tableview.cpp +++ b/src/tableview.cpp @@ -147,3 +147,6 @@ bool TableView::createConnection() QSqlRelationalTableModel */ +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(TableView) +#endif diff --git a/src/tableview.h b/src/tableview.h index 3c3e1dd..c1e153e 100755 --- a/src/tableview.h +++ b/src/tableview.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef TABLEVIEW_H #define TABLEVIEW_H diff --git a/src/tablewidget_view.cpp b/src/tablewidget_view.cpp index 3d7be31..11d3b68 100755 --- a/src/tablewidget_view.cpp +++ b/src/tablewidget_view.cpp @@ -302,3 +302,6 @@ QTableWidget->sortItems(0, Qt::AscendingOrder) +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(TableWidget_View) +#endif diff --git a/src/tablewidget_view.h b/src/tablewidget_view.h index 988a627..5355e3f 100755 --- a/src/tablewidget_view.h +++ b/src/tablewidget_view.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef TABLEWIDGET_VIEW_H #define TABLEWIDGET_VIEW_H diff --git a/src/treeview.h b/src/treeview.h index c01bbe4..aaba437 100755 --- a/src/treeview.h +++ b/src/treeview.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef TREEVIEW_H #define TREEVIEW_H diff --git a/src/util.cpp b/src/util.cpp index f4a4184..3e192ea 100755 --- a/src/util.cpp +++ b/src/util.cpp @@ -34,6 +34,7 @@ ***********************************************************************/ #include "util.h" +#include void ksMsg(const QString &msg) { diff --git a/src/util.h b/src/util.h index 4e0a1be..f0a1f7d 100755 --- a/src/util.h +++ b/src/util.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef UTIL_H #define UTIL_H diff --git a/src/videoplayer.cpp b/src/videoplayer.cpp index fdd4430..34186d6 100755 --- a/src/videoplayer.cpp +++ b/src/videoplayer.cpp @@ -39,6 +39,16 @@ #include #include +#include +#include +#include +#include +#include + +#ifdef W_REGISTER_ARGTYPE +W_REGISTER_ARGTYPE(QMovie::MovieState) +#endif + VideoPlayer::VideoPlayer(QWidget *parent) : QWidget(parent), m_surface(0) @@ -184,3 +194,6 @@ bool VideoPlayer::presentImage(const QImage &image) void VideoPlayer::actionClose() { this->parentWidget()->close(); } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(VideoPlayer) +#endif diff --git a/src/videoplayer.h b/src/videoplayer.h index b53e225..19eeabc 100755 --- a/src/videoplayer.h +++ b/src/videoplayer.h @@ -32,12 +32,16 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef VIDEOPLAYER_H #define VIDEOPLAYER_H #include -#include +#include #include class VideoPlayer : public QWidget diff --git a/src/videosurface.cpp b/src/videosurface.cpp index c71603a..2cc1d91 100755 --- a/src/videosurface.cpp +++ b/src/videosurface.cpp @@ -161,3 +161,6 @@ void VideoSurface::paint(QPainter *painter) } } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(VideoSurface) +#endif diff --git a/src/videosurface.h b/src/videosurface.h index 6a8165c..d305c1f 100755 --- a/src/videosurface.h +++ b/src/videosurface.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef VIDEOSURFACE_H #define VIDEOSURFACE_H diff --git a/src/videowidget.cpp b/src/videowidget.cpp index 2ee2d25..5349081 100755 --- a/src/videowidget.cpp +++ b/src/videowidget.cpp @@ -92,3 +92,6 @@ void VideoWidget::resizeEvent(QResizeEvent *event) surface->updateVideoRect(); } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(VideoWidget) +#endif diff --git a/src/videowidget.h b/src/videowidget.h index 78d7572..0eb0674 100755 --- a/src/videowidget.h +++ b/src/videowidget.h @@ -32,13 +32,17 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef VIDEOWIDGET_H #define VIDEOWIDGET_H #include "videosurface.h" -#include +#include #include class VideoWidget : public QWidget diff --git a/src/xml.cpp b/src/xml.cpp index 59849c2..0c00ba5 100755 --- a/src/xml.cpp +++ b/src/xml.cpp @@ -205,3 +205,6 @@ void Xml::actionClose() { this->parentWidget()->close(); } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(Xml) +#endif diff --git a/src/xml.h b/src/xml.h index eed6ce0..d375132 100755 --- a/src/xml.h +++ b/src/xml.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef XML_H #define XML_H diff --git a/src/xmlpatterns.cpp b/src/xmlpatterns.cpp index 3de5643..1d28568 100755 --- a/src/xmlpatterns.cpp +++ b/src/xmlpatterns.cpp @@ -123,3 +123,6 @@ void XmlPatterns::evaluate(const QString &str) this->findChild("outputTextEdit")->setPlainText(QString::fromUtf8(outArray.constData())); } +#ifdef W_OBJECT_IMPL +W_OBJECT_IMPL(XmlPatterns) +#endif diff --git a/src/xmlpatterns.h b/src/xmlpatterns.h index 4ee7daf..d33dd51 100755 --- a/src/xmlpatterns.h +++ b/src/xmlpatterns.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef XMLPATTERNS_H #define XMLPATTERNS_H diff --git a/src/xmlsyntaxhighlighter.h b/src/xmlsyntaxhighlighter.h index adbe1cc..784f3d1 100755 --- a/src/xmlsyntaxhighlighter.h +++ b/src/xmlsyntaxhighlighter.h @@ -32,6 +32,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ +#include "cs_abstraction.h" +#if 0 +struct dummy { Q_OBJECT }; /* (for qmake) */ +#endif #ifndef XMLSYNTAXHIGHLIGHTER_H #define XMLSYNTAXHIGHLIGHTER_H verdigris-1.3/benchmarks/benchmarks.pro000066400000000000000000000000501427643277200203400ustar00rootroot00000000000000TEMPLATE = subdirs SUBDIRS += qobject verdigris-1.3/benchmarks/benchmarks.qbs000066400000000000000000000001441427643277200203310ustar00rootroot00000000000000import qbs Project { name: "benchmarks" references: [ "qobject", ] } verdigris-1.3/benchmarks/compile/000077500000000000000000000000001427643277200171365ustar00rootroot00000000000000verdigris-1.3/benchmarks/compile/compile.cpp000066400000000000000000001070251427643277200212770ustar00rootroot00000000000000/* This can be compiled with CopperSpice, Verdigris, or moc depending of the option passed */ #ifdef USE_VERDIGRIS #include #define CS_OBJECT(X) W_OBJECT(X) #define CS_OBJECT_MULTIPLE(X,XX) W_OBJECT(X) #define CS_SLOT_1(XX,...) __VA_ARGS__; #define CS_SLOT_2(X) W_SLOT(X) #define CS_SIGNAL_1(XX,...) __VA_ARGS__ #define CS_SIGNAL_2(...) W_SIGNAL(__VA_ARGS__) #define CS_INTERFACES(XX) Q_INTERFACES(XX) #elif defined(USE_QT) #define CS_OBJECT(X) Q_OBJECT #define CS_OBJECT_MULTIPLE(X,XX) Q_OBJECT #define CS_SLOT_1(XX,...) Q_SLOT __VA_ARGS__; #define CS_SLOT_2(...) #define CS_SIGNAL_1(XX,...) Q_SIGNAL __VA_ARGS__; #define CS_SIGNAL_2(...) #define CS_INTERFACES(XX) Q_INTERFACES(XX) #endif #ifndef W_OBJECT_IMPL #define W_OBJECT_IMPL(XXX) #endif #include class Object1 : public QObject { CS_OBJECT(Object1) public: CS_SLOT_1(Public, void slot0001(int)) CS_SLOT_2(slot0001) CS_SLOT_1(Public, void slot0002(int)) CS_SLOT_2(slot0002) CS_SLOT_1(Public, void slot0003(int)) CS_SLOT_2(slot0003) CS_SLOT_1(Public, void slot0004(int)) CS_SLOT_2(slot0004) CS_SLOT_1(Public, void slot0005(int)) CS_SLOT_2(slot0005) CS_SLOT_1(Public, void slot0006(int)) CS_SLOT_2(slot0006) CS_SLOT_1(Public, void slot0007(int)) CS_SLOT_2(slot0007) CS_SLOT_1(Public, void slot0008(int)) CS_SLOT_2(slot0008) CS_SLOT_1(Public, void slot0009(int)) CS_SLOT_2(slot0009) CS_SLOT_1(Public, void slot0010(int)) CS_SLOT_2(slot0010) CS_SLOT_1(Public, void slot0011(int)) CS_SLOT_2(slot0011) CS_SLOT_1(Public, void slot0012(int)) CS_SLOT_2(slot0012) CS_SLOT_1(Public, void slot0013(int)) CS_SLOT_2(slot0013) CS_SLOT_1(Public, void slot0014(int)) CS_SLOT_2(slot0014) CS_SLOT_1(Public, void slot0015(int)) CS_SLOT_2(slot0015) CS_SLOT_1(Public, void slot0016(int)) CS_SLOT_2(slot0016) CS_SLOT_1(Public, void slot0017(int)) CS_SLOT_2(slot0017) CS_SLOT_1(Public, void slot0018(int)) CS_SLOT_2(slot0018) CS_SLOT_1(Public, void slot0019(int)) CS_SLOT_2(slot0019) CS_SIGNAL_1(Public, void signal0001(int arg)) CS_SIGNAL_2(signal0001, arg) CS_SIGNAL_1(Public, void signal0002(int arg)) CS_SIGNAL_2(signal0002, arg) CS_SIGNAL_1(Public, void signal0003(int arg)) CS_SIGNAL_2(signal0003, arg) CS_SIGNAL_1(Public, void signal0004(int arg)) CS_SIGNAL_2(signal0004, arg) CS_SIGNAL_1(Public, void signal0005(int arg)) CS_SIGNAL_2(signal0005, arg) CS_SIGNAL_1(Public, void signal0006(int arg)) CS_SIGNAL_2(signal0006, arg) CS_SIGNAL_1(Public, void signal0007(int arg)) CS_SIGNAL_2(signal0007, arg) CS_SIGNAL_1(Public, void signal0008(int arg)) CS_SIGNAL_2(signal0008, arg) CS_SIGNAL_1(Public, void signal0009(int arg)) CS_SIGNAL_2(signal0009, arg) CS_SIGNAL_1(Public, void signal0010(int arg)) CS_SIGNAL_2(signal0010, arg) CS_SIGNAL_1(Public, void signal0011(int arg)) CS_SIGNAL_2(signal0011, arg) CS_SIGNAL_1(Public, void signal0012(int arg)) CS_SIGNAL_2(signal0012, arg) CS_SIGNAL_1(Public, void signal0013(int arg)) CS_SIGNAL_2(signal0013, arg) CS_SIGNAL_1(Public, void signal0014(int arg)) CS_SIGNAL_2(signal0014, arg) CS_SIGNAL_1(Public, void signal0015(int arg)) CS_SIGNAL_2(signal0015, arg) CS_SIGNAL_1(Public, void signal0016(int arg)) CS_SIGNAL_2(signal0016, arg) CS_SIGNAL_1(Public, void signal0017(int arg)) CS_SIGNAL_2(signal0017, arg) CS_SIGNAL_1(Public, void signal0018(int arg)) CS_SIGNAL_2(signal0018, arg) CS_SIGNAL_1(Public, void signal0019(int arg)) CS_SIGNAL_2(signal0019, arg) }; W_OBJECT_IMPL(Object1) class Object2 : public QObject { CS_OBJECT(Object2) public: CS_SLOT_1(Public, void slot0001(int)) CS_SLOT_2(slot0001) CS_SLOT_1(Public, void slot0002(int)) CS_SLOT_2(slot0002) CS_SLOT_1(Public, void slot0003(int)) CS_SLOT_2(slot0003) CS_SLOT_1(Public, void slot0004(int)) CS_SLOT_2(slot0004) CS_SLOT_1(Public, void slot0005(int)) CS_SLOT_2(slot0005) CS_SLOT_1(Public, void slot0006(int)) CS_SLOT_2(slot0006) CS_SLOT_1(Public, void slot0007(int)) CS_SLOT_2(slot0007) CS_SLOT_1(Public, void slot0008(int)) CS_SLOT_2(slot0008) CS_SLOT_1(Public, void slot0009(int)) CS_SLOT_2(slot0009) CS_SLOT_1(Public, void slot0010(int)) CS_SLOT_2(slot0010) CS_SLOT_1(Public, void slot0011(int)) CS_SLOT_2(slot0011) CS_SLOT_1(Public, void slot0012(int)) CS_SLOT_2(slot0012) CS_SLOT_1(Public, void slot0013(int)) CS_SLOT_2(slot0013) CS_SLOT_1(Public, void slot0014(int)) CS_SLOT_2(slot0014) CS_SLOT_1(Public, void slot0015(int)) CS_SLOT_2(slot0015) CS_SLOT_1(Public, void slot0016(int)) CS_SLOT_2(slot0016) CS_SLOT_1(Public, void slot0017(int)) CS_SLOT_2(slot0017) CS_SLOT_1(Public, void slot0018(int)) CS_SLOT_2(slot0018) CS_SLOT_1(Public, void slot0019(int)) CS_SLOT_2(slot0019) CS_SIGNAL_1(Public, void signal0001(int arg)) CS_SIGNAL_2(signal0001, arg) CS_SIGNAL_1(Public, void signal0002(int arg)) CS_SIGNAL_2(signal0002, arg) CS_SIGNAL_1(Public, void signal0003(int arg)) CS_SIGNAL_2(signal0003, arg) CS_SIGNAL_1(Public, void signal0004(int arg)) CS_SIGNAL_2(signal0004, arg) CS_SIGNAL_1(Public, void signal0005(int arg)) CS_SIGNAL_2(signal0005, arg) CS_SIGNAL_1(Public, void signal0006(int arg)) CS_SIGNAL_2(signal0006, arg) CS_SIGNAL_1(Public, void signal0007(int arg)) CS_SIGNAL_2(signal0007, arg) CS_SIGNAL_1(Public, void signal0008(int arg)) CS_SIGNAL_2(signal0008, arg) CS_SIGNAL_1(Public, void signal0009(int arg)) CS_SIGNAL_2(signal0009, arg) CS_SIGNAL_1(Public, void signal0010(int arg)) CS_SIGNAL_2(signal0010, arg) CS_SIGNAL_1(Public, void signal0011(int arg)) CS_SIGNAL_2(signal0011, arg) CS_SIGNAL_1(Public, void signal0012(int arg)) CS_SIGNAL_2(signal0012, arg) CS_SIGNAL_1(Public, void signal0013(int arg)) CS_SIGNAL_2(signal0013, arg) CS_SIGNAL_1(Public, void signal0014(int arg)) CS_SIGNAL_2(signal0014, arg) CS_SIGNAL_1(Public, void signal0015(int arg)) CS_SIGNAL_2(signal0015, arg) CS_SIGNAL_1(Public, void signal0016(int arg)) CS_SIGNAL_2(signal0016, arg) CS_SIGNAL_1(Public, void signal0017(int arg)) CS_SIGNAL_2(signal0017, arg) CS_SIGNAL_1(Public, void signal0018(int arg)) CS_SIGNAL_2(signal0018, arg) CS_SIGNAL_1(Public, void signal0019(int arg)) CS_SIGNAL_2(signal0019, arg) }; W_OBJECT_IMPL(Object2) class Object3 : public QObject { CS_OBJECT(Object3) public: CS_SLOT_1(Public, void slot0001(int)) CS_SLOT_2(slot0001) CS_SLOT_1(Public, void slot0002(int)) CS_SLOT_2(slot0002) CS_SLOT_1(Public, void slot0003(int)) CS_SLOT_2(slot0003) CS_SLOT_1(Public, void slot0004(int)) CS_SLOT_2(slot0004) CS_SLOT_1(Public, void slot0005(int)) CS_SLOT_2(slot0005) CS_SLOT_1(Public, void slot0006(int)) CS_SLOT_2(slot0006) CS_SLOT_1(Public, void slot0007(int)) CS_SLOT_2(slot0007) CS_SLOT_1(Public, void slot0008(int)) CS_SLOT_2(slot0008) CS_SLOT_1(Public, void slot0009(int)) CS_SLOT_2(slot0009) CS_SLOT_1(Public, void slot0010(int)) CS_SLOT_2(slot0010) CS_SLOT_1(Public, void slot0011(int)) CS_SLOT_2(slot0011) CS_SLOT_1(Public, void slot0012(int)) CS_SLOT_2(slot0012) CS_SLOT_1(Public, void slot0013(int)) CS_SLOT_2(slot0013) CS_SLOT_1(Public, void slot0014(int)) CS_SLOT_2(slot0014) CS_SLOT_1(Public, void slot0015(int)) CS_SLOT_2(slot0015) CS_SLOT_1(Public, void slot0016(int)) CS_SLOT_2(slot0016) CS_SLOT_1(Public, void slot0017(int)) CS_SLOT_2(slot0017) CS_SLOT_1(Public, void slot0018(int)) CS_SLOT_2(slot0018) CS_SLOT_1(Public, void slot0019(int)) CS_SLOT_2(slot0019) CS_SIGNAL_1(Public, void signal0001(int arg)) CS_SIGNAL_2(signal0001, arg) CS_SIGNAL_1(Public, void signal0002(int arg)) CS_SIGNAL_2(signal0002, arg) CS_SIGNAL_1(Public, void signal0003(int arg)) CS_SIGNAL_2(signal0003, arg) CS_SIGNAL_1(Public, void signal0004(int arg)) CS_SIGNAL_2(signal0004, arg) CS_SIGNAL_1(Public, void signal0005(int arg)) CS_SIGNAL_2(signal0005, arg) CS_SIGNAL_1(Public, void signal0006(int arg)) CS_SIGNAL_2(signal0006, arg) CS_SIGNAL_1(Public, void signal0007(int arg)) CS_SIGNAL_2(signal0007, arg) CS_SIGNAL_1(Public, void signal0008(int arg)) CS_SIGNAL_2(signal0008, arg) CS_SIGNAL_1(Public, void signal0009(int arg)) CS_SIGNAL_2(signal0009, arg) CS_SIGNAL_1(Public, void signal0010(int arg)) CS_SIGNAL_2(signal0010, arg) CS_SIGNAL_1(Public, void signal0011(int arg)) CS_SIGNAL_2(signal0011, arg) CS_SIGNAL_1(Public, void signal0012(int arg)) CS_SIGNAL_2(signal0012, arg) CS_SIGNAL_1(Public, void signal0013(int arg)) CS_SIGNAL_2(signal0013, arg) CS_SIGNAL_1(Public, void signal0014(int arg)) CS_SIGNAL_2(signal0014, arg) CS_SIGNAL_1(Public, void signal0015(int arg)) CS_SIGNAL_2(signal0015, arg) CS_SIGNAL_1(Public, void signal0016(int arg)) CS_SIGNAL_2(signal0016, arg) CS_SIGNAL_1(Public, void signal0017(int arg)) CS_SIGNAL_2(signal0017, arg) CS_SIGNAL_1(Public, void signal0018(int arg)) CS_SIGNAL_2(signal0018, arg) CS_SIGNAL_1(Public, void signal0019(int arg)) CS_SIGNAL_2(signal0019, arg) }; W_OBJECT_IMPL(Object3) class Object4 : public QObject { CS_OBJECT(Object4) public: CS_SLOT_1(Public, void slot0001(int)) CS_SLOT_2(slot0001) CS_SLOT_1(Public, void slot0002(int)) CS_SLOT_2(slot0002) CS_SLOT_1(Public, void slot0003(int)) CS_SLOT_2(slot0003) CS_SLOT_1(Public, void slot0004(int)) CS_SLOT_2(slot0004) CS_SLOT_1(Public, void slot0005(int)) CS_SLOT_2(slot0005) CS_SLOT_1(Public, void slot0006(int)) CS_SLOT_2(slot0006) CS_SLOT_1(Public, void slot0007(int)) CS_SLOT_2(slot0007) CS_SLOT_1(Public, void slot0008(int)) CS_SLOT_2(slot0008) CS_SLOT_1(Public, void slot0009(int)) CS_SLOT_2(slot0009) CS_SLOT_1(Public, void slot0010(int)) CS_SLOT_2(slot0010) CS_SLOT_1(Public, void slot0011(int)) CS_SLOT_2(slot0011) CS_SLOT_1(Public, void slot0012(int)) CS_SLOT_2(slot0012) CS_SLOT_1(Public, void slot0013(int)) CS_SLOT_2(slot0013) CS_SLOT_1(Public, void slot0014(int)) CS_SLOT_2(slot0014) CS_SLOT_1(Public, void slot0015(int)) CS_SLOT_2(slot0015) CS_SLOT_1(Public, void slot0016(int)) CS_SLOT_2(slot0016) CS_SLOT_1(Public, void slot0017(int)) CS_SLOT_2(slot0017) CS_SLOT_1(Public, void slot0018(int)) CS_SLOT_2(slot0018) CS_SLOT_1(Public, void slot0019(int)) CS_SLOT_2(slot0019) CS_SIGNAL_1(Public, void signal0001(int arg)) CS_SIGNAL_2(signal0001, arg) CS_SIGNAL_1(Public, void signal0002(int arg)) CS_SIGNAL_2(signal0002, arg) CS_SIGNAL_1(Public, void signal0003(int arg)) CS_SIGNAL_2(signal0003, arg) CS_SIGNAL_1(Public, void signal0004(int arg)) CS_SIGNAL_2(signal0004, arg) CS_SIGNAL_1(Public, void signal0005(int arg)) CS_SIGNAL_2(signal0005, arg) CS_SIGNAL_1(Public, void signal0006(int arg)) CS_SIGNAL_2(signal0006, arg) CS_SIGNAL_1(Public, void signal0007(int arg)) CS_SIGNAL_2(signal0007, arg) CS_SIGNAL_1(Public, void signal0008(int arg)) CS_SIGNAL_2(signal0008, arg) CS_SIGNAL_1(Public, void signal0009(int arg)) CS_SIGNAL_2(signal0009, arg) CS_SIGNAL_1(Public, void signal0010(int arg)) CS_SIGNAL_2(signal0010, arg) CS_SIGNAL_1(Public, void signal0011(int arg)) CS_SIGNAL_2(signal0011, arg) CS_SIGNAL_1(Public, void signal0012(int arg)) CS_SIGNAL_2(signal0012, arg) CS_SIGNAL_1(Public, void signal0013(int arg)) CS_SIGNAL_2(signal0013, arg) CS_SIGNAL_1(Public, void signal0014(int arg)) CS_SIGNAL_2(signal0014, arg) CS_SIGNAL_1(Public, void signal0015(int arg)) CS_SIGNAL_2(signal0015, arg) CS_SIGNAL_1(Public, void signal0016(int arg)) CS_SIGNAL_2(signal0016, arg) CS_SIGNAL_1(Public, void signal0017(int arg)) CS_SIGNAL_2(signal0017, arg) CS_SIGNAL_1(Public, void signal0018(int arg)) CS_SIGNAL_2(signal0018, arg) CS_SIGNAL_1(Public, void signal0019(int arg)) CS_SIGNAL_2(signal0019, arg) }; W_OBJECT_IMPL(Object4) class Object5 : public QObject { CS_OBJECT(Object5) public: CS_SLOT_1(Public, void slot0001(int)) CS_SLOT_2(slot0001) CS_SLOT_1(Public, void slot0002(int)) CS_SLOT_2(slot0002) CS_SLOT_1(Public, void slot0003(int)) CS_SLOT_2(slot0003) CS_SLOT_1(Public, void slot0004(int)) CS_SLOT_2(slot0004) CS_SLOT_1(Public, void slot0005(int)) CS_SLOT_2(slot0005) CS_SLOT_1(Public, void slot0006(int)) CS_SLOT_2(slot0006) CS_SLOT_1(Public, void slot0007(int)) CS_SLOT_2(slot0007) CS_SLOT_1(Public, void slot0008(int)) CS_SLOT_2(slot0008) CS_SLOT_1(Public, void slot0009(int)) CS_SLOT_2(slot0009) CS_SLOT_1(Public, void slot0010(int)) CS_SLOT_2(slot0010) CS_SLOT_1(Public, void slot0011(int)) CS_SLOT_2(slot0011) CS_SLOT_1(Public, void slot0012(int)) CS_SLOT_2(slot0012) CS_SLOT_1(Public, void slot0013(int)) CS_SLOT_2(slot0013) CS_SLOT_1(Public, void slot0014(int)) CS_SLOT_2(slot0014) CS_SLOT_1(Public, void slot0015(int)) CS_SLOT_2(slot0015) CS_SLOT_1(Public, void slot0016(int)) CS_SLOT_2(slot0016) CS_SLOT_1(Public, void slot0017(int)) CS_SLOT_2(slot0017) CS_SLOT_1(Public, void slot0018(int)) CS_SLOT_2(slot0018) CS_SLOT_1(Public, void slot0019(int)) CS_SLOT_2(slot0019) CS_SIGNAL_1(Public, void signal0001(int arg)) CS_SIGNAL_2(signal0001, arg) CS_SIGNAL_1(Public, void signal0002(int arg)) CS_SIGNAL_2(signal0002, arg) CS_SIGNAL_1(Public, void signal0003(int arg)) CS_SIGNAL_2(signal0003, arg) CS_SIGNAL_1(Public, void signal0004(int arg)) CS_SIGNAL_2(signal0004, arg) CS_SIGNAL_1(Public, void signal0005(int arg)) CS_SIGNAL_2(signal0005, arg) CS_SIGNAL_1(Public, void signal0006(int arg)) CS_SIGNAL_2(signal0006, arg) CS_SIGNAL_1(Public, void signal0007(int arg)) CS_SIGNAL_2(signal0007, arg) CS_SIGNAL_1(Public, void signal0008(int arg)) CS_SIGNAL_2(signal0008, arg) CS_SIGNAL_1(Public, void signal0009(int arg)) CS_SIGNAL_2(signal0009, arg) CS_SIGNAL_1(Public, void signal0010(int arg)) CS_SIGNAL_2(signal0010, arg) CS_SIGNAL_1(Public, void signal0011(int arg)) CS_SIGNAL_2(signal0011, arg) CS_SIGNAL_1(Public, void signal0012(int arg)) CS_SIGNAL_2(signal0012, arg) CS_SIGNAL_1(Public, void signal0013(int arg)) CS_SIGNAL_2(signal0013, arg) CS_SIGNAL_1(Public, void signal0014(int arg)) CS_SIGNAL_2(signal0014, arg) CS_SIGNAL_1(Public, void signal0015(int arg)) CS_SIGNAL_2(signal0015, arg) CS_SIGNAL_1(Public, void signal0016(int arg)) CS_SIGNAL_2(signal0016, arg) CS_SIGNAL_1(Public, void signal0017(int arg)) CS_SIGNAL_2(signal0017, arg) CS_SIGNAL_1(Public, void signal0018(int arg)) CS_SIGNAL_2(signal0018, arg) CS_SIGNAL_1(Public, void signal0019(int arg)) CS_SIGNAL_2(signal0019, arg) }; W_OBJECT_IMPL(Object5) class Object6 : public QObject { CS_OBJECT(Object6) public: CS_SLOT_1(Public, void slot0001(int)) CS_SLOT_2(slot0001) CS_SLOT_1(Public, void slot0002(int)) CS_SLOT_2(slot0002) CS_SLOT_1(Public, void slot0003(int)) CS_SLOT_2(slot0003) CS_SLOT_1(Public, void slot0004(int)) CS_SLOT_2(slot0004) CS_SLOT_1(Public, void slot0005(int)) CS_SLOT_2(slot0005) CS_SLOT_1(Public, void slot0006(int)) CS_SLOT_2(slot0006) CS_SLOT_1(Public, void slot0007(int)) CS_SLOT_2(slot0007) CS_SLOT_1(Public, void slot0008(int)) CS_SLOT_2(slot0008) CS_SLOT_1(Public, void slot0009(int)) CS_SLOT_2(slot0009) CS_SLOT_1(Public, void slot0010(int)) CS_SLOT_2(slot0010) CS_SLOT_1(Public, void slot0011(int)) CS_SLOT_2(slot0011) CS_SLOT_1(Public, void slot0012(int)) CS_SLOT_2(slot0012) CS_SLOT_1(Public, void slot0013(int)) CS_SLOT_2(slot0013) CS_SLOT_1(Public, void slot0014(int)) CS_SLOT_2(slot0014) CS_SLOT_1(Public, void slot0015(int)) CS_SLOT_2(slot0015) CS_SLOT_1(Public, void slot0016(int)) CS_SLOT_2(slot0016) CS_SLOT_1(Public, void slot0017(int)) CS_SLOT_2(slot0017) CS_SLOT_1(Public, void slot0018(int)) CS_SLOT_2(slot0018) CS_SLOT_1(Public, void slot0019(int)) CS_SLOT_2(slot0019) CS_SIGNAL_1(Public, void signal0001(int arg)) CS_SIGNAL_2(signal0001, arg) CS_SIGNAL_1(Public, void signal0002(int arg)) CS_SIGNAL_2(signal0002, arg) CS_SIGNAL_1(Public, void signal0003(int arg)) CS_SIGNAL_2(signal0003, arg) CS_SIGNAL_1(Public, void signal0004(int arg)) CS_SIGNAL_2(signal0004, arg) CS_SIGNAL_1(Public, void signal0005(int arg)) CS_SIGNAL_2(signal0005, arg) CS_SIGNAL_1(Public, void signal0006(int arg)) CS_SIGNAL_2(signal0006, arg) CS_SIGNAL_1(Public, void signal0007(int arg)) CS_SIGNAL_2(signal0007, arg) CS_SIGNAL_1(Public, void signal0008(int arg)) CS_SIGNAL_2(signal0008, arg) CS_SIGNAL_1(Public, void signal0009(int arg)) CS_SIGNAL_2(signal0009, arg) CS_SIGNAL_1(Public, void signal0010(int arg)) CS_SIGNAL_2(signal0010, arg) CS_SIGNAL_1(Public, void signal0011(int arg)) CS_SIGNAL_2(signal0011, arg) CS_SIGNAL_1(Public, void signal0012(int arg)) CS_SIGNAL_2(signal0012, arg) CS_SIGNAL_1(Public, void signal0013(int arg)) CS_SIGNAL_2(signal0013, arg) CS_SIGNAL_1(Public, void signal0014(int arg)) CS_SIGNAL_2(signal0014, arg) CS_SIGNAL_1(Public, void signal0015(int arg)) CS_SIGNAL_2(signal0015, arg) CS_SIGNAL_1(Public, void signal0016(int arg)) CS_SIGNAL_2(signal0016, arg) CS_SIGNAL_1(Public, void signal0017(int arg)) CS_SIGNAL_2(signal0017, arg) CS_SIGNAL_1(Public, void signal0018(int arg)) CS_SIGNAL_2(signal0018, arg) CS_SIGNAL_1(Public, void signal0019(int arg)) CS_SIGNAL_2(signal0019, arg) }; W_OBJECT_IMPL(Object6) class Object7 : public QObject { CS_OBJECT(Object7) public: CS_SLOT_1(Public, void slot0001(int)) CS_SLOT_2(slot0001) CS_SLOT_1(Public, void slot0002(int)) CS_SLOT_2(slot0002) CS_SLOT_1(Public, void slot0003(int)) CS_SLOT_2(slot0003) CS_SLOT_1(Public, void slot0004(int)) CS_SLOT_2(slot0004) CS_SLOT_1(Public, void slot0005(int)) CS_SLOT_2(slot0005) CS_SLOT_1(Public, void slot0006(int)) CS_SLOT_2(slot0006) CS_SLOT_1(Public, void slot0007(int)) CS_SLOT_2(slot0007) CS_SLOT_1(Public, void slot0008(int)) CS_SLOT_2(slot0008) CS_SLOT_1(Public, void slot0009(int)) CS_SLOT_2(slot0009) CS_SLOT_1(Public, void slot0010(int)) CS_SLOT_2(slot0010) CS_SLOT_1(Public, void slot0011(int)) CS_SLOT_2(slot0011) CS_SLOT_1(Public, void slot0012(int)) CS_SLOT_2(slot0012) CS_SLOT_1(Public, void slot0013(int)) CS_SLOT_2(slot0013) CS_SLOT_1(Public, void slot0014(int)) CS_SLOT_2(slot0014) CS_SLOT_1(Public, void slot0015(int)) CS_SLOT_2(slot0015) CS_SLOT_1(Public, void slot0016(int)) CS_SLOT_2(slot0016) CS_SLOT_1(Public, void slot0017(int)) CS_SLOT_2(slot0017) CS_SLOT_1(Public, void slot0018(int)) CS_SLOT_2(slot0018) CS_SLOT_1(Public, void slot0019(int)) CS_SLOT_2(slot0019) CS_SIGNAL_1(Public, void signal0001(int arg)) CS_SIGNAL_2(signal0001, arg) CS_SIGNAL_1(Public, void signal0002(int arg)) CS_SIGNAL_2(signal0002, arg) CS_SIGNAL_1(Public, void signal0003(int arg)) CS_SIGNAL_2(signal0003, arg) CS_SIGNAL_1(Public, void signal0004(int arg)) CS_SIGNAL_2(signal0004, arg) CS_SIGNAL_1(Public, void signal0005(int arg)) CS_SIGNAL_2(signal0005, arg) CS_SIGNAL_1(Public, void signal0006(int arg)) CS_SIGNAL_2(signal0006, arg) CS_SIGNAL_1(Public, void signal0007(int arg)) CS_SIGNAL_2(signal0007, arg) CS_SIGNAL_1(Public, void signal0008(int arg)) CS_SIGNAL_2(signal0008, arg) CS_SIGNAL_1(Public, void signal0009(int arg)) CS_SIGNAL_2(signal0009, arg) CS_SIGNAL_1(Public, void signal0010(int arg)) CS_SIGNAL_2(signal0010, arg) CS_SIGNAL_1(Public, void signal0011(int arg)) CS_SIGNAL_2(signal0011, arg) CS_SIGNAL_1(Public, void signal0012(int arg)) CS_SIGNAL_2(signal0012, arg) CS_SIGNAL_1(Public, void signal0013(int arg)) CS_SIGNAL_2(signal0013, arg) CS_SIGNAL_1(Public, void signal0014(int arg)) CS_SIGNAL_2(signal0014, arg) CS_SIGNAL_1(Public, void signal0015(int arg)) CS_SIGNAL_2(signal0015, arg) CS_SIGNAL_1(Public, void signal0016(int arg)) CS_SIGNAL_2(signal0016, arg) CS_SIGNAL_1(Public, void signal0017(int arg)) CS_SIGNAL_2(signal0017, arg) CS_SIGNAL_1(Public, void signal0018(int arg)) CS_SIGNAL_2(signal0018, arg) CS_SIGNAL_1(Public, void signal0019(int arg)) CS_SIGNAL_2(signal0019, arg) }; W_OBJECT_IMPL(Object7) class Object8 : public QObject { CS_OBJECT(Object8) public: CS_SLOT_1(Public, void slot0001(int)) CS_SLOT_2(slot0001) CS_SLOT_1(Public, void slot0002(int)) CS_SLOT_2(slot0002) CS_SLOT_1(Public, void slot0003(int)) CS_SLOT_2(slot0003) CS_SLOT_1(Public, void slot0004(int)) CS_SLOT_2(slot0004) CS_SLOT_1(Public, void slot0005(int)) CS_SLOT_2(slot0005) CS_SLOT_1(Public, void slot0006(int)) CS_SLOT_2(slot0006) CS_SLOT_1(Public, void slot0007(int)) CS_SLOT_2(slot0007) CS_SLOT_1(Public, void slot0008(int)) CS_SLOT_2(slot0008) CS_SLOT_1(Public, void slot0009(int)) CS_SLOT_2(slot0009) CS_SLOT_1(Public, void slot0010(int)) CS_SLOT_2(slot0010) CS_SLOT_1(Public, void slot0011(int)) CS_SLOT_2(slot0011) CS_SLOT_1(Public, void slot0012(int)) CS_SLOT_2(slot0012) CS_SLOT_1(Public, void slot0013(int)) CS_SLOT_2(slot0013) CS_SLOT_1(Public, void slot0014(int)) CS_SLOT_2(slot0014) CS_SLOT_1(Public, void slot0015(int)) CS_SLOT_2(slot0015) CS_SLOT_1(Public, void slot0016(int)) CS_SLOT_2(slot0016) CS_SLOT_1(Public, void slot0017(int)) CS_SLOT_2(slot0017) CS_SLOT_1(Public, void slot0018(int)) CS_SLOT_2(slot0018) CS_SLOT_1(Public, void slot0019(int)) CS_SLOT_2(slot0019) CS_SIGNAL_1(Public, void signal0001(int arg)) CS_SIGNAL_2(signal0001, arg) CS_SIGNAL_1(Public, void signal0002(int arg)) CS_SIGNAL_2(signal0002, arg) CS_SIGNAL_1(Public, void signal0003(int arg)) CS_SIGNAL_2(signal0003, arg) CS_SIGNAL_1(Public, void signal0004(int arg)) CS_SIGNAL_2(signal0004, arg) CS_SIGNAL_1(Public, void signal0005(int arg)) CS_SIGNAL_2(signal0005, arg) CS_SIGNAL_1(Public, void signal0006(int arg)) CS_SIGNAL_2(signal0006, arg) CS_SIGNAL_1(Public, void signal0007(int arg)) CS_SIGNAL_2(signal0007, arg) CS_SIGNAL_1(Public, void signal0008(int arg)) CS_SIGNAL_2(signal0008, arg) CS_SIGNAL_1(Public, void signal0009(int arg)) CS_SIGNAL_2(signal0009, arg) CS_SIGNAL_1(Public, void signal0010(int arg)) CS_SIGNAL_2(signal0010, arg) CS_SIGNAL_1(Public, void signal0011(int arg)) CS_SIGNAL_2(signal0011, arg) CS_SIGNAL_1(Public, void signal0012(int arg)) CS_SIGNAL_2(signal0012, arg) CS_SIGNAL_1(Public, void signal0013(int arg)) CS_SIGNAL_2(signal0013, arg) CS_SIGNAL_1(Public, void signal0014(int arg)) CS_SIGNAL_2(signal0014, arg) CS_SIGNAL_1(Public, void signal0015(int arg)) CS_SIGNAL_2(signal0015, arg) CS_SIGNAL_1(Public, void signal0016(int arg)) CS_SIGNAL_2(signal0016, arg) CS_SIGNAL_1(Public, void signal0017(int arg)) CS_SIGNAL_2(signal0017, arg) CS_SIGNAL_1(Public, void signal0018(int arg)) CS_SIGNAL_2(signal0018, arg) CS_SIGNAL_1(Public, void signal0019(int arg)) CS_SIGNAL_2(signal0019, arg) }; W_OBJECT_IMPL(Object8) class Object9 : public QObject { CS_OBJECT(Object9) public: CS_SLOT_1(Public, void slot0001(int)) CS_SLOT_2(slot0001) CS_SLOT_1(Public, void slot0002(int)) CS_SLOT_2(slot0002) CS_SLOT_1(Public, void slot0003(int)) CS_SLOT_2(slot0003) CS_SLOT_1(Public, void slot0004(int)) CS_SLOT_2(slot0004) CS_SLOT_1(Public, void slot0005(int)) CS_SLOT_2(slot0005) CS_SLOT_1(Public, void slot0006(int)) CS_SLOT_2(slot0006) CS_SLOT_1(Public, void slot0007(int)) CS_SLOT_2(slot0007) CS_SLOT_1(Public, void slot0008(int)) CS_SLOT_2(slot0008) CS_SLOT_1(Public, void slot0009(int)) CS_SLOT_2(slot0009) CS_SLOT_1(Public, void slot0010(int)) CS_SLOT_2(slot0010) CS_SLOT_1(Public, void slot0011(int)) CS_SLOT_2(slot0011) CS_SLOT_1(Public, void slot0012(int)) CS_SLOT_2(slot0012) CS_SLOT_1(Public, void slot0013(int)) CS_SLOT_2(slot0013) CS_SLOT_1(Public, void slot0014(int)) CS_SLOT_2(slot0014) CS_SLOT_1(Public, void slot0015(int)) CS_SLOT_2(slot0015) CS_SLOT_1(Public, void slot0016(int)) CS_SLOT_2(slot0016) CS_SLOT_1(Public, void slot0017(int)) CS_SLOT_2(slot0017) CS_SLOT_1(Public, void slot0018(int)) CS_SLOT_2(slot0018) CS_SLOT_1(Public, void slot0019(int)) CS_SLOT_2(slot0019) CS_SIGNAL_1(Public, void signal0001(int arg)) CS_SIGNAL_2(signal0001, arg) CS_SIGNAL_1(Public, void signal0002(int arg)) CS_SIGNAL_2(signal0002, arg) CS_SIGNAL_1(Public, void signal0003(int arg)) CS_SIGNAL_2(signal0003, arg) CS_SIGNAL_1(Public, void signal0004(int arg)) CS_SIGNAL_2(signal0004, arg) CS_SIGNAL_1(Public, void signal0005(int arg)) CS_SIGNAL_2(signal0005, arg) CS_SIGNAL_1(Public, void signal0006(int arg)) CS_SIGNAL_2(signal0006, arg) CS_SIGNAL_1(Public, void signal0007(int arg)) CS_SIGNAL_2(signal0007, arg) CS_SIGNAL_1(Public, void signal0008(int arg)) CS_SIGNAL_2(signal0008, arg) CS_SIGNAL_1(Public, void signal0009(int arg)) CS_SIGNAL_2(signal0009, arg) CS_SIGNAL_1(Public, void signal0010(int arg)) CS_SIGNAL_2(signal0010, arg) CS_SIGNAL_1(Public, void signal0011(int arg)) CS_SIGNAL_2(signal0011, arg) CS_SIGNAL_1(Public, void signal0012(int arg)) CS_SIGNAL_2(signal0012, arg) CS_SIGNAL_1(Public, void signal0013(int arg)) CS_SIGNAL_2(signal0013, arg) CS_SIGNAL_1(Public, void signal0014(int arg)) CS_SIGNAL_2(signal0014, arg) CS_SIGNAL_1(Public, void signal0015(int arg)) CS_SIGNAL_2(signal0015, arg) CS_SIGNAL_1(Public, void signal0016(int arg)) CS_SIGNAL_2(signal0016, arg) CS_SIGNAL_1(Public, void signal0017(int arg)) CS_SIGNAL_2(signal0017, arg) CS_SIGNAL_1(Public, void signal0018(int arg)) CS_SIGNAL_2(signal0018, arg) CS_SIGNAL_1(Public, void signal0019(int arg)) CS_SIGNAL_2(signal0019, arg) }; W_OBJECT_IMPL(Object9) class Object10 : public QObject { CS_OBJECT(Object10) public: CS_SLOT_1(Public, void slot0001(int)) CS_SLOT_2(slot0001) CS_SLOT_1(Public, void slot0002(int)) CS_SLOT_2(slot0002) CS_SLOT_1(Public, void slot0003(int)) CS_SLOT_2(slot0003) CS_SLOT_1(Public, void slot0004(int)) CS_SLOT_2(slot0004) CS_SLOT_1(Public, void slot0005(int)) CS_SLOT_2(slot0005) CS_SLOT_1(Public, void slot0006(int)) CS_SLOT_2(slot0006) CS_SLOT_1(Public, void slot0007(int)) CS_SLOT_2(slot0007) CS_SLOT_1(Public, void slot0008(int)) CS_SLOT_2(slot0008) CS_SLOT_1(Public, void slot0009(int)) CS_SLOT_2(slot0009) CS_SLOT_1(Public, void slot0010(int)) CS_SLOT_2(slot0010) CS_SLOT_1(Public, void slot0011(int)) CS_SLOT_2(slot0011) CS_SLOT_1(Public, void slot0012(int)) CS_SLOT_2(slot0012) CS_SLOT_1(Public, void slot0013(int)) CS_SLOT_2(slot0013) CS_SLOT_1(Public, void slot0014(int)) CS_SLOT_2(slot0014) CS_SLOT_1(Public, void slot0015(int)) CS_SLOT_2(slot0015) CS_SLOT_1(Public, void slot0016(int)) CS_SLOT_2(slot0016) CS_SLOT_1(Public, void slot0017(int)) CS_SLOT_2(slot0017) CS_SLOT_1(Public, void slot0018(int)) CS_SLOT_2(slot0018) CS_SLOT_1(Public, void slot0019(int)) CS_SLOT_2(slot0019) CS_SIGNAL_1(Public, void signal0001(int arg)) CS_SIGNAL_2(signal0001, arg) CS_SIGNAL_1(Public, void signal0002(int arg)) CS_SIGNAL_2(signal0002, arg) CS_SIGNAL_1(Public, void signal0003(int arg)) CS_SIGNAL_2(signal0003, arg) CS_SIGNAL_1(Public, void signal0004(int arg)) CS_SIGNAL_2(signal0004, arg) CS_SIGNAL_1(Public, void signal0005(int arg)) CS_SIGNAL_2(signal0005, arg) CS_SIGNAL_1(Public, void signal0006(int arg)) CS_SIGNAL_2(signal0006, arg) CS_SIGNAL_1(Public, void signal0007(int arg)) CS_SIGNAL_2(signal0007, arg) CS_SIGNAL_1(Public, void signal0008(int arg)) CS_SIGNAL_2(signal0008, arg) CS_SIGNAL_1(Public, void signal0009(int arg)) CS_SIGNAL_2(signal0009, arg) CS_SIGNAL_1(Public, void signal0010(int arg)) CS_SIGNAL_2(signal0010, arg) CS_SIGNAL_1(Public, void signal0011(int arg)) CS_SIGNAL_2(signal0011, arg) CS_SIGNAL_1(Public, void signal0012(int arg)) CS_SIGNAL_2(signal0012, arg) CS_SIGNAL_1(Public, void signal0013(int arg)) CS_SIGNAL_2(signal0013, arg) CS_SIGNAL_1(Public, void signal0014(int arg)) CS_SIGNAL_2(signal0014, arg) CS_SIGNAL_1(Public, void signal0015(int arg)) CS_SIGNAL_2(signal0015, arg) CS_SIGNAL_1(Public, void signal0016(int arg)) CS_SIGNAL_2(signal0016, arg) CS_SIGNAL_1(Public, void signal0017(int arg)) CS_SIGNAL_2(signal0017, arg) CS_SIGNAL_1(Public, void signal0018(int arg)) CS_SIGNAL_2(signal0018, arg) CS_SIGNAL_1(Public, void signal0019(int arg)) CS_SIGNAL_2(signal0019, arg) }; W_OBJECT_IMPL(Object10) class Object11 : public QObject { CS_OBJECT(Object11) public: CS_SLOT_1(Public, void slot0001(int)) CS_SLOT_2(slot0001) CS_SLOT_1(Public, void slot0002(int)) CS_SLOT_2(slot0002) CS_SLOT_1(Public, void slot0003(int)) CS_SLOT_2(slot0003) CS_SLOT_1(Public, void slot0004(int)) CS_SLOT_2(slot0004) CS_SLOT_1(Public, void slot0005(int)) CS_SLOT_2(slot0005) CS_SLOT_1(Public, void slot0006(int)) CS_SLOT_2(slot0006) CS_SLOT_1(Public, void slot0007(int)) CS_SLOT_2(slot0007) CS_SLOT_1(Public, void slot0008(int)) CS_SLOT_2(slot0008) CS_SLOT_1(Public, void slot0009(int)) CS_SLOT_2(slot0009) CS_SLOT_1(Public, void slot0010(int)) CS_SLOT_2(slot0010) CS_SLOT_1(Public, void slot0011(int)) CS_SLOT_2(slot0011) CS_SLOT_1(Public, void slot0012(int)) CS_SLOT_2(slot0012) CS_SLOT_1(Public, void slot0013(int)) CS_SLOT_2(slot0013) CS_SLOT_1(Public, void slot0014(int)) CS_SLOT_2(slot0014) CS_SLOT_1(Public, void slot0015(int)) CS_SLOT_2(slot0015) CS_SLOT_1(Public, void slot0016(int)) CS_SLOT_2(slot0016) CS_SLOT_1(Public, void slot0017(int)) CS_SLOT_2(slot0017) CS_SLOT_1(Public, void slot0018(int)) CS_SLOT_2(slot0018) CS_SLOT_1(Public, void slot0019(int)) CS_SLOT_2(slot0019) CS_SIGNAL_1(Public, void signal0001(int arg)) CS_SIGNAL_2(signal0001, arg) CS_SIGNAL_1(Public, void signal0002(int arg)) CS_SIGNAL_2(signal0002, arg) CS_SIGNAL_1(Public, void signal0003(int arg)) CS_SIGNAL_2(signal0003, arg) CS_SIGNAL_1(Public, void signal0004(int arg)) CS_SIGNAL_2(signal0004, arg) CS_SIGNAL_1(Public, void signal0005(int arg)) CS_SIGNAL_2(signal0005, arg) CS_SIGNAL_1(Public, void signal0006(int arg)) CS_SIGNAL_2(signal0006, arg) CS_SIGNAL_1(Public, void signal0007(int arg)) CS_SIGNAL_2(signal0007, arg) CS_SIGNAL_1(Public, void signal0008(int arg)) CS_SIGNAL_2(signal0008, arg) CS_SIGNAL_1(Public, void signal0009(int arg)) CS_SIGNAL_2(signal0009, arg) CS_SIGNAL_1(Public, void signal0010(int arg)) CS_SIGNAL_2(signal0010, arg) CS_SIGNAL_1(Public, void signal0011(int arg)) CS_SIGNAL_2(signal0011, arg) CS_SIGNAL_1(Public, void signal0012(int arg)) CS_SIGNAL_2(signal0012, arg) CS_SIGNAL_1(Public, void signal0013(int arg)) CS_SIGNAL_2(signal0013, arg) CS_SIGNAL_1(Public, void signal0014(int arg)) CS_SIGNAL_2(signal0014, arg) CS_SIGNAL_1(Public, void signal0015(int arg)) CS_SIGNAL_2(signal0015, arg) CS_SIGNAL_1(Public, void signal0016(int arg)) CS_SIGNAL_2(signal0016, arg) CS_SIGNAL_1(Public, void signal0017(int arg)) CS_SIGNAL_2(signal0017, arg) CS_SIGNAL_1(Public, void signal0018(int arg)) CS_SIGNAL_2(signal0018, arg) CS_SIGNAL_1(Public, void signal0019(int arg)) CS_SIGNAL_2(signal0019, arg) }; W_OBJECT_IMPL(Object11) class Object12 : public QObject { CS_OBJECT(Object12) public: CS_SLOT_1(Public, void slot0001(int)) CS_SLOT_2(slot0001) CS_SLOT_1(Public, void slot0002(int)) CS_SLOT_2(slot0002) CS_SLOT_1(Public, void slot0003(int)) CS_SLOT_2(slot0003) CS_SLOT_1(Public, void slot0004(int)) CS_SLOT_2(slot0004) CS_SLOT_1(Public, void slot0005(int)) CS_SLOT_2(slot0005) CS_SLOT_1(Public, void slot0006(int)) CS_SLOT_2(slot0006) CS_SLOT_1(Public, void slot0007(int)) CS_SLOT_2(slot0007) CS_SLOT_1(Public, void slot0008(int)) CS_SLOT_2(slot0008) CS_SLOT_1(Public, void slot0009(int)) CS_SLOT_2(slot0009) CS_SLOT_1(Public, void slot0010(int)) CS_SLOT_2(slot0010) CS_SLOT_1(Public, void slot0011(int)) CS_SLOT_2(slot0011) CS_SLOT_1(Public, void slot0012(int)) CS_SLOT_2(slot0012) CS_SLOT_1(Public, void slot0013(int)) CS_SLOT_2(slot0013) CS_SLOT_1(Public, void slot0014(int)) CS_SLOT_2(slot0014) CS_SLOT_1(Public, void slot0015(int)) CS_SLOT_2(slot0015) CS_SLOT_1(Public, void slot0016(int)) CS_SLOT_2(slot0016) CS_SLOT_1(Public, void slot0017(int)) CS_SLOT_2(slot0017) CS_SLOT_1(Public, void slot0018(int)) CS_SLOT_2(slot0018) CS_SLOT_1(Public, void slot0019(int)) CS_SLOT_2(slot0019) CS_SIGNAL_1(Public, void signal0001(int arg)) CS_SIGNAL_2(signal0001, arg) CS_SIGNAL_1(Public, void signal0002(int arg)) CS_SIGNAL_2(signal0002, arg) CS_SIGNAL_1(Public, void signal0003(int arg)) CS_SIGNAL_2(signal0003, arg) CS_SIGNAL_1(Public, void signal0004(int arg)) CS_SIGNAL_2(signal0004, arg) CS_SIGNAL_1(Public, void signal0005(int arg)) CS_SIGNAL_2(signal0005, arg) CS_SIGNAL_1(Public, void signal0006(int arg)) CS_SIGNAL_2(signal0006, arg) CS_SIGNAL_1(Public, void signal0007(int arg)) CS_SIGNAL_2(signal0007, arg) CS_SIGNAL_1(Public, void signal0008(int arg)) CS_SIGNAL_2(signal0008, arg) CS_SIGNAL_1(Public, void signal0009(int arg)) CS_SIGNAL_2(signal0009, arg) CS_SIGNAL_1(Public, void signal0010(int arg)) CS_SIGNAL_2(signal0010, arg) CS_SIGNAL_1(Public, void signal0011(int arg)) CS_SIGNAL_2(signal0011, arg) CS_SIGNAL_1(Public, void signal0012(int arg)) CS_SIGNAL_2(signal0012, arg) CS_SIGNAL_1(Public, void signal0013(int arg)) CS_SIGNAL_2(signal0013, arg) CS_SIGNAL_1(Public, void signal0014(int arg)) CS_SIGNAL_2(signal0014, arg) CS_SIGNAL_1(Public, void signal0015(int arg)) CS_SIGNAL_2(signal0015, arg) CS_SIGNAL_1(Public, void signal0016(int arg)) CS_SIGNAL_2(signal0016, arg) CS_SIGNAL_1(Public, void signal0017(int arg)) CS_SIGNAL_2(signal0017, arg) CS_SIGNAL_1(Public, void signal0018(int arg)) CS_SIGNAL_2(signal0018, arg) CS_SIGNAL_1(Public, void signal0019(int arg)) CS_SIGNAL_2(signal0019, arg) }; W_OBJECT_IMPL(Object12) #if defined (USE_QT) #include "moc_compile.h" #endif /* $CXX compile.cpp -I $CS_HOME/include -I $CS_HOME/include/QtCore -std=c++14 -O2 -c -o /dev/null $CXX compile.cpp -I/usr/include/qt -I/usr/include/qt/QtCore -std=c++14 -O2 -fPIC -c -o /dev/null -I../../src -DUSE_VERDIGRIS moc compile.cpp -I/use/include/qt -I/usr/include/qt/QtCore -o moc_compile.h -DUSE_QT $CXX compile.cpp -I/usr/include/qt -I/usr/include/qt/QtCore -std=c++14 -O2 -fPIC -c -o /dev/null -DUSE_QT */ verdigris-1.3/benchmarks/qobject/000077500000000000000000000000001427643277200171355ustar00rootroot00000000000000verdigris-1.3/benchmarks/qobject/main.cpp000066400000000000000000000201501427643277200205630ustar00rootroot00000000000000/**************************************************************************** ** ** 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 #include #include "object.h" #include #include enum { CreationDeletionBenckmarkConstant = 34567, SignalsAndSlotsBenchmarkConstant = 456789 }; class QObjectBenchmark : public QObject { Q_OBJECT private slots: void signal_slot_benchmark(); void signal_slot_benchmark_data(); void connect_disconnect_benchmark_data(); void connect_disconnect_benchmark(); }; struct Functor { void operator()(){} }; void QObjectBenchmark::signal_slot_benchmark_data() { QTest::addColumn("type"); QTest::addColumn("w"); QTest::newRow("simple function") << 0 << false; QTest::newRow("single signal/slot") << 1 << false; QTest::newRow("multi signal/slot") << 2 << false; QTest::newRow("unconnected signal") << 3 << false; QTest::newRow("single signal/ptr") << 4 << false; QTest::newRow("functor") << 5 << false; QTest::newRow("w simple function") << 0 << true; QTest::newRow("w single signal/slot") << 1 << true; QTest::newRow("w multi signal/slot") << 2 << true; QTest::newRow("w unconnected signal") << 3 << true; QTest::newRow("w single signal/ptr") << 4 << true; QTest::newRow("w functor") << 5 << true; } template void signal_slot_benchmark() { QFETCH(int, type); Object singleObject; Object multiObject; Functor functor; singleObject.setObjectName("single"); multiObject.setObjectName("multi"); if (type == 5) { QObject::connect(&singleObject, &Object::signal0, functor); } else if (type == 4) { QObject::connect(&singleObject, &Object::signal0, &singleObject, &Object::slot0); } else { singleObject.connect(&singleObject, SIGNAL(signal0()), SLOT(slot0())); } multiObject.connect(&multiObject, SIGNAL(signal0()), SLOT(slot0())); // multiObject.connect(&multiObject, SIGNAL(signal0()), SLOT(signal1())); multiObject.connect(&multiObject, SIGNAL(signal1()), SLOT(slot1())); // multiObject.connect(&multiObject, SIGNAL(signal0()), SLOT(signal2())); multiObject.connect(&multiObject, SIGNAL(signal2()), SLOT(slot2())); // multiObject.connect(&multiObject, SIGNAL(signal0()), SLOT(signal3())); multiObject.connect(&multiObject, SIGNAL(signal3()), SLOT(slot3())); // multiObject.connect(&multiObject, SIGNAL(signal0()), SLOT(signal4())); multiObject.connect(&multiObject, SIGNAL(signal4()), SLOT(slot4())); // multiObject.connect(&multiObject, SIGNAL(signal0()), SLOT(signal5())); multiObject.connect(&multiObject, SIGNAL(signal5()), SLOT(slot5())); // multiObject.connect(&multiObject, SIGNAL(signal0()), SLOT(signal6())); multiObject.connect(&multiObject, SIGNAL(signal6()), SLOT(slot6())); // multiObject.connect(&multiObject, SIGNAL(signal0()), SLOT(signal7())); multiObject.connect(&multiObject, SIGNAL(signal7()), SLOT(slot7())); // multiObject.connect(&multiObject, SIGNAL(signal0()), SLOT(signal8())); multiObject.connect(&multiObject, SIGNAL(signal8()), SLOT(slot8())); // multiObject.connect(&multiObject, SIGNAL(signal0()), SLOT(signal9())); multiObject.connect(&multiObject, SIGNAL(signal9()), SLOT(slot9())); if (type == 0) { QBENCHMARK { singleObject.slot0(); } } else if (type == 1) { QBENCHMARK { singleObject.emitSignal0(); } } else if (type == 2) { QBENCHMARK { multiObject.emitSignal0(); } } else if (type == 3) { QBENCHMARK { singleObject.emitSignal1(); } } else if (type == 4 || type == 5) { QBENCHMARK { singleObject.emitSignal0(); } } } void QObjectBenchmark::signal_slot_benchmark() { QFETCH(bool, w); if (w) ::signal_slot_benchmark(); else ::signal_slot_benchmark(); } void QObjectBenchmark::connect_disconnect_benchmark_data() { QTest::addColumn("type"); QTest::addColumn("w"); QTest::newRow("normalized signature") << 0 << false; QTest::newRow("unormalized signature") << 1 << false; QTest::newRow("function pointer") << 2 << false; QTest::newRow("normalized signature/handle") << 3 << false; QTest::newRow("unormalized signature/handle") << 4 << false; QTest::newRow("function pointer/handle") << 5 << false; QTest::newRow("functor/handle") << 6 << false; QTest::newRow("w normalized signature") << 0 << true; QTest::newRow("w unormalized signature") << 1 << true; QTest::newRow("w function pointer") << 2 << true; QTest::newRow("w normalized signature/handle") << 3 << true; QTest::newRow("w unormalized signature/handle") << 4 << true; QTest::newRow("w function pointer/handle") << 5 << true; QTest::newRow("w functor/handle") << 6 << true; } template void connect_disconnect_benchmark() { QFETCH(int, type); switch (type) { case 0: { Object obj; QBENCHMARK { QObject::connect (&obj, SIGNAL(signal5()), &obj, SLOT(slot5())); QObject::disconnect(&obj, SIGNAL(signal5()), &obj, SLOT(slot5())); } } break; case 1: { Object obj; QBENCHMARK { QObject::connect (&obj, SIGNAL(signal5( )), &obj, SLOT(slot5( ))); // sic: non-normalised QObject::disconnect(&obj, SIGNAL(signal5( )), &obj, SLOT(slot5( ))); // sic: non-normalised } } break; case 2: { Object obj; QBENCHMARK { QObject::connect (&obj, &Object::signal5, &obj, &Object::slot5); QObject::disconnect(&obj, &Object::signal5, &obj, &Object::slot5); } } break; case 3: { Object obj; QBENCHMARK { QObject::disconnect(QObject::connect(&obj, SIGNAL(signal5()), &obj, SLOT(slot5()))); } } break; case 4: { Object obj; QBENCHMARK { QObject::disconnect(QObject::connect(&obj, SIGNAL(signal5( )), &obj, SLOT(slot5( )))); // sic: non-normalised } } break; case 5: { Object obj; QBENCHMARK { QObject::disconnect(QObject::connect(&obj, &Object::signal5, &obj, &Object::slot5)); } } break; case 6: { Object obj; Functor functor; QBENCHMARK { QObject::disconnect(QObject::connect(&obj, &Object::signal5, functor)); } } break; } } void QObjectBenchmark::connect_disconnect_benchmark() { QFETCH(bool, w); if (w) ::connect_disconnect_benchmark(); else ::connect_disconnect_benchmark(); } QTEST_MAIN(QObjectBenchmark) #include "main.moc"verdigris-1.3/benchmarks/qobject/object.cpp000066400000000000000000000037461427643277200211210ustar00rootroot00000000000000/**************************************************************************** ** ** 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 "object.h" void Object::emitSignal0() { emit signal0(); } void Object::emitSignal1() { emit signal1(); } void Object::slot0() { } void Object::slot1() { } void Object::slot2() { } void Object::slot3() { } void Object::slot4() { } void Object::slot5() { } void Object::slot6() { } void Object::slot7() { } void Object::slot8() { } void Object::slot9() { } void ObjectW::emitSignal0() { emit signal0(); } void ObjectW::emitSignal1() { emit signal1(); } void ObjectW::slot0() { } void ObjectW::slot1() { } void ObjectW::slot2() { } void ObjectW::slot3() { } void ObjectW::slot4() { } void ObjectW::slot5() { } void ObjectW::slot6() { } void ObjectW::slot7() { } void ObjectW::slot8() { } void ObjectW::slot9() { } W_OBJECT_IMPL(ObjectW) verdigris-1.3/benchmarks/qobject/object.h000066400000000000000000000052331427643277200205570ustar00rootroot00000000000000/**************************************************************************** ** ** 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$ ** ****************************************************************************/ #ifndef OBJECT_H #define OBJECT_H #include #include "wobjectimpl.h" class Object : public QObject { Q_OBJECT public: void emitSignal0(); void emitSignal1(); signals: void signal0(); void signal1(); void signal2(); void signal3(); void signal4(); void signal5(); void signal6(); void signal7(); void signal8(); void signal9(); public slots: void slot0(); void slot1(); void slot2(); void slot3(); void slot4(); void slot5(); void slot6(); void slot7(); void slot8(); void slot9(); }; class ObjectW : public QObject { W_OBJECT(ObjectW) public: void emitSignal0(); void emitSignal1(); //signals: void signal0() W_SIGNAL(signal0) void signal1() W_SIGNAL(signal1) void signal2() W_SIGNAL(signal2) void signal3() W_SIGNAL(signal3) void signal4() W_SIGNAL(signal4) void signal5() W_SIGNAL(signal5) void signal6() W_SIGNAL(signal6) void signal7() W_SIGNAL(signal7) void signal8() W_SIGNAL(signal8) void signal9() W_SIGNAL(signal9) //public slots: void slot0(); W_SLOT(slot0) void slot1(); W_SLOT(slot1) void slot2(); W_SLOT(slot2) void slot3(); W_SLOT(slot3) void slot4(); W_SLOT(slot4) void slot5(); W_SLOT(slot5) void slot6(); W_SLOT(slot6) void slot7(); W_SLOT(slot7) void slot8(); W_SLOT(slot8) void slot9(); W_SLOT(slot9) }; #endif // OBJECT_H verdigris-1.3/benchmarks/qobject/qobject.pro000066400000000000000000000002231427643277200213030ustar00rootroot00000000000000QT = core testlib TEMPLATE = app TARGET = tst_bench_qobject HEADERS += object.h SOURCES += main.cpp object.cpp include(../../src/verdigris.pri) verdigris-1.3/benchmarks/qobject/qobject.qbs000066400000000000000000000004221427643277200212710ustar00rootroot00000000000000import qbs Application { name: "qobject_bench" consoleApplication: true type: ["application"] Depends { name: "Verdigris" } Depends { name: "Qt.test" } files: [ "main.cpp", "object.cpp", "object.h", ] } verdigris-1.3/benchmarks/startup/000077500000000000000000000000001427643277200172105ustar00rootroot00000000000000verdigris-1.3/benchmarks/startup/main.cpp000066400000000000000000000006371427643277200206460ustar00rootroot00000000000000#include int main() { QObject o; return 1; } /* clang++ main.cpp -I/usr/include/qt4 -I/usr/include/qt4/QtCore -lQtCore -lQtGui -std=c++14 -O2 -o qt4 clang++ main.cpp -I $CS_HOME/include -I $CS_HOME/include/QtCore -L $CS_HOME/lib -lCsCore1 -lCsGui1 -std=c++14 -O2 -o cs clang++ main.cpp -I/usr/include/qt -I/usr/include/qt/QtCore -lQt5Core -lQt5Gui -lQt5Widgets -std=c++14 -O2 -fPIC -o qt5 */ verdigris-1.3/src/000077500000000000000000000000001427643277200141605ustar00rootroot00000000000000verdigris-1.3/src/verdigris.pri000066400000000000000000000000451427643277200166710ustar00rootroot00000000000000INCLUDEPATH += $$PWD CONFIG += c++14 verdigris-1.3/src/wobjectcpp.h000066400000000000000000000300541427643277200164730ustar00rootroot00000000000000#pragma once #include "wobjectdefs.h" namespace w_internal { #if __cplusplus <= 201700L template constexpr bool all() { bool b = true; ordered2({(b = b && Bs)...}); return b; } #endif template, class ParamNames = w_internal::StringViewArray<>> struct MetaMethodInfoBuilder { StringView name; F func; ParamTypes paramTypes{}; ParamNames paramNames{}; static constexpr int flags = Flags; using IntegralConstant = IC; #if __cplusplus > 201700L template, StringView> && ...)>> #else template, StringView>::value...>()>> #endif constexpr auto setParamTypes(Args... paramTypes) const -> MetaMethodInfoBuilder, ParamNames> { return {name, func, {paramTypes...}, paramNames}; } #if __cplusplus > 201700L template, StringView> && ...)>> #else template, StringView>::value...>()>> #endif constexpr auto setParamNames(Args... paramNames) const -> MetaMethodInfoBuilder> { return {name, func, paramTypes, {paramNames...}}; } template constexpr auto addFlags(w_internal::W_MethodFlags...) const #if __cplusplus > 201700L -> MetaMethodInfoBuilder { #else -> MetaMethodInfoBuilder, IC, ParamTypes, ParamNames> { #endif return {name, func, paramTypes, paramNames}; } template constexpr auto setIntegralConstant() const -> MetaMethodInfoBuilder { return {name, func, paramTypes, paramNames}; } constexpr auto build() const -> w_internal::MetaMethodInfo { return {func, name, paramTypes, paramNames}; } }; } // namespace w_internal namespace w_cpp { /// Very simple constexpr version of std::string_view /// /// example usage: /// constexpr char text[6] = "Hello"; // if you have a string literal use `viewLiteral` below. /// constexpr auto view = w_cpp::StringView{&text[0], &text[5]}; /// /// \note the end pointer has to point behind the last character using w_internal::StringView; /// Array of StringView /// /// example usage: /// auto array = w_cpp::StringViewArray<2>{{w_cpp::viewLiteral("Hello"), w_cpp::viewLiteral("World")}}; /// array.data[1] = w_cpp::viewLiteral("World !!!"); using w_internal::StringViewArray; /// Generate a constexpr StringView from a C++ string literal. /// /// example usage: /// constexpr auto view = w_cpp::viewLiteral{"Hello"}; using w_internal::viewLiteral; /// Store a compile time sequence of enum values /// /// example usage: /// enum class Level { Easy, Normal, Hard }; /// constexpr auto sequence = w_cpp::enum_sequence{}; using w_internal::enum_sequence; /// create a compile time property description for registraton usage /// /// \arg T the type of the property /// \arg name the compile time StringView for the property name /// \arg type the compile time StringView for the type of the property /// /// Following methods may be called in chain: /// * .setGetter(F) - set the member function that returns the value of the property `() -> T` /// * .setSetter(F) - set the member function that changes the value of the property `(T) -> void` /// * .setMember(M) - set the class attribute to read and write the value of the property /// * .setNotify(F) - set the member function that represents the changed signal for the property /// * .setReset(F) - set the member function that resets the property value to it's default /// * .addFlag() - add one or multiple flags for the property template constexpr auto makeProperty(StringView name, StringView type) { return w_internal::MetaPropertyInfo{ name, type, {}, {}, {}, {}, {} }; } /// create a builder for a signal description /// /// \arg name the compile time StringView for the function name /// \arg func the member function that implements the signal /// /// Following methods may be call in chain: /// * .setParamNames(StringView...) - set the names for all the function parameters (optional) /// * .setParamTypes(StringView...) - set the names of for all parameter types /// * .addFlag(Flags...) - add some methods flags /// * .setIntegralConstant() - set a compile time integral value type as a unique identifier /// * .build() - build the final MethodInfo for this signal template constexpr auto makeSignalBuilder(StringView name, F func) -> w_internal::MetaMethodInfoBuilder { return {name, func}; } /// create a compile time enum description for registraton usage /// /// \arg Enum type /// \arg name the compile time StringView for the enum name /// \arg memberValueSequence the compile time enum_sequence of all enum member values /// \arg memberNames the compile time StringViewArray of all enum member names /// /// \note to correct map between values and names, member values in memberValueSequence must be in the same order as member names in memberNames template constexpr auto makeEnumInfo(StringView name, w_internal::enum_sequence memberValueSequence, w_internal::StringViewArray memberNames) { return w_internal::makeMetaEnumInfo(name, 0, memberValueSequence, memberNames); } /// create a compile time flags description for registraton usage /// /// \arg Enum type /// \arg name the compile time StringView for the flag name /// \arg enumAliasName the compile time StringView for the enum name that is used as alias by flags /// \arg memberValueSequence the compile time enum_sequence of all enum member values /// \arg memberNames the compile time StringViewArray of all enum member names /// /// \note to correct map between values and names, member values in memberValueSequence must be in the same order as member names in memberNames template constexpr auto makeFlagInfo(StringView name, StringView enumAliasName, w_internal::enum_sequence memberValueSequence, w_internal::StringViewArray memberNames) { return w_internal::makeMetaEnumInfo(name, enumAliasName, memberValueSequence, memberNames); } } // namespace w_cpp /// \macro W_CPP_PROPERTY(callback) /// allows to create multiple properties from a templated structure using regular C++. /// /// example usage: /// template /// struct MyProperties; /// template<> /// struct MyProperties<0> { /// constexpr static auto property = w_cpp::makeProperty(w_cpp::viewLiteral("name"), w_cpp::viewLiteral("QString")) /// .setGetter(&Example::getName); /// }; /// W_CPP_PROPERTY(MyProperties) /// /// \note you have to ensure that the struct is only valid for some `I`s. #define W_CPP_PROPERTY(a) \ static constexpr size_t W_MACRO_CONCAT(a,_O) = w_internal::stateCount<__COUNTER__, w_internal::PropertyStateTag, W_ThisType**>; \ template \ friend constexpr auto w_state(w_internal::Index, w_internal::PropertyStateTag, W_ThisType**) W_RETURN((a::property)) /// \macro W_CPP_SIGNAL(callback) /// allows to register multiple signals from a templated structure using regular C++. /// /// example usage: /// template /// struct MySignals; /// template<> /// struct MySignals<0> { /// constexpr static auto signal = w_cpp::makeSignalBuilder(w_cpp::viewLiteral("nameChanged"), &Example::nameChanged).build(); /// }; /// W_CPP_SIGNAL(MySignals) /// /// \note you have to ensure that the struct is only valid for some `I`s. #define W_CPP_SIGNAL(a) \ static constexpr size_t W_MACRO_CONCAT(a,_O) = w_internal::stateCount<__COUNTER__, w_internal::SignalStateTag, W_ThisType**>; \ template \ friend constexpr auto w_state(w_internal::Index, w_internal::SignalStateTag, W_ThisType**) W_RETURN((a::signal)) /// \macro W_CPP_SIGNAL_IMPL(type, callback, index) /// allows to implement a signal /// /// example usage: /// template /// void notifyPropertyChanged() W_CPP_SIGNAL_IMPL(decltype (&tst_CppApi::notifyPropertyChanged), MySignals, I, 0) /// #define W_CPP_SIGNAL_IMPL(type, a, i, ...) \ constexpr int index = W_ThisType::W_MACRO_CONCAT(a,_O) + i; \ return w_internal::SignalImplementation{this}(__VA_ARGS__) /// \macro W_CPP_ENUM(type, callback) /// allows to register a enum type for a QObject type from a templated structure using regular C++. /// additionally enum can be declared outside QObject where it is registered. /// /// example usage: /// enum class Level { Easy, Normal, Hard }; /// /// template /// struct MyEnums; /// template<> /// struct MyEnums { /// constexpr static auto enumInfo = w_cpp::makeEnumInfo( /// w_cpp::viewLiteral("Level"), /// w_cpp::enum_sequence{}, /// w_cpp::StringViewArray<3>{ /// {w_cpp::viewLiteral("Easy"), w_cpp::viewLiteral("Normal"), w_cpp::viewLiteral("Hard")}}); /// }; /// W_CPP_ENUM(Level, MyEnums) /// #define W_CPP_ENUM(type, a) \ W_STATE_APPEND(EnumState, a::enumInfo) \ Q_ENUM(type) /// \macro W_CPP_ENUM_NS(type, callback) /// allows to register a enum type for a namespace that was declarated with W_NAMESPACE from a templated structure using regular C++. /// additionally enum can be declared outside namespace where it is registered. /// /// example usage: /// Similar to usage of W_CPP_ENUM but you must use W_CPP_ENUM_NS instead of W_CPP_ENUM #define W_CPP_ENUM_NS(type, a) \ W_STATE_APPEND_NS(EnumState, a::enumInfo) \ Q_ENUM_NS(type) /// \macro W_CPP_FLAG(type, callback) /// allows to register a enum type as QFlags for a QObject type from a templated structure using regular C++. /// additionally enum can be declared outside QObject where it is registered. /// /// example usage: /// enum class Filter { None = 0x00, Name = 0x01, Comment = 0x02, Any = Name | Comment }; /// /// Q_DECLARE_FLAGS(Filters, Filter) /// template<> /// struct MyEnums { /// constexpr static auto flagInfo = w_cpp::makeFlagInfo( /// w_cpp::viewLiteral("Filters"), /// w_cpp::viewLiteral("Filter"), /// w_cpp::enum_sequence{}, /// w_cpp::StringViewArray<4>{{w_cpp::viewLiteral("None"), /// w_cpp::viewLiteral("Name"), /// w_cpp::viewLiteral("Comment"), /// w_cpp::viewLiteral("Any")}}); /// }; /// W_CPP_FLAG(Filters, MyEnums) /// #define W_CPP_FLAG(type, a) \ W_STATE_APPEND(EnumState, a::flagInfo) \ Q_FLAG(type) /// \macro W_CPP_FLAG_NS(type, callback) /// allows to register a enum type as QFlags for a namespace that was declarated with W_NAMESPACE from a templated structure using regular C++. /// additionally enum can be declared outside namespace where it is registered. /// /// example usage: /// Similar to usage of W_CPP_FLAG but you must use W_CPP_FLAG_NS instead of W_CPP_FLAG #define W_CPP_FLAG_NS(type, a) \ W_STATE_APPEND_NS(EnumState, a::flagInfo) \ Q_FLAG_NS(type) verdigris-1.3/src/wobjectdefs.h000066400000000000000000001264031427643277200166360ustar00rootroot00000000000000/**************************************************************************** * Copyright (C) 2016-2018 Woboq GmbH * Olivier Goffart * https://woboq.com/ * * This file is part of Verdigris: a way to use Qt without moc. * https://github.com/woboq/verdigris * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. * If not, see . */ #pragma once #ifndef Q_MOC_RUN // don't define anything when moc is run #include #include #include #define W_VERSION 0x010200 namespace w_internal { using std::index_sequence; // From C++14, make sure to enable the C++14 option in your compiler #ifdef W_USE_CUSTOM_MAKE_INDEX_SEQUENCE // The default std::make_index_sequence from libstdc++ is recursing O(N) times which is reaching // recursion limits level for big strings. This implementation has only O(log N) recursion template index_sequence make_index_sequence_helper_merge(index_sequence, index_sequence); template struct make_index_sequence_helper { using part1 = typename make_index_sequence_helper<(N+1)/2>::result; using part2 = typename make_index_sequence_helper::result; using result = decltype(make_index_sequence_helper_merge(part1(), part2())); }; template<> struct make_index_sequence_helper<1> { using result = index_sequence<0>; }; template<> struct make_index_sequence_helper<0> { using result = index_sequence<>; }; template using make_index_sequence = typename make_index_sequence_helper::result; #else using std::make_index_sequence; #endif /// integral_constant with an inheritance based fallback struct IndexBase {}; template struct Index : IndexBase {}; template constexpr auto index = Index{}; template constexpr void ordered(Args...) {} template constexpr void ordered2(std::initializer_list) {} /// Compute the sum of many integers template constexpr int sums(Args... args) { #if __cplusplus > 201700L return static_cast((args + ... + 0)); #else auto r = int{}; ordered2({(r += args)...}); return r; #endif } // This indirection is required to work around a MSVC bug. (See https://github.com/woboq/verdigris/issues/6 ) template constexpr int summed = sums(args...); /// constexpr friendly string_view struct StringView { const char* b{}; const char* e{}; constexpr auto size() const -> qptrdiff { return e - b; } constexpr auto begin() const { return b; } constexpr auto end() const { return e; } }; // adding this constructor requires more constructors which generates overhead template constexpr auto viewLiteral(const char (&d)[N]) -> StringView { return {&d[0], &d[N-1]}; } /// raw arrays cannot be returned from functions so we wrap it template struct StringViewArray { StringView data[(N > 0 ? N : 1)]{}; constexpr auto operator[] (size_t i) const { return data[i]; } }; template constexpr auto countParsedLiterals(const char (&s)[SN]) { auto r = size_t{}; auto i = 0u; while (true) { while (true) { if (i >= SN-1) return r; if (s[i] != ' ' && s[i] != ',') break; // start found i++; } r++; i++; while (true) { if (i >= SN-1) return r; if (s[i] == ',') break; i++; } i++; } } template constexpr auto viewParsedLiterals(const char (&s)[SN]) -> StringViewArray { // assumtions: // 1. s is generated from a macro // 2. each value is seperated by comma // 3. exactly N values are generated // 4. no second space can follow a space (no tabs or line breaks) auto r = StringViewArray{}; auto ri = size_t{}; auto i = 0u; while (true) { while (true) { if (i >= SN-1) return r; if (s[i] != ' ' && s[i] != ',') break; // start found i++; } r.data[ri].b = &s[i]; i++; while (true) { if (i >= SN-1) { r.data[ri].e = &s[i]; return r; // text - end } if (s[i] == ' ') { if (i+1 >= SN-1) { r.data[ri].e = &s[i]; return r; // text - whitespace - end } if (s[i+1] == ',') { r.data[ri].e = &s[i]; i += 2; break; // text - whitespace - comma } i += 2; continue; // text - whitespace - text } if (s[i] == ',') { r.data[ri].e = &s[i]; i++; break; // text - comma } i++; } ri++; } } template constexpr auto viewScopedLiterals(const char (&s)[SN]) -> StringViewArray { auto r = StringViewArray{}; auto ri = size_t{}; auto i = 0u; while (true) { while (true) { if (i >= SN-1) return r; if (s[i] != ' ' && s[i] != ',' && s[i] != ':') break; // start found i++; } r.data[ri].b = &s[i]; i++; while (true) { if (i >= SN-1) { r.data[ri].e = &s[i]; return r; // text - end } if (s[i] == ':') { i++; if (s[i] == ' ') i++; r.data[ri].b = &s[i]; continue; } if (s[i] == ' ') { if (i+1 >= SN-1) { r.data[ri].e = &s[i]; return r; // text - whitespace - end } if (s[i+1] == ',') { r.data[ri].e = &s[i]; i += 2; break; // text - whitespace - comma } i += 2; continue; // text - whitespace - text } if (s[i] == ',') { r.data[ri].e = &s[i]; i++; break; // text - comma } i++; } ri++; } } //----------- // From qmetaobject_p.h enum class PropertyFlags { Invalid = 0x00000000, Readable = 0x00000001, Writable = 0x00000002, Resettable = 0x00000004, EnumOrFlag = 0x00000008, StdCppSet = 0x00000100, // Override = 0x00000200, Constant = 0x00000400, Final = 0x00000800, Designable = 0x00001000, ResolveDesignable = 0x00002000, Scriptable = 0x00004000, ResolveScriptable = 0x00008000, Stored = 0x00010000, ResolveStored = 0x00020000, Editable = 0x00040000, ResolveEditable = 0x00080000, User = 0x00100000, ResolveUser = 0x00200000, Notify = 0x00400000, Revisioned = 0x00800000 }; constexpr uint operator|(uint a, PropertyFlags b) { return a | uint(b); } template struct W_MethodFlags { static constexpr int value = N; }; constexpr W_MethodFlags<0> W_EmptyFlag{}; } // namespace w_internal /// Objects that are used as flags in the W_SLOT macro // Mirror of QMetaMethod::Access namespace W_Access { // From qmetaobject_p.h MethodFlags // AccessPrivate = 0x00, // AccessProtected = 0x01, // AccessPublic = 0x02, // AccessMask = 0x03, //mask constexpr w_internal::W_MethodFlags<0x1000> Private{}; // Note: Private has a higher number to differentiate it from the default constexpr w_internal::W_MethodFlags<0x01> Protected{}; constexpr w_internal::W_MethodFlags<0x02> Public{}; } // Mirror of QMetaMethod::MethodType namespace W_MethodType { // From qmetaobject_p.h MethodFlags // MethodMethod = 0x00, // MethodSignal = 0x04, // MethodSlot = 0x08, // MethodConstructor = 0x0c, // MethodTypeMask = 0x0c, constexpr w_internal::W_MethodFlags<0x00> Method{}; constexpr w_internal::W_MethodFlags<0x04> Signal{}; constexpr w_internal::W_MethodFlags<0x08> Slot{}; constexpr w_internal::W_MethodFlags<0x0c> Constructor{}; } // From qmetaobject_p.h MethodFlags // MethodCompatibility = 0x10, // MethodCloned = 0x20, // MethodScriptable = 0x40, // MethodRevisioned = 0x80 constexpr w_internal::W_MethodFlags<0x10> W_Compat{}; constexpr w_internal::W_MethodFlags<0x40> W_Scriptable{}; constexpr struct {} W_Notify{}; constexpr struct {} W_Reset{}; constexpr std::integral_constant W_Constant{}; constexpr std::integral_constant W_Final{}; namespace w_internal { #if QT_VERSION >= QT_VERSION_CHECK(6,2,0) template struct isConstMemberMethod : std::false_type {}; template struct isConstMemberMethod : std::true_type {}; template struct isConstMemberMethod : std::true_type {}; #endif /// Holds information about a method template> struct MetaMethodInfo { using Func = F; Func func; StringView name; ParamTypes paramTypes; ParamNames paramNames; static constexpr int argCount = QtPrivate::FunctionPointer::ArgumentCount; using ArgSequence = make_index_sequence; static constexpr auto argSequence = ArgSequence{}; #if QT_VERSION >= QT_VERSION_CHECK(6,2,0) static constexpr int flags = Flags + (isConstMemberMethod::value ? 0x100 : 0); #else static constexpr int flags = Flags; #endif using IntegralConstant = IC; }; // Called from the W_SLOT macro template constexpr MetaMethodInfo | W_MethodType::Slot.value, IntegralConstant, ParamTypes> makeMetaSlotInfo(F f, StringView name, IntegralConstant, const ParamTypes ¶mTypes, W_MethodFlags...) { return { f, name, paramTypes, {} }; } // Called from the W_METHOD macro template constexpr MetaMethodInfo | W_MethodType::Method.value, IntegralConstant, ParamTypes> makeMetaMethodInfo(F f, StringView name, IntegralConstant, const ParamTypes ¶mTypes, W_MethodFlags...) { return { f, name, paramTypes, {} }; } // Called from the W_SIGNAL macro template constexpr MetaMethodInfo | W_MethodType::Signal.value, IntegralConstant, ParamTypes, ParamNames> makeMetaSignalInfo(F f, StringView name, IntegralConstant, const ParamTypes ¶mTypes, const ParamNames ¶mNames, W_MethodFlags...) { return { f, name, paramTypes, paramNames }; } /// Holds information about a constructor template struct MetaConstructorInfo { static constexpr std::size_t argCount = sizeof...(Args); static constexpr auto argSequence = make_index_sequence{}; static constexpr int flags = W_MethodType::Constructor.value | W_Access::Public.value; using IntegralConstant = void*; // Used to detect the access specifier, but it is always public, so no need for this StringView name; }; // called from the W_CONSTRUCTOR macro template constexpr MetaConstructorInfo makeMetaConstructorInfo(StringView name) { return { name }; } struct Empty{ constexpr bool operator!=(std::nullptr_t) const { return false; } }; /// Holds information about a property template struct MetaPropertyInfo { using PropertyType = Type; StringView name; StringView typeStr; Getter getter; Setter setter; Member member; Notify notify; Reset reset; static constexpr uint flags = Flags; template constexpr auto setGetter(const S&s) const { return MetaPropertyInfo {name, typeStr, s, setter, member, notify, reset}; } template constexpr auto setSetter(const S&s) const { return MetaPropertyInfo {name, typeStr, getter, s, member, notify, reset}; } template constexpr auto setMember(const S&s) const { return MetaPropertyInfo {name, typeStr, getter, setter, s, notify, reset}; } template constexpr auto setNotify(const S&s) const { return MetaPropertyInfo { name, typeStr, getter, setter, member, s, reset}; } template constexpr auto setReset(const S&s) const { return MetaPropertyInfo { name, typeStr, getter, setter, member, notify, s}; } template constexpr auto addFlag() const { return MetaPropertyInfo { name, typeStr, getter, setter, member, notify, reset}; } }; /// Parse a property and fill a MetaPropertyInfo (called from W_PROPERTY macro) // base case template constexpr auto parseProperty(const PropInfo &p) { return p; } // setter template constexpr auto parseProperty(const PropInfo &p, Ret (Obj::*s)(Arg), Tail... t) { return parseProperty(p.setSetter(s) , t...); } #if defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510 template constexpr auto parseProperty(const PropInfo &p, Ret (Obj::*s)(Arg) noexcept, Tail... t) { return parseProperty(p.setSetter(s) , t...); } #endif // getter template constexpr auto parseProperty(const PropInfo &p, Ret (Obj::*s)(), Tail... t) { return parseProperty(p.setGetter(s), t...); } template constexpr auto parseProperty(const PropInfo &p, Ret (Obj::*s)() const, Tail... t) { return parseProperty(p.setGetter(s), t...); } #if defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510 template constexpr auto parseProperty(const PropInfo &p, Ret (Obj::*s)() noexcept, Tail... t) { return parseProperty(p.setGetter(s), t...); } template constexpr auto parseProperty(const PropInfo &p, Ret (Obj::*s)() const noexcept, Tail... t) { return parseProperty(p.setGetter(s), t...); } #endif // member template constexpr auto parseProperty(const PropInfo &p, Ret Obj::*s, Tail... t) { return parseProperty(p.setMember(s) ,t...); } // notify template constexpr auto parseProperty(const PropInfo &p, decltype(W_Notify), F f, Tail... t) { return parseProperty(p.setNotify(f) ,t...); } // reset template constexpr auto parseProperty(const PropInfo &p, decltype(W_Reset), Ret (Obj::*s)(), Tail... t) { return parseProperty(p.setReset(s) ,t...); } #if defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510 template constexpr auto parseProperty(const PropInfo &p, decltype(W_Reset), Ret (Obj::*s)() noexcept, Tail... t) { return parseProperty(p.setReset(s) ,t...); } #endif // other flags flags template constexpr auto parseProperty(const PropInfo &p, std::integral_constant, Tail... t) { return parseProperty(p.template addFlag() ,t...); } template constexpr auto makeMetaPropertyInfo(StringView name, StringView type, Args... args) { auto meta = MetaPropertyInfo{ name, type, {}, {}, {}, {}, {} }; return parseProperty(meta, args...); } template struct EnumIsScoped { enum { Value = std::is_convertible::value ? 0 : 2 }; }; template struct EnumIsScoped, void> : EnumIsScoped::enum_type> {}; template struct QEnumOrQFlags { using Type = T; }; template struct QEnumOrQFlags> { using Type = T; }; /// Holds information about an enum template struct MetaEnumInfo { StringView name; StringView alias; Names names; using Values = Values_; static constexpr uint flags = Flags; static constexpr auto count = Values::size(); static constexpr auto sequence = make_index_sequence{}; static constexpr auto hasAlias = HasAlias; }; template struct enum_sequence {}; // called from W_ENUM and W_FLAG template constexpr auto makeMetaEnumInfo(StringView name, int, enum_sequence, Names names) -> MetaEnumInfo, Names, Flag | EnumIsScoped::Value> { return { name, viewLiteral(""), names }; } template constexpr auto makeMetaEnumInfo(StringView name, StringView alias, enum_sequence, Names names) -> MetaEnumInfo, Names, Flag | EnumIsScoped::Value> { return { name, alias, names }; } // Helper function to remove the scope in a scoped enum name. (so "Foo::Bar" -> Bar) template constexpr int removedScopeSize(const char (&name)[N]) { // Find the position of the last colon (or 0 if it is not there) int p = N - 1; while (p > 0 && name[p] != ':') p--; if (name[p] == ':') p++; return N - p; } /// Helper for the implementation of a signal. /// Called from the signal implementation within the W_SIGNAL macro. /// /// 'Func' is the type of the signal. 'Idx' is the signal index (relative). /// It is implemented as a functor so the operator() has exactly the same amount of argument of the /// signal so the __VA_ARGS__ works also if there is no arguments (no leading commas) /// /// There is specialization for const and non-const, and for void and non-void signals. /// /// the last argument of the operator() is an int, to workaround the ",0" required in the W_SIGNAL /// macro to make sure there is at least one argument for the ... template struct SignalImplementation {}; template struct SignalImplementation{ Obj *this_; Ret operator()(Args... args, int) const { Ret r{}; const void * a[]= { std::addressof(r), std::addressof(args)... }; QMetaObject::activate(this_, &Obj::staticMetaObject, Idx, const_cast(a)); return r; } }; template struct SignalImplementation{ Obj *this_; void operator()(Args... args, int) { const void * a[]= { nullptr, std::addressof(args)... }; QMetaObject::activate(this_, &Obj::staticMetaObject, Idx, const_cast(a)); } }; template struct SignalImplementation{ const Obj *this_; Ret operator()(Args... args, int) const { Ret r{}; const void * a[]= { std::addressof(r), std::addressof(args)... }; QMetaObject::activate(const_cast(this_), &Obj::staticMetaObject, Idx, const_cast(a)); return r; } }; template struct SignalImplementation{ const Obj *this_; void operator()(Args... args, int) { const void * a[]= { nullptr, std::addressof(args)... }; QMetaObject::activate(const_cast(this_), &Obj::staticMetaObject, Idx, const_cast(a)); } }; /// Used in the W_OBJECT macro to compute the base type. /// Used like this: /// using W_BaseType = std::remove_reference_t; /// Since qt_metacast for W_ThisType will be declared later, the pointer to member function will be /// pointing to the qt_metacast of the base class, so T will be deduced to the base class type. /// /// Returns a reference so this work if T is an abstract class. template T &getParentObjectHelper(void* (T::*)(const char*)); // helper class that can access the private member of any class with W_OBJECT struct FriendHelper; inline namespace w_ShouldBeInQt { // qOverload is already in Qt 5.7, but we need it with older version. // Note that as of Qt 5.11, it is still not enabled with MSVC as Qt relies on feature macro. template struct QNonConstOverload { template constexpr auto operator()(R (T::*ptr)(Args...)) const { return ptr; } }; template struct QConstOverload { template constexpr auto operator()(R (T::*ptr)(Args...) const) const { return ptr; } }; template struct QOverload : QConstOverload, QNonConstOverload { using QConstOverload::operator(); using QNonConstOverload::operator(); template constexpr auto operator()(R (*ptr)(Args...)) const { return ptr; } }; template constexpr QOverload qOverload = {}; #ifndef QT_ANNOTATE_CLASS // Was added in Qt 5.6.1 #define QT_ANNOTATE_CLASS(...) #endif } // namespace w_ShouldBeInQt } // namespace w_internal #if defined(Q_CC_MSVC) && !defined(Q_CC_CLANG) #if _MSC_VER >= 1928 #if defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL // MSVC in /Zc:preprocessor- mode (default) #define W_CONFORMING_PREPROCESSOR 0 #else // MSVC in /Zc:preprocessor mode #define W_CONFORMING_PREPROCESSOR 1 #endif #else // Older versions of MSVC without the /Zc:preprocessor flag #define W_CONFORMING_PREPROCESSOR 0 #endif #else // Other compilers, generally conforming #define W_CONFORMING_PREPROCESSOR 1 #endif #if !W_CONFORMING_PREPROCESSOR // Workaround for MSVC: expension rules are different so we need some extra macro. #define W_MACRO_MSVC_EXPAND(...) __VA_ARGS__ #define W_MACRO_MSVC_DELAY(X,...) W_MACRO_MSVC_EXPAND(X(__VA_ARGS__)) #define W_MACRO_MSVC_EMPTY /##* *##/ #else #define W_MACRO_MSVC_EXPAND(...) __VA_ARGS__ #define W_MACRO_MSVC_DELAY(X,...) X(__VA_ARGS__) #define W_MACRO_MSVC_EMPTY #endif // Private macro helpers for macro programming #define W_MACRO_EMPTY #define W_MACRO_EVAL(...) __VA_ARGS__ #define W_MACRO_DELAY(X,...) W_MACRO_MSVC_EXPAND(X(__VA_ARGS__)) #define W_MACRO_DELAY2(X,...) W_MACRO_MSVC_EXPAND(X(__VA_ARGS__)) #define W_MACRO_TAIL(A, ...) __VA_ARGS__ #define W_MACRO_FIRST(...) W_MACRO_MSVC_EXPAND(W_MACRO_FIRST2(__VA_ARGS__,)) #define W_MACRO_FIRST2(A, ...) A #define W_MACRO_STRIGNIFY(...) W_MACRO_STRIGNIFY2(__VA_ARGS__) #define W_MACRO_STRIGNIFY2(...) #__VA_ARGS__ #define W_MACRO_CONCAT(A, B) W_MACRO_CONCAT2(A,B) #define W_MACRO_CONCAT2(A, B) A##_##B // strignify and make a StaticStringList out of an array of arguments #define W_PARAM_TOSTRING(...) W_MACRO_MSVC_EMPTY W_MACRO_MSVC_DELAY(W_PARAM_TOSTRING2,__VA_ARGS__) #define W_PARAM_TOSTRING2(...) w_internal::viewParsedLiterals("" #__VA_ARGS__) #define W_PARAM_TOSTRING_REMOVE_SCOPE(...) W_MACRO_MSVC_EMPTY W_MACRO_MSVC_DELAY(W_PARAM_TOSTRING2_REMOVE_SCOPE,__VA_ARGS__) #define W_PARAM_TOSTRING2_REMOVE_SCOPE(...) w_internal::viewScopedLiterals("" #__VA_ARGS__) // remove the surrounding parentheses #define W_MACRO_REMOVEPAREN(A) W_MACRO_DELAY(W_MACRO_REMOVEPAREN2, W_MACRO_REMOVEPAREN_HELPER A) #define W_MACRO_REMOVEPAREN2(...) W_MACRO_DELAY2(W_MACRO_TAIL, W_MACRO_REMOVEPAREN_HELPER_##__VA_ARGS__) #define W_MACRO_REMOVEPAREN_HELPER(...) _ , __VA_ARGS__ #define W_MACRO_REMOVEPAREN_HELPER_W_MACRO_REMOVEPAREN_HELPER , // if __VA_ARGS__ is "(types), foobar" then return just the types, otherwise return nothing #define W_OVERLOAD_TYPES(...) W_MACRO_DELAY(W_OVERLOAD_TYPES2,W_OVERLOAD_TYPES_HELPER __VA_ARGS__,) #define W_OVERLOAD_TYPES2(A,...) W_MACRO_DELAY2(W_OVERLOAD_TYPES3, W_OVERLOAD_TYPES_HELPER_##A ...) #define W_OVERLOAD_TYPES3(A,...) W_MACRO_EVAL A #define W_OVERLOAD_TYPES_HELPER(...) YES(__VA_ARGS__) #define W_OVERLOAD_TYPES_HELPER_W_OVERLOAD_TYPES_HELPER (), #define W_OVERLOAD_TYPES_HELPER_YES(...) (__VA_ARGS__), #define W_OVERLOAD_RESOLVE(...) W_MACRO_DELAY(W_OVERLOAD_RESOLVE2,W_OVERLOAD_RESOLVE_HELPER __VA_ARGS__,) #define W_OVERLOAD_RESOLVE2(A, ...) W_MACRO_DELAY2(W_MACRO_FIRST,W_OVERLOAD_RESOLVE_HELPER_##A) #define W_OVERLOAD_RESOLVE_HELPER(...) YES(w_internal::qOverload<__VA_ARGS__>) #define W_OVERLOAD_RESOLVE_HELPER_YES(...) (__VA_ARGS__) #define W_OVERLOAD_RESOLVE_HELPER_W_OVERLOAD_RESOLVE_HELPER , // remove the first argument if it is in parentheses" #define W_OVERLOAD_REMOVE(...) W_MACRO_DELAY(W_OVERLOAD_REMOVE2, W_OVERLOAD_REMOVE_HELPER __VA_ARGS__) #define W_OVERLOAD_REMOVE2(...) W_MACRO_DELAY2(W_MACRO_TAIL, W_OVERLOAD_REMOVE_HELPER_##__VA_ARGS__) #define W_OVERLOAD_REMOVE_HELPER(...) _ #define W_OVERLOAD_REMOVE_HELPER_W_OVERLOAD_REMOVE_HELPER , #define W_RETURN(R) -> decltype(R) { return R; } #ifndef Q_CC_MSVC //Define a unique integral_constant type for a given function pointer #define W_INTEGRAL_CONSTANT_HELPER(NAME, ...) std::integral_constant #else // On MSVC 2017 we trying to get a function pointer in the type cause compiler internal error, so use a simple hash function namespace w_internal { constexpr auto simple_hash(char const *p) { unsigned long long h = *p; while (*p++) h = ((h >> 8)*37ull) ^ *p ^ ((h & 0xff) << 56) ; return h; } } // namespace w_internal #define W_INTEGRAL_CONSTANT_HELPER(NAME, ...) std::integral_constant #endif namespace w_internal { /// We store state in overloads for this method. /// This overload is found if no better overload was found. /// All overloads are found using ADL in the QObject T template void w_state(IndexBase, State, TPP); #if __cplusplus > 201700L template constexpr size_t countBetween() { using R = decltype(w_state(index, State{}, TPP{})); if constexpr (N==X) { return std::is_same_v ? N : M; } else if constexpr (std::is_same_v) { return countBetween(); } else { return countBetween(); } } template constexpr size_t count() { using R = decltype(w_state(index, State{}, TPP{})); if constexpr (std::is_same_v) { return countBetween(); } else { return count(); } } template constexpr auto stateCount = count(); #else template, State{}, TPP{}))>::value , bool up = N==X> struct CountBetween; template struct CountBetween { static constexpr auto value = N; }; template struct CountBetween { static constexpr auto value = M; }; template struct CountBetween { static constexpr auto value = CountBetween::value; }; template struct CountBetween { static constexpr auto value = CountBetween::value; }; template, State{}, TPP{}))>::value> struct Count; template struct Count { static constexpr auto value = CountBetween::value; }; template struct Count { static constexpr auto value = Count::value; }; template constexpr auto stateCount = Count::value; #endif struct SlotStateTag {}; struct SignalStateTag {}; struct MethodStateTag {}; struct ConstructorStateTag {}; struct PropertyStateTag {}; struct EnumStateTag {}; struct ClassInfoStateTag {}; struct InterfaceStateTag {}; } // namespace w_internal #define W_OBJECT_COMMON(TYPE) \ using W_ThisType = TYPE; \ static constexpr auto W_UnscopedName = w_internal::viewLiteral(#TYPE); /* so we don't repeat it in W_CONSTRUCTOR */ \ friend struct w_internal::FriendHelper; \ template static inline constexpr int w_flagAlias(W_Flag) { return 0; } \ public: \ struct W_MetaObjectCreatorHelper; #define W_STATE_APPEND(STATE, ...) \ friend constexpr auto w_state(w_internal::Index>, \ w_internal::STATE##Tag, W_ThisType**) W_RETURN((__VA_ARGS__)) #define W_STATE_APPEND_NS(STATE, ...) \ static constexpr auto w_state(w_internal::Index>, \ w_internal::STATE##Tag, W_ThisType**) W_RETURN((__VA_ARGS__)) // public macros /// \macro W_OBJECT(TYPE) /// Like the Q_OBJECT macro, this declare that the object might have signals, slots or properties. /// Must contains the class name as a parameter and need to be put before any other W_ macro in the class. #define W_OBJECT(TYPE) \ W_OBJECT_COMMON(TYPE) \ public: \ using W_BaseType = std::remove_reference_t; \ Q_OBJECT \ QT_ANNOTATE_CLASS(qt_fake, "") /// \macro W_GADGET(TYPE) /// Like the Q_GADGET macro, this declare that the object might have properties. /// Must contains the class name as a parameter and need to be put before any other W_ macro in the class. #define W_GADGET(TYPE) \ W_OBJECT_COMMON(TYPE) \ Q_GADGET \ QT_ANNOTATE_CLASS(qt_fake, "") /// \macro W_NAMESPACE(NAMESPACE) /// Like the Q_GADGET macro, this declare that the object might have properties. /// Must contains the class name as a parameter and need to be put before any other W_ macro in the class. #define W_NAMESPACE(NAMESPACE) \ Q_NAMESPACE \ struct W_MetaObjectCreatorHelper; \ struct W_ThisType { \ using W_MetaObjectCreatorHelper = NAMESPACE::W_MetaObjectCreatorHelper; \ static constexpr auto qt_static_metacall = nullptr; \ }; \ static constexpr auto W_UnscopedName = w_internal::viewLiteral(#NAMESPACE); \ template Q_DECL_UNUSED static inline constexpr int w_flagAlias(W_Flag) { Q_UNUSED(W_UnscopedName) return 0; } \ QT_ANNOTATE_CLASS(qt_fake, "") /// \macro W_SLOT( [, () ] [, ]* ) /// /// The W_SLOT macro needs to be put after the slot declaration. /// /// The W_SLOT macro can optionally have a list of parameter types as second argument to disambiguate /// overloads or use types that are not registered with W_REGISTER_ARGTYPE. The list of parameter /// need to be within parentheses (even if there is 0 or 1 argument). /// /// The W_SLOT macro can have flags: /// - Specifying the the access: W_Access::Protected, W_Access::Private /// or W_Access::Public. (By default, it is auto-detected from the location of this macro.) /// - W_Compat: for deprecated methods (equivalent of Q_MOC_COMPAT) #define W_SLOT(...) W_MACRO_MSVC_EXPAND(W_SLOT2(__VA_ARGS__, w_internal::W_EmptyFlag)) #define W_SLOT2(NAME, ...) \ W_STATE_APPEND(SlotState, w_internal::makeMetaSlotInfo( \ W_OVERLOAD_RESOLVE(__VA_ARGS__)(&W_ThisType::NAME), w_internal::viewLiteral(#NAME), \ W_INTEGRAL_CONSTANT_HELPER(NAME, __VA_ARGS__)(), \ W_PARAM_TOSTRING(W_OVERLOAD_TYPES(__VA_ARGS__)), \ W_OVERLOAD_REMOVE(__VA_ARGS__))) \ static inline void w_GetAccessSpecifierHelper(W_INTEGRAL_CONSTANT_HELPER(NAME, __VA_ARGS__)) {} /// \macro W_INVOKABLE( [, () ] [, ]* ) /// Exactly like W_SLOT but for Q_INVOKABLE methods. #define W_INVOKABLE(...) W_MACRO_MSVC_EXPAND(W_INVOKABLE2(__VA_ARGS__, w_internal::W_EmptyFlag)) #define W_INVOKABLE2(NAME, ...) \ W_STATE_APPEND(MethodState, w_internal::makeMetaMethodInfo( \ W_OVERLOAD_RESOLVE(__VA_ARGS__)(&W_ThisType::NAME), w_internal::viewLiteral(#NAME), \ W_INTEGRAL_CONSTANT_HELPER(NAME, __VA_ARGS__)(), \ W_PARAM_TOSTRING(W_OVERLOAD_TYPES(__VA_ARGS__)), \ W_OVERLOAD_REMOVE(__VA_ARGS__))) \ static inline void w_GetAccessSpecifierHelper(W_INTEGRAL_CONSTANT_HELPER(NAME, __VA_ARGS__)) {} /// /// \macro W_SIGNAL( [, () ] , ) /// /// Unlike W_SLOT, W_SIGNAL must be placed directly after the signal signature declaration. /// There should not be a semi colon between the signal signature and the macro /// /// Like W_SLOT, there can be the types of the parametter as a second argument, within parentheses. /// You must then follow with the parameter names /// /// Note about exported classes: since the signal is inline, GCC won't export it when compiling /// with -fvisibility-inlines-hidden (which is the default), so connecting using pointer to member /// functions won't work accross library boundaries. You need to explicitly export the signal with /// your MYLIB_EXPORT macro in front of the signal declaration. #define W_SIGNAL(...) W_MACRO_MSVC_EXPAND(W_SIGNAL2(__VA_ARGS__ , 0)) #define W_SIGNAL2(NAME, ...) \ { /* W_SIGNAL need to be placed directly after the signal declaration, without semicolon. */\ using w_SignalType = decltype(W_OVERLOAD_RESOLVE(__VA_ARGS__)(&W_ThisType::NAME)); \ return w_internal::SignalImplementation{this}(W_OVERLOAD_REMOVE(__VA_ARGS__)); \ } \ static constexpr int W_MACRO_CONCAT(w_signalIndex_##NAME,__LINE__) = \ w_internal::stateCount<__COUNTER__, w_internal::SignalStateTag, W_ThisType**>; \ friend constexpr auto w_state(w_internal::Index, w_internal::SignalStateTag, W_ThisType**) \ W_RETURN(w_internal::makeMetaSignalInfo( \ W_OVERLOAD_RESOLVE(__VA_ARGS__)(&W_ThisType::NAME), w_internal::viewLiteral(#NAME), \ W_INTEGRAL_CONSTANT_HELPER(NAME, __VA_ARGS__)(), \ W_PARAM_TOSTRING(W_OVERLOAD_TYPES(__VA_ARGS__)), W_PARAM_TOSTRING(W_OVERLOAD_REMOVE(__VA_ARGS__)))) \ static inline void w_GetAccessSpecifierHelper(W_INTEGRAL_CONSTANT_HELPER(NAME, __VA_ARGS__)) {} /// \macro W_SIGNAL_COMPAT /// Same as W_SIGNAL, but set the W_Compat flag #define W_SIGNAL_COMPAT(...) W_MACRO_MSVC_EXPAND(W_SIGNAL_COMPAT2(__VA_ARGS__, 0)) #define W_SIGNAL_COMPAT2(NAME, ...) \ { \ using w_SignalType = decltype(W_OVERLOAD_RESOLVE(__VA_ARGS__)(&W_ThisType::NAME)); \ return w_internal::SignalImplementation{this}(W_OVERLOAD_REMOVE(__VA_ARGS__)); \ } \ static constexpr int W_MACRO_CONCAT(w_signalIndex_##NAME,__LINE__) = \ w_internal::stateCount<__COUNTER__, w_internal::SignalStateTag, W_ThisType**>; \ friend constexpr auto w_state(w_internal::Index, w_internal::SignalStateTag, W_ThisType**) \ W_RETURN(w_internal::makeMetaSignalInfo( \ W_OVERLOAD_RESOLVE(__VA_ARGS__)(&W_ThisType::NAME), w_internal::viewLiteral(#NAME), \ W_INTEGRAL_CONSTANT_HELPER(NAME, __VA_ARGS__)(), \ W_PARAM_TOSTRING(W_OVERLOAD_TYPES(__VA_ARGS__)), W_PARAM_TOSTRING(W_OVERLOAD_REMOVE(__VA_ARGS__)), W_Compat)) \ static inline void w_GetAccessSpecifierHelper(W_INTEGRAL_CONSTANT_HELPER(NAME, __VA_ARGS__)) {} /// \macro W_CONSTRUCTOR() /// Declares that this class can be constructed with this list of argument. /// Equivalent to Q_INVOKABLE constructor. /// One can have W_CONSTRUCTOR() for the default constructor even if it is implicit. #define W_CONSTRUCTOR(...) \ W_STATE_APPEND(ConstructorState, \ w_internal::makeMetaConstructorInfo<__VA_ARGS__>(W_UnscopedName)) /// \macro W_PROPERTY(, [, ]*) /// /// Declare a property with the type . /// The flags can be function pointers that are detected to be setter, getters, notify signal or /// other flags. Use the macro READ, WRITE, MEMBER, ... for the flag so you can write W_PROPERTY /// just like in a Q_PROPERTY. The only difference with Q_PROPERTY would be the semicolon before the /// name. /// W_PROPERTY need to be put after all the setters, getters, signals and members have been declared. /// /// can optionally be put in parentheses, if you have a type containing a comma /// /// The macro to be used inside W_PROPERTY can also be prefixed by W_ (W_READ, W_WRITE, ...) /// If you define the macro W_NO_PROPERTY_MACRO in your build settings, the macro without prefix /// won't be defined. #define W_PROPERTY(...) W_MACRO_MSVC_EXPAND(W_PROPERTY2(__VA_ARGS__)) // expands the READ, WRITE, and other sub marcos #define W_PROPERTY2(TYPE, NAME, ...) \ W_STATE_APPEND(PropertyState, \ w_internal::makeMetaPropertyInfo(\ w_internal::viewLiteral(#NAME), w_internal::viewLiteral(W_MACRO_STRIGNIFY(W_MACRO_REMOVEPAREN(TYPE))), __VA_ARGS__)) #define W_WRITE , &W_ThisType:: #define W_READ , &W_ThisType:: #define W_NOTIFY , W_Notify, &W_ThisType:: #define W_RESET , W_Reset, &W_ThisType:: #define W_MEMBER , &W_ThisType:: #define W_CONSTANT , W_Constant #define W_FINAL , W_Final #ifndef W_NO_PROPERTY_MACRO #define WRITE W_WRITE #define READ W_READ #define NOTIFY W_NOTIFY #define RESET W_RESET #define MEMBER W_MEMBER #define CONSTANT W_CONSTANT #define FINAL W_FINAL #endif #undef Q_PRIVATE_PROPERTY // the official macro is not a variadic macro, and the coma in READ would break it #define Q_PRIVATE_PROPERTY(...) /// \macro W_ENUM(, ) /// Similar to Q_ENUM, but one must also manually write all the values. #define W_ENUM(NAME, ...) \ W_STATE_APPEND(EnumState, w_internal::makeMetaEnumInfo( \ w_internal::viewLiteral(#NAME), w_flagAlias(NAME{}), \ w_internal::enum_sequence{}, W_PARAM_TOSTRING_REMOVE_SCOPE(__VA_ARGS__))) \ Q_ENUM(NAME) /// \macro W_ENUM_NS(, ) /// Similar to Q_ENUM_NS, like W_ENUM #define W_ENUM_NS(NAME, ...) \ W_STATE_APPEND_NS(EnumState, w_internal::makeMetaEnumInfo( \ w_internal::viewLiteral(#NAME), w_flagAlias(NAME{}), \ w_internal::enum_sequence{}, W_PARAM_TOSTRING_REMOVE_SCOPE(__VA_ARGS__))) \ Q_ENUM_NS(NAME) /// \macro W_FLAG(, ) /// Similar to Q_FLAG, but one must also manually write all the values. #define W_FLAG(NAME, ...) \ W_STATE_APPEND(EnumState, w_internal::makeMetaEnumInfo::Type,true>( \ w_internal::viewLiteral(#NAME), w_flagAlias(NAME{}), \ w_internal::enum_sequence::Type,__VA_ARGS__>{}, \ W_PARAM_TOSTRING_REMOVE_SCOPE(__VA_ARGS__))) \ Q_FLAG(NAME) /// \macro W_FLAG_NS(, ) /// Similar to Q_FLAG_NS, like W_FLAG. #define W_FLAG_NS(NAME, ...) \ W_STATE_APPEND_NS(EnumState, w_internal::makeMetaEnumInfo::Type,true>( \ w_internal::viewLiteral(#NAME), w_flagAlias(NAME{}), \ w_internal::enum_sequence::Type,__VA_ARGS__>{}, \ W_PARAM_TOSTRING_REMOVE_SCOPE(__VA_ARGS__))) \ Q_FLAG_NS(NAME) /// Same as Q_CLASSINFO. Note, Q_CLASSINFO_NS is required for namespace #define W_CLASSINFO(A, B) \ W_STATE_APPEND(ClassInfoState, \ std::pair{ w_internal::viewLiteral(A), w_internal::viewLiteral(B) }) /// Same as Q_CLASSINFO, but within a namespace #define W_CLASSINFO_NS(A, B) \ W_STATE_APPEND_NS(ClassInfoState, \ std::pair{ w_internal::viewLiteral(A), w_internal::viewLiteral(B) }) /// Same as Q_INTERFACE #define W_INTERFACE(A) \ W_STATE_APPEND(InterfaceState, static_cast(nullptr)) /// Same as Q_DECLARE_FLAGS #define W_DECLARE_FLAGS(Flags, Enum) \ Q_DECLARE_FLAGS(Flags, Enum) \ static inline constexpr w_internal::StringView w_flagAlias(Flags) { return w_internal::viewLiteral(#Enum); } /// \macro W_REGISTER_ARGTYPE(TYPE) /// Registers TYPE so it can be used as a parameter of a signal/slot or return value. /// The normalized signature must be used. /// Note: This does not imply Q_DECLARE_METATYPE, and Q_DECLARE_METATYPE does not imply this namespace w_internal { template struct W_TypeRegistery { enum { registered = false }; }; } #define W_REGISTER_ARGTYPE(...) namespace w_internal { \ template<> struct W_TypeRegistery<__VA_ARGS__> { \ enum { registered = true }; \ static constexpr auto name = viewLiteral(#__VA_ARGS__); \ };} W_REGISTER_ARGTYPE(char*) W_REGISTER_ARGTYPE(const char*) #else // Q_MOC_RUN // just to avoid parse errors when moc is run over things that it should ignore #define W_SIGNAL(...) ; #define W_SIGNAL_COMPAT(...) ; #define W_PROPERTY(...) #define W_SLOT(...) #define W_CLASSINFO(...) #define W_INTERFACE(...) #define W_CONSTRUCTOR(...) #define W_FLAG(...) #define W_ENUM(...) #define W_DECLARE_FLAGS(...) #endif verdigris-1.3/src/wobjectimpl.h000066400000000000000000001636671427643277200166730ustar00rootroot00000000000000/**************************************************************************** * Copyright (C) 2016-2018 Woboq GmbH * Olivier Goffart * https://woboq.com/ * * This file is part of Verdigris: a way to use Qt without moc. * https://github.com/woboq/verdigris * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. If not, see . */ #pragma once #include "wobjectdefs.h" #include namespace w_internal { #if __cplusplus > 201700L #define W_IF_CONSTEXPR constexpr #else #define W_IF_CONSTEXPR #endif // Match MetaDataFlags constants form the MetaDataFlags in qmetaobject_p.h enum : uint { IsUnresolvedType = 0x80000000, IsUnresolvedNotifySignal = 0x70000000 }; /// all details about a class T template struct ObjectInfo { using Type = T; static constexpr auto counter = L; static constexpr auto name = StringView{Name::value}; static constexpr int signalCount = stateCount; static constexpr int slotCount = stateCount; static constexpr int methodCount = signalCount + slotCount + stateCount; static constexpr int constructorCount = stateCount; static constexpr int propertyCount = stateCount; static constexpr int enumCount = stateCount; static constexpr int classInfoCount = stateCount; static constexpr int interfaceCount = stateCount; static constexpr auto methodSequence = make_index_sequence{}; static constexpr auto constructorSequence = make_index_sequence{}; static constexpr auto propertySequence = make_index_sequence{}; static constexpr auto interfaceSequence = make_index_sequence{}; #if __cplusplus > 201700L template static constexpr auto method(Index) { using TPP = T**; if constexpr (Idx < signalCount) return w_state(index, SignalStateTag{}, TPP{}); else if constexpr (Idx - signalCount < slotCount) return w_state(index, SlotStateTag{}, TPP{}); else return w_state(index, MethodStateTag{}, TPP{}); } #else template static constexpr auto method(Index, std::enable_if_t<(Idx < signalCount)>* = {}) { using TPP = T**; return w_state(index, SignalStateTag{}, TPP{}); } template static constexpr auto method(Index, std::enable_if_t<(Idx >= signalCount && Idx - signalCount < slotCount)>* = {}) { using TPP = T**; return w_state(index, SlotStateTag{}, TPP{}); } template static constexpr auto method(Index, std::enable_if_t<(Idx >= signalCount + slotCount)>* = {}) { using TPP = T**; return w_state(index, MethodStateTag{}, TPP{}); } #endif }; template constexpr void fold(index_sequence, F&& f) { (void)f; #if __cplusplus > 201700L (f(index), ...); #else ordered((f(index),0)...); #endif } #if __cplusplus > 201700L template constexpr void foldState(F&& f) { fold(make_index_sequence>{}, [&](auto i) { f(w_state(i, State{}, TPP{}), i); }); } #else template struct FoldState { F&& f; template constexpr void operator() (I i) { f(w_state(i, State{}, TPP{}), i); } }; template constexpr void foldState(F&& f) { auto fs = FoldState{std::forward(f)}; fold(make_index_sequence>{}, fs); } #endif template constexpr void foldMethods(F&& f) { foldState(f); foldState(f); foldState(f); } template constexpr auto fetchExplicitName(const StringView& defaultName, ...) { return defaultName; } template constexpr auto fetchExplicitName(const StringView&, int) -> decltype (w_explicitObjectName(static_cast(nullptr))) { return w_explicitObjectName(static_cast(nullptr)); } constexpr bool isPropertyMetacall(QMetaObject::Call call) noexcept { #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) return (call >= QMetaObject::ReadProperty && call <= QMetaObject::ResetProperty) || call == QMetaObject::RegisterPropertyMetaType || call == QMetaObject::BindableProperty; #else return (call >= QMetaObject::ReadProperty && call <= QMetaObject::QueryPropertyUser) || call == QMetaObject::RegisterPropertyMetaType; #endif } /// Helper to get information about the notify signal of the property within object T template struct ResolveNotifySignal { private: using TP = T**; using OP = O**; static constexpr auto prop = w_state(index, PropertyStateTag{}, TP{}); template, SignalStateTag{}, OP{}).func == prop.notify> static constexpr auto match(int) { return Eq; } template static constexpr auto match(float) { return false; } template static constexpr int indexFold(index_sequence) { int r = -1; #if __cplusplus > 201700L ((match(0) ? r = (int)Is : 0), ...); #else ordered2({(match(0) ? r = (int)Is : 0)...}); #endif return r; } public: static constexpr int signalIndex() { return indexFold(make_index_sequence>{}); } }; /// returns true if the object T has at least one property with a notify signal #if __cplusplus > 201700L template constexpr bool hasNotifySignal() { auto r = bool{}; foldState([&](auto p, auto) { r = r || !std::is_same::value; }); return r; } #else struct HasNotifySignal { bool r{}; template constexpr void operator() (P p, I) { r = r || !std::is_same::value; } }; template constexpr bool hasNotifySignal() { auto hns = HasNotifySignal{}; foldState(hns); return hns.r; } #endif template struct ClassInfoGenerator { State& s; constexpr ClassInfoGenerator(State& s) : s(s) {} template constexpr void operator() (const ClassInfo& ci, Index) { s.addString(ci.first); s.addString(ci.second); } }; /// auto-detect the access specifiers template auto test_public(int) -> std::enable_if_t::value, std::true_type>; template auto test_public(float) -> std::false_type; template using isPublic = decltype(test_public(0)); template struct isProtected : std::false_type {}; template ::value>> struct Derived : T { template static decltype(X::w_GetAccessSpecifierHelper(std::declval())) test(M); }; template struct isProtected::test(std::declval()))> : std::true_type {}; template struct MethodGenerator { State& s; int parameterIndex; MethodGenerator(const MethodGenerator&) = delete; constexpr MethodGenerator(State& s, int pi) : s(s), parameterIndex(pi) {} template constexpr void operator() (const Method& method, Index) { s.addString(method.name); // name constexpr uint flags = adjustFlags(Method::flags, typename Method::IntegralConstant()); s.addInts( (uint)Method::argCount, parameterIndex, //parameters 1, //tag, always \0 flags #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) , s.metaTypeCount #endif ); parameterIndex += 1 + Method::argCount * 2; #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) registerMetaTypes(method); #endif } private: template static constexpr uint adjustFlags(uint f, M) { if (!(f & (W_Access::Protected.value | W_Access::Private.value | W_Access::Public.value))) { // Auto-detect the access specifier f |= isPublic::value ? W_Access::Public.value : isProtected::value ? W_Access::Protected.value : W_Access::Private.value; } f &= static_cast(~W_Access::Private.value); // Because QMetaMethod::Private is 0, but not W_Access::Private; return f; } #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) template constexpr void registerMetaTypes(const Method& method) { generateSingleMethodParameter(method.func); } template constexpr void registerMetaTypes(const MetaConstructorInfo&) { (s.template addMetaType(), ...); } // non-const function template constexpr void generateSingleMethodParameter(Ret (Obj::*)(Args...)) { s.template addMetaType(); (s.template addMetaType(), ...); } template constexpr void generateSingleMethodParameter(Ret (Obj::*)(Args...) noexcept) { s.template addMetaType(); (s.template addMetaType(), ...); } template // const function constexpr void generateSingleMethodParameter(Ret (Obj::*)(Args...) const) { s.template addMetaType(); (s.template addMetaType(), ...); } template constexpr void generateSingleMethodParameter(Ret (Obj::*)(Args...) const noexcept) { s.template addMetaType(); (s.template addMetaType(), ...); } // static member functions template constexpr void generateSingleMethodParameter(Ret (*)(Args...)) { s.template addMetaType(); (s.template addMetaType(), ...); } template constexpr void generateSingleMethodParameter(Ret (*)(Args...) noexcept) { s.template addMetaType(); (s.template addMetaType(), ...); } #endif }; /// compute if type T is a builtin QMetaType template struct MetaTypeIdIsBuiltIn : std::false_type {}; template struct MetaTypeIdIsBuiltIn::IsBuiltIn>::type> : std::true_type{}; /// Helper to generate the type information of type 'T': /// If T is a builtin QMetaType, its meta type id need to be added in the state. /// If it's not builtin, then it would be an reference to T's name. #if __cplusplus > 201700L template constexpr void handleType(State& s, TypeStr v = {}) { (void)v; if constexpr (MetaTypeIdIsBuiltIn::value) { s.addInts(QMetaTypeId2::MetaType); } else if constexpr (std::is_same_v, StringView>) { s.addTypeString(v); } else { s.addTypeString(W_TypeRegistery::name); static_assert(W_TypeRegistery::registered, "Please Register T with W_REGISTER_ARGTYPE"); } } #else template constexpr void handleType(State& s, TypeStr = {}, std::enable_if_t::value>* = {}) { s.addInts(QMetaTypeId2::MetaType); } template constexpr void handleType(State& s, TypeStr = {}, std::enable_if_t::value>* = {}) { s.addTypeString(W_TypeRegistery::name); static_assert(W_TypeRegistery::registered, "Please Register T with W_REGISTER_ARGTYPE"); } template constexpr void handleType(State& s, StringView v, std::enable_if_t::value>* = {}) { s.addTypeString(v); } #endif #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) template #else template #endif struct PropertyGenerator { State& s; constexpr PropertyGenerator(State& s) : s(s) {} template constexpr void operator() (const Prop& prop, Index) { s.addString(prop.name); handleType(s, prop.typeStr); constexpr uint moreFlags = (QtPrivate::IsQEnumHelper::Value ? uint(PropertyFlags::EnumOrFlag) : 0); constexpr uint finalFlag = std::is_final::value ? 0 | PropertyFlags::Final : 0; constexpr uint defaultFlags = 0 | PropertyFlags::Stored | PropertyFlags::Scriptable | PropertyFlags::Designable; s.addInts(Prop::flags | moreFlags | finalFlag | defaultFlags); #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) addSignal(prop.notify, index); s.addInts(0); // revision #endif } #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) template constexpr void addSignal(Empty, Index) { s.addInts(-1); } // Signal in the same class template constexpr void addSignal(Func, Index, std::enable_if_t::Object>::value, int> = 0) { constexpr int signalIndex = ResolveNotifySignal::signalIndex(); static_assert(signalIndex >= 0, "NOTIFY signal in parent class not registered as a W_SIGNAL"); s.addInts(signalIndex); } // Signal in a parent class template constexpr void addSignal(Func, Index, std::enable_if_t::Object>::value, int> = 0) { using O = typename QtPrivate::FunctionPointer::Object; using OP = O**; constexpr int signalIndex = ResolveNotifySignal::signalIndex(); static_assert(signalIndex >= 0, "NOTIFY signal in parent class not registered as a W_SIGNAL"); constexpr auto sig = w_state(index, SignalStateTag{}, OP{}); s.template addTypeString(sig.name); } #endif }; #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) template struct PropertyMetaTypeGenerator { State& s; constexpr PropertyMetaTypeGenerator(State& s) : s(s) {} template constexpr void operator() (const Prop&, I) { s.template addMetaType(); } }; #endif #if __cplusplus > 201700L template struct NotifySignalGenerator { #else template struct NotifySignalGenerator; template struct NotifySignalGenerator { constexpr NotifySignalGenerator(State&) {} template constexpr void operator() (const Prop&, Index) {} }; template struct NotifySignalGenerator { #endif State& s; constexpr NotifySignalGenerator(State& s) : s(s) {} #if __cplusplus > 201700L template constexpr void operator() (const Prop& prop, Index) { if constexpr (hasNotify) { process(prop.notify, index); } } #else template constexpr void operator() (const Prop& prop, Index) { process(prop.notify, index); } #endif private: template constexpr void process(Empty, Index) { s.addInts(0); } // Signal in the same class template constexpr void process(Func, Index, std::enable_if_t::Object>::value, int> = 0) { constexpr int signalIndex = ResolveNotifySignal::signalIndex(); static_assert(signalIndex >= 0, "NOTIFY signal in parent class not registered as a W_SIGNAL"); s.addInts(signalIndex); } // Signal in a parent class template constexpr void process(Func, Index, std::enable_if_t::Object>::value, int> = 0) { using O = typename QtPrivate::FunctionPointer::Object; using OP = O**; constexpr int signalIndex = ResolveNotifySignal::signalIndex(); static_assert(signalIndex >= 0, "NOTIFY signal in parent class not registered as a W_SIGNAL"); static_assert(signalIndex < 0 || QT_VERSION >= QT_VERSION_CHECK(5, 10, 0), "NOTIFY signal in parent class requires Qt 5.10"); constexpr auto sig = w_state(index, SignalStateTag{}, OP{}); s.template addTypeString(sig.name); } }; template struct EnumGenerator { State& s; int dataIndex{}; EnumGenerator(const EnumGenerator&) = delete; constexpr EnumGenerator(State& s, int di) : s(s), dataIndex(di) {} template constexpr void operator() (const Enum& e, Index) { auto nameIndex = s.stringCount; // required for MSVC-2019 (void)nameIndex; s.addString(e.name); // name #if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) if W_IF_CONSTEXPR (Enum::hasAlias) s.addString(e.alias); // alias else s.addInts(nameIndex); #endif s.addInts(Enum::flags, (uint)Enum::count, dataIndex); dataIndex += Enum::count * 2; } }; template struct EnumValuesGenerator { State& s; constexpr EnumValuesGenerator(State& s) : s(s) {} template constexpr void operator() (const Enum& e, Index) { generateAll(typename Enum::Values{}, e.names, Enum::sequence); } private: template constexpr void generateAll(index_sequence, const Names& names, index_sequence) { #if __cplusplus > 201700L ((s.addString(names[Is]), s.addInts((uint)Values)), ...); #else ordered((s.addString(names[Is]), s.addInts((uint)Values), 0)...); #endif } }; #if __cplusplus > 201700L template constexpr auto stringFetch(const StringViewArray& s) { if constexpr (I < N) { return s[I]; } else { (void)s; struct _{}; return _{}; } } #else template constexpr auto stringFetch(const StringViewArray& s, std::enable_if_t<(I < N)>* = {}) { return s[I]; } template constexpr auto stringFetch(const StringViewArray& s, std::enable_if_t* = {}) { (void)s; struct _{}; return _{}; } #endif template constexpr void handleArgType(State& ss, const TypeName& typeName) { using Type = typename QtPrivate::RemoveConstRef::Type; // This way, the overload of result will not pick the StringView one if it is a tuple (because registered types have the priority) auto typeName2 = std::conditional_t::value, TypeName, std::tuple>{typeName}; handleType(ss, typeName2); } template constexpr void handleArgTypes(State& ss, const TypeNames& typeNames, index_sequence) { #if __cplusplus > 201700L (handleArgType(ss, stringFetch(typeNames)), ...); #else ordered((handleArgType(ss, stringFetch(typeNames)), 0)...); #endif } template constexpr void handleArgNames(State& ss, const StringViewArray& paramNames) { auto i = size_t{}; for (; i < ArgCount && i < NameCount; ++i) ss.addString(paramNames[i]); for (; i < ArgCount; ++i) ss.addInts(1); } template struct MethodParametersGenerator { State& s; constexpr MethodParametersGenerator(State& s) : s(s) {} template constexpr void operator() (const Method& method, Index) { generateSingleMethodParameter(method.func, method); } private: // non-const function template constexpr void generateSingleMethodParameter(Ret (Obj::*)(Args...), const Method &method) { handleType(s); handleArgTypes(s, method.paramTypes, Method::argSequence); handleArgNames(s, method.paramNames); } #if defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510 template constexpr void generateSingleMethodParameter(Ret (Obj::*)(Args...) noexcept, const Method &method) { handleType(s); handleArgTypes(s, method.paramTypes, Method::argSequence); handleArgNames(s, method.paramNames); } #endif template // const function constexpr void generateSingleMethodParameter(Ret (Obj::*)(Args...) const, const Method &method) { handleType(s); handleArgTypes(s, method.paramTypes, Method::argSequence); handleArgNames(s, method.paramNames); } #if defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510 template constexpr void generateSingleMethodParameter(Ret (Obj::*)(Args...) const noexcept, const Method &method) { handleType(s); handleArgTypes(s, method.paramTypes, Method::argSequence); handleArgNames(s, method.paramNames); } #endif // static member functions template constexpr void generateSingleMethodParameter(Ret (*)(Args...), const Method &method) { handleType(s); handleArgTypes(s, method.paramTypes, Method::argSequence); handleArgNames(s, method.paramNames); } #if defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510 template constexpr void generateSingleMethodParameter(Ret (*)(Args...) noexcept, const Method &method) { handleType(s); handleArgTypes(s, method.paramTypes, Method::argSequence); handleArgNames(s, method.paramNames); } #endif }; template struct ConstructorParametersGenerator { State& s; constexpr ConstructorParametersGenerator(State& s) : s(s) {} template constexpr void operator() (const MetaConstructorInfo& info, Index) { s.addInts(IsUnresolvedType | 1); handleArgTypes(s, StringViewArray<>{}, info.argSequence); s.addInts(((void)sizeof(Args),1)...); // all the names are 1 (for "\0") } }; /// Given method, a binary::tree containing information about methods or constructor, /// return the amount of item it will add in the int array. #if __cplusplus > 201700L template constexpr int methodsParamOffset() { auto sum = int{}; foldMethods([&](auto m, auto) { sum += int(1 + m.argCount * 2); }); return sum; } #else struct MethodParamOffset { int sum{}; template constexpr void operator() (M m, I) { sum += int(1 + m.argCount * 2); } }; template constexpr int methodsParamOffset() { auto mpo = MethodParamOffset{}; foldMethods(mpo); return mpo.sum; } #endif #if __cplusplus > 201700L template constexpr int constructorParamOffset() { auto sum = int{}; foldState([&](auto m, auto) { sum += int(1 + m.argCount * 2); }); return sum; } #else struct ConstructorParamOffset { int sum{}; template constexpr void operator() (M m, I) { sum += int(1 + m.argCount * 2); } }; template constexpr int constructorParamOffset() { auto cpo = ConstructorParamOffset{}; foldState(cpo); return cpo.sum; } #endif template using RawArray = T[N]; template struct OwnArray { RawArray data{}; constexpr OwnArray(const T (&s)[N]) { auto p = data; for (auto c : s) *p++ = c; } }; struct LayoutBuilder { size_t stringSize{}; uint stringCount{}; uint intCount{}; #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) uint metaTypeCount{}; #endif constexpr void addString(const StringView& s) { stringSize += s.size() + 1; stringCount += 1; intCount += 1; } constexpr void addStringUntracked(const StringView& s) { stringSize += s.size() + 1; stringCount += 1; } template constexpr void addTypeString(const StringView& s) { stringSize += s.size() + 1; stringCount += 1; intCount += 1; } template constexpr void addInts(Ts...) { intCount += sizeof... (Ts); } #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) template constexpr void addMetaType() { metaTypeCount += 1; } #endif }; struct DataBuilder { char* stringCharP{}; qptrdiff* stringOffestP{}; int* stringLengthP{}; uint* intP{}; #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) const QtPrivate::QMetaTypeInterface** metaTypeP{}; #endif uint stringCount{}; uint intCount{}; qptrdiff stringOffset{}; #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) uint metaTypeCount{}; #endif constexpr DataBuilder() = default; DataBuilder(const DataBuilder&) = delete; template constexpr DataBuilder(Holder& r) : stringCharP(r.stringChars) , stringOffestP(r.stringOffsets) , stringLengthP(r.stringLengths) , intP(r.ints) #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) , metaTypeP(r.metaTypes) #endif , stringOffset(r.stringOffset) {} constexpr void addString(const StringView& s) { for (auto c : s) *stringCharP++ = c; *stringCharP++ = '\0'; *stringOffestP++ = stringOffset; *stringLengthP++ = s.size(); *intP++ = stringCount; #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) stringOffset += 1 + s.size(); #else stringOffset += 1 + s.size() - qptrdiff(sizeof(QByteArrayData)); #endif stringCount += 1; intCount += 1; } constexpr void addStringUntracked(const StringView& s) { for (auto c : s) *stringCharP++ = c; *stringCharP++ = '\0'; *stringOffestP++ = stringOffset; *stringLengthP++ = s.size(); #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) stringOffset += 1 + s.size(); #else stringOffset += 1 + s.size() - qptrdiff(sizeof(QByteArrayData)); #endif stringCount += 1; } template constexpr void addTypeString(const StringView& s) { for (auto c : s) *stringCharP++ = c; *stringCharP++ = '\0'; *stringOffestP++ = stringOffset; *stringLengthP++ = s.size(); *intP++ = Flag | stringCount; #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) stringOffset += 1 + s.size(); #else stringOffset += 1 + s.size() - qptrdiff(sizeof(QByteArrayData)); #endif stringCount += 1; intCount += 1; } template constexpr void addInts(Ts... vs) { #if __cplusplus > 201700L ((*intP++ = vs),...); #else ordered2({(*intP++ = vs)...}); #endif intCount += sizeof... (Ts); } #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) template static constexpr const QtPrivate::QMetaTypeInterface *metaTypeInterface = QtPrivate::qTryMetaTypeInterfaceForType>>(); template constexpr void addMetaType() { *metaTypeP++ = metaTypeInterface; metaTypeCount += 1; } #endif }; /// fold ObjectInfo into State template constexpr void generateDataPass(State& state) { using ObjI = typename T::W_MetaObjectCreatorHelper::ObjectInfo; constexpr size_t L = ObjI::counter; constexpr bool hasNotify = hasNotifySignal(); constexpr int classInfoOffset = 14; constexpr int methodOffset = classInfoOffset + ObjI::classInfoCount * 2; constexpr int propertyOffset = methodOffset + ObjI::methodCount * (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) ? 6 : 5); constexpr int enumOffset = propertyOffset + ObjI::propertyCount * (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) ? 5 : (hasNotify ? 4: 3)); constexpr int constructorOffset = enumOffset + ObjI::enumCount * (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) ? 5 : 4); constexpr int paramIndex = constructorOffset + ObjI::constructorCount * (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) ? 6 : 5); constexpr int constructorParamIndex = paramIndex + methodsParamOffset(); constexpr int enumValueOffset = constructorParamIndex + constructorParamOffset(); #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) state.addInts(QT_VERSION >= QT_VERSION_CHECK(6, 2, 0) ? 10 : 9); // revision #else state.addInts(QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) ? 8 : 7); // revision #endif state.addString(ObjI::name); state.addStringUntracked(viewLiteral("")); state.addInts( ObjI::classInfoCount, classInfoOffset, // classinfo ObjI::methodCount, methodOffset, // methods ObjI::propertyCount, propertyOffset, // properties ObjI::enumCount, enumOffset, // enums/sets ObjI::constructorCount, constructorOffset, // constructors 0x4 /* PropertyAccessInStaticMetaCall */, // flags ObjI::signalCount); //if (state.intCount != classInfoOffset) throw "offset mismatch!"; foldState(ClassInfoGenerator{state}); #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) foldState(PropertyMetaTypeGenerator{state}); #endif #if QT_VERSION >= QT_VERSION_CHECK(6,2,0) state.template addMetaType(); #endif //if (state.intCount != methodOffset) throw "offset mismatch!"; foldMethods(MethodGenerator{state, paramIndex}); //if (state.intCount != propertyOffset) throw "offset mismatch!"; #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) foldState(PropertyGenerator{state}); #else foldState(PropertyGenerator{state}); foldState(NotifySignalGenerator{state}); #endif //if (state.intCount != enumOffset) throw "offset mismatch!"; foldState(EnumGenerator{state, enumValueOffset}); //if (state.intCount != constructorOffset) throw "offset mismatch!"; foldState(MethodGenerator{state, constructorParamIndex}); //if (state.intCount != paramIndex) throw "offset mismatch!"; foldMethods(MethodParametersGenerator{state}); //if (state.intCount != constructorParamIndex) throw "offset mismatch!"; foldState(ConstructorParametersGenerator{state}); //if (state.intCount != enumValueOffset) throw "offset mismatch!"; foldState(EnumValuesGenerator{state}); } #if __cplusplus > 201700L template constexpr LayoutBuilder dataLayout = [](){ auto r = LayoutBuilder{}; generateDataPass(r); return r; }(); #else template constexpr auto createLayout() { auto r = LayoutBuilder{}; generateDataPass(r); return r; } template constexpr LayoutBuilder dataLayout = createLayout(); #endif #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) struct OffsetLenPair { uint offset; uint length; }; #endif /// Final data holder template struct MetaDataHolder { #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) RawArray stringOffsetLens; #else RawArray byteArrays; #endif OwnArray stringChars; #if __cplusplus > 201700L const uint* ints; #else OwnArray ints; #endif }; template struct MetaDataProvider { static constexpr auto stringSize = dataLayout.stringSize; static constexpr auto stringCount = dataLayout.stringCount; static constexpr auto intCount = dataLayout.intCount; #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) static constexpr auto metaTypeCount = dataLayout.metaTypeCount == 0 ? 1 : dataLayout.metaTypeCount; #endif using MetaDataType = const MetaDataHolder; struct Arrays { #ifndef Q_CC_MSVC constexpr static qptrdiff stringOffset = offsetof(MetaDataType, stringChars); #else // offsetof does not work with MSVC #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) constexpr static qptrdiff stringOffset = sizeof(MetaDataType::stringOffsetLens); #else constexpr static qptrdiff stringOffset = sizeof(MetaDataType::byteArrays); #endif #endif RawArray stringOffsets{}; RawArray stringLengths{}; RawArray stringChars{}; RawArray ints{}; #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) RawArray metaTypes{}; #endif }; #if __cplusplus > 201700L constexpr static Arrays arrays = []() { auto r = Arrays{}; DataBuilder b{r}; generateDataPass(b); return r; }(); #else constexpr static auto buildArrays() { auto r = Arrays{}; DataBuilder b{r}; generateDataPass(b); return r; } constexpr static Arrays arrays = buildArrays(); #endif }; template struct MetaDataBuilder; template struct MetaDataBuilder> { using P = MetaDataProvider; using MetaDataType = typename P::MetaDataType; #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) constexpr static MetaDataType meta_data = { { OffsetLenPair{static_cast(P::arrays.stringOffsets[Is]), P::arrays.stringLengths[Is]}..., OffsetLenPair{static_cast(P::arrays.stringOffsets[sizeof...(Is)-1] + P::arrays.stringLengths[sizeof...(Is)-1]), 0}, }, P::arrays.stringChars, P::arrays.ints }; #elif __cplusplus > 201700L constexpr static MetaDataType meta_data = { {Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(P::arrays.stringLengths[Is], P::arrays.stringOffsets[Is])...}, P::arrays.stringChars, P::arrays.ints }; #else static MetaDataType meta_data; }; template typename MetaDataBuilder>::MetaDataType MetaDataBuilder>::meta_data = { {Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(P::arrays.stringLengths[Is], P::arrays.stringOffsets[Is])...}, {P::arrays.stringChars}, {P::arrays.ints} #endif }; /// Returns the QMetaObject* of the base type. Use SFINAE to only return it if it exists template static constexpr auto parentMetaObject(int) W_RETURN(&T::W_BaseType::staticMetaObject) template static constexpr const QMetaObject *parentMetaObject(...) { return nullptr; } // Bunch of helpers for propertyOperation // this uses SFINAE of the return value to work either with F a pointer to member, or to member function // or nullptr. template inline auto propSet(F f, O *o, const T &t) W_RETURN(((o->*f)(t),0)) template inline auto propSet(F f, O *o, const T &t) W_RETURN(o->*f = t) template inline void propSet(Empty, O *, const T &) {} template inline auto propGet(F f, O *o, T &t) W_RETURN(t = (o->*f)()) template inline auto propGet(F f, O *o, T &t) W_RETURN(t = o->*f) template inline void propGet(Empty, O *, T &) {} template inline auto propNotify(F f, M m, O *o) W_RETURN(((o->*f)(o->*m),0)) template inline auto propNotify(F f, M, O *o) W_RETURN(((o->*f)(),0)) template inline void propNotify(T...) {} template inline auto propReset(F f, O *o) W_RETURN(((o->*f)(),0)) template inline void propReset(T...) {} #if QT_VERSION >= QT_VERSION_CHECK(6,3,0) // note: Qt 6.3 introduced a check here that allows only QObjects - but we need it for Gadgets as well template struct FunctorCall; template struct FunctorCall, QtPrivate::List, R, Function> { static void call(Function f, void **arg) { f((*reinterpret_cast::Type *>(arg[II+1]))...), QtPrivate::ApplyReturnValue(arg[0]); } }; template struct FunctorCall, QtPrivate::List, R, SlotRet (Obj::*)(SlotArgs...)> { static void call(SlotRet (Obj::*f)(SlotArgs...), Obj *o, void **arg) { (o->*f)((*reinterpret_cast::Type *>(arg[II+1]))...), QtPrivate::ApplyReturnValue(arg[0]); } }; template struct FunctorCall, QtPrivate::List, R, SlotRet (Obj::*)(SlotArgs...) const> { static void call(SlotRet (Obj::*f)(SlotArgs...) const, Obj *o, void **arg) { (o->*f)((*reinterpret_cast::Type *>(arg[II+1]))...), QtPrivate::ApplyReturnValue(arg[0]); } }; template struct FunctorCall, QtPrivate::List, R, SlotRet (Obj::*)(SlotArgs...) noexcept> { static void call(SlotRet (Obj::*f)(SlotArgs...) noexcept, Obj *o, void **arg) { (o->*f)((*reinterpret_cast::Type *>(arg[II+1]))...), QtPrivate::ApplyReturnValue(arg[0]); } }; template struct FunctorCall, QtPrivate::List, R, SlotRet (Obj::*)(SlotArgs...) const noexcept> { static void call(SlotRet (Obj::*f)(SlotArgs...) const noexcept, Obj *o, void **arg) { (o->*f)((*reinterpret_cast::Type *>(arg[II+1]))...), QtPrivate::ApplyReturnValue(arg[0]); } }; #endif struct FriendHelper { template static constexpr QMetaObject createMetaObject() { using MetaData = MetaDataBuilder.stringCount>>; #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) using P = MetaDataProvider; return { { parentMetaObject(0), &MetaData::meta_data.stringOffsetLens[0].offset, MetaData::meta_data.ints, T::qt_static_metacall, nullptr, P::arrays.metaTypes, nullptr, } }; #elif __cplusplus > 201700L return { { parentMetaObject(0), MetaData::meta_data.byteArrays, MetaData::meta_data.ints, T::qt_static_metacall, {}, {} } }; #else return { { parentMetaObject(0), MetaData::meta_data.byteArrays, MetaData::meta_data.ints.data, T::qt_static_metacall, {}, {} } }; #endif } template static int qt_metacall_impl(T *_o, QMetaObject::Call _c, int _id, void** _a) { using ObjI = typename T::W_MetaObjectCreatorHelper::ObjectInfo; _id = _o->T::W_BaseType::qt_metacall(_c, _id, _a); if (_id < 0) return _id; if (_c == QMetaObject::InvokeMetaMethod || _c == QMetaObject::RegisterMethodArgumentMetaType) { constexpr int methodCount = ObjI::methodCount; if (_id < methodCount) T::qt_static_metacall(_o, _c, _id, _a); _id -= methodCount; } else if (isPropertyMetacall(_c)) { constexpr int propertyCount = ObjI::propertyCount; if (_id < propertyCount) T::qt_static_metacall(_o, _c, _id, _a); _id -= propertyCount; } return _id; } QT_WARNING_PUSH QT_WARNING_DISABLE_GCC("-Waddress") /// Helper for implementation of qt_static_metacall for QMetaObject::IndexOfMethod /// T is the class, and I is the index of a method. /// Returns I if the argument is equal to the pointer to member function of the signal of index 'I' template static int indexOfMethod(void **func) { using ObjI = typename T::W_MetaObjectCreatorHelper::ObjectInfo; constexpr auto m = ObjI::method(index); if ((m.flags & 0xc) == W_MethodType::Signal.value && m.func == *reinterpret_cast(func)) return I; return -1; } QT_WARNING_POP /// Helper for implementation of qt_static_metacall for QMetaObject::InvokeMetaMethod /// T is the class, and I is the index of a method. /// Invoke the method with index I if id == I. template static void invokeMethod(T *_o, int _id, void **_a) { if (_id == I) { using ObjI = typename T::W_MetaObjectCreatorHelper::ObjectInfo; constexpr auto method = ObjI::method(index); using Func = typename decltype(method)::Func; using FP = QtPrivate::FunctionPointer; #if QT_VERSION >= QT_VERSION_CHECK(6,3,0) if constexpr (FP::IsPointerToMemberFunction) { FunctorCall::call(method.func, _o, _a); } else { (void)_o; FunctorCall::call(method.func, _a); } #else FP::template call(method.func, _o, _a); #endif } } /// Helper for implementation of qt_static_metacall for QMetaObject::RegisterMethodArgumentMetaType /// T is the class, and I is the index of a method. template static void registerMethodArgumentType(int _id, void **_a) { if (_id == I) { using ObjI = typename T::W_MetaObjectCreatorHelper::ObjectInfo; constexpr auto f = ObjI::method(index).func; using P = QtPrivate::FunctionPointer>; auto _t = QtPrivate::ConnectionTypes::types(); uint arg = *reinterpret_cast(_a[1]); #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) *reinterpret_cast(_a[0]) = _t && arg < P::ArgumentCount ? QMetaType(_t[arg]) : QMetaType(); #else *reinterpret_cast(_a[0]) = _t && arg < P::ArgumentCount ? _t[arg] : -1; #endif } } /// Helper for implementation of qt_static_metacall for any of the operations in a property /// T is the class, and I is the index of a property. template static void propertyOperation(T *_o, QMetaObject::Call _c, int _id, void **_a) { if (_id != I) return; using TPP = T**; constexpr auto p = w_state(index, PropertyStateTag{}, TPP{}); using Type = typename decltype(p)::PropertyType; switch(+_c) { case QMetaObject::ReadProperty: if W_IF_CONSTEXPR (p.getter != nullptr) { propGet(p.getter, _o, *reinterpret_cast(_a[0])); } else if W_IF_CONSTEXPR (p.member != nullptr) { propGet(p.member, _o, *reinterpret_cast(_a[0])); } break; case QMetaObject::WriteProperty: if W_IF_CONSTEXPR (p.setter != nullptr) { propSet(p.setter, _o, *reinterpret_cast(_a[0])); } else if W_IF_CONSTEXPR (p.member != nullptr) { propSet(p.member, _o, *reinterpret_cast(_a[0])); propNotify(p.notify, p.member, _o); } break; case QMetaObject::ResetProperty: if W_IF_CONSTEXPR (p.reset != nullptr) { propReset(p.reset, _o); } break; case QMetaObject::RegisterPropertyMetaType: *reinterpret_cast(_a[0]) = QtPrivate::QMetaTypeIdHelper::qt_metatype_id(); } } /// Helper for implementation of qt_static_metacall for QMetaObject::CreateInstance /// T is the class, and I is the index of a constructor. template static void createInstanceImpl(void **_a, const MetaConstructorInfo&, index_sequence) { *reinterpret_cast(_a[0]) = new T(*reinterpret_cast *>(_a[I+1])...); } template static void createInstance(int _id, void** _a) { if (_id == I) { using TPP = T**; constexpr auto m = w_state(index, ConstructorStateTag{}, TPP{}); createInstanceImpl(_a, m, m.argSequence); } } /// Implementation of qt_static_metacall for W_OBJECT_IMPL which should be called with /// std::index_sequence for the amount of method, constructor, and properties. template static void qt_static_metacall_impl2(QObject *_o, QMetaObject::Call _c, int _id, void** _a, std::index_sequence, std::index_sequence, std::index_sequence) { Q_UNUSED(_id) Q_UNUSED(_o) Q_UNUSED(_a) if (_c == QMetaObject::InvokeMetaMethod) { Q_ASSERT(T::staticMetaObject.cast(_o)); #if __cplusplus > 201700L (invokeMethod(reinterpret_cast(_o), _id, _a),...); #else ordered((invokeMethod(reinterpret_cast(_o), _id, _a),0)...); #endif } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) { #if __cplusplus > 201700L (registerMethodArgumentType(_id, _a),...); #else ordered((registerMethodArgumentType(_id, _a),0)...); #endif } else if (_c == QMetaObject::IndexOfMethod) { #if __cplusplus > 201700L *reinterpret_cast(_a[0]) = ((1+indexOfMethod(reinterpret_cast(_a[1]))) + ... + 0)-1; #else auto r = int{-1}; ordered2({(r += (1+indexOfMethod(reinterpret_cast(_a[1]))))...}); *reinterpret_cast(_a[0]) = r; #endif } else if (_c == QMetaObject::CreateInstance) { #if __cplusplus > 201700L (createInstance(_id, _a),...); #else ordered((createInstance(_id, _a),0)...); #endif } else if (isPropertyMetacall(_c)) { #if __cplusplus > 201700L (propertyOperation(static_cast(_o), _c, _id, _a),...); #else ordered((propertyOperation(static_cast(_o), _c, _id, _a),0)...); #endif } } // Same for W_GADGET template static void qt_static_metacall_impl2(T *_o, QMetaObject::Call _c, int _id, void** _a, std::index_sequence, std::index_sequence, std::index_sequence) { Q_UNUSED(_id) Q_UNUSED(_o) Q_UNUSED(_a) if (_c == QMetaObject::InvokeMetaMethod) { #if __cplusplus > 201700L (invokeMethod(_o, _id, _a),...); #else ordered((invokeMethod(_o, _id, _a), 0)...); #endif } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) { #if __cplusplus > 201700L (registerMethodArgumentType(_id, _a),...); #else ordered((registerMethodArgumentType(_id, _a), 0)...); #endif } else if (_c == QMetaObject::IndexOfMethod) { Q_ASSERT_X(false, "qt_static_metacall", "IndexOfMethod called on a Q_GADGET"); } else if (_c == QMetaObject::CreateInstance) { #if __cplusplus > 201700L (createInstance(_id, _a),...); #else ordered((createInstance(_id, _a), 0)...); #endif } else if (isPropertyMetacall(_c)) { #if __cplusplus > 201700L (propertyOperation(_o, _c, _id, _a),...); #else ordered((propertyOperation(_o, _c, _id, _a), 0)...); #endif } } template static void qt_static_metacall_impl(Ts &&... args) { using ObjI = typename T::W_MetaObjectCreatorHelper::ObjectInfo; return qt_static_metacall_impl2(std::forward(args)..., ObjI::methodSequence, ObjI::constructorSequence, ObjI::propertySequence); } /// implementation of qt_metacast template static void* qt_metacast_impl(T *o, const char *_clname) { if (!_clname) return nullptr; #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) using MetaData = MetaDataBuilder.stringCount>>; if (!strcmp(_clname, MetaData::meta_data.stringChars.data)) return o; #else const QByteArrayDataPtr sd = { const_cast(T::staticMetaObject.d.stringdata) }; if (_clname == QByteArray(sd)) return o; #endif using ObjI = typename T::W_MetaObjectCreatorHelper::ObjectInfo; void *result = {}; auto l = [&](auto i) { using TPP = T**; using Interface = decltype(w_state(i, InterfaceStateTag{}, TPP{})); const char *iid = qobject_interface_iid(); if (iid && !strcmp(_clname, iid)) result = static_cast(o); }; fold(ObjI::interfaceSequence, l); if (!result) return o->T::W_BaseType::qt_metacast(_clname); return result; } }; // FriendHelper } // namespace w_internal #ifndef QT_INIT_METAOBJECT // Defined in qglobal.h since Qt 5.10 #define QT_INIT_METAOBJECT #endif // W_OBJECT_IMPL was designed to take advantage of the GNU extension that ... can have zero arguments. // So we need to work around that to extract the template stuff which may not exist or be composed // of several macro arguments: If the first argument has parentheses, there must be at least two // arguments, so just do a tail. Otherwise, there should be only one or two argument, so take the second. #define W_MACRO_TEMPLATE_STUFF(...) W_MACRO_CONCAT(W_MACRO_TEMPLATE_STUFF_HELPER, W_MACRO_DELAY(W_MACRO_TEMPLATE_STUFF_QUERY,W_MACRO_TEMPLATE_STUFF_HELPER __VA_ARGS__))(__VA_ARGS__) #define W_MACRO_TEMPLATE_STUFF_QUERY(...) W_MACRO_DELAY2(W_MACRO_FIRST, W_MACRO_TEMPLATE_STUFF_HELPER_ ## __VA_ARGS__) #define W_MACRO_TEMPLATE_STUFF_HELPER(...) YES #define W_MACRO_TEMPLATE_STUFF_HELPER_YES TAIL, #define W_MACRO_TEMPLATE_STUFF_HELPER_W_MACRO_TEMPLATE_STUFF_HELPER SECOND, #define W_MACRO_TEMPLATE_STUFF_HELPER_TAIL(...) W_MACRO_MSVC_EXPAND(W_MACRO_TAIL(__VA_ARGS__)) #define W_MACRO_TEMPLATE_STUFF_HELPER_SECOND(...) W_MACRO_MSVC_EXPAND(W_MACRO_TEMPLATE_STUFF_HELPER_SECOND2(__VA_ARGS__,,)) #define W_MACRO_TEMPLATE_STUFF_HELPER_SECOND2(A,B,...) B #define W_MACRO_FIRST_REMOVEPAREN(...) W_MACRO_REMOVEPAREN(W_MACRO_FIRST(__VA_ARGS__)) #define W_OBJECT_IMPL_COMMON(INLINE, ...) \ W_MACRO_TEMPLATE_STUFF(__VA_ARGS__) struct W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::W_MetaObjectCreatorHelper { \ struct Name { \ static constexpr auto defaultName = w_internal::viewLiteral(W_MACRO_STRIGNIFY(W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__))); \ static constexpr auto value = w_internal::fetchExplicitName(defaultName, 0); \ }; \ using ObjectInfo = w_internal::ObjectInfo; \ }; \ W_MACRO_TEMPLATE_STUFF(__VA_ARGS__) INLINE const QT_INIT_METAOBJECT QMetaObject W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::staticMetaObject = \ w_internal::FriendHelper::createMetaObject(); /// \macro W_OBJECT_IMPL(TYPE [, TEMPLATE_STUFF]) /// This macro expand to the code that instantiate the QMetaObject. It must be placed outside of /// the class, in the .cpp file. The TYPE argument must be the qualified name of the class, /// including the namespace, if any. /// Example: `W_OBJECT_IMPL(Namespace::MyClass)` /// /// If the class is a templated class, the second argument contains the template introducer. /// Example: `W_OBJECT_IMPL(MyTemplate, template )` /// Parentheses are required if there is several template arguments: /// `W_OBJECT_IMPL((MyTemplate2), template)` #define W_OBJECT_IMPL(...) \ W_OBJECT_IMPL_COMMON(W_MACRO_EMPTY, __VA_ARGS__) \ W_MACRO_TEMPLATE_STUFF(__VA_ARGS__) void W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void** _a) \ { w_internal::FriendHelper::qt_static_metacall_impl(_o, _c, _id, _a); } \ W_MACRO_TEMPLATE_STUFF(__VA_ARGS__) const QMetaObject *W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::metaObject() const \ { return this->QObject::d_ptr->metaObject ? this->QObject::d_ptr->dynamicMetaObject() : &staticMetaObject; } \ W_MACRO_TEMPLATE_STUFF(__VA_ARGS__) void *W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::qt_metacast(const char *_clname) \ { return w_internal::FriendHelper::qt_metacast_impl(this, _clname); } \ W_MACRO_TEMPLATE_STUFF(__VA_ARGS__) int W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::qt_metacall(QMetaObject::Call _c, int _id, void** _a) \ { return w_internal::FriendHelper::qt_metacall_impl(this, _c, _id, _a); } /// \macro W_GADGET_IMPL(TYPE [, TEMPLATE_STUFF]) /// Same as W_OBJECT_IMPL, but for a W_GADGET #define W_GADGET_IMPL(...) \ W_OBJECT_IMPL_COMMON(W_MACRO_EMPTY, __VA_ARGS__) \ W_MACRO_TEMPLATE_STUFF(__VA_ARGS__) void W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void** _a) \ { w_internal::FriendHelper::qt_static_metacall_impl(reinterpret_cast(_o), _c, _id, _a); } /// \macro W_NAMESPACE_IMPL(...) /// Same as W_OBJECT_IMPL, but for a W_NAMESPACE #define W_NAMESPACE_IMPL(...) \ W_OBJECT_IMPL_COMMON(W_MACRO_EMPTY, __VA_ARGS__) /// \macro W_OBJECT_IMPL_INLINE(TYPE [, TEMPLATE_STUFF]) /// Same as W_OBJECT_IMPL, but to be used in a header /// (Requires support for c++17 inline variables) #define W_OBJECT_IMPL_INLINE(...) \ W_OBJECT_IMPL_COMMON(inline, __VA_ARGS__) \ W_MACRO_TEMPLATE_STUFF(__VA_ARGS__) inline void W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void** _a) \ { w_internal::FriendHelper::qt_static_metacall_impl(_o, _c, _id, _a); } \ W_MACRO_TEMPLATE_STUFF(__VA_ARGS__) inline const QMetaObject *W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::metaObject() const \ { return this->QObject::d_ptr->metaObject ? this->QObject::d_ptr->dynamicMetaObject() : &staticMetaObject; } \ W_MACRO_TEMPLATE_STUFF(__VA_ARGS__) inline void *W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::qt_metacast(const char *_clname) \ { return w_internal::FriendHelper::qt_metacast_impl(this, _clname); } \ W_MACRO_TEMPLATE_STUFF(__VA_ARGS__) inline int W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::qt_metacall(QMetaObject::Call _c, int _id, void** _a) \ { return w_internal::FriendHelper::qt_metacall_impl(this, _c, _id, _a); } /// \macro W_GADGET_IMPL_INLINE(TYPE [, TEMPLATE_STUFF]) /// Same as W_GADGET_IMPL, but to be used in a header /// (Requires support for c++17 inline variables) #define W_GADGET_IMPL_INLINE(...) \ W_OBJECT_IMPL_COMMON(inline, __VA_ARGS__) \ W_MACRO_TEMPLATE_STUFF(__VA_ARGS__) inline void W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void** _a) \ { w_internal::FriendHelper::qt_static_metacall_impl(reinterpret_cast(_o), _c, _id, _a); } /// \macro W_NAMESPACE_IMPL_INLINE(...) /// Same as W_NAMESPACE_IMPL, but to be used in a header /// (Requires support for c++17 inline variables) #define W_NAMESPACE_IMPL_INLINE(...) \ W_OBJECT_IMPL_COMMON(inline, __VA_ARGS__) verdigris-1.3/tests/000077500000000000000000000000001427643277200145335ustar00rootroot00000000000000verdigris-1.3/tests/basic/000077500000000000000000000000001427643277200156145ustar00rootroot00000000000000verdigris-1.3/tests/basic/anothertu.cpp000066400000000000000000000017311427643277200203330ustar00rootroot00000000000000/**************************************************************************** * Copyright (C) 2018 Woboq GmbH * Olivier Goffart * https://woboq.com/ * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. * If not, see . */ #include "anothertu.h" W_GADGET_IMPL(AnotherTU::Gaga) #ifdef Q_NAMESPACE // Since Qt 5.8 W_NAMESPACE_IMPL(AnotherTU) #endif verdigris-1.3/tests/basic/anothertu.h000066400000000000000000000034361427643277200200040ustar00rootroot00000000000000/**************************************************************************** * Copyright (C) 2018 Woboq GmbH * Olivier Goffart * https://woboq.com/ * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. * If not, see . */ #pragma once #include #include namespace AnotherTU { struct Gaga { W_GADGET(Gaga) public: int m_foo; W_PROPERTY(int, foo MEMBER m_foo); }; struct InlineGadget { W_GADGET(InlineGadget) public: int m_foo; W_PROPERTY(int, foo MEMBER m_foo) }; struct InlineObject : QObject { W_OBJECT(InlineObject) public: int m_foo; W_PROPERTY(int, foo MEMBER m_foo) }; #ifdef Q_NAMESPACE // Since Qt 5.8 W_NAMESPACE(AnotherTU) enum ATTestEnum { Key1 = 31, Key2, Key3 }; W_ENUM_NS(ATTestEnum, Key1, Key2, Key3) #endif } #if defined (__cpp_inline_variables) && Q_CC_MSVC > 192000000 W_GADGET_IMPL_INLINE(AnotherTU::InlineGadget) W_OBJECT_IMPL_INLINE(AnotherTU::InlineObject) #ifdef Q_NAMESPACE // Since Qt 5.8 namespace Inline_NS { W_NAMESPACE(Inline_NS) enum InlineEnum { I1 = 45, I2 }; W_ENUM_NS(InlineEnum, I1, I2) } W_NAMESPACE_IMPL_INLINE(Inline_NS) #endif #endif verdigris-1.3/tests/basic/basic.pro000066400000000000000000000002541427643277200174200ustar00rootroot00000000000000CONFIG += testcase TARGET = tst_basic QT = core testlib include(../../src/verdigris.pri) SOURCES = tst_basic.cpp anothertu.cpp contains(QT_CONFIG, c++1z): CONFIG += c++1z verdigris-1.3/tests/basic/basic.qbs000066400000000000000000000006371427643277200174120ustar00rootroot00000000000000import qbs Application { name: "basic" consoleApplication: true type: ["application", "autotest"] Depends { name: "Verdigris" } Depends { name: "Qt.test" } Group { name: "source" fileTags: ["unmocable"] overrideTags: false files: [ "anothertu.cpp", "tst_basic.cpp", "anothertu.h", ] } } verdigris-1.3/tests/basic/tst_basic.cpp000066400000000000000000000337221427643277200203020ustar00rootroot00000000000000/**************************************************************************** * Copyright (C) 2013-2015 Woboq GmbH * Olivier Goffart * https://woboq.com/ * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. * If not, see . */ #include #include #include #include // only for compilation check #include "anothertu.h" class tst_Basic : public QObject { W_OBJECT(tst_Basic) struct SubObject; private slots: void firstTest(); W_SLOT(firstTest, W_Access::Private) void signalSlot_data(); W_SLOT(signalSlot_data, W_Access::Private) void signalSlot(); W_SLOT(signalSlot, W_Access::Private) void property_data(); W_SLOT(property_data, W_Access::Private) void property(); W_SLOT(property, W_Access::Private) void signalArgs(); W_SLOT(signalArgs, W_Access::Private) void overloadForm(); W_SLOT(overloadForm,(), W_Access::Private) void enumBase(); W_SLOT(enumBase, W_Access::Private) void subObject(); W_SLOT(subObject, W_Access::Private) void abstractParent(); W_SLOT(abstractParent, W_Access::Private) void testQNamespace(); W_SLOT(testQNamespace, W_Access::Private) void testAccess(); W_SLOT(testAccess, W_Access::Private) void testAnotherTU(); W_SLOT(testAnotherTU, W_Access::Private) void testFinal(); W_SLOT(testFinal, W_Access::Private) void overloadedAddressOperator(); W_SLOT(overloadedAddressOperator, W_Access::Private) }; #include #include W_OBJECT_IMPL(tst_Basic) void tst_Basic::firstTest() { QCOMPARE(metaObject()->className(), "tst_Basic"); QCOMPARE(metaObject()->superClass()->className(), "QObject"); } class BTestObj : public QObject { W_OBJECT(BTestObj) W_CONSTRUCTOR() QString value; public: void setValue(const QString &s) { value = s; emit valueChanged(s); } W_SLOT(setValue) void resetValue() { value = QString(); } W_SLOT(resetValue) QString getValue() const { return value; } enum XXX { X1, X2, X3 = 45 }; W_ENUM(XXX, X1, X2, X3) void setValueNoex(const QString &s) noexcept { value = s; emit valueChanged(s); } W_SLOT(setValueNoex) QString getValueNoex() const noexcept { return value; } public: /*signals*/ void valueChanged(const QString &s) W_SIGNAL(valueChanged, s) void simpleSignal() W_SIGNAL(simpleSignal) void signalSeveralArgs(int a, const QString &b, char * c = nullptr) W_SIGNAL(signalSeveralArgs, a, b, c) void anotherSignal() W_SIGNAL(anotherSignal) public: W_PROPERTY(QString, value1, &BTestObj::setValue, &BTestObj::getValue ) QString member; W_PROPERTY(QString, member1, &BTestObj::member) W_PROPERTY(QString, all, &BTestObj::value, &BTestObj::setValue, &BTestObj::getValue) W_PROPERTY(QString, notify1 MEMBER member NOTIFY simpleSignal) W_PROPERTY(QString, notify2 MEMBER member NOTIFY anotherSignal) W_PROPERTY(QString, valueNoex, &BTestObj::setValueNoex, &BTestObj::getValueNoex) }; W_OBJECT_IMPL(BTestObj) void tst_Basic::signalSlot_data() { QTest::addColumn("old"); QTest::newRow("old") << true; QTest::newRow("new") << false; } void tst_Basic::signalSlot() { BTestObj obj1, obj2; QFETCH(bool, old); if (old) { QVERIFY(connect(&obj1, SIGNAL(valueChanged(QString)), &obj2, SLOT(setValue(QString)))); QVERIFY(connect(&obj1, SIGNAL(simpleSignal()), &obj2, SLOT(resetValue()))); } else { QVERIFY(connect(&obj1, &BTestObj::valueChanged, &obj2, &BTestObj::setValue)); QVERIFY(connect(&obj1, &BTestObj::simpleSignal, &obj2, &BTestObj::resetValue)); } obj1.setValue("HOLLA"); QCOMPARE(obj2.getValue(), QString("HOLLA")); emit obj1.simpleSignal(); QCOMPARE(obj2.getValue(), QString()); } void tst_Basic::property_data() { QTest::addColumn("name"); QTest::newRow("value1") << QByteArrayLiteral("value1"); QTest::newRow("member1") << QByteArrayLiteral("member1"); QTest::newRow("all") << QByteArrayLiteral("all"); QTest::newRow("valueNoex") << QByteArrayLiteral("valueNoex"); } void tst_Basic::property() { QFETCH(QByteArray, name); BTestObj obj; QString str = "TRALAL"; QVERIFY(obj.setProperty(name, str)); QCOMPARE(obj.property(name), QVariant(str)); } void tst_Basic::signalArgs() { auto method = QMetaMethod::fromSignal(&BTestObj::signalSeveralArgs); QCOMPARE(method.parameterTypes(), (QByteArrayList{ "int", "QString", "char*" })); QCOMPARE(method.parameterNames(), (QByteArrayList{ "a", "b", "c" })); } struct My {}; class OverloadForm : public QObject { W_OBJECT(OverloadForm) public: int over1(My, int x) { return x; } W_SLOT(over1,(My,int)) int over1() const { return 34; } W_INVOKABLE(over1,()) }; W_OBJECT_IMPL(OverloadForm) void tst_Basic::overloadForm() { OverloadForm obj; int result; QVERIFY(QMetaObject::invokeMethod(&obj, "over1", Q_RETURN_ARG(int, result), Q_ARG(My, {}), Q_ARG(int, 23))); QCOMPARE(result, 23); QVERIFY(QMetaObject::invokeMethod(&obj, "over1", Q_RETURN_ARG(int, result))); QCOMPARE(result, 34); } void tst_Basic::enumBase() { QMetaEnum em = BTestObj::staticMetaObject.enumerator( BTestObj::staticMetaObject.indexOfEnumerator("XXX")); QVERIFY(em.isValid()); QCOMPARE(em.keyCount(), 3); } struct tst_Basic::SubObject : QObject { W_OBJECT(SubObject) public: void mySignal() W_SIGNAL(mySignal) }; W_OBJECT_IMPL(tst_Basic::SubObject) void tst_Basic::subObject() { QVERIFY(QMetaMethod::fromSignal(&tst_Basic::SubObject::mySignal).isValid()); } class AbstractClass : public QObject { W_OBJECT(AbstractClass) int prop; W_PROPERTY(int, prop MEMBER prop) public: void mySignal() W_SIGNAL(mySignal) virtual void pureSlot() = 0; W_SLOT(pureSlot) }; W_OBJECT_IMPL(AbstractClass) class ConcreateClass : public AbstractClass { W_OBJECT(ConcreateClass) int prop2; W_PROPERTY(int, prop2 MEMBER prop2) public: void mySignal2() W_SIGNAL(mySignal2) void pureSlot() override {} }; W_OBJECT_IMPL(ConcreateClass) void tst_Basic::abstractParent() { QVERIFY(QMetaMethod::fromSignal(&AbstractClass::mySignal).isValid()); QVERIFY(QMetaMethod::fromSignal(&ConcreateClass::mySignal2).isValid()); ConcreateClass cl; AbstractClass *ab = &cl; QCOMPARE(ab->metaObject()->superClass(), &AbstractClass::staticMetaObject); QVERIFY(ab->setProperty("prop", 8989)); QCOMPARE(ab->property("prop"), QVariant(8989)); } #ifdef Q_NAMESPACE // since Qt 5.8 namespace TestQNamespace { W_NAMESPACE(TestQNamespace) enum TestEnum1 { Key1 = 11, Key2 }; W_ENUM_NS(TestEnum1, Key1, Key2) enum TestFlag1 { None = 0, Flag1 = 1, Flag2 = 2, Any = Flag1 | Flag2 }; W_FLAG_NS(TestFlag1, None, Flag1, Flag2, Any) W_CLASSINFO_NS("Foo", "Bar") } W_NAMESPACE_IMPL(TestQNamespace) static void checkEnum(const QMetaEnum &enumerator, const QByteArray &name, const QVector> &keys) { QCOMPARE(name, QByteArray{enumerator.name()}); QCOMPARE(keys.size(), enumerator.keyCount()); for (int i = 0; i < enumerator.keyCount(); ++i) { QCOMPARE(keys[i].first, QByteArray{enumerator.key(i)}); QCOMPARE(keys[i].second, enumerator.value(i)); } } #endif void tst_Basic::testQNamespace() { #ifdef Q_NAMESPACE QCOMPARE(TestQNamespace::staticMetaObject.enumeratorCount(), 2); checkEnum(TestQNamespace::staticMetaObject.enumerator(0), "TestEnum1", {{"Key1", 11}, {"Key2", 12}}); checkEnum(TestQNamespace::staticMetaObject.enumerator(1), "TestFlag1", {{"None", 0}, {"Flag1", 1}, {"Flag2", 2}, {"Any", 1 | 2}}); QMetaEnum meta = QMetaEnum::fromType(); QVERIFY(meta.isValid()); QCOMPARE(meta.name(), "TestEnum1"); QCOMPARE(meta.enclosingMetaObject(), &TestQNamespace::staticMetaObject); QCOMPARE(meta.keyCount(), 2); QCOMPARE(TestQNamespace::staticMetaObject.classInfoCount(), 1); QMetaClassInfo info = TestQNamespace::staticMetaObject.classInfo(0); QCOMPARE(info.name(), "Foo"); QCOMPARE(info.value(), "Bar"); QCOMPARE(info.enclosingMetaObject(), &TestQNamespace::staticMetaObject); QCOMPARE(TestQNamespace::staticMetaObject.className(), "TestQNamespace"); QCOMPARE(AnotherTU::staticMetaObject.className(), "AnotherTU"); QCOMPARE(AnotherTU::staticMetaObject.enumeratorCount(), 1); QCOMPARE(AnotherTU::staticMetaObject.enumerator(0).name(), "ATTestEnum"); QCOMPARE(QMetaEnum::fromType().name(), "ATTestEnum"); #if defined (__cpp_inline_variables) && Q_CC_MSVC > 192000000 QCOMPARE(Inline_NS::staticMetaObject.className(), "Inline_NS"); QCOMPARE(Inline_NS::staticMetaObject.enumeratorCount(), 1); QCOMPARE(Inline_NS::staticMetaObject.enumerator(0).name(), "InlineEnum"); QCOMPARE(QMetaEnum::fromType().name(), "InlineEnum"); #endif #endif } struct TestAccess : QObject { W_OBJECT(TestAccess) public: void publicSlot(){} W_SLOT(publicSlot) void publicMethod(){} W_INVOKABLE(publicMethod) void forcePrivateSlot(){} W_SLOT(forcePrivateSlot, W_Access::Private) void forcePrivateMethod(){} W_INVOKABLE(forcePrivateMethod, W_Access::Private) protected: void protectedSlot(){} W_SLOT(protectedSlot) void protectedMethod(){} W_INVOKABLE(protectedMethod) private: void privateSlot(){} W_SLOT(privateSlot) void privateMethod(){} W_INVOKABLE(privateMethod) void forcePublicSlot(){} W_SLOT(forcePublicSlot, W_Access::Public) void forcePublicMethod(){} W_INVOKABLE(forcePublicMethod, W_Access::Public) }; W_OBJECT_IMPL(TestAccess) struct TestAccess2 final { W_GADGET(TestAccess2) private: void slot(int){} W_SLOT(slot, (int)) public: void slot(double){} W_SLOT(slot, (double)) }; W_GADGET_IMPL(TestAccess2) void tst_Basic::testAccess() { auto mo = &TestAccess::staticMetaObject; QCOMPARE(mo->method(mo->indexOfMethod("publicSlot()")).access(), QMetaMethod::Public); QCOMPARE(mo->method(mo->indexOfMethod("publicMethod()")).access(), QMetaMethod::Public); QCOMPARE(mo->method(mo->indexOfMethod("protectedSlot()")).access(), QMetaMethod::Protected); QCOMPARE(mo->method(mo->indexOfMethod("protectedMethod()")).access(), QMetaMethod::Protected); QCOMPARE(mo->method(mo->indexOfMethod("privateSlot()")).access(), QMetaMethod::Private); QCOMPARE(mo->method(mo->indexOfMethod("privateMethod()")).access(), QMetaMethod::Private); QCOMPARE(mo->method(mo->indexOfMethod("forcePublicSlot()")).access(), QMetaMethod::Public); QCOMPARE(mo->method(mo->indexOfMethod("forcePublicMethod()")).access(), QMetaMethod::Public); QCOMPARE(mo->method(mo->indexOfMethod("forcePrivateSlot()")).access(), QMetaMethod::Private); QCOMPARE(mo->method(mo->indexOfMethod("forcePrivateMethod()")).access(), QMetaMethod::Private); auto mo2 = &TestAccess2::staticMetaObject; QCOMPARE(mo2->method(mo2->indexOfMethod("slot(int)")).access(), QMetaMethod::Private); QCOMPARE(mo2->method(mo2->indexOfMethod("slot(double)")).access(), QMetaMethod::Public); } void tst_Basic::testAnotherTU() { auto mo = &AnotherTU::Gaga::staticMetaObject; QCOMPARE(mo->className(), "AnotherTU::Gaga"); #if defined (__cpp_inline_variables) && Q_CC_MSVC > 192000000 auto mo2 = &AnotherTU::InlineGadget::staticMetaObject; QCOMPARE(mo2->className(), "AnotherTU::InlineGadget"); auto mo3 = &AnotherTU::InlineObject::staticMetaObject; QCOMPARE(mo3->className(), "AnotherTU::InlineObject"); #endif } struct TestFinalObject final : public QObject { W_OBJECT(TestFinalObject) public: int foo() { return 0;} void setFoo(int) { } void fooChanged(int v) W_SIGNAL(fooChanged, v) W_PROPERTY(int, foo READ foo WRITE setFoo NOTIFY fooChanged) }; W_OBJECT_IMPL(TestFinalObject) struct TestFinalGadget final { W_GADGET(TestFinalGadget) public: int foo() { return 0;} void setFoo(int) { } W_PROPERTY(int, foo READ foo WRITE setFoo) }; W_GADGET_IMPL(TestFinalGadget) void tst_Basic::testFinal() { { auto mo = &TestFinalObject::staticMetaObject; QVERIFY(mo->property(mo->propertyOffset()).isFinal()); } { auto mo = &TestFinalGadget::staticMetaObject; QVERIFY(mo->property(mo->propertyOffset()).isFinal()); } { // Don't put final by default auto mo = &ConcreateClass::staticMetaObject; QVERIFY(!mo->property(mo->propertyOffset()).isFinal()); } } class OverloadedAddressOperator : public QObject { W_OBJECT(OverloadedAddressOperator) public: void* operator&() { return nullptr; } signals: void self(OverloadedAddressOperator &s) W_SIGNAL(self, s) public slots: void assertSelf(OverloadedAddressOperator &o) { QCOMPARE(std::addressof(o), this); testResult = (std::addressof(o) == this); } W_SLOT(assertSelf) public: bool testResult = false; }; W_REGISTER_ARGTYPE(OverloadedAddressOperator&) W_OBJECT_IMPL(OverloadedAddressOperator) void tst_Basic::overloadedAddressOperator() { OverloadedAddressOperator o; OverloadedAddressOperator *p = std::addressof(o); QCOMPARE(&o, static_cast(nullptr)); QVERIFY(p); QObject::connect(p, &OverloadedAddressOperator::self, p, &OverloadedAddressOperator::assertSelf); emit o.self(o); QVERIFY(o.testResult); } QTEST_MAIN(tst_Basic) verdigris-1.3/tests/cppapi/000077500000000000000000000000001427643277200160075ustar00rootroot00000000000000verdigris-1.3/tests/cppapi/cppapi.pro000066400000000000000000000002301427643277200200000ustar00rootroot00000000000000CONFIG += testcase TARGET = tst_cppapi QT = core testlib include(../../src/verdigris.pri) SOURCES = tst_cppapi.cpp msvc:QMAKE_CXXFLAGS += -permissive- verdigris-1.3/tests/cppapi/cppapi.qbs000066400000000000000000000003611427643277200177720ustar00rootroot00000000000000import qbs Application { name: "cppapi" consoleApplication: true type: ["application", "autotest"] Depends { name: "Verdigris" } Depends { name: "Qt.test" } files: [ "tst_cppapi.cpp", ] } verdigris-1.3/tests/cppapi/tst_cppapi.cpp000066400000000000000000000144341427643277200206670ustar00rootroot00000000000000#include #include #include #include class tst_CppApi : public QObject { W_OBJECT(tst_CppApi) #if !defined(Q_CC_GNU) || defined(Q_CC_CLANG) // GCC does not allow specialization // see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85282 enum class Level { Easy, Normal, Hard, }; template struct EnumInfos; template<> struct EnumInfos { constexpr static auto enumInfo = w_cpp::makeEnumInfo( w_cpp::viewLiteral("Level"), w_cpp::enum_sequence{}, w_cpp::StringViewArray<3>{ {w_cpp::viewLiteral("Easy"), w_cpp::viewLiteral("Normal"), w_cpp::viewLiteral("Hard")}}); }; W_CPP_ENUM(Level, EnumInfos) enum XXX { X1, X2, X3 = 45 }; template<> struct EnumInfos { constexpr static auto enumInfo = w_cpp::makeEnumInfo( w_cpp::viewLiteral("XXX"), w_cpp::enum_sequence{}, w_cpp::StringViewArray<3>{ {w_cpp::viewLiteral("X1"), w_cpp::viewLiteral("X2"), w_cpp::viewLiteral("X3")}}); }; W_CPP_ENUM(XXX, EnumInfos) private slots: void enumBase(); W_SLOT(enumBase, W_Access::Private) void firstTest(); W_SLOT(firstTest, W_Access::Private) void notifyTest(); W_SLOT(notifyTest, W_Access::Private) private: QString m_name{}; Level m_level{}; public: int m_age{}; public: QString getName() const { return m_name; } Level getLevel() const { return m_level; } template void notifyPropertyChanged() { W_CPP_SIGNAL_IMPL(decltype (&tst_CppApi::notifyPropertyChanged), MySignals, I, 0); } #if __cplusplus > 201700L template static constexpr auto signalName() { if constexpr (I == 0) return w_cpp::viewLiteral("nameChanged"); else if constexpr (I == 1) return w_cpp::viewLiteral("ageChanged"); else if constexpr (I == 2) return w_cpp::viewLiteral("levelChanged"); } template> struct MySignals { constexpr static auto signal = w_cpp::makeSignalBuilder(signalName(), &tst_CppApi::notifyPropertyChanged).build(); }; #else template struct MySignals; template<> struct MySignals<0> { constexpr static auto signal = w_cpp::makeSignalBuilder(w_cpp::viewLiteral("nameChanged"), &tst_CppApi::notifyPropertyChanged<0>).build(); }; template<> struct MySignals<1> { constexpr static auto signal = w_cpp::makeSignalBuilder(w_cpp::viewLiteral("ageChanged"), &tst_CppApi::notifyPropertyChanged<1>).build(); }; template<> struct MySignals<2> { constexpr static auto signal = w_cpp::makeSignalBuilder(w_cpp::viewLiteral("levelChanged"), &tst_CppApi::notifyPropertyChanged<2>).build(); }; #endif W_CPP_SIGNAL(MySignals) private: #if __cplusplus > 201700L template> struct MyProperties { constexpr static auto property = []{ using namespace w_cpp; if constexpr (I == 0) { return makeProperty(viewLiteral("name"), viewLiteral("QString")) .setGetter(&tst_CppApi::getName) .setNotify(&tst_CppApi::notifyPropertyChanged<0>); } else if constexpr (I == 1) { return makeProperty(viewLiteral("age"), viewLiteral("int")) .setMember(&tst_CppApi::m_age) .setNotify(&tst_CppApi::notifyPropertyChanged<1>); } else if constexpr (I == 2) { return makeProperty(viewLiteral("level"), viewLiteral("Level")) .setMember(&tst_CppApi::getLevel) .setNotify(&tst_CppApi::notifyPropertyChanged<2>); } }(); }; #else template struct MyProperties; template<> struct MyProperties<0> { constexpr static auto property = w_cpp::makeProperty(w_cpp::viewLiteral("name"), w_cpp::viewLiteral("QString")) .setGetter(&tst_CppApi::getName) .setNotify(&tst_CppApi::notifyPropertyChanged<0>); }; template<> struct MyProperties<1> { constexpr static auto property = w_cpp::makeProperty(w_cpp::viewLiteral("age"), w_cpp::viewLiteral("int")) .setMember(&tst_CppApi::m_age) .setNotify(&tst_CppApi::notifyPropertyChanged<1>); }; template<> struct MyProperties<2> { constexpr static auto property = w_cpp::makeProperty(w_cpp::viewLiteral("level"), w_cpp::viewLiteral("Level")) .setGetter(&tst_CppApi::getLevel) .setNotify(&tst_CppApi::notifyPropertyChanged<2>); }; #endif W_CPP_PROPERTY(MyProperties) }; void tst_CppApi::firstTest() { const QMetaObject *mo = metaObject(); QMetaProperty prop = mo->property(mo->indexOfProperty("name")); QVERIFY(prop.isValid()); QVERIFY(!prop.isConstant()); m_name = "Hello"; auto v = prop.read(this); QCOMPARE(QVariant(m_name), v); prop = mo->property(mo->indexOfProperty("age")); QVERIFY(prop.isValid()); QVERIFY(!prop.isConstant()); prop.write(this, 23); QCOMPARE(23, m_age); } void tst_CppApi::notifyTest() { bool notified0 = false; auto conn0 = connect(this, &tst_CppApi::notifyPropertyChanged<0>, [&](){ notified0 = true; }); notifyPropertyChanged<0>(); QVERIFY(notified0); bool notified1 = false; auto conn1 = connect(this, &tst_CppApi::notifyPropertyChanged<1>, [&](){ notified1 = true; }); setProperty("age", 100); QVERIFY(notified1); disconnect(conn0); disconnect(conn1); } void tst_CppApi::enumBase() { QMetaEnum em = tst_CppApi::staticMetaObject.enumerator( tst_CppApi::staticMetaObject.indexOfEnumerator("XXX")); QVERIFY(em.isValid()); QCOMPARE(em.keyCount(), 3); } #else // Q_CC_GNU }; #endif W_OBJECT_IMPL(tst_CppApi) QTEST_MAIN(tst_CppApi) verdigris-1.3/tests/internal/000077500000000000000000000000001427643277200163475ustar00rootroot00000000000000verdigris-1.3/tests/internal/internal.pro000066400000000000000000000001701427643277200207030ustar00rootroot00000000000000CONFIG += testcase TARGET = tst_internal QT = core testlib include(../../src/verdigris.pri) SOURCES = tst_internal.cpp verdigris-1.3/tests/internal/internal.qbs000066400000000000000000000003641427643277200206750ustar00rootroot00000000000000import qbs Application { name: "internal" consoleApplication: true type: ["application", "autotest"] Depends { name: "Verdigris" } Depends { name: "Qt.test" } files: [ "tst_internal.cpp" ] } verdigris-1.3/tests/internal/tst_internal.cpp000066400000000000000000000046041427643277200215650ustar00rootroot00000000000000/**************************************************************************** * Copyright (C) 2016-2018 Woboq GmbH * Olivier Goffart * https://woboq.com/ * * This file is part of Verdigris: a way to use Qt without moc. * https://github.com/woboq/verdigris * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. * If not, see . */ // Just some unit test for internal functions #include #include namespace w_internal { constexpr auto operator==(StringView a, StringView b) { if (a.size() != b.size()) return false; for (auto i = 0u; i < a.size() && i < b.size(); i++) if (a.b[i] != b.b[i]) return false; return true; } static_assert (countParsedLiterals(" a ")==1, ""); static_assert (countParsedLiterals(" a, b ")==2, ""); static_assert (countParsedLiterals(",")==0, ""); static_assert (viewParsedLiterals<2>("H, el")[0] == viewLiteral("H"), ""); static_assert (viewParsedLiterals<2>("H, el")[1] == viewLiteral("el"), ""); static_assert (viewParsedLiterals<2>(" c H , , el")[0] == viewLiteral("c H"), ""); static_assert (viewParsedLiterals<2>(" H , , el")[1] == viewLiteral("el"), ""); static_assert (viewScopedLiterals<1>("one")[0] == viewLiteral("one"), ""); static_assert (viewScopedLiterals<1>("::two")[0] == viewLiteral("two"), ""); static_assert (viewScopedLiterals<1>(" hallo::one ")[0] == viewLiteral("one"), ""); static_assert (viewScopedLiterals<1>("x::h:: two ")[0] == viewLiteral("two"), ""); } namespace testEnum { enum ME1 {}; enum class ME2 {}; static_assert(w_internal::EnumIsScoped::Value == 0, ""); static_assert(w_internal::EnumIsScoped::Value == 2, ""); } class tst_Internal : public QObject { W_OBJECT(tst_Internal) private slots: }; W_OBJECT_IMPL(tst_Internal) QTEST_MAIN(tst_Internal) verdigris-1.3/tests/manyproperties/000077500000000000000000000000001427643277200176145ustar00rootroot00000000000000verdigris-1.3/tests/manyproperties/manyproperties.pro000066400000000000000000000002041427643277200234130ustar00rootroot00000000000000CONFIG += testcase TARGET = tst_manyproperties QT = core testlib include(../../src/verdigris.pri) SOURCES = tst_manyproperties.cpp verdigris-1.3/tests/manyproperties/manyproperties.qbs000066400000000000000000000004011427643277200233770ustar00rootroot00000000000000import qbs Application { name: "manyproperties" consoleApplication: true type: ["application", "autotest"] Depends { name: "Verdigris" } Depends { name: "Qt.test" } files: [ "tst_manyproperties.cpp", ] } verdigris-1.3/tests/manyproperties/tst_manyproperties.cpp000066400000000000000000000115311427643277200242740ustar00rootroot00000000000000/**************************************************************************** * Copyright (C) 2018 Woboq GmbH * Olivier Goffart * https://woboq.com/ * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. * If not, see . */ #include #include class tst_ManyProperties : public QObject { W_OBJECT(tst_ManyProperties) private slots: void manyProperties(); W_SLOT(manyProperties) }; class HasManyProperties : public QObject { W_OBJECT(HasManyProperties) public: #define DeclareProperty(Type, Name) \ Type m_##Name; \ void Name##Changed() W_SIGNAL(Name##Changed) \ W_PROPERTY(Type, Name MEMBER m_##Name NOTIFY Name##Changed) \ DeclareProperty(QString, prop0) DeclareProperty(QString, prop1) DeclareProperty(QString, prop2) DeclareProperty(QString, prop3) DeclareProperty(QString, prop4) DeclareProperty(QString, prop5) DeclareProperty(QString, prop6) DeclareProperty(QString, prop7) DeclareProperty(QString, prop8) DeclareProperty(QString, prop9) DeclareProperty(QString, prop10) DeclareProperty(QString, prop11) DeclareProperty(QString, prop12) DeclareProperty(QString, prop13) DeclareProperty(QString, prop14) DeclareProperty(QString, prop15) DeclareProperty(QString, prop16) DeclareProperty(QString, prop17) DeclareProperty(QString, prop18) DeclareProperty(QString, prop19) DeclareProperty(QString, prop20) DeclareProperty(QString, prop21) DeclareProperty(QString, prop22) DeclareProperty(QString, prop23) DeclareProperty(QString, prop24) DeclareProperty(QString, prop25) DeclareProperty(QString, prop26) DeclareProperty(QString, prop27) DeclareProperty(QString, prop28) DeclareProperty(QString, prop29) DeclareProperty(QString, prop30) DeclareProperty(QString, prop31) DeclareProperty(QString, prop32) DeclareProperty(QString, prop33) DeclareProperty(QString, prop34) DeclareProperty(QString, prop35) DeclareProperty(QString, prop36) DeclareProperty(QString, prop37) DeclareProperty(QString, prop38) DeclareProperty(QString, prop39) DeclareProperty(QString, prop40) DeclareProperty(QString, prop41) DeclareProperty(QString, prop42) DeclareProperty(QString, prop43) DeclareProperty(QString, prop44) DeclareProperty(QString, prop45) DeclareProperty(QString, prop46) DeclareProperty(QString, prop47) DeclareProperty(QString, prop48) DeclareProperty(QString, prop49) DeclareProperty(QString, prop50) DeclareProperty(QString, prop51) DeclareProperty(QString, prop52) DeclareProperty(QString, prop53) DeclareProperty(QString, prop54) DeclareProperty(QString, prop55) DeclareProperty(QString, prop56) DeclareProperty(QString, prop57) DeclareProperty(QString, prop58) DeclareProperty(QString, prop59) DeclareProperty(QString, prop60) DeclareProperty(int, intProp0) }; #include W_OBJECT_IMPL(tst_ManyProperties) W_OBJECT_IMPL(HasManyProperties) void tst_ManyProperties::manyProperties() { HasManyProperties obj; { // test that the corresponding signal is emitted when setting a prop bool ok = false; auto c = connect(&obj, &HasManyProperties::prop11Changed, [&ok] { ok = true; }); QVERIFY(obj.setProperty("prop45", QStringLiteral("yo"))); QCOMPARE(ok, false); QVERIFY(obj.setProperty("prop11", QStringLiteral("salut"))); QCOMPARE(ok, true); QCOMPARE(obj.property("prop11"), QVariant(QStringLiteral("salut"))); disconnect(c); } { QMetaProperty prop = obj.metaObject()->property(obj.metaObject()->indexOfProperty("prop34")); QCOMPARE(prop.name(), "prop34"); QCOMPARE(prop.typeName(), "QString"); QCOMPARE(prop.hasNotifySignal(), true); QCOMPARE(prop.notifySignal().name(), QByteArray("prop34Changed")); } { QMetaProperty prop = obj.metaObject()->property(obj.metaObject()->indexOfProperty("intProp0")); QCOMPARE(prop.name(), "intProp0"); QCOMPARE(prop.typeName(), "int"); QCOMPARE(prop.hasNotifySignal(), true); QCOMPARE(prop.notifySignal().name(), QByteArray("intProp0Changed")); } } QTEST_MAIN(tst_ManyProperties) verdigris-1.3/tests/qt/000077500000000000000000000000001427643277200151575ustar00rootroot00000000000000verdigris-1.3/tests/qt/README000066400000000000000000000020271427643277200160400ustar00rootroot00000000000000The tests here are modified version of the test within Qt. The branch `tests_from_qt` contains the tests from Qt as is and is updated and merged into master. Here is the method used to update the tests: ``` export QTBASE=~/path/to/qt/sources/qtbase git checkout tests_from_qt # remove the previous tests, and replace it by the newer test from Qt rm -r qmetamethod qmetaproperty qmetaobject qobject qmetaenum cp -r $QTBASE/tests/auto/corelib/kernel/qmetamethod . cp -r $QTBASE/tests/auto/corelib/kernel/qmetaproperty . cp -r $QTBASE/tests/auto/corelib/kernel/qmetaobject . cp -r $QTBASE/tests/auto/corelib/kernel/qobject . cp -r $QTBASE/tests/auto/corelib/kernel/qmetaenum . # check if you need to add files maybe? git status git commit -a git checkout master git merge tests_from_qt # Fix conflicts and adapt to verdigris ``` The tests are still supposed to work with older Qt version, so tests that test Qt behavior should be wrapped with `#if QT_VERSION >= QT_VERSION_CHECK(5, X, 0)` or be skipped with old version verdigris-1.3/tests/qt/qmetaenum/000077500000000000000000000000001427643277200171535ustar00rootroot00000000000000verdigris-1.3/tests/qt/qmetaenum/qmetaenum.pro000066400000000000000000000001741427643277200216730ustar00rootroot00000000000000CONFIG += testcase TARGET = tst_qmetaenum QT = core testlib SOURCES = tst_qmetaenum.cpp include(../../../src/verdigris.pri) verdigris-1.3/tests/qt/qmetaenum/qmetaenum.qbs000066400000000000000000000003671427643277200216640ustar00rootroot00000000000000import qbs Application { name: "qmetaenum" consoleApplication: true type: ["application", "autotest"] Depends { name: "Verdigris" } Depends { name: "Qt.test" } files: [ "tst_qmetaenum.cpp", ] } verdigris-1.3/tests/qt/qmetaenum/tst_qmetaenum.cpp000066400000000000000000000104761427643277200225550ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2015 Olivier Goffart ** 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 #include #include #include "wobjectimpl.h" class tst_QMetaEnum : public QObject { W_OBJECT(tst_QMetaEnum) public: enum SuperEnum { SuperValue1 = 1 , SuperValue2 = 2 }; enum Flag { Flag1 = 1 , Flag2 = 2 }; W_DECLARE_FLAGS(Flags, Flag) W_ENUM(SuperEnum, SuperValue1, SuperValue2) W_FLAG(Flags, Flag1, Flag2) private: void fromType(); W_SLOT(fromType) void valuesToKeys_data(); W_SLOT(valuesToKeys_data) void valuesToKeys(); W_SLOT(valuesToKeys) void defaultConstructed(); W_SLOT(defaultConstructed) }; W_OBJECT_IMPL(tst_QMetaEnum) void tst_QMetaEnum::fromType() { QMetaEnum meta = QMetaEnum::fromType(); QVERIFY(meta.isValid()); QVERIFY(!meta.isFlag()); QCOMPARE(meta.name(), "SuperEnum"); #if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) QCOMPARE(meta.enumName(), "SuperEnum"); #endif QCOMPARE(meta.enclosingMetaObject(), &staticMetaObject); QCOMPARE(meta.keyCount(), 2); meta = QMetaEnum::fromType(); QVERIFY(meta.isValid()); QVERIFY(meta.isFlag()); QCOMPARE(meta.name(), "Flags"); #if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) QCOMPARE(meta.enumName(), "Flag"); #endif QCOMPARE(meta.enclosingMetaObject(), &staticMetaObject); QCOMPARE(meta.keyCount(), 2); } Q_DECLARE_METATYPE(Qt::WindowFlags) void tst_QMetaEnum::valuesToKeys_data() { QTest::addColumn("windowFlags"); QTest::addColumn("expected"); QTest::newRow("Window") << Qt::WindowFlags(Qt::Window) << QByteArrayLiteral("Window"); // Verify that Qt::Dialog does not cause 'Window' to appear in the output. QTest::newRow("Frameless_Dialog") << (Qt::Dialog | Qt::FramelessWindowHint) << QByteArrayLiteral("Dialog|FramelessWindowHint"); // Similarly, Qt::WindowMinMaxButtonsHint should not show up as // WindowMinimizeButtonHint|WindowMaximizeButtonHint QTest::newRow("Tool_MinMax_StaysOnTop") << (Qt::Tool | Qt::WindowMinMaxButtonsHint | Qt::WindowStaysOnTopHint) << QByteArrayLiteral("Tool|WindowMinMaxButtonsHint|WindowStaysOnTopHint"); } void tst_QMetaEnum::valuesToKeys() { QFETCH(Qt::WindowFlags, windowFlags); QFETCH(QByteArray, expected); QMetaEnum me = QMetaEnum::fromType(); QCOMPARE(me.valueToKeys(windowFlags), expected); } void tst_QMetaEnum::defaultConstructed() { QMetaEnum e; QVERIFY(!e.isValid()); #if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0) QVERIFY(!e.isScoped()); #endif QVERIFY(!e.isFlag()); QCOMPARE(QByteArray(e.name()), QByteArray()); } Q_STATIC_ASSERT(QtPrivate::IsQEnumHelper::Value); Q_STATIC_ASSERT(QtPrivate::IsQEnumHelper::Value); Q_STATIC_ASSERT(QtPrivate::IsQEnumHelper::Value); Q_STATIC_ASSERT(!QtPrivate::IsQEnumHelper::Value); Q_STATIC_ASSERT(!QtPrivate::IsQEnumHelper::Value); Q_STATIC_ASSERT(!QtPrivate::IsQEnumHelper::Value); Q_STATIC_ASSERT(!QtPrivate::IsQEnumHelper::Value); QTEST_MAIN(tst_QMetaEnum) verdigris-1.3/tests/qt/qmetamethod/000077500000000000000000000000001427643277200174675ustar00rootroot00000000000000verdigris-1.3/tests/qt/qmetamethod/qmetamethod.pro000066400000000000000000000003501427643277200225170ustar00rootroot00000000000000CONFIG += testcase TARGET = tst_qmetamethod QT = core testlib greaterThan(QT_MAJOR_VERSION, 5) { SOURCES = tst_qmetamethod6.cpp } else { SOURCES = tst_qmetamethod5.cpp } mac:CONFIG -= app_bundle include(../../../src/verdigris.pri) verdigris-1.3/tests/qt/qmetamethod/qmetamethod.qbs000066400000000000000000000007671427643277200225200ustar00rootroot00000000000000import qbs Application { name: "qmetamethod" consoleApplication: true type: ["application", "autotest"] Depends { name: "Verdigris" } Depends { name: "Qt.test" } Group { name: "qt5" condition: Qt.core.versionMajor < 6 files: [ "tst_qmetamethod5.cpp", ] } Group { name: "qt6" condition: Qt.core.versionMajor >= 6 files: [ "tst_qmetamethod6.cpp", ] } } verdigris-1.3/tests/qt/qmetamethod/tst_qmetamethod5.cpp000066400000000000000000001073741427643277200234760ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2014 Olivier Goffart ** 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 #include #include #include "wobjectimpl.h" class tst_QMetaMethod : public QObject { W_OBJECT(tst_QMetaMethod) private slots: void method_data(); W_SLOT(method_data, W_Access::Private) void method(); W_SLOT(method, W_Access::Private) void invalidMethod(); W_SLOT(invalidMethod, W_Access::Private) void comparisonOperators(); W_SLOT(comparisonOperators, W_Access::Private) void fromSignal(); W_SLOT(fromSignal, W_Access::Private) void gadget(); W_SLOT(gadget, W_Access::Private) }; struct CustomType { }; Q_DECLARE_METATYPE(CustomType) W_REGISTER_ARGTYPE(CustomType) struct CustomUnregisteredType { }; W_REGISTER_ARGTYPE(CustomUnregisteredType) Q_DECLARE_METATYPE(QMetaMethod::Access) Q_DECLARE_METATYPE(QMetaMethod::MethodType) class MethodTestObject : public QObject { W_OBJECT(MethodTestObject) public: MethodTestObject(); MethodTestObject(int constructorIntArg); MethodTestObject(qreal constructorQRealArg); MethodTestObject(const QString &constructorQStringArg); MethodTestObject(CustomType constructorCustomTypeArg); MethodTestObject(CustomUnregisteredType constructorCustomUnregisteredTypeArg); MethodTestObject(bool boolArg, int intArg, uint uintArg, qlonglong longlongArg, qulonglong ulonglongArg, double doubleArg, long longArg, short shortArg, char charArg, ulong ulongArg, ushort ushortArg, uchar ucharArg, float floatArg); MethodTestObject(bool, int); W_CONSTRUCTOR(); W_CONSTRUCTOR(int); W_CONSTRUCTOR(qreal); W_CONSTRUCTOR(QString); W_CONSTRUCTOR(CustomType); W_CONSTRUCTOR(CustomUnregisteredType); W_CONSTRUCTOR(bool, int, uint, qlonglong, qulonglong, double, long, short, char, ulong, ushort, uchar, float); W_CONSTRUCTOR(bool, int); void voidInvokable(); W_INVOKABLE(voidInvokable) void voidInvokableInt(int voidInvokableIntArg); W_INVOKABLE(voidInvokableInt) void voidInvokableQReal(qreal voidInvokableQRealArg); W_INVOKABLE(voidInvokableQReal) void voidInvokableQString(const QString &voidInvokableQStringArg); W_INVOKABLE(voidInvokableQString) void voidInvokableCustomType(CustomType voidInvokableCustomTypeArg); W_INVOKABLE(voidInvokableCustomType) void voidInvokableCustomUnregisteredType(CustomUnregisteredType voidInvokableCustomUnregisteredTypeArg); W_INVOKABLE(voidInvokableCustomUnregisteredType) bool boolInvokable(); W_INVOKABLE(boolInvokable) qreal qrealInvokable(); W_INVOKABLE(qrealInvokable) QString qstringInvokable(); W_INVOKABLE(qstringInvokable) CustomType customTypeInvokable(); W_INVOKABLE(customTypeInvokable) CustomUnregisteredType customUnregisteredTypeInvokable(); W_INVOKABLE(customUnregisteredTypeInvokable) QVariant qvariantInvokableBoolIntUIntLonglongULonglongDoubleLongShortCharUlongUshortUcharFloat( bool boolArg, int intArg, uint uintArg, qlonglong longlongArg, qulonglong ulonglongArg, double doubleArg, long longArg, short shortArg, char charArg, ulong ulongArg, ushort ushortArg, uchar ucharArg, float floatArg); W_INVOKABLE(qvariantInvokableBoolIntUIntLonglongULonglongDoubleLongShortCharUlongUshortUcharFloat) void voidInvokableNoParameterNames(bool, int); W_INVOKABLE(voidInvokableNoParameterNames) public slots: void voidSlot(); W_SLOT(voidSlot) void voidSlotInt(int voidSlotIntArg); W_SLOT(voidSlotInt) void voidSlotQReal(qreal voidSlotQRealArg); W_SLOT(voidSlotQReal) void voidSlotQString(const QString &voidSlotQStringArg); W_SLOT(voidSlotQString) void voidSlotCustomType(CustomType voidSlotCustomTypeArg); W_SLOT(voidSlotCustomType) void voidSlotCustomUnregisteredType(CustomUnregisteredType voidSlotCustomUnregisteredTypeArg); W_SLOT(voidSlotCustomUnregisteredType) bool boolSlot(); W_SLOT(boolSlot) qreal qrealSlot(); W_SLOT(qrealSlot) QString qstringSlot(); W_SLOT(qstringSlot) CustomType customTypeSlot(); W_SLOT(customTypeSlot) CustomUnregisteredType customUnregisteredTypeSlot(); W_SLOT(customUnregisteredTypeSlot) QVariant qvariantSlotBoolIntUIntLonglongULonglongDoubleLongShortCharUlongUshortUcharFloat( bool boolArg, int intArg, uint uintArg, qlonglong longlongArg, qulonglong ulonglongArg, double doubleArg, long longArg, short shortArg, char charArg, ulong ulongArg, ushort ushortArg, uchar ucharArg, float floatArg); W_SLOT(qvariantSlotBoolIntUIntLonglongULonglongDoubleLongShortCharUlongUshortUcharFloat) void voidSlotNoParameterNames(bool, int); W_SLOT(voidSlotNoParameterNames) signals: void voidSignal() W_SIGNAL(voidSignal) void voidSignalVoid(void) W_SIGNAL(voidSignalVoid) void voidSignalInt(int voidSignalIntArg) W_SIGNAL(voidSignalInt,voidSignalIntArg) void voidSignalQReal(qreal voidSignalQRealArg) W_SIGNAL(voidSignalQReal,voidSignalQRealArg) void voidSignalQString(const QString &voidSignalQStringArg) W_SIGNAL(voidSignalQString,voidSignalQStringArg) void voidSignalCustomType(CustomType voidSignalCustomTypeArg) W_SIGNAL(voidSignalCustomType,voidSignalCustomTypeArg) void voidSignalCustomUnregisteredType(CustomUnregisteredType voidSignalCustomUnregisteredTypeArg) W_SIGNAL(voidSignalCustomUnregisteredType,voidSignalCustomUnregisteredTypeArg) bool boolSignal() W_SIGNAL(boolSignal) qreal qrealSignal() W_SIGNAL(qrealSignal) QString qstringSignal() W_SIGNAL(qstringSignal) CustomType customTypeSignal() W_SIGNAL(customTypeSignal) CustomUnregisteredType customUnregisteredTypeSignal() W_SIGNAL(customUnregisteredTypeSignal) QVariant qvariantSignalBoolIntUIntLonglongULonglongDoubleLongShortCharUlongUshortUcharFloat( bool boolArg, int intArg, uint uintArg, qlonglong longlongArg, qulonglong ulonglongArg, double doubleArg, long longArg, short shortArg, char charArg, ulong ulongArg, ushort ushortArg, uchar ucharArg, float floatArg) W_SIGNAL(qvariantSignalBoolIntUIntLonglongULonglongDoubleLongShortCharUlongUshortUcharFloat, boolArg, intArg, uintArg, longlongArg, ulonglongArg, doubleArg, longArg, shortArg, charArg, ulongArg, ushortArg, ucharArg, floatArg) void voidSignalNoParameterNames(bool _1, int _2) W_SIGNAL(voidSignalNoParameterNames, _1, _2) }; MethodTestObject::MethodTestObject() {} MethodTestObject::MethodTestObject(int) {} MethodTestObject::MethodTestObject(qreal) {} MethodTestObject::MethodTestObject(const QString &) {} MethodTestObject::MethodTestObject(CustomType) {} MethodTestObject::MethodTestObject(CustomUnregisteredType) {} MethodTestObject::MethodTestObject(bool, int, uint, qlonglong, qulonglong, double, long, short, char, ulong, ushort, uchar, float) {} MethodTestObject::MethodTestObject(bool, int) {} void MethodTestObject::voidInvokable() {} void MethodTestObject::voidInvokableInt(int) {} void MethodTestObject::voidInvokableQReal(qreal) {} void MethodTestObject::voidInvokableQString(const QString &) {} void MethodTestObject::voidInvokableCustomType(CustomType) {} void MethodTestObject::voidInvokableCustomUnregisteredType(CustomUnregisteredType) {} bool MethodTestObject::boolInvokable() { return true; } qreal MethodTestObject::qrealInvokable() { return 1.0; } QString MethodTestObject::qstringInvokable() { return QString(); } CustomType MethodTestObject::customTypeInvokable() { return CustomType(); } CustomUnregisteredType MethodTestObject::customUnregisteredTypeInvokable() { return CustomUnregisteredType(); } QVariant MethodTestObject::qvariantInvokableBoolIntUIntLonglongULonglongDoubleLongShortCharUlongUshortUcharFloat( bool, int, uint, qlonglong, qulonglong, double, long, short, char, ulong, ushort, uchar, float) { return QVariant(); } void MethodTestObject::voidInvokableNoParameterNames(bool, int) {} void MethodTestObject::voidSlot() {} void MethodTestObject::voidSlotInt(int) {} void MethodTestObject::voidSlotQReal(qreal) {} void MethodTestObject::voidSlotQString(const QString &) {} void MethodTestObject::voidSlotCustomType(CustomType) {} void MethodTestObject::voidSlotCustomUnregisteredType(CustomUnregisteredType) {} bool MethodTestObject::boolSlot() { return true; } qreal MethodTestObject::qrealSlot() { return 1.0; } QString MethodTestObject::qstringSlot() { return QString(); } CustomType MethodTestObject::customTypeSlot() { return CustomType(); } CustomUnregisteredType MethodTestObject::customUnregisteredTypeSlot() { return CustomUnregisteredType(); } QVariant MethodTestObject::qvariantSlotBoolIntUIntLonglongULonglongDoubleLongShortCharUlongUshortUcharFloat( bool, int, uint, qlonglong, qulonglong, double, long, short, char, ulong, ushort, uchar, float) { return QVariant(); } void MethodTestObject::voidSlotNoParameterNames(bool, int) {} void tst_QMetaMethod::method_data() { QTest::addColumn("signature"); QTest::addColumn("returnType"); QTest::addColumn("returnTypeName"); QTest::addColumn >("parameterTypes"); QTest::addColumn >("parameterTypeNames"); QTest::addColumn >("parameterNames"); QTest::addColumn("access"); QTest::addColumn("methodType"); QTest::newRow("voidSignal") << QByteArray("voidSignal()") << int(QMetaType::Void) << QByteArray("void") << (QList()) << (QList()) << (QList()) << QMetaMethod::Public << QMetaMethod::Signal; QTest::newRow("voidInvokable") << QByteArray("voidInvokable()") << int(QMetaType::Void) << QByteArray("void") << (QList()) << (QList()) << (QList()) << QMetaMethod::Public << QMetaMethod::Method; QTest::newRow("voidSlot") << QByteArray("voidSlot()") << int(QMetaType::Void) << QByteArray("void") << (QList()) << (QList()) << (QList()) << QMetaMethod::Public << QMetaMethod::Slot; QTest::newRow("MethodTestObject()") << QByteArray("MethodTestObject()") << int(QMetaType::UnknownType) << QByteArray("") << (QList()) << (QList()) << (QList()) << QMetaMethod::Public << QMetaMethod::Constructor; QTest::newRow("voidSignalVoid") << QByteArray("voidSignalVoid()") << int(QMetaType::Void) << QByteArray("void") << QList() << QList() << QList() << QMetaMethod::Public << QMetaMethod::Signal; QTest::newRow("voidSignalInt") << QByteArray("voidSignalInt(int)") << int(QMetaType::Void) << QByteArray("void") << (QList() << int(QMetaType::Int)) << (QList() << QByteArray("int")) << (QList() << QByteArray("voidSignalIntArg")) << QMetaMethod::Public << QMetaMethod::Signal; QTest::newRow("voidInvokableInt") << QByteArray("voidInvokableInt(int)") << int(QMetaType::Void) << QByteArray("void") << (QList() << int(QMetaType::Int)) << (QList() << QByteArray("int")) << (QList() << QByteArray("voidInvokableIntArg")) << QMetaMethod::Public << QMetaMethod::Method; QTest::newRow("voidSlotInt") << QByteArray("voidSlotInt(int)") << int(QMetaType::Void) << QByteArray("void") << (QList() << int(QMetaType::Int)) << (QList() << QByteArray("int")) << (QList() << QByteArray("voidSlotIntArg")) << QMetaMethod::Public << QMetaMethod::Slot; QTest::newRow("MethodTestObject(int)") << QByteArray("MethodTestObject(int)") << int(QMetaType::UnknownType) << QByteArray("") << (QList() << int(QMetaType::Int)) << (QList() << QByteArray("int")) << (QList() << QByteArray("constructorIntArg")) << QMetaMethod::Public << QMetaMethod::Constructor; QTest::newRow("voidSignalQReal") << QByteArray("voidSignalQReal(qreal)") << int(QMetaType::Void) << QByteArray("void") << (QList() << qMetaTypeId()) << (QList() << QByteArray("qreal")) << (QList() << QByteArray("voidSignalQRealArg")) << QMetaMethod::Public << QMetaMethod::Signal; QTest::newRow("voidInvokableQReal") << QByteArray("voidInvokableQReal(qreal)") << int(QMetaType::Void) << QByteArray("void") << (QList() << qMetaTypeId()) << (QList() << QByteArray("qreal")) << (QList() << QByteArray("voidInvokableQRealArg")) << QMetaMethod::Public << QMetaMethod::Method; QTest::newRow("voidSlotQReal") << QByteArray("voidSlotQReal(qreal)") << int(QMetaType::Void) << QByteArray("void") << (QList() << qMetaTypeId()) << (QList() << QByteArray("qreal")) << (QList() << QByteArray("voidSlotQRealArg")) << QMetaMethod::Public << QMetaMethod::Slot; QTest::newRow("MethodTestObject(qreal)") << QByteArray("MethodTestObject(qreal)") << int(QMetaType::UnknownType) << QByteArray("") << (QList() << qMetaTypeId()) << (QList() << QByteArray("qreal")) << (QList() << QByteArray("constructorQRealArg")) << QMetaMethod::Public << QMetaMethod::Constructor; QTest::newRow("voidSignalQString") << QByteArray("voidSignalQString(QString)") << int(QMetaType::Void) << QByteArray("void") << (QList() << int(QMetaType::QString)) << (QList() << QByteArray("QString")) << (QList() << QByteArray("voidSignalQStringArg")) << QMetaMethod::Public << QMetaMethod::Signal; QTest::newRow("voidInvokableQString") << QByteArray("voidInvokableQString(QString)") << int(QMetaType::Void) << QByteArray("void") << (QList() << int(QMetaType::QString)) << (QList() << QByteArray("QString")) << (QList() << QByteArray("voidInvokableQStringArg")) << QMetaMethod::Public << QMetaMethod::Method; QTest::newRow("voidSlotQString") << QByteArray("voidSlotQString(QString)") << int(QMetaType::Void) << QByteArray("void") << (QList() << int(QMetaType::QString)) << (QList() << QByteArray("QString")) << (QList() << QByteArray("voidSlotQStringArg")) << QMetaMethod::Public << QMetaMethod::Slot; QTest::newRow("MethodTestObject(QString)") << QByteArray("MethodTestObject(QString)") << int(QMetaType::UnknownType) << QByteArray("") << (QList() << int(QMetaType::QString)) << (QList() << QByteArray("QString")) << (QList() << QByteArray("constructorQStringArg")) << QMetaMethod::Public << QMetaMethod::Constructor; QTest::newRow("voidSignalCustomType") << QByteArray("voidSignalCustomType(CustomType)") << int(QMetaType::Void) << QByteArray("void") << (QList() << qMetaTypeId()) << (QList() << QByteArray("CustomType")) << (QList() << QByteArray("voidSignalCustomTypeArg")) << QMetaMethod::Public << QMetaMethod::Signal; QTest::newRow("voidInvokableCustomType") << QByteArray("voidInvokableCustomType(CustomType)") << int(QMetaType::Void) << QByteArray("void") << (QList() << qMetaTypeId()) << (QList() << QByteArray("CustomType")) << (QList() << QByteArray("voidInvokableCustomTypeArg")) << QMetaMethod::Public << QMetaMethod::Method; QTest::newRow("voidSlotCustomType") << QByteArray("voidSlotCustomType(CustomType)") << int(QMetaType::Void) << QByteArray("void") << (QList() << qMetaTypeId()) << (QList() << QByteArray("CustomType")) << (QList() << QByteArray("voidSlotCustomTypeArg")) << QMetaMethod::Public << QMetaMethod::Slot; QTest::newRow("MethodTestObject(CustomType)") << QByteArray("MethodTestObject(CustomType)") << int(QMetaType::UnknownType) << QByteArray("") << (QList() << qMetaTypeId()) << (QList() << QByteArray("CustomType")) << (QList() << QByteArray("constructorCustomTypeArg")) << QMetaMethod::Public << QMetaMethod::Constructor; QTest::newRow("voidSignalCustomUnregisteredType") << QByteArray("voidSignalCustomUnregisteredType(CustomUnregisteredType)") << int(QMetaType::Void) << QByteArray("void") << (QList() << 0) << (QList() << QByteArray("CustomUnregisteredType")) << (QList() << QByteArray("voidSignalCustomUnregisteredTypeArg")) << QMetaMethod::Public << QMetaMethod::Signal; QTest::newRow("voidInvokableCustomUnregisteredType") << QByteArray("voidInvokableCustomUnregisteredType(CustomUnregisteredType)") << int(QMetaType::Void) << QByteArray("void") << (QList() << 0) << (QList() << QByteArray("CustomUnregisteredType")) << (QList() << QByteArray("voidInvokableCustomUnregisteredTypeArg")) << QMetaMethod::Public << QMetaMethod::Method; QTest::newRow("voidSlotCustomUnregisteredType") << QByteArray("voidSlotCustomUnregisteredType(CustomUnregisteredType)") << int(QMetaType::Void) << QByteArray("void") << (QList() << 0) << (QList() << QByteArray("CustomUnregisteredType")) << (QList() << QByteArray("voidSlotCustomUnregisteredTypeArg")) << QMetaMethod::Public << QMetaMethod::Slot; QTest::newRow("MethodTestObject(CustomUnregisteredType)") << QByteArray("MethodTestObject(CustomUnregisteredType)") << int(QMetaType::UnknownType) << QByteArray("") << (QList() << 0) << (QList() << QByteArray("CustomUnregisteredType")) << (QList() << QByteArray("constructorCustomUnregisteredTypeArg")) << QMetaMethod::Public << QMetaMethod::Constructor; QTest::newRow("boolSignal") << QByteArray("boolSignal()") << int(QMetaType::Bool) << QByteArray("bool") << (QList()) << (QList()) << (QList()) << QMetaMethod::Public << QMetaMethod::Signal; QTest::newRow("boolInvokable") << QByteArray("boolInvokable()") << int(QMetaType::Bool) << QByteArray("bool") << (QList()) << (QList()) << (QList()) << QMetaMethod::Public << QMetaMethod::Method; QTest::newRow("boolSlot") << QByteArray("boolSlot()") << int(QMetaType::Bool) << QByteArray("bool") << (QList()) << (QList()) << (QList()) << QMetaMethod::Public << QMetaMethod::Slot; QTest::newRow("qrealSignal") << QByteArray("qrealSignal()") << int(QMetaType::QReal) << QByteArray("qreal") << (QList()) << (QList()) << (QList()) << QMetaMethod::Public << QMetaMethod::Signal; QTest::newRow("qrealInvokable") << QByteArray("qrealInvokable()") << int(QMetaType::QReal) << QByteArray("qreal") << (QList()) << (QList()) << (QList()) << QMetaMethod::Public << QMetaMethod::Method; QTest::newRow("qrealSlot") << QByteArray("qrealSlot()") << int(QMetaType::QReal) << QByteArray("qreal") << (QList()) << (QList()) << (QList()) << QMetaMethod::Public << QMetaMethod::Slot; QTest::newRow("qstringSignal") << QByteArray("qstringSignal()") << int(QMetaType::QString) << QByteArray("QString") << (QList()) << (QList()) << (QList()) << QMetaMethod::Public << QMetaMethod::Signal; QTest::newRow("qstringInvokable") << QByteArray("qstringInvokable()") << int(QMetaType::QString) << QByteArray("QString") << (QList()) << (QList()) << (QList()) << QMetaMethod::Public << QMetaMethod::Method; QTest::newRow("qstringSlot") << QByteArray("qstringSlot()") << int(QMetaType::QString) << QByteArray("QString") << (QList()) << (QList()) << (QList()) << QMetaMethod::Public << QMetaMethod::Slot; { QList parameterTypes = QList() << int(QMetaType::Bool) << int(QMetaType::Int) << int(QMetaType::UInt) << int(QMetaType::LongLong) << int(QMetaType::ULongLong) << int(QMetaType::Double) << int(QMetaType::Long) << int(QMetaType::Short) << int(QMetaType::Char) << int(QMetaType::ULong) << int(QMetaType::UShort) << int(QMetaType::UChar) << int(QMetaType::Float); QList parameterTypeNames = QList() << QByteArray("bool") << QByteArray("int") << QByteArray("uint") << QByteArray("qlonglong") << QByteArray("qulonglong") << QByteArray("double") << QByteArray("long") << QByteArray("short") << QByteArray("char") << QByteArray("ulong") << QByteArray("ushort") << QByteArray("uchar") << QByteArray("float"); QList parameterNames = QList() << QByteArray("boolArg") << QByteArray("intArg") << QByteArray("uintArg") << QByteArray("longlongArg") << QByteArray("ulonglongArg") << QByteArray("doubleArg") << QByteArray("longArg") << QByteArray("shortArg") << QByteArray("charArg") << QByteArray("ulongArg") << QByteArray("ushortArg") << QByteArray("ucharArg") << QByteArray("floatArg"); QTest::newRow("qvariantSignalBoolIntUIntLonglongULonglongDoubleLongShortCharUlongUshortUcharFloat") << QByteArray("qvariantSignalBoolIntUIntLonglongULonglongDoubleLongShortCharUlongUshortUcharFloat(" "bool,int,uint,qlonglong,qulonglong,double,long,short,char,ulong,ushort,uchar,float)") << int(QMetaType::QVariant) << QByteArray("QVariant") << parameterTypes << parameterTypeNames << parameterNames << QMetaMethod::Public << QMetaMethod::Signal; QTest::newRow("qvariantInvokableBoolIntUIntLonglongULonglongDoubleLongShortCharUlongUshortUcharFloat") << QByteArray("qvariantInvokableBoolIntUIntLonglongULonglongDoubleLongShortCharUlongUshortUcharFloat(" "bool,int,uint,qlonglong,qulonglong,double,long,short,char,ulong,ushort,uchar,float)") << int(QMetaType::QVariant) << QByteArray("QVariant") << parameterTypes << parameterTypeNames << parameterNames << QMetaMethod::Public << QMetaMethod::Method; QTest::newRow("qvariantSlotBoolIntUIntLonglongULonglongDoubleLongShortCharUlongUshortUcharFloat") << QByteArray("qvariantSlotBoolIntUIntLonglongULonglongDoubleLongShortCharUlongUshortUcharFloat(" "bool,int,uint,qlonglong,qulonglong,double,long,short,char,ulong,ushort,uchar,float)") << int(QMetaType::QVariant) << QByteArray("QVariant") << parameterTypes << parameterTypeNames << parameterNames << QMetaMethod::Public << QMetaMethod::Slot; QTest::newRow("MethodTestObject(bool,int,uint,qlonglong,qulonglong,double,long,short,char,ulong,ushort,uchar,float)") << QByteArray("MethodTestObject(bool,int,uint,qlonglong,qulonglong,double,long,short,char,ulong,ushort,uchar,float)") << int(QMetaType::UnknownType) << QByteArray("") << parameterTypes << parameterTypeNames << parameterNames << QMetaMethod::Public << QMetaMethod::Constructor; } QTest::newRow("voidSignalNoParameterNames") << QByteArray("voidSignalNoParameterNames(bool,int)") << int(QMetaType::Void) << QByteArray("void") << (QList() << int(QMetaType::Bool) << int(QMetaType::Int)) << (QList() << QByteArray("bool") << QByteArray("int")) << (QList() << QByteArray("") << QByteArray("")) << QMetaMethod::Public << QMetaMethod::Signal; QTest::newRow("voidInvokableNoParameterNames") << QByteArray("voidInvokableNoParameterNames(bool,int)") << int(QMetaType::Void) << QByteArray("void") << (QList() << int(QMetaType::Bool) << int(QMetaType::Int)) << (QList() << QByteArray("bool") << QByteArray("int")) << (QList() << QByteArray("") << QByteArray("")) << QMetaMethod::Public << QMetaMethod::Method; QTest::newRow("voidSlotNoParameterNames") << QByteArray("voidSlotNoParameterNames(bool,int)") << int(QMetaType::Void) << QByteArray("void") << (QList() << int(QMetaType::Bool) << int(QMetaType::Int)) << (QList() << QByteArray("bool") << QByteArray("int")) << (QList() << QByteArray("") << QByteArray("")) << QMetaMethod::Public << QMetaMethod::Slot; QTest::newRow("MethodTestObject(bool,int)") << QByteArray("MethodTestObject(bool,int)") << int(QMetaType::UnknownType) << QByteArray("") << (QList() << int(QMetaType::Bool) << int(QMetaType::Int)) << (QList() << QByteArray("bool") << QByteArray("int")) << (QList() << QByteArray("") << QByteArray("")) << QMetaMethod::Public << QMetaMethod::Constructor; } void tst_QMetaMethod::method() { QFETCH(QByteArray, signature); QFETCH(int, returnType); QFETCH(QByteArray, returnTypeName); QFETCH(QList, parameterTypes); QFETCH(QList, parameterTypeNames); QFETCH(QList, parameterNames); QFETCH(QMetaMethod::MethodType, methodType); QFETCH(QMetaMethod::Access, access); QCOMPARE(parameterTypes.size(), parameterTypeNames.size()); QCOMPARE(parameterTypes.size(), parameterNames.size()); const QMetaObject *mo = &MethodTestObject::staticMetaObject; int index = (methodType == QMetaMethod::Constructor) ? mo->indexOfConstructor(signature) : mo->indexOfMethod(signature); QVERIFY(index != -1); QMetaMethod method = (methodType == QMetaMethod::Constructor) ? mo->constructor(index) : mo->method(index); QVERIFY(method.isValid()); QCOMPARE(method.methodType(), methodType); QCOMPARE(method.access(), access); QVERIFY(!method.methodSignature().isEmpty()); if (method.methodSignature() != signature) { // QMetaMethod should always produce a semantically equivalent signature int signatureIndex = (methodType == QMetaMethod::Constructor) ? mo->indexOfConstructor(method.methodSignature()) : mo->indexOfMethod(method.methodSignature()); QCOMPARE(signatureIndex, index); } QByteArray computedName = signature.left(signature.indexOf('(')); QCOMPARE(method.name(), computedName); QCOMPARE(method.tag(), ""); QCOMPARE(method.returnType(), returnType); QVERIFY(method.typeName() != 0); if (QByteArray(method.typeName()) != returnTypeName) { // QMetaMethod should always produce a semantically equivalent typename QCOMPARE(QMetaType::type(method.typeName()), QMetaType::type(returnTypeName)); } if (method.parameterTypes() != parameterTypeNames) { // QMetaMethod should always produce semantically equivalent typenames QList actualTypeNames = method.parameterTypes(); QCOMPARE(actualTypeNames.size(), parameterTypeNames.size()); for (int i = 0; i < parameterTypeNames.size(); ++i) { QCOMPARE(QMetaType::type(actualTypeNames.at(i)), QMetaType::type(parameterTypeNames.at(i))); } } //QCOMPARE(method.parameterNames(), parameterNames); // ### not supported by W_INVOKABLE QCOMPARE(method.parameterCount(), parameterTypes.size()); for (int i = 0; i < parameterTypes.size(); ++i) QCOMPARE(method.parameterType(i), parameterTypes.at(i)); { QVector actualParameterTypes(parameterTypes.size()); method.getParameterTypes(actualParameterTypes.data()); for (int i = 0; i < parameterTypes.size(); ++i) QCOMPARE(actualParameterTypes.at(i), parameterTypes.at(i)); } // Bogus indexes QCOMPARE(method.parameterType(-1), 0); QCOMPARE(method.parameterType(parameterTypes.size()), 0); } void tst_QMetaMethod::invalidMethod() { QMetaMethod method; QVERIFY(!method.isValid()); QMetaMethod method2 = staticMetaObject.method(staticMetaObject.methodCount()); QVERIFY(!method2.isValid()); QMetaMethod method3 = staticMetaObject.method(-1); QVERIFY(!method3.isValid()); } void tst_QMetaMethod::comparisonOperators() { static const QMetaObject *mo = &MethodTestObject::staticMetaObject; for (int x = 0; x < 2; ++x) { int count = x ? mo->constructorCount() : mo->methodCount(); for (int i = 0; i < count; ++i) { QMetaMethod method = x ? mo->constructor(i) : mo->method(i); const QMetaObject *methodMo = method.enclosingMetaObject(); for (int j = 0; j < count; ++j) { QMetaMethod other = x ? mo->constructor(j) : mo->method(j); bool expectedEqual = ((methodMo == other.enclosingMetaObject()) && (i == j)); QCOMPARE(method == other, expectedEqual); QCOMPARE(method != other, !expectedEqual); QCOMPARE(other == method, expectedEqual); QCOMPARE(other != method, !expectedEqual); } QVERIFY(method != QMetaMethod()); QVERIFY(QMetaMethod() != method); QVERIFY(!(method == QMetaMethod())); QVERIFY(!(QMetaMethod() == method)); } } // Constructors and normal methods with identical index should not // compare equal for (int i = 0; i < qMin(mo->methodCount(), mo->constructorCount()); ++i) { QMetaMethod method = mo->method(i); QMetaMethod constructor = mo->constructor(i); QVERIFY(method != constructor); QVERIFY(!(method == constructor)); } } void tst_QMetaMethod::fromSignal() { #define FROMSIGNAL_HELPER(ObjectType, Name, Arguments) { \ const QMetaObject *signalMeta = &ObjectType::staticMetaObject; \ QCOMPARE(QMetaMethod::fromSignal(&ObjectType::Name), \ signalMeta->method(signalMeta->indexOfSignal(QMetaObject::normalizedSignature(#Name #Arguments)))); \ } FROMSIGNAL_HELPER(MethodTestObject, voidSignal, ()) FROMSIGNAL_HELPER(MethodTestObject, voidSignalQString, (const QString&)) FROMSIGNAL_HELPER(QObject, destroyed, (QObject*)) FROMSIGNAL_HELPER(QObject, objectNameChanged, (const QString &)) // Inherited from QObject FROMSIGNAL_HELPER(MethodTestObject, destroyed, (QObject*)) FROMSIGNAL_HELPER(MethodTestObject, objectNameChanged, (const QString &)) // Methods that are not signals; fromSignal should return invalid method FROMSIGNAL_HELPER(MethodTestObject, voidSlot, ()) FROMSIGNAL_HELPER(QObject, deleteLater, ()) #undef FROMSIGNAL_HELPER } class MyGadget { W_GADGET(MyGadget) public: QString m_value; void setValue(const QString &value) { m_value = value; } W_INVOKABLE(setValue) QString getValue() { return m_value; } W_INVOKABLE(getValue) }; void tst_QMetaMethod::gadget() { int idx; idx = MyGadget::staticMetaObject.indexOfMethod("setValue(QString)"); QVERIFY(idx >= 0); QMetaMethod setValueMethod = MyGadget::staticMetaObject.method(idx); QVERIFY(setValueMethod.isValid()); idx = MyGadget::staticMetaObject.indexOfMethod("getValue()"); QVERIFY(idx >= 0); QMetaMethod getValueMethod = MyGadget::staticMetaObject.method(idx); QVERIFY(getValueMethod.isValid()); { MyGadget gadget; QString string; QVERIFY(getValueMethod.invokeOnGadget(&gadget, Q_RETURN_ARG(QString, string))); QCOMPARE(string, gadget.m_value); QVERIFY(setValueMethod.invokeOnGadget(&gadget, Q_ARG(QString, QLatin1String("hello")))); QCOMPARE(gadget.m_value, QLatin1String("hello")); QVERIFY(getValueMethod.invokeOnGadget(&gadget, Q_RETURN_ARG(QString, string))); QCOMPARE(string, gadget.m_value); } { // Call with null should not crash MyGadget *gadget = nullptr; QString string; QVERIFY(!setValueMethod.invokeOnGadget(gadget, Q_ARG(QString, QLatin1String("hi")))); QVERIFY(!getValueMethod.invokeOnGadget(gadget, Q_RETURN_ARG(QString, string))); } } W_OBJECT_IMPL(tst_QMetaMethod) W_OBJECT_IMPL(MethodTestObject) W_GADGET_IMPL(MyGadget) QTEST_MAIN(tst_QMetaMethod) verdigris-1.3/tests/qt/qmetamethod/tst_qmetamethod6.cpp000066400000000000000000001204621427643277200234700ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2014 Olivier Goffart ** 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 #include #include #include "wobjectimpl.h" class tst_QMetaMethod : public QObject { W_OBJECT(tst_QMetaMethod) private: void method_data(); W_SLOT(method_data) void method(); W_SLOT(method, W_Access::Private) void invalidMethod(); W_SLOT(invalidMethod, W_Access::Private) void comparisonOperators(); W_SLOT(comparisonOperators, W_Access::Private) void fromSignal(); W_SLOT(fromSignal, W_Access::Private) void gadget(); W_SLOT(gadget, W_Access::Private) void revision(); W_SLOT(revision, W_Access::Private) void returnMetaType(); W_SLOT(returnMetaType, W_Access::Private) void parameterMetaType(); W_SLOT(parameterMetaType, W_Access::Private) void parameterTypeName(); W_SLOT(parameterTypeName, W_Access::Private) #if QT_VERSION >= QT_VERSION_CHECK(6,2,0) void isConst(); W_SLOT(isConst, W_Access::Private) #endif }; W_OBJECT_IMPL(tst_QMetaMethod) struct CustomType { }; Q_DECLARE_METATYPE(CustomType) W_REGISTER_ARGTYPE(CustomType) struct CustomUnregisteredType { }; W_REGISTER_ARGTYPE(CustomUnregisteredType) Q_DECLARE_METATYPE(QMetaMethod::Access) Q_DECLARE_METATYPE(QMetaMethod::MethodType) class MethodTestObject : public QObject { W_OBJECT(MethodTestObject) public: MethodTestObject(); MethodTestObject(int constructorIntArg); MethodTestObject(qreal constructorQRealArg); MethodTestObject(const QString &constructorQStringArg); MethodTestObject(CustomType constructorCustomTypeArg); MethodTestObject(CustomUnregisteredType constructorCustomUnregisteredTypeArg); MethodTestObject(bool boolArg, int intArg, uint uintArg, qlonglong longlongArg, qulonglong ulonglongArg, double doubleArg, long longArg, short shortArg, char charArg, ulong ulongArg, ushort ushortArg, uchar ucharArg, float floatArg); MethodTestObject(bool, int); W_CONSTRUCTOR(); W_CONSTRUCTOR(int); W_CONSTRUCTOR(qreal); W_CONSTRUCTOR(QString); W_CONSTRUCTOR(CustomType); W_CONSTRUCTOR(CustomUnregisteredType); W_CONSTRUCTOR(bool, int, uint, qlonglong, qulonglong, double, long, short, char, ulong, ushort, uchar, float); W_CONSTRUCTOR(bool, int); #if QT_VERSION >= QT_VERSION_CHECK(6,2,0) void voidInvokable() const; #else void voidInvokable(); #endif W_INVOKABLE(voidInvokable) void voidInvokableInt(int voidInvokableIntArg); W_INVOKABLE(voidInvokableInt) void voidInvokableQReal(qreal voidInvokableQRealArg); W_INVOKABLE(voidInvokableQReal) void voidInvokableQString(const QString &voidInvokableQStringArg); W_INVOKABLE(voidInvokableQString) void voidInvokableCustomType(CustomType voidInvokableCustomTypeArg); W_INVOKABLE(voidInvokableCustomType) void voidInvokableCustomUnregisteredType(CustomUnregisteredType voidInvokableCustomUnregisteredTypeArg); W_INVOKABLE(voidInvokableCustomUnregisteredType) bool boolInvokable(); W_INVOKABLE(boolInvokable) qreal qrealInvokable(); W_INVOKABLE(qrealInvokable) QString qstringInvokable(); W_INVOKABLE(qstringInvokable) CustomType customTypeInvokable(); W_INVOKABLE(customTypeInvokable) CustomUnregisteredType customUnregisteredTypeInvokable(); W_INVOKABLE(customUnregisteredTypeInvokable) QVariant qvariantInvokableBoolIntUIntLonglongULonglongDoubleLongShortCharUlongUshortUcharFloat( bool boolArg, int intArg, uint uintArg, qlonglong longlongArg, qulonglong ulonglongArg, double doubleArg, long longArg, short shortArg, char charArg, ulong ulongArg, ushort ushortArg, uchar ucharArg, float floatArg); W_INVOKABLE(qvariantInvokableBoolIntUIntLonglongULonglongDoubleLongShortCharUlongUshortUcharFloat) void voidInvokableNoParameterNames(bool, int); W_INVOKABLE(voidInvokableNoParameterNames) public slots: void voidSlot(); W_SLOT(voidSlot) void voidSlotInt(int voidSlotIntArg); W_SLOT(voidSlotInt) void voidSlotQReal(qreal voidSlotQRealArg); W_SLOT(voidSlotQReal) void voidSlotQString(const QString &voidSlotQStringArg); W_SLOT(voidSlotQString) void voidSlotCustomType(CustomType voidSlotCustomTypeArg); W_SLOT(voidSlotCustomType) void voidSlotCustomUnregisteredType(CustomUnregisteredType voidSlotCustomUnregisteredTypeArg); W_SLOT(voidSlotCustomUnregisteredType) bool boolSlot(); W_SLOT(boolSlot) qreal qrealSlot(); W_SLOT(qrealSlot) QString qstringSlot(); W_SLOT(qstringSlot) CustomType customTypeSlot(); W_SLOT(customTypeSlot) CustomUnregisteredType customUnregisteredTypeSlot(); W_SLOT(customUnregisteredTypeSlot) QVariant qvariantSlotBoolIntUIntLonglongULonglongDoubleLongShortCharUlongUshortUcharFloat( bool boolArg, int intArg, uint uintArg, qlonglong longlongArg, qulonglong ulonglongArg, double doubleArg, long longArg, short shortArg, char charArg, ulong ulongArg, ushort ushortArg, uchar ucharArg, float floatArg); W_SLOT(qvariantSlotBoolIntUIntLonglongULonglongDoubleLongShortCharUlongUshortUcharFloat) void voidSlotNoParameterNames(bool, int); W_SLOT(voidSlotNoParameterNames) signals: void voidSignal() W_SIGNAL(voidSignal) void voidSignalVoid(void) W_SIGNAL(voidSignalVoid) void voidSignalInt(int voidSignalIntArg) W_SIGNAL(voidSignalInt,voidSignalIntArg) void voidSignalQReal(qreal voidSignalQRealArg) W_SIGNAL(voidSignalQReal,voidSignalQRealArg) void voidSignalQString(const QString &voidSignalQStringArg) W_SIGNAL(voidSignalQString,voidSignalQStringArg) void voidSignalCustomType(CustomType voidSignalCustomTypeArg) W_SIGNAL(voidSignalCustomType,voidSignalCustomTypeArg) void voidSignalCustomUnregisteredType(CustomUnregisteredType voidSignalCustomUnregisteredTypeArg) W_SIGNAL(voidSignalCustomUnregisteredType,voidSignalCustomUnregisteredTypeArg) bool boolSignal() W_SIGNAL(boolSignal) qreal qrealSignal() W_SIGNAL(qrealSignal) QString qstringSignal() W_SIGNAL(qstringSignal) CustomType customTypeSignal() W_SIGNAL(customTypeSignal) CustomUnregisteredType customUnregisteredTypeSignal() W_SIGNAL(customUnregisteredTypeSignal) QVariant qvariantSignalBoolIntUIntLonglongULonglongDoubleLongShortCharUlongUshortUcharFloat( bool boolArg, int intArg, uint uintArg, qlonglong longlongArg, qulonglong ulonglongArg, double doubleArg, long longArg, short shortArg, char charArg, ulong ulongArg, ushort ushortArg, uchar ucharArg, float floatArg) W_SIGNAL(qvariantSignalBoolIntUIntLonglongULonglongDoubleLongShortCharUlongUshortUcharFloat, boolArg, intArg, uintArg, longlongArg, ulonglongArg, doubleArg, longArg, shortArg, charArg, ulongArg, ushortArg, ucharArg, floatArg) void voidSignalNoParameterNames(bool _1, int _2) W_SIGNAL(voidSignalNoParameterNames, _1, _2) }; W_OBJECT_IMPL(MethodTestObject) MethodTestObject::MethodTestObject() {} MethodTestObject::MethodTestObject(int) {} MethodTestObject::MethodTestObject(qreal) {} MethodTestObject::MethodTestObject(const QString &) {} MethodTestObject::MethodTestObject(CustomType) {} MethodTestObject::MethodTestObject(CustomUnregisteredType) {} MethodTestObject::MethodTestObject(bool, int, uint, qlonglong, qulonglong, double, long, short, char, ulong, ushort, uchar, float) {} MethodTestObject::MethodTestObject(bool, int) {} #if QT_VERSION >= QT_VERSION_CHECK(6,2,0) void MethodTestObject::voidInvokable() const {} #else void MethodTestObject::voidInvokable() {} #endif void MethodTestObject::voidInvokableInt(int) {} void MethodTestObject::voidInvokableQReal(qreal) {} void MethodTestObject::voidInvokableQString(const QString &) {} void MethodTestObject::voidInvokableCustomType(CustomType) {} void MethodTestObject::voidInvokableCustomUnregisteredType(CustomUnregisteredType) {} bool MethodTestObject::boolInvokable() { return true; } qreal MethodTestObject::qrealInvokable() { return 1.0; } QString MethodTestObject::qstringInvokable() { return QString(); } CustomType MethodTestObject::customTypeInvokable() { return CustomType(); } CustomUnregisteredType MethodTestObject::customUnregisteredTypeInvokable() { return CustomUnregisteredType(); } QVariant MethodTestObject::qvariantInvokableBoolIntUIntLonglongULonglongDoubleLongShortCharUlongUshortUcharFloat( bool, int, uint, qlonglong, qulonglong, double, long, short, char, ulong, ushort, uchar, float) { return QVariant(); } void MethodTestObject::voidInvokableNoParameterNames(bool, int) {} void MethodTestObject::voidSlot() {} void MethodTestObject::voidSlotInt(int) {} void MethodTestObject::voidSlotQReal(qreal) {} void MethodTestObject::voidSlotQString(const QString &) {} void MethodTestObject::voidSlotCustomType(CustomType) {} void MethodTestObject::voidSlotCustomUnregisteredType(CustomUnregisteredType) {} bool MethodTestObject::boolSlot() { return true; } qreal MethodTestObject::qrealSlot() { return 1.0; } QString MethodTestObject::qstringSlot() { return QString(); } CustomType MethodTestObject::customTypeSlot() { return CustomType(); } CustomUnregisteredType MethodTestObject::customUnregisteredTypeSlot() { return CustomUnregisteredType(); } QVariant MethodTestObject::qvariantSlotBoolIntUIntLonglongULonglongDoubleLongShortCharUlongUshortUcharFloat( bool, int, uint, qlonglong, qulonglong, double, long, short, char, ulong, ushort, uchar, float) { return QVariant(); } void MethodTestObject::voidSlotNoParameterNames(bool, int) {} void tst_QMetaMethod::method_data() { QTest::addColumn("signature"); QTest::addColumn("returnType"); QTest::addColumn("returnTypeName"); QTest::addColumn >("parameterTypes"); QTest::addColumn >("parameterTypeNames"); QTest::addColumn >("parameterNames"); QTest::addColumn("access"); QTest::addColumn("methodType"); QTest::newRow("voidSignal") << QByteArray("voidSignal()") << int(QMetaType::Void) << QByteArray("void") << (QList()) << (QList()) << (QList()) << QMetaMethod::Public << QMetaMethod::Signal; QTest::newRow("voidInvokable") << QByteArray("voidInvokable()") << int(QMetaType::Void) << QByteArray("void") << (QList()) << (QList()) << (QList()) << QMetaMethod::Public << QMetaMethod::Method; QTest::newRow("voidSlot") << QByteArray("voidSlot()") << int(QMetaType::Void) << QByteArray("void") << (QList()) << (QList()) << (QList()) << QMetaMethod::Public << QMetaMethod::Slot; QTest::newRow("MethodTestObject()") << QByteArray("MethodTestObject()") << int(QMetaType::UnknownType) << QByteArray("") << (QList()) << (QList()) << (QList()) << QMetaMethod::Public << QMetaMethod::Constructor; QTest::newRow("voidSignalVoid") << QByteArray("voidSignalVoid()") << int(QMetaType::Void) << QByteArray("void") << QList() << QList() << QList() << QMetaMethod::Public << QMetaMethod::Signal; QTest::newRow("voidSignalInt") << QByteArray("voidSignalInt(int)") << int(QMetaType::Void) << QByteArray("void") << (QList() << int(QMetaType::Int)) << (QList() << QByteArray("int")) << (QList() << QByteArray("voidSignalIntArg")) << QMetaMethod::Public << QMetaMethod::Signal; QTest::newRow("voidInvokableInt") << QByteArray("voidInvokableInt(int)") << int(QMetaType::Void) << QByteArray("void") << (QList() << int(QMetaType::Int)) << (QList() << QByteArray("int")) << (QList() << QByteArray("voidInvokableIntArg")) << QMetaMethod::Public << QMetaMethod::Method; QTest::newRow("voidSlotInt") << QByteArray("voidSlotInt(int)") << int(QMetaType::Void) << QByteArray("void") << (QList() << int(QMetaType::Int)) << (QList() << QByteArray("int")) << (QList() << QByteArray("voidSlotIntArg")) << QMetaMethod::Public << QMetaMethod::Slot; QTest::newRow("MethodTestObject(int)") << QByteArray("MethodTestObject(int)") << int(QMetaType::UnknownType) << QByteArray("") << (QList() << int(QMetaType::Int)) << (QList() << QByteArray("int")) << (QList() << QByteArray("constructorIntArg")) << QMetaMethod::Public << QMetaMethod::Constructor; QTest::newRow("voidSignalQReal") << QByteArray("voidSignalQReal(qreal)") << int(QMetaType::Void) << QByteArray("void") << (QList() << qMetaTypeId()) << (QList() << QByteArray("qreal")) << (QList() << QByteArray("voidSignalQRealArg")) << QMetaMethod::Public << QMetaMethod::Signal; QTest::newRow("voidInvokableQReal") << QByteArray("voidInvokableQReal(qreal)") << int(QMetaType::Void) << QByteArray("void") << (QList() << qMetaTypeId()) << (QList() << QByteArray("qreal")) << (QList() << QByteArray("voidInvokableQRealArg")) << QMetaMethod::Public << QMetaMethod::Method; QTest::newRow("voidSlotQReal") << QByteArray("voidSlotQReal(qreal)") << int(QMetaType::Void) << QByteArray("void") << (QList() << qMetaTypeId()) << (QList() << QByteArray("qreal")) << (QList() << QByteArray("voidSlotQRealArg")) << QMetaMethod::Public << QMetaMethod::Slot; QTest::newRow("MethodTestObject(qreal)") << QByteArray("MethodTestObject(qreal)") << int(QMetaType::UnknownType) << QByteArray("") << (QList() << qMetaTypeId()) << (QList() << QByteArray("qreal")) << (QList() << QByteArray("constructorQRealArg")) << QMetaMethod::Public << QMetaMethod::Constructor; QTest::newRow("voidSignalQString") << QByteArray("voidSignalQString(QString)") << int(QMetaType::Void) << QByteArray("void") << (QList() << int(QMetaType::QString)) << (QList() << QByteArray("QString")) << (QList() << QByteArray("voidSignalQStringArg")) << QMetaMethod::Public << QMetaMethod::Signal; QTest::newRow("voidInvokableQString") << QByteArray("voidInvokableQString(QString)") << int(QMetaType::Void) << QByteArray("void") << (QList() << int(QMetaType::QString)) << (QList() << QByteArray("QString")) << (QList() << QByteArray("voidInvokableQStringArg")) << QMetaMethod::Public << QMetaMethod::Method; QTest::newRow("voidSlotQString") << QByteArray("voidSlotQString(QString)") << int(QMetaType::Void) << QByteArray("void") << (QList() << int(QMetaType::QString)) << (QList() << QByteArray("QString")) << (QList() << QByteArray("voidSlotQStringArg")) << QMetaMethod::Public << QMetaMethod::Slot; QTest::newRow("MethodTestObject(QString)") << QByteArray("MethodTestObject(QString)") << int(QMetaType::UnknownType) << QByteArray("") << (QList() << int(QMetaType::QString)) << (QList() << QByteArray("QString")) << (QList() << QByteArray("constructorQStringArg")) << QMetaMethod::Public << QMetaMethod::Constructor; QTest::newRow("voidSignalCustomType") << QByteArray("voidSignalCustomType(CustomType)") << int(QMetaType::Void) << QByteArray("void") << (QList() << qMetaTypeId()) << (QList() << QByteArray("CustomType")) << (QList() << QByteArray("voidSignalCustomTypeArg")) << QMetaMethod::Public << QMetaMethod::Signal; QTest::newRow("voidInvokableCustomType") << QByteArray("voidInvokableCustomType(CustomType)") << int(QMetaType::Void) << QByteArray("void") << (QList() << qMetaTypeId()) << (QList() << QByteArray("CustomType")) << (QList() << QByteArray("voidInvokableCustomTypeArg")) << QMetaMethod::Public << QMetaMethod::Method; QTest::newRow("voidSlotCustomType") << QByteArray("voidSlotCustomType(CustomType)") << int(QMetaType::Void) << QByteArray("void") << (QList() << qMetaTypeId()) << (QList() << QByteArray("CustomType")) << (QList() << QByteArray("voidSlotCustomTypeArg")) << QMetaMethod::Public << QMetaMethod::Slot; QTest::newRow("MethodTestObject(CustomType)") << QByteArray("MethodTestObject(CustomType)") << int(QMetaType::UnknownType) << QByteArray("") << (QList() << qMetaTypeId()) << (QList() << QByteArray("CustomType")) << (QList() << QByteArray("constructorCustomTypeArg")) << QMetaMethod::Public << QMetaMethod::Constructor; // since Qt 6.0, parameter types get automatically registered QTest::newRow("voidSignalCustomUnregisteredType") << QByteArray("voidSignalCustomUnregisteredType(CustomUnregisteredType)") << int(QMetaType::Void) << QByteArray("void") << (QList() << QMetaType::fromType().id()) << (QList() << QByteArray("CustomUnregisteredType")) << (QList() << QByteArray("voidSignalCustomUnregisteredTypeArg")) << QMetaMethod::Public << QMetaMethod::Signal; QTest::newRow("voidInvokableCustomUnregisteredType") << QByteArray("voidInvokableCustomUnregisteredType(CustomUnregisteredType)") << int(QMetaType::Void) << QByteArray("void") << (QList() << QMetaType::fromType().id()) << (QList() << QByteArray("CustomUnregisteredType")) << (QList() << QByteArray("voidInvokableCustomUnregisteredTypeArg")) << QMetaMethod::Public << QMetaMethod::Method; QTest::newRow("voidSlotCustomUnregisteredType") << QByteArray("voidSlotCustomUnregisteredType(CustomUnregisteredType)") << int(QMetaType::Void) << QByteArray("void") << (QList() << QMetaType::fromType().id()) << (QList() << QByteArray("CustomUnregisteredType")) << (QList() << QByteArray("voidSlotCustomUnregisteredTypeArg")) << QMetaMethod::Public << QMetaMethod::Slot; QTest::newRow("MethodTestObject(CustomUnregisteredType)") << QByteArray("MethodTestObject(CustomUnregisteredType)") << int(QMetaType::UnknownType) << QByteArray("") << (QList() << QMetaType::fromType().id()) << (QList() << QByteArray("CustomUnregisteredType")) << (QList() << QByteArray("constructorCustomUnregisteredTypeArg")) << QMetaMethod::Public << QMetaMethod::Constructor; QTest::newRow("boolSignal") << QByteArray("boolSignal()") << int(QMetaType::Bool) << QByteArray("bool") << (QList()) << (QList()) << (QList()) << QMetaMethod::Public << QMetaMethod::Signal; QTest::newRow("boolInvokable") << QByteArray("boolInvokable()") << int(QMetaType::Bool) << QByteArray("bool") << (QList()) << (QList()) << (QList()) << QMetaMethod::Public << QMetaMethod::Method; QTest::newRow("boolSlot") << QByteArray("boolSlot()") << int(QMetaType::Bool) << QByteArray("bool") << (QList()) << (QList()) << (QList()) << QMetaMethod::Public << QMetaMethod::Slot; QTest::newRow("qrealSignal") << QByteArray("qrealSignal()") << int(QMetaType::QReal) << QByteArray("qreal") << (QList()) << (QList()) << (QList()) << QMetaMethod::Public << QMetaMethod::Signal; QTest::newRow("qrealInvokable") << QByteArray("qrealInvokable()") << int(QMetaType::QReal) << QByteArray("qreal") << (QList()) << (QList()) << (QList()) << QMetaMethod::Public << QMetaMethod::Method; QTest::newRow("qrealSlot") << QByteArray("qrealSlot()") << int(QMetaType::QReal) << QByteArray("qreal") << (QList()) << (QList()) << (QList()) << QMetaMethod::Public << QMetaMethod::Slot; QTest::newRow("qstringSignal") << QByteArray("qstringSignal()") << int(QMetaType::QString) << QByteArray("QString") << (QList()) << (QList()) << (QList()) << QMetaMethod::Public << QMetaMethod::Signal; QTest::newRow("qstringInvokable") << QByteArray("qstringInvokable()") << int(QMetaType::QString) << QByteArray("QString") << (QList()) << (QList()) << (QList()) << QMetaMethod::Public << QMetaMethod::Method; QTest::newRow("qstringSlot") << QByteArray("qstringSlot()") << int(QMetaType::QString) << QByteArray("QString") << (QList()) << (QList()) << (QList()) << QMetaMethod::Public << QMetaMethod::Slot; { QList parameterTypes = QList() << int(QMetaType::Bool) << int(QMetaType::Int) << int(QMetaType::UInt) << int(QMetaType::LongLong) << int(QMetaType::ULongLong) << int(QMetaType::Double) << int(QMetaType::Long) << int(QMetaType::Short) << int(QMetaType::Char) << int(QMetaType::ULong) << int(QMetaType::UShort) << int(QMetaType::UChar) << int(QMetaType::Float); QList parameterTypeNames = QList() << QByteArray("bool") << QByteArray("int") << QByteArray("uint") << QByteArray("qlonglong") << QByteArray("qulonglong") << QByteArray("double") << QByteArray("long") << QByteArray("short") << QByteArray("char") << QByteArray("ulong") << QByteArray("ushort") << QByteArray("uchar") << QByteArray("float"); QList parameterNames = QList() << QByteArray("boolArg") << QByteArray("intArg") << QByteArray("uintArg") << QByteArray("longlongArg") << QByteArray("ulonglongArg") << QByteArray("doubleArg") << QByteArray("longArg") << QByteArray("shortArg") << QByteArray("charArg") << QByteArray("ulongArg") << QByteArray("ushortArg") << QByteArray("ucharArg") << QByteArray("floatArg"); QTest::newRow("qvariantSignalBoolIntUIntLonglongULonglongDoubleLongShortCharUlongUshortUcharFloat") << QByteArray("qvariantSignalBoolIntUIntLonglongULonglongDoubleLongShortCharUlongUshortUcharFloat(" "bool,int,uint,qlonglong,qulonglong,double,long,short,char,ulong,ushort,uchar,float)") << int(QMetaType::QVariant) << QByteArray("QVariant") << parameterTypes << parameterTypeNames << parameterNames << QMetaMethod::Public << QMetaMethod::Signal; QTest::newRow("qvariantInvokableBoolIntUIntLonglongULonglongDoubleLongShortCharUlongUshortUcharFloat") << QByteArray("qvariantInvokableBoolIntUIntLonglongULonglongDoubleLongShortCharUlongUshortUcharFloat(" "bool,int,uint,qlonglong,qulonglong,double,long,short,char,ulong,ushort,uchar,float)") << int(QMetaType::QVariant) << QByteArray("QVariant") << parameterTypes << parameterTypeNames << parameterNames << QMetaMethod::Public << QMetaMethod::Method; QTest::newRow("qvariantSlotBoolIntUIntLonglongULonglongDoubleLongShortCharUlongUshortUcharFloat") << QByteArray("qvariantSlotBoolIntUIntLonglongULonglongDoubleLongShortCharUlongUshortUcharFloat(" "bool,int,uint,qlonglong,qulonglong,double,long,short,char,ulong,ushort,uchar,float)") << int(QMetaType::QVariant) << QByteArray("QVariant") << parameterTypes << parameterTypeNames << parameterNames << QMetaMethod::Public << QMetaMethod::Slot; QTest::newRow("MethodTestObject(bool,int,uint,qlonglong,qulonglong,double,long,short,char,ulong,ushort,uchar,float)") << QByteArray("MethodTestObject(bool,int,uint,qlonglong,qulonglong,double,long,short,char,ulong,ushort,uchar,float)") << int(QMetaType::UnknownType) << QByteArray("") << parameterTypes << parameterTypeNames << parameterNames << QMetaMethod::Public << QMetaMethod::Constructor; } QTest::newRow("voidSignalNoParameterNames") << QByteArray("voidSignalNoParameterNames(bool,int)") << int(QMetaType::Void) << QByteArray("void") << (QList() << int(QMetaType::Bool) << int(QMetaType::Int)) << (QList() << QByteArray("bool") << QByteArray("int")) << (QList() << QByteArray("") << QByteArray("")) << QMetaMethod::Public << QMetaMethod::Signal; QTest::newRow("voidInvokableNoParameterNames") << QByteArray("voidInvokableNoParameterNames(bool,int)") << int(QMetaType::Void) << QByteArray("void") << (QList() << int(QMetaType::Bool) << int(QMetaType::Int)) << (QList() << QByteArray("bool") << QByteArray("int")) << (QList() << QByteArray("") << QByteArray("")) << QMetaMethod::Public << QMetaMethod::Method; QTest::newRow("voidSlotNoParameterNames") << QByteArray("voidSlotNoParameterNames(bool,int)") << int(QMetaType::Void) << QByteArray("void") << (QList() << int(QMetaType::Bool) << int(QMetaType::Int)) << (QList() << QByteArray("bool") << QByteArray("int")) << (QList() << QByteArray("") << QByteArray("")) << QMetaMethod::Public << QMetaMethod::Slot; QTest::newRow("MethodTestObject(bool,int)") << QByteArray("MethodTestObject(bool,int)") << int(QMetaType::UnknownType) << QByteArray("") << (QList() << int(QMetaType::Bool) << int(QMetaType::Int)) << (QList() << QByteArray("bool") << QByteArray("int")) << (QList() << QByteArray("") << QByteArray("")) << QMetaMethod::Public << QMetaMethod::Constructor; } void tst_QMetaMethod::method() { QFETCH(QByteArray, signature); QFETCH(int, returnType); QFETCH(QByteArray, returnTypeName); QFETCH(QList, parameterTypes); QFETCH(QList, parameterTypeNames); QFETCH(QList, parameterNames); QFETCH(QMetaMethod::MethodType, methodType); QFETCH(QMetaMethod::Access, access); QCOMPARE(parameterTypes.size(), parameterTypeNames.size()); QCOMPARE(parameterTypes.size(), parameterNames.size()); const QMetaObject *mo = &MethodTestObject::staticMetaObject; int index = (methodType == QMetaMethod::Constructor) ? mo->indexOfConstructor(signature) : mo->indexOfMethod(signature); QVERIFY(index != -1); QMetaMethod method = (methodType == QMetaMethod::Constructor) ? mo->constructor(index) : mo->method(index); QVERIFY(method.isValid()); QCOMPARE(method.methodType(), methodType); QCOMPARE(method.access(), access); QVERIFY(!method.methodSignature().isEmpty()); if (method.methodSignature() != signature) { // QMetaMethod should always produce a semantically equivalent signature int signatureIndex = (methodType == QMetaMethod::Constructor) ? mo->indexOfConstructor(method.methodSignature()) : mo->indexOfMethod(method.methodSignature()); QCOMPARE(signatureIndex, index); } QByteArray computedName = signature.left(signature.indexOf('(')); QCOMPARE(method.name(), computedName); QCOMPARE(method.tag(), ""); QCOMPARE(method.returnType(), returnType); QVERIFY(method.typeName() != 0); if (QByteArray(method.typeName()) != returnTypeName) { // QMetaMethod should always produce a semantically equivalent typename QCOMPARE(QMetaType::fromName(method.typeName()), QMetaType::fromName(returnTypeName)); } // check that parameterNames and parameterTypeName agree const auto methodParmaterTypes = method.parameterTypes(); for (int i = 0; i< methodParmaterTypes.size(); ++i) { QCOMPARE(methodParmaterTypes[i], method.parameterTypeName(i)); } if (method.parameterTypes() != parameterTypeNames) { // QMetaMethod should always produce semantically equivalent typenames QList actualTypeNames = method.parameterTypes(); QCOMPARE(actualTypeNames.size(), parameterTypeNames.size()); for (int i = 0; i < parameterTypeNames.size(); ++i) { QCOMPARE(QMetaType::fromName(actualTypeNames.at(i)), QMetaType::fromName(parameterTypeNames.at(i))); } } //QCOMPARE(method.parameterNames(), parameterNames); // ### not supported by W_INVOKABLE QCOMPARE(method.parameterCount(), parameterTypes.size()); for (int i = 0; i < parameterTypes.size(); ++i) QCOMPARE(method.parameterType(i), parameterTypes.at(i)); { QList actualParameterTypes(parameterTypes.size()); method.getParameterTypes(actualParameterTypes.data()); for (int i = 0; i < parameterTypes.size(); ++i) QCOMPARE(actualParameterTypes.at(i), parameterTypes.at(i)); } // Bogus indexes QCOMPARE(method.parameterType(-1), 0); QCOMPARE(method.parameterType(parameterTypes.size()), 0); } void tst_QMetaMethod::invalidMethod() { QMetaMethod method; QVERIFY(!method.isValid()); QMetaMethod method2 = staticMetaObject.method(staticMetaObject.methodCount()); QVERIFY(!method2.isValid()); QMetaMethod method3 = staticMetaObject.method(-1); QVERIFY(!method3.isValid()); } void tst_QMetaMethod::comparisonOperators() { static const QMetaObject *mo = &MethodTestObject::staticMetaObject; for (int x = 0; x < 2; ++x) { int count = x ? mo->constructorCount() : mo->methodCount(); for (int i = 0; i < count; ++i) { QMetaMethod method = x ? mo->constructor(i) : mo->method(i); const QMetaObject *methodMo = method.enclosingMetaObject(); for (int j = 0; j < count; ++j) { QMetaMethod other = x ? mo->constructor(j) : mo->method(j); bool expectedEqual = ((methodMo == other.enclosingMetaObject()) && (i == j)); QCOMPARE(method == other, expectedEqual); QCOMPARE(method != other, !expectedEqual); QCOMPARE(other == method, expectedEqual); QCOMPARE(other != method, !expectedEqual); } QVERIFY(method != QMetaMethod()); QVERIFY(QMetaMethod() != method); QVERIFY(!(method == QMetaMethod())); QVERIFY(!(QMetaMethod() == method)); } } // Constructors and normal methods with identical index should not // compare equal for (int i = 0; i < qMin(mo->methodCount(), mo->constructorCount()); ++i) { QMetaMethod method = mo->method(i); QMetaMethod constructor = mo->constructor(i); QVERIFY(method != constructor); QVERIFY(!(method == constructor)); } } void tst_QMetaMethod::fromSignal() { #define FROMSIGNAL_HELPER(ObjectType, Name, Arguments) { \ const QMetaObject *signalMeta = &ObjectType::staticMetaObject; \ QCOMPARE(QMetaMethod::fromSignal(&ObjectType::Name), \ signalMeta->method(signalMeta->indexOfSignal(QMetaObject::normalizedSignature(#Name #Arguments)))); \ } FROMSIGNAL_HELPER(MethodTestObject, voidSignal, ()) FROMSIGNAL_HELPER(MethodTestObject, voidSignalQString, (const QString&)) FROMSIGNAL_HELPER(QObject, destroyed, (QObject*)) FROMSIGNAL_HELPER(QObject, objectNameChanged, (const QString &)) // Inherited from QObject FROMSIGNAL_HELPER(MethodTestObject, destroyed, (QObject*)) FROMSIGNAL_HELPER(MethodTestObject, objectNameChanged, (const QString &)) // Methods that are not signals; fromSignal should return invalid method FROMSIGNAL_HELPER(MethodTestObject, voidSlot, ()) FROMSIGNAL_HELPER(QObject, deleteLater, ()) #undef FROMSIGNAL_HELPER } class MyGadget { W_GADGET(MyGadget) public: QString m_value; void setValue(const QString &value) { m_value = value; } W_INVOKABLE(setValue) QString getValue() { return m_value; } W_INVOKABLE(getValue) }; W_GADGET_IMPL(MyGadget) W_REGISTER_ARGTYPE(MyGadget) void tst_QMetaMethod::gadget() { int idx; idx = MyGadget::staticMetaObject.indexOfMethod("setValue(QString)"); QVERIFY(idx >= 0); QMetaMethod setValueMethod = MyGadget::staticMetaObject.method(idx); QVERIFY(setValueMethod.isValid()); idx = MyGadget::staticMetaObject.indexOfMethod("getValue()"); QVERIFY(idx >= 0); QMetaMethod getValueMethod = MyGadget::staticMetaObject.method(idx); QVERIFY(getValueMethod.isValid()); { MyGadget gadget; QString string; QVERIFY(getValueMethod.invokeOnGadget(&gadget, Q_RETURN_ARG(QString, string))); QCOMPARE(string, gadget.m_value); QVERIFY(setValueMethod.invokeOnGadget(&gadget, Q_ARG(QString, QLatin1String("hello")))); QCOMPARE(gadget.m_value, QLatin1String("hello")); QVERIFY(getValueMethod.invokeOnGadget(&gadget, Q_RETURN_ARG(QString, string))); QCOMPARE(string, gadget.m_value); } { // Call with null should not crash MyGadget *gadget = nullptr; QString string; QVERIFY(!setValueMethod.invokeOnGadget(gadget, Q_ARG(QString, QLatin1String("hi")))); QVERIFY(!getValueMethod.invokeOnGadget(gadget, Q_RETURN_ARG(QString, string))); } } class MyTestClass : public QObject { W_OBJECT(MyTestClass) public: MyTestClass() {}; // public Q_SLOTS: /*Q_REVISION(42)*/ MyGadget doStuff(int, float, MyGadget) {return {};} W_SLOT(doStuff, (int, float, MyGadget)) public: QObject *mySignal() W_SIGNAL(mySignal) }; W_OBJECT_IMPL(MyTestClass) void tst_QMetaMethod::revision() { QSKIP("Not supported by Verdigris"); auto mo = MyTestClass::staticMetaObject; const auto normalized = QMetaObject::normalizedSignature("doStuff(int, float, MyGadget)"); const int idx = mo.indexOfSlot(normalized); QMetaMethod mm = mo.method(idx); QVERIFY(mm.isValid()); QCOMPARE(QTypeRevision::fromEncodedVersion(mm.revision()), QTypeRevision::fromMinorVersion(42)); } void tst_QMetaMethod::returnMetaType() { { QMetaMethod mm = QMetaMethod::fromSignal(&MyTestClass::mySignal); QCOMPARE(mm.returnMetaType(), QMetaType::fromType()); } auto mo = MyTestClass::staticMetaObject; { const auto normalized = QMetaObject::normalizedSignature("doStuff(int, float, MyGadget)"); const int idx = mo.indexOfSlot(normalized); QMetaMethod mm = mo.method(idx); QVERIFY(mm.isValid()); QCOMPARE(mm.returnMetaType(), QMetaType::fromType()); } { // access of parent class meta methods works, too const auto normalized = QMetaObject::normalizedSignature("deleteLater()"); const int idx = mo.indexOfSlot(normalized); QMetaMethod mm = mo.method(idx); QVERIFY(mm.isValid()); QCOMPARE(mm.returnMetaType(), QMetaType::fromType()); } } void tst_QMetaMethod::parameterMetaType() { auto mo = MyTestClass::staticMetaObject; const auto normalized = QMetaObject::normalizedSignature("doStuff(int, float, MyGadget)"); const int idx = mo.indexOfSlot(normalized); QMetaMethod mm = mo.method(idx); { QVERIFY(!mm.parameterMetaType(-1).isValid()); QVERIFY(!mm.parameterMetaType(3).isValid()); } { QCOMPARE(mm.parameterMetaType(0), QMetaType::fromType()); QCOMPARE(mm.parameterMetaType(1), QMetaType::fromType()); QCOMPARE(mm.parameterMetaType(2), QMetaType::fromType()); } } void tst_QMetaMethod::parameterTypeName() { auto mo = MyTestClass::staticMetaObject; const auto normalized = QMetaObject::normalizedSignature("doStuff(int, float, MyGadget)"); const int idx = mo.indexOfSlot(normalized); QMetaMethod mm = mo.method(idx); { // check invalid indices QVERIFY(mm.parameterTypeName(-1).isEmpty()); QVERIFY(mm.parameterTypeName(3).isEmpty()); } { QCOMPARE(mm.parameterTypeName(0), QByteArray("int")); QCOMPARE(mm.parameterTypeName(1), QByteArray("float")); QCOMPARE(mm.parameterTypeName(2), QByteArray("MyGadget")); } } #if QT_VERSION >= QT_VERSION_CHECK(6,2,0) void tst_QMetaMethod::isConst() { auto mo = MethodTestObject::staticMetaObject; { const auto normalized = QMetaObject::normalizedSignature("qrealInvokable()"); const int idx = mo.indexOfSlot(normalized); QMetaMethod mm = mo.method(idx); QVERIFY(mm.isValid()); QCOMPARE(mm.isConst(), false); } { const auto normalized = QMetaObject::normalizedSignature("voidInvokable()"); const int idx = mo.indexOfSlot(normalized); QMetaMethod mm = mo.method(idx); QVERIFY(mm.isValid()); QCOMPARE(mm.isConst(), true); } } #endif QTEST_MAIN(tst_QMetaMethod) verdigris-1.3/tests/qt/qmetaobject/000077500000000000000000000000001427643277200174555ustar00rootroot00000000000000verdigris-1.3/tests/qt/qmetaobject/qmetaobject.pro000066400000000000000000000003571427643277200225020ustar00rootroot00000000000000CONFIG += testcase qtConfig(c++14): CONFIG += c++14 TARGET = tst_qmetaobject QT = core testlib greaterThan(QT_MAJOR_VERSION, 5) { SOURCES = tst_qmetaobject6.cpp } else { SOURCES = tst_qmetaobject5.cpp } include(../../../src/verdigris.pri) verdigris-1.3/tests/qt/qmetaobject/qmetaobject.qbs000066400000000000000000000007671427643277200224740ustar00rootroot00000000000000import qbs Application { name: "qmetaobject" consoleApplication: true type: ["application", "autotest"] Depends { name: "Verdigris" } Depends { name: "Qt.test" } Group { name: "qt5" condition: Qt.core.versionMajor < 6 files: [ "tst_qmetaobject5.cpp", ] } Group { name: "qt6" condition: Qt.core.versionMajor >= 6 files: [ "tst_qmetaobject6.cpp", ] } } verdigris-1.3/tests/qt/qmetaobject/tst_qmetaobject5.cpp000066400000000000000000002314521427643277200234450ustar00rootroot00000000000000/**************************************************************************** ** ** 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 #include #include #include #ifdef QT_BUILD_INTERNAL #undef QT_BUILD_INTERNAL // Verdigris don't test the internals #endif #include Q_DECLARE_METATYPE(const QMetaObject *) W_REGISTER_ARGTYPE(QList) struct MyStruct { int i; }; class MyGadget { W_GADGET(MyGadget) public: MyGadget() {} W_CONSTRUCTOR() }; W_GADGET_IMPL(MyGadget) namespace MyNamespace { // Used in tst_QMetaObject::checkScope class MyClass : public QObject { W_OBJECT(MyClass) public: enum MyEnum { MyEnum1, MyEnum2, MyEnum3 }; enum class MyScopedEnum { Enum1, Enum2, Enum3 }; enum MyAnotherEnum { MyAnotherEnum1 = 1, MyAnotherEnum2 = 2, MyAnotherEnum3 = -1 }; enum MyFlag { MyFlag1 = 0x01, MyFlag2 = 0x02, MyFlag3 = 0x04 }; enum class MyScopedFlag { MyFlag1 = 0x10, MyFlag2 = 0x20, MyFlag3 = 0x40 }; W_DECLARE_FLAGS(MyFlags, MyFlag) W_DECLARE_FLAGS(MyScopedFlags, MyScopedFlag) MyEnum myEnum() const { return m_enum; } void setMyEnum(MyEnum val) { m_enum = val; } MyFlags myFlags() const { return m_flags; } void setMyFlags(MyFlags val) { m_flags = val; } MyClass(QObject *parent = 0) : QObject(parent), m_enum(MyEnum1), m_flags(MyFlag1|MyFlag2) { } private: W_ENUM(MyEnum, MyEnum1, MyEnum2, MyEnum3) W_ENUM(MyScopedEnum, MyScopedEnum::Enum1, MyScopedEnum::Enum2, MyScopedEnum::Enum3) W_ENUM(MyAnotherEnum,MyAnotherEnum1,MyAnotherEnum2,MyAnotherEnum3) W_FLAG(MyFlags,MyFlag1,MyFlag2,MyFlag3) W_FLAG(MyScopedFlags, MyScopedFlag::MyFlag1, MyScopedFlag::MyFlag2, MyScopedFlag::MyFlag3) MyEnum m_enum; MyFlags m_flags; W_PROPERTY(MyEnum, myEnum READ myEnum WRITE setMyEnum) W_PROPERTY(MyFlags, myFlags READ myFlags WRITE setMyFlags) }; Q_DECLARE_OPERATORS_FOR_FLAGS(MyClass::MyFlags) // test the old Q_ENUMS macro class MyClass2 : public QObject { W_OBJECT(MyClass2) public: enum MyEnum { MyEnum1, MyEnum2, MyEnum3 }; enum MyAnotherEnum { MyAnotherEnum1 = 1, MyAnotherEnum2 = 2, MyAnotherEnum3 = -1 }; enum MyFlag { MyFlag1 = 0x01, MyFlag2 = 0x02, MyFlag3 = 0x04 }; Q_DECLARE_FLAGS(MyFlags, MyFlag) MyEnum myEnum() const { return m_enum; } void setMyEnum(MyEnum val) { m_enum = val; } MyFlags myFlags() const { return m_flags; } void setMyFlags(MyFlags val) { m_flags = val; } MyClass2(QObject *parent = 0) : QObject(parent), m_enum(MyEnum1), m_flags(MyFlag1|MyFlag2) { } private: W_ENUM(MyEnum, MyEnum1, MyEnum2, MyEnum3) W_ENUM(MyAnotherEnum,MyAnotherEnum1,MyAnotherEnum2,MyAnotherEnum3) W_FLAG(MyFlags,MyFlag1,MyFlag2,MyFlag3) MyEnum m_enum; MyFlags m_flags; W_PROPERTY(MyEnum, myEnum READ myEnum WRITE setMyEnum) W_PROPERTY(MyFlags, myFlags READ myFlags WRITE setMyFlags) }; // Test inherits class MyClassSubclass : public MyClass { W_OBJECT(MyClassSubclass) }; class MyClassSubclass2 : public MyClass2 { W_OBJECT(MyClassSubclass2) }; class MyClass2Subclass : public MyClass { W_OBJECT(MyClass2Subclass) }; #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) class ClassWithSetterGetterSignals : public QObject { W_OBJECT(ClassWithSetterGetterSignals) public: int value1() const { return m_value1; } void setValue1(int v) { if (v != m_value1) { m_value1 = v; Q_EMIT value1Changed(); } } int value2() const { return m_value2; } void setValue2(int v) { if (v != m_value2) { m_value2 = v; Q_EMIT value2Changed(); } } Q_SIGNALS: void value1Changed() W_SIGNAL(value1Changed) void value2Changed() W_SIGNAL(value2Changed) private: int m_value1 = 0; int m_value2 = 0; }; class ClassWithSetterGetterSignalsAddsProperties : public ClassWithSetterGetterSignals { W_OBJECT(ClassWithSetterGetterSignalsAddsProperties) W_PROPERTY(int, value1 READ value1 WRITE setValue1 NOTIFY value1Changed) W_PROPERTY(int, value2 READ value2 WRITE setValue2 NOTIFY value2Changed) }; class ClassWithChangedSignal : public QObject { W_OBJECT(ClassWithChangedSignal) public: int value1() const { return m_value1; } void setValue1(int v) { if (v != m_value1) { m_value1 = v; Q_EMIT propertiesChanged(); } } void thisIsNotASignal() { } Q_SIGNALS: void propertiesChanged() W_SIGNAL(propertiesChanged) private: int m_value1 = 0; }; class ClassWithChangedSignalNewValue : public ClassWithChangedSignal { W_OBJECT(ClassWithChangedSignalNewValue) private: int m_value2 = 0; W_PROPERTY(int, value2 MEMBER m_value2 NOTIFY propertiesChanged) #if 0 // With verdigris, this is a compilation error when the NOTIFY signal is not a signal int m_value3 = 0; W_PROPERTY(int, value3 MEMBER m_value3 NOTIFY thisIsNotASignal) #endif }; #endif } W_OBJECT_IMPL(MyNamespace::MyClass) W_OBJECT_IMPL(MyNamespace::MyClass2) W_OBJECT_IMPL(MyNamespace::MyClassSubclass) W_OBJECT_IMPL(MyNamespace::MyClassSubclass2) W_OBJECT_IMPL(MyNamespace::MyClass2Subclass) #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) W_OBJECT_IMPL(MyNamespace::ClassWithSetterGetterSignals) W_OBJECT_IMPL(MyNamespace::ClassWithSetterGetterSignalsAddsProperties) W_OBJECT_IMPL(MyNamespace::ClassWithChangedSignal) W_OBJECT_IMPL(MyNamespace::ClassWithChangedSignalNewValue) #endif class tst_QMetaObject : public QObject { W_OBJECT(tst_QMetaObject) public: enum EnumType { EnumType1 }; W_ENUM(EnumType,EnumType1); void setValue(EnumType) {} EnumType getValue() const { return EnumType1; } void set_value(EnumType) {} EnumType get_value() const { return EnumType1; } void setVal3(MyStruct) {} MyStruct val3() const { MyStruct s = {42}; return s; } void setVal4(const QList &list) { value4 = list; } QList val4() const { return value4; } void setVal5(const QVariantList &list) { value5 = list; } QVariantList val5() const { return value5; } int value6() const { return 1; } void setVal7(MyStruct) {} MyStruct value7() const { MyStruct s = {42}; return s; } int value8() const { return 1; } int value9() const { return 1; } int value10() const { return 1; } QList value4; QVariantList value5; private slots: #define DECLARE_TEST(NAME) void NAME(); W_SLOT(NAME) DECLARE_TEST(connectSlotsByName) DECLARE_TEST(invokeMetaMember) DECLARE_TEST(invokePointer) DECLARE_TEST(invokeQueuedMetaMember) DECLARE_TEST(invokeQueuedPointer) DECLARE_TEST(invokeBlockingQueuedMetaMember) DECLARE_TEST(invokeBlockingQueuedPointer) DECLARE_TEST(invokeCustomTypes) DECLARE_TEST(invokeMetaConstructor) DECLARE_TEST(invokeTypedefTypes) DECLARE_TEST(invokeException) DECLARE_TEST(invokeQueuedAutoRegister) DECLARE_TEST(qtMetaObjectInheritance) DECLARE_TEST(normalizedSignature_data) DECLARE_TEST(normalizedSignature) DECLARE_TEST(normalizedType_data) DECLARE_TEST(normalizedType) DECLARE_TEST(customPropertyType) DECLARE_TEST(checkScope_data) DECLARE_TEST(checkScope) DECLARE_TEST(propertyNotify) DECLARE_TEST(propertyConstant) DECLARE_TEST(propertyFinal) DECLARE_TEST(stdSet) DECLARE_TEST(classInfo) DECLARE_TEST(metaMethod) DECLARE_TEST(indexOfMethod_data) DECLARE_TEST(indexOfMethod) DECLARE_TEST(indexOfMethodPMF) #ifdef QT_BUILD_INTERNAL DECLARE_TEST(signalOffset_data) DECLARE_TEST(signalOffset) DECLARE_TEST(signalCount_data) DECLARE_TEST(signalCount) DECLARE_TEST(signal_data) DECLARE_TEST(signal) DECLARE_TEST(signalIndex_data) DECLARE_TEST(signalIndex) #endif DECLARE_TEST(enumDebugStream_data) DECLARE_TEST(enumDebugStream) DECLARE_TEST(inherits_data) DECLARE_TEST(inherits) DECLARE_TEST(notifySignalsInParentClass) #undef DECLARE_TEST signals: void value6Changed() W_SIGNAL(value6Changed) void value7Changed(const QString &_) W_SIGNAL(value7Changed,_) W_PROPERTY(EnumType, value WRITE setValue READ getValue) W_PROPERTY(EnumType, value2 WRITE set_value READ get_value) W_PROPERTY(MyStruct, value3 WRITE setVal3 READ val3) W_PROPERTY(QList, value4 WRITE setVal4 READ val4) W_PROPERTY(QVariantList, value5 WRITE setVal5 READ val5) W_PROPERTY(int, value6 READ value6 NOTIFY value6Changed) W_PROPERTY(MyStruct, value7 READ value7 WRITE setVal7 NOTIFY value7Changed) W_PROPERTY(int, value8 READ value8) W_PROPERTY(int, value9 READ value9 CONSTANT) W_PROPERTY(int, value10 READ value10 FINAL) }; W_OBJECT_IMPL(tst_QMetaObject) void tst_QMetaObject::stdSet() { QSKIP("Not supported by W_PROPERTY"); const QMetaObject *mo = metaObject(); QMetaProperty prop = mo->property(mo->indexOfProperty("value")); QVERIFY(prop.isValid()); QVERIFY(prop.hasStdCppSet()); prop = mo->property(mo->indexOfProperty("value2")); QVERIFY(prop.isValid()); QVERIFY(!prop.hasStdCppSet()); } class CTestObject: public QObject { W_OBJECT(CTestObject) public: CTestObject(): QObject(), invokeCount1(0), invokeCount2(0) { } void fire(const QString &name) { child = new QObject(this); child->setObjectName(name); QMetaObject::connectSlotsByName(this); delete child; child = 0; } int invokeCount1; int invokeCount2; QObject *child; public slots: void on_child1_destroyed(QObject *obj = 0) { ++invokeCount1; if (!obj || obj != child) qWarning() << "on_child1_destroyed invoked with wrong child object"; } W_SLOT(on_child1_destroyed) void on_child2_destroyed() { ++invokeCount2; } W_SLOT(on_child2_destroyed) }; W_OBJECT_IMPL(CTestObject) class CTestObjectOverloads: public QObject { W_OBJECT(CTestObjectOverloads) public: CTestObjectOverloads(): invokeCount1(0), invokeCount2(0) {} int invokeCount1; int invokeCount2; QObject *child; void fire(const QString &name) { child = new QObject(this); child->setObjectName(name); QMetaObject::connectSlotsByName(this); delete child; child = 0; } private slots: void on_child1_destroyed(QObject *obj) { ++invokeCount1; if (!obj || obj != child) qWarning() << "on_child1_destroyed invoked with wrong child object"; } W_SLOT(on_child1_destroyed,(QObject*)) void on_child1_destroyed() { ++invokeCount2; } W_SLOT(on_child1_destroyed,()) }; W_OBJECT_IMPL(CTestObjectOverloads) #define FUNCTION(x) "QMetaObject::" x ": " void tst_QMetaObject::connectSlotsByName() { CTestObject obj; QCOMPARE(obj.invokeCount1, 0); QCOMPARE(obj.invokeCount2, 0); QTest::ignoreMessage(QtWarningMsg, FUNCTION("connectSlotsByName") "No matching signal for on_child1_destroyed(QObject*)"); QTest::ignoreMessage(QtWarningMsg, FUNCTION("connectSlotsByName") "No matching signal for on_child2_destroyed()"); obj.fire("bubu"); QCOMPARE(obj.invokeCount1, 0); QCOMPARE(obj.invokeCount2, 0); QTest::ignoreMessage(QtWarningMsg, FUNCTION("connectSlotsByName") "No matching signal for on_child2_destroyed()"); obj.fire("child1"); QCOMPARE(obj.invokeCount1, 1); QCOMPARE(obj.invokeCount2, 0); QTest::ignoreMessage(QtWarningMsg, FUNCTION("connectSlotsByName") "No matching signal for on_child1_destroyed(QObject*)"); obj.fire("child2"); QCOMPARE(obj.invokeCount1, 1); QCOMPARE(obj.invokeCount2, 1); QTest::ignoreMessage(QtWarningMsg, FUNCTION("connectSlotsByName") "No matching signal for on_child2_destroyed()"); obj.fire("child1"); QCOMPARE(obj.invokeCount1, 2); QCOMPARE(obj.invokeCount2, 1); // now test with real overloads CTestObjectOverloads obj2; obj2.fire("child1"); QCOMPARE(obj2.invokeCount1, 1); QCOMPARE(obj2.invokeCount2, 1); } struct MyUnregisteredType { }; static int countedStructObjectsCount = 0; struct CountedStruct { CountedStruct() { ++countedStructObjectsCount; } CountedStruct(const CountedStruct &) { ++countedStructObjectsCount; } CountedStruct &operator=(const CountedStruct &) { return *this; } ~CountedStruct() { --countedStructObjectsCount; } }; #ifndef QT_NO_EXCEPTIONS class ObjectException : public std::exception { }; #endif W_REGISTER_ARGTYPE(QString&) W_REGISTER_ARGTYPE(QThread*) W_REGISTER_ARGTYPE(MyUnregisteredType) W_REGISTER_ARGTYPE(CountedStruct) class QtTestObject: public QObject { friend class tst_QMetaObject; W_OBJECT(QtTestObject) public: QtTestObject(); QtTestObject(const QString &s) : slotResult(s) {} QtTestObject(QObject *parent); W_CONSTRUCTOR(QObject*) public slots: void sl0(); W_SLOT(sl0) QString sl1(QString s1); W_SLOT(sl1) void sl2(QString s1, QString s2); W_SLOT(sl2) void sl3(QString s1, QString s2, QString s3); W_SLOT(sl3) void sl4(QString s1, QString s2, QString s3, const QString s4); W_SLOT(sl4) void sl5(QString s1, QString s2, QString s3, QString s4, const QString &s5); W_SLOT(sl5) void sl6(QString s1, QString s2, QString s3, QString s4, const QString s5, QString s6); W_SLOT(sl6) void sl7(QString s1, QString s2, QString s3, QString s4, QString s5, QString s6, QString s7); W_SLOT(sl7) void sl8(QString s1, QString s2, QString s3, QString s4, QString s5, QString s6, QString s7, QString s8); W_SLOT(sl8) void sl9(QString s1, QString s2, QString s3, QString s4, QString s5, QString s6, QString s7, QString s8, QString s9); W_SLOT(sl9) void sl10(QString s1, QString s2, QString s3, QString s4, QString s5, QString s6, QString s7, QString s8, QString s9, QString s10); W_SLOT(sl10) QObject *sl11(); W_SLOT(sl11) const char *sl12(); W_SLOT(sl12) QList sl13(QList l1); W_SLOT(sl13) qint64 sl14(); W_SLOT(sl14) void testSender(); W_SLOT(testSender) void testReference(QString &str); W_SLOT(testReference) void testLongLong(qint64 ll1, quint64 ll2); W_SLOT(testLongLong) void moveToThread(QThread *t) { QObject::moveToThread(t); } W_SLOT(moveToThread) void slotWithUnregisteredParameterType(MyUnregisteredType); W_SLOT(slotWithUnregisteredParameterType) CountedStruct throwingSlot(const CountedStruct &, CountedStruct s2) { #ifndef QT_NO_EXCEPTIONS throw ObjectException(); #endif return s2; } W_SLOT(throwingSlot) void slotWithRegistrableArgument(QtTestObject *o1, QPointer o2, QSharedPointer o3, QWeakPointer o4, QVector o5, QList o6) { slotResult = QLatin1String("slotWithRegistrableArgument:") + o1->slotResult + o2->slotResult + o3->slotResult + o4.lock().data()->slotResult + QString::number(o5.size()) + QString::number(o6.size()); } W_SLOT(slotWithRegistrableArgument, (QtTestObject*, QPointer, QSharedPointer, QWeakPointer, QVector,QList)) public: static void staticFunction0(); static qint64 staticFunction1(); signals: void sig0() W_SIGNAL(sig0) QString sig1(QString s1) W_SIGNAL(sig1,s1) void sig10(QString s1, QString s2, QString s3, QString s4, QString s5, QString s6, QString s7, QString s8, QString s9, QString s10) W_SIGNAL(sig10,s1,s2,s3,s4,s5,s6,s7,s8,s9,s10) protected: QtTestObject(QVariant) {} private: QtTestObject(QVariant, QVariant) {} public: QString slotResult; static QString staticResult; }; W_OBJECT_IMPL(QtTestObject) QString QtTestObject::staticResult; QtTestObject::QtTestObject() { connect(this, SIGNAL(sig0()), this, SLOT(sl0())); connect(this, SIGNAL(sig1(QString)), this, SLOT(sl1(QString))); } QtTestObject::QtTestObject(QObject *parent) : QObject(parent) { } void QtTestObject::sl0() { slotResult = "sl0"; } QString QtTestObject::sl1(QString s1) { slotResult = "sl1:" + s1; return "yessir"; } void QtTestObject::sl2(QString s1, QString s2) { slotResult = "sl2:" + s1 + s2; } void QtTestObject::sl3(QString s1, QString s2, QString s3) { slotResult = "sl3:" + s1 + s2 + s3; } void QtTestObject::sl4(QString s1, QString s2, QString s3, const QString s4) { slotResult = "sl4:" + s1 + s2 + s3 + s4; } void QtTestObject::sl5(QString s1, QString s2, QString s3, QString s4, const QString &s5) { slotResult = "sl5:" + s1 + s2 + s3 + s4 + s5; } void QtTestObject::sl6(QString s1, QString s2, QString s3, QString s4, const QString s5, QString s6) { slotResult = "sl6:" + s1 + s2 + s3 + s4 + s5 + s6; } void QtTestObject::sl7(QString s1, QString s2, QString s3, QString s4, QString s5, QString s6, QString s7) { slotResult = "sl7:" + s1 + s2 + s3 + s4 + s5 + s6 + s7; } void QtTestObject::sl8(QString s1, QString s2, QString s3, QString s4, QString s5, QString s6, QString s7, QString s8) { slotResult = "sl8:" + s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8; } void QtTestObject::sl9(QString s1, QString s2, QString s3, QString s4, QString s5, QString s6, QString s7, QString s8, QString s9) { slotResult = "sl9:" + s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9; } void QtTestObject::sl10(QString s1, QString s2, QString s3, QString s4, QString s5, QString s6, QString s7, QString s8, QString s9, QString s10) { slotResult = "sl10:" + s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10; } QObject *QtTestObject::sl11() { slotResult = "sl11"; return this; } const char *QtTestObject::sl12() { slotResult = "sl12"; return "foo"; } QList QtTestObject::sl13(QList l1) { slotResult = "sl13"; return l1; } qint64 QtTestObject::sl14() { slotResult = "sl14"; return Q_INT64_C(123456789)*123456789; } void QtTestObject::testReference(QString &str) { slotResult = "testReference:" + str; str = "gotcha"; } void QtTestObject::testLongLong(qint64 ll1, quint64 ll2) { slotResult = "testLongLong:" + QString::number(ll1) + "," + QString::number(ll2); } void QtTestObject::testSender() { slotResult = QString::asprintf("%p", sender()); } void QtTestObject::slotWithUnregisteredParameterType(MyUnregisteredType) { slotResult = "slotWithUnregisteredReturnType"; } void QtTestObject::staticFunction0() { staticResult = "staticFunction0"; } qint64 QtTestObject::staticFunction1() { staticResult = "staticFunction1"; return Q_INT64_C(123456789)*123456789; } void tst_QMetaObject::invokeMetaMember() { QtTestObject obj; QString t1("1"); QString t2("2"); QString t3("3"); QString t4("4"); QString t5("5"); QString t6("6"); QString t7("7"); QString t8("8"); QString t9("9"); QString t10("X"); // Test nullptr char *nullCharArray = nullptr; const char *nullConstCharArray = nullptr; QVERIFY(!QMetaObject::invokeMethod(nullptr, nullCharArray)); QVERIFY(!QMetaObject::invokeMethod(nullptr, nullConstCharArray)); QVERIFY(!QMetaObject::invokeMethod(nullptr, "sl0")); QVERIFY(!QMetaObject::invokeMethod(&obj, nullCharArray)); QVERIFY(!QMetaObject::invokeMethod(&obj, nullConstCharArray)); QVERIFY(!QMetaObject::invokeMethod(&obj, nullCharArray, Qt::AutoConnection)); QVERIFY(!QMetaObject::invokeMethod(&obj, nullConstCharArray, Qt::AutoConnection)); QVERIFY(!QMetaObject::invokeMethod(&obj, nullCharArray, Qt::AutoConnection, QGenericReturnArgument())); QVERIFY(!QMetaObject::invokeMethod(&obj, nullConstCharArray, Qt::AutoConnection, QGenericReturnArgument())); QVERIFY(QMetaObject::invokeMethod(&obj, "sl0")); QCOMPARE(obj.slotResult, QString("sl0")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", Q_ARG(QString, t1))); QCOMPARE(obj.slotResult, QString("sl1:1")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl2", Q_ARG(const QString, t1), Q_ARG(QString, t2))); QCOMPARE(obj.slotResult, QString("sl2:12")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl3", Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3))); QCOMPARE(obj.slotResult, QString("sl3:123")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl4", Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), Q_ARG(QString, t4))); QCOMPARE(obj.slotResult, QString("sl4:1234")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl5", Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, "5"))); QCOMPARE(obj.slotResult, QString("sl5:12345")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl6", Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, t5), Q_ARG(QString, t6))); QCOMPARE(obj.slotResult, QString("sl6:123456")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl7", Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, t5), Q_ARG(QString, t6), Q_ARG(QString, t7))); QCOMPARE(obj.slotResult, QString("sl7:1234567")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl8", Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, t5), Q_ARG(QString, t6), Q_ARG(QString, t7), Q_ARG(QString, t8))); QCOMPARE(obj.slotResult, QString("sl8:12345678")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl9", Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, t5), Q_ARG(QString, t6), Q_ARG(QString, t7), Q_ARG(QString, t8), Q_ARG(QString, t9))); QCOMPARE(obj.slotResult, QString("sl9:123456789")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl11")); QCOMPARE(obj.slotResult, QString("sl11")); QVERIFY(QMetaObject::invokeMethod(&obj, "testSender")); QCOMPARE(obj.slotResult, QString("0x0")); QString refStr("whatever"); QVERIFY(QMetaObject::invokeMethod(&obj, "testReference", QGenericArgument("QString&", &refStr))); QCOMPARE(obj.slotResult, QString("testReference:whatever")); QCOMPARE(refStr, QString("gotcha")); qint64 ll1 = -1; quint64 ll2 = 0; QVERIFY(QMetaObject::invokeMethod(&obj, "testLongLong", Q_ARG(qint64, ll1), Q_ARG(quint64, ll2))); QCOMPARE(obj.slotResult, QString("testLongLong:-1,0")); QString exp; QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", Q_RETURN_ARG(QString, exp), Q_ARG(QString, "bubu"))); QCOMPARE(exp, QString("yessir")); QCOMPARE(obj.slotResult, QString("sl1:bubu")); QObject *ptr = 0; QVERIFY(QMetaObject::invokeMethod(&obj, "sl11", Q_RETURN_ARG(QObject*,ptr))); QCOMPARE(ptr, (QObject *)&obj); QCOMPARE(obj.slotResult, QString("sl11")); // try again with a space: ptr = 0; QVERIFY(QMetaObject::invokeMethod(&obj, "sl11", Q_RETURN_ARG(QObject * , ptr))); QCOMPARE(ptr, (QObject *)&obj); QCOMPARE(obj.slotResult, QString("sl11")); const char *ptr2 = 0; QVERIFY(QMetaObject::invokeMethod(&obj, "sl12", Q_RETURN_ARG(const char*, ptr2))); QVERIFY(ptr2 != 0); QCOMPARE(obj.slotResult, QString("sl12")); // try again with a space: ptr2 = 0; QVERIFY(QMetaObject::invokeMethod(&obj, "sl12", Q_RETURN_ARG(char const * , ptr2))); QVERIFY(ptr2 != 0); QCOMPARE(obj.slotResult, QString("sl12")); // test w/ template args QList returnValue, argument; argument << QString("one") << QString("two") << QString("three"); QVERIFY(QMetaObject::invokeMethod(&obj, "sl13", Q_RETURN_ARG(QList, returnValue), Q_ARG(QList, argument))); QCOMPARE(returnValue, argument); QCOMPARE(obj.slotResult, QString("sl13")); // return qint64 qint64 return64; QVERIFY(QMetaObject::invokeMethod(&obj, "sl14", Q_RETURN_ARG(qint64, return64))); QCOMPARE(return64, Q_INT64_C(123456789)*123456789); QCOMPARE(obj.slotResult, QString("sl14")); //test signals QVERIFY(QMetaObject::invokeMethod(&obj, "sig0")); QCOMPARE(obj.slotResult, QString("sl0")); QVERIFY(QMetaObject::invokeMethod(&obj, "sig1", Q_ARG(QString, "baba"))); QCOMPARE(obj.slotResult, QString("sl1:baba")); exp.clear(); QVERIFY(QMetaObject::invokeMethod(&obj, "sig1", Q_RETURN_ARG(QString, exp), Q_ARG(QString, "hehe"))); QCOMPARE(exp, QString("yessir")); QCOMPARE(obj.slotResult, QString("sl1:hehe")); QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::doesNotExist()"); QVERIFY(!QMetaObject::invokeMethod(&obj, "doesNotExist")); QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString)(QString)"); QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1(QString)", Q_ARG(QString, "arg"))); QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl3(QString)\n" "Candidates are:\n sl3(QString,QString,QString)"); QVERIFY(!QMetaObject::invokeMethod(&obj, "sl3", Q_ARG(QString, "arg"))); QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString,QString,QString)\n" "Candidates are:\n sl1(QString)"); QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1", Q_ARG(QString, "arg"), Q_ARG(QString, "arg"), Q_ARG(QString, "arg"))); //should not have changed since last test. QCOMPARE(exp, QString("yessir")); QCOMPARE(obj.slotResult, QString("sl1:hehe")); } void testFunction(){} void tst_QMetaObject::invokePointer() { #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 1) QtTestObject obj; QtTestObject *const nullTestObject = nullptr; QString t1("1"); // Test member functions QVERIFY(!QMetaObject::invokeMethod(nullTestObject, &QtTestObject::sl0)); QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sl0)); QCOMPARE(obj.slotResult, QString("sl0")); QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::testSender)); QCOMPARE(obj.slotResult, QString("0x0")); qint64 return64 = 0; QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sl14, &return64)); QCOMPARE(return64, Q_INT64_C(123456789)*123456789); QCOMPARE(obj.slotResult, QString("sl14")); // signals QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sig0)); QCOMPARE(obj.slotResult, QString("sl0")); // Test function pointers QVERIFY(!QMetaObject::invokeMethod(0, &testFunction)); QVERIFY(QMetaObject::invokeMethod(&obj, &testFunction)); QVERIFY(!QMetaObject::invokeMethod(0, &QtTestObject::staticFunction0)); QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::staticFunction0)); QCOMPARE(QtTestObject::staticResult, QString("staticFunction0")); return64 = 0; QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::staticFunction1, &return64)); QCOMPARE(return64, Q_INT64_C(123456789)*123456789); QCOMPARE(QtTestObject::staticResult, QString("staticFunction1")); // Test lambdas QCOMPARE(countedStructObjectsCount, 0); { CountedStruct str; QVERIFY(QMetaObject::invokeMethod(&obj, [str, &t1, &obj]() { obj.sl1(t1); })); QCOMPARE(obj.slotResult, QString("sl1:1")); } QCOMPARE(countedStructObjectsCount, 0); { CountedStruct str; QString exp; QVERIFY(QMetaObject::invokeMethod( &obj, [str, &obj]() -> QString { return obj.sl1("bubu"); }, &exp)); QCOMPARE(exp, QString("yessir")); QCOMPARE(obj.slotResult, QString("sl1:bubu")); } QCOMPARE(countedStructObjectsCount, 0); #if defined(__cpp_init_captures) && QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) { CountedStruct str; std::unique_ptr ptr( new int ); QVERIFY(QMetaObject::invokeMethod(&obj, [str, &t1, &obj, p = std::move(ptr)]() { obj.sl1(t1); })); QCOMPARE(obj.slotResult, QString("sl1:1")); } QCOMPARE(countedStructObjectsCount, 0); #endif #endif } void tst_QMetaObject::invokeQueuedMetaMember() { QtTestObject obj; QVERIFY(QMetaObject::invokeMethod(&obj, "sl0", Qt::QueuedConnection)); QVERIFY(obj.slotResult.isEmpty()); qApp->processEvents(QEventLoop::AllEvents); QCOMPARE(obj.slotResult, QString("sl0")); obj.slotResult = QString(); QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", Qt::QueuedConnection, Q_ARG(QString, QString("hallo")))); QVERIFY(obj.slotResult.isEmpty()); qApp->processEvents(QEventLoop::AllEvents); QCOMPARE(obj.slotResult, QString("sl1:hallo")); obj.slotResult = QString(); QVERIFY(QMetaObject::invokeMethod(&obj, "sl9", Qt::QueuedConnection, Q_ARG(QString, "1"), Q_ARG(QString, "2"), Q_ARG(QString, "3"), Q_ARG(QString, "4"), Q_ARG(QString, "5"), Q_ARG(QString, "6"), Q_ARG(QString, "7"), Q_ARG(QString, "8"), Q_ARG(QString, "9"))); QVERIFY(obj.slotResult.isEmpty()); qApp->processEvents(QEventLoop::AllEvents); QCOMPARE(obj.slotResult, QString("sl9:123456789")); // signals obj.slotResult.clear(); QVERIFY(QMetaObject::invokeMethod(&obj, "sig0", Qt::QueuedConnection)); QVERIFY(obj.slotResult.isEmpty()); qApp->processEvents(QEventLoop::AllEvents); QCOMPARE(obj.slotResult, QString("sl0")); QVERIFY(QMetaObject::invokeMethod(&obj, "sig1", Qt::QueuedConnection, Q_ARG(QString, "gogo"))); qApp->processEvents(QEventLoop::AllEvents); QCOMPARE(obj.slotResult, QString("sl1:gogo")); QString exp; QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invoke: Unable to invoke methods with return values in queued connections"); QVERIFY(!QMetaObject::invokeMethod(&obj, "sig1", Qt::QueuedConnection, Q_RETURN_ARG(QString, exp), Q_ARG(QString, "nono"))); qint64 ll1 = -1; quint64 ll2 = 0; QVERIFY(QMetaObject::invokeMethod(&obj, "testLongLong", Qt::QueuedConnection, Q_ARG(qint64, ll1), Q_ARG(quint64, ll2))); qApp->processEvents(QEventLoop::AllEvents); QCOMPARE(obj.slotResult, QString("testLongLong:-1,0")); obj.slotResult.clear(); { MyUnregisteredType t; QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invoke: Unable to handle unregistered datatype 'MyUnregisteredType'"); QVERIFY(!QMetaObject::invokeMethod(&obj, "slotWithUnregisteredParameterType", Qt::QueuedConnection, Q_ARG(MyUnregisteredType, t))); QVERIFY(obj.slotResult.isEmpty()); } } void tst_QMetaObject::invokeQueuedPointer() { #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 1) QtTestObject obj; // Test member function QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sl0, Qt::QueuedConnection)); QVERIFY(obj.slotResult.isEmpty()); qApp->processEvents(QEventLoop::AllEvents); QCOMPARE(obj.slotResult, QString("sl0")); // signals obj.slotResult.clear(); QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sig0, Qt::QueuedConnection)); QVERIFY(obj.slotResult.isEmpty()); qApp->processEvents(QEventLoop::AllEvents); QCOMPARE(obj.slotResult, QString("sl0")); // Test function pointers QtTestObject::staticResult.clear(); QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::staticFunction0, Qt::QueuedConnection)); QVERIFY(QtTestObject::staticResult.isEmpty()); qApp->processEvents(QEventLoop::AllEvents); QCOMPARE(QtTestObject::staticResult, QString("staticFunction0")); // Test lambda QCOMPARE(countedStructObjectsCount, 0); { CountedStruct str; obj.slotResult.clear(); QVERIFY( QMetaObject::invokeMethod(&obj, [str, &obj]() { obj.sl0(); }, Qt::QueuedConnection)); QVERIFY(obj.slotResult.isEmpty()); qApp->processEvents(QEventLoop::AllEvents); QCOMPARE(obj.slotResult, QString("sl0")); } QCOMPARE(countedStructObjectsCount, 0); { CountedStruct str; qint32 var = 0; QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: Unable to invoke methods with return " "values in queued connections"); QVERIFY(!QMetaObject::invokeMethod(&obj, [str]() -> qint32 { return 1; }, Qt::QueuedConnection, &var)); QCOMPARE(var, 0); } QCOMPARE(countedStructObjectsCount, 0); #endif } void tst_QMetaObject::invokeBlockingQueuedMetaMember() { QThread t; t.start(); QtTestObject obj; obj.moveToThread(&t); QString t1("1"); QString t2("2"); QString t3("3"); QString t4("4"); QString t5("5"); QString t6("6"); QString t7("7"); QString t8("8"); QString t9("9"); QString t10("X"); QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", Qt::BlockingQueuedConnection, Q_ARG(QString, t1))); QCOMPARE(obj.slotResult, QString("sl1:1")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl2", Qt::BlockingQueuedConnection, Q_ARG(const QString, t1), Q_ARG(QString, t2))); QCOMPARE(obj.slotResult, QString("sl2:12")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl3", Qt::BlockingQueuedConnection, Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3))); QCOMPARE(obj.slotResult, QString("sl3:123")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl4", Qt::BlockingQueuedConnection, Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), Q_ARG(QString, t4))); QCOMPARE(obj.slotResult, QString("sl4:1234")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl5", Qt::BlockingQueuedConnection, Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, "5"))); QCOMPARE(obj.slotResult, QString("sl5:12345")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl6", Qt::BlockingQueuedConnection, Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, t5), Q_ARG(QString, t6))); QCOMPARE(obj.slotResult, QString("sl6:123456")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl7", Qt::BlockingQueuedConnection, Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, t5), Q_ARG(QString, t6), Q_ARG(QString, t7))); QCOMPARE(obj.slotResult, QString("sl7:1234567")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl8", Qt::BlockingQueuedConnection, Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, t5), Q_ARG(QString, t6), Q_ARG(QString, t7), Q_ARG(QString, t8))); QCOMPARE(obj.slotResult, QString("sl8:12345678")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl9", Qt::BlockingQueuedConnection, Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, t5), Q_ARG(QString, t6), Q_ARG(QString, t7), Q_ARG(QString, t8), Q_ARG(QString, t9))); QCOMPARE(obj.slotResult, QString("sl9:123456789")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl11", Qt::BlockingQueuedConnection)); QCOMPARE(obj.slotResult, QString("sl11")); QVERIFY(QMetaObject::invokeMethod(&obj, "testSender", Qt::BlockingQueuedConnection)); QCOMPARE(obj.slotResult, QString("0x0")); QString refStr("whatever"); QVERIFY(QMetaObject::invokeMethod(&obj, "testReference", Qt::BlockingQueuedConnection, QGenericArgument("QString&", &refStr))); QCOMPARE(obj.slotResult, QString("testReference:whatever")); QCOMPARE(refStr, QString("gotcha")); qint64 ll1 = -1; quint64 ll2 = 0; QVERIFY(QMetaObject::invokeMethod(&obj, "testLongLong", Qt::BlockingQueuedConnection, Q_ARG(qint64, ll1), Q_ARG(quint64, ll2))); QCOMPARE(obj.slotResult, QString("testLongLong:-1,0")); QString exp; QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, exp), Q_ARG(QString, "bubu"))); QCOMPARE(exp, QString("yessir")); QCOMPARE(obj.slotResult, QString("sl1:bubu")); QObject *ptr = 0; QVERIFY(QMetaObject::invokeMethod(&obj, "sl11", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QObject*,ptr))); QCOMPARE(ptr, (QObject *)&obj); QCOMPARE(obj.slotResult, QString("sl11")); // try again with a space: ptr = 0; QVERIFY(QMetaObject::invokeMethod(&obj, "sl11", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QObject * , ptr))); QCOMPARE(ptr, (QObject *)&obj); QCOMPARE(obj.slotResult, QString("sl11")); const char *ptr2 = 0; QVERIFY(QMetaObject::invokeMethod(&obj, "sl12", Qt::BlockingQueuedConnection, Q_RETURN_ARG(const char*, ptr2))); QVERIFY(ptr2 != 0); QCOMPARE(obj.slotResult, QString("sl12")); // try again with a space: ptr2 = 0; QVERIFY(QMetaObject::invokeMethod(&obj, "sl12", Qt::BlockingQueuedConnection, Q_RETURN_ARG(char const * , ptr2))); QVERIFY(ptr2 != 0); QCOMPARE(obj.slotResult, QString("sl12")); // test w/ template args QList returnValue, argument; argument << QString("one") << QString("two") << QString("three"); QVERIFY(QMetaObject::invokeMethod(&obj, "sl13", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QList, returnValue), Q_ARG(QList, argument))); QCOMPARE(returnValue, argument); QCOMPARE(obj.slotResult, QString("sl13")); //test signals QVERIFY(QMetaObject::invokeMethod(&obj, "sig0", Qt::BlockingQueuedConnection)); QCOMPARE(obj.slotResult, QString("sl0")); QVERIFY(QMetaObject::invokeMethod(&obj, "sig1", Qt::BlockingQueuedConnection, Q_ARG(QString, "baba"))); QCOMPARE(obj.slotResult, QString("sl1:baba")); exp.clear(); QVERIFY(QMetaObject::invokeMethod(&obj, "sig1", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, exp), Q_ARG(QString, "hehe"))); QCOMPARE(exp, QString("yessir")); QCOMPARE(obj.slotResult, QString("sl1:hehe")); QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::doesNotExist()"); QVERIFY(!QMetaObject::invokeMethod(&obj, "doesNotExist", Qt::BlockingQueuedConnection)); QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString)(QString)"); QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1(QString)", Qt::BlockingQueuedConnection, Q_ARG(QString, "arg"))); QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl3(QString)\n" "Candidates are:\n sl3(QString,QString,QString)"); QVERIFY(!QMetaObject::invokeMethod(&obj, "sl3", Qt::BlockingQueuedConnection, Q_ARG(QString, "arg"))); QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString,QString,QString)\n" "Candidates are:\n sl1(QString)"); QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1", Qt::BlockingQueuedConnection, Q_ARG(QString, "arg"), Q_ARG(QString, "arg"), Q_ARG(QString, "arg"))); //should not have changed since last test. QCOMPARE(exp, QString("yessir")); QCOMPARE(obj.slotResult, QString("sl1:hehe")); QVERIFY(QMetaObject::invokeMethod(&obj, "moveToThread", Qt::BlockingQueuedConnection, Q_ARG(QThread*, QThread::currentThread()))); t.quit(); QVERIFY(t.wait()); } void tst_QMetaObject::invokeBlockingQueuedPointer() { #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 1) QtTestObject *const nullTestObject = nullptr; QThread t; t.start(); QtTestObject obj; obj.moveToThread(&t); QString t1("1"); // Test member functions QVERIFY(!QMetaObject::invokeMethod(nullTestObject, &QtTestObject::sl0, Qt::BlockingQueuedConnection)); QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sl0, Qt::BlockingQueuedConnection)); QCOMPARE(obj.slotResult, QString("sl0")); QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::testSender, Qt::BlockingQueuedConnection)); QCOMPARE(obj.slotResult, QString("0x0")); // return qint64 qint64 return64 = 0; QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sl14, Qt::BlockingQueuedConnection, &return64)); QCOMPARE(return64, Q_INT64_C(123456789)*123456789); QCOMPARE(obj.slotResult, QString("sl14")); //test signals QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sig0, Qt::BlockingQueuedConnection)); QCOMPARE(obj.slotResult, QString("sl0")); // Test function pointers QVERIFY(!QMetaObject::invokeMethod(0, &testFunction, Qt::BlockingQueuedConnection)); QVERIFY(QMetaObject::invokeMethod(&obj, &testFunction, Qt::BlockingQueuedConnection)); QVERIFY(!QMetaObject::invokeMethod(0, &QtTestObject::staticFunction0, Qt::BlockingQueuedConnection)); QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::staticFunction0, Qt::BlockingQueuedConnection)); QCOMPARE(QtTestObject::staticResult, QString("staticFunction0")); return64 = 0; QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::staticFunction1, Qt::BlockingQueuedConnection, &return64)); QCOMPARE(return64, Q_INT64_C(123456789)*123456789); QCOMPARE(QtTestObject::staticResult, QString("staticFunction1")); // Test lambdas QCOMPARE(countedStructObjectsCount, 0); { CountedStruct str; QVERIFY(QMetaObject::invokeMethod(&obj, [str, &obj, &t1]() { obj.sl1(t1); }, Qt::BlockingQueuedConnection)); QCOMPARE(obj.slotResult, QString("sl1:1")); } { CountedStruct str; QString exp; QVERIFY(QMetaObject::invokeMethod(&obj, [&obj, str]() -> QString { return obj.sl1("bubu"); }, Qt::BlockingQueuedConnection, &exp)); QCOMPARE(exp, QString("yessir")); QCOMPARE(obj.slotResult, QString("sl1:bubu")); } #if defined(__cpp_init_captures) && QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) { std::unique_ptr ptr(new int); QVERIFY(QMetaObject::invokeMethod(&obj, [&obj, p = std::move(ptr)]() { return obj.sl1("hehe"); }, Qt::BlockingQueuedConnection)); QCOMPARE(obj.slotResult, QString("sl1:hehe")); } #endif QVERIFY(QMetaObject::invokeMethod(&obj, [&](){obj.moveToThread(QThread::currentThread());}, Qt::BlockingQueuedConnection)); t.quit(); QVERIFY(t.wait()); QCOMPARE(countedStructObjectsCount, 0); #endif } void tst_QMetaObject::qtMetaObjectInheritance() { QVERIFY(!QObject::staticMetaObject.superClass()); QCOMPARE(QSortFilterProxyModel::staticMetaObject.indexOfEnumerator("Qt::CaseSensitivity"), -1); QCOMPARE(QSortFilterProxyModel::staticMetaObject.indexOfEnumerator("CaseSensitivity"), -1); int indexOfSortCaseSensitivity = QSortFilterProxyModel::staticMetaObject.indexOfProperty("sortCaseSensitivity"); QVERIFY(indexOfSortCaseSensitivity != -1); QMetaProperty sortCaseSensitivity = QSortFilterProxyModel::staticMetaObject.property(indexOfSortCaseSensitivity); QVERIFY(sortCaseSensitivity.isValid()); QCOMPARE(sortCaseSensitivity.enumerator().name(), "CaseSensitivity"); } struct MyType { int i1, i2, i3; }; W_REGISTER_ARGTYPE(MyType) typedef QString CustomString; class QtTestCustomObject: public QObject { W_OBJECT(QtTestCustomObject) friend class tst_QMetaObject; public: QtTestCustomObject(): QObject(), sum(0) {} public slots: void sl1(MyType myType); W_SLOT(sl1) signals: void sig_custom(const CustomString &string) W_SIGNAL(sig_custom,string) public: int sum; }; W_OBJECT_IMPL(QtTestCustomObject) void QtTestCustomObject::sl1(MyType myType) { sum = myType.i1 + myType.i2 + myType.i3; } void tst_QMetaObject::invokeCustomTypes() { QtTestCustomObject obj; MyType tp = {1, 1, 1}; QCOMPARE(obj.sum, 0); QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", Q_ARG(MyType, tp))); QCOMPARE(obj.sum, 3); } namespace NamespaceWithConstructibleClass { class ConstructibleClass : public QObject { W_OBJECT(ConstructibleClass) public: ConstructibleClass(QObject *parent = 0) : QObject(parent) {} W_CONSTRUCTOR(QObject*) }; } W_OBJECT_IMPL(NamespaceWithConstructibleClass::ConstructibleClass) void tst_QMetaObject::invokeMetaConstructor() { const QMetaObject *mo = &QtTestObject::staticMetaObject; { QObject *obj = mo->newInstance(); QVERIFY(!obj); } { QtTestObject obj; QObject *obj2 = mo->newInstance(Q_ARG(QObject*, &obj)); QVERIFY(obj2 != 0); QCOMPARE(obj2->parent(), (QObject*)&obj); QVERIFY(qobject_cast(obj2) != 0); } // class in namespace const QMetaObject *nsmo = &NamespaceWithConstructibleClass::ConstructibleClass::staticMetaObject; { QtTestObject obj; QObject *obj2 = nsmo->newInstance(Q_ARG(QObject*, &obj)); QVERIFY(obj2 != 0); QCOMPARE(obj2->parent(), (QObject*)&obj); QVERIFY(qobject_cast(obj2) != 0); } // gadget shouldn't return a valid pointer #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) { QCOMPARE(MyGadget::staticMetaObject.constructorCount(), 1); QTest::ignoreMessage(QtWarningMsg, "QMetaObject::newInstance: type MyGadget does not inherit QObject"); QVERIFY(!MyGadget::staticMetaObject.newInstance()); } #endif } void tst_QMetaObject::invokeTypedefTypes() { qRegisterMetaType("CustomString"); QtTestCustomObject obj; QSignalSpy spy(&obj, &QtTestCustomObject::sig_custom); QVERIFY(spy.isValid()); QCOMPARE(spy.count(), 0); CustomString arg("hello"); QVERIFY(QMetaObject::invokeMethod(&obj, "sig_custom", Q_ARG(CustomString, arg))); QCOMPARE(spy.count(), 1); QCOMPARE(spy.at(0).count(), 1); QCOMPARE(spy.at(0).at(0), QVariant(arg)); } void tst_QMetaObject::invokeException() { #ifndef QT_NO_EXCEPTIONS QtTestObject obj; QCOMPARE(countedStructObjectsCount, 0); try { CountedStruct s; QVERIFY(QMetaObject::invokeMethod(&obj, "throwingSlot", Q_RETURN_ARG(CountedStruct, s), Q_ARG(CountedStruct, s), Q_ARG(CountedStruct, s))); QFAIL("Did not throw"); } catch(ObjectException &) {} QCOMPARE(countedStructObjectsCount, 0); #else QSKIP("Needs exceptions"); #endif } void tst_QMetaObject::invokeQueuedAutoRegister() { #if QT_VERSION < QT_VERSION_CHECK(5, 9, 0) QSKIP("Bug fixed in Qt 5.9"); #endif QtTestObject obj; auto shared = QSharedPointer::create(QStringLiteral("myShared-")); QVERIFY(QMetaObject::invokeMethod( &obj, "slotWithRegistrableArgument", Qt::QueuedConnection, Q_ARG(QtTestObject *, shared.data()), Q_ARG(QPointer, shared.data()), Q_ARG(QSharedPointer, shared), Q_ARG(QWeakPointer, shared), Q_ARG(QVector, QVector()), Q_ARG(QList, QList()))); QVERIFY(obj.slotResult.isEmpty()); qApp->processEvents(QEventLoop::AllEvents); QCOMPARE(obj.slotResult, QString("slotWithRegistrableArgument:myShared-myShared-myShared-myShared-00")); } void tst_QMetaObject::normalizedSignature_data() { QTest::addColumn("signature"); QTest::addColumn("result"); QTest::newRow("function") << "void foo()" << "void foo()"; QTest::newRow("spaces") << " void foo( ) " << "void foo()"; QTest::newRow("void") << "void foo(void)" << "void foo()"; QTest::newRow("void spaces") << "void foo( void )" << "void foo()"; QTest::newRow("void*") << "void foo(void*)" << "void foo(void*)"; QTest::newRow("void* spaces") << "void foo( void * )" << "void foo(void*)"; QTest::newRow("function ptr") << "void foo(void(*)(void))" << "void foo(void(*)())"; QTest::newRow("function ptr spaces") << "void foo( void ( * ) ( void ))" << "void foo(void(*)())"; QTest::newRow("function ptr void*") << "void foo(void(*)(void*))" << "void foo(void(*)(void*))"; QTest::newRow("function ptr void* spaces") << "void foo( void ( * ) ( void * ))" << "void foo(void(*)(void*))"; QTest::newRow("template args") << " void foo( QMap, QList) " << "void foo(QMap,QList)"; QTest::newRow("void template args") << " void foo( Foo, Bar ) " << "void foo(Foo,Bar)"; QTest::newRow("void* template args") << " void foo( Foo, Bar ) " << "void foo(Foo,Bar)"; QTest::newRow("rettype") << "QList foo()" << "QListfoo()"; QTest::newRow("rettype void template") << "Foo foo()" << "Foofoo()"; QTest::newRow("const rettype") << "const QString *foo()" << "const QString*foo()"; QTest::newRow("const ref") << "const QString &foo()" << "const QString&foo()"; QTest::newRow("reference") << "QString &foo()" << "QString&foo()"; QTest::newRow("const1") << "void foo(QString const *)" << "void foo(const QString*)"; QTest::newRow("const2") << "void foo(QString * const)" << "void foo(QString*const)"; QTest::newRow("const3") << "void foo(QString const &)" << "void foo(QString)"; QTest::newRow("const4") << "void foo(const int)" << "void foo(int)"; QTest::newRow("const5") << "void foo(const int, int const, const int &, int const &)" << "void foo(int,int,int,int)"; QTest::newRow("const6") << "void foo(QList)" << "void foo(QList)"; QTest::newRow("const7") << "void foo(QList)" << "void foo(QList)"; QTest::newRow("const8") << "void foo(QList)" << "void foo(QList)"; QTest::newRow("const9") << "void foo(const Foo)" << "void foo(Foo)"; QTest::newRow("const10") << "void foo(Fooconst)" << "void foo(Foo)"; QTest::newRow("const11") << "void foo(Foo *const)" << "void foo(Foo*const)"; QTest::newRow("const12") << "void foo(Fooconst*const *const)" << "void foo(Foo*const*const)"; QTest::newRow("const13") << "void foo(const Foo&)" << "void foo(Foo)"; QTest::newRow("const14") << "void foo(Fooconst&)" << "void foo(Foo)"; QTest::newRow("invalid1") << "a( b" << "a(b"; } void tst_QMetaObject::normalizedSignature() { QFETCH(QString, signature); QFETCH(QString, result); QCOMPARE(QMetaObject::normalizedSignature(signature.toLatin1()), result.toLatin1()); } void tst_QMetaObject::normalizedType_data() { QTest::addColumn("type"); QTest::addColumn("result"); QTest::newRow("simple") << "int" << "int"; QTest::newRow("white") << " int " << "int"; QTest::newRow("const1") << "int const *" << "const int*"; QTest::newRow("const2") << "const int *" << "const int*"; QTest::newRow("template1") << "QList" << "QList"; QTest::newRow("template2") << "QList" << "QList"; QTest::newRow("template3") << "QMap" << "QMap"; QTest::newRow("template4") << "const QMap &" << "QMap"; QTest::newRow("template5") << "QList< ::Foo::Bar>" << "QList< ::Foo::Bar>"; QTest::newRow("template6") << "QList<::Foo::Bar>" << "QList<::Foo::Bar>"; QTest::newRow("template7") << "QList >" << "QList >"; QTest::newRow("template8") << "QMap" << "QMap"; QTest::newRow("template9") << "QPair , QPair > >" << "QPair,QPair > >"; QTest::newRow("value1") << "const QString &" << "QString"; QTest::newRow("value2") << "QString const &" << "QString"; QTest::newRow("constInName1") << "constconst" << "constconst"; QTest::newRow("constInName2") << "constconst*" << "constconst*"; QTest::newRow("constInName3") << "const constconst&" << "constconst"; QTest::newRow("constInName4") << "constconst const*const" << "constconst*const"; QTest::newRow("class") << "const class foo&" << "foo"; QTest::newRow("struct") << "const struct foo*" << "const foo*"; QTest::newRow("struct2") << "struct foo const*" << "const foo*"; QTest::newRow("enum") << "enum foo" << "foo"; QTest::newRow("void") << "void" << "void"; } void tst_QMetaObject::normalizedType() { QFETCH(QString, type); QFETCH(QString, result); QCOMPARE(QMetaObject::normalizedType(type.toLatin1()), result.toLatin1()); } void tst_QMetaObject::customPropertyType() { QMetaProperty prop = metaObject()->property(metaObject()->indexOfProperty("value3")); QCOMPARE(prop.type(), QVariant::UserType); QCOMPARE(prop.userType(), 0); qRegisterMetaType("MyStruct"); QCOMPARE(prop.userType(), QMetaType::type("MyStruct")); prop = metaObject()->property(metaObject()->indexOfProperty("value4")); QCOMPARE(prop.type(), QVariant::List); prop = metaObject()->property(metaObject()->indexOfProperty("value5")); QCOMPARE(prop.type(), QVariant::List); } void tst_QMetaObject::checkScope_data() { QTest::addColumn("object"); QTest::addColumn("name"); static MyNamespace::MyClass obj1; static MyNamespace::MyClass2 obj2; QTest::newRow("MyClass") << static_cast(&obj1) << QByteArray("MyClass"); QTest::newRow("MyClass2") << static_cast(&obj2) << QByteArray("MyClass2"); } void tst_QMetaObject::checkScope() { QFETCH(QObject *, object); QFETCH(QByteArray, name); QObject &obj = *object; bool ok; const QMetaObject *mo = obj.metaObject(); QMetaEnum me = mo->enumerator(mo->indexOfEnumerator("MyEnum")); QVERIFY(me.isValid()); QVERIFY(!me.isFlag()); QCOMPARE(QByteArray(me.scope()), QByteArray("MyNamespace::" + name)); QCOMPARE(me.keyToValue("MyNamespace::" + name + "::MyEnum2", &ok), 1); QCOMPARE(ok, true); QCOMPARE(me.keyToValue(name + "::MyEnum2", &ok), -1); QCOMPARE(ok, false); QCOMPARE(me.keyToValue("MyNamespace::MyEnum2", &ok), -1); QCOMPARE(ok, false); QCOMPARE(me.keyToValue("MyEnum2", &ok), 1); QCOMPARE(ok, true); QCOMPARE(me.keyToValue("MyEnum", &ok), -1); QCOMPARE(ok, false); QCOMPARE(QLatin1String(me.valueToKey(1)), QLatin1String("MyEnum2")); QMetaEnum me2 = mo->enumerator(mo->indexOfEnumerator("MyAnotherEnum")); QVERIFY(me2.isValid()); QVERIFY(!me2.isFlag()); QCOMPARE(me2.keyToValue("MyAnotherEnum1", &ok), 1); QCOMPARE(ok, true); QCOMPARE(me2.keyToValue("MyAnotherEnum2", &ok), 2); QCOMPARE(ok, true); QCOMPARE(me2.keyToValue("MyAnotherEnum3", &ok), -1); QCOMPARE(ok, true); QCOMPARE(me2.keyToValue("MyAnotherEnum", &ok), -1); QCOMPARE(ok, false); QMetaEnum mf = mo->enumerator(mo->indexOfEnumerator("MyFlags")); QVERIFY(mf.isValid()); QVERIFY(mf.isFlag()); QCOMPARE(QByteArray(mf.scope()), QByteArray("MyNamespace::" + name)); QCOMPARE(mf.keysToValue("MyNamespace::" + name + "::MyFlag2", &ok), 2); QCOMPARE(ok, true); QCOMPARE(mf.keysToValue(name + "::MyFlag2", &ok), -1); QCOMPARE(ok, false); QCOMPARE(mf.keysToValue("MyNamespace::MyFlag2", &ok), -1); QCOMPARE(ok, false); QCOMPARE(mf.keysToValue("MyFlag2", &ok), 2); QCOMPARE(ok, true); QCOMPARE(mf.keysToValue("MyFlag", &ok), -1); QCOMPARE(ok, false); QCOMPARE(QLatin1String(mf.valueToKey(2)), QLatin1String("MyFlag2")); QCOMPARE(mf.keysToValue("MyNamespace::" + name + "::MyFlag1|MyNamespace::" + name + "::MyFlag2", &ok), 3); QCOMPARE(ok, true); QCOMPARE(mf.keysToValue(name + "::MyFlag1|" + name + "::MyFlag2", &ok), -1); QCOMPARE(ok, false); QCOMPARE(mf.keysToValue("MyNamespace::MyFlag1|MyNamespace::MyFlag2", &ok), -1); QCOMPARE(ok, false); QCOMPARE(mf.keysToValue("MyFlag1|MyFlag2", &ok), 3); QCOMPARE(ok, true); QCOMPARE(mf.keysToValue("MyFlag2|MyFlag2", &ok), 2); QCOMPARE(ok, true); QCOMPARE(mf.keysToValue("MyFlag1|MyNamespace::" + name + "::MyFlag2", &ok), 3); QCOMPARE(ok, true); QCOMPARE(mf.keysToValue("MyNamespace::" + name + "::MyFlag2|MyNamespace::" + name + "::MyFlag2", &ok), 2); QCOMPARE(ok, true); QCOMPARE(QLatin1String(mf.valueToKeys(3)), QLatin1String("MyFlag1|MyFlag2")); } void tst_QMetaObject::propertyNotify() { const QMetaObject *mo = metaObject(); QMetaProperty prop = mo->property(mo->indexOfProperty("value6")); QVERIFY(prop.isValid()); QVERIFY(prop.hasNotifySignal()); QMetaMethod signal = prop.notifySignal(); QCOMPARE(signal.methodSignature(), QByteArray("value6Changed()")); prop = mo->property(mo->indexOfProperty("value7")); QVERIFY(prop.isValid()); QVERIFY(prop.hasNotifySignal()); signal = prop.notifySignal(); QCOMPARE(signal.methodSignature(), QByteArray("value7Changed(QString)")); prop = mo->property(mo->indexOfProperty("value8")); QVERIFY(prop.isValid()); QVERIFY(!prop.hasNotifySignal()); signal = prop.notifySignal(); QCOMPARE(signal.methodSignature(), QByteArray()); prop = mo->property(mo->indexOfProperty("value")); QVERIFY(prop.isValid()); QVERIFY(!prop.hasNotifySignal()); signal = prop.notifySignal(); QCOMPARE(signal.methodSignature(), QByteArray()); } void tst_QMetaObject::propertyConstant() { const QMetaObject *mo = metaObject(); QMetaProperty prop = mo->property(mo->indexOfProperty("value8")); QVERIFY(prop.isValid()); QVERIFY(!prop.isConstant()); prop = mo->property(mo->indexOfProperty("value9")); QVERIFY(prop.isValid()); QVERIFY(prop.isConstant()); } void tst_QMetaObject::propertyFinal() { const QMetaObject *mo = metaObject(); QMetaProperty prop = mo->property(mo->indexOfProperty("value10")); QVERIFY(prop.isValid()); QVERIFY(prop.isFinal()); prop = mo->property(mo->indexOfProperty("value9")); QVERIFY(prop.isValid()); QVERIFY(!prop.isFinal()); } class ClassInfoTestObjectA : public QObject { W_OBJECT(ClassInfoTestObjectA) W_CLASSINFO("Author", "Christopher Pike") }; W_OBJECT_IMPL(ClassInfoTestObjectA) class ClassInfoTestObjectB : public ClassInfoTestObjectA { W_OBJECT(ClassInfoTestObjectB) }; W_OBJECT_IMPL(ClassInfoTestObjectB) void tst_QMetaObject::classInfo() { ClassInfoTestObjectB b; int index = b.metaObject()->indexOfClassInfo("Author"); QCOMPARE(index, 0); QVERIFY(index <= b.metaObject()->classInfoOffset()); QCOMPARE(QLatin1String(b.metaObject()->classInfo(index).value()), QLatin1String("Christopher Pike")); } void tst_QMetaObject::metaMethod() { QString str("foo"); QString ret("bar"); QMetaMethod method; QVERIFY(!method.invoke(this)); QVERIFY(!method.invoke(this, Q_ARG(QString, str))); QVERIFY(!method.invoke(this, Q_RETURN_ARG(QString, ret), Q_ARG(QString, str))); QCOMPARE(str, QString("foo")); QCOMPARE(ret, QString("bar")); QtTestObject obj; QString t1("1"); QString t2("2"); QString t3("3"); QString t4("4"); QString t5("5"); QString t6("6"); QString t7("7"); QString t8("8"); QString t9("9"); QString t10("X"); int index = QtTestObject::staticMetaObject.indexOfMethod("sl5(QString,QString,QString,QString,QString)"); QVERIFY(index > 0); method = QtTestObject::staticMetaObject.method(index); //wrong args QVERIFY(!method.invoke(&obj, Q_ARG(QString, "1"), Q_ARG(QString, "2"), Q_ARG(QString, "3"), Q_ARG(QString, "4"))); //QVERIFY(!method.invoke(&obj, Q_ARG(QString, "1"), Q_ARG(QString, "2"), Q_ARG(QString, "3"), Q_ARG(QString, "4"), Q_ARG(QString, "5"), Q_ARG(QString, "6"))); //QVERIFY(!method.invoke(&obj, Q_ARG(QString, "1"), Q_ARG(QString, "2"), Q_ARG(QString, "3"), Q_ARG(QString, "4"), Q_ARG(int, 5))); QVERIFY(!method.invoke(&obj, Q_RETURN_ARG(QString, ret), Q_ARG(QString, "1"), Q_ARG(QString, "2"), Q_ARG(QString, "3"), Q_ARG(QString, "4"), Q_ARG(QString, "5"))); //wrong object //QVERIFY(!method.invoke(this, Q_ARG(QString, "1"), Q_ARG(QString, "2"), Q_ARG(QString, "3"), Q_ARG(QString, "4"), Q_ARG(QString, "5"))); QVERIFY(!method.invoke(0, Q_ARG(QString, "1"), Q_ARG(QString, "2"), Q_ARG(QString, "3"), Q_ARG(QString, "4"), Q_ARG(QString, "5"))); QCOMPARE(ret, QString("bar")); QCOMPARE(obj.slotResult, QString()); QVERIFY(method.invoke(&obj, Q_ARG(QString, "1"), Q_ARG(QString, "2"), Q_ARG(QString, "3"), Q_ARG(QString, "4"), Q_ARG(QString, "5"))); QCOMPARE(obj.slotResult, QString("sl5:12345")); index = QtTestObject::staticMetaObject.indexOfMethod("sl13(QList)"); QVERIFY(index > 0); QMetaMethod sl13 = QtTestObject::staticMetaObject.method(index); QList returnValue, argument; argument << QString("one") << QString("two") << QString("three"); //wrong object //QVERIFY(!sl13.invoke(this, Q_RETURN_ARG(QList, returnValue), Q_ARG(QList, argument))); QVERIFY(!sl13.invoke(0, Q_RETURN_ARG(QList, returnValue), Q_ARG(QList, argument))); QCOMPARE(returnValue, QList()); QVERIFY(sl13.invoke(&obj, Q_RETURN_ARG(QList, returnValue), Q_ARG(QList, argument))); QCOMPARE(returnValue, argument); QCOMPARE(obj.slotResult, QString("sl13")); } void tst_QMetaObject::indexOfMethod_data() { QTest::addColumn("object"); QTest::addColumn("name"); QTest::addColumn("isSignal"); QTest::newRow("indexOfMethod_data") << (QObject*)this << QByteArray("indexOfMethod_data()") << false; QTest::newRow("deleteLater") << (QObject*)this << QByteArray("deleteLater()") << false; QTest::newRow("value6changed") << (QObject*)this << QByteArray("value6Changed()") << true; QTest::newRow("value7changed") << (QObject*)this << QByteArray("value7Changed(QString)") << true; QTest::newRow("destroyed") << (QObject*)this << QByteArray("destroyed()") << true; QTest::newRow("destroyed2") << (QObject*)this << QByteArray("destroyed(QObject*)") << true; } void tst_QMetaObject::indexOfMethod() { QFETCH(QObject *, object); QFETCH(QByteArray, name); QFETCH(bool, isSignal); int idx = object->metaObject()->indexOfMethod(name); QVERIFY(idx >= 0); QCOMPARE(object->metaObject()->method(idx).methodSignature(), name); QCOMPARE(object->metaObject()->indexOfSlot(name), isSignal ? -1 : idx); QCOMPARE(object->metaObject()->indexOfSignal(name), !isSignal ? -1 : idx); } void tst_QMetaObject::indexOfMethodPMF() { #define INDEXOFMETHODPMF_HELPER(ObjectType, Name, Arguments) { \ int idx = -1; \ void (ObjectType::*signal)Arguments = &ObjectType::Name; \ void *signal_p = &signal; \ void *args[] = { &idx, signal_p, 0}; \ ObjectType::qt_static_metacall(0, QMetaObject::IndexOfMethod, 0, args); \ QCOMPARE(ObjectType::staticMetaObject.indexOfMethod(QMetaObject::normalizedSignature(#Name #Arguments)), \ ObjectType::staticMetaObject.methodOffset() + idx); \ } INDEXOFMETHODPMF_HELPER(tst_QMetaObject, value7Changed, (const QString&)) INDEXOFMETHODPMF_HELPER(QtTestObject, sig0, ()) INDEXOFMETHODPMF_HELPER(QtTestObject, sig10, (QString,QString,QString,QString,QString,QString,QString,QString,QString,QString)) INDEXOFMETHODPMF_HELPER(QtTestCustomObject, sig_custom, (const CustomString &)) } #ifdef QT_BUILD_INTERNAL namespace SignalTestHelper { // These functions use the public QMetaObject/QMetaMethod API to implement // the functionality of the internal API, and are used to check the results. static int signalCount(const QMetaObject *mo) { int n = 0; for (int i = 0; i < mo->methodCount(); ++i) { QMetaMethod mm = mo->method(i); if (mm.methodType() == QMetaMethod::Signal) ++n; } return n; } static int signalOffset(const QMetaObject *mo) { return mo->superClass() ? signalCount(mo->superClass()) : 0; } static QMetaMethod signal(const QMetaObject *mo, int index) { int k = 0; for (int i = 0; i < mo->methodCount(); ++i) { QMetaMethod mm = mo->method(i); if (mm.methodType() != QMetaMethod::Signal) continue; if (k == index) return mm; ++k; } return QMetaMethod(); } static int signalIndex(const QMetaMethod &mm) { int k = mm.methodIndex(); const QMetaObject *mo = mm.enclosingMetaObject(); for (int i = 0; i < mm.methodIndex(); ++i) { if (mo->method(i).methodType() != QMetaMethod::Signal) --k; } return k; } } // namespace SignalTestHelper void tst_QMetaObject::signalOffset_data() { QTest::addColumn("metaObject"); QTest::newRow("QObject") << &QObject::staticMetaObject; QTest::newRow("tst_QMetaObject") << &tst_QMetaObject::staticMetaObject; QTest::newRow("QtTestObject") << &QtTestObject::staticMetaObject; } void tst_QMetaObject::signalOffset() { QFETCH(const QMetaObject *, metaObject); QCOMPARE(QMetaObjectPrivate::signalOffset(metaObject), SignalTestHelper::signalOffset(metaObject)); } void tst_QMetaObject::signalCount_data() { signalOffset_data(); } void tst_QMetaObject::signalCount() { QFETCH(const QMetaObject *, metaObject); QCOMPARE(QMetaObjectPrivate::absoluteSignalCount(metaObject), SignalTestHelper::signalCount(metaObject)); } void tst_QMetaObject::signal_data() { QTest::addColumn("metaObject"); QTest::addColumn("index"); struct SignalTestDataHelper { static void addSignals(const QMetaObject *mo) { int count = SignalTestHelper::signalCount(mo); for (int i = 0; i < count; ++i) { QMetaMethod mm = SignalTestHelper::signal(mo, i); QByteArray tag(mo->className()); tag.append("::"); tag.append(mm.methodSignature()); QTest::newRow(tag.constData()) << mo << i; } } }; SignalTestDataHelper::addSignals(&QObject::staticMetaObject); SignalTestDataHelper::addSignals(&tst_QMetaObject::staticMetaObject); SignalTestDataHelper::addSignals(&QtTestObject::staticMetaObject); } void tst_QMetaObject::signal() { QFETCH(const QMetaObject *, metaObject); QFETCH(int, index); QCOMPARE(QMetaObjectPrivate::signal(metaObject, index), SignalTestHelper::signal(metaObject, index)); } void tst_QMetaObject::signalIndex_data() { signal_data(); } void tst_QMetaObject::signalIndex() { QFETCH(const QMetaObject *, metaObject); QFETCH(int, index); QMetaMethod mm = SignalTestHelper::signal(metaObject, index); QCOMPARE(QMetaObjectPrivate::signalIndex(mm), SignalTestHelper::signalIndex(mm)); } #endif void tst_QMetaObject::enumDebugStream_data() { QTest::addColumn("verbosity"); QTest::addColumn("normalEnumMsg"); QTest::addColumn("scopedEnumMsg"); QTest::addColumn("globalEnumMsg"); QTest::addColumn("normalFlagMsg"); QTest::addColumn("normalFlagsMsg"); QTest::addColumn("scopedFlagMsg"); QTest::addColumn("scopedFlagsMsg"); QTest::addColumn("flagAsEnumMsg"); QTest::newRow("verbosity=0") << 0 << "hello MyEnum2 world" << "hello MyScopedEnum::Enum3 scoped world" << "WindowTitleHint Window Desktop WindowSystemMenuHint" << "hello MyFlag1 world" << "MyFlag1 MyFlag2|MyFlag3" << "MyScopedFlag(MyFlag2)" << "MyScopedFlag(MyFlag2|MyFlag3)" << "MyFlag1"; QTest::newRow("verbosity=1") << 1 << "hello MyEnum::MyEnum2 world" << "hello MyScopedEnum::Enum3 scoped world" << "WindowType::WindowTitleHint WindowType::Window WindowType::Desktop WindowType::WindowSystemMenuHint" << "hello MyFlag(MyFlag1) world" << "MyFlag(MyFlag1) MyFlag(MyFlag2|MyFlag3)" << "MyScopedFlag(MyFlag2)" << "MyScopedFlag(MyFlag2|MyFlag3)" << "MyFlag::MyFlag1"; QTest::newRow("verbosity=2") << 2 << "hello MyNamespace::MyClass::MyEnum2 world" << "hello MyNamespace::MyClass::MyScopedEnum::Enum3 scoped world" << "Qt::WindowTitleHint Qt::Window Qt::Desktop Qt::WindowSystemMenuHint" << "hello QFlags(MyFlag1) world" << "QFlags(MyFlag1) QFlags(MyFlag2|MyFlag3)" << "QFlags(MyFlag2)" << "QFlags(MyFlag2|MyFlag3)" << "MyNamespace::MyClass::MyFlag1"; QTest::newRow("verbosity=3") << 3 << "hello MyNamespace::MyClass::MyEnum::MyEnum2 world" << "hello MyNamespace::MyClass::MyScopedEnum::Enum3 scoped world" << "Qt::WindowType::WindowTitleHint Qt::WindowType::Window Qt::WindowType::Desktop Qt::WindowType::WindowSystemMenuHint" << "hello QFlags(MyFlag1) world" << "QFlags(MyFlag1) QFlags(MyFlag2|MyFlag3)" << "QFlags(MyFlag2)" << "QFlags(MyFlag2|MyFlag3)" << "MyNamespace::MyClass::MyFlag::MyFlag1"; } void tst_QMetaObject::enumDebugStream() { #if QT_VERSION < QT_VERSION_CHECK(5, 12, 0) QTest::ignoreMessage(QtDebugMsg, "hello MyNamespace::MyClass::MyEnum(MyEnum2) world "); MyNamespace::MyClass::MyEnum e = MyNamespace::MyClass::MyEnum2; qDebug() << "hello" << e << "world"; QTest::ignoreMessage(QtDebugMsg, "Qt::WindowType(WindowTitleHint) Qt::WindowType(Window) Qt::WindowType(Desktop) Qt::WindowType(WindowSystemMenuHint)"); qDebug() << Qt::WindowTitleHint << Qt::Window <(MyFlag1) world"); MyNamespace::MyClass::MyFlags f1 = MyNamespace::MyClass::MyFlag1; qDebug() << "hello" << f1 << "world"; MyNamespace::MyClass::MyFlags f2 = MyNamespace::MyClass::MyFlag2 | MyNamespace::MyClass::MyFlag3; QTest::ignoreMessage(QtDebugMsg, "QFlags(MyFlag1) QFlags(MyFlag2|MyFlag3)"); qDebug() << f1 << f2; #elif QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) QFETCH(int, verbosity); QFETCH(QString, normalEnumMsg); QFETCH(QString, scopedEnumMsg); QFETCH(QString, globalEnumMsg); QFETCH(QString, normalFlagMsg); QFETCH(QString, normalFlagsMsg); QFETCH(QString, scopedFlagMsg); QFETCH(QString, scopedFlagsMsg); QFETCH(QString, flagAsEnumMsg); // Enums QTest::ignoreMessage(QtDebugMsg, qPrintable(normalEnumMsg)); qDebug().verbosity(verbosity) << "hello" << MyNamespace::MyClass::MyEnum2 << "world"; QTest::ignoreMessage(QtDebugMsg, qPrintable(scopedEnumMsg)); qDebug().verbosity(verbosity) << "hello" << MyNamespace::MyClass::MyScopedEnum::Enum3 << "scoped world"; QTest::ignoreMessage(QtDebugMsg, qPrintable(globalEnumMsg)); qDebug().verbosity(verbosity) << Qt::WindowTitleHint << Qt::Window << Qt::Desktop << Qt::WindowSystemMenuHint; // Flags QTest::ignoreMessage(QtDebugMsg, qPrintable(normalFlagMsg)); MyNamespace::MyClass::MyFlags f1 = MyNamespace::MyClass::MyFlag1; qDebug().verbosity(verbosity) << "hello" << f1 << "world"; MyNamespace::MyClass::MyFlags f2 = MyNamespace::MyClass::MyFlag2 | MyNamespace::MyClass::MyFlag3; QTest::ignoreMessage(QtDebugMsg, qPrintable(normalFlagsMsg)); qDebug().verbosity(verbosity) << f1 << f2; QTest::ignoreMessage(QtDebugMsg, qPrintable(scopedFlagMsg)); MyNamespace::MyClass::MyScopedFlags f3 = MyNamespace::MyClass::MyScopedFlag::MyFlag2; qDebug().verbosity(verbosity) << f3; QTest::ignoreMessage(QtDebugMsg, qPrintable(scopedFlagsMsg)); f3 |= MyNamespace::MyClass::MyScopedFlag::MyFlag3; qDebug().verbosity(verbosity) << f3; // Single flag recognized as enum: QTest::ignoreMessage(QtDebugMsg, qPrintable(flagAsEnumMsg)); MyNamespace::MyClass::MyFlag f4 = MyNamespace::MyClass::MyFlag1; qDebug().verbosity(verbosity) << f4; #endif } void tst_QMetaObject::inherits_data() { QTest::addColumn("derivedMetaObject"); QTest::addColumn("baseMetaObject"); QTest::addColumn("inheritsResult"); QTest::newRow("MyClass inherits QObject") << &MyNamespace::MyClass::staticMetaObject << &QObject::staticMetaObject << true; QTest::newRow("QObject inherits MyClass") << &QObject::staticMetaObject << &MyNamespace::MyClass::staticMetaObject << false; QTest::newRow("MyClass inherits MyClass") << &MyNamespace::MyClass::staticMetaObject << &MyNamespace::MyClass::staticMetaObject << true; QTest::newRow("MyClassSubclass inherits QObject") << &MyNamespace::MyClassSubclass::staticMetaObject << &QObject::staticMetaObject << true; QTest::newRow("MyClassSubclass2 inherits QObject") << &MyNamespace::MyClassSubclass2::staticMetaObject << &QObject::staticMetaObject << true; QTest::newRow("MyClassSubclass2 inherits MyClass2") << &MyNamespace::MyClassSubclass2::staticMetaObject << &MyNamespace::MyClass2Subclass::staticMetaObject << false; } void tst_QMetaObject::inherits() { #if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) QFETCH(const QMetaObject *, derivedMetaObject); QFETCH(const QMetaObject *, baseMetaObject); QFETCH(bool, inheritsResult); QCOMPARE(derivedMetaObject->inherits(baseMetaObject), inheritsResult); #endif } void tst_QMetaObject::notifySignalsInParentClass() { #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) MyNamespace::ClassWithSetterGetterSignalsAddsProperties obj; QCOMPARE(obj.metaObject()->property(obj.metaObject()->indexOfProperty("value1")).notifySignal().name(), QByteArray("value1Changed")); QCOMPARE(obj.metaObject()->property(obj.metaObject()->indexOfProperty("value2")).notifySignal().name(), QByteArray("value2Changed")); MyNamespace::ClassWithChangedSignalNewValue obj2; QCOMPARE(obj2.metaObject()->property(obj2.metaObject()->indexOfProperty("value2")).notifySignal().name(), QByteArray("propertiesChanged")); #if 0 // With verdigris, this is a compilation error when the NOTIFY signal is not a signal QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::notifySignal: cannot find the NOTIFY signal thisIsNotASignal in class MyNamespace::ClassWithChangedSignalNewValue for property 'value3'"); obj2.metaObject()->property(obj2.metaObject()->indexOfProperty("value3")).notifySignal(); #endif #endif } QTEST_MAIN(tst_QMetaObject) verdigris-1.3/tests/qt/qmetaobject/tst_qmetaobject6.cpp000066400000000000000000002453621427643277200234530ustar00rootroot00000000000000/**************************************************************************** ** ** 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 #if QT_VERSION >= QT_VERSION_CHECK(6,1,0) #include #include #endif #include #include #include #ifdef QT_BUILD_INTERNAL #undef QT_BUILD_INTERNAL // Verdigris don't test the internals #endif #include Q_DECLARE_METATYPE(const QMetaObject *) W_REGISTER_ARGTYPE(QList) struct MyStruct { int i; }; class MyGadget { W_GADGET(MyGadget) public: MyGadget() {} W_CONSTRUCTOR() }; W_GADGET_IMPL(MyGadget) namespace MyNamespace { // Used in tst_QMetaObject::checkScope class MyClass : public QObject { W_OBJECT(MyClass) public: enum MyEnum { MyEnum1, MyEnum2, MyEnum3 }; enum class MyScopedEnum { Enum1, Enum2, Enum3 }; enum MyAnotherEnum { MyAnotherEnum1 = 1, MyAnotherEnum2 = 2, MyAnotherEnum3 = -1 }; enum MyFlag { MyFlag1 = 0x01, MyFlag2 = 0x02, MyFlag3 = 0x04 }; enum class MyScopedFlag { MyFlag1 = 0x10, MyFlag2 = 0x20, MyFlag3 = 0x40 }; W_DECLARE_FLAGS(MyFlags, MyFlag) W_DECLARE_FLAGS(MyScopedFlags, MyScopedFlag) MyEnum myEnum() const { return m_enum; } void setMyEnum(MyEnum val) { m_enum = val; } MyFlags myFlags() const { return m_flags; } void setMyFlags(MyFlags val) { m_flags = val; } MyClass(QObject *parent = nullptr) : QObject(parent), m_enum(MyEnum1), m_flags(MyFlag1|MyFlag2) { } private: W_ENUM(MyEnum, MyEnum1, MyEnum2, MyEnum3) W_ENUM(MyScopedEnum, MyScopedEnum::Enum1, MyScopedEnum::Enum2, MyScopedEnum::Enum3) W_ENUM(MyAnotherEnum,MyAnotherEnum1,MyAnotherEnum2,MyAnotherEnum3) W_FLAG(MyFlags,MyFlag1,MyFlag2,MyFlag3) W_FLAG(MyScopedFlags, MyScopedFlag::MyFlag1, MyScopedFlag::MyFlag2, MyScopedFlag::MyFlag3) MyEnum m_enum; MyFlags m_flags; W_PROPERTY(MyEnum, myEnum READ myEnum WRITE setMyEnum) W_PROPERTY(MyFlags, myFlags READ myFlags WRITE setMyFlags) }; Q_DECLARE_OPERATORS_FOR_FLAGS(MyClass::MyFlags) // test the old Q_ENUMS macro class MyClass2 : public QObject { W_OBJECT(MyClass2) public: enum MyEnum { MyEnum1, MyEnum2, MyEnum3 }; enum MyAnotherEnum { MyAnotherEnum1 = 1, MyAnotherEnum2 = 2, MyAnotherEnum3 = -1 }; enum MyFlag { MyFlag1 = 0x01, MyFlag2 = 0x02, MyFlag3 = 0x04 }; Q_DECLARE_FLAGS(MyFlags, MyFlag) MyEnum myEnum() const { return m_enum; } void setMyEnum(MyEnum val) { m_enum = val; } MyFlags myFlags() const { return m_flags; } void setMyFlags(MyFlags val) { m_flags = val; } MyClass2(QObject *parent = nullptr) : QObject(parent), m_enum(MyEnum1), m_flags(MyFlag1|MyFlag2) { } private: W_ENUM(MyEnum, MyEnum1, MyEnum2, MyEnum3) W_ENUM(MyAnotherEnum,MyAnotherEnum1,MyAnotherEnum2,MyAnotherEnum3) W_FLAG(MyFlags,MyFlag1,MyFlag2,MyFlag3) MyEnum m_enum; MyFlags m_flags; W_PROPERTY(MyEnum, myEnum READ myEnum WRITE setMyEnum) W_PROPERTY(MyFlags, myFlags READ myFlags WRITE setMyFlags) }; // Test inherits class MyClassSubclass : public MyClass { W_OBJECT(MyClassSubclass) }; class MyClassSubclass2 : public MyClass2 { W_OBJECT(MyClassSubclass2) }; class MyClass2Subclass : public MyClass { W_OBJECT(MyClass2Subclass) }; #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) class ClassWithSetterGetterSignals : public QObject { W_OBJECT(ClassWithSetterGetterSignals) public: int value1() const { return m_value1; } void setValue1(int v) { if (v != m_value1) { m_value1 = v; Q_EMIT value1Changed(); } } int value2() const { return m_value2; } void setValue2(int v) { if (v != m_value2) { m_value2 = v; Q_EMIT value2Changed(); } } Q_SIGNALS: void value1Changed() W_SIGNAL(value1Changed) void value2Changed() W_SIGNAL(value2Changed) private: int m_value1 = 0; int m_value2 = 0; }; class ClassWithSetterGetterSignalsAddsProperties : public ClassWithSetterGetterSignals { W_OBJECT(ClassWithSetterGetterSignalsAddsProperties) W_PROPERTY(int, value1 READ value1 WRITE setValue1 NOTIFY value1Changed) W_PROPERTY(int, value2 READ value2 WRITE setValue2 NOTIFY value2Changed) }; class ClassWithChangedSignal : public QObject { W_OBJECT(ClassWithChangedSignal) public: int value1() const { return m_value1; } void setValue1(int v) { if (v != m_value1) { m_value1 = v; Q_EMIT propertiesChanged(); } } void thisIsNotASignal() { } Q_SIGNALS: void propertiesChanged() W_SIGNAL(propertiesChanged) private: int m_value1 = 0; }; class ClassWithChangedSignalNewValue : public ClassWithChangedSignal { W_OBJECT(ClassWithChangedSignalNewValue) private: int m_value2 = 0; W_PROPERTY(int, value2 MEMBER m_value2 NOTIFY propertiesChanged) #if 0 // With verdigris, this is a compilation error when the NOTIFY signal is not a signal int m_value3 = 0; W_PROPERTY(int, value3 MEMBER m_value3 NOTIFY thisIsNotASignal) #endif }; #endif } W_OBJECT_IMPL(MyNamespace::MyClass) W_OBJECT_IMPL(MyNamespace::MyClass2) W_OBJECT_IMPL(MyNamespace::MyClassSubclass) W_OBJECT_IMPL(MyNamespace::MyClassSubclass2) W_OBJECT_IMPL(MyNamespace::MyClass2Subclass) #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) W_OBJECT_IMPL(MyNamespace::ClassWithSetterGetterSignals) W_OBJECT_IMPL(MyNamespace::ClassWithSetterGetterSignalsAddsProperties) W_OBJECT_IMPL(MyNamespace::ClassWithChangedSignal) W_OBJECT_IMPL(MyNamespace::ClassWithChangedSignalNewValue) #endif class tst_QMetaObject : public QObject { W_OBJECT(tst_QMetaObject) public: enum EnumType { EnumType1 }; W_ENUM(EnumType,EnumType1); void setValue(EnumType) {} EnumType getValue() const { return EnumType1; } void set_value(EnumType) {} EnumType get_value() const { return EnumType1; } void setVal3(MyStruct) {} MyStruct val3() const { MyStruct s = {42}; return s; } void setVal4(const QList &list) { value4 = list; } QList val4() const { return value4; } void setVal5(const QVariantList &list) { value5 = list; } QVariantList val5() const { return value5; } int value6() const { return 1; } void setVal7(MyStruct) {} MyStruct value7() const { MyStruct s = {42}; return s; } int value8() const { return 1; } int value9() const { return 1; } int value10() const { return 1; } QList value4; QVariantList value5; private slots: #define DECLARE_TEST(NAME) void NAME(); W_SLOT(NAME) DECLARE_TEST(connectSlotsByName) DECLARE_TEST(invokeMetaMember) DECLARE_TEST(invokePointer) DECLARE_TEST(invokeQueuedMetaMember) DECLARE_TEST(invokeQueuedPointer) DECLARE_TEST(invokeBlockingQueuedMetaMember) DECLARE_TEST(invokeBlockingQueuedPointer) DECLARE_TEST(invokeCustomTypes) DECLARE_TEST(invokeMetaConstructor) DECLARE_TEST(invokeTypedefTypes) DECLARE_TEST(invokeException) DECLARE_TEST(invokeQueuedAutoRegister) DECLARE_TEST(qtMetaObjectInheritance) DECLARE_TEST(normalizedSignature_data) DECLARE_TEST(normalizedSignature) DECLARE_TEST(normalizedType_data) DECLARE_TEST(normalizedType) DECLARE_TEST(customPropertyType) DECLARE_TEST(checkScope_data) DECLARE_TEST(checkScope) DECLARE_TEST(propertyNotify) DECLARE_TEST(propertyConstant) DECLARE_TEST(propertyFinal) #if QT_VERSION >= QT_VERSION_CHECK(6,2,0) DECLARE_TEST(metaType) #endif DECLARE_TEST(stdSet) DECLARE_TEST(classInfo) DECLARE_TEST(metaMethod) DECLARE_TEST(indexOfMethod_data) DECLARE_TEST(indexOfMethod) #if QT_VERSION >= QT_VERSION_CHECK(6,1,0) DECLARE_TEST(firstMethod_data) DECLARE_TEST(firstMethod) #endif DECLARE_TEST(indexOfMethodPMF) #ifdef QT_BUILD_INTERNAL DECLARE_TEST(signalOffset_data) DECLARE_TEST(signalOffset) DECLARE_TEST(signalCount_data) DECLARE_TEST(signalCount) DECLARE_TEST(signal_data) DECLARE_TEST(signal) DECLARE_TEST(signalIndex_data) DECLARE_TEST(signalIndex) #endif DECLARE_TEST(enumDebugStream_data) DECLARE_TEST(enumDebugStream) DECLARE_TEST(inherits_data) DECLARE_TEST(inherits) DECLARE_TEST(notifySignalsInParentClass) #undef DECLARE_TEST signals: void value6Changed() W_SIGNAL(value6Changed) void value7Changed(const QString &_) W_SIGNAL(value7Changed,_) W_PROPERTY(EnumType, value WRITE setValue READ getValue) W_PROPERTY(EnumType, value2 WRITE set_value READ get_value) W_PROPERTY(MyStruct, value3 WRITE setVal3 READ val3) W_PROPERTY(QList, value4 WRITE setVal4 READ val4) W_PROPERTY(QVariantList, value5 WRITE setVal5 READ val5) W_PROPERTY(int, value6 READ value6 NOTIFY value6Changed) W_PROPERTY(MyStruct, value7 READ value7 WRITE setVal7 NOTIFY value7Changed) W_PROPERTY(int, value8 READ value8) W_PROPERTY(int, value9 READ value9 CONSTANT) W_PROPERTY(int, value10 READ value10 FINAL) }; W_OBJECT_IMPL(tst_QMetaObject) void tst_QMetaObject::stdSet() { QSKIP("Not supported by W_PROPERTY"); const QMetaObject *mo = metaObject(); QMetaProperty prop = mo->property(mo->indexOfProperty("value")); QVERIFY(prop.isValid()); QVERIFY(prop.hasStdCppSet()); prop = mo->property(mo->indexOfProperty("value2")); QVERIFY(prop.isValid()); QVERIFY(!prop.hasStdCppSet()); } class CTestObject: public QObject { W_OBJECT(CTestObject) public: CTestObject(): QObject(), invokeCount1(0), invokeCount2(0) { } void fire(const QString &name) { child = new QObject(this); child->setObjectName(name); QMetaObject::connectSlotsByName(this); delete child; child = 0; } int invokeCount1; int invokeCount2; QObject *child; public slots: void on_child1_destroyed(QObject *obj = 0) { ++invokeCount1; if (!obj || obj != child) qWarning() << "on_child1_destroyed invoked with wrong child object"; } W_SLOT(on_child1_destroyed) void on_child2_destroyed() { ++invokeCount2; } W_SLOT(on_child2_destroyed) }; W_OBJECT_IMPL(CTestObject) class CTestObjectOverloads: public QObject { W_OBJECT(CTestObjectOverloads) public: CTestObjectOverloads(): invokeCount1(0), invokeCount2(0) {} int invokeCount1; int invokeCount2; QObject *child; void fire(const QString &name) { child = new QObject(this); child->setObjectName(name); QMetaObject::connectSlotsByName(this); delete child; child = 0; } private slots: void on_child1_destroyed(QObject *obj) { ++invokeCount1; if (!obj || obj != child) qWarning() << "on_child1_destroyed invoked with wrong child object"; } W_SLOT(on_child1_destroyed,(QObject*)) void on_child1_destroyed() { ++invokeCount2; } W_SLOT(on_child1_destroyed,()) }; W_OBJECT_IMPL(CTestObjectOverloads) #define FUNCTION(x) "QMetaObject::" x ": " void tst_QMetaObject::connectSlotsByName() { CTestObject obj; QCOMPARE(obj.invokeCount1, 0); QCOMPARE(obj.invokeCount2, 0); QTest::ignoreMessage(QtWarningMsg, FUNCTION("connectSlotsByName") "No matching signal for on_child1_destroyed(QObject*)"); QTest::ignoreMessage(QtWarningMsg, FUNCTION("connectSlotsByName") "No matching signal for on_child2_destroyed()"); obj.fire("bubu"); QCOMPARE(obj.invokeCount1, 0); QCOMPARE(obj.invokeCount2, 0); QTest::ignoreMessage(QtWarningMsg, FUNCTION("connectSlotsByName") "No matching signal for on_child2_destroyed()"); obj.fire("child1"); QCOMPARE(obj.invokeCount1, 1); QCOMPARE(obj.invokeCount2, 0); QTest::ignoreMessage(QtWarningMsg, FUNCTION("connectSlotsByName") "No matching signal for on_child1_destroyed(QObject*)"); obj.fire("child2"); QCOMPARE(obj.invokeCount1, 1); QCOMPARE(obj.invokeCount2, 1); QTest::ignoreMessage(QtWarningMsg, FUNCTION("connectSlotsByName") "No matching signal for on_child2_destroyed()"); obj.fire("child1"); QCOMPARE(obj.invokeCount1, 2); QCOMPARE(obj.invokeCount2, 1); // now test with real overloads CTestObjectOverloads obj2; obj2.fire("child1"); QCOMPARE(obj2.invokeCount1, 1); QCOMPARE(obj2.invokeCount2, 1); } struct MyUnregisteredType { }; static int countedStructObjectsCount = 0; struct CountedStruct { CountedStruct() { ++countedStructObjectsCount; } CountedStruct(const CountedStruct &) { ++countedStructObjectsCount; } CountedStruct &operator=(const CountedStruct &) { return *this; } ~CountedStruct() { --countedStructObjectsCount; } }; #ifndef QT_NO_EXCEPTIONS class ObjectException : public std::exception { }; #endif W_REGISTER_ARGTYPE(QString&) W_REGISTER_ARGTYPE(QThread*) W_REGISTER_ARGTYPE(MyUnregisteredType) W_REGISTER_ARGTYPE(CountedStruct) class QtTestObject: public QObject { friend class tst_QMetaObject; W_OBJECT(QtTestObject) public: QtTestObject(); QtTestObject(const QString &s) : slotResult(s) {} QtTestObject(QObject *parent); W_CONSTRUCTOR(QObject*) public slots: void sl0(); W_SLOT(sl0) QString sl1(QString s1); W_SLOT(sl1) void sl2(QString s1, QString s2); W_SLOT(sl2) void sl3(QString s1, QString s2, QString s3); W_SLOT(sl3) void sl4(QString s1, QString s2, QString s3, const QString s4); W_SLOT(sl4) void sl5(QString s1, QString s2, QString s3, QString s4, const QString &s5); W_SLOT(sl5) void sl6(QString s1, QString s2, QString s3, QString s4, const QString s5, QString s6); W_SLOT(sl6) void sl7(QString s1, QString s2, QString s3, QString s4, QString s5, QString s6, QString s7); W_SLOT(sl7) void sl8(QString s1, QString s2, QString s3, QString s4, QString s5, QString s6, QString s7, QString s8); W_SLOT(sl8) void sl9(QString s1, QString s2, QString s3, QString s4, QString s5, QString s6, QString s7, QString s8, QString s9); W_SLOT(sl9) void sl10(QString s1, QString s2, QString s3, QString s4, QString s5, QString s6, QString s7, QString s8, QString s9, QString s10); W_SLOT(sl10) QObject *sl11(); W_SLOT(sl11) const char *sl12(); W_SLOT(sl12) QList sl13(QList l1); W_SLOT(sl13) qint64 sl14(); W_SLOT(sl14) void testSender(); W_SLOT(testSender) void testReference(QString &str); W_SLOT(testReference) void testLongLong(qint64 ll1, quint64 ll2); W_SLOT(testLongLong) void moveToThread(QThread *t) { QObject::moveToThread(t); } W_SLOT(moveToThread) void slotWithUnregisteredParameterType(MyUnregisteredType); W_SLOT(slotWithUnregisteredParameterType) void slotWithOneUnregisteredParameterType(QString a1, MyUnregisteredType a2); W_SLOT(slotWithOneUnregisteredParameterType) CountedStruct throwingSlot(const CountedStruct &, CountedStruct s2) { #ifndef QT_NO_EXCEPTIONS throw ObjectException(); #endif return s2; } W_SLOT(throwingSlot) void slotWithRegistrableArgument(QtTestObject *o1, QPointer o2, QSharedPointer o3, QWeakPointer o4, QList o5, QList o6) { slotResult = QLatin1String("slotWithRegistrableArgument:") + o1->slotResult + o2->slotResult + o3->slotResult + o4.toStrongRef()->slotResult + QString::number(o5.size()) + QString::number(o6.size()); } W_SLOT(slotWithRegistrableArgument, (QtTestObject*, QPointer, QSharedPointer, QWeakPointer, QList,QList)) public: static void staticFunction0(); static qint64 staticFunction1(); signals: void sig0() W_SIGNAL(sig0) QString sig1(QString s1) W_SIGNAL(sig1,s1) void sig10(QString s1, QString s2, QString s3, QString s4, QString s5, QString s6, QString s7, QString s8, QString s9, QString s10) W_SIGNAL(sig10,s1,s2,s3,s4,s5,s6,s7,s8,s9,s10) protected: QtTestObject(QVariant) {} private: QtTestObject(QVariant, QVariant) {} public: QString slotResult; static QString staticResult; }; W_OBJECT_IMPL(QtTestObject) QString QtTestObject::staticResult; QtTestObject::QtTestObject() { connect(this, SIGNAL(sig0()), this, SLOT(sl0())); connect(this, SIGNAL(sig1(QString)), this, SLOT(sl1(QString))); } QtTestObject::QtTestObject(QObject *parent) : QObject(parent) { } void QtTestObject::sl0() { slotResult = "sl0"; } QString QtTestObject::sl1(QString s1) { slotResult = "sl1:" + s1; return "yessir"; } void QtTestObject::sl2(QString s1, QString s2) { slotResult = "sl2:" + s1 + s2; } void QtTestObject::sl3(QString s1, QString s2, QString s3) { slotResult = "sl3:" + s1 + s2 + s3; } void QtTestObject::sl4(QString s1, QString s2, QString s3, const QString s4) { slotResult = "sl4:" + s1 + s2 + s3 + s4; } void QtTestObject::sl5(QString s1, QString s2, QString s3, QString s4, const QString &s5) { slotResult = "sl5:" + s1 + s2 + s3 + s4 + s5; } void QtTestObject::sl6(QString s1, QString s2, QString s3, QString s4, const QString s5, QString s6) { slotResult = "sl6:" + s1 + s2 + s3 + s4 + s5 + s6; } void QtTestObject::sl7(QString s1, QString s2, QString s3, QString s4, QString s5, QString s6, QString s7) { slotResult = "sl7:" + s1 + s2 + s3 + s4 + s5 + s6 + s7; } void QtTestObject::sl8(QString s1, QString s2, QString s3, QString s4, QString s5, QString s6, QString s7, QString s8) { slotResult = "sl8:" + s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8; } void QtTestObject::sl9(QString s1, QString s2, QString s3, QString s4, QString s5, QString s6, QString s7, QString s8, QString s9) { slotResult = "sl9:" + s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9; } void QtTestObject::sl10(QString s1, QString s2, QString s3, QString s4, QString s5, QString s6, QString s7, QString s8, QString s9, QString s10) { slotResult = "sl10:" + s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10; } QObject *QtTestObject::sl11() { slotResult = "sl11"; return this; } const char *QtTestObject::sl12() { slotResult = "sl12"; return "foo"; } QList QtTestObject::sl13(QList l1) { slotResult = "sl13"; return l1; } qint64 QtTestObject::sl14() { slotResult = "sl14"; return Q_INT64_C(123456789)*123456789; } void QtTestObject::testReference(QString &str) { slotResult = "testReference:" + str; str = "gotcha"; } void QtTestObject::testLongLong(qint64 ll1, quint64 ll2) { slotResult = "testLongLong:" + QString::number(ll1) + "," + QString::number(ll2); } void QtTestObject::testSender() { slotResult = QString::asprintf("%p", sender()); } void QtTestObject::slotWithUnregisteredParameterType(MyUnregisteredType) { slotResult = "slotWithUnregisteredReturnType"; } void QtTestObject::slotWithOneUnregisteredParameterType(QString a1, MyUnregisteredType) { slotResult = "slotWithUnregisteredReturnType-" + a1; } void QtTestObject::staticFunction0() { staticResult = "staticFunction0"; } qint64 QtTestObject::staticFunction1() { staticResult = "staticFunction1"; return Q_INT64_C(123456789)*123456789; } void tst_QMetaObject::invokeMetaMember() { QtTestObject obj; QString t1("1"); QString t2("2"); QString t3("3"); QString t4("4"); QString t5("5"); QString t6("6"); QString t7("7"); QString t8("8"); QString t9("9"); QString t10("X"); // Test nullptr char *nullCharArray = nullptr; const char *nullConstCharArray = nullptr; QVERIFY(!QMetaObject::invokeMethod(nullptr, nullCharArray)); QVERIFY(!QMetaObject::invokeMethod(nullptr, nullConstCharArray)); QVERIFY(!QMetaObject::invokeMethod(nullptr, "sl0")); QVERIFY(!QMetaObject::invokeMethod(&obj, nullCharArray)); QVERIFY(!QMetaObject::invokeMethod(&obj, nullConstCharArray)); QVERIFY(!QMetaObject::invokeMethod(&obj, nullCharArray, Qt::AutoConnection)); QVERIFY(!QMetaObject::invokeMethod(&obj, nullConstCharArray, Qt::AutoConnection)); QVERIFY(!QMetaObject::invokeMethod(&obj, nullCharArray, Qt::AutoConnection, QGenericReturnArgument())); QVERIFY(!QMetaObject::invokeMethod(&obj, nullConstCharArray, Qt::AutoConnection, QGenericReturnArgument())); QVERIFY(QMetaObject::invokeMethod(&obj, "sl0")); QCOMPARE(obj.slotResult, QString("sl0")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", Q_ARG(QString, t1))); QCOMPARE(obj.slotResult, QString("sl1:1")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl2", Q_ARG(const QString, t1), Q_ARG(QString, t2))); QCOMPARE(obj.slotResult, QString("sl2:12")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl3", Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3))); QCOMPARE(obj.slotResult, QString("sl3:123")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl4", Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), Q_ARG(QString, t4))); QCOMPARE(obj.slotResult, QString("sl4:1234")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl5", Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, "5"))); QCOMPARE(obj.slotResult, QString("sl5:12345")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl6", Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, t5), Q_ARG(QString, t6))); QCOMPARE(obj.slotResult, QString("sl6:123456")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl7", Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, t5), Q_ARG(QString, t6), Q_ARG(QString, t7))); QCOMPARE(obj.slotResult, QString("sl7:1234567")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl8", Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, t5), Q_ARG(QString, t6), Q_ARG(QString, t7), Q_ARG(QString, t8))); QCOMPARE(obj.slotResult, QString("sl8:12345678")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl9", Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, t5), Q_ARG(QString, t6), Q_ARG(QString, t7), Q_ARG(QString, t8), Q_ARG(QString, t9))); QCOMPARE(obj.slotResult, QString("sl9:123456789")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl11")); QCOMPARE(obj.slotResult, QString("sl11")); QVERIFY(QMetaObject::invokeMethod(&obj, "testSender")); QCOMPARE(obj.slotResult, QString("0x0")); QString refStr("whatever"); QVERIFY(QMetaObject::invokeMethod(&obj, "testReference", QGenericArgument("QString&", &refStr))); QCOMPARE(obj.slotResult, QString("testReference:whatever")); QCOMPARE(refStr, QString("gotcha")); qint64 ll1 = -1; quint64 ll2 = 0; QVERIFY(QMetaObject::invokeMethod(&obj, "testLongLong", Q_ARG(qint64, ll1), Q_ARG(quint64, ll2))); QCOMPARE(obj.slotResult, QString("testLongLong:-1,0")); QString exp; QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", Q_RETURN_ARG(QString, exp), Q_ARG(QString, "bubu"))); QCOMPARE(exp, QString("yessir")); QCOMPARE(obj.slotResult, QString("sl1:bubu")); QObject *ptr = nullptr; QVERIFY(QMetaObject::invokeMethod(&obj, "sl11", Q_RETURN_ARG(QObject*,ptr))); QCOMPARE(ptr, (QObject *)&obj); QCOMPARE(obj.slotResult, QString("sl11")); // try again with a space: ptr = nullptr; QVERIFY(QMetaObject::invokeMethod(&obj, "sl11", Q_RETURN_ARG(QObject * , ptr))); QCOMPARE(ptr, (QObject *)&obj); QCOMPARE(obj.slotResult, QString("sl11")); const char *ptr2 = nullptr; QVERIFY(QMetaObject::invokeMethod(&obj, "sl12", Q_RETURN_ARG(const char*, ptr2))); QVERIFY(ptr2 != nullptr); QCOMPARE(obj.slotResult, QString("sl12")); // try again with a space: ptr2 = nullptr; QVERIFY(QMetaObject::invokeMethod(&obj, "sl12", Q_RETURN_ARG(char const * , ptr2))); QVERIFY(ptr2 != nullptr); QCOMPARE(obj.slotResult, QString("sl12")); // test w/ template args QList returnValue, argument; argument << QString("one") << QString("two") << QString("three"); QVERIFY(QMetaObject::invokeMethod(&obj, "sl13", Q_RETURN_ARG(QList, returnValue), Q_ARG(QList, argument))); QCOMPARE(returnValue, argument); QCOMPARE(obj.slotResult, QString("sl13")); // return qint64 qint64 return64; QVERIFY(QMetaObject::invokeMethod(&obj, "sl14", Q_RETURN_ARG(qint64, return64))); QCOMPARE(return64, Q_INT64_C(123456789)*123456789); QCOMPARE(obj.slotResult, QString("sl14")); //test signals QVERIFY(QMetaObject::invokeMethod(&obj, "sig0")); QCOMPARE(obj.slotResult, QString("sl0")); QVERIFY(QMetaObject::invokeMethod(&obj, "sig1", Q_ARG(QString, "baba"))); QCOMPARE(obj.slotResult, QString("sl1:baba")); exp.clear(); QVERIFY(QMetaObject::invokeMethod(&obj, "sig1", Q_RETURN_ARG(QString, exp), Q_ARG(QString, "hehe"))); QCOMPARE(exp, QString("yessir")); QCOMPARE(obj.slotResult, QString("sl1:hehe")); QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::doesNotExist()"); QVERIFY(!QMetaObject::invokeMethod(&obj, "doesNotExist")); QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString)(QString)"); QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1(QString)", Q_ARG(QString, "arg"))); QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl3(QString)\n" "Candidates are:\n sl3(QString,QString,QString)"); QVERIFY(!QMetaObject::invokeMethod(&obj, "sl3", Q_ARG(QString, "arg"))); QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString,QString,QString)\n" "Candidates are:\n sl1(QString)"); QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1", Q_ARG(QString, "arg"), Q_ARG(QString, "arg"), Q_ARG(QString, "arg"))); //should not have changed since last test. QCOMPARE(exp, QString("yessir")); QCOMPARE(obj.slotResult, QString("sl1:hehe")); } void testFunction(){} void tst_QMetaObject::invokePointer() { #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 1) QtTestObject obj; QtTestObject *const nullTestObject = nullptr; QString t1("1"); // Test member functions QVERIFY(!QMetaObject::invokeMethod(nullTestObject, &QtTestObject::sl0)); QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sl0)); QCOMPARE(obj.slotResult, QString("sl0")); QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::testSender)); QCOMPARE(obj.slotResult, QString("0x0")); qint64 return64 = 0; QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sl14, &return64)); QCOMPARE(return64, Q_INT64_C(123456789)*123456789); QCOMPARE(obj.slotResult, QString("sl14")); // signals QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sig0)); QCOMPARE(obj.slotResult, QString("sl0")); // Test function pointers QVERIFY(!QMetaObject::invokeMethod(0, &testFunction)); QVERIFY(QMetaObject::invokeMethod(&obj, &testFunction)); QVERIFY(!QMetaObject::invokeMethod(0, &QtTestObject::staticFunction0)); QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::staticFunction0)); QCOMPARE(QtTestObject::staticResult, QString("staticFunction0")); return64 = 0; QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::staticFunction1, &return64)); QCOMPARE(return64, Q_INT64_C(123456789)*123456789); QCOMPARE(QtTestObject::staticResult, QString("staticFunction1")); // Test lambdas QCOMPARE(countedStructObjectsCount, 0); { CountedStruct str; QVERIFY(QMetaObject::invokeMethod(&obj, [str, &t1, &obj]() { obj.sl1(t1); })); QCOMPARE(obj.slotResult, QString("sl1:1")); } QCOMPARE(countedStructObjectsCount, 0); { CountedStruct str; QString exp; QVERIFY(QMetaObject::invokeMethod( &obj, [str, &obj]() -> QString { return obj.sl1("bubu"); }, &exp)); QCOMPARE(exp, QString("yessir")); QCOMPARE(obj.slotResult, QString("sl1:bubu")); } QCOMPARE(countedStructObjectsCount, 0); #if defined(__cpp_init_captures) && QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) { CountedStruct str; std::unique_ptr ptr( new int ); QVERIFY(QMetaObject::invokeMethod(&obj, [str, &t1, &obj, p = std::move(ptr)]() { obj.sl1(t1); })); QCOMPARE(obj.slotResult, QString("sl1:1")); } QCOMPARE(countedStructObjectsCount, 0); #endif #endif } void tst_QMetaObject::invokeQueuedMetaMember() { QtTestObject obj; QVERIFY(QMetaObject::invokeMethod(&obj, "sl0", Qt::QueuedConnection)); QVERIFY(obj.slotResult.isEmpty()); qApp->processEvents(QEventLoop::AllEvents); QCOMPARE(obj.slotResult, QString("sl0")); obj.slotResult = QString(); QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", Qt::QueuedConnection, Q_ARG(QString, QString("hallo")))); QVERIFY(obj.slotResult.isEmpty()); qApp->processEvents(QEventLoop::AllEvents); QCOMPARE(obj.slotResult, QString("sl1:hallo")); obj.slotResult = QString(); QVERIFY(QMetaObject::invokeMethod(&obj, "sl9", Qt::QueuedConnection, Q_ARG(QString, "1"), Q_ARG(QString, "2"), Q_ARG(QString, "3"), Q_ARG(QString, "4"), Q_ARG(QString, "5"), Q_ARG(QString, "6"), Q_ARG(QString, "7"), Q_ARG(QString, "8"), Q_ARG(QString, "9"))); QVERIFY(obj.slotResult.isEmpty()); qApp->processEvents(QEventLoop::AllEvents); QCOMPARE(obj.slotResult, QString("sl9:123456789")); // signals obj.slotResult.clear(); QVERIFY(QMetaObject::invokeMethod(&obj, "sig0", Qt::QueuedConnection)); QVERIFY(obj.slotResult.isEmpty()); qApp->processEvents(QEventLoop::AllEvents); QCOMPARE(obj.slotResult, QString("sl0")); QVERIFY(QMetaObject::invokeMethod(&obj, "sig1", Qt::QueuedConnection, Q_ARG(QString, "gogo"))); qApp->processEvents(QEventLoop::AllEvents); QCOMPARE(obj.slotResult, QString("sl1:gogo")); QString exp; QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invoke: Unable to invoke methods with return values in queued connections"); QVERIFY(!QMetaObject::invokeMethod(&obj, "sig1", Qt::QueuedConnection, Q_RETURN_ARG(QString, exp), Q_ARG(QString, "nono"))); qint64 ll1 = -1; quint64 ll2 = 0; QVERIFY(QMetaObject::invokeMethod(&obj, "testLongLong", Qt::QueuedConnection, Q_ARG(qint64, ll1), Q_ARG(quint64, ll2))); qApp->processEvents(QEventLoop::AllEvents); QCOMPARE(obj.slotResult, QString("testLongLong:-1,0")); obj.slotResult.clear(); { MyUnregisteredType t; QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invoke: Unable to handle unregistered datatype 'MyUnregisteredType'"); 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() { #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 1) QtTestObject obj; // Test member function QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sl0, Qt::QueuedConnection)); QVERIFY(obj.slotResult.isEmpty()); qApp->processEvents(QEventLoop::AllEvents); QCOMPARE(obj.slotResult, QString("sl0")); // signals obj.slotResult.clear(); QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sig0, Qt::QueuedConnection)); QVERIFY(obj.slotResult.isEmpty()); qApp->processEvents(QEventLoop::AllEvents); QCOMPARE(obj.slotResult, QString("sl0")); // Test function pointers QtTestObject::staticResult.clear(); QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::staticFunction0, Qt::QueuedConnection)); QVERIFY(QtTestObject::staticResult.isEmpty()); qApp->processEvents(QEventLoop::AllEvents); QCOMPARE(QtTestObject::staticResult, QString("staticFunction0")); // Test lambda QCOMPARE(countedStructObjectsCount, 0); { CountedStruct str; obj.slotResult.clear(); QVERIFY( QMetaObject::invokeMethod(&obj, [str, &obj]() { obj.sl0(); }, Qt::QueuedConnection)); QVERIFY(obj.slotResult.isEmpty()); qApp->processEvents(QEventLoop::AllEvents); QCOMPARE(obj.slotResult, QString("sl0")); } QCOMPARE(countedStructObjectsCount, 0); { CountedStruct str; qint32 var = 0; QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: Unable to invoke methods with return " "values in queued connections"); QVERIFY(!QMetaObject::invokeMethod(&obj, [str]() -> qint32 { return 1; }, Qt::QueuedConnection, &var)); QCOMPARE(var, 0); } QCOMPARE(countedStructObjectsCount, 0); #endif } void tst_QMetaObject::invokeBlockingQueuedMetaMember() { QThread t; t.start(); QtTestObject obj; obj.moveToThread(&t); QString t1("1"); QString t2("2"); QString t3("3"); QString t4("4"); QString t5("5"); QString t6("6"); QString t7("7"); QString t8("8"); QString t9("9"); QString t10("X"); QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", Qt::BlockingQueuedConnection, Q_ARG(QString, t1))); QCOMPARE(obj.slotResult, QString("sl1:1")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl2", Qt::BlockingQueuedConnection, Q_ARG(const QString, t1), Q_ARG(QString, t2))); QCOMPARE(obj.slotResult, QString("sl2:12")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl3", Qt::BlockingQueuedConnection, Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3))); QCOMPARE(obj.slotResult, QString("sl3:123")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl4", Qt::BlockingQueuedConnection, Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), Q_ARG(QString, t4))); QCOMPARE(obj.slotResult, QString("sl4:1234")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl5", Qt::BlockingQueuedConnection, Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, "5"))); QCOMPARE(obj.slotResult, QString("sl5:12345")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl6", Qt::BlockingQueuedConnection, Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, t5), Q_ARG(QString, t6))); QCOMPARE(obj.slotResult, QString("sl6:123456")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl7", Qt::BlockingQueuedConnection, Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, t5), Q_ARG(QString, t6), Q_ARG(QString, t7))); QCOMPARE(obj.slotResult, QString("sl7:1234567")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl8", Qt::BlockingQueuedConnection, Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, t5), Q_ARG(QString, t6), Q_ARG(QString, t7), Q_ARG(QString, t8))); QCOMPARE(obj.slotResult, QString("sl8:12345678")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl9", Qt::BlockingQueuedConnection, Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, t5), Q_ARG(QString, t6), Q_ARG(QString, t7), Q_ARG(QString, t8), Q_ARG(QString, t9))); QCOMPARE(obj.slotResult, QString("sl9:123456789")); QVERIFY(QMetaObject::invokeMethod(&obj, "sl11", Qt::BlockingQueuedConnection)); QCOMPARE(obj.slotResult, QString("sl11")); QVERIFY(QMetaObject::invokeMethod(&obj, "testSender", Qt::BlockingQueuedConnection)); QCOMPARE(obj.slotResult, QString("0x0")); QString refStr("whatever"); QVERIFY(QMetaObject::invokeMethod(&obj, "testReference", Qt::BlockingQueuedConnection, QGenericArgument("QString&", &refStr))); QCOMPARE(obj.slotResult, QString("testReference:whatever")); QCOMPARE(refStr, QString("gotcha")); qint64 ll1 = -1; quint64 ll2 = 0; QVERIFY(QMetaObject::invokeMethod(&obj, "testLongLong", Qt::BlockingQueuedConnection, Q_ARG(qint64, ll1), Q_ARG(quint64, ll2))); QCOMPARE(obj.slotResult, QString("testLongLong:-1,0")); QString exp; QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, exp), Q_ARG(QString, "bubu"))); QCOMPARE(exp, QString("yessir")); QCOMPARE(obj.slotResult, QString("sl1:bubu")); QObject *ptr = nullptr; QVERIFY(QMetaObject::invokeMethod(&obj, "sl11", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QObject*,ptr))); QCOMPARE(ptr, (QObject *)&obj); QCOMPARE(obj.slotResult, QString("sl11")); // try again with a space: ptr = nullptr; QVERIFY(QMetaObject::invokeMethod(&obj, "sl11", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QObject * , ptr))); QCOMPARE(ptr, (QObject *)&obj); QCOMPARE(obj.slotResult, QString("sl11")); const char *ptr2 = 0; QVERIFY(QMetaObject::invokeMethod(&obj, "sl12", Qt::BlockingQueuedConnection, Q_RETURN_ARG(const char*, ptr2))); QVERIFY(ptr2 != 0); QCOMPARE(obj.slotResult, QString("sl12")); // try again with a space: ptr2 = 0; QVERIFY(QMetaObject::invokeMethod(&obj, "sl12", Qt::BlockingQueuedConnection, Q_RETURN_ARG(char const * , ptr2))); QVERIFY(ptr2 != 0); QCOMPARE(obj.slotResult, QString("sl12")); // test w/ template args QList returnValue, argument; argument << QString("one") << QString("two") << QString("three"); QVERIFY(QMetaObject::invokeMethod(&obj, "sl13", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QList, returnValue), Q_ARG(QList, argument))); QCOMPARE(returnValue, argument); QCOMPARE(obj.slotResult, QString("sl13")); //test signals QVERIFY(QMetaObject::invokeMethod(&obj, "sig0", Qt::BlockingQueuedConnection)); QCOMPARE(obj.slotResult, QString("sl0")); QVERIFY(QMetaObject::invokeMethod(&obj, "sig1", Qt::BlockingQueuedConnection, Q_ARG(QString, "baba"))); QCOMPARE(obj.slotResult, QString("sl1:baba")); exp.clear(); QVERIFY(QMetaObject::invokeMethod(&obj, "sig1", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, exp), Q_ARG(QString, "hehe"))); QCOMPARE(exp, QString("yessir")); QCOMPARE(obj.slotResult, QString("sl1:hehe")); QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::doesNotExist()"); QVERIFY(!QMetaObject::invokeMethod(&obj, "doesNotExist", Qt::BlockingQueuedConnection)); QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString)(QString)"); QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1(QString)", Qt::BlockingQueuedConnection, Q_ARG(QString, "arg"))); QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl3(QString)\n" "Candidates are:\n sl3(QString,QString,QString)"); QVERIFY(!QMetaObject::invokeMethod(&obj, "sl3", Qt::BlockingQueuedConnection, Q_ARG(QString, "arg"))); QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString,QString,QString)\n" "Candidates are:\n sl1(QString)"); QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1", Qt::BlockingQueuedConnection, Q_ARG(QString, "arg"), Q_ARG(QString, "arg"), Q_ARG(QString, "arg"))); //should not have changed since last test. QCOMPARE(exp, QString("yessir")); QCOMPARE(obj.slotResult, QString("sl1:hehe")); QVERIFY(QMetaObject::invokeMethod(&obj, "moveToThread", Qt::BlockingQueuedConnection, Q_ARG(QThread*, QThread::currentThread()))); t.quit(); QVERIFY(t.wait()); } void tst_QMetaObject::invokeBlockingQueuedPointer() { #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 1) QtTestObject *const nullTestObject = nullptr; QThread t; t.start(); QtTestObject obj; obj.moveToThread(&t); QString t1("1"); // Test member functions QVERIFY(!QMetaObject::invokeMethod(nullTestObject, &QtTestObject::sl0, Qt::BlockingQueuedConnection)); QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sl0, Qt::BlockingQueuedConnection)); QCOMPARE(obj.slotResult, QString("sl0")); QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::testSender, Qt::BlockingQueuedConnection)); QCOMPARE(obj.slotResult, QString("0x0")); // return qint64 qint64 return64 = 0; QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sl14, Qt::BlockingQueuedConnection, &return64)); QCOMPARE(return64, Q_INT64_C(123456789)*123456789); QCOMPARE(obj.slotResult, QString("sl14")); //test signals QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sig0, Qt::BlockingQueuedConnection)); QCOMPARE(obj.slotResult, QString("sl0")); // Test function pointers QVERIFY(!QMetaObject::invokeMethod(0, &testFunction, Qt::BlockingQueuedConnection)); QVERIFY(QMetaObject::invokeMethod(&obj, &testFunction, Qt::BlockingQueuedConnection)); QVERIFY(!QMetaObject::invokeMethod(0, &QtTestObject::staticFunction0, Qt::BlockingQueuedConnection)); QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::staticFunction0, Qt::BlockingQueuedConnection)); QCOMPARE(QtTestObject::staticResult, QString("staticFunction0")); return64 = 0; QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::staticFunction1, Qt::BlockingQueuedConnection, &return64)); QCOMPARE(return64, Q_INT64_C(123456789)*123456789); QCOMPARE(QtTestObject::staticResult, QString("staticFunction1")); // Test lambdas QCOMPARE(countedStructObjectsCount, 0); { CountedStruct str; QVERIFY(QMetaObject::invokeMethod(&obj, [str, &obj, &t1]() { obj.sl1(t1); }, Qt::BlockingQueuedConnection)); QCOMPARE(obj.slotResult, QString("sl1:1")); } { CountedStruct str; QString exp; QVERIFY(QMetaObject::invokeMethod(&obj, [&obj, str]() -> QString { return obj.sl1("bubu"); }, Qt::BlockingQueuedConnection, &exp)); QCOMPARE(exp, QString("yessir")); QCOMPARE(obj.slotResult, QString("sl1:bubu")); } #ifdef __cpp_init_captures { std::unique_ptr ptr(new int); QVERIFY(QMetaObject::invokeMethod(&obj, [&obj, p = std::move(ptr)]() { return obj.sl1("hehe"); }, Qt::BlockingQueuedConnection)); QCOMPARE(obj.slotResult, QString("sl1:hehe")); } #endif QVERIFY(QMetaObject::invokeMethod(&obj, [&](){obj.moveToThread(QThread::currentThread());}, Qt::BlockingQueuedConnection)); t.quit(); QVERIFY(t.wait()); QCOMPARE(countedStructObjectsCount, 0); #endif } void tst_QMetaObject::qtMetaObjectInheritance() { QVERIFY(!QObject::staticMetaObject.superClass()); QCOMPARE(QSortFilterProxyModel::staticMetaObject.indexOfEnumerator("Qt::CaseSensitivity"), -1); QCOMPARE(QSortFilterProxyModel::staticMetaObject.indexOfEnumerator("CaseSensitivity"), -1); int indexOfSortCaseSensitivity = QSortFilterProxyModel::staticMetaObject.indexOfProperty("sortCaseSensitivity"); QVERIFY(indexOfSortCaseSensitivity != -1); QMetaProperty sortCaseSensitivity = QSortFilterProxyModel::staticMetaObject.property(indexOfSortCaseSensitivity); QVERIFY(sortCaseSensitivity.isValid()); QCOMPARE(sortCaseSensitivity.enumerator().name(), "CaseSensitivity"); } struct MyType { int i1, i2, i3; }; W_REGISTER_ARGTYPE(MyType) typedef QString CustomString; class QtTestCustomObject: public QObject { W_OBJECT(QtTestCustomObject) friend class tst_QMetaObject; public: QtTestCustomObject(): QObject(), sum(0) {} public slots: void sl1(MyType myType); W_SLOT(sl1) signals: void sig_custom(const CustomString &string) W_SIGNAL(sig_custom,string) public: int sum; }; W_OBJECT_IMPL(QtTestCustomObject) void QtTestCustomObject::sl1(MyType myType) { sum = myType.i1 + myType.i2 + myType.i3; } void tst_QMetaObject::invokeCustomTypes() { QtTestCustomObject obj; MyType tp = {1, 1, 1}; QCOMPARE(obj.sum, 0); QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", Q_ARG(MyType, tp))); QCOMPARE(obj.sum, 3); } namespace NamespaceWithConstructibleClass { class ConstructibleClass : public QObject { W_OBJECT(ConstructibleClass) public: ConstructibleClass(QObject *parent = 0) : QObject(parent) {} W_CONSTRUCTOR(QObject*) }; } W_OBJECT_IMPL(NamespaceWithConstructibleClass::ConstructibleClass) void tst_QMetaObject::invokeMetaConstructor() { const QMetaObject *mo = &QtTestObject::staticMetaObject; { QObject *obj = mo->newInstance(); QVERIFY(!obj); } { QtTestObject obj; QObject *obj2 = mo->newInstance(Q_ARG(QObject*, &obj)); QVERIFY(obj2 != 0); QCOMPARE(obj2->parent(), (QObject*)&obj); QVERIFY(qobject_cast(obj2) != 0); } // class in namespace const QMetaObject *nsmo = &NamespaceWithConstructibleClass::ConstructibleClass::staticMetaObject; { QtTestObject obj; QObject *obj2 = nsmo->newInstance(Q_ARG(QObject*, &obj)); QVERIFY(obj2 != 0); QCOMPARE(obj2->parent(), (QObject*)&obj); QVERIFY(qobject_cast(obj2) != 0); } // gadget shouldn't return a valid pointer #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) { QCOMPARE(MyGadget::staticMetaObject.constructorCount(), 1); QTest::ignoreMessage(QtWarningMsg, "QMetaObject::newInstance: type MyGadget does not inherit QObject"); QVERIFY(!MyGadget::staticMetaObject.newInstance()); } #endif } void tst_QMetaObject::invokeTypedefTypes() { qRegisterMetaType("CustomString"); QtTestCustomObject obj; QSignalSpy spy(&obj, &QtTestCustomObject::sig_custom); QVERIFY(spy.isValid()); QCOMPARE(spy.count(), 0); CustomString arg("hello"); QVERIFY(QMetaObject::invokeMethod(&obj, "sig_custom", Q_ARG(CustomString, arg))); QCOMPARE(spy.count(), 1); QCOMPARE(spy.at(0).count(), 1); QCOMPARE(spy.at(0).at(0), QVariant(arg)); } void tst_QMetaObject::invokeException() { #ifndef QT_NO_EXCEPTIONS QtTestObject obj; QCOMPARE(countedStructObjectsCount, 0); try { CountedStruct s; QVERIFY(QMetaObject::invokeMethod(&obj, "throwingSlot", Q_RETURN_ARG(CountedStruct, s), Q_ARG(CountedStruct, s), Q_ARG(CountedStruct, s))); QFAIL("Did not throw"); } catch(ObjectException &) {} QCOMPARE(countedStructObjectsCount, 0); #else QSKIP("Needs exceptions"); #endif } void tst_QMetaObject::invokeQueuedAutoRegister() { #if QT_VERSION < QT_VERSION_CHECK(5, 9, 0) QSKIP("Bug fixed in Qt 5.9"); #endif QtTestObject obj; auto shared = QSharedPointer::create(QStringLiteral("myShared-")); QVERIFY(QMetaObject::invokeMethod( &obj, "slotWithRegistrableArgument", Qt::QueuedConnection, Q_ARG(QtTestObject *, shared.data()), Q_ARG(QPointer, shared.data()), Q_ARG(QSharedPointer, shared), Q_ARG(QWeakPointer, shared), Q_ARG(QList, QList()), Q_ARG(QList, QList()))); QVERIFY(obj.slotResult.isEmpty()); qApp->processEvents(QEventLoop::AllEvents); QCOMPARE(obj.slotResult, QString("slotWithRegistrableArgument:myShared-myShared-myShared-myShared-00")); } void tst_QMetaObject::normalizedSignature_data() { QTest::addColumn("signature"); QTest::addColumn("result"); QTest::newRow("function") << "void foo()" << "void foo()"; QTest::newRow("spaces") << " void foo( ) " << "void foo()"; QTest::newRow("void") << "void foo(void)" << "void foo()"; QTest::newRow("void spaces") << "void foo( void )" << "void foo()"; QTest::newRow("void*") << "void foo(void*)" << "void foo(void*)"; QTest::newRow("void* spaces") << "void foo( void * )" << "void foo(void*)"; QTest::newRow("function ptr") << "void foo(void(*)(void))" << "void foo(void(*)())"; QTest::newRow("function ptr spaces") << "void foo( void ( * ) ( void ))" << "void foo(void(*)())"; QTest::newRow("function ptr void*") << "void foo(void(*)(void*))" << "void foo(void(*)(void*))"; QTest::newRow("function ptr void* spaces") << "void foo( void ( * ) ( void * ))" << "void foo(void(*)(void*))"; QTest::newRow("template args") << " void foo( QMap, QList) " << "void foo(QMap,QList)"; QTest::newRow("void template args") << " void foo( Foo, Bar ) " << "void foo(Foo,Bar)"; QTest::newRow("void* template args") << " void foo( Foo, Bar ) " << "void foo(Foo,Bar)"; QTest::newRow("rettype") << "QList foo()" << "QListfoo()"; QTest::newRow("rettype void template") << "Foo foo()" << "Foofoo()"; QTest::newRow("const rettype") << "const QString *foo()" << "const QString*foo()"; QTest::newRow("const ref") << "const QString &foo()" << "const QString&foo()"; QTest::newRow("reference") << "QString &foo()" << "QString&foo()"; QTest::newRow("const1") << "void foo(QString const *)" << "void foo(const QString*)"; QTest::newRow("const2") << "void foo(QString * const)" << "void foo(QString*)"; QTest::newRow("const3") << "void foo(QString const &)" << "void foo(QString)"; QTest::newRow("const4") << "void foo(const int)" << "void foo(int)"; QTest::newRow("const5") << "void foo(const int, int const, const int &, int const &)" << "void foo(int,int,int,int)"; QTest::newRow("const6") << "void foo(QList)" << "void foo(QList)"; QTest::newRow("const7") << "void foo(QList)" << "void foo(QList)"; QTest::newRow("const8") << "void foo(QList)" << "void foo(QList)"; QTest::newRow("const9") << "void foo(const Foo)" << "void foo(Foo)"; QTest::newRow("const10") << "void foo(Fooconst)" << "void foo(Foo)"; QTest::newRow("const11") << "void foo(Foo *const)" << "void foo(Foo*)"; QTest::newRow("const12") << "void foo(Fooconst*const *const)" << "void foo(const Foo*const*)"; QTest::newRow("const13") << "void foo(const Foo&)" << "void foo(Foo)"; QTest::newRow("const14") << "void foo(Fooconst&)" << "void foo(Foo)"; QTest::newRow("QVector") << "void foo(QVector)" << "void foo(QList)"; QTest::newRow("QVector1") << "void foo(const Template)" << "void foo(Template)"; QTest::newRow("refref") << "const char* foo(const X &&,X const &&, const X* &&) && " << "const char*foo(const X&&,const X&&,const X*&&)&&"; QTest::newRow("invalid1") << "a( b" << "a(b"; } void tst_QMetaObject::normalizedSignature() { QFETCH(QString, signature); QFETCH(QString, result); QCOMPARE(QMetaObject::normalizedSignature(signature.toLatin1()), result.toLatin1()); } void tst_QMetaObject::normalizedType_data() { QTest::addColumn("type"); QTest::addColumn("result"); QTest::newRow("simple") << "int" << "int"; QTest::newRow("white") << " int " << "int"; QTest::newRow("const1") << "int const *" << "const int*"; QTest::newRow("const2") << "const int *" << "const int*"; QTest::newRow("template1") << "QList" << "QList"; QTest::newRow("template2") << "QList" << "QList"; QTest::newRow("template3") << "QMap" << "QMap"; QTest::newRow("template4") << "const QMap &" << "QMap"; QTest::newRow("template5") << "QList< ::Foo::Bar>" << "QList<::Foo::Bar>"; QTest::newRow("template6") << "QList<::Foo::Bar>" << "QList<::Foo::Bar>"; QTest::newRow("template7") << "QList >" << "QList>"; QTest::newRow("template8") << "QMap" << "QMap"; QTest::newRow("template9") << "QPair , QPair > >" << "std::pair,std::pair>>"; QTest::newRow("template10") << "QVector const" << "QList"; QTest::newRow("template11") << " QSharedPointer> 2 )> > const & " << "QSharedPointer>2)>>"; QTest::newRow("template_sub") << "X<( Y < 8), (Y >6)> const & " << "X<(Y<8),(Y>6)>"; QTest::newRow("value1") << "const QString &" << "QString"; QTest::newRow("value2") << "QString const &" << "QString"; QTest::newRow("constInName1") << "constconst" << "constconst"; QTest::newRow("constInName2") << "constconst*" << "constconst*"; QTest::newRow("constInName3") << "const constconst&" << "constconst"; QTest::newRow("constInName4") << "constconst const*const" << "const constconst*"; QTest::newRow("class") << "const class foo&" << "foo"; QTest::newRow("struct") << "const struct foo*" << "const foo*"; QTest::newRow("struct2") << "struct foo const*" << "const foo*"; QTest::newRow("enum") << "enum foo" << "foo"; QTest::newRow("void") << "void" << "void"; QTest::newRow("QList") << "QList" << "QList"; QTest::newRow("QVector") << "QVector" << "QList"; QTest::newRow("refref") << "X const*const&&" << "const X*const&&"; QTest::newRow("refref2") << "const X&&" << "const X&&"; QTest::newRow("long1") << "long unsigned int long" << "qulonglong"; QTest::newRow("long2") << "int signed long" << "long"; QTest::newRow("long3") << "long unsigned" << "ulong"; QTest::newRow("long double") << " long double" << "long double"; QTest::newRow("signed char") << "char signed" << "signed char"; QTest::newRow("unsigned char") << "char unsigned" << "uchar"; QTest::newRow("signed short") << "short signed" << "short"; QTest::newRow("unsigned short") << "unsigned short" << "ushort"; QTest::newRow("short unsigned") << "short unsigned" << "ushort"; QTest::newRow("array1") << "unsigned int [4]" << "uint[4]"; QTest::newRow("array2") << "unsigned int const [4][5]" << "const uint[4][5]"; QTest::newRow("array3") << "unsigned[] const" << "uint[]"; QTest::newRow("nttp1") << "S<'>', int const> const" << "S<'>',const int>"; QTest::newRow("nttp2") << "S< \"> \\\">const * \\\\\" , int const> const" << "S<\"> \\\">const * \\\\\",const int>"; QTest::newRow("nttp3") << "S<\"Q <\" , int const> const*" << "const S<\"Q <\",const int>*"; QTest::newRow("nttp4") << "S< 1'2 , int const> const" << "S<1'2,const int>"; QTest::newRow("invalid") << "'const" << "'const"; QTest::newRow("anonym1") << "XX::" << "XX::"; QTest::newRow("anonym2") << "XX::{unnamed type#1}" << "XX::{unnamed type#1}"; QTest::newRow("anonym3") << "struct XX::" << "XX::"; QTest::newRow("anonym4") << "XX::(anonymous struct at ./example.cpp:10:13)" << "XX::(anonymous struct at./example.cpp:10:13)"; } void tst_QMetaObject::normalizedType() { QFETCH(QString, type); QFETCH(QString, result); QCOMPARE(QMetaObject::normalizedType(type.toLatin1()), result.toLatin1()); QCOMPARE(QMetaObject::normalizedType(result.toLatin1()), result.toLatin1()); } void tst_QMetaObject::customPropertyType() { QMetaProperty prop = metaObject()->property(metaObject()->indexOfProperty("value3")); #if QT_DEPRECATED_SINCE(6, 0) QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED QCOMPARE(prop.type(), QVariant::UserType); QT_WARNING_POP #endif QCOMPARE(prop.userType(), QMetaType::fromType().id()); QCOMPARE(prop.metaType(), QMetaType::fromType()); qRegisterMetaType("MyStruct"); QCOMPARE(prop.userType(), QMetaType::fromName("MyStruct").id()); prop = metaObject()->property(metaObject()->indexOfProperty("value4")); QCOMPARE(prop.metaType().id(), QMetaType::QVariantList); QCOMPARE(prop.metaType(), QMetaType::fromType>()); prop = metaObject()->property(metaObject()->indexOfProperty("value5")); QCOMPARE(prop.metaType().id(), QMetaType::QVariantList); } void tst_QMetaObject::checkScope_data() { QTest::addColumn("object"); QTest::addColumn("name"); static MyNamespace::MyClass obj1; static MyNamespace::MyClass2 obj2; QTest::newRow("MyClass") << static_cast(&obj1) << QByteArray("MyClass"); QTest::newRow("MyClass2") << static_cast(&obj2) << QByteArray("MyClass2"); } void tst_QMetaObject::checkScope() { QFETCH(QObject *, object); QFETCH(QByteArray, name); QObject &obj = *object; bool ok; const QMetaObject *mo = obj.metaObject(); QMetaEnum me = mo->enumerator(mo->indexOfEnumerator("MyEnum")); QVERIFY(me.isValid()); QVERIFY(!me.isFlag()); QCOMPARE(QByteArray(me.scope()), QByteArray("MyNamespace::" + name)); QCOMPARE(me.keyToValue("MyNamespace::" + name + "::MyEnum2", &ok), 1); QCOMPARE(ok, true); QCOMPARE(me.keyToValue(name + "::MyEnum2", &ok), -1); QCOMPARE(ok, false); QCOMPARE(me.keyToValue("MyNamespace::MyEnum2", &ok), -1); QCOMPARE(ok, false); QCOMPARE(me.keyToValue("MyEnum2", &ok), 1); QCOMPARE(ok, true); QCOMPARE(me.keyToValue("MyEnum", &ok), -1); QCOMPARE(ok, false); QCOMPARE(QLatin1String(me.valueToKey(1)), QLatin1String("MyEnum2")); QMetaEnum me2 = mo->enumerator(mo->indexOfEnumerator("MyAnotherEnum")); QVERIFY(me2.isValid()); QVERIFY(!me2.isFlag()); QCOMPARE(me2.keyToValue("MyAnotherEnum1", &ok), 1); QCOMPARE(ok, true); QCOMPARE(me2.keyToValue("MyAnotherEnum2", &ok), 2); QCOMPARE(ok, true); QCOMPARE(me2.keyToValue("MyAnotherEnum3", &ok), -1); QCOMPARE(ok, true); QCOMPARE(me2.keyToValue("MyAnotherEnum", &ok), -1); QCOMPARE(ok, false); QMetaEnum mf = mo->enumerator(mo->indexOfEnumerator("MyFlags")); QVERIFY(mf.isValid()); QVERIFY(mf.isFlag()); QCOMPARE(QByteArray(mf.scope()), QByteArray("MyNamespace::" + name)); QCOMPARE(mf.keysToValue("MyNamespace::" + name + "::MyFlag2", &ok), 2); QCOMPARE(ok, true); QCOMPARE(mf.keysToValue(name + "::MyFlag2", &ok), -1); QCOMPARE(ok, false); QCOMPARE(mf.keysToValue("MyNamespace::MyFlag2", &ok), -1); QCOMPARE(ok, false); QCOMPARE(mf.keysToValue("MyFlag2", &ok), 2); QCOMPARE(ok, true); QCOMPARE(mf.keysToValue("MyFlag", &ok), -1); QCOMPARE(ok, false); QCOMPARE(QLatin1String(mf.valueToKey(2)), QLatin1String("MyFlag2")); QCOMPARE(mf.keysToValue("MyNamespace::" + name + "::MyFlag1|MyNamespace::" + name + "::MyFlag2", &ok), 3); QCOMPARE(ok, true); QCOMPARE(mf.keysToValue(name + "::MyFlag1|" + name + "::MyFlag2", &ok), -1); QCOMPARE(ok, false); QCOMPARE(mf.keysToValue("MyNamespace::MyFlag1|MyNamespace::MyFlag2", &ok), -1); QCOMPARE(ok, false); QCOMPARE(mf.keysToValue("MyFlag1|MyFlag2", &ok), 3); QCOMPARE(ok, true); QCOMPARE(mf.keysToValue("MyFlag2|MyFlag2", &ok), 2); QCOMPARE(ok, true); QCOMPARE(mf.keysToValue("MyFlag1|MyNamespace::" + name + "::MyFlag2", &ok), 3); QCOMPARE(ok, true); QCOMPARE(mf.keysToValue("MyNamespace::" + name + "::MyFlag2|MyNamespace::" + name + "::MyFlag2", &ok), 2); QCOMPARE(ok, true); QCOMPARE(QLatin1String(mf.valueToKeys(3)), QLatin1String("MyFlag1|MyFlag2")); } void tst_QMetaObject::propertyNotify() { const QMetaObject *mo = metaObject(); QMetaProperty prop = mo->property(mo->indexOfProperty("value6")); QVERIFY(prop.isValid()); QVERIFY(prop.hasNotifySignal()); QMetaMethod signal = prop.notifySignal(); QCOMPARE(signal.methodSignature(), QByteArray("value6Changed()")); prop = mo->property(mo->indexOfProperty("value7")); QVERIFY(prop.isValid()); QVERIFY(prop.hasNotifySignal()); signal = prop.notifySignal(); QCOMPARE(signal.methodSignature(), QByteArray("value7Changed(QString)")); prop = mo->property(mo->indexOfProperty("value8")); QVERIFY(prop.isValid()); QVERIFY(!prop.hasNotifySignal()); signal = prop.notifySignal(); QCOMPARE(signal.methodSignature(), QByteArray()); prop = mo->property(mo->indexOfProperty("value")); QVERIFY(prop.isValid()); QVERIFY(!prop.hasNotifySignal()); signal = prop.notifySignal(); QCOMPARE(signal.methodSignature(), QByteArray()); } void tst_QMetaObject::propertyConstant() { const QMetaObject *mo = metaObject(); QMetaProperty prop = mo->property(mo->indexOfProperty("value8")); QVERIFY(prop.isValid()); QVERIFY(!prop.isConstant()); prop = mo->property(mo->indexOfProperty("value9")); QVERIFY(prop.isValid()); QVERIFY(prop.isConstant()); } void tst_QMetaObject::propertyFinal() { const QMetaObject *mo = metaObject(); QMetaProperty prop = mo->property(mo->indexOfProperty("value10")); QVERIFY(prop.isValid()); QVERIFY(prop.isFinal()); prop = mo->property(mo->indexOfProperty("value9")); QVERIFY(prop.isValid()); QVERIFY(!prop.isFinal()); } #if QT_VERSION >= QT_VERSION_CHECK(6,2,0) void tst_QMetaObject::metaType() { QCOMPARE(QObject::staticMetaObject.metaType(), QMetaType::fromType()); QCOMPARE(MyGadget::staticMetaObject.metaType(), QMetaType::fromType()); QCOMPARE(QAbstractProxyModel::staticMetaObject.metaType(), QMetaType::fromType()); auto qtNameSpaceMetaType = Qt::staticMetaObject.metaType(); QVERIFY2(!qtNameSpaceMetaType.isValid(), qtNameSpaceMetaType.name()); } #endif class ClassInfoTestObjectA : public QObject { W_OBJECT(ClassInfoTestObjectA) W_CLASSINFO("Author", "Christopher Pike") }; W_OBJECT_IMPL(ClassInfoTestObjectA) class ClassInfoTestObjectB : public ClassInfoTestObjectA { W_OBJECT(ClassInfoTestObjectB) }; W_OBJECT_IMPL(ClassInfoTestObjectB) void tst_QMetaObject::classInfo() { ClassInfoTestObjectB b; int index = b.metaObject()->indexOfClassInfo("Author"); QCOMPARE(index, 0); QVERIFY(index <= b.metaObject()->classInfoOffset()); QCOMPARE(QLatin1String(b.metaObject()->classInfo(index).value()), QLatin1String("Christopher Pike")); } void tst_QMetaObject::metaMethod() { QString str("foo"); QString ret("bar"); QMetaMethod method; QVERIFY(!method.invoke(this)); QVERIFY(!method.invoke(this, Q_ARG(QString, str))); QVERIFY(!method.invoke(this, Q_RETURN_ARG(QString, ret), Q_ARG(QString, str))); QCOMPARE(str, QString("foo")); QCOMPARE(ret, QString("bar")); QtTestObject obj; QString t1("1"); QString t2("2"); QString t3("3"); QString t4("4"); QString t5("5"); QString t6("6"); QString t7("7"); QString t8("8"); QString t9("9"); QString t10("X"); int index = QtTestObject::staticMetaObject.indexOfMethod("sl5(QString,QString,QString,QString,QString)"); QVERIFY(index > 0); method = QtTestObject::staticMetaObject.method(index); //wrong args QVERIFY(!method.invoke(&obj, Q_ARG(QString, "1"), Q_ARG(QString, "2"), Q_ARG(QString, "3"), Q_ARG(QString, "4"))); //QVERIFY(!method.invoke(&obj, Q_ARG(QString, "1"), Q_ARG(QString, "2"), Q_ARG(QString, "3"), Q_ARG(QString, "4"), Q_ARG(QString, "5"), Q_ARG(QString, "6"))); //QVERIFY(!method.invoke(&obj, Q_ARG(QString, "1"), Q_ARG(QString, "2"), Q_ARG(QString, "3"), Q_ARG(QString, "4"), Q_ARG(int, 5))); QVERIFY(!method.invoke(&obj, Q_RETURN_ARG(QString, ret), Q_ARG(QString, "1"), Q_ARG(QString, "2"), Q_ARG(QString, "3"), Q_ARG(QString, "4"), Q_ARG(QString, "5"))); //wrong object //QVERIFY(!method.invoke(this, Q_ARG(QString, "1"), Q_ARG(QString, "2"), Q_ARG(QString, "3"), Q_ARG(QString, "4"), Q_ARG(QString, "5"))); QVERIFY(!method.invoke(0, Q_ARG(QString, "1"), Q_ARG(QString, "2"), Q_ARG(QString, "3"), Q_ARG(QString, "4"), Q_ARG(QString, "5"))); QCOMPARE(ret, QString("bar")); QCOMPARE(obj.slotResult, QString()); QVERIFY(method.invoke(&obj, Q_ARG(QString, "1"), Q_ARG(QString, "2"), Q_ARG(QString, "3"), Q_ARG(QString, "4"), Q_ARG(QString, "5"))); QCOMPARE(obj.slotResult, QString("sl5:12345")); index = QtTestObject::staticMetaObject.indexOfMethod("sl13(QList)"); QVERIFY(index > 0); QMetaMethod sl13 = QtTestObject::staticMetaObject.method(index); QList returnValue, argument; argument << QString("one") << QString("two") << QString("three"); //wrong object //QVERIFY(!sl13.invoke(this, Q_RETURN_ARG(QList, returnValue), Q_ARG(QList, argument))); QVERIFY(!sl13.invoke(0, Q_RETURN_ARG(QList, returnValue), Q_ARG(QList, argument))); QVERIFY(returnValue.isEmpty()); QVERIFY(sl13.invoke(&obj, Q_RETURN_ARG(QList, returnValue), Q_ARG(QList, argument))); QCOMPARE(returnValue, argument); QCOMPARE(obj.slotResult, QString("sl13")); } void tst_QMetaObject::indexOfMethod_data() { QTest::addColumn("object"); QTest::addColumn("name"); QTest::addColumn("isSignal"); QTest::newRow("indexOfMethod_data") << (QObject*)this << QByteArray("indexOfMethod_data()") << false; QTest::newRow("deleteLater") << (QObject*)this << QByteArray("deleteLater()") << false; QTest::newRow("value6changed") << (QObject*)this << QByteArray("value6Changed()") << true; QTest::newRow("value7changed") << (QObject*)this << QByteArray("value7Changed(QString)") << true; QTest::newRow("destroyed") << (QObject*)this << QByteArray("destroyed()") << true; QTest::newRow("destroyed2") << (QObject*)this << QByteArray("destroyed(QObject*)") << true; } void tst_QMetaObject::indexOfMethod() { QFETCH(QObject *, object); QFETCH(QByteArray, name); QFETCH(bool, isSignal); int idx = object->metaObject()->indexOfMethod(name); QVERIFY(idx >= 0); QCOMPARE(object->metaObject()->method(idx).methodSignature(), name); QCOMPARE(object->metaObject()->indexOfSlot(name), isSignal ? -1 : idx); QCOMPARE(object->metaObject()->indexOfSignal(name), !isSignal ? -1 : idx); } #if QT_VERSION >= QT_VERSION_CHECK(6,1,0) class Base : public QObject { W_OBJECT(Base) public: int test() {return 0;} W_SLOT(test) int baseOnly() {return 0;} W_SLOT(baseOnly) }; class Derived : public Base { W_OBJECT(Derived) public: int test() {return 1;} W_SLOT(test) }; void tst_QMetaObject::firstMethod_data() { QTest::addColumn("name"); QTest::addColumn("method"); const QMetaObject &derived = Derived::staticMetaObject; const QMetaObject &base = Base::staticMetaObject; QTest::newRow("own method") << QByteArray("test") << derived.method(derived.indexOfMethod("test()")); QTest::newRow("parent method") << QByteArray("baseOnly") << derived.method(base.indexOfMethod("baseOnly()")); QTest::newRow("invalid") << QByteArray("invalid") << QMetaMethod(); } void tst_QMetaObject::firstMethod() { QFETCH(QByteArray, name); QFETCH(QMetaMethod, method); #ifdef QT_BUILD_INTERNAL QMetaMethod firstMethod = QMetaObjectPrivate::firstMethod(&Derived::staticMetaObject, name); QCOMPARE(firstMethod, method); #endif } W_OBJECT_IMPL(Base) W_OBJECT_IMPL(Derived) #endif void tst_QMetaObject::indexOfMethodPMF() { #define INDEXOFMETHODPMF_HELPER(ObjectType, Name, Arguments) { \ int idx = -1; \ void (ObjectType::*signal)Arguments = &ObjectType::Name; \ void *signal_p = &signal; \ void *args[] = { &idx, signal_p, 0}; \ ObjectType::qt_static_metacall(0, QMetaObject::IndexOfMethod, 0, args); \ QCOMPARE(ObjectType::staticMetaObject.indexOfMethod(QMetaObject::normalizedSignature(#Name #Arguments)), \ ObjectType::staticMetaObject.methodOffset() + idx); \ } INDEXOFMETHODPMF_HELPER(tst_QMetaObject, value7Changed, (const QString&)) INDEXOFMETHODPMF_HELPER(QtTestObject, sig0, ()) INDEXOFMETHODPMF_HELPER(QtTestObject, sig10, (QString,QString,QString,QString,QString,QString,QString,QString,QString,QString)) INDEXOFMETHODPMF_HELPER(QtTestCustomObject, sig_custom, (const CustomString &)) } #ifdef QT_BUILD_INTERNAL namespace SignalTestHelper { // These functions use the public QMetaObject/QMetaMethod API to implement // the functionality of the internal API, and are used to check the results. static int signalCount(const QMetaObject *mo) { int n = 0; for (int i = 0; i < mo->methodCount(); ++i) { QMetaMethod mm = mo->method(i); if (mm.methodType() == QMetaMethod::Signal) ++n; } return n; } static int signalOffset(const QMetaObject *mo) { return mo->superClass() ? signalCount(mo->superClass()) : 0; } static QMetaMethod signal(const QMetaObject *mo, int index) { int k = 0; for (int i = 0; i < mo->methodCount(); ++i) { QMetaMethod mm = mo->method(i); if (mm.methodType() != QMetaMethod::Signal) continue; if (k == index) return mm; ++k; } return QMetaMethod(); } static int signalIndex(const QMetaMethod &mm) { int k = mm.methodIndex(); const QMetaObject *mo = mm.enclosingMetaObject(); for (int i = 0; i < mm.methodIndex(); ++i) { if (mo->method(i).methodType() != QMetaMethod::Signal) --k; } return k; } } // namespace SignalTestHelper void tst_QMetaObject::signalOffset_data() { QTest::addColumn("metaObject"); QTest::newRow("QObject") << &QObject::staticMetaObject; QTest::newRow("tst_QMetaObject") << &tst_QMetaObject::staticMetaObject; QTest::newRow("QtTestObject") << &QtTestObject::staticMetaObject; } void tst_QMetaObject::signalOffset() { QFETCH(const QMetaObject *, metaObject); QCOMPARE(QMetaObjectPrivate::signalOffset(metaObject), SignalTestHelper::signalOffset(metaObject)); } void tst_QMetaObject::signalCount_data() { signalOffset_data(); } void tst_QMetaObject::signalCount() { QFETCH(const QMetaObject *, metaObject); QCOMPARE(QMetaObjectPrivate::absoluteSignalCount(metaObject), SignalTestHelper::signalCount(metaObject)); } void tst_QMetaObject::signal_data() { QTest::addColumn("metaObject"); QTest::addColumn("index"); struct SignalTestDataHelper { static void addSignals(const QMetaObject *mo) { int count = SignalTestHelper::signalCount(mo); for (int i = 0; i < count; ++i) { QMetaMethod mm = SignalTestHelper::signal(mo, i); QByteArray tag(mo->className()); tag.append("::"); tag.append(mm.methodSignature()); QTest::newRow(tag.constData()) << mo << i; } } }; SignalTestDataHelper::addSignals(&QObject::staticMetaObject); SignalTestDataHelper::addSignals(&tst_QMetaObject::staticMetaObject); SignalTestDataHelper::addSignals(&QtTestObject::staticMetaObject); } void tst_QMetaObject::signal() { QFETCH(const QMetaObject *, metaObject); QFETCH(int, index); QCOMPARE(QMetaObjectPrivate::signal(metaObject, index), SignalTestHelper::signal(metaObject, index)); } void tst_QMetaObject::signalIndex_data() { signal_data(); } void tst_QMetaObject::signalIndex() { QFETCH(const QMetaObject *, metaObject); QFETCH(int, index); QMetaMethod mm = SignalTestHelper::signal(metaObject, index); QCOMPARE(QMetaObjectPrivate::signalIndex(mm), SignalTestHelper::signalIndex(mm)); } #endif void tst_QMetaObject::enumDebugStream_data() { QTest::addColumn("verbosity"); QTest::addColumn("normalEnumMsg"); QTest::addColumn("scopedEnumMsg"); QTest::addColumn("globalEnumMsg"); QTest::addColumn("normalFlagMsg"); QTest::addColumn("normalFlagsMsg"); QTest::addColumn("scopedFlagMsg"); QTest::addColumn("scopedFlagsMsg"); QTest::addColumn("flagAsEnumMsg"); QTest::newRow("verbosity=0") << 0 << "hello MyEnum2 world" << "hello MyScopedEnum::Enum3 scoped world" << "WindowTitleHint Window Desktop WindowSystemMenuHint" << "hello MyFlag1 world" << "MyFlag1 MyFlag2|MyFlag3" << "MyScopedFlag(MyFlag2)" << "MyScopedFlag(MyFlag2|MyFlag3)" << "MyFlag1"; QTest::newRow("verbosity=1") << 1 << "hello MyEnum::MyEnum2 world" << "hello MyScopedEnum::Enum3 scoped world" << "WindowType::WindowTitleHint WindowType::Window WindowType::Desktop WindowType::WindowSystemMenuHint" << "hello MyFlag(MyFlag1) world" << "MyFlag(MyFlag1) MyFlag(MyFlag2|MyFlag3)" << "MyScopedFlag(MyFlag2)" << "MyScopedFlag(MyFlag2|MyFlag3)" << "MyFlag::MyFlag1"; QTest::newRow("verbosity=2") << 2 << "hello MyNamespace::MyClass::MyEnum2 world" << "hello MyNamespace::MyClass::MyScopedEnum::Enum3 scoped world" << "Qt::WindowTitleHint Qt::Window Qt::Desktop Qt::WindowSystemMenuHint" << "hello QFlags(MyFlag1) world" << "QFlags(MyFlag1) QFlags(MyFlag2|MyFlag3)" << "QFlags(MyFlag2)" << "QFlags(MyFlag2|MyFlag3)" << "MyNamespace::MyClass::MyFlag1"; QTest::newRow("verbosity=3") << 3 << "hello MyNamespace::MyClass::MyEnum::MyEnum2 world" << "hello MyNamespace::MyClass::MyScopedEnum::Enum3 scoped world" << "Qt::WindowType::WindowTitleHint Qt::WindowType::Window Qt::WindowType::Desktop Qt::WindowType::WindowSystemMenuHint" << "hello QFlags(MyFlag1) world" << "QFlags(MyFlag1) QFlags(MyFlag2|MyFlag3)" << "QFlags(MyFlag2)" << "QFlags(MyFlag2|MyFlag3)" << "MyNamespace::MyClass::MyFlag::MyFlag1"; } void tst_QMetaObject::enumDebugStream() { #if QT_VERSION < QT_VERSION_CHECK(5, 12, 0) QTest::ignoreMessage(QtDebugMsg, "hello MyNamespace::MyClass::MyEnum(MyEnum2) world "); MyNamespace::MyClass::MyEnum e = MyNamespace::MyClass::MyEnum2; qDebug() << "hello" << e << "world"; QTest::ignoreMessage(QtDebugMsg, "Qt::WindowType(WindowTitleHint) Qt::WindowType(Window) Qt::WindowType(Desktop) Qt::WindowType(WindowSystemMenuHint)"); qDebug() << Qt::WindowTitleHint << Qt::Window <(MyFlag1) world"); MyNamespace::MyClass::MyFlags f1 = MyNamespace::MyClass::MyFlag1; qDebug() << "hello" << f1 << "world"; MyNamespace::MyClass::MyFlags f2 = MyNamespace::MyClass::MyFlag2 | MyNamespace::MyClass::MyFlag3; QTest::ignoreMessage(QtDebugMsg, "QFlags(MyFlag1) QFlags(MyFlag2|MyFlag3)"); qDebug() << f1 << f2; #elif QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) QFETCH(int, verbosity); QFETCH(QString, normalEnumMsg); QFETCH(QString, scopedEnumMsg); QFETCH(QString, globalEnumMsg); QFETCH(QString, normalFlagMsg); QFETCH(QString, normalFlagsMsg); QFETCH(QString, scopedFlagMsg); QFETCH(QString, scopedFlagsMsg); QFETCH(QString, flagAsEnumMsg); // Enums QTest::ignoreMessage(QtDebugMsg, qPrintable(normalEnumMsg)); qDebug().verbosity(verbosity) << "hello" << MyNamespace::MyClass::MyEnum2 << "world"; QTest::ignoreMessage(QtDebugMsg, qPrintable(scopedEnumMsg)); qDebug().verbosity(verbosity) << "hello" << MyNamespace::MyClass::MyScopedEnum::Enum3 << "scoped world"; QTest::ignoreMessage(QtDebugMsg, qPrintable(globalEnumMsg)); qDebug().verbosity(verbosity) << Qt::WindowTitleHint << Qt::Window << Qt::Desktop << Qt::WindowSystemMenuHint; // Flags QTest::ignoreMessage(QtDebugMsg, qPrintable(normalFlagMsg)); MyNamespace::MyClass::MyFlags f1 = MyNamespace::MyClass::MyFlag1; qDebug().verbosity(verbosity) << "hello" << f1 << "world"; MyNamespace::MyClass::MyFlags f2 = MyNamespace::MyClass::MyFlag2 | MyNamespace::MyClass::MyFlag3; QTest::ignoreMessage(QtDebugMsg, qPrintable(normalFlagsMsg)); qDebug().verbosity(verbosity) << f1 << f2; QTest::ignoreMessage(QtDebugMsg, qPrintable(scopedFlagMsg)); MyNamespace::MyClass::MyScopedFlags f3 = MyNamespace::MyClass::MyScopedFlag::MyFlag2; qDebug().verbosity(verbosity) << f3; QTest::ignoreMessage(QtDebugMsg, qPrintable(scopedFlagsMsg)); f3 |= MyNamespace::MyClass::MyScopedFlag::MyFlag3; qDebug().verbosity(verbosity) << f3; // Single flag recognized as enum: QTest::ignoreMessage(QtDebugMsg, qPrintable(flagAsEnumMsg)); MyNamespace::MyClass::MyFlag f4 = MyNamespace::MyClass::MyFlag1; qDebug().verbosity(verbosity) << f4; #endif } void tst_QMetaObject::inherits_data() { QTest::addColumn("derivedMetaObject"); QTest::addColumn("baseMetaObject"); QTest::addColumn("inheritsResult"); QTest::newRow("MyClass inherits QObject") << &MyNamespace::MyClass::staticMetaObject << &QObject::staticMetaObject << true; QTest::newRow("QObject inherits MyClass") << &QObject::staticMetaObject << &MyNamespace::MyClass::staticMetaObject << false; QTest::newRow("MyClass inherits MyClass") << &MyNamespace::MyClass::staticMetaObject << &MyNamespace::MyClass::staticMetaObject << true; QTest::newRow("MyClassSubclass inherits QObject") << &MyNamespace::MyClassSubclass::staticMetaObject << &QObject::staticMetaObject << true; QTest::newRow("MyClassSubclass2 inherits QObject") << &MyNamespace::MyClassSubclass2::staticMetaObject << &QObject::staticMetaObject << true; QTest::newRow("MyClassSubclass2 inherits MyClass2") << &MyNamespace::MyClassSubclass2::staticMetaObject << &MyNamespace::MyClass2Subclass::staticMetaObject << false; } void tst_QMetaObject::inherits() { #if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) QFETCH(const QMetaObject *, derivedMetaObject); QFETCH(const QMetaObject *, baseMetaObject); QFETCH(bool, inheritsResult); QCOMPARE(derivedMetaObject->inherits(baseMetaObject), inheritsResult); #endif } void tst_QMetaObject::notifySignalsInParentClass() { #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) MyNamespace::ClassWithSetterGetterSignalsAddsProperties obj; QCOMPARE(obj.metaObject()->property(obj.metaObject()->indexOfProperty("value1")).notifySignal().name(), QByteArray("value1Changed")); QCOMPARE(obj.metaObject()->property(obj.metaObject()->indexOfProperty("value2")).notifySignal().name(), QByteArray("value2Changed")); MyNamespace::ClassWithChangedSignalNewValue obj2; QCOMPARE(obj2.metaObject()->property(obj2.metaObject()->indexOfProperty("value2")).notifySignal().name(), QByteArray("propertiesChanged")); #if 0 // With verdigris, this is a compilation error when the NOTIFY signal is not a signal QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::notifySignal: cannot find the NOTIFY signal thisIsNotASignal in class MyNamespace::ClassWithChangedSignalNewValue for property 'value3'"); obj2.metaObject()->property(obj2.metaObject()->indexOfProperty("value3")).notifySignal(); #endif #endif } QTEST_MAIN(tst_QMetaObject) verdigris-1.3/tests/qt/qmetaproperty/000077500000000000000000000000001427643277200200735ustar00rootroot00000000000000verdigris-1.3/tests/qt/qmetaproperty/qmetaproperty.pro000066400000000000000000000003241427643277200235300ustar00rootroot00000000000000CONFIG += testcase TARGET = tst_qmetaproperty QT = core testlib greaterThan(QT_MAJOR_VERSION, 5) { SOURCES = tst_qmetaproperty6.cpp } else { SOURCES = tst_qmetaproperty5.cpp } include(../../../src/verdigris.pri) verdigris-1.3/tests/qt/qmetaproperty/qmetaproperty.qbs000066400000000000000000000007751427643277200235270ustar00rootroot00000000000000import qbs Application { name: "qmetaproperty" consoleApplication: true type: ["application", "autotest"] Depends { name: "Verdigris" } Depends { name: "Qt.test" } Group { name: "qt5" condition: Qt.core.versionMajor < 6 files: [ "tst_qmetaproperty5.cpp", ] } Group { name: "qt6" condition: Qt.core.versionMajor >= 6 files: [ "tst_qmetaproperty6.cpp", ] } } verdigris-1.3/tests/qt/qmetaproperty/tst_qmetaproperty5.cpp000066400000000000000000000204341427643277200244750ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2015 Olivier Goffart ** 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 #include #include #include struct CustomType { int padding; QString str; CustomType(const QString &str = QString()) : str(str) {} operator QString() const { return str; } friend bool operator!=(const CustomType &a, const CustomType &b) { return a.str != b.str; } }; Q_DECLARE_METATYPE(CustomType) class tst_QMetaProperty : public QObject { W_OBJECT(tst_QMetaProperty) private slots: #define DECLARE_TEST(NAME) void NAME(); W_SLOT(NAME) DECLARE_TEST(hasStdCppSet) DECLARE_TEST(isConstant) DECLARE_TEST(isFinal) DECLARE_TEST(gadget) DECLARE_TEST(readAndWriteWithLazyRegistration) DECLARE_TEST(mapProperty) DECLARE_TEST(conversion) #undef DECLARE_TEST public: enum EnumType { EnumType1 }; void setValue(EnumType) {} EnumType getValue() const { return EnumType1; } void set_value(EnumType) {} EnumType get_value() const { return EnumType1; } void resetValue7() { value7 = QStringLiteral("reset"); } int value8() const { return 1; } int value9() const { return 1; } int value10() const { return 1; } QString value7; QMap map; CustomType custom; W_PROPERTY(EnumType, value WRITE setValue READ getValue) W_PROPERTY(EnumType, value2 WRITE set_value READ get_value) W_PROPERTY(QString, value7 MEMBER value7 RESET resetValue7) W_PROPERTY(int, value8 READ value8) W_PROPERTY(int, value9 READ value9 CONSTANT) W_PROPERTY(int, value10 READ value10 FINAL) W_PROPERTY((QMap), map MEMBER map) W_PROPERTY(CustomType, custom MEMBER custom) }; W_OBJECT_IMPL(tst_QMetaProperty) void tst_QMetaProperty::hasStdCppSet() { QSKIP("Not supported by W_PROPERTY"); const QMetaObject *mo = metaObject(); QMetaProperty prop = mo->property(mo->indexOfProperty("value")); QVERIFY(prop.isValid()); QVERIFY(prop.hasStdCppSet()); prop = mo->property(mo->indexOfProperty("value2")); QVERIFY(prop.isValid()); QVERIFY(!prop.hasStdCppSet()); } void tst_QMetaProperty::isConstant() { const QMetaObject *mo = metaObject(); QMetaProperty prop = mo->property(mo->indexOfProperty("value8")); QVERIFY(prop.isValid()); QVERIFY(!prop.isConstant()); prop = mo->property(mo->indexOfProperty("value9")); QVERIFY(prop.isValid()); QVERIFY(prop.isConstant()); } void tst_QMetaProperty::isFinal() { const QMetaObject *mo = metaObject(); QMetaProperty prop = mo->property(mo->indexOfProperty("value10")); QVERIFY(prop.isValid()); QVERIFY(prop.isFinal()); prop = mo->property(mo->indexOfProperty("value9")); QVERIFY(prop.isValid()); QVERIFY(!prop.isFinal()); } class MyGadget { public: QString m_value; void setValue(const QString &value) { m_value = value; } QString getValue() { return m_value; } void resetValue() { m_value = QLatin1String("reset"); } W_GADGET(MyGadget) W_PROPERTY(QString, value READ getValue WRITE setValue RESET resetValue) }; W_GADGET_IMPL(MyGadget) void tst_QMetaProperty::gadget() { const QMetaObject *mo = &MyGadget::staticMetaObject; QMetaProperty valueProp = mo->property(mo->indexOfProperty("value")); QVERIFY(valueProp.isValid()); { MyGadget g; QString hello = QLatin1String("hello"); QVERIFY(valueProp.writeOnGadget(&g, hello)); QCOMPARE(g.m_value, QLatin1String("hello")); QCOMPARE(valueProp.readOnGadget(&g), QVariant(hello)); QVERIFY(valueProp.resetOnGadget(&g)); QCOMPARE(valueProp.readOnGadget(&g), QVariant(QLatin1String("reset"))); } } struct CustomReadObject : QObject { W_OBJECT(CustomReadObject) }; struct CustomWriteObject : QObject { W_OBJECT(CustomWriteObject) }; struct CustomWriteObjectChild : CustomWriteObject { W_OBJECT(CustomWriteObjectChild) }; struct TypeLazyRegistration : QObject { W_OBJECT(TypeLazyRegistration) CustomReadObject *_read; CustomWriteObject *_write; W_PROPERTY(CustomReadObject *,read MEMBER _read) W_PROPERTY(CustomWriteObject *,write MEMBER _write) public: TypeLazyRegistration() : _read() , _write() {} }; W_OBJECT_IMPL(CustomReadObject) W_OBJECT_IMPL(CustomWriteObject) W_OBJECT_IMPL(CustomWriteObjectChild) W_OBJECT_IMPL(TypeLazyRegistration) void tst_QMetaProperty::readAndWriteWithLazyRegistration() { QCOMPARE(QMetaType::type("CustomReadObject*"), int(QMetaType::UnknownType)); QCOMPARE(QMetaType::type("CustomWriteObject*"), int(QMetaType::UnknownType)); TypeLazyRegistration o; QVERIFY(o.property("read").isValid()); QVERIFY(QMetaType::type("CustomReadObject*") != QMetaType::UnknownType); QCOMPARE(QMetaType::type("CustomWriteObject*"), int(QMetaType::UnknownType)); CustomWriteObjectChild data; QVariant value = QVariant::fromValue(&data); // this register CustomWriteObjectChild // check if base classes are not registered automatically, otherwise this test would be meaningless QCOMPARE(QMetaType::type("CustomWriteObject*"), int(QMetaType::UnknownType)); QVERIFY(o.setProperty("write", value)); QVERIFY(QMetaType::type("CustomWriteObject*") != QMetaType::UnknownType); QCOMPARE(o.property("write").value(), &data); } void tst_QMetaProperty::mapProperty() { map.insert(5, 9); QVariant v1 = QVariant::fromValue(map); QVariant v = property("map"); QVERIFY(v.isValid()); QCOMPARE(map, (v.value >())); QCOMPARE(v.typeName(), "QMap"); } void tst_QMetaProperty::conversion() { if (qVersion() < QByteArray("5.6.0")) QSKIP("this is a test for a bug in 5.5"); QMetaType::registerConverter(); QMetaType::registerConverter(); QString hello = QStringLiteral("Hello"); // Write to a QString property using a CustomType in a QVariant QMetaProperty value7P = metaObject()->property(metaObject()->indexOfProperty("value7")); QVERIFY(value7P.isValid()); QVERIFY(value7P.write(this, QVariant::fromValue(CustomType(hello)))); QCOMPARE(value7, hello); // Write to a CustomType property using a QString in a QVariant QMetaProperty customP = metaObject()->property(metaObject()->indexOfProperty("custom")); QVERIFY(customP.isValid()); QVERIFY(customP.write(this, hello)); QCOMPARE(custom.str, hello); // Something that cannot be converted should fail QVERIFY(!customP.write(this, 45)); QVERIFY(!customP.write(this, QVariant::fromValue(this))); QVERIFY(!value7P.write(this, QVariant::fromValue(this))); QVERIFY(!value7P.write(this, QVariant::fromValue(this))); // none of this should have changed the values QCOMPARE(value7, hello); QCOMPARE(custom.str, hello); // Empty variant should be converted to default object QVERIFY(customP.write(this, QVariant())); QCOMPARE(custom.str, QString()); // or reset resetable QVERIFY(value7P.write(this, QVariant())); QCOMPARE(value7, QLatin1String("reset")); } QTEST_MAIN(tst_QMetaProperty) verdigris-1.3/tests/qt/qmetaproperty/tst_qmetaproperty6.cpp000066400000000000000000000237021427643277200244770ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2015 Olivier Goffart ** 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 #include #include #include struct CustomType { int padding; QString str; CustomType(const QString &str = QString()) : str(str) {} operator QString() const { return str; } friend bool operator!=(const CustomType &a, const CustomType &b) { return a.str != b.str; } }; Q_DECLARE_METATYPE(CustomType) class tst_QMetaProperty : public QObject { W_OBJECT(tst_QMetaProperty) private slots: #define DECLARE_TEST(NAME) void NAME(); W_SLOT(NAME) DECLARE_TEST(hasStdCppSet) DECLARE_TEST(isConstant) DECLARE_TEST(isFinal) DECLARE_TEST(gadget) DECLARE_TEST(readAndWriteWithLazyRegistration) DECLARE_TEST(mapProperty) DECLARE_TEST(conversion) DECLARE_TEST(enumsFlags) #undef DECLARE_TEST public: enum EnumType { EnumType1 }; void setValue(EnumType) {} EnumType getValue() const { return EnumType1; } void set_value(EnumType) {} EnumType get_value() const { return EnumType1; } void resetValue7() { value7 = QStringLiteral("reset"); } int value8() const { return 1; } int value9() const { return 1; } int value10() const { return 1; } QString value7; QMap map; CustomType custom; W_PROPERTY(EnumType, value WRITE setValue READ getValue) W_PROPERTY(EnumType, value2 WRITE set_value READ get_value) W_PROPERTY(QString, value7 MEMBER value7 RESET resetValue7) W_PROPERTY(int, value8 READ value8) W_PROPERTY(int, value9 READ value9 CONSTANT) W_PROPERTY(int, value10 READ value10 FINAL) W_PROPERTY((QMap), map MEMBER map) W_PROPERTY(CustomType, custom MEMBER custom) }; W_OBJECT_IMPL(tst_QMetaProperty) void tst_QMetaProperty::hasStdCppSet() { QSKIP("Not supported by W_PROPERTY"); const QMetaObject *mo = metaObject(); QMetaProperty prop = mo->property(mo->indexOfProperty("value")); QVERIFY(prop.isValid()); QVERIFY(prop.hasStdCppSet()); prop = mo->property(mo->indexOfProperty("value2")); QVERIFY(prop.isValid()); QVERIFY(!prop.hasStdCppSet()); } void tst_QMetaProperty::isConstant() { const QMetaObject *mo = metaObject(); QMetaProperty prop = mo->property(mo->indexOfProperty("value8")); QVERIFY(prop.isValid()); QVERIFY(!prop.isConstant()); prop = mo->property(mo->indexOfProperty("value9")); QVERIFY(prop.isValid()); QVERIFY(prop.isConstant()); } void tst_QMetaProperty::isFinal() { const QMetaObject *mo = metaObject(); QMetaProperty prop = mo->property(mo->indexOfProperty("value10")); QVERIFY(prop.isValid()); QVERIFY(prop.isFinal()); prop = mo->property(mo->indexOfProperty("value9")); QVERIFY(prop.isValid()); QVERIFY(!prop.isFinal()); } class MyGadget { public: QString m_value; void setValue(const QString &value) { m_value = value; } QString getValue() { return m_value; } void resetValue() { m_value = QLatin1String("reset"); } W_GADGET(MyGadget) W_PROPERTY(QString, value READ getValue WRITE setValue RESET resetValue) }; W_GADGET_IMPL(MyGadget) void tst_QMetaProperty::gadget() { const QMetaObject *mo = &MyGadget::staticMetaObject; QMetaProperty valueProp = mo->property(mo->indexOfProperty("value")); QVERIFY(valueProp.isValid()); QCOMPARE(valueProp.metaType(), QMetaType::fromType()); { MyGadget g; QString hello = QLatin1String("hello"); QVERIFY(valueProp.writeOnGadget(&g, hello)); QCOMPARE(g.m_value, QLatin1String("hello")); QCOMPARE(valueProp.readOnGadget(&g), QVariant(hello)); QVERIFY(valueProp.resetOnGadget(&g)); QCOMPARE(valueProp.readOnGadget(&g), QVariant(QLatin1String("reset"))); } } struct CustomReadObject : QObject { W_OBJECT(CustomReadObject) }; struct CustomWriteObject : QObject { W_OBJECT(CustomWriteObject) }; struct CustomWriteObjectChild : CustomWriteObject { W_OBJECT(CustomWriteObjectChild) }; struct TypeLazyRegistration : QObject { W_OBJECT(TypeLazyRegistration) CustomReadObject *_read; CustomWriteObject *_write; W_PROPERTY(CustomReadObject *,read MEMBER _read) W_PROPERTY(CustomWriteObject *,write MEMBER _write) public: TypeLazyRegistration() : _read() , _write() {} }; class EnumFlagsTester : public QObject { W_OBJECT(EnumFlagsTester) public: enum TestEnum { e1, e2 }; W_ENUM(TestEnum, e1, e2) enum TestFlag { flag1 = 0x1, flag2 = 0x2 }; W_DECLARE_FLAGS(TestFlags, TestFlag) public: using QObject::QObject; TestEnum enumProperty() const { return m_enum; } void setEnumProperty(TestEnum e) { m_enum = e; } TestFlags flagProperty() const { return m_flags; } void setFlagProperty(TestFlags f) { m_flags = f; } private: W_PROPERTY(TestEnum, enumProperty WRITE setEnumProperty READ enumProperty) W_PROPERTY(TestFlags, flagProperty WRITE setFlagProperty READ flagProperty) private: TestEnum m_enum = e1; TestFlags m_flags; }; W_OBJECT_IMPL(CustomReadObject) W_OBJECT_IMPL(CustomWriteObject) W_OBJECT_IMPL(CustomWriteObjectChild) W_OBJECT_IMPL(TypeLazyRegistration) W_OBJECT_IMPL(EnumFlagsTester) Q_DECLARE_OPERATORS_FOR_FLAGS(EnumFlagsTester::TestFlags) void tst_QMetaProperty::readAndWriteWithLazyRegistration() { QVERIFY(!QMetaType::fromName("CustomReadObject*").isValid()); QVERIFY(!QMetaType::fromName("CustomWriteObject*").isValid()); TypeLazyRegistration o; QVERIFY(o.property("read").isValid()); QVERIFY(QMetaType::fromName("CustomReadObject*").isValid()); QVERIFY(!QMetaType::fromName("CustomWriteObject*").isValid()); CustomWriteObjectChild data; QVariant value = QVariant::fromValue(&data); // this register CustomWriteObjectChild // check if base classes are not registered automatically, otherwise this test would be meaningless QVERIFY(!QMetaType::fromName("CustomWriteObject*").isValid()); QVERIFY(o.setProperty("write", value)); QVERIFY(QMetaType::fromName("CustomWriteObject*").isValid()); QCOMPARE(o.property("write").value(), &data); } void tst_QMetaProperty::mapProperty() { map.insert(5, 9); QVariant v1 = QVariant::fromValue(map); QVariant v = property("map"); QVERIFY(v.isValid()); QCOMPARE(map, (v.value >())); } void tst_QMetaProperty::conversion() { if (qVersion() < QByteArray("5.6.0")) QSKIP("this is a test for a bug in 5.5"); QMetaType::registerConverter(); QMetaType::registerConverter(); QString hello = QStringLiteral("Hello"); // Write to a QString property using a CustomType in a QVariant QMetaProperty value7P = metaObject()->property(metaObject()->indexOfProperty("value7")); QVERIFY(value7P.isValid()); QVERIFY(value7P.write(this, QVariant::fromValue(CustomType(hello)))); QCOMPARE(value7, hello); // Write to a CustomType property using a QString in a QVariant QMetaProperty customP = metaObject()->property(metaObject()->indexOfProperty("custom")); QVERIFY(customP.isValid()); QVERIFY(customP.write(this, hello)); QCOMPARE(custom.str, hello); // Something that cannot be converted should fail QVERIFY(!customP.write(this, 45)); QVERIFY(!customP.write(this, QVariant::fromValue(this))); QVERIFY(!value7P.write(this, QVariant::fromValue(this))); QVERIFY(!value7P.write(this, QVariant::fromValue(this))); // none of this should have changed the values QCOMPARE(value7, hello); QCOMPARE(custom.str, hello); // Empty variant should be converted to default object QVERIFY(customP.write(this, QVariant())); QCOMPARE(custom.str, QString()); // or reset resetable QVERIFY(value7P.write(this, QVariant())); QCOMPARE(value7, QLatin1String("reset")); } void tst_QMetaProperty::enumsFlags() { // QTBUG-83689, verify that enumerations and flags can be assigned from int, // which is important for Qt Designer. EnumFlagsTester t; auto mo = t.metaObject(); const int enumIndex = mo->indexOfProperty("enumProperty"); QVERIFY(enumIndex >= 0); auto enumProperty = mo->property(enumIndex); QVERIFY(enumProperty.metaType().flags().testFlag(QMetaType::IsEnumeration)); QVERIFY(enumProperty.write(&t, QVariant(int(EnumFlagsTester::e2)))); QCOMPARE(t.enumProperty(), EnumFlagsTester::e2); const int flagsIndex = mo->indexOfProperty("flagProperty"); QVERIFY(flagsIndex >= 0); auto flagsProperty = mo->property(flagsIndex); QVERIFY(flagsProperty.metaType().flags().testFlag(QMetaType::IsEnumeration)); QVERIFY(flagsProperty.write(&t, QVariant(int(EnumFlagsTester::flag2)))); QCOMPARE(t.flagProperty(), EnumFlagsTester::flag2); } QTEST_MAIN(tst_QMetaProperty) verdigris-1.3/tests/qt/qobject/000077500000000000000000000000001427643277200166065ustar00rootroot00000000000000verdigris-1.3/tests/qt/qobject/.gitignore000066400000000000000000000002321427643277200205730ustar00rootroot00000000000000tst_qobject signalbug_helper signalbug_helper.exe debug/signalbug_helper release/signalbug_helper debug/signalbug_helper.exe release/signalbug_helper.exe verdigris-1.3/tests/qt/qobject/BLACKLIST000066400000000000000000000000271427643277200200400ustar00rootroot00000000000000[moveToThread] windows verdigris-1.3/tests/qt/qobject/qobject.pro000066400000000000000000000001051427643277200207530ustar00rootroot00000000000000TEMPLATE = subdirs SUBDIRS += test.pro !winrt: SUBDIRS += signalbug verdigris-1.3/tests/qt/qobject/qobject.qbs000066400000000000000000000025011427643277200207420ustar00rootroot00000000000000import qbs import qbs.Utilities Project { references: [ "signalbug" ] Application { name: "qobject" consoleApplication: true type: ["application", "autotest"] Depends { name: "cpp" } cpp.defines: base.concat("QT_DISABLE_DEPRECATED_BEFORE=0", "QT_NO_DEBUG") Depends { name: "Verdigris" } Depends { name: "Qt.core" } Depends { name: "Qt.network" } Depends { name: "Qt.test" } Depends { name: "Qt.testlib-private" condition: Utilities.versionCompare(Qt.core.version, "6.2") >= 0 } Depends { name: "signalbug" } Properties { condition: qbs.toolchain.contains('msvc') cpp.cxxFlags: base.concat( "/wd4573", // vs2019 warns about static connect/disconnect in lambdas "/wd4340" // vs2019 warns about wrapped enum value ) } Group { name: "qt5" condition: Qt.core.versionMajor === 5 files: [ "tst_qobject5.cpp", ] } Group { name: "qt6" condition: Qt.core.versionMajor === 6 files: [ "tst_qobject6.cpp", ] } } } verdigris-1.3/tests/qt/qobject/signalbug/000077500000000000000000000000001427643277200205615ustar00rootroot00000000000000verdigris-1.3/tests/qt/qobject/signalbug/signalbug.cpp000066400000000000000000000072661427643277200232530ustar00rootroot00000000000000/**************************************************************************** ** ** 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 "signalbug.h" #include #include #include W_OBJECT_IMPL(Receiver) W_OBJECT_IMPL(Sender) W_OBJECT_IMPL(Disconnector) #include static int Step = 0; Sender RandomSender (0, 0); void TRACE (int step, const char *name) { for (int t = 0; t < step - 1; t++) fprintf (stderr, "\t"); fprintf (stderr, "Step %d: %s\n", step, name); return; } Receiver::Receiver () : QObject () { } void Receiver::received () { ::Step++; const int stepCopy = ::Step; TRACE (stepCopy, "Receiver::received()"); if (::Step != 2 && ::Step != 4) qFatal("%s: Incorrect Step: %d (should be 2 or 4)", Q_FUNC_INFO, ::Step); if (::Step == 2) s->fire (); fprintf (stderr, "Receiver<%s>::received() sender=%s\n", (const char *) objectName ().toLatin1 (), sender ()->metaObject()->className()); TRACE (stepCopy, "ends Receiver::received()"); } Disconnector::Disconnector () : QObject () { } void Disconnector::received () { ::Step++; const int stepCopy = ::Step; TRACE (stepCopy, "Disconnector::received()"); if (::Step != 5 && ::Step != 6) qFatal("%s: Incorrect Step: %d (should be 5 or 6)", Q_FUNC_INFO, ::Step); fprintf (stderr, "Disconnector<%s>::received() sender=%s\n", (const char *) objectName ().toLatin1 (), sender ()->metaObject()->className()); if (sender () == 0) fprintf (stderr, "WE SHOULD NOT BE RECEIVING THIS SIGNAL\n"); if (::Step == 5) { disconnect (s, SIGNAL(fired()), s->d, SLOT(received())); connect (&RandomSender, SIGNAL(fired()), s->d, SLOT(received())); } TRACE (stepCopy, "ends Disconnector::received()"); } Sender::Sender (Receiver *r, Disconnector *d) : QObject () { this->r = r; this->d = d; if (r) connect (this, SIGNAL(fired()), r, SLOT(received())); if (d) connect (this, SIGNAL(fired()), d, SLOT(received())); } void Sender::fire () { ::Step++; const int stepCopy = ::Step; TRACE (stepCopy, "Sender::fire()"); if (::Step != 1 && ::Step != 3) qFatal("%s: Incorrect Step: %d (should be 1 or 3)", Q_FUNC_INFO, ::Step); emit fired (); TRACE (stepCopy, "ends Sender::fire()"); } int main (int argc, char *argv []) { QCoreApplication app (argc, argv); Receiver r; Disconnector d; Sender s (&r, &d); r.s = &s; d.s = &s; ::Step = 0; s.fire (); return 0; } verdigris-1.3/tests/qt/qobject/signalbug/signalbug.h000066400000000000000000000040431427643277200227060ustar00rootroot00000000000000/**************************************************************************** ** ** 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$ ** ****************************************************************************/ #ifndef SIGNAL_BUG_H #define SIGNAL_BUG_H #include #include class Sender; class Receiver : public QObject { W_OBJECT(Receiver) public: Receiver (); virtual ~Receiver () {} protected slots: void received (); W_SLOT(received) public: Sender *s; }; class Disconnector : public QObject { W_OBJECT(Disconnector) public: Disconnector (); virtual ~Disconnector () {} protected slots: void received (); W_SLOT(received) public: Sender *s; }; class Sender : public QObject { W_OBJECT(Sender) public: Sender (Receiver *r, Disconnector *d); virtual ~Sender () {} void fire (); W_SLOT(fire) signals: void fired () W_SIGNAL(fired) public: Receiver *r; Disconnector *d; }; #endif // SIGNAL_BUG_H verdigris-1.3/tests/qt/qobject/signalbug/signalbug.pro000066400000000000000000000001431427643277200232540ustar00rootroot00000000000000QT = core HEADERS += signalbug.h SOURCES += signalbug.cpp include(../../../../src/verdigris.pri) verdigris-1.3/tests/qt/qobject/signalbug/signalbug.qbs000066400000000000000000000005541427643277200232470ustar00rootroot00000000000000import qbs Application { id: root name: "signalbug" consoleApplication: true Depends { name: "Verdigris" } files: [ "signalbug.cpp", "signalbug.h", ] Export { Depends { name: "cpp" } cpp.defines: base.concat("W_SIGNALBUG=\""+root.buildDirectory+"/"+root.targetName+"\"") } } verdigris-1.3/tests/qt/qobject/test.pro000066400000000000000000000006451427643277200203140ustar00rootroot00000000000000CONFIG += testcase console QT = network testlib TARGET = tst_qobject versionAtLeast(QT_VERSION, 6.2.0) { QT += testlib-private } equals(QT_MAJOR_VERSION, 6): SOURCES = tst_qobject6.cpp equals(QT_MAJOR_VERSION, 5): SOURCES = tst_qobject5.cpp # Force C++17 if available (needed due to P0012R1) contains(QT_CONFIG, c++1z): CONFIG += c++1z DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 include(../../../src/verdigris.pri) verdigris-1.3/tests/qt/qobject/tst_qobject5.cpp000066400000000000000000011000421427643277200217160ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2015 Olivier Goffart ** 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 #include #include #include #include #include #include #include #include #include #include #include #include #include # include #include "qobject.h" #ifdef QT_BUILD_INTERNAL #undef QT_BUILD_INTERNAL // Verdigris don't test the internals #endif #include #include QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations") QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations") QT_WARNING_DISABLE_GCC("-Wdeprecated-copy") W_REGISTER_ARGTYPE(int&) W_REGISTER_ARGTYPE(short&) W_REGISTER_ARGTYPE(bool&) W_REGISTER_ARGTYPE(QObject) W_REGISTER_ARGTYPE(QObject&) class tst_QObject : public QObject { W_OBJECT(tst_QObject) private slots: void disconnect(); W_SLOT(disconnect, W_Access::Private) void connectSlotsByName(); W_SLOT(connectSlotsByName, W_Access::Private) void connectSignalsToSignalsWithDefaultArguments(); W_SLOT(connectSignalsToSignalsWithDefaultArguments, W_Access::Private) void receivers(); W_SLOT(receivers, W_Access::Private) void normalize(); W_SLOT(normalize, W_Access::Private) void qobject_castTemplate(); W_SLOT(qobject_castTemplate, W_Access::Private) void findChildren(); W_SLOT(findChildren, W_Access::Private) void connectDisconnectNotify_data(); W_SLOT(connectDisconnectNotify_data, W_Access::Private) void connectDisconnectNotify(); W_SLOT(connectDisconnectNotify, W_Access::Private) void connectDisconnectNotifyPMF(); W_SLOT(connectDisconnectNotifyPMF, W_Access::Private) void disconnectNotify_receiverDestroyed(); W_SLOT(disconnectNotify_receiverDestroyed, W_Access::Private) void disconnectNotify_metaObjConnection(); W_SLOT(disconnectNotify_metaObjConnection, W_Access::Private) void connectNotify_connectSlotsByName(); W_SLOT(connectNotify_connectSlotsByName, W_Access::Private) void connectDisconnectNotify_shadowing(); W_SLOT(connectDisconnectNotify_shadowing, W_Access::Private) void emitInDefinedOrder(); W_SLOT(emitInDefinedOrder, W_Access::Private) void customTypes(); W_SLOT(customTypes, W_Access::Private) void streamCustomTypes(); W_SLOT(streamCustomTypes, W_Access::Private) void metamethod(); W_SLOT(metamethod, W_Access::Private) void namespaces(); W_SLOT(namespaces, W_Access::Private) void threadSignalEmissionCrash(); W_SLOT(threadSignalEmissionCrash, W_Access::Private) void thread(); W_SLOT(thread, W_Access::Private) void thread0(); W_SLOT(thread0, W_Access::Private) void moveToThread(); W_SLOT(moveToThread, W_Access::Private) void senderTest(); W_SLOT(senderTest, W_Access::Private) void declareInterface(); W_SLOT(declareInterface, W_Access::Private) void qpointerResetBeforeDestroyedSignal(); W_SLOT(qpointerResetBeforeDestroyedSignal, W_Access::Private) void testUserData(); W_SLOT(testUserData, W_Access::Private) void childDeletesItsSibling(); W_SLOT(childDeletesItsSibling, W_Access::Private) void dynamicProperties(); W_SLOT(dynamicProperties, W_Access::Private) void floatProperty(); W_SLOT(floatProperty, W_Access::Private) void qrealProperty(); W_SLOT(qrealProperty, W_Access::Private) void property(); W_SLOT(property, W_Access::Private) void recursiveSignalEmission(); W_SLOT(recursiveSignalEmission, W_Access::Private) void signalBlocking(); W_SLOT(signalBlocking, W_Access::Private) void blockingQueuedConnection(); W_SLOT(blockingQueuedConnection, W_Access::Private) void childEvents(); W_SLOT(childEvents, W_Access::Private) void installEventFilter(); W_SLOT(installEventFilter, W_Access::Private) void deleteSelfInSlot(); W_SLOT(deleteSelfInSlot, W_Access::Private) void disconnectSelfInSlotAndDeleteAfterEmit(); W_SLOT(disconnectSelfInSlotAndDeleteAfterEmit, W_Access::Private) void dumpObjectInfo(); W_SLOT(dumpObjectInfo, W_Access::Private) void connectToSender(); W_SLOT(connectToSender, W_Access::Private) void qobjectConstCast(); W_SLOT(qobjectConstCast, W_Access::Private) void uniqConnection(); W_SLOT(uniqConnection, W_Access::Private) void uniqConnectionPtr(); W_SLOT(uniqConnectionPtr, W_Access::Private) void interfaceIid(); W_SLOT(interfaceIid, W_Access::Private) void deleteQObjectWhenDeletingEvent(); W_SLOT(deleteQObjectWhenDeletingEvent, W_Access::Private) void overloads(); W_SLOT(overloads, W_Access::Private) void isSignalConnected(); W_SLOT(isSignalConnected, W_Access::Private) void isSignalConnectedAfterDisconnection(); W_SLOT(isSignalConnectedAfterDisconnection, W_Access::Private) void qMetaObjectConnect(); W_SLOT(qMetaObjectConnect, W_Access::Private) void qMetaObjectDisconnectOne(); W_SLOT(qMetaObjectDisconnectOne, W_Access::Private) void sameName(); W_SLOT(sameName, W_Access::Private) void connectByMetaMethods(); W_SLOT(connectByMetaMethods, W_Access::Private) void connectByMetaMethodSlotInsteadOfSignal(); W_SLOT(connectByMetaMethodSlotInsteadOfSignal, W_Access::Private) void connectConstructorByMetaMethod(); W_SLOT(connectConstructorByMetaMethod, W_Access::Private) void disconnectByMetaMethod(); W_SLOT(disconnectByMetaMethod, W_Access::Private) void disconnectNotSignalMetaMethod(); W_SLOT(disconnectNotSignalMetaMethod, W_Access::Private) void autoConnectionBehavior(); W_SLOT(autoConnectionBehavior, W_Access::Private) void baseDestroyed(); W_SLOT(baseDestroyed, W_Access::Private) void pointerConnect(); W_SLOT(pointerConnect, W_Access::Private) void pointerDisconnect(); W_SLOT(pointerDisconnect, W_Access::Private) void emitInDefinedOrderPointer(); W_SLOT(emitInDefinedOrderPointer, W_Access::Private) void customTypesPointer(); W_SLOT(customTypesPointer, W_Access::Private) void connectCxx0x(); W_SLOT(connectCxx0x, W_Access::Private) void connectToStaticCxx0x(); W_SLOT(connectToStaticCxx0x, W_Access::Private) void connectCxx0xTypeMatching(); W_SLOT(connectCxx0xTypeMatching, W_Access::Private) void connectCxx17Noexcept(); W_SLOT(connectCxx17Noexcept, W_Access::Private) void connectConvert(); W_SLOT(connectConvert, W_Access::Private) void connectWithReference(); W_SLOT(connectWithReference, W_Access::Private) void connectManyArguments(); W_SLOT(connectManyArguments, W_Access::Private) void connectForwardDeclare(); W_SLOT(connectForwardDeclare, W_Access::Private) void connectNoDefaultConstructorArg(); W_SLOT(connectNoDefaultConstructorArg, W_Access::Private) void returnValue_data(); W_SLOT(returnValue_data, W_Access::Private) void returnValue(); W_SLOT(returnValue, W_Access::Private) void returnValue2_data(); W_SLOT(returnValue2_data, W_Access::Private) void returnValue2(); W_SLOT(returnValue2, W_Access::Private) void connectVirtualSlots(); W_SLOT(connectVirtualSlots, W_Access::Private) void connectSlotsVMIClass(); W_SLOT(connectSlotsVMIClass, W_Access::Private) // VMI = Virtual or Multiple Inheritance void connectPrivateSlots(); W_SLOT(connectPrivateSlots, W_Access::Private) void connectFunctorArgDifference(); W_SLOT(connectFunctorArgDifference, W_Access::Private) void connectFunctorOverloads(); W_SLOT(connectFunctorOverloads, W_Access::Private) void connectFunctorQueued(); W_SLOT(connectFunctorQueued, W_Access::Private) void connectFunctorWithContext(); W_SLOT(connectFunctorWithContext, W_Access::Private) void connectFunctorWithContextUnique(); W_SLOT(connectFunctorWithContextUnique, W_Access::Private) void connectFunctorDeadlock(); W_SLOT(connectFunctorDeadlock, W_Access::Private) void connectFunctorMoveOnly(); W_SLOT(connectFunctorMoveOnly, W_Access::Private) void connectStaticSlotWithObject(); W_SLOT(connectStaticSlotWithObject, W_Access::Private) void disconnectDoesNotLeakFunctor(); W_SLOT(disconnectDoesNotLeakFunctor, W_Access::Private) void contextDoesNotLeakFunctor(); W_SLOT(contextDoesNotLeakFunctor, W_Access::Private) void connectBase(); W_SLOT(connectBase, W_Access::Private) void qmlConnect(); W_SLOT(qmlConnect, W_Access::Private) void connectWarnings(); W_SLOT(connectWarnings, W_Access::Private) void exceptions(); W_SLOT(exceptions, W_Access::Private) void noDeclarativeParentChangedOnDestruction(); W_SLOT(noDeclarativeParentChangedOnDestruction, W_Access::Private) void deleteLaterInAboutToBlockHandler(); W_SLOT(deleteLaterInAboutToBlockHandler, W_Access::Private) void mutableFunctor(); W_SLOT(mutableFunctor, W_Access::Private) void checkArgumentsForNarrowing(); W_SLOT(checkArgumentsForNarrowing, W_Access::Private) void nullReceiver(); W_SLOT(nullReceiver, W_Access::Private) }; struct QObjectCreatedOnShutdown { QObjectCreatedOnShutdown() {} ~QObjectCreatedOnShutdown() { QObject(); } }; static QObjectCreatedOnShutdown s_qobjectCreatedOnShutdown; class SenderObject : public QObject { W_OBJECT(SenderObject) public: SenderObject() : aPublicSlotCalled(0), recursionCount(0) {} void emitSignal1AfterRecursion() { if (recursionCount++ < 100) emitSignal1AfterRecursion(); else emitSignal1(); } void emitSignal1() { emit signal1(); } void emitSignal2() { emit signal2(); } void emitSignal3() { emit signal3(); } void emitSignal4() { emit signal4(); } signals: void signal1() W_SIGNAL(signal1) void signal2() W_SIGNAL(signal2) void signal3() W_SIGNAL(signal3) void signal4() W_SIGNAL(signal4) void signal5() W_SIGNAL_COMPAT(signal5) void signal6(void) W_SIGNAL(signal6) void signal7(int a, const QString &b) W_SIGNAL(signal7,a,b) public slots: void aPublicSlot() { aPublicSlotCalled++; } W_SLOT(aPublicSlot) public: void invoke1(){} W_INVOKABLE(invoke1) void sinvoke1(){} W_INVOKABLE(sinvoke1, W_Scriptable) int aPublicSlotCalled; protected: void invoke2(){} W_INVOKABLE(invoke2,(), W_Compat, W_Access::Protected) void invoke2(int){} W_INVOKABLE(invoke2,(int), W_Compat, W_Access::Protected) void sinvoke2(){} W_INVOKABLE(sinvoke2, W_Compat, W_Scriptable, W_Access::Protected) private: void invoke3(int hinz = 0, int kunz = 0){Q_UNUSED(hinz) Q_UNUSED(kunz)} W_INVOKABLE(invoke3, W_Access::Private) void sinvoke3(){} W_INVOKABLE(sinvoke3, W_Scriptable, W_Access::Private) int recursionCount; }; class ReceiverObject : public QObject { W_OBJECT(ReceiverObject) public: ReceiverObject() : sequence_slot1( 0 ) , sequence_slot2( 0 ) , sequence_slot3( 0 ) , sequence_slot4( 0 ) {} void reset() { sequence_slot4 = 0; sequence_slot3 = 0; sequence_slot2 = 0; sequence_slot1 = 0; count_slot1 = 0; count_slot2 = 0; count_slot3 = 0; count_slot4 = 0; } int sequence_slot1; int sequence_slot2; int sequence_slot3; int sequence_slot4; int count_slot1; int count_slot2; int count_slot3; int count_slot4; bool called(int slot) { switch (slot) { case 1: return sequence_slot1; case 2: return sequence_slot2; case 3: return sequence_slot3; case 4: return sequence_slot4; default: return false; } } static int sequence; public slots: void slot1() { sequence_slot1 = ++sequence; count_slot1++; } W_SLOT(slot1) void slot2() { sequence_slot2 = ++sequence; count_slot2++; } W_SLOT(slot2) void slot3() { sequence_slot3 = ++sequence; count_slot3++; } W_SLOT(slot3) void slot4() { sequence_slot4 = ++sequence; count_slot4++; } W_SLOT(slot4) }; int ReceiverObject::sequence = 0; static void playWithObjects() { // Do operations that will lock the internal signalSlotLock mutex on many QObjects. // The more QObjects, the higher the chance that the signalSlotLock mutex used // is already in use. If the number of objects is higher than the number of mutexes in // the pool (currently 131), the deadlock should always trigger. Use an even higher number // to be on the safe side. const int objectCount = 1024; SenderObject lotsOfObjects[objectCount]; for (int i = 0; i < objectCount; ++i) { QObject::connect(&lotsOfObjects[i], &SenderObject::signal1, &lotsOfObjects[i], &SenderObject::aPublicSlot); } } void tst_QObject::disconnect() { SenderObject s; ReceiverObject r1; ReceiverObject r2; connect(&s, SIGNAL(signal1()), &r1, SLOT(slot1())); connect(&s, SIGNAL(signal2()), &r1, SLOT(slot2())); connect(&s, SIGNAL(signal3()), &r1, SLOT(slot3())); connect(&s, SIGNAL(signal4()), &r1, SLOT(slot4())); s.emitSignal1(); s.emitSignal2(); s.emitSignal3(); s.emitSignal4(); QVERIFY(r1.called(1)); QVERIFY(r1.called(2)); QVERIFY(r1.called(3)); QVERIFY(r1.called(4)); r1.reset(); // usual disconnect with all parameters given bool ret = QObject::disconnect(&s, SIGNAL(signal1()), &r1, SLOT(slot1())); s.emitSignal1(); QVERIFY(!r1.called(1)); r1.reset(); QVERIFY(ret); ret = QObject::disconnect(&s, SIGNAL(signal1()), &r1, SLOT(slot1())); QVERIFY(!ret); // disconnect all signals from s from all slots from r1 QObject::disconnect(&s, 0, &r1, 0); s.emitSignal2(); s.emitSignal3(); s.emitSignal4(); QVERIFY(!r1.called(2)); QVERIFY(!r1.called(3)); QVERIFY(!r1.called(4)); r1.reset(); connect(&s, SIGNAL(signal1()), &r1, SLOT(slot1())); connect(&s, SIGNAL(signal1()), &r1, SLOT(slot2())); connect(&s, SIGNAL(signal1()), &r1, SLOT(slot3())); connect(&s, SIGNAL(signal2()), &r1, SLOT(slot4())); // disconnect s's signal1() from all slots of r1 QObject::disconnect(&s, SIGNAL(signal1()), &r1, 0); s.emitSignal1(); s.emitSignal2(); QVERIFY(!r1.called(1)); QVERIFY(!r1.called(2)); QVERIFY(!r1.called(3)); QVERIFY(r1.called(4)); r1.reset(); // make sure all is disconnected again QObject::disconnect(&s, 0, &r1, 0); connect(&s, SIGNAL(signal1()), &r1, SLOT(slot1())); connect(&s, SIGNAL(signal1()), &r2, SLOT(slot1())); connect(&s, SIGNAL(signal2()), &r1, SLOT(slot2())); connect(&s, SIGNAL(signal2()), &r2, SLOT(slot2())); connect(&s, SIGNAL(signal3()), &r1, SLOT(slot3())); connect(&s, SIGNAL(signal3()), &r2, SLOT(slot3())); // disconnect signal1() from all receivers QObject::disconnect(&s, SIGNAL(signal1()), 0, 0); s.emitSignal1(); s.emitSignal2(); s.emitSignal3(); QVERIFY(!r1.called(1)); QVERIFY(!r2.called(1)); QVERIFY(r1.called(2)); QVERIFY(r2.called(2)); QVERIFY(r1.called(2)); QVERIFY(r2.called(2)); r1.reset(); r2.reset(); // disconnect all signals of s from all receivers QObject::disconnect(&s, 0, 0, 0); QVERIFY(!r1.called(2)); QVERIFY(!r2.called(2)); QVERIFY(!r1.called(2)); QVERIFY(!r2.called(2)); } class AutoConnectSender : public QObject { W_OBJECT(AutoConnectSender) public: AutoConnectSender(QObject *parent) : QObject(parent) {} void emitSignalNoParams() { emit signalNoParams(); } void emitSignalWithParams(int i) { emit signalWithParams(i); } void emitSignalWithParams(int i, QString string) { emit signalWithParams(i, string); } void emitSignalManyParams(int i1, int i2, int i3, QString string, bool onoff) { emit signalManyParams(i1, i2, i3, string, onoff); } void emitSignalManyParams(int i1, int i2, int i3, QString string, bool onoff, bool dummy) { emit signalManyParams(i1, i2, i3, string, onoff, dummy); } void emitSignalManyParams2(int i1, int i2, int i3, QString string, bool onoff) { emit signalManyParams2(i1, i2, i3, string, onoff); } void emitSignalLoopBack() { emit signalLoopBack(); } signals: void signalNoParams() W_SIGNAL(signalNoParams) void signalWithParams(int i) W_SIGNAL(signalWithParams,(int),i) void signalWithParams(int i, QString string) W_SIGNAL(signalWithParams,(int,QString),i, string) void signalManyParams(int i1, int i2, int i3, QString string, bool onoff) W_SIGNAL(signalManyParams,(int,int,int,QString,bool),i1,i2,i3,string,onoff) void signalManyParams(int i1, int i2, int i3, QString string, bool onoff, bool _) W_SIGNAL(signalManyParams,(int,int,int,QString,bool,bool),i1,i2,i3,string,onoff,_) void signalManyParams2(int i1, int i2, int i3, QString string, bool onoff) W_SIGNAL(signalManyParams2, i1,i2,i3,string,onoff) void signalLoopBack() W_SIGNAL(signalLoopBack) }; class AutoConnectReceiver : public QObject { W_OBJECT(AutoConnectReceiver) public: QList called_slots; AutoConnectReceiver() { connect(this, SIGNAL(on_Sender_signalLoopBack()), this, SLOT(slotLoopBack())); } void emitSignalNoParams() { emit signalNoParams(); } void emit_signal_with_underscore() { emit signal_with_underscore(); } public slots: void on_Sender_signalNoParams() { called_slots << 1; } W_SLOT(on_Sender_signalNoParams) void on_Sender_signalWithParams(int i = 0) { called_slots << 2; Q_UNUSED(i); } W_SLOT(on_Sender_signalWithParams,(int)) void on_Sender_signalWithParams(int i, QString string) { called_slots << 3; Q_UNUSED(i);Q_UNUSED(string); } W_SLOT(on_Sender_signalWithParams,(int, QString)) void on_Sender_signalManyParams() { called_slots << 4; } W_SLOT(on_Sender_signalManyParams,()) void on_Sender_signalManyParams(int i1, int i2, int i3, QString string, bool onoff) { called_slots << 5; Q_UNUSED(i1);Q_UNUSED(i2);Q_UNUSED(i3);Q_UNUSED(string);Q_UNUSED(onoff); } W_SLOT(on_Sender_signalManyParams,(int,int,int,QString,bool)) void on_Sender_signalManyParams(int i1, int i2, int i3, QString string, bool onoff, bool dummy) { called_slots << 6; Q_UNUSED(i1);Q_UNUSED(i2);Q_UNUSED(i3);Q_UNUSED(string);Q_UNUSED(onoff); Q_UNUSED(dummy);} W_SLOT(on_Sender_signalManyParams,(int,int,int,QString,bool,bool)) void on_Sender_signalManyParams2(int i1, int i2, int i3, QString string, bool onoff) { called_slots << 7; Q_UNUSED(i1);Q_UNUSED(i2);Q_UNUSED(i3);Q_UNUSED(string);Q_UNUSED(onoff); } W_SLOT(on_Sender_signalManyParams2) void slotLoopBack() { called_slots << 8; } W_SLOT(slotLoopBack) void on_Receiver_signalNoParams() { called_slots << 9; } W_SLOT(on_Receiver_signalNoParams) void on_Receiver_signal_with_underscore() { called_slots << 10; } W_SLOT(on_Receiver_signal_with_underscore) protected slots: void o() { called_slots << -1; } W_SLOT(o) void on() { called_slots << -1; } W_SLOT(on) void on_() { called_slots << -1; } W_SLOT(on_) void on_something() { called_slots << -1; } W_SLOT(on_something) void on_child_signal() { called_slots << -1; } W_SLOT(on_child_signal) signals: void on_Sender_signalLoopBack() W_SIGNAL(on_Sender_signalLoopBack) void signalNoParams() W_SIGNAL(signalNoParams) void signal_with_underscore() W_SIGNAL(signal_with_underscore) }; void tst_QObject::connectSlotsByName() { AutoConnectReceiver receiver; receiver.setObjectName("Receiver"); AutoConnectSender sender(&receiver); sender.setObjectName("Sender"); QTest::ignoreMessage(QtWarningMsg, "QMetaObject::connectSlotsByName: No matching signal for on_child_signal()"); QTest::ignoreMessage(QtWarningMsg, "QMetaObject::connectSlotsByName: Connecting slot on_Sender_signalManyParams() with the first of the following compatible signals: (\"signalManyParams(int,int,int,QString,bool)\", \"signalManyParams(int,int,int,QString,bool,bool)\")"); QMetaObject::connectSlotsByName(&receiver); receiver.called_slots.clear(); sender.emitSignalNoParams(); QCOMPARE(receiver.called_slots, QList() << 1); receiver.called_slots.clear(); sender.emitSignalWithParams(0); QCOMPARE(receiver.called_slots, QList() << 2); receiver.called_slots.clear(); sender.emitSignalWithParams(0, "string"); QCOMPARE(receiver.called_slots, QList() << 3); receiver.called_slots.clear(); sender.emitSignalManyParams(1, 2, 3, "string", true); sender.emitSignalManyParams(1, 2, 3, "string", true, false); // the slot '4' (signalManyParams()) will get connected // to either of the two signalManyParams(...) overloads QCOMPARE(receiver.called_slots, QList() << 4 << 5 << 6); receiver.called_slots.clear(); sender.emitSignalManyParams2(1, 2, 3, "string", true); QCOMPARE(receiver.called_slots, QList() << 7); receiver.called_slots.clear(); sender.emitSignalLoopBack(); QCOMPARE(receiver.called_slots, QList() << 8); receiver.called_slots.clear(); receiver.emitSignalNoParams(); QCOMPARE(receiver.called_slots, QList() << 9); receiver.called_slots.clear(); receiver.emit_signal_with_underscore(); QCOMPARE(receiver.called_slots, QList() << 10); } void tst_QObject::qobject_castTemplate() { QScopedPointer o; QVERIFY(!::qobject_cast(o.data())); o.reset(new SenderObject); QVERIFY(::qobject_cast(o.data())); QVERIFY(::qobject_cast(o.data())); QVERIFY(!::qobject_cast(o.data())); } void tst_QObject::findChildren() { QObject o; QObject o1(&o); QObject o2(&o); QObject o11(&o1); QObject o12(&o1); QObject o111(&o11); QObject unnamed(&o); QTimer t1(&o); QTimer t121(&o12); QTimer emptyname(&o); Q_SET_OBJECT_NAME(o); Q_SET_OBJECT_NAME(o1); Q_SET_OBJECT_NAME(o2); Q_SET_OBJECT_NAME(o11); Q_SET_OBJECT_NAME(o12); Q_SET_OBJECT_NAME(o111); Q_SET_OBJECT_NAME(t1); Q_SET_OBJECT_NAME(t121); emptyname.setObjectName(""); QObject *op = 0; op = qFindChild(&o, "o1"); QCOMPARE(op, &o1); op = qFindChild(&o, "o2"); QCOMPARE(op, &o2); op = qFindChild(&o, "o11"); QCOMPARE(op, &o11); op = qFindChild(&o, "o12"); QCOMPARE(op, &o12); op = qFindChild(&o, "o111"); QCOMPARE(op, &o111); op = qFindChild(&o, "t1"); QCOMPARE(op, static_cast(&t1)); op = qFindChild(&o, "t121"); QCOMPARE(op, static_cast(&t121)); op = qFindChild(&o, "t1"); QCOMPARE(op, static_cast(&t1)); op = qFindChild(&o, "t121"); QCOMPARE(op, static_cast(&t121)); op = qFindChild(&o, "o12"); QCOMPARE(op, static_cast(0)); op = qFindChild(&o, "o"); QCOMPARE(op, static_cast(0)); op = qFindChild(&o, "harry"); QCOMPARE(op, static_cast(0)); op = qFindChild(&o, "o1"); QCOMPARE(op, &o1); QList l; QList tl; l = qFindChildren(&o, "o1"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o1); l = qFindChildren(&o, "o2"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o2); l = qFindChildren(&o, "o11"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o11); l = qFindChildren(&o, "o12"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o12); l = qFindChildren(&o, "o111"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o111); l = qFindChildren(&o, "t1"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), static_cast(&t1)); l = qFindChildren(&o, "t121"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), static_cast(&t121)); tl = qFindChildren(&o, "t1"); QCOMPARE(tl.size(), 1); QCOMPARE(tl.at(0), &t1); tl = qFindChildren(&o, "t121"); QCOMPARE(tl.size(), 1); QCOMPARE(tl.at(0), &t121); l = qFindChildren(&o, "o"); QCOMPARE(l.size(), 0); l = qFindChildren(&o, "harry"); QCOMPARE(l.size(), 0); tl = qFindChildren(&o, "o12"); QCOMPARE(tl.size(), 0); l = qFindChildren(&o, "o1"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o1); l = qFindChildren(&o, QRegExp("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(&o, QRegExp("t.*")); QCOMPARE(l.size(), 2); QVERIFY(l.contains(&t1)); QVERIFY(l.contains(&t121)); tl = qFindChildren(&o, QRegExp(".*")); QCOMPARE(tl.size(), 3); QVERIFY(tl.contains(&t1)); QVERIFY(tl.contains(&t121)); tl = qFindChildren(&o, QRegExp("o.*")); QCOMPARE(tl.size(), 0); l = qFindChildren(&o, QRegExp("harry")); QCOMPARE(l.size(), 0); l = o.findChildren(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 = o.findChildren(QRegularExpression("t.*")); QCOMPARE(l.size(), 2); QVERIFY(l.contains(&t1)); QVERIFY(l.contains(&t121)); tl = o.findChildren(QRegularExpression(".*")); QCOMPARE(tl.size(), 3); QVERIFY(tl.contains(&t1)); QVERIFY(tl.contains(&t121)); tl = o.findChildren(QRegularExpression("o.*")); QCOMPARE(tl.size(), 0); l = o.findChildren(QRegularExpression("harry")); QCOMPARE(l.size(), 0); // empty and null string check op = qFindChild(&o); QCOMPARE(op, &o1); op = qFindChild(&o, ""); QCOMPARE(op, &unnamed); op = qFindChild(&o, "unnamed"); QCOMPARE(op, static_cast(0)); l = qFindChildren(&o); QCOMPARE(l.size(), 9); l = qFindChildren(&o, ""); QCOMPARE(l.size(), 2); l = qFindChildren(&o, "unnamed"); QCOMPARE(l.size(), 0); tl = o.findChildren("t1"); QCOMPARE(tl.size(), 1); QCOMPARE(tl.at(0), &t1); // Find direct child/children op = o.findChild("o1", Qt::FindDirectChildrenOnly); QCOMPARE(op, &o1); op = o.findChild("o2", Qt::FindDirectChildrenOnly); QCOMPARE(op, &o2); op = o.findChild("o11", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(0)); op = o.findChild("o12", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(0)); op = o.findChild("o111", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(0)); op = o.findChild("t1", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(&t1)); op = o.findChild("t121", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(0)); op = o.findChild("t1", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(&t1)); op = o.findChild("t121", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(0)); op = o.findChild("o12", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(0)); op = o.findChild("o", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(0)); op = o.findChild("harry", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(0)); op = o.findChild("o1", Qt::FindDirectChildrenOnly); QCOMPARE(op, &o1); l = o.findChildren("o1", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o1); l = o.findChildren("o2", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o2); l = o.findChildren("o11", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 0); l = o.findChildren("o12", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 0); l = o.findChildren("o111", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 0); l = o.findChildren("t1", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), static_cast(&t1)); l = o.findChildren("t121", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 0); tl = o.findChildren("t1", Qt::FindDirectChildrenOnly); QCOMPARE(tl.size(), 1); QCOMPARE(tl.at(0), &t1); tl = o.findChildren("t121", Qt::FindDirectChildrenOnly); QCOMPARE(tl.size(), 0); l = o.findChildren("o", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 0); l = o.findChildren("harry", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 0); tl = o.findChildren("o12", Qt::FindDirectChildrenOnly); QCOMPARE(tl.size(), 0); l = o.findChildren("o1", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o1); l = o.findChildren(QRegExp("o.*"), Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 2); QVERIFY(l.contains(&o1)); QVERIFY(l.contains(&o2)); l = o.findChildren(QRegExp("t.*"), Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 1); QVERIFY(l.contains(&t1)); tl = o.findChildren(QRegExp(".*"), Qt::FindDirectChildrenOnly); QCOMPARE(tl.size(), 2); QVERIFY(tl.contains(&t1)); tl = o.findChildren(QRegExp("o.*"), Qt::FindDirectChildrenOnly); QCOMPARE(tl.size(), 0); l = o.findChildren(QRegExp("harry"), Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 0); // empty and null string check op = o.findChild(QString(), Qt::FindDirectChildrenOnly); QCOMPARE(op, &o1); op = o.findChild("", Qt::FindDirectChildrenOnly); QCOMPARE(op, &unnamed); op = o.findChild("unnamed", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(0)); l = o.findChildren(QString(), Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 5); l = o.findChildren("", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 2); l = o.findChildren("unnamed", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 0); tl = o.findChildren("t1", Qt::FindDirectChildrenOnly); QCOMPARE(tl.size(), 1); QCOMPARE(tl.at(0), &t1); } class NotifyObject : public SenderObject, public ReceiverObject { public: NotifyObject() : SenderObject(), ReceiverObject() {} QList connectedSignals; QList disconnectedSignals; void clearNotifications() { connectedSignals.clear(); disconnectedSignals.clear(); } protected: void connectNotify(const QMetaMethod &signal) { connectedSignals.append(signal); } void disconnectNotify(const QMetaMethod &signal) { disconnectedSignals.append(signal); } }; void tst_QObject::connectDisconnectNotify_data() { QTest::addColumn("a_signal"); QTest::addColumn("a_slot"); QTest::newRow("combo1") << SIGNAL( signal1() ) << SLOT( slot1() ); QTest::newRow("combo2") << SIGNAL( signal2(void) ) << SLOT( slot2( ) ); QTest::newRow("combo3") << SIGNAL( signal3( ) ) << SLOT( slot3(void) ); QTest::newRow("combo4") << SIGNAL( signal4( void ) )<< SLOT( slot4( void ) ); QTest::newRow("combo5") << SIGNAL( signal6( void ) ) << SLOT( slot4() ); QTest::newRow("combo6") << SIGNAL( signal6() ) << SLOT( slot4() ); QTest::newRow("combo7") << SIGNAL( signal7( int , const QString & ) ) << SLOT( slot4() ); } void tst_QObject::connectDisconnectNotify() { NotifyObject s; NotifyObject r; QFETCH(QString, a_signal); QFETCH(QString, a_slot); // Obtaining meta methods int signalIndx = ((SenderObject &)s).metaObject()->indexOfSignal( QMetaObject::normalizedSignature(a_signal.toLatin1().constData()+1).constData()); int methodIndx = ((ReceiverObject &)r).metaObject()->indexOfMethod( QMetaObject::normalizedSignature(a_slot.toLatin1().constData()+1).constData()); QMetaMethod signal = ((SenderObject &)s).metaObject()->method(signalIndx); QMetaMethod method = ((ReceiverObject &)r).metaObject()->method(methodIndx); QVERIFY(signal.isValid()); QVERIFY(method.isValid()); // Test connectNotify QVERIFY(QObject::connect((SenderObject *)&s, a_signal.toLatin1(), (ReceiverObject *)&r, a_slot.toLatin1())); QCOMPARE(s.connectedSignals.size(), 1); QCOMPARE(s.connectedSignals.at(0), signal); QVERIFY(s.disconnectedSignals.isEmpty()); // Test disconnectNotify QVERIFY(QObject::disconnect((SenderObject *)&s, a_signal.toLatin1(), (ReceiverObject *)&r, a_slot.toLatin1())); QCOMPARE(s.disconnectedSignals.size(), 1); QCOMPARE(s.disconnectedSignals.at(0), signal); QCOMPARE(s.connectedSignals.size(), 1); // Reconnect s.clearNotifications(); QVERIFY(QObject::connect((SenderObject *)&s, a_signal.toLatin1(), (ReceiverObject *)&r, a_slot.toLatin1())); QCOMPARE(s.connectedSignals.size(), 1); QCOMPARE(s.connectedSignals.at(0), signal); QVERIFY(s.disconnectedSignals.isEmpty()); // Test disconnectNotify for a complete disconnect QVERIFY(((SenderObject *)&s)->disconnect((ReceiverObject *)&r)); QCOMPARE(s.disconnectedSignals.size(), 1); QCOMPARE(s.disconnectedSignals.at(0), QMetaMethod()); QCOMPARE(s.connectedSignals.size(), 1); // Test connectNotify when connecting by QMetaMethod s.clearNotifications(); QVERIFY(QObject::connect((SenderObject *)&s, signal, (ReceiverObject *)&r, method)); QCOMPARE(s.connectedSignals.size(), 1); QCOMPARE(s.connectedSignals.at(0), signal); QVERIFY(s.disconnectedSignals.isEmpty()); // Test disconnectNotify when disconnecting by QMetaMethod QVERIFY(QObject::disconnect((SenderObject *)&s, signal, (ReceiverObject *)&r, method)); QCOMPARE(s.disconnectedSignals.size(), 1); QCOMPARE(s.disconnectedSignals.at(0), signal); QCOMPARE(s.connectedSignals.size(), 1); // Reconnect s.clearNotifications(); QVERIFY(QObject::connect((SenderObject *)&s, a_signal.toLatin1(), (ReceiverObject *)&r, a_slot.toLatin1())); // Test disconnectNotify for a complete disconnect by QMetaMethod QVERIFY(QObject::disconnect((SenderObject *)&s, QMetaMethod(), 0, QMetaMethod())); QCOMPARE(s.disconnectedSignals.size(), 1); QCOMPARE(s.disconnectedSignals.at(0), QMetaMethod()); QCOMPARE(s.connectedSignals.size(), 1); // Test connectNotify when connecting by index s.clearNotifications(); QVERIFY(QMetaObject::connect((SenderObject *)&s, signalIndx, (ReceiverObject *)&r, methodIndx)); QCOMPARE(s.connectedSignals.size(), 1); QCOMPARE(s.connectedSignals.at(0), signal); QVERIFY(s.disconnectedSignals.isEmpty()); // Test disconnectNotify when disconnecting by index QVERIFY(QMetaObject::disconnect((SenderObject *)&s, signalIndx, (ReceiverObject *)&r, methodIndx)); QCOMPARE(s.disconnectedSignals.size(), 1); QCOMPARE(s.disconnectedSignals.at(0), signal); QCOMPARE(s.connectedSignals.size(), 1); } static void connectDisconnectNotifyTestSlot() {} void tst_QObject::connectDisconnectNotifyPMF() { NotifyObject s; NotifyObject r; QMetaMethod signal = QMetaMethod::fromSignal(&SenderObject::signal1); // Test connectNotify QVERIFY(QObject::connect((SenderObject *)&s, &SenderObject::signal1, (ReceiverObject *)&r, &ReceiverObject::slot1)); QCOMPARE(s.connectedSignals.size(), 1); QCOMPARE(s.connectedSignals.at(0), signal); QVERIFY(s.disconnectedSignals.isEmpty()); // Test disconnectNotify QVERIFY(QObject::disconnect((SenderObject *)&s, &SenderObject::signal1, (ReceiverObject *)&r, &ReceiverObject::slot1)); QCOMPARE(s.disconnectedSignals.size(), 1); QCOMPARE(s.disconnectedSignals.at(0), signal); QCOMPARE(s.connectedSignals.size(), 1); // Reconnect s.clearNotifications(); QVERIFY(QObject::connect((SenderObject *)&s, &SenderObject::signal1, (ReceiverObject *)&r, &ReceiverObject::slot1)); QCOMPARE(s.connectedSignals.size(), 1); QCOMPARE(s.connectedSignals.at(0), signal); QVERIFY(s.disconnectedSignals.isEmpty()); // Test disconnectNotify with wildcard slot QVERIFY(QObject::disconnect((SenderObject *)&s, &SenderObject::signal1, (ReceiverObject *)&r, 0)); QCOMPARE(s.disconnectedSignals.size(), 1); QCOMPARE(s.disconnectedSignals.at(0), signal); QCOMPARE(s.connectedSignals.size(), 1); // Reconnect s.clearNotifications(); QMetaObject::Connection conn = connect((SenderObject *)&s, &SenderObject::signal1, (ReceiverObject *)&r, &ReceiverObject::slot1); QVERIFY(conn); // Test disconnectNotify when disconnecting by QMetaObject::Connection QVERIFY(QObject::disconnect(conn)); // Test connectNotify when connecting by function pointer s.clearNotifications(); QVERIFY(QObject::connect((SenderObject *)&s, &SenderObject::signal1, connectDisconnectNotifyTestSlot)); QCOMPARE(s.connectedSignals.size(), 1); QCOMPARE(s.connectedSignals.at(0), signal); QVERIFY(s.disconnectedSignals.isEmpty()); } void tst_QObject::disconnectNotify_receiverDestroyed() { NotifyObject s; { NotifyObject r; QVERIFY(QObject::connect((SenderObject *)&s, SIGNAL(signal1()), (ReceiverObject *)&r, SLOT(slot1()))); } QCOMPARE(s.disconnectedSignals.count(), 1); QCOMPARE(s.disconnectedSignals.at(0), QMetaMethod::fromSignal(&SenderObject::signal1)); s.disconnectedSignals.clear(); { NotifyObject r; QVERIFY(QObject::connect((SenderObject *)&s, SIGNAL(signal3()), (ReceiverObject *)&r, SLOT(slot3()))); } QCOMPARE(s.disconnectedSignals.count(), 1); QCOMPARE(s.disconnectedSignals.at(0), QMetaMethod::fromSignal(&SenderObject::signal3)); s.disconnectedSignals.clear(); { NotifyObject r; QVERIFY(QObject::connect((SenderObject *)&s, SIGNAL(destroyed()), (ReceiverObject *)&r, SLOT(slot3()))); } QCOMPARE(s.disconnectedSignals.count(), 1); QCOMPARE(s.disconnectedSignals.at(0), QMetaMethod::fromSignal(&QObject::destroyed)); } void tst_QObject::disconnectNotify_metaObjConnection() { if (qVersion() < QByteArray("5.8.0")) QSKIP("This bug was only fixed in 5.8"); NotifyObject s; { NotifyObject r; QMetaObject::Connection c = QObject::connect((SenderObject *)&s, SIGNAL(signal1()), (ReceiverObject *)&r, SLOT(slot1())); QVERIFY(c); QVERIFY(QObject::disconnect(c)); QCOMPARE(s.disconnectedSignals.count(), 1); QCOMPARE(s.disconnectedSignals.at(0), QMetaMethod::fromSignal(&SenderObject::signal1)); QCOMPARE(s.disconnectedSignals.count(), 1); } } class ConnectByNameNotifySenderObject : public QObject { W_OBJECT(ConnectByNameNotifySenderObject) public: QList connectedSignals; QList disconnectedSignals; void clearNotifications() { connectedSignals.clear(); disconnectedSignals.clear(); } protected: void connectNotify(const QMetaMethod &signal) { connectedSignals.append(signal); } void disconnectNotify(const QMetaMethod &signal) { disconnectedSignals.append(signal); } Q_SIGNALS: void signal1() W_SIGNAL(signal1) }; class ConnectByNameNotifyReceiverObject : public QObject { W_OBJECT(ConnectByNameNotifyReceiverObject) void createNotifyChild(const char *name) { QObject *o = new ConnectByNameNotifySenderObject; o->setParent(this); o->setObjectName(QString::fromLatin1(name)); } public: ConnectByNameNotifyReceiverObject() { createNotifyChild("foo"); createNotifyChild("bar"); createNotifyChild("baz"); }; public Q_SLOTS: void on_foo_signal1() {} W_SLOT(on_foo_signal1) void on_bar_signal1() {} W_SLOT(on_bar_signal1) void on_baz_signal1() {} W_SLOT(on_baz_signal1) }; void tst_QObject::connectNotify_connectSlotsByName() { ConnectByNameNotifyReceiverObject testObject; QList senders = qFindChildren(&testObject); for (int i = 0; i < senders.size(); ++i) { ConnectByNameNotifySenderObject *o = senders.at(i); QVERIFY(o->connectedSignals.isEmpty()); QVERIFY(o->disconnectedSignals.isEmpty()); } QMetaObject::connectSlotsByName(&testObject); for (int i = 0; i < senders.size(); ++i) { ConnectByNameNotifySenderObject *o = senders.at(i); QCOMPARE(o->connectedSignals.size(), 1); QCOMPARE(o->connectedSignals.at(0), QMetaMethod::fromSignal(&ConnectByNameNotifySenderObject::signal1)); QVERIFY(o->disconnectedSignals.isEmpty()); } } class ConnectDisconnectNotifyShadowObject : public ConnectByNameNotifySenderObject { W_OBJECT(ConnectDisconnectNotifyShadowObject) public Q_SLOTS: void slot1() {} W_SLOT(slot1) Q_SIGNALS: void signal1() W_SIGNAL(signal1) }; void tst_QObject::connectDisconnectNotify_shadowing() { ConnectDisconnectNotifyShadowObject s; // Obtain QMetaMethods QMetaMethod shadowedSignal1 = QMetaMethod::fromSignal(&ConnectByNameNotifySenderObject::signal1); QMetaMethod redefinedSignal1 = QMetaMethod::fromSignal(&ConnectDisconnectNotifyShadowObject::signal1); QVERIFY(shadowedSignal1 != redefinedSignal1); int slot1Index = s.metaObject()->indexOfSlot("slot1()"); QVERIFY(slot1Index != -1); QMetaMethod slot1 = s.metaObject()->method(slot1Index); // Test connectNotify #ifndef QT_NO_DEBUG const char *warning = "QMetaObject::indexOfSignal: signal signal1() from " "ConnectByNameNotifySenderObject redefined in " "ConnectDisconnectNotifyShadowObject"; QTest::ignoreMessage(QtWarningMsg, warning); #endif QVERIFY(QObject::connect(&s, SIGNAL(signal1()), &s, SLOT(slot1()))); QCOMPARE(s.connectedSignals.size(), 1); QCOMPARE(s.connectedSignals.at(0), redefinedSignal1); QVERIFY(s.disconnectedSignals.isEmpty()); // Test disconnectNotify #ifndef QT_NO_DEBUG QTest::ignoreMessage(QtWarningMsg, warning); #endif QVERIFY(QObject::disconnect(&s, SIGNAL(signal1()), &s, SLOT(slot1()))); QCOMPARE(s.disconnectedSignals.size(), 1); QCOMPARE(s.disconnectedSignals.at(0), redefinedSignal1); QCOMPARE(s.connectedSignals.size(), 1); // Test connectNotify when connecting by shadowed QMetaMethod s.clearNotifications(); QVERIFY(QObject::connect(&s, shadowedSignal1, &s, slot1)); QCOMPARE(s.connectedSignals.size(), 1); QCOMPARE(s.connectedSignals.at(0), shadowedSignal1); QVERIFY(s.disconnectedSignals.isEmpty()); // Test disconnectNotify when disconnecting by shadowed QMetaMethod QVERIFY(QObject::disconnect(&s, shadowedSignal1, &s, slot1)); QCOMPARE(s.disconnectedSignals.size(), 1); QCOMPARE(s.disconnectedSignals.at(0), shadowedSignal1); QCOMPARE(s.connectedSignals.size(), 1); // Test connectNotify when connecting by redefined QMetaMethod s.clearNotifications(); QVERIFY(QObject::connect(&s, redefinedSignal1, &s, slot1)); QCOMPARE(s.connectedSignals.size(), 1); QCOMPARE(s.connectedSignals.at(0), redefinedSignal1); QVERIFY(s.disconnectedSignals.isEmpty()); // Test disconnectNotify when disconnecting by redefined QMetaMethod QVERIFY(QObject::disconnect(&s, redefinedSignal1, &s, slot1)); QCOMPARE(s.disconnectedSignals.size(), 1); QCOMPARE(s.disconnectedSignals.at(0), redefinedSignal1); QCOMPARE(s.connectedSignals.size(), 1); } class SequenceObject : public ReceiverObject { W_OBJECT(SequenceObject) public: QObject *next; SequenceObject() : next(0) { } public slots: void slot1_disconnectThis() { slot1(); disconnect(sender(), SIGNAL(signal1()), this, SLOT(slot1_disconnectThis())); } W_SLOT(slot1_disconnectThis) void slot2_reconnectThis() { slot2(); const QObject *s = sender(); disconnect(s, SIGNAL(signal1()), this, SLOT(slot2_reconnectThis())); connect(s, SIGNAL(signal1()), this, SLOT(slot2_reconnectThis())); } W_SLOT(slot2_reconnectThis) void slot1_disconnectNext() { slot1(); disconnect(sender(), SIGNAL(signal1()), next, SLOT(slot1())); } W_SLOT(slot1_disconnectNext) void slot2_reconnectNext() { slot2(); // modify the connection list in 'this' disconnect(sender(), SIGNAL(signal1()), next, SLOT(slot2())); connect(sender(), SIGNAL(signal1()), next, SLOT(slot2())); // modify the sender list in 'this' connect(next, SIGNAL(destroyed()), this, SLOT(deleteLater())); connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(deleteLater())); disconnect(next, SIGNAL(destroyed()), this, SLOT(deleteLater())); disconnect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(deleteLater())); } W_SLOT(slot2_reconnectNext) void slot1_deleteNext() { slot1(); delete next; } W_SLOT(slot1_deleteNext) void slot2_deleteSender() { slot2(); delete sender(); } W_SLOT(slot2_deleteSender) }; void tst_QObject::emitInDefinedOrder() { SenderObject sender; ReceiverObject receiver1, receiver2, receiver3, receiver4; connect(&sender, SIGNAL(signal1()), &receiver1, SLOT(slot1())); connect(&sender, SIGNAL(signal1()), &receiver2, SLOT(slot1())); connect(&sender, SIGNAL(signal1()), &receiver3, SLOT(slot1())); connect(&sender, SIGNAL(signal1()), &receiver4, SLOT(slot1())); connect(&sender, SIGNAL(signal1()), &receiver1, SLOT(slot2())); connect(&sender, SIGNAL(signal1()), &receiver2, SLOT(slot2())); connect(&sender, SIGNAL(signal1()), &receiver3, SLOT(slot2())); connect(&sender, SIGNAL(signal1()), &receiver4, SLOT(slot2())); int sequence; ReceiverObject::sequence = sequence = 0; sender.emitSignal1(); QCOMPARE(receiver1.sequence_slot1, ++sequence); QCOMPARE(receiver2.sequence_slot1, ++sequence); QCOMPARE(receiver3.sequence_slot1, ++sequence); QCOMPARE(receiver4.sequence_slot1, ++sequence); QCOMPARE(receiver1.sequence_slot2, ++sequence); QCOMPARE(receiver2.sequence_slot2, ++sequence); QCOMPARE(receiver3.sequence_slot2, ++sequence); QCOMPARE(receiver4.sequence_slot2, ++sequence); QObject::disconnect(&sender, SIGNAL(signal1()), &receiver2, SLOT(slot1())); connect(&sender, SIGNAL(signal1()), &receiver2, SLOT(slot1())); ReceiverObject::sequence = sequence = 0; sender.emitSignal1(); QCOMPARE(receiver1.sequence_slot1, ++sequence); QCOMPARE(receiver3.sequence_slot1, ++sequence); QCOMPARE(receiver4.sequence_slot1, ++sequence); QCOMPARE(receiver1.sequence_slot2, ++sequence); QCOMPARE(receiver2.sequence_slot2, ++sequence); QCOMPARE(receiver3.sequence_slot2, ++sequence); QCOMPARE(receiver4.sequence_slot2, ++sequence); QCOMPARE(receiver2.sequence_slot1, ++sequence); QObject::disconnect(&sender, SIGNAL(signal1()), &receiver1, SLOT(slot1())); connect(&sender, SIGNAL(signal1()), &receiver1, SLOT(slot1())); ReceiverObject::sequence = sequence = 0; sender.emitSignal1(); QCOMPARE(receiver3.sequence_slot1, ++sequence); QCOMPARE(receiver4.sequence_slot1, ++sequence); QCOMPARE(receiver1.sequence_slot2, ++sequence); QCOMPARE(receiver2.sequence_slot2, ++sequence); QCOMPARE(receiver3.sequence_slot2, ++sequence); QCOMPARE(receiver4.sequence_slot2, ++sequence); QCOMPARE(receiver2.sequence_slot1, ++sequence); QCOMPARE(receiver1.sequence_slot1, ++sequence); // ensure emission order even if the connections change during emission SenderObject *sender2 = new SenderObject; SequenceObject seq1, seq2, *seq3 = new SequenceObject, seq4; seq1.next = &seq2; seq2.next = seq3; seq3->next = &seq4; // try 1 connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot1_disconnectThis())); connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot1_disconnectNext())); connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot1())); connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot1())); connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot2_reconnectThis())); connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot2_reconnectNext())); connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot2())); connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot2())); SequenceObject::sequence = sequence = 0; sender2->emitSignal1(); QVERIFY(seq1.called(1)); QVERIFY(seq2.called(1)); QVERIFY(!seq3->called(1)); QVERIFY(seq4.called(1)); QVERIFY(seq1.called(2)); QVERIFY(seq2.called(2)); QVERIFY(!seq3->called(2)); QVERIFY(seq4.called(2)); QCOMPARE(seq1.sequence_slot1, ++sequence); QCOMPARE(seq2.sequence_slot1, ++sequence); QCOMPARE(seq4.sequence_slot1, ++sequence); QCOMPARE(seq1.sequence_slot2, ++sequence); QCOMPARE(seq2.sequence_slot2, ++sequence); QCOMPARE(seq4.sequence_slot2, ++sequence); QObject::disconnect(sender2, 0, &seq1, 0); QObject::disconnect(sender2, 0, &seq2, 0); QObject::disconnect(sender2, 0, seq3, 0); QObject::disconnect(sender2, 0, &seq4, 0); seq1.reset(); seq2.reset(); seq3->reset(); seq4.reset(); // try 2 connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot2_reconnectThis())); connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot2_reconnectNext())); connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot2())); connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot2())); connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot1_disconnectThis())); connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot1_disconnectNext())); connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot1())); connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot1())); SequenceObject::sequence = sequence = 0; sender2->emitSignal1(); QVERIFY(seq1.called(2)); QVERIFY(seq2.called(2)); QVERIFY(!seq3->called(2)); QVERIFY(seq4.called(2)); QVERIFY(seq1.called(1)); QVERIFY(seq2.called(1)); QVERIFY(!seq3->called(1)); QVERIFY(seq4.called(1)); QCOMPARE(seq1.sequence_slot2, ++sequence); QCOMPARE(seq2.sequence_slot2, ++sequence); QCOMPARE(seq4.sequence_slot2, ++sequence); QCOMPARE(seq1.sequence_slot1, ++sequence); QCOMPARE(seq2.sequence_slot1, ++sequence); QCOMPARE(seq4.sequence_slot1, ++sequence); QObject::disconnect(sender2, 0, &seq1, 0); QObject::disconnect(sender2, 0, &seq2, 0); QObject::disconnect(sender2, 0, seq3, 0); QObject::disconnect(sender2, 0, &seq4, 0); seq1.reset(); seq2.reset(); seq3->reset(); seq4.reset(); // try 3 connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot1())); connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot1_disconnectNext())); connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot1())); connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot1())); connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot2())); connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot2_reconnectNext())); connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot2())); connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot2())); SequenceObject::sequence = sequence = 0; sender2->emitSignal1(); QVERIFY(seq1.called(1)); QVERIFY(seq2.called(1)); QVERIFY(!seq3->called(1)); QVERIFY(seq4.called(1)); QVERIFY(seq1.called(2)); QVERIFY(seq2.called(2)); QVERIFY(!seq3->called(2)); QVERIFY(seq4.called(2)); QCOMPARE(seq1.sequence_slot1, ++sequence); QCOMPARE(seq2.sequence_slot1, ++sequence); QCOMPARE(seq4.sequence_slot1, ++sequence); QCOMPARE(seq1.sequence_slot2, ++sequence); QCOMPARE(seq2.sequence_slot2, ++sequence); QCOMPARE(seq4.sequence_slot2, ++sequence); // ensure emission order even if objects are destroyed during emission QObject::disconnect(sender2, 0, &seq1, 0); QObject::disconnect(sender2, 0, &seq2, 0); QObject::disconnect(sender2, 0, seq3, 0); QObject::disconnect(sender2, 0, &seq4, 0); seq1.reset(); seq2.reset(); seq3->reset(); seq4.reset(); connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot1())); connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot1_deleteNext())); connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot1())); connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot1())); connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot2())); connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot2_deleteSender())); connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot2())); connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot2())); QPointer psender = sender2; QPointer pseq3 = seq3; SequenceObject::sequence = sequence = 0; sender2->emitSignal1(); QCOMPARE(static_cast(psender), static_cast(0)); QCOMPARE(static_cast(pseq3), static_cast(0)); QVERIFY(seq1.called(1)); QVERIFY(seq2.called(1)); QVERIFY(seq4.called(1)); QVERIFY(seq1.called(2)); QVERIFY(seq2.called(2)); QVERIFY(!seq4.called(2)); QCOMPARE(seq1.sequence_slot1, ++sequence); QCOMPARE(seq2.sequence_slot1, ++sequence); QCOMPARE(seq4.sequence_slot1, ++sequence); QCOMPARE(seq1.sequence_slot2, ++sequence); QCOMPARE(seq2.sequence_slot2, ++sequence); QPointer psender3 = new SenderObject; connect(psender3, SIGNAL(signal1()), psender3, SIGNAL(signal2())); connect(psender3, SIGNAL(signal2()), &seq1, SLOT(slot2_deleteSender())); psender3->emitSignal1(); QVERIFY(!psender3); } static int instanceCount = 0; struct CheckInstanceCount { const int saved; CheckInstanceCount() : saved(instanceCount) {} ~CheckInstanceCount() { QCOMPARE(saved, instanceCount); } }; struct CustomType { CustomType(int l1 = 0, int l2 = 0, int l3 = 0): i1(l1), i2(l2), i3(l3) { ++instanceCount; playWithObjects(); } CustomType(const CustomType &other): i1(other.i1), i2(other.i2), i3(other.i3) { ++instanceCount; playWithObjects(); } ~CustomType() { --instanceCount; playWithObjects(); } int i1, i2, i3; int value() { return i1 + i2 + i3; } }; Q_DECLARE_METATYPE(CustomType*) W_REGISTER_ARGTYPE(CustomType*) Q_DECLARE_METATYPE(CustomType) W_REGISTER_ARGTYPE(CustomType) W_REGISTER_ARGTYPE(QList) class QCustomTypeChecker: public QObject { W_OBJECT(QCustomTypeChecker) public: QCustomTypeChecker(QObject *parent = 0): QObject(parent) {} void doEmit(CustomType ct) { emit signal1(ct); } public slots: void slot1(CustomType ct); W_SLOT(slot1) void slot2(const QList &ct); W_SLOT(slot2) signals: void signal1(CustomType ct) W_SIGNAL(signal1,ct) void signal2(const QList &ct) W_SIGNAL(signal2,ct) public: CustomType received; }; void QCustomTypeChecker::slot1(CustomType ct) { received = ct; } void QCustomTypeChecker::slot2(const QList< CustomType >& ct) { received = ct[0]; } void tst_QObject::customTypes() { CustomType t0; CustomType t1(1, 2, 3); CustomType t2(2, 3, 4); { QCustomTypeChecker checker; QCOMPARE(instanceCount, 4); connect(&checker, SIGNAL(signal1(CustomType)), &checker, SLOT(slot1(CustomType)), Qt::DirectConnection); QCOMPARE(checker.received.value(), 0); checker.doEmit(t1); QCOMPARE(checker.received.value(), t1.value()); checker.received = t0; int idx = qRegisterMetaType("CustomType"); QCOMPARE(QMetaType::type("CustomType"), idx); checker.disconnect(); connect(&checker, SIGNAL(signal1(CustomType)), &checker, SLOT(slot1(CustomType)), Qt::QueuedConnection); QCOMPARE(instanceCount, 4); checker.doEmit(t2); QCOMPARE(instanceCount, 5); QCOMPARE(checker.received.value(), t0.value()); QCoreApplication::processEvents(); QCOMPARE(checker.received.value(), t2.value()); QCOMPARE(instanceCount, 4); QVERIFY(QMetaType::isRegistered(idx)); QCOMPARE(qRegisterMetaType("CustomType"), idx); QCOMPARE(QMetaType::type("CustomType"), idx); QVERIFY(QMetaType::isRegistered(idx)); } QCOMPARE(instanceCount, 3); } QDataStream &operator<<(QDataStream &stream, const CustomType &ct) { stream << ct.i1 << ct.i2 << ct.i3; return stream; } QDataStream &operator>>(QDataStream &stream, CustomType &ct) { stream >> ct.i1; stream >> ct.i2; stream >> ct.i3; return stream; } void tst_QObject::streamCustomTypes() { QByteArray ba; int idx = qRegisterMetaType("CustomType"); qRegisterMetaTypeStreamOperators("CustomType"); { CustomType t1(1, 2, 3); QCOMPARE(instanceCount, 1); QDataStream stream(&ba, (QIODevice::OpenMode)QIODevice::WriteOnly); QMetaType::save(stream, idx, &t1); } QCOMPARE(instanceCount, 0); { CustomType t2; QCOMPARE(instanceCount, 1); QDataStream stream(&ba, (QIODevice::OpenMode)QIODevice::ReadOnly); QMetaType::load(stream, idx, &t2); QCOMPARE(instanceCount, 1); QCOMPARE(t2.i1, 1); QCOMPARE(t2.i2, 2); QCOMPARE(t2.i3, 3); } QCOMPARE(instanceCount, 0); } typedef QString CustomString; class PropertyObject : public QObject { W_OBJECT(PropertyObject) public: enum Alpha { Alpha0, Alpha1, Alpha2 }; enum Priority { High, Low, VeryHigh, VeryLow }; PropertyObject() : m_alpha(Alpha0), m_priority(High), m_number(0), m_custom(0), m_float(42) {} Alpha alpha() const { return m_alpha; } void setAlpha(Alpha alpha) { m_alpha = alpha; } Priority priority() const { return m_priority; } void setPriority(Priority priority) { m_priority = priority; } int number() const { return m_number; } void setNumber(int number) { m_number = number; } QString string() const { return m_string; } void setString(const QString &string) { m_string = string; } QVariant variant() const { return m_variant; } void setVariant(const QVariant &variant) { m_variant = variant; } CustomType *custom() const { return m_custom; } void setCustom(CustomType *custom) { m_custom = custom; } void setMyFloat(float value) { m_float = value; } inline float myFloat() const { return m_float; } void setMyQReal(qreal value) { m_qreal = value; } qreal myQReal() const { return m_qreal; } CustomString customString() const { return m_customString; } void setCustomString(const QString &string) { m_customString = string; } private: Alpha m_alpha; Priority m_priority; int m_number; QString m_string; QVariant m_variant; CustomType *m_custom; float m_float; qreal m_qreal; CustomString m_customString; W_ENUM(Alpha, Alpha0, Alpha1, Alpha2) W_ENUM(Priority, High, Low, VeryHigh, VeryLow) W_PROPERTY(Alpha, alpha READ alpha WRITE setAlpha) W_PROPERTY(Priority, priority READ priority WRITE setPriority) W_PROPERTY(int, number READ number WRITE setNumber) W_PROPERTY(QString, string READ string WRITE setString) W_PROPERTY(QVariant, variant READ variant WRITE setVariant) W_PROPERTY(CustomType*, custom READ custom WRITE setCustom) W_PROPERTY(float, myFloat READ myFloat WRITE setMyFloat) W_PROPERTY(qreal, myQReal READ myQReal WRITE setMyQReal) W_PROPERTY(CustomString, customString READ customString WRITE setCustomString ) }; Q_DECLARE_METATYPE(PropertyObject::Priority) void tst_QObject::threadSignalEmissionCrash() { int loopCount = 1000; for (int i = 0; i < loopCount; ++i) { QTcpSocket socket; socket.connectToHost("localhost", 80); } } class TestThread : public QThread { W_OBJECT(TestThread) public: inline void run() { *object = new QObject; *child = new QObject(*object); mutex.lock(); cond.wakeOne(); cond.wait(&mutex); mutex.unlock(); } QObject **object, **child; QMutex mutex; QWaitCondition cond; }; void tst_QObject::thread() { QThread *currentThread = QThread::currentThread(); // the current thread is the same as the QApplication // thread... see tst_QApplication::thread() { QObject object; // thread affinity for objects with no parent should be the // current thread QVERIFY(object.thread() != 0); QCOMPARE(object.thread(), currentThread); // children inherit their parent's thread QObject child(&object); QCOMPARE(child.thread(), object.thread()); } QObject *object = 0; QObject *child = 0; { TestThread thr; QVERIFY(thr.thread() != 0); QCOMPARE(thr.thread(), currentThread); thr.object = &object; thr.child = &child; thr.mutex.lock(); thr.start(); thr.cond.wait(&thr.mutex); // thread affinity for an object with no parent should be the // thread in which the object was created QCOMPARE(object->thread(), (QThread *)&thr); // children inherit their parent's thread QCOMPARE(child->thread(), object->thread()); thr.cond.wakeOne(); thr.mutex.unlock(); thr.wait(); // even though the thread is no longer running, the affinity // should not change QCOMPARE(object->thread(), (QThread *)&thr); QCOMPARE(child->thread(), object->thread()); } // the thread has been destroyed, thread affinity should // automatically reset to no thread QCOMPARE(object->thread(), (QThread *)0); QCOMPARE(child->thread(), object->thread()); delete object; } class MoveToThreadObject : public QObject { W_OBJECT(MoveToThreadObject) public: QThread *timerEventThread; QThread *customEventThread; QThread *slotThread; MoveToThreadObject(QObject *parent = 0) : QObject(parent), timerEventThread(0), customEventThread(0), slotThread(0) { } void customEvent(QEvent *) { if (customEventThread) qFatal("%s: customEventThread should be null", Q_FUNC_INFO); customEventThread = QThread::currentThread(); emit theSignal(); } void timerEvent(QTimerEvent *) { if (timerEventThread) qFatal("%s: timerEventThread should be null", Q_FUNC_INFO); timerEventThread = QThread::currentThread(); emit theSignal(); } public slots: void theSlot() { if (slotThread) qFatal("%s: slotThread should be null", Q_FUNC_INFO); slotThread = QThread::currentThread(); emit theSignal(); } W_SLOT(theSlot) signals: void theSignal() W_SIGNAL(theSignal) }; class MoveToThreadThread : public QThread { public: ~MoveToThreadThread() { if (isRunning()) { terminate(); wait(); } } void start() { QEventLoop eventLoop; connect(this, SIGNAL(started()), &eventLoop, SLOT(quit()), Qt::QueuedConnection); QThread::start(); // wait for thread to start (void) eventLoop.exec(); } void run() { (void) exec(); } }; void tst_QObject::thread0() { QObject *object = new QObject; object->moveToThread(0); QObject *child = new QObject(object); QCOMPARE(child->parent(), object); QCOMPARE(child->thread(), (QThread *)0); #if 0 // We don't support moving children into a parent that has no thread // affinity (yet?). QObject *child2 = new QObject; child2->moveToThread(0); child2->setParent(object); QCOMPARE(child2->parent(), object); QCOMPARE(child2->thread(), (QThread *)0); #endif delete object; } void tst_QObject::moveToThread() { QThread *currentThread = QThread::currentThread(); { QObject *object = new QObject; QObject *child = new QObject(object); QCOMPARE(object->thread(), currentThread); QCOMPARE(child->thread(), currentThread); object->moveToThread(0); QCOMPARE(object->thread(), (QThread *)0); QCOMPARE(child->thread(), (QThread *)0); object->moveToThread(currentThread); QCOMPARE(object->thread(), currentThread); QCOMPARE(child->thread(), currentThread); object->moveToThread(0); QCOMPARE(object->thread(), (QThread *)0); QCOMPARE(child->thread(), (QThread *)0); // can delete an object with no thread anywhere delete object; } { MoveToThreadThread thread; thread.start(); QObject *object = new QObject; QObject *child = new QObject(object); QPointer opointer = object; QPointer cpointer = object; QCOMPARE(object->thread(), currentThread); QCOMPARE(child->thread(), currentThread); object->moveToThread(&thread); QCOMPARE(object->thread(), (QThread *)&thread); QCOMPARE(child->thread(), (QThread *)&thread); connect(object, SIGNAL(destroyed()), &thread, SLOT(quit()), Qt::DirectConnection); QMetaObject::invokeMethod(object, "deleteLater", Qt::QueuedConnection); thread.wait(); QVERIFY(opointer == 0); QVERIFY(cpointer == 0); } { // make sure posted events are moved with the object MoveToThreadThread thread; thread.start(); MoveToThreadObject *object = new MoveToThreadObject; MoveToThreadObject *child = new MoveToThreadObject(object); connect(object, SIGNAL(theSignal()), &thread, SLOT(quit()), Qt::DirectConnection); QCoreApplication::postEvent(child, new QEvent(QEvent::User)); QCoreApplication::postEvent(object, new QEvent(QEvent::User)); QCOMPARE(object->thread(), currentThread); QCOMPARE(child->thread(), currentThread); object->moveToThread(&thread); QCOMPARE(object->thread(), (QThread *)&thread); QCOMPARE(child->thread(), (QThread *)&thread); thread.wait(); QCOMPARE(object->customEventThread, (QThread *)&thread); QCOMPARE(child->customEventThread, (QThread *)&thread); thread.start(); connect(object, SIGNAL(destroyed()), &thread, SLOT(quit()), Qt::DirectConnection); QMetaObject::invokeMethod(object, "deleteLater", Qt::QueuedConnection); thread.wait(); } { // make sure timers are moved with the object MoveToThreadThread thread; thread.start(); MoveToThreadObject *object = new MoveToThreadObject; MoveToThreadObject *child = new MoveToThreadObject(object); connect(object, SIGNAL(theSignal()), &thread, SLOT(quit()), Qt::DirectConnection); child->startTimer(90); object->startTimer(100); QCOMPARE(object->thread(), currentThread); QCOMPARE(child->thread(), currentThread); object->moveToThread(&thread); QCOMPARE(object->thread(), (QThread *)&thread); QCOMPARE(child->thread(), (QThread *)&thread); thread.wait(); QCOMPARE(object->timerEventThread, (QThread *)&thread); QCOMPARE(child->timerEventThread, (QThread *)&thread); thread.start(); connect(object, SIGNAL(destroyed()), &thread, SLOT(quit()), Qt::DirectConnection); QMetaObject::invokeMethod(object, "deleteLater", Qt::QueuedConnection); thread.wait(); } // WinRT does not allow connection to localhost #ifndef Q_OS_WINRT { // make sure socket notifiers are moved with the object MoveToThreadThread thread; thread.start(); QTcpServer server; QVERIFY(server.listen(QHostAddress::LocalHost, 0)); QTcpSocket *socket = new QTcpSocket; MoveToThreadObject *child = new MoveToThreadObject(socket); connect(socket, SIGNAL(disconnected()), child, SLOT(theSlot()), Qt::DirectConnection); connect(child, SIGNAL(theSignal()), &thread, SLOT(quit()), Qt::DirectConnection); socket->connectToHost(server.serverAddress(), server.serverPort()); QVERIFY(server.waitForNewConnection(1000)); QTcpSocket *serverSocket = server.nextPendingConnection(); QVERIFY(serverSocket); socket->waitForConnected(); QCOMPARE(socket->thread(), currentThread); socket->moveToThread(&thread); QCOMPARE(socket->thread(), (QThread *)&thread); serverSocket->close(); QVERIFY(thread.wait(10000)); QCOMPARE(child->slotThread, (QThread *)&thread); thread.start(); connect(socket, SIGNAL(destroyed()), &thread, SLOT(quit()), Qt::DirectConnection); QMetaObject::invokeMethod(socket, "deleteLater", Qt::QueuedConnection); thread.wait(); } #endif } void tst_QObject::property() { PropertyObject object; const QMetaObject *mo = object.metaObject(); QMetaProperty property; QVERIFY(mo); QVERIFY(mo->indexOfProperty("alpha") != -1); property = mo->property(mo->indexOfProperty("alpha")); QVERIFY(property.isEnumType()); QCOMPARE(property.typeName(), "Alpha"); QCOMPARE(property.type(), QVariant::Int); QVariant var = object.property("alpha"); QVERIFY(!var.isNull()); QCOMPARE(var.toInt(), int(PropertyObject::Alpha0)); object.setAlpha(PropertyObject::Alpha1); QCOMPARE(object.property("alpha").toInt(), int(PropertyObject::Alpha1)); QVERIFY(object.setProperty("alpha", PropertyObject::Alpha2)); QCOMPARE(object.property("alpha").toInt(), int(PropertyObject::Alpha2)); QVERIFY(object.setProperty("alpha", "Alpha1")); QCOMPARE(object.property("alpha").toInt(), int(PropertyObject::Alpha1)); QVERIFY(!object.setProperty("alpha", QVariant())); QVERIFY(mo->indexOfProperty("number") != -1); QCOMPARE(object.property("number").toInt(), 0); object.setNumber(24); QCOMPARE(object.property("number"), QVariant(24)); QVERIFY(object.setProperty("number", 12)); QCOMPARE(object.property("number"), QVariant(12)); QVERIFY(object.setProperty("number", "42")); QCOMPARE(object.property("number"), QVariant(42)); QVERIFY(mo->indexOfProperty("string") != -1); QCOMPARE(object.property("string").toString(), QString()); object.setString("String1"); QCOMPARE(object.property("string"), QVariant("String1")); QVERIFY(object.setProperty("string", "String2")); QCOMPARE(object.property("string"), QVariant("String2")); if (qVersion() < QByteArray("5.6.0")) QSKIP("this tests bugs in 5.5"); QVERIFY(object.setProperty("string", QVariant())); const int idx = mo->indexOfProperty("variant"); QVERIFY(idx != -1); QCOMPARE(QMetaType::Type(mo->property(idx).type()), QMetaType::QVariant); QCOMPARE(object.property("variant"), QVariant()); QVariant variant1(42); QVariant variant2("string"); object.setVariant(variant1); QCOMPARE(object.property("variant"), variant1); QVERIFY(object.setProperty("variant", variant2)); QCOMPARE(object.variant(), QVariant(variant2)); QCOMPARE(object.property("variant"), variant2); QVERIFY(object.setProperty("variant", QVariant())); QCOMPARE(object.property("variant"), QVariant()); QVERIFY(mo->indexOfProperty("custom") != -1); property = mo->property(mo->indexOfProperty("custom")); QVERIFY(property.isValid()); QVERIFY(property.isWritable()); QVERIFY(!property.isEnumType()); QCOMPARE(property.typeName(), "CustomType*"); qRegisterMetaType(); QCOMPARE(property.type(), QVariant::UserType); QCOMPARE(property.userType(), qMetaTypeId()); CustomType *customPointer = 0; QVariant customVariant = object.property("custom"); customPointer = qvariant_cast(customVariant); QCOMPARE(customPointer, object.custom()); CustomType custom; customPointer = &custom; customVariant.setValue(customPointer); property = mo->property(mo->indexOfProperty("custom")); QVERIFY(property.isWritable()); QCOMPARE(property.typeName(), "CustomType*"); QCOMPARE(property.type(), QVariant::UserType); QCOMPARE(property.userType(), qMetaTypeId()); QVERIFY(object.setProperty("custom", customVariant)); QCOMPARE(object.custom(), customPointer); customVariant = object.property("custom"); customPointer = qvariant_cast(customVariant); QCOMPARE(object.custom(), customPointer); // this enum property has a meta type, but it's not yet registered, so we know this fails QVERIFY(mo->indexOfProperty("priority") != -1); property = mo->property(mo->indexOfProperty("priority")); QVERIFY(property.isEnumType()); QCOMPARE(property.typeName(), "Priority"); QCOMPARE(property.type(), QVariant::Int); var = object.property("priority"); QVERIFY(!var.isNull()); QCOMPARE(var.toInt(), int(PropertyObject::High)); object.setPriority(PropertyObject::Low); QCOMPARE(object.property("priority").toInt(), int(PropertyObject::Low)); QVERIFY(object.setProperty("priority", PropertyObject::VeryHigh)); QCOMPARE(object.property("priority").toInt(), int(PropertyObject::VeryHigh)); QVERIFY(object.setProperty("priority", "High")); QCOMPARE(object.property("priority").toInt(), int(PropertyObject::High)); QVERIFY(!object.setProperty("priority", QVariant())); // now it's registered, so it works as expected int priorityMetaTypeId = qRegisterMetaType("PropertyObject::Priority"); QVERIFY(mo->indexOfProperty("priority") != -1); property = mo->property(mo->indexOfProperty("priority")); QVERIFY(property.isEnumType()); QCOMPARE(property.typeName(), "Priority"); QCOMPARE(property.type(), QVariant::UserType); QCOMPARE(property.userType(), priorityMetaTypeId); var = object.property("priority"); QVERIFY(!var.isNull()); QVERIFY(var.canConvert()); QCOMPARE(qvariant_cast(var), PropertyObject::High); object.setPriority(PropertyObject::Low); QCOMPARE(qvariant_cast(object.property("priority")), PropertyObject::Low); QVERIFY(object.setProperty("priority", PropertyObject::VeryHigh)); QCOMPARE(qvariant_cast(object.property("priority")), PropertyObject::VeryHigh); QVERIFY(object.setProperty("priority", "High")); QCOMPARE(qvariant_cast(object.property("priority")), PropertyObject::High); QVERIFY(!object.setProperty("priority", QVariant())); var = object.property("priority"); QCOMPARE(qvariant_cast(var), PropertyObject::High); object.setPriority(PropertyObject::Low); QCOMPARE(qvariant_cast(object.property("priority")), PropertyObject::Low); object.setProperty("priority", var); QCOMPARE(qvariant_cast(object.property("priority")), PropertyObject::High); qRegisterMetaType("CustomString"); QVERIFY(mo->indexOfProperty("customString") != -1); QCOMPARE(object.property("customString").toString(), QString()); object.setCustomString("String1"); QCOMPARE(object.property("customString"), QVariant("String1")); QVERIFY(object.setProperty("customString", "String2")); QCOMPARE(object.property("customString"), QVariant("String2")); QVERIFY(object.setProperty("customString", QVariant())); } void tst_QObject::metamethod() { SenderObject obj; const QMetaObject *mobj = obj.metaObject(); QMetaMethod m; m = mobj->method(mobj->indexOfMethod("invoke1()")); QVERIFY(m.methodSignature() == "invoke1()"); QCOMPARE(m.methodType(), QMetaMethod::Method); QCOMPARE(m.access(), QMetaMethod::Public); QVERIFY(!(m.attributes() & QMetaMethod::Scriptable)); QVERIFY(!(m.attributes() & QMetaMethod::Compatibility)); m = mobj->method(mobj->indexOfMethod("sinvoke1()")); QVERIFY(m.methodSignature() == "sinvoke1()"); QCOMPARE(m.methodType(), QMetaMethod::Method); QCOMPARE(m.access(), QMetaMethod::Public); QVERIFY((m.attributes() & QMetaMethod::Scriptable)); QVERIFY(!(m.attributes() & QMetaMethod::Compatibility)); m = mobj->method(mobj->indexOfMethod("invoke2()")); QVERIFY(m.methodSignature() == "invoke2()"); QCOMPARE(m.methodType(), QMetaMethod::Method); QCOMPARE(m.access(), QMetaMethod::Protected); QVERIFY(!(m.attributes() & QMetaMethod::Scriptable)); QVERIFY((m.attributes() & QMetaMethod::Compatibility)); m = mobj->method(mobj->indexOfMethod("sinvoke2()")); QVERIFY(m.methodSignature() == "sinvoke2()"); QCOMPARE(m.methodType(), QMetaMethod::Method); QCOMPARE(m.access(), QMetaMethod::Protected); QVERIFY((m.attributes() & QMetaMethod::Scriptable)); QVERIFY((m.attributes() & QMetaMethod::Compatibility)); m = mobj->method(mobj->indexOfMethod("invoke3(int,int)")); // ### Default value are not supported by W_INVOKABLE QVERIFY(m.methodSignature() == "invoke3(int,int)"); QCOMPARE(m.methodType(), QMetaMethod::Method); QCOMPARE(m.access(), QMetaMethod::Private); QVERIFY(!(m.attributes() & QMetaMethod::Scriptable)); QVERIFY(!(m.attributes() & QMetaMethod::Compatibility)); m = mobj->method(mobj->indexOfMethod("sinvoke3()")); QVERIFY(m.methodSignature() == "sinvoke3()"); QCOMPARE(m.methodType(), QMetaMethod::Method); QCOMPARE(m.access(), QMetaMethod::Private); QVERIFY((m.attributes() & QMetaMethod::Scriptable)); QVERIFY(!(m.attributes() & QMetaMethod::Compatibility)); m = mobj->method(mobj->indexOfMethod("signal5()")); QVERIFY(m.methodSignature() == "signal5()"); QCOMPARE(m.methodType(), QMetaMethod::Signal); QCOMPARE(m.access(), QMetaMethod::Public); QVERIFY(!(m.attributes() & QMetaMethod::Scriptable)); QVERIFY((m.attributes() & QMetaMethod::Compatibility)); m = mobj->method(mobj->indexOfMethod("aPublicSlot()")); QVERIFY(m.methodSignature() == "aPublicSlot()"); QCOMPARE(m.methodType(), QMetaMethod::Slot); QCOMPARE(m.access(), QMetaMethod::Public); QVERIFY(!(m.attributes() & QMetaMethod::Scriptable)); QVERIFY(!(m.attributes() & QMetaMethod::Compatibility)); m = mobj->method(mobj->indexOfMethod("invoke1()")); QCOMPARE(m.parameterNames().count(), 0); QCOMPARE(m.parameterTypes().count(), 0); m = mobj->method(mobj->indexOfMethod("invoke2(int)")); QCOMPARE(m.parameterNames().count(), 1); QCOMPARE(m.parameterTypes().count(), 1); QCOMPARE(m.parameterTypes().at(0), QByteArray("int")); QVERIFY(m.parameterNames().at(0).isEmpty()); m = mobj->method(mobj->indexOfMethod("invoke3(int,int)")); QCOMPARE(m.parameterNames().count(), 2); QCOMPARE(m.parameterTypes().count(), 2); QCOMPARE(m.parameterTypes().at(0), QByteArray("int")); //QCOMPARE(m.parameterNames().at(0), QByteArray("hinz")); // ### parameterNames not supported QCOMPARE(m.parameterTypes().at(1), QByteArray("int")); //QCOMPARE(m.parameterNames().at(1), QByteArray("kunz")); } namespace QObjectTest { class TestObject: public QObject { W_OBJECT(TestObject) public: TestObject(): QObject(), i(0) {} void doEmit() { emit aSignal(); } int i; public slots: void aSlot() { ++i; } W_SLOT(aSlot) signals: void aSignal() W_SIGNAL(aSignal) }; } void tst_QObject::namespaces() { QObjectTest::TestObject obj; QVERIFY(connect(&obj, SIGNAL(aSignal()), &obj, SLOT(aSlot()))); obj.doEmit(); QCOMPARE(obj.i, 1); } class SuperObject : public QObject { W_OBJECT(SuperObject) public: QObject *theSender; int theSignalId; SuperObject() { theSender = 0; theSignalId = 0; } friend class tst_QObject; using QObject::sender; public slots: void rememberSender() { theSender = sender(); theSignalId = senderSignalIndex(); } W_SLOT(rememberSender) void deleteAndRememberSender() { delete theSender; rememberSender(); } W_SLOT(deleteAndRememberSender) signals: void anotherSignal() W_SIGNAL(anotherSignal) void theSignal() W_SIGNAL(theSignal) }; void tst_QObject::senderTest() { { SuperObject sender; SuperObject receiver; connect(&sender, SIGNAL(anotherSignal()), &receiver, SLOT(rememberSender())); connect(&sender, SIGNAL(theSignal()), &receiver, SLOT(rememberSender())); QCOMPARE(receiver.sender(), (QObject *)0); QCOMPARE(receiver.senderSignalIndex(), -1); emit sender.theSignal(); QCOMPARE(receiver.theSender, (QObject *)&sender); QCOMPARE(receiver.sender(), (QObject *)0); QCOMPARE(receiver.theSignalId, sender.metaObject()->indexOfSignal("theSignal()")); QCOMPARE(receiver.senderSignalIndex(), -1); emit sender.anotherSignal(); QCOMPARE(receiver.theSignalId, sender.metaObject()->indexOfSignal("anotherSignal()")); QCOMPARE(receiver.senderSignalIndex(), -1); } { SuperObject *sender = new SuperObject; SuperObject *receiver = new SuperObject; connect(sender, SIGNAL(theSignal()), receiver, SLOT(rememberSender()), Qt::BlockingQueuedConnection); QThread thread; receiver->moveToThread(&thread); connect(sender, SIGNAL(theSignal()), &thread, SLOT(quit()), Qt::DirectConnection); QCOMPARE(receiver->sender(), (QObject *)0); QCOMPARE(receiver->senderSignalIndex(), -1); receiver->theSender = 0; receiver->theSignalId = -1; thread.start(); emit sender->theSignal(); QCOMPARE(receiver->theSender, (QObject *) sender); QCOMPARE(receiver->sender(), (QObject *)0); QCOMPARE(receiver->theSignalId, sender->metaObject()->indexOfSignal("theSignal()")); QCOMPARE(receiver->senderSignalIndex(), -1); QVERIFY(thread.wait(10000)); delete receiver; delete sender; } { SuperObject *sender = new SuperObject; SuperObject receiver; connect(sender, SIGNAL(theSignal()), &receiver, SLOT(deleteAndRememberSender())); QCOMPARE(receiver.sender(), (QObject *)0); receiver.theSender = sender; emit sender->theSignal(); QCOMPARE(receiver.theSender, (QObject *)0); QCOMPARE(receiver.sender(), (QObject *)0); } { SuperObject *sender = new SuperObject; SuperObject *receiver = new SuperObject; connect(sender, SIGNAL(theSignal()), receiver, SLOT(deleteAndRememberSender()), Qt::BlockingQueuedConnection); QThread thread; receiver->moveToThread(&thread); connect(sender, SIGNAL(destroyed()), &thread, SLOT(quit()), Qt::DirectConnection); QCOMPARE(receiver->sender(), (QObject *)0); receiver->theSender = sender; thread.start(); emit sender->theSignal(); QCOMPARE(receiver->theSender, (QObject *)0); QCOMPARE(receiver->sender(), (QObject *)0); QVERIFY(thread.wait(10000)); delete receiver; } } namespace Foo { struct Bar { virtual ~Bar() {} virtual int rtti() const = 0; }; struct Bleh { virtual ~Bleh() {} virtual int rtti() const = 0; }; } QT_BEGIN_NAMESPACE Q_DECLARE_INTERFACE(Foo::Bar, "com.qtest.foobar") QT_END_NAMESPACE #define Bleh_iid "com.qtest.bleh" QT_BEGIN_NAMESPACE Q_DECLARE_INTERFACE(Foo::Bleh, Bleh_iid) QT_END_NAMESPACE class FooObject: public QObject, public Foo::Bar { W_OBJECT(FooObject) W_INTERFACE(Foo::Bar) public: int rtti() const { return 42; } }; class BlehObject : public QObject, public Foo::Bleh { W_OBJECT(BlehObject) W_INTERFACE(Foo::Bleh) public: int rtti() const { return 43; } }; void tst_QObject::declareInterface() { FooObject obj; Foo::Bar *bar = qobject_cast(&obj); QVERIFY(bar); QCOMPARE(bar->rtti(), 42); QCOMPARE(static_cast(&obj), bar); BlehObject bleh; bar = qobject_cast(&bleh); QVERIFY(!bar); Foo::Bleh *b = qobject_cast(&bleh); QCOMPARE(b->rtti(), 43); QCOMPARE(static_cast(&bleh), b); } class CustomData : public QObjectUserData { public: int id; }; void tst_QObject::testUserData() { const int USER_DATA_COUNT = 100; int user_data_ids[USER_DATA_COUNT]; // Register a few for (int i=0; ibounded(USER_DATA_COUNT); int p2 = QRandomGenerator::global()->bounded(USER_DATA_COUNT); #endif int tmp = user_data_ids[p1]; user_data_ids[p1] = user_data_ids[p2]; user_data_ids[p2] = tmp; } // insert the user data into an object QObject my_test_object; for (int i=0; iid = user_data_ids[i]; my_test_object.setUserData(data->id, data); } // verify that all ids and positions are matching for (int i=0; i(my_test_object.userData(id)); QVERIFY(data != 0); QCOMPARE(data->id, id); } } class DestroyedListener : public QObject { W_OBJECT(DestroyedListener) public: inline DestroyedListener() : pointerWasZero(false) {} QPointer pointer; bool pointerWasZero; private slots: inline void otherObjectDestroyed() { pointerWasZero = pointer.isNull(); } W_SLOT(otherObjectDestroyed) }; void tst_QObject::qpointerResetBeforeDestroyedSignal() { QObject *obj = new QObject; DestroyedListener listener; listener.pointer = obj; listener.pointerWasZero = false; connect(obj, SIGNAL(destroyed()), &listener, SLOT(otherObjectDestroyed())); delete obj; QVERIFY(listener.pointerWasZero); QVERIFY(listener.pointer.isNull()); } class DefaultArguments : public QObject { W_OBJECT(DefaultArguments) public slots: void theSlot(const QString &s) { result = s; } W_SLOT(theSlot) signals: void theOriginalSignal() W_SIGNAL(theOriginalSignal) void theSecondSignal(const QString &s = QString("secondDefault")) W_SIGNAL(theSecondSignal,s) public: void emitTheOriginalSignal() { emit theOriginalSignal(); } void emitTheSecondSignal() { emit theSecondSignal(); } QString result; }; void tst_QObject::connectSignalsToSignalsWithDefaultArguments() { QSKIP("Not supported by W_SLOT/W_SIGNAL"); DefaultArguments o; connect(&o, SIGNAL(theOriginalSignal()), &o, SIGNAL(theSecondSignal())); connect(&o, SIGNAL(theSecondSignal(QString)), &o, SLOT(theSlot(QString))); QVERIFY( o.result.isEmpty() ); o.emitTheSecondSignal(); QCOMPARE(o.result, QString("secondDefault")); o.result = "Not called"; o.emitTheOriginalSignal(); QCOMPARE(o.result, QString("secondDefault")); } void tst_QObject::receivers() { class Object : public QObject { public: int receivers(const char* signal) const { return QObject::receivers(signal); } }; Object object; QCOMPARE(object.receivers(SIGNAL(destroyed())), 0); object.connect(&object, SIGNAL(destroyed()), SLOT(deleteLater())); QCOMPARE(object.receivers(SIGNAL(destroyed())), 1); object.connect(&object, SIGNAL(destroyed()), SLOT(deleteLater())); QCOMPARE(object.receivers(SIGNAL(destroyed())), 2); object.disconnect(SIGNAL(destroyed()), &object, SLOT(deleteLater())); QCOMPARE(object.receivers(SIGNAL(destroyed())), 0); } enum Enum { }; struct Struct { }; class Class { }; template class Template { }; W_REGISTER_ARGTYPE(uint*) W_REGISTER_ARGTYPE(ulong*) W_REGISTER_ARGTYPE(const uint*) W_REGISTER_ARGTYPE(const ulong*) W_REGISTER_ARGTYPE(Struct) W_REGISTER_ARGTYPE(Class) W_REGISTER_ARGTYPE(Enum) W_REGISTER_ARGTYPE(Struct*) W_REGISTER_ARGTYPE(Class*) W_REGISTER_ARGTYPE(Enum*) W_REGISTER_ARGTYPE(const Struct*) W_REGISTER_ARGTYPE(const Class*) W_REGISTER_ARGTYPE(const Enum*) W_REGISTER_ARGTYPE(const Struct*const*) W_REGISTER_ARGTYPE(const Class*const*) W_REGISTER_ARGTYPE(const Enum*const*) W_REGISTER_ARGTYPE(Template&) W_REGISTER_ARGTYPE(Template) W_REGISTER_ARGTYPE(Class*const&) W_REGISTER_ARGTYPE(Template) W_REGISTER_ARGTYPE(Template) class NormalizeObject : public QObject { W_OBJECT(NormalizeObject) public: signals: void uintPointerSignal(uint * a) W_SIGNAL(uintPointerSignal,a) void ulongPointerSignal(ulong * a) W_SIGNAL(ulongPointerSignal,a) void constUintPointerSignal(const uint * a) W_SIGNAL(constUintPointerSignal,a) void constUlongPointerSignal(const ulong * a) W_SIGNAL(constUlongPointerSignal,a) void structSignal(Struct s) W_SIGNAL(structSignal,s) void classSignal(Class c) W_SIGNAL(classSignal,c) void enumSignal(Enum e) W_SIGNAL(enumSignal,e) void structPointerSignal(Struct *s) W_SIGNAL(structPointerSignal,s) void classPointerSignal(Class *c) W_SIGNAL(classPointerSignal,c) void enumPointerSignal(Enum *e) W_SIGNAL(enumPointerSignal,e) void constStructPointerSignal(const Struct *s) W_SIGNAL(constStructPointerSignal,s) void constClassPointerSignal(const Class *c) W_SIGNAL(constClassPointerSignal,c) void constEnumPointerSignal(const Enum *e) W_SIGNAL(constEnumPointerSignal,e) void constStructPointerConstPointerSignal(const Struct * const *s) W_SIGNAL(constStructPointerConstPointerSignal,s) void constClassPointerConstPointerSignal(const Class * const *c) W_SIGNAL(constClassPointerConstPointerSignal,c) void constEnumPointerConstPointerSignal(const Enum * const *e) W_SIGNAL(constEnumPointerConstPointerSignal,e) void unsignedintSignal(unsigned int a) W_SIGNAL(unsignedintSignal,a) void unsignedSignal(unsigned a) W_SIGNAL(unsignedSignal,a) void unsignedlongSignal(unsigned long a) W_SIGNAL(unsignedlongSignal,a) void unsignedlonglongSignal(quint64 a) W_SIGNAL(unsignedlonglongSignal,a) void unsignedlongintSignal(unsigned long int a) W_SIGNAL(unsignedlongintSignal,a) void unsignedshortSignal(unsigned short a) W_SIGNAL(unsignedshortSignal,a) void unsignedcharSignal(unsigned char a) W_SIGNAL(unsignedcharSignal,a) void typeRefSignal(Template &ref) W_SIGNAL(typeRefSignal,ref) void constTypeRefSignal(const Template &ref) W_SIGNAL(constTypeRefSignal,ref) void typeConstRefSignal(Template const &ref) W_SIGNAL(typeConstRefSignal,ref) void typePointerConstRefSignal(Class * const &a) W_SIGNAL(typePointerConstRefSignal,a) void constTemplateSignal1( Template a) W_SIGNAL(constTemplateSignal1,a) void constTemplateSignal2( Template< const int >a) W_SIGNAL(constTemplateSignal2,a) public slots: void uintPointerSlot(uint *) { } W_SLOT(uintPointerSlot) void ulongPointerSlot(ulong *) { } W_SLOT(ulongPointerSlot) void constUintPointerSlot(const uint *) { } W_SLOT(constUintPointerSlot) void constUlongPointerSlot(const ulong *) { } W_SLOT(constUlongPointerSlot) void structSlot(Struct s) { Q_UNUSED(s); } W_SLOT(structSlot) void classSlot(Class c) { Q_UNUSED(c); } W_SLOT(classSlot) void enumSlot(Enum e) { Q_UNUSED(e); } W_SLOT(enumSlot) void structPointerSlot(Struct *s) { Q_UNUSED(s); } W_SLOT(structPointerSlot) void classPointerSlot(Class *c) { Q_UNUSED(c); } W_SLOT(classPointerSlot) void enumPointerSlot(Enum *e) { Q_UNUSED(e); } W_SLOT(enumPointerSlot) void constStructPointerSlot(const Struct *s) { Q_UNUSED(s); } W_SLOT(constStructPointerSlot) void constClassPointerSlot(const Class *c) { Q_UNUSED(c); } W_SLOT(constClassPointerSlot) void constEnumPointerSlot(const Enum *e) { Q_UNUSED(e); } W_SLOT(constEnumPointerSlot) void constStructPointerConstPointerSlot(const Struct * const *s) { Q_UNUSED(s); } W_SLOT(constStructPointerConstPointerSlot) void constClassPointerConstPointerSlot(const Class * const *c) { Q_UNUSED(c); } W_SLOT(constClassPointerConstPointerSlot) void constEnumPointerConstPointerSlot(const Enum * const *e) { Q_UNUSED(e); } W_SLOT(constEnumPointerConstPointerSlot) void uintSlot(uint) {} W_SLOT(uintSlot); void unsignedintSlot(unsigned int) {} W_SLOT(unsignedintSlot); void unsignedSlot(unsigned) {} W_SLOT(unsignedSlot); void unsignedlongSlot(unsigned long) {} W_SLOT(unsignedlongSlot); void unsignedlonglongSlot(quint64) {} W_SLOT(unsignedlonglongSlot); void unsignedlongintSlot(unsigned long int) {} W_SLOT(unsignedlongintSlot); void unsignedshortSlot(unsigned short) {} W_SLOT(unsignedshortSlot); void unsignedcharSlot(unsigned char) {} W_SLOT(unsignedcharSlot); void typeRefSlot(Template &) {} W_SLOT(typeRefSlot) void constTypeRefSlot(const Template &) {} W_SLOT(constTypeRefSlot) void typeConstRefSlot(Template const &) {} W_SLOT(typeConstRefSlot) void typePointerConstRefSlot(Class * const &) {} W_SLOT(typePointerConstRefSlot) void constTemplateSlot1(Template const) {} W_SLOT(constTemplateSlot1) void constTemplateSlot2(const Template ) {} W_SLOT(constTemplateSlot2) void constTemplateSlot3(const Template< const int >) {} W_SLOT(constTemplateSlot3) }; void tst_QObject::normalize() { NormalizeObject object; // unsigned int -> uint, unsigned long -> ulong QVERIFY(object.connect(&object, SIGNAL(uintPointerSignal(uint *)), SLOT(uintPointerSlot(uint *)))); QVERIFY(object.connect(&object, SIGNAL(uintPointerSignal(unsigned int *)), SLOT(uintPointerSlot(uint *)))); QVERIFY(object.connect(&object, SIGNAL(uintPointerSignal(uint *)), SLOT(uintPointerSlot(unsigned int *)))); QVERIFY(object.connect(&object, SIGNAL(constUintPointerSignal(const uint *)), SLOT(constUintPointerSlot(const uint *)))); QVERIFY(object.connect(&object, SIGNAL(constUintPointerSignal(const unsigned int *)), SLOT(constUintPointerSlot(const uint *)))); QVERIFY(object.connect(&object, SIGNAL(constUintPointerSignal(const uint *)), SLOT(constUintPointerSlot(const unsigned int *)))); QVERIFY(object.connect(&object, SIGNAL(ulongPointerSignal(ulong *)), SLOT(ulongPointerSlot(ulong *)))); QVERIFY(object.connect(&object, SIGNAL(ulongPointerSignal(unsigned long *)), SLOT(ulongPointerSlot(ulong *)))); QVERIFY(object.connect(&object, SIGNAL(ulongPointerSignal(ulong *)), SLOT(ulongPointerSlot(unsigned long *)))); QVERIFY(object.connect(&object, SIGNAL(constUlongPointerSignal(const ulong *)), SLOT(constUlongPointerSlot(const ulong *)))); QVERIFY(object.connect(&object, SIGNAL(constUlongPointerSignal(const unsigned long *)), SLOT(constUlongPointerSlot(const ulong *)))); QVERIFY(object.connect(&object, SIGNAL(constUlongPointerSignal(const ulong *)), SLOT(constUlongPointerSlot(const unsigned long *)))); // struct, class, and enum are optional QVERIFY(object.connect(&object, SIGNAL(structSignal(struct Struct)), SLOT(structSlot(struct Struct)))); QVERIFY(object.connect(&object, SIGNAL(structSignal(Struct)), SLOT(structSlot(struct Struct)))); QVERIFY(object.connect(&object, SIGNAL(structSignal(struct Struct)), SLOT(structSlot(Struct)))); QVERIFY(object.connect(&object, SIGNAL(classSignal(class Class)), SLOT(classSlot(class Class)))); QVERIFY(object.connect(&object, SIGNAL(classSignal(Class)), SLOT(classSlot(class Class)))); QVERIFY(object.connect(&object, SIGNAL(classSignal(class Class)), SLOT(classSlot(Class)))); QVERIFY(object.connect(&object, SIGNAL(enumSignal(enum Enum)), SLOT(enumSlot(enum Enum)))); QVERIFY(object.connect(&object, SIGNAL(enumSignal(Enum)), SLOT(enumSlot(enum Enum)))); QVERIFY(object.connect(&object, SIGNAL(enumSignal(enum Enum)), SLOT(enumSlot(Enum)))); QVERIFY(object.connect(&object, SIGNAL(structPointerSignal(struct Struct *)), SLOT(structPointerSlot(struct Struct *)))); QVERIFY(object.connect(&object, SIGNAL(structPointerSignal(Struct *)), SLOT(structPointerSlot(struct Struct *)))); QVERIFY(object.connect(&object, SIGNAL(structPointerSignal(struct Struct *)), SLOT(structPointerSlot(Struct *)))); QVERIFY(object.connect(&object, SIGNAL(classPointerSignal(class Class *)), SLOT(classPointerSlot(class Class *)))); QVERIFY(object.connect(&object, SIGNAL(classPointerSignal(Class *)), SLOT(classPointerSlot(class Class *)))); QVERIFY(object.connect(&object, SIGNAL(classPointerSignal(class Class *)), SLOT(classPointerSlot(Class *)))); QVERIFY(object.connect(&object, SIGNAL(enumPointerSignal(enum Enum *)), SLOT(enumPointerSlot(enum Enum *)))); QVERIFY(object.connect(&object, SIGNAL(enumPointerSignal(Enum *)), SLOT(enumPointerSlot(enum Enum *)))); QVERIFY(object.connect(&object, SIGNAL(enumPointerSignal(enum Enum *)), SLOT(enumPointerSlot(Enum *)))); QVERIFY(object.connect(&object, SIGNAL(constStructPointerSignal(const struct Struct *)), SLOT(constStructPointerSlot(const struct Struct *)))); QVERIFY(object.connect(&object, SIGNAL(constStructPointerSignal(const Struct *)), SLOT(constStructPointerSlot(const struct Struct *)))); QVERIFY(object.connect(&object, SIGNAL(constStructPointerSignal(const struct Struct *)), SLOT(constStructPointerSlot(const Struct *)))); QVERIFY(object.connect(&object, SIGNAL(constClassPointerSignal(const class Class *)), SLOT(constClassPointerSlot(const class Class *)))); QVERIFY(object.connect(&object, SIGNAL(constClassPointerSignal(const Class *)), SLOT(constClassPointerSlot(const class Class *)))); QVERIFY(object.connect(&object, SIGNAL(constClassPointerSignal(const class Class *)), SLOT(constClassPointerSlot(const Class *)))); QVERIFY(object.connect(&object, SIGNAL(constEnumPointerSignal(const enum Enum *)), SLOT(constEnumPointerSlot(const enum Enum *)))); QVERIFY(object.connect(&object, SIGNAL(constEnumPointerSignal(const Enum *)), SLOT(constEnumPointerSlot(const enum Enum *)))); QVERIFY(object.connect(&object, SIGNAL(constEnumPointerSignal(const enum Enum *)), SLOT(constEnumPointerSlot(const Enum *)))); QVERIFY(object.connect(&object, SIGNAL(constStructPointerSignal(struct Struct const *)), SLOT(constStructPointerSlot(struct Struct const *)))); QVERIFY(object.connect(&object, SIGNAL(constStructPointerSignal(Struct const *)), SLOT(constStructPointerSlot(struct Struct const *)))); QVERIFY(object.connect(&object, SIGNAL(constStructPointerSignal(struct Struct const *)), SLOT(constStructPointerSlot(Struct const *)))); QVERIFY(object.connect(&object, SIGNAL(constClassPointerSignal(class Class const *)), SLOT(constClassPointerSlot(class Class const *)))); QVERIFY(object.connect(&object, SIGNAL(constClassPointerSignal(Class const *)), SLOT(constClassPointerSlot(class Class const *)))); QVERIFY(object.connect(&object, SIGNAL(constClassPointerSignal(class Class const *)), SLOT(constClassPointerSlot(Class const *)))); QVERIFY(object.connect(&object, SIGNAL(constEnumPointerSignal(enum Enum const *)), SLOT(constEnumPointerSlot(enum Enum const *)))); QVERIFY(object.connect(&object, SIGNAL(constEnumPointerSignal(Enum const *)), SLOT(constEnumPointerSlot(enum Enum const *)))); QVERIFY(object.connect(&object, SIGNAL(constEnumPointerSignal(enum Enum const *)), SLOT(constEnumPointerSlot(Enum const *)))); QVERIFY(object.connect(&object, SIGNAL(constStructPointerConstPointerSignal(const struct Struct * const *)), SLOT(constStructPointerConstPointerSlot(const struct Struct * const *)))); QVERIFY(object.connect(&object, SIGNAL(constStructPointerConstPointerSignal(const Struct * const *)), SLOT(constStructPointerConstPointerSlot(const struct Struct * const *)))); QVERIFY(object.connect(&object, SIGNAL(constStructPointerConstPointerSignal(const struct Struct * const *)), SLOT(constStructPointerConstPointerSlot(const Struct * const *)))); QVERIFY(object.connect(&object, SIGNAL(constClassPointerConstPointerSignal(const class Class * const *)), SLOT(constClassPointerConstPointerSlot(const class Class * const *)))); QVERIFY(object.connect(&object, SIGNAL(constClassPointerConstPointerSignal(const Class * const *)), SLOT(constClassPointerConstPointerSlot(const class Class * const *)))); QVERIFY(object.connect(&object, SIGNAL(constClassPointerConstPointerSignal(const class Class * const *)), SLOT(constClassPointerConstPointerSlot(const Class * const *)))); QVERIFY(object.connect(&object, SIGNAL(constEnumPointerConstPointerSignal(const enum Enum * const *)), SLOT(constEnumPointerConstPointerSlot(const enum Enum * const *)))); QVERIFY(object.connect(&object, SIGNAL(constEnumPointerConstPointerSignal(const Enum * const *)), SLOT(constEnumPointerConstPointerSlot(const enum Enum * const *)))); QVERIFY(object.connect(&object, SIGNAL(constEnumPointerConstPointerSignal(const enum Enum * const *)), SLOT(constEnumPointerConstPointerSlot(const Enum * const *)))); QVERIFY(object.connect(&object, SIGNAL(constStructPointerConstPointerSignal(struct Struct const * const *)), SLOT(constStructPointerConstPointerSlot(struct Struct const * const *)))); QVERIFY(object.connect(&object, SIGNAL(constStructPointerConstPointerSignal(Struct const * const *)), SLOT(constStructPointerConstPointerSlot(struct Struct const * const *)))); QVERIFY(object.connect(&object, SIGNAL(constStructPointerConstPointerSignal(struct Struct const * const *)), SLOT(constStructPointerConstPointerSlot(Struct const * const *)))); QVERIFY(object.connect(&object, SIGNAL(constClassPointerConstPointerSignal(class Class const * const *)), SLOT(constClassPointerConstPointerSlot(class Class const * const *)))); QVERIFY(object.connect(&object, SIGNAL(constClassPointerConstPointerSignal(Class const * const *)), SLOT(constClassPointerConstPointerSlot(class Class const * const *)))); QVERIFY(object.connect(&object, SIGNAL(constClassPointerConstPointerSignal(class Class const * const *)), SLOT(constClassPointerConstPointerSlot(Class const * const *)))); QVERIFY(object.connect(&object, SIGNAL(constEnumPointerConstPointerSignal(enum Enum const * const *)), SLOT(constEnumPointerConstPointerSlot(enum Enum const * const *)))); QVERIFY(object.connect(&object, SIGNAL(constEnumPointerConstPointerSignal(Enum const * const *)), SLOT(constEnumPointerConstPointerSlot(enum Enum const * const *)))); QVERIFY(object.connect(&object, SIGNAL(constEnumPointerConstPointerSignal(enum Enum const * const *)), SLOT(constEnumPointerConstPointerSlot(Enum const * const *)))); QVERIFY(object.connect(&object, SIGNAL(unsignedintSignal(unsigned int)), SLOT(unsignedintSlot(unsigned int)))); QVERIFY(object.connect(&object, SIGNAL(unsignedSignal(unsigned)), SLOT(unsignedSlot(unsigned)))); QVERIFY(object.connect(&object, SIGNAL(unsignedSignal(unsigned)), SLOT(uintSlot(uint)))); QVERIFY(object.connect(&object, SIGNAL(unsignedlongSignal(unsigned long)), SLOT(unsignedlongSlot(unsigned long)))); QVERIFY(object.connect(&object, SIGNAL(unsignedlonglongSignal(quint64)), SLOT(unsignedlonglongSlot(quint64)))); QVERIFY(object.connect(&object, SIGNAL(unsignedlongintSignal(unsigned long)), // ### fixme; normalisation problem SLOT(unsignedlongintSlot(unsigned long)))); QVERIFY(object.connect(&object, SIGNAL(unsignedshortSignal(unsigned short)), SLOT(unsignedshortSlot(unsigned short)))); QVERIFY(object.connect(&object, SIGNAL(unsignedcharSignal(unsigned char)), SLOT(unsignedcharSlot(unsigned char)))); // connect when original template signature and mixed usage of 'T const &', // 'const T &', and 'T' QVERIFY(object.connect(&object, SIGNAL(typeRefSignal(Template &)), SLOT(typeRefSlot(Template &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(const Template &)), SLOT(constTypeRefSlot(const Template &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(const Template &)), SLOT(constTypeRefSlot(const Template &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(const Template &)), SLOT(constTypeRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(Template const &)), SLOT(constTypeRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(Template const &)), SLOT(constTypeRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(const Template &)), SLOT(typeConstRefSlot(const Template &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(const Template &)), SLOT(typeConstRefSlot(const Template &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(const Template &)), SLOT(typeConstRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(Template const &)), SLOT(typeConstRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(Template const &)), SLOT(typeConstRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(const Template &)), SLOT(constTypeRefSlot(const Template &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(const Template &)), SLOT(constTypeRefSlot(const Template &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(const Template &)), SLOT(constTypeRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(Template const &)), SLOT(constTypeRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(Template const &)), SLOT(constTypeRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(const Template &)), SLOT(typeConstRefSlot(const Template &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(const Template &)), SLOT(typeConstRefSlot(const Template &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(const Template &)), SLOT(typeConstRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(Template const &)), SLOT(typeConstRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(Template const &)), SLOT(typeConstRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(typePointerConstRefSignal(Class*const&)), SLOT(typePointerConstRefSlot(Class*const&)))); QVERIFY(object.connect(&object, SIGNAL(typePointerConstRefSignal(Class*const&)), SLOT(typePointerConstRefSlot(Class*)))); QVERIFY(object.connect(&object, SIGNAL(typePointerConstRefSignal(Class*)), SLOT(typePointerConstRefSlot(Class*const&)))); QVERIFY(object.connect(&object, SIGNAL(typePointerConstRefSignal(Class*)), SLOT(typePointerConstRefSlot(Class*)))); QVERIFY( connect(&object, SIGNAL(constTemplateSignal1(Template )), &object , SLOT(constTemplateSlot1 (Template ) ) )); QVERIFY( connect(&object, SIGNAL(constTemplateSignal1(Template )), &object , SLOT(constTemplateSlot2 (Template ) ) )); QVERIFY( connect(&object, SIGNAL(constTemplateSignal2(Template )), &object , SLOT(constTemplateSlot3(Template ) ) )); //type does not match QTest::ignoreMessage(QtWarningMsg, "QObject::connect: Incompatible sender/receiver arguments\n" " NormalizeObject::constTemplateSignal1(Template) --> NormalizeObject::constTemplateSlot3(Template)"); QVERIFY(!connect(&object, SIGNAL(constTemplateSignal1(Template )), &object , SLOT(constTemplateSlot3(Template ) ) )); } class SiblingDeleter : public QObject { public: inline SiblingDeleter(QObject *sibling, QObject *parent) : QObject(parent), sibling(sibling) {} inline virtual ~SiblingDeleter() { delete sibling; } private: QPointer sibling; }; void tst_QObject::childDeletesItsSibling() { QObject *commonParent = new QObject(0); QPointer child = new QObject(0); QPointer siblingDeleter = new SiblingDeleter(child, commonParent); child->setParent(commonParent); delete commonParent; // don't crash QVERIFY(!child); QVERIFY(!siblingDeleter); } void tst_QObject::floatProperty() { PropertyObject obj; const int idx = obj.metaObject()->indexOfProperty("myFloat"); QVERIFY(idx > 0); QMetaProperty prop = obj.metaObject()->property(idx); QVERIFY(prop.isValid()); QCOMPARE(int(prop.type()), QMetaType::type("float")); QVERIFY(!prop.write(&obj, QVariant("Hello"))); QVERIFY(prop.write(&obj, QVariant::fromValue(128.0f))); QVariant v = prop.read(&obj); QCOMPARE(v.userType(), int(QMetaType::Float)); QCOMPARE(qvariant_cast(v), 128.0f); } void tst_QObject::qrealProperty() { PropertyObject obj; const int idx = obj.metaObject()->indexOfProperty("myQReal"); QVERIFY(idx > 0); QMetaProperty prop = obj.metaObject()->property(idx); QVERIFY(prop.isValid()); QCOMPARE(int(prop.type()), QMetaType::type("qreal")); QVERIFY(!prop.write(&obj, QVariant("Hello"))); QVERIFY(prop.write(&obj, QVariant::fromValue(128.0f))); QVariant v = prop.read(&obj); QCOMPARE(v.userType(), qMetaTypeId()); QCOMPARE(qvariant_cast(v), 128.0); QVERIFY(prop.write(&obj, QVariant::fromValue(double(127)))); v = prop.read(&obj); QCOMPARE(v.userType(), qMetaTypeId()); QCOMPARE(qvariant_cast(v), 127.0); } class DynamicPropertyObject : public PropertyObject { public: inline DynamicPropertyObject() {} inline virtual bool event(QEvent *e) { if (e->type() == QEvent::DynamicPropertyChange) { changedDynamicProperties.append(static_cast(e)->propertyName()); } return QObject::event(e); } QList changedDynamicProperties; }; void tst_QObject::dynamicProperties() { DynamicPropertyObject obj; QVERIFY(obj.dynamicPropertyNames().isEmpty()); // set a non-dynamic property QVERIFY(obj.setProperty("number", 42)); QVERIFY(obj.changedDynamicProperties.isEmpty()); QCOMPARE(obj.property("number").toInt(), 42); QVERIFY(!obj.setProperty("number", "invalid string")); QVERIFY(obj.changedDynamicProperties.isEmpty()); // set a dynamic property QVERIFY(!obj.setProperty("myuserproperty", "Hello")); QCOMPARE(obj.changedDynamicProperties.count(), 1); QCOMPARE(obj.changedDynamicProperties.first(), QByteArray("myuserproperty")); //check if there is no redundant DynamicPropertyChange events QVERIFY(!obj.setProperty("myuserproperty", "Hello")); QCOMPARE(obj.changedDynamicProperties.count(), 1); QCOMPARE(obj.property("myuserproperty").type(), QVariant::String); QCOMPARE(obj.property("myuserproperty").toString(), QString("Hello")); QCOMPARE(obj.dynamicPropertyNames().count(), 1); QCOMPARE(obj.dynamicPropertyNames().first(), QByteArray("myuserproperty")); #if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) // change type of the dynamic property obj.changedDynamicProperties.clear(); QVERIFY(!obj.setProperty("myuserproperty", QByteArray("Hello"))); QCOMPARE(obj.changedDynamicProperties.count(), 1); QCOMPARE(obj.changedDynamicProperties.first(), QByteArray("myuserproperty")); QCOMPARE(obj.property("myuserproperty").type(), QVariant::ByteArray); QCOMPARE(obj.property("myuserproperty").toString(), QByteArray("Hello")); #endif // unset the property obj.changedDynamicProperties.clear(); QVERIFY(!obj.setProperty("myuserproperty", QVariant())); QCOMPARE(obj.changedDynamicProperties.count(), 1); QCOMPARE(obj.changedDynamicProperties.first(), QByteArray("myuserproperty")); obj.changedDynamicProperties.clear(); QVERIFY(obj.property("myuserproperty").isNull()); QVERIFY(obj.dynamicPropertyNames().isEmpty()); } void tst_QObject::recursiveSignalEmission() { #if !defined(Q_OS_MAC) && !defined(Q_OS_WIN) // because it does not find the executable QProcess proc; // signalbug helper app should always be next to this test binary #ifdef W_SIGNALBUG const QString path = QStringLiteral(W_SIGNALBUG); #else const QString path = QStringLiteral("signalbug/signalbug"); #endif proc.start(path); QVERIFY2(proc.waitForStarted(), qPrintable(QString::fromLatin1("Cannot start '%1': %2").arg(path, proc.errorString()))); QVERIFY(proc.waitForFinished()); QCOMPARE(proc.exitStatus(), QProcess::NormalExit); QCOMPARE(proc.exitCode(), 0); #endif } void tst_QObject::signalBlocking() { SenderObject sender; ReceiverObject receiver; receiver.connect(&sender, SIGNAL(signal1()), SLOT(slot1())); sender.emitSignal1(); QVERIFY(receiver.called(1)); receiver.reset(); sender.blockSignals(true); sender.emitSignal1(); QVERIFY(!receiver.called(1)); receiver.reset(); sender.blockSignals(false); sender.emitSignal1(); QVERIFY(receiver.called(1)); receiver.reset(); } void tst_QObject::blockingQueuedConnection() { { SenderObject sender; MoveToThreadThread thread; ReceiverObject receiver; receiver.moveToThread(&thread); thread.start(); receiver.connect(&sender, SIGNAL(signal1()), SLOT(slot1()), Qt::BlockingQueuedConnection); sender.emitSignal1(); QVERIFY(receiver.called(1)); receiver.reset(); QVERIFY(QMetaObject::invokeMethod(&receiver, "slot1", Qt::BlockingQueuedConnection)); QVERIFY(receiver.called(1)); connect(&sender, &SenderObject::signal2, &receiver, &ReceiverObject::slot2, Qt::BlockingQueuedConnection); sender.emitSignal2(); QVERIFY(receiver.called(2)); thread.quit(); QVERIFY(thread.wait()); } } class EventSpy : public QObject { W_OBJECT(EventSpy) public: typedef QList > EventList; EventSpy(QObject *parent = 0) : QObject(parent) { } EventList eventList() { return events; } void clear() { events.clear(); } bool eventFilter(QObject *object, QEvent *event) { events.append(qMakePair(object, event->type())); return false; } private: EventList events; }; void tst_QObject::childEvents() { EventSpy::EventList expected; { // no children created, so we expect no events QObject object; EventSpy spy; object.installEventFilter(&spy); QCoreApplication::postEvent(&object, new QEvent(QEvent::Type(QEvent::User + 1))); QCoreApplication::processEvents(); expected = EventSpy::EventList() << qMakePair(&object, QEvent::Type(QEvent::User + 1)); QCOMPARE(spy.eventList(), expected); } { // 2 children, so we expect 2 ChildAdded events QObject object; EventSpy spy; object.installEventFilter(&spy); QCoreApplication::postEvent(&object, new QEvent(QEvent::Type(QEvent::User + 1))); QObject child1(&object); QObject child2; child2.setParent(&object); QCoreApplication::postEvent(&object, new QEvent(QEvent::Type(QEvent::User + 2))); expected = EventSpy::EventList() << qMakePair(&object, QEvent::ChildAdded) << qMakePair(&object, QEvent::ChildAdded); QCOMPARE(spy.eventList(), expected); spy.clear(); QCoreApplication::processEvents(); expected = EventSpy::EventList() << qMakePair(&object, QEvent::Type(QEvent::User + 1)) << qMakePair(&object, QEvent::Type(QEvent::User + 2)); QCOMPARE(spy.eventList(), expected); } { // 2 children, but one is reparented away, so we expect: // 2 ChildAdded, 1 ChildRemoved QObject object; EventSpy spy; object.installEventFilter(&spy); QCoreApplication::postEvent(&object, new QEvent(QEvent::Type(QEvent::User + 1))); QObject child1(&object); QObject child2; child2.setParent(&object); child2.setParent(0); QCoreApplication::postEvent(&object, new QEvent(QEvent::Type(QEvent::User + 2))); expected = EventSpy::EventList() << qMakePair(&object, QEvent::ChildAdded) << qMakePair(&object, QEvent::ChildAdded) << qMakePair(&object, QEvent::ChildRemoved); QCOMPARE(spy.eventList(), expected); spy.clear(); QCoreApplication::processEvents(); expected = EventSpy::EventList() << qMakePair(&object, QEvent::Type(QEvent::User + 1)) << qMakePair(&object, QEvent::Type(QEvent::User + 2)); QCOMPARE(spy.eventList(), expected); } } void tst_QObject::installEventFilter() { QEvent event(QEvent::User); EventSpy::EventList expected; QObject object; EventSpy spy; object.installEventFilter(&spy); // nothing special, should just work QCoreApplication::sendEvent(&object, &event); expected = EventSpy::EventList() << qMakePair(&object, QEvent::User); QCOMPARE(spy.eventList(), expected); spy.clear(); // moving the filter causes QCoreApplication to skip the filter spy.moveToThread(0); QTest::ignoreMessage(QtWarningMsg, "QCoreApplication: Object event filter cannot be in a different thread."); QCoreApplication::sendEvent(&object, &event); QVERIFY(spy.eventList().isEmpty()); // move it back, and the filter works again spy.moveToThread(object.thread()); QCoreApplication::sendEvent(&object, &event); expected = EventSpy::EventList() << qMakePair(&object, QEvent::User); QCOMPARE(spy.eventList(), expected); spy.clear(); // cannot install an event filter that lives in a different thread object.removeEventFilter(&spy); spy.moveToThread(0); QTest::ignoreMessage(QtWarningMsg, "QObject::installEventFilter(): Cannot filter events for objects in a different thread."); object.installEventFilter(&spy); QCoreApplication::sendEvent(&object, &event); QVERIFY(spy.eventList().isEmpty()); } class EmitThread : public QThread { W_OBJECT(EmitThread) public: void run(void) { emit work(); } signals: void work() W_SIGNAL(work) }; namespace QObjectTest { // Do not clash with WinAPI 'DeleteObject' class DeleteObject : public QObject { W_OBJECT(DeleteObject) public slots: void deleteSelf() { delete this; } W_SLOT(deleteSelf) void relaySignalAndProcessEvents() { emit relayedSignal(); QCoreApplication::processEvents(); } W_SLOT(relaySignalAndProcessEvents) signals: void relayedSignal() W_SIGNAL(relayedSignal) }; } // namespace QObjectTest void tst_QObject::deleteSelfInSlot() { { SenderObject sender; QObjectTest::DeleteObject *receiver = new QObjectTest::DeleteObject(); receiver->connect(&sender, SIGNAL(signal1()), SLOT(deleteSelf()), Qt::BlockingQueuedConnection); QThread thread; receiver->moveToThread(&thread); thread.connect(receiver, SIGNAL(destroyed()), SLOT(quit()), Qt::DirectConnection); thread.start(); QPointer p = receiver; sender.emitSignal1(); QVERIFY(p.isNull()); QVERIFY(thread.wait(10000)); } { SenderObject sender; QObjectTest::DeleteObject *receiver = new QObjectTest::DeleteObject(); receiver->connect(&sender, SIGNAL(signal1()), SLOT(relaySignalAndProcessEvents()), Qt::BlockingQueuedConnection); receiver->connect(receiver, SIGNAL(relayedSignal()), SLOT(deleteSelf()), Qt::QueuedConnection); QThread thread; receiver->moveToThread(&thread); thread.connect(receiver, SIGNAL(destroyed()), SLOT(quit()), Qt::DirectConnection); thread.start(); QPointer p = receiver; sender.emitSignal1(); QVERIFY(p.isNull()); QVERIFY(thread.wait(10000)); } { EmitThread sender; QObjectTest::DeleteObject *receiver = new QObjectTest::DeleteObject(); connect(&sender, SIGNAL(work()), receiver, SLOT(deleteSelf()), Qt::DirectConnection); QPointer p = receiver; sender.start(); QVERIFY(sender.wait(10000)); QVERIFY(p.isNull()); } } class DisconnectObject : public QObject { W_OBJECT(DisconnectObject) public slots: void disconnectSelf() { disconnect(sender(), 0, this, 0); } W_SLOT(disconnectSelf) void relaySignalAndProcessEvents() { emit relayedSignal(); QCoreApplication::processEvents(); } W_SLOT(relaySignalAndProcessEvents) signals: void relayedSignal() W_SIGNAL(relayedSignal) }; void tst_QObject::disconnectSelfInSlotAndDeleteAfterEmit() { { SenderObject sender; DisconnectObject *receiver = new DisconnectObject(); receiver->connect(&sender, SIGNAL(signal1()), SLOT(disconnectSelf())); sender.emitSignal1AfterRecursion(); delete receiver; } { SenderObject sender; DisconnectObject *receiver = new DisconnectObject(); receiver->connect(&sender, SIGNAL(signal1()), SLOT(disconnectSelf()), Qt::BlockingQueuedConnection); QThread thread; receiver->moveToThread(&thread); thread.connect(receiver, SIGNAL(destroyed()), SLOT(quit()), Qt::DirectConnection); thread.start(); QPointer p = receiver; sender.emitSignal1(); QVERIFY(!p.isNull()); receiver->deleteLater(); QVERIFY(thread.wait(10000)); QVERIFY(p.isNull()); } { SenderObject sender; DisconnectObject *receiver = new DisconnectObject(); receiver->connect(&sender, SIGNAL(signal1()), SLOT(relaySignalAndProcessEvents()), Qt::BlockingQueuedConnection); receiver->connect(receiver, SIGNAL(relayedSignal()), SLOT(disconnectSelf()), Qt::QueuedConnection); QThread thread; receiver->moveToThread(&thread); thread.connect(receiver, SIGNAL(destroyed()), SLOT(quit()), Qt::DirectConnection); thread.start(); QPointer p = receiver; sender.emitSignal1(); QVERIFY(!p.isNull()); receiver->deleteLater(); QVERIFY(thread.wait(10000)); QVERIFY(p.isNull()); } } void tst_QObject::dumpObjectInfo() { QObject a, b; #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) QObject::connect(&a, SIGNAL(destroyed(QObject*)), &b, SLOT(deleteLater())); a.disconnect(&b); #else QObject::connect(&a, &QObject::destroyed, &b, &QObject::deleteLater); #endif #if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) QTest::ignoreMessage(QtDebugMsg, "OBJECT QObject::unnamed"); QTest::ignoreMessage(QtDebugMsg, " SIGNALS OUT"); QTest::ignoreMessage(QtDebugMsg, " signal: destroyed(QObject*)"); #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) QTest::ignoreMessage(QtDebugMsg, " "); #else QTest::ignoreMessage(QtDebugMsg, " "); #endif QTest::ignoreMessage(QtDebugMsg, " SIGNALS IN"); QTest::ignoreMessage(QtDebugMsg, " "); #endif a.dumpObjectInfo(); // should not crash } class ConnectToSender : public QObject { W_OBJECT(ConnectToSender) public slots: void uselessSlot() { count++; } W_SLOT(uselessSlot) void harmfullSlot() { //this used to crash connect(sender(), SIGNAL(signal4()), this, SLOT(uselessSlot())); //play a little bit with the memory in order to really get a segfault. connect(sender(), SIGNAL(signal1()), this, SLOT(uselessSlot())); QList() << 45 << 78 << 65 << 121 << 45 << 78 << 12; } W_SLOT(harmfullSlot) public: int count; }; void tst_QObject::connectToSender() { SenderObject s; ConnectToSender r; r.count = 0; QObject::connect(&s, SIGNAL(signal1()), &r, SLOT(harmfullSlot())); QObject::connect(&s, SIGNAL(signal1()), &r, SLOT(uselessSlot())); s.emitSignal1(); QCOMPARE(r.count, 1); s.emitSignal4(); QCOMPARE(r.count, 2); } void tst_QObject::qobjectConstCast() { FooObject obj; QObject *ptr = &obj; const QObject *cptr = &obj; QVERIFY(qobject_cast(ptr)); QVERIFY(qobject_cast(cptr)); } void tst_QObject::uniqConnection() { SenderObject s; ReceiverObject r1; ReceiverObject r2; r1.reset(); r2.reset(); ReceiverObject::sequence = 0; QVERIFY(connect(&s, SIGNAL(signal1()), &r1, SLOT(slot1()) , Qt::UniqueConnection) ); QVERIFY(connect(&s, SIGNAL(signal1()), &r2, SLOT(slot1()) , Qt::UniqueConnection) ); QVERIFY(connect(&s, SIGNAL(signal1()), &r1, SLOT(slot3()) , Qt::UniqueConnection) ); QVERIFY(connect(&s, SIGNAL(signal3()), &r1, SLOT(slot3()) , Qt::UniqueConnection) ); s.emitSignal1(); s.emitSignal2(); s.emitSignal3(); s.emitSignal4(); QCOMPARE(r1.count_slot1, 1); QCOMPARE(r1.count_slot2, 0); QCOMPARE(r1.count_slot3, 2); QCOMPARE(r1.count_slot4, 0); QCOMPARE(r2.count_slot1, 1); QCOMPARE(r2.count_slot2, 0); QCOMPARE(r2.count_slot3, 0); QCOMPARE(r2.count_slot4, 0); QCOMPARE(r1.sequence_slot1, 1); QCOMPARE(r2.sequence_slot1, 2); QCOMPARE(r1.sequence_slot3, 4); r1.reset(); r2.reset(); ReceiverObject::sequence = 0; QVERIFY( connect(&s, SIGNAL(signal4()), &r1, SLOT(slot4()) , Qt::UniqueConnection)); QVERIFY( connect(&s, SIGNAL(signal4()), &r2, SLOT(slot4()) , Qt::UniqueConnection)); QVERIFY(!connect(&s, SIGNAL(signal4()), &r2, SLOT(slot4()) , Qt::UniqueConnection)); QVERIFY( connect(&s, SIGNAL(signal1()), &r2, SLOT(slot4()) , Qt::UniqueConnection)); QVERIFY(!connect(&s, SIGNAL(signal4()), &r1, SLOT(slot4()) , Qt::UniqueConnection)); s.emitSignal4(); QCOMPARE(r1.count_slot4, 1); QCOMPARE(r2.count_slot4, 1); QCOMPARE(r1.sequence_slot4, 1); QCOMPARE(r2.sequence_slot4, 2); r1.reset(); r2.reset(); ReceiverObject::sequence = 0; connect(&s, SIGNAL(signal4()), &r1, SLOT(slot4())); s.emitSignal4(); QCOMPARE(r1.count_slot4, 2); QCOMPARE(r2.count_slot4, 1); QCOMPARE(r1.sequence_slot4, 3); QCOMPARE(r2.sequence_slot4, 2); } void tst_QObject::uniqConnectionPtr() { SenderObject s; ReceiverObject r1; ReceiverObject r2; r1.reset(); r2.reset(); ReceiverObject::sequence = 0; QVERIFY(connect(&s, &SenderObject::signal1, &r1, &ReceiverObject::slot1 , Qt::UniqueConnection)); QVERIFY(connect(&s, &SenderObject::signal1, &r2, &ReceiverObject::slot1 , Qt::UniqueConnection)); QVERIFY(connect(&s, &SenderObject::signal1, &r1, &ReceiverObject::slot3 , Qt::UniqueConnection)); QVERIFY(connect(&s, &SenderObject::signal3, &r1, &ReceiverObject::slot3 , Qt::UniqueConnection)); s.emitSignal1(); s.emitSignal2(); s.emitSignal3(); s.emitSignal4(); QCOMPARE(r1.count_slot1, 1); QCOMPARE(r1.count_slot2, 0); QCOMPARE(r1.count_slot3, 2); QCOMPARE(r1.count_slot4, 0); QCOMPARE(r2.count_slot1, 1); QCOMPARE(r2.count_slot2, 0); QCOMPARE(r2.count_slot3, 0); QCOMPARE(r2.count_slot4, 0); QCOMPARE(r1.sequence_slot1, 1); QCOMPARE(r2.sequence_slot1, 2); QCOMPARE(r1.sequence_slot3, 4); r1.reset(); r2.reset(); ReceiverObject::sequence = 0; QVERIFY( connect(&s, &SenderObject::signal4, &r1, &ReceiverObject::slot4 , Qt::UniqueConnection)); QVERIFY( connect(&s, &SenderObject::signal4, &r2, &ReceiverObject::slot4 , Qt::UniqueConnection)); QVERIFY(!connect(&s, &SenderObject::signal4, &r2, &ReceiverObject::slot4 , Qt::UniqueConnection)); QVERIFY( connect(&s, &SenderObject::signal1, &r2, &ReceiverObject::slot4 , Qt::UniqueConnection)); QVERIFY(!connect(&s, &SenderObject::signal4, &r1, &ReceiverObject::slot4 , Qt::UniqueConnection)); s.emitSignal4(); QCOMPARE(r1.count_slot4, 1); QCOMPARE(r2.count_slot4, 1); QCOMPARE(r1.sequence_slot4, 1); QCOMPARE(r2.sequence_slot4, 2); r1.reset(); r2.reset(); ReceiverObject::sequence = 0; connect(&s, &SenderObject::signal4, &r1, &ReceiverObject::slot4); s.emitSignal4(); QCOMPARE(r1.count_slot4, 2); QCOMPARE(r2.count_slot4, 1); QCOMPARE(r1.sequence_slot4, 3); QCOMPARE(r2.sequence_slot4, 2); } void tst_QObject::interfaceIid() { QCOMPARE(QByteArray(qobject_interface_iid()), QByteArray(Bleh_iid)); QCOMPARE(QByteArray(qobject_interface_iid()), QByteArray("com.qtest.foobar")); QCOMPARE(QByteArray(qobject_interface_iid()), QByteArray()); } void tst_QObject::deleteQObjectWhenDeletingEvent() { // This is a regression test for an old bug that used to deadlock // when the QObject from the event was destroyed. struct MyEvent : public QEvent { MyEvent() : QEvent(QEvent::User) { } QObject obj; }; QObject o; QCoreApplication::postEvent(&o, new MyEvent); QCoreApplication::removePostedEvents(&o); // here you would get a deadlock } class OverloadObject : public QObject { friend class tst_QObject; W_OBJECT(OverloadObject) signals: void sig(int i, char c, qreal m = 12) W_SIGNAL(sig,(int, char, qreal),i,c,m) void sig(int i, int j = 12) W_SIGNAL(sig,(int,int),i,j) void sig(QObject *o, QObject *p, QObject *q = 0, QObject *r = 0) const W_SIGNAL(sig,(QObject*,QObject*,QObject*,QObject*),o,p,q,r) void other(int a = 0) W_SIGNAL(other,(int),a) void sig(QObject *o, OverloadObject *p = 0, QObject *q = 0, QObject *r = 0) W_SIGNAL(sig,(QObject*,OverloadObject*,QObject*,QObject*),o,p,q,r) void sig(double r = 0.5) W_SIGNAL(sig,(double),r) public slots: void slo(int i, int j = 43) { s_num += 1; i1_num = i; i2_num = j; } W_SLOT(slo,(int,int)) void slo(QObject *o, QObject *p = qApp, QObject *q = qApp, QObject *r = qApp) { s_num += 10; o1_obj = o; o2_obj = p; o3_obj = q; o4_obj = r; } W_SLOT(slo,(QObject*,QObject*,QObject*,QObject*)) void slo() { s_num += 100; } W_SLOT(slo,()) public: int s_num; int i1_num; int i2_num; QObject *o1_obj; QObject *o2_obj; QObject *o3_obj; QObject *o4_obj; }; void tst_QObject::overloads() { QSKIP("Overload not supported by W_SIGNAL/W_SLOT"); OverloadObject obj1; OverloadObject obj2; QObject obj3; obj1.s_num = 0; obj2.s_num = 0; connect (&obj1, SIGNAL(sig(int)) , &obj1, SLOT(slo(int))); connect (&obj1, SIGNAL(sig(QObject*,QObject*,QObject*)) , &obj1, SLOT(slo(QObject*,QObject*,QObject*))); connect (&obj1, SIGNAL(sig(QObject*,QObject*,QObject*,QObject*)) , &obj2, SLOT(slo(QObject*,QObject*,QObject*))); connect (&obj1, SIGNAL(sig(QObject*)) , &obj2, SLOT(slo())); connect (&obj1, SIGNAL(sig(int,int)) , &obj2, SLOT(slo(int,int))); emit obj1.sig(0.5); //connected to nothing emit obj1.sig(1, 'a'); //connected to nothing QCOMPARE(obj1.s_num, 0); QCOMPARE(obj2.s_num, 0); emit obj1.sig(1); //this signal is connected QCOMPARE(obj1.s_num, 1); QCOMPARE(obj1.i1_num, 1); QCOMPARE(obj1.i2_num, 43); //default argument of the slot QCOMPARE(obj2.s_num, 1); QCOMPARE(obj2.i1_num, 1); QCOMPARE(obj2.i2_num, 12); //default argument of the signal emit obj1.sig(&obj2); //this signal is conencted to obj2 QCOMPARE(obj1.s_num, 1); QCOMPARE(obj2.s_num, 101); emit obj1.sig(&obj2, &obj3); //this signal is connected QCOMPARE(obj1.s_num, 11); QCOMPARE(obj1.o1_obj, (QObject *)&obj2); QCOMPARE(obj1.o2_obj, &obj3); QCOMPARE(obj1.o3_obj, (QObject *)0); //default arg of the signal QCOMPARE(obj1.o4_obj, (QObject *)qApp); //default arg of the slot QCOMPARE(obj2.s_num, 111); QCOMPARE(obj2.o1_obj, (QObject *)&obj2); QCOMPARE(obj2.o2_obj, &obj3); QCOMPARE(obj2.o3_obj, (QObject *)0); //default arg of the signal QCOMPARE(obj2.o4_obj, (QObject *)qApp); //default arg of the slot } class ManySignals : public QObject { W_OBJECT(ManySignals) friend class tst_QObject; signals: void sig00() W_SIGNAL(sig00) void sig01() W_SIGNAL(sig01) void sig02() W_SIGNAL(sig02) void sig03() W_SIGNAL(sig03) void sig04() W_SIGNAL(sig04) void sig05() W_SIGNAL(sig05) void sig06() W_SIGNAL(sig06) void sig07() W_SIGNAL(sig07) void sig08() W_SIGNAL(sig08) void sig09() W_SIGNAL(sig09) void sig10() W_SIGNAL(sig10) void sig11() W_SIGNAL(sig11) void sig12() W_SIGNAL(sig12) void sig13() W_SIGNAL(sig13) void sig14() W_SIGNAL(sig14) void sig15() W_SIGNAL(sig15) void sig16() W_SIGNAL(sig16) void sig17() W_SIGNAL(sig17) void sig18() W_SIGNAL(sig18) void sig19() W_SIGNAL(sig19) void sig20() W_SIGNAL(sig20) void sig21() W_SIGNAL(sig21) void sig22() W_SIGNAL(sig22) void sig23() W_SIGNAL(sig23) void sig24() W_SIGNAL(sig24) void sig25() W_SIGNAL(sig25) void sig26() W_SIGNAL(sig26) void sig27() W_SIGNAL(sig27) void sig28() W_SIGNAL(sig28) void sig29() W_SIGNAL(sig29) void sig30() W_SIGNAL(sig30) void sig31() W_SIGNAL(sig31) void sig32() W_SIGNAL(sig32) void sig33() W_SIGNAL(sig33) void sig34() W_SIGNAL(sig34) void sig35() W_SIGNAL(sig35) void sig36() W_SIGNAL(sig36) void sig37() W_SIGNAL(sig37) void sig38() W_SIGNAL(sig38) void sig39() W_SIGNAL(sig39) void sig40() W_SIGNAL(sig40) void sig41() W_SIGNAL(sig41) void sig42() W_SIGNAL(sig42) void sig43() W_SIGNAL(sig43) void sig44() W_SIGNAL(sig44) void sig45() W_SIGNAL(sig45) void sig46() W_SIGNAL(sig46) void sig47() W_SIGNAL(sig47) void sig48() W_SIGNAL(sig48) void sig49() W_SIGNAL(sig49) void sig50() W_SIGNAL(sig50) void sig51() W_SIGNAL(sig51) void sig52() W_SIGNAL(sig52) void sig53() W_SIGNAL(sig53) void sig54() W_SIGNAL(sig54) void sig55() W_SIGNAL(sig55) void sig56() W_SIGNAL(sig56) void sig57() W_SIGNAL(sig57) void sig58() W_SIGNAL(sig58) void sig59() W_SIGNAL(sig59) void sig60() W_SIGNAL(sig60) void sig61() W_SIGNAL(sig61) void sig62() W_SIGNAL(sig62) void sig63() W_SIGNAL(sig63) void sig64() W_SIGNAL(sig64) void sig65() W_SIGNAL(sig65) void sig66() W_SIGNAL(sig66) void sig67() W_SIGNAL(sig67) void sig68() W_SIGNAL(sig68) void sig69() W_SIGNAL(sig69) public slots: void received() { rec++; } W_SLOT(received) public: int rec; }; void tst_QObject::isSignalConnected() { ManySignals o; const QMetaObject *meta = o.metaObject(); o.rec = 0; #ifdef QT_BUILD_INTERNAL QObjectPrivate *priv = QObjectPrivate::get(&o); QVERIFY(!priv->isSignalConnected(priv->signalIndex("destroyed()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig00()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig05()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig15()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig29()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig60()"))); #endif QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("destroyed()")))); QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig00()")))); QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig05()")))); QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig15()")))); QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig29()")))); QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig60()")))); QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig69()")))); QObject::connect(&o, SIGNAL(sig00()), &o, SIGNAL(sig69())); QObject::connect(&o, SIGNAL(sig34()), &o, SIGNAL(sig03())); QObject::connect(&o, SIGNAL(sig69()), &o, SIGNAL(sig34())); QObject::connect(&o, SIGNAL(sig03()), &o, SIGNAL(sig18())); #ifdef QT_BUILD_INTERNAL QVERIFY(!priv->isSignalConnected(priv->signalIndex("destroyed()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig05()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig15()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig29()"))); QVERIFY(priv->isSignalConnected(priv->signalIndex("sig00()"))); QVERIFY(priv->isSignalConnected(priv->signalIndex("sig03()"))); QVERIFY(priv->isSignalConnected(priv->signalIndex("sig34()"))); QVERIFY(priv->isSignalConnected(priv->signalIndex("sig69()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig18()"))); #endif QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("destroyed()")))); QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("destroyed(QObject*)")))); QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig05()")))); QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig15()")))); QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig29()")))); QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig00()")))); QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig03()")))); QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig34()")))); QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig69()")))); QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig18()")))); QObject::connect(&o, SIGNAL(sig18()), &o, SIGNAL(sig29())); QObject::connect(&o, SIGNAL(sig29()), &o, SIGNAL(sig62())); QObject::connect(&o, SIGNAL(sig62()), &o, SIGNAL(sig28())); QObject::connect(&o, SIGNAL(sig28()), &o, SIGNAL(sig27())); #ifdef QT_BUILD_INTERNAL QVERIFY(priv->isSignalConnected(priv->signalIndex("sig18()"))); QVERIFY(priv->isSignalConnected(priv->signalIndex("sig62()"))); QVERIFY(priv->isSignalConnected(priv->signalIndex("sig28()"))); QVERIFY(priv->isSignalConnected(priv->signalIndex("sig69()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig27()"))); #endif QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig18()")))); QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig62()")))); QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig28()")))); QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig69()")))); QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig27()")))); QCOMPARE(o.rec, 0); emit o.sig01(); emit o.sig34(); QCOMPARE(o.rec, 0); QObject::connect(&o, SIGNAL(sig27()), &o, SLOT(received())); #ifdef QT_BUILD_INTERNAL QVERIFY(priv->isSignalConnected(priv->signalIndex("sig00()"))); QVERIFY(priv->isSignalConnected(priv->signalIndex("sig03()"))); QVERIFY(priv->isSignalConnected(priv->signalIndex("sig34()"))); QVERIFY(priv->isSignalConnected(priv->signalIndex("sig18()"))); QVERIFY(priv->isSignalConnected(priv->signalIndex("sig62()"))); QVERIFY(priv->isSignalConnected(priv->signalIndex("sig28()"))); QVERIFY(priv->isSignalConnected(priv->signalIndex("sig69()"))); QVERIFY(priv->isSignalConnected(priv->signalIndex("sig27()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig04()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig21()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig25()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig55()"))); #endif emit o.sig00(); QCOMPARE(o.rec, 1); emit o.sig69(); QCOMPARE(o.rec, 2); emit o.sig36(); QCOMPARE(o.rec, 2); QObject::connect(&o, &QObject::destroyed, qt_noop); QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("destroyed()")))); QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("destroyed(QObject*)")))); QVERIFY(!o.isSignalConnected(QMetaMethod())); } void tst_QObject::isSignalConnectedAfterDisconnection() { #if QT_VERSION < QT_VERSION_CHECK(5, 13, 0) QSKIP("Fixed in 5.13 only"); #endif ManySignals o; const QMetaObject *meta = o.metaObject(); const QMetaMethod sig00 = meta->method(meta->indexOfSignal("sig00()")); QVERIFY(!o.isSignalConnected(sig00)); QObject::connect(&o, &ManySignals::sig00, qt_noop); QVERIFY(o.isSignalConnected(sig00)); QVERIFY(QObject::disconnect(&o, &ManySignals::sig00, 0, 0)); QVERIFY(!o.isSignalConnected(sig00)); const QMetaMethod sig69 = meta->method(meta->indexOfSignal("sig69()")); QVERIFY(!o.isSignalConnected(sig69)); QObject::connect(&o, &ManySignals::sig69, qt_noop); QVERIFY(o.isSignalConnected(sig69)); QVERIFY(QObject::disconnect(&o, &ManySignals::sig69, 0, 0)); QVERIFY(!o.isSignalConnected(sig69)); { ManySignals o2; QObject::connect(&o, &ManySignals::sig00, &o2, &ManySignals::sig00); QVERIFY(o.isSignalConnected(sig00)); // o2 is destructed } QVERIFY(!o.isSignalConnected(sig00)); const QMetaMethod sig01 = meta->method(meta->indexOfSignal("sig01()")); QObject::connect(&o, &ManySignals::sig00, qt_noop); QObject::connect(&o, &ManySignals::sig01, qt_noop); QObject::connect(&o, &ManySignals::sig69, qt_noop); QVERIFY(o.isSignalConnected(sig00)); QVERIFY(o.isSignalConnected(sig01)); QVERIFY(o.isSignalConnected(sig69)); QVERIFY(QObject::disconnect(&o, &ManySignals::sig69, 0, 0)); QVERIFY(o.isSignalConnected(sig00)); QVERIFY(o.isSignalConnected(sig01)); QVERIFY(!o.isSignalConnected(sig69)); QVERIFY(QObject::disconnect(&o, &ManySignals::sig00, 0, 0)); QVERIFY(!o.isSignalConnected(sig00)); QVERIFY(o.isSignalConnected(sig01)); QVERIFY(!o.isSignalConnected(sig69)); QObject::connect(&o, &ManySignals::sig69, qt_noop); QVERIFY(!o.isSignalConnected(sig00)); QVERIFY(o.isSignalConnected(sig01)); QVERIFY(o.isSignalConnected(sig69)); QVERIFY(QObject::disconnect(&o, &ManySignals::sig01, 0, 0)); QVERIFY(!o.isSignalConnected(sig00)); QVERIFY(!o.isSignalConnected(sig01)); QVERIFY(o.isSignalConnected(sig69)); } void tst_QObject::qMetaObjectConnect() { ReceiverObject r1; ReceiverObject r2; int slot1Index, slot2Index, slot3Index; { SenderObject s; r1.reset(); r2.reset(); ReceiverObject::sequence = 0; int signal1Index = s.metaObject()->indexOfSignal("signal1()"); int signal3Index = s.metaObject()->indexOfSignal("signal3()"); slot1Index = r1.metaObject()->indexOfSlot("slot1()"); slot2Index = r1.metaObject()->indexOfSlot("slot2()"); slot3Index = r1.metaObject()->indexOfSlot("slot3()"); QVERIFY(slot1Index > 0); QVERIFY(slot2Index > 0); QVERIFY(slot3Index > 0); QVERIFY(QMetaObject::connect(&s, signal1Index, &r1, slot1Index)); QVERIFY(QMetaObject::connect(&s, signal3Index, &r2, slot3Index)); QVERIFY(QMetaObject::connect(&s, -1, &r2, slot2Index)); QCOMPARE(r1.count_slot1, 0); QCOMPARE(r1.count_slot2, 0); QCOMPARE(r1.count_slot3, 0); QCOMPARE(r2.count_slot1, 0); QCOMPARE(r2.count_slot2, 0); QCOMPARE(r2.count_slot3, 0); s.emitSignal1(); QCOMPARE(r1.count_slot1, 1); QCOMPARE(r1.count_slot2, 0); QCOMPARE(r1.count_slot3, 0); QCOMPARE(r2.count_slot1, 0); QCOMPARE(r2.count_slot2, 1); QCOMPARE(r2.count_slot3, 0); s.emitSignal2(); s.emitSignal3(); s.emitSignal4(); QCOMPARE(r1.count_slot1, 1); QCOMPARE(r1.count_slot2, 0); QCOMPARE(r1.count_slot3, 0); QCOMPARE(r2.count_slot1, 0); QCOMPARE(r2.count_slot2, 4); QCOMPARE(r2.count_slot3, 1); QVERIFY(QMetaObject::disconnect(&s, signal1Index, &r1, slot1Index)); QVERIFY(QMetaObject::disconnect(&s, signal3Index, &r2, slot3Index)); QVERIFY(QMetaObject::disconnect(&s, -1, &r2, slot2Index)); s.emitSignal1(); s.emitSignal2(); s.emitSignal3(); s.emitSignal4(); QCOMPARE(r1.count_slot1, 1); QCOMPARE(r1.count_slot2, 0); QCOMPARE(r1.count_slot3, 0); QCOMPARE(r2.count_slot1, 0); QCOMPARE(r2.count_slot2, 4); QCOMPARE(r2.count_slot3, 1); //some "dynamic" signal QVERIFY(QMetaObject::connect(&s, s.metaObject()->methodOffset() + 20, &r1, slot3Index)); QVERIFY(QMetaObject::connect(&s, s.metaObject()->methodOffset() + 35, &r2, slot1Index)); QVERIFY(QMetaObject::connect(&s, -1, &r1, slot2Index)); r1.reset(); r2.reset(); void *args[] = { 0 , 0 }; QMetaObject::activate(&s, s.metaObject()->methodOffset() + 20, args); QMetaObject::activate(&s, s.metaObject()->methodOffset() + 48, args); QCOMPARE(r1.count_slot1, 0); QCOMPARE(r1.count_slot2, 2); QCOMPARE(r1.count_slot3, 1); QCOMPARE(r2.count_slot1, 0); QCOMPARE(r2.count_slot2, 0); QCOMPARE(r2.count_slot3, 0); QMetaObject::activate(&s, s.metaObject()->methodOffset() + 35, args); s.emitSignal1(); s.emitSignal2(); QCOMPARE(r1.count_slot1, 0); QCOMPARE(r1.count_slot2, 5); QCOMPARE(r1.count_slot3, 1); QCOMPARE(r2.count_slot1, 1); QCOMPARE(r2.count_slot2, 0); QCOMPARE(r2.count_slot3, 0); } r1.reset(); r2.reset(); #define SIGNAL_INDEX(S) obj1.metaObject()->indexOfSignal(QMetaObject::normalizedSignature(#S)) OverloadObject obj1; QObject obj2, obj3; QMetaObject::connect(&obj1, SIGNAL_INDEX(sig(int, int)) , &r1, slot1Index); QMetaObject::connect(&obj1, SIGNAL_INDEX(sig(QObject *, QObject *, QObject *, QObject *)) , &r2, slot1Index); QMetaObject::connect(&obj1, SIGNAL_INDEX(sig(QObject *, QObject *, QObject *, QObject *)) , &r1, slot2Index); QMetaObject::connect(&obj1, SIGNAL_INDEX(sig(QObject *, OverloadObject *,QObject *,QObject *)) , &r2, slot2Index); QMetaObject::connect(&obj1, SIGNAL_INDEX(sig(int, int)) , &r1, slot3Index); emit obj1.sig(0.5); //connected to nothing emit obj1.sig(1, 'a'); //connected to nothing QCOMPARE(r1.count_slot1, 0); QCOMPARE(r1.count_slot2, 0); QCOMPARE(r1.count_slot3, 0); QCOMPARE(r2.count_slot1, 0); QCOMPARE(r2.count_slot2, 0); QCOMPARE(r2.count_slot3, 0); emit obj1.sig(1); //this signal is connected emit obj1.sig(&obj2); QCOMPARE(r1.count_slot1, 1); QCOMPARE(r1.count_slot2, 0); QCOMPARE(r1.count_slot3, 1); QCOMPARE(r2.count_slot1, 0); QCOMPARE(r2.count_slot2, 1); QCOMPARE(r2.count_slot3, 0); emit obj1.sig(&obj2, &obj3); //this signal is connected QCOMPARE(r1.count_slot1, 1); QCOMPARE(r1.count_slot2, 1); QCOMPARE(r1.count_slot3, 1); QCOMPARE(r2.count_slot1, 1); QCOMPARE(r2.count_slot2, 1); QCOMPARE(r2.count_slot3, 0); } void tst_QObject::qMetaObjectDisconnectOne() { SenderObject s; ReceiverObject r1; int signal1Index = s.metaObject()->indexOfSignal("signal1()"); int signal3Index = s.metaObject()->indexOfSignal("signal3()"); int slot1Index = r1.metaObject()->indexOfSlot("slot1()"); int slot2Index = r1.metaObject()->indexOfSlot("slot2()"); QVERIFY(signal1Index > 0); QVERIFY(signal3Index > 0); QVERIFY(slot1Index > 0); QVERIFY(slot2Index > 0); QVERIFY(QMetaObject::connect(&s, signal1Index, &r1, slot1Index)); QVERIFY(QMetaObject::connect(&s, signal3Index, &r1, slot2Index)); QVERIFY(QMetaObject::connect(&s, signal3Index, &r1, slot2Index)); QVERIFY(QMetaObject::connect(&s, signal3Index, &r1, slot2Index)); r1.reset(); QCOMPARE(r1.count_slot1, 0); QCOMPARE(r1.count_slot2, 0); s.emitSignal1(); QCOMPARE(r1.count_slot1, 1); QCOMPARE(r1.count_slot2, 0); s.emitSignal3(); QCOMPARE(r1.count_slot1, 1); QCOMPARE(r1.count_slot2, 3); r1.reset(); QVERIFY(QMetaObject::disconnectOne(&s, signal1Index, &r1, slot1Index)); QVERIFY(QMetaObject::disconnectOne(&s, signal3Index, &r1, slot2Index)); s.emitSignal1(); QCOMPARE(r1.count_slot1, 0); QCOMPARE(r1.count_slot2, 0); s.emitSignal3(); QCOMPARE(r1.count_slot1, 0); QCOMPARE(r1.count_slot2, 2); r1.reset(); QVERIFY(!QMetaObject::disconnectOne(&s, signal1Index, &r1, slot1Index)); QVERIFY( QMetaObject::disconnectOne(&s, signal3Index, &r1, slot2Index)); s.emitSignal1(); QCOMPARE(r1.count_slot1, 0); QCOMPARE(r1.count_slot2, 0); s.emitSignal3(); QCOMPARE(r1.count_slot1, 0); QCOMPARE(r1.count_slot2, 1); r1.reset(); QVERIFY(!QMetaObject::disconnectOne(&s, signal1Index, &r1, slot1Index)); QVERIFY( QMetaObject::disconnectOne(&s, signal3Index, &r1, slot2Index)); s.emitSignal1(); QCOMPARE(r1.count_slot1, 0); QCOMPARE(r1.count_slot2, 0); s.emitSignal3(); QCOMPARE(r1.count_slot1, 0); QCOMPARE(r1.count_slot2, 0); } class ConfusingObject : public SenderObject { W_OBJECT(ConfusingObject) public slots: void signal1() { s++; } W_SLOT(signal1) signals: void aPublicSlot() W_SIGNAL(aPublicSlot) public: int s; ConfusingObject() : s(0) {} friend class tst_QObject; }; void tst_QObject::sameName() { ConfusingObject c1, c2; QVERIFY(connect(&c1, SIGNAL(signal1()), &c1, SLOT(signal1()))); c1.emitSignal1(); QCOMPARE(c1.s, 1); QVERIFY(connect(&c2, SIGNAL(signal1()), &c1, SIGNAL(signal1()))); c2.emitSignal1(); QCOMPARE(c1.s, 2); #ifndef QT_NO_DEBUG QTest::ignoreMessage(QtWarningMsg, "QMetaObject::indexOfSignal: signal aPublicSlot() from SenderObject redefined in ConfusingObject"); #endif QVERIFY(connect(&c2, SIGNAL(aPublicSlot()), &c1, SLOT(signal1()))); c2.aPublicSlot(); QCOMPARE(c2.aPublicSlotCalled, 0); QCOMPARE(c1.aPublicSlotCalled, 0); QCOMPARE(c1.s, 3); #ifndef QT_NO_DEBUG QTest::ignoreMessage(QtWarningMsg, "QMetaObject::indexOfSignal: signal aPublicSlot() from SenderObject redefined in ConfusingObject"); #endif QVERIFY(connect(&c2, SIGNAL(aPublicSlot()), &c1, SLOT(aPublicSlot()))); c2.aPublicSlot(); QCOMPARE(c2.aPublicSlotCalled, 0); QCOMPARE(c1.aPublicSlotCalled, 1); QCOMPARE(c1.s, 4); } void tst_QObject::connectByMetaMethods() { SenderObject s; ReceiverObject r; const QMetaObject *smeta = s.metaObject(); const QMetaObject *rmeta = r.metaObject(); int sigIndx = smeta->indexOfSignal(QMetaObject::normalizedSignature("signal1()")); int slotIndx = rmeta->indexOfSlot(QMetaObject::normalizedSignature("slot1()")); QVERIFY( sigIndx != -1 ); QVERIFY( slotIndx != -1 ); QMetaMethod signal = smeta->method(sigIndx); QMetaMethod slot = rmeta->method(slotIndx); QVERIFY(connect(&s,signal, &r,slot)); QVERIFY(!r.called(1)); s.emitSignal1(); QVERIFY(r.called(1)); } void tst_QObject::connectByMetaMethodSlotInsteadOfSignal() { SenderObject s; ReceiverObject r; const QMetaObject *smeta = s.metaObject(); const QMetaObject *rmeta = r.metaObject(); int badIndx = smeta->indexOfSlot(QMetaObject::normalizedSignature("aPublicSlot()")); int slotIndx = rmeta->indexOfSlot(QMetaObject::normalizedSignature("slot1()")); QVERIFY( badIndx != -1 ); QVERIFY( slotIndx != -1 ); QMetaMethod badMethod = smeta->method(badIndx); QMetaMethod slot = rmeta->method(slotIndx); QTest::ignoreMessage(QtWarningMsg,"QObject::connect: Cannot connect SenderObject::aPublicSlot() to ReceiverObject::slot1()"); QVERIFY(!connect(&s,badMethod, &r,slot)); } class Constructable: public QObject { W_OBJECT(Constructable) public: Constructable(){} W_CONSTRUCTOR() }; void tst_QObject::connectConstructorByMetaMethod() { Constructable sc; Constructable rc; SenderObject s; ReceiverObject r; const QMetaObject cmeta = Constructable::staticMetaObject; const QMetaObject *smeta = s.metaObject(); const QMetaObject *rmeta = r.metaObject(); int constructorIndx = cmeta.indexOfConstructor(QMetaObject::normalizedSignature("Constructable()")); int sigIndx = smeta->indexOfSignal(QMetaObject::normalizedSignature("signal1()")); int slotIndx = rmeta->indexOfSlot(QMetaObject::normalizedSignature("slot1()")); QVERIFY( constructorIndx != -1 ); QVERIFY( sigIndx != -1 ); QVERIFY( slotIndx != -1 ); QMetaMethod constructor = cmeta.constructor(constructorIndx); QMetaMethod signal = smeta->method(sigIndx); QMetaMethod slot = rmeta->method(slotIndx); QTest::ignoreMessage(QtWarningMsg,"QObject::connect: Cannot connect Constructable::Constructable() to ReceiverObject::slot1()"); QVERIFY(!connect(&sc,constructor, &r,slot)); QTest::ignoreMessage(QtWarningMsg,"QObject::connect: Cannot connect SenderObject::signal1() to Constructable::Constructable()"); QVERIFY(!connect(&s,signal, &rc,constructor)); QTest::ignoreMessage(QtWarningMsg,"QObject::connect: Cannot connect Constructable::Constructable() to Constructable::Constructable()"); QVERIFY(!connect(&sc,constructor, &rc,constructor)); } void tst_QObject::disconnectByMetaMethod() { SenderObject s; ReceiverObject r1; ReceiverObject r2; QMetaMethod signal1 = s.metaObject()->method(s.metaObject()->indexOfMethod("signal1()")); QMetaMethod signal2 = s.metaObject()->method(s.metaObject()->indexOfMethod("signal2()")); QMetaMethod signal3 = s.metaObject()->method(s.metaObject()->indexOfMethod("signal3()")); QMetaMethod slot1 = r1.metaObject()->method(r1.metaObject()->indexOfMethod("slot1()")); QMetaMethod slot2 = r1.metaObject()->method(r1.metaObject()->indexOfMethod("slot2()")); QMetaMethod slot3 = r1.metaObject()->method(r1.metaObject()->indexOfMethod("slot3()")); QMetaMethod slot4 = r1.metaObject()->method(r1.metaObject()->indexOfMethod("slot4()")); connect(&s, signal1, &r1, slot1); s.emitSignal1(); QVERIFY(r1.called(1)); r1.reset(); // usual disconnect with all parameters given bool ret = QObject::disconnect(&s, signal1, &r1, slot1); s.emitSignal1(); QVERIFY(!r1.called(1)); r1.reset(); QVERIFY(ret); ret = QObject::disconnect(&s, signal1, &r1, slot1); QVERIFY(!ret); r1.reset(); connect(&s, signal1, &r1, slot1); connect(&s, signal1, &r1, slot2); connect(&s, signal1, &r1, slot3); connect(&s, signal2, &r1, slot4); // disconnect s's signal1() from all slots of r1 QObject::disconnect(&s, signal1, &r1, QMetaMethod()); s.emitSignal1(); s.emitSignal2(); QVERIFY(!r1.called(1)); QVERIFY(!r1.called(2)); QVERIFY(!r1.called(3)); QVERIFY(r1.called(4)); r1.reset(); // make sure all is disconnected again QObject::disconnect(&s, 0, &r1, 0); connect(&s, signal1, &r1, slot1); connect(&s, signal1, &r2, slot1); connect(&s, signal2, &r1, slot2); connect(&s, signal2, &r2, slot2); connect(&s, signal3, &r1, slot3); connect(&s, signal3, &r2, slot3); // disconnect signal1() from all receivers QObject::disconnect(&s, signal1, 0, QMetaMethod()); s.emitSignal1(); s.emitSignal2(); s.emitSignal3(); QVERIFY(!r1.called(1)); QVERIFY(!r2.called(1)); QVERIFY(r1.called(2)); QVERIFY(r2.called(2)); QVERIFY(r1.called(2)); QVERIFY(r2.called(2)); r1.reset(); r2.reset(); // disconnect all signals of s from all receivers QObject::disconnect(&s, 0, 0, 0); connect(&s, signal1, &r1, slot1); connect(&s, signal1, &r2, slot1); // disconnect all signals from slot1 of r1 QObject::disconnect(&s, QMetaMethod(), &r1, slot1); s.emitSignal1(); QVERIFY(!r1.called(1)); QVERIFY(r2.called(1)); } void tst_QObject::disconnectNotSignalMetaMethod() { SenderObject s; ReceiverObject r; connect(&s, SIGNAL(signal1()), &r, SLOT(slot1())); QMetaMethod slot = s.metaObject()->method( s.metaObject()->indexOfMethod("aPublicSlot()")); QTest::ignoreMessage(QtWarningMsg,"QObject::disconnect: Attempt to unbind non-signal SenderObject::aPublicSlot()"); QVERIFY(!QObject::disconnect(&s, slot, &r, QMetaMethod())); } class ThreadAffinityThread : public QThread { public: SenderObject *sender; ThreadAffinityThread(SenderObject *sender) : sender(sender) { } void run() { sender->emitSignal1(); } }; void tst_QObject::autoConnectionBehavior() { SenderObject *sender = new SenderObject; ReceiverObject *receiver = new ReceiverObject; connect(sender, SIGNAL(signal1()), receiver, SLOT(slot1())); // at emit, currentThread == sender->thread(), currentThread == receiver->thread(), sender->thread() == receiver->thread() QVERIFY(!receiver->called(1)); sender->emitSignal1(); QVERIFY(receiver->called(1)); receiver->reset(); // at emit, currentThread != sender->thread(), currentThread != receiver->thread(), sender->thread() == receiver->thread() ThreadAffinityThread emitThread1(sender); QVERIFY(!receiver->called(1)); emitThread1.start(); QVERIFY(emitThread1.wait(30000)); QVERIFY(!receiver->called(1)); QCoreApplication::sendPostedEvents(receiver, QEvent::MetaCall); QVERIFY(receiver->called(1)); receiver->reset(); // at emit, currentThread == sender->thread(), currentThread != receiver->thread(), sender->thread() != receiver->thread() sender->moveToThread(&emitThread1); QVERIFY(!receiver->called(1)); emitThread1.start(); QVERIFY(emitThread1.wait(30000)); QVERIFY(!receiver->called(1)); QCoreApplication::sendPostedEvents(receiver, QEvent::MetaCall); QVERIFY(receiver->called(1)); receiver->reset(); // at emit, currentThread != sender->thread(), currentThread == receiver->thread(), sender->thread() != receiver->thread() QVERIFY(!receiver->called(1)); sender->emitSignal1(); QVERIFY(receiver->called(1)); receiver->reset(); // at emit, currentThread != sender->thread(), currentThread != receiver->thread(), sender->thread() != receiver->thread() ThreadAffinityThread emitThread2(sender); QThread receiverThread; QTimer *timer = new QTimer; timer->setSingleShot(true); timer->setInterval(100); connect(&receiverThread, SIGNAL(started()), timer, SLOT(start())); connect(timer, SIGNAL(timeout()), &receiverThread, SLOT(quit()), Qt::DirectConnection); connect(&receiverThread, SIGNAL(finished()), timer, SLOT(deleteLater())); timer->moveToThread(&receiverThread); receiver->moveToThread(&receiverThread); QVERIFY(!receiver->called(1)); emitThread2.start(); QVERIFY(emitThread2.wait(30000)); QVERIFY(!receiver->called(1)); receiverThread.start(); QVERIFY(receiverThread.wait(30000)); QVERIFY(receiver->called(1)); receiver->reset(); delete sender; delete receiver; } class BaseDestroyed : public QObject { W_OBJECT(BaseDestroyed) QList fooList; bool destroyed; public: BaseDestroyed() : destroyed(false) { fooList << "a" << "b"; } ~BaseDestroyed() { QVERIFY(!destroyed); destroyed = true; } public slots: void slotUseList() { QVERIFY(!destroyed); fooList << "c" << "d"; } W_SLOT(slotUseList) }; static void processEvents() { qApp->processEvents(); } void tst_QObject::baseDestroyed() { { BaseDestroyed d; connect(&d, SIGNAL(destroyed()), &d, SLOT(slotUseList())); //When d goes out of scope, slotUseList should not be called as the BaseDestroyed has // already been destroyed while ~QObject emit destroyed } { BaseDestroyed d; connect(&d, &QObject::destroyed, processEvents); QMetaObject::invokeMethod(&d, "slotUseList", Qt::QueuedConnection); //the destructor will call processEvents, that should not call the slotUseList } } void tst_QObject::pointerConnect() { SenderObject s; ReceiverObject r1; ReceiverObject r2; r1.reset(); r2.reset(); ReceiverObject::sequence = 0; QTimer timer; QVERIFY(connect(&s, &SenderObject::signal1 , &r1, &ReceiverObject::slot1)); QVERIFY(connect(&s, &SenderObject::signal1 , &r2, &ReceiverObject::slot1)); QVERIFY(connect(&s, &SenderObject::signal1 , &r1, &ReceiverObject::slot3)); QVERIFY(connect(&s, &SenderObject::signal3 , &r1, &ReceiverObject::slot3)); QVERIFY2(connect(&timer, &QTimer::timeout, &r1, &ReceiverObject::deleteLater), "Signal connection failed most likely due to failing comparison of pointers to member " "functions caused by problems with -reduce-relocations on this platform."); s.emitSignal1(); s.emitSignal2(); s.emitSignal3(); s.emitSignal4(); QCOMPARE(r1.count_slot1, 1); QCOMPARE(r1.count_slot2, 0); QCOMPARE(r1.count_slot3, 2); QCOMPARE(r1.count_slot4, 0); QCOMPARE(r2.count_slot1, 1); QCOMPARE(r2.count_slot2, 0); QCOMPARE(r2.count_slot3, 0); QCOMPARE(r2.count_slot4, 0); QCOMPARE(r1.sequence_slot1, 1); QCOMPARE(r2.sequence_slot1, 2); QCOMPARE(r1.sequence_slot3, 4); r1.reset(); r2.reset(); ReceiverObject::sequence = 0; QVERIFY(connect(&s, &SenderObject::signal4, &r1, &ReceiverObject::slot4)); QVERIFY(connect(&s, &SenderObject::signal4, &r2, &ReceiverObject::slot4)); QVERIFY(connect(&s, &SenderObject::signal1, &r2, &ReceiverObject::slot4)); s.emitSignal4(); QCOMPARE(r1.count_slot4, 1); QCOMPARE(r2.count_slot4, 1); QCOMPARE(r1.sequence_slot4, 1); QCOMPARE(r2.sequence_slot4, 2); r1.reset(); r2.reset(); ReceiverObject::sequence = 0; connect(&s, &SenderObject::signal4 , &r1, &ReceiverObject::slot4); s.emitSignal4(); QCOMPARE(r1.count_slot4, 2); QCOMPARE(r2.count_slot4, 1); QCOMPARE(r1.sequence_slot4, 3); QCOMPARE(r2.sequence_slot4, 2); QMetaObject::Connection con; QVERIFY(!con); QVERIFY(!QObject::disconnect(con)); //connect a slot to a signal (== error) QTest::ignoreMessage(QtWarningMsg, "QObject::connect: signal not found in ReceiverObject"); con = connect(&r1, &ReceiverObject::slot4 , &s, &SenderObject::signal4); QVERIFY(!con); QVERIFY(!QObject::disconnect(con)); } void tst_QObject::pointerDisconnect() { SenderObject s; ReceiverObject r1; ReceiverObject r2; connect(&s, &SenderObject::signal1, &r1, &ReceiverObject::slot1); connect(&s, &SenderObject::signal2, &r1, &ReceiverObject::slot2); connect(&s, &SenderObject::signal3, &r1, &ReceiverObject::slot3); connect(&s, &SenderObject::signal4, &r1, &ReceiverObject::slot4); s.emitSignal1(); s.emitSignal2(); s.emitSignal3(); s.emitSignal4(); QVERIFY(r1.called(1)); QVERIFY(r1.called(2)); QVERIFY(r1.called(3)); QVERIFY(r1.called(4)); r1.reset(); // usual disconnect with all parameters given bool ret = QObject::disconnect(&s, &SenderObject::signal1, &r1, &ReceiverObject::slot1); s.emitSignal1(); QVERIFY(!r1.called(1)); r1.reset(); QVERIFY(ret); ret = QObject::disconnect(&s, &SenderObject::signal1, &r1, &ReceiverObject::slot1); QVERIFY(!ret); // disconnect all signals from s from all slots from r1 QObject::disconnect(&s, 0, &r1, 0); s.emitSignal2(); s.emitSignal3(); s.emitSignal4(); QVERIFY(!r1.called(2)); QVERIFY(!r1.called(3)); QVERIFY(!r1.called(4)); r1.reset(); connect(&s, &SenderObject::signal1, &r1, &ReceiverObject::slot1); connect(&s, &SenderObject::signal1, &r1, &ReceiverObject::slot2); connect(&s, &SenderObject::signal1, &r1, &ReceiverObject::slot3); connect(&s, &SenderObject::signal2, &r1, &ReceiverObject::slot4); // disconnect s's signal1() from all slots of r1 QObject::disconnect(&s, &SenderObject::signal1, &r1, 0); s.emitSignal1(); s.emitSignal2(); QVERIFY(!r1.called(1)); QVERIFY(!r1.called(2)); QVERIFY(!r1.called(3)); QVERIFY(r1.called(4)); r1.reset(); // make sure all is disconnected again QObject::disconnect(&s, 0, &r1, 0); connect(&s, &SenderObject::signal1, &r1, &ReceiverObject::slot1); connect(&s, &SenderObject::signal1, &r2, &ReceiverObject::slot1); connect(&s, &SenderObject::signal2, &r1, &ReceiverObject::slot2); connect(&s, &SenderObject::signal2, &r2, &ReceiverObject::slot2); connect(&s, &SenderObject::signal3, &r1, &ReceiverObject::slot3); connect(&s, &SenderObject::signal3, &r2, &ReceiverObject::slot3); // disconnect signal1() from all receivers QObject::disconnect(&s, &SenderObject::signal1, 0, 0); s.emitSignal1(); s.emitSignal2(); s.emitSignal3(); QVERIFY(!r1.called(1)); QVERIFY(!r2.called(1)); QVERIFY(r1.called(2)); QVERIFY(r2.called(2)); QVERIFY(r1.called(2)); QVERIFY(r2.called(2)); r1.reset(); r2.reset(); // disconnect all signals of s from all receivers QObject::disconnect(&s, 0, 0, 0); QVERIFY(!r1.called(2)); QVERIFY(!r2.called(2)); QVERIFY(!r1.called(2)); QVERIFY(!r2.called(2)); } void tst_QObject::emitInDefinedOrderPointer() { SenderObject sender; ReceiverObject receiver1, receiver2, receiver3, receiver4; QMetaObject::Connection h0 = connect(&sender, &SenderObject::signal1, &receiver1, &SequenceObject::slot1); QMetaObject::Connection h1 = connect(&sender, &SenderObject::signal1, &receiver2, &SequenceObject::slot1); QVERIFY(h0); QVERIFY(h1); connect(&sender, &SenderObject::signal1, &receiver3, &SequenceObject::slot1); connect(&sender, &SenderObject::signal1, &receiver4, &SequenceObject::slot1); connect(&sender, &SenderObject::signal1, &receiver1, &SequenceObject::slot2); connect(&sender, &SenderObject::signal1, &receiver2, &SequenceObject::slot2); connect(&sender, &SenderObject::signal1, &receiver3, &SequenceObject::slot2); connect(&sender, &SenderObject::signal1, &receiver4, &SequenceObject::slot2); int sequence; ReceiverObject::sequence = sequence = 0; sender.emitSignal1(); QCOMPARE(receiver1.sequence_slot1, ++sequence); QCOMPARE(receiver2.sequence_slot1, ++sequence); QCOMPARE(receiver3.sequence_slot1, ++sequence); QCOMPARE(receiver4.sequence_slot1, ++sequence); QCOMPARE(receiver1.sequence_slot2, ++sequence); QCOMPARE(receiver2.sequence_slot2, ++sequence); QCOMPARE(receiver3.sequence_slot2, ++sequence); QCOMPARE(receiver4.sequence_slot2, ++sequence); QObject::disconnect(h1); h1 = connect(&sender, &SenderObject::signal1, &receiver2, &SequenceObject::slot1); ReceiverObject::sequence = sequence = 0; sender.emitSignal1(); QCOMPARE(receiver1.sequence_slot1, ++sequence); QCOMPARE(receiver3.sequence_slot1, ++sequence); QCOMPARE(receiver4.sequence_slot1, ++sequence); QCOMPARE(receiver1.sequence_slot2, ++sequence); QCOMPARE(receiver2.sequence_slot2, ++sequence); QCOMPARE(receiver3.sequence_slot2, ++sequence); QCOMPARE(receiver4.sequence_slot2, ++sequence); QCOMPARE(receiver2.sequence_slot1, ++sequence); QObject::disconnect(h0); h0 = connect(&sender, &SenderObject::signal1, &receiver1, &SequenceObject::slot1); ReceiverObject::sequence = sequence = 0; sender.emitSignal1(); QCOMPARE(receiver3.sequence_slot1, ++sequence); QCOMPARE(receiver4.sequence_slot1, ++sequence); QCOMPARE(receiver1.sequence_slot2, ++sequence); QCOMPARE(receiver2.sequence_slot2, ++sequence); QCOMPARE(receiver3.sequence_slot2, ++sequence); QCOMPARE(receiver4.sequence_slot2, ++sequence); QCOMPARE(receiver2.sequence_slot1, ++sequence); QCOMPARE(receiver1.sequence_slot1, ++sequence); QVERIFY(QObject::disconnect(h0)); QVERIFY(!QObject::disconnect(h0)); } void tst_QObject::customTypesPointer() { CustomType t0; CustomType t1(1, 2, 3); CustomType t2(2, 3, 4); { QCustomTypeChecker checker; QCOMPARE(instanceCount, 4); connect(&checker, &QCustomTypeChecker::signal1, &checker, &QCustomTypeChecker::slot1, Qt::DirectConnection); QCOMPARE(checker.received.value(), 0); checker.doEmit(t1); QCOMPARE(checker.received.value(), t1.value()); checker.received = t0; checker.disconnect(); int idx = qRegisterMetaType("CustomType"); QCOMPARE(QMetaType::type("CustomType"), idx); connect(&checker, &QCustomTypeChecker::signal1, &checker, &QCustomTypeChecker::slot1, Qt::QueuedConnection); QCOMPARE(instanceCount, 4); checker.doEmit(t2); QCOMPARE(instanceCount, 5); QCOMPARE(checker.received.value(), t0.value()); QCoreApplication::processEvents(); QCOMPARE(checker.received.value(), t2.value()); QCOMPARE(instanceCount, 4); QVERIFY(QMetaType::isRegistered(idx)); QCOMPARE(qRegisterMetaType("CustomType"), idx); QCOMPARE(QMetaType::type("CustomType"), idx); QVERIFY(QMetaType::isRegistered(idx)); // Test auto registered type (QList) QList list; QCOMPARE(instanceCount, 4); list.append(t1); QCOMPARE(instanceCount, 5); QVERIFY(connect(&checker, &QCustomTypeChecker::signal2, &checker, &QCustomTypeChecker::slot2, Qt::QueuedConnection)); emit checker.signal2(list); QCOMPARE(instanceCount, 5); //because the list is implicitly shared. list.clear(); QCOMPARE(instanceCount, 5); QCoreApplication::processEvents(); QCOMPARE(checker.received.value(), t1.value()); QCOMPARE(instanceCount, 4); } QCOMPARE(instanceCount, 3); } void tst_QObject::connectCxx0x() { SenderObject s; ReceiverObject r1; QObject::connect(&s, &SenderObject::signal1, &r1, &ReceiverObject::slot1); QObject::connect(&s, &SenderObject::signal3, &r1, &ReceiverObject::slot2); QObject::connect(&s, &SenderObject::signal3, &r1, &ReceiverObject::slot2); QObject::connect(&s, &SenderObject::signal3, &r1, &ReceiverObject::slot2); r1.reset(); QCOMPARE(r1.count_slot1, 0); QCOMPARE(r1.count_slot2, 0); s.emitSignal1(); QCOMPARE(r1.count_slot1, 1); QCOMPARE(r1.count_slot2, 0); s.emitSignal3(); QCOMPARE(r1.count_slot1, 1); QCOMPARE(r1.count_slot2, 3); // connect signal to signal QObject::connect(&s, &SenderObject::signal2, &s, &SenderObject::signal1); r1.reset(); s.emitSignal2(); QCOMPARE(r1.count_slot1, 1); } int receivedCount; void receiverFunction() { ++receivedCount; } void tst_QObject::connectToStaticCxx0x() { SenderObject *s = new SenderObject; void (*receiver)() = receiverFunction; QObject::connect(s, &SenderObject::signal1, receiver); receivedCount = 0; s->emitSignal1(); QCOMPARE(receivedCount, 1); QObject::connect(s, &SenderObject::signal1, receiver); receivedCount = 0; s->emitSignal1(); QCOMPARE(receivedCount, 2); delete s; } class LotsOfSignalsAndSlots: public QObject { W_OBJECT(LotsOfSignalsAndSlots) typedef void (*fptr)(); public slots: void slot_v() {} W_SLOT(slot_v) void slot_v_noexcept() Q_DECL_NOTHROW {} W_SLOT(slot_v_noexcept) void slot_vi(int) {} W_SLOT(slot_vi) void slot_vi_noexcept() Q_DECL_NOTHROW {} W_SLOT(slot_vi_noexcept) void slot_vii(int, int) {} W_SLOT(slot_vii) void slot_viii(int, int, int) {} W_SLOT(slot_viii) int slot_i() { return 0; } W_SLOT(slot_i) int slot_i_noexcept() Q_DECL_NOTHROW { return 0; } W_SLOT(slot_i_noexcept) int slot_ii(int) { return 0; } W_SLOT(slot_ii) int slot_iii(int, int) { return 0; } W_SLOT(slot_iii) int slot_iiii(int, int, int) { return 0; } W_SLOT(slot_iiii) void slot_vRi(int &) {} W_SLOT(slot_vRi) void slot_vs(short) {} W_SLOT(slot_vs) void slot_vRs(short&) {} W_SLOT(slot_vRs) /* #ifdef Q_COMPILER_RVALUE_REFS void slot_vOi(int &&) {} W_SLOT(slot_vOi) void slot_vOs(short &&) {} W_SLOT(slot_vOs) #endif*/ void slot_vPFvvE(fptr) {} W_SLOT(slot_vPFvvE,(fptr)) void const_slot_v() const {} W_SLOT(const_slot_v); void const_slot_v_noexcept() const Q_DECL_NOTHROW {} W_SLOT(const_slot_v_noexcept); void const_slot_vi(int) const {} W_SLOT(const_slot_vi); void const_slot_vi_noexcept(int) Q_DECL_NOTHROW {} W_SLOT(const_slot_vi_noexcept); static void static_slot_v() {} W_SLOT(static_slot_v) static void static_slot_v_noexcept() Q_DECL_NOTHROW {} W_SLOT(static_slot_v_noexcept) static void static_slot_vi(int) {} W_SLOT(static_slot_vi) static void static_slot_vi_noexcept(int) Q_DECL_NOTHROW {} W_SLOT(static_slot_vi_noexcept) static void static_slot_vii(int, int) {} W_SLOT(static_slot_vii) static void static_slot_viii(int, int, int) {} W_SLOT(static_slot_viii) static int static_slot_i() { return 0; } W_SLOT(static_slot_i) static int static_slot_i_noexcept() Q_DECL_NOTHROW { return 0; } W_SLOT(static_slot_i_noexcept) static int static_slot_ii(int) { return 0; } W_SLOT(static_slot_ii) static int static_slot_iii(int, int) { return 0; } W_SLOT(static_slot_iii) static int static_slot_iiii(int, int, int) { return 0; } W_SLOT(static_slot_iiii) static void static_slot_vRi(int &) {} W_SLOT(static_slot_vRi) static void static_slot_vs(short) {} W_SLOT(static_slot_vs) static void static_slot_vRs(short&) {} W_SLOT(static_slot_vRs) /* #if defined(Q_COMPILER_RVALUE_REFS) || defined(QT_ENABLE_CXX0X) static void static_slot_vOi(int &&) {} W_SLOT(static_slot_vOi) static void static_slot_vOs(short &&) {} W_SLOT(static_slot_vOs) #endif*/ static void static_slot_vPFvvE(fptr) {} W_SLOT(static_slot_vPFvvE,(fptr)) void slot_vcRQObject(const QObject &) {} W_SLOT(slot_vcRQObject) void slot_vRQObject(QObject &) {} W_SLOT(slot_vRQObject) signals: void signal_v() W_SIGNAL(signal_v) void signal_vi(int a) W_SIGNAL(signal_vi, a) void signal_vii(int a, int b) W_SIGNAL(signal_vii, a,b) void signal_viii(int a, int b, int c) W_SIGNAL(signal_viii, a,b,c) void signal_vRi(int &a) W_SIGNAL(signal_vRi, a) void signal_vs(short a) W_SIGNAL(signal_vs, a) void signal_vRs(short &a) W_SIGNAL(signal_vRs, a) /* #if defined(Q_COMPILER_RVALUE_REFS) || defined(QT_ENABLE_CXX0X) void signal_vOi(int &&) W_SIGNAL() void signal_vOs(short &&) W_SIGNAL() #endif*/ void signal_vPFvvE(fptr a) W_SIGNAL(signal_vPFvvE,(fptr), a) void const_signal_v() const W_SIGNAL(const_signal_v) void const_signal_vi(int a) const W_SIGNAL(const_signal_vi, a) void signal_vcRQObject(const QObject &a) W_SIGNAL(signal_vcRQObject, a) void signal_vRQObject(QObject &a) W_SIGNAL(signal_vRQObject, a) void signal(short&a, short b, long long c, short d) W_SIGNAL(signal, a,b,c,d) void otherSignal(const char *a) W_SIGNAL(otherSignal, a) }; void tst_QObject::connectCxx0xTypeMatching() { // this is just about connecting the signals to the slots // if this fails, this will be a compiler failure typedef LotsOfSignalsAndSlots Foo; Foo obj; // member connects QObject::connect(&obj, &Foo::signal_v, &obj, &Foo::slot_v); QObject::connect(&obj, &Foo::signal_v, &obj, &Foo::slot_i); QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::slot_v); QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::slot_i); QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::slot_vi); QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::slot_ii); QObject::connect(&obj, &Foo::signal_vii, &obj, &Foo::slot_v); QObject::connect(&obj, &Foo::signal_vii, &obj, &Foo::slot_i); QObject::connect(&obj, &Foo::signal_vii, &obj, &Foo::slot_vi); QObject::connect(&obj, &Foo::signal_vii, &obj, &Foo::slot_ii); QObject::connect(&obj, &Foo::signal_vii, &obj, &Foo::slot_vii); QObject::connect(&obj, &Foo::signal_vii, &obj, &Foo::slot_iii); QObject::connect(&obj, &Foo::signal_viii, &obj, &Foo::slot_v); QObject::connect(&obj, &Foo::signal_viii, &obj, &Foo::slot_i); QObject::connect(&obj, &Foo::signal_viii, &obj, &Foo::slot_vi); QObject::connect(&obj, &Foo::signal_viii, &obj, &Foo::slot_ii); QObject::connect(&obj, &Foo::signal_viii, &obj, &Foo::slot_vii); QObject::connect(&obj, &Foo::signal_viii, &obj, &Foo::slot_iii); QObject::connect(&obj, &Foo::signal_viii, &obj, &Foo::slot_viii); QObject::connect(&obj, &Foo::signal_viii, &obj, &Foo::slot_iiii); QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::slot_vi); // repeated from above QObject::connect(&obj, &Foo::signal_vRi, &obj, &Foo::slot_vi); QObject::connect(&obj, &Foo::signal_vRi, &obj, &Foo::slot_vRi); /*#if defined(Q_COMPILER_RVALUE_REFS) || defined(QT_ENABLE_CXX0X) QObject::connect(&obj, &Foo::signal_vOi, &obj, &Foo::slot_vi); QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::slot_vOi); QObject::connect(&obj, &Foo::signal_vRi, &obj, &Foo::slot_vOi); QObject::connect(&obj, &Foo::signal_vOi, &obj, &Foo::slot_vOi); #endif*/ // these are not supposed to compile: //QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::slot_vRi); //QObject::connect(&obj, &Foo::signal_vOi, &obj, &Foo::slot_vRi); QObject::connect(&obj, &Foo::signal_vs, &obj, &Foo::slot_vi); QObject::connect(&obj, &Foo::signal_vRs, &obj, &Foo::slot_vi); /*#if defined(Q_COMPILER_RVALUE_REFS) || defined(QT_ENABLE_CXX0X) QObject::connect(&obj, &Foo::signal_vOs, &obj, &Foo::slot_vi); QObject::connect(&obj, &Foo::signal_vRs, &obj, &Foo::slot_vOi); QObject::connect(&obj, &Foo::signal_vOs, &obj, &Foo::slot_vOi); // these are not supposed to compile: //QObject::connect(&obj, &Foo::signal_vOs, &obj, &Foo::slot_vRi); //QObject::connect(&obj, &Foo::signal_vRs, &obj, &Foo::slot_vRi); #endif*/ QObject::connect(&obj, &Foo::signal_vPFvvE, &obj, &Foo::slot_v); QObject::connect(&obj, &Foo::signal_vPFvvE, &obj, &Foo::slot_i); QObject::connect(&obj, &Foo::signal_vPFvvE, &obj, &Foo::slot_vPFvvE); QObject::connect(&obj, &Foo::signal_v, &Foo::static_slot_v); QObject::connect(&obj, &Foo::signal_v, &Foo::static_slot_i); QObject::connect(&obj, &Foo::signal_vi, &Foo::static_slot_v); QObject::connect(&obj, &Foo::signal_vi, &Foo::static_slot_i); QObject::connect(&obj, &Foo::signal_vi, &Foo::static_slot_vi); QObject::connect(&obj, &Foo::signal_vi, &Foo::static_slot_ii); QObject::connect(&obj, &Foo::signal_vii, &Foo::static_slot_v); QObject::connect(&obj, &Foo::signal_vii, &Foo::static_slot_i); QObject::connect(&obj, &Foo::signal_vii, &Foo::static_slot_vi); QObject::connect(&obj, &Foo::signal_vii, &Foo::static_slot_ii); QObject::connect(&obj, &Foo::signal_vii, &Foo::static_slot_vii); QObject::connect(&obj, &Foo::signal_vii, &Foo::static_slot_iii); QObject::connect(&obj, &Foo::signal_viii, &Foo::static_slot_v); QObject::connect(&obj, &Foo::signal_viii, &Foo::static_slot_i); QObject::connect(&obj, &Foo::signal_viii, &Foo::static_slot_vi); QObject::connect(&obj, &Foo::signal_viii, &Foo::static_slot_ii); QObject::connect(&obj, &Foo::signal_viii, &Foo::static_slot_vii); QObject::connect(&obj, &Foo::signal_viii, &Foo::static_slot_iii); QObject::connect(&obj, &Foo::signal_viii, &Foo::static_slot_viii); QObject::connect(&obj, &Foo::signal_viii, &Foo::static_slot_iiii); /*#if defined(Q_COMPILER_RVALUE_REFS) && defined(QT_ENABLE_CXX0X) QObject::connect(&obj, &Foo::signal_vi, &Foo::static_slot_vOi); QObject::connect(&obj, &Foo::signal_vRi, &Foo::static_slot_vi); QObject::connect(&obj, &Foo::signal_vRi, &Foo::static_slot_vRi); QObject::connect(&obj, &Foo::signal_vRi, &Foo::static_slot_vOi); QObject::connect(&obj, &Foo::signal_vOi, &Foo::static_slot_vi); QObject::connect(&obj, &Foo::signal_vOi, &Foo::static_slot_vOi); //QObject::connect(&obj, &Foo::signal_vi, &Foo::static_slot_vRi); //QObject::connect(&obj, &Foo::signal_vOi, &Foo::static_slot_vRi); #endif*/ QObject::connect(&obj, &Foo::signal_vs, &Foo::static_slot_vi); QObject::connect(&obj, &Foo::signal_vRs, &Foo::static_slot_vi); /*#if defined(Q_COMPILER_RVALUE_REFS) && defined(QT_ENABLE_CXX0X) QObject::connect(&obj, &Foo::signal_vOs, &Foo::static_slot_vi); QObject::connect(&obj, &Foo::signal_vRs, &Foo::static_slot_vOi); QObject::connect(&obj, &Foo::signal_vOs, &Foo::static_slot_vOi); //QObject::connect(&obj, &Foo::signal_vOs, &Foo::static_slot_vRi); //QObject::connect(&obj, &Foo::signal_vRs, &Foo::static_slot_vRi); #endif*/ QObject::connect(&obj, &Foo::signal_vPFvvE, &Foo::static_slot_v); QObject::connect(&obj, &Foo::signal_vPFvvE, &Foo::static_slot_i); QObject::connect(&obj, &Foo::signal_vPFvvE, &Foo::static_slot_vPFvvE); QVERIFY(QObject::connect(&obj, &Foo::const_signal_v, &obj, &Foo::const_slot_v)); QVERIFY(QObject::connect(&obj, &Foo::const_signal_vi, &obj, &Foo::const_slot_v)); QVERIFY(QObject::connect(&obj, &Foo::const_signal_vi, &obj, &Foo::slot_vi)); QVERIFY(QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::const_slot_vi)); QVERIFY(QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::const_slot_v)); QVERIFY(QObject::connect(&obj, &Foo::signal_vcRQObject, &obj, &Foo::slot_vcRQObject)); QVERIFY(QObject::connect(&obj, &Foo::signal_vRQObject, &obj, &Foo::slot_vRQObject)); QVERIFY(QObject::connect(&obj, &Foo::signal_vRQObject, &obj, &Foo::slot_vcRQObject)); // QVERIFY(QObject::connect(&obj, &Foo::signal_vcRQObject, &obj, &Foo::slot_vRQObject)); // Should be an error (const& -> &) QVERIFY(QObject::connect(&obj, &Foo::signal_vRi, &obj, &Foo::slot_vs)); } void receiverFunction_noexcept() Q_DECL_NOTHROW {} struct Functor_noexcept { void operator()() Q_DECL_NOTHROW {} }; void tst_QObject::connectCxx17Noexcept() { // this is about connecting signals to slots with the Q_DECL_NOTHROW qualifier // as semantics changed due to http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html typedef LotsOfSignalsAndSlots Foo; Foo obj; QObject::connect(&obj, &Foo::signal_v, &obj, &Foo::slot_v_noexcept); QObject::connect(&obj, &Foo::signal_v, &obj, &Foo::slot_i_noexcept); QObject::connect(&obj, &Foo::signal_v, &obj, &Foo::slot_vi_noexcept); QObject::connect(&obj, &Foo::signal_vii, &Foo::static_slot_v_noexcept); QObject::connect(&obj, &Foo::signal_vii, &Foo::static_slot_i_noexcept); QObject::connect(&obj, &Foo::signal_vii, &Foo::static_slot_vi_noexcept); QVERIFY(QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::const_slot_vi_noexcept)); QVERIFY(QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::const_slot_v_noexcept)); QObject::connect(&obj, &Foo::signal_v, receiverFunction_noexcept); Functor_noexcept fn; QObject::connect(&obj, &Foo::signal_v, fn); } class StringVariant : public QObject { W_OBJECT(StringVariant) signals: void stringSignal(const QString &str) W_SIGNAL(stringSignal, str) public slots: void variantSlot(const QVariant &v) { var = v; } W_SLOT(variantSlot) public: QVariant var; friend class tst_QObject; }; struct Functor { QVariant *var; void operator() (const QVariant &v) { *var = v; } }; void tst_QObject::connectConvert() { StringVariant obj; QVERIFY(connect(&obj, &StringVariant::stringSignal, &obj, &StringVariant::variantSlot)); QString s = QString::fromLatin1("Hello World"); emit obj.stringSignal(s); QCOMPARE(obj.var.toString(), s); QVERIFY(obj.var.toString().isSharedWith(s)); QVariant var; Functor f; f.var = &var; QVERIFY(connect(&obj, &StringVariant::stringSignal, f)); s = QString::fromLatin1("GoodBye"); emit obj.stringSignal(s); QCOMPARE(obj.var.toString(), s); QVERIFY(obj.var.toString().isSharedWith(s)); QCOMPARE(var, obj.var); } W_REGISTER_ARGTYPE(QString&) W_REGISTER_ARGTYPE(bool*) W_REGISTER_ARGTYPE(QString*) class ConnectWithReferenceObject : public QObject { W_OBJECT(ConnectWithReferenceObject) friend class tst_QObject; signals: void boolRef(bool &a, bool b) W_SIGNAL(boolRef,a,b) void stringRef(QString &a, const QString & b) W_SIGNAL(stringRef,a,b) void boolPtr(bool *a, bool b) W_SIGNAL(boolPtr,a,b) void stringPtr(QString *a, const QString & b) W_SIGNAL(stringPtr,a,b) public slots: void boolRefSlot(bool &b1, bool b2) { b1 = b2; } W_SLOT(boolRefSlot) void stringRefSlot(QString &s1, const QString &s2) { s1 = s2; } W_SLOT(stringRefSlot) void boolPtrSlot(bool *b1, bool b2) { *b1 = b2; } W_SLOT(boolPtrSlot) void stringPtrSlot(QString *s1, const QString &s2) { *s1 = s2; } W_SLOT(stringPtrSlot) void stringSlot1(QString s) { last = s; } W_SLOT(stringSlot1) void stringSlot2(const QString &s) { last = s; } W_SLOT(stringSlot2) void stringSlot3(QString &s) { last = s; } W_SLOT(stringSlot3) public: QString last; }; void tst_QObject::connectWithReference() { ConnectWithReferenceObject o; bool b1 = true; QString s1 = QString::fromLatin1("str1"); const QString s2 = QString::fromLatin1("str2"); const QString s3 = QString::fromLatin1("str3"); o.boolRef(b1, false); o.stringRef(s1, s2); QCOMPARE(b1, true); QCOMPARE(s1, QString::fromLatin1("str1")); o.boolPtr(&b1, false); o.stringPtr(&s1, s2); QCOMPARE(b1, true); QCOMPARE(s1, QString::fromLatin1("str1")); QVERIFY(connect(&o, &ConnectWithReferenceObject::boolRef, &o, &ConnectWithReferenceObject::boolRefSlot)); QVERIFY(connect(&o, &ConnectWithReferenceObject::stringRef, &o, &ConnectWithReferenceObject::stringRefSlot)); QVERIFY(connect(&o, &ConnectWithReferenceObject::boolPtr, &o, &ConnectWithReferenceObject::boolPtrSlot)); QVERIFY(connect(&o, &ConnectWithReferenceObject::stringPtr, &o, &ConnectWithReferenceObject::stringPtrSlot)); o.boolRef(b1, false); o.stringRef(s1, s2); QCOMPARE(b1, false); QCOMPARE(s1, QString::fromLatin1("str2")); o.boolPtr(&b1, true); o.stringPtr(&s1, s3); QCOMPARE(b1, true); QCOMPARE(s1, QString::fromLatin1("str3")); { ConnectWithReferenceObject o2; QVERIFY(connect(&o2, &ConnectWithReferenceObject::stringRef, &o2, &ConnectWithReferenceObject::stringSlot1)); o2.stringRef(s1, s2); QCOMPARE(s1, s3); QCOMPARE(o2.last, s3); } { ConnectWithReferenceObject o2; QVERIFY(connect(&o2, &ConnectWithReferenceObject::stringRef, &o2, &ConnectWithReferenceObject::stringSlot2)); o2.stringRef(s1, s2); QCOMPARE(s1, s3); QCOMPARE(o2.last, s3); } { ConnectWithReferenceObject o2; QVERIFY(connect(&o2, &ConnectWithReferenceObject::stringRef, &o2, &ConnectWithReferenceObject::stringSlot3)); o2.stringRef(s1, s2); QCOMPARE(s1, s3); QCOMPARE(o2.last, s3); } } class ManyArgumentObject : public QObject { W_OBJECT(ManyArgumentObject) signals: void signal1(const QString &a) W_SIGNAL(signal1,a) void signal2(const QString &a, const QString &b) W_SIGNAL(signal2,a,b) void signal3(const QString &a, const QString &b, const QString &c) W_SIGNAL(signal3,a,b,c) void signal4(const QString &a, const QString &b, const QString &c, const QString&d) W_SIGNAL(signal4,a,b,c,d) void signal5(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e) W_SIGNAL(signal5,a,b,c,d,e) void signal6(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e, const QString&f) W_SIGNAL(signal6,a,b,c,d,e,f) public slots: #define MANYARGUMENT_COMPARE(L) QCOMPARE(L, QString(#L)) void slot1(const QString &a) { MANYARGUMENT_COMPARE(a); count++; } W_SLOT(slot1) void slot2(const QString &a, const QString &b) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); count++; } W_SLOT(slot2) void slot3(const QString &a, const QString &b, const QString &c) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); count++; } W_SLOT(slot3) void slot4(const QString &a, const QString &b, const QString &c, const QString&d) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); MANYARGUMENT_COMPARE(d); count++; } W_SLOT(slot4) void slot5(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); MANYARGUMENT_COMPARE(d); MANYARGUMENT_COMPARE(e); count++; } W_SLOT(slot5) void slot6(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e, const QString&f) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); MANYARGUMENT_COMPARE(d); MANYARGUMENT_COMPARE(e); MANYARGUMENT_COMPARE(f); count++; } W_SLOT(slot6) public: int count; }; namespace ManyArgumentNamespace { int count; void slot1(const QString &a) { MANYARGUMENT_COMPARE(a); count++; } void slot2(const QString &a, const QString &b) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); count++; } void slot3(const QString &a, const QString &b, const QString &c) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); count++; } void slot4(const QString &a, const QString &b, const QString &c, const QString&d) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); MANYARGUMENT_COMPARE(d); count++; } void slot5(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); MANYARGUMENT_COMPARE(d); MANYARGUMENT_COMPARE(e); count++; } void slot6(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e, const QString&f) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); MANYARGUMENT_COMPARE(d); MANYARGUMENT_COMPARE(e); MANYARGUMENT_COMPARE(f); count++; } struct Funct1 { void operator()(const QString &a) { MANYARGUMENT_COMPARE(a); count++; } }; struct Funct2 { void operator()(const QString &a, const QString &b) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); count++; } }; struct Funct3 { void operator()(const QString &a, const QString &b, const QString &c) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); count++; } }; struct Funct4 { void operator()(const QString &a, const QString &b, const QString &c, const QString&d) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); MANYARGUMENT_COMPARE(d); count++; } }; struct Funct5 { void operator()(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); MANYARGUMENT_COMPARE(d); MANYARGUMENT_COMPARE(e); count++; } }; struct Funct6 { void operator()(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e, const QString&f) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); MANYARGUMENT_COMPARE(d); MANYARGUMENT_COMPARE(e); MANYARGUMENT_COMPARE(f); count++; } }; } void tst_QObject::connectManyArguments() { ManyArgumentObject ob; ob.count = 0; ManyArgumentNamespace::count = 0; connect(&ob, &ManyArgumentObject::signal1, &ob, &ManyArgumentObject::slot1); connect(&ob, &ManyArgumentObject::signal2, &ob, &ManyArgumentObject::slot2); connect(&ob, &ManyArgumentObject::signal3, &ob, &ManyArgumentObject::slot3); connect(&ob, &ManyArgumentObject::signal4, &ob, &ManyArgumentObject::slot4); connect(&ob, &ManyArgumentObject::signal5, &ob, &ManyArgumentObject::slot5); connect(&ob, &ManyArgumentObject::signal6, &ob, &ManyArgumentObject::slot6); connect(&ob, &ManyArgumentObject::signal1, ManyArgumentNamespace::slot1); connect(&ob, &ManyArgumentObject::signal2, ManyArgumentNamespace::slot2); connect(&ob, &ManyArgumentObject::signal3, ManyArgumentNamespace::slot3); connect(&ob, &ManyArgumentObject::signal4, ManyArgumentNamespace::slot4); connect(&ob, &ManyArgumentObject::signal5, ManyArgumentNamespace::slot5); connect(&ob, &ManyArgumentObject::signal6, ManyArgumentNamespace::slot6); connect(&ob, &ManyArgumentObject::signal6, &ob, &ManyArgumentObject::signal5); connect(&ob, &ManyArgumentObject::signal5, &ob, &ManyArgumentObject::signal4); connect(&ob, &ManyArgumentObject::signal4, &ob, &ManyArgumentObject::signal3); connect(&ob, &ManyArgumentObject::signal3, &ob, &ManyArgumentObject::signal2); connect(&ob, &ManyArgumentObject::signal2, &ob, &ManyArgumentObject::signal1); emit ob.signal6("a", "b", "c", "d", "e", "f"); QCOMPARE(ob.count, 6); QCOMPARE(ManyArgumentNamespace::count, 6); ManyArgumentObject ob2; ob2.count = 0; ManyArgumentNamespace::count = 0; connect(&ob2, &ManyArgumentObject::signal6, &ob2, &ManyArgumentObject::slot1); connect(&ob2, &ManyArgumentObject::signal6, &ob2, &ManyArgumentObject::slot2); connect(&ob2, &ManyArgumentObject::signal6, &ob2, &ManyArgumentObject::slot3); connect(&ob2, &ManyArgumentObject::signal6, &ob2, &ManyArgumentObject::slot4); connect(&ob2, &ManyArgumentObject::signal6, &ob2, &ManyArgumentObject::slot5); connect(&ob2, &ManyArgumentObject::signal6, &ob2, &ManyArgumentObject::slot6); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::slot1); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::slot2); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::slot3); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::slot4); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::slot5); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::slot6); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::Funct1()); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::Funct2()); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::Funct3()); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::Funct4()); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::Funct5()); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::Funct6()); emit ob2.signal6("a", "b", "c", "d", "e", "f"); QCOMPARE(ob2.count, 6); QCOMPARE(ManyArgumentNamespace::count, 12); } class ForwardDeclared; W_REGISTER_ARGTYPE(ForwardDeclared) class ForwardDeclareArguments : public QObject { W_OBJECT(ForwardDeclareArguments) signals: void mySignal(const ForwardDeclared&a) W_SIGNAL(mySignal,a) public slots: void mySlot(const ForwardDeclared&) {} W_SLOT(mySlot) }; void tst_QObject::connectForwardDeclare() { ForwardDeclareArguments ob; // it should compile QVERIFY(connect(&ob, &ForwardDeclareArguments::mySignal, &ob, &ForwardDeclareArguments::mySlot, Qt::QueuedConnection)); } class NoDefaultConstructor { W_GADGET(NoDefaultConstructor) public: NoDefaultConstructor(int) {} }; W_REGISTER_ARGTYPE(NoDefaultConstructor) class NoDefaultContructorArguments : public QObject { W_OBJECT(NoDefaultContructorArguments) signals: void mySignal(const NoDefaultConstructor&a) W_SIGNAL(mySignal,a) public slots: void mySlot(const NoDefaultConstructor&) {} W_SLOT(mySlot) }; void tst_QObject::connectNoDefaultConstructorArg() { NoDefaultContructorArguments ob; // it should compile QVERIFY(connect(&ob, &NoDefaultContructorArguments::mySignal, &ob, &NoDefaultContructorArguments::mySlot, Qt::QueuedConnection)); } struct MoveOnly { int value; explicit MoveOnly(int v = 1) : value(v) {} #if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) // MoveOnly is not supported by Qt before that MoveOnly(MoveOnly &&o) : value(o.value) { o.value = -1; } MoveOnly &operator=(MoveOnly &&o) { value = o.value; o.value = -1; return *this; } Q_DISABLE_COPY(MoveOnly) #endif }; W_REGISTER_ARGTYPE(MoveOnly) class ReturnValue : public QObject { friend class tst_QObject; W_OBJECT(ReturnValue) signals: QVariant returnVariant(int a) W_SIGNAL(returnVariant,a) QString returnString(int a) W_SIGNAL(returnString,a) int returnInt(int a) W_SIGNAL(returnInt,a) void returnVoid(int a) W_SIGNAL(returnVoid,a) CustomType returnCustomType(int a) W_SIGNAL(returnCustomType,a) MoveOnly returnMoveOnly(int a) W_SIGNAL(returnMoveOnly,a) QObject *returnPointer() W_SIGNAL(returnPointer) public slots: QVariant returnVariantSlot(int i) { return i; } W_SLOT(returnVariantSlot) QString returnStringSlot(int i) { return QString::number(i); } W_SLOT(returnStringSlot) int returnIntSlot(int i) { return i; } W_SLOT(returnIntSlot) CustomType returnCustomTypeSlot(int i) { return CustomType(i); } W_SLOT(returnCustomTypeSlot) void returnVoidSlot() {} W_SLOT(returnVoidSlot) int return23() { return 23; } W_SLOT(return23) QString returnHello() { return QStringLiteral("hello"); } W_SLOT(returnHello) QObject *returnThisSlot1() { return this; } W_SLOT(returnThisSlot1) ReturnValue *returnThisSlot2() { return this; } W_SLOT(returnThisSlot2) MoveOnly returnMoveOnlySlot(int i) { return MoveOnly(i); } W_SLOT(returnMoveOnlySlot) public: struct VariantFunctor { QVariant operator()(int i) { return i; } }; struct CustomTypeFunctor { CustomType operator()(int i) { return CustomType(i); } }; struct StringFunctor { QString operator()(int i) { return QString::number(i); } }; struct IntFunctor { int operator()(int i) { return i; } }; struct VoidFunctor { void operator()(int) {} }; struct MoveOnlyFunctor { MoveOnly operator()(int i) { return MoveOnly(i); } }; }; W_REGISTER_ARGTYPE(ReturnValue*) QString someFunctionReturningString(int i) { return '\'' + QString::number(i) + '\''; } void tst_QObject::returnValue_data() { QTest::addColumn("isBlockingQueued"); QTest::newRow("DirectConnection") << false; QTest::newRow("BlockingQueuedConnection") << true; } void tst_QObject::returnValue() { CheckInstanceCount checker; QFETCH(bool, isBlockingQueued); QThread thread; ReturnValue receiver; Qt::ConnectionType type = Qt::DirectConnection; if (isBlockingQueued) { thread.start(); receiver.moveToThread(&thread); type = Qt::BlockingQueuedConnection; } { // connected to nothing CheckInstanceCount checker; ReturnValue r; QCOMPARE(emit r.returnVariant(45), QVariant()); QCOMPARE(emit r.returnString(45), QString()); QCOMPARE(emit r.returnInt(45), int()); emit r.returnVoid(45); QCOMPARE((emit r.returnCustomType(45)).value(), CustomType().value()); QCOMPARE((emit r.returnPointer()), static_cast(0)); QCOMPARE((emit r.returnMoveOnly(666)).value, MoveOnly().value); } { // connected to a slot returning the same type CheckInstanceCount checker; ReturnValue r; QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::returnVariantSlot, type)); QCOMPARE(emit r.returnVariant(45), QVariant(45)); QVERIFY(connect(&r, &ReturnValue::returnString, &receiver, &ReturnValue::returnStringSlot, type)); QCOMPARE(emit r.returnString(45), QString::fromLatin1("45")); QVERIFY(connect(&r, &ReturnValue::returnInt, &receiver, &ReturnValue::returnIntSlot, type)); QCOMPARE(emit r.returnInt(45), int(45)); QVERIFY(connect(&r, &ReturnValue::returnCustomType, &receiver, &ReturnValue::returnCustomTypeSlot, type)); QCOMPARE((emit r.returnCustomType(45)).value(), CustomType(45).value()); QVERIFY(connect(&r, &ReturnValue::returnPointer, &receiver, &ReturnValue::returnThisSlot1, type)); QCOMPARE((emit r.returnPointer()), static_cast(&receiver)); QVERIFY(connect(&r, &ReturnValue::returnMoveOnly, &receiver, &ReturnValue::returnMoveOnlySlot, type)); QCOMPARE((emit r.returnMoveOnly(666)).value, 666); } if (!isBlockingQueued) { // connected to simple functions or functor CheckInstanceCount checker; ReturnValue r; QVERIFY(connect(&r, &ReturnValue::returnString, someFunctionReturningString)); QCOMPARE(emit r.returnString(49), QString::fromLatin1("'49'")); ReturnValue::CustomTypeFunctor customTypeFunctor; QVERIFY(connect(&r, &ReturnValue::returnCustomType, customTypeFunctor)); QCOMPARE((emit r.returnCustomType(49)).value(), CustomType(49).value()); ReturnValue::VariantFunctor variantFunctor; QVERIFY(connect(&r, &ReturnValue::returnVariant, variantFunctor)); QCOMPARE(emit r.returnVariant(45), QVariant(45)); ReturnValue::IntFunctor intFunctor; QVERIFY(connect(&r, &ReturnValue::returnInt, intFunctor)); QCOMPARE(emit r.returnInt(45), int(45)); ReturnValue::MoveOnlyFunctor moveOnlyFunctor; QVERIFY(connect(&r, &ReturnValue::returnMoveOnly, moveOnlyFunctor)); QCOMPARE((emit r.returnMoveOnly(666)).value, 666); } { // connected to a slot with different type CheckInstanceCount checker; ReturnValue r; QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::returnStringSlot, type)); QCOMPARE(emit r.returnVariant(48), QVariant(QString::fromLatin1("48"))); QVERIFY(connect(&r, &ReturnValue::returnCustomType, &receiver, &ReturnValue::returnIntSlot, type)); QCOMPARE((emit r.returnCustomType(48)).value(), CustomType(48).value()); QVERIFY(connect(&r, &ReturnValue::returnVoid, &receiver, &ReturnValue::returnCustomTypeSlot, type)); emit r.returnVoid(48); QVERIFY(connect(&r, &ReturnValue::returnPointer, &receiver, &ReturnValue::returnThisSlot2, type)); QCOMPARE((emit r.returnPointer()), static_cast(&receiver)); } if (!isBlockingQueued) { // connected to functor with different type CheckInstanceCount checker; ReturnValue r; ReturnValue::CustomTypeFunctor customTypeFunctor; QVERIFY(connect(&r, &ReturnValue::returnCustomType, customTypeFunctor)); QCOMPARE((emit r.returnCustomType(49)).value(), CustomType(49).value()); ReturnValue::StringFunctor stringFunctor; QVERIFY(connect(&r, &ReturnValue::returnVariant, stringFunctor)); QCOMPARE(emit r.returnVariant(45), QVariant(QString::fromLatin1("45"))); } { // connected to a void CheckInstanceCount checker; ReturnValue r; QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::returnVoidSlot, type)); QCOMPARE(emit r.returnVariant(45), QVariant()); QVERIFY(connect(&r, &ReturnValue::returnString, &receiver, &ReturnValue::returnVoidSlot, type)); QCOMPARE(emit r.returnString(45), QString()); QVERIFY(connect(&r, &ReturnValue::returnInt, &receiver, &ReturnValue::returnVoidSlot, type)); QCOMPARE(emit r.returnInt(45), int()); QVERIFY(connect(&r, &ReturnValue::returnCustomType, &receiver, &ReturnValue::returnVoidSlot, type)); QCOMPARE((emit r.returnCustomType(45)).value(), CustomType().value()); QVERIFY(connect(&r, &ReturnValue::returnPointer, &receiver, &ReturnValue::returnVoidSlot, type)); QCOMPARE((emit r.returnPointer()), static_cast(0)); QVERIFY(connect(&r, &ReturnValue::returnMoveOnly, &receiver, &ReturnValue::returnVoidSlot, type)); QCOMPARE((emit r.returnMoveOnly(666)).value, MoveOnly().value); } if (!isBlockingQueued) { // queued connection should not forward the return value CheckInstanceCount checker; ReturnValue r; QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::returnVariantSlot, Qt::QueuedConnection)); QCOMPARE(emit r.returnVariant(45), QVariant()); QVERIFY(connect(&r, &ReturnValue::returnString, &receiver, &ReturnValue::returnStringSlot, Qt::QueuedConnection)); QCOMPARE(emit r.returnString(45), QString()); QVERIFY(connect(&r, &ReturnValue::returnInt, &receiver, &ReturnValue::returnIntSlot, Qt::QueuedConnection)); QCOMPARE(emit r.returnInt(45), int()); QVERIFY(connect(&r, &ReturnValue::returnCustomType, &receiver, &ReturnValue::returnCustomTypeSlot, Qt::QueuedConnection)); QCOMPARE((emit r.returnCustomType(45)).value(), CustomType().value()); QVERIFY(connect(&r, &ReturnValue::returnPointer, &receiver, &ReturnValue::returnThisSlot1, Qt::QueuedConnection)); QCOMPARE((emit r.returnPointer()), static_cast(0)); QVERIFY(connect(&r, &ReturnValue::returnMoveOnly, &receiver, &ReturnValue::returnMoveOnlySlot, Qt::QueuedConnection)); QCOMPARE((emit r.returnMoveOnly(666)).value, MoveOnly().value); QCoreApplication::processEvents(); QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::returnStringSlot, Qt::QueuedConnection)); QCOMPARE(emit r.returnVariant(48), QVariant()); QVERIFY(connect(&r, &ReturnValue::returnCustomType, &receiver, &ReturnValue::returnIntSlot, Qt::QueuedConnection)); QCOMPARE((emit r.returnCustomType(48)).value(), CustomType().value()); QVERIFY(connect(&r, &ReturnValue::returnVoid, &receiver, &ReturnValue::returnCustomTypeSlot, Qt::QueuedConnection)); emit r.returnVoid(48); QCoreApplication::processEvents(); } { // connected to many slots ReturnValue::VoidFunctor voidFunctor; ReturnValue::IntFunctor intFunctor; ReturnValue r; QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::returnVariantSlot, type)); QCOMPARE(emit r.returnVariant(45), QVariant(45)); QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::return23, type)); QCOMPARE(emit r.returnVariant(45), QVariant(23)); QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::returnVoidSlot, type)); QCOMPARE(emit r.returnVariant(45), QVariant(23)); QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::returnHello, type)); QCOMPARE(emit r.returnVariant(45), QVariant(QStringLiteral("hello"))); QVERIFY(connect(&r, &ReturnValue::returnVariant, voidFunctor)); QCOMPARE(emit r.returnVariant(45), QVariant(QStringLiteral("hello"))); QVERIFY(connect(&r, &ReturnValue::returnVariant, intFunctor)); QCOMPARE(emit r.returnVariant(45), QVariant(45)); QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::return23, Qt::QueuedConnection)); QCOMPARE(emit r.returnVariant(45), QVariant(45)); QCOMPARE(emit r.returnInt(45), int()); QVERIFY(connect(&r, &ReturnValue::returnInt, &receiver, &ReturnValue::returnVoidSlot, type)); QCOMPARE(emit r.returnInt(45), int()); QVERIFY(connect(&r, &ReturnValue::returnInt, &receiver, &ReturnValue::returnIntSlot, type)); QCOMPARE(emit r.returnInt(45), int(45)); QVERIFY(connect(&r, &ReturnValue::returnInt, &receiver, &ReturnValue::return23, type)); QCOMPARE(emit r.returnInt(45), int(23)); QVERIFY(connect(&r, &ReturnValue::returnInt, voidFunctor)); QCOMPARE(emit r.returnInt(45), int(23)); QVERIFY(connect(&r, &ReturnValue::returnInt, intFunctor)); QCOMPARE(emit r.returnInt(45), int(45)); QVERIFY(connect(&r, &ReturnValue::returnInt, &receiver, &ReturnValue::return23, Qt::QueuedConnection)); QCOMPARE(emit r.returnInt(45), int(45)); QCoreApplication::processEvents(); } if (isBlockingQueued) { thread.quit(); thread.wait(); } } void tst_QObject::returnValue2_data() { returnValue_data(); } //String based syntax void tst_QObject::returnValue2() { CheckInstanceCount checker; QFETCH(bool, isBlockingQueued); QThread thread; ReturnValue receiver; Qt::ConnectionType type = Qt::DirectConnection; if (isBlockingQueued) { thread.start(); receiver.moveToThread(&thread); type = Qt::BlockingQueuedConnection; } { // connected to a simple slot CheckInstanceCount checker; ReturnValue r; QVERIFY(connect(&r, SIGNAL(returnVariant(int)), &receiver, SLOT(returnVariantSlot(int)), type)); QCOMPARE(emit r.returnVariant(45), QVariant(45)); QVERIFY(connect(&r, SIGNAL(returnString(int)), &receiver, SLOT(returnStringSlot(int)), type)); QCOMPARE(emit r.returnString(45), QString(QStringLiteral("45"))); QVERIFY(connect(&r, SIGNAL(returnInt(int)), &receiver, SLOT(returnIntSlot(int)), type)); QCOMPARE(emit r.returnInt(45), int(45)); QVERIFY(connect(&r, SIGNAL(returnCustomType(int)), &receiver, SLOT(returnCustomTypeSlot(int)), type)); QCOMPARE((emit r.returnCustomType(45)).value(), CustomType(45).value()); QVERIFY(connect(&r, SIGNAL(returnMoveOnly(int)), &receiver, SLOT(returnMoveOnlySlot(int)), type)); QCOMPARE((emit r.returnMoveOnly(45)).value, 45); } { // connected to a slot returning void CheckInstanceCount checker; ReturnValue r; QVERIFY(connect(&r, SIGNAL(returnVariant(int)), &receiver, SLOT(returnVoidSlot()), type)); QCOMPARE(emit r.returnVariant(45), QVariant()); QVERIFY(connect(&r, SIGNAL(returnString(int)), &receiver, SLOT(returnVoidSlot()), type)); QCOMPARE(emit r.returnString(45), QString()); QVERIFY(connect(&r, SIGNAL(returnInt(int)), &receiver, SLOT(returnVoidSlot()), type)); QCOMPARE(emit r.returnInt(45), int()); QVERIFY(connect(&r, SIGNAL(returnCustomType(int)), &receiver, SLOT(returnVoidSlot()), type)); QCOMPARE((emit r.returnCustomType(45)).value(), CustomType().value()); QVERIFY(connect(&r, SIGNAL(returnMoveOnly(int)), &receiver, SLOT(returnVoidSlot()), type)); QCOMPARE((emit r.returnMoveOnly(45)).value, MoveOnly().value); } if (!isBlockingQueued) { // queued connection should not forward the return value CheckInstanceCount checker; ReturnValue r; QVERIFY(connect(&r, SIGNAL(returnVariant(int)), &receiver, SLOT(returnVariantSlot(int)), Qt::QueuedConnection)); QCOMPARE(emit r.returnVariant(45), QVariant()); QVERIFY(connect(&r, SIGNAL(returnString(int)), &receiver, SLOT(returnStringSlot(int)), Qt::QueuedConnection)); QCOMPARE(emit r.returnString(45), QString()); QVERIFY(connect(&r, SIGNAL(returnInt(int)), &receiver, SLOT(returnIntSlot(int)), Qt::QueuedConnection)); QCOMPARE(emit r.returnInt(45), int()); QVERIFY(connect(&r, SIGNAL(returnCustomType(int)), &receiver, SLOT(returnCustomTypeSlot(int)), Qt::QueuedConnection)); QCOMPARE((emit r.returnCustomType(45)).value(), CustomType().value()); QVERIFY(connect(&r, SIGNAL(returnMoveOnly(int)), &receiver, SLOT(returnMoveOnlySlot(int)), Qt::QueuedConnection)); QCOMPARE((emit r.returnMoveOnly(45)).value, MoveOnly().value); QCoreApplication::processEvents(); //Queued conneciton with different return type should be safe QVERIFY(connect(&r, SIGNAL(returnVariant(int)), &receiver, SLOT(returnStringSlot(int)), Qt::QueuedConnection)); QCOMPARE(emit r.returnVariant(48), QVariant()); QVERIFY(connect(&r, SIGNAL(returnCustomType(int)), &receiver, SLOT(returnIntSlot(int)), Qt::QueuedConnection)); QCOMPARE((emit r.returnCustomType(48)).value(), CustomType().value()); QVERIFY(connect(&r, SIGNAL(returnVoid(int)), &receiver, SLOT(returnCustomTypeSlot(int)), Qt::QueuedConnection)); emit r.returnVoid(48); QCoreApplication::processEvents(); } { // connected to many slots ReturnValue r; QVERIFY(connect(&r, SIGNAL(returnInt(int)), &receiver, SLOT(returnIntSlot(int)), type)); QCOMPARE(emit r.returnInt(45), int(45)); QVERIFY(connect(&r, SIGNAL(returnInt(int)), &receiver, SLOT(returnVoidSlot()), type)); QCOMPARE(emit r.returnInt(45), int(45)); QVERIFY(connect(&r, SIGNAL(returnInt(int)), &receiver, SLOT(return23()), type)); QCOMPARE(emit r.returnInt(45), int(23)); QVERIFY(connect(&r, SIGNAL(returnInt(int)), &receiver, SLOT(returnIntSlot(int)), Qt::QueuedConnection)); QCOMPARE(emit r.returnInt(45), int(23)); QVERIFY(connect(&r, SIGNAL(returnString(int)), &receiver, SLOT(returnStringSlot(int)), type)); QCOMPARE(emit r.returnString(45), QString(QStringLiteral("45"))); QVERIFY(connect(&r, SIGNAL(returnString(int)), &receiver, SLOT(returnVoidSlot()), type)); QCOMPARE(emit r.returnString(45), QString(QStringLiteral("45"))); QVERIFY(connect(&r, SIGNAL(returnString(int)), &receiver, SLOT(returnHello()), type)); QCOMPARE(emit r.returnString(45), QString(QStringLiteral("hello"))); QVERIFY(connect(&r, SIGNAL(returnString(int)), &receiver, SLOT(returnStringSlot(int)), Qt::QueuedConnection)); QCOMPARE(emit r.returnString(45), QString(QStringLiteral("hello"))); } if (isBlockingQueued) { thread.quit(); thread.wait(); } } class VirtualSlotsObjectBase : public QObject { W_OBJECT(VirtualSlotsObjectBase) public slots: virtual void slot1() { base_counter1++; } W_SLOT(slot1) public: VirtualSlotsObjectBase() : base_counter1(0) {} int base_counter1; signals: void signal1() W_SIGNAL(signal1) }; class VirtualSlotsObject : public VirtualSlotsObjectBase { W_OBJECT(VirtualSlotsObject) public slots: virtual void slot1() { derived_counter1++; } W_SLOT(slot1) public: VirtualSlotsObject() : derived_counter1(0) {} int derived_counter1; }; void tst_QObject::connectVirtualSlots() { VirtualSlotsObject obj; QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1, Qt::UniqueConnection)); QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1, Qt::UniqueConnection)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 1); QVERIFY(QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1)); QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 1); /* the C++ standard say the comparison between pointer to virtual member function is unspecified QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1, Qt::UniqueConnection)); QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObject::slot1, Qt::UniqueConnection)); */ } #ifdef Q_CC_MSVC void tst_QObject::connectSlotsVMIClass() {QSKIP("MSVC Internal compiler error when taking constexpr pointer to virtual member function of a class with multiple inheritance for W_SLOT");} #else struct VirtualBase { int virtual_base_count; VirtualBase() : virtual_base_count(0) {} virtual ~VirtualBase() {} virtual void slot2() = 0; }; class ObjectWithVirtualBase : public VirtualSlotsObject, public virtual VirtualBase { W_OBJECT(ObjectWithVirtualBase) public: ObjectWithVirtualBase() : regular_call_count(0), derived_counter2(0) {} int regular_call_count; int derived_counter2; public slots: void regularSlot() { ++regular_call_count; } W_SLOT(regularSlot) virtual void slot1() { ++derived_counter2; } W_SLOT(slot1) virtual void slot2() { ++virtual_base_count; } W_SLOT(slot2) }; W_OBJECT_IMPL(ObjectWithVirtualBase) struct NormalBase { QByteArray lastCalled; virtual ~NormalBase() {} virtual void virtualBaseSlot() { lastCalled = "virtualBaseSlot"; } void normalBaseSlot() { lastCalled = "normalBaseSlot"; } }; class ObjectWithMultiInheritance : public VirtualSlotsObject, public NormalBase { W_OBJECT(ObjectWithMultiInheritance) }; W_OBJECT_IMPL(ObjectWithMultiInheritance) // Normally, the class that inherit QObject always must go first, because of the way qobject_cast // work, and moc checks for that. But if we don't use Q_OBJECT, this should work class ObjectWithMultiInheritance2 : public NormalBase, public VirtualSlotsObject { // no QObject as QObject always must go first // Q_OBJECT }; // VMI = Virtual or Multiple Inheritance // (in this case, both) void tst_QObject::connectSlotsVMIClass() { // test connecting by the base { ObjectWithVirtualBase obj; QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1, Qt::UniqueConnection)); QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1, Qt::UniqueConnection)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 0); QCOMPARE(obj.derived_counter2, 1); QCOMPARE(obj.virtual_base_count, 0); QVERIFY(QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1)); QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 0); QCOMPARE(obj.derived_counter2, 1); QCOMPARE(obj.virtual_base_count, 0); } // test connecting with the actual class { ObjectWithVirtualBase obj; QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::regularSlot, Qt::UniqueConnection)); QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::regularSlot, Qt::UniqueConnection)); QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot1, Qt::UniqueConnection)); QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot1, Qt::UniqueConnection)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 0); QCOMPARE(obj.derived_counter2, 1); QCOMPARE(obj.regular_call_count, 1); QCOMPARE(obj.virtual_base_count, 0); QVERIFY( QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::regularSlot)); QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::regularSlot)); QVERIFY( QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot1)); QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot1)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 0); QCOMPARE(obj.derived_counter2, 1); QCOMPARE(obj.regular_call_count, 1); QCOMPARE(obj.virtual_base_count, 0); /* the C++ standard say the comparison between pointer to virtual member function is unspecified QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1, Qt::UniqueConnection)); QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot1, Qt::UniqueConnection)); */ } // test connecting a slot that is virtual from the virtual base { ObjectWithVirtualBase obj; QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot2, Qt::UniqueConnection)); QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot2, Qt::UniqueConnection)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 0); QCOMPARE(obj.derived_counter2, 0); QCOMPARE(obj.virtual_base_count, 1); QCOMPARE(obj.regular_call_count, 0); QVERIFY( QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot2)); QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot2)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 0); QCOMPARE(obj.derived_counter2, 0); QCOMPARE(obj.virtual_base_count, 1); QCOMPARE(obj.regular_call_count, 0); } // test connecting a slot that is virtual within the second base { ObjectWithMultiInheritance obj; void (ObjectWithMultiInheritance::*slot)() = &ObjectWithMultiInheritance::virtualBaseSlot; QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot, Qt::UniqueConnection)); QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot, Qt::UniqueConnection)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 0); QCOMPARE(obj.lastCalled, QByteArray("virtualBaseSlot")); obj.lastCalled.clear(); QVERIFY( QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot)); QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 0); QCOMPARE(obj.lastCalled, QByteArray()); } // test connecting a slot that is not virtual within the second base { ObjectWithMultiInheritance obj; void (ObjectWithMultiInheritance::*slot)() = &ObjectWithMultiInheritance::normalBaseSlot; QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot, Qt::UniqueConnection)); QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot, Qt::UniqueConnection)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 0); QCOMPARE(obj.lastCalled, QByteArray("normalBaseSlot")); obj.lastCalled.clear(); QVERIFY( QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot)); QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 0); QCOMPARE(obj.lastCalled, QByteArray()); } // test connecting a slot within the first non-QObject base { ObjectWithMultiInheritance2 obj; void (ObjectWithMultiInheritance2::*slot)() = &ObjectWithMultiInheritance2::normalBaseSlot; QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot, Qt::UniqueConnection)); QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot, Qt::UniqueConnection)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 0); QCOMPARE(obj.lastCalled, QByteArray("normalBaseSlot")); obj.lastCalled.clear(); QVERIFY( QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot)); QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 0); QCOMPARE(obj.lastCalled, QByteArray()); } // test connecting a slot within the second QObject base { ObjectWithMultiInheritance2 obj; void (ObjectWithMultiInheritance2::*slot)() = &ObjectWithMultiInheritance2::slot1; QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot, Qt::UniqueConnection)); QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot, Qt::UniqueConnection)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 1); QCOMPARE(obj.lastCalled, QByteArray()); QVERIFY( QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot)); QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 1); QCOMPARE(obj.lastCalled, QByteArray()); } } #endif // Q_CC_MSVC #ifndef QT_BUILD_INTERNAL void tst_QObject::connectPrivateSlots() {QSKIP("Needs QT_BUILD_INTERNAL");} #else class ConnectToPrivateSlotPrivate; class ConnectToPrivateSlot :public QObject { W_OBJECT(ConnectToPrivateSlot) public: ConnectToPrivateSlot(); void test(SenderObject *obj1) ; Q_DECLARE_PRIVATE(ConnectToPrivateSlot) }; class ConnectToPrivateSlotPrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(ConnectToPrivateSlot) public: int receivedCount; QVariant receivedValue; void thisIsAPrivateSlot() { receivedCount++; }; void thisIsAPrivateSlotWithArg(const QVariant &v) { receivedCount++; receivedValue = v; }; }; ConnectToPrivateSlot::ConnectToPrivateSlot(): QObject(*new ConnectToPrivateSlotPrivate) {} void ConnectToPrivateSlot::test(SenderObject* obj1) { Q_D(ConnectToPrivateSlot); d->receivedCount = 0; QVERIFY(QObjectPrivate::connect(obj1, &SenderObject::signal1, d, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlot)); QVERIFY(QObjectPrivate::connect(obj1, &SenderObject::signal7, d, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlotWithArg)); QCOMPARE(d->receivedCount, 0); obj1->signal1(); QCOMPARE(d->receivedCount, 1); QCOMPARE(d->receivedValue, QVariant()); obj1->signal7(666, QLatin1Literal("_")); QCOMPARE(d->receivedCount, 2); QCOMPARE(d->receivedValue, QVariant(666)); QVERIFY(QObjectPrivate::connect(obj1, &SenderObject::signal2, d, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlot, Qt::UniqueConnection)); QVERIFY(!QObjectPrivate::connect(obj1, &SenderObject::signal2, d, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlot, Qt::UniqueConnection)); obj1->signal2(); QCOMPARE(d->receivedCount, 3); QVERIFY(QObjectPrivate::disconnect(obj1, &SenderObject::signal2, d, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlot)); obj1->signal2(); QCOMPARE(d->receivedCount, 3); QVERIFY(!QObjectPrivate::disconnect(obj1, &SenderObject::signal2, d, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlot)); } void tst_QObject::connectPrivateSlots() { SenderObject sender; { ConnectToPrivateSlot o; o.test(&sender); } sender.signal7(777, QLatin1String("check that deleting the object properly disconnected")); sender.signal1(); } #endif struct SlotFunctor { void operator()() {} }; struct SlotFunctorString { void operator()(const QString &) {} }; void tst_QObject::connectFunctorArgDifference() { QTimer timer; // Compile-time tests that the connection is successful. connect(&timer, &QTimer::timeout, SlotFunctor()); connect(&timer, &QTimer::objectNameChanged, SlotFunctorString()); connect(qApp, &QCoreApplication::aboutToQuit, SlotFunctor()); connect(&timer, &QTimer::objectNameChanged, SlotFunctor()); 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, [=](){}); connect(&timer, &QTimer::objectNameChanged, [=](){}); connect(&model, &QStringListModel::rowsInserted, [=](){}); connect(&model, &QStringListModel::rowsInserted, [=](const QModelIndex &){}); #endif QVERIFY(true); } class ContextObject : public QObject { W_OBJECT(ContextObject) public: void compareSender(QObject *s) { QCOMPARE(s, sender()); } }; struct SlotArgFunctor { SlotArgFunctor(int *s) : status(s), context(nullptr), sender(nullptr) {} SlotArgFunctor(ContextObject *context, QObject *sender, int *s) : status(s), context(context), sender(sender) {} void operator()() { *status = 2; if (context) context->compareSender(sender); } protected: int *status; ContextObject *context; QObject *sender; }; void tst_QObject::connectFunctorQueued() { int status = 1; SenderObject obj; QEventLoop e; connect(&obj, &SenderObject::signal1, this, SlotArgFunctor(&status), Qt::QueuedConnection); connect(&obj, &SenderObject::signal1, &e, &QEventLoop::quit, Qt::QueuedConnection); obj.emitSignal1(); QCOMPARE(status, 1); e.exec(); QCOMPARE(status, 2); #if defined(Q_COMPILER_LAMBDA) status = 1; connect(&obj, &SenderObject::signal1, this, [&status] { status = 2; }, Qt::QueuedConnection); obj.emitSignal1(); QCOMPARE(status, 1); e.exec(); QCOMPARE(status, 2); #endif } void tst_QObject::connectFunctorWithContext() { int status = 1; SenderObject obj; ContextObject *context = new ContextObject; QEventLoop e; connect(&obj, &SenderObject::signal1, context, SlotArgFunctor(&status)); connect(&obj, &SenderObject::signal1, &e, &QEventLoop::quit, Qt::QueuedConnection); // When the context gets deleted, the connection should decay and the signal shouldn't trigger // The connection is queued to make sure the destroyed signal propagates correctly and // cuts the connection. connect(context, &QObject::destroyed, &obj, &SenderObject::signal1, Qt::QueuedConnection); context->deleteLater(); QCOMPARE(status, 1); e.exec(); QCOMPARE(status, 1); // Check the sender arg is set correctly in the context context = new ContextObject; connect(&obj, &SenderObject::signal1, context, SlotArgFunctor(context, &obj, &status), Qt::QueuedConnection); obj.emitSignal1(); QCOMPARE(status, 1); 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); obj.emitSignal1(); QCOMPARE(status, 1); e.exec(); QCOMPARE(status, 2); #endif // Free context->deleteLater(); } class StatusChanger : public QObject { W_OBJECT(StatusChanger) public: StatusChanger(int *status) : m_status(status) { } ~StatusChanger() { *m_status = 2; } private: int *m_status; }; W_OBJECT_IMPL(StatusChanger) class DispatcherWatcher : public QObject { W_OBJECT(DispatcherWatcher) public: DispatcherWatcher(QEventLoop &e, int *statusAwake, int *statusAboutToBlock) : m_eventLoop(&e), m_statusAwake(statusAwake), m_statusAboutToBlock(statusAboutToBlock), m_aboutToBlocks(0), m_awakes(0) { awake = new StatusChanger(statusAwake); abouttoblock = new StatusChanger(statusAboutToBlock); QCOMPARE(*statusAwake, 1); QCOMPARE(*statusAboutToBlock, 1); connect(QAbstractEventDispatcher::instance(), SIGNAL(awake()), this, SLOT(onAwake())); connect(QAbstractEventDispatcher::instance(), SIGNAL(aboutToBlock()), this, SLOT(onAboutToBlock())); } ~DispatcherWatcher() { if (awake) awake->deleteLater(); if (abouttoblock) abouttoblock->deleteLater(); } public slots: // The order of these 2 handlers differs on different event dispatchers void onAboutToBlock() { if (abouttoblock) { abouttoblock->deleteLater(); abouttoblock = 0; } ++m_aboutToBlocks; } W_SLOT(onAboutToBlock) void onAwake() { if (awake) { awake->deleteLater(); awake = 0; } ++m_awakes; } W_SLOT(onAwake) void onSignal1() { // Status check. At this point the event loop should have spinned enough to delete all the objects. QCOMPARE(*m_statusAwake, 2); QCOMPARE(*m_statusAboutToBlock, 2); QMetaObject::invokeMethod(m_eventLoop, "quit", Qt::QueuedConnection); } W_SLOT(onSignal1) private: StatusChanger *awake; StatusChanger *abouttoblock; QEventLoop *m_eventLoop; int *m_statusAwake; int *m_statusAboutToBlock; int m_aboutToBlocks; int m_awakes; }; W_OBJECT_IMPL(DispatcherWatcher) void tst_QObject::deleteLaterInAboutToBlockHandler() { #if QT_VERSION < QT_VERSION_CHECK(5, 7, 0) if (qVersion() < QByteArray("5.7.0")) QSKIP("Fixed in 5.7 only"); #endif int statusAwake = 1; int statusAboutToBlock = 1; QEventLoop e; DispatcherWatcher dw(e, &statusAwake, &statusAboutToBlock); QTimer::singleShot(2000, &dw, &DispatcherWatcher::onSignal1); QCOMPARE(statusAwake, 1); QCOMPARE(statusAboutToBlock, 1); e.exec(); QCOMPARE(statusAwake, 2); QCOMPARE(statusAboutToBlock, 2); } void tst_QObject::connectFunctorWithContextUnique() { #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 2) // Qt::UniqueConnections currently don't work for functors, but we need to // be sure that they don't crash. If that is implemented, change this test. SenderObject sender; ReceiverObject receiver; QObject::connect(&sender, &SenderObject::signal1, &receiver, &ReceiverObject::slot1); receiver.count_slot1 = 0; QObject::connect(&sender, &SenderObject::signal1, &receiver, SlotFunctor(), Qt::UniqueConnection); sender.emitSignal1(); QCOMPARE(receiver.count_slot1, 1); #endif } class MyFunctor { public: explicit MyFunctor(QObject *objectToDisconnect) : m_objectToDisconnect(objectToDisconnect) {} ~MyFunctor() { playWithObjects(); } void operator()() { // This will cause the slot object associated with this functor to be destroyed after // this function returns. That in turn will destroy this functor. // If our dtor runs with the signalSlotLock held, the bunch of connect() // performed there will deadlock trying to lock that lock again. m_objectToDisconnect->disconnect(); } private: QObject *m_objectToDisconnect; }; void tst_QObject::connectFunctorDeadlock() { SenderObject sender; MyFunctor functor(&sender); QObject::connect(&sender, &SenderObject::signal1, functor); sender.emitSignal1(); } void tst_QObject::connectFunctorMoveOnly() { #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) struct MoveOnlyFunctor { Q_DISABLE_COPY(MoveOnlyFunctor) MoveOnlyFunctor(int *status) : status(status) {} MoveOnlyFunctor(MoveOnlyFunctor &&o) : status(o.status) { o.status = nullptr; }; void operator()(int i) { *status = i; } void operator()() { *status = -8; } int *status; }; int status = 1; SenderObject obj; QEventLoop e; connect(&obj, &SenderObject::signal1, MoveOnlyFunctor(&status)); QCOMPARE(status, 1); obj.signal1(); QCOMPARE(status, -8); connect(&obj, &SenderObject::signal7, MoveOnlyFunctor(&status)); QCOMPARE(status, -8); obj.signal7(7888, "Hello"); QCOMPARE(status, 7888); // With a context status = 1; connect(&obj, &SenderObject::signal2, this, MoveOnlyFunctor(&status)); QCOMPARE(status, 1); obj.signal2(); QCOMPARE(status, -8); // QueuedConnection status = 1; connect(&obj, &SenderObject::signal3, this, MoveOnlyFunctor(&status), Qt::QueuedConnection); obj.signal3(); QCOMPARE(status, 1); QCoreApplication::processEvents(); QCOMPARE(status, -8); #endif } static int s_static_slot_checker = 1; class StaticSlotChecker : public QObject { W_OBJECT(StaticSlotChecker) public Q_SLOTS: static void staticSlot() { s_static_slot_checker = 2; } W_SLOT(staticSlot) }; void tst_QObject::connectStaticSlotWithObject() { SenderObject sender; StaticSlotChecker *receiver = new StaticSlotChecker; QEventLoop e; QVERIFY(connect(&sender, &SenderObject::signal1, receiver, &StaticSlotChecker::staticSlot, Qt::QueuedConnection)); connect(&sender, &SenderObject::signal1, &e, &QEventLoop::quit, Qt::QueuedConnection); sender.emitSignal1(); QCOMPARE(s_static_slot_checker, 1); e.exec(); QCOMPARE(s_static_slot_checker, 2); s_static_slot_checker = 1; connect(receiver, &QObject::destroyed, &sender, &SenderObject::signal1, Qt::QueuedConnection); receiver->deleteLater(); QCOMPARE(s_static_slot_checker, 1); e.exec(); QCOMPARE(s_static_slot_checker, 1); } struct ComplexFunctor { ComplexFunctor(int &overload, QList &result) : overload(overload), result(result) {} void operator()(int a, int b) { overload = 1; result << a << b; } void operator()(double a, double b) { overload = 2; result << a << b; } void operator()(const QString &s) { overload = 3; result << s; } void operator()(const QString &) const { Q_ASSERT(!"Should not be called because the non-const one should"); overload = -1; } template void operator()(const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4) { overload = 4; result << QVariant::fromValue(t1) << QVariant::fromValue(t2) << QVariant::fromValue(t3) << QVariant::fromValue(t4); } int &overload; QList &result; protected: void operator()() const { Q_ASSERT(!"Should not be called because it is protected"); overload = -1; } }; struct ComplexFunctorDeriv : ComplexFunctor { ComplexFunctorDeriv(int &overload, QList &result) : ComplexFunctor(overload, result) {} void operator()() const { overload = 10; } void operator()(int a, int b) { overload = 11; result << a << b; } using ComplexFunctor::operator(); private: void operator()(int) { Q_ASSERT(!"Should not be called because it is private"); overload = -1; } }; class FunctorArgDifferenceObject : public QObject { W_OBJECT(FunctorArgDifferenceObject) signals: void signal_ii(int a,int b) W_SIGNAL(signal_ii,a,b) void signal_iiS(int a,int b, const QString &c) W_SIGNAL(signal_iiS,a,b,c) void signal_dd(double a,double b) W_SIGNAL(signal_dd,a,b) void signal_ddS(double a,double b, const QString &c) W_SIGNAL(signal_ddS,a,b,c) void signal_S(const QString &a) W_SIGNAL(signal_S,a) void signal_SSSS(const QString &a, const QString &c, const QString &d, const QString &e) W_SIGNAL(signal_SSSS,a,c,d,e) void signal_iiSS(int a, int b, const QString &c, const QString &d) W_SIGNAL(signal_iiSS,a,b,c,d) void signal_VV(const QVariant &a, const QVariant &b) W_SIGNAL(signal_VV,a,b) }; template void connectFunctorOverload_impl(Signal signal, int expOverload, QList expResult) { FunctorArgDifferenceObject obj; int overload; QList result; QVERIFY(QObject::connect(&obj, signal, Functor(overload, result))); obj.signal_ii(1,2); obj.signal_iiS(3,4,"5"); obj.signal_dd(6.6,7.7); obj.signal_ddS(8.8,9.9,"10"); obj.signal_S("11"); obj.signal_SSSS("12", "13", "14", "15"); obj.signal_iiSS(16, 17, "18", "19"); obj.signal_VV(20,21); QCOMPARE(overload, expOverload); QCOMPARE(result, expResult); } void tst_QObject::connectFunctorOverloads() { #if defined (Q_COMPILER_DECLTYPE) && defined (Q_COMPILER_VARIADIC_TEMPLATES) connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_ii, 1, (QList() << 1 << 2)); connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_iiS, 1, (QList() << 3 << 4)); connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_dd, 2, (QList() << 6.6 << 7.7)); connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_ddS, 2, (QList() << 8.8 << 9.9)); connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_S, 3, (QList() << QString("11"))); connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_SSSS, 4, (QList() << QString("12") << QString("13") << QString("14") << QString("15"))); connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_iiSS, 4, (QList() << 16 << 17 << QString("18") << QString("19"))); connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_ii, 11, (QList() << 1 << 2)); connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_iiS, 11, (QList() << 3 << 4)); connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_dd, 2, (QList() << 6.6 << 7.7)); connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_ddS, 2, (QList() << 8.8 << 9.9)); connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_S, 3, (QList() << QString("11"))); connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_SSSS, 4, (QList() << QString("12") << QString("13") << QString("14") << QString("15"))); connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_iiSS, 4, (QList() << 16 << 17 << QString("18") << QString("19"))); connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_VV, 10, (QList())); #else QSKIP("Does not compile without C++11 variadic template"); #endif } class GetSenderObject : public QObject { W_OBJECT(GetSenderObject) public: using QObject::sender; // make public public Q_SLOTS: void triggerSignal() { Q_EMIT aSignal(); } W_SLOT(triggerSignal) Q_SIGNALS: void aSignal() W_SIGNAL(aSignal) }; static int countedStructObjectsCount = 0; struct CountedStruct { CountedStruct() : sender(nullptr) { ++countedStructObjectsCount; } CountedStruct(GetSenderObject *sender) : sender(sender) { ++countedStructObjectsCount; } CountedStruct(const CountedStruct &o) : sender(o.sender) { ++countedStructObjectsCount; } CountedStruct &operator=(const CountedStruct &) { return *this; } // calling sender() here allows us to check if there's a deadlock ~CountedStruct() { --countedStructObjectsCount; if (sender) (void)sender->sender(); } void operator()() const { } GetSenderObject *sender; }; W_REGISTER_ARGTYPE(CountedStruct) void tst_QObject::disconnectDoesNotLeakFunctor() { QCOMPARE(countedStructObjectsCount, 0); { GetSenderObject obj; QMetaObject::Connection c; { CountedStruct s(&obj); QCOMPARE(countedStructObjectsCount, 1); c = connect(&obj, &GetSenderObject::aSignal, s); QVERIFY(c); QCOMPARE(countedStructObjectsCount, 2); QVERIFY(QObject::disconnect(c)); QCOMPARE(countedStructObjectsCount, 1); } QCOMPARE(countedStructObjectsCount, 0); } QCOMPARE(countedStructObjectsCount, 0); { GetSenderObject obj; QMetaObject::Connection c; { CountedStruct s(&obj); QObject context; QCOMPARE(countedStructObjectsCount, 1); c = connect(&obj, &GetSenderObject::aSignal, &context, s); QVERIFY(c); QCOMPARE(countedStructObjectsCount, 2); QVERIFY(QObject::disconnect(c)); QCOMPARE(countedStructObjectsCount, 1); } QCOMPARE(countedStructObjectsCount, 0); } QCOMPARE(countedStructObjectsCount, 0); { QMetaObject::Connection c1, c2; { CountedStruct s; QCOMPARE(countedStructObjectsCount, 1); QTimer timer; c1 = connect(&timer, &QTimer::timeout, s); QVERIFY(c1); c2 = c1; QVERIFY(c2); QCOMPARE(countedStructObjectsCount, 2); QVERIFY(QObject::disconnect(c1)); QVERIFY(!c1); QVERIFY(!c2); // functor object has been destroyed QCOMPARE(countedStructObjectsCount, 1); QVERIFY(!QObject::disconnect(c2)); QCOMPARE(countedStructObjectsCount, 1); } QCOMPARE(countedStructObjectsCount, 0); } QCOMPARE(countedStructObjectsCount, 0); { CountedStruct s; QCOMPARE(countedStructObjectsCount, 1); QTimer timer; QMetaObject::Connection c = connect(&timer, &QTimer::timeout, s); QVERIFY(c); QCOMPARE(countedStructObjectsCount, 2); QVERIFY(QObject::disconnect(c)); QCOMPARE(countedStructObjectsCount, 1); } QCOMPARE(countedStructObjectsCount, 0); { QTimer timer; QMetaObject::Connection c = connect(&timer, &QTimer::timeout, CountedStruct()); QVERIFY(c); QCOMPARE(countedStructObjectsCount, 1); // only one instance, in Qt internals QVERIFY(QObject::disconnect(c)); QCOMPARE(countedStructObjectsCount, 0); // functor being destroyed } QCOMPARE(countedStructObjectsCount, 0); { QTimer *timer = new QTimer; QEventLoop e; connect(timer, &QTimer::timeout, CountedStruct()); QCOMPARE(countedStructObjectsCount, 1); // only one instance, in Qt internals timer->deleteLater(); connect(timer, &QObject::destroyed, &e, &QEventLoop::quit, Qt::QueuedConnection); e.exec(); QCOMPARE(countedStructObjectsCount, 0); // functor being destroyed } QCOMPARE(countedStructObjectsCount, 0); { GetSenderObject obj; connect(&obj, &GetSenderObject::aSignal, CountedStruct(&obj)); QCOMPARE(countedStructObjectsCount, 1); } QCOMPARE(countedStructObjectsCount, 0); { GetSenderObject obj; connect(&obj, &GetSenderObject::aSignal, CountedStruct(&obj)); QCOMPARE(countedStructObjectsCount, 1); QObject::disconnect(&obj, &GetSenderObject::aSignal, 0, 0); } QCOMPARE(countedStructObjectsCount, 0); { #if defined(Q_COMPILER_LAMBDA) CountedStruct s; QCOMPARE(countedStructObjectsCount, 1); QTimer timer; QMetaObject::Connection c = connect(&timer, &QTimer::timeout, [s](){}); QVERIFY(c); QCOMPARE(countedStructObjectsCount, 2); QVERIFY(QObject::disconnect(c)); QCOMPARE(countedStructObjectsCount, 1); #endif // Q_COMPILER_LAMBDA } QCOMPARE(countedStructObjectsCount, 0); } void tst_QObject::contextDoesNotLeakFunctor() { QCOMPARE(countedStructObjectsCount, 0); { QMetaObject::Connection c; { QEventLoop e; ContextObject *context = new ContextObject; SenderObject obj; connect(&obj, &SenderObject::signal1, context, CountedStruct()); connect(context, &QObject::destroyed, &e, &QEventLoop::quit, Qt::QueuedConnection); context->deleteLater(); QCOMPARE(countedStructObjectsCount, 1); e.exec(); QCOMPARE(countedStructObjectsCount, 0); } QCOMPARE(countedStructObjectsCount, 0); } QCOMPARE(countedStructObjectsCount, 0); { GetSenderObject obj; QMetaObject::Connection c; { CountedStruct s(&obj); QEventLoop e; ContextObject *context = new ContextObject; QCOMPARE(countedStructObjectsCount, 1); connect(&obj, &GetSenderObject::aSignal, context, s); QCOMPARE(countedStructObjectsCount, 2); connect(context, &QObject::destroyed, &e, &QEventLoop::quit, Qt::QueuedConnection); context->deleteLater(); e.exec(); QCOMPARE(countedStructObjectsCount, 1); } QCOMPARE(countedStructObjectsCount, 0); } QCOMPARE(countedStructObjectsCount, 0); { #if defined(Q_COMPILER_LAMBDA) CountedStruct s; QEventLoop e; ContextObject *context = new ContextObject; QCOMPARE(countedStructObjectsCount, 1); QTimer timer; connect(&timer, &QTimer::timeout, context, [s](){}); QCOMPARE(countedStructObjectsCount, 2); connect(context, &QObject::destroyed, &e, &QEventLoop::quit, Qt::QueuedConnection); context->deleteLater(); e.exec(); QCOMPARE(countedStructObjectsCount, 1); #endif // Q_COMPILER_LAMBDA } QCOMPARE(countedStructObjectsCount, 0); } class SubSender : public SenderObject { W_OBJECT(SubSender) }; void tst_QObject::connectBase() { SubSender sub; ReceiverObject r1; r1.reset(); QVERIFY( connect( &sub, &SubSender::signal1 , &r1, &ReceiverObject::slot1 ) ); QVERIFY( connect( &sub, static_cast(&SubSender::signal2) , &r1, &ReceiverObject::slot2 ) ); QVERIFY( connect( &sub, static_cast(&SubSender::signal3) , &r1, &ReceiverObject::slot3 ) ); sub.emitSignal1(); sub.emitSignal2(); sub.emitSignal3(); QCOMPARE( r1.count_slot1, 1 ); QCOMPARE( r1.count_slot2, 1 ); QCOMPARE( r1.count_slot3, 1 ); QVERIFY( QObject::disconnect( &sub, &SubSender::signal1 , &r1, &ReceiverObject::slot1 ) ); QVERIFY( QObject::disconnect( &sub, static_cast(&SubSender::signal2) , &r1, &ReceiverObject::slot2 ) ); QVERIFY( QObject::disconnect( &sub, static_cast(&SubSender::signal3) , &r1, &ReceiverObject::slot3 ) ); sub.emitSignal1(); sub.emitSignal2(); sub.emitSignal3(); QCOMPARE( r1.count_slot1, 1 ); QCOMPARE( r1.count_slot2, 1 ); QCOMPARE( r1.count_slot3, 1 ); } void tst_QObject::connectWarnings() { #if QT_VERSION < QT_VERSION_CHECK(5, 12, 0) return; #endif SubSender sub; SenderObject obj; ReceiverObject r1; r1.reset(); #if QT_VERSION < QT_VERSION_CHECK(5, 14, 1) QTest::ignoreMessage(QtWarningMsg, "QObject::connect(SenderObject, ReceiverObject): invalid null parameter"); #else QTest::ignoreMessage(QtWarningMsg, "QObject::connect(SenderObject, ReceiverObject): invalid nullptr parameter"); #endif connect(static_cast(nullptr), &SubSender::signal1, &r1, &ReceiverObject::slot1); #if QT_VERSION < QT_VERSION_CHECK(5, 14, 1) QTest::ignoreMessage(QtWarningMsg, "QObject::connect(SubSender, Unknown): invalid null parameter"); #else QTest::ignoreMessage(QtWarningMsg, "QObject::connect(SubSender, Unknown): invalid nullptr parameter"); #endif connect(&sub, &SubSender::signal1, static_cast(nullptr), &ReceiverObject::slot1); #if QT_VERSION < QT_VERSION_CHECK(5, 14, 1) QTest::ignoreMessage(QtWarningMsg, "QObject::connect(SenderObject, ReceiverObject): invalid null parameter"); #else QTest::ignoreMessage(QtWarningMsg, "QObject::connect(SenderObject, ReceiverObject): invalid nullptr parameter"); #endif connect(static_cast(nullptr), &SenderObject::signal1, &r1, &ReceiverObject::slot1); #if QT_VERSION < QT_VERSION_CHECK(5, 14, 1) QTest::ignoreMessage(QtWarningMsg, "QObject::connect(SenderObject, Unknown): invalid null parameter"); #else QTest::ignoreMessage(QtWarningMsg, "QObject::connect(SenderObject, Unknown): invalid nullptr parameter"); #endif connect(&obj, &SenderObject::signal1, static_cast(nullptr), &ReceiverObject::slot1); } struct QmlReceiver : public QtPrivate::QSlotObjectBase { int callCount; void *magic; QmlReceiver() : QtPrivate::QSlotObjectBase(&impl) , callCount(0) , magic(0) {} static void impl(int which, QSlotObjectBase *this_, QObject *, void **metaArgs, bool *ret) { switch (which) { case Destroy: delete static_cast(this_); return; case Call: static_cast(this_)->callCount++; return; case Compare: *ret = static_cast(this_)->magic == metaArgs[0]; return; case NumOperations: break; } } }; void tst_QObject::qmlConnect() { #ifdef QT_BUILD_INTERNAL SenderObject sender; QmlReceiver *receiver = new QmlReceiver; receiver->magic = receiver; receiver->ref(); QVERIFY(QObjectPrivate::connect(&sender, sender.metaObject()->indexOfSignal("signal1()"), receiver, Qt::AutoConnection)); QCOMPARE(receiver->callCount, 0); sender.emitSignal1(); QCOMPARE(receiver->callCount, 1); void *a[] = { receiver }; QVERIFY(QObjectPrivate::disconnect(&sender, sender.metaObject()->indexOfSignal("signal1()"), reinterpret_cast(&a))); sender.emitSignal1(); QCOMPARE(receiver->callCount, 1); receiver->destroyIfLastRef(); #else QSKIP("Needs QT_BUILD_INTERNAL"); #endif } #ifndef QT_NO_EXCEPTIONS class ObjectException : public std::exception { }; struct ThrowFunctor { CountedStruct operator()(const CountedStruct &, CountedStruct s2) const { throw ObjectException(); return s2; } CountedStruct s; }; #endif class ExceptionThrower : public QObject { W_OBJECT(ExceptionThrower) public slots: CountedStruct throwException(const CountedStruct &, CountedStruct s2) { #ifndef QT_NO_EXCEPTIONS throw ObjectException(); #endif return s2; } W_SLOT(throwException) signals: CountedStruct mySignal(const CountedStruct &s1, CountedStruct s2) W_SIGNAL(mySignal,s1,s2) }; class CountedExceptionThrower : public QObject { W_OBJECT(CountedExceptionThrower) public: explicit CountedExceptionThrower(bool throwException, QObject *parent = nullptr) : QObject(parent) { if (throwException) throw ObjectException(); ++counter; } ~CountedExceptionThrower() { --counter; } static int counter; }; int CountedExceptionThrower::counter = 0; void tst_QObject::exceptions() { #ifndef QT_NO_EXCEPTIONS ReceiverObject receiver; // String based syntax { QCOMPARE(countedStructObjectsCount, 0); ExceptionThrower thrower; receiver.reset(); connect(&thrower, SIGNAL(mySignal(CountedStruct,CountedStruct)), &receiver, SLOT(slot1())); connect(&thrower, SIGNAL(mySignal(CountedStruct,CountedStruct)), &thrower, SLOT(throwException(CountedStruct,CountedStruct))); connect(&thrower, SIGNAL(mySignal(CountedStruct,CountedStruct)), &receiver, SLOT(slot2())); try { CountedStruct s; emit thrower.mySignal(s, s); QFAIL("Exception not thrown?"); } catch (ObjectException&) {} QCOMPARE(receiver.count_slot1, 1); QCOMPARE(receiver.count_slot2, 0); QCOMPARE(countedStructObjectsCount, 0); } // Pointer to member function { QCOMPARE(countedStructObjectsCount, 0); ExceptionThrower thrower; receiver.reset(); connect(&thrower, &ExceptionThrower::mySignal, &receiver, &ReceiverObject::slot1); connect(&thrower, &ExceptionThrower::mySignal, &thrower, &ExceptionThrower::throwException); connect(&thrower, &ExceptionThrower::mySignal, &receiver, &ReceiverObject::slot2); try { CountedStruct s; emit thrower.mySignal(s, s); QFAIL("Exception not thrown?"); } catch (ObjectException&) {} QCOMPARE(receiver.count_slot1, 1); QCOMPARE(receiver.count_slot2, 0); QCOMPARE(countedStructObjectsCount, 0); } // Functor { QCOMPARE(countedStructObjectsCount, 0); ExceptionThrower thrower; receiver.reset(); connect(&thrower, &ExceptionThrower::mySignal, &receiver, &ReceiverObject::slot1); connect(&thrower, &ExceptionThrower::mySignal, ThrowFunctor()); connect(&thrower, &ExceptionThrower::mySignal, &receiver, &ReceiverObject::slot2); try { CountedStruct s; emit thrower.mySignal(s, s); QFAIL("Exception not thrown?"); } catch (ObjectException&) {} QCOMPARE(receiver.count_slot1, 1); QCOMPARE(receiver.count_slot2, 0); QCOMPARE(countedStructObjectsCount, 1); // the Functor } QCOMPARE(countedStructObjectsCount, 0); // Child object reaping in case of exceptions thrown by constructors { QCOMPARE(CountedExceptionThrower::counter, 0); try { class ParentObject : public QObject { public: explicit ParentObject(QObject *parent = nullptr) : QObject(parent) { new CountedExceptionThrower(false, this); new CountedExceptionThrower(false, this); new CountedExceptionThrower(true, this); // throws } }; ParentObject p; QFAIL("Exception not thrown"); } catch (const ObjectException &) { } catch (...) { QFAIL("Wrong exception thrown"); } QCOMPARE(CountedExceptionThrower::counter, 0); try { QObject o; new CountedExceptionThrower(false, &o); new CountedExceptionThrower(false, &o); new CountedExceptionThrower(true, &o); // throws QFAIL("Exception not thrown"); } catch (const ObjectException &) { } catch (...) { QFAIL("Wrong exception thrown"); } QCOMPARE(CountedExceptionThrower::counter, 0); try { QObject o; CountedExceptionThrower c1(false, &o); CountedExceptionThrower c2(false, &o); CountedExceptionThrower c3(true, &o); // throws QFAIL("Exception not thrown"); } catch (const ObjectException &) { } catch (...) { QFAIL("Wrong exception thrown"); } QCOMPARE(CountedExceptionThrower::counter, 0); } #else QSKIP("Needs exceptions"); #endif } #ifdef QT_BUILD_INTERNAL static bool parentChangeCalled = false; static void testParentChanged(QAbstractDeclarativeData *, QObject *, QObject *) { parentChangeCalled = true; } #endif void tst_QObject::noDeclarativeParentChangedOnDestruction() { #ifdef QT_BUILD_INTERNAL typedef void (*ParentChangedCallback)(QAbstractDeclarativeData *, QObject *, QObject *); QScopedValueRollback rollback(QAbstractDeclarativeData::parentChanged); QAbstractDeclarativeData::parentChanged = testParentChanged; QObject *parent = new QObject; QObject *child = new QObject; QAbstractDeclarativeDataImpl dummy; dummy.ownedByQml1 = false; QObjectPrivate::get(child)->declarativeData = &dummy; parentChangeCalled = false; child->setParent(parent); QVERIFY(parentChangeCalled); parentChangeCalled = false; delete child; QVERIFY(!parentChangeCalled); delete parent; #else QSKIP("Needs QT_BUILD_INTERNAL"); #endif } struct MutableFunctor { int count; MutableFunctor() : count(0) {} int operator()() { return ++count; } }; void tst_QObject::mutableFunctor() { #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 1) ReturnValue o; MutableFunctor functor; QCOMPARE(functor.count, 0); connect(&o, &ReturnValue::returnInt, functor); QCOMPARE(emit o.returnInt(0), 1); QCOMPARE(emit o.returnInt(0), 2); // each emit should increase the internal count QCOMPARE(functor.count, 0); // but the original object should have been copied at connect time #endif } void tst_QObject::checkArgumentsForNarrowing() { enum UnscopedEnum {}; enum SignedUnscopedEnum { SignedUnscopedEnumV1 = -1, SignedUnscopedEnumV2 = 1 }; // a constexpr would suffice, but MSVC2013 RTM doesn't support them... #define IS_UNSCOPED_ENUM_SIGNED (std::is_signed::type>::value) #define NARROWS_IF(x, y, test) Q_STATIC_ASSERT((QtPrivate::AreArgumentsNarrowedBase::value) == (test)) #define FITS_IF(x, y, test) Q_STATIC_ASSERT((QtPrivate::AreArgumentsNarrowedBase::value) != (test)) #define NARROWS(x, y) NARROWS_IF(x, y, true) #define FITS(x, y) FITS_IF(x, y, true) Q_STATIC_ASSERT(sizeof(UnscopedEnum) <= sizeof(int)); Q_STATIC_ASSERT(sizeof(SignedUnscopedEnum) <= sizeof(int)); #if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0) // floating point to integral NARROWS(float, bool); NARROWS(double, bool); NARROWS(long double, bool); NARROWS(float, char); NARROWS(double, char); NARROWS(long double, char); NARROWS(float, short); NARROWS(double, short); NARROWS(long double, short); NARROWS(float, int); NARROWS(double, int); NARROWS(long double, int); NARROWS(float, long); NARROWS(double, long); NARROWS(long double, long); NARROWS(float, long long); NARROWS(double, long long); NARROWS(long double, long long); // floating point to a smaller floating point NARROWS_IF(double, float, (sizeof(double) > sizeof(float))); NARROWS_IF(long double, float, (sizeof(long double) > sizeof(float))); FITS(float, double); FITS(float, long double); NARROWS_IF(long double, double, (sizeof(long double) > sizeof(double))); FITS(double, long double); // integral to floating point NARROWS(bool, float); NARROWS(bool, double); NARROWS(bool, long double); NARROWS(char, float); NARROWS(char, double); NARROWS(char, long double); NARROWS(short, float); NARROWS(short, double); NARROWS(short, long double); NARROWS(int, float); NARROWS(int, double); NARROWS(int, long double); NARROWS(long, float); NARROWS(long, double); NARROWS(long, long double); NARROWS(long long, float); NARROWS(long long, double); NARROWS(long long, long double); // enum to floating point NARROWS(UnscopedEnum, float); NARROWS(UnscopedEnum, double); NARROWS(UnscopedEnum, long double); NARROWS(SignedUnscopedEnum, float); NARROWS(SignedUnscopedEnum, double); NARROWS(SignedUnscopedEnum, long double); // integral to smaller integral FITS(bool, bool); FITS(char, char); FITS(signed char, signed char); FITS(signed char, short); FITS(signed char, int); FITS(signed char, long); FITS(signed char, long long); FITS(unsigned char, unsigned char); FITS(unsigned char, unsigned short); FITS(unsigned char, unsigned int); FITS(unsigned char, unsigned long); FITS(unsigned char, unsigned long long); NARROWS_IF(bool, unsigned char, (sizeof(bool) > sizeof(char) || std::is_signed::value)); NARROWS_IF(bool, unsigned short, (sizeof(bool) > sizeof(short) || std::is_signed::value)); NARROWS_IF(bool, unsigned int, (sizeof(bool) > sizeof(int) || std::is_signed::value)); NARROWS_IF(bool, unsigned long, (sizeof(bool) > sizeof(long) || std::is_signed::value)); NARROWS_IF(bool, unsigned long long, (sizeof(bool) > sizeof(long long) || std::is_signed::value)); NARROWS_IF(short, char, (sizeof(short) > sizeof(char) || std::is_unsigned::value)); NARROWS_IF(short, unsigned char, (sizeof(short) > sizeof(char))); NARROWS_IF(short, signed char, (sizeof(short) > sizeof(char))); NARROWS_IF(unsigned short, char, (sizeof(short) > sizeof(char) || std::is_signed::value)); NARROWS_IF(unsigned short, unsigned char, (sizeof(short) > sizeof(char))); NARROWS_IF(unsigned short, signed char, (sizeof(short) > sizeof(char))); FITS(short, short); FITS(short, int); FITS(short, long); FITS(short, long long); FITS(unsigned short, unsigned short); FITS(unsigned short, unsigned int); FITS(unsigned short, unsigned long); FITS(unsigned short, unsigned long long); NARROWS_IF(int, char, (sizeof(int) > sizeof(char) || std::is_unsigned::value)); NARROWS(int, unsigned char); NARROWS_IF(int, signed char, (sizeof(int) > sizeof(char))); NARROWS_IF(int, short, (sizeof(int) > sizeof(short))); NARROWS(int, unsigned short); NARROWS_IF(unsigned int, char, (sizeof(int) > sizeof(char) || std::is_signed::value)); NARROWS_IF(unsigned int, unsigned char, (sizeof(int) > sizeof(char))); NARROWS(unsigned int, signed char); NARROWS(unsigned int, short); NARROWS_IF(unsigned int, unsigned short, (sizeof(int) > sizeof(short))); FITS(int, int); FITS(int, long); FITS(int, long long); FITS(unsigned int, unsigned int); FITS(unsigned int, unsigned long); FITS(unsigned int, unsigned long long); NARROWS_IF(long, char, (sizeof(long) > sizeof(char) || std::is_unsigned::value)); NARROWS(long, unsigned char); NARROWS_IF(long, signed char, (sizeof(long) > sizeof(char))); NARROWS_IF(long, short, (sizeof(long) > sizeof(short))); NARROWS(long, unsigned short); NARROWS_IF(long, int, (sizeof(long) > sizeof(int))); NARROWS(long, unsigned int); NARROWS_IF(unsigned long, char, (sizeof(long) > sizeof(char) || std::is_signed::value)); NARROWS_IF(unsigned long, unsigned char, (sizeof(long) > sizeof(char))); NARROWS(unsigned long, signed char); NARROWS(unsigned long, short); NARROWS_IF(unsigned long, unsigned short, (sizeof(long) > sizeof(short))); NARROWS(unsigned long, int); NARROWS_IF(unsigned long, unsigned int, (sizeof(long) > sizeof(int))); FITS(long, long); FITS(long, long long); FITS(unsigned long, unsigned long); FITS(unsigned long, unsigned long long); NARROWS_IF(long long, char, (sizeof(long long) > sizeof(char) || std::is_unsigned::value)); NARROWS(long long, unsigned char); NARROWS_IF(long long, signed char, (sizeof(long long) > sizeof(char))); NARROWS_IF(long long, short, (sizeof(long long) > sizeof(short))); NARROWS(long long, unsigned short); NARROWS_IF(long long, int, (sizeof(long long) > sizeof(int))); NARROWS(long long, unsigned int); NARROWS_IF(long long, long, (sizeof(long long) > sizeof(long))); NARROWS(long long, unsigned long); NARROWS_IF(unsigned long long, char, (sizeof(long long) > sizeof(char) || std::is_signed::value)); NARROWS_IF(unsigned long long, unsigned char, (sizeof(long long) > sizeof(char))); NARROWS(unsigned long long, signed char); NARROWS(unsigned long long, short); NARROWS_IF(unsigned long long, unsigned short, (sizeof(long long) > sizeof(short))); NARROWS(unsigned long long, int); NARROWS_IF(unsigned long long, unsigned int, (sizeof(long long) > sizeof(int))); NARROWS(unsigned long long, long); NARROWS_IF(unsigned long long, unsigned long, (sizeof(long long) > sizeof(long))); FITS(long long, long long); FITS(unsigned long long, unsigned long long); // integral to integral with different signedness. smaller ones tested above NARROWS(signed char, unsigned char); NARROWS(signed char, unsigned short); NARROWS(signed char, unsigned int); NARROWS(signed char, unsigned long); NARROWS(signed char, unsigned long long); NARROWS(unsigned char, signed char); FITS(unsigned char, short); FITS(unsigned char, int); FITS(unsigned char, long); FITS(unsigned char, long long); NARROWS(short, unsigned short); NARROWS(short, unsigned int); NARROWS(short, unsigned long); NARROWS(short, unsigned long long); NARROWS(unsigned short, short); FITS(unsigned short, int); FITS(unsigned short, long); FITS(unsigned short, long long); NARROWS(int, unsigned int); NARROWS(int, unsigned long); NARROWS(int, unsigned long long); NARROWS(unsigned int, int); NARROWS_IF(unsigned int, long, (sizeof(int) >= sizeof(long))); FITS(unsigned int, long long); NARROWS(long, unsigned long); NARROWS(long, unsigned long long); NARROWS(unsigned long, long); NARROWS_IF(unsigned long, long long, (sizeof(long) >= sizeof(long long))); NARROWS(long long, unsigned long long); NARROWS(unsigned long long, long long); // enum to smaller integral // (note that we know that sizeof(UnscopedEnum) <= sizeof(int) FITS(UnscopedEnum, UnscopedEnum); FITS(SignedUnscopedEnum, SignedUnscopedEnum); NARROWS_IF(UnscopedEnum, char, ((sizeof(UnscopedEnum) > sizeof(char)) || (sizeof(UnscopedEnum) == sizeof(char) && IS_UNSCOPED_ENUM_SIGNED == std::is_signed::value))); NARROWS_IF(UnscopedEnum, signed char, ((sizeof(UnscopedEnum) > sizeof(char)) || (sizeof(UnscopedEnum) == sizeof(char) && !IS_UNSCOPED_ENUM_SIGNED))); NARROWS_IF(UnscopedEnum, unsigned char, ((sizeof(UnscopedEnum) > sizeof(char)) || IS_UNSCOPED_ENUM_SIGNED)); NARROWS_IF(UnscopedEnum, short, ((sizeof(UnscopedEnum) > sizeof(short)) || (sizeof(UnscopedEnum) == sizeof(short) && !IS_UNSCOPED_ENUM_SIGNED))); NARROWS_IF(UnscopedEnum, unsigned short, ((sizeof(UnscopedEnum) > sizeof(short)) || IS_UNSCOPED_ENUM_SIGNED)); NARROWS_IF(UnscopedEnum, int, (sizeof(UnscopedEnum) == sizeof(int) && !IS_UNSCOPED_ENUM_SIGNED)); NARROWS_IF(UnscopedEnum, unsigned int, IS_UNSCOPED_ENUM_SIGNED); NARROWS_IF(UnscopedEnum, long, (sizeof(UnscopedEnum) == sizeof(long) && !IS_UNSCOPED_ENUM_SIGNED)); NARROWS_IF(UnscopedEnum, unsigned long, IS_UNSCOPED_ENUM_SIGNED); NARROWS_IF(UnscopedEnum, long long, (sizeof(UnscopedEnum) == sizeof(long long) && !IS_UNSCOPED_ENUM_SIGNED)); NARROWS_IF(UnscopedEnum, unsigned long long, IS_UNSCOPED_ENUM_SIGNED); Q_STATIC_ASSERT(std::is_signed::type>::value); NARROWS_IF(SignedUnscopedEnum, signed char, (sizeof(SignedUnscopedEnum) > sizeof(char))); NARROWS_IF(SignedUnscopedEnum, short, (sizeof(SignedUnscopedEnum) > sizeof(short))); FITS(SignedUnscopedEnum, int); FITS(SignedUnscopedEnum, long); FITS(SignedUnscopedEnum, long long); enum class ScopedEnumBackedBySChar : signed char { A }; enum class ScopedEnumBackedByUChar : unsigned char { A }; enum class ScopedEnumBackedByShort : short { A }; enum class ScopedEnumBackedByUShort : unsigned short { A }; enum class ScopedEnumBackedByInt : int { A }; enum class ScopedEnumBackedByUInt : unsigned int { A }; enum class ScopedEnumBackedByLong : long { A }; enum class ScopedEnumBackedByULong : unsigned long { A }; enum class ScopedEnumBackedByLongLong : long long { A }; enum class ScopedEnumBackedByULongLong : unsigned long long { A }; FITS(ScopedEnumBackedBySChar, ScopedEnumBackedBySChar); FITS(ScopedEnumBackedByUChar, ScopedEnumBackedByUChar); FITS(ScopedEnumBackedByShort, ScopedEnumBackedByShort); FITS(ScopedEnumBackedByUShort, ScopedEnumBackedByUShort); FITS(ScopedEnumBackedByInt, ScopedEnumBackedByInt); FITS(ScopedEnumBackedByUInt, ScopedEnumBackedByUInt); FITS(ScopedEnumBackedByLong, ScopedEnumBackedByLong); FITS(ScopedEnumBackedByULong, ScopedEnumBackedByULong); FITS(ScopedEnumBackedByLongLong, ScopedEnumBackedByLongLong); FITS(ScopedEnumBackedByULongLong, ScopedEnumBackedByULongLong); FITS(ScopedEnumBackedBySChar, signed char); FITS(ScopedEnumBackedByUChar, unsigned char); FITS(ScopedEnumBackedByShort, short); FITS(ScopedEnumBackedByUShort, unsigned short); FITS(ScopedEnumBackedByInt, int); FITS(ScopedEnumBackedByUInt, unsigned int); FITS(ScopedEnumBackedByLong, long); FITS(ScopedEnumBackedByULong, unsigned long); FITS(ScopedEnumBackedByLongLong, long long); FITS(ScopedEnumBackedByULongLong, unsigned long long); FITS(ScopedEnumBackedBySChar, signed char); FITS(ScopedEnumBackedBySChar, short); FITS(ScopedEnumBackedBySChar, int); FITS(ScopedEnumBackedBySChar, long); FITS(ScopedEnumBackedBySChar, long long); FITS(ScopedEnumBackedByUChar, unsigned char); FITS(ScopedEnumBackedByUChar, unsigned short); FITS(ScopedEnumBackedByUChar, unsigned int); FITS(ScopedEnumBackedByUChar, unsigned long); FITS(ScopedEnumBackedByUChar, unsigned long long); NARROWS_IF(ScopedEnumBackedByShort, char, (sizeof(short) > sizeof(char) || std::is_unsigned::value)); NARROWS_IF(ScopedEnumBackedByUShort, char, (sizeof(short) > sizeof(char) || std::is_signed::value)); NARROWS_IF(ScopedEnumBackedByInt, char, (sizeof(int) > sizeof(char) || std::is_unsigned::value)); NARROWS_IF(ScopedEnumBackedByUInt, char, (sizeof(int) > sizeof(char) || std::is_signed::value)); NARROWS_IF(ScopedEnumBackedByLong, char, (sizeof(long) > sizeof(char) || std::is_unsigned::value)); NARROWS_IF(ScopedEnumBackedByULong, char, (sizeof(long) > sizeof(char) || std::is_signed::value)); NARROWS_IF(ScopedEnumBackedByLongLong, char, (sizeof(long long) > sizeof(char) || std::is_unsigned::value)); NARROWS_IF(ScopedEnumBackedByULongLong, char, (sizeof(long long) > sizeof(char) || std::is_signed::value)); NARROWS_IF(ScopedEnumBackedByShort, signed char, (sizeof(short) > sizeof(char))); NARROWS(ScopedEnumBackedByUShort, signed char); NARROWS_IF(ScopedEnumBackedByInt, signed char, (sizeof(int) > sizeof(char))); NARROWS(ScopedEnumBackedByUInt, signed char); NARROWS_IF(ScopedEnumBackedByLong, signed char, (sizeof(long) > sizeof(char))); NARROWS(ScopedEnumBackedByULong, signed char); NARROWS_IF(ScopedEnumBackedByLongLong, signed char, (sizeof(long long) > sizeof(char))); NARROWS(ScopedEnumBackedByULongLong, signed char); NARROWS(ScopedEnumBackedByShort, unsigned char); NARROWS_IF(ScopedEnumBackedByUShort, unsigned char, (sizeof(short) > sizeof(char))); NARROWS(ScopedEnumBackedByInt, unsigned char); NARROWS_IF(ScopedEnumBackedByUInt, unsigned char, (sizeof(int) > sizeof(char))); NARROWS(ScopedEnumBackedByLong, unsigned char); NARROWS_IF(ScopedEnumBackedByULong, unsigned char, (sizeof(long) > sizeof(char))); NARROWS(ScopedEnumBackedByLongLong, unsigned char); NARROWS_IF(ScopedEnumBackedByULongLong, unsigned char, (sizeof(long long) > sizeof(char))); NARROWS_IF(ScopedEnumBackedByInt, short, (sizeof(int) > sizeof(short))); NARROWS(ScopedEnumBackedByUInt, short); NARROWS_IF(ScopedEnumBackedByLong, short, (sizeof(long) > sizeof(short))); NARROWS(ScopedEnumBackedByULong, short); NARROWS_IF(ScopedEnumBackedByLongLong, short, (sizeof(long long) > sizeof(short))); NARROWS(ScopedEnumBackedByULongLong, short); NARROWS(ScopedEnumBackedByInt, unsigned short); NARROWS_IF(ScopedEnumBackedByUInt, unsigned short, (sizeof(int) > sizeof(short))); NARROWS(ScopedEnumBackedByLong, unsigned short); NARROWS_IF(ScopedEnumBackedByULong, unsigned short, (sizeof(long) > sizeof(short))); NARROWS(ScopedEnumBackedByLongLong, unsigned short); NARROWS_IF(ScopedEnumBackedByULongLong, unsigned short, (sizeof(long long) > sizeof(short))); NARROWS_IF(ScopedEnumBackedByLong, int, (sizeof(long) > sizeof(int))); NARROWS(ScopedEnumBackedByULong, int); NARROWS_IF(ScopedEnumBackedByLongLong, int, (sizeof(long long) > sizeof(int))); NARROWS(ScopedEnumBackedByULongLong, int); NARROWS(ScopedEnumBackedByLong, unsigned int); NARROWS_IF(ScopedEnumBackedByULong, unsigned int, (sizeof(long) > sizeof(int))); NARROWS(ScopedEnumBackedByLongLong, unsigned int); NARROWS_IF(ScopedEnumBackedByULongLong, unsigned int, (sizeof(long long) > sizeof(int))); NARROWS_IF(ScopedEnumBackedByLongLong, long, (sizeof(long long) > sizeof(long))); NARROWS(ScopedEnumBackedByULongLong, long); NARROWS(ScopedEnumBackedByLongLong, unsigned long); NARROWS_IF(ScopedEnumBackedByULongLong, unsigned long, (sizeof(long long) > sizeof(long))); // different signedness of the underlying type NARROWS(SignedUnscopedEnum, unsigned char); NARROWS(SignedUnscopedEnum, unsigned short); NARROWS(SignedUnscopedEnum, unsigned int); NARROWS(SignedUnscopedEnum, unsigned long); NARROWS(SignedUnscopedEnum, unsigned long long); NARROWS(ScopedEnumBackedBySChar, unsigned char); NARROWS(ScopedEnumBackedBySChar, unsigned short); NARROWS(ScopedEnumBackedBySChar, unsigned int); NARROWS(ScopedEnumBackedBySChar, unsigned long); NARROWS(ScopedEnumBackedBySChar, unsigned long long); NARROWS(ScopedEnumBackedByShort, unsigned char); NARROWS(ScopedEnumBackedByShort, unsigned short); NARROWS(ScopedEnumBackedByShort, unsigned int); NARROWS(ScopedEnumBackedByShort, unsigned long); NARROWS(ScopedEnumBackedByShort, unsigned long long); NARROWS(ScopedEnumBackedByInt, unsigned char); NARROWS(ScopedEnumBackedByInt, unsigned short); NARROWS(ScopedEnumBackedByInt, unsigned int); NARROWS(ScopedEnumBackedByInt, unsigned long); NARROWS(ScopedEnumBackedByInt, unsigned long long); NARROWS(ScopedEnumBackedByLong, unsigned char); NARROWS(ScopedEnumBackedByLong, unsigned short); NARROWS(ScopedEnumBackedByLong, unsigned int); NARROWS(ScopedEnumBackedByLong, unsigned long); NARROWS(ScopedEnumBackedByLong, unsigned long long); NARROWS(ScopedEnumBackedByLongLong, unsigned char); NARROWS(ScopedEnumBackedByLongLong, unsigned short); NARROWS(ScopedEnumBackedByLongLong, unsigned int); NARROWS(ScopedEnumBackedByLongLong, unsigned long); NARROWS(ScopedEnumBackedByLongLong, unsigned long long); NARROWS(ScopedEnumBackedByUChar, signed char); FITS_IF(ScopedEnumBackedByUChar, short, (sizeof(char) < sizeof(short))); FITS_IF(ScopedEnumBackedByUChar, int, (sizeof(char) < sizeof(int))); FITS_IF(ScopedEnumBackedByUChar, long, (sizeof(char) < sizeof(long))); FITS_IF(ScopedEnumBackedByUChar, long long, (sizeof(char) < sizeof(long long))); NARROWS(ScopedEnumBackedByUShort, signed char); NARROWS(ScopedEnumBackedByUShort, short); FITS_IF(ScopedEnumBackedByUShort, int, (sizeof(short) < sizeof(int))); FITS_IF(ScopedEnumBackedByUShort, long, (sizeof(short) < sizeof(long))); FITS_IF(ScopedEnumBackedByUShort, long long, (sizeof(short) < sizeof(long long))); NARROWS(ScopedEnumBackedByUInt, signed char); NARROWS(ScopedEnumBackedByUInt, short); NARROWS(ScopedEnumBackedByUInt, int); FITS_IF(ScopedEnumBackedByUInt, long, (sizeof(ScopedEnumBackedByUInt) < sizeof(long))); FITS(ScopedEnumBackedByUInt, long long); NARROWS(ScopedEnumBackedByULong, signed char); NARROWS(ScopedEnumBackedByULong, short); NARROWS(ScopedEnumBackedByULong, int); NARROWS(ScopedEnumBackedByULong, long); FITS_IF(ScopedEnumBackedByULong, long long, (sizeof(ScopedEnumBackedByULong) < sizeof(long long))); NARROWS(ScopedEnumBackedByULongLong, signed char); NARROWS(ScopedEnumBackedByULongLong, short); NARROWS(ScopedEnumBackedByULongLong, int); NARROWS(ScopedEnumBackedByULongLong, long); NARROWS(ScopedEnumBackedByULongLong, long long); // other types which should be always unaffected FITS(void *, void *); FITS(QString, QString); FITS(QString &, QString &); FITS(const QString &, const QString &); FITS(QObject, QObject); FITS(QObject *, QObject *); FITS(const QObject *, const QObject *); FITS(std::nullptr_t, std::nullptr_t); FITS(QString, QObject); FITS(QString, QVariant); FITS(QString, void *); FITS(QString, long long); FITS(bool, const QObject *&); FITS(int (*)(bool), void (QObject::*)()); #endif #undef IS_UNSCOPED_ENUM_SIGNED #undef NARROWS_IF #undef FITS_IF #undef NARROWS #undef FITS } void tst_QObject::nullReceiver() { #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 1) QObject o; QObject *nullObj = nullptr; // Passing nullptr directly doesn't compile with gcc 4.8 QVERIFY(!connect(&o, &QObject::destroyed, nullObj, &QObject::deleteLater)); QVERIFY(!connect(&o, &QObject::destroyed, nullObj, [] {})); QVERIFY(!connect(&o, &QObject::destroyed, nullObj, Functor_noexcept())); QVERIFY(!connect(&o, SIGNAL(destroyed()), nullObj, SLOT(deleteLater()))); #endif } // Test for QtPrivate::HasQ_OBJECT_Macro Q_STATIC_ASSERT(QtPrivate::HasQ_OBJECT_Macro::Value); Q_STATIC_ASSERT(!QtPrivate::HasQ_OBJECT_Macro::Value); QTEST_MAIN(tst_QObject) W_OBJECT_IMPL(tst_QObject) W_OBJECT_IMPL(SenderObject) W_OBJECT_IMPL(ReceiverObject) W_OBJECT_IMPL(AutoConnectSender) W_OBJECT_IMPL(AutoConnectReceiver) W_OBJECT_IMPL(ConnectByNameNotifySenderObject) W_OBJECT_IMPL(ConnectByNameNotifyReceiverObject) W_OBJECT_IMPL(ConnectDisconnectNotifyShadowObject) W_OBJECT_IMPL(SequenceObject) W_OBJECT_IMPL(QCustomTypeChecker) W_OBJECT_IMPL(PropertyObject) W_OBJECT_IMPL(TestThread) W_OBJECT_IMPL(MoveToThreadObject) W_OBJECT_IMPL(QObjectTest::TestObject) W_OBJECT_IMPL(SuperObject) W_OBJECT_IMPL(FooObject) W_OBJECT_IMPL(BlehObject) W_OBJECT_IMPL(DestroyedListener) W_OBJECT_IMPL(DefaultArguments) W_OBJECT_IMPL(NormalizeObject) W_OBJECT_IMPL(EventSpy) W_OBJECT_IMPL(EmitThread) W_OBJECT_IMPL(QObjectTest::DeleteObject) W_OBJECT_IMPL(DisconnectObject) W_OBJECT_IMPL(ConnectToSender) W_OBJECT_IMPL(OverloadObject) W_OBJECT_IMPL(ManySignals) W_OBJECT_IMPL(ConfusingObject) W_OBJECT_IMPL(Constructable) W_OBJECT_IMPL(BaseDestroyed) W_OBJECT_IMPL(LotsOfSignalsAndSlots) W_OBJECT_IMPL(StringVariant) W_OBJECT_IMPL(ConnectWithReferenceObject) W_OBJECT_IMPL(ManyArgumentObject) W_OBJECT_IMPL(ForwardDeclareArguments) W_GADGET_IMPL(NoDefaultConstructor) W_OBJECT_IMPL(NoDefaultContructorArguments) W_OBJECT_IMPL(ReturnValue) W_OBJECT_IMPL(VirtualSlotsObjectBase) W_OBJECT_IMPL(VirtualSlotsObject) #ifdef QT_BUILD_INTERNAL W_OBJECT_IMPL(ConnectToPrivateSlot) #endif W_OBJECT_IMPL(ContextObject) W_OBJECT_IMPL(StaticSlotChecker) W_OBJECT_IMPL(FunctorArgDifferenceObject) W_OBJECT_IMPL(GetSenderObject) W_OBJECT_IMPL(SubSender) W_OBJECT_IMPL(ExceptionThrower) W_OBJECT_IMPL(CountedExceptionThrower) verdigris-1.3/tests/qt/qobject/tst_qobject6.cpp000066400000000000000000011524531427643277200217340ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2015 Olivier Goffart ** 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 #if QT_VERSION >= QT_VERSION_CHECK(6,2,0) #include #endif #include #include #if QT_VERSION >= QT_VERSION_CHECK(6,2,0) #include #endif #include #include #include #include #include #include #include #include #include #include #if QT_CONFIG(process) # include #endif #include "qobject.h" #ifdef QT_BUILD_INTERNAL #undef QT_BUILD_INTERNAL // Verdigris don't test the internals #endif #include #include #include QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations") QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations") QT_WARNING_DISABLE_GCC("-Wdeprecated-copy") W_REGISTER_ARGTYPE(int&) W_REGISTER_ARGTYPE(short&) W_REGISTER_ARGTYPE(bool&) W_REGISTER_ARGTYPE(QObject) W_REGISTER_ARGTYPE(QObject&) class tst_QObject : public QObject { W_OBJECT(tst_QObject) private slots: void disconnect(); W_SLOT(disconnect, W_Access::Private) void connectSlotsByName(); W_SLOT(connectSlotsByName, W_Access::Private) void connectSignalsToSignalsWithDefaultArguments(); W_SLOT(connectSignalsToSignalsWithDefaultArguments, W_Access::Private) void receivers(); W_SLOT(receivers, W_Access::Private) void normalize(); W_SLOT(normalize, W_Access::Private) void qobject_castTemplate(); W_SLOT(qobject_castTemplate, W_Access::Private) void findChildren(); W_SLOT(findChildren, W_Access::Private) void connectDisconnectNotify_data(); W_SLOT(connectDisconnectNotify_data, W_Access::Private) void connectDisconnectNotify(); W_SLOT(connectDisconnectNotify, W_Access::Private) void connectDisconnectNotifyPMF(); W_SLOT(connectDisconnectNotifyPMF, W_Access::Private) void disconnectNotify_receiverDestroyed(); W_SLOT(disconnectNotify_receiverDestroyed, W_Access::Private) void disconnectNotify_metaObjConnection(); W_SLOT(disconnectNotify_metaObjConnection, W_Access::Private) void connectNotify_connectSlotsByName(); W_SLOT(connectNotify_connectSlotsByName, W_Access::Private) void connectDisconnectNotify_shadowing(); W_SLOT(connectDisconnectNotify_shadowing, W_Access::Private) void connectReferenceToIncompleteTypes(); W_SLOT(connectReferenceToIncompleteTypes, W_Access::Private) void emitInDefinedOrder(); W_SLOT(emitInDefinedOrder, W_Access::Private) void customTypes(); W_SLOT(customTypes, W_Access::Private) void streamCustomTypes(); W_SLOT(streamCustomTypes, W_Access::Private) void metamethod(); W_SLOT(metamethod, W_Access::Private) void namespaces(); W_SLOT(namespaces, W_Access::Private) void threadSignalEmissionCrash(); W_SLOT(threadSignalEmissionCrash, W_Access::Private) void thread(); W_SLOT(thread, W_Access::Private) void thread0(); W_SLOT(thread0, W_Access::Private) void moveToThread(); W_SLOT(moveToThread, W_Access::Private) void senderTest(); W_SLOT(senderTest, W_Access::Private) void declareInterface(); W_SLOT(declareInterface, W_Access::Private) void qpointerResetBeforeDestroyedSignal(); W_SLOT(qpointerResetBeforeDestroyedSignal, W_Access::Private) void childDeletesItsSibling(); W_SLOT(childDeletesItsSibling, W_Access::Private) void dynamicProperties(); W_SLOT(dynamicProperties, W_Access::Private) void floatProperty(); W_SLOT(floatProperty, W_Access::Private) void qrealProperty(); W_SLOT(qrealProperty, W_Access::Private) void property(); W_SLOT(property, W_Access::Private) void recursiveSignalEmission(); W_SLOT(recursiveSignalEmission, W_Access::Private) void signalBlocking(); W_SLOT(signalBlocking, W_Access::Private) void blockingQueuedConnection(); W_SLOT(blockingQueuedConnection, W_Access::Private) void childEvents(); W_SLOT(childEvents, W_Access::Private) void installEventFilter(); W_SLOT(installEventFilter, W_Access::Private) void deleteSelfInSlot(); W_SLOT(deleteSelfInSlot, W_Access::Private) void disconnectSelfInSlotAndDeleteAfterEmit(); W_SLOT(disconnectSelfInSlotAndDeleteAfterEmit, W_Access::Private) void dumpObjectInfo(); W_SLOT(dumpObjectInfo, W_Access::Private) #if QT_VERSION >= QT_VERSION_CHECK(6,3,0) void dumpObjectTree(); W_SLOT(dumpObjectTree, W_Access::Private) #endif void connectToSender(); W_SLOT(connectToSender, W_Access::Private) void qobjectConstCast(); W_SLOT(qobjectConstCast, W_Access::Private) void uniqConnection(); W_SLOT(uniqConnection, W_Access::Private) void uniqConnectionPtr(); W_SLOT(uniqConnectionPtr, W_Access::Private) void interfaceIid(); W_SLOT(interfaceIid, W_Access::Private) void deleteQObjectWhenDeletingEvent(); W_SLOT(deleteQObjectWhenDeletingEvent, W_Access::Private) void overloads(); W_SLOT(overloads, W_Access::Private) void isSignalConnected(); W_SLOT(isSignalConnected, W_Access::Private) void isSignalConnectedAfterDisconnection(); W_SLOT(isSignalConnectedAfterDisconnection, W_Access::Private) void qMetaObjectConnect(); W_SLOT(qMetaObjectConnect, W_Access::Private) void qMetaObjectDisconnectOne(); W_SLOT(qMetaObjectDisconnectOne, W_Access::Private) void sameName(); W_SLOT(sameName, W_Access::Private) void connectByMetaMethods(); W_SLOT(connectByMetaMethods, W_Access::Private) void connectByMetaMethodSlotInsteadOfSignal(); W_SLOT(connectByMetaMethodSlotInsteadOfSignal, W_Access::Private) void connectConstructorByMetaMethod(); W_SLOT(connectConstructorByMetaMethod, W_Access::Private) void disconnectByMetaMethod(); W_SLOT(disconnectByMetaMethod, W_Access::Private) void disconnectNotSignalMetaMethod(); W_SLOT(disconnectNotSignalMetaMethod, W_Access::Private) void autoConnectionBehavior(); W_SLOT(autoConnectionBehavior, W_Access::Private) void baseDestroyed(); W_SLOT(baseDestroyed, W_Access::Private) void pointerConnect(); W_SLOT(pointerConnect, W_Access::Private) void pointerDisconnect(); W_SLOT(pointerDisconnect, W_Access::Private) void emitInDefinedOrderPointer(); W_SLOT(emitInDefinedOrderPointer, W_Access::Private) void customTypesPointer(); W_SLOT(customTypesPointer, W_Access::Private) void connectCxx0x(); W_SLOT(connectCxx0x, W_Access::Private) void connectToStaticCxx0x(); W_SLOT(connectToStaticCxx0x, W_Access::Private) void connectCxx0xTypeMatching(); W_SLOT(connectCxx0xTypeMatching, W_Access::Private) void connectCxx17Noexcept(); W_SLOT(connectCxx17Noexcept, W_Access::Private) void connectConvert(); W_SLOT(connectConvert, W_Access::Private) void connectWithReference(); W_SLOT(connectWithReference, W_Access::Private) void connectManyArguments(); W_SLOT(connectManyArguments, W_Access::Private) void connectForwardDeclare(); W_SLOT(connectForwardDeclare, W_Access::Private) void connectNoDefaultConstructorArg(); W_SLOT(connectNoDefaultConstructorArg, W_Access::Private) void returnValue_data(); W_SLOT(returnValue_data, W_Access::Private) void returnValue(); W_SLOT(returnValue, W_Access::Private) void returnValue2_data(); W_SLOT(returnValue2_data, W_Access::Private) void returnValue2(); W_SLOT(returnValue2, W_Access::Private) void connectVirtualSlots(); W_SLOT(connectVirtualSlots, W_Access::Private) void connectSlotsVMIClass(); W_SLOT(connectSlotsVMIClass, W_Access::Private) // VMI = Virtual or Multiple Inheritance void connectPrivateSlots(); W_SLOT(connectPrivateSlots, W_Access::Private) void connectFunctorArgDifference(); W_SLOT(connectFunctorArgDifference, W_Access::Private) void connectFunctorOverloads(); W_SLOT(connectFunctorOverloads, W_Access::Private) void connectFunctorQueued(); W_SLOT(connectFunctorQueued, W_Access::Private) void connectFunctorWithContext(); W_SLOT(connectFunctorWithContext, W_Access::Private) void connectFunctorWithContextUnique(); W_SLOT(connectFunctorWithContextUnique, W_Access::Private) void connectFunctorDeadlock(); W_SLOT(connectFunctorDeadlock, W_Access::Private) void connectFunctorMoveOnly(); W_SLOT(connectFunctorMoveOnly, W_Access::Private) void connectStaticSlotWithObject(); W_SLOT(connectStaticSlotWithObject, W_Access::Private) void disconnectDoesNotLeakFunctor(); W_SLOT(disconnectDoesNotLeakFunctor, W_Access::Private) void contextDoesNotLeakFunctor(); W_SLOT(contextDoesNotLeakFunctor, W_Access::Private) void connectBase(); W_SLOT(connectBase, W_Access::Private) void connectWarnings(); W_SLOT(connectWarnings, W_Access::Private) void qmlConnect(); W_SLOT(qmlConnect, W_Access::Private) void exceptions(); W_SLOT(exceptions, W_Access::Private) #if QT_VERSION < QT_VERSION_CHECK(6,2,0) void noDeclarativeParentChangedOnDestruction(); W_SLOT(noDeclarativeParentChangedOnDestruction, W_Access::Private) #endif void deleteLaterInAboutToBlockHandler(); W_SLOT(deleteLaterInAboutToBlockHandler, W_Access::Private) void mutableFunctor(); W_SLOT(mutableFunctor, W_Access::Private) void checkArgumentsForNarrowing(); W_SLOT(checkArgumentsForNarrowing, W_Access::Private) void nullReceiver(); W_SLOT(nullReceiver, W_Access::Private) void functorReferencesConnection(); W_SLOT(functorReferencesConnection, W_Access::Private) void disconnectDisconnects(); W_SLOT(disconnectDisconnects, W_Access::Private) void singleShotConnection(); W_SLOT(singleShotConnection, W_Access::Private) #if QT_VERSION >= QT_VERSION_CHECK(6,2,0) void objectNameBinding(); W_SLOT(objectNameBinding, W_Access::Private) #endif #if QT_VERSION >= QT_VERSION_CHECK(6,3,0) void emitToDestroyedClass(); W_SLOT(emitToDestroyedClass, W_Access::Private) #endif }; struct QObjectCreatedOnShutdown { QObjectCreatedOnShutdown() {} ~QObjectCreatedOnShutdown() { QObject(); } }; static QObjectCreatedOnShutdown s_qobjectCreatedOnShutdown; class SenderObject : public QObject { W_OBJECT(SenderObject) public: SenderObject() : aPublicSlotCalled(0), recursionCount(0) {} void emitSignal1AfterRecursion() { if (recursionCount++ < 100) emitSignal1AfterRecursion(); else emitSignal1(); } void emitSignal1() { emit signal1(); } void emitSignal2() { emit signal2(); } void emitSignal3() { emit signal3(); } void emitSignal4() { emit signal4(); } signals: void signal1() W_SIGNAL(signal1) void signal2() W_SIGNAL(signal2) void signal3() W_SIGNAL(signal3) void signal4() W_SIGNAL(signal4) void signal5() W_SIGNAL_COMPAT(signal5) void signal6(void) W_SIGNAL(signal6) void signal7(int a, const QString &b) W_SIGNAL(signal7,a,b) public slots: void aPublicSlot() { aPublicSlotCalled++; } W_SLOT(aPublicSlot) public: void invoke1(){} W_INVOKABLE(invoke1) void sinvoke1(){} W_INVOKABLE(sinvoke1, W_Scriptable) int aPublicSlotCalled; protected: void invoke2(){} W_INVOKABLE(invoke2,(), W_Compat, W_Access::Protected) void invoke2(int){} W_INVOKABLE(invoke2,(int), W_Compat, W_Access::Protected) void sinvoke2(){} W_INVOKABLE(sinvoke2, W_Compat, W_Scriptable, W_Access::Protected) private: void invoke3(int hinz = 0, int kunz = 0) { Q_UNUSED(hinz) Q_UNUSED(kunz) } W_INVOKABLE(invoke3, W_Access::Private) void sinvoke3(){} W_INVOKABLE(sinvoke3, W_Scriptable, W_Access::Private) int recursionCount; }; class ReceiverObject : public QObject { W_OBJECT(ReceiverObject) public: ReceiverObject() : sequence_slot1( 0 ) , sequence_slot2( 0 ) , sequence_slot3( 0 ) , sequence_slot4( 0 ) {} void reset() { sequence_slot4 = 0; sequence_slot3 = 0; sequence_slot2 = 0; sequence_slot1 = 0; count_slot1 = 0; count_slot2 = 0; count_slot3 = 0; count_slot4 = 0; } int sequence_slot1; int sequence_slot2; int sequence_slot3; int sequence_slot4; int count_slot1; int count_slot2; int count_slot3; int count_slot4; bool called(int slot) { switch (slot) { case 1: return sequence_slot1; case 2: return sequence_slot2; case 3: return sequence_slot3; case 4: return sequence_slot4; default: return false; } } static int sequence; public slots: void slot1() { sequence_slot1 = ++sequence; count_slot1++; } W_SLOT(slot1) void slot2() { sequence_slot2 = ++sequence; count_slot2++; } W_SLOT(slot2) void slot3() { sequence_slot3 = ++sequence; count_slot3++; } W_SLOT(slot3) void slot4() { sequence_slot4 = ++sequence; count_slot4++; } W_SLOT(slot4) }; int ReceiverObject::sequence = 0; static void playWithObjects() { // Do operations that will lock the internal signalSlotLock mutex on many QObjects. // The more QObjects, the higher the chance that the signalSlotLock mutex used // is already in use. If the number of objects is higher than the number of mutexes in // the pool (currently 131), the deadlock should always trigger. Use an even higher number // to be on the safe side. const int objectCount = 1024; SenderObject lotsOfObjects[objectCount]; for (int i = 0; i < objectCount; ++i) { QObject::connect(&lotsOfObjects[i], &SenderObject::signal1, &lotsOfObjects[i], &SenderObject::aPublicSlot); } } void tst_QObject::disconnect() { SenderObject s; ReceiverObject r1; ReceiverObject r2; connect(&s, SIGNAL(signal1()), &r1, SLOT(slot1())); connect(&s, SIGNAL(signal2()), &r1, SLOT(slot2())); connect(&s, SIGNAL(signal3()), &r1, SLOT(slot3())); connect(&s, SIGNAL(signal4()), &r1, SLOT(slot4())); s.emitSignal1(); s.emitSignal2(); s.emitSignal3(); s.emitSignal4(); QVERIFY(r1.called(1)); QVERIFY(r1.called(2)); QVERIFY(r1.called(3)); QVERIFY(r1.called(4)); r1.reset(); // usual disconnect with all parameters given bool ret = QObject::disconnect(&s, SIGNAL(signal1()), &r1, SLOT(slot1())); s.emitSignal1(); QVERIFY(!r1.called(1)); r1.reset(); QVERIFY(ret); ret = QObject::disconnect(&s, SIGNAL(signal1()), &r1, SLOT(slot1())); QVERIFY(!ret); // disconnect all signals from s from all slots from r1 QObject::disconnect(&s, 0, &r1, 0); s.emitSignal2(); s.emitSignal3(); s.emitSignal4(); QVERIFY(!r1.called(2)); QVERIFY(!r1.called(3)); QVERIFY(!r1.called(4)); r1.reset(); connect(&s, SIGNAL(signal1()), &r1, SLOT(slot1())); connect(&s, SIGNAL(signal1()), &r1, SLOT(slot2())); connect(&s, SIGNAL(signal1()), &r1, SLOT(slot3())); connect(&s, SIGNAL(signal2()), &r1, SLOT(slot4())); // disconnect s's signal1() from all slots of r1 QObject::disconnect(&s, SIGNAL(signal1()), &r1, 0); s.emitSignal1(); s.emitSignal2(); QVERIFY(!r1.called(1)); QVERIFY(!r1.called(2)); QVERIFY(!r1.called(3)); QVERIFY(r1.called(4)); r1.reset(); // make sure all is disconnected again QObject::disconnect(&s, 0, &r1, 0); connect(&s, SIGNAL(signal1()), &r1, SLOT(slot1())); connect(&s, SIGNAL(signal1()), &r2, SLOT(slot1())); connect(&s, SIGNAL(signal2()), &r1, SLOT(slot2())); connect(&s, SIGNAL(signal2()), &r2, SLOT(slot2())); connect(&s, SIGNAL(signal3()), &r1, SLOT(slot3())); connect(&s, SIGNAL(signal3()), &r2, SLOT(slot3())); // disconnect signal1() from all receivers QObject::disconnect(&s, SIGNAL(signal1()), 0, 0); s.emitSignal1(); s.emitSignal2(); s.emitSignal3(); QVERIFY(!r1.called(1)); QVERIFY(!r2.called(1)); QVERIFY(r1.called(2)); QVERIFY(r2.called(2)); QVERIFY(r1.called(2)); QVERIFY(r2.called(2)); r1.reset(); r2.reset(); // disconnect all signals of s from all receivers QObject::disconnect(&s, 0, 0, 0); QVERIFY(!r1.called(2)); QVERIFY(!r2.called(2)); QVERIFY(!r1.called(2)); QVERIFY(!r2.called(2)); } class AutoConnectSender : public QObject { W_OBJECT(AutoConnectSender) public: AutoConnectSender(QObject *parent) : QObject(parent) {} void emitSignalNoParams() { emit signalNoParams(); } void emitSignalWithParams(int i) { emit signalWithParams(i); } void emitSignalWithParams(int i, QString string) { emit signalWithParams(i, string); } void emitSignalManyParams(int i1, int i2, int i3, QString string, bool onoff) { emit signalManyParams(i1, i2, i3, string, onoff); } void emitSignalManyParams(int i1, int i2, int i3, QString string, bool onoff, bool dummy) { emit signalManyParams(i1, i2, i3, string, onoff, dummy); } void emitSignalManyParams2(int i1, int i2, int i3, QString string, bool onoff) { emit signalManyParams2(i1, i2, i3, string, onoff); } void emitSignalLoopBack() { emit signalLoopBack(); } signals: void signalNoParams() W_SIGNAL(signalNoParams) void signalWithParams(int i) W_SIGNAL(signalWithParams,(int),i) void signalWithParams(int i, QString string) W_SIGNAL(signalWithParams,(int,QString),i, string) void signalManyParams(int i1, int i2, int i3, QString string, bool onoff) W_SIGNAL(signalManyParams,(int,int,int,QString,bool),i1,i2,i3,string,onoff) void signalManyParams(int i1, int i2, int i3, QString string, bool onoff, bool _) W_SIGNAL(signalManyParams,(int,int,int,QString,bool,bool),i1,i2,i3,string,onoff,_) void signalManyParams2(int i1, int i2, int i3, QString string, bool onoff) W_SIGNAL(signalManyParams2, i1,i2,i3,string,onoff) void signalLoopBack() W_SIGNAL(signalLoopBack) }; class AutoConnectReceiver : public QObject { W_OBJECT(AutoConnectReceiver) public: QList called_slots; AutoConnectReceiver() { connect(this, SIGNAL(on_Sender_signalLoopBack()), this, SLOT(slotLoopBack())); } void emitSignalNoParams() { emit signalNoParams(); } void emit_signal_with_underscore() { emit signal_with_underscore(); } public slots: void on_Sender_signalNoParams() { called_slots << 1; } W_SLOT(on_Sender_signalNoParams) void on_Sender_signalWithParams(int = 0) { called_slots << 2; } W_SLOT(on_Sender_signalWithParams,(int)) void on_Sender_signalWithParams(int, QString) { called_slots << 3; } W_SLOT(on_Sender_signalWithParams,(int, QString)) void on_Sender_signalManyParams() { called_slots << 4; } W_SLOT(on_Sender_signalManyParams,()) void on_Sender_signalManyParams(int, int, int, QString, bool) { called_slots << 5; } W_SLOT(on_Sender_signalManyParams,(int,int,int,QString,bool)) void on_Sender_signalManyParams(int, int, int, QString, bool, bool) { called_slots << 6;} W_SLOT(on_Sender_signalManyParams,(int,int,int,QString,bool,bool)) void on_Sender_signalManyParams2(int, int, int, QString, bool) { called_slots << 7; } W_SLOT(on_Sender_signalManyParams2) void slotLoopBack() { called_slots << 8; } W_SLOT(slotLoopBack) void on_Receiver_signalNoParams() { called_slots << 9; } W_SLOT(on_Receiver_signalNoParams) void on_Receiver_signal_with_underscore() { called_slots << 10; } W_SLOT(on_Receiver_signal_with_underscore) protected slots: void o() { called_slots << -1; } W_SLOT(o) void on() { called_slots << -1; } W_SLOT(on) void on_() { called_slots << -1; } W_SLOT(on_) void on_something() { called_slots << -1; } W_SLOT(on_something) void on_child_signal() { called_slots << -1; } W_SLOT(on_child_signal) signals: void on_Sender_signalLoopBack() W_SIGNAL(on_Sender_signalLoopBack) void signalNoParams() W_SIGNAL(signalNoParams) void signal_with_underscore() W_SIGNAL(signal_with_underscore) }; void tst_QObject::connectSlotsByName() { AutoConnectReceiver receiver; receiver.setObjectName("Receiver"); AutoConnectSender sender(&receiver); sender.setObjectName("Sender"); QTest::ignoreMessage(QtWarningMsg, "QMetaObject::connectSlotsByName: No matching signal for on_child_signal()"); QTest::ignoreMessage(QtWarningMsg, "QMetaObject::connectSlotsByName: Connecting slot on_Sender_signalManyParams() with the first of the following compatible signals: QList(\"signalManyParams(int,int,int,QString,bool)\", \"signalManyParams(int,int,int,QString,bool,bool)\")"); QMetaObject::connectSlotsByName(&receiver); receiver.called_slots.clear(); sender.emitSignalNoParams(); QCOMPARE(receiver.called_slots, QList() << 1); receiver.called_slots.clear(); sender.emitSignalWithParams(0); QCOMPARE(receiver.called_slots, QList() << 2); receiver.called_slots.clear(); sender.emitSignalWithParams(0, "string"); QCOMPARE(receiver.called_slots, QList() << 3); receiver.called_slots.clear(); sender.emitSignalManyParams(1, 2, 3, "string", true); sender.emitSignalManyParams(1, 2, 3, "string", true, false); // the slot '4' (signalManyParams()) will get connected // to either of the two signalManyParams(...) overloads QCOMPARE(receiver.called_slots, QList() << 4 << 5 << 6); receiver.called_slots.clear(); sender.emitSignalManyParams2(1, 2, 3, "string", true); QCOMPARE(receiver.called_slots, QList() << 7); receiver.called_slots.clear(); sender.emitSignalLoopBack(); QCOMPARE(receiver.called_slots, QList() << 8); receiver.called_slots.clear(); receiver.emitSignalNoParams(); QCOMPARE(receiver.called_slots, QList() << 9); receiver.called_slots.clear(); receiver.emit_signal_with_underscore(); QCOMPARE(receiver.called_slots, QList() << 10); } void tst_QObject::qobject_castTemplate() { QScopedPointer o; QVERIFY(!::qobject_cast(o.data())); o.reset(new SenderObject); QVERIFY(::qobject_cast(o.data())); QVERIFY(::qobject_cast(o.data())); QVERIFY(!::qobject_cast(o.data())); } void tst_QObject::findChildren() { QObject o; QObject o1(&o); QObject o2(&o); QObject o11(&o1); QObject o12(&o1); QObject o111(&o11); QObject unnamed(&o); QTimer t1(&o); QTimer t121(&o12); QTimer emptyname(&o); Q_SET_OBJECT_NAME(o); Q_SET_OBJECT_NAME(o1); Q_SET_OBJECT_NAME(o2); Q_SET_OBJECT_NAME(o11); Q_SET_OBJECT_NAME(o12); Q_SET_OBJECT_NAME(o111); Q_SET_OBJECT_NAME(t1); Q_SET_OBJECT_NAME(t121); emptyname.setObjectName(""); QObject *op = nullptr; op = o.findChild("o1"); QCOMPARE(op, &o1); op = o.findChild("o2"); QCOMPARE(op, &o2); op = o.findChild("o11"); QCOMPARE(op, &o11); op = o.findChild("o12"); QCOMPARE(op, &o12); op = o.findChild("o111"); QCOMPARE(op, &o111); op = o.findChild("t1"); QCOMPARE(op, static_cast(&t1)); op = o.findChild("t121"); QCOMPARE(op, static_cast(&t121)); op = o.findChild("t1"); QCOMPARE(op, static_cast(&t1)); op = o.findChild("t121"); QCOMPARE(op, static_cast(&t121)); op = o.findChild("o12"); QCOMPARE(op, static_cast(0)); op = o.findChild("o"); QCOMPARE(op, static_cast(0)); op = o.findChild("harry"); QCOMPARE(op, static_cast(0)); op = o.findChild("o1"); QCOMPARE(op, &o1); QList l; QList tl; l = o.findChildren("o1"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o1); l = o.findChildren("o2"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o2); l = o.findChildren("o11"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o11); l = o.findChildren("o12"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o12); l = o.findChildren("o111"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o111); l = o.findChildren("t1"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), static_cast(&t1)); l = o.findChildren("t121"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), static_cast(&t121)); tl = o.findChildren("t1"); QCOMPARE(tl.size(), 1); QCOMPARE(tl.at(0), &t1); tl = o.findChildren("t121"); QCOMPARE(tl.size(), 1); QCOMPARE(tl.at(0), &t121); l = o.findChildren("o"); QCOMPARE(l.size(), 0); l = o.findChildren("harry"); QCOMPARE(l.size(), 0); tl = o.findChildren("o12"); QCOMPARE(tl.size(), 0); l = o.findChildren("o1"); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o1); l = o.findChildren(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 = o.findChildren(QRegularExpression("t.*")); QCOMPARE(l.size(), 2); QVERIFY(l.contains(&t1)); QVERIFY(l.contains(&t121)); tl = o.findChildren(QRegularExpression("^.*$")); QCOMPARE(tl.size(), 3); QVERIFY(tl.contains(&t1)); QVERIFY(tl.contains(&t121)); tl = o.findChildren(QRegularExpression("^o.*$")); QCOMPARE(tl.size(), 0); l = o.findChildren(QRegularExpression("^harry$")); QCOMPARE(l.size(), 0); l = o.findChildren(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 = o.findChildren(QRegularExpression("t.*")); QCOMPARE(l.size(), 2); QVERIFY(l.contains(&t1)); QVERIFY(l.contains(&t121)); tl = o.findChildren(QRegularExpression(".*")); QCOMPARE(tl.size(), 3); QVERIFY(tl.contains(&t1)); QVERIFY(tl.contains(&t121)); tl = o.findChildren(QRegularExpression("o.*")); QCOMPARE(tl.size(), 0); l = o.findChildren(QRegularExpression("harry")); QCOMPARE(l.size(), 0); // empty and null string check op = o.findChild(); QCOMPARE(op, &o1); op = o.findChild(""); QCOMPARE(op, &unnamed); op = o.findChild("unnamed"); QCOMPARE(op, static_cast(0)); l = o.findChildren(); QCOMPARE(l.size(), 9); l = o.findChildren(""); QCOMPARE(l.size(), 2); l = o.findChildren("unnamed"); QCOMPARE(l.size(), 0); tl = o.findChildren("t1"); QCOMPARE(tl.size(), 1); QCOMPARE(tl.at(0), &t1); // Find direct child/children op = o.findChild("o1", Qt::FindDirectChildrenOnly); QCOMPARE(op, &o1); op = o.findChild("o2", Qt::FindDirectChildrenOnly); QCOMPARE(op, &o2); op = o.findChild("o11", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(0)); op = o.findChild("o12", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(0)); op = o.findChild("o111", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(0)); op = o.findChild("t1", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(&t1)); op = o.findChild("t121", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(0)); op = o.findChild("t1", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(&t1)); op = o.findChild("t121", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(0)); op = o.findChild("o12", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(0)); op = o.findChild("o", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(0)); op = o.findChild("harry", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(0)); op = o.findChild("o1", Qt::FindDirectChildrenOnly); QCOMPARE(op, &o1); l = o.findChildren("o1", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o1); l = o.findChildren("o2", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o2); l = o.findChildren("o11", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 0); l = o.findChildren("o12", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 0); l = o.findChildren("o111", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 0); l = o.findChildren("t1", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), static_cast(&t1)); l = o.findChildren("t121", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 0); tl = o.findChildren("t1", Qt::FindDirectChildrenOnly); QCOMPARE(tl.size(), 1); QCOMPARE(tl.at(0), &t1); tl = o.findChildren("t121", Qt::FindDirectChildrenOnly); QCOMPARE(tl.size(), 0); l = o.findChildren("o", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 0); l = o.findChildren("harry", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 0); tl = o.findChildren("o12", Qt::FindDirectChildrenOnly); QCOMPARE(tl.size(), 0); l = o.findChildren("o1", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 1); QCOMPARE(l.at(0), &o1); l = o.findChildren(QRegularExpression("^o.*$"), Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 2); QVERIFY(l.contains(&o1)); QVERIFY(l.contains(&o2)); l = o.findChildren(QRegularExpression("^t.*$"), Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 1); QVERIFY(l.contains(&t1)); tl = o.findChildren(QRegularExpression("^.*$"), Qt::FindDirectChildrenOnly); QCOMPARE(tl.size(), 2); QVERIFY(tl.contains(&t1)); tl = o.findChildren(QRegularExpression("^o.*$"), Qt::FindDirectChildrenOnly); QCOMPARE(tl.size(), 0); l = o.findChildren(QRegularExpression("^harry$"), Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 0); // empty and null string check op = o.findChild(QString(), Qt::FindDirectChildrenOnly); QCOMPARE(op, &o1); op = o.findChild("", Qt::FindDirectChildrenOnly); QCOMPARE(op, &unnamed); op = o.findChild("unnamed", Qt::FindDirectChildrenOnly); QCOMPARE(op, static_cast(0)); #if QT_VERSION >= QT_VERSION_CHECK(6,3,0) l = o.findChildren(Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 5); #endif l = o.findChildren(QString(), Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 5); l = o.findChildren("", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 2); l = o.findChildren("unnamed", Qt::FindDirectChildrenOnly); QCOMPARE(l.size(), 0); tl = o.findChildren("t1", Qt::FindDirectChildrenOnly); QCOMPARE(tl.size(), 1); QCOMPARE(tl.at(0), &t1); } class NotifyObject : public SenderObject, public ReceiverObject { public: NotifyObject() : SenderObject(), ReceiverObject() {} QList connectedSignals; QList disconnectedSignals; void clearNotifications() { connectedSignals.clear(); disconnectedSignals.clear(); } protected: void connectNotify(const QMetaMethod &signal) override { connectedSignals.append(signal); } void disconnectNotify(const QMetaMethod &signal) override { disconnectedSignals.append(signal); } }; void tst_QObject::connectDisconnectNotify_data() { QTest::addColumn("a_signal"); QTest::addColumn("a_slot"); QTest::newRow("combo1") << SIGNAL( signal1() ) << SLOT( slot1() ); QTest::newRow("combo2") << SIGNAL( signal2(void) ) << SLOT( slot2( ) ); QTest::newRow("combo3") << SIGNAL( signal3( ) ) << SLOT( slot3(void) ); QTest::newRow("combo4") << SIGNAL( signal4( void ) )<< SLOT( slot4( void ) ); QTest::newRow("combo5") << SIGNAL( signal6( void ) ) << SLOT( slot4() ); QTest::newRow("combo6") << SIGNAL( signal6() ) << SLOT( slot4() ); QTest::newRow("combo7") << SIGNAL( signal7( int , const QString & ) ) << SLOT( slot4() ); } void tst_QObject::connectDisconnectNotify() { NotifyObject s; NotifyObject r; QFETCH(QString, a_signal); QFETCH(QString, a_slot); // Obtaining meta methods int signalIndx = ((SenderObject &)s).metaObject()->indexOfSignal( QMetaObject::normalizedSignature(a_signal.toLatin1().constData()+1).constData()); int methodIndx = ((ReceiverObject &)r).metaObject()->indexOfMethod( QMetaObject::normalizedSignature(a_slot.toLatin1().constData()+1).constData()); QMetaMethod signal = ((SenderObject &)s).metaObject()->method(signalIndx); QMetaMethod method = ((ReceiverObject &)r).metaObject()->method(methodIndx); QVERIFY(signal.isValid()); QVERIFY(method.isValid()); // Test connectNotify QVERIFY(QObject::connect((SenderObject *)&s, a_signal.toLatin1(), (ReceiverObject *)&r, a_slot.toLatin1())); QCOMPARE(s.connectedSignals.size(), 1); QCOMPARE(s.connectedSignals.at(0), signal); QVERIFY(s.disconnectedSignals.isEmpty()); // Test disconnectNotify QVERIFY(QObject::disconnect((SenderObject *)&s, a_signal.toLatin1(), (ReceiverObject *)&r, a_slot.toLatin1())); QCOMPARE(s.disconnectedSignals.size(), 1); QCOMPARE(s.disconnectedSignals.at(0), signal); QCOMPARE(s.connectedSignals.size(), 1); // Reconnect s.clearNotifications(); QVERIFY(QObject::connect((SenderObject *)&s, a_signal.toLatin1(), (ReceiverObject *)&r, a_slot.toLatin1())); QCOMPARE(s.connectedSignals.size(), 1); QCOMPARE(s.connectedSignals.at(0), signal); QVERIFY(s.disconnectedSignals.isEmpty()); // Test disconnectNotify for a complete disconnect QVERIFY(((SenderObject *)&s)->disconnect((ReceiverObject *)&r)); QCOMPARE(s.disconnectedSignals.size(), 1); QCOMPARE(s.disconnectedSignals.at(0), QMetaMethod()); QCOMPARE(s.connectedSignals.size(), 1); // Test connectNotify when connecting by QMetaMethod s.clearNotifications(); QVERIFY(QObject::connect((SenderObject *)&s, signal, (ReceiverObject *)&r, method)); QCOMPARE(s.connectedSignals.size(), 1); QCOMPARE(s.connectedSignals.at(0), signal); QVERIFY(s.disconnectedSignals.isEmpty()); // Test disconnectNotify when disconnecting by QMetaMethod QVERIFY(QObject::disconnect((SenderObject *)&s, signal, (ReceiverObject *)&r, method)); QCOMPARE(s.disconnectedSignals.size(), 1); QCOMPARE(s.disconnectedSignals.at(0), signal); QCOMPARE(s.connectedSignals.size(), 1); // Reconnect s.clearNotifications(); QVERIFY(QObject::connect((SenderObject *)&s, a_signal.toLatin1(), (ReceiverObject *)&r, a_slot.toLatin1())); // Test disconnectNotify for a complete disconnect by QMetaMethod QVERIFY(QObject::disconnect((SenderObject *)&s, QMetaMethod(), 0, QMetaMethod())); QCOMPARE(s.disconnectedSignals.size(), 1); QCOMPARE(s.disconnectedSignals.at(0), QMetaMethod()); QCOMPARE(s.connectedSignals.size(), 1); // Test connectNotify when connecting by index s.clearNotifications(); QVERIFY(QMetaObject::connect((SenderObject *)&s, signalIndx, (ReceiverObject *)&r, methodIndx)); QCOMPARE(s.connectedSignals.size(), 1); QCOMPARE(s.connectedSignals.at(0), signal); QVERIFY(s.disconnectedSignals.isEmpty()); // Test disconnectNotify when disconnecting by index QVERIFY(QMetaObject::disconnect((SenderObject *)&s, signalIndx, (ReceiverObject *)&r, methodIndx)); QCOMPARE(s.disconnectedSignals.size(), 1); QCOMPARE(s.disconnectedSignals.at(0), signal); QCOMPARE(s.connectedSignals.size(), 1); } struct Incomplete; W_REGISTER_ARGTYPE(Incomplete) class QObjectWithIncomplete : public QObject { W_OBJECT(QObjectWithIncomplete) public: QObjectWithIncomplete(QObject *parent=nullptr) : QObject(parent) {} signals: void signalWithIncomplete(const Incomplete & x) W_SIGNAL(signalWithIncomplete, (const Incomplete &), x) public slots: void slotWithIncomplete(const Incomplete &) {} W_SLOT(slotWithIncomplete,(const Incomplete &)) }; void tst_QObject::connectReferenceToIncompleteTypes() { QObjectWithIncomplete withIncomplete; auto connection = QObject::connect(&withIncomplete, &QObjectWithIncomplete::signalWithIncomplete, &withIncomplete, &QObjectWithIncomplete::slotWithIncomplete); QVERIFY(connection); } static void connectDisconnectNotifyTestSlot() {} void tst_QObject::connectDisconnectNotifyPMF() { NotifyObject s; NotifyObject r; QMetaMethod signal = QMetaMethod::fromSignal(&SenderObject::signal1); // Test connectNotify QVERIFY(QObject::connect((SenderObject *)&s, &SenderObject::signal1, (ReceiverObject *)&r, &ReceiverObject::slot1)); QCOMPARE(s.connectedSignals.size(), 1); QCOMPARE(s.connectedSignals.at(0), signal); QVERIFY(s.disconnectedSignals.isEmpty()); // Test disconnectNotify QVERIFY(QObject::disconnect((SenderObject *)&s, &SenderObject::signal1, (ReceiverObject *)&r, &ReceiverObject::slot1)); QCOMPARE(s.disconnectedSignals.size(), 1); QCOMPARE(s.disconnectedSignals.at(0), signal); QCOMPARE(s.connectedSignals.size(), 1); // Reconnect s.clearNotifications(); QVERIFY(QObject::connect((SenderObject *)&s, &SenderObject::signal1, (ReceiverObject *)&r, &ReceiverObject::slot1)); QCOMPARE(s.connectedSignals.size(), 1); QCOMPARE(s.connectedSignals.at(0), signal); QVERIFY(s.disconnectedSignals.isEmpty()); // Test disconnectNotify with wildcard slot QVERIFY(QObject::disconnect((SenderObject *)&s, &SenderObject::signal1, (ReceiverObject *)&r, 0)); QCOMPARE(s.disconnectedSignals.size(), 1); QCOMPARE(s.disconnectedSignals.at(0), signal); QCOMPARE(s.connectedSignals.size(), 1); // Reconnect s.clearNotifications(); QMetaObject::Connection conn = connect((SenderObject *)&s, &SenderObject::signal1, (ReceiverObject *)&r, &ReceiverObject::slot1); QVERIFY(conn); // Test disconnectNotify when disconnecting by QMetaObject::Connection QVERIFY(QObject::disconnect(conn)); QVERIFY(!s.disconnectedSignals.isEmpty()); // Test connectNotify when connecting by function pointer s.clearNotifications(); QVERIFY(QObject::connect((SenderObject *)&s, &SenderObject::signal1, connectDisconnectNotifyTestSlot)); QCOMPARE(s.connectedSignals.size(), 1); QCOMPARE(s.connectedSignals.at(0), signal); QVERIFY(s.disconnectedSignals.isEmpty()); } void tst_QObject::disconnectNotify_receiverDestroyed() { NotifyObject s; { NotifyObject r; QVERIFY(QObject::connect((SenderObject *)&s, SIGNAL(signal1()), (ReceiverObject *)&r, SLOT(slot1()))); } QCOMPARE(s.disconnectedSignals.count(), 1); QCOMPARE(s.disconnectedSignals.at(0), QMetaMethod::fromSignal(&SenderObject::signal1)); s.disconnectedSignals.clear(); { NotifyObject r; QVERIFY(QObject::connect((SenderObject *)&s, SIGNAL(signal3()), (ReceiverObject *)&r, SLOT(slot3()))); } QCOMPARE(s.disconnectedSignals.count(), 1); QCOMPARE(s.disconnectedSignals.at(0), QMetaMethod::fromSignal(&SenderObject::signal3)); s.disconnectedSignals.clear(); { NotifyObject r; QVERIFY(QObject::connect((SenderObject *)&s, SIGNAL(destroyed()), (ReceiverObject *)&r, SLOT(slot3()))); } QCOMPARE(s.disconnectedSignals.count(), 1); QCOMPARE(s.disconnectedSignals.at(0), QMetaMethod::fromSignal(&QObject::destroyed)); } void tst_QObject::disconnectNotify_metaObjConnection() { NotifyObject s; { NotifyObject r; QMetaObject::Connection c = QObject::connect((SenderObject *)&s, SIGNAL(signal1()), (ReceiverObject *)&r, SLOT(slot1())); QVERIFY(c); QVERIFY(QObject::disconnect(c)); QCOMPARE(s.disconnectedSignals.count(), 1); QCOMPARE(s.disconnectedSignals.at(0), QMetaMethod::fromSignal(&SenderObject::signal1)); QCOMPARE(s.disconnectedSignals.count(), 1); } } class ConnectByNameNotifySenderObject : public QObject { W_OBJECT(ConnectByNameNotifySenderObject) public: QList connectedSignals; QList disconnectedSignals; void clearNotifications() { connectedSignals.clear(); disconnectedSignals.clear(); } protected: void connectNotify(const QMetaMethod &signal) override { connectedSignals.append(signal); } void disconnectNotify(const QMetaMethod &signal) override { disconnectedSignals.append(signal); } Q_SIGNALS: void signal1() W_SIGNAL(signal1) }; class ConnectByNameNotifyReceiverObject : public QObject { W_OBJECT(ConnectByNameNotifyReceiverObject) void createNotifyChild(const char *name) { QObject *o = new ConnectByNameNotifySenderObject; o->setParent(this); o->setObjectName(QString::fromLatin1(name)); } public: ConnectByNameNotifyReceiverObject() { createNotifyChild("foo"); createNotifyChild("bar"); createNotifyChild("baz"); }; public Q_SLOTS: void on_foo_signal1() {} W_SLOT(on_foo_signal1) void on_bar_signal1() {} W_SLOT(on_bar_signal1) void on_baz_signal1() {} W_SLOT(on_baz_signal1) }; void tst_QObject::connectNotify_connectSlotsByName() { ConnectByNameNotifyReceiverObject testObject; const QList senders = testObject.findChildren(); for (ConnectByNameNotifySenderObject *o : senders) { QVERIFY(o->connectedSignals.isEmpty()); QVERIFY(o->disconnectedSignals.isEmpty()); } QMetaObject::connectSlotsByName(&testObject); for (ConnectByNameNotifySenderObject *o : senders) { QCOMPARE(o->connectedSignals.size(), 1); QCOMPARE(o->connectedSignals.at(0), QMetaMethod::fromSignal(&ConnectByNameNotifySenderObject::signal1)); QVERIFY(o->disconnectedSignals.isEmpty()); } } class ConnectDisconnectNotifyShadowObject : public ConnectByNameNotifySenderObject { W_OBJECT(ConnectDisconnectNotifyShadowObject) public Q_SLOTS: void slot1() {} W_SLOT(slot1) Q_SIGNALS: void signal1() W_SIGNAL(signal1) }; void tst_QObject::connectDisconnectNotify_shadowing() { ConnectDisconnectNotifyShadowObject s; // Obtain QMetaMethods QMetaMethod shadowedSignal1 = QMetaMethod::fromSignal(&ConnectByNameNotifySenderObject::signal1); QMetaMethod redefinedSignal1 = QMetaMethod::fromSignal(&ConnectDisconnectNotifyShadowObject::signal1); QVERIFY(shadowedSignal1 != redefinedSignal1); int slot1Index = s.metaObject()->indexOfSlot("slot1()"); QVERIFY(slot1Index != -1); QMetaMethod slot1 = s.metaObject()->method(slot1Index); // Test connectNotify #ifndef QT_NO_DEBUG const char *warning = "QMetaObject::indexOfSignal: signal signal1() from " "ConnectByNameNotifySenderObject redefined in " "ConnectDisconnectNotifyShadowObject"; QTest::ignoreMessage(QtWarningMsg, warning); #endif QVERIFY(QObject::connect(&s, SIGNAL(signal1()), &s, SLOT(slot1()))); QCOMPARE(s.connectedSignals.size(), 1); QCOMPARE(s.connectedSignals.at(0), redefinedSignal1); QVERIFY(s.disconnectedSignals.isEmpty()); // Test disconnectNotify #ifndef QT_NO_DEBUG QTest::ignoreMessage(QtWarningMsg, warning); #endif QVERIFY(QObject::disconnect(&s, SIGNAL(signal1()), &s, SLOT(slot1()))); QCOMPARE(s.disconnectedSignals.size(), 1); QCOMPARE(s.disconnectedSignals.at(0), redefinedSignal1); QCOMPARE(s.connectedSignals.size(), 1); // Test connectNotify when connecting by shadowed QMetaMethod s.clearNotifications(); QVERIFY(QObject::connect(&s, shadowedSignal1, &s, slot1)); QCOMPARE(s.connectedSignals.size(), 1); QCOMPARE(s.connectedSignals.at(0), shadowedSignal1); QVERIFY(s.disconnectedSignals.isEmpty()); // Test disconnectNotify when disconnecting by shadowed QMetaMethod QVERIFY(QObject::disconnect(&s, shadowedSignal1, &s, slot1)); QCOMPARE(s.disconnectedSignals.size(), 1); QCOMPARE(s.disconnectedSignals.at(0), shadowedSignal1); QCOMPARE(s.connectedSignals.size(), 1); // Test connectNotify when connecting by redefined QMetaMethod s.clearNotifications(); QVERIFY(QObject::connect(&s, redefinedSignal1, &s, slot1)); QCOMPARE(s.connectedSignals.size(), 1); QCOMPARE(s.connectedSignals.at(0), redefinedSignal1); QVERIFY(s.disconnectedSignals.isEmpty()); // Test disconnectNotify when disconnecting by redefined QMetaMethod QVERIFY(QObject::disconnect(&s, redefinedSignal1, &s, slot1)); QCOMPARE(s.disconnectedSignals.size(), 1); QCOMPARE(s.disconnectedSignals.at(0), redefinedSignal1); QCOMPARE(s.connectedSignals.size(), 1); } class SequenceObject : public ReceiverObject { W_OBJECT(SequenceObject) public: QObject *next; SequenceObject() : next(0) { } public slots: void slot1_disconnectThis() { slot1(); disconnect(sender(), SIGNAL(signal1()), this, SLOT(slot1_disconnectThis())); } W_SLOT(slot1_disconnectThis) void slot2_reconnectThis() { slot2(); const QObject *s = sender(); disconnect(s, SIGNAL(signal1()), this, SLOT(slot2_reconnectThis())); connect(s, SIGNAL(signal1()), this, SLOT(slot2_reconnectThis())); } W_SLOT(slot2_reconnectThis) void slot1_disconnectNext() { slot1(); disconnect(sender(), SIGNAL(signal1()), next, SLOT(slot1())); } W_SLOT(slot1_disconnectNext) void slot2_reconnectNext() { slot2(); // modify the connection list in 'this' disconnect(sender(), SIGNAL(signal1()), next, SLOT(slot2())); connect(sender(), SIGNAL(signal1()), next, SLOT(slot2())); // modify the sender list in 'this' connect(next, SIGNAL(destroyed()), this, SLOT(deleteLater())); connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(deleteLater())); disconnect(next, SIGNAL(destroyed()), this, SLOT(deleteLater())); disconnect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(deleteLater())); } W_SLOT(slot2_reconnectNext) void slot1_deleteNext() { slot1(); delete next; } W_SLOT(slot1_deleteNext) void slot2_deleteSender() { slot2(); delete sender(); } W_SLOT(slot2_deleteSender) }; void tst_QObject::emitInDefinedOrder() { SenderObject sender; ReceiverObject receiver1, receiver2, receiver3, receiver4; connect(&sender, SIGNAL(signal1()), &receiver1, SLOT(slot1())); connect(&sender, SIGNAL(signal1()), &receiver2, SLOT(slot1())); connect(&sender, SIGNAL(signal1()), &receiver3, SLOT(slot1())); connect(&sender, SIGNAL(signal1()), &receiver4, SLOT(slot1())); connect(&sender, SIGNAL(signal1()), &receiver1, SLOT(slot2())); connect(&sender, SIGNAL(signal1()), &receiver2, SLOT(slot2())); connect(&sender, SIGNAL(signal1()), &receiver3, SLOT(slot2())); connect(&sender, SIGNAL(signal1()), &receiver4, SLOT(slot2())); int sequence; ReceiverObject::sequence = sequence = 0; sender.emitSignal1(); QCOMPARE(receiver1.sequence_slot1, ++sequence); QCOMPARE(receiver2.sequence_slot1, ++sequence); QCOMPARE(receiver3.sequence_slot1, ++sequence); QCOMPARE(receiver4.sequence_slot1, ++sequence); QCOMPARE(receiver1.sequence_slot2, ++sequence); QCOMPARE(receiver2.sequence_slot2, ++sequence); QCOMPARE(receiver3.sequence_slot2, ++sequence); QCOMPARE(receiver4.sequence_slot2, ++sequence); QObject::disconnect(&sender, SIGNAL(signal1()), &receiver2, SLOT(slot1())); connect(&sender, SIGNAL(signal1()), &receiver2, SLOT(slot1())); ReceiverObject::sequence = sequence = 0; sender.emitSignal1(); QCOMPARE(receiver1.sequence_slot1, ++sequence); QCOMPARE(receiver3.sequence_slot1, ++sequence); QCOMPARE(receiver4.sequence_slot1, ++sequence); QCOMPARE(receiver1.sequence_slot2, ++sequence); QCOMPARE(receiver2.sequence_slot2, ++sequence); QCOMPARE(receiver3.sequence_slot2, ++sequence); QCOMPARE(receiver4.sequence_slot2, ++sequence); QCOMPARE(receiver2.sequence_slot1, ++sequence); QObject::disconnect(&sender, SIGNAL(signal1()), &receiver1, SLOT(slot1())); connect(&sender, SIGNAL(signal1()), &receiver1, SLOT(slot1())); ReceiverObject::sequence = sequence = 0; sender.emitSignal1(); QCOMPARE(receiver3.sequence_slot1, ++sequence); QCOMPARE(receiver4.sequence_slot1, ++sequence); QCOMPARE(receiver1.sequence_slot2, ++sequence); QCOMPARE(receiver2.sequence_slot2, ++sequence); QCOMPARE(receiver3.sequence_slot2, ++sequence); QCOMPARE(receiver4.sequence_slot2, ++sequence); QCOMPARE(receiver2.sequence_slot1, ++sequence); QCOMPARE(receiver1.sequence_slot1, ++sequence); // ensure emission order even if the connections change during emission SenderObject *sender2 = new SenderObject; SequenceObject seq1, seq2, *seq3 = new SequenceObject, seq4; seq1.next = &seq2; seq2.next = seq3; seq3->next = &seq4; // try 1 connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot1_disconnectThis())); connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot1_disconnectNext())); connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot1())); connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot1())); connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot2_reconnectThis())); connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot2_reconnectNext())); connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot2())); connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot2())); SequenceObject::sequence = sequence = 0; sender2->emitSignal1(); QVERIFY(seq1.called(1)); QVERIFY(seq2.called(1)); QVERIFY(!seq3->called(1)); QVERIFY(seq4.called(1)); QVERIFY(seq1.called(2)); QVERIFY(seq2.called(2)); QVERIFY(!seq3->called(2)); QVERIFY(seq4.called(2)); QCOMPARE(seq1.sequence_slot1, ++sequence); QCOMPARE(seq2.sequence_slot1, ++sequence); QCOMPARE(seq4.sequence_slot1, ++sequence); QCOMPARE(seq1.sequence_slot2, ++sequence); QCOMPARE(seq2.sequence_slot2, ++sequence); QCOMPARE(seq4.sequence_slot2, ++sequence); QObject::disconnect(sender2, 0, &seq1, 0); QObject::disconnect(sender2, 0, &seq2, 0); QObject::disconnect(sender2, 0, seq3, 0); QObject::disconnect(sender2, 0, &seq4, 0); seq1.reset(); seq2.reset(); seq3->reset(); seq4.reset(); // try 2 connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot2_reconnectThis())); connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot2_reconnectNext())); connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot2())); connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot2())); connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot1_disconnectThis())); connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot1_disconnectNext())); connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot1())); connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot1())); SequenceObject::sequence = sequence = 0; sender2->emitSignal1(); QVERIFY(seq1.called(2)); QVERIFY(seq2.called(2)); QVERIFY(!seq3->called(2)); QVERIFY(seq4.called(2)); QVERIFY(seq1.called(1)); QVERIFY(seq2.called(1)); QVERIFY(!seq3->called(1)); QVERIFY(seq4.called(1)); QCOMPARE(seq1.sequence_slot2, ++sequence); QCOMPARE(seq2.sequence_slot2, ++sequence); QCOMPARE(seq4.sequence_slot2, ++sequence); QCOMPARE(seq1.sequence_slot1, ++sequence); QCOMPARE(seq2.sequence_slot1, ++sequence); QCOMPARE(seq4.sequence_slot1, ++sequence); QObject::disconnect(sender2, 0, &seq1, 0); QObject::disconnect(sender2, 0, &seq2, 0); QObject::disconnect(sender2, 0, seq3, 0); QObject::disconnect(sender2, 0, &seq4, 0); seq1.reset(); seq2.reset(); seq3->reset(); seq4.reset(); // try 3 connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot1())); connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot1_disconnectNext())); connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot1())); connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot1())); connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot2())); connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot2_reconnectNext())); connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot2())); connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot2())); SequenceObject::sequence = sequence = 0; sender2->emitSignal1(); QVERIFY(seq1.called(1)); QVERIFY(seq2.called(1)); QVERIFY(!seq3->called(1)); QVERIFY(seq4.called(1)); QVERIFY(seq1.called(2)); QVERIFY(seq2.called(2)); QVERIFY(!seq3->called(2)); QVERIFY(seq4.called(2)); QCOMPARE(seq1.sequence_slot1, ++sequence); QCOMPARE(seq2.sequence_slot1, ++sequence); QCOMPARE(seq4.sequence_slot1, ++sequence); QCOMPARE(seq1.sequence_slot2, ++sequence); QCOMPARE(seq2.sequence_slot2, ++sequence); QCOMPARE(seq4.sequence_slot2, ++sequence); // ensure emission order even if objects are destroyed during emission QObject::disconnect(sender2, 0, &seq1, 0); QObject::disconnect(sender2, 0, &seq2, 0); QObject::disconnect(sender2, 0, seq3, 0); QObject::disconnect(sender2, 0, &seq4, 0); seq1.reset(); seq2.reset(); seq3->reset(); seq4.reset(); connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot1())); connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot1_deleteNext())); connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot1())); connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot1())); connect(sender2, SIGNAL(signal1()), &seq1, SLOT(slot2())); connect(sender2, SIGNAL(signal1()), &seq2, SLOT(slot2_deleteSender())); connect(sender2, SIGNAL(signal1()), seq3, SLOT(slot2())); connect(sender2, SIGNAL(signal1()), &seq4, SLOT(slot2())); QPointer psender = sender2; QPointer pseq3 = seq3; SequenceObject::sequence = sequence = 0; sender2->emitSignal1(); QCOMPARE(static_cast(psender), static_cast(0)); QCOMPARE(static_cast(pseq3), static_cast(0)); QVERIFY(seq1.called(1)); QVERIFY(seq2.called(1)); QVERIFY(seq4.called(1)); QVERIFY(seq1.called(2)); QVERIFY(seq2.called(2)); QVERIFY(!seq4.called(2)); QCOMPARE(seq1.sequence_slot1, ++sequence); QCOMPARE(seq2.sequence_slot1, ++sequence); QCOMPARE(seq4.sequence_slot1, ++sequence); QCOMPARE(seq1.sequence_slot2, ++sequence); QCOMPARE(seq2.sequence_slot2, ++sequence); QPointer psender3 = new SenderObject; connect(psender3, SIGNAL(signal1()), psender3, SIGNAL(signal2())); connect(psender3, SIGNAL(signal2()), &seq1, SLOT(slot2_deleteSender())); psender3->emitSignal1(); QVERIFY(!psender3); } static int instanceCount = 0; struct CheckInstanceCount { const int saved; CheckInstanceCount() : saved(instanceCount) {} ~CheckInstanceCount() { QCOMPARE(saved, instanceCount); } }; struct CustomType { CustomType(int l1 = 0, int l2 = 0, int l3 = 0): i1(l1), i2(l2), i3(l3) { ++instanceCount; playWithObjects(); } 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; } }; QDataStream &operator<<(QDataStream &stream, const CustomType &ct) { stream << ct.i1 << ct.i2 << ct.i3; return stream; } QDataStream &operator>>(QDataStream &stream, CustomType &ct) { stream >> ct.i1; stream >> ct.i2; stream >> ct.i3; return stream; } Q_DECLARE_METATYPE(CustomType*) W_REGISTER_ARGTYPE(CustomType*) Q_DECLARE_METATYPE(CustomType) W_REGISTER_ARGTYPE(CustomType) W_REGISTER_ARGTYPE(QList) class QCustomTypeChecker: public QObject { W_OBJECT(QCustomTypeChecker) public: QCustomTypeChecker(QObject *parent = nullptr): QObject(parent) {} void doEmit(CustomType ct) { emit signal1(ct); } public slots: void slot1(CustomType ct); W_SLOT(slot1) void slot2(const QList &ct); W_SLOT(slot2) signals: void signal1(CustomType ct) W_SIGNAL(signal1,ct) void signal2(const QList &ct) W_SIGNAL(signal2,ct) public: CustomType received; }; void QCustomTypeChecker::slot1(CustomType ct) { received = ct; } void QCustomTypeChecker::slot2(const QList< CustomType >& ct) { received = ct[0]; } void tst_QObject::customTypes() { CustomType t0; CustomType t1(1, 2, 3); CustomType t2(2, 3, 4); { QCustomTypeChecker checker; QCOMPARE(instanceCount, 4); connect(&checker, SIGNAL(signal1(CustomType)), &checker, SLOT(slot1(CustomType)), Qt::DirectConnection); QCOMPARE(checker.received.value(), 0); checker.doEmit(t1); QCOMPARE(checker.received.value(), t1.value()); checker.received = t0; int idx = qRegisterMetaType("CustomType"); QCOMPARE(QMetaType::type("CustomType"), idx); checker.disconnect(); connect(&checker, SIGNAL(signal1(CustomType)), &checker, SLOT(slot1(CustomType)), Qt::QueuedConnection); QCOMPARE(instanceCount, 4); checker.doEmit(t2); QCOMPARE(instanceCount, 5); QCOMPARE(checker.received.value(), t0.value()); QCoreApplication::processEvents(); QCOMPARE(checker.received.value(), t2.value()); QCOMPARE(instanceCount, 4); QVERIFY(QMetaType::isRegistered(idx)); QCOMPARE(qRegisterMetaType("CustomType"), idx); QCOMPARE(QMetaType::type("CustomType"), idx); QVERIFY(QMetaType::isRegistered(idx)); } QCOMPARE(instanceCount, 3); } void tst_QObject::streamCustomTypes() { QByteArray ba; int idx = qRegisterMetaType("CustomType"); { CustomType t1(1, 2, 3); QCOMPARE(instanceCount, 1); QDataStream stream(&ba, (QIODevice::OpenMode)QIODevice::WriteOnly); QMetaType::save(stream, idx, &t1); } QCOMPARE(instanceCount, 0); { CustomType t2; QCOMPARE(instanceCount, 1); QDataStream stream(&ba, (QIODevice::OpenMode)QIODevice::ReadOnly); QMetaType::load(stream, idx, &t2); QCOMPARE(instanceCount, 1); QCOMPARE(t2.i1, 1); QCOMPARE(t2.i2, 2); QCOMPARE(t2.i3, 3); } QCOMPARE(instanceCount, 0); } typedef QString CustomString; class PropertyObject : public QObject { W_OBJECT(PropertyObject) public: enum Alpha { Alpha0, Alpha1, Alpha2 }; enum Priority { High, Low, VeryHigh, VeryLow }; PropertyObject() : m_alpha(Alpha0), m_priority(High), m_number(0), m_custom(0), m_float(42) {} Alpha alpha() const { return m_alpha; } void setAlpha(Alpha alpha) { m_alpha = alpha; } Priority priority() const { return m_priority; } void setPriority(Priority priority) { m_priority = priority; } int number() const { return m_number; } void setNumber(int number) { m_number = number; } QString string() const { return m_string; } void setString(const QString &string) { m_string = string; } QVariant variant() const { return m_variant; } void setVariant(const QVariant &variant) { m_variant = variant; } CustomType *custom() const { return m_custom; } void setCustom(CustomType *custom) { m_custom = custom; } void setMyFloat(float value) { m_float = value; } inline float myFloat() const { return m_float; } void setMyQReal(qreal value) { m_qreal = value; } qreal myQReal() const { return m_qreal; } CustomString customString() const { return m_customString; } void setCustomString(const QString &string) { m_customString = string; } private: Alpha m_alpha; Priority m_priority; int m_number; QString m_string; QVariant m_variant; CustomType *m_custom; float m_float; qreal m_qreal; CustomString m_customString; W_ENUM(Alpha, Alpha0, Alpha1, Alpha2) W_ENUM(Priority, High, Low, VeryHigh, VeryLow) W_PROPERTY(Alpha, alpha READ alpha WRITE setAlpha) W_PROPERTY(Priority, priority READ priority WRITE setPriority) W_PROPERTY(int, number READ number WRITE setNumber) W_PROPERTY(QString, string READ string WRITE setString) W_PROPERTY(QVariant, variant READ variant WRITE setVariant) W_PROPERTY(CustomType*, custom READ custom WRITE setCustom) W_PROPERTY(float, myFloat READ myFloat WRITE setMyFloat) W_PROPERTY(qreal, myQReal READ myQReal WRITE setMyQReal) W_PROPERTY(CustomString, customString READ customString WRITE setCustomString ) }; Q_DECLARE_METATYPE(PropertyObject::Priority) void tst_QObject::threadSignalEmissionCrash() { int loopCount = 1000; for (int i = 0; i < loopCount; ++i) { QTcpSocket socket; socket.connectToHost("localhost", 80); } } class TestThread : public QThread { W_OBJECT(TestThread) public: inline void run() override { *object = new QObject; *child = new QObject(*object); mutex.lock(); cond.wakeOne(); cond.wait(&mutex); mutex.unlock(); } QObject **object, **child; QMutex mutex; QWaitCondition cond; }; void tst_QObject::thread() { QThread *currentThread = QThread::currentThread(); // the current thread is the same as the QApplication // thread... see tst_QApplication::thread() { QObject object; // thread affinity for objects with no parent should be the // current thread QVERIFY(object.thread() != nullptr); QCOMPARE(object.thread(), currentThread); // children inherit their parent's thread QObject child(&object); QCOMPARE(child.thread(), object.thread()); } QObject *object = nullptr; QObject *child = nullptr; { TestThread thr; QVERIFY(thr.thread() != nullptr); QCOMPARE(thr.thread(), currentThread); thr.object = &object; thr.child = &child; thr.mutex.lock(); thr.start(); thr.cond.wait(&thr.mutex); // thread affinity for an object with no parent should be the // thread in which the object was created QCOMPARE(object->thread(), (QThread *)&thr); // children inherit their parent's thread QCOMPARE(child->thread(), object->thread()); thr.cond.wakeOne(); thr.mutex.unlock(); thr.wait(); // even though the thread is no longer running, the affinity // should not change QCOMPARE(object->thread(), (QThread *)&thr); QCOMPARE(child->thread(), object->thread()); } // the thread has been destroyed, thread affinity should // automatically reset to no thread QCOMPARE(object->thread(), (QThread *)0); QCOMPARE(child->thread(), object->thread()); delete object; } class MoveToThreadObject : public QObject { W_OBJECT(MoveToThreadObject) public: QThread *timerEventThread = nullptr; QThread *customEventThread = nullptr; QThread *slotThread = nullptr; MoveToThreadObject(QObject *parent = nullptr) : QObject(parent) { } void customEvent(QEvent *) override { if (customEventThread) qFatal("%s: customEventThread should be null", Q_FUNC_INFO); customEventThread = QThread::currentThread(); emit theSignal(); } void timerEvent(QTimerEvent *) override { if (timerEventThread) qFatal("%s: timerEventThread should be null", Q_FUNC_INFO); timerEventThread = QThread::currentThread(); emit theSignal(); } public slots: void theSlot() { if (slotThread) qFatal("%s: slotThread should be null", Q_FUNC_INFO); slotThread = QThread::currentThread(); emit theSignal(); } W_SLOT(theSlot) signals: void theSignal() W_SIGNAL(theSignal) }; class MoveToThreadThread : public QThread { public: ~MoveToThreadThread() { if (isRunning()) { terminate(); wait(); } } void start() { QEventLoop eventLoop; connect(this, SIGNAL(started()), &eventLoop, SLOT(quit()), Qt::QueuedConnection); QThread::start(); // wait for thread to start (void) eventLoop.exec(); } void run() override { (void) exec(); } }; void tst_QObject::thread0() { QObject *object = new QObject; object->moveToThread(0); QObject *child = new QObject(object); QCOMPARE(child->parent(), object); QCOMPARE(child->thread(), (QThread *)0); #if 0 // We don't support moving children into a parent that has no thread // affinity (yet?). QObject *child2 = new QObject; child2->moveToThread(0); child2->setParent(object); QCOMPARE(child2->parent(), object); QCOMPARE(child2->thread(), (QThread *)0); #endif delete object; } void tst_QObject::moveToThread() { QThread *currentThread = QThread::currentThread(); { QObject *object = new QObject; QObject *child = new QObject(object); QCOMPARE(object->thread(), currentThread); QCOMPARE(child->thread(), currentThread); object->moveToThread(0); QCOMPARE(object->thread(), (QThread *)0); QCOMPARE(child->thread(), (QThread *)0); object->moveToThread(currentThread); QCOMPARE(object->thread(), currentThread); QCOMPARE(child->thread(), currentThread); object->moveToThread(0); QCOMPARE(object->thread(), (QThread *)0); QCOMPARE(child->thread(), (QThread *)0); // can delete an object with no thread anywhere delete object; } { MoveToThreadThread thread; thread.start(); QObject *object = new QObject; QObject *child = new QObject(object); QPointer opointer = object; QPointer cpointer = object; QCOMPARE(object->thread(), currentThread); QCOMPARE(child->thread(), currentThread); object->moveToThread(&thread); QCOMPARE(object->thread(), (QThread *)&thread); QCOMPARE(child->thread(), (QThread *)&thread); connect(object, SIGNAL(destroyed()), &thread, SLOT(quit()), Qt::DirectConnection); QMetaObject::invokeMethod(object, "deleteLater", Qt::QueuedConnection); thread.wait(); QVERIFY(opointer == nullptr); QVERIFY(cpointer == nullptr); } { // make sure posted events are moved with the object MoveToThreadThread thread; thread.start(); MoveToThreadObject *object = new MoveToThreadObject; MoveToThreadObject *child = new MoveToThreadObject(object); connect(object, SIGNAL(theSignal()), &thread, SLOT(quit()), Qt::DirectConnection); QCoreApplication::postEvent(child, new QEvent(QEvent::User)); QCoreApplication::postEvent(object, new QEvent(QEvent::User)); QCOMPARE(object->thread(), currentThread); QCOMPARE(child->thread(), currentThread); object->moveToThread(&thread); QCOMPARE(object->thread(), (QThread *)&thread); QCOMPARE(child->thread(), (QThread *)&thread); thread.wait(); QCOMPARE(object->customEventThread, (QThread *)&thread); QCOMPARE(child->customEventThread, (QThread *)&thread); thread.start(); connect(object, SIGNAL(destroyed()), &thread, SLOT(quit()), Qt::DirectConnection); QMetaObject::invokeMethod(object, "deleteLater", Qt::QueuedConnection); thread.wait(); } { // make sure timers are moved with the object MoveToThreadThread thread; thread.start(); MoveToThreadObject *object = new MoveToThreadObject; MoveToThreadObject *child = new MoveToThreadObject(object); connect(object, SIGNAL(theSignal()), &thread, SLOT(quit()), Qt::DirectConnection); child->startTimer(90); object->startTimer(100); QCOMPARE(object->thread(), currentThread); QCOMPARE(child->thread(), currentThread); object->moveToThread(&thread); QCOMPARE(object->thread(), (QThread *)&thread); QCOMPARE(child->thread(), (QThread *)&thread); thread.wait(); QCOMPARE(object->timerEventThread, (QThread *)&thread); QCOMPARE(child->timerEventThread, (QThread *)&thread); thread.start(); connect(object, SIGNAL(destroyed()), &thread, SLOT(quit()), Qt::DirectConnection); QMetaObject::invokeMethod(object, "deleteLater", Qt::QueuedConnection); thread.wait(); } { // make sure socket notifiers are moved with the object MoveToThreadThread thread; thread.start(); QTcpServer server; QVERIFY(server.listen(QHostAddress::LocalHost, 0)); QTcpSocket *socket = new QTcpSocket; MoveToThreadObject *child = new MoveToThreadObject(socket); connect(socket, SIGNAL(disconnected()), child, SLOT(theSlot()), Qt::DirectConnection); connect(child, SIGNAL(theSignal()), &thread, SLOT(quit()), Qt::DirectConnection); socket->connectToHost(server.serverAddress(), server.serverPort()); QVERIFY(server.waitForNewConnection(1000)); QTcpSocket *serverSocket = server.nextPendingConnection(); QVERIFY(serverSocket); socket->waitForConnected(); QCOMPARE(socket->thread(), currentThread); socket->moveToThread(&thread); QCOMPARE(socket->thread(), (QThread *)&thread); serverSocket->close(); QVERIFY(thread.wait(10000)); QCOMPARE(child->slotThread, (QThread *)&thread); thread.start(); connect(socket, SIGNAL(destroyed()), &thread, SLOT(quit()), Qt::DirectConnection); QMetaObject::invokeMethod(socket, "deleteLater", Qt::QueuedConnection); thread.wait(); } } void tst_QObject::property() { PropertyObject object; const QMetaObject *mo = object.metaObject(); QMetaProperty property; QVERIFY(mo); QVERIFY(mo->indexOfProperty("alpha") != -1); property = mo->property(mo->indexOfProperty("alpha")); QVERIFY(property.isEnumType()); #if QT_VERSION < QT_VERSION_CHECK(6, 1, 0) QCOMPARE(property.typeName(), "Alpha"); #else QCOMPARE(property.typeName(), "PropertyObject::Alpha"); #endif QCOMPARE(property.userType(), QMetaType::fromType().id()); QVariant var = object.property("alpha"); QVERIFY(!var.isNull()); QCOMPARE(var.toInt(), int(PropertyObject::Alpha0)); object.setAlpha(PropertyObject::Alpha1); QCOMPARE(object.property("alpha").toInt(), int(PropertyObject::Alpha1)); QVERIFY(object.setProperty("alpha", PropertyObject::Alpha2)); QCOMPARE(object.property("alpha").toInt(), int(PropertyObject::Alpha2)); QVERIFY(object.setProperty("alpha", "Alpha1")); QCOMPARE(object.property("alpha").toInt(), int(PropertyObject::Alpha1)); QVERIFY(object.setProperty("alpha", QVariant())); QCOMPARE(object.property("alpha").toInt(), 0); QVERIFY(mo->indexOfProperty("number") != -1); QCOMPARE(object.property("number").toInt(), 0); object.setNumber(24); QCOMPARE(object.property("number"), QVariant(24)); QVERIFY(object.setProperty("number", 12)); QCOMPARE(object.property("number"), QVariant(12)); QVERIFY(object.setProperty("number", "42")); QCOMPARE(object.property("number"), QVariant(42)); QVERIFY(mo->indexOfProperty("string") != -1); QCOMPARE(object.property("string").toString(), QString()); object.setString("String1"); QCOMPARE(object.property("string"), QVariant("String1")); QVERIFY(object.setProperty("string", "String2")); QCOMPARE(object.property("string"), QVariant("String2")); QVERIFY(object.setProperty("string", QVariant())); const int idx = mo->indexOfProperty("variant"); QVERIFY(idx != -1); QCOMPARE(QMetaType::Type(mo->property(idx).type()), QMetaType::QVariant); QCOMPARE(object.property("variant"), QVariant()); QVariant variant1(42); QVariant variant2("string"); object.setVariant(variant1); QCOMPARE(object.property("variant"), variant1); QVERIFY(object.setProperty("variant", variant2)); QCOMPARE(object.variant(), QVariant(variant2)); QCOMPARE(object.property("variant"), variant2); QVERIFY(object.setProperty("variant", QVariant())); QCOMPARE(object.property("variant"), QVariant()); QVERIFY(mo->indexOfProperty("custom") != -1); property = mo->property(mo->indexOfProperty("custom")); QVERIFY(property.isValid()); QVERIFY(property.isWritable()); QVERIFY(!property.isEnumType()); QCOMPARE(property.typeName(), "CustomType*"); qRegisterMetaType(); QCOMPARE(property.type(), QVariant::UserType); QCOMPARE(property.userType(), qMetaTypeId()); CustomType *customPointer = nullptr; QVariant customVariant = object.property("custom"); customPointer = qvariant_cast(customVariant); QCOMPARE(customPointer, object.custom()); CustomType custom; customPointer = &custom; customVariant.setValue(customPointer); property = mo->property(mo->indexOfProperty("custom")); QVERIFY(property.isWritable()); QCOMPARE(property.typeName(), "CustomType*"); QCOMPARE(property.type(), QVariant::UserType); QCOMPARE(property.userType(), qMetaTypeId()); QVERIFY(object.setProperty("custom", customVariant)); QCOMPARE(object.custom(), customPointer); customVariant = object.property("custom"); customPointer = qvariant_cast(customVariant); QCOMPARE(object.custom(), customPointer); // this enum property has a meta type, but it's not yet registered, so we know this fails QVERIFY(mo->indexOfProperty("priority") != -1); property = mo->property(mo->indexOfProperty("priority")); QVERIFY(property.isEnumType()); #if QT_VERSION < QT_VERSION_CHECK(6, 1, 0) QCOMPARE(property.typeName(), "Priority"); #else QCOMPARE(property.typeName(), "PropertyObject::Priority"); #endif QCOMPARE(property.userType(), QMetaType::fromType().id()); var = object.property("priority"); QVERIFY(!var.isNull()); QCOMPARE(var.toInt(), int(PropertyObject::High)); object.setPriority(PropertyObject::Low); QCOMPARE(object.property("priority").toInt(), int(PropertyObject::Low)); QVERIFY(object.setProperty("priority", PropertyObject::VeryHigh)); QCOMPARE(object.property("priority").toInt(), int(PropertyObject::VeryHigh)); QVERIFY(object.setProperty("priority", "High")); QCOMPARE(object.property("priority").toInt(), int(PropertyObject::High)); QVERIFY(object.setProperty("priority", QVariant())); QCOMPARE(object.property("priority").toInt(), 0); // now it's registered, so it works as expected int priorityMetaTypeId = qRegisterMetaType("PropertyObject::Priority"); QVERIFY(mo->indexOfProperty("priority") != -1); property = mo->property(mo->indexOfProperty("priority")); QVERIFY(property.isEnumType()); #if QT_VERSION < QT_VERSION_CHECK(6, 1, 0) QCOMPARE(property.typeName(), "Priority"); #else QCOMPARE(property.typeName(), "PropertyObject::Priority"); #endif QCOMPARE(property.type(), QVariant::UserType); QCOMPARE(property.userType(), priorityMetaTypeId); var = object.property("priority"); QVERIFY(!var.isNull()); QVERIFY(var.canConvert()); QCOMPARE(qvariant_cast(var), PropertyObject::High); object.setPriority(PropertyObject::Low); QCOMPARE(qvariant_cast(object.property("priority")), PropertyObject::Low); QVERIFY(object.setProperty("priority", PropertyObject::VeryHigh)); QCOMPARE(qvariant_cast(object.property("priority")), PropertyObject::VeryHigh); QVERIFY(object.setProperty("priority", "High")); QCOMPARE(qvariant_cast(object.property("priority")), PropertyObject::High); QVERIFY(object.setProperty("priority", QVariant())); QCOMPARE(object.property("priority").toInt(), 0); var = object.property("priority"); QCOMPARE(qvariant_cast(var), PropertyObject::High); object.setPriority(PropertyObject::Low); QCOMPARE(qvariant_cast(object.property("priority")), PropertyObject::Low); object.setProperty("priority", var); QCOMPARE(qvariant_cast(object.property("priority")), PropertyObject::High); qRegisterMetaType("CustomString"); QVERIFY(mo->indexOfProperty("customString") != -1); QCOMPARE(object.property("customString").toString(), QString()); object.setCustomString("String1"); QCOMPARE(object.property("customString"), QVariant("String1")); QVERIFY(object.setProperty("customString", "String2")); QCOMPARE(object.property("customString"), QVariant("String2")); QVERIFY(object.setProperty("customString", QVariant())); } void tst_QObject::metamethod() { SenderObject obj; const QMetaObject *mobj = obj.metaObject(); QMetaMethod m; m = mobj->method(mobj->indexOfMethod("invoke1()")); QVERIFY(m.methodSignature() == "invoke1()"); QCOMPARE(m.methodType(), QMetaMethod::Method); QCOMPARE(m.access(), QMetaMethod::Public); QVERIFY(!(m.attributes() & QMetaMethod::Scriptable)); QVERIFY(!(m.attributes() & QMetaMethod::Compatibility)); m = mobj->method(mobj->indexOfMethod("sinvoke1()")); QVERIFY(m.methodSignature() == "sinvoke1()"); QCOMPARE(m.methodType(), QMetaMethod::Method); QCOMPARE(m.access(), QMetaMethod::Public); QVERIFY((m.attributes() & QMetaMethod::Scriptable)); QVERIFY(!(m.attributes() & QMetaMethod::Compatibility)); m = mobj->method(mobj->indexOfMethod("invoke2()")); QVERIFY(m.methodSignature() == "invoke2()"); QCOMPARE(m.methodType(), QMetaMethod::Method); QCOMPARE(m.access(), QMetaMethod::Protected); QVERIFY(!(m.attributes() & QMetaMethod::Scriptable)); QVERIFY((m.attributes() & QMetaMethod::Compatibility)); m = mobj->method(mobj->indexOfMethod("sinvoke2()")); QVERIFY(m.methodSignature() == "sinvoke2()"); QCOMPARE(m.methodType(), QMetaMethod::Method); QCOMPARE(m.access(), QMetaMethod::Protected); QVERIFY((m.attributes() & QMetaMethod::Scriptable)); QVERIFY((m.attributes() & QMetaMethod::Compatibility)); #if 0 // Verdigris does not support default values with W_INVOKABLE m = mobj->method(mobj->indexOfMethod("invoke3()")); QVERIFY(m.methodSignature() == "invoke3()"); #else m = mobj->method(mobj->indexOfMethod("invoke3(int,int)")); QVERIFY(m.methodSignature() == "invoke3(int,int)"); #endif QCOMPARE(m.methodType(), QMetaMethod::Method); QCOMPARE(m.access(), QMetaMethod::Private); QVERIFY(!(m.attributes() & QMetaMethod::Scriptable)); QVERIFY(!(m.attributes() & QMetaMethod::Compatibility)); m = mobj->method(mobj->indexOfMethod("sinvoke3()")); QVERIFY(m.methodSignature() == "sinvoke3()"); QCOMPARE(m.methodType(), QMetaMethod::Method); QCOMPARE(m.access(), QMetaMethod::Private); QVERIFY((m.attributes() & QMetaMethod::Scriptable)); QVERIFY(!(m.attributes() & QMetaMethod::Compatibility)); m = mobj->method(mobj->indexOfMethod("signal5()")); QVERIFY(m.methodSignature() == "signal5()"); QCOMPARE(m.methodType(), QMetaMethod::Signal); QCOMPARE(m.access(), QMetaMethod::Public); QVERIFY(!(m.attributes() & QMetaMethod::Scriptable)); QVERIFY((m.attributes() & QMetaMethod::Compatibility)); m = mobj->method(mobj->indexOfMethod("aPublicSlot()")); QVERIFY(m.methodSignature() == "aPublicSlot()"); QCOMPARE(m.methodType(), QMetaMethod::Slot); QCOMPARE(m.access(), QMetaMethod::Public); QVERIFY(!(m.attributes() & QMetaMethod::Scriptable)); QVERIFY(!(m.attributes() & QMetaMethod::Compatibility)); m = mobj->method(mobj->indexOfMethod("invoke1()")); QCOMPARE(m.parameterNames().count(), 0); QCOMPARE(m.parameterTypes().count(), 0); m = mobj->method(mobj->indexOfMethod("invoke2(int)")); QCOMPARE(m.parameterNames().count(), 1); QCOMPARE(m.parameterTypes().count(), 1); QCOMPARE(m.parameterTypes().at(0), QByteArray("int")); QVERIFY(m.parameterNames().at(0).isEmpty()); m = mobj->method(mobj->indexOfMethod("invoke3(int,int)")); QCOMPARE(m.parameterNames().count(), 2); QCOMPARE(m.parameterTypes().count(), 2); QCOMPARE(m.parameterTypes().at(0), QByteArray("int")); #if 0 // Verdigris does not support parameterNames() QCOMPARE(m.parameterNames().at(0), QByteArray("hinz")); #endif QCOMPARE(m.parameterTypes().at(1), QByteArray("int")); #if 0 // Verdigris does not support parameterNames() QCOMPARE(m.parameterNames().at(1), QByteArray("kunz")); #endif } namespace QObjectTest { class TestObject: public QObject { W_OBJECT(TestObject) public: TestObject(): QObject(), i(0) {} void doEmit() { emit aSignal(); } int i; public slots: void aSlot() { ++i; } W_SLOT(aSlot) signals: void aSignal() W_SIGNAL(aSignal) }; } void tst_QObject::namespaces() { QObjectTest::TestObject obj; QVERIFY(connect(&obj, SIGNAL(aSignal()), &obj, SLOT(aSlot()))); obj.doEmit(); QCOMPARE(obj.i, 1); } class SuperObject : public QObject { W_OBJECT(SuperObject) public: QObject *theSender; int theSignalId; SuperObject() { theSender = nullptr; theSignalId = 0; } friend class tst_QObject; using QObject::sender; public slots: void rememberSender() { theSender = sender(); theSignalId = senderSignalIndex(); } W_SLOT(rememberSender) void deleteAndRememberSender() { delete theSender; rememberSender(); } W_SLOT(deleteAndRememberSender) signals: void anotherSignal() W_SIGNAL(anotherSignal) void theSignal() W_SIGNAL(theSignal) }; void tst_QObject::senderTest() { { SuperObject sender; SuperObject receiver; connect(&sender, SIGNAL(anotherSignal()), &receiver, SLOT(rememberSender())); connect(&sender, SIGNAL(theSignal()), &receiver, SLOT(rememberSender())); QCOMPARE(receiver.sender(), (QObject *)0); QCOMPARE(receiver.senderSignalIndex(), -1); emit sender.theSignal(); QCOMPARE(receiver.theSender, (QObject *)&sender); QCOMPARE(receiver.sender(), (QObject *)0); QCOMPARE(receiver.theSignalId, sender.metaObject()->indexOfSignal("theSignal()")); QCOMPARE(receiver.senderSignalIndex(), -1); emit sender.anotherSignal(); QCOMPARE(receiver.theSignalId, sender.metaObject()->indexOfSignal("anotherSignal()")); QCOMPARE(receiver.senderSignalIndex(), -1); } { SuperObject *sender = new SuperObject; SuperObject *receiver = new SuperObject; connect(sender, SIGNAL(theSignal()), receiver, SLOT(rememberSender()), Qt::BlockingQueuedConnection); QThread thread; receiver->moveToThread(&thread); connect(sender, SIGNAL(theSignal()), &thread, SLOT(quit()), Qt::DirectConnection); QCOMPARE(receiver->sender(), (QObject *)0); QCOMPARE(receiver->senderSignalIndex(), -1); receiver->theSender = nullptr; receiver->theSignalId = -1; thread.start(); emit sender->theSignal(); QCOMPARE(receiver->theSender, (QObject *) sender); QCOMPARE(receiver->sender(), (QObject *)0); QCOMPARE(receiver->theSignalId, sender->metaObject()->indexOfSignal("theSignal()")); QCOMPARE(receiver->senderSignalIndex(), -1); QVERIFY(thread.wait(10000)); delete receiver; delete sender; } { SuperObject *sender = new SuperObject; SuperObject receiver; connect(sender, SIGNAL(theSignal()), &receiver, SLOT(deleteAndRememberSender())); QCOMPARE(receiver.sender(), (QObject *)0); receiver.theSender = sender; emit sender->theSignal(); QCOMPARE(receiver.theSender, (QObject *)0); QCOMPARE(receiver.sender(), (QObject *)0); } { SuperObject *sender = new SuperObject; SuperObject *receiver = new SuperObject; connect(sender, SIGNAL(theSignal()), receiver, SLOT(deleteAndRememberSender()), Qt::BlockingQueuedConnection); QThread thread; receiver->moveToThread(&thread); connect(sender, SIGNAL(destroyed()), &thread, SLOT(quit()), Qt::DirectConnection); QCOMPARE(receiver->sender(), (QObject *)0); receiver->theSender = sender; thread.start(); emit sender->theSignal(); QCOMPARE(receiver->theSender, (QObject *)0); QCOMPARE(receiver->sender(), (QObject *)0); QVERIFY(thread.wait(10000)); delete receiver; } } namespace Foo { struct Bar { virtual ~Bar() {} virtual int rtti() const = 0; }; struct Bleh { virtual ~Bleh() {} virtual int rtti() const = 0; }; } QT_BEGIN_NAMESPACE Q_DECLARE_INTERFACE(Foo::Bar, "com.qtest.foobar") QT_END_NAMESPACE #define Bleh_iid "com.qtest.bleh" QT_BEGIN_NAMESPACE Q_DECLARE_INTERFACE(Foo::Bleh, Bleh_iid) QT_END_NAMESPACE class FooObject: public QObject, public Foo::Bar { W_OBJECT(FooObject) W_INTERFACE(Foo::Bar) public: int rtti() const override { return 42; } }; class BlehObject : public QObject, public Foo::Bleh { W_OBJECT(BlehObject) W_INTERFACE(Foo::Bleh) public: int rtti() const override { return 43; } }; void tst_QObject::declareInterface() { FooObject obj; Foo::Bar *bar = qobject_cast(&obj); QVERIFY(bar); QCOMPARE(bar->rtti(), 42); QCOMPARE(static_cast(&obj), bar); BlehObject bleh; bar = qobject_cast(&bleh); QVERIFY(!bar); Foo::Bleh *b = qobject_cast(&bleh); QCOMPARE(b->rtti(), 43); QCOMPARE(static_cast(&bleh), b); } class DestroyedListener : public QObject { W_OBJECT(DestroyedListener) public: inline DestroyedListener() : pointerWasZero(false) {} QPointer pointer; bool pointerWasZero; private slots: inline void otherObjectDestroyed() { pointerWasZero = pointer.isNull(); } W_SLOT(otherObjectDestroyed) }; void tst_QObject::qpointerResetBeforeDestroyedSignal() { QObject *obj = new QObject; DestroyedListener listener; listener.pointer = obj; listener.pointerWasZero = false; connect(obj, SIGNAL(destroyed()), &listener, SLOT(otherObjectDestroyed())); delete obj; QVERIFY(listener.pointerWasZero); QVERIFY(listener.pointer.isNull()); } class DefaultArguments : public QObject { W_OBJECT(DefaultArguments) public slots: void theSlot(const QString &s) { result = s; } W_SLOT(theSlot) signals: void theOriginalSignal() W_SIGNAL(theOriginalSignal) void theSecondSignal(const QString &s = QString("secondDefault")) W_SIGNAL(theSecondSignal,s) public: void emitTheOriginalSignal() { emit theOriginalSignal(); } void emitTheSecondSignal() { emit theSecondSignal(); } QString result; }; void tst_QObject::connectSignalsToSignalsWithDefaultArguments() { QSKIP("Not supported by W_SLOT/W_SIGNAL"); DefaultArguments o; connect(&o, SIGNAL(theOriginalSignal()), &o, SIGNAL(theSecondSignal())); connect(&o, SIGNAL(theSecondSignal(QString)), &o, SLOT(theSlot(QString))); QVERIFY( o.result.isEmpty() ); o.emitTheSecondSignal(); QCOMPARE(o.result, QString("secondDefault")); o.result = "Not called"; o.emitTheOriginalSignal(); QCOMPARE(o.result, QString("secondDefault")); } void tst_QObject::receivers() { class Object : public QObject { public: int receivers(const char* signal) const { return QObject::receivers(signal); } }; Object object; QCOMPARE(object.receivers(SIGNAL(destroyed())), 0); object.connect(&object, SIGNAL(destroyed()), SLOT(deleteLater())); QCOMPARE(object.receivers(SIGNAL(destroyed())), 1); object.connect(&object, SIGNAL(destroyed()), SLOT(deleteLater())); QCOMPARE(object.receivers(SIGNAL(destroyed())), 2); object.disconnect(SIGNAL(destroyed()), &object, SLOT(deleteLater())); QCOMPARE(object.receivers(SIGNAL(destroyed())), 0); } enum Enum { }; struct Struct { }; class Class { }; template class Template { }; W_REGISTER_ARGTYPE(uint*) W_REGISTER_ARGTYPE(ulong*) W_REGISTER_ARGTYPE(const uint*) W_REGISTER_ARGTYPE(const ulong*) W_REGISTER_ARGTYPE(Struct) W_REGISTER_ARGTYPE(Class) W_REGISTER_ARGTYPE(Enum) W_REGISTER_ARGTYPE(Struct*) W_REGISTER_ARGTYPE(Class*) W_REGISTER_ARGTYPE(Enum*) W_REGISTER_ARGTYPE(const Struct*) W_REGISTER_ARGTYPE(const Class*) W_REGISTER_ARGTYPE(const Enum*) W_REGISTER_ARGTYPE(const Struct*const*) W_REGISTER_ARGTYPE(const Class*const*) W_REGISTER_ARGTYPE(const Enum*const*) W_REGISTER_ARGTYPE(Template&) W_REGISTER_ARGTYPE(Template) W_REGISTER_ARGTYPE(Class*const&) W_REGISTER_ARGTYPE(Template) W_REGISTER_ARGTYPE(Template) class NormalizeObject : public QObject { W_OBJECT(NormalizeObject) public: signals: void uintPointerSignal(uint * a) W_SIGNAL(uintPointerSignal,a) void ulongPointerSignal(ulong * a) W_SIGNAL(ulongPointerSignal,a) void constUintPointerSignal(const uint * a) W_SIGNAL(constUintPointerSignal,a) void constUlongPointerSignal(const ulong * a) W_SIGNAL(constUlongPointerSignal,a) void structSignal(Struct s) W_SIGNAL(structSignal,s) void classSignal(Class c) W_SIGNAL(classSignal,c) void enumSignal(Enum e) W_SIGNAL(enumSignal,e) void structPointerSignal(Struct *s) W_SIGNAL(structPointerSignal,s) void classPointerSignal(Class *c) W_SIGNAL(classPointerSignal,c) void enumPointerSignal(Enum *e) W_SIGNAL(enumPointerSignal,e) void constStructPointerSignal(const Struct *s) W_SIGNAL(constStructPointerSignal,s) void constClassPointerSignal(const Class *c) W_SIGNAL(constClassPointerSignal,c) void constEnumPointerSignal(const Enum *e) W_SIGNAL(constEnumPointerSignal,e) void constStructPointerConstPointerSignal(const Struct * const *s) W_SIGNAL(constStructPointerConstPointerSignal,s) void constClassPointerConstPointerSignal(const Class * const *c) W_SIGNAL(constClassPointerConstPointerSignal,c) void constEnumPointerConstPointerSignal(const Enum * const *e) W_SIGNAL(constEnumPointerConstPointerSignal,e) void unsignedintSignal(unsigned int a) W_SIGNAL(unsignedintSignal,a) void unsignedSignal(unsigned a) W_SIGNAL(unsignedSignal,a) void unsignedlongSignal(unsigned long a) W_SIGNAL(unsignedlongSignal,a) void unsignedlonglongSignal(quint64 a) W_SIGNAL(unsignedlonglongSignal,a) void unsignedlongintSignal(unsigned long int a) W_SIGNAL(unsignedlongintSignal,a) void unsignedshortSignal(unsigned short a) W_SIGNAL(unsignedshortSignal,a) void unsignedcharSignal(unsigned char a) W_SIGNAL(unsignedcharSignal,a) void typeRefSignal(Template &ref) W_SIGNAL(typeRefSignal,ref) void constTypeRefSignal(const Template &ref) W_SIGNAL(constTypeRefSignal,ref) void typeConstRefSignal(Template const &ref) W_SIGNAL(typeConstRefSignal,ref) void typePointerConstRefSignal(Class * const &a) W_SIGNAL(typePointerConstRefSignal,a) void constTemplateSignal1( Template a) W_SIGNAL(constTemplateSignal1,a) void constTemplateSignal2( Template< const int >a) W_SIGNAL(constTemplateSignal2,a) public slots: void uintPointerSlot(uint *) { } W_SLOT(uintPointerSlot) void ulongPointerSlot(ulong *) { } W_SLOT(ulongPointerSlot) void constUintPointerSlot(const uint *) { } W_SLOT(constUintPointerSlot) void constUlongPointerSlot(const ulong *) { } W_SLOT(constUlongPointerSlot) void structSlot(Struct s) { Q_UNUSED(s); } W_SLOT(structSlot) void classSlot(Class c) { Q_UNUSED(c); } W_SLOT(classSlot) void enumSlot(Enum e) { Q_UNUSED(e); } W_SLOT(enumSlot) void structPointerSlot(Struct *s) { Q_UNUSED(s); } W_SLOT(structPointerSlot) void classPointerSlot(Class *c) { Q_UNUSED(c); } W_SLOT(classPointerSlot) void enumPointerSlot(Enum *e) { Q_UNUSED(e); } W_SLOT(enumPointerSlot) void constStructPointerSlot(const Struct *s) { Q_UNUSED(s); } W_SLOT(constStructPointerSlot) void constClassPointerSlot(const Class *c) { Q_UNUSED(c); } W_SLOT(constClassPointerSlot) void constEnumPointerSlot(const Enum *e) { Q_UNUSED(e); } W_SLOT(constEnumPointerSlot) void constStructPointerConstPointerSlot(const Struct * const *s) { Q_UNUSED(s); } W_SLOT(constStructPointerConstPointerSlot) void constClassPointerConstPointerSlot(const Class * const *c) { Q_UNUSED(c); } W_SLOT(constClassPointerConstPointerSlot) void constEnumPointerConstPointerSlot(const Enum * const *e) { Q_UNUSED(e); } W_SLOT(constEnumPointerConstPointerSlot) void uintSlot(uint) {} W_SLOT(uintSlot); void unsignedintSlot(unsigned int) {} W_SLOT(unsignedintSlot); void unsignedSlot(unsigned) {} W_SLOT(unsignedSlot); void unsignedlongSlot(unsigned long) {} W_SLOT(unsignedlongSlot); void unsignedlonglongSlot(quint64) {} W_SLOT(unsignedlonglongSlot); void unsignedlongintSlot(unsigned long int) {} W_SLOT(unsignedlongintSlot); void unsignedshortSlot(unsigned short) {} W_SLOT(unsignedshortSlot); void unsignedcharSlot(unsigned char) {} W_SLOT(unsignedcharSlot); void typeRefSlot(Template &) {} W_SLOT(typeRefSlot) void constTypeRefSlot(const Template &) {} W_SLOT(constTypeRefSlot) void typeConstRefSlot(Template const &) {} W_SLOT(typeConstRefSlot) void typePointerConstRefSlot(Class * const &) {} W_SLOT(typePointerConstRefSlot) void constTemplateSlot1(Template const) {} W_SLOT(constTemplateSlot1) void constTemplateSlot2(const Template ) {} W_SLOT(constTemplateSlot2) void constTemplateSlot3(const Template< const int >) {} W_SLOT(constTemplateSlot3) }; void tst_QObject::normalize() { NormalizeObject object; // unsigned int -> uint, unsigned long -> ulong QVERIFY(object.connect(&object, SIGNAL(uintPointerSignal(uint *)), SLOT(uintPointerSlot(uint *)))); QVERIFY(object.connect(&object, SIGNAL(uintPointerSignal(unsigned int *)), SLOT(uintPointerSlot(uint *)))); QVERIFY(object.connect(&object, SIGNAL(uintPointerSignal(uint *)), SLOT(uintPointerSlot(unsigned int *)))); QVERIFY(object.connect(&object, SIGNAL(constUintPointerSignal(const uint *)), SLOT(constUintPointerSlot(const uint *)))); QVERIFY(object.connect(&object, SIGNAL(constUintPointerSignal(const unsigned int *)), SLOT(constUintPointerSlot(const uint *)))); QVERIFY(object.connect(&object, SIGNAL(constUintPointerSignal(const uint *)), SLOT(constUintPointerSlot(const unsigned int *)))); QVERIFY(object.connect(&object, SIGNAL(ulongPointerSignal(ulong *)), SLOT(ulongPointerSlot(ulong *)))); QVERIFY(object.connect(&object, SIGNAL(ulongPointerSignal(unsigned long *)), SLOT(ulongPointerSlot(ulong *)))); QVERIFY(object.connect(&object, SIGNAL(ulongPointerSignal(ulong *)), SLOT(ulongPointerSlot(unsigned long *)))); QVERIFY(object.connect(&object, SIGNAL(constUlongPointerSignal(const ulong *)), SLOT(constUlongPointerSlot(const ulong *)))); QVERIFY(object.connect(&object, SIGNAL(constUlongPointerSignal(const unsigned long *)), SLOT(constUlongPointerSlot(const ulong *)))); QVERIFY(object.connect(&object, SIGNAL(constUlongPointerSignal(const ulong *)), SLOT(constUlongPointerSlot(const unsigned long *)))); // struct, class, and enum are optional QVERIFY(object.connect(&object, SIGNAL(structSignal(struct Struct)), SLOT(structSlot(struct Struct)))); QVERIFY(object.connect(&object, SIGNAL(structSignal(Struct)), SLOT(structSlot(struct Struct)))); QVERIFY(object.connect(&object, SIGNAL(structSignal(struct Struct)), SLOT(structSlot(Struct)))); QVERIFY(object.connect(&object, SIGNAL(classSignal(class Class)), SLOT(classSlot(class Class)))); QVERIFY(object.connect(&object, SIGNAL(classSignal(Class)), SLOT(classSlot(class Class)))); QVERIFY(object.connect(&object, SIGNAL(classSignal(class Class)), SLOT(classSlot(Class)))); QVERIFY(object.connect(&object, SIGNAL(enumSignal(enum Enum)), SLOT(enumSlot(enum Enum)))); QVERIFY(object.connect(&object, SIGNAL(enumSignal(Enum)), SLOT(enumSlot(enum Enum)))); QVERIFY(object.connect(&object, SIGNAL(enumSignal(enum Enum)), SLOT(enumSlot(Enum)))); QVERIFY(object.connect(&object, SIGNAL(structPointerSignal(struct Struct *)), SLOT(structPointerSlot(struct Struct *)))); QVERIFY(object.connect(&object, SIGNAL(structPointerSignal(Struct *)), SLOT(structPointerSlot(struct Struct *)))); QVERIFY(object.connect(&object, SIGNAL(structPointerSignal(struct Struct *)), SLOT(structPointerSlot(Struct *)))); QVERIFY(object.connect(&object, SIGNAL(classPointerSignal(class Class *)), SLOT(classPointerSlot(class Class *)))); QVERIFY(object.connect(&object, SIGNAL(classPointerSignal(Class *)), SLOT(classPointerSlot(class Class *)))); QVERIFY(object.connect(&object, SIGNAL(classPointerSignal(class Class *)), SLOT(classPointerSlot(Class *)))); QVERIFY(object.connect(&object, SIGNAL(enumPointerSignal(enum Enum *)), SLOT(enumPointerSlot(enum Enum *)))); QVERIFY(object.connect(&object, SIGNAL(enumPointerSignal(Enum *)), SLOT(enumPointerSlot(enum Enum *)))); QVERIFY(object.connect(&object, SIGNAL(enumPointerSignal(enum Enum *)), SLOT(enumPointerSlot(Enum *)))); QVERIFY(object.connect(&object, SIGNAL(constStructPointerSignal(const struct Struct *)), SLOT(constStructPointerSlot(const struct Struct *)))); QVERIFY(object.connect(&object, SIGNAL(constStructPointerSignal(const Struct *)), SLOT(constStructPointerSlot(const struct Struct *)))); QVERIFY(object.connect(&object, SIGNAL(constStructPointerSignal(const struct Struct *)), SLOT(constStructPointerSlot(const Struct *)))); QVERIFY(object.connect(&object, SIGNAL(constClassPointerSignal(const class Class *)), SLOT(constClassPointerSlot(const class Class *)))); QVERIFY(object.connect(&object, SIGNAL(constClassPointerSignal(const Class *)), SLOT(constClassPointerSlot(const class Class *)))); QVERIFY(object.connect(&object, SIGNAL(constClassPointerSignal(const class Class *)), SLOT(constClassPointerSlot(const Class *)))); QVERIFY(object.connect(&object, SIGNAL(constEnumPointerSignal(const enum Enum *)), SLOT(constEnumPointerSlot(const enum Enum *)))); QVERIFY(object.connect(&object, SIGNAL(constEnumPointerSignal(const Enum *)), SLOT(constEnumPointerSlot(const enum Enum *)))); QVERIFY(object.connect(&object, SIGNAL(constEnumPointerSignal(const enum Enum *)), SLOT(constEnumPointerSlot(const Enum *)))); QVERIFY(object.connect(&object, SIGNAL(constStructPointerSignal(struct Struct const *)), SLOT(constStructPointerSlot(struct Struct const *)))); QVERIFY(object.connect(&object, SIGNAL(constStructPointerSignal(Struct const *)), SLOT(constStructPointerSlot(struct Struct const *)))); QVERIFY(object.connect(&object, SIGNAL(constStructPointerSignal(struct Struct const *)), SLOT(constStructPointerSlot(Struct const *)))); QVERIFY(object.connect(&object, SIGNAL(constClassPointerSignal(class Class const *)), SLOT(constClassPointerSlot(class Class const *)))); QVERIFY(object.connect(&object, SIGNAL(constClassPointerSignal(Class const *)), SLOT(constClassPointerSlot(class Class const *)))); QVERIFY(object.connect(&object, SIGNAL(constClassPointerSignal(class Class const *)), SLOT(constClassPointerSlot(Class const *)))); QVERIFY(object.connect(&object, SIGNAL(constEnumPointerSignal(enum Enum const *)), SLOT(constEnumPointerSlot(enum Enum const *)))); QVERIFY(object.connect(&object, SIGNAL(constEnumPointerSignal(Enum const *)), SLOT(constEnumPointerSlot(enum Enum const *)))); QVERIFY(object.connect(&object, SIGNAL(constEnumPointerSignal(enum Enum const *)), SLOT(constEnumPointerSlot(Enum const *)))); QVERIFY(object.connect(&object, SIGNAL(constStructPointerConstPointerSignal(const struct Struct * const *)), SLOT(constStructPointerConstPointerSlot(const struct Struct * const *)))); QVERIFY(object.connect(&object, SIGNAL(constStructPointerConstPointerSignal(const Struct * const *)), SLOT(constStructPointerConstPointerSlot(const struct Struct * const *)))); QVERIFY(object.connect(&object, SIGNAL(constStructPointerConstPointerSignal(const struct Struct * const *)), SLOT(constStructPointerConstPointerSlot(const Struct * const *)))); QVERIFY(object.connect(&object, SIGNAL(constClassPointerConstPointerSignal(const class Class * const *)), SLOT(constClassPointerConstPointerSlot(const class Class * const *)))); QVERIFY(object.connect(&object, SIGNAL(constClassPointerConstPointerSignal(const Class * const *)), SLOT(constClassPointerConstPointerSlot(const class Class * const *)))); QVERIFY(object.connect(&object, SIGNAL(constClassPointerConstPointerSignal(const class Class * const *)), SLOT(constClassPointerConstPointerSlot(const Class * const *)))); QVERIFY(object.connect(&object, SIGNAL(constEnumPointerConstPointerSignal(const enum Enum * const *)), SLOT(constEnumPointerConstPointerSlot(const enum Enum * const *)))); QVERIFY(object.connect(&object, SIGNAL(constEnumPointerConstPointerSignal(const Enum * const *)), SLOT(constEnumPointerConstPointerSlot(const enum Enum * const *)))); QVERIFY(object.connect(&object, SIGNAL(constEnumPointerConstPointerSignal(const enum Enum * const *)), SLOT(constEnumPointerConstPointerSlot(const Enum * const *)))); QVERIFY(object.connect(&object, SIGNAL(constStructPointerConstPointerSignal(struct Struct const * const *)), SLOT(constStructPointerConstPointerSlot(struct Struct const * const *)))); QVERIFY(object.connect(&object, SIGNAL(constStructPointerConstPointerSignal(Struct const * const *)), SLOT(constStructPointerConstPointerSlot(struct Struct const * const *)))); QVERIFY(object.connect(&object, SIGNAL(constStructPointerConstPointerSignal(struct Struct const * const *)), SLOT(constStructPointerConstPointerSlot(Struct const * const *)))); QVERIFY(object.connect(&object, SIGNAL(constClassPointerConstPointerSignal(class Class const * const *)), SLOT(constClassPointerConstPointerSlot(class Class const * const *)))); QVERIFY(object.connect(&object, SIGNAL(constClassPointerConstPointerSignal(Class const * const *)), SLOT(constClassPointerConstPointerSlot(class Class const * const *)))); QVERIFY(object.connect(&object, SIGNAL(constClassPointerConstPointerSignal(class Class const * const *)), SLOT(constClassPointerConstPointerSlot(Class const * const *)))); QVERIFY(object.connect(&object, SIGNAL(constEnumPointerConstPointerSignal(enum Enum const * const *)), SLOT(constEnumPointerConstPointerSlot(enum Enum const * const *)))); QVERIFY(object.connect(&object, SIGNAL(constEnumPointerConstPointerSignal(Enum const * const *)), SLOT(constEnumPointerConstPointerSlot(enum Enum const * const *)))); QVERIFY(object.connect(&object, SIGNAL(constEnumPointerConstPointerSignal(enum Enum const * const *)), SLOT(constEnumPointerConstPointerSlot(Enum const * const *)))); QVERIFY(object.connect(&object, SIGNAL(unsignedintSignal(unsigned int)), SLOT(unsignedintSlot(unsigned int)))); QVERIFY(object.connect(&object, SIGNAL(unsignedSignal(unsigned)), SLOT(unsignedSlot(unsigned)))); QVERIFY(object.connect(&object, SIGNAL(unsignedSignal(unsigned)), SLOT(uintSlot(uint)))); QVERIFY(object.connect(&object, SIGNAL(unsignedlongSignal(unsigned long)), SLOT(unsignedlongSlot(unsigned long)))); QVERIFY(object.connect(&object, SIGNAL(unsignedlonglongSignal(quint64)), SLOT(unsignedlonglongSlot(quint64)))); QVERIFY(object.connect(&object, SIGNAL(unsignedlongintSignal(unsigned long int)), SLOT(unsignedlongintSlot(unsigned long int)))); QVERIFY(object.connect(&object, SIGNAL(unsignedshortSignal(unsigned short)), SLOT(unsignedshortSlot(unsigned short)))); QVERIFY(object.connect(&object, SIGNAL(unsignedcharSignal(unsigned char)), SLOT(unsignedcharSlot(unsigned char)))); // connect when original template signature and mixed usage of 'T const &', // 'const T &', and 'T' QVERIFY(object.connect(&object, SIGNAL(typeRefSignal(Template &)), SLOT(typeRefSlot(Template &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(const Template &)), SLOT(constTypeRefSlot(const Template &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(const Template &)), SLOT(constTypeRefSlot(const Template &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(const Template &)), SLOT(constTypeRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(Template const &)), SLOT(constTypeRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(Template const &)), SLOT(constTypeRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(const Template &)), SLOT(typeConstRefSlot(const Template &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(const Template &)), SLOT(typeConstRefSlot(const Template &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(const Template &)), SLOT(typeConstRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(Template const &)), SLOT(typeConstRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(constTypeRefSignal(Template const &)), SLOT(typeConstRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(const Template &)), SLOT(constTypeRefSlot(const Template &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(const Template &)), SLOT(constTypeRefSlot(const Template &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(const Template &)), SLOT(constTypeRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(Template const &)), SLOT(constTypeRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(Template const &)), SLOT(constTypeRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(const Template &)), SLOT(typeConstRefSlot(const Template &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(const Template &)), SLOT(typeConstRefSlot(const Template &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(const Template &)), SLOT(typeConstRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(Template const &)), SLOT(typeConstRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(typeConstRefSignal(Template const &)), SLOT(typeConstRefSlot(Template const &)))); QVERIFY(object.connect(&object, SIGNAL(typePointerConstRefSignal(Class*const&)), SLOT(typePointerConstRefSlot(Class*const&)))); QVERIFY(object.connect(&object, SIGNAL(typePointerConstRefSignal(Class*const&)), SLOT(typePointerConstRefSlot(Class*)))); QVERIFY(object.connect(&object, SIGNAL(typePointerConstRefSignal(Class*)), SLOT(typePointerConstRefSlot(Class*const&)))); QVERIFY(object.connect(&object, SIGNAL(typePointerConstRefSignal(Class*)), SLOT(typePointerConstRefSlot(Class*)))); QVERIFY( connect(&object, SIGNAL(constTemplateSignal1(Template )), &object , SLOT(constTemplateSlot1 (Template ) ) )); QVERIFY( connect(&object, SIGNAL(constTemplateSignal1(Template )), &object , SLOT(constTemplateSlot2 (Template ) ) )); QVERIFY( connect(&object, SIGNAL(constTemplateSignal2(Template )), &object , SLOT(constTemplateSlot3(Template ) ) )); //type does not match QTest::ignoreMessage(QtWarningMsg, "QObject::connect: Incompatible sender/receiver arguments\n" " NormalizeObject::constTemplateSignal1(Template) --> NormalizeObject::constTemplateSlot3(Template)"); QVERIFY(!connect(&object, SIGNAL(constTemplateSignal1(Template )), &object , SLOT(constTemplateSlot3(Template ) ) )); } class SiblingDeleter : public QObject { public: inline SiblingDeleter(QObject *sibling, QObject *parent) : QObject(parent), sibling(sibling) {} inline virtual ~SiblingDeleter() { delete sibling; } private: QPointer sibling; }; void tst_QObject::childDeletesItsSibling() { QObject *commonParent = new QObject(0); QPointer child = new QObject(0); QPointer siblingDeleter = new SiblingDeleter(child, commonParent); child->setParent(commonParent); delete commonParent; // don't crash QVERIFY(!child); QVERIFY(!siblingDeleter); } void tst_QObject::floatProperty() { PropertyObject obj; const int idx = obj.metaObject()->indexOfProperty("myFloat"); QVERIFY(idx > 0); QMetaProperty prop = obj.metaObject()->property(idx); QVERIFY(prop.isValid()); QCOMPARE(int(prop.type()), QMetaType::type("float")); QVERIFY(!prop.write(&obj, QVariant("Hello"))); QVERIFY(prop.write(&obj, QVariant::fromValue(128.0f))); QVariant v = prop.read(&obj); QCOMPARE(v.userType(), int(QMetaType::Float)); QCOMPARE(qvariant_cast(v), 128.0f); } void tst_QObject::qrealProperty() { PropertyObject obj; const int idx = obj.metaObject()->indexOfProperty("myQReal"); QVERIFY(idx > 0); QMetaProperty prop = obj.metaObject()->property(idx); QVERIFY(prop.isValid()); QCOMPARE(int(prop.type()), QMetaType::type("qreal")); QVERIFY(!prop.write(&obj, QVariant("Hello"))); QVERIFY(prop.write(&obj, QVariant::fromValue(128.0f))); QVariant v = prop.read(&obj); QCOMPARE(v.userType(), qMetaTypeId()); QCOMPARE(qvariant_cast(v), 128.0); QVERIFY(prop.write(&obj, QVariant::fromValue(double(127)))); v = prop.read(&obj); QCOMPARE(v.userType(), qMetaTypeId()); QCOMPARE(qvariant_cast(v), 127.0); } class DynamicPropertyObject : public PropertyObject { public: inline DynamicPropertyObject() {} inline virtual bool event(QEvent *e) override { if (e->type() == QEvent::DynamicPropertyChange) { changedDynamicProperties.append(static_cast(e)->propertyName()); } return QObject::event(e); } QList changedDynamicProperties; }; void tst_QObject::dynamicProperties() { DynamicPropertyObject obj; QVERIFY(obj.dynamicPropertyNames().isEmpty()); // set a non-dynamic property QVERIFY(obj.setProperty("number", 42)); QVERIFY(obj.changedDynamicProperties.isEmpty()); QCOMPARE(obj.property("number").toInt(), 42); QVERIFY(!obj.setProperty("number", "invalid string")); QVERIFY(obj.changedDynamicProperties.isEmpty()); // set a dynamic property QVERIFY(!obj.setProperty("myuserproperty", "Hello")); QCOMPARE(obj.changedDynamicProperties.count(), 1); QCOMPARE(obj.changedDynamicProperties.first(), QByteArray("myuserproperty")); //check if there is no redundant DynamicPropertyChange events QVERIFY(!obj.setProperty("myuserproperty", "Hello")); QCOMPARE(obj.changedDynamicProperties.count(), 1); QCOMPARE(obj.property("myuserproperty").type(), QVariant::String); QCOMPARE(obj.property("myuserproperty").toString(), QString("Hello")); QCOMPARE(obj.dynamicPropertyNames().count(), 1); QCOMPARE(obj.dynamicPropertyNames().first(), QByteArray("myuserproperty")); // change type of the dynamic property obj.changedDynamicProperties.clear(); QVERIFY(!obj.setProperty("myuserproperty", QByteArray("Hello"))); QCOMPARE(obj.changedDynamicProperties.count(), 1); QCOMPARE(obj.changedDynamicProperties.first(), QByteArray("myuserproperty")); QCOMPARE(obj.property("myuserproperty").type(), QVariant::ByteArray); QCOMPARE(obj.property("myuserproperty").toString(), QByteArray("Hello")); // unset the property obj.changedDynamicProperties.clear(); QVERIFY(!obj.setProperty("myuserproperty", QVariant())); QCOMPARE(obj.changedDynamicProperties.count(), 1); QCOMPARE(obj.changedDynamicProperties.first(), QByteArray("myuserproperty")); obj.changedDynamicProperties.clear(); QVERIFY(obj.property("myuserproperty").isNull()); QVERIFY(obj.dynamicPropertyNames().isEmpty()); } void tst_QObject::recursiveSignalEmission() { #if !QT_CONFIG(process) QSKIP("No qprocess support", SkipAll); #elif !defined(Q_OS_MAC) && !defined(Q_OS_WIN) // because it does not find the executable QProcess proc; // signalbug helper app should always be next to this test binary #ifdef W_SIGNALBUG const QString path = QStringLiteral(W_SIGNALBUG); #else const QString path = QStringLiteral("signalbug/signalbug"); #endif proc.start(path); QVERIFY2(proc.waitForStarted(), qPrintable(QString::fromLatin1("Cannot start '%1': %2").arg(path, proc.errorString()))); QVERIFY(proc.waitForFinished()); QCOMPARE(proc.exitStatus(), QProcess::NormalExit); QCOMPARE(proc.exitCode(), 0); #endif } void tst_QObject::signalBlocking() { SenderObject sender; ReceiverObject receiver; receiver.connect(&sender, SIGNAL(signal1()), SLOT(slot1())); sender.emitSignal1(); QVERIFY(receiver.called(1)); receiver.reset(); sender.blockSignals(true); sender.emitSignal1(); QVERIFY(!receiver.called(1)); receiver.reset(); sender.blockSignals(false); sender.emitSignal1(); QVERIFY(receiver.called(1)); receiver.reset(); } void tst_QObject::blockingQueuedConnection() { { SenderObject sender; MoveToThreadThread thread; ReceiverObject receiver; receiver.moveToThread(&thread); thread.start(); receiver.connect(&sender, SIGNAL(signal1()), SLOT(slot1()), Qt::BlockingQueuedConnection); sender.emitSignal1(); QVERIFY(receiver.called(1)); receiver.reset(); QVERIFY(QMetaObject::invokeMethod(&receiver, "slot1", Qt::BlockingQueuedConnection)); QVERIFY(receiver.called(1)); connect(&sender, &SenderObject::signal2, &receiver, &ReceiverObject::slot2, Qt::BlockingQueuedConnection); sender.emitSignal2(); QVERIFY(receiver.called(2)); thread.quit(); QVERIFY(thread.wait()); } } class EventSpy : public QObject { W_OBJECT(EventSpy) public: typedef QList > EventList; EventSpy(QObject *parent = nullptr) : QObject(parent) { } EventList eventList() { return events; } void clear() { events.clear(); } bool eventFilter(QObject *object, QEvent *event) override { events.append(qMakePair(object, event->type())); return false; } private: EventList events; }; void tst_QObject::childEvents() { EventSpy::EventList expected; { // no children created, so we expect no events QObject object; EventSpy spy; object.installEventFilter(&spy); QCoreApplication::postEvent(&object, new QEvent(QEvent::Type(QEvent::User + 1))); QCoreApplication::processEvents(); expected = EventSpy::EventList() << qMakePair(&object, QEvent::Type(QEvent::User + 1)); QCOMPARE(spy.eventList(), expected); } { // 2 children, so we expect 2 ChildAdded events QObject object; EventSpy spy; object.installEventFilter(&spy); QCoreApplication::postEvent(&object, new QEvent(QEvent::Type(QEvent::User + 1))); QObject child1(&object); QObject child2; child2.setParent(&object); QCoreApplication::postEvent(&object, new QEvent(QEvent::Type(QEvent::User + 2))); expected = EventSpy::EventList() << qMakePair(&object, QEvent::ChildAdded) << qMakePair(&object, QEvent::ChildAdded); QCOMPARE(spy.eventList(), expected); spy.clear(); QCoreApplication::processEvents(); expected = EventSpy::EventList() << qMakePair(&object, QEvent::Type(QEvent::User + 1)) << qMakePair(&object, QEvent::Type(QEvent::User + 2)); QCOMPARE(spy.eventList(), expected); } { // 2 children, but one is reparented away, so we expect: // 2 ChildAdded, 1 ChildRemoved QObject object; EventSpy spy; object.installEventFilter(&spy); QCoreApplication::postEvent(&object, new QEvent(QEvent::Type(QEvent::User + 1))); QObject child1(&object); QObject child2; child2.setParent(&object); child2.setParent(0); QCoreApplication::postEvent(&object, new QEvent(QEvent::Type(QEvent::User + 2))); expected = EventSpy::EventList() << qMakePair(&object, QEvent::ChildAdded) << qMakePair(&object, QEvent::ChildAdded) << qMakePair(&object, QEvent::ChildRemoved); QCOMPARE(spy.eventList(), expected); spy.clear(); QCoreApplication::processEvents(); expected = EventSpy::EventList() << qMakePair(&object, QEvent::Type(QEvent::User + 1)) << qMakePair(&object, QEvent::Type(QEvent::User + 2)); QCOMPARE(spy.eventList(), expected); } } void tst_QObject::installEventFilter() { QEvent event(QEvent::User); EventSpy::EventList expected; QObject object; EventSpy spy; object.installEventFilter(&spy); // nothing special, should just work QCoreApplication::sendEvent(&object, &event); expected = EventSpy::EventList() << qMakePair(&object, QEvent::User); QCOMPARE(spy.eventList(), expected); spy.clear(); // moving the filter causes QCoreApplication to skip the filter spy.moveToThread(0); QTest::ignoreMessage(QtWarningMsg, "QCoreApplication: Object event filter cannot be in a different thread."); QCoreApplication::sendEvent(&object, &event); QVERIFY(spy.eventList().isEmpty()); // move it back, and the filter works again spy.moveToThread(object.thread()); QCoreApplication::sendEvent(&object, &event); expected = EventSpy::EventList() << qMakePair(&object, QEvent::User); QCOMPARE(spy.eventList(), expected); spy.clear(); // cannot install an event filter that lives in a different thread object.removeEventFilter(&spy); spy.moveToThread(0); QTest::ignoreMessage(QtWarningMsg, "QObject::installEventFilter(): Cannot filter events for objects in a different thread."); object.installEventFilter(&spy); QCoreApplication::sendEvent(&object, &event); QVERIFY(spy.eventList().isEmpty()); } class EmitThread : public QThread { W_OBJECT(EmitThread) public: void run(void) override { emit work(); } signals: void work() W_SIGNAL(work) }; namespace QObjectTest { // Do not clash with WinAPI 'DeleteObject' class DeleteObject : public QObject { W_OBJECT(DeleteObject) public slots: void deleteSelf() { delete this; } W_SLOT(deleteSelf) void relaySignalAndProcessEvents() { emit relayedSignal(); QCoreApplication::processEvents(); } W_SLOT(relaySignalAndProcessEvents) signals: void relayedSignal() W_SIGNAL(relayedSignal) }; } // namespace QObjectTest void tst_QObject::deleteSelfInSlot() { { SenderObject sender; QObjectTest::DeleteObject *receiver = new QObjectTest::DeleteObject(); receiver->connect(&sender, SIGNAL(signal1()), SLOT(deleteSelf()), Qt::BlockingQueuedConnection); QThread thread; receiver->moveToThread(&thread); thread.connect(receiver, SIGNAL(destroyed()), SLOT(quit()), Qt::DirectConnection); thread.start(); QPointer p = receiver; sender.emitSignal1(); QVERIFY(p.isNull()); QVERIFY(thread.wait(10000)); } { SenderObject sender; QObjectTest::DeleteObject *receiver = new QObjectTest::DeleteObject(); receiver->connect(&sender, SIGNAL(signal1()), SLOT(relaySignalAndProcessEvents()), Qt::BlockingQueuedConnection); receiver->connect(receiver, SIGNAL(relayedSignal()), SLOT(deleteSelf()), Qt::QueuedConnection); QThread thread; receiver->moveToThread(&thread); thread.connect(receiver, SIGNAL(destroyed()), SLOT(quit()), Qt::DirectConnection); thread.start(); QPointer p = receiver; sender.emitSignal1(); QVERIFY(p.isNull()); QVERIFY(thread.wait(10000)); } { EmitThread sender; QObjectTest::DeleteObject *receiver = new QObjectTest::DeleteObject(); connect(&sender, SIGNAL(work()), receiver, SLOT(deleteSelf()), Qt::DirectConnection); QPointer p = receiver; sender.start(); QVERIFY(sender.wait(10000)); QVERIFY(p.isNull()); } } class DisconnectObject : public QObject { W_OBJECT(DisconnectObject) public slots: void disconnectSelf() { disconnect(sender(), 0, this, 0); } W_SLOT(disconnectSelf) void relaySignalAndProcessEvents() { emit relayedSignal(); QCoreApplication::processEvents(); } W_SLOT(relaySignalAndProcessEvents) signals: void relayedSignal() W_SIGNAL(relayedSignal) }; void tst_QObject::disconnectSelfInSlotAndDeleteAfterEmit() { { SenderObject sender; DisconnectObject *receiver = new DisconnectObject(); receiver->connect(&sender, SIGNAL(signal1()), SLOT(disconnectSelf())); sender.emitSignal1AfterRecursion(); delete receiver; } { SenderObject sender; DisconnectObject *receiver = new DisconnectObject(); receiver->connect(&sender, SIGNAL(signal1()), SLOT(disconnectSelf()), Qt::BlockingQueuedConnection); QThread thread; receiver->moveToThread(&thread); thread.connect(receiver, SIGNAL(destroyed()), SLOT(quit()), Qt::DirectConnection); thread.start(); QPointer p = receiver; sender.emitSignal1(); QVERIFY(!p.isNull()); receiver->deleteLater(); QVERIFY(thread.wait(10000)); QVERIFY(p.isNull()); } { SenderObject sender; DisconnectObject *receiver = new DisconnectObject(); receiver->connect(&sender, SIGNAL(signal1()), SLOT(relaySignalAndProcessEvents()), Qt::BlockingQueuedConnection); receiver->connect(receiver, SIGNAL(relayedSignal()), SLOT(disconnectSelf()), Qt::QueuedConnection); QThread thread; receiver->moveToThread(&thread); thread.connect(receiver, SIGNAL(destroyed()), SLOT(quit()), Qt::DirectConnection); thread.start(); QPointer p = receiver; sender.emitSignal1(); QVERIFY(!p.isNull()); receiver->deleteLater(); QVERIFY(thread.wait(10000)); QVERIFY(p.isNull()); } } void tst_QObject::dumpObjectInfo() { QObject a, 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, " "); QTest::ignoreMessage(QtDebugMsg, " SIGNALS IN"); QTest::ignoreMessage(QtDebugMsg, " "); a.dumpObjectInfo(); // should not crash } #if QT_VERSION >= QT_VERSION_CHECK(6,3,0) void tst_QObject::dumpObjectTree() { QObject a; Q_SET_OBJECT_NAME(a); QTimer b(&a); Q_SET_OBJECT_NAME(b); QObject c(&b); Q_SET_OBJECT_NAME(c); QFile f(&a); Q_SET_OBJECT_NAME(f); const char * const output[] = { "QObject::a ", " QTimer::b ", " QObject::c ", " QFile::f ", }; for (const char *line : output) QTest::ignoreMessage(QtDebugMsg, line); a.dumpObjectTree(); } #endif class ConnectToSender : public QObject { W_OBJECT(ConnectToSender) public slots: void uselessSlot() { count++; } W_SLOT(uselessSlot) void harmfullSlot() { //this used to crash connect(sender(), SIGNAL(signal4()), this, SLOT(uselessSlot())); //play a little bit with the memory in order to really get a segfault. connect(sender(), SIGNAL(signal1()), this, SLOT(uselessSlot())); QList() << 45 << 78 << 65 << 121 << 45 << 78 << 12; } W_SLOT(harmfullSlot) public: int count; }; void tst_QObject::connectToSender() { SenderObject s; ConnectToSender r; r.count = 0; QObject::connect(&s, SIGNAL(signal1()), &r, SLOT(harmfullSlot())); QObject::connect(&s, SIGNAL(signal1()), &r, SLOT(uselessSlot())); s.emitSignal1(); QCOMPARE(r.count, 1); s.emitSignal4(); QCOMPARE(r.count, 2); } void tst_QObject::qobjectConstCast() { FooObject obj; QObject *ptr = &obj; const QObject *cptr = &obj; QVERIFY(qobject_cast(ptr)); QVERIFY(qobject_cast(cptr)); } void tst_QObject::uniqConnection() { SenderObject s; ReceiverObject r1; ReceiverObject r2; r1.reset(); r2.reset(); ReceiverObject::sequence = 0; QVERIFY(connect(&s, SIGNAL(signal1()), &r1, SLOT(slot1()) , Qt::UniqueConnection) ); QVERIFY(connect(&s, SIGNAL(signal1()), &r2, SLOT(slot1()) , Qt::UniqueConnection) ); QVERIFY(connect(&s, SIGNAL(signal1()), &r1, SLOT(slot3()) , Qt::UniqueConnection) ); QVERIFY(connect(&s, SIGNAL(signal3()), &r1, SLOT(slot3()) , Qt::UniqueConnection) ); s.emitSignal1(); s.emitSignal2(); s.emitSignal3(); s.emitSignal4(); QCOMPARE(r1.count_slot1, 1); QCOMPARE(r1.count_slot2, 0); QCOMPARE(r1.count_slot3, 2); QCOMPARE(r1.count_slot4, 0); QCOMPARE(r2.count_slot1, 1); QCOMPARE(r2.count_slot2, 0); QCOMPARE(r2.count_slot3, 0); QCOMPARE(r2.count_slot4, 0); QCOMPARE(r1.sequence_slot1, 1); QCOMPARE(r2.sequence_slot1, 2); QCOMPARE(r1.sequence_slot3, 4); r1.reset(); r2.reset(); ReceiverObject::sequence = 0; QVERIFY( connect(&s, SIGNAL(signal4()), &r1, SLOT(slot4()) , Qt::UniqueConnection)); QVERIFY( connect(&s, SIGNAL(signal4()), &r2, SLOT(slot4()) , Qt::UniqueConnection)); QVERIFY(!connect(&s, SIGNAL(signal4()), &r2, SLOT(slot4()) , Qt::UniqueConnection)); QVERIFY( connect(&s, SIGNAL(signal1()), &r2, SLOT(slot4()) , Qt::UniqueConnection)); QVERIFY(!connect(&s, SIGNAL(signal4()), &r1, SLOT(slot4()) , Qt::UniqueConnection)); s.emitSignal4(); QCOMPARE(r1.count_slot4, 1); QCOMPARE(r2.count_slot4, 1); QCOMPARE(r1.sequence_slot4, 1); QCOMPARE(r2.sequence_slot4, 2); r1.reset(); r2.reset(); ReceiverObject::sequence = 0; connect(&s, SIGNAL(signal4()), &r1, SLOT(slot4())); s.emitSignal4(); QCOMPARE(r1.count_slot4, 2); QCOMPARE(r2.count_slot4, 1); QCOMPARE(r1.sequence_slot4, 3); QCOMPARE(r2.sequence_slot4, 2); } void tst_QObject::uniqConnectionPtr() { SenderObject s; ReceiverObject r1; ReceiverObject r2; r1.reset(); r2.reset(); ReceiverObject::sequence = 0; QVERIFY(connect(&s, &SenderObject::signal1, &r1, &ReceiverObject::slot1 , Qt::UniqueConnection)); QVERIFY(connect(&s, &SenderObject::signal1, &r2, &ReceiverObject::slot1 , Qt::UniqueConnection)); QVERIFY(connect(&s, &SenderObject::signal1, &r1, &ReceiverObject::slot3 , Qt::UniqueConnection)); QVERIFY(connect(&s, &SenderObject::signal3, &r1, &ReceiverObject::slot3 , Qt::UniqueConnection)); s.emitSignal1(); s.emitSignal2(); s.emitSignal3(); s.emitSignal4(); QCOMPARE(r1.count_slot1, 1); QCOMPARE(r1.count_slot2, 0); QCOMPARE(r1.count_slot3, 2); QCOMPARE(r1.count_slot4, 0); QCOMPARE(r2.count_slot1, 1); QCOMPARE(r2.count_slot2, 0); QCOMPARE(r2.count_slot3, 0); QCOMPARE(r2.count_slot4, 0); QCOMPARE(r1.sequence_slot1, 1); QCOMPARE(r2.sequence_slot1, 2); QCOMPARE(r1.sequence_slot3, 4); r1.reset(); r2.reset(); ReceiverObject::sequence = 0; QVERIFY( connect(&s, &SenderObject::signal4, &r1, &ReceiverObject::slot4 , Qt::UniqueConnection)); QVERIFY( connect(&s, &SenderObject::signal4, &r2, &ReceiverObject::slot4 , Qt::UniqueConnection)); QVERIFY(!connect(&s, &SenderObject::signal4, &r2, &ReceiverObject::slot4 , Qt::UniqueConnection)); QVERIFY( connect(&s, &SenderObject::signal1, &r2, &ReceiverObject::slot4 , Qt::UniqueConnection)); QVERIFY(!connect(&s, &SenderObject::signal4, &r1, &ReceiverObject::slot4 , Qt::UniqueConnection)); s.emitSignal4(); QCOMPARE(r1.count_slot4, 1); QCOMPARE(r2.count_slot4, 1); QCOMPARE(r1.sequence_slot4, 1); QCOMPARE(r2.sequence_slot4, 2); r1.reset(); r2.reset(); ReceiverObject::sequence = 0; connect(&s, &SenderObject::signal4, &r1, &ReceiverObject::slot4); s.emitSignal4(); QCOMPARE(r1.count_slot4, 2); QCOMPARE(r2.count_slot4, 1); QCOMPARE(r1.sequence_slot4, 3); QCOMPARE(r2.sequence_slot4, 2); } void tst_QObject::interfaceIid() { QCOMPARE(QByteArray(qobject_interface_iid()), QByteArray(Bleh_iid)); QCOMPARE(QByteArray(qobject_interface_iid()), QByteArray("com.qtest.foobar")); #if QT_VERSION < QT_VERSION_CHECK(6,3,0) QCOMPARE(QByteArray(qobject_interface_iid()), QByteArray()); #endif } void tst_QObject::deleteQObjectWhenDeletingEvent() { // This is a regression test for an old bug that used to deadlock // when the QObject from the event was destroyed. struct MyEvent : public QEvent { MyEvent() : QEvent(QEvent::User) { } QObject obj; }; QObject o; QCoreApplication::postEvent(&o, new MyEvent); QCoreApplication::removePostedEvents(&o); // here you would get a deadlock } class OverloadObject : public QObject { friend class tst_QObject; W_OBJECT(OverloadObject) signals: void sig(int i, char c, qreal m = 12) W_SIGNAL(sig,(int, char, qreal),i,c,m) void sig(int i, int j = 12) W_SIGNAL(sig,(int,int),i,j) void sig(QObject *o, QObject *p, QObject *q = 0, QObject *r = 0) const W_SIGNAL(sig,(QObject*,QObject*,QObject*,QObject*),o,p,q,r) void other(int a = 0) W_SIGNAL(other,(int),a) void sig(QObject *o, OverloadObject *p = 0, QObject *q = 0, QObject *r = 0) W_SIGNAL(sig,(QObject*,OverloadObject*,QObject*,QObject*),o,p,q,r) void sig(double r = 0.5) W_SIGNAL(sig,(double),r) public slots: void slo(int i, int j = 43) { s_num += 1; i1_num = i; i2_num = j; } W_SLOT(slo,(int,int)) void slo(QObject *o, QObject *p = qApp, QObject *q = qApp, QObject *r = qApp) { s_num += 10; o1_obj = o; o2_obj = p; o3_obj = q; o4_obj = r; } W_SLOT(slo,(QObject*,QObject*,QObject*,QObject*)) void slo() { s_num += 100; } W_SLOT(slo,()) public: int s_num; int i1_num; int i2_num; QObject *o1_obj; QObject *o2_obj; QObject *o3_obj; QObject *o4_obj; }; void tst_QObject::overloads() { QSKIP("Overload not supported by W_SIGNAL/W_SLOT"); OverloadObject obj1; OverloadObject obj2; QObject obj3; obj1.s_num = 0; obj2.s_num = 0; connect (&obj1, SIGNAL(sig(int)) , &obj1, SLOT(slo(int))); connect (&obj1, SIGNAL(sig(QObject*,QObject*,QObject*)) , &obj1, SLOT(slo(QObject*,QObject*,QObject*))); connect (&obj1, SIGNAL(sig(QObject*,QObject*,QObject*,QObject*)) , &obj2, SLOT(slo(QObject*,QObject*,QObject*))); connect (&obj1, SIGNAL(sig(QObject*)) , &obj2, SLOT(slo())); connect (&obj1, SIGNAL(sig(int,int)) , &obj2, SLOT(slo(int,int))); emit obj1.sig(0.5); //connected to nothing emit obj1.sig(1, 'a'); //connected to nothing QCOMPARE(obj1.s_num, 0); QCOMPARE(obj2.s_num, 0); emit obj1.sig(1); //this signal is connected QCOMPARE(obj1.s_num, 1); QCOMPARE(obj1.i1_num, 1); QCOMPARE(obj1.i2_num, 43); //default argument of the slot QCOMPARE(obj2.s_num, 1); QCOMPARE(obj2.i1_num, 1); QCOMPARE(obj2.i2_num, 12); //default argument of the signal emit obj1.sig(&obj2); //this signal is conencted to obj2 QCOMPARE(obj1.s_num, 1); QCOMPARE(obj2.s_num, 101); emit obj1.sig(&obj2, &obj3); //this signal is connected QCOMPARE(obj1.s_num, 11); QCOMPARE(obj1.o1_obj, (QObject *)&obj2); QCOMPARE(obj1.o2_obj, &obj3); QCOMPARE(obj1.o3_obj, (QObject *)0); //default arg of the signal QCOMPARE(obj1.o4_obj, (QObject *)qApp); //default arg of the slot QCOMPARE(obj2.s_num, 111); QCOMPARE(obj2.o1_obj, (QObject *)&obj2); QCOMPARE(obj2.o2_obj, &obj3); QCOMPARE(obj2.o3_obj, (QObject *)0); //default arg of the signal QCOMPARE(obj2.o4_obj, (QObject *)qApp); //default arg of the slot } class ManySignals : public QObject { W_OBJECT(ManySignals) friend class tst_QObject; signals: void sig00() W_SIGNAL(sig00) void sig01() W_SIGNAL(sig01) void sig02() W_SIGNAL(sig02) void sig03() W_SIGNAL(sig03) void sig04() W_SIGNAL(sig04) void sig05() W_SIGNAL(sig05) void sig06() W_SIGNAL(sig06) void sig07() W_SIGNAL(sig07) void sig08() W_SIGNAL(sig08) void sig09() W_SIGNAL(sig09) void sig10() W_SIGNAL(sig10) void sig11() W_SIGNAL(sig11) void sig12() W_SIGNAL(sig12) void sig13() W_SIGNAL(sig13) void sig14() W_SIGNAL(sig14) void sig15() W_SIGNAL(sig15) void sig16() W_SIGNAL(sig16) void sig17() W_SIGNAL(sig17) void sig18() W_SIGNAL(sig18) void sig19() W_SIGNAL(sig19) void sig20() W_SIGNAL(sig20) void sig21() W_SIGNAL(sig21) void sig22() W_SIGNAL(sig22) void sig23() W_SIGNAL(sig23) void sig24() W_SIGNAL(sig24) void sig25() W_SIGNAL(sig25) void sig26() W_SIGNAL(sig26) void sig27() W_SIGNAL(sig27) void sig28() W_SIGNAL(sig28) void sig29() W_SIGNAL(sig29) void sig30() W_SIGNAL(sig30) void sig31() W_SIGNAL(sig31) void sig32() W_SIGNAL(sig32) void sig33() W_SIGNAL(sig33) void sig34() W_SIGNAL(sig34) void sig35() W_SIGNAL(sig35) void sig36() W_SIGNAL(sig36) void sig37() W_SIGNAL(sig37) void sig38() W_SIGNAL(sig38) void sig39() W_SIGNAL(sig39) void sig40() W_SIGNAL(sig40) void sig41() W_SIGNAL(sig41) void sig42() W_SIGNAL(sig42) void sig43() W_SIGNAL(sig43) void sig44() W_SIGNAL(sig44) void sig45() W_SIGNAL(sig45) void sig46() W_SIGNAL(sig46) void sig47() W_SIGNAL(sig47) void sig48() W_SIGNAL(sig48) void sig49() W_SIGNAL(sig49) void sig50() W_SIGNAL(sig50) void sig51() W_SIGNAL(sig51) void sig52() W_SIGNAL(sig52) void sig53() W_SIGNAL(sig53) void sig54() W_SIGNAL(sig54) void sig55() W_SIGNAL(sig55) void sig56() W_SIGNAL(sig56) void sig57() W_SIGNAL(sig57) void sig58() W_SIGNAL(sig58) void sig59() W_SIGNAL(sig59) void sig60() W_SIGNAL(sig60) void sig61() W_SIGNAL(sig61) void sig62() W_SIGNAL(sig62) void sig63() W_SIGNAL(sig63) void sig64() W_SIGNAL(sig64) void sig65() W_SIGNAL(sig65) void sig66() W_SIGNAL(sig66) void sig67() W_SIGNAL(sig67) void sig68() W_SIGNAL(sig68) void sig69() W_SIGNAL(sig69) public slots: void received() { rec++; } W_SLOT(received) public: int rec; }; void tst_QObject::isSignalConnected() { ManySignals o; const QMetaObject *meta = o.metaObject(); o.rec = 0; #ifdef QT_BUILD_INTERNAL QObjectPrivate *priv = QObjectPrivate::get(&o); QVERIFY(!priv->isSignalConnected(priv->signalIndex("destroyed()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig00()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig05()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig15()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig29()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig60()"))); #endif QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("destroyed()")))); QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig00()")))); QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig05()")))); QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig15()")))); QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig29()")))); QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig60()")))); QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig69()")))); QObject::connect(&o, SIGNAL(sig00()), &o, SIGNAL(sig69())); QObject::connect(&o, SIGNAL(sig34()), &o, SIGNAL(sig03())); QObject::connect(&o, SIGNAL(sig69()), &o, SIGNAL(sig34())); QObject::connect(&o, SIGNAL(sig03()), &o, SIGNAL(sig18())); #ifdef QT_BUILD_INTERNAL QVERIFY(!priv->isSignalConnected(priv->signalIndex("destroyed()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig05()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig15()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig29()"))); QVERIFY(priv->isSignalConnected(priv->signalIndex("sig00()"))); QVERIFY(priv->isSignalConnected(priv->signalIndex("sig03()"))); QVERIFY(priv->isSignalConnected(priv->signalIndex("sig34()"))); QVERIFY(priv->isSignalConnected(priv->signalIndex("sig69()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig18()"))); #endif QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("destroyed()")))); QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("destroyed(QObject*)")))); QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig05()")))); QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig15()")))); QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig29()")))); QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig00()")))); QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig03()")))); QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig34()")))); QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig69()")))); QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig18()")))); QObject::connect(&o, SIGNAL(sig18()), &o, SIGNAL(sig29())); QObject::connect(&o, SIGNAL(sig29()), &o, SIGNAL(sig62())); QObject::connect(&o, SIGNAL(sig62()), &o, SIGNAL(sig28())); QObject::connect(&o, SIGNAL(sig28()), &o, SIGNAL(sig27())); #ifdef QT_BUILD_INTERNAL QVERIFY(priv->isSignalConnected(priv->signalIndex("sig18()"))); QVERIFY(priv->isSignalConnected(priv->signalIndex("sig62()"))); QVERIFY(priv->isSignalConnected(priv->signalIndex("sig28()"))); QVERIFY(priv->isSignalConnected(priv->signalIndex("sig69()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig27()"))); #endif QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig18()")))); QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig62()")))); QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig28()")))); QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig69()")))); QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig27()")))); QCOMPARE(o.rec, 0); emit o.sig01(); emit o.sig34(); QCOMPARE(o.rec, 0); QObject::connect(&o, SIGNAL(sig27()), &o, SLOT(received())); #ifdef QT_BUILD_INTERNAL QVERIFY(priv->isSignalConnected(priv->signalIndex("sig00()"))); QVERIFY(priv->isSignalConnected(priv->signalIndex("sig03()"))); QVERIFY(priv->isSignalConnected(priv->signalIndex("sig34()"))); QVERIFY(priv->isSignalConnected(priv->signalIndex("sig18()"))); QVERIFY(priv->isSignalConnected(priv->signalIndex("sig62()"))); QVERIFY(priv->isSignalConnected(priv->signalIndex("sig28()"))); QVERIFY(priv->isSignalConnected(priv->signalIndex("sig69()"))); QVERIFY(priv->isSignalConnected(priv->signalIndex("sig27()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig04()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig21()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig25()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig55()"))); #endif emit o.sig00(); QCOMPARE(o.rec, 1); emit o.sig69(); QCOMPARE(o.rec, 2); emit o.sig36(); QCOMPARE(o.rec, 2); QObject::connect(&o, &QObject::destroyed, qt_noop); QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("destroyed()")))); QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("destroyed(QObject*)")))); QVERIFY(!o.isSignalConnected(QMetaMethod())); } void tst_QObject::isSignalConnectedAfterDisconnection() { ManySignals o; const QMetaObject *meta = o.metaObject(); const QMetaMethod sig00 = meta->method(meta->indexOfSignal("sig00()")); QVERIFY(!o.isSignalConnected(sig00)); QObject::connect(&o, &ManySignals::sig00, qt_noop); QVERIFY(o.isSignalConnected(sig00)); QVERIFY(QObject::disconnect(&o, &ManySignals::sig00, 0, 0)); QVERIFY(!o.isSignalConnected(sig00)); const QMetaMethod sig69 = meta->method(meta->indexOfSignal("sig69()")); QVERIFY(!o.isSignalConnected(sig69)); QObject::connect(&o, &ManySignals::sig69, qt_noop); QVERIFY(o.isSignalConnected(sig69)); QVERIFY(QObject::disconnect(&o, &ManySignals::sig69, 0, 0)); QVERIFY(!o.isSignalConnected(sig69)); { ManySignals o2; QObject::connect(&o, &ManySignals::sig00, &o2, &ManySignals::sig00); QVERIFY(o.isSignalConnected(sig00)); // o2 is destructed } QVERIFY(!o.isSignalConnected(sig00)); const QMetaMethod sig01 = meta->method(meta->indexOfSignal("sig01()")); QObject::connect(&o, &ManySignals::sig00, qt_noop); QObject::connect(&o, &ManySignals::sig01, qt_noop); QObject::connect(&o, &ManySignals::sig69, qt_noop); QVERIFY(o.isSignalConnected(sig00)); QVERIFY(o.isSignalConnected(sig01)); QVERIFY(o.isSignalConnected(sig69)); QVERIFY(QObject::disconnect(&o, &ManySignals::sig69, 0, 0)); QVERIFY(o.isSignalConnected(sig00)); QVERIFY(o.isSignalConnected(sig01)); QVERIFY(!o.isSignalConnected(sig69)); QVERIFY(QObject::disconnect(&o, &ManySignals::sig00, 0, 0)); QVERIFY(!o.isSignalConnected(sig00)); QVERIFY(o.isSignalConnected(sig01)); QVERIFY(!o.isSignalConnected(sig69)); QObject::connect(&o, &ManySignals::sig69, qt_noop); QVERIFY(!o.isSignalConnected(sig00)); QVERIFY(o.isSignalConnected(sig01)); QVERIFY(o.isSignalConnected(sig69)); QVERIFY(QObject::disconnect(&o, &ManySignals::sig01, 0, 0)); QVERIFY(!o.isSignalConnected(sig00)); QVERIFY(!o.isSignalConnected(sig01)); QVERIFY(o.isSignalConnected(sig69)); } void tst_QObject::qMetaObjectConnect() { ReceiverObject r1; ReceiverObject r2; int slot1Index, slot2Index, slot3Index; { SenderObject s; r1.reset(); r2.reset(); ReceiverObject::sequence = 0; int signal1Index = s.metaObject()->indexOfSignal("signal1()"); int signal3Index = s.metaObject()->indexOfSignal("signal3()"); slot1Index = r1.metaObject()->indexOfSlot("slot1()"); slot2Index = r1.metaObject()->indexOfSlot("slot2()"); slot3Index = r1.metaObject()->indexOfSlot("slot3()"); QVERIFY(slot1Index > 0); QVERIFY(slot2Index > 0); QVERIFY(slot3Index > 0); QVERIFY(QMetaObject::connect(&s, signal1Index, &r1, slot1Index)); QVERIFY(QMetaObject::connect(&s, signal3Index, &r2, slot3Index)); QVERIFY(QMetaObject::connect(&s, -1, &r2, slot2Index)); QCOMPARE(r1.count_slot1, 0); QCOMPARE(r1.count_slot2, 0); QCOMPARE(r1.count_slot3, 0); QCOMPARE(r2.count_slot1, 0); QCOMPARE(r2.count_slot2, 0); QCOMPARE(r2.count_slot3, 0); s.emitSignal1(); QCOMPARE(r1.count_slot1, 1); QCOMPARE(r1.count_slot2, 0); QCOMPARE(r1.count_slot3, 0); QCOMPARE(r2.count_slot1, 0); QCOMPARE(r2.count_slot2, 1); QCOMPARE(r2.count_slot3, 0); s.emitSignal2(); s.emitSignal3(); s.emitSignal4(); QCOMPARE(r1.count_slot1, 1); QCOMPARE(r1.count_slot2, 0); QCOMPARE(r1.count_slot3, 0); QCOMPARE(r2.count_slot1, 0); QCOMPARE(r2.count_slot2, 4); QCOMPARE(r2.count_slot3, 1); QVERIFY(QMetaObject::disconnect(&s, signal1Index, &r1, slot1Index)); QVERIFY(QMetaObject::disconnect(&s, signal3Index, &r2, slot3Index)); QVERIFY(QMetaObject::disconnect(&s, -1, &r2, slot2Index)); s.emitSignal1(); s.emitSignal2(); s.emitSignal3(); s.emitSignal4(); QCOMPARE(r1.count_slot1, 1); QCOMPARE(r1.count_slot2, 0); QCOMPARE(r1.count_slot3, 0); QCOMPARE(r2.count_slot1, 0); QCOMPARE(r2.count_slot2, 4); QCOMPARE(r2.count_slot3, 1); //some "dynamic" signal QVERIFY(QMetaObject::connect(&s, s.metaObject()->methodOffset() + 20, &r1, slot3Index)); QVERIFY(QMetaObject::connect(&s, s.metaObject()->methodOffset() + 35, &r2, slot1Index)); QVERIFY(QMetaObject::connect(&s, -1, &r1, slot2Index)); r1.reset(); r2.reset(); void *args[] = { 0 , 0 }; QMetaObject::activate(&s, s.metaObject()->methodOffset() + 20, args); QMetaObject::activate(&s, s.metaObject()->methodOffset() + 48, args); QCOMPARE(r1.count_slot1, 0); QCOMPARE(r1.count_slot2, 2); QCOMPARE(r1.count_slot3, 1); QCOMPARE(r2.count_slot1, 0); QCOMPARE(r2.count_slot2, 0); QCOMPARE(r2.count_slot3, 0); QMetaObject::activate(&s, s.metaObject()->methodOffset() + 35, args); s.emitSignal1(); s.emitSignal2(); QCOMPARE(r1.count_slot1, 0); QCOMPARE(r1.count_slot2, 5); QCOMPARE(r1.count_slot3, 1); QCOMPARE(r2.count_slot1, 1); QCOMPARE(r2.count_slot2, 0); QCOMPARE(r2.count_slot3, 0); } r1.reset(); r2.reset(); #define SIGNAL_INDEX(S) obj1.metaObject()->indexOfSignal(QMetaObject::normalizedSignature(#S)) OverloadObject obj1; QObject obj2, obj3; #if 0 // Verdigris does not support optional arguments QMetaObject::connect(&obj1, SIGNAL_INDEX(sig(int)) , &r1, slot1Index); QMetaObject::connect(&obj1, SIGNAL_INDEX(sig(QObject *, QObject *, QObject *)) , &r2, slot1Index); #else QMetaObject::connect(&obj1, SIGNAL_INDEX(sig(int,int)) , &r1, slot1Index); QMetaObject::connect(&obj1, SIGNAL_INDEX(sig(QObject *, QObject *, QObject *, QObject *)) , &r2, slot1Index); #endif QMetaObject::connect(&obj1, SIGNAL_INDEX(sig(QObject *, QObject *, QObject *, QObject *)) , &r1, slot2Index); #if 0 // Verdigris does not support optional arguments QMetaObject::connect(&obj1, SIGNAL_INDEX(sig(QObject *)) , &r2, slot2Index); #else QMetaObject::connect(&obj1, SIGNAL_INDEX(sig(QObject *, OverloadObject *,QObject *,QObject *)) , &r2, slot2Index); #endif QMetaObject::connect(&obj1, SIGNAL_INDEX(sig(int, int)) , &r1, slot3Index); emit obj1.sig(0.5); //connected to nothing emit obj1.sig(1, 'a'); //connected to nothing QCOMPARE(r1.count_slot1, 0); QCOMPARE(r1.count_slot2, 0); QCOMPARE(r1.count_slot3, 0); QCOMPARE(r2.count_slot1, 0); QCOMPARE(r2.count_slot2, 0); QCOMPARE(r2.count_slot3, 0); emit obj1.sig(1); //this signal is connected emit obj1.sig(&obj2); QCOMPARE(r1.count_slot1, 1); QCOMPARE(r1.count_slot2, 0); QCOMPARE(r1.count_slot3, 1); QCOMPARE(r2.count_slot1, 0); QCOMPARE(r2.count_slot2, 1); QCOMPARE(r2.count_slot3, 0); emit obj1.sig(&obj2, &obj3); //this signal is connected QCOMPARE(r1.count_slot1, 1); QCOMPARE(r1.count_slot2, 1); QCOMPARE(r1.count_slot3, 1); QCOMPARE(r2.count_slot1, 1); QCOMPARE(r2.count_slot2, 1); QCOMPARE(r2.count_slot3, 0); } void tst_QObject::qMetaObjectDisconnectOne() { SenderObject s; ReceiverObject r1; int signal1Index = s.metaObject()->indexOfSignal("signal1()"); int signal3Index = s.metaObject()->indexOfSignal("signal3()"); int slot1Index = r1.metaObject()->indexOfSlot("slot1()"); int slot2Index = r1.metaObject()->indexOfSlot("slot2()"); QVERIFY(signal1Index > 0); QVERIFY(signal3Index > 0); QVERIFY(slot1Index > 0); QVERIFY(slot2Index > 0); QVERIFY(QMetaObject::connect(&s, signal1Index, &r1, slot1Index)); QVERIFY(QMetaObject::connect(&s, signal3Index, &r1, slot2Index)); QVERIFY(QMetaObject::connect(&s, signal3Index, &r1, slot2Index)); QVERIFY(QMetaObject::connect(&s, signal3Index, &r1, slot2Index)); r1.reset(); QCOMPARE(r1.count_slot1, 0); QCOMPARE(r1.count_slot2, 0); s.emitSignal1(); QCOMPARE(r1.count_slot1, 1); QCOMPARE(r1.count_slot2, 0); s.emitSignal3(); QCOMPARE(r1.count_slot1, 1); QCOMPARE(r1.count_slot2, 3); r1.reset(); QVERIFY(QMetaObject::disconnectOne(&s, signal1Index, &r1, slot1Index)); QVERIFY(QMetaObject::disconnectOne(&s, signal3Index, &r1, slot2Index)); s.emitSignal1(); QCOMPARE(r1.count_slot1, 0); QCOMPARE(r1.count_slot2, 0); s.emitSignal3(); QCOMPARE(r1.count_slot1, 0); QCOMPARE(r1.count_slot2, 2); r1.reset(); QVERIFY(!QMetaObject::disconnectOne(&s, signal1Index, &r1, slot1Index)); QVERIFY( QMetaObject::disconnectOne(&s, signal3Index, &r1, slot2Index)); s.emitSignal1(); QCOMPARE(r1.count_slot1, 0); QCOMPARE(r1.count_slot2, 0); s.emitSignal3(); QCOMPARE(r1.count_slot1, 0); QCOMPARE(r1.count_slot2, 1); r1.reset(); QVERIFY(!QMetaObject::disconnectOne(&s, signal1Index, &r1, slot1Index)); QVERIFY( QMetaObject::disconnectOne(&s, signal3Index, &r1, slot2Index)); s.emitSignal1(); QCOMPARE(r1.count_slot1, 0); QCOMPARE(r1.count_slot2, 0); s.emitSignal3(); QCOMPARE(r1.count_slot1, 0); QCOMPARE(r1.count_slot2, 0); } class ConfusingObject : public SenderObject { W_OBJECT(ConfusingObject) public slots: void signal1() { s++; } W_SLOT(signal1) signals: void aPublicSlot() W_SIGNAL(aPublicSlot) public: int s; ConfusingObject() : s(0) {} friend class tst_QObject; }; void tst_QObject::sameName() { ConfusingObject c1, c2; QVERIFY(connect(&c1, SIGNAL(signal1()), &c1, SLOT(signal1()))); c1.emitSignal1(); QCOMPARE(c1.s, 1); QVERIFY(connect(&c2, SIGNAL(signal1()), &c1, SIGNAL(signal1()))); c2.emitSignal1(); QCOMPARE(c1.s, 2); #ifndef QT_NO_DEBUG QTest::ignoreMessage(QtWarningMsg, "QMetaObject::indexOfSignal: signal aPublicSlot() from SenderObject redefined in ConfusingObject"); #endif QVERIFY(connect(&c2, SIGNAL(aPublicSlot()), &c1, SLOT(signal1()))); c2.aPublicSlot(); QCOMPARE(c2.aPublicSlotCalled, 0); QCOMPARE(c1.aPublicSlotCalled, 0); QCOMPARE(c1.s, 3); #ifndef QT_NO_DEBUG QTest::ignoreMessage(QtWarningMsg, "QMetaObject::indexOfSignal: signal aPublicSlot() from SenderObject redefined in ConfusingObject"); #endif QVERIFY(connect(&c2, SIGNAL(aPublicSlot()), &c1, SLOT(aPublicSlot()))); c2.aPublicSlot(); QCOMPARE(c2.aPublicSlotCalled, 0); QCOMPARE(c1.aPublicSlotCalled, 1); QCOMPARE(c1.s, 4); } void tst_QObject::connectByMetaMethods() { SenderObject s; ReceiverObject r; const QMetaObject *smeta = s.metaObject(); const QMetaObject *rmeta = r.metaObject(); int sigIndx = smeta->indexOfSignal(QMetaObject::normalizedSignature("signal1()")); int slotIndx = rmeta->indexOfSlot(QMetaObject::normalizedSignature("slot1()")); QVERIFY( sigIndx != -1 ); QVERIFY( slotIndx != -1 ); QMetaMethod signal = smeta->method(sigIndx); QMetaMethod slot = rmeta->method(slotIndx); QVERIFY(connect(&s,signal, &r,slot)); QVERIFY(!r.called(1)); s.emitSignal1(); QVERIFY(r.called(1)); } void tst_QObject::connectByMetaMethodSlotInsteadOfSignal() { SenderObject s; ReceiverObject r; const QMetaObject *smeta = s.metaObject(); const QMetaObject *rmeta = r.metaObject(); int badIndx = smeta->indexOfSlot(QMetaObject::normalizedSignature("aPublicSlot()")); int slotIndx = rmeta->indexOfSlot(QMetaObject::normalizedSignature("slot1()")); QVERIFY( badIndx != -1 ); QVERIFY( slotIndx != -1 ); QMetaMethod badMethod = smeta->method(badIndx); QMetaMethod slot = rmeta->method(slotIndx); QTest::ignoreMessage(QtWarningMsg,"QObject::connect: Cannot connect SenderObject::aPublicSlot() to ReceiverObject::slot1()"); QVERIFY(!connect(&s,badMethod, &r,slot)); } class Constructable: public QObject { W_OBJECT(Constructable) public: Constructable(){} W_CONSTRUCTOR() }; void tst_QObject::connectConstructorByMetaMethod() { Constructable sc; Constructable rc; SenderObject s; ReceiverObject r; const QMetaObject cmeta = Constructable::staticMetaObject; const QMetaObject *smeta = s.metaObject(); const QMetaObject *rmeta = r.metaObject(); int constructorIndx = cmeta.indexOfConstructor(QMetaObject::normalizedSignature("Constructable()")); int sigIndx = smeta->indexOfSignal(QMetaObject::normalizedSignature("signal1()")); int slotIndx = rmeta->indexOfSlot(QMetaObject::normalizedSignature("slot1()")); QVERIFY( constructorIndx != -1 ); QVERIFY( sigIndx != -1 ); QVERIFY( slotIndx != -1 ); QMetaMethod constructor = cmeta.constructor(constructorIndx); QMetaMethod signal = smeta->method(sigIndx); QMetaMethod slot = rmeta->method(slotIndx); QTest::ignoreMessage(QtWarningMsg,"QObject::connect: Cannot connect Constructable::Constructable() to ReceiverObject::slot1()"); QVERIFY(!connect(&sc,constructor, &r,slot)); QTest::ignoreMessage(QtWarningMsg,"QObject::connect: Cannot connect SenderObject::signal1() to Constructable::Constructable()"); QVERIFY(!connect(&s,signal, &rc,constructor)); QTest::ignoreMessage(QtWarningMsg,"QObject::connect: Cannot connect Constructable::Constructable() to Constructable::Constructable()"); QVERIFY(!connect(&sc,constructor, &rc,constructor)); } void tst_QObject::disconnectByMetaMethod() { SenderObject s; ReceiverObject r1; ReceiverObject r2; QMetaMethod signal1 = s.metaObject()->method(s.metaObject()->indexOfMethod("signal1()")); QMetaMethod signal2 = s.metaObject()->method(s.metaObject()->indexOfMethod("signal2()")); QMetaMethod signal3 = s.metaObject()->method(s.metaObject()->indexOfMethod("signal3()")); QMetaMethod slot1 = r1.metaObject()->method(r1.metaObject()->indexOfMethod("slot1()")); QMetaMethod slot2 = r1.metaObject()->method(r1.metaObject()->indexOfMethod("slot2()")); QMetaMethod slot3 = r1.metaObject()->method(r1.metaObject()->indexOfMethod("slot3()")); QMetaMethod slot4 = r1.metaObject()->method(r1.metaObject()->indexOfMethod("slot4()")); connect(&s, signal1, &r1, slot1); s.emitSignal1(); QVERIFY(r1.called(1)); r1.reset(); // usual disconnect with all parameters given bool ret = QObject::disconnect(&s, signal1, &r1, slot1); s.emitSignal1(); QVERIFY(!r1.called(1)); r1.reset(); QVERIFY(ret); ret = QObject::disconnect(&s, signal1, &r1, slot1); QVERIFY(!ret); r1.reset(); connect(&s, signal1, &r1, slot1); connect(&s, signal1, &r1, slot2); connect(&s, signal1, &r1, slot3); connect(&s, signal2, &r1, slot4); // disconnect s's signal1() from all slots of r1 QObject::disconnect(&s, signal1, &r1, QMetaMethod()); s.emitSignal1(); s.emitSignal2(); QVERIFY(!r1.called(1)); QVERIFY(!r1.called(2)); QVERIFY(!r1.called(3)); QVERIFY(r1.called(4)); r1.reset(); // make sure all is disconnected again QObject::disconnect(&s, 0, &r1, 0); connect(&s, signal1, &r1, slot1); connect(&s, signal1, &r2, slot1); connect(&s, signal2, &r1, slot2); connect(&s, signal2, &r2, slot2); connect(&s, signal3, &r1, slot3); connect(&s, signal3, &r2, slot3); // disconnect signal1() from all receivers QObject::disconnect(&s, signal1, 0, QMetaMethod()); s.emitSignal1(); s.emitSignal2(); s.emitSignal3(); QVERIFY(!r1.called(1)); QVERIFY(!r2.called(1)); QVERIFY(r1.called(2)); QVERIFY(r2.called(2)); QVERIFY(r1.called(2)); QVERIFY(r2.called(2)); r1.reset(); r2.reset(); // disconnect all signals of s from all receivers QObject::disconnect(&s, 0, 0, 0); connect(&s, signal1, &r1, slot1); connect(&s, signal1, &r2, slot1); // disconnect all signals from slot1 of r1 QObject::disconnect(&s, QMetaMethod(), &r1, slot1); s.emitSignal1(); QVERIFY(!r1.called(1)); QVERIFY(r2.called(1)); } void tst_QObject::disconnectNotSignalMetaMethod() { SenderObject s; ReceiverObject r; connect(&s, SIGNAL(signal1()), &r, SLOT(slot1())); QMetaMethod slot = s.metaObject()->method( s.metaObject()->indexOfMethod("aPublicSlot()")); QTest::ignoreMessage(QtWarningMsg,"QObject::disconnect: Attempt to unbind non-signal SenderObject::aPublicSlot()"); QVERIFY(!QObject::disconnect(&s, slot, &r, QMetaMethod())); } class ThreadAffinityThread : public QThread { public: SenderObject *sender; ThreadAffinityThread(SenderObject *sender) : sender(sender) { } void run() override { sender->emitSignal1(); } }; void tst_QObject::autoConnectionBehavior() { SenderObject *sender = new SenderObject; ReceiverObject *receiver = new ReceiverObject; connect(sender, SIGNAL(signal1()), receiver, SLOT(slot1())); // at emit, currentThread == sender->thread(), currentThread == receiver->thread(), sender->thread() == receiver->thread() QVERIFY(!receiver->called(1)); sender->emitSignal1(); QVERIFY(receiver->called(1)); receiver->reset(); // at emit, currentThread != sender->thread(), currentThread != receiver->thread(), sender->thread() == receiver->thread() ThreadAffinityThread emitThread1(sender); QVERIFY(!receiver->called(1)); emitThread1.start(); QVERIFY(emitThread1.wait(30000)); QVERIFY(!receiver->called(1)); QCoreApplication::sendPostedEvents(receiver, QEvent::MetaCall); QVERIFY(receiver->called(1)); receiver->reset(); // at emit, currentThread == sender->thread(), currentThread != receiver->thread(), sender->thread() != receiver->thread() sender->moveToThread(&emitThread1); QVERIFY(!receiver->called(1)); emitThread1.start(); QVERIFY(emitThread1.wait(30000)); QVERIFY(!receiver->called(1)); QCoreApplication::sendPostedEvents(receiver, QEvent::MetaCall); QVERIFY(receiver->called(1)); receiver->reset(); // at emit, currentThread != sender->thread(), currentThread == receiver->thread(), sender->thread() != receiver->thread() QVERIFY(!receiver->called(1)); sender->emitSignal1(); QVERIFY(receiver->called(1)); receiver->reset(); // at emit, currentThread != sender->thread(), currentThread != receiver->thread(), sender->thread() != receiver->thread() ThreadAffinityThread emitThread2(sender); QThread receiverThread; QTimer *timer = new QTimer; timer->setSingleShot(true); timer->setInterval(100); connect(&receiverThread, SIGNAL(started()), timer, SLOT(start())); connect(timer, SIGNAL(timeout()), &receiverThread, SLOT(quit()), Qt::DirectConnection); connect(&receiverThread, SIGNAL(finished()), timer, SLOT(deleteLater())); timer->moveToThread(&receiverThread); receiver->moveToThread(&receiverThread); QVERIFY(!receiver->called(1)); emitThread2.start(); QVERIFY(emitThread2.wait(30000)); QVERIFY(!receiver->called(1)); receiverThread.start(); QVERIFY(receiverThread.wait(30000)); QVERIFY(receiver->called(1)); receiver->reset(); delete sender; delete receiver; } class BaseDestroyed : public QObject { W_OBJECT(BaseDestroyed) QList fooList; bool destroyed; public: BaseDestroyed() : destroyed(false) { fooList << "a" << "b"; } ~BaseDestroyed() { QVERIFY(!destroyed); destroyed = true; } public slots: void slotUseList() { QVERIFY(!destroyed); fooList << "c" << "d"; } W_SLOT(slotUseList) }; static void processEvents() { qApp->processEvents(); } void tst_QObject::baseDestroyed() { { BaseDestroyed d; connect(&d, SIGNAL(destroyed()), &d, SLOT(slotUseList())); //When d goes out of scope, slotUseList should not be called as the BaseDestroyed has // already been destroyed while ~QObject emit destroyed } { BaseDestroyed d; connect(&d, &QObject::destroyed, processEvents); QMetaObject::invokeMethod(&d, "slotUseList", Qt::QueuedConnection); //the destructor will call processEvents, that should not call the slotUseList } } void tst_QObject::pointerConnect() { SenderObject s; ReceiverObject r1; ReceiverObject r2; r1.reset(); r2.reset(); ReceiverObject::sequence = 0; QTimer timer; QVERIFY(connect(&s, &SenderObject::signal1 , &r1, &ReceiverObject::slot1)); QVERIFY(connect(&s, &SenderObject::signal1 , &r2, &ReceiverObject::slot1)); QVERIFY(connect(&s, &SenderObject::signal1 , &r1, &ReceiverObject::slot3)); QVERIFY(connect(&s, &SenderObject::signal3 , &r1, &ReceiverObject::slot3)); QVERIFY2(connect(&timer, &QTimer::timeout, &r1, &ReceiverObject::deleteLater), "Signal connection failed most likely due to failing comparison of pointers to member " "functions caused by problems with -reduce-relocations on this platform."); s.emitSignal1(); s.emitSignal2(); s.emitSignal3(); s.emitSignal4(); QCOMPARE(r1.count_slot1, 1); QCOMPARE(r1.count_slot2, 0); QCOMPARE(r1.count_slot3, 2); QCOMPARE(r1.count_slot4, 0); QCOMPARE(r2.count_slot1, 1); QCOMPARE(r2.count_slot2, 0); QCOMPARE(r2.count_slot3, 0); QCOMPARE(r2.count_slot4, 0); QCOMPARE(r1.sequence_slot1, 1); QCOMPARE(r2.sequence_slot1, 2); QCOMPARE(r1.sequence_slot3, 4); r1.reset(); r2.reset(); ReceiverObject::sequence = 0; QVERIFY(connect(&s, &SenderObject::signal4, &r1, &ReceiverObject::slot4)); QVERIFY(connect(&s, &SenderObject::signal4, &r2, &ReceiverObject::slot4)); QVERIFY(connect(&s, &SenderObject::signal1, &r2, &ReceiverObject::slot4)); s.emitSignal4(); QCOMPARE(r1.count_slot4, 1); QCOMPARE(r2.count_slot4, 1); QCOMPARE(r1.sequence_slot4, 1); QCOMPARE(r2.sequence_slot4, 2); r1.reset(); r2.reset(); ReceiverObject::sequence = 0; connect(&s, &SenderObject::signal4 , &r1, &ReceiverObject::slot4); s.emitSignal4(); QCOMPARE(r1.count_slot4, 2); QCOMPARE(r2.count_slot4, 1); QCOMPARE(r1.sequence_slot4, 3); QCOMPARE(r2.sequence_slot4, 2); QMetaObject::Connection con; QVERIFY(!con); QVERIFY(!QObject::disconnect(con)); //connect a slot to a signal (== error) QTest::ignoreMessage(QtWarningMsg, "QObject::connect: signal not found in ReceiverObject"); con = connect(&r1, &ReceiverObject::slot4 , &s, &SenderObject::signal4); QVERIFY(!con); QVERIFY(!QObject::disconnect(con)); } void tst_QObject::pointerDisconnect() { SenderObject s; ReceiverObject r1; ReceiverObject r2; connect(&s, &SenderObject::signal1, &r1, &ReceiverObject::slot1); connect(&s, &SenderObject::signal2, &r1, &ReceiverObject::slot2); connect(&s, &SenderObject::signal3, &r1, &ReceiverObject::slot3); connect(&s, &SenderObject::signal4, &r1, &ReceiverObject::slot4); s.emitSignal1(); s.emitSignal2(); s.emitSignal3(); s.emitSignal4(); QVERIFY(r1.called(1)); QVERIFY(r1.called(2)); QVERIFY(r1.called(3)); QVERIFY(r1.called(4)); r1.reset(); // usual disconnect with all parameters given bool ret = QObject::disconnect(&s, &SenderObject::signal1, &r1, &ReceiverObject::slot1); s.emitSignal1(); QVERIFY(!r1.called(1)); r1.reset(); QVERIFY(ret); ret = QObject::disconnect(&s, &SenderObject::signal1, &r1, &ReceiverObject::slot1); QVERIFY(!ret); // disconnect all signals from s from all slots from r1 QObject::disconnect(&s, 0, &r1, 0); s.emitSignal2(); s.emitSignal3(); s.emitSignal4(); QVERIFY(!r1.called(2)); QVERIFY(!r1.called(3)); QVERIFY(!r1.called(4)); r1.reset(); connect(&s, &SenderObject::signal1, &r1, &ReceiverObject::slot1); connect(&s, &SenderObject::signal1, &r1, &ReceiverObject::slot2); connect(&s, &SenderObject::signal1, &r1, &ReceiverObject::slot3); connect(&s, &SenderObject::signal2, &r1, &ReceiverObject::slot4); // disconnect s's signal1() from all slots of r1 QObject::disconnect(&s, &SenderObject::signal1, &r1, 0); s.emitSignal1(); s.emitSignal2(); QVERIFY(!r1.called(1)); QVERIFY(!r1.called(2)); QVERIFY(!r1.called(3)); QVERIFY(r1.called(4)); r1.reset(); // make sure all is disconnected again QObject::disconnect(&s, 0, &r1, 0); connect(&s, &SenderObject::signal1, &r1, &ReceiverObject::slot1); connect(&s, &SenderObject::signal1, &r2, &ReceiverObject::slot1); connect(&s, &SenderObject::signal2, &r1, &ReceiverObject::slot2); connect(&s, &SenderObject::signal2, &r2, &ReceiverObject::slot2); connect(&s, &SenderObject::signal3, &r1, &ReceiverObject::slot3); connect(&s, &SenderObject::signal3, &r2, &ReceiverObject::slot3); // disconnect signal1() from all receivers QObject::disconnect(&s, &SenderObject::signal1, 0, 0); s.emitSignal1(); s.emitSignal2(); s.emitSignal3(); QVERIFY(!r1.called(1)); QVERIFY(!r2.called(1)); QVERIFY(r1.called(2)); QVERIFY(r2.called(2)); QVERIFY(r1.called(2)); QVERIFY(r2.called(2)); r1.reset(); r2.reset(); // disconnect all signals of s from all receivers QObject::disconnect(&s, 0, 0, 0); QVERIFY(!r1.called(2)); QVERIFY(!r2.called(2)); QVERIFY(!r1.called(2)); QVERIFY(!r2.called(2)); } void tst_QObject::emitInDefinedOrderPointer() { SenderObject sender; ReceiverObject receiver1, receiver2, receiver3, receiver4; QMetaObject::Connection h0 = connect(&sender, &SenderObject::signal1, &receiver1, &SequenceObject::slot1); QMetaObject::Connection h1 = connect(&sender, &SenderObject::signal1, &receiver2, &SequenceObject::slot1); QVERIFY(h0); QVERIFY(h1); connect(&sender, &SenderObject::signal1, &receiver3, &SequenceObject::slot1); connect(&sender, &SenderObject::signal1, &receiver4, &SequenceObject::slot1); connect(&sender, &SenderObject::signal1, &receiver1, &SequenceObject::slot2); connect(&sender, &SenderObject::signal1, &receiver2, &SequenceObject::slot2); connect(&sender, &SenderObject::signal1, &receiver3, &SequenceObject::slot2); connect(&sender, &SenderObject::signal1, &receiver4, &SequenceObject::slot2); int sequence; ReceiverObject::sequence = sequence = 0; sender.emitSignal1(); QCOMPARE(receiver1.sequence_slot1, ++sequence); QCOMPARE(receiver2.sequence_slot1, ++sequence); QCOMPARE(receiver3.sequence_slot1, ++sequence); QCOMPARE(receiver4.sequence_slot1, ++sequence); QCOMPARE(receiver1.sequence_slot2, ++sequence); QCOMPARE(receiver2.sequence_slot2, ++sequence); QCOMPARE(receiver3.sequence_slot2, ++sequence); QCOMPARE(receiver4.sequence_slot2, ++sequence); QObject::disconnect(h1); h1 = connect(&sender, &SenderObject::signal1, &receiver2, &SequenceObject::slot1); ReceiverObject::sequence = sequence = 0; sender.emitSignal1(); QCOMPARE(receiver1.sequence_slot1, ++sequence); QCOMPARE(receiver3.sequence_slot1, ++sequence); QCOMPARE(receiver4.sequence_slot1, ++sequence); QCOMPARE(receiver1.sequence_slot2, ++sequence); QCOMPARE(receiver2.sequence_slot2, ++sequence); QCOMPARE(receiver3.sequence_slot2, ++sequence); QCOMPARE(receiver4.sequence_slot2, ++sequence); QCOMPARE(receiver2.sequence_slot1, ++sequence); QObject::disconnect(h0); h0 = connect(&sender, &SenderObject::signal1, &receiver1, &SequenceObject::slot1); ReceiverObject::sequence = sequence = 0; sender.emitSignal1(); QCOMPARE(receiver3.sequence_slot1, ++sequence); QCOMPARE(receiver4.sequence_slot1, ++sequence); QCOMPARE(receiver1.sequence_slot2, ++sequence); QCOMPARE(receiver2.sequence_slot2, ++sequence); QCOMPARE(receiver3.sequence_slot2, ++sequence); QCOMPARE(receiver4.sequence_slot2, ++sequence); QCOMPARE(receiver2.sequence_slot1, ++sequence); QCOMPARE(receiver1.sequence_slot1, ++sequence); QVERIFY(QObject::disconnect(h0)); QVERIFY(!QObject::disconnect(h0)); } void tst_QObject::customTypesPointer() { CustomType t0; CustomType t1(1, 2, 3); CustomType t2(2, 3, 4); { QCustomTypeChecker checker; QCOMPARE(instanceCount, 4); connect(&checker, &QCustomTypeChecker::signal1, &checker, &QCustomTypeChecker::slot1, Qt::DirectConnection); QCOMPARE(checker.received.value(), 0); checker.doEmit(t1); QCOMPARE(checker.received.value(), t1.value()); checker.received = t0; checker.disconnect(); int idx = qRegisterMetaType("CustomType"); QCOMPARE(QMetaType::type("CustomType"), idx); connect(&checker, &QCustomTypeChecker::signal1, &checker, &QCustomTypeChecker::slot1, Qt::QueuedConnection); QCOMPARE(instanceCount, 4); checker.doEmit(t2); QCOMPARE(instanceCount, 5); QCOMPARE(checker.received.value(), t0.value()); QCoreApplication::processEvents(); QCOMPARE(checker.received.value(), t2.value()); QCOMPARE(instanceCount, 4); QVERIFY(QMetaType::isRegistered(idx)); QCOMPARE(qRegisterMetaType("CustomType"), idx); QCOMPARE(QMetaType::type("CustomType"), idx); QVERIFY(QMetaType::isRegistered(idx)); // Test auto registered type (QList) QList list; QCOMPARE(instanceCount, 4); list.append(t1); QCOMPARE(instanceCount, 5); QVERIFY(connect(&checker, &QCustomTypeChecker::signal2, &checker, &QCustomTypeChecker::slot2, Qt::QueuedConnection)); emit checker.signal2(list); QCOMPARE(instanceCount, 5); //because the list is implicitly shared. list.clear(); QCOMPARE(instanceCount, 5); QCoreApplication::processEvents(); QCOMPARE(checker.received.value(), t1.value()); QCOMPARE(instanceCount, 4); } QCOMPARE(instanceCount, 3); } void tst_QObject::connectCxx0x() { SenderObject s; ReceiverObject r1; QObject::connect(&s, &SenderObject::signal1, &r1, &ReceiverObject::slot1); QObject::connect(&s, &SenderObject::signal3, &r1, &ReceiverObject::slot2); QObject::connect(&s, &SenderObject::signal3, &r1, &ReceiverObject::slot2); QObject::connect(&s, &SenderObject::signal3, &r1, &ReceiverObject::slot2); r1.reset(); QCOMPARE(r1.count_slot1, 0); QCOMPARE(r1.count_slot2, 0); s.emitSignal1(); QCOMPARE(r1.count_slot1, 1); QCOMPARE(r1.count_slot2, 0); s.emitSignal3(); QCOMPARE(r1.count_slot1, 1); QCOMPARE(r1.count_slot2, 3); // connect signal to signal QObject::connect(&s, &SenderObject::signal2, &s, &SenderObject::signal1); r1.reset(); s.emitSignal2(); QCOMPARE(r1.count_slot1, 1); } int receivedCount; void receiverFunction() { ++receivedCount; } void tst_QObject::connectToStaticCxx0x() { SenderObject *s = new SenderObject; void (*receiver)() = receiverFunction; QObject::connect(s, &SenderObject::signal1, receiver); receivedCount = 0; s->emitSignal1(); QCOMPARE(receivedCount, 1); QObject::connect(s, &SenderObject::signal1, receiver); receivedCount = 0; s->emitSignal1(); QCOMPARE(receivedCount, 2); delete s; } class LotsOfSignalsAndSlots: public QObject { W_OBJECT(LotsOfSignalsAndSlots) typedef void (*fptr)(); public slots: void slot_v() {} W_SLOT(slot_v) void slot_v_noexcept() Q_DECL_NOTHROW {} W_SLOT(slot_v_noexcept) void slot_vi(int) {} W_SLOT(slot_vi) void slot_vi_noexcept() Q_DECL_NOTHROW {} W_SLOT(slot_vi_noexcept) void slot_vii(int, int) {} W_SLOT(slot_vii) void slot_viii(int, int, int) {} W_SLOT(slot_viii) int slot_i() { return 0; } W_SLOT(slot_i) int slot_i_noexcept() Q_DECL_NOTHROW { return 0; } W_SLOT(slot_i_noexcept) int slot_ii(int) { return 0; } W_SLOT(slot_ii) int slot_iii(int, int) { return 0; } W_SLOT(slot_iii) int slot_iiii(int, int, int) { return 0; } W_SLOT(slot_iiii) void slot_vRi(int &) {} W_SLOT(slot_vRi) void slot_vs(short) {} W_SLOT(slot_vs) void slot_vRs(short&) {} W_SLOT(slot_vRs) /* #ifdef Q_COMPILER_RVALUE_REFS void slot_vOi(int &&) {} W_SLOT(slot_vOi) void slot_vOs(short &&) {} W_SLOT(slot_vOs) #endif*/ void slot_vPFvvE(fptr) {} W_SLOT(slot_vPFvvE,(fptr)) void const_slot_v() const {} W_SLOT(const_slot_v); void const_slot_v_noexcept() const Q_DECL_NOTHROW {} W_SLOT(const_slot_v_noexcept); void const_slot_vi(int) const {} W_SLOT(const_slot_vi); void const_slot_vi_noexcept(int) Q_DECL_NOTHROW {} W_SLOT(const_slot_vi_noexcept); static void static_slot_v() {} W_SLOT(static_slot_v) static void static_slot_v_noexcept() Q_DECL_NOTHROW {} W_SLOT(static_slot_v_noexcept) static void static_slot_vi(int) {} W_SLOT(static_slot_vi) static void static_slot_vi_noexcept(int) Q_DECL_NOTHROW {} W_SLOT(static_slot_vi_noexcept) static void static_slot_vii(int, int) {} W_SLOT(static_slot_vii) static void static_slot_viii(int, int, int) {} W_SLOT(static_slot_viii) static int static_slot_i() { return 0; } W_SLOT(static_slot_i) static int static_slot_i_noexcept() Q_DECL_NOTHROW { return 0; } W_SLOT(static_slot_i_noexcept) static int static_slot_ii(int) { return 0; } W_SLOT(static_slot_ii) static int static_slot_iii(int, int) { return 0; } W_SLOT(static_slot_iii) static int static_slot_iiii(int, int, int) { return 0; } W_SLOT(static_slot_iiii) static void static_slot_vRi(int &) {} W_SLOT(static_slot_vRi) static void static_slot_vs(short) {} W_SLOT(static_slot_vs) static void static_slot_vRs(short&) {} W_SLOT(static_slot_vRs) /* #if defined(Q_COMPILER_RVALUE_REFS) || defined(QT_ENABLE_CXX0X) static void static_slot_vOi(int &&) {} W_SLOT(static_slot_vOi) static void static_slot_vOs(short &&) {} W_SLOT(static_slot_vOs) #endif*/ static void static_slot_vPFvvE(fptr) {} W_SLOT(static_slot_vPFvvE,(fptr)) void slot_vcRQObject(const QObject &) {} W_SLOT(slot_vcRQObject) void slot_vRQObject(QObject &) {} W_SLOT(slot_vRQObject) signals: void signal_v() W_SIGNAL(signal_v) void signal_vi(int a) W_SIGNAL(signal_vi, a) void signal_vii(int a, int b) W_SIGNAL(signal_vii, a,b) void signal_viii(int a, int b, int c) W_SIGNAL(signal_viii, a,b,c) void signal_vRi(int &a) W_SIGNAL(signal_vRi, a) void signal_vs(short a) W_SIGNAL(signal_vs, a) void signal_vRs(short &a) W_SIGNAL(signal_vRs, a) /* #if defined(Q_COMPILER_RVALUE_REFS) || defined(QT_ENABLE_CXX0X) void signal_vOi(int &&) W_SIGNAL() void signal_vOs(short &&) W_SIGNAL() #endif*/ void signal_vPFvvE(fptr a) W_SIGNAL(signal_vPFvvE,(fptr), a) void const_signal_v() const W_SIGNAL(const_signal_v) void const_signal_vi(int a) const W_SIGNAL(const_signal_vi, a) void signal_vcRQObject(const QObject &a) W_SIGNAL(signal_vcRQObject, a) void signal_vRQObject(QObject &a) W_SIGNAL(signal_vRQObject, a) void signal(short&a, short b, long long c, short d) W_SIGNAL(signal, a,b,c,d) void otherSignal(const char *a) W_SIGNAL(otherSignal, a) }; void tst_QObject::connectCxx0xTypeMatching() { // this is just about connecting the signals to the slots // if this fails, this will be a compiler failure typedef LotsOfSignalsAndSlots Foo; Foo obj; // member connects QObject::connect(&obj, &Foo::signal_v, &obj, &Foo::slot_v); QObject::connect(&obj, &Foo::signal_v, &obj, &Foo::slot_i); QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::slot_v); QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::slot_i); QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::slot_vi); QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::slot_ii); QObject::connect(&obj, &Foo::signal_vii, &obj, &Foo::slot_v); QObject::connect(&obj, &Foo::signal_vii, &obj, &Foo::slot_i); QObject::connect(&obj, &Foo::signal_vii, &obj, &Foo::slot_vi); QObject::connect(&obj, &Foo::signal_vii, &obj, &Foo::slot_ii); QObject::connect(&obj, &Foo::signal_vii, &obj, &Foo::slot_vii); QObject::connect(&obj, &Foo::signal_vii, &obj, &Foo::slot_iii); QObject::connect(&obj, &Foo::signal_viii, &obj, &Foo::slot_v); QObject::connect(&obj, &Foo::signal_viii, &obj, &Foo::slot_i); QObject::connect(&obj, &Foo::signal_viii, &obj, &Foo::slot_vi); QObject::connect(&obj, &Foo::signal_viii, &obj, &Foo::slot_ii); QObject::connect(&obj, &Foo::signal_viii, &obj, &Foo::slot_vii); QObject::connect(&obj, &Foo::signal_viii, &obj, &Foo::slot_iii); QObject::connect(&obj, &Foo::signal_viii, &obj, &Foo::slot_viii); QObject::connect(&obj, &Foo::signal_viii, &obj, &Foo::slot_iiii); QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::slot_vi); // repeated from above QObject::connect(&obj, &Foo::signal_vRi, &obj, &Foo::slot_vi); QObject::connect(&obj, &Foo::signal_vRi, &obj, &Foo::slot_vRi); /*#if defined(Q_COMPILER_RVALUE_REFS) || defined(QT_ENABLE_CXX0X) QObject::connect(&obj, &Foo::signal_vOi, &obj, &Foo::slot_vi); QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::slot_vOi); QObject::connect(&obj, &Foo::signal_vRi, &obj, &Foo::slot_vOi); QObject::connect(&obj, &Foo::signal_vOi, &obj, &Foo::slot_vOi); #endif*/ // these are not supposed to compile: //QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::slot_vRi); //QObject::connect(&obj, &Foo::signal_vOi, &obj, &Foo::slot_vRi); QObject::connect(&obj, &Foo::signal_vs, &obj, &Foo::slot_vi); QObject::connect(&obj, &Foo::signal_vRs, &obj, &Foo::slot_vi); /*#if defined(Q_COMPILER_RVALUE_REFS) || defined(QT_ENABLE_CXX0X) QObject::connect(&obj, &Foo::signal_vOs, &obj, &Foo::slot_vi); QObject::connect(&obj, &Foo::signal_vRs, &obj, &Foo::slot_vOi); QObject::connect(&obj, &Foo::signal_vOs, &obj, &Foo::slot_vOi); // these are not supposed to compile: //QObject::connect(&obj, &Foo::signal_vOs, &obj, &Foo::slot_vRi); //QObject::connect(&obj, &Foo::signal_vRs, &obj, &Foo::slot_vRi); #endif*/ QObject::connect(&obj, &Foo::signal_vPFvvE, &obj, &Foo::slot_v); QObject::connect(&obj, &Foo::signal_vPFvvE, &obj, &Foo::slot_i); QObject::connect(&obj, &Foo::signal_vPFvvE, &obj, &Foo::slot_vPFvvE); QObject::connect(&obj, &Foo::signal_v, &Foo::static_slot_v); QObject::connect(&obj, &Foo::signal_v, &Foo::static_slot_i); QObject::connect(&obj, &Foo::signal_vi, &Foo::static_slot_v); QObject::connect(&obj, &Foo::signal_vi, &Foo::static_slot_i); QObject::connect(&obj, &Foo::signal_vi, &Foo::static_slot_vi); QObject::connect(&obj, &Foo::signal_vi, &Foo::static_slot_ii); QObject::connect(&obj, &Foo::signal_vii, &Foo::static_slot_v); QObject::connect(&obj, &Foo::signal_vii, &Foo::static_slot_i); QObject::connect(&obj, &Foo::signal_vii, &Foo::static_slot_vi); QObject::connect(&obj, &Foo::signal_vii, &Foo::static_slot_ii); QObject::connect(&obj, &Foo::signal_vii, &Foo::static_slot_vii); QObject::connect(&obj, &Foo::signal_vii, &Foo::static_slot_iii); QObject::connect(&obj, &Foo::signal_viii, &Foo::static_slot_v); QObject::connect(&obj, &Foo::signal_viii, &Foo::static_slot_i); QObject::connect(&obj, &Foo::signal_viii, &Foo::static_slot_vi); QObject::connect(&obj, &Foo::signal_viii, &Foo::static_slot_ii); QObject::connect(&obj, &Foo::signal_viii, &Foo::static_slot_vii); QObject::connect(&obj, &Foo::signal_viii, &Foo::static_slot_iii); QObject::connect(&obj, &Foo::signal_viii, &Foo::static_slot_viii); QObject::connect(&obj, &Foo::signal_viii, &Foo::static_slot_iiii); /*#if defined(Q_COMPILER_RVALUE_REFS) && defined(QT_ENABLE_CXX0X) QObject::connect(&obj, &Foo::signal_vi, &Foo::static_slot_vOi); QObject::connect(&obj, &Foo::signal_vRi, &Foo::static_slot_vi); QObject::connect(&obj, &Foo::signal_vRi, &Foo::static_slot_vRi); QObject::connect(&obj, &Foo::signal_vRi, &Foo::static_slot_vOi); QObject::connect(&obj, &Foo::signal_vOi, &Foo::static_slot_vi); QObject::connect(&obj, &Foo::signal_vOi, &Foo::static_slot_vOi); //QObject::connect(&obj, &Foo::signal_vi, &Foo::static_slot_vRi); //QObject::connect(&obj, &Foo::signal_vOi, &Foo::static_slot_vRi); #endif*/ QObject::connect(&obj, &Foo::signal_vs, &Foo::static_slot_vi); QObject::connect(&obj, &Foo::signal_vRs, &Foo::static_slot_vi); /*#if defined(Q_COMPILER_RVALUE_REFS) && defined(QT_ENABLE_CXX0X) QObject::connect(&obj, &Foo::signal_vOs, &Foo::static_slot_vi); QObject::connect(&obj, &Foo::signal_vRs, &Foo::static_slot_vOi); QObject::connect(&obj, &Foo::signal_vOs, &Foo::static_slot_vOi); //QObject::connect(&obj, &Foo::signal_vOs, &Foo::static_slot_vRi); //QObject::connect(&obj, &Foo::signal_vRs, &Foo::static_slot_vRi); #endif*/ QObject::connect(&obj, &Foo::signal_vPFvvE, &Foo::static_slot_v); QObject::connect(&obj, &Foo::signal_vPFvvE, &Foo::static_slot_i); QObject::connect(&obj, &Foo::signal_vPFvvE, &Foo::static_slot_vPFvvE); QVERIFY(QObject::connect(&obj, &Foo::const_signal_v, &obj, &Foo::const_slot_v)); QVERIFY(QObject::connect(&obj, &Foo::const_signal_vi, &obj, &Foo::const_slot_v)); QVERIFY(QObject::connect(&obj, &Foo::const_signal_vi, &obj, &Foo::slot_vi)); QVERIFY(QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::const_slot_vi)); QVERIFY(QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::const_slot_v)); QVERIFY(QObject::connect(&obj, &Foo::signal_vcRQObject, &obj, &Foo::slot_vcRQObject)); QVERIFY(QObject::connect(&obj, &Foo::signal_vRQObject, &obj, &Foo::slot_vRQObject)); QVERIFY(QObject::connect(&obj, &Foo::signal_vRQObject, &obj, &Foo::slot_vcRQObject)); // QVERIFY(QObject::connect(&obj, &Foo::signal_vcRQObject, &obj, &Foo::slot_vRQObject)); // Should be an error (const& -> &) QVERIFY(QObject::connect(&obj, &Foo::signal_vRi, &obj, &Foo::slot_vs)); } void receiverFunction_noexcept() noexcept {} struct Functor_noexcept { void operator()() noexcept {} }; void tst_QObject::connectCxx17Noexcept() { // 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; QObject::connect(&obj, &Foo::signal_v, &obj, &Foo::slot_v_noexcept); QObject::connect(&obj, &Foo::signal_v, &obj, &Foo::slot_i_noexcept); QObject::connect(&obj, &Foo::signal_v, &obj, &Foo::slot_vi_noexcept); QObject::connect(&obj, &Foo::signal_vii, &Foo::static_slot_v_noexcept); QObject::connect(&obj, &Foo::signal_vii, &Foo::static_slot_i_noexcept); QObject::connect(&obj, &Foo::signal_vii, &Foo::static_slot_vi_noexcept); QVERIFY(QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::const_slot_vi_noexcept)); QVERIFY(QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::const_slot_v_noexcept)); QObject::connect(&obj, &Foo::signal_v, receiverFunction_noexcept); Functor_noexcept fn; QObject::connect(&obj, &Foo::signal_v, fn); } class StringVariant : public QObject { W_OBJECT(StringVariant) signals: void stringSignal(const QString &str) W_SIGNAL(stringSignal, str) public slots: void variantSlot(const QVariant &v) { var = v; } W_SLOT(variantSlot) public: QVariant var; friend class tst_QObject; }; struct Functor { QVariant *var; void operator() (const QVariant &v) { *var = v; } }; void tst_QObject::connectConvert() { StringVariant obj; QVERIFY(connect(&obj, &StringVariant::stringSignal, &obj, &StringVariant::variantSlot)); QString s = QString::fromLatin1("Hello World"); emit obj.stringSignal(s); QCOMPARE(obj.var.toString(), s); QVERIFY(obj.var.toString().isSharedWith(s)); QVariant var; Functor f; f.var = &var; QVERIFY(connect(&obj, &StringVariant::stringSignal, f)); s = QString::fromLatin1("GoodBye"); emit obj.stringSignal(s); QCOMPARE(obj.var.toString(), s); QVERIFY(obj.var.toString().isSharedWith(s)); QCOMPARE(var, obj.var); } W_REGISTER_ARGTYPE(QString&) W_REGISTER_ARGTYPE(bool*) W_REGISTER_ARGTYPE(QString*) class ConnectWithReferenceObject : public QObject { W_OBJECT(ConnectWithReferenceObject) friend class tst_QObject; signals: void boolRef(bool &a, bool b) W_SIGNAL(boolRef,a,b) void stringRef(QString &a, const QString & b) W_SIGNAL(stringRef,a,b) void boolPtr(bool *a, bool b) W_SIGNAL(boolPtr,a,b) void stringPtr(QString *a, const QString & b) W_SIGNAL(stringPtr,a,b) public slots: void boolRefSlot(bool &b1, bool b2) { b1 = b2; } W_SLOT(boolRefSlot) void stringRefSlot(QString &s1, const QString &s2) { s1 = s2; } W_SLOT(stringRefSlot) void boolPtrSlot(bool *b1, bool b2) { *b1 = b2; } W_SLOT(boolPtrSlot) void stringPtrSlot(QString *s1, const QString &s2) { *s1 = s2; } W_SLOT(stringPtrSlot) void stringSlot1(QString s) { last = s; } W_SLOT(stringSlot1) void stringSlot2(const QString &s) { last = s; } W_SLOT(stringSlot2) void stringSlot3(QString &s) { last = s; } W_SLOT(stringSlot3) public: QString last; }; void tst_QObject::connectWithReference() { ConnectWithReferenceObject o; bool b1 = true; QString s1 = QString::fromLatin1("str1"); const QString s2 = QString::fromLatin1("str2"); const QString s3 = QString::fromLatin1("str3"); o.boolRef(b1, false); o.stringRef(s1, s2); QCOMPARE(b1, true); QCOMPARE(s1, QString::fromLatin1("str1")); o.boolPtr(&b1, false); o.stringPtr(&s1, s2); QCOMPARE(b1, true); QCOMPARE(s1, QString::fromLatin1("str1")); QVERIFY(connect(&o, &ConnectWithReferenceObject::boolRef, &o, &ConnectWithReferenceObject::boolRefSlot)); QVERIFY(connect(&o, &ConnectWithReferenceObject::stringRef, &o, &ConnectWithReferenceObject::stringRefSlot)); QVERIFY(connect(&o, &ConnectWithReferenceObject::boolPtr, &o, &ConnectWithReferenceObject::boolPtrSlot)); QVERIFY(connect(&o, &ConnectWithReferenceObject::stringPtr, &o, &ConnectWithReferenceObject::stringPtrSlot)); o.boolRef(b1, false); o.stringRef(s1, s2); QCOMPARE(b1, false); QCOMPARE(s1, QString::fromLatin1("str2")); o.boolPtr(&b1, true); o.stringPtr(&s1, s3); QCOMPARE(b1, true); QCOMPARE(s1, QString::fromLatin1("str3")); { ConnectWithReferenceObject o2; QVERIFY(connect(&o2, &ConnectWithReferenceObject::stringRef, &o2, &ConnectWithReferenceObject::stringSlot1)); o2.stringRef(s1, s2); QCOMPARE(s1, s3); QCOMPARE(o2.last, s3); } { ConnectWithReferenceObject o2; QVERIFY(connect(&o2, &ConnectWithReferenceObject::stringRef, &o2, &ConnectWithReferenceObject::stringSlot2)); o2.stringRef(s1, s2); QCOMPARE(s1, s3); QCOMPARE(o2.last, s3); } { ConnectWithReferenceObject o2; QVERIFY(connect(&o2, &ConnectWithReferenceObject::stringRef, &o2, &ConnectWithReferenceObject::stringSlot3)); o2.stringRef(s1, s2); QCOMPARE(s1, s3); QCOMPARE(o2.last, s3); } } class ManyArgumentObject : public QObject { W_OBJECT(ManyArgumentObject) signals: void signal1(const QString &a) W_SIGNAL(signal1,a) void signal2(const QString &a, const QString &b) W_SIGNAL(signal2,a,b) void signal3(const QString &a, const QString &b, const QString &c) W_SIGNAL(signal3,a,b,c) void signal4(const QString &a, const QString &b, const QString &c, const QString&d) W_SIGNAL(signal4,a,b,c,d) void signal5(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e) W_SIGNAL(signal5,a,b,c,d,e) void signal6(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e, const QString&f) W_SIGNAL(signal6,a,b,c,d,e,f) public slots: #define MANYARGUMENT_COMPARE(L) QCOMPARE(L, QString(#L)) void slot1(const QString &a) { MANYARGUMENT_COMPARE(a); count++; } W_SLOT(slot1) void slot2(const QString &a, const QString &b) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); count++; } W_SLOT(slot2) void slot3(const QString &a, const QString &b, const QString &c) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); count++; } W_SLOT(slot3) void slot4(const QString &a, const QString &b, const QString &c, const QString&d) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); MANYARGUMENT_COMPARE(d); count++; } W_SLOT(slot4) void slot5(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); MANYARGUMENT_COMPARE(d); MANYARGUMENT_COMPARE(e); count++; } W_SLOT(slot5) void slot6(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e, const QString&f) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); MANYARGUMENT_COMPARE(d); MANYARGUMENT_COMPARE(e); MANYARGUMENT_COMPARE(f); count++; } W_SLOT(slot6) public: int count; }; namespace ManyArgumentNamespace { int count; void slot1(const QString &a) { MANYARGUMENT_COMPARE(a); count++; } void slot2(const QString &a, const QString &b) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); count++; } void slot3(const QString &a, const QString &b, const QString &c) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); count++; } void slot4(const QString &a, const QString &b, const QString &c, const QString&d) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); MANYARGUMENT_COMPARE(d); count++; } void slot5(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); MANYARGUMENT_COMPARE(d); MANYARGUMENT_COMPARE(e); count++; } void slot6(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e, const QString&f) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); MANYARGUMENT_COMPARE(d); MANYARGUMENT_COMPARE(e); MANYARGUMENT_COMPARE(f); count++; } struct Funct1 { void operator()(const QString &a) { MANYARGUMENT_COMPARE(a); count++; } }; struct Funct2 { void operator()(const QString &a, const QString &b) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); count++; } }; struct Funct3 { void operator()(const QString &a, const QString &b, const QString &c) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); count++; } }; struct Funct4 { void operator()(const QString &a, const QString &b, const QString &c, const QString&d) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); MANYARGUMENT_COMPARE(d); count++; } }; struct Funct5 { void operator()(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); MANYARGUMENT_COMPARE(d); MANYARGUMENT_COMPARE(e); count++; } }; #if QT_VERSION >= QT_VERSION_CHECK(6,3,0) struct Funct6 final { #else struct Funct6 { #endif void operator()(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e, const QString&f) { MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); MANYARGUMENT_COMPARE(d); MANYARGUMENT_COMPARE(e); MANYARGUMENT_COMPARE(f); count++; } }; } void tst_QObject::connectManyArguments() { ManyArgumentObject ob; ob.count = 0; ManyArgumentNamespace::count = 0; connect(&ob, &ManyArgumentObject::signal1, &ob, &ManyArgumentObject::slot1); connect(&ob, &ManyArgumentObject::signal2, &ob, &ManyArgumentObject::slot2); connect(&ob, &ManyArgumentObject::signal3, &ob, &ManyArgumentObject::slot3); connect(&ob, &ManyArgumentObject::signal4, &ob, &ManyArgumentObject::slot4); connect(&ob, &ManyArgumentObject::signal5, &ob, &ManyArgumentObject::slot5); connect(&ob, &ManyArgumentObject::signal6, &ob, &ManyArgumentObject::slot6); connect(&ob, &ManyArgumentObject::signal1, ManyArgumentNamespace::slot1); connect(&ob, &ManyArgumentObject::signal2, ManyArgumentNamespace::slot2); connect(&ob, &ManyArgumentObject::signal3, ManyArgumentNamespace::slot3); connect(&ob, &ManyArgumentObject::signal4, ManyArgumentNamespace::slot4); connect(&ob, &ManyArgumentObject::signal5, ManyArgumentNamespace::slot5); connect(&ob, &ManyArgumentObject::signal6, ManyArgumentNamespace::slot6); connect(&ob, &ManyArgumentObject::signal6, &ob, &ManyArgumentObject::signal5); connect(&ob, &ManyArgumentObject::signal5, &ob, &ManyArgumentObject::signal4); connect(&ob, &ManyArgumentObject::signal4, &ob, &ManyArgumentObject::signal3); connect(&ob, &ManyArgumentObject::signal3, &ob, &ManyArgumentObject::signal2); connect(&ob, &ManyArgumentObject::signal2, &ob, &ManyArgumentObject::signal1); emit ob.signal6("a", "b", "c", "d", "e", "f"); QCOMPARE(ob.count, 6); QCOMPARE(ManyArgumentNamespace::count, 6); ManyArgumentObject ob2; ob2.count = 0; ManyArgumentNamespace::count = 0; connect(&ob2, &ManyArgumentObject::signal6, &ob2, &ManyArgumentObject::slot1); connect(&ob2, &ManyArgumentObject::signal6, &ob2, &ManyArgumentObject::slot2); connect(&ob2, &ManyArgumentObject::signal6, &ob2, &ManyArgumentObject::slot3); connect(&ob2, &ManyArgumentObject::signal6, &ob2, &ManyArgumentObject::slot4); connect(&ob2, &ManyArgumentObject::signal6, &ob2, &ManyArgumentObject::slot5); connect(&ob2, &ManyArgumentObject::signal6, &ob2, &ManyArgumentObject::slot6); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::slot1); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::slot2); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::slot3); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::slot4); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::slot5); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::slot6); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::Funct1()); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::Funct2()); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::Funct3()); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::Funct4()); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::Funct5()); connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::Funct6()); emit ob2.signal6("a", "b", "c", "d", "e", "f"); QCOMPARE(ob2.count, 6); QCOMPARE(ManyArgumentNamespace::count, 12); } class ForwardDeclared; W_REGISTER_ARGTYPE(ForwardDeclared) class ForwardDeclareArguments : public QObject { W_OBJECT(ForwardDeclareArguments) signals: void mySignal(const ForwardDeclared&a) W_SIGNAL(mySignal,a) public slots: void mySlot(const ForwardDeclared&) {} W_SLOT(mySlot) }; void tst_QObject::connectForwardDeclare() { ForwardDeclareArguments ob; // it should compile QVERIFY(connect(&ob, &ForwardDeclareArguments::mySignal, &ob, &ForwardDeclareArguments::mySlot, Qt::QueuedConnection)); } class NoDefaultConstructor { W_GADGET(NoDefaultConstructor) public: NoDefaultConstructor(int) {} }; W_REGISTER_ARGTYPE(NoDefaultConstructor) class NoDefaultContructorArguments : public QObject { W_OBJECT(NoDefaultContructorArguments) signals: void mySignal(const NoDefaultConstructor&a) W_SIGNAL(mySignal,a) public slots: void mySlot(const NoDefaultConstructor&) {} W_SLOT(mySlot) }; void tst_QObject::connectNoDefaultConstructorArg() { NoDefaultContructorArguments ob; // it should compile QVERIFY(connect(&ob, &NoDefaultContructorArguments::mySignal, &ob, &NoDefaultContructorArguments::mySlot, Qt::QueuedConnection)); } struct MoveOnly { int value; explicit MoveOnly(int v = 1) : value(v) {} MoveOnly(MoveOnly &&o) : value(o.value) { o.value = -1; } MoveOnly &operator=(MoveOnly &&o) { value = o.value; o.value = -1; return *this; } Q_DISABLE_COPY(MoveOnly); }; W_REGISTER_ARGTYPE(MoveOnly) class ReturnValue : public QObject { friend class tst_QObject; W_OBJECT(ReturnValue) signals: QVariant returnVariant(int a) W_SIGNAL(returnVariant,a) QString returnString(int a) W_SIGNAL(returnString,a) int returnInt(int a) W_SIGNAL(returnInt,a) void returnVoid(int a) W_SIGNAL(returnVoid,a) CustomType returnCustomType(int a) W_SIGNAL(returnCustomType,a) MoveOnly returnMoveOnly(int a) W_SIGNAL(returnMoveOnly,a) QObject *returnPointer() W_SIGNAL(returnPointer) public slots: QVariant returnVariantSlot(int i) { return i; } W_SLOT(returnVariantSlot) QString returnStringSlot(int i) { return QString::number(i); } W_SLOT(returnStringSlot) int returnIntSlot(int i) { return i; } W_SLOT(returnIntSlot) CustomType returnCustomTypeSlot(int i) { return CustomType(i); } W_SLOT(returnCustomTypeSlot) void returnVoidSlot() {} W_SLOT(returnVoidSlot) int return23() { return 23; } W_SLOT(return23) QString returnHello() { return QStringLiteral("hello"); } W_SLOT(returnHello) QObject *returnThisSlot1() { return this; } W_SLOT(returnThisSlot1) ReturnValue *returnThisSlot2() { return this; } W_SLOT(returnThisSlot2) MoveOnly returnMoveOnlySlot(int i) { return MoveOnly(i); } W_SLOT(returnMoveOnlySlot) public: struct VariantFunctor { QVariant operator()(int i) { return i; } }; struct CustomTypeFunctor { CustomType operator()(int i) { return CustomType(i); } }; struct StringFunctor { QString operator()(int i) { return QString::number(i); } }; struct IntFunctor { int operator()(int i) { return i; } }; struct VoidFunctor { void operator()(int) {} }; struct MoveOnlyFunctor { MoveOnly operator()(int i) { return MoveOnly(i); } }; }; W_REGISTER_ARGTYPE(ReturnValue*) QString someFunctionReturningString(int i) { return '\'' + QString::number(i) + '\''; } void tst_QObject::returnValue_data() { QTest::addColumn("isBlockingQueued"); QTest::newRow("DirectConnection") << false; QTest::newRow("BlockingQueuedConnection") << true; } void tst_QObject::returnValue() { CheckInstanceCount checker; QFETCH(bool, isBlockingQueued); QThread thread; ReturnValue receiver; Qt::ConnectionType type = Qt::DirectConnection; if (isBlockingQueued) { thread.start(); receiver.moveToThread(&thread); type = Qt::BlockingQueuedConnection; } { // connected to nothing CheckInstanceCount checker; ReturnValue r; QCOMPARE(emit r.returnVariant(45), QVariant()); QCOMPARE(emit r.returnString(45), QString()); QCOMPARE(emit r.returnInt(45), int()); emit r.returnVoid(45); QCOMPARE((emit r.returnCustomType(45)).value(), CustomType().value()); QCOMPARE((emit r.returnPointer()), static_cast(0)); QCOMPARE((emit r.returnMoveOnly(666)).value, MoveOnly().value); } { // connected to a slot returning the same type CheckInstanceCount checker; ReturnValue r; QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::returnVariantSlot, type)); QCOMPARE(emit r.returnVariant(45), QVariant(45)); QVERIFY(connect(&r, &ReturnValue::returnString, &receiver, &ReturnValue::returnStringSlot, type)); QCOMPARE(emit r.returnString(45), QString::fromLatin1("45")); QVERIFY(connect(&r, &ReturnValue::returnInt, &receiver, &ReturnValue::returnIntSlot, type)); QCOMPARE(emit r.returnInt(45), int(45)); QVERIFY(connect(&r, &ReturnValue::returnCustomType, &receiver, &ReturnValue::returnCustomTypeSlot, type)); QCOMPARE((emit r.returnCustomType(45)).value(), CustomType(45).value()); QVERIFY(connect(&r, &ReturnValue::returnPointer, &receiver, &ReturnValue::returnThisSlot1, type)); QCOMPARE((emit r.returnPointer()), static_cast(&receiver)); QVERIFY(connect(&r, &ReturnValue::returnMoveOnly, &receiver, &ReturnValue::returnMoveOnlySlot, type)); QCOMPARE((emit r.returnMoveOnly(666)).value, 666); } if (!isBlockingQueued) { // connected to simple functions or functor CheckInstanceCount checker; ReturnValue r; QVERIFY(connect(&r, &ReturnValue::returnString, someFunctionReturningString)); QCOMPARE(emit r.returnString(49), QString::fromLatin1("'49'")); ReturnValue::CustomTypeFunctor customTypeFunctor; QVERIFY(connect(&r, &ReturnValue::returnCustomType, customTypeFunctor)); QCOMPARE((emit r.returnCustomType(49)).value(), CustomType(49).value()); ReturnValue::VariantFunctor variantFunctor; QVERIFY(connect(&r, &ReturnValue::returnVariant, variantFunctor)); QCOMPARE(emit r.returnVariant(45), QVariant(45)); ReturnValue::IntFunctor intFunctor; QVERIFY(connect(&r, &ReturnValue::returnInt, intFunctor)); QCOMPARE(emit r.returnInt(45), int(45)); ReturnValue::MoveOnlyFunctor moveOnlyFunctor; QVERIFY(connect(&r, &ReturnValue::returnMoveOnly, moveOnlyFunctor)); QCOMPARE((emit r.returnMoveOnly(666)).value, 666); } { // connected to a slot with different type CheckInstanceCount checker; ReturnValue r; QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::returnStringSlot, type)); QCOMPARE(emit r.returnVariant(48), QVariant(QString::fromLatin1("48"))); QVERIFY(connect(&r, &ReturnValue::returnCustomType, &receiver, &ReturnValue::returnIntSlot, type)); QCOMPARE((emit r.returnCustomType(48)).value(), CustomType(48).value()); QVERIFY(connect(&r, &ReturnValue::returnVoid, &receiver, &ReturnValue::returnCustomTypeSlot, type)); emit r.returnVoid(48); QVERIFY(connect(&r, &ReturnValue::returnPointer, &receiver, &ReturnValue::returnThisSlot2, type)); QCOMPARE((emit r.returnPointer()), static_cast(&receiver)); } if (!isBlockingQueued) { // connected to functor with different type CheckInstanceCount checker; ReturnValue r; ReturnValue::CustomTypeFunctor customTypeFunctor; QVERIFY(connect(&r, &ReturnValue::returnCustomType, customTypeFunctor)); QCOMPARE((emit r.returnCustomType(49)).value(), CustomType(49).value()); ReturnValue::StringFunctor stringFunctor; QVERIFY(connect(&r, &ReturnValue::returnVariant, stringFunctor)); QCOMPARE(emit r.returnVariant(45), QVariant(QString::fromLatin1("45"))); } { // connected to a void CheckInstanceCount checker; ReturnValue r; QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::returnVoidSlot, type)); QCOMPARE(emit r.returnVariant(45), QVariant()); QVERIFY(connect(&r, &ReturnValue::returnString, &receiver, &ReturnValue::returnVoidSlot, type)); QCOMPARE(emit r.returnString(45), QString()); QVERIFY(connect(&r, &ReturnValue::returnInt, &receiver, &ReturnValue::returnVoidSlot, type)); QCOMPARE(emit r.returnInt(45), int()); QVERIFY(connect(&r, &ReturnValue::returnCustomType, &receiver, &ReturnValue::returnVoidSlot, type)); QCOMPARE((emit r.returnCustomType(45)).value(), CustomType().value()); QVERIFY(connect(&r, &ReturnValue::returnPointer, &receiver, &ReturnValue::returnVoidSlot, type)); QCOMPARE((emit r.returnPointer()), static_cast(0)); QVERIFY(connect(&r, &ReturnValue::returnMoveOnly, &receiver, &ReturnValue::returnVoidSlot, type)); QCOMPARE((emit r.returnMoveOnly(666)).value, MoveOnly().value); } if (!isBlockingQueued) { // queued connection should not forward the return value CheckInstanceCount checker; ReturnValue r; QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::returnVariantSlot, Qt::QueuedConnection)); QCOMPARE(emit r.returnVariant(45), QVariant()); QVERIFY(connect(&r, &ReturnValue::returnString, &receiver, &ReturnValue::returnStringSlot, Qt::QueuedConnection)); QCOMPARE(emit r.returnString(45), QString()); QVERIFY(connect(&r, &ReturnValue::returnInt, &receiver, &ReturnValue::returnIntSlot, Qt::QueuedConnection)); QCOMPARE(emit r.returnInt(45), int()); QVERIFY(connect(&r, &ReturnValue::returnCustomType, &receiver, &ReturnValue::returnCustomTypeSlot, Qt::QueuedConnection)); QCOMPARE((emit r.returnCustomType(45)).value(), CustomType().value()); QVERIFY(connect(&r, &ReturnValue::returnPointer, &receiver, &ReturnValue::returnThisSlot1, Qt::QueuedConnection)); QCOMPARE((emit r.returnPointer()), static_cast(0)); QVERIFY(connect(&r, &ReturnValue::returnMoveOnly, &receiver, &ReturnValue::returnMoveOnlySlot, Qt::QueuedConnection)); QCOMPARE((emit r.returnMoveOnly(666)).value, MoveOnly().value); QCoreApplication::processEvents(); QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::returnStringSlot, Qt::QueuedConnection)); QCOMPARE(emit r.returnVariant(48), QVariant()); QVERIFY(connect(&r, &ReturnValue::returnCustomType, &receiver, &ReturnValue::returnIntSlot, Qt::QueuedConnection)); QCOMPARE((emit r.returnCustomType(48)).value(), CustomType().value()); QVERIFY(connect(&r, &ReturnValue::returnVoid, &receiver, &ReturnValue::returnCustomTypeSlot, Qt::QueuedConnection)); emit r.returnVoid(48); QCoreApplication::processEvents(); } { // connected to many slots ReturnValue::VoidFunctor voidFunctor; ReturnValue::IntFunctor intFunctor; ReturnValue r; QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::returnVariantSlot, type)); QCOMPARE(emit r.returnVariant(45), QVariant(45)); QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::return23, type)); QCOMPARE(emit r.returnVariant(45), QVariant(23)); QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::returnVoidSlot, type)); QCOMPARE(emit r.returnVariant(45), QVariant(23)); QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::returnHello, type)); QCOMPARE(emit r.returnVariant(45), QVariant(QStringLiteral("hello"))); QVERIFY(connect(&r, &ReturnValue::returnVariant, voidFunctor)); QCOMPARE(emit r.returnVariant(45), QVariant(QStringLiteral("hello"))); QVERIFY(connect(&r, &ReturnValue::returnVariant, intFunctor)); QCOMPARE(emit r.returnVariant(45), QVariant(45)); QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::return23, Qt::QueuedConnection)); QCOMPARE(emit r.returnVariant(45), QVariant(45)); QCOMPARE(emit r.returnInt(45), int()); QVERIFY(connect(&r, &ReturnValue::returnInt, &receiver, &ReturnValue::returnVoidSlot, type)); QCOMPARE(emit r.returnInt(45), int()); QVERIFY(connect(&r, &ReturnValue::returnInt, &receiver, &ReturnValue::returnIntSlot, type)); QCOMPARE(emit r.returnInt(45), int(45)); QVERIFY(connect(&r, &ReturnValue::returnInt, &receiver, &ReturnValue::return23, type)); QCOMPARE(emit r.returnInt(45), int(23)); QVERIFY(connect(&r, &ReturnValue::returnInt, voidFunctor)); QCOMPARE(emit r.returnInt(45), int(23)); QVERIFY(connect(&r, &ReturnValue::returnInt, intFunctor)); QCOMPARE(emit r.returnInt(45), int(45)); QVERIFY(connect(&r, &ReturnValue::returnInt, &receiver, &ReturnValue::return23, Qt::QueuedConnection)); QCOMPARE(emit r.returnInt(45), int(45)); QCoreApplication::processEvents(); } if (isBlockingQueued) { thread.quit(); thread.wait(); } } void tst_QObject::returnValue2_data() { returnValue_data(); } //String based syntax void tst_QObject::returnValue2() { CheckInstanceCount checker; QFETCH(bool, isBlockingQueued); QThread thread; ReturnValue receiver; Qt::ConnectionType type = Qt::DirectConnection; if (isBlockingQueued) { thread.start(); receiver.moveToThread(&thread); type = Qt::BlockingQueuedConnection; } { // connected to a simple slot CheckInstanceCount checker; ReturnValue r; QVERIFY(connect(&r, SIGNAL(returnVariant(int)), &receiver, SLOT(returnVariantSlot(int)), type)); QCOMPARE(emit r.returnVariant(45), QVariant(45)); QVERIFY(connect(&r, SIGNAL(returnString(int)), &receiver, SLOT(returnStringSlot(int)), type)); QCOMPARE(emit r.returnString(45), QString(QStringLiteral("45"))); QVERIFY(connect(&r, SIGNAL(returnInt(int)), &receiver, SLOT(returnIntSlot(int)), type)); QCOMPARE(emit r.returnInt(45), int(45)); QVERIFY(connect(&r, SIGNAL(returnCustomType(int)), &receiver, SLOT(returnCustomTypeSlot(int)), type)); QCOMPARE((emit r.returnCustomType(45)).value(), CustomType(45).value()); QVERIFY(connect(&r, SIGNAL(returnMoveOnly(int)), &receiver, SLOT(returnMoveOnlySlot(int)), type)); QCOMPARE((emit r.returnMoveOnly(45)).value, 45); } { // connected to a slot returning void CheckInstanceCount checker; ReturnValue r; QVERIFY(connect(&r, SIGNAL(returnVariant(int)), &receiver, SLOT(returnVoidSlot()), type)); QCOMPARE(emit r.returnVariant(45), QVariant()); QVERIFY(connect(&r, SIGNAL(returnString(int)), &receiver, SLOT(returnVoidSlot()), type)); QCOMPARE(emit r.returnString(45), QString()); QVERIFY(connect(&r, SIGNAL(returnInt(int)), &receiver, SLOT(returnVoidSlot()), type)); QCOMPARE(emit r.returnInt(45), int()); QVERIFY(connect(&r, SIGNAL(returnCustomType(int)), &receiver, SLOT(returnVoidSlot()), type)); QCOMPARE((emit r.returnCustomType(45)).value(), CustomType().value()); QVERIFY(connect(&r, SIGNAL(returnMoveOnly(int)), &receiver, SLOT(returnVoidSlot()), type)); QCOMPARE((emit r.returnMoveOnly(45)).value, MoveOnly().value); } if (!isBlockingQueued) { // queued connection should not forward the return value CheckInstanceCount checker; ReturnValue r; QVERIFY(connect(&r, SIGNAL(returnVariant(int)), &receiver, SLOT(returnVariantSlot(int)), Qt::QueuedConnection)); QCOMPARE(emit r.returnVariant(45), QVariant()); QVERIFY(connect(&r, SIGNAL(returnString(int)), &receiver, SLOT(returnStringSlot(int)), Qt::QueuedConnection)); QCOMPARE(emit r.returnString(45), QString()); QVERIFY(connect(&r, SIGNAL(returnInt(int)), &receiver, SLOT(returnIntSlot(int)), Qt::QueuedConnection)); QCOMPARE(emit r.returnInt(45), int()); QVERIFY(connect(&r, SIGNAL(returnCustomType(int)), &receiver, SLOT(returnCustomTypeSlot(int)), Qt::QueuedConnection)); QCOMPARE((emit r.returnCustomType(45)).value(), CustomType().value()); QVERIFY(connect(&r, SIGNAL(returnMoveOnly(int)), &receiver, SLOT(returnMoveOnlySlot(int)), Qt::QueuedConnection)); QCOMPARE((emit r.returnMoveOnly(45)).value, MoveOnly().value); QCoreApplication::processEvents(); //Queued conneciton with different return type should be safe QVERIFY(connect(&r, SIGNAL(returnVariant(int)), &receiver, SLOT(returnStringSlot(int)), Qt::QueuedConnection)); QCOMPARE(emit r.returnVariant(48), QVariant()); QVERIFY(connect(&r, SIGNAL(returnCustomType(int)), &receiver, SLOT(returnIntSlot(int)), Qt::QueuedConnection)); QCOMPARE((emit r.returnCustomType(48)).value(), CustomType().value()); QVERIFY(connect(&r, SIGNAL(returnVoid(int)), &receiver, SLOT(returnCustomTypeSlot(int)), Qt::QueuedConnection)); emit r.returnVoid(48); QCoreApplication::processEvents(); } { // connected to many slots ReturnValue r; QVERIFY(connect(&r, SIGNAL(returnInt(int)), &receiver, SLOT(returnIntSlot(int)), type)); QCOMPARE(emit r.returnInt(45), int(45)); QVERIFY(connect(&r, SIGNAL(returnInt(int)), &receiver, SLOT(returnVoidSlot()), type)); QCOMPARE(emit r.returnInt(45), int(45)); QVERIFY(connect(&r, SIGNAL(returnInt(int)), &receiver, SLOT(return23()), type)); QCOMPARE(emit r.returnInt(45), int(23)); QVERIFY(connect(&r, SIGNAL(returnInt(int)), &receiver, SLOT(returnIntSlot(int)), Qt::QueuedConnection)); QCOMPARE(emit r.returnInt(45), int(23)); QVERIFY(connect(&r, SIGNAL(returnString(int)), &receiver, SLOT(returnStringSlot(int)), type)); QCOMPARE(emit r.returnString(45), QString(QStringLiteral("45"))); QVERIFY(connect(&r, SIGNAL(returnString(int)), &receiver, SLOT(returnVoidSlot()), type)); QCOMPARE(emit r.returnString(45), QString(QStringLiteral("45"))); QVERIFY(connect(&r, SIGNAL(returnString(int)), &receiver, SLOT(returnHello()), type)); QCOMPARE(emit r.returnString(45), QString(QStringLiteral("hello"))); QVERIFY(connect(&r, SIGNAL(returnString(int)), &receiver, SLOT(returnStringSlot(int)), Qt::QueuedConnection)); QCOMPARE(emit r.returnString(45), QString(QStringLiteral("hello"))); } if (isBlockingQueued) { thread.quit(); thread.wait(); } } class VirtualSlotsObjectBase : public QObject { W_OBJECT(VirtualSlotsObjectBase) public slots: virtual void slot1() { base_counter1++; } W_SLOT(slot1) public: VirtualSlotsObjectBase() : base_counter1(0) {} int base_counter1; signals: void signal1() W_SIGNAL(signal1) }; class VirtualSlotsObject : public VirtualSlotsObjectBase { W_OBJECT(VirtualSlotsObject) public slots: virtual void slot1() { derived_counter1++; } W_SLOT(slot1) public: VirtualSlotsObject() : derived_counter1(0) {} int derived_counter1; }; void tst_QObject::connectVirtualSlots() { VirtualSlotsObject obj; QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1, Qt::UniqueConnection)); QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1, Qt::UniqueConnection)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 1); QVERIFY(QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1)); QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 1); /* the C++ standard say the comparison between pointer to virtual member function is unspecified QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1, Qt::UniqueConnection)); QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObject::slot1, Qt::UniqueConnection)); */ } struct VirtualBase { int virtual_base_count; VirtualBase() : virtual_base_count(0) {} virtual ~VirtualBase() {} virtual void slot2() = 0; }; class ObjectWithVirtualBase : public VirtualSlotsObject, public virtual VirtualBase { W_OBJECT(ObjectWithVirtualBase) public: ObjectWithVirtualBase() : regular_call_count(0), derived_counter2(0) {} int regular_call_count; int derived_counter2; public slots: void regularSlot() { ++regular_call_count; } W_SLOT(regularSlot) virtual void slot1() { ++derived_counter2; } W_SLOT(slot1) virtual void slot2() { ++virtual_base_count; } W_SLOT(slot2) }; W_OBJECT_IMPL(ObjectWithVirtualBase) struct NormalBase { QByteArray lastCalled; virtual ~NormalBase() {} virtual void virtualBaseSlot() { lastCalled = "virtualBaseSlot"; } void normalBaseSlot() { lastCalled = "normalBaseSlot"; } }; class ObjectWithMultiInheritance : public VirtualSlotsObject, public NormalBase { W_OBJECT(ObjectWithMultiInheritance) }; W_OBJECT_IMPL(ObjectWithMultiInheritance) // Normally, the class that inherit QObject always must go first, because of the way qobject_cast // work, and moc checks for that. But if we don't use Q_OBJECT, this should work class ObjectWithMultiInheritance2 : public NormalBase, public VirtualSlotsObject { // no QObject as QObject always must go first // Q_OBJECT }; // VMI = Virtual or Multiple Inheritance // (in this case, both) void tst_QObject::connectSlotsVMIClass() { // test connecting by the base { ObjectWithVirtualBase obj; QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1, Qt::UniqueConnection)); QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1, Qt::UniqueConnection)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 0); QCOMPARE(obj.derived_counter2, 1); QCOMPARE(obj.virtual_base_count, 0); QVERIFY(QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1)); QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 0); QCOMPARE(obj.derived_counter2, 1); QCOMPARE(obj.virtual_base_count, 0); } // test connecting with the actual class { ObjectWithVirtualBase obj; QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::regularSlot, Qt::UniqueConnection)); QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::regularSlot, Qt::UniqueConnection)); QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot1, Qt::UniqueConnection)); QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot1, Qt::UniqueConnection)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 0); QCOMPARE(obj.derived_counter2, 1); QCOMPARE(obj.regular_call_count, 1); QCOMPARE(obj.virtual_base_count, 0); QVERIFY( QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::regularSlot)); QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::regularSlot)); QVERIFY( QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot1)); QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot1)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 0); QCOMPARE(obj.derived_counter2, 1); QCOMPARE(obj.regular_call_count, 1); QCOMPARE(obj.virtual_base_count, 0); /* the C++ standard say the comparison between pointer to virtual member function is unspecified QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1, Qt::UniqueConnection)); QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot1, Qt::UniqueConnection)); */ } // test connecting a slot that is virtual from the virtual base { ObjectWithVirtualBase obj; QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot2, Qt::UniqueConnection)); QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot2, Qt::UniqueConnection)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 0); QCOMPARE(obj.derived_counter2, 0); QCOMPARE(obj.virtual_base_count, 1); QCOMPARE(obj.regular_call_count, 0); QVERIFY( QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot2)); QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot2)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 0); QCOMPARE(obj.derived_counter2, 0); QCOMPARE(obj.virtual_base_count, 1); QCOMPARE(obj.regular_call_count, 0); } // test connecting a slot that is virtual within the second base { ObjectWithMultiInheritance obj; void (ObjectWithMultiInheritance::*slot)() = &ObjectWithMultiInheritance::virtualBaseSlot; QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot, Qt::UniqueConnection)); QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot, Qt::UniqueConnection)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 0); QCOMPARE(obj.lastCalled, QByteArray("virtualBaseSlot")); obj.lastCalled.clear(); QVERIFY( QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot)); QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 0); QCOMPARE(obj.lastCalled, QByteArray()); } // test connecting a slot that is not virtual within the second base { ObjectWithMultiInheritance obj; void (ObjectWithMultiInheritance::*slot)() = &ObjectWithMultiInheritance::normalBaseSlot; QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot, Qt::UniqueConnection)); QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot, Qt::UniqueConnection)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 0); QCOMPARE(obj.lastCalled, QByteArray("normalBaseSlot")); obj.lastCalled.clear(); QVERIFY( QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot)); QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 0); QCOMPARE(obj.lastCalled, QByteArray()); } // test connecting a slot within the first non-QObject base { ObjectWithMultiInheritance2 obj; void (ObjectWithMultiInheritance2::*slot)() = &ObjectWithMultiInheritance2::normalBaseSlot; QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot, Qt::UniqueConnection)); QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot, Qt::UniqueConnection)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 0); QCOMPARE(obj.lastCalled, QByteArray("normalBaseSlot")); obj.lastCalled.clear(); QVERIFY( QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot)); QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 0); QCOMPARE(obj.lastCalled, QByteArray()); } // test connecting a slot within the second QObject base { ObjectWithMultiInheritance2 obj; void (ObjectWithMultiInheritance2::*slot)() = &ObjectWithMultiInheritance2::slot1; QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot, Qt::UniqueConnection)); QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot, Qt::UniqueConnection)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 1); QCOMPARE(obj.lastCalled, QByteArray()); QVERIFY( QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot)); QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot)); emit obj.signal1(); QCOMPARE(obj.base_counter1, 0); QCOMPARE(obj.derived_counter1, 1); QCOMPARE(obj.lastCalled, QByteArray()); } } #ifndef QT_BUILD_INTERNAL void tst_QObject::connectPrivateSlots() {QSKIP("Needs QT_BUILD_INTERNAL");} #else class ConnectToPrivateSlotPrivate; class ConnectToPrivateSlot :public QObject { W_OBJECT(ConnectToPrivateSlot) public: ConnectToPrivateSlot(); void test(SenderObject *obj1) ; Q_DECLARE_PRIVATE(ConnectToPrivateSlot) }; class ConnectToPrivateSlotPrivate : public QObjectPrivate { #if QT_VERSION >= QT_VERSION_CHECK(6,3,0) public: Q_DECLARE_PUBLIC(ConnectToPrivateSlot) #else Q_DECLARE_PUBLIC(ConnectToPrivateSlot) public: #endif int receivedCount; QVariant receivedValue; void thisIsAPrivateSlot() { receivedCount++; }; void thisIsAPrivateSlotWithArg(const QVariant &v) { receivedCount++; receivedValue = v; }; }; ConnectToPrivateSlot::ConnectToPrivateSlot(): QObject(*new ConnectToPrivateSlotPrivate) {} void ConnectToPrivateSlot::test(SenderObject* obj1) { Q_D(ConnectToPrivateSlot); d->receivedCount = 0; QVERIFY(QObjectPrivate::connect(obj1, &SenderObject::signal1, d, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlot)); QVERIFY(QObjectPrivate::connect(obj1, &SenderObject::signal7, d, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlotWithArg)); QCOMPARE(d->receivedCount, 0); obj1->signal1(); QCOMPARE(d->receivedCount, 1); QCOMPARE(d->receivedValue, QVariant()); obj1->signal7(666, QLatin1String("_")); QCOMPARE(d->receivedCount, 2); QCOMPARE(d->receivedValue, QVariant(666)); QVERIFY(QObjectPrivate::connect(obj1, &SenderObject::signal2, d, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlot, Qt::UniqueConnection)); QVERIFY(!QObjectPrivate::connect(obj1, &SenderObject::signal2, d, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlot, Qt::UniqueConnection)); obj1->signal2(); QCOMPARE(d->receivedCount, 3); QVERIFY(QObjectPrivate::disconnect(obj1, &SenderObject::signal2, d, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlot)); obj1->signal2(); QCOMPARE(d->receivedCount, 3); QVERIFY(!QObjectPrivate::disconnect(obj1, &SenderObject::signal2, d, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlot)); } void tst_QObject::connectPrivateSlots() { SenderObject sender; { ConnectToPrivateSlot o; o.test(&sender); } sender.signal7(777, QLatin1String("check that deleting the object properly disconnected")); sender.signal1(); } #endif struct SlotFunctor { void operator()() {} }; struct SlotFunctorString { void operator()(const QString &) {} }; void tst_QObject::connectFunctorArgDifference() { QTimer timer; // Compile-time tests that the connection is successful. connect(&timer, &QTimer::timeout, SlotFunctor()); connect(&timer, &QTimer::objectNameChanged, SlotFunctorString()); connect(qApp, &QCoreApplication::aboutToQuit, SlotFunctor()); connect(&timer, &QTimer::objectNameChanged, SlotFunctor()); QStringListModel model; connect(&model, &QStringListModel::rowsInserted, SlotFunctor()); connect(&timer, &QTimer::timeout, [=](){}); connect(&timer, &QTimer::objectNameChanged, [=](const QString &){}); connect(qApp, &QCoreApplication::aboutToQuit, [=](){}); connect(&timer, &QTimer::objectNameChanged, [=](){}); connect(&model, &QStringListModel::rowsInserted, [=](){}); connect(&model, &QStringListModel::rowsInserted, [=](const QModelIndex &){}); QVERIFY(true); } class ContextObject : public QObject { W_OBJECT(ContextObject) public: void compareSender(QObject *s) { QCOMPARE(s, sender()); } }; struct SlotArgFunctor { SlotArgFunctor(int *s) : status(s), context(nullptr), sender(nullptr) {} SlotArgFunctor(ContextObject *context, QObject *sender, int *s) : status(s), context(context), sender(sender) {} void operator()() { *status = 2; if (context) context->compareSender(sender); } protected: int *status; ContextObject *context; QObject *sender; }; void tst_QObject::connectFunctorQueued() { int status = 1; SenderObject obj; QEventLoop e; connect(&obj, &SenderObject::signal1, this, SlotArgFunctor(&status), Qt::QueuedConnection); connect(&obj, &SenderObject::signal1, &e, &QEventLoop::quit, Qt::QueuedConnection); obj.emitSignal1(); QCOMPARE(status, 1); e.exec(); QCOMPARE(status, 2); status = 1; connect(&obj, &SenderObject::signal1, this, [&status] { status = 2; }, Qt::QueuedConnection); obj.emitSignal1(); QCOMPARE(status, 1); e.exec(); QCOMPARE(status, 2); } void tst_QObject::connectFunctorWithContext() { int status = 1; SenderObject obj; ContextObject *context = new ContextObject; QEventLoop e; connect(&obj, &SenderObject::signal1, context, SlotArgFunctor(&status)); connect(&obj, &SenderObject::signal1, &e, &QEventLoop::quit, Qt::QueuedConnection); // When the context gets deleted, the connection should decay and the signal shouldn't trigger // The connection is queued to make sure the destroyed signal propagates correctly and // cuts the connection. connect(context, &QObject::destroyed, &obj, &SenderObject::signal1, Qt::QueuedConnection); context->deleteLater(); obj.emitSignal1(); QCOMPARE(status, 2); e.exec(); QCOMPARE(status, 2); // Check disconnect with the context object as "receiver" argument, all signals context = new ContextObject; status = 1; connect(&obj, &SenderObject::signal1, context, SlotArgFunctor(&status)); obj.emitSignal1(); QCOMPARE(status, 2); QObject::disconnect(&obj, nullptr, context, nullptr); obj.emitSignal1(); QCOMPARE(status, 2); delete context; // Check disconnect with the context object as "receiver" argument, specific signal context = new ContextObject; status = 1; connect(&obj, &SenderObject::signal1, context, SlotArgFunctor(&status)); obj.emitSignal1(); QCOMPARE(status, 2); QObject::disconnect(&obj, &SenderObject::signal1, context, nullptr); obj.emitSignal1(); QCOMPARE(status, 2); delete context; // Check the sender arg is set correctly in the context context = new ContextObject; status = 1; connect(&obj, &SenderObject::signal1, context, SlotArgFunctor(context, &obj, &status), Qt::QueuedConnection); obj.emitSignal1(); QCOMPARE(status, 1); e.exec(); QCOMPARE(status, 2); status = 1; connect(&obj, &SenderObject::signal1, this, [this, &status, &obj] { status = 2; QCOMPARE(sender(), &obj); }, Qt::QueuedConnection); obj.emitSignal1(); QCOMPARE(status, 1); e.exec(); QCOMPARE(status, 2); delete context; } class StatusChanger : public QObject { W_OBJECT(StatusChanger) public: StatusChanger(int *status) : m_status(status) { } ~StatusChanger() { *m_status = 2; } private: int *m_status; }; W_OBJECT_IMPL(StatusChanger) class DispatcherWatcher : public QObject { W_OBJECT(DispatcherWatcher) public: DispatcherWatcher(QEventLoop &e, int *statusAwake, int *statusAboutToBlock) : m_eventLoop(&e), m_statusAwake(statusAwake), m_statusAboutToBlock(statusAboutToBlock), m_aboutToBlocks(0), m_awakes(0) { awake = new StatusChanger(statusAwake); abouttoblock = new StatusChanger(statusAboutToBlock); QCOMPARE(*statusAwake, 1); QCOMPARE(*statusAboutToBlock, 1); connect(QAbstractEventDispatcher::instance(), SIGNAL(awake()), this, SLOT(onAwake())); connect(QAbstractEventDispatcher::instance(), SIGNAL(aboutToBlock()), this, SLOT(onAboutToBlock())); } ~DispatcherWatcher() { if (awake) awake->deleteLater(); if (abouttoblock) abouttoblock->deleteLater(); } public slots: // The order of these 2 handlers differs on different event dispatchers void onAboutToBlock() { if (abouttoblock) { abouttoblock->deleteLater(); abouttoblock = nullptr; } ++m_aboutToBlocks; } W_SLOT(onAboutToBlock) void onAwake() { if (awake) { awake->deleteLater(); awake = nullptr; } ++m_awakes; } W_SLOT(onAwake) void onSignal1() { // Status check. At this point the event loop should have spinned enough to delete all the objects. QCOMPARE(*m_statusAwake, 2); QCOMPARE(*m_statusAboutToBlock, 2); QMetaObject::invokeMethod(m_eventLoop, "quit", Qt::QueuedConnection); } W_SLOT(onSignal1) private: StatusChanger *awake; StatusChanger *abouttoblock; QEventLoop *m_eventLoop; int *m_statusAwake; int *m_statusAboutToBlock; int m_aboutToBlocks; int m_awakes; }; W_OBJECT_IMPL(DispatcherWatcher) void tst_QObject::deleteLaterInAboutToBlockHandler() { int statusAwake = 1; int statusAboutToBlock = 1; QEventLoop e; DispatcherWatcher dw(e, &statusAwake, &statusAboutToBlock); QTimer::singleShot(2000, &dw, &DispatcherWatcher::onSignal1); QCOMPARE(statusAwake, 1); QCOMPARE(statusAboutToBlock, 1); e.exec(); QCOMPARE(statusAwake, 2); QCOMPARE(statusAboutToBlock, 2); } void tst_QObject::connectFunctorWithContextUnique() { // Qt::UniqueConnections currently don't work for functors, but we need to // be sure that they don't crash. If that is implemented, change this test. SenderObject sender; ReceiverObject receiver; QVERIFY(QObject::connect(&sender, &SenderObject::signal1, &receiver, &ReceiverObject::slot1)); receiver.count_slot1 = 0; #if QT_VERSION >= QT_VERSION_CHECK(6,3,0) QTest::ignoreMessage(QtWarningMsg, "QObject::connect(SenderObject, ReceiverObject): unique connections require a pointer to member function of a QObject subclass"); QVERIFY(!QObject::connect(&sender, &SenderObject::signal1, &receiver, [&](){ receiver.slot1(); }, Qt::UniqueConnection)); #else QObject::connect(&sender, &SenderObject::signal1, &receiver, SlotFunctor(), Qt::UniqueConnection); #endif sender.emitSignal1(); QCOMPARE(receiver.count_slot1, 1); } class MyFunctor { public: explicit MyFunctor(QObject *objectToDisconnect) : m_objectToDisconnect(objectToDisconnect) {} ~MyFunctor() { playWithObjects(); } void operator()() { // This will cause the slot object associated with this functor to be destroyed after // this function returns. That in turn will destroy this functor. // If our dtor runs with the signalSlotLock held, the bunch of connect() // performed there will deadlock trying to lock that lock again. m_objectToDisconnect->disconnect(); } private: QObject *m_objectToDisconnect; }; void tst_QObject::connectFunctorDeadlock() { SenderObject sender; MyFunctor functor(&sender); QObject::connect(&sender, &SenderObject::signal1, functor); sender.emitSignal1(); } void tst_QObject::connectFunctorMoveOnly() { struct MoveOnlyFunctor { Q_DISABLE_COPY(MoveOnlyFunctor) MoveOnlyFunctor(int *status) : status(status) {} MoveOnlyFunctor(MoveOnlyFunctor &&o) : status(o.status) { o.status = nullptr; }; void operator()(int i) { *status = i; } void operator()() { *status = -8; } int *status; }; int status = 1; SenderObject obj; QEventLoop e; connect(&obj, &SenderObject::signal1, MoveOnlyFunctor(&status)); QCOMPARE(status, 1); obj.signal1(); QCOMPARE(status, -8); connect(&obj, &SenderObject::signal7, MoveOnlyFunctor(&status)); QCOMPARE(status, -8); obj.signal7(7888, "Hello"); QCOMPARE(status, 7888); // With a context status = 1; connect(&obj, &SenderObject::signal2, this, MoveOnlyFunctor(&status)); QCOMPARE(status, 1); obj.signal2(); QCOMPARE(status, -8); // QueuedConnection status = 1; connect(&obj, &SenderObject::signal3, this, MoveOnlyFunctor(&status), Qt::QueuedConnection); obj.signal3(); QCOMPARE(status, 1); QCoreApplication::processEvents(); QCOMPARE(status, -8); } static int s_static_slot_checker = 1; class StaticSlotChecker : public QObject { W_OBJECT(StaticSlotChecker) public Q_SLOTS: static void staticSlot() { s_static_slot_checker = 2; } W_SLOT(staticSlot) }; void tst_QObject::connectStaticSlotWithObject() { SenderObject sender; StaticSlotChecker *receiver = new StaticSlotChecker; QEventLoop e; QVERIFY(connect(&sender, &SenderObject::signal1, receiver, &StaticSlotChecker::staticSlot, Qt::QueuedConnection)); connect(&sender, &SenderObject::signal1, &e, &QEventLoop::quit, Qt::QueuedConnection); sender.emitSignal1(); QCOMPARE(s_static_slot_checker, 1); e.exec(); QCOMPARE(s_static_slot_checker, 2); s_static_slot_checker = 1; connect(receiver, &QObject::destroyed, &sender, &SenderObject::signal1, Qt::QueuedConnection); receiver->deleteLater(); QCOMPARE(s_static_slot_checker, 1); e.exec(); QCOMPARE(s_static_slot_checker, 1); } struct ComplexFunctor { ComplexFunctor(int &overload, QList &result) : overload(overload), result(result) {} void operator()(int a, int b) { overload = 1; result << a << b; } void operator()(double a, double b) { overload = 2; result << a << b; } void operator()(const QString &s) { overload = 3; result << s; } void operator()(const QString &) const { Q_ASSERT(!"Should not be called because the non-const one should"); overload = -1; } template void operator()(const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4) { overload = 4; result << QVariant::fromValue(t1) << QVariant::fromValue(t2) << QVariant::fromValue(t3) << QVariant::fromValue(t4); } int &overload; QList &result; protected: void operator()() const { Q_ASSERT(!"Should not be called because it is protected"); overload = -1; } }; struct ComplexFunctorDeriv : ComplexFunctor { ComplexFunctorDeriv(int &overload, QList &result) : ComplexFunctor(overload, result) {} void operator()() const { overload = 10; } void operator()(int a, int b) { overload = 11; result << a << b; } using ComplexFunctor::operator(); private: void operator()(int) { Q_ASSERT(!"Should not be called because it is private"); overload = -1; } }; class FunctorArgDifferenceObject : public QObject { W_OBJECT(FunctorArgDifferenceObject) signals: void signal_ii(int a,int b) W_SIGNAL(signal_ii,a,b) void signal_iiS(int a,int b, const QString &c) W_SIGNAL(signal_iiS,a,b,c) void signal_dd(double a,double b) W_SIGNAL(signal_dd,a,b) void signal_ddS(double a,double b, const QString &c) W_SIGNAL(signal_ddS,a,b,c) void signal_S(const QString &a) W_SIGNAL(signal_S,a) void signal_SSSS(const QString &a, const QString &c, const QString &d, const QString &e) W_SIGNAL(signal_SSSS,a,c,d,e) void signal_iiSS(int a, int b, const QString &c, const QString &d) W_SIGNAL(signal_iiSS,a,b,c,d) void signal_VV(const QVariant &a, const QVariant &b) W_SIGNAL(signal_VV,a,b) }; template void connectFunctorOverload_impl(Signal signal, int expOverload, QList expResult) { FunctorArgDifferenceObject obj; int overload; QList result; QVERIFY(QObject::connect(&obj, signal, Functor(overload, result))); obj.signal_ii(1,2); obj.signal_iiS(3,4,"5"); obj.signal_dd(6.6,7.7); obj.signal_ddS(8.8,9.9,"10"); obj.signal_S("11"); obj.signal_SSSS("12", "13", "14", "15"); obj.signal_iiSS(16, 17, "18", "19"); obj.signal_VV(20,21); QCOMPARE(overload, expOverload); QCOMPARE(result, expResult); } void tst_QObject::connectFunctorOverloads() { #if defined (Q_COMPILER_VARIADIC_TEMPLATES) connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_ii, 1, (QList() << 1 << 2)); connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_iiS, 1, (QList() << 3 << 4)); connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_dd, 2, (QList() << 6.6 << 7.7)); connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_ddS, 2, (QList() << 8.8 << 9.9)); connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_S, 3, (QList() << QString("11"))); connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_SSSS, 4, (QList() << QString("12") << QString("13") << QString("14") << QString("15"))); connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_iiSS, 4, (QList() << 16 << 17 << QString("18") << QString("19"))); connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_ii, 11, (QList() << 1 << 2)); connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_iiS, 11, (QList() << 3 << 4)); connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_dd, 2, (QList() << 6.6 << 7.7)); connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_ddS, 2, (QList() << 8.8 << 9.9)); connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_S, 3, (QList() << QString("11"))); connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_SSSS, 4, (QList() << QString("12") << QString("13") << QString("14") << QString("15"))); connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_iiSS, 4, (QList() << 16 << 17 << QString("18") << QString("19"))); connectFunctorOverload_impl(&FunctorArgDifferenceObject::signal_VV, 10, (QList())); #else QSKIP("Does not compile without C++11 variadic template"); #endif } class GetSenderObject : public QObject { W_OBJECT(GetSenderObject) public: using QObject::sender; // make public public Q_SLOTS: void triggerSignal() { Q_EMIT aSignal(); } W_SLOT(triggerSignal) Q_SIGNALS: void aSignal() W_SIGNAL(aSignal) }; static int countedStructObjectsCount = 0; struct CountedStruct { CountedStruct() : sender(nullptr) { ++countedStructObjectsCount; } CountedStruct(GetSenderObject *sender) : sender(sender) { ++countedStructObjectsCount; } CountedStruct(const CountedStruct &o) : sender(o.sender) { ++countedStructObjectsCount; } CountedStruct &operator=(const CountedStruct &) { return *this; } // calling sender() here allows us to check if there's a deadlock ~CountedStruct() { --countedStructObjectsCount; if (sender) (void)sender->sender(); } void operator()() const { } GetSenderObject *sender; }; void tst_QObject::disconnectDoesNotLeakFunctor() { QCOMPARE(countedStructObjectsCount, 0); { GetSenderObject obj; QMetaObject::Connection c; { CountedStruct s(&obj); QCOMPARE(countedStructObjectsCount, 1); c = connect(&obj, &GetSenderObject::aSignal, s); QVERIFY(c); QCOMPARE(countedStructObjectsCount, 2); QVERIFY(QObject::disconnect(c)); QCOMPARE(countedStructObjectsCount, 1); } QCOMPARE(countedStructObjectsCount, 0); } QCOMPARE(countedStructObjectsCount, 0); { GetSenderObject obj; QMetaObject::Connection c; { CountedStruct s(&obj); QObject context; QCOMPARE(countedStructObjectsCount, 1); c = connect(&obj, &GetSenderObject::aSignal, &context, s); QVERIFY(c); QCOMPARE(countedStructObjectsCount, 2); QVERIFY(QObject::disconnect(c)); QCOMPARE(countedStructObjectsCount, 1); } QCOMPARE(countedStructObjectsCount, 0); } QCOMPARE(countedStructObjectsCount, 0); { QMetaObject::Connection c1, c2; { CountedStruct s; QCOMPARE(countedStructObjectsCount, 1); QTimer timer; c1 = connect(&timer, &QTimer::timeout, s); QVERIFY(c1); c2 = c1; QVERIFY(c2); QCOMPARE(countedStructObjectsCount, 2); QVERIFY(QObject::disconnect(c1)); QVERIFY(!c1); QVERIFY(!c2); // functor object has been destroyed QCOMPARE(countedStructObjectsCount, 1); QVERIFY(!QObject::disconnect(c2)); QCOMPARE(countedStructObjectsCount, 1); } QCOMPARE(countedStructObjectsCount, 0); } QCOMPARE(countedStructObjectsCount, 0); { CountedStruct s; QCOMPARE(countedStructObjectsCount, 1); QTimer timer; QMetaObject::Connection c = connect(&timer, &QTimer::timeout, s); QVERIFY(c); QCOMPARE(countedStructObjectsCount, 2); QVERIFY(QObject::disconnect(c)); QCOMPARE(countedStructObjectsCount, 1); } QCOMPARE(countedStructObjectsCount, 0); { QTimer timer; QMetaObject::Connection c = connect(&timer, &QTimer::timeout, CountedStruct()); QVERIFY(c); QCOMPARE(countedStructObjectsCount, 1); // only one instance, in Qt internals QVERIFY(QObject::disconnect(c)); QCOMPARE(countedStructObjectsCount, 0); // functor being destroyed } QCOMPARE(countedStructObjectsCount, 0); { QTimer *timer = new QTimer; QEventLoop e; connect(timer, &QTimer::timeout, CountedStruct()); QCOMPARE(countedStructObjectsCount, 1); // only one instance, in Qt internals timer->deleteLater(); connect(timer, &QObject::destroyed, &e, &QEventLoop::quit, Qt::QueuedConnection); e.exec(); QCOMPARE(countedStructObjectsCount, 0); // functor being destroyed } QCOMPARE(countedStructObjectsCount, 0); { GetSenderObject obj; connect(&obj, &GetSenderObject::aSignal, CountedStruct(&obj)); QCOMPARE(countedStructObjectsCount, 1); } QCOMPARE(countedStructObjectsCount, 0); { GetSenderObject obj; connect(&obj, &GetSenderObject::aSignal, CountedStruct(&obj)); QCOMPARE(countedStructObjectsCount, 1); QObject::disconnect(&obj, &GetSenderObject::aSignal, 0, 0); } QCOMPARE(countedStructObjectsCount, 0); { CountedStruct s; QCOMPARE(countedStructObjectsCount, 1); QTimer timer; QMetaObject::Connection c = connect(&timer, &QTimer::timeout, [s](){}); QVERIFY(c); QCOMPARE(countedStructObjectsCount, 2); QVERIFY(QObject::disconnect(c)); QCOMPARE(countedStructObjectsCount, 1); } QCOMPARE(countedStructObjectsCount, 0); } void tst_QObject::contextDoesNotLeakFunctor() { QCOMPARE(countedStructObjectsCount, 0); { QMetaObject::Connection c; { QEventLoop e; ContextObject *context = new ContextObject; SenderObject obj; connect(&obj, &SenderObject::signal1, context, CountedStruct()); connect(context, &QObject::destroyed, &e, &QEventLoop::quit, Qt::QueuedConnection); context->deleteLater(); QCOMPARE(countedStructObjectsCount, 1); e.exec(); QCOMPARE(countedStructObjectsCount, 0); } QCOMPARE(countedStructObjectsCount, 0); } QCOMPARE(countedStructObjectsCount, 0); { GetSenderObject obj; QMetaObject::Connection c; { CountedStruct s(&obj); QEventLoop e; ContextObject *context = new ContextObject; QCOMPARE(countedStructObjectsCount, 1); connect(&obj, &GetSenderObject::aSignal, context, s); QCOMPARE(countedStructObjectsCount, 2); connect(context, &QObject::destroyed, &e, &QEventLoop::quit, Qt::QueuedConnection); context->deleteLater(); e.exec(); QCOMPARE(countedStructObjectsCount, 1); } QCOMPARE(countedStructObjectsCount, 0); } QCOMPARE(countedStructObjectsCount, 0); { CountedStruct s; QEventLoop e; ContextObject *context = new ContextObject; QCOMPARE(countedStructObjectsCount, 1); QTimer timer; connect(&timer, &QTimer::timeout, context, [s](){}); QCOMPARE(countedStructObjectsCount, 2); connect(context, &QObject::destroyed, &e, &QEventLoop::quit, Qt::QueuedConnection); context->deleteLater(); e.exec(); QCOMPARE(countedStructObjectsCount, 1); } QCOMPARE(countedStructObjectsCount, 0); } class SubSender : public SenderObject { W_OBJECT(SubSender) }; void tst_QObject::connectBase() { SubSender sub; ReceiverObject r1; r1.reset(); QVERIFY( connect( &sub, &SubSender::signal1 , &r1, &ReceiverObject::slot1 ) ); QVERIFY( connect( &sub, static_cast(&SubSender::signal2) , &r1, &ReceiverObject::slot2 ) ); QVERIFY( connect( &sub, static_cast(&SubSender::signal3) , &r1, &ReceiverObject::slot3 ) ); sub.emitSignal1(); sub.emitSignal2(); sub.emitSignal3(); QCOMPARE( r1.count_slot1, 1 ); QCOMPARE( r1.count_slot2, 1 ); QCOMPARE( r1.count_slot3, 1 ); QVERIFY( QObject::disconnect( &sub, &SubSender::signal1 , &r1, &ReceiverObject::slot1 ) ); QVERIFY( QObject::disconnect( &sub, static_cast(&SubSender::signal2) , &r1, &ReceiverObject::slot2 ) ); QVERIFY( QObject::disconnect( &sub, static_cast(&SubSender::signal3) , &r1, &ReceiverObject::slot3 ) ); sub.emitSignal1(); sub.emitSignal2(); sub.emitSignal3(); QCOMPARE( r1.count_slot1, 1 ); QCOMPARE( r1.count_slot2, 1 ); QCOMPARE( r1.count_slot3, 1 ); } void tst_QObject::connectWarnings() { SubSender sub; SenderObject obj; ReceiverObject r1; r1.reset(); QTest::ignoreMessage(QtWarningMsg, "QObject::connect(SenderObject, ReceiverObject): invalid nullptr parameter"); connect(static_cast(nullptr), &SubSender::signal1, &r1, &ReceiverObject::slot1); QTest::ignoreMessage(QtWarningMsg, "QObject::connect(SubSender, Unknown): invalid nullptr parameter"); connect(&sub, &SubSender::signal1, static_cast(nullptr), &ReceiverObject::slot1); QTest::ignoreMessage(QtWarningMsg, "QObject::connect(SenderObject, ReceiverObject): invalid nullptr parameter"); connect(static_cast(nullptr), &SenderObject::signal1, &r1, &ReceiverObject::slot1); QTest::ignoreMessage(QtWarningMsg, "QObject::connect(SenderObject, Unknown): invalid nullptr parameter"); connect(&obj, &SenderObject::signal1, static_cast(nullptr), &ReceiverObject::slot1); } struct QmlReceiver : public QtPrivate::QSlotObjectBase { int callCount; void *magic; QmlReceiver() : QtPrivate::QSlotObjectBase(&impl) , callCount(0) , magic(0) {} static void impl(int which, QSlotObjectBase *this_, QObject *, void **metaArgs, bool *ret) { switch (which) { case Destroy: delete static_cast(this_); return; case Call: static_cast(this_)->callCount++; return; case Compare: *ret = static_cast(this_)->magic == metaArgs[0]; return; case NumOperations: break; } } }; void tst_QObject::qmlConnect() { #ifdef QT_BUILD_INTERNAL SenderObject sender; QmlReceiver *receiver = new QmlReceiver; receiver->magic = receiver; receiver->ref(); QVERIFY(QObjectPrivate::connect(&sender, sender.metaObject()->indexOfSignal("signal1()"), receiver, Qt::AutoConnection)); QCOMPARE(receiver->callCount, 0); sender.emitSignal1(); QCOMPARE(receiver->callCount, 1); void *a[] = { receiver }; QVERIFY(QObjectPrivate::disconnect(&sender, sender.metaObject()->indexOfSignal("signal1()"), reinterpret_cast(&a))); sender.emitSignal1(); QCOMPARE(receiver->callCount, 1); receiver->destroyIfLastRef(); #else QSKIP("Needs QT_BUILD_INTERNAL"); #endif } #ifndef QT_NO_EXCEPTIONS class ObjectException : public std::exception { }; struct ThrowFunctor { CountedStruct operator()(const CountedStruct &, CountedStruct s2) const { throw ObjectException(); return s2; } CountedStruct s; }; #endif W_REGISTER_ARGTYPE(CountedStruct) class ExceptionThrower : public QObject { W_OBJECT(ExceptionThrower) public slots: CountedStruct throwException(const CountedStruct &, CountedStruct s2) { #ifndef QT_NO_EXCEPTIONS throw ObjectException(); #endif return s2; } W_SLOT(throwException) signals: CountedStruct mySignal(const CountedStruct &s1, CountedStruct s2) W_SIGNAL(mySignal,s1,s2) }; class CountedExceptionThrower : public QObject { W_OBJECT(CountedExceptionThrower) public: explicit CountedExceptionThrower(bool throwException, QObject *parent = nullptr) : QObject(parent) { Q_UNUSED(throwException); #ifndef QT_NO_EXCEPTIONS if (throwException) throw ObjectException(); #endif ++counter; } ~CountedExceptionThrower() { --counter; } static int counter; }; int CountedExceptionThrower::counter = 0; void tst_QObject::exceptions() { #ifndef QT_NO_EXCEPTIONS ReceiverObject receiver; // String based syntax { QCOMPARE(countedStructObjectsCount, 0); ExceptionThrower thrower; receiver.reset(); connect(&thrower, SIGNAL(mySignal(CountedStruct,CountedStruct)), &receiver, SLOT(slot1())); connect(&thrower, SIGNAL(mySignal(CountedStruct,CountedStruct)), &thrower, SLOT(throwException(CountedStruct,CountedStruct))); connect(&thrower, SIGNAL(mySignal(CountedStruct,CountedStruct)), &receiver, SLOT(slot2())); try { CountedStruct s; emit thrower.mySignal(s, s); QFAIL("Exception not thrown?"); } catch (ObjectException&) {} QCOMPARE(receiver.count_slot1, 1); QCOMPARE(receiver.count_slot2, 0); QCOMPARE(countedStructObjectsCount, 0); } // Pointer to member function { QCOMPARE(countedStructObjectsCount, 0); ExceptionThrower thrower; receiver.reset(); connect(&thrower, &ExceptionThrower::mySignal, &receiver, &ReceiverObject::slot1); connect(&thrower, &ExceptionThrower::mySignal, &thrower, &ExceptionThrower::throwException); connect(&thrower, &ExceptionThrower::mySignal, &receiver, &ReceiverObject::slot2); try { CountedStruct s; emit thrower.mySignal(s, s); QFAIL("Exception not thrown?"); } catch (ObjectException&) {} QCOMPARE(receiver.count_slot1, 1); QCOMPARE(receiver.count_slot2, 0); QCOMPARE(countedStructObjectsCount, 0); } // Functor { QCOMPARE(countedStructObjectsCount, 0); ExceptionThrower thrower; receiver.reset(); connect(&thrower, &ExceptionThrower::mySignal, &receiver, &ReceiverObject::slot1); connect(&thrower, &ExceptionThrower::mySignal, ThrowFunctor()); connect(&thrower, &ExceptionThrower::mySignal, &receiver, &ReceiverObject::slot2); try { CountedStruct s; emit thrower.mySignal(s, s); QFAIL("Exception not thrown?"); } catch (ObjectException&) {} QCOMPARE(receiver.count_slot1, 1); QCOMPARE(receiver.count_slot2, 0); QCOMPARE(countedStructObjectsCount, 1); // the Functor } QCOMPARE(countedStructObjectsCount, 0); // Child object reaping in case of exceptions thrown by constructors { QCOMPARE(CountedExceptionThrower::counter, 0); try { class ParentObject : public QObject { public: explicit ParentObject(QObject *parent = nullptr) : QObject(parent) { new CountedExceptionThrower(false, this); new CountedExceptionThrower(false, this); new CountedExceptionThrower(true, this); // throws } }; ParentObject p; QFAIL("Exception not thrown"); } catch (const ObjectException &) { } catch (...) { QFAIL("Wrong exception thrown"); } QCOMPARE(CountedExceptionThrower::counter, 0); try { QObject o; new CountedExceptionThrower(false, &o); new CountedExceptionThrower(false, &o); new CountedExceptionThrower(true, &o); // throws QFAIL("Exception not thrown"); } catch (const ObjectException &) { } catch (...) { QFAIL("Wrong exception thrown"); } QCOMPARE(CountedExceptionThrower::counter, 0); try { QObject o; CountedExceptionThrower c1(false, &o); CountedExceptionThrower c2(false, &o); CountedExceptionThrower c3(true, &o); // throws QFAIL("Exception not thrown"); } catch (const ObjectException &) { } catch (...) { QFAIL("Wrong exception thrown"); } QCOMPARE(CountedExceptionThrower::counter, 0); } #else QSKIP("Needs exceptions"); #endif } #if QT_VERSION < QT_VERSION_CHECK(6,2,0) #ifdef QT_BUILD_INTERNAL static bool parentChangeCalled = false; static void testParentChanged(QAbstractDeclarativeData *, QObject *, QObject *) { parentChangeCalled = true; } #endif void tst_QObject::noDeclarativeParentChangedOnDestruction() { #ifdef QT_BUILD_INTERNAL typedef void (*ParentChangedCallback)(QAbstractDeclarativeData *, QObject *, QObject *); QScopedValueRollback rollback(QAbstractDeclarativeData::parentChanged); QAbstractDeclarativeData::parentChanged = testParentChanged; QObject *parent = new QObject; QObject *child = new QObject; QAbstractDeclarativeData dummy; QObjectPrivate::get(child)->declarativeData = &dummy; parentChangeCalled = false; child->setParent(parent); QVERIFY(parentChangeCalled); parentChangeCalled = false; delete child; QVERIFY(!parentChangeCalled); delete parent; #else QSKIP("Needs QT_BUILD_INTERNAL"); #endif } #endif struct MutableFunctor { int count; MutableFunctor() : count(0) {} int operator()() { return ++count; } }; void tst_QObject::mutableFunctor() { ReturnValue o; MutableFunctor functor; QCOMPARE(functor.count, 0); connect(&o, &ReturnValue::returnInt, functor); QCOMPARE(emit o.returnInt(0), 1); QCOMPARE(emit o.returnInt(0), 2); // each emit should increase the internal count QCOMPARE(functor.count, 0); // but the original object should have been copied at connect time } void tst_QObject::checkArgumentsForNarrowing() { enum UnscopedEnum { UnscopedEnumV1 = INT_MAX, UnscopedEnumV2}; enum SignedUnscopedEnum { SignedUnscopedEnumV1 = INT_MIN, SignedUnscopedEnumV2 = INT_MAX }; static constexpr bool IsUnscopedEnumSigned = std::is_signed_v>; #define NARROWS_IF(x, y, test) static_assert((QtPrivate::AreArgumentsConvertibleWithoutNarrowingBase::value) != (test)) #define FITS_IF(x, y, test) static_assert((QtPrivate::AreArgumentsConvertibleWithoutNarrowingBase::value) == (test)) #define NARROWS(x, y) NARROWS_IF(x, y, true) #define FITS(x, y) FITS_IF(x, y, true) static_assert(sizeof(UnscopedEnum) <= sizeof(int)); static_assert(sizeof(SignedUnscopedEnum) <= sizeof(int)); // floating point to integral // GCC < 9 does not consider floating point to bool to be narrowing, // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65043 #if !defined(Q_CC_GNU) || Q_CC_GNU >= 900 NARROWS(float, bool); NARROWS(double, bool); NARROWS(long double, bool); #endif NARROWS(float, char); NARROWS(double, char); NARROWS(long double, char); NARROWS(float, short); NARROWS(double, short); NARROWS(long double, short); NARROWS(float, int); NARROWS(double, int); NARROWS(long double, int); NARROWS(float, long); NARROWS(double, long); NARROWS(long double, long); NARROWS(float, long long); NARROWS(double, long long); NARROWS(long double, long long); // floating point to a smaller floating point NARROWS(double, float); NARROWS(long double, float); FITS(float, double); FITS(float, long double); // GCC thinks this is narrowing only on architectures where // sizeof(long double) > sizeof(double) // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92856 #if defined(Q_CC_GNU) NARROWS_IF(long double, double, sizeof(long double) > sizeof(double)); #else NARROWS(long double, double); #endif FITS(double, long double); // integral to floating point NARROWS(bool, float); NARROWS(bool, double); NARROWS(bool, long double); NARROWS(char, float); NARROWS(char, double); NARROWS(char, long double); NARROWS(short, float); NARROWS(short, double); NARROWS(short, long double); NARROWS(int, float); NARROWS(int, double); NARROWS(int, long double); NARROWS(long, float); NARROWS(long, double); NARROWS(long, long double); NARROWS(long long, float); NARROWS(long long, double); NARROWS(long long, long double); // enum to floating point NARROWS(UnscopedEnum, float); NARROWS(UnscopedEnum, double); NARROWS(UnscopedEnum, long double); NARROWS(SignedUnscopedEnum, float); NARROWS(SignedUnscopedEnum, double); NARROWS(SignedUnscopedEnum, long double); // integral to smaller integral FITS(bool, bool); FITS(char, char); FITS(signed char, signed char); FITS(signed char, short); FITS(signed char, int); FITS(signed char, long); FITS(signed char, long long); FITS(unsigned char, unsigned char); FITS(unsigned char, unsigned short); FITS(unsigned char, unsigned int); FITS(unsigned char, unsigned long); FITS(unsigned char, unsigned long long); NARROWS_IF(bool, unsigned char, (sizeof(bool) > sizeof(char) || std::is_signed::value)); NARROWS_IF(bool, unsigned short, (sizeof(bool) > sizeof(short) || std::is_signed::value)); NARROWS_IF(bool, unsigned int, (sizeof(bool) > sizeof(int) || std::is_signed::value)); NARROWS_IF(bool, unsigned long, (sizeof(bool) > sizeof(long) || std::is_signed::value)); NARROWS_IF(bool, unsigned long long, (sizeof(bool) > sizeof(long long) || std::is_signed::value)); NARROWS_IF(short, char, (sizeof(short) > sizeof(char) || std::is_unsigned::value)); NARROWS_IF(short, unsigned char, (sizeof(short) > sizeof(char))); NARROWS_IF(short, signed char, (sizeof(short) > sizeof(char))); NARROWS_IF(unsigned short, char, (sizeof(short) > sizeof(char) || std::is_signed::value)); NARROWS_IF(unsigned short, unsigned char, (sizeof(short) > sizeof(char))); NARROWS_IF(unsigned short, signed char, (sizeof(short) > sizeof(char))); FITS(short, short); FITS(short, int); FITS(short, long); FITS(short, long long); FITS(unsigned short, unsigned short); FITS(unsigned short, unsigned int); FITS(unsigned short, unsigned long); FITS(unsigned short, unsigned long long); NARROWS_IF(int, char, (sizeof(int) > sizeof(char) || std::is_unsigned::value)); NARROWS(int, unsigned char); NARROWS_IF(int, signed char, (sizeof(int) > sizeof(char))); NARROWS_IF(int, short, (sizeof(int) > sizeof(short))); NARROWS(int, unsigned short); NARROWS_IF(unsigned int, char, (sizeof(int) > sizeof(char) || std::is_signed::value)); NARROWS_IF(unsigned int, unsigned char, (sizeof(int) > sizeof(char))); NARROWS(unsigned int, signed char); NARROWS(unsigned int, short); NARROWS_IF(unsigned int, unsigned short, (sizeof(int) > sizeof(short))); FITS(int, int); FITS(int, long); FITS(int, long long); FITS(unsigned int, unsigned int); FITS(unsigned int, unsigned long); FITS(unsigned int, unsigned long long); NARROWS_IF(long, char, (sizeof(long) > sizeof(char) || std::is_unsigned::value)); NARROWS(long, unsigned char); NARROWS_IF(long, signed char, (sizeof(long) > sizeof(char))); NARROWS_IF(long, short, (sizeof(long) > sizeof(short))); NARROWS(long, unsigned short); NARROWS_IF(long, int, (sizeof(long) > sizeof(int))); NARROWS(long, unsigned int); NARROWS_IF(unsigned long, char, (sizeof(long) > sizeof(char) || std::is_signed::value)); NARROWS_IF(unsigned long, unsigned char, (sizeof(long) > sizeof(char))); NARROWS(unsigned long, signed char); NARROWS(unsigned long, short); NARROWS_IF(unsigned long, unsigned short, (sizeof(long) > sizeof(short))); NARROWS(unsigned long, int); NARROWS_IF(unsigned long, unsigned int, (sizeof(long) > sizeof(int))); FITS(long, long); FITS(long, long long); FITS(unsigned long, unsigned long); FITS(unsigned long, unsigned long long); NARROWS_IF(long long, char, (sizeof(long long) > sizeof(char) || std::is_unsigned::value)); NARROWS(long long, unsigned char); NARROWS_IF(long long, signed char, (sizeof(long long) > sizeof(char))); NARROWS_IF(long long, short, (sizeof(long long) > sizeof(short))); NARROWS(long long, unsigned short); NARROWS_IF(long long, int, (sizeof(long long) > sizeof(int))); NARROWS(long long, unsigned int); NARROWS_IF(long long, long, (sizeof(long long) > sizeof(long))); NARROWS(long long, unsigned long); NARROWS_IF(unsigned long long, char, (sizeof(long long) > sizeof(char) || std::is_signed::value)); NARROWS_IF(unsigned long long, unsigned char, (sizeof(long long) > sizeof(char))); NARROWS(unsigned long long, signed char); NARROWS(unsigned long long, short); NARROWS_IF(unsigned long long, unsigned short, (sizeof(long long) > sizeof(short))); NARROWS(unsigned long long, int); NARROWS_IF(unsigned long long, unsigned int, (sizeof(long long) > sizeof(int))); NARROWS(unsigned long long, long); NARROWS_IF(unsigned long long, unsigned long, (sizeof(long long) > sizeof(long))); FITS(long long, long long); FITS(unsigned long long, unsigned long long); // integral to integral with different signedness. smaller ones tested above NARROWS(signed char, unsigned char); // Issue is reported to Green Hills, 2021-09-14. #if !defined(Q_CC_GHS) NARROWS(signed char, unsigned short); NARROWS(signed char, unsigned int); NARROWS(signed char, unsigned long); NARROWS(signed char, unsigned long long); #endif // Q_CC_GHS NARROWS(unsigned char, signed char); FITS(unsigned char, short); FITS(unsigned char, int); FITS(unsigned char, long); FITS(unsigned char, long long); NARROWS(short, unsigned short); #if !defined(Q_CC_GHS) NARROWS(short, unsigned int); NARROWS(short, unsigned long); NARROWS(short, unsigned long long); #endif // Q_CC_GHS NARROWS(unsigned short, short); FITS(unsigned short, int); FITS(unsigned short, long); FITS(unsigned short, long long); NARROWS(int, unsigned int); #if !defined(Q_CC_GHS) NARROWS(int, unsigned long); NARROWS(int, unsigned long long); #endif // Q_CC_GHS NARROWS(unsigned int, int); NARROWS_IF(unsigned int, long, (sizeof(int) >= sizeof(long))); FITS(unsigned int, long long); NARROWS(long, unsigned long); NARROWS(long, unsigned long long); NARROWS(unsigned long, long); NARROWS_IF(unsigned long, long long, (sizeof(long) >= sizeof(long long))); NARROWS(long long, unsigned long long); NARROWS(unsigned long long, long long); // enum to smaller integral // (note that we know that sizeof(UnscopedEnum) <= sizeof(int) FITS(UnscopedEnum, UnscopedEnum); FITS(SignedUnscopedEnum, SignedUnscopedEnum); NARROWS_IF(UnscopedEnum, char, ((sizeof(UnscopedEnum) > sizeof(char)) || (sizeof(UnscopedEnum) == sizeof(char) && IsUnscopedEnumSigned == std::is_signed::value))); NARROWS_IF(UnscopedEnum, signed char, ((sizeof(UnscopedEnum) > sizeof(char)) || (sizeof(UnscopedEnum) == sizeof(char) && !IsUnscopedEnumSigned))); NARROWS_IF(UnscopedEnum, unsigned char, ((sizeof(UnscopedEnum) > sizeof(char)) || IsUnscopedEnumSigned)); NARROWS_IF(UnscopedEnum, short, ((sizeof(UnscopedEnum) > sizeof(short)) || (sizeof(UnscopedEnum) == sizeof(short) && !IsUnscopedEnumSigned))); NARROWS_IF(UnscopedEnum, unsigned short, ((sizeof(UnscopedEnum) > sizeof(short)) || IsUnscopedEnumSigned)); NARROWS_IF(UnscopedEnum, int, sizeof(UnscopedEnum) > sizeof(int) || (sizeof(UnscopedEnum) == sizeof(int) && !IsUnscopedEnumSigned)); NARROWS_IF(UnscopedEnum, unsigned int, IsUnscopedEnumSigned); NARROWS_IF(UnscopedEnum, long, sizeof(UnscopedEnum) > sizeof(long) || (sizeof(UnscopedEnum) == sizeof(long) && !IsUnscopedEnumSigned)); NARROWS_IF(UnscopedEnum, unsigned long, IsUnscopedEnumSigned); NARROWS_IF(UnscopedEnum, long long, sizeof(UnscopedEnum) > sizeof(long long) || (sizeof(UnscopedEnum) == sizeof(long long) && !IsUnscopedEnumSigned)); NARROWS_IF(UnscopedEnum, unsigned long long, IsUnscopedEnumSigned); static_assert(std::is_signed::type>::value); NARROWS_IF(SignedUnscopedEnum, signed char, (sizeof(SignedUnscopedEnum) > sizeof(char))); NARROWS_IF(SignedUnscopedEnum, short, (sizeof(SignedUnscopedEnum) > sizeof(short))); FITS(SignedUnscopedEnum, int); FITS(SignedUnscopedEnum, long); FITS(SignedUnscopedEnum, long long); // other types which should be always unaffected FITS(void *, void *); FITS(QString, QString); FITS(QObject, QObject); FITS(QObject *, QObject *); FITS(const QObject *, const QObject *); FITS(std::nullptr_t, std::nullptr_t); // classes with conversion operators undergoing implicit conversions struct ConvertingToDouble { /* implicit */ operator double() const { return 42.0; } }; #if !defined(Q_CC_GHS) NARROWS(ConvertingToDouble, char); NARROWS(ConvertingToDouble, short); NARROWS(ConvertingToDouble, int); NARROWS(ConvertingToDouble, long); NARROWS(ConvertingToDouble, long long); NARROWS(ConvertingToDouble, float); #endif // Q_CC_GHS FITS(ConvertingToDouble, double); FITS(ConvertingToDouble, long double); // GCC, GHS and clang don't implement this properly yet: // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99625 // https://bugs.llvm.org/show_bug.cgi?id=49676 #if defined(Q_CC_MSVC) && !defined(Q_CC_CLANG) // at least since VS2017 struct ConstructibleFromInt { /* implicit */ ConstructibleFromInt(int) {} }; FITS(char, ConstructibleFromInt); FITS(short, ConstructibleFromInt); FITS(int, ConstructibleFromInt); NARROWS(unsigned int, ConstructibleFromInt); NARROWS_IF(long, ConstructibleFromInt, sizeof(long) > sizeof(int)); NARROWS_IF(long long, ConstructibleFromInt, sizeof(long long) > sizeof(int)); NARROWS(float, ConstructibleFromInt); NARROWS(double, ConstructibleFromInt); #endif // forward declared classes must work class ForwardDeclared; FITS(ForwardDeclared, ForwardDeclared); #if (defined(Q_CC_EXACTLY_GCC) && Q_CC_EXACTLY_GCC >= 1100) \ || (defined(Q_CC_CLANG) && Q_CC_CLANG >= 1100) \ || defined(Q_CC_MSVC) // at least since VS2017 { // wg21.link/P1957 NARROWS(char*, bool); NARROWS(void (QObject::*)(), bool); } #endif #undef NARROWS_IF #undef FITS_IF #undef NARROWS #undef FITS } void tst_QObject::nullReceiver() { QObject o; QObject *nullObj = nullptr; // Passing nullptr directly doesn't compile with gcc 4.8 QVERIFY(!connect(&o, &QObject::destroyed, nullObj, &QObject::deleteLater)); QVERIFY(!connect(&o, &QObject::destroyed, nullObj, [] {})); QVERIFY(!connect(&o, &QObject::destroyed, nullObj, Functor_noexcept())); 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::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::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::create(); auto c2 = QSharedPointer::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::create(); auto de = QSharedPointer::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 receiver(new QObject); auto s2 = QSharedPointer::create(); QPointer 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); // + δ } class ReceiverDisconnecting : public QObject { W_OBJECT(ReceiverDisconnecting) public: SenderObject *sender; int slotCalledCount = 0; public slots: void aSlotByName() { ++slotCalledCount; QVERIFY(!disconnect(sender, SIGNAL(signal1()), this, SLOT(aSlotByName()))); } W_SLOT(aSlotByName) void aSlotByPtr() { ++slotCalledCount; QVERIFY(!disconnect(sender, &SenderObject::signal1, this, &ReceiverDisconnecting::aSlotByPtr)); } W_SLOT(aSlotByPtr) }; class DeleteThisReceiver : public QObject { W_OBJECT(DeleteThisReceiver) public: static int counter; public slots: void deleteThis() { ++counter; delete this; } W_SLOT(deleteThis) }; int DeleteThisReceiver::counter = 0; void tst_QObject::singleShotConnection() { { // Non single shot behavior: slot called every time the signal is emitted SenderObject sender; QMetaObject::Connection c = connect(&sender, &SenderObject::signal1, &sender, &SenderObject::aPublicSlot); QVERIFY(c); QCOMPARE(sender.aPublicSlotCalled, 0); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 1); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 2); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 3); } { // Non single shot behavior: multiple connections cause multiple invocations SenderObject sender; QMetaObject::Connection c = connect(&sender, &SenderObject::signal1, &sender, &SenderObject::aPublicSlot); QVERIFY(c); QCOMPARE(sender.aPublicSlotCalled, 0); sender.emitSignal1(); QVERIFY(c); QCOMPARE(sender.aPublicSlotCalled, 1); sender.emitSignal1(); QVERIFY(c); QCOMPARE(sender.aPublicSlotCalled, 2); QMetaObject::Connection c2 = connect(&sender, &SenderObject::signal1, &sender, &SenderObject::aPublicSlot); QVERIFY(c); QVERIFY(c2); QCOMPARE(sender.aPublicSlotCalled, 2); sender.emitSignal1(); QVERIFY(c); QVERIFY(c2); QCOMPARE(sender.aPublicSlotCalled, 4); sender.emitSignal1(); QVERIFY(c); QVERIFY(c2); QCOMPARE(sender.aPublicSlotCalled, 6); } { // Single shot behavior: slot called only once SenderObject sender; QMetaObject::Connection c = connect(&sender, &SenderObject::signal1, &sender, &SenderObject::aPublicSlot, static_cast(Qt::SingleShotConnection)); QVERIFY(c); QCOMPARE(sender.aPublicSlotCalled, 0); sender.emitSignal1(); QVERIFY(!c); QCOMPARE(sender.aPublicSlotCalled, 1); sender.emitSignal1(); QVERIFY(!c); QCOMPARE(sender.aPublicSlotCalled, 1); sender.emitSignal1(); QVERIFY(!c); QCOMPARE(sender.aPublicSlotCalled, 1); } { // Same, without holding a Connection object SenderObject sender; bool ok = connect(&sender, &SenderObject::signal1, &sender, &SenderObject::aPublicSlot, static_cast(Qt::SingleShotConnection)); QVERIFY(ok); QCOMPARE(sender.aPublicSlotCalled, 0); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 1); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 1); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 1); } { // Single shot, disconnect before emitting SenderObject sender; QMetaObject::Connection c = connect(&sender, &SenderObject::signal1, &sender, &SenderObject::aPublicSlot, static_cast(Qt::SingleShotConnection)); QVERIFY(c); QCOMPARE(sender.aPublicSlotCalled, 0); QVERIFY(QObject::disconnect(c)); QVERIFY(!c); sender.emitSignal1(); QVERIFY(!c); QCOMPARE(sender.aPublicSlotCalled, 0); sender.emitSignal1(); QVERIFY(!c); QCOMPARE(sender.aPublicSlotCalled, 0); } { // Single shot together with another connection SenderObject sender; QVERIFY(connect(&sender, &SenderObject::signal1, &sender, &SenderObject::aPublicSlot)); QCOMPARE(sender.aPublicSlotCalled, 0); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 1); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 2); QVERIFY(connect(&sender, &SenderObject::signal1, &sender, &SenderObject::aPublicSlot, static_cast(Qt::SingleShotConnection))); QCOMPARE(sender.aPublicSlotCalled, 2); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 4); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 5); } { // Two single shot, from the same signal, to the same slot SenderObject sender; QVERIFY(connect(&sender, &SenderObject::signal1, &sender, &SenderObject::aPublicSlot, static_cast(Qt::SingleShotConnection))); QVERIFY(connect(&sender, &SenderObject::signal1, &sender, &SenderObject::aPublicSlot, static_cast(Qt::SingleShotConnection))); QCOMPARE(sender.aPublicSlotCalled, 0); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 2); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 2); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 2); } { // Two single shot, from different signals, to the same slot SenderObject sender; QVERIFY(connect(&sender, &SenderObject::signal1, &sender, &SenderObject::aPublicSlot, static_cast(Qt::SingleShotConnection))); QVERIFY(connect(&sender, &SenderObject::signal2, &sender, &SenderObject::aPublicSlot, static_cast(Qt::SingleShotConnection))); QCOMPARE(sender.aPublicSlotCalled, 0); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 1); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 1); sender.emitSignal2(); QCOMPARE(sender.aPublicSlotCalled, 2); sender.emitSignal2(); QCOMPARE(sender.aPublicSlotCalled, 2); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 2); } { // Same signal, different connections SenderObject sender; ReceiverObject receiver1, receiver2; receiver1.reset(); receiver2.reset(); QVERIFY(connect(&sender, &SenderObject::signal1, &receiver1, &ReceiverObject::slot1)); QVERIFY(connect(&sender, &SenderObject::signal1, &receiver2, &ReceiverObject::slot1, static_cast(Qt::SingleShotConnection))); QCOMPARE(receiver1.count_slot1, 0); QCOMPARE(receiver2.count_slot1, 0); sender.emitSignal1(); QCOMPARE(receiver1.count_slot1, 1); QCOMPARE(receiver2.count_slot1, 1); sender.emitSignal1(); QCOMPARE(receiver1.count_slot1, 2); QCOMPARE(receiver2.count_slot1, 1); sender.emitSignal1(); QCOMPARE(receiver1.count_slot1, 3); QCOMPARE(receiver2.count_slot1, 1); // Reestablish a single shot QVERIFY(connect(&sender, &SenderObject::signal1, &receiver2, &ReceiverObject::slot1, static_cast(Qt::SingleShotConnection))); QCOMPARE(receiver1.count_slot1, 3); QCOMPARE(receiver2.count_slot1, 1); sender.emitSignal1(); QCOMPARE(receiver1.count_slot1, 4); QCOMPARE(receiver2.count_slot1, 2); sender.emitSignal1(); QCOMPARE(receiver1.count_slot1, 5); QCOMPARE(receiver2.count_slot1, 2); } { // Check that the slot is invoked with the connection already disconnected SenderObject sender; QMetaObject::Connection c; auto breakSlot = [&]() { QVERIFY(!c); ++sender.aPublicSlotCalled; }; c = connect(&sender, &SenderObject::signal1, &sender, breakSlot, static_cast(Qt::SingleShotConnection)); QVERIFY(c); QCOMPARE(sender.aPublicSlotCalled, 0); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 1); QVERIFY(!c); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 1); QVERIFY(!c); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 1); QVERIFY(!c); } { // Same SenderObject sender; ReceiverDisconnecting receiver; receiver.sender = &sender; bool ok = connect(&sender, SIGNAL(signal1()), &receiver, SLOT(aSlotByName()), static_cast(Qt::SingleShotConnection)); QVERIFY(ok); QCOMPARE(receiver.slotCalledCount, 0); sender.emitSignal1(); QCOMPARE(receiver.slotCalledCount, 1); sender.emitSignal1(); QCOMPARE(receiver.slotCalledCount, 1); // reconnect ok = connect(&sender, SIGNAL(signal1()), &receiver, SLOT(aSlotByName()), static_cast(Qt::SingleShotConnection)); QVERIFY(ok); QCOMPARE(receiver.slotCalledCount, 1); sender.emitSignal1(); QCOMPARE(receiver.slotCalledCount, 2); sender.emitSignal1(); QCOMPARE(receiver.slotCalledCount, 2); } { // Same SenderObject sender; ReceiverDisconnecting receiver; receiver.sender = &sender; bool ok = connect(&sender, &SenderObject::signal1, &receiver, &ReceiverDisconnecting::aSlotByPtr, static_cast(Qt::SingleShotConnection)); QVERIFY(ok); QCOMPARE(receiver.slotCalledCount, 0); sender.emitSignal1(); QCOMPARE(receiver.slotCalledCount, 1); sender.emitSignal1(); QCOMPARE(receiver.slotCalledCount, 1); // reconnect ok = connect(&sender, &SenderObject::signal1, &receiver, &ReceiverDisconnecting::aSlotByPtr, static_cast(Qt::SingleShotConnection)); QVERIFY(ok); QCOMPARE(receiver.slotCalledCount, 1); sender.emitSignal1(); QCOMPARE(receiver.slotCalledCount, 2); sender.emitSignal1(); QCOMPARE(receiver.slotCalledCount, 2); } { // Reconnect from inside the slot SenderObject sender; std::function reconnectingSlot; bool reconnect = false; reconnectingSlot = [&]() { ++sender.aPublicSlotCalled; if (reconnect) { QObject::connect(&sender, &SenderObject::signal1, &sender, reconnectingSlot, static_cast(Qt::SingleShotConnection)); } }; bool ok = connect(&sender, &SenderObject::signal1, &sender, reconnectingSlot, static_cast(Qt::SingleShotConnection)); QVERIFY(ok); QCOMPARE(sender.aPublicSlotCalled, 0); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 1); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 1); reconnect = true; ok = connect(&sender, &SenderObject::signal1, &sender, reconnectingSlot, static_cast(Qt::SingleShotConnection)); QVERIFY(ok); QCOMPARE(sender.aPublicSlotCalled, 1); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 2); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 3); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 4); reconnect = false; sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 5); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 5); } { // Delete the receiver from inside the slot SenderObject sender; QPointer p = new DeleteThisReceiver; DeleteThisReceiver::counter = 0; QVERIFY(connect(&sender, &SenderObject::signal1, p.get(), &DeleteThisReceiver::deleteThis, static_cast(Qt::SingleShotConnection))); QVERIFY(p); QCOMPARE(DeleteThisReceiver::counter, 0); sender.emitSignal1(); QCOMPARE(DeleteThisReceiver::counter, 1); QVERIFY(!p); sender.emitSignal1(); QCOMPARE(DeleteThisReceiver::counter, 1); QVERIFY(!p); } { // Queued, non single shot SenderObject sender; QVERIFY(connect(&sender, &SenderObject::signal1, &sender, &SenderObject::aPublicSlot, static_cast(Qt::QueuedConnection))); QCOMPARE(sender.aPublicSlotCalled, 0); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 0); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 0); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 0); QTRY_COMPARE(sender.aPublicSlotCalled, 3); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 3); QTRY_COMPARE(sender.aPublicSlotCalled, 4); } { // Queued, single shot SenderObject sender; QVERIFY(connect(&sender, &SenderObject::signal1, &sender, &SenderObject::aPublicSlot, static_cast(Qt::QueuedConnection | Qt::SingleShotConnection))); QCOMPARE(sender.aPublicSlotCalled, 0); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 0); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 0); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 0); QTRY_COMPARE(sender.aPublicSlotCalled, 1); QTest::qWait(0); QCOMPARE(sender.aPublicSlotCalled, 1); } { // Queued, single shot, checking the connection handle SenderObject sender; QMetaObject::Connection c = connect(&sender, &SenderObject::signal1, &sender, &SenderObject::aPublicSlot, static_cast(Qt::QueuedConnection | Qt::SingleShotConnection)); QVERIFY(c); QCOMPARE(sender.aPublicSlotCalled, 0); sender.emitSignal1(); QVERIFY(!c); QCOMPARE(sender.aPublicSlotCalled, 0); sender.emitSignal1(); QVERIFY(!c); QCOMPARE(sender.aPublicSlotCalled, 0); sender.emitSignal1(); QVERIFY(!c); QCOMPARE(sender.aPublicSlotCalled, 0); QTRY_COMPARE(sender.aPublicSlotCalled, 1); QVERIFY(!c); QTest::qWait(0); QVERIFY(!c); QCOMPARE(sender.aPublicSlotCalled, 1); } { // Queued, single shot, disconnect before emitting SenderObject sender; QVERIFY(connect(&sender, &SenderObject::signal1, &sender, &SenderObject::aPublicSlot, static_cast(Qt::QueuedConnection | Qt::SingleShotConnection))); QCOMPARE(sender.aPublicSlotCalled, 0); QVERIFY(QObject::disconnect(&sender, &SenderObject::signal1, &sender, &SenderObject::aPublicSlot)); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 0); sender.emitSignal1(); QCOMPARE(sender.aPublicSlotCalled, 0); QTest::qWait(0); QCOMPARE(sender.aPublicSlotCalled, 0); } { // Queued, single shot, disconnect before emitting by using the connection handle SenderObject sender; QMetaObject::Connection c = connect(&sender, &SenderObject::signal1, &sender, &SenderObject::aPublicSlot, static_cast(Qt::QueuedConnection | Qt::SingleShotConnection)); QVERIFY(c); QCOMPARE(sender.aPublicSlotCalled, 0); QVERIFY(QObject::disconnect(c)); QVERIFY(!c); sender.emitSignal1(); QVERIFY(!c); QCOMPARE(sender.aPublicSlotCalled, 0); sender.emitSignal1(); QVERIFY(!c); QCOMPARE(sender.aPublicSlotCalled, 0); QTest::qWait(0); QVERIFY(!c); QCOMPARE(sender.aPublicSlotCalled, 0); } { // Queued, single shot, delete the receiver from inside the slot SenderObject sender; QPointer p = new DeleteThisReceiver; DeleteThisReceiver::counter = 0; QVERIFY(connect(&sender, &SenderObject::signal1, p.get(), &DeleteThisReceiver::deleteThis, static_cast(Qt::QueuedConnection | Qt::SingleShotConnection))); QCOMPARE(DeleteThisReceiver::counter, 0); sender.emitSignal1(); QVERIFY(p); QCOMPARE(DeleteThisReceiver::counter, 0); sender.emitSignal1(); QVERIFY(p); QCOMPARE(DeleteThisReceiver::counter, 0); sender.emitSignal1(); QVERIFY(p); QCOMPARE(DeleteThisReceiver::counter, 0); QTRY_COMPARE(DeleteThisReceiver::counter, 1); QVERIFY(!p); QTest::qWait(0); QCOMPARE(DeleteThisReceiver::counter, 1); QVERIFY(!p); } } #if QT_VERSION >= QT_VERSION_CHECK(6,2,0) void tst_QObject::objectNameBinding() { QObject obj; QTestPrivate::testReadWritePropertyBasics(obj, "test1", "test2", "objectName"); } #endif #if QT_VERSION >= QT_VERSION_CHECK(6,3,0) namespace EmitToDestroyedClass { static int assertionCallCount = 0; static int wouldHaveAssertedCount = 0; struct WouldAssert : std::exception {}; class Base : public QObject { W_OBJECT(Base) public: ~Base() { try { emit theSignal(); } catch (const WouldAssert &) { ++wouldHaveAssertedCount; } } void theSignal() W_SIGNAL(theSignal) }; class Derived : public Base { W_OBJECT(Derived) public: ~Derived() { } void doNothing() {} W_SLOT(doNothing) }; } // namespace EmitToDestroyedClass QT_BEGIN_NAMESPACE namespace QtPrivate { template<> void assertObjectType(QObject *o) { // override the assertion so we don't assert and so something does happen // when assertions are disabled. By throwing, we also prevent the UB from // happening. using namespace EmitToDestroyedClass; ++assertionCallCount; if (!qobject_cast(o)) throw WouldAssert(); } } // namespace QtPrivate QT_END_NAMESPACE void tst_QObject::emitToDestroyedClass() { using namespace EmitToDestroyedClass; std::unique_ptr ptr = std::make_unique(); QObject::connect(ptr.get(), &Base::theSignal, ptr.get(), &Derived::doNothing); QCOMPARE(assertionCallCount, 0); QCOMPARE(wouldHaveAssertedCount, 0); // confirm our replacement function did get called emit ptr->theSignal(); QCOMPARE(assertionCallCount, 1); QCOMPARE(wouldHaveAssertedCount, 0); ptr.reset(); QCOMPARE(assertionCallCount, 2); QCOMPARE(wouldHaveAssertedCount, 1); } #endif // Test for QtPrivate::HasQ_OBJECT_Macro static_assert(QtPrivate::HasQ_OBJECT_Macro::Value); static_assert(!QtPrivate::HasQ_OBJECT_Macro::Value); QTEST_MAIN(tst_QObject) W_OBJECT_IMPL(tst_QObject) W_OBJECT_IMPL(SenderObject) W_OBJECT_IMPL(ReceiverObject) W_OBJECT_IMPL(AutoConnectSender) W_OBJECT_IMPL(AutoConnectReceiver) W_OBJECT_IMPL(QObjectWithIncomplete) W_OBJECT_IMPL(ConnectByNameNotifySenderObject) W_OBJECT_IMPL(ConnectByNameNotifyReceiverObject) W_OBJECT_IMPL(ConnectDisconnectNotifyShadowObject) W_OBJECT_IMPL(SequenceObject) W_OBJECT_IMPL(QCustomTypeChecker) W_OBJECT_IMPL(PropertyObject) W_OBJECT_IMPL(TestThread) W_OBJECT_IMPL(MoveToThreadObject) W_OBJECT_IMPL(QObjectTest::TestObject) W_OBJECT_IMPL(SuperObject) W_OBJECT_IMPL(FooObject) W_OBJECT_IMPL(BlehObject) W_OBJECT_IMPL(DestroyedListener) W_OBJECT_IMPL(DefaultArguments) W_OBJECT_IMPL(NormalizeObject) W_OBJECT_IMPL(EventSpy) W_OBJECT_IMPL(EmitThread) W_OBJECT_IMPL(QObjectTest::DeleteObject) W_OBJECT_IMPL(DisconnectObject) W_OBJECT_IMPL(ConnectToSender) W_OBJECT_IMPL(OverloadObject) W_OBJECT_IMPL(ManySignals) W_OBJECT_IMPL(ConfusingObject) W_OBJECT_IMPL(Constructable) W_OBJECT_IMPL(BaseDestroyed) W_OBJECT_IMPL(LotsOfSignalsAndSlots) W_OBJECT_IMPL(StringVariant) W_OBJECT_IMPL(ConnectWithReferenceObject) W_OBJECT_IMPL(ManyArgumentObject) W_OBJECT_IMPL(ForwardDeclareArguments) W_GADGET_IMPL(NoDefaultConstructor) W_OBJECT_IMPL(NoDefaultContructorArguments) W_OBJECT_IMPL(ReturnValue) W_OBJECT_IMPL(VirtualSlotsObjectBase) W_OBJECT_IMPL(VirtualSlotsObject) #ifdef QT_BUILD_INTERNAL W_OBJECT_IMPL(ConnectToPrivateSlot) #endif W_OBJECT_IMPL(ContextObject) W_OBJECT_IMPL(StaticSlotChecker) W_OBJECT_IMPL(FunctorArgDifferenceObject) W_OBJECT_IMPL(GetSenderObject) W_OBJECT_IMPL(SubSender) W_OBJECT_IMPL(CountedExceptionThrower) W_OBJECT_IMPL(ReceiverDisconnecting) W_OBJECT_IMPL(ExceptionThrower) W_OBJECT_IMPL(DeleteThisReceiver) #if QT_VERSION >= QT_VERSION_CHECK(6,3,0) W_OBJECT_IMPL(EmitToDestroyedClass::Base) W_OBJECT_IMPL(EmitToDestroyedClass::Derived) #endif verdigris-1.3/tests/qt/qt.pro000066400000000000000000000001261427643277200163240ustar00rootroot00000000000000TEMPLATE = subdirs SUBDIRS = qmetaobject qobject qmetamethod qmetaproperty qmetaenum verdigris-1.3/tests/qt/qt.qbs000066400000000000000000000002761427643277200163170ustar00rootroot00000000000000import qbs Project { name: "tests" references: [ "qmetaenum", "qmetamethod", "qmetaobject", "qmetaproperty", "qobject" ] } verdigris-1.3/tests/templates/000077500000000000000000000000001427643277200165315ustar00rootroot00000000000000verdigris-1.3/tests/templates/templates.pro000066400000000000000000000001711427643277200212500ustar00rootroot00000000000000CONFIG += testcase TARGET = tst_templates QT = core testlib SOURCES = tst_templates.cpp include(../../src/verdigris.pri) verdigris-1.3/tests/templates/templates.qbs000066400000000000000000000003671427643277200212440ustar00rootroot00000000000000import qbs Application { name: "templates" consoleApplication: true type: ["application", "autotest"] Depends { name: "Verdigris" } Depends { name: "Qt.test" } files: [ "tst_templates.cpp", ] } verdigris-1.3/tests/templates/tst_templates.cpp000066400000000000000000000254661427643277200221420ustar00rootroot00000000000000/**************************************************************************** * Copyright (C) 2013-2015 Woboq GmbH * Olivier Goffart * https://woboq.com/ * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. * If not, see . */ #include #include class tst_Templates : public QObject { W_OBJECT(tst_Templates) private slots: // from https://codereview.qt-project.org/49864/ void templatesMethod_data(); W_SLOT(templatesMethod_data, W_Access::Private) void templatesMethod(); W_SLOT(templatesMethod, W_Access::Private) // from https://codereview.qt-project.org/49866/ void connectTemplate(); W_SLOT(connectTemplate, W_Access::Private) void gadget(); W_SLOT(gadget, W_Access::Private) void smartPointer(); W_SLOT(smartPointer, W_Access::Private) }; #include struct MyStruct {}; struct MyStruct2 {}; Q_DECLARE_METATYPE(MyStruct) Q_DECLARE_METATYPE(MyStruct*) W_REGISTER_ARGTYPE(MyStruct) W_REGISTER_ARGTYPE(MyStruct*) template 5), class S = void> class TestTemplate : public QObject { W_OBJECT(TestTemplate) public: void mySlot(const T&) {} W_SLOT(mySlot,(const T&)) //signals: void mySignal(const T& t) W_SIGNAL(mySignal,(const T&), t) }; template class TestTemplate2 : public TestTemplate { W_OBJECT(TestTemplate2) public: void sl2() {} W_SLOT(sl2) //signals: void si2() W_SIGNAL(si2) }; template class FunctionTemplateParameter : public QObject { W_OBJECT(FunctionTemplateParameter) QString member; W_PROPERTY(QString, member MEMBER member) public: //signals: void hello() W_SIGNAL(hello) }; template class Container1, template class, #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) template class Container3> #else template class Container3> #endif class TemplateTemplateParameter : public QObject { W_OBJECT(TemplateTemplateParameter) public: //signals: void hello() W_SIGNAL(hello) }; template struct ReduceKernel{}; struct Functor { typedef int result_type; }; template > class MappedReducedKernel : public QObject { W_OBJECT(MappedReducedKernel) public: // signals: void hello(Reducer*r) W_SIGNAL(hello,(Reducer*),r) }; Q_DECLARE_METATYPE(const QMetaObject*) void tst_Templates::templatesMethod_data() { QTest::addColumn("metaObject"); QTest::addColumn("method"); QTest::addColumn("exist"); typedef QByteArray _; QTest::newRow("TestTemplate mySlot(T)") << &TestTemplate::staticMetaObject << _("mySlot(T)") << false; QTest::newRow("TestTemplate mySlot(QString)") << &TestTemplate::staticMetaObject << _("mySlot(QString)") << true; QTest::newRow("TestTemplate mySlot(MyStruct)") << &TestTemplate::staticMetaObject << _("mySlot(MyStruct)") << false; QTest::newRow("TestTemplate mySignal(T)") << &TestTemplate::staticMetaObject << _("mySignal(T)") << false; QTest::newRow("TestTemplate mySignal(QString)") << &TestTemplate::staticMetaObject << _("mySignal(QString)") << true; QTest::newRow("TestTemplate mySignal(MyStruct)") << &TestTemplate::staticMetaObject << _("mySignal(MyStruct)") << false; QTest::newRow("TestTemplate mySlot(T)") << &TestTemplate::staticMetaObject << _("mySlot(T)") << false; QTest::newRow("TestTemplate mySlot(QString)") << &TestTemplate::staticMetaObject << _("mySlot(QString)") << false; QTest::newRow("TestTemplate mySlot(MyStruct)") << &TestTemplate::staticMetaObject << _("mySlot(MyStruct)") << true; QTest::newRow("TestTemplate mySignal(T)") << &TestTemplate::staticMetaObject << _("mySignal(T)") << false; QTest::newRow("TestTemplate mySignal(QString)") << &TestTemplate::staticMetaObject << _("mySignal(QString)") << false; QTest::newRow("TestTemplate mySignal(MyStruct)") << &TestTemplate::staticMetaObject << _("mySignal(MyStruct)") << true; QTest::newRow("TestTemplate2 mySlot(T)") << &TestTemplate2::staticMetaObject << _("mySlot(T)") << false; QTest::newRow("TestTemplate2 mySlot(QString)") << &TestTemplate2::staticMetaObject << _("mySlot(QString)") << true; QTest::newRow("FunctionTemplateParameter") << &FunctionTemplateParameter, QString, &TestTemplate::mySlot, &TestTemplate::mySignal>::staticMetaObject << _("hello()") << true; QTest::newRow("TemplateTemplateParameter") << &TemplateTemplateParameter::staticMetaObject << _("hello()") << true; QTest::newRow("MappedReducedKernel") << &MappedReducedKernel::staticMetaObject << _("hello(Reducer*)") << true; } void tst_Templates::templatesMethod() { QFETCH(const QMetaObject *, metaObject); QFETCH(QByteArray, method); QFETCH(bool, exist); int index = metaObject->indexOfMethod(method); QCOMPARE(index != -1, exist); } template class TemplateObject : public QObject { W_OBJECT(TemplateObject) public: // signals void signalTemplate(const T &t) W_SIGNAL(signalTemplate, t) void signalString(const QString & str) W_SIGNAL(signalString, str) public: void slotTemplate(const T &t) { result = QVariant::fromValue(t); count++; } W_SLOT(slotTemplate) void slotVariant(const QVariant &t) { result = t; count += 100; } W_SLOT(slotVariant) public: TemplateObject() : count(0) { } int count; QVariant result; }; void tst_Templates::connectTemplate() { TemplateObject oi; TemplateObject os; QVERIFY(QObject::connect(&oi, &TemplateObject::signalTemplate, &os, &TemplateObject::slotVariant)); oi.signalTemplate(25); QCOMPARE(os.count, 100); QCOMPARE(os.result, QVariant(25)); os.count = 0; QVERIFY(QObject::connect(&oi, &TemplateObject::signalString, &os, &TemplateObject::slotTemplate)); oi.signalString("hello"); QCOMPARE(os.count, 1); QCOMPARE(os.result, QVariant("hello")); os.count = 0; QVERIFY(QObject::connect(&os, &TemplateObject::signalTemplate, &oi, &TemplateObject::slotVariant)); os.signalTemplate("world"); QCOMPARE(oi.count, 100); QCOMPARE(oi.result, QVariant("world")); } template class TemplateGadget { W_GADGET(TemplateGadget) public: T data; T readData() { return data; } W_INVOKABLE(readData) void writeData(const T &d) { data = d; } W_INVOKABLE(writeData) W_PROPERTY(T, data READ readData WRITE writeData) QVariant readVariant() { return QVariant::fromValue(data); } W_INVOKABLE(readVariant) void writeVariant(const QVariant &d) { data = qvariant_cast(d); } W_INVOKABLE(writeVariant) W_PROPERTY(QVariant, variant READ readVariant WRITE writeVariant) }; template void testGadget(const T &val1) { TemplateGadget xx; const QMetaObject *mo = &xx.staticMetaObject; { auto id = mo->indexOfProperty("data"); QVERIFY(id >= 0); auto prop = mo->property(id); prop.writeOnGadget(&xx, QVariant::fromValue(val1)); QCOMPARE(xx.data, val1); QVariant v = prop.readOnGadget(&xx); QCOMPARE(v.value(), val1); } { auto id = mo->indexOfProperty("variant"); QVERIFY(id >= 0); auto prop = mo->property(id); prop.writeOnGadget(&xx, QVariant::fromValue(val1)); QCOMPARE(xx.data, val1); id = mo->indexOfMethod("readVariant()"); QVERIFY(id >= 0); auto meth = mo->method(id); QVariant v; meth.invokeOnGadget(&xx, Q_RETURN_ARG(QVariant, v)); QCOMPARE(v.value(), val1); } } void tst_Templates::gadget() { testGadget(34); testGadget(QString("hello")); testGadget(QByteArray("toto")); } #include namespace test { template class RegisterTemplate : public QObject { W_OBJECT(RegisterTemplate) }; using IntTest = RegisterTemplate; constexpr auto w_explicitObjectName(IntTest*) { return w_cpp::viewLiteral("IntTest"); } } // namespace test void tst_Templates::smartPointer() { auto smart_ptr = QSharedPointer{}; // note: this will fail if no w_explicitObjectName was registered auto var = QVariant::fromValue(smart_ptr); } QTEST_MAIN(tst_Templates) W_REGISTER_ARGTYPE(ReduceKernel*) #include W_OBJECT_IMPL(tst_Templates) W_OBJECT_IMPL((TestTemplate), template) W_OBJECT_IMPL(TestTemplate2, template) W_OBJECT_IMPL((FunctionTemplateParameter), template) #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) W_OBJECT_IMPL((TemplateTemplateParameter), template class C1, template class C2, template class C3>) #else W_OBJECT_IMPL((TemplateTemplateParameter), template class C1, template class C2, template class C3>) #endif W_OBJECT_IMPL((MappedReducedKernel), template ) W_OBJECT_IMPL(TemplateObject, template) W_GADGET_IMPL(TemplateGadget, template) W_OBJECT_IMPL((test::RegisterTemplate), template) verdigris-1.3/tests/tests.pro000066400000000000000000000001421427643277200164140ustar00rootroot00000000000000TEMPLATE = subdirs SUBDIRS += internal basic qt templates manyproperties !gcc:SUBDIRS += cppapi verdigris-1.3/tests/tests.qbs000066400000000000000000000003051427643277200164020ustar00rootroot00000000000000import qbs Project { name: "tests" references: [ "basic", "cppapi", "internal", "manyproperties", "qt", "templates", ] } verdigris-1.3/tutorial/000077500000000000000000000000001427643277200152345ustar00rootroot00000000000000verdigris-1.3/tutorial/cpp_tutorial.cpp000066400000000000000000000165531427643277200204570ustar00rootroot00000000000000/** This file presents Verdigris C++ API. This allows you to add multiple properties with a single macro invocation. You will create a basic PropertyHolder template that allows you to very easily make Properties available to QML. */ /** ******************************************************************************************** **/ /** INTRODUCTION **/ // Include the C++ API for Verdigris #include // To implement the template QObjects you need the Verdigris implementation as well #include // And because you will inherit from QObject you also need to QObject header #include // To simplify matters your properties make use of QVariant #include // std::tuple will handle storage for your properties #include // You want to represent each property as a strong type // note: This is a very basic strong type template but sufficient for this tutorial template struct Strong { V v; }; // Use the Strong type template to define the person properties using Name = Strong; using BirthYear = Strong; // This wrapper allows you to build constexpr functions that depend on non constexpr types. // For example a `QString` would not be instantiatable at compile time, but `Wrap` is. template struct Wrap {}; // Define names for the properties as constexpr functions. // These names are used by QML to access the properties constexpr auto getPropertyName(Wrap) { return w_cpp::viewLiteral("name"); } constexpr auto getPropertyName(Wrap) { return w_cpp::viewLiteral("birthYear"); } // Also define the names for the changed signals as constexpr functions. // Hint: You might generate these names programmatically from the PropertyName at compile time. constexpr auto getPropertyChangedName(Wrap) { return w_cpp::viewLiteral("nameChanged"); } constexpr auto getPropertyChangedName(Wrap) { return w_cpp::viewLiteral("birthYearChanged"); } // Now it's time to build the GenericPropertyHolder as a templated QObject. // Thanks to Verdigris it accepts any number of strong typed properties as template arguments. template class GenericPropertyHolder : public QObject { // W_OBJECT macro as usual for Verdigris W_OBJECT(GenericPropertyHolder) // To keep matters simple you store the properties as a std::tuple for now using Storage = std::tuple; Storage m_storage{}; // You can also use std::tuple to resolve the property type for a given index. template using PropertyAt = std::remove_reference_t(std::declval()))>; public: // A constructor that fills the intial values for all the properties GenericPropertyHolder(Properties... properties, QObject* parent = {}) : QObject(parent), m_storage(std::move(properties)...) {} private: // Now you need to implement Signals, Getter, Setter and registrations for all properties. // To prevent repetition you can simply create indexed template functions and use the C++ Verdigris API. // Create a property changed signal implemenation for all properties in one template template void propertyChanged() { W_CPP_SIGNAL_IMPL(decltype (&GenericPropertyHolder::propertyChanged), PropertyChangedSignals, I, 0); } // Register a property changed signal for all properties // Verdigris increments I starting with 0 until this template is invalid. // So you should limit the instantiation to the number of Properties. template> struct PropertyChangedSignals { using Property = PropertyAt; constexpr static auto signalName = getPropertyChangedName(Wrap{}); // signal is the only thing used by the W_CPP_SIGNAL macro. constexpr static auto signal = w_cpp::makeSignalBuilder(signalName, &GenericPropertyHolder::propertyChanged).build(); }; // The W_CPP_SIGNAL macro registers our PropertyChangedSignals template to Verdigris W_CPP_SIGNAL(PropertyChangedSignals) // Next you should implement the getter and setter functions for all properties. // QML does not care about our C++ types so you can convert them directly to QVariant. // notice: For useful C++ Api you would probably want to use your strong types instead of indices anyways. template auto getPropertyValue() const -> QVariant { const auto& property = std::get(m_storage); return QVariant::fromValue(property.v); } template void setPropertyValue(QVariant variant) { auto& property = std::get(m_storage); // Before you can set the property value you have to extract the right type from the QVariant using Property = PropertyAt; using ValueType = decltype (std::declval().v); property.v = variant.value(); propertyChanged(); // send notification for the property } // Finally you have everything to register all your properties // Again Verdigris increments I starting with 0 until this template is no longer valid. template> struct RegisterProperties { using Property = PropertyAt; constexpr static auto name = getPropertyName(Wrap{}); // property is the only thing used by the W_CPP_PROPERTY macro. constexpr static auto property = w_cpp::makeProperty(name, w_cpp::viewLiteral("QVariant")) .setGetter(&GenericPropertyHolder::getPropertyValue) .setSetter(&GenericPropertyHolder::setPropertyValue) .setNotify(&GenericPropertyHolder::propertyChanged); }; W_CPP_PROPERTY(RegisterProperties) }; // Generate the QObject implementation for all instances of the template W_OBJECT_IMPL(GenericPropertyHolder, template) // note: consider using W_OBJECT_IMPL_INLINE to prevent linker issues when you use the same instances from multiple compile units // For your person example you can now instanciate our template using PersonHolder = GenericPropertyHolder; constexpr auto w_explicitObjectName(PersonHolder*) { return w_cpp::viewLiteral("PersonHolder"); } // Implement a QML Quick application #include #include #include int main(int argc, char *argv[]) { #if QT_VERSION < QT_VERSION_CHECK(6,0,0) QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif QGuiApplication app{argc, argv}; QQmlApplicationEngine engine{}; // register your PersonHolder for QML as uncreatable type qmlRegisterUncreatableType("CppTutorial", 1, 0, "PersonHolder", ""); // create a famous person of your liking PersonHolder person{Name{"Albert Einstein"}, BirthYear{1879}, {}}; // make this person accessable as global context property in QML auto context = engine.rootContext(); context->setContextProperty("person", &person); // now you can use it like any other QObject with properties from QML engine.load(QStringLiteral("qrc:/cpp_tutorial.qml")); return app.exec(); } // Notice that with the GenericPropertyHolder template in place, you can add more properties very easy. verdigris-1.3/tutorial/cpp_tutorial.qml000066400000000000000000000025311427643277200204550ustar00rootroot00000000000000import QtQuick 2.2 import QtQuick.Layouts 1.1 import QtQuick.Controls 2.0 import QtQuick.Window 2.0 import CppTutorial 1.0 Window { visible: true width: 640 height: 480 title: qsTr("Cpp Tutorial") ColumnLayout { anchors.fill: parent anchors.margins: 20 TextField { Layout.fillWidth: true readOnly: true placeholderText: "Missing name" text: person && person.name } RowLayout { Layout.fillWidth: true TextField { Layout.fillWidth: true readOnly: true text: person && person.birthYear } Button { text: "+1" onClicked: person.birthYear += +1 } Button { text: "-1" onClicked: person.birthYear += -1 } } Item { Layout.fillWidth: true Layout.fillHeight: true } RowLayout { Layout.fillWidth: true TextField { id: renameName Layout.fillWidth: true placeholderText: "Enter new name here" } Button { text: "Rename" onClicked: person.name = renameName.text } } } } verdigris-1.3/tutorial/cpp_tutorial.qrc000066400000000000000000000001371427643277200204510ustar00rootroot00000000000000 cpp_tutorial.qml verdigris-1.3/tutorial/tutorial.cpp000066400000000000000000000276501427643277200176150ustar00rootroot00000000000000/** This file presents Verdigris, a "fork" of CopperSpice. CopperSpice is a fork of Qt 4 whose specificity is to get rid of moc (Qt Meta-object compiler) In order to get rid of moc, they changed the Qt macros to be less optimal. They made a complete, incompatible fork of Qt. Verdigris is not a fork of CopperSpice, but rather a re-implementation of their macro in a way that is binary compatible with Qt. You can write your application without needing moc, and still use it with existing Qt 5 releases. CopperSpice generates the metaobjects at run-time. But moc generates them at compile time. Verdigris uses constexpr to generate QMetaObject at compile time. It is using C++14 for simplicity because it is much more easy to handle constexpr. The code is originally taken from my previous work https://woboq.com/blog/reflection-in-cpp-and-qt-moc.html In that experiment, I was trying to use same macros that Qt does (keeping source compatibility). When using more complex but uglier macros (CopperSpice style) we can do it without the moc. */ /** ******************************************************************************************** **/ /** INTRODUCTION **/ // In a header file you would include the wobjectdefs.h header // This is equivalent to the qobjectdefs.h header #include // And because you will inherit from QObject you also need to QObject header #include // Now declare your class: class MyObject : public QObject { /** The W_OBJECT macro is equivalent to the Q_OBJECT macro. The difference is that it must contains the class name as a parameter and need to be put before any other W_ macro in the class. So it's the same as the CS_OBJECT macro from CopperSpice. */ W_OBJECT(MyObject) public /* slots */: // Here we declare a slot: void mySlot(const QString &name) { qDebug("hello %s", qPrintable(name)); } /* If you're going to use the new connection syntax, no need to do anything else for slots. But if you want to use the other connection syntax, or QML, you need to register the slot just like so: */ W_SLOT(mySlot) /* The W_SLOT has optional arguments that we will see later. It is already much simpler than the two CopperSpice macros: CS_SLOT_1 and CS_SLOT_2. Also, CopperSpice slots cannot be declared inline in the class definition. */ public /* signals */: // Now a signal: void mySignal(const QString &name) W_SIGNAL(mySignal, name) /* Note the absence of semi colon after the signal declaration */ }; /* Here is what would go in the C++ .cpp file: */ #include // And now this is the macro you need to instantiate the meta object. // It's an additional macro that basically does the same as the code generated by moc. W_OBJECT_IMPL(MyObject) // That's it! MyObject is a QObject that can be used in QML or connected. void aaa(MyObject *obj1) { bool ok = true; // new syntax ok = ok && QObject::connect(obj1, &MyObject::mySignal, obj1, &MyObject::mySlot); // old syntax ok = ok && QObject::connect(obj1, SIGNAL(mySignal(QString)), obj1, SLOT(mySlot(QString))); Q_ASSERT(ok); } /** ******************************************************************************************** **/ /** SLOTS **/ class SlotTutorial : public QObject { W_OBJECT(SlotTutorial) /** W_SLOT( [, () ] [, ]* ) The W_SLOT macro needs to be put after the slot declaration. The W_SLOT macro can have the W_Compat for deprecated methods (equivalent of Q_MOC_COMPAT The W_SLOT macro can optionally have a list of parameter types as second argument to disambiguate or declare types. */ /* Examples: */ protected: // Declares a protected slot void protectedSlot() {} W_SLOT(protectedSlot) private: // and a private slot void privateSlot() {} W_SLOT(privateSlot) public: // Overloaded function needs a parameter list as second argument of the macro // to disambiguate void overload() {} W_SLOT(overload, ()) void overload(int) {} W_SLOT(overload, (int)) private: void overload(double) {} W_SLOT(overload, (double)) void overload(int, int) {} W_SLOT(overload, (int, int)) // Note: for custom type that are not const reference, one must use the normalized signature }; W_OBJECT_IMPL(SlotTutorial) /** ******************************************************************************************** **/ /** SIGNALS **/ class SignalTutorial : public QObject { W_OBJECT(SignalTutorial) /** W_SIGNAL( [, () ] , ) Unlike W_SLOT, W_SIGNAL must be placed directly after the signal signature declaration. There should not be a semi colon after the signal signature. */ public: // Example: void sig1(int a , int b) W_SIGNAL(sig1, a, b) // Or on the same line void sig2(int a, int b) W_SIGNAL(sig2, a, b) // For overloaded signals: void overload(int a, int b) W_SIGNAL(overload, (int, int), a, b) }; W_OBJECT_IMPL(SignalTutorial) /** ******************************************************************************************** **/ /** Gadgets, invokable, constructor **/ class InvokableTutorial { // Just like Qt has Q_GADGET, here we have W_GADGET W_GADGET(InvokableTutorial) public: /** W_INVOKABLE is the same as W_SLOT. * It can take another flag (W_Scriptable) which corresponds to Q_SCRIPTABLE */ void myInvokable() {} W_INVOKABLE(myInvokable) /** W_CONSTRUCTOR() for Q_INVOKABLE constructor, just pass the parameter types to this macro. one can have W_CONSTRUCTOR() for the default constructor even if it is implicit */ InvokableTutorial(int, int) {} W_CONSTRUCTOR(int, int) InvokableTutorial(void*, void* =nullptr) {} W_CONSTRUCTOR(void*, void*) // Because of the default argument we can also do that: (only in this macro) W_CONSTRUCTOR(void*) }; // For gadget there is also a different IMPL macro W_GADGET_IMPL(InvokableTutorial) /** ******************************************************************************************** **/ /** PROPERTY **/ #include class PropertyTutorial : public QObject { W_OBJECT(PropertyTutorial) public: /** W_PROPERTY(, [, ]*) There are the macro READ WRITE MEMBER and so on which have been defined so you can just add a comma after the type, just like in a Q_PROPERTY. W_PROPERTY need to be put after all the setters, getters, signals and members have been declared. */ QString m_value; QString value() const { return m_value; } void setValue(const QString &value) { m_value = value; emit valueChanged(); } void valueChanged() W_SIGNAL(valueChanged) // Just like in Qt only with one additional comma after the type W_PROPERTY(QString, prop1 READ value WRITE setValue NOTIFY valueChanged) // Is equivalent to: W_PROPERTY(QString, prop2, &PropertyTutorial::value, &PropertyTutorial::setValue, W_Notify, &PropertyTutorial::valueChanged) // The setter and getter are matched by signature. add W_Notify before the notify signal // By member: W_PROPERTY(QString, prop3 MEMBER m_value NOTIFY valueChanged) //equivalent to W_PROPERTY(QString, prop4, &PropertyTutorial::m_value, W_Notify, &PropertyTutorial::valueChanged) // Optionally, you can put parentheses around the type, useful if it contains a comma QMap m_map; W_PROPERTY((QMap), map MEMBER m_map) }; W_OBJECT_IMPL(PropertyTutorial) /** ******************************************************************************************** **/ /** Enums **/ class EnumTutorial { W_GADGET(EnumTutorial) public: /** W_ENUM(, ) Similar to Q_ENUM, but we also have to manually write all the values. Maybe in the future it could be made nicer that declares the enum in the same macro but now that's all we have */ enum MyEnum { Blue, Red, Green, Yellow = 45, Violet = Blue + Green*3 }; W_ENUM(MyEnum, Blue, Red, Green, Yellow) // CS_ENUM is a bit better, but i don't believe CopperSpice works with complex expressions // such as "Blue + Green*3". // W_ENUM is currently limited to 16 enum values. // enum class are not yet supported // There is a W_FLAG which is the same as Q_FLAG }; W_GADGET_IMPL(EnumTutorial) /** ******************************************************************************************** **/ /** TYPE REGISTRATION **/ /* Here is where the thing gets a bit more awkward: The types of parameters of signals and slots need to be registered so that we can generate the function signature To use a type as a return type or signal slot parameter, it needs to: - be a builtin QMetaType; or - be registered with W_REGISTER_ARGTYPE; or - use the overload syntax, but not with const reference. */ struct CustomType1 {}; struct CustomType2 {}; struct CustomType3 {}; /** W_REGISTER_ARGTYPE(TYPE) register TYPE so it can be used as a parameter of a signal/slot or return value One must use the normalized signature. Note: This does not imply Q_DECLARE_METATYPE, and Q_DECLARE_METATYPE does not imply this. */ W_REGISTER_ARGTYPE(CustomType1) W_REGISTER_ARGTYPE(CustomType1*) W_REGISTER_ARGTYPE(CustomType2) class ArgTypes : public QObject { W_OBJECT(ArgTypes) public: void slot1(CustomType1, CustomType2) {} W_SLOT(slot1) // OK, all arguments register with W_REGISTER_ARGTYPE void slot2(CustomType1 *, CustomType2 *) {} W_SLOT(slot2, (CustomType1*,CustomType2*)) // Need to use the overload syntax because // CustomType2* is not registered typedef int MyInt; typedef CustomType1 MyCustomType1; void slot3(ArgTypes::MyInt, ArgTypes::MyCustomType1) {} W_SLOT(slot3, (ArgTypes::MyInt,ArgTypes::MyCustomType1)) // Need to use the overload syntax to use // different type name (typedefs) }; W_OBJECT_IMPL(ArgTypes) /** ******************************************************************************************** **/ /** TEMPLATES **/ #include // We can have templated class: template class MyTemplate : public QObject { W_OBJECT(MyTemplate) public: // Template class can have slots and signals that depends on the parameter: void slot(T t) { qDebug() << "templated slot" << t; } W_SLOT(slot) void signal(T t) W_SIGNAL(signal, t) }; //The syntax of W_OBJECT_IMPL changes a bit: as a second parameter you need to specify the template //prefix: W_OBJECT_IMPL(MyTemplate, template ) // When you have several template arguments: template class MyTemplate2 : public QObject { W_OBJECT(MyTemplate2) }; // The first argument of W_OBJECT_IMPL need to be within parentheses: W_OBJECT_IMPL((MyTemplate2), template) void templ() { // This shows that it is possible; bool ok = true; MyTemplate obj; // old syntax ok = ok && QObject::connect(&obj, SIGNAL(signal(QString)), &obj, SLOT(slot(QString))); // new syntax ok = ok && QObject::connect(&obj, &MyTemplate::signal, &obj, &MyTemplate::slot); Q_ASSERT(ok); emit obj.signal("Hallo"); // Will show the qDebug twice } /** ******************************************************************************************** **/ // Nested classes are possible: struct MyStruct { class Nested : public QObject { W_OBJECT(Nested) public: int foobar() const { return 0; } W_INVOKABLE(foobar) }; }; W_OBJECT_IMPL(MyStruct::Nested) /** ******************************************************************************************** **/ int main() { MyObject o; aaa(&o); templ(); } verdigris-1.3/tutorial/tutorial.pro000066400000000000000000000004741427643277200176260ustar00rootroot00000000000000###################################################################### # Automatically generated by qmake (3.0) Di. Feb. 16 17:05:14 2016 ###################################################################### TEMPLATE = app TARGET = tutorial QT -= gui include(../src/verdigris.pri) # Input SOURCES += tutorial.cpp verdigris-1.3/tutorial/tutorial.qbs000066400000000000000000000010051427643277200176020ustar00rootroot00000000000000import qbs Project { Application { name: "tutorial" consoleApplication: true Depends { name: "Verdigris" } files: [ "tutorial.cpp" ] } Application { name: "cpp_tutorial" consoleApplication: true Depends { name: "Verdigris" } Depends { name: "Qt.quick" } files: [ "cpp_tutorial.cpp", "cpp_tutorial.qml", "cpp_tutorial.qrc", ] } } verdigris-1.3/verdigris.pro000066400000000000000000000000711427643277200161070ustar00rootroot00000000000000TEMPLATE = subdirs SUBDIRS += tutorial tests benchmarks verdigris-1.3/verdigris.qbs000066400000000000000000000043661427643277200161070ustar00rootroot00000000000000import qbs Project { name: "Verdigris" references: [ "tutorial", "tests", "benchmarks", ] AutotestRunner {} Product { name: "Verdigris" files: [ "src/wobjectcpp.h", "src/wobjectdefs.h", "src/wobjectimpl.h", ] Export { Depends { name: "cpp" } Depends { name: "Qt.core" } cpp.cxxLanguageVersion: "c++14" cpp.includePaths: ['src'] Properties { condition: qbs.toolchain.contains('msvc') cpp.cxxFlags: base.concat( "/permissive-", "/Zc:__cplusplus", "/Zc:externConstexpr", "/Zc:inline", "/Zc:preprocessor", "/Zc:throwingNew", // best C++ compatibility "/diagnostics:caret" // better errors ) } Properties { condition: qbs.toolchain.contains('clang') cpp.cxxFlags: base.concat( "--pedantic", // best C++ compatibility "-Wall", "-Wextra", // enable more warnings "-ftemplate-backtrace-limit=0", // do not cut template backtraces "-Wno-gnu-zero-variadic-macro-arguments" // accept this extension ) // note: use qbs build parameters if you need this! // cpp.cxxStandardLibrary: "libc++" // cpp.staticLibraries: ["c++", "c++abi"] } Properties { condition: qbs.toolchain.contains('gcc') cpp.cxxFlags: base.concat( "--pedantic", // best C++ compatibility "-Wall", "-Wextra", "-Wno-noexcept-type", // enable more warnings "-ftemplate-backtrace-limit=0" // do not cut template backtraces ) } } } Product { name: "[Extra Files]" files: [ ".appveyor.yml", ".github/workflows/clang.yml", ".github/workflows/gcc.yml", ".github/workflows/windows.yml", "ChangeLog", "LICENSE.LGPLv3", "README.md", ] } }