diff options
Diffstat (limited to 'tests/auto')
46 files changed, 1838 insertions, 287 deletions
diff --git a/tests/auto/CMakeLists.txt b/tests/auto/CMakeLists.txt index 8537f4f..2f384ae 100644 --- a/tests/auto/CMakeLists.txt +++ b/tests/auto/CMakeLists.txt @@ -1,9 +1,18 @@ -# Generated from auto.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause add_subdirectory(conversion) add_subdirectory(qaxobject) -# add_subdirectory(dumpcpp) (needs typelib target) # special case -#add_subdirectory(cmake) # special case +add_subdirectory(dumpcpp) +add_subdirectory(cmake) +add_subdirectory(qbstr) + +find_program(midl midl.exe) +if (midl) + add_subdirectory(qaxobjectcom) +endif() + if(NOT GCC) add_subdirectory(qaxscript) + add_subdirectory(qaxscriptmanager) endif() diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro deleted file mode 100644 index 0b43b0d..0000000 --- a/tests/auto/auto.pro +++ /dev/null @@ -1,10 +0,0 @@ -TEMPLATE = subdirs -SUBDIRS += \ - conversion \ - qaxobject \ - qaxscript \ - dumpcpp \ - cmake - -*g++*: SUBDIRS -= \ - qaxscript \ diff --git a/tests/auto/cmake/CMakeLists.txt b/tests/auto/cmake/CMakeLists.txt index 4f15a69..3611659 100644 --- a/tests/auto/cmake/CMakeLists.txt +++ b/tests/auto/cmake/CMakeLists.txt @@ -1,12 +1,46 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause -cmake_minimum_required(VERSION 2.8) -project(qmake_cmake_files) +cmake_minimum_required(VERSION 3.16) + +project(qtactivetqt_cmake_tests) enable_testing() -find_package(Qt5Core REQUIRED) +set(required_packages Core) +set(optional_packages Widgets Gui) + +# Setup the test when called as a completely standalone project. +if(TARGET Qt6::Core) + # Tests are built as part of the qtactiveqt build tree. + # Setup paths so that the Qt packages are found. + qt_internal_set_up_build_dir_package_paths() +endif() + +find_package(Qt6 REQUIRED COMPONENTS ${required_packages}) +find_package(Qt6 OPTIONAL_COMPONENTS ${optional_packages}) + +# Setup common test variables which were previously set by ctest_testcase_common.prf. +set(CMAKE_MODULES_UNDER_TEST "${required_packages}" "${optional_packages}") + +foreach(qt_package ${CMAKE_MODULES_UNDER_TEST}) + set(package_name "${QT_CMAKE_EXPORT_NAMESPACE}${qt_package}") + if(${package_name}_FOUND) + set(CMAKE_${qt_package}_MODULE_MAJOR_VERSION "${${package_name}_VERSION_MAJOR}") + set(CMAKE_${qt_package}_MODULE_MINOR_VERSION "${${package_name}_VERSION_MINOR}") + set(CMAKE_${qt_package}_MODULE_PATCH_VERSION "${${package_name}_VERSION_PATCH}") + endif() +endforeach() -include("${_Qt5CTestMacros}") +include("${_Qt6CTestMacros}") -expect_pass(test_modules) +if(TARGET Qt6::Widgets AND TARGET Qt6::Gui) + _qt_internal_test_expect_pass(test_target_typelibs) + _qt_internal_test_expect_pass(test_target_typelibs_absolute) + _qt_internal_test_expect_fail(test_target_typelibs_empty_libs) + _qt_internal_test_expect_fail(test_target_typelibs_non_existing_libs) + _qt_internal_test_expect_pass(test_target_typelibs_out_dir) + _qt_internal_test_expect_pass(test_modules/container) + _qt_internal_test_expect_pass(test_modules/server) +endif() diff --git a/tests/auto/cmake/cmake.pro b/tests/auto/cmake/cmake.pro deleted file mode 100644 index bf2dbcb..0000000 --- a/tests/auto/cmake/cmake.pro +++ /dev/null @@ -1,5 +0,0 @@ - -# Cause make to do nothing. -TEMPLATE = subdirs - -CONFIG += ctest_testcase diff --git a/tests/auto/cmake/test_modules/CMakeLists.txt b/tests/auto/cmake/test_modules/CMakeLists.txt deleted file mode 100644 index 4336ad4..0000000 --- a/tests/auto/cmake/test_modules/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ - -cmake_minimum_required(VERSION 2.8) - -project(test_modules) - -add_subdirectory(server) -add_subdirectory(container) diff --git a/tests/auto/cmake/test_modules/container/CMakeLists.txt b/tests/auto/cmake/test_modules/container/CMakeLists.txt index 6d04576..999e241 100644 --- a/tests/auto/cmake/test_modules/container/CMakeLists.txt +++ b/tests/auto/cmake/test_modules/container/CMakeLists.txt @@ -1,24 +1,10 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 3.16) project(cmake_axcontainer) -find_package(Qt5Core REQUIRED) -find_package(Qt5Gui REQUIRED) -find_package(Qt5Widgets REQUIRED) - -find_package(Qt5AxContainer REQUIRED) - -include_directories( - ${Qt5AxContainer_INCLUDE_DIRS} -) - -add_definitions(${Qt5AxContainer_DEFINITIONS}) - -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Core_EXECUTABLE_COMPILE_FLAGS}") - +find_package(Qt6 COMPONENTS Core Gui Widgets AxContainer CONFIG REQUIRED) add_executable(axcontainerapp axcontainer.cpp) - -target_link_libraries(axcontainerapp - ${Qt5AxContainer_LIBRARIES} -) +target_link_libraries(axcontainerapp Qt6::Core Qt6::Gui Qt6::Widgets Qt6::AxContainer) diff --git a/tests/auto/cmake/test_modules/container/axcontainer.cpp b/tests/auto/cmake/test_modules/container/axcontainer.cpp index e16bddb..73d8ebb 100644 --- a/tests/auto/cmake/test_modules/container/axcontainer.cpp +++ b/tests/auto/cmake/test_modules/container/axcontainer.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly <stephen.kelly@kdab.com> -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly <stephen.kelly@kdab.com> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <qt_windows.h> #include <QtAxContainer/QAxWidget> diff --git a/tests/auto/cmake/test_modules/server/CMakeLists.txt b/tests/auto/cmake/test_modules/server/CMakeLists.txt index f553990..0a8d420 100644 --- a/tests/auto/cmake/test_modules/server/CMakeLists.txt +++ b/tests/auto/cmake/test_modules/server/CMakeLists.txt @@ -1,24 +1,10 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 3.16) project(cmake_axserver) -find_package(Qt5Core REQUIRED) -find_package(Qt5Gui REQUIRED) -find_package(Qt5Widgets REQUIRED) - -find_package(Qt5AxServer REQUIRED) - -include_directories( - ${Qt5AxServer_INCLUDE_DIRS} -) - -add_definitions(${Qt5AxServer_DEFINITIONS}) - -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Core_EXECUTABLE_COMPILE_FLAGS}") - +find_package(Qt6 COMPONENTS Core Gui Widgets AxServer CONFIG REQUIRED) add_executable(axserverapp WIN32 axserver.cpp) - -target_link_libraries(axserverapp - ${Qt5AxServer_LIBRARIES} -) +target_link_libraries(axserverapp Qt6::Core Qt6::Gui Qt6::Widgets Qt6::AxServer) diff --git a/tests/auto/cmake/test_modules/server/axserver.cpp b/tests/auto/cmake/test_modules/server/axserver.cpp index b31014c..6dabc17 100644 --- a/tests/auto/cmake/test_modules/server/axserver.cpp +++ b/tests/auto/cmake/test_modules/server/axserver.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly <stephen.kelly@kdab.com> -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly <stephen.kelly@kdab.com> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <qt_windows.h> #include <QAxFactory> diff --git a/tests/auto/cmake/test_target_typelibs/CMakeLists.txt b/tests/auto/cmake/test_target_typelibs/CMakeLists.txt new file mode 100644 index 0000000..528aa08 --- /dev/null +++ b/tests/auto/cmake/test_target_typelibs/CMakeLists.txt @@ -0,0 +1,12 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.16) +project(tst_typelibs) + +find_package(Qt6 COMPONENTS AxContainer Gui Widgets CONFIG REQUIRED) + +add_executable(tst_typelibs main.cpp) +target_link_libraries(tst_typelibs PRIVATE Qt6::AxContainer Qt6::Gui Qt6::Widgets) + +qt6_target_typelibs(tst_typelibs LIBRARIES "ieframe.dll") diff --git a/tests/auto/cmake/test_target_typelibs/main.cpp b/tests/auto/cmake/test_target_typelibs/main.cpp new file mode 100644 index 0000000..4b69f66 --- /dev/null +++ b/tests/auto/cmake/test_target_typelibs/main.cpp @@ -0,0 +1,11 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "ieframe.h" + +int main(int argc, char *argv[]) +{ + SHDocVw::WebBrowser* webBrowser = new SHDocVw::WebBrowser; + delete webBrowser; + return 0; +} diff --git a/tests/auto/cmake/test_target_typelibs_absolute/CMakeLists.txt b/tests/auto/cmake/test_target_typelibs_absolute/CMakeLists.txt new file mode 100644 index 0000000..942fa54 --- /dev/null +++ b/tests/auto/cmake/test_target_typelibs_absolute/CMakeLists.txt @@ -0,0 +1,12 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.16) +project(tst_typelibs) + +find_package(Qt6 COMPONENTS AxContainer Gui Widgets CONFIG REQUIRED) + +add_executable(tst_typelibs main.cpp) +target_link_libraries(tst_typelibs PRIVATE Qt6::AxContainer Qt6::Gui Qt6::Widgets) + +qt6_target_typelibs(tst_typelibs LIBRARIES "$ENV{SystemRoot}/System32/ieframe.dll") diff --git a/tests/auto/cmake/test_target_typelibs_absolute/main.cpp b/tests/auto/cmake/test_target_typelibs_absolute/main.cpp new file mode 100644 index 0000000..4b69f66 --- /dev/null +++ b/tests/auto/cmake/test_target_typelibs_absolute/main.cpp @@ -0,0 +1,11 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "ieframe.h" + +int main(int argc, char *argv[]) +{ + SHDocVw::WebBrowser* webBrowser = new SHDocVw::WebBrowser; + delete webBrowser; + return 0; +} diff --git a/tests/auto/cmake/test_target_typelibs_empty_libs/CMakeLists.txt b/tests/auto/cmake/test_target_typelibs_empty_libs/CMakeLists.txt new file mode 100644 index 0000000..2971c1b --- /dev/null +++ b/tests/auto/cmake/test_target_typelibs_empty_libs/CMakeLists.txt @@ -0,0 +1,12 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.16) +project(tst_typelibs) + +find_package(Qt6 COMPONENTS AxContainer Gui Widgets CONFIG REQUIRED) + +add_executable(tst_typelibs main.cpp) +target_link_libraries(tst_typelibs PRIVATE Qt6::AxContainer Qt6::Gui Qt6::Widgets) + +qt6_target_typelibs(tst_typelibs) diff --git a/tests/auto/cmake/test_target_typelibs_empty_libs/main.cpp b/tests/auto/cmake/test_target_typelibs_empty_libs/main.cpp new file mode 100644 index 0000000..4b69f66 --- /dev/null +++ b/tests/auto/cmake/test_target_typelibs_empty_libs/main.cpp @@ -0,0 +1,11 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "ieframe.h" + +int main(int argc, char *argv[]) +{ + SHDocVw::WebBrowser* webBrowser = new SHDocVw::WebBrowser; + delete webBrowser; + return 0; +} diff --git a/tests/auto/cmake/test_target_typelibs_non_existing_libs/CMakeLists.txt b/tests/auto/cmake/test_target_typelibs_non_existing_libs/CMakeLists.txt new file mode 100644 index 0000000..aaca1c9 --- /dev/null +++ b/tests/auto/cmake/test_target_typelibs_non_existing_libs/CMakeLists.txt @@ -0,0 +1,12 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.16) +project(tst_typelibs) + +find_package(Qt6 COMPONENTS AxContainer Gui Widgets CONFIG REQUIRED) + +add_executable(tst_typelibs main.cpp) +target_link_libraries(tst_typelibs PRIVATE Qt6::AxContainer Qt6::Gui Qt6::Widgets) + +qt6_target_typelibs(tst_typelibs LIBRARIES "ieframe.dll" "qt100notexistinglib.dll") diff --git a/tests/auto/cmake/test_target_typelibs_non_existing_libs/main.cpp b/tests/auto/cmake/test_target_typelibs_non_existing_libs/main.cpp new file mode 100644 index 0000000..4b69f66 --- /dev/null +++ b/tests/auto/cmake/test_target_typelibs_non_existing_libs/main.cpp @@ -0,0 +1,11 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "ieframe.h" + +int main(int argc, char *argv[]) +{ + SHDocVw::WebBrowser* webBrowser = new SHDocVw::WebBrowser; + delete webBrowser; + return 0; +} diff --git a/tests/auto/cmake/test_target_typelibs_out_dir/CMakeLists.txt b/tests/auto/cmake/test_target_typelibs_out_dir/CMakeLists.txt new file mode 100644 index 0000000..d1c38ae --- /dev/null +++ b/tests/auto/cmake/test_target_typelibs_out_dir/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.16) +project(tst_typelibs) + +find_package(Qt6 COMPONENTS AxContainer Gui Widgets CONFIG REQUIRED) + +add_executable(tst_typelibs main.cpp) +target_link_libraries(tst_typelibs PRIVATE Qt6::AxContainer Qt6::Gui Qt6::Widgets) +target_include_directories(tst_typelibs PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") + +qt6_target_typelibs(tst_typelibs LIBRARIES "ieframe.dll" + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/typelibs" +) diff --git a/tests/auto/cmake/test_target_typelibs_out_dir/main.cpp b/tests/auto/cmake/test_target_typelibs_out_dir/main.cpp new file mode 100644 index 0000000..a2f659a --- /dev/null +++ b/tests/auto/cmake/test_target_typelibs_out_dir/main.cpp @@ -0,0 +1,11 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "typelibs/ieframe.h" + +int main(int argc, char *argv[]) +{ + SHDocVw::WebBrowser* webBrowser = new SHDocVw::WebBrowser; + delete webBrowser; + return 0; +} diff --git a/tests/auto/conversion/CMakeLists.txt b/tests/auto/conversion/CMakeLists.txt index 4aab821..1e25aeb 100644 --- a/tests/auto/conversion/CMakeLists.txt +++ b/tests/auto/conversion/CMakeLists.txt @@ -1,13 +1,24 @@ -# Generated from conversion.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## conversion Test: ##################################################################### -qt_add_test(conversion +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(conversion LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(conversion SOURCES tst_conversion.cpp - PUBLIC_LIBRARIES + INCLUDE_DIRECTORIES + ../../../src/activeqt/shared/ + LIBRARIES Qt::AxContainer Qt::Gui + Qt::AxBasePrivate + Qt::CorePrivate ) diff --git a/tests/auto/conversion/comutil_p.h b/tests/auto/conversion/comutil_p.h new file mode 100644 index 0000000..e722ed5 --- /dev/null +++ b/tests/auto/conversion/comutil_p.h @@ -0,0 +1,250 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#ifndef COMUTIL_P_H +#define COMUTIL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/QtGlobal> +#include <QtAxBase/private/qbstr_p.h> +#include <comdef.h> +#include <type_traits> +#include <oleauto.h> +#include <wrl/client.h> + +using Microsoft::WRL::ComPtr; + +template<typename T> +ComPtr<T> makeComObject() +{ + ComPtr<T> ptr; + *ptr.GetAddressOf() = new T; + return ptr; +} + +template<typename T> +constexpr VARTYPE ValueType() +{ + using ValueType = std::remove_cv_t<std::remove_pointer_t<T>>; + + constexpr VARTYPE maybeByref = std::is_pointer_v<T> ? VT_BYREF : VT_EMPTY; + if constexpr (std::is_same_v<ValueType, bool>) + return VT_BOOL | maybeByref; + else if constexpr (std::is_same_v<ValueType, char>) + return VT_I1 | maybeByref; + else if constexpr (std::is_same_v<ValueType, unsigned char>) + return VT_UI1 | maybeByref; + else if constexpr (std::is_same_v<ValueType, short>) + return VT_I2 | maybeByref; + else if constexpr (std::is_same_v<ValueType, unsigned short>) + return VT_UI2 | maybeByref; + else if constexpr (std::is_same_v<ValueType, int>) + return VT_I4 | maybeByref; + else if constexpr (std::is_same_v<ValueType, unsigned int>) + return VT_UI4 | maybeByref; + else if constexpr (std::is_same_v<ValueType, long long>) + return VT_I8 | maybeByref; + else if constexpr (std::is_same_v<ValueType, unsigned long long>) + return VT_UI8 | maybeByref; + else if constexpr (std::is_same_v<ValueType, float>) + return VT_R4 | maybeByref; + else if constexpr (std::is_same_v<ValueType, double>) + return VT_R8 | maybeByref; + else if constexpr (std::is_same_v<const ValueType *, const wchar_t *>) + return VT_BSTR; + else if constexpr (std::is_base_of_v<IDispatch, ValueType>) + return VT_DISPATCH; + else if constexpr (std::is_base_of_v<IUnknown, ValueType>) + return VT_UNKNOWN; + else + return VT_EMPTY; +}; + +template<typename T> +constexpr auto ValueField() +{ + using Type = std::remove_const_t<T>; + if constexpr (std::is_same_v<Type, bool>) + return &VARIANT::boolVal; + else if constexpr (std::is_same_v<Type, bool *>) + return &VARIANT::pboolVal; + else if constexpr (std::is_same_v<Type, char>) + return &VARIANT::cVal; + else if constexpr (std::is_same_v<Type, char *>) + return &VARIANT::pcVal; + else if constexpr (std::is_same_v<Type, unsigned char>) + return &VARIANT::bVal; + else if constexpr (std::is_same_v<Type, unsigned char *>) + return &VARIANT::pbVal; + else if constexpr (std::is_same_v<Type, short>) + return &VARIANT::iVal; + else if constexpr (std::is_same_v<Type, short *>) + return &VARIANT::piVal; + else if constexpr (std::is_same_v<Type, unsigned short>) + return &VARIANT::uiVal; + else if constexpr (std::is_same_v<Type, unsigned short *>) + return &VARIANT::puiVal; + else if constexpr (std::is_same_v<Type, int>) + return &VARIANT::intVal; + else if constexpr (std::is_same_v<Type, int *>) + return &VARIANT::pintVal; + else if constexpr (std::is_same_v<Type, unsigned int>) + return &VARIANT::uintVal; + else if constexpr (std::is_same_v<Type, unsigned int *>) + return &VARIANT::puintVal; + else if constexpr (std::is_same_v<Type, long long>) + return &VARIANT::llVal; + else if constexpr (std::is_same_v<Type, long long *>) + return &VARIANT::pllVal; + else if constexpr (std::is_same_v<Type, unsigned long long>) + return &VARIANT::ullVal; + else if constexpr (std::is_same_v<Type, unsigned long long *>) + return &VARIANT::pullVal; + else if constexpr (std::is_same_v<Type, float>) + return &VARIANT::fltVal; + else if constexpr (std::is_same_v<Type, float *>) + return &VARIANT::pfltVal; + else if constexpr (std::is_same_v<Type, double>) + return &VARIANT::dblVal; + else if constexpr (std::is_same_v<Type, double *>) + return &VARIANT::pdblVal; + else if constexpr (std::is_same_v<T, const wchar_t *>) + return &VARIANT::bstrVal; + else if constexpr (std::is_base_of_v<IDispatch, std::remove_pointer_t<Type>>) + return &VARIANT::pdispVal; + else if constexpr (std::is_base_of_v<IUnknown, std::remove_pointer_t<Type>>) + return &VARIANT::punkVal; +} + +class ComVariant : public tagVARIANT +{ +public: + ComVariant() noexcept : VARIANT{} { ::VariantInit(this); } + + ~ComVariant() + { + const HRESULT hr = ::VariantClear(this); + Q_ASSERT(hr == S_OK); + Q_UNUSED(hr) + } + + ComVariant(const ComVariant &src) : ComVariant() { copy(&src); } + ComVariant(const VARIANT &src) noexcept : ComVariant() { copy(&src); } + ComVariant(const QBStr &src) noexcept : ComVariant() { copy(src.bstr()); } + + template<typename T> + ComVariant(const T &value) : ComVariant() + { + assign(value); + } + + ComVariant &operator=(const ComVariant &rhs) noexcept + { + if (this == &rhs) + return *this; + + clear(); + copy(&rhs); + + return *this; + } + + template<typename T> + ComVariant &operator=(const T &rhs) + { + assign(rhs); + return *this; + } + + void clear() + { + const HRESULT hr = ::VariantClear(this); + + Q_ASSERT(hr == S_OK); + Q_UNUSED(hr) + } + + void copy(const VARIANT *src) + { + vt = VT_EMPTY; + const HRESULT hr = ::VariantCopy(this, const_cast<VARIANT *>(src)); + + Q_ASSERT(hr == S_OK); + Q_UNUSED(hr) + } + + void copy(const BSTR &src) + { + vt = VT_EMPTY; + if (!src) + return; + + vt = VT_BSTR; + bstrVal = ::SysAllocStringByteLen(reinterpret_cast<const char *>(src), + ::SysStringByteLen(src)); + + Q_ASSERT(bstrVal); + } + + bool operator==(const ComVariant &rhs) const + { + auto *lhs = const_cast<tagVARIANT *>(static_cast<const tagVARIANT *>(this)); + auto *other = const_cast<tagVARIANT *>(static_cast<const tagVARIANT *>(&rhs)); + return compare(lhs, other, LOCALE_USER_DEFAULT, 0) == static_cast<HRESULT>(VARCMP_EQ); + } + +private: + template<typename T> + void assign(const T &value) + { + constexpr VARTYPE valueType = ValueType<T>(); + static_assert(valueType != VT_EMPTY, "Invalid type for ComVariant"); + + vt = valueType; + + constexpr auto VARIANT::*field = ValueField<T>(); + if constexpr (valueType == VT_BSTR) + this->*field = QBStr{ value }.release(); + else + this->*field = value; + + if constexpr (valueType == VT_UNKNOWN || valueType == VT_DISPATCH) + value->AddRef(); + } + + static HRESULT compare(VARIANT *lhs, VARIANT *rhs, LCID lcid, ULONG flags) + { + // Workaround missing support for VT_I1, VT_UI2, VT_UI4 and VT_UI8 in VarCmp + switch (lhs->vt) { + case VT_I1: + if (lhs->cVal == rhs->cVal) + return VARCMP_EQ; + return lhs->cVal > rhs->cVal ? VARCMP_GT : VARCMP_LT; + case VT_UI2: + if (lhs->uiVal == rhs->uiVal) + return VARCMP_EQ; + return lhs->uiVal > rhs->uiVal ? VARCMP_GT : VARCMP_LT; + case VT_UI4: + if (lhs->uintVal == rhs->uintVal) + return VARCMP_EQ; + return lhs->uintVal > rhs->uintVal ? VARCMP_GT : VARCMP_LT; + case VT_UI8: + if (lhs->ullVal == rhs->ullVal) + return VARCMP_EQ; + return lhs->ullVal > rhs->ullVal ? VARCMP_GT : VARCMP_LT; + } + return ::VarCmp(lhs, rhs, lcid, flags); + } +}; + +#endif diff --git a/tests/auto/conversion/conversion.pro b/tests/auto/conversion/conversion.pro deleted file mode 100644 index 47f0699..0000000 --- a/tests/auto/conversion/conversion.pro +++ /dev/null @@ -1,3 +0,0 @@ -CONFIG += testcase -QT += axcontainer testlib -SOURCES += tst_conversion.cpp diff --git a/tests/auto/conversion/testutil_p.h b/tests/auto/conversion/testutil_p.h new file mode 100644 index 0000000..572e3d1 --- /dev/null +++ b/tests/auto/conversion/testutil_p.h @@ -0,0 +1,60 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#ifndef TESTUTIL_P_H +#define TESTUTIL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <qtcore/qt_windows.h> +#include <qtcore/private/qcomobject_p.h> +#include <qtcore/qtglobal> +#include <wrl/client.h> +#include <atomic> + +using Microsoft::WRL::ComPtr; + +template <typename T> +ULONG refCount(const ComPtr<T> &p) +{ + p->AddRef(); + return p->Release(); +} + +struct IUnknownStub : QComObject<IUnknown> +{ +}; + +struct IDispatchStub : QComObject<IDispatch> +{ + HRESULT GetTypeInfoCount(UINT * /*pctinfo*/) override { return E_NOTIMPL; } + + HRESULT GetTypeInfo(UINT /*iTInfo*/, LCID /*lcid*/, ITypeInfo ** /*ppTInfo*/) override + { + return E_NOTIMPL; + } + + HRESULT GetIDsOfNames(const IID & /*riid*/, LPOLESTR * /*rgszNames*/, UINT /*cNames*/, + LCID /*lcid*/, DISPID * /*rgDispId*/) override + { + return E_NOTIMPL; + } + + HRESULT Invoke(DISPID /*dispIdMember*/, const IID & /*riid*/, LCID /*lcid*/, WORD /*wFlags*/, + DISPPARAMS * /*pDispParams*/, VARIANT * /*pVarResult*/, + EXCEPINFO * /*pExcepInfo*/, UINT * /*puArgErr*/) override + { + return E_NOTIMPL; + } +}; + +#endif diff --git a/tests/auto/conversion/tst_conversion.cpp b/tests/auto/conversion/tst_conversion.cpp index 52be69b..ba7bb5d 100644 --- a/tests/auto/conversion/tst_conversion.cpp +++ b/tests/auto/conversion/tst_conversion.cpp @@ -1,30 +1,11 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "comutil_p.h" +#include "testutil_p.h" + +#include <qaxtypes_p.h> +#include <ActiveQt/qaxobject.h> #include <QtTest/QtTest> #include <QtCore/QVariant> @@ -32,18 +13,13 @@ #include <QtCore/QMetaType> #include <qt_windows.h> +#include <wrl/client.h> -QT_BEGIN_NAMESPACE - -// Conversion functions from statically linked library (axtypes.h) -bool QVariantToVARIANT_container(const QVariant &var, VARIANT &arg, - const QByteArray &typeName = QByteArray(), - bool out = false); +using Microsoft::WRL::ComPtr; -QVariant VARIANTToQVariant_container(const VARIANT &arg, const QByteArray &typeName, - uint type = 0); +QT_BEGIN_NAMESPACE -QT_END_NAMESPACE +using namespace Qt::StringLiterals; class tst_Conversion : public QObject { @@ -52,6 +28,36 @@ class tst_Conversion : public QObject private slots: void conversion_data(); void conversion(); + + void VARIANTToQVariant_ReturnsBool_WhenCalledWithVariantBool(); + void QVariantToVARIANT_ReturnsVariantBool_WhenCalledWithBool(); + + void VARIANTToQVariant_ReturnsString_WhenCalledWithString_data(); + void VARIANTToQVariant_ReturnsString_WhenCalledWithString(); + + void QVariantToVARIANT_ReturnsString_WhenCalledWithString_data(); + void QVariantToVARIANT_ReturnsString_WhenCalledWithString(); + + void VARIANTToQVariant_ReturnsCopyOfValue_WhenCalledWithMaxPossibleValueOrPointer_data(); + void VARIANTToQVariant_ReturnsCopyOfValue_WhenCalledWithMaxPossibleValueOrPointer(); + + void QVariantToVARIANT_ReturnsCopyOfValue_WhenCalledWithMaxPossibleValue_data(); + void QVariantToVARIANT_ReturnsCopyOfValue_WhenCalledWithMaxPossibleValue(); + + void VARIANTToQVariant_DoesNotIncreaseRefCount_WhenGivenAnIUnknown(); + void QVariantToVARIANT_RecoversIUnknown_WhenQVariantHasIUnknown(); + + void VARIANTToQVariant_DoesNotIncreaseRefCount_WhenGivenAnIDispatch(); + void QVariantToVARIANT_RecoversIDispatch_WhenQVariantHasIDispatch(); + + void VARIANTToQVariant_IncreasesRefCount_WhenCalledWithQVariantTypeName(); + + void ObserveThat_VARIANTToQVariant_ReturnsEmptyQVariant_WhenWrappingIDispatchInQAxObjectPtr(); + void VARIANTToQVariant_CreatesQAxObject_WhenCalledWithMetaTypeId(); + +private: + template<typename T> + static void addScalarMaxValueRow(); }; enum Mode { @@ -170,6 +176,11 @@ void tst_Conversion::conversion_data() << qvar << uint(VT_DATE | VT_BYREF) << typeName << ByReference; QTest::newRow("datetime-out") << qvar << uint(VT_DATE | VT_BYREF) << typeName << OutParameter; + + // QTBUG-122762; do not create a 2-dimensional array from a string (sequence). + qvar = QVariant(QVariantList{QVariant(QString("test"_L1)), QVariant(42)}); + QTest::newRow("list") + << qvar << uint(VT_VARIANT | VT_ARRAY | VT_BYREF) << typeName << OutParameter; } void tst_Conversion::conversion() @@ -195,5 +206,271 @@ void tst_Conversion::conversion() delete variant.pullVal; } +void tst_Conversion::VARIANTToQVariant_ReturnsBool_WhenCalledWithVariantBool() +{ + { + const ComVariant v = true; + const QVariant result = VARIANTToQVariant(v, "canBeAnything"); + QVERIFY(result == true); + } + + { + const ComVariant v = false; + const QVariant result = VARIANTToQVariant(v, "canBeAnything"); + QVERIFY(result == false); + } +} + +void tst_Conversion::QVariantToVARIANT_ReturnsVariantBool_WhenCalledWithBool() +{ + { + const QVariant v = true; + ComVariant result; + QVERIFY(QVariantToVARIANT(v, result)); + QVERIFY(result.vt == VT_BOOL); + QVERIFY(result.boolVal == VARIANT_TRUE); + } + + { + const QVariant v = false; + ComVariant result; + QVERIFY(QVariantToVARIANT(v, result)); + QVERIFY(result.vt == VT_BOOL); + QVERIFY(result.boolVal == VARIANT_FALSE); + } +} + +void tst_Conversion::VARIANTToQVariant_ReturnsString_WhenCalledWithString_data() +{ + QTest::addColumn<QString>("text"); + QTest::newRow("empty") << QString{ "" }; + QTest::newRow("nonempty") << QString{ "Some Latin 1 text" }; +} + +void tst_Conversion::VARIANTToQVariant_ReturnsString_WhenCalledWithString() +{ + QFETCH(QString, text); + + const ComVariant comVariant = text.toStdWString().c_str(); + const QVariant actual = VARIANTToQVariant(comVariant, {}); + + QCOMPARE(actual, text); +} + +void tst_Conversion::QVariantToVARIANT_ReturnsString_WhenCalledWithString_data() +{ + QTest::addColumn<QString>("text"); + QTest::newRow("empty") << QString{ "" }; + QTest::newRow("nonempty") << QString{ "Some Latin 1 text" }; +} + +void tst_Conversion::QVariantToVARIANT_ReturnsString_WhenCalledWithString() +{ + QFETCH(QString, text); + + ComVariant comVariant; + QVERIFY(QVariantToVARIANT(text, comVariant)); + + const QString actual = QString::fromWCharArray(comVariant.bstrVal); + + QCOMPARE(actual, text); +} + +void tst_Conversion:: + VARIANTToQVariant_ReturnsCopyOfValue_WhenCalledWithMaxPossibleValueOrPointer_data() +{ + QTest::addColumn<ComVariant>("comVariant"); + QTest::addColumn<QVariant>("qvariant"); + + addScalarMaxValueRow<char>(); + addScalarMaxValueRow<unsigned char>(); + addScalarMaxValueRow<short>(); + addScalarMaxValueRow<unsigned short>(); + addScalarMaxValueRow<int>(); + addScalarMaxValueRow<unsigned int>(); + addScalarMaxValueRow<long long>(); + addScalarMaxValueRow<unsigned long long>(); + addScalarMaxValueRow<float>(); + addScalarMaxValueRow<double>(); + + addScalarMaxValueRow<char *>(); + addScalarMaxValueRow<unsigned char *>(); + addScalarMaxValueRow<short *>(); + addScalarMaxValueRow<unsigned short *>(); + addScalarMaxValueRow<int *>(); + addScalarMaxValueRow<unsigned int *>(); + addScalarMaxValueRow<long long *>(); + addScalarMaxValueRow<unsigned long long *>(); + addScalarMaxValueRow<float *>(); + addScalarMaxValueRow<double *>(); +} + +void tst_Conversion::VARIANTToQVariant_ReturnsCopyOfValue_WhenCalledWithMaxPossibleValueOrPointer() +{ + QFETCH(ComVariant, comVariant); + QFETCH(QVariant, qvariant); + + const QVariant actual = VARIANTToQVariant(comVariant, qvariant.typeName()); + + QCOMPARE(actual, qvariant); +} + +void tst_Conversion::QVariantToVARIANT_ReturnsCopyOfValue_WhenCalledWithMaxPossibleValue_data() +{ + QTest::addColumn<ComVariant>("comVariant"); + QTest::addColumn<QVariant>("qvariant"); + + addScalarMaxValueRow<int>(); + addScalarMaxValueRow<unsigned int>(); + addScalarMaxValueRow<long long>(); + addScalarMaxValueRow<unsigned long long>(); + addScalarMaxValueRow<float>(); + addScalarMaxValueRow<double>(); +} + +void tst_Conversion::QVariantToVARIANT_ReturnsCopyOfValue_WhenCalledWithMaxPossibleValue() +{ + QFETCH(ComVariant, comVariant); + QFETCH(QVariant, qvariant); + + ComVariant actual; + QVERIFY(QVariantToVARIANT(qvariant, actual)); + + QCOMPARE(actual, comVariant); +} + +void tst_Conversion::VARIANTToQVariant_DoesNotIncreaseRefCount_WhenGivenAnIUnknown() +{ + const auto stub = makeComObject<IUnknownStub>(); + + const ComVariant value = stub.Get(); + + const ULONG expectedRefCount = refCount(stub); + + const QVariant qVariant = VARIANTToQVariant(value, {}); + + QVERIFY(refCount(stub) == expectedRefCount); + + Q_UNUSED(qVariant); +} + +void tst_Conversion::QVariantToVARIANT_RecoversIUnknown_WhenQVariantHasIUnknown() +{ + const auto stub = makeComObject<IUnknownStub>(); + const ComVariant value = stub.Get(); + + const QVariant qvar = VARIANTToQVariant(value, {}); + + ComVariant comVariant; + + const ULONG expectedRefCount = refCount(stub) + 1; // Add one for the VARIANT + + QVERIFY(QVariantToVARIANT(qvar, comVariant)); + + QCOMPARE(refCount(stub), expectedRefCount); + + const ComPtr<IUnknown> recovered = comVariant.punkVal; + + QCOMPARE(recovered, stub); +} + +void tst_Conversion::VARIANTToQVariant_DoesNotIncreaseRefCount_WhenGivenAnIDispatch() +{ + const auto stub = makeComObject<IDispatchStub>(); + + const ComVariant value = stub.Get(); + + const ULONG expectedRefCount = refCount(stub); + + const QVariant qVariant = VARIANTToQVariant(value, "IDispatch*"); + + QCOMPARE(refCount(stub), expectedRefCount); + + Q_UNUSED(qVariant); +} + +struct IDispatchFixture +{ + const ComPtr<IDispatchStub> m_iDispatchStub = makeComObject<IDispatchStub>(); + const ComVariant m_comVariant = m_iDispatchStub.Get(); + const QVariant m_qVariant = VARIANTToQVariant(m_comVariant, "IDispatch*"); +}; + +void tst_Conversion::QVariantToVARIANT_RecoversIDispatch_WhenQVariantHasIDispatch() +{ + const IDispatchFixture testFixture; + const auto expectedRefCount = refCount(testFixture.m_iDispatchStub) + 1; + + ComVariant comVariant; + QVERIFY(QVariantToVARIANT(testFixture.m_qVariant, comVariant)); + + QCOMPARE(refCount(testFixture.m_iDispatchStub), expectedRefCount); + + const ComPtr<IUnknown> recovered = comVariant.pdispVal; + + QCOMPARE(recovered, testFixture.m_iDispatchStub); +} + +void tst_Conversion::VARIANTToQVariant_IncreasesRefCount_WhenCalledWithQVariantTypeName() +{ + const IDispatchFixture testFixture; + const auto expectedRefCount = refCount(testFixture.m_iDispatchStub) + 1; + + QVariant qVariant = VARIANTToQVariant(testFixture.m_comVariant, "QVariant"); + qVariant = {}; + + // Observe that IDispatch interface is leaked here, since + // the QVariant destructor does not decrement the refcount + QCOMPARE(refCount(testFixture.m_iDispatchStub), expectedRefCount); + + // Workaround to ensure cleanup + testFixture.m_iDispatchStub->Release(); +} + +void tst_Conversion::ObserveThat_VARIANTToQVariant_ReturnsEmptyQVariant_WhenWrappingIDispatchInQAxObjectPtr() +{ + const IDispatchFixture testFixture; + QCOMPARE(refCount(testFixture.m_iDispatchStub), 2u); + + qRegisterMetaType<QAxObject *>("QAxObject*"); + qRegisterMetaType<QAxObject>("QAxObject"); + + const QVariant qVariant = VARIANTToQVariant(testFixture.m_comVariant, "QAxObject*"); + QVERIFY(qVariant.isNull()); +} + +void tst_Conversion::VARIANTToQVariant_CreatesQAxObject_WhenCalledWithMetaTypeId() +{ + const IDispatchFixture testFixture; + QCOMPARE(refCount(testFixture.m_iDispatchStub), 2u); + + qRegisterMetaType<QAxObject *>("QAxObject*"); + qRegisterMetaType<QAxObject>("QAxObject"); + + const QVariant qVariant = VARIANTToQVariant(testFixture.m_comVariant, "QAxObject*", QMetaType::fromType<QAxObject*>().id()); + + QAxObject *recovered = qVariant.value<QAxObject *>(); + QVERIFY(recovered != nullptr); +} + +template<typename T> +void tst_Conversion::addScalarMaxValueRow() +{ + using ValueType = std::remove_pointer_t<T>; + static ValueType v = std::numeric_limits<ValueType>::max(); + + ComVariant comVariant; + if constexpr (std::is_pointer_v<T>) + comVariant = &v; + else + comVariant = v; + + const char *typeName = QMetaType::fromType<T>().name(); + QTest::newRow(typeName) << comVariant << QVariant{ v }; +} + QTEST_MAIN(tst_Conversion) + +QT_END_NAMESPACE + #include "tst_conversion.moc" diff --git a/tests/auto/dumpcpp/CMakeLists.txt b/tests/auto/dumpcpp/CMakeLists.txt index 91da6c3..a5ff2dc 100644 --- a/tests/auto/dumpcpp/CMakeLists.txt +++ b/tests/auto/dumpcpp/CMakeLists.txt @@ -1,20 +1,24 @@ -# Generated from dumpcpp.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_dumpcpp Test: ##################################################################### -qt_add_test(tst_dumpcpp +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_dumpcpp LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_dumpcpp SOURCES tst_dumpcpp.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::AxContainer Qt::Gui Qt::Widgets ) -#### Keys ignored in scope 1:.:.:dumpcpp.pro:<TRUE>: -# TYPELIBS = "$$(SystemRoot)\\system32\\ieframe.dll" - -## Scopes: -##################################################################### +qt6_target_typelibs(tst_dumpcpp LIBRARIES "ieframe.dll") +qt6_target_typelibs(tst_dumpcpp LIBRARIES "msxml6.dll") diff --git a/tests/auto/dumpcpp/dumpcpp.pro b/tests/auto/dumpcpp/dumpcpp.pro deleted file mode 100644 index aae7bd8..0000000 --- a/tests/auto/dumpcpp/dumpcpp.pro +++ /dev/null @@ -1,11 +0,0 @@ -CONFIG += testcase -QT += widgets axcontainer testlib -SOURCES += tst_dumpcpp.cpp -TARGET = tst_dumpcpp - -# Assume Web Browser type library is available in all windows installations -TYPELIBS = $$(SystemRoot)\\system32\\ieframe.dll - -!exists($$TYPELIBS) { - message("Web Browser type library for test not found!") -} diff --git a/tests/auto/dumpcpp/tst_dumpcpp.cpp b/tests/auto/dumpcpp/tst_dumpcpp.cpp index 039c090..66cd158 100644 --- a/tests/auto/dumpcpp/tst_dumpcpp.cpp +++ b/tests/auto/dumpcpp/tst_dumpcpp.cpp @@ -1,47 +1,55 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtTest/QtTest> #include "ieframe.h" // generated header +#include "msxml6.h" // generated header #include <QApplication> + +struct XmlFixture +{ + MSXML2::DOMDocument60 doc; + MSXML2::IXMLDOMNodeList *root; + + const QString xml{ + R"( + <root prop="The root property"> + The value + </root> + )" }; +}; + class tst_dumpcpp : public QObject { Q_OBJECT private slots: + void init(); void toggleAddressBar(); + void propertyGetter_ReturnsValue_WhenValueIsInt(); + void propertyGetter_ReturnsValue_WhenValueIsString(); + void invokeGetter_ReturnsValue_WhenValueInheritsIDispatch(); + void propertyGetter_ReturnsValue_WhenValueInheritsIDispatch(); + + void propertySetter_SetsValue_WhenValueIsVariantInt(); + void propertySetter_SetsValue_WhenValueIsString(); + void invoke_SetsValue_WhenValueDerivesFromIDispatch(); + +private: + XmlFixture m_xml; }; +void tst_dumpcpp::init() +{ + m_xml.doc.loadXML(m_xml.xml); + m_xml.root = m_xml.doc.childNodes(); +} + // A simple test to verify that an object can be instantiated and interacted with void tst_dumpcpp::toggleAddressBar() { - SHDocVw::WebBrowser* webBrowser = new SHDocVw::WebBrowser; + SHDocVw::WebBrowser *webBrowser = new SHDocVw::WebBrowser; QVERIFY(webBrowser); bool addressBar = webBrowser->AddressBar(); addressBar = !addressBar; @@ -50,5 +58,60 @@ void tst_dumpcpp::toggleAddressBar() delete webBrowser; } +void tst_dumpcpp::propertyGetter_ReturnsValue_WhenValueIsInt() +{ + int length = m_xml.root->length(); + QVERIFY(length == 1); +} + +void tst_dumpcpp::invokeGetter_ReturnsValue_WhenValueInheritsIDispatch() +{ + // item(...) takes an argument and is called as a function invocation + MSXML2::IXMLDOMNode *firstChild = m_xml.root->item(0); + QVERIFY(firstChild); +} + +void tst_dumpcpp::propertyGetter_ReturnsValue_WhenValueInheritsIDispatch() +{ + // attributes() takes an argument and is called as property getter + MSXML2::IXMLDOMNamedNodeMap *attributes = m_xml.root->item(0)->attributes(); + QVERIFY(attributes); +} + +void tst_dumpcpp::propertyGetter_ReturnsValue_WhenValueIsString() +{ + MSXML2::IXMLDOMNamedNodeMap *attributes = m_xml.root->item(0)->attributes(); + + // nodeValue is a property getter + QVariant p = attributes->getNamedItem("prop")->nodeValue(); + QCOMPARE(p, "The root property"); +} + +void tst_dumpcpp::propertySetter_SetsValue_WhenValueIsVariantInt() +{ + MSXML2::IXMLDOMNamedNodeMap *attributes = m_xml.root->item(0)->attributes(); + MSXML2::IXMLDOMNode *attribNode = attributes->item(0); + attribNode->setNodeValue(QVariant { 42 } ); + + QVariant p = attributes->getNamedItem("prop")->nodeValue(); + QCOMPARE(p, 42); +} + +void tst_dumpcpp::propertySetter_SetsValue_WhenValueIsString() +{ + m_xml.root->item(0)->setText("The new value"); + QCOMPARE(m_xml.root->item(0)->text(), "The new value"); +} + +void tst_dumpcpp::invoke_SetsValue_WhenValueDerivesFromIDispatch() +{ + MSXML2::IXMLDOMNode *node = m_xml.doc.createNode(MSXML2::NODE_ELEMENT, "sometag", ""); + node->setText("The new text"); + + m_xml.root->item(0)->appendChild(node); + + QCOMPARE(m_xml.root->item(0)->childNodes()->item(1)->text(), "The new text"); +} + QTEST_MAIN(tst_dumpcpp) #include "tst_dumpcpp.moc" diff --git a/tests/auto/qaxobject/CMakeLists.txt b/tests/auto/qaxobject/CMakeLists.txt index 7c07415..87fe2e1 100644 --- a/tests/auto/qaxobject/CMakeLists.txt +++ b/tests/auto/qaxobject/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qaxobject.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### -## qaxobject Test: +## QAxObject Test: ##################################################################### -qt_add_test(qaxobject +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qaxobject LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qaxobject SOURCES tst_qaxobject.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::AxContainer Qt::Gui ) diff --git a/tests/auto/qaxobject/qaxobject.pro b/tests/auto/qaxobject/qaxobject.pro deleted file mode 100644 index e6f51a1..0000000 --- a/tests/auto/qaxobject/qaxobject.pro +++ /dev/null @@ -1,3 +0,0 @@ -CONFIG += testcase -QT += axcontainer testlib -SOURCES += tst_qaxobject.cpp diff --git a/tests/auto/qaxobject/tst_qaxobject.cpp b/tests/auto/qaxobject/tst_qaxobject.cpp index 3955a6c..dfae5f0 100644 --- a/tests/auto/qaxobject/tst_qaxobject.cpp +++ b/tests/auto/qaxobject/tst_qaxobject.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtTest/QtTest> diff --git a/tests/auto/qaxobjectcom/CMakeLists.txt b/tests/auto/qaxobjectcom/CMakeLists.txt new file mode 100644 index 0000000..09ce6a1 --- /dev/null +++ b/tests/auto/qaxobjectcom/CMakeLists.txt @@ -0,0 +1,33 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +# Configure the manifest file to point to the com_server dll +# because the dll name is different in debug and release +set(TestServerDll "TestServer${CMAKE_DEBUG_POSTFIX}.dll") +configure_file( + tst_qaxobjectcom.exe.manifest.in + tst_qaxobjectcom.exe.manifest +) + +qt_internal_add_test(tst_qaxobjectcom + SOURCES + tst_qaxobjectcom.cpp + ${CMAKE_CURRENT_BINARY_DIR}/tst_qaxobjectcom.exe.manifest + LIBRARIES + Qt::AxContainer + Qt::CorePrivate + Qt::AxBasePrivate +) + +# Embed the manifest file into the binary for registry free COM +target_link_options(tst_qaxobjectcom PRIVATE "/MANIFEST") + +# Build the com_server automatically +add_subdirectory(testserver) +add_dependencies(tst_qaxobjectcom testserver) + +# Generate qaxobject COM wrapper for our COM test server +qt6_target_typelibs(tst_qaxobjectcom + LIBRARIES + ${CMAKE_CURRENT_BINARY_DIR}/testserver/testserverlib.tlb +) diff --git a/tests/auto/qaxobjectcom/testserver/CMakeLists.txt b/tests/auto/qaxobjectcom/testserver/CMakeLists.txt new file mode 100644 index 0000000..f05ebc0 --- /dev/null +++ b/tests/auto/qaxobjectcom/testserver/CMakeLists.txt @@ -0,0 +1,47 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +# Configure file allow execute_process to detect changes to idl file. +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/testserverlib.idl + ${CMAKE_CURRENT_BINARY_DIR}/testserverlib.idl + COPYONLY +) + +# Run midl at configure time because qt6_target_typelibs checks +# for presence of tlb file at configure time +execute_process( + COMMAND + midl /h testserverlib.h /tlb testserverlib.tlb testserverlib.idl + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMAND_ERROR_IS_FATAL ANY +) + +qt_add_library(testserver +SHARED + testserver.h + testserver.cpp + testserver.def + testserverlib.idl + testserver.rc +) + +# Trigger rebuild of resources if tlb file changed +set_property( + SOURCE + testserver.rc + PROPERTY + OBJECT_DEPENDS + ${CMAKE_CURRENT_BINARY_DIR}/testserverlib.tlb +) + +target_include_directories(testserver + PRIVATE + ${CMAKE_CURRENT_BINARY_DIR} +) + +target_link_libraries(testserver + PRIVATE + Qt::CorePrivate + Qt::AxBasePrivate +) diff --git a/tests/auto/qaxobjectcom/testserver/testserver.cpp b/tests/auto/qaxobjectcom/testserver/testserver.cpp new file mode 100644 index 0000000..1145565 --- /dev/null +++ b/tests/auto/qaxobjectcom/testserver/testserver.cpp @@ -0,0 +1,132 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include <QString> +#include <QUuid> +#include <QtCore/qassert.h> +#include <QtCore/qdebug.h> +#include "testserverlib.h" +#include "testserver.h" + +extern "C" IMAGE_DOS_HEADER __ImageBase; // Trickery to get path to current dll +static long s_serverLock = 0; + +static const std::array<wchar_t, MAX_PATH> GetModuleFilename() +{ + std::array<wchar_t, MAX_PATH> filename; + const DWORD length = GetModuleFileName(reinterpret_cast<HMODULE>(&__ImageBase), filename.data(), + static_cast<DWORD>(filename.size())); + + if (0 == length || filename.size() == length) + return {}; + + return filename; +} + +// Create a dispatcher that implements IDispatch for the input owner +static ComPtr<IUnknown> CreateDispatcher(const QUuid &guid, IUnknown *owner) +{ + ComPtr<ITypeLib> typeLib; + if (LoadTypeLib(GetModuleFilename().data(), &typeLib) != S_OK) + { + qCritical("Failed to load type library"); + return {}; + } + + ComPtr<ITypeInfo> typeInfo; + if (typeLib->GetTypeInfoOfGuid(guid, &typeInfo) + != S_OK) { + qCritical("Failed to get type info"); + return {}; + } + + ComPtr<IUnknown> dispatcher; + if (CreateStdDispatch(owner, owner, typeInfo.Get(), &dispatcher) != S_OK) { + qCritical("Failed to create standard dispatch"); + return {}; + } + + return dispatcher; +} + +TestServer::TestServer() +{ + m_unkDisp = CreateDispatcher(__uuidof(IComServer), this); + ++s_serverLock; +} + +HRESULT __stdcall TestServer::QueryInterface(IID const &id, void **result) +{ + Q_ASSERT(result); + if (id == __uuidof(IDispatch)) { + ComPtr<IDispatch> disp; + m_unkDisp.As(&disp); + *result = disp.Detach(); + return S_OK; + } + return QComObject::QueryInterface(id, result); +} + +HRESULT TestServer::SetObserver(IUnknown* observer) +{ + const ComPtr<IUnknown> rcv{ observer }; + return rcv.As(&m_receiver); +} + +HRESULT TestServer::VariantIn(VARIANT v) +{ + return m_receiver->VariantIn(v); +} + +struct Factory : IClassFactory +{ + ULONG __stdcall AddRef() override { return 2; } + ULONG __stdcall Release() override { return 1; } + HRESULT __stdcall QueryInterface(IID const &id, void **result) override + { + Q_ASSERT(result); + + if (id == __uuidof(IClassFactory) || id == __uuidof(IUnknown)) { + *result = static_cast<IClassFactory *>(this); + return S_OK; + } + + *result = nullptr; + return E_NOINTERFACE; + } + + HRESULT __stdcall CreateInstance(IUnknown *outer, IID const &iid, void **result) override + { + Q_ASSERT(result); + Q_ASSERT(!outer); + + const ComPtr<TestServer> server{ new (std::nothrow) TestServer }; + return server->QueryInterface(iid, result); + } + + HRESULT __stdcall LockServer(BOOL lock) override + { + if (lock) + ++s_serverLock; + else + --s_serverLock; + + return S_OK; + } +}; + +HRESULT __stdcall DllGetClassObject(CLSID const &clsid, IID const &iid, void **result) +{ + if (__uuidof(TestServer) == clsid) { + static Factory farm; + + return farm.QueryInterface(iid, result); + } + + return CLASS_E_CLASSNOTAVAILABLE; +} + +HRESULT __stdcall DllCanUnloadNow() +{ + return s_serverLock ? S_FALSE : S_OK; +} diff --git a/tests/auto/qaxobjectcom/testserver/testserver.def b/tests/auto/qaxobjectcom/testserver/testserver.def new file mode 100644 index 0000000..56e1a71 --- /dev/null +++ b/tests/auto/qaxobjectcom/testserver/testserver.def @@ -0,0 +1,3 @@ +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE diff --git a/tests/auto/qaxobjectcom/testserver/testserver.h b/tests/auto/qaxobjectcom/testserver/testserver.h new file mode 100644 index 0000000..53663ef --- /dev/null +++ b/tests/auto/qaxobjectcom/testserver/testserver.h @@ -0,0 +1,43 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef TEST_SERVER_H +#define TEST_SERVER_H + +#include <qt_windows.h> +#include "testserverlib.h" +#include <wrl/client.h> +#include <QtCore/private/qcomobject_p.h> +#include "../../conversion/comutil_p.h" + +using Microsoft::WRL::ComPtr; + +class __declspec(uuid("af732aba-95cf-4ee7-bd59-8f946b7f82e3")) +TestServer : public QComObject<IComServer> +{ +public: + TestServer(); + + HRESULT __stdcall QueryInterface(IID const &id, void **result) override; + HRESULT __stdcall SetObserver(IUnknown *observer) override; + HRESULT __stdcall VariantIn(VARIANT v) override; + +private: + ComPtr<IUnknown> m_unkDisp; + ComPtr<IComServer> m_receiver; +}; + +struct Receiver : public QComObject<IComServer> +{ + HRESULT SetObserver(IUnknown *observer) override { return E_NOTIMPL; } + + HRESULT VariantIn(VARIANT arg) override + { + lastArg = ComVariant{ arg }; + return S_OK; + } + + ComVariant lastArg{}; +}; + +#endif diff --git a/tests/auto/qaxobjectcom/testserver/testserver.rc b/tests/auto/qaxobjectcom/testserver/testserver.rc new file mode 100644 index 0000000..51dfeed --- /dev/null +++ b/tests/auto/qaxobjectcom/testserver/testserver.rc @@ -0,0 +1 @@ +1 TYPELIB "testserverlib.tlb" diff --git a/tests/auto/qaxobjectcom/testserver/testserverlib.idl b/tests/auto/qaxobjectcom/testserver/testserverlib.idl new file mode 100644 index 0000000..00d64ab --- /dev/null +++ b/tests/auto/qaxobjectcom/testserver/testserverlib.idl @@ -0,0 +1,33 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import "oaidl.idl"; +import "ocidl.idl"; + +[ + object, + dual, + uuid(f4811a11-3092-415e-a473-38c627544246), + oleautomation, + pointer_default(unique) +] +interface IComServer : IUnknown +{ + HRESULT SetObserver([in] IUnknown *observer); + HRESULT VariantIn([in] VARIANT arg); +}; + +[ + uuid(104d435f-7504-4786-aae7-b22745450c4c), + version(1.0), +] +library ComServerLib +{ + [ + uuid(af732aba-95cf-4ee7-bd59-8f946b7f82e3), + ] + coclass TestServer + { + interface IComServer; + }; +}; diff --git a/tests/auto/qaxobjectcom/tst_qaxobjectcom.cpp b/tests/auto/qaxobjectcom/tst_qaxobjectcom.cpp new file mode 100644 index 0000000..fec1d8d --- /dev/null +++ b/tests/auto/qaxobjectcom/tst_qaxobjectcom.cpp @@ -0,0 +1,87 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include <QtTest/QtTest> +#include "testserverlib.h" +#include <testserver/testserverlib.h> +#include "testserver/testserver.h" +#include "../conversion/comutil_p.h" +#include <QtAxBase/private/qbstr_p.h> + +class tst_qaxobjectcom : public QObject +{ + Q_OBJECT +private slots: + void comObject_receivesVARIANT_whenCalledWithQVariant_data() + { + QTest::addColumn<QVariant>("value"); + QTest::addColumn<ComVariant>("expected"); + + QTest::addRow("bool") << QVariant{ true } << ComVariant{ VARIANT_TRUE }; + QTest::addRow("short") << QVariant{ static_cast<short>(3) } << ComVariant{ static_cast<int>(3) }; // TODO: Fixme + QTest::addRow("unsigned short") << QVariant{ static_cast<ushort>(3) } << ComVariant{ static_cast<int>(3) }; // TODO: Fixme + QTest::addRow("int") << QVariant{ 3 } << ComVariant{ 3 }; + QTest::addRow("unsigned int") << QVariant{ 3u } << ComVariant{ 3u }; + QTest::addRow("long long") << QVariant{ 3ll } << ComVariant{ 3ll }; + QTest::addRow("unsigned long long") << QVariant{ 3ull } << ComVariant{ 3ull }; + QTest::addRow("float") << QVariant{ 3.3f } << ComVariant{ 3.3f }; + QTest::addRow("double") << QVariant{ 3.3 } << ComVariant{ 3.3 }; + } + + void comObject_receivesVARIANT_whenCalledWithQVariant() + { + QFETCH(const QVariant, value); + QFETCH(const ComVariant, expected); + + // Arrange + ComServerLib::TestServer server; + const ComPtr<Receiver> observer = makeComObject<Receiver>(); + server.SetObserver(observer.Get()); + + // Act + server.VariantIn(value); + + // Assert + QCOMPARE_EQ(observer->lastArg, expected); + } + + void comObject_receivesVARIANT_whenCalledWithVariantStringList() + { + const QVariant value{ QList{ QVariant{ "A" }, QVariant{ "BC" } } }; + + // Arrange + ComServerLib::TestServer server; + const ComPtr<Receiver> observer = makeComObject<Receiver>(); + server.SetObserver(observer.Get()); + + // Act + server.VariantIn(value); + + // Assert + QVERIFY(V_ISARRAY(&observer->lastArg)); + + LPSAFEARRAY safeArray = V_ARRAY(&observer->lastArg); + + VARTYPE itemType; + if (SUCCEEDED(SafeArrayGetVartype(safeArray, &itemType))) + + QCOMPARE_EQ(itemType, VT_VARIANT); + + LPVOID data; + QCOMPARE_EQ(SafeArrayAccessData(safeArray, &data), S_OK); + + const auto *pItems = static_cast<const VARIANT*>(data); + ComVariant item1{ pItems[0] }; + ComVariant item2{ pItems[1] }; + + QCOMPARE_EQ(item1, ComVariant{ QBStr{ L"A" } }); + QCOMPARE_EQ(item2, ComVariant{ QBStr{ L"BC" } }); + + // end accessing data + QCOMPARE_EQ(SafeArrayUnaccessData(safeArray), S_OK); + + } +}; + +QTEST_MAIN(tst_qaxobjectcom) +#include "tst_qaxobjectcom.moc" diff --git a/tests/auto/qaxobjectcom/tst_qaxobjectcom.exe.manifest.in b/tests/auto/qaxobjectcom/tst_qaxobjectcom.exe.manifest.in new file mode 100644 index 0000000..7d6ef11 --- /dev/null +++ b/tests/auto/qaxobjectcom/tst_qaxobjectcom.exe.manifest.in @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"> + <assemblyIdentity version="1.0.0.0" name="tst_qaxobjectcom.app"/> + <file name="testserver/${TestServerDll}"> + <comClass + description="Com Server" + clsid="{af732aba-95cf-4ee7-bd59-8f946b7f82e3}" + progid="Qt.TestServer" + threadingModel = "Both" + /> + </file> +</assembly> diff --git a/tests/auto/qaxscript/CMakeLists.txt b/tests/auto/qaxscript/CMakeLists.txt index 4312217..351ab2f 100644 --- a/tests/auto/qaxscript/CMakeLists.txt +++ b/tests/auto/qaxscript/CMakeLists.txt @@ -1,12 +1,19 @@ -# Generated from qaxscript.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### -## qaxscript Test: +## tst_QAxScript Test: ##################################################################### -qt_add_test(qaxscript +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qaxscript LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qaxscript SOURCES tst_qaxscript.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::AxContainer ) diff --git a/tests/auto/qaxscript/qaxscript.pro b/tests/auto/qaxscript/qaxscript.pro deleted file mode 100644 index 704b2cd..0000000 --- a/tests/auto/qaxscript/qaxscript.pro +++ /dev/null @@ -1,3 +0,0 @@ -CONFIG += testcase -QT = core axcontainer testlib -SOURCES += tst_qaxscript.cpp diff --git a/tests/auto/qaxscript/tst_qaxscript.cpp b/tests/auto/qaxscript/tst_qaxscript.cpp index 3b3ab88..1eb4258 100644 --- a/tests/auto/qaxscript/tst_qaxscript.cpp +++ b/tests/auto/qaxscript/tst_qaxscript.cpp @@ -1,57 +1,162 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtTest/QtTest> #include <QAxScriptManager> #include <QAxScript> +using namespace Qt::StringLiterals; + class tst_QAxScript : public QObject { Q_OBJECT private slots: + void call(); void scriptReturnValue(); + void scriptOutParameters(); + void error_data(); + void error(); }; +void tst_QAxScript::call() +{ + QAxScriptManager scriptManager; + const auto scriptCode_js = uR"JS( + function test1() { + return 'JScript'; + } + )JS"_s; + const auto scriptCode_vb = uR"VB( + Function test2() + test2 = "VBScript" + End Function + )VB"_s; + QAxScript *jsscript = scriptManager.load(scriptCode_js, u"JS"_s, u"JScript"_s); + QVERIFY2(jsscript, "Unable to load script (CoInitializeEx() called?)"); + QVERIFY(jsscript->scriptEngine()->hasIntrospection()); + QAxScript *vbscript = scriptManager.load(scriptCode_vb, u"VB"_s, u"VBScript"_s); + QVERIFY2(vbscript, "Unable to load script (CoInitializeEx() called?)"); + QVERIFY(vbscript->scriptEngine()->hasIntrospection()); + + QCOMPARE(jsscript->call("test1()"), "JScript"); + QTest::ignoreMessage(QtWarningMsg, "QAxBase::dynamicCallHelper: test1(): No such method in [unknown]"); + QTest::ignoreMessage(QtWarningMsg, "\tCandidates are:"); + QCOMPARE(vbscript->call("test1()"), QVariant()); + QCOMPARE(vbscript->call("test2()"), "VBScript"); + QTest::ignoreMessage(QtWarningMsg, "QAxBase::dynamicCallHelper: test2(): No such method in [unknown]"); + QTest::ignoreMessage(QtWarningMsg, "\tCandidates are:"); + QCOMPARE(jsscript->call("test2()"), QVariant()); +} + void tst_QAxScript::scriptReturnValue() { QAxScriptManager scriptManager; - const char scriptCode[] = - "function foo() {\n" - " return 'test';\n" - "}\n"; // QTBUG-42289, fails when DISPATCH_PROPERTYGET is used. - QAxScript *script = scriptManager.load(QLatin1String(scriptCode), - QStringLiteral("Test"), - QStringLiteral("JScript")); + const auto scriptCode = uR"JS( + function foo() { + return 'test'; + } + )JS"_s; // QTBUG-42289, fails when DISPATCH_PROPERTYGET is used. + QAxScript *script = scriptManager.load(scriptCode, u"Test"_s, u"JScript"_s); QVERIFY2(script, "Unable to load script (CoInitializeEx() called?)"); const QVariant result = script->call("foo()"); - QCOMPARE(result, QVariant(QStringLiteral("test"))); + QCOMPARE(result, QVariant(u"test"_s)); +} + +void tst_QAxScript::scriptOutParameters() +{ + QAxScriptManager scriptManager; + const auto scriptCode = uR"VB( + Function GetProductName(ByRef manufacturer, ByRef name, ByRef version) + manufacturer = "The Qt Company" + name = "ActiveQt" + version = 650 + On Error Resume Next + GetProductName = 42 + End Function + )VB"_s; + + QAxScript *script = scriptManager.load(scriptCode, u"Test"_s, u"VBScript"_s); + QVERIFY2(script, "Unable to load script (CoInitializeEx() called?)"); + + QVariant returnValue; + QList<QVariant> results = {{}, {}, {}}; + + returnValue = script->scriptEngine()->dynamicCall("GetProductName(QVariant&,QVariant&,QVariant&)", results); + QCOMPARE(returnValue, 42); + QCOMPARE(results.size(), 3); + QCOMPARE(results.at(0), "The Qt Company"); + QCOMPARE(results.at(1), "ActiveQt"); + QCOMPARE(results.at(2), 650); + + results = {{}, {}, {}}; + returnValue = script->call("GetProductName(QVariant&,QVariant&,QVariant&)", results); + QCOMPARE(returnValue, 42); + QCOMPARE(results.size(), 3); + QCOMPARE(results.at(0), "The Qt Company"); + QCOMPARE(results.at(1), "ActiveQt"); + QCOMPARE(results.at(2), 650); +} + +void tst_QAxScript::error_data() +{ + QTest::addColumn<QString>("scriptCode"); + QTest::addColumn<QString>("language"); + QTest::addColumn<int>("expectedErrorCode"); + QTest::addColumn<QString>("expectedDescription"); + QTest::addColumn<int>("expectedSourcePosition"); + QTest::addColumn<QString>("expectedSourceText"); + + QTest::addRow("JS syntax error") + << "function foo {}" + << "JScript" + << 0 << "Expected '('" << 0 << "function foo {}"; + + QTest::addRow("VB syntax error") + << "Funktion test" + << "VBScript" + << 0 << "Type mismatch: 'Funktion'" << 0 << ""; +} + +void tst_QAxScript::error() +{ + QFETCH(QString, scriptCode); + QFETCH(QString, language); + QFETCH(int, expectedErrorCode); + QFETCH(QString, expectedDescription); + QFETCH(int, expectedSourcePosition); + QFETCH(QString, expectedSourceText); + + QAxScriptManager scriptManager; + QAxScript script(u"Test"_s, &scriptManager); + + QAxScript *actualScript = nullptr; + int actualCode; + QString actualDescription; + int actualSourcePosition; + QString actualSourceText; + + connect(&scriptManager, &QAxScriptManager::error, + this, [&](QAxScript *script){ + actualScript = script; + }); + + connect(&script, &QAxScript::error, + this, [&](int code, const QString &description, int sourcePosition, const QString &sourceText){ + actualCode = code; + actualDescription = description; + actualSourcePosition = sourcePosition; + actualSourceText = sourceText.trimmed(); + }); + + script.load(scriptCode, language); + + QCOMPARE(actualScript, &script); + QCOMPARE(actualCode, expectedErrorCode); + QCOMPARE(actualDescription, expectedDescription); + QCOMPARE(actualSourcePosition, expectedSourcePosition); + QCOMPARE(actualSourceText, expectedSourceText); } QTEST_MAIN(tst_QAxScript) diff --git a/tests/auto/qaxscriptmanager/CMakeLists.txt b/tests/auto/qaxscriptmanager/CMakeLists.txt new file mode 100644 index 0000000..37b83ab --- /dev/null +++ b/tests/auto/qaxscriptmanager/CMakeLists.txt @@ -0,0 +1,19 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +##################################################################### +## QAxScriptManager Test: +##################################################################### + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qaxscriptmanager LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qaxscriptmanager + SOURCES + tst_qaxscriptmanager.cpp + LIBRARIES + Qt::AxContainer +) diff --git a/tests/auto/qaxscriptmanager/tst_qaxscriptmanager.cpp b/tests/auto/qaxscriptmanager/tst_qaxscriptmanager.cpp new file mode 100644 index 0000000..9ecb7c2 --- /dev/null +++ b/tests/auto/qaxscriptmanager/tst_qaxscriptmanager.cpp @@ -0,0 +1,188 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + + +#include <QtTest/QtTest> +#include <QAxScriptManager> +#include <QAxScript> + +using namespace Qt::StringLiterals; + +class tst_QAxScriptManager : public QObject +{ + Q_OBJECT + +public: + struct Script { + QString language; + QString name; + QString code; + }; + +private slots: + void functions_data(); + void functions(); + + void scriptNames_data(); + void scriptNames(); + + void script_data(); + void script(); + + void call_data(); + void call(); +}; + +void tst_QAxScriptManager::functions_data() +{ + const auto scriptCode_js = Script{u"JScript"_s, u"test1"_s, uR"JS( + function js1() { + return 'JScript 1'; + } + function js2(value) { + return 'JScript 2'; + } + )JS"_s}; + const auto scriptCode_vb = Script{u"VBScript"_s, u"test2"_s, uR"VB( + Function vb1() + vb1 = "VBScript 1" + End Function + + Function vb2(value) + vb2 = "VBScript 2" + End Function + )VB"_s}; + + QTest::addColumn<QList<Script>>("scripts"); + QTest::addColumn<QStringList>("functions"); + QTest::addColumn<QStringList>("signatures"); + + QTest::addRow("js") << QList{scriptCode_js} + << QStringList{"js1", "js2"} + << QStringList{"js1()", "js2(QVariant)"}; + QTest::addRow("vb") << QList{scriptCode_vb} + << QStringList{"vb1", "vb2"} + << QStringList{"vb1()", "vb2(QVariant)"}; + QTest::addRow("both") << QList{scriptCode_js, scriptCode_vb} + << QStringList{"js1", "js2", "vb1", "vb2"} + << QStringList{"js1()", "js2(QVariant)", "vb1()", "vb2(QVariant)"}; +} + +void tst_QAxScriptManager::functions() +{ + // QStringList functions(QAxScript::FunctionFlags = QAxScript::FunctionNames) const; + + QFETCH(QList<Script>, scripts); + QFETCH(QStringList, functions); + QFETCH(QStringList, signatures); + + QAxScriptManager scriptManager; + for (const auto &script : scripts) { + QVERIFY2(scriptManager.load(script.code, script.name, script.language), + "Unable to load script (CoInitializeEx() called?)"); + } + functions.sort(); + QStringList actualFunctions = scriptManager.functions(); + actualFunctions.sort(); + QCOMPARE(actualFunctions, functions); + + QStringList actualSignatures = scriptManager.functions(QAxScript::FunctionSignatures); + actualSignatures.sort(); + QCOMPARE(actualSignatures, signatures); +} + +void tst_QAxScriptManager::scriptNames_data() +{ + functions_data(); +} + +void tst_QAxScriptManager::scriptNames() +{ + // QStringList scriptNames() const; + QFETCH(QList<Script>, scripts); + QFETCH(QStringList, functions); + + QAxScriptManager scriptManager; + QStringList expectedNames; + for (const auto &script : scripts) { + expectedNames << script.name; + QVERIFY2(scriptManager.load(script.code, script.name, script.language), + "Unable to load script (CoInitializeEx() called?)"); + } + expectedNames.sort(); + QStringList actualNames = scriptManager.scriptNames(); + actualNames.sort(); + QCOMPARE(actualNames, expectedNames); +} + +void tst_QAxScriptManager::script_data() +{ + functions_data(); +} + +void tst_QAxScriptManager::script() +{ + QFETCH(QList<Script>, scripts); + QFETCH(QStringList, functions); + + QAxScriptManager scriptManager; + QStringList expectedNames; + for (const auto &script : scripts) { + expectedNames << script.name; + QVERIFY2(scriptManager.load(script.code, script.name, script.language), + "Unable to load script (CoInitializeEx() called?)"); + } + + for (const auto &script : scripts) { + QAxScript *axscript = scriptManager.script(script.name); + QVERIFY(axscript); + QVERIFY(axscript->scriptEngine()); + QVERIFY(axscript->scriptEngine()->isValid()); + const auto scriptFunctions = axscript->functions(); + for (const auto &scriptFunction : scriptFunctions) { + auto index = functions.indexOf(scriptFunction); + QCOMPARE_NE(index, -1); + functions.remove(index); + } + + QCOMPARE(axscript->scriptEngine()->scriptLanguage(), script.language); + } + + // verify that all functions were found across the different QAxScript objects + QVERIFY(functions.isEmpty()); +} + +void tst_QAxScriptManager::call_data() +{ + functions_data(); +} + +void tst_QAxScriptManager::call() +{ + QFETCH(QList<Script>, scripts); + QFETCH(QStringList, functions); + QFETCH(QStringList, signatures); + + QAxScriptManager scriptManager; + for (const auto &script : scripts) { + QAxScript *axScript = scriptManager.load(script.code, script.name, script.language); + + QVERIFY2(axScript, "Unable to load script (CoInitializeEx() called?)"); + QVERIFY(axScript->scriptEngine()); + QVERIFY(axScript->scriptEngine()->hasIntrospection()); + } + + // QAxScriptManager::call finds the script based on function name... + for (const auto &function : std::as_const(functions)) { + QVariant result = scriptManager.call(function); + QCOMPARE(result.metaType(), QMetaType::fromType<QString>()); + } + // ...or fully qualified function signature + for (const auto &function : std::as_const(signatures)) { + QVariant result = scriptManager.call(function); + QCOMPARE(result.metaType(), QMetaType::fromType<QString>()); + } +} + +QTEST_MAIN(tst_QAxScriptManager) +#include "tst_qaxscriptmanager.moc" diff --git a/tests/auto/qbstr/CMakeLists.txt b/tests/auto/qbstr/CMakeLists.txt new file mode 100644 index 0000000..65a49a6 --- /dev/null +++ b/tests/auto/qbstr/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qbstr LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qbstr + SOURCES + tst_qbstr.cpp + LIBRARIES + Qt::AxBasePrivate +) diff --git a/tests/auto/qbstr/tst_qbstr.cpp b/tests/auto/qbstr/tst_qbstr.cpp new file mode 100644 index 0000000..3a757f6 --- /dev/null +++ b/tests/auto/qbstr/tst_qbstr.cpp @@ -0,0 +1,138 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include <QtTest/QtTest> +#include <QtAxBase/private/qbstr_p.h> + +QT_USE_NAMESPACE + +using namespace Qt::StringLiterals; + +typedef int (*SETOANOCACHE)(void); + +void DisableBSTRCache() +{ + const HINSTANCE hLib = LoadLibraryA("OLEAUT32.DLL"); + if (hLib != nullptr) { + const SETOANOCACHE SetOaNoCache = + reinterpret_cast<SETOANOCACHE>(GetProcAddress(hLib, "SetOaNoCache")); + if (SetOaNoCache != nullptr) + SetOaNoCache(); + FreeLibrary(hLib); + } +} + +class tst_qbstr : public QObject +{ + Q_OBJECT +private slots: + void initTestCase() { DisableBSTRCache(); } + void constructor_nullInitializes() + { + const QBStr str; + QVERIFY(!str.bstr()); + } + + void constructor_initializes_withLiteral() + { + const QBStr str{ L"hello world" }; + QCOMPARE_EQ(str.bstr(), "hello world"_L1); + } + + void constructor_initializes_withQString() + { + const QString expected{ "hello world"_L1 }; + QBStr str{ expected }; + QCOMPARE_EQ(QStringView{ str.bstr() }, expected); + } + + void copyConstructor_initializes_withNullString() + { + const QBStr null; + const QBStr dest = null; + QCOMPARE_EQ(dest.bstr(), nullptr); + } + + void copyConstructor_initializes_withValidString() + { + const QBStr expected{ L"hello world" }; + const QBStr dest = expected; + QCOMPARE_EQ(QStringView{ dest.bstr() }, expected.bstr()); + } + + void moveConstructor_initializes_withNullString() + { + const QBStr str{ QBStr{} }; + QCOMPARE_EQ(str.bstr(), nullptr); + } + + void moveConstructor_initializes_withValidString() + { + QBStr source { L"hello world" }; + const QBStr str{ std::move(source) }; + QCOMPARE_EQ(str.bstr(), "hello world"_L1); + } + + void assignment_assigns_withNullString() + { + const QBStr source{}; + const QBStr dest = source; + QCOMPARE_EQ(dest.bstr(), nullptr); + } + + void assignment_assigns_withValidString() + { + const QBStr source{ L"hello world" }; + const QBStr dest = source; + QCOMPARE_EQ(dest.bstr(), "hello world"_L1); + } + + void moveAssignment_assigns_withNullString() + { + QBStr source{}; + const QBStr dest = std::move(source); + QCOMPARE_EQ(dest.bstr(), nullptr); + } + + void moveAssignment_assigns_withValidString() + { + QBStr source{ L"hello world" }; + const QBStr dest = std::move(source); + QCOMPARE_EQ(dest.bstr(), "hello world"_L1); + } + + void release_returnsStringAndClearsValue() + { + QBStr str{ L"hello world" }; + BSTR val = str.release(); + QCOMPARE_EQ(str.bstr(), nullptr); + QCOMPARE_EQ(val, "hello world"_L1); + SysFreeString(val); + } + + void str_returnsQString_withNullString() + { + const QBStr bstr{}; + const QString str = bstr.str(); + QVERIFY(str.isEmpty()); + } + + void str_returnsQString_withValidString() + { + const QBStr bstr{L"hello world"}; + const QString str = bstr.str(); + QCOMPARE_EQ(str, "hello world"); + } + + void operatorBool_returnsFalse_withNullString() { + QVERIFY(!QBStr{}); + } + + void operatorBool_returnsTrue_withValidString() + { + QVERIFY(QBStr{ "hello world" }); + } +}; + +QTEST_MAIN(tst_qbstr) +#include "tst_qbstr.moc" |