qt5base-lts/tests/manual/wasm/qtwasmtestlib/qtwasmtestlib.cpp
Morten Johan Sørvig 122aa530d6 wasm: add qtwasmtestlib
qtwasmtestlib supports writing asynchronous tests for
the web platform.

Asynchronous test functions differ from normal test
functions in that they allow returning from the test
function before the test has completed:

void TestObject::testTimer()
{
    QTimer::singleShot(100, [](){
        completeTestFunction(); // Test pass if we get here
    });
}

Currently one logging backend is supported which
writes the results to an html element. See the README
file for further documentation.

Change-Id: Ia633ad3f41a653e40d6bf35dd09d62a97c608f84
Reviewed-by: Mikołaj Boc <Mikolaj.Boc@qt.io>
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
2022-06-29 15:09:02 +02:00

136 lines
3.6 KiB
C++

// 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 "qtwasmtestlib.h"
#include <QtCore/qmetaobject.h>
#include <emscripten/bind.h>
#include <emscripten.h>
#include <emscripten/threading.h>
namespace QtWasmTest {
QObject *g_testObject = nullptr;
std::function<void ()> g_cleanup;
void runOnMainThread(std::function<void(void)> fn);
static bool isValidSlot(const QMetaMethod &sl);
//
// Public API
//
// Initializes the test case with a test object and cleanup function. The
// cleanup function is called when all test functions have completed.
void initTestCase(QObject *testObject, std::function<void ()> cleanup)
{
g_testObject = testObject;
g_cleanup = cleanup;
}
// Completes the currently running test function with a result. This function is
// thread-safe and call be called from any thread.
void completeTestFunction(TestResult result)
{
// Report test result to JavaScript test runner, on the main thread
runOnMainThread([result](){
const char *resultString;
switch (result) {
case TestResult::Pass:
resultString = "PASS";
break;
case TestResult::Fail:
resultString = "FAIL";
break;
};
EM_ASM({
completeTestFunction(UTF8ToString($0));
}, resultString);
});
}
//
// Private API for the Javascript test runnner
//
void cleanupTestCase()
{
g_testObject = nullptr;
g_cleanup();
}
std::string getTestFunctions()
{
std::string testFunctions;
// Duplicate qPrintTestSlots (private QTestLib function) logic.
for (int i = 0; i < g_testObject->metaObject()->methodCount(); ++i) {
QMetaMethod sl = g_testObject->metaObject()->method(i);
if (!isValidSlot(sl))
continue;
QByteArray signature = sl.methodSignature();
Q_ASSERT(signature.endsWith("()"));
signature.chop(2);
if (!testFunctions.empty())
testFunctions += " ";
testFunctions += std::string(signature.constData());
}
return testFunctions;
}
void runTestFunction(std::string name)
{
QMetaObject::invokeMethod(g_testObject, name.c_str());
}
EMSCRIPTEN_BINDINGS(qtwebtestrunner) {
emscripten::function("cleanupTestCase", &cleanupTestCase);
emscripten::function("getTestFunctions", &getTestFunctions);
emscripten::function("runTestFunction", &runTestFunction);
}
//
// Test lib implementation
//
static bool isValidSlot(const QMetaMethod &sl)
{
if (sl.access() != QMetaMethod::Private || sl.parameterCount() != 0
|| sl.returnType() != QMetaType::Void || sl.methodType() != QMetaMethod::Slot)
return false;
const QByteArray name = sl.name();
return !(name.isEmpty() || name.endsWith("_data")
|| name == "initTestCase" || name == "cleanupTestCase"
|| name == "init" || name == "cleanup");
}
void trampoline(void *context)
{
Q_ASSERT(emscripten_is_main_runtime_thread());
emscripten_async_call([](void *context) {
std::function<void(void)> *fn = reinterpret_cast<std::function<void(void)> *>(context);
(*fn)();
delete fn;
}, context, 0);
}
// Runs the given function on the main thread, asynchronously
void runOnMainThread(std::function<void(void)> fn)
{
void *context = new std::function<void(void)>(fn);
if (emscripten_is_main_runtime_thread()) {
trampoline(context);
} else {
#if QT_CONFIG(thread)
emscripten_async_run_in_main_runtime_thread_(EM_FUNC_SIG_VI, reinterpret_cast<void *>(trampoline), context);
#endif
}
}
} // namespace QtWasmTest