qt5base-lts/tests/manual/permissions/tst_qpermissions.cpp

117 lines
2.9 KiB
C++
Raw Normal View History

// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <QtCore/qpermissions.h>
#include <QtCore/qthread.h>
#include <QtCore/qmutex.h>
#include <QtCore/qwaitcondition.h>
#include <QtCore/qtimer.h>
Add permission API backend for macOS and iOS When submitting applications to the iOS and macOS AppStore the application goes through static analysis, which will trigger on uses of various privacy protected APIs, unless the application has a corresponding usage description for the permission in the Info.plist file. This applies even if the application never requests the given permission, but just links to a Qt library that has the offending symbols or library dependencies. To ensure that the application does not have to add usage descriptions to their Info.plist for permissions they never plan to use we split up the various permission implementations into small static libraries that register with the Qt plugin mechanism as permission backends. We can then inspect the application's Info.plist at configure time and only add the relevant static permission libraries. Furthermore, since some permissions can be checked without any usage description, we allow the implementation to be split up into two separate translation units. By putting the request in its own translation unit we can selectively include it during linking by telling the linker to look for a special symbol. This is useful for libraries such as Qt Multimedia who would like to check the current permission status, but without needing to request any permission of its own. Done-with: Tor Arne Vestbø <tor.arne.vestbo@qt.io> Change-Id: Ic2a43e1a0c45a91df6101020639f473ffd9454cc Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
2022-05-10 13:02:43 +00:00
#if defined(Q_OS_MACOS) && defined(QT_BUILD_INTERNAL)
#include <private/qcore_mac_p.h>
Q_CONSTRUCTOR_FUNCTION(qt_mac_ensureResponsible);
#endif
class tst_QPermissions : public QObject
{
Q_OBJECT
private slots:
void initTestCase_data();
void checkPermission();
void checkPermissionInNonMainThread();
void requestPermission();
void requestPermissionInNonMainThread();
};
void tst_QPermissions::initTestCase_data()
{
QTest::addColumn<QPermission>("permission");
QTest::newRow("Camera") << QPermission(QCameraPermission{});
QTest::newRow("Microphone") << QPermission(QMicrophonePermission{});
QTest::newRow("Bluetooth") << QPermission(QBluetoothPermission{});
QTest::newRow("Contacts") << QPermission(QContactsPermission{});
QTest::newRow("Calendar") << QPermission(QCalendarPermission{});
QTest::newRow("Location") << QPermission(QLocationPermission{});
}
void tst_QPermissions::checkPermission()
{
QFETCH_GLOBAL(QPermission, permission);
qApp->checkPermission(permission);
}
class Thread : public QThread
{
public:
QMutex mutex;
QWaitCondition cond;
std::function<void()> function;
void run() override
{
QMutexLocker locker(&mutex);
function();
cond.wakeOne();
}
};
void tst_QPermissions::checkPermissionInNonMainThread()
{
QFETCH_GLOBAL(QPermission, permission);
Thread thread;
thread.function = [=]{
qApp->checkPermission(permission);
};
QVERIFY(!thread.isFinished());
QMutexLocker locker(&thread.mutex);
thread.start();
QVERIFY(!thread.isFinished());
thread.cond.wait(locker.mutex());
QVERIFY(thread.wait(1000));
QVERIFY(thread.isFinished());
}
void tst_QPermissions::requestPermission()
{
QFETCH_GLOBAL(QPermission, permission);
QTimer::singleShot(0, this, [=] {
qApp->requestPermission(permission, [=](auto result) {
qDebug() << result;
Q_ASSERT(QThread::currentThread() == thread());
qApp->exit();
});
});
qApp->exec();
}
void tst_QPermissions::requestPermissionInNonMainThread()
{
QFETCH_GLOBAL(QPermission, permission);
QTest::ignoreMessage(QtWarningMsg, "Permissions can only be requested from the GUI (main) thread");
Thread thread;
thread.function = [&]{
qApp->requestPermission(permission, [&]() {});
};
QVERIFY(!thread.isFinished());
QMutexLocker locker(&thread.mutex);
thread.start();
QVERIFY(!thread.isFinished());
thread.cond.wait(locker.mutex());
QVERIFY(thread.wait(1000));
QVERIFY(thread.isFinished());
}
QTEST_MAIN(tst_QPermissions)
#include "tst_qpermissions.moc"