summaryrefslogtreecommitdiffstats
path: root/tests/manual/wasm/qstdweb/promise_main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/manual/wasm/qstdweb/promise_main.cpp')
-rw-r--r--tests/manual/wasm/qstdweb/promise_main.cpp486
1 files changed, 486 insertions, 0 deletions
diff --git a/tests/manual/wasm/qstdweb/promise_main.cpp b/tests/manual/wasm/qstdweb/promise_main.cpp
new file mode 100644
index 0000000000..c5f6f7f412
--- /dev/null
+++ b/tests/manual/wasm/qstdweb/promise_main.cpp
@@ -0,0 +1,486 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QEvent>
+#include <QtCore/QMutex>
+#include <QtCore/QObject>
+#include <QtCore/private/qstdweb_p.h>
+
+#include <qtwasmtestlib.h>
+#include <emscripten.h>
+
+using namespace emscripten;
+
+class WasmPromiseTest : public QObject
+{
+ Q_OBJECT
+
+public:
+ WasmPromiseTest() : m_window(val::global("window")), m_testSupport(val::object()) {}
+
+ ~WasmPromiseTest() noexcept = default;
+
+private:
+ void init() {
+ m_testSupport = val::object();
+ m_window.set("testSupport", m_testSupport);
+
+ EM_ASM({
+ testSupport.resolve = {};
+ testSupport.reject = {};
+ testSupport.promises = {};
+ testSupport.waitConditionPromise = new Promise((resolve, reject) => {
+ testSupport.finishWaiting = resolve;
+ });
+
+ testSupport.makeTestPromise = (param) => {
+ testSupport.promises[param] = new Promise((resolve, reject) => {
+ testSupport.resolve[param] = resolve;
+ testSupport.reject[param] = reject;
+ });
+
+ return testSupport.promises[param];
+ };
+ });
+ }
+
+ val m_window;
+ val m_testSupport;
+
+private slots:
+ void simpleResolve();
+ void multipleResolve();
+ void simpleReject();
+ void multipleReject();
+ void throwInThen();
+ void bareFinally();
+ void finallyWithThen();
+ void finallyWithThrow();
+ void finallyWithThrowInThen();
+ void nested();
+ void all();
+ void allWithThrow();
+ void allWithFinally();
+ void allWithFinallyAndThrow();
+};
+
+class BarrierCallback {
+public:
+ BarrierCallback(int number, std::function<void()> onDone)
+ : m_remaining(number), m_onDone(std::move(onDone)) {}
+
+ void operator()() {
+ if (!--m_remaining) {
+ m_onDone();
+ }
+ }
+
+private:
+ int m_remaining;
+ std::function<void()> m_onDone;
+};
+
+// Post event to the main thread and verify that it is processed.
+void WasmPromiseTest::simpleResolve()
+{
+ init();
+
+ qstdweb::Promise::make(m_testSupport, "makeTestPromise", {
+ .thenFunc = [](val result) {
+ QWASMVERIFY(result.isString());
+ QWASMCOMPARE("Some lovely data", result.as<std::string>());
+
+ QWASMSUCCESS();
+ },
+ .catchFunc = [](val error) {
+ Q_UNUSED(error);
+
+ QWASMFAIL("Unexpected catch");
+ }
+ }, std::string("simpleResolve"));
+
+ EM_ASM({
+ testSupport.resolve["simpleResolve"]("Some lovely data");
+ });
+}
+
+void WasmPromiseTest::multipleResolve()
+{
+ init();
+
+ static constexpr int promiseCount = 1000;
+
+ auto onThen = std::make_shared<BarrierCallback>(promiseCount, []() {
+ QWASMSUCCESS();
+ });
+
+ for (int i = 0; i < promiseCount; ++i) {
+ qstdweb::Promise::make(m_testSupport, "makeTestPromise", {
+ .thenFunc = [=](val result) {
+ QWASMVERIFY(result.isString());
+ QWASMCOMPARE(QString::number(i).toStdString(), result.as<std::string>());
+
+ (*onThen)();
+ },
+ .catchFunc = [](val error) {
+ Q_UNUSED(error);
+ QWASMFAIL("Unexpected catch");
+ }
+ }, (QStringLiteral("test") + QString::number(i)).toStdString());
+ }
+
+ EM_ASM({
+ for (let i = $0 - 1; i >= 0; --i) {
+ testSupport.resolve['test' + i](`${i}`);
+ }
+ }, promiseCount);
+}
+
+void WasmPromiseTest::simpleReject()
+{
+ init();
+
+ qstdweb::Promise::make(m_testSupport, "makeTestPromise", {
+ .thenFunc = [](val result) {
+ Q_UNUSED(result);
+ QWASMFAIL("Unexpected then");
+ },
+ .catchFunc = [](val result) {
+ QWASMVERIFY(result.isString());
+ QWASMCOMPARE("Evil error", result.as<std::string>());
+ QWASMSUCCESS();
+ }
+ }, std::string("simpleReject"));
+
+ EM_ASM({
+ testSupport.reject["simpleReject"]("Evil error");
+ });
+}
+
+void WasmPromiseTest::multipleReject()
+{
+ static constexpr int promiseCount = 1000;
+
+ auto onCatch = std::make_shared<BarrierCallback>(promiseCount, []() {
+ QWASMSUCCESS();
+ });
+
+ for (int i = 0; i < promiseCount; ++i) {
+ qstdweb::Promise::make(m_testSupport, "makeTestPromise", {
+ .thenFunc = [=](val result) {
+ QWASMVERIFY(result.isString());
+ QWASMCOMPARE(QString::number(i).toStdString(), result.as<std::string>());
+
+ (*onCatch)();
+ },
+ .catchFunc = [](val error) {
+ Q_UNUSED(error);
+ QWASMFAIL("Unexpected catch");
+ }
+ }, (QStringLiteral("test") + QString::number(i)).toStdString());
+ }
+
+ EM_ASM({
+ for (let i = $0 - 1; i >= 0; --i) {
+ testSupport.resolve['test' + i](`${i}`);
+ }
+ }, promiseCount);
+}
+
+void WasmPromiseTest::throwInThen()
+{
+ init();
+
+ qstdweb::Promise::make(m_testSupport, "makeTestPromise", {
+ .thenFunc = [](val result) {
+ Q_UNUSED(result);
+ EM_ASM({
+ throw "Expected error";
+ });
+ },
+ .catchFunc = [](val error) {
+ QWASMCOMPARE("Expected error", error.as<std::string>());
+ QWASMSUCCESS();
+ }
+ }, std::string("throwInThen"));
+
+ EM_ASM({
+ testSupport.resolve["throwInThen"]();
+ });
+}
+
+void WasmPromiseTest::bareFinally()
+{
+ init();
+
+ qstdweb::Promise::make(m_testSupport, "makeTestPromise", {
+ .finallyFunc = []() {
+ QWASMSUCCESS();
+ }
+ }, std::string("bareFinally"));
+
+ EM_ASM({
+ testSupport.resolve["bareFinally"]();
+ });
+}
+
+void WasmPromiseTest::finallyWithThen()
+{
+ init();
+
+ auto thenCalled = std::make_shared<bool>();
+ qstdweb::Promise::make(m_testSupport, "makeTestPromise", {
+ .thenFunc = [thenCalled] (val result) {
+ Q_UNUSED(result);
+ *thenCalled = true;
+ },
+ .finallyFunc = [thenCalled]() {
+ QWASMVERIFY(*thenCalled);
+ QWASMSUCCESS();
+ }
+ }, std::string("finallyWithThen"));
+
+ EM_ASM({
+ testSupport.resolve["finallyWithThen"]();
+ });
+}
+
+void WasmPromiseTest::finallyWithThrow()
+{
+ init();
+
+ qstdweb::Promise::make(m_testSupport, "makeTestPromise", {
+ .catchFunc = [](val error) {
+ Q_UNUSED(error);
+ },
+ .finallyFunc = []() {
+ QWASMSUCCESS();
+ }
+ }, std::string("finallyWithThrow"));
+
+ EM_ASM({
+ testSupport.reject["finallyWithThrow"]();
+ });
+}
+
+void WasmPromiseTest::finallyWithThrowInThen()
+{
+ init();
+
+ qstdweb::Promise::make(m_testSupport, "makeTestPromise", {
+ .thenFunc = [](val result) {
+ Q_UNUSED(result);
+ EM_ASM({
+ throw "Expected error";
+ });
+ },
+ .catchFunc = [](val result) {
+ QWASMVERIFY(result.isString());
+ QWASMCOMPARE("Expected error", result.as<std::string>());
+ },
+ .finallyFunc = []() {
+ QWASMSUCCESS();
+ }
+ }, std::string("bareFinallyWithThen"));
+
+ EM_ASM({
+ testSupport.resolve["bareFinallyWithThen"]();
+ });
+}
+
+void WasmPromiseTest::nested()
+{
+ init();
+
+ qstdweb::Promise::make(m_testSupport, "makeTestPromise", {
+ .thenFunc = [this](val result) {
+ QWASMVERIFY(result.isString());
+ QWASMCOMPARE("Outer data", result.as<std::string>());
+
+ qstdweb::Promise::make(m_testSupport, "makeTestPromise", {
+ .thenFunc = [this](val innerResult) {
+ QWASMVERIFY(innerResult.isString());
+ QWASMCOMPARE("Inner data", innerResult.as<std::string>());
+
+ qstdweb::Promise::make(m_testSupport, "makeTestPromise", {
+ .thenFunc = [](val innerResult) {
+ QWASMVERIFY(innerResult.isString());
+ QWASMCOMPARE("Innermost data", innerResult.as<std::string>());
+
+ QWASMSUCCESS();
+ },
+ .catchFunc = [](val error) {
+ Q_UNUSED(error);
+ QWASMFAIL("Unexpected catch");
+ }
+ }, std::string("innermost"));
+
+ EM_ASM({
+ testSupport.resolve["innermost"]("Innermost data");
+ });
+ },
+ .catchFunc = [](val error) {
+ Q_UNUSED(error);
+ QWASMFAIL("Unexpected catch");
+ }
+ }, std::string("inner"));
+
+ EM_ASM({
+ testSupport.resolve["inner"]("Inner data");
+ });
+ },
+ .catchFunc = [](val error) {
+ Q_UNUSED(error);
+ QWASMFAIL("Unexpected catch");
+ }
+ }, std::string("outer"));
+
+ EM_ASM({
+ testSupport.resolve["outer"]("Outer data");
+ });
+}
+
+void WasmPromiseTest::all()
+{
+ init();
+
+ static constexpr int promiseCount = 1000;
+ auto thenCalledOnce = std::shared_ptr<bool>();
+ *thenCalledOnce = true;
+
+ std::vector<val> promises;
+ promises.reserve(promiseCount);
+
+ for (int i = 0; i < promiseCount; ++i) {
+ promises.push_back(m_testSupport.call<val>("makeTestPromise", val(("all" + QString::number(i)).toStdString())));
+ }
+
+ qstdweb::Promise::all(std::move(promises), {
+ .thenFunc = [=](val result) {
+ QWASMVERIFY(*thenCalledOnce);
+ *thenCalledOnce = false;
+
+ QWASMVERIFY(result.isArray());
+ QWASMCOMPARE(promiseCount, result["length"].as<int>());
+ for (int i = 0; i < promiseCount; ++i) {
+ QWASMCOMPARE(QStringLiteral("Data %1").arg(i).toStdString(), result[i].as<std::string>());
+ }
+
+ QWASMSUCCESS();
+ },
+ .catchFunc = [](val error) {
+ Q_UNUSED(error);
+ QWASMFAIL("Unexpected catch");
+ }
+ });
+
+ EM_ASM({
+ console.log('Resolving');
+ for (let i = $0 - 1; i >= 0; --i) {
+ testSupport.resolve['all' + i](`Data ${i}`);
+ }
+ }, promiseCount);
+}
+
+void WasmPromiseTest::allWithThrow()
+{
+ init();
+
+ val promise1 = m_testSupport.call<val>("makeTestPromise", val("promise1"));
+ val promise2 = m_testSupport.call<val>("makeTestPromise", val("promise2"));
+ val promise3 = m_testSupport.call<val>("makeTestPromise", val("promise3"));
+
+ auto catchCalledOnce = std::shared_ptr<bool>();
+ *catchCalledOnce = true;
+
+ qstdweb::Promise::all({promise1, promise2, promise3}, {
+ .thenFunc = [](val result) {
+ Q_UNUSED(result);
+ QWASMFAIL("Unexpected then");
+ },
+ .catchFunc = [catchCalledOnce](val result) {
+ QWASMVERIFY(*catchCalledOnce);
+ *catchCalledOnce = false;
+ QWASMVERIFY(result.isString());
+ QWASMCOMPARE("Error 2", result.as<std::string>());
+ QWASMSUCCESS();
+ }
+ });
+
+ EM_ASM({
+ testSupport.resolve["promise3"]("Data 3");
+ testSupport.resolve["promise1"]("Data 1");
+ testSupport.reject["promise2"]("Error 2");
+ });
+}
+
+void WasmPromiseTest::allWithFinally()
+{
+ init();
+
+ val promise1 = m_testSupport.call<val>("makeTestPromise", val("promise1"));
+ val promise2 = m_testSupport.call<val>("makeTestPromise", val("promise2"));
+ val promise3 = m_testSupport.call<val>("makeTestPromise", val("promise3"));
+
+ auto finallyCalledOnce = std::shared_ptr<bool>();
+ *finallyCalledOnce = true;
+
+ qstdweb::Promise::all({promise1, promise2, promise3}, {
+ .thenFunc = [](val result) {
+ Q_UNUSED(result);
+ },
+ .finallyFunc = [finallyCalledOnce]() {
+ QWASMVERIFY(*finallyCalledOnce);
+ *finallyCalledOnce = false;
+ QWASMSUCCESS();
+ }
+ });
+
+ EM_ASM({
+ testSupport.resolve["promise3"]("Data 3");
+ testSupport.resolve["promise1"]("Data 1");
+ testSupport.resolve["promise2"]("Data 2");
+ });
+}
+
+void WasmPromiseTest::allWithFinallyAndThrow()
+{
+ init();
+
+ val promise1 = m_testSupport.call<val>("makeTestPromise", val("promise1"));
+ val promise2 = m_testSupport.call<val>("makeTestPromise", val("promise2"));
+ val promise3 = m_testSupport.call<val>("makeTestPromise", val("promise3"));
+
+ auto finallyCalledOnce = std::shared_ptr<bool>();
+ *finallyCalledOnce = true;
+
+ qstdweb::Promise::all({promise1, promise2, promise3}, {
+ .thenFunc = [](val result) {
+ Q_UNUSED(result);
+ EM_ASM({
+ throw "This breaks it all!!!";
+ });
+ },
+ .finallyFunc = [finallyCalledOnce]() {
+ QWASMVERIFY(*finallyCalledOnce);
+ *finallyCalledOnce = false;
+ QWASMSUCCESS();
+ }
+ });
+
+ EM_ASM({
+ testSupport.resolve["promise3"]("Data 3");
+ testSupport.resolve["promise1"]("Data 1");
+ testSupport.resolve["promise2"]("Data 2");
+ });
+}
+
+int main(int argc, char **argv)
+{
+ auto testObject = std::make_shared<WasmPromiseTest>();
+ QtWasmTest::initTestCase<QCoreApplication>(argc, argv, testObject);
+ return 0;
+}
+
+#include "promise_main.moc"