diff options
Diffstat (limited to 'tests/auto/corelib/global/qxp')
5 files changed, 424 insertions, 0 deletions
diff --git a/tests/auto/corelib/global/qxp/CMakeLists.txt b/tests/auto/corelib/global/qxp/CMakeLists.txt new file mode 100644 index 0000000000..2178f446db --- /dev/null +++ b/tests/auto/corelib/global/qxp/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(function_ref) +add_subdirectory(is_virtual_base_of) diff --git a/tests/auto/corelib/global/qxp/function_ref/CMakeLists.txt b/tests/auto/corelib/global/qxp/function_ref/CMakeLists.txt new file mode 100644 index 0000000000..351fe24b22 --- /dev/null +++ b/tests/auto/corelib/global/qxp/function_ref/CMakeLists.txt @@ -0,0 +1,16 @@ +# Copyright (C) 2022 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_qxp_function_ref LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qxp_function_ref + EXCEPTIONS + SOURCES + tst_qxp_function_ref.cpp + LIBRARIES + Qt::Core +) diff --git a/tests/auto/corelib/global/qxp/function_ref/tst_qxp_function_ref.cpp b/tests/auto/corelib/global/qxp/function_ref/tst_qxp_function_ref.cpp new file mode 100644 index 0000000000..ee50a311ef --- /dev/null +++ b/tests/auto/corelib/global/qxp/function_ref/tst_qxp_function_ref.cpp @@ -0,0 +1,281 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QtCore/qxpfunctional.h> + +#include <QTest> + +#include <type_traits> + +// checking dependency q20::remove_cvref_t: +#define CHECK(in, out) \ + static_assert(std::is_same_v<q20::remove_cvref_t< in >, out >) +CHECK(int, int); +CHECK(const int, int); +CHECK(int &, int); +CHECK(const int &, int); +CHECK(int &&, int); +CHECK(const int &&, int); +CHECK(int *, int *); +CHECK(const int *, const int *); +CHECK(int[4], int[4]); +CHECK(const int (&)[4], int[4]); +#undef CHECK + +template <typename T> constexpr inline bool +is_noexcept_function_ref_helper_v = false; +template <typename R, typename...Args> constexpr inline bool +is_noexcept_function_ref_helper_v<qxp::function_ref<R(Args...) noexcept(true)>> = true; +template <typename R, typename...Args> constexpr inline bool +is_noexcept_function_ref_helper_v<qxp::function_ref<R(Args...) const noexcept(true)>> = true; + +template <typename T> constexpr inline bool +is_noexcept_function_ref_v = is_noexcept_function_ref_helper_v<q20::remove_cvref_t<T>>; + +class tst_qxp_function_ref : public QObject +{ + Q_OBJECT +public: + using QObject::QObject; + +private Q_SLOTS: + void basics(); + void constOverloads(); + void constExpr(); + void voidReturning(); + void ctad(); +}; + +void tst_qxp_function_ref::basics() +{ + static_assert(std::is_trivially_copyable_v<qxp::function_ref<int(int)>>); + static_assert(std::is_trivially_copyable_v<qxp::function_ref<int()>>); + static_assert(std::is_trivially_copyable_v<qxp::function_ref<void()>>); + + { + Q_CONSTINIT static int invoked = 0; + auto lambda = [](int i) noexcept { ++invoked; return i; }; + const qxp::function_ref<int(int)> f = lambda; + QCOMPARE(invoked, 0); + QCOMPARE(f(42), 42); + QCOMPARE(invoked, 1); + + const int fourtyTwo = 42; + + const qxp::function_ref<int(int) noexcept> f2 = std::move(lambda); + QCOMPARE(invoked, 1); + QCOMPARE(f2(fourtyTwo), 42); + QCOMPARE(invoked, 2); + + int (*fpr)(int) = lambda; + + const qxp::function_ref f3 = fpr; + static_assert(!is_noexcept_function_ref_v<decltype(f3)>); + QCOMPARE(invoked, 2); + QCOMPARE(f3(42), 42); + QCOMPARE(invoked, 3); + + int (*fpr2)(int) noexcept = lambda; + + const qxp::function_ref f4 = fpr2; + static_assert(is_noexcept_function_ref_v<decltype(f4)>); + QCOMPARE(invoked, 3); + QCOMPARE(f4(42), 42); + QCOMPARE(invoked, 4); + } + { + Q_CONSTINIT static int invoked = 0; + auto lambda = [] { ++invoked; return 42; }; + const qxp::function_ref<int()> f = lambda; + QCOMPARE(invoked, 0); + QCOMPARE(f(), 42); + QCOMPARE(invoked, 1); + + const qxp::function_ref<int()> f2 = std::move(lambda); + QCOMPARE(invoked, 1); + QCOMPARE(f2(), 42); + QCOMPARE(invoked, 2); + + int (*fpr)() = lambda; + + const qxp::function_ref f3 = fpr; + static_assert(!is_noexcept_function_ref_v<decltype(f3)>); + QCOMPARE(invoked, 2); + QCOMPARE(f3(), 42); + QCOMPARE(invoked, 3); + } + { + Q_CONSTINIT static int invoked = 0; + auto lambda = [] { ++invoked; }; + const qxp::function_ref<void()> f = lambda; + QCOMPARE(invoked, 0); + f(); + QCOMPARE(invoked, 1); + + const qxp::function_ref<void()> f2 = std::move(lambda); + QCOMPARE(invoked, 1); + f2(); + QCOMPARE(invoked, 2); + + void (*fpr)() = lambda; + + const qxp::function_ref f3 = fpr; + QCOMPARE(invoked, 2); + f3(); + QCOMPARE(invoked, 3); + } +} + +void tst_qxp_function_ref::constOverloads() +{ + auto func_c = [](qxp::function_ref<int() const> callable) + { + return callable(); + }; + auto func_m = [](qxp::function_ref<int() /*mutable*/> callable) + { + return callable(); + }; + + struct S + { + int operator()() { return 1; } + int operator()() const { return 2; } + }; + S s; + QCOMPARE(func_c(s), 2); + QCOMPARE(func_m(s), 1); + const S cs; + QCOMPARE(func_c(cs), 2); +#if 0 + // this should not compile (and doesn't, but currently fails with an error in the impl, + // not by failing a constructor constaint → spec issue?). + QCOMPARE(func_m(cs), 2); +#endif +} + +void tst_qxp_function_ref::constExpr() +{ + Q_CONSTINIT static int invoked = 0; + { + Q_CONSTINIT static auto lambda = [] (int i) { ++invoked; return i; }; + // the function object constructor is constexpr, so this should be constinit: + Q_CONSTINIT static qxp::function_ref<int(int)> f = lambda; + + QCOMPARE(invoked, 0); + QCOMPARE(f(15), 15); + QCOMPARE(invoked, 1); + } + { + constexpr static auto lambda = [] (int i) { ++invoked; return i; }; + // the function object constructor is constexpr, so this should be constinit: + Q_CONSTINIT static qxp::function_ref<int(int) const> f = lambda; + + QCOMPARE(invoked, 1); + QCOMPARE(f(51), 51); + QCOMPARE(invoked, 2); + +#if 0 // ### should this work?: + Q_CONSTINIT static qxp::function_ref<int(int)> f2 = lambda; + + QCOMPARE(invoked, 2); + QCOMPARE(f(150), 150); + QCOMPARE(invoked, 3); +#endif + + } +} + +int i_f_i_nx(int i) noexcept { return i; } +void v_f_i_nx(int) noexcept {} +int i_f_v_nx() noexcept { return 42; } +void v_f_v_nx() noexcept {} + +int i_f_i_ex(int i) { return i; } +void v_f_i_ex(int) {} +int i_f_v_ex() { return 42; } +void v_f_v_ex() {} + +void tst_qxp_function_ref::voidReturning() +{ + // check that "casting" int to void returns works: + + using Fi = qxp::function_ref<void(int)>; + using Fv = qxp::function_ref<void()>; + + { + Fi fi = i_f_i_nx; + fi(42); + Fv fv = i_f_v_nx; + fv(); + } + + { + Fi fi = i_f_i_ex; + fi(42); + Fv fv = i_f_v_ex; + fv(); + } + + // now with lambdas + + bool ok = false; // prevent lambdas from decaying to function pointers + { + auto lambda1 = [&](int i) noexcept { return i + int(ok); }; + Fi fi = lambda1; + fi(42); + auto lambda2 = [&]() noexcept { return int(ok); }; + Fv fv = lambda2; + fv(); + } + + { + auto lambda1 = [&](int i) { return i + int(ok); }; + Fi fi = lambda1; + fi(42); + auto lambda2 = [&]() { return int(ok); }; + Fv fv = lambda2; + fv(); + } +} + +void tst_qxp_function_ref::ctad() +{ +#define CHECK(fun, sig) \ + do { \ + qxp::function_ref f = fun; \ + static_assert(std::is_same_v<decltype(f), \ + qxp::function_ref<sig>>); \ + qxp::function_ref f2 = &fun; \ + static_assert(std::is_same_v<decltype(f2), \ + qxp::function_ref<sig>>); \ + static_assert(std::is_trivially_copyable_v<decltype(f)>); \ + static_assert(std::is_trivially_copyable_v<decltype(f2)>); \ + } while (false) + + CHECK(i_f_i_nx, int (int) noexcept); + CHECK(v_f_i_nx, void(int) noexcept); + CHECK(i_f_v_nx, int ( ) noexcept); + CHECK(v_f_v_nx, void( ) noexcept); + + CHECK(i_f_i_ex, int (int)); + CHECK(v_f_i_ex, void(int)); + CHECK(i_f_v_ex, int ( )); + CHECK(v_f_v_ex, void( )); + +#undef CHECK + +#if 0 // no deduction guides for the non-function-pointer case, so no CTAD for lambdas + { + auto lambda = [](int i) -> int { return i; }; + qxp::function_ref f = lambda; + static_assert(std::is_same_v<decltype(f), + qxp::function_ref<int(int)>>); + } +#endif +} + + +QTEST_APPLESS_MAIN(tst_qxp_function_ref); + +#include "tst_qxp_function_ref.moc" diff --git a/tests/auto/corelib/global/qxp/is_virtual_base_of/CMakeLists.txt b/tests/auto/corelib/global/qxp/is_virtual_base_of/CMakeLists.txt new file mode 100644 index 0000000000..85a6daab7c --- /dev/null +++ b/tests/auto/corelib/global/qxp/is_virtual_base_of/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright (C) 2022 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_qxp_is_virtual_base_of LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qxp_is_virtual_base_of + EXCEPTIONS + SOURCES + tst_is_virtual_base_of.cpp + LIBRARIES + Qt::Core +) + +# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90449 +# GCCs < 10 have no way to suppress "inaccessible base" warnings, except by disabling all warnings: +qt_internal_extend_target(tst_qxp_is_virtual_base_of + CONDITION GCC AND (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "10") + COMPILE_OPTIONS -w +) diff --git a/tests/auto/corelib/global/qxp/is_virtual_base_of/tst_is_virtual_base_of.cpp b/tests/auto/corelib/global/qxp/is_virtual_base_of/tst_is_virtual_base_of.cpp new file mode 100644 index 0000000000..e50575f5ec --- /dev/null +++ b/tests/auto/corelib/global/qxp/is_virtual_base_of/tst_is_virtual_base_of.cpp @@ -0,0 +1,102 @@ +// Copyright (C) 2023 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QtCore/qxptype_traits.h> + +#include <QTest> + +class tst_qxp_is_virtual_base_of : public QObject +{ + Q_OBJECT +}; + +class Base { +public: + virtual ~Base() {} +}; + +// Only works with classes +static_assert(!qxp::is_virtual_base_of_v<int, int>); +static_assert(!qxp::is_virtual_base_of_v<int, Base>); +static_assert(!qxp::is_virtual_base_of_v<Base, int>); + +// A class isn't a virtual base of itself +static_assert(!qxp::is_virtual_base_of_v<Base, Base>); + +// Non-virtual bases +class NonVirtualDerived : public Base {}; +class NonVirtualPrivateDerived : private Base {}; + +static_assert(!qxp::is_virtual_base_of_v<Base, NonVirtualDerived>); +static_assert(!qxp::is_virtual_base_of_v<Base, NonVirtualPrivateDerived>); + +static_assert(!qxp::is_virtual_base_of_v<NonVirtualPrivateDerived, NonVirtualDerived>); +static_assert(!qxp::is_virtual_base_of_v<NonVirtualDerived, NonVirtualPrivateDerived>); + +static_assert(!qxp::is_virtual_base_of_v<tst_qxp_is_virtual_base_of, QObject>); + +// Virtual bases +class VirtualDerived1 : public virtual Base {}; +class VirtualDerived2 : public virtual Base {}; +class VirtualDerived3 : public VirtualDerived1, public VirtualDerived2 {}; +class VirtualDerived4 : public VirtualDerived3, public virtual Base {}; +class VirtualPrivateDerived : private virtual Base {}; + +static_assert(qxp::is_virtual_base_of_v<Base, VirtualDerived1>); +static_assert(qxp::is_virtual_base_of_v<Base, VirtualDerived2>); +static_assert(qxp::is_virtual_base_of_v<Base, VirtualDerived3>); +static_assert(!qxp::is_virtual_base_of_v<VirtualDerived1, VirtualDerived3>); +static_assert(qxp::is_virtual_base_of_v<Base, VirtualDerived4>); +static_assert(qxp::is_virtual_base_of_v<Base, VirtualPrivateDerived>); + +QT_WARNING_PUSH +QT_WARNING_DISABLE_GCC("-Winaccessible-base") +QT_WARNING_DISABLE_CLANG("-Winaccessible-base") +// Ambiguous non-virtual base +class IntermediateDerived : public Base {}; +class AmbiguousBase1 : public IntermediateDerived, public Base {}; +class AmbiguousBase2 : public IntermediateDerived, public virtual Base {}; + +static_assert(!qxp::is_virtual_base_of_v<Base, AmbiguousBase1>); +#ifndef Q_CC_MSVC_ONLY // https://developercommunity.visualstudio.com/t/c-templates-multiple-inheritance-ambiguous-access/185674 +static_assert(!qxp::is_virtual_base_of_v<Base, AmbiguousBase2>); +#endif +QT_WARNING_POP + +// Const +static_assert(!qxp::is_virtual_base_of_v< Base, const NonVirtualDerived>); +static_assert(!qxp::is_virtual_base_of_v<const Base, NonVirtualDerived>); +static_assert(!qxp::is_virtual_base_of_v<const Base, const NonVirtualDerived>); + +static_assert(!qxp::is_virtual_base_of_v< Base, const NonVirtualPrivateDerived>); +static_assert(!qxp::is_virtual_base_of_v<const Base, NonVirtualPrivateDerived>); +static_assert(!qxp::is_virtual_base_of_v<const Base, const NonVirtualPrivateDerived>); + +static_assert(qxp::is_virtual_base_of_v< Base, const VirtualDerived1>); +static_assert(qxp::is_virtual_base_of_v<const Base, VirtualDerived1>); +static_assert(qxp::is_virtual_base_of_v<const Base, const VirtualDerived1>); + +static_assert(qxp::is_virtual_base_of_v< Base, const VirtualDerived2>); +static_assert(qxp::is_virtual_base_of_v<const Base, VirtualDerived2>); +static_assert(qxp::is_virtual_base_of_v<const Base, const VirtualDerived2>); + +static_assert(qxp::is_virtual_base_of_v< Base, const VirtualDerived3>); +static_assert(qxp::is_virtual_base_of_v<const Base, VirtualDerived3>); +static_assert(qxp::is_virtual_base_of_v<const Base, const VirtualDerived3>); + +static_assert(qxp::is_virtual_base_of_v< Base, const VirtualDerived4>); +static_assert(qxp::is_virtual_base_of_v<const Base, VirtualDerived4>); +static_assert(qxp::is_virtual_base_of_v<const Base, const VirtualDerived4>); + +static_assert(qxp::is_virtual_base_of_v< Base, const VirtualDerived4>); +static_assert(qxp::is_virtual_base_of_v<const Base, VirtualDerived4>); +static_assert(qxp::is_virtual_base_of_v<const Base, const VirtualDerived4>); + +static_assert(qxp::is_virtual_base_of_v< Base, const VirtualPrivateDerived>); +static_assert(qxp::is_virtual_base_of_v<const Base, VirtualPrivateDerived>); +static_assert(qxp::is_virtual_base_of_v<const Base, const VirtualPrivateDerived>); + + +QTEST_APPLESS_MAIN(tst_qxp_is_virtual_base_of); + +#include "tst_is_virtual_base_of.moc" |