162 lines
4.7 KiB
C++
162 lines
4.7 KiB
C++
// Copyright (C) 2024 The Qt Company Ltd.
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
|
|
|
#include <QtTest/QtTest>
|
|
#include <QtCore/qdebug.h>
|
|
#include <QtCore/qprocess.h>
|
|
#include <QtCore/qcoreapplication.h>
|
|
#include <QtCore/qstring.h>
|
|
#include <QtCore/qmetaobject.h>
|
|
#include <QtMultimedia/qsoundeffect.h>
|
|
#include <QtMultimedia/qmediadevices.h>
|
|
#include <QtMultimedia/qaudiodevice.h>
|
|
|
|
using namespace Qt::StringLiterals;
|
|
|
|
QT_USE_NAMESPACE
|
|
|
|
namespace {
|
|
bool executeTestOutOfProcess(const QString &testName);
|
|
void playSound();
|
|
} // namespace
|
|
|
|
class tst_multiapp : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
public slots:
|
|
void initTestCase()
|
|
{
|
|
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
|
QSKIP("Out-of-process testing does not behave correctly on mobile OS");
|
|
#endif
|
|
}
|
|
|
|
private slots:
|
|
void mediaDevices_doesNotCrash_whenRecreatingApplication()
|
|
{
|
|
QVERIFY(executeTestOutOfProcess(
|
|
"mediaDevices_doesNotCrash_whenRecreatingApplication_impl"_L1));
|
|
}
|
|
|
|
bool mediaDevices_doesNotCrash_whenRecreatingApplication_impl(int argc, char ** argv)
|
|
{
|
|
{
|
|
QCoreApplication app{ argc, argv };
|
|
QMediaDevices::defaultAudioOutput();
|
|
}
|
|
{
|
|
QCoreApplication app{ argc, argv };
|
|
QMediaDevices::defaultAudioOutput();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void soundEffect_doesNotCrash_whenRecreatingApplication()
|
|
{
|
|
QVERIFY(executeTestOutOfProcess(
|
|
"soundEffect_doesNotCrash_whenRecreatingApplication_impl"_L1));
|
|
}
|
|
|
|
bool soundEffect_doesNotCrash_whenRecreatingApplication_impl(int argc, char **argv)
|
|
{
|
|
QTEST_ASSERT(!qApp);
|
|
|
|
// Play a sound twice under two different application objects
|
|
// This verifies that QSoundEffect works in use cases where
|
|
// client application recreates Qt application instances,
|
|
// for example when the client application loads plugins
|
|
// implemented using Qt.
|
|
{
|
|
QCoreApplication app{ argc, argv };
|
|
playSound();
|
|
}
|
|
{
|
|
QCoreApplication app{ argc, argv };
|
|
playSound();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
};
|
|
|
|
namespace {
|
|
|
|
void playSound()
|
|
{
|
|
const QUrl url{ "qrc:double-drop.wav"_L1 };
|
|
|
|
QSoundEffect effect;
|
|
effect.setSource(url);
|
|
effect.play();
|
|
|
|
QObject::connect(&effect, &QSoundEffect::playingChanged, qApp, [&]() {
|
|
if (!effect.isPlaying())
|
|
qApp->quit();
|
|
});
|
|
|
|
// In some CI configurations, we do not have any audio devices. We must therefore
|
|
// close the qApp on error signal instead of on playingChanged.
|
|
QObject::connect(&effect, &QSoundEffect::statusChanged, qApp, [&]() {
|
|
if (effect.status() == QSoundEffect::Status::Error) {
|
|
qDebug() << "Failed to play sound effect";
|
|
qApp->quit();
|
|
}
|
|
});
|
|
|
|
qApp->exec();
|
|
}
|
|
|
|
bool executeTestOutOfProcess(const QString &testName)
|
|
{
|
|
const QStringList args{ "--run-test"_L1, testName };
|
|
const QString processName = QCoreApplication::applicationFilePath();
|
|
const int status = QProcess::execute(processName, args);
|
|
return status == 0;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
// This main function executes tests like normal qTest, and adds support
|
|
// for executing specific test functions when called out of process. In this
|
|
// case we don't create a QApplication, because the intent is to test how features
|
|
// behave when no QApplication exists.
|
|
int main(int argc, char *argv[])
|
|
{
|
|
QCommandLineParser cmd;
|
|
const QCommandLineOption runTest{ QStringList{ "run-test" }, "Executes a named test",
|
|
"runTest" };
|
|
cmd.addOption(runTest);
|
|
cmd.parse({ argv, argv + argc });
|
|
|
|
if (cmd.isSet(runTest)) {
|
|
// We are requested to run a test case in a separate process without a Qt application
|
|
const QString testName = cmd.value(runTest);
|
|
|
|
bool returnValue = false;
|
|
tst_multiapp tc;
|
|
|
|
// Call the requested function on the test class
|
|
const bool invokeResult =
|
|
QMetaObject::invokeMethod(&tc, testName.toLatin1(), Qt::DirectConnection,
|
|
qReturnArg(returnValue), argc, argv);
|
|
|
|
return (invokeResult && returnValue) ? 0 : 1;
|
|
}
|
|
|
|
// If no special arguments are set, enter the regular QTest main routine
|
|
// The below lines are the same that QTEST_GUILESS_MAIN would stamp out,
|
|
// except the `int main(...)`
|
|
TESTLIB_SELFCOVERAGE_START("tst_multiapp")
|
|
QT_PREPEND_NAMESPACE(QTest::Internal::callInitMain)<tst_multiapp>();
|
|
QCoreApplication app(argc, argv);
|
|
app.setAttribute(Qt::AA_Use96Dpi, true);
|
|
tst_multiapp tc;
|
|
QTEST_SET_MAIN_SOURCE_PATH
|
|
return QTest::qExec(&tc, argc, argv);
|
|
}
|
|
|
|
#include "tst_multiapp.moc"
|