diff options
Diffstat (limited to 'tests/auto/corelib/kernel/qpermission')
-rw-r--r-- | tests/auto/corelib/kernel/qpermission/.gitignore | 1 | ||||
-rw-r--r-- | tests/auto/corelib/kernel/qpermission/CMakeLists.txt | 19 | ||||
-rw-r--r-- | tests/auto/corelib/kernel/qpermission/tst_qpermission.cpp | 284 |
3 files changed, 304 insertions, 0 deletions
diff --git a/tests/auto/corelib/kernel/qpermission/.gitignore b/tests/auto/corelib/kernel/qpermission/.gitignore new file mode 100644 index 0000000000..56a6bf0795 --- /dev/null +++ b/tests/auto/corelib/kernel/qpermission/.gitignore @@ -0,0 +1 @@ +tst_qpermission diff --git a/tests/auto/corelib/kernel/qpermission/CMakeLists.txt b/tests/auto/corelib/kernel/qpermission/CMakeLists.txt new file mode 100644 index 0000000000..1af0331186 --- /dev/null +++ b/tests/auto/corelib/kernel/qpermission/CMakeLists.txt @@ -0,0 +1,19 @@ +# 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_qpermission LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +if (NOT QT_FEATURE_permissions) + return() +endif() + +qt_internal_add_test(tst_qpermission + SOURCES + tst_qpermission.cpp + LIBRARIES + Qt::Core +) diff --git a/tests/auto/corelib/kernel/qpermission/tst_qpermission.cpp b/tests/auto/corelib/kernel/qpermission/tst_qpermission.cpp new file mode 100644 index 0000000000..dbf1d2dd84 --- /dev/null +++ b/tests/auto/corelib/kernel/qpermission/tst_qpermission.cpp @@ -0,0 +1,284 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QPermission> + +#include <QTest> + +struct DummyPermission // a minimal QPermission-compatible type +{ + using QtPermissionHelper = void; + int state = 0; +}; +Q_DECLARE_METATYPE(DummyPermission) + +class tst_QPermission : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void converting_Dummy() const { return converting_impl<DummyPermission>(); } + void converting_Location() const { return converting_impl<QLocationPermission>(); } + void converting_Calendar() const { return converting_impl<QCalendarPermission>(); } + void converting_Contacts() const { return converting_impl<QContactsPermission>(); } + void converting_Camera() const { return converting_impl<QCameraPermission>(); } + void converting_Microphone() const { return converting_impl<QMicrophonePermission>(); } + void converting_Bluetooth() const { return converting_impl<QBluetoothPermission>(); } + + void conversionMaintainsState() const; + + void functorWithoutContext(); + void functorWithContextInThread(); + void receiverInThread(); + void destroyedContextObject(); +private: + template <typename T> + void converting_impl() const; +}; + +template <typename T> +void tst_QPermission::converting_impl() const +{ + T concrete; + const T cconcrete = concrete; + const auto metaType = QMetaType::fromType<T>(); + + // construction is implicit: + // from rvalue: + { + QPermission p = T(); + QCOMPARE_EQ(p.type(), metaType); + } + // from mutable lvalue: + { + QPermission p = concrete; + QCOMPARE_EQ(p.type(), metaType); + } + // from const lvalue: + { + QPermission p = cconcrete; + QCOMPARE_EQ(p.type(), metaType); + } + + // value<>() compiles: + { + const QPermission p = concrete; + auto v = p.value<T>(); + static_assert(std::is_same_v<decltype(v), std::optional<T>>); + QCOMPARE_NE(v, std::nullopt); + } +} + +void tst_QPermission::conversionMaintainsState() const +{ + DummyPermission dummy{42}, dummy_default; + QCOMPARE_NE(dummy.state, dummy_default.state); + + QLocationPermission loc, loc_default; + QCOMPARE_EQ(loc_default.accuracy(), QLocationPermission::Accuracy::Approximate); + QCOMPARE_EQ(loc_default.availability(), QLocationPermission::Availability::WhenInUse); + + loc.setAccuracy(QLocationPermission::Accuracy::Precise); + loc.setAvailability(QLocationPermission::Availability::Always); + + QCOMPARE_EQ(loc.accuracy(), QLocationPermission::Accuracy::Precise); + QCOMPARE_EQ(loc.availability(), QLocationPermission::Availability::Always); + + QCalendarPermission cal, cal_default; + QCOMPARE_EQ(cal_default.accessMode(), QCalendarPermission::AccessMode::ReadOnly); + + cal.setAccessMode(QCalendarPermission::AccessMode::ReadWrite); + + QCOMPARE_EQ(cal.accessMode(), QCalendarPermission::AccessMode::ReadWrite); + + QContactsPermission con, con_default; + QCOMPARE_EQ(con_default.accessMode(), QContactsPermission::AccessMode::ReadOnly); + + con.setAccessMode(QContactsPermission::AccessMode::ReadWrite); + + QCOMPARE_EQ(con.accessMode(), QContactsPermission::AccessMode::ReadWrite); + + // + // QCameraPermission, QMicrophonePermission, QBluetoothPermission don't have + // state at the time of writing + // + + QPermission p; // maintain state between the blocks below to test reset behavior + + { + p = dummy; + auto v = p.value<DummyPermission>(); + QCOMPARE_NE(v, std::nullopt); + auto &r = *v; + QCOMPARE_EQ(r.state, dummy.state); + // check mismatched returns nullopt: + QCOMPARE_EQ(p.value<QCalendarPermission>(), std::nullopt); + } + + { + p = loc; + auto v = p.value<QLocationPermission>(); + QCOMPARE_NE(v, std::nullopt); + auto &r = *v; + QCOMPARE_EQ(r.accuracy(), loc.accuracy()); + QCOMPARE_EQ(r.availability(), loc.availability()); + // check mismatched returns nullopt: + QCOMPARE_EQ(p.value<DummyPermission>(), std::nullopt); + } + + { + p = con; + auto v = p.value<QContactsPermission>(); + QCOMPARE_NE(v, std::nullopt); + auto &r = *v; + QCOMPARE_EQ(r.accessMode(), con.accessMode()); + // check mismatched returns nullopt: + QCOMPARE_EQ(p.value<QLocationPermission>(), std::nullopt); + } + + { + p = cal; + auto v = p.value<QCalendarPermission>(); + QCOMPARE_NE(v, std::nullopt); + auto &r = *v; + QCOMPARE_EQ(r.accessMode(), cal.accessMode()); + // check mismatched returns nullopt: + QCOMPARE_EQ(p.value<QContactsPermission>(), std::nullopt); + } +} + +template <typename Func, + typename T = std::void_t<decltype(qApp->requestPermission(std::declval<DummyPermission>(), + std::declval<Func>()))> + > +void wrapRequestPermission(const QPermission &p, Func &&f) +{ + qApp->requestPermission(p, std::forward<Func>(f)); +} + +template <typename Functor> +using CompatibleTest = decltype(wrapRequestPermission(std::declval<QPermission>(), std::declval<Functor>())); + + +// Compile test for context-less functor overloads +void tst_QPermission::functorWithoutContext() +{ + int argc = 0; + char *argv = nullptr; + QCoreApplication app(argc, &argv); + + DummyPermission dummy; +#ifdef Q_OS_DARWIN + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*Could not find permission plugin for DummyPermission.*")); +#endif + + qApp->requestPermission(dummy, [](const QPermission &permission){ + QVERIFY(permission.value<DummyPermission>()); + }); + wrapRequestPermission(dummy, [](const QPermission &permission){ + QVERIFY(permission.value<DummyPermission>()); + }); + + auto compatible = [](const QPermission &) {}; + using Compatible = decltype(compatible); + auto incompatible = [](const QString &) {}; + using Incompatible = decltype(incompatible); + + static_assert(qxp::is_detected_v<CompatibleTest, Compatible>); + static_assert(!qxp::is_detected_v<CompatibleTest, Incompatible>); +} + +void tst_QPermission::functorWithContextInThread() +{ + int argc = 0; + char *argv = nullptr; + QCoreApplication app(argc, &argv); + QThread::currentThread()->setObjectName("main thread"); + QThread receiverThread; + receiverThread.setObjectName("receiverThread"); + QObject receiver; + receiver.moveToThread(&receiverThread); + receiverThread.start(); + auto guard = qScopeGuard([&receiverThread]{ + receiverThread.quit(); + QVERIFY(receiverThread.wait(1000)); + }); + + DummyPermission dummy; +#ifdef Q_OS_DARWIN + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*Could not find permission plugin for DummyPermission.*")); +#endif + QThread *permissionReceiverThread = nullptr; + qApp->requestPermission(dummy, &receiver, [&](const QPermission &permission){ + auto dummy = permission.value<DummyPermission>(); + QVERIFY(dummy); + permissionReceiverThread = QThread::currentThread(); + }); + QTRY_COMPARE(permissionReceiverThread, &receiverThread); +} + +void tst_QPermission::receiverInThread() +{ + int argc = 0; + char *argv = nullptr; + QCoreApplication app(argc, &argv); + QThread::currentThread()->setObjectName("main thread"); + QThread receiverThread; + receiverThread.setObjectName("receiverThread"); + class Receiver : public QObject + { + public: + using QObject::QObject; + void handlePermission(const QPermission &permission) + { + auto dummy = permission.value<DummyPermission>(); + QVERIFY(dummy); + permissionReceiverThread = QThread::currentThread(); + } + + QThread *permissionReceiverThread = nullptr; + } receiver; + receiver.moveToThread(&receiverThread); + receiverThread.start(); + auto guard = qScopeGuard([&receiverThread]{ + receiverThread.quit(); + QVERIFY(receiverThread.wait(1000)); + }); + + DummyPermission dummy; +#ifdef Q_OS_DARWIN + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*Could not find permission plugin for DummyPermission.*")); +#endif + + qApp->requestPermission(dummy, &receiver, &Receiver::handlePermission); + QTRY_COMPARE(receiver.permissionReceiverThread, &receiverThread); + + // compile tests: none of these work and the error output isn't horrible + // qApp->requestPermission(dummy, &receiver, "&tst_QPermission::receiverInThread"); + // qApp->requestPermission(dummy, &receiver, &tst_QPermission::receiverInThread); + // qApp->requestPermission(dummy, &receiver, &QObject::destroyed); +} + +void tst_QPermission::destroyedContextObject() +{ + int argc = 0; + char *argv = nullptr; + QCoreApplication app(argc, &argv); + + QObject *context = new QObject; + + DummyPermission dummy; +#ifdef Q_OS_DARWIN + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*Could not find permission plugin for DummyPermission.*")); +#endif + bool permissionReceived = false; + qApp->requestPermission(dummy, context, [&]{ + permissionReceived = true; + }); + QVERIFY2(!permissionReceived, "Permission received synchronously"); + delete context; + QTest::qWait(100); + QVERIFY(!permissionReceived); +} + +QTEST_APPLESS_MAIN(tst_QPermission) +#include "tst_qpermission.moc" |