summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/corelib/global/q23/expected/tst_q23_expected.cpp2
-rw-r--r--tests/auto/corelib/kernel/qjniobject/CMakeLists.txt8
-rw-r--r--tests/auto/corelib/kernel/qjniobject/testdata/src/org/qtproject/qt/android/testdata/QtJniObjectTestClass.java4
-rw-r--r--tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp567
-rw-r--r--tests/auto/corelib/text/qstring/tst_qstring.cpp2
-rw-r--r--tests/auto/corelib/tools/qatomicscopedvaluerollback/tst_qatomicscopedvaluerollback.cpp29
-rw-r--r--tests/auto/corelib/tools/qflatmap/tst_qflatmap.cpp1
-rw-r--r--tests/auto/wasm/CMakeLists.txt1
-rw-r--r--tests/auto/wasm/qwasmpromise/CMakeLists.txt23
-rw-r--r--tests/auto/wasm/qwasmpromise/tst_qwasmpromise.cpp526
-rw-r--r--tests/manual/wasm/qstdweb/CMakeLists.txt23
-rw-r--r--tests/manual/wasm/qstdweb/promise_auto.html10
-rw-r--r--tests/manual/wasm/qstdweb/promise_main.cpp488
13 files changed, 1159 insertions, 525 deletions
diff --git a/tests/auto/corelib/global/q23/expected/tst_q23_expected.cpp b/tests/auto/corelib/global/q23/expected/tst_q23_expected.cpp
index 6de836da9d0..92df31d1a75 100644
--- a/tests/auto/corelib/global/q23/expected/tst_q23_expected.cpp
+++ b/tests/auto/corelib/global/q23/expected/tst_q23_expected.cpp
@@ -20,7 +20,7 @@ private Q_SLOTS:
void tst_q23_expected::value_throw_exception_unreachable_data()
{
QTest::addColumn<bool>("unexpected");
- QTest::addRow("") << false;
+ QTest::addRow("expected") << false;
}
void tst_q23_expected::value_throw_exception_unreachable()
diff --git a/tests/auto/corelib/kernel/qjniobject/CMakeLists.txt b/tests/auto/corelib/kernel/qjniobject/CMakeLists.txt
index 98509dc0e5f..1d320b49c86 100644
--- a/tests/auto/corelib/kernel/qjniobject/CMakeLists.txt
+++ b/tests/auto/corelib/kernel/qjniobject/CMakeLists.txt
@@ -14,8 +14,16 @@ endif()
qt_internal_add_test(tst_qjniobject
SOURCES
tst_qjniobject.cpp
+ LIBRARIES
+ Qt::CorePrivate
)
+# if we can, enable C++23 so that we can use std::expected in the test
+# otherwise the test will use our own tl::expected copy from qexpected_p.h
+if ("${CMAKE_CXX_COMPILE_FEATURES}" MATCHES "cxx_std_23")
+ set_property(TARGET tst_qjniobject PROPERTY CXX_STANDARD 23)
+endif()
+
if(ANDROID)
set_property(TARGET tst_qjniobject APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
${CMAKE_CURRENT_SOURCE_DIR}/testdata
diff --git a/tests/auto/corelib/kernel/qjniobject/testdata/src/org/qtproject/qt/android/testdata/QtJniObjectTestClass.java b/tests/auto/corelib/kernel/qjniobject/testdata/src/org/qtproject/qt/android/testdata/QtJniObjectTestClass.java
index e0765fcb7e0..bdec173ca97 100644
--- a/tests/auto/corelib/kernel/qjniobject/testdata/src/org/qtproject/qt/android/testdata/QtJniObjectTestClass.java
+++ b/tests/auto/corelib/kernel/qjniobject/testdata/src/org/qtproject/qt/android/testdata/QtJniObjectTestClass.java
@@ -137,6 +137,10 @@ public class QtJniObjectTestClass
public Throwable throwableMethod() { return staticThrowableMethod(); }
// --------------------------------------------------------------------------------------------
+ public static void staticThrowingMethod() throws Throwable { throw new Throwable(A_STRING_OBJECT); }
+ public void throwingMethod() throws Throwable { throw new Throwable(A_STRING_OBJECT); }
+
+ // --------------------------------------------------------------------------------------------
public static Object[] staticObjectArrayMethod()
{ Object[] array = { new Object(), new Object(), new Object() }; return array; }
public Object[] objectArrayMethod() { return staticObjectArrayMethod(); }
diff --git a/tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp b/tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp
index c06b500778b..215b3bf3b78 100644
--- a/tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp
+++ b/tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp
@@ -8,12 +8,20 @@
#include <QtCore/QJniObject>
#include <QTest>
+#if defined(__cpp_lib_expected)
+# include <expected>
+#else
+# include <QtCore/private/qexpected_p.h>
+#endif
+
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
static constexpr const char testClassName[] = "org/qtproject/qt/android/testdatapackage/QtJniObjectTestClass";
Q_DECLARE_JNI_CLASS(QtJniObjectTestClass, testClassName)
+Q_DECLARE_JNI_CLASS(NoSuchClass, "no/such/Class")
+
using TestClass = QtJniTypes::QtJniObjectTestClass;
static const jbyte A_BYTE_VALUE = 127;
@@ -125,6 +133,24 @@ private slots:
void callback();
void callStaticOverloadResolution();
+ void implicitExceptionHandling_construct();
+ void implicitExceptionHandling_callMethod();
+ void implicitExceptionHandling_callStaticMethod();
+ void implicitExceptionHandling_getField();
+ void implicitExceptionHandling_setField();
+ void implicitExceptionHandling_getStaticField();
+ void implicitExceptionHandling_setStaticField();
+
+ void constructWithException();
+ void callMethodWithException();
+ void callMethodWithMonadic();
+ void callMethodWithTryCatch();
+ void callStaticMethodWithException();
+ void getFieldWithException();
+ void setFieldWithException();
+ void getStaticFieldWithException();
+ void setStaticFieldWithException();
+
void cleanupTestCase();
};
@@ -2303,8 +2329,547 @@ void tst_QJniObject::callStaticOverloadResolution()
QCOMPARE(result, value);
}
-QT_END_NAMESPACE
+void tst_QJniObject::implicitExceptionHandling_construct()
+{
+ QJniEnvironment env;
+ const QRegularExpression invalidClass("java.lang.ClassNotFoundException: .*");
+ const QRegularExpression invalidMethod("java.lang.NoSuchMethodError: .*");
+
+ // Constructor, including named constructor
+ {
+ QTest::ignoreMessage(QtWarningMsg, invalidClass);
+ QJniObject testObject("NoSuchClass");
+ QVERIFY(!env.checkAndClearExceptions());
+ }
+ {
+ QTest::ignoreMessage(QtWarningMsg, invalidMethod);
+ QJniObject testObject = QJniObject::construct<TestClass>(u"NoSuchConstructor"_s);
+ QVERIFY(!env.checkAndClearExceptions());
+ }
+}
+
+void tst_QJniObject::implicitExceptionHandling_callMethod()
+{
+ QJniEnvironment env;
+ const QRegularExpression invalidMethod("java.lang.NoSuchMethodError: .*");
+ const QRegularExpression throwingMethod("java.lang.Throwable: .*");
+
+ QJniObject testObject = QJniObject::construct<TestClass>();
+
+ QTest::ignoreMessage(QtWarningMsg, invalidMethod);
+ testObject.callMethod<void>("noSuchMethod1");
+ QVERIFY(!env.checkAndClearExceptions());
+
+ QTest::ignoreMessage(QtWarningMsg, invalidMethod);
+ testObject.callMethod<void>("noSuchMethod2", "()V");
+ QVERIFY(!env.checkAndClearExceptions());
+
+ QTest::ignoreMessage(QtWarningMsg, throwingMethod);
+ testObject.callMethod<void>("throwingMethod");
+ QVERIFY(!env.checkAndClearExceptions());
+
+ QTest::ignoreMessage(QtWarningMsg, invalidMethod);
+ (void)testObject.callObjectMethod<jstring>("noSuchMethod");
+ QVERIFY(!env.checkAndClearExceptions());
+
+ QTest::ignoreMessage(QtWarningMsg, invalidMethod);
+ testObject.callObjectMethod("noSuchMethod", "()V");
+ QVERIFY(!env.checkAndClearExceptions());
+}
+
+void tst_QJniObject::implicitExceptionHandling_callStaticMethod()
+{
+ QJniEnvironment env;
+ const QRegularExpression invalidClass("java.lang.ClassNotFoundException: .*");
+ const QRegularExpression invalidMethod("java.lang.NoSuchMethodError: .*");
+ const QRegularExpression throwingMethod("java.lang.Throwable: .*");
+
+ const jclass classId = env.findClass<TestClass>();
+ QVERIFY(classId != nullptr);
+
+ QTest::ignoreMessage(QtWarningMsg, invalidMethod);
+ TestClass::callStaticMethod<void>("noSuchStaticMethod");
+ QVERIFY(!env.checkAndClearExceptions());
+
+ QTest::ignoreMessage(QtWarningMsg, invalidMethod);
+ QJniObject::callStaticMethod<void>(QtJniTypes::Traits<TestClass>::className(),
+ "noSuchStaticMethod2", "()V");
+ QVERIFY(!env.checkAndClearExceptions());
+
+ QTest::ignoreMessage(QtWarningMsg, invalidClass);
+ QJniObject::callStaticMethod<void>("noSuchClass", "noSuchStaticMethod2", "()V");
+ QVERIFY(!env.checkAndClearExceptions());
+
+ QTest::ignoreMessage(QtWarningMsg, throwingMethod);
+ jmethodID methodId = env.findStaticMethod<void>(classId, "staticThrowingMethod");
+ QVERIFY(methodId != nullptr);
+ QJniObject::callStaticMethod<void>(classId, methodId);
+ QVERIFY(!env.checkAndClearExceptions());
+
+ QTest::ignoreMessage(QtWarningMsg, invalidClass);
+ QJniObject::callStaticObjectMethod("noSuchClass", "noSuchStaticMethod", "()V");
+ QVERIFY(!env.checkAndClearExceptions());
+
+ QTest::ignoreMessage(QtWarningMsg, invalidMethod);
+ QJniObject::callStaticObjectMethod(classId, "noSuchStaticMethod", "()V");
+ QVERIFY(!env.checkAndClearExceptions());
+}
+
+void tst_QJniObject::implicitExceptionHandling_getField()
+{
+ QJniEnvironment env;
+ const QRegularExpression invalidField("java.lang.NoSuchFieldError: .*");
+
+ QJniObject testObject = QJniObject::construct<TestClass>();
+ QTest::ignoreMessage(QtWarningMsg, invalidField);
+ (void)testObject.getField<int>("noSuchField");
+ QVERIFY(!env.checkAndClearExceptions());
+
+ QTest::ignoreMessage(QtWarningMsg, invalidField);
+ (void)testObject.getObjectField<jobject>("noSuchObjectField");
+ QVERIFY(!env.checkAndClearExceptions());
+
+ QTest::ignoreMessage(QtWarningMsg, invalidField);
+ (void)testObject.getObjectField("noSuchObjectField2", "Ljava/lang/Object;");
+ QVERIFY(!env.checkAndClearExceptions());
+}
+
+void tst_QJniObject::implicitExceptionHandling_setField()
+{
+ QJniEnvironment env;
+ const QRegularExpression invalidField("java.lang.NoSuchFieldError: .*");
+
+ QJniObject testObject = QJniObject::construct<TestClass>();
+ QTest::ignoreMessage(QtWarningMsg, invalidField);
+ testObject.setField("noSuchField", 123);
+ QVERIFY(!env.checkAndClearExceptions());
+
+ QTest::ignoreMessage(QtWarningMsg, invalidField);
+ testObject.setField("BOOLEAN_VAR", "I", 123);
+ QVERIFY(!env.checkAndClearExceptions());
+
+ // make sure that code specifying deducible type explicitly still works
+ static_assert(std::is_same_v<decltype(testObject.setField<jboolean>("BOOLEAN_VAR", true)),
+ void>);
+}
+
+void tst_QJniObject::implicitExceptionHandling_getStaticField()
+{
+ QJniEnvironment env;
+ const QRegularExpression invalidClass("java.lang.ClassNotFoundException: .*");
+ const QRegularExpression invalidField("java.lang.NoSuchFieldError: .*");
+
+ const jclass classId = env.findClass<TestClass>();
+ QVERIFY(classId != nullptr);
+
+ QTest::ignoreMessage(QtWarningMsg, invalidField);
+ (void)TestClass::getStaticField<int>("noSuchStaticField");
+ QVERIFY(!env.checkAndClearExceptions());
+
+ QTest::ignoreMessage(QtWarningMsg, invalidField);
+ (void)QJniObject::getStaticField<int>(classId, "noSuchStaticField");
+ QVERIFY(!env.checkAndClearExceptions());
+
+ QTest::ignoreMessage(QtWarningMsg, invalidClass);
+ (void)QJniObject::getStaticObjectField("noSuchClass", "noSuchStaticField", "I");
+ QVERIFY(!env.checkAndClearExceptions());
+
+ QTest::ignoreMessage(QtWarningMsg, invalidField);
+ (void)QJniObject::getStaticObjectField(classId, "S_BOOLEAN_VAR", "I");
+ QVERIFY(!env.checkAndClearExceptions());
+}
+
+void tst_QJniObject::implicitExceptionHandling_setStaticField()
+{
+ QJniEnvironment env;
+ const QRegularExpression invalidClass("java.lang.ClassNotFoundException: .*");
+ const QRegularExpression invalidField("java.lang.NoSuchFieldError: .*");
+
+ const jclass classId = env.findClass<TestClass>();
+ QVERIFY(classId != nullptr);
+
+ QTest::ignoreMessage(QtWarningMsg, invalidField);
+ TestClass::setStaticField("noSuchStaticField", 123);
+ QVERIFY(!env.checkAndClearExceptions());
+
+ QTest::ignoreMessage(QtWarningMsg, invalidField);
+ QJniObject::setStaticField(classId, "noSuchStaticField", 123);
+ QVERIFY(!env.checkAndClearExceptions());
+
+ QTest::ignoreMessage(QtWarningMsg, invalidClass);
+ QJniObject::setStaticField("noSuchClass", "noSuchStaticField", 123);
+ QVERIFY(!env.checkAndClearExceptions());
+
+ QTest::ignoreMessage(QtWarningMsg, invalidField);
+ QJniObject::setStaticField(QtJniTypes::Traits<TestClass>::className(),
+ "S_BOOLEAN_VAR", "I", 123);
+ QVERIFY(!env.checkAndClearExceptions());
+
+ // make sure that code specifying deducible type explicitly still works
+ static_assert(std::is_same_v<decltype(TestClass::setStaticField<jboolean>("S_BOOLEAN_VAR", true)),
+ void>);
+}
+
+#if __cpp_lib_expected
+template <typename T>
+using QJniReturnValue = std::expected<T, jthrowable>;
+using BadAccessException = std::bad_expected_access<jthrowable>;
+// even with __cpp_lib_expected >= 202211L, monadic functions seem to be rather
+// broken or not reliably available
+#define EXPECTED_HAS_MONADIC false
+#elif TL_EXPECTED_VERSION_MAJOR
+#define EXPECTED_HAS_MONADIC true
+template <typename T>
+using QJniReturnValue = tl::expected<T, jthrowable>;
+using BadAccessException = tl::bad_expected_access<jthrowable>;
+#endif
+
+static_assert(QtJniTypes::Traits<QJniReturnValue<int>>::signature() ==
+ QtJniTypes::Traits<int>::signature());
+static_assert(QtJniTypes::Traits<QJniReturnValue<QString>>::signature() ==
+ QtJniTypes::Traits<QString>::signature());
+
+
+void tst_QJniObject::constructWithException()
+{
+#if __cpp_lib_expected
+ qInfo() << "Testing explicit exception handling with std::expected" << __cpp_lib_expected;
+#elif defined(TL_EXPECTED_VERSION_MAJOR)
+ qInfo() << "Testing explicit exception handling with tl::expected";
+#else
+ qInfo() << "Testing explicit exception handling with QJniReturnValue";
+#endif
+
+ const QRegularExpression invalidClass("java.lang.ClassNotFoundException: .*");
+ {
+ QTest::ignoreMessage(QtWarningMsg, invalidClass);
+ QJniObject invalid = QJniObject::construct<QtJniTypes::NoSuchClass>();
+ }
+
+ QVERIFY(!QJniEnvironment().checkAndClearExceptions());
+
+ {
+ // can only handle exceptions when using the named constructor
+ auto result = QJniObject::construct<QJniReturnValue<TestClass>>();
+ QVERIFY(result);
+ result = QJniObject::construct<QJniReturnValue<TestClass>>(u"123"_s);
+ QVERIFY(!result);
+ QVERIFY(result.error());
+ }
+
+ QVERIFY(!QJniEnvironment().checkAndClearExceptions());
+
+ {
+ const auto result = QJniObject::construct<QJniReturnValue<QtJniTypes::NoSuchClass>>();
+ QVERIFY(!result);
+ QVERIFY(result.error());
+ }
+
+ QVERIFY(!QJniEnvironment().checkAndClearExceptions());
+
+ {
+ // no way to prevent implicit exception here
+ QTest::ignoreMessage(QtWarningMsg, invalidClass);
+ QtJniTypes::NoSuchClass noSuchClass;
+ QVERIFY(!noSuchClass.isValid());
+ }
+
+ QVERIFY(!QJniEnvironment().checkAndClearExceptions());
+}
+
+void tst_QJniObject::callMethodWithException()
+{
+ TestClass testObject;
+ {
+ auto result = testObject.callMethod<QJniReturnValue<void>>("voidMethod");
+ QVERIFY(result);
+ result = testObject.callMethod<QJniReturnValue<void>>("voidMethod", 123);
+ QVERIFY(!result);
+ QVERIFY(result.error());
+ }
+
+ {
+ auto result = testObject.callMethod<QJniReturnValue<jint>>("intMethod");
+ QVERIFY(result);
+ QCOMPARE(result.value(), A_INT_VALUE);
+ result = testObject.callMethod<QJniReturnValue<jint>>("intMethod", 123);
+ QVERIFY(!result);
+ QVERIFY(result.error());
+ QCOMPARE(result.value_or(456), 456);
+ }
+
+ {
+ auto result = testObject.callMethod<QJniReturnValue<jstring>>("stringMethod");
+ QVERIFY(result);
+ QVERIFY(result.value());
+ result = testObject.callMethod<QJniReturnValue<jstring>>("stringMethod", 123);
+ QVERIFY(!result);
+ QVERIFY(result.error());
+ }
+
+ {
+ auto result = testObject.callMethod<QJniReturnValue<QString>>("stringMethod");
+ QVERIFY(result);
+ QVERIFY(!result.value().isEmpty());
+ result = testObject.callMethod<QJniReturnValue<QString>>("stringMethod", 123);
+ QVERIFY(!result);
+ QVERIFY(result.error());
+ QCOMPARE(result.value_or(u"Default"_s), u"Default"_s);
+ }
+
+ {
+ QJniArray<jboolean> newArray(QList<jboolean>{true, false, false});
+ auto result = testObject.callMethod<QJniReturnValue<QJniArray<jboolean>>>("reverseBooleanArray", newArray);
+ // this shorthand cannot work with e.g. std::expected
+ // result = testObject.callMethod<QJniReturnValue<jboolean[]>>("reverseBooleanArray", newArray);
+ QVERIFY(result);
+ QCOMPARE(result.value().toContainer(), (QList<jboolean>{false, false, true}));
+ result = testObject.callMethod<QJniReturnValue<QJniArray<jboolean>>>("reverseBooleanArray", 123);
+ QVERIFY(!result);
+ QVERIFY(result.error());
+ }
+
+ // throwing method - QJniObject cleans the exception and prints qWarning
+ {
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(u"java.lang.Throwable: "_s + A_STRING_OBJECT() + u".*"_s));
+ testObject.callMethod<void>("throwingMethod");
+
+ auto result = testObject.callMethod<QJniReturnValue<void>>("throwingMethod");
+ QVERIFY(!result);
+ const QStringList stackTrace = QJniEnvironment::stackTrace(result.error());
+ QCOMPARE_GE(stackTrace.size(), 1);
+ QCOMPARE(stackTrace.at(0), u"java.lang.Throwable: "_s + A_STRING_OBJECT());
+ }
+}
+
+void tst_QJniObject::callMethodWithMonadic()
+{
+#if !EXPECTED_HAS_MONADIC
+ QSKIP("Used version of std::expected does not have monadic functions");
+#else
+ enum Monadic {
+ AndThen,
+ OrElse,
+ Transform,
+ };
+
+ TestClass testObject;
+ {
+ QList<Monadic> flow;
+ const auto result = testObject.callMethod<QJniReturnValue<void>>("voidMethod")
+ .and_then([&flow]{
+ flow << AndThen;
+ return QJniReturnValue<void>();
+ })
+ .or_else([&flow](jthrowable error){
+ if (error)
+ flow << OrElse;
+ else
+ qWarning("Invalid call to or_else monadic");
+ return QJniReturnValue<void>();
+ })
+ .transform([&flow](){
+ flow << Transform;
+ return 42;
+ });
+ QCOMPARE(flow, (QList<Monadic>{AndThen, Transform}));
+ QVERIFY(result);
+ QCOMPARE(*result, 42);
+ }
+ {
+ QList<Monadic> flow;
+ const auto result = testObject.callMethod<QJniReturnValue<void>>("voidMethod", 123)
+ .and_then([&flow]{
+ flow << AndThen;
+ return QJniReturnValue<void>();
+ })
+ .or_else([&flow](jthrowable error){
+ if (error)
+ flow << OrElse;
+ else
+ qWarning("Invalid call to or_else monadic");
+ return QJniReturnValue<void>(typename QJniReturnValue<void>::unexpected_type(error));
+ })
+ .transform([&flow](){
+ flow << Transform;
+ return 42;
+ });
+ QCOMPARE(flow, (QList<Monadic>{OrElse}));
+ QVERIFY(!result);
+ }
+
+ {
+ QList<Monadic> flow;
+ const auto result = testObject.callMethod<QJniReturnValue<jobject>>("objectMethod")
+ .and_then([&flow](auto &&obj){
+ flow << AndThen;
+ return QJniReturnValue<jobject>(obj);
+ })
+ .or_else([&flow](jthrowable error){
+ if (error)
+ flow << OrElse;
+ else
+ qWarning("Invalid call to or_else monadic");
+ return QJniReturnValue<jobject>(typename QJniReturnValue<void>::unexpected_type(error));
+ })
+ .transform([&flow](auto &&obj){
+ flow << Transform;
+ return QJniObject(obj).template getField<int>("INT_FIELD");
+ })
+ .and_then([&flow](auto value){
+ flow << AndThen;
+ return QJniReturnValue<int>(value * 2);
+ });
+ QCOMPARE(flow, (QList<Monadic>{AndThen, Transform, AndThen}));
+ QVERIFY(result);
+ QCOMPARE(*result, 246);
+ }
+ {
+ QList<Monadic> flow;
+ const auto result = testObject.callMethod<QJniReturnValue<jobject>>("objectMethod", 123)
+ .and_then([&flow](const QJniObject &obj){
+ flow << AndThen;
+ return QJniReturnValue<jobject>(obj.object());
+ })
+ .or_else([&flow](jthrowable error){
+ if (error)
+ flow << OrElse;
+ else
+ qWarning("Invalid call to or_else monadic");
+ return QJniReturnValue<jobject>(typename QJniReturnValue<jobject>::unexpected_type(error));
+ })
+ .transform([&flow](const QJniObject &obj){
+ flow << Transform;
+ return obj.getField<int>("INT_FIELD");
+ });
+ QCOMPARE(flow, (QList<Monadic>{OrElse}));
+ QVERIFY(!result);
+ }
+#endif
+}
+
+void tst_QJniObject::callMethodWithTryCatch()
+{
+ TestClass testObject;
+
+ const QRegularExpression invalidMethod("java.lang.NoSuchMethodError: .*");
+ QTest::ignoreMessage(QtWarningMsg, invalidMethod);
+
+ try {
+ const auto result = testObject.callMethod<QJniReturnValue<QJniObject>>("objectMethod", 123);
+ result.value().getField<int>("INT_FIELD");
+ }
+ catch (BadAccessException &e) {
+ qWarning().noquote() << QJniEnvironment::stackTrace(e.error()).join('\n');
+ }
+}
+
+void tst_QJniObject::callStaticMethodWithException()
+{
+ {
+ auto result = TestClass::callStaticMethod<QJniReturnValue<int>>("staticIntMethod");
+ QVERIFY(result);
+ QCOMPARE(*result, A_INT_VALUE);
+ result = TestClass::callStaticMethod<QJniReturnValue<int>>("staticIntMethod", 123);
+ QVERIFY(!result && result.error());
+ }
+
+ {
+ auto result = TestClass::callStaticMethod<QJniReturnValue<QString>>("staticStringMethod");
+ QVERIFY(result);
+ QCOMPARE(*result, A_STRING_OBJECT());
+ result = TestClass::callStaticMethod<QJniReturnValue<QString>>("staticStringMethod", 123);
+ QVERIFY(!result && result.error());
+ }
+
+ // throwing method
+ {
+ const auto result = TestClass::callStaticMethod<QJniReturnValue<void>>("staticThrowingMethod");
+ QVERIFY(!result);
+ QStringList stackTrace = QJniEnvironment::stackTrace(result.error());
+ QCOMPARE_GE(stackTrace.size(), 1);
+ QCOMPARE(stackTrace.at(0), u"java.lang.Throwable: "_s + A_STRING_OBJECT());
+ }
+}
+
+void tst_QJniObject::getFieldWithException()
+{
+ TestClass testObject;
+ {
+ auto result = testObject.getField<QJniReturnValue<jboolean>>("BOOL_FIELD");
+ QVERIFY(result);
+ result = testObject.getField<QJniReturnValue<jboolean>>("INVALID_BOOL");
+ QVERIFY(!result && result.error());
+ }
+
+ {
+ auto result = testObject.getField<QJniReturnValue<QString>>("STRING_OBJECT_VAR");
+ QVERIFY(result);
+ result = testObject.getField<QJniReturnValue<QString>>("INVALID_STRING");
+ QVERIFY(!result && result.error());
+ }
+}
+
+void tst_QJniObject::setFieldWithException()
+{
+ TestClass testObject;
+ {
+ auto result = testObject.setField<QJniReturnValue<jboolean>>("BOOL_FIELD", true);
+ QVERIFY(result);
+ result = testObject.setField<QJniReturnValue<jboolean>>("SET_INVALID_BOOL", true);
+ QVERIFY(!result);
+ QVERIFY(result.error());
+ }
+
+ {
+ auto result = testObject.setField<QJniReturnValue<QString>>("STRING_OBJECT_VAR", u"test"_s);
+ QVERIFY(result);
+ result = testObject.setField<QJniReturnValue<QString>>("SET_INVALID_STRING", u"test"_s);
+ QVERIFY(!result);
+ QVERIFY(result.error());
+ }
+}
+
+void tst_QJniObject::getStaticFieldWithException()
+{
+ {
+ auto result = TestClass::getStaticField<QJniReturnValue<jshort>>("S_SHORT_VAR");
+ QVERIFY(result);
+ result = TestClass::getStaticField<QJniReturnValue<jshort>>("S_INVALID_SHORT");
+ QVERIFY(!result);
+ QVERIFY(result.error());
+ }
+
+ {
+ auto result = TestClass::getStaticField<QJniReturnValue<QString>>("S_STRING_OBJECT_VAR");
+ QVERIFY(result);
+ result = TestClass::getStaticField<QJniReturnValue<QString>>("S_INVALID_STRING");
+ QVERIFY(!result);
+ QVERIFY(result.error());
+ }
+}
+
+void tst_QJniObject::setStaticFieldWithException()
+{
+ {
+ auto result = TestClass::setStaticField<QJniReturnValue<jboolean>>("S_BOOLEAN_VAR", true);
+ QVERIFY(result);
+ result = TestClass::setStaticField<QJniReturnValue<jboolean>>("SET_S_INVALID_BOOL", true);
+ QVERIFY(!result);
+ QVERIFY(result.error());
+ }
+
+ {
+ auto result = TestClass::setStaticField<QJniReturnValue<QString>>("S_STRING_OBJECT_VAR", u"test"_s);
+ QVERIFY(result);
+ result = TestClass::setStaticField<QJniReturnValue<QString>>("SET_S_INVALID_STRING", u"test"_s);
+ QVERIFY(!result);
+ QVERIFY(result.error());
+ }
+}
QTEST_MAIN(tst_QJniObject)
+QT_END_NAMESPACE
+
#include "tst_qjniobject.moc"
diff --git a/tests/auto/corelib/text/qstring/tst_qstring.cpp b/tests/auto/corelib/text/qstring/tst_qstring.cpp
index db2b18a5c01..8217da843e0 100644
--- a/tests/auto/corelib/text/qstring/tst_qstring.cpp
+++ b/tests/auto/corelib/text/qstring/tst_qstring.cpp
@@ -9409,7 +9409,7 @@ void tst_QString::rawData()
void tst_QString::testUtf16()
{
{
- const char16_t arr[] = {'a', 'b', 'c'};
+ constexpr char16_t arr[] = {u'a', u'b', u'c'};
QString s = QString::fromRawData(arr, 3); // doesn't guarantee null-termination
QCOMPARE(s.size(), qsizetype(std::size(arr)));
// The string points to the raw data
diff --git a/tests/auto/corelib/tools/qatomicscopedvaluerollback/tst_qatomicscopedvaluerollback.cpp b/tests/auto/corelib/tools/qatomicscopedvaluerollback/tst_qatomicscopedvaluerollback.cpp
index b53362b43e9..f4699f92959 100644
--- a/tests/auto/corelib/tools/qatomicscopedvaluerollback/tst_qatomicscopedvaluerollback.cpp
+++ b/tests/auto/corelib/tools/qatomicscopedvaluerollback/tst_qatomicscopedvaluerollback.cpp
@@ -20,6 +20,7 @@ private Q_SLOTS:
void exceptions();
void earlyExitScope();
void mixedTypes();
+ void sharedPtr();
private:
void earlyExitScope_helper(int exitpoint, std::atomic<int> &member);
};
@@ -221,6 +222,34 @@ void tst_QAtomicScopedValueRollback::mixedTypes()
}
}
+void tst_QAtomicScopedValueRollback::sharedPtr()
+{
+#ifdef __cpp_lib_atomic_shared_ptr
+ std::atomic<std::shared_ptr<int>> a{std::make_shared<int>(42)};
+ QCOMPARE_NE(a.load(), nullptr);
+ QCOMPARE_EQ(*a.load(), 42);
+ {
+ QAtomicScopedValueRollback rb(a, nullptr);
+ QCOMPARE_EQ(a.load(), nullptr);
+ }
+ QCOMPARE_NE(a.load(), nullptr);
+ QCOMPARE_EQ(*a.load(), 42);
+ {
+ QAtomicScopedValueRollback rb{a, std::make_shared<int>(123)};
+ QCOMPARE_NE(a.load(), nullptr);
+ QCOMPARE_EQ(*a.load(), 123);
+ rb.commit();
+ a.store(std::make_shared<int>(256));
+ QCOMPARE_NE(a.load(), nullptr);
+ QCOMPARE_EQ(*a.load(), 256);
+ }
+ QCOMPARE_NE(a.load(), nullptr);
+ QCOMPARE_EQ(*a.load(), 123);
+#else
+ QSKIP("This test requires atomic<shared_ptr> support enabled in the C++ standard library.");
+#endif
+}
+
static void operator*=(std::atomic<int> &lhs, int rhs)
{
int expected = lhs.load();
diff --git a/tests/auto/corelib/tools/qflatmap/tst_qflatmap.cpp b/tests/auto/corelib/tools/qflatmap/tst_qflatmap.cpp
index 986cf2407b7..fd960581cf9 100644
--- a/tests/auto/corelib/tools/qflatmap/tst_qflatmap.cpp
+++ b/tests/auto/corelib/tools/qflatmap/tst_qflatmap.cpp
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#define QT_USE_QSTRINGBUILDER
-#define QFLATMAP_ENABLE_STL_COMPATIBLE_INSERT
#include <QTest>
diff --git a/tests/auto/wasm/CMakeLists.txt b/tests/auto/wasm/CMakeLists.txt
index 35b4d45e533..ffa2b9ca98c 100644
--- a/tests/auto/wasm/CMakeLists.txt
+++ b/tests/auto/wasm/CMakeLists.txt
@@ -6,4 +6,5 @@ add_subdirectory(localfileapi)
add_subdirectory(qwasmkeytranslator)
add_subdirectory(qwasmwindowstack)
add_subdirectory(qwasmwindowtreenode)
+add_subdirectory(qwasmpromise)
add_subdirectory(selenium)
diff --git a/tests/auto/wasm/qwasmpromise/CMakeLists.txt b/tests/auto/wasm/qwasmpromise/CMakeLists.txt
new file mode 100644
index 00000000000..44e6203ec86
--- /dev/null
+++ b/tests/auto/wasm/qwasmpromise/CMakeLists.txt
@@ -0,0 +1,23 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qwasmpromise Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qwasmpromise LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qwasmpromise
+ SOURCES
+ tst_qwasmpromise.cpp
+ DEFINES
+ QT_NO_FOREACH
+ LIBRARIES
+ Qt::Core
+ Qt::Gui
+ Qt::GuiPrivate
+)
diff --git a/tests/auto/wasm/qwasmpromise/tst_qwasmpromise.cpp b/tests/auto/wasm/qwasmpromise/tst_qwasmpromise.cpp
new file mode 100644
index 00000000000..0c8582d49a0
--- /dev/null
+++ b/tests/auto/wasm/qwasmpromise/tst_qwasmpromise.cpp
@@ -0,0 +1,526 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QTest>
+
+#include <emscripten/val.h>
+#include <emscripten.h>
+
+#include <QtCore/private/qstdweb_p.h>
+
+namespace {
+
+emscripten::val g_testSupport;
+
+void init() {
+ g_testSupport = emscripten::val::object();
+ EM_ASM({
+ var testSupport = Emval.toValue($0);
+ 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];
+ };
+ }, g_testSupport.as_handle());
+}
+}
+
+class tst_QWasmPromise : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QWasmPromise() = default;
+
+private slots:
+ void init();
+ void suspendExclusive();
+ 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();
+};
+
+static bool g_Done = false;
+
+#define QWASMDONE() g_Done = true;
+
+void tst_QWasmPromise::init() {
+ g_Done = false;
+ ::init();
+}
+
+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;
+};
+
+void tst_QWasmPromise::suspendExclusive()
+{
+ init();
+
+ {
+ auto promise = qstdweb::Promise(
+ g_testSupport,
+ "makeTestPromise",
+ std::string("simpleResolve"))
+ .addThenFunction([](emscripten::val result) {
+ QVERIFY(result.isString());
+ QCOMPARE("Some lovely data", result.as<std::string>());
+ QWASMDONE();
+ })
+ .addCatchFunction([](emscripten::val error) {
+ Q_UNUSED(error);
+ QFAIL("Unexpected catch");
+ QWASMDONE();
+ });
+
+ g_testSupport["resolve"].call<void>("simpleResolve", std::string("Some lovely data"));
+ promise.suspendExclusive();
+ }
+ QVERIFY(g_Done);
+ QVERIFY(qstdweb::Promise::State::numInstances() == 0);
+}
+
+void tst_QWasmPromise::simpleResolve()
+{
+ init();
+
+ qstdweb::Promise(
+ g_testSupport,
+ "makeTestPromise",
+ std::string("simpleResolve"))
+ .addThenFunction([](emscripten::val result) {
+ QVERIFY(result.isString());
+ QCOMPARE("Some lovely data", result.as<std::string>());
+ QWASMDONE();
+ })
+ .addCatchFunction([](emscripten::val error) {
+ Q_UNUSED(error);
+ QFAIL("Unexpected catch");
+ QWASMDONE();
+ })
+ .addFinallyFunction([](){});
+
+ g_testSupport["resolve"].call<void>("simpleResolve", std::string("Some lovely data"));
+ QVERIFY(QTest::qWaitFor([]() { return g_Done; }));
+ QVERIFY(QTest::qWaitFor([]() { return qstdweb::Promise::State::numInstances() == 0; }));
+}
+
+void tst_QWasmPromise::multipleResolve()
+{
+ init();
+ static constexpr int promiseCount = 1000;
+
+ auto onThen = std::make_shared<BarrierCallback>(promiseCount, []() {
+ QWASMDONE();
+ });
+
+ for (int i = 0; i < promiseCount; ++i) {
+ qstdweb::Promise(
+ g_testSupport,
+ "makeTestPromise",
+ (QStringLiteral("test") + QString::number(i)).toStdString())
+ .addThenFunction([=](emscripten::val result) {
+ QVERIFY(result.isString());
+ QCOMPARE(QString::number(i).toStdString(), result.as<std::string>());
+ (*onThen)();
+ })
+ .addCatchFunction([](emscripten::val error) {
+ Q_UNUSED(error);
+ QFAIL("Unexpected catch");
+ QWASMDONE();
+ });
+ }
+
+ for (int i = 0; i < promiseCount; ++i)
+ g_testSupport["resolve"].call<void>(("test" + std::to_string(i)).c_str(), std::to_string(i));
+
+ QVERIFY(QTest::qWaitFor([]() { return g_Done; }));
+ QVERIFY(QTest::qWaitFor([]() { return qstdweb::Promise::State::numInstances() == 0; }));
+}
+
+void tst_QWasmPromise::simpleReject()
+{
+ init();
+
+ qstdweb::Promise(
+ g_testSupport,
+ "makeTestPromise",
+ std::string("simpleReject"))
+ .addThenFunction([](emscripten::val result) {
+ Q_UNUSED(result);
+ QFAIL("Unexpected then");
+ QWASMDONE();
+ })
+ .addCatchFunction([](emscripten::val result) {
+ QVERIFY(result.isString());
+ QCOMPARE("Evil error", result.as<std::string>());
+ QWASMDONE();
+ });
+
+ g_testSupport["reject"].call<void>("simpleReject", std::string("Evil error"));
+ QVERIFY(QTest::qWaitFor([]() { return g_Done; }));
+ QVERIFY(QTest::qWaitFor([]() { return qstdweb::Promise::State::numInstances() == 0; }));
+}
+
+void tst_QWasmPromise::multipleReject()
+{
+ static constexpr int promiseCount = 1000;
+
+ auto onCatch = std::make_shared<BarrierCallback>(promiseCount, []() {
+ QWASMDONE();
+ });
+
+ for (int i = 0; i < promiseCount; ++i) {
+ qstdweb::Promise(
+ g_testSupport,
+ "makeTestPromise",
+ (QStringLiteral("test") + QString::number(i)).toStdString())
+ .addThenFunction([](emscripten::val result) {
+ Q_UNUSED(result);
+ QFAIL("Unexpected then");
+ })
+ .addCatchFunction([=](emscripten::val error) {
+ Q_UNUSED(error);
+ (*onCatch)();
+ });
+ }
+
+ for (int i = 0; i < promiseCount; ++i)
+ g_testSupport["reject"].call<void>(("test" + std::to_string(i)).c_str(), std::to_string(i));
+ QVERIFY(QTest::qWaitFor([]() { return g_Done; }));
+ QVERIFY(QTest::qWaitFor([]() { return qstdweb::Promise::State::numInstances() == 0; }));
+}
+
+void tst_QWasmPromise::throwInThen()
+{
+ init();
+ QSKIP("Throw not supported");
+ qstdweb::Promise(
+ g_testSupport,
+ "makeTestPromise",
+ std::string("throwInThen"))
+ .addThenFunction([](emscripten::val result) {
+ Q_UNUSED(result);
+ EM_ASM({
+ throw "Expected error";
+ });
+ })
+ .addCatchFunction([](emscripten::val error) {
+ QCOMPARE("Expected error", error.as<std::string>());
+ QWASMDONE();
+ });
+
+ g_testSupport["resolve"].call<void>("throwInThen", std::string("Evil error"));
+ QVERIFY(QTest::qWaitFor([]() { return g_Done; }));
+ QVERIFY(QTest::qWaitFor([]() { return qstdweb::Promise::State::numInstances() == 0; }));
+}
+
+void tst_QWasmPromise::bareFinally()
+{
+ init();
+
+ qstdweb::Promise(
+ g_testSupport,
+ "makeTestPromise",
+ std::string("bareFinally"))
+ .addFinallyFunction([]() {
+ QWASMDONE();
+ });
+
+ g_testSupport["resolve"].call<void>("bareFinally", std::string("Evil error"));
+ QVERIFY(QTest::qWaitFor([]() { return g_Done; }));
+ QVERIFY(QTest::qWaitFor([]() { return qstdweb::Promise::State::numInstances() == 0; }));
+}
+
+void tst_QWasmPromise::finallyWithThen()
+{
+ init();
+
+ bool *thenCalled = new bool(false);
+ qstdweb::Promise(
+ g_testSupport,
+ "makeTestPromise",
+ std::string("finallyWithThen"))
+ .addThenFunction([thenCalled] (emscripten::val result) {
+ Q_UNUSED(result);
+ *thenCalled = true;
+ })
+ .addFinallyFunction([thenCalled]() {
+ QVERIFY(*thenCalled);
+ delete thenCalled;
+ QWASMDONE();
+ });
+
+ g_testSupport["resolve"].call<void>("finallyWithThen", std::string("Evil error"));
+ QVERIFY(QTest::qWaitFor([]() { return g_Done; }));
+ QVERIFY(QTest::qWaitFor([]() { return qstdweb::Promise::State::numInstances() == 0; }));
+}
+
+void tst_QWasmPromise::finallyWithThrow()
+{
+ init();
+
+ qstdweb::Promise(
+ g_testSupport,
+ "makeTestPromise",
+ std::string("finallyWithThrow"))
+ .addCatchFunction([](emscripten::val error) {
+ Q_UNUSED(error);
+ })
+ .addFinallyFunction([]() {
+ QWASMDONE();
+ });
+
+ g_testSupport["reject"].call<void>("finallyWithThrow", std::string("Evil error"));
+ QVERIFY(QTest::qWaitFor([]() { return g_Done; }));
+ QVERIFY(QTest::qWaitFor([]() { return qstdweb::Promise::State::numInstances() == 0; }));
+}
+
+void tst_QWasmPromise::finallyWithThrowInThen()
+{
+ init();
+ QSKIP("Throw not supported");
+
+ qstdweb::Promise(
+ g_testSupport,
+ "makeTestPromise",
+ std::string("finallyWithThrowInThen"))
+ .addThenFunction([](emscripten::val result) {
+ Q_UNUSED(result);
+ EM_ASM({
+ throw "Expected error";
+ });
+ })
+ .addCatchFunction([](emscripten::val result) {
+ QVERIFY(result.isString());
+ QCOMPARE("Expected error", result.as<std::string>());
+ })
+ .addFinallyFunction([]() {
+ QWASMDONE();
+ });
+
+ g_testSupport["resolve"].call<void>("finallyWithThrowInThen", std::string("Evil error"));
+ QVERIFY(QTest::qWaitFor([]() { return g_Done; }));
+ QVERIFY(QTest::qWaitFor([]() { return qstdweb::Promise::State::numInstances() == 0; }));
+}
+
+void tst_QWasmPromise::nested()
+{
+ init();
+
+ qstdweb::Promise(
+ g_testSupport,
+ "makeTestPromise",
+ std::string("outer"))
+ .addThenFunction([](emscripten::val result) {
+ QVERIFY(result.isString());
+ QCOMPARE("Outer data", result.as<std::string>());
+ qstdweb::Promise(
+ g_testSupport,
+ "makeTestPromise",
+ std::string("inner"))
+ .addThenFunction([](emscripten::val innerResult) {
+ QVERIFY(innerResult.isString());
+ QCOMPARE("Inner data", innerResult.as<std::string>());
+ qstdweb::Promise(
+ g_testSupport,
+ "makeTestPromise",
+ std::string("innermost"))
+ .addThenFunction([](emscripten::val innerResult) {
+ QVERIFY(innerResult.isString());
+ QCOMPARE("Innermost data", innerResult.as<std::string>());
+ QWASMDONE();
+ })
+ .addCatchFunction([](emscripten::val error) {
+ Q_UNUSED(error);
+ QFAIL("Unexpected catch");
+ });
+ g_testSupport["resolve"].call<void>("innermost", std::string("Innermost data"));
+ });
+ g_testSupport["resolve"].call<void>("inner", std::string("Inner data"));
+ })
+ .addCatchFunction([](emscripten::val error) {
+ Q_UNUSED(error);
+ QFAIL("Unexpected catch");
+ });
+
+ g_testSupport["resolve"].call<void>("outer", std::string("Outer data"));
+ QVERIFY(QTest::qWaitFor([]() { return g_Done; }));
+ QVERIFY(QTest::qWaitFor([]() { return qstdweb::Promise::State::numInstances() == 0; }));
+}
+
+void tst_QWasmPromise::all()
+{
+ init();
+
+ {
+ static constexpr int promiseCount = 1000;
+ auto thenCalledOnce = std::make_shared<bool>(true);
+
+ std::vector<qstdweb::Promise> promises;
+ promises.reserve(promiseCount);
+
+ for (int i = 0; i < promiseCount; ++i) {
+ promises.push_back(
+ qstdweb::Promise(
+ g_testSupport,
+ "makeTestPromise",
+ emscripten::val(("all" + QString::number(i)).toStdString())));
+ }
+
+ qstdweb::Promise(
+ promises)
+ .addThenFunction([thenCalledOnce](emscripten::val result) {
+ QVERIFY(*thenCalledOnce);
+ *thenCalledOnce = false;
+
+ QVERIFY(result.isArray());
+ QCOMPARE(promiseCount, result["length"].as<int>());
+ for (int i = 0; i < promiseCount; ++i)
+ QCOMPARE(QStringLiteral("Data %1").arg(i).toStdString(), result[i].as<std::string>());
+
+ QWASMDONE();
+ })
+ .addCatchFunction([](emscripten::val error) {
+ Q_UNUSED(error);
+ QFAIL("Unexpected catch");
+ });
+
+ for (int i = promiseCount - 1; i >= 0; --i)
+ g_testSupport["resolve"].call<void>(("all" + std::to_string(i)).c_str(), "Data " + std::to_string(i));
+ }
+ QVERIFY(QTest::qWaitFor([]() { return g_Done; }));
+ QVERIFY(QTest::qWaitFor([]() { return qstdweb::Promise::State::numInstances() == 0; }));
+}
+
+void tst_QWasmPromise::allWithThrow()
+{
+ init();
+
+ {
+ auto promise1 = qstdweb::Promise(g_testSupport, "makeTestPromise", std::string("promise1"));
+ auto promise2 = qstdweb::Promise(g_testSupport, "makeTestPromise", std::string("promise2"));
+ auto promise3 = qstdweb::Promise(g_testSupport, "makeTestPromise", std::string("promise3"));
+ auto catchCalledOnce = std::make_shared<bool>(true);
+
+ qstdweb::Promise(
+ {promise1, promise2, promise3})
+ .addThenFunction([](emscripten::val result) {
+ Q_UNUSED(result);
+ QFAIL("Unexpected then");
+ })
+ .addCatchFunction([catchCalledOnce](emscripten::val result) {
+ QVERIFY(*catchCalledOnce);
+ *catchCalledOnce = false;
+ QVERIFY(result.isString());
+ QCOMPARE("Error 2", result.as<std::string>());
+ QWASMDONE();
+ });
+
+ g_testSupport["resolve"].call<void>("promise3", std::string("Data 3"));
+ g_testSupport["resolve"].call<void>("promise1", std::string("Data 1"));
+ g_testSupport["reject"].call<void>("promise2", std::string("Error 2"));
+ }
+
+ QVERIFY(QTest::qWaitFor([]() { return g_Done; }));
+ QVERIFY(QTest::qWaitFor([]() { return qstdweb::Promise::State::numInstances() == 0; }));
+}
+
+void tst_QWasmPromise::allWithFinally()
+{
+ init();
+ {
+ auto promise1 = qstdweb::Promise(g_testSupport, "makeTestPromise", std::string("promise1"));
+ auto promise2 = qstdweb::Promise(g_testSupport, "makeTestPromise", std::string("promise2"));
+ auto promise3 = qstdweb::Promise(g_testSupport, "makeTestPromise", std::string("promise3"));
+
+ auto finallyCalledOnce = std::make_shared<bool>(true);
+
+ qstdweb::Promise(
+ {promise1, promise2, promise3})
+ .addThenFunction([](emscripten::val result) {
+ Q_UNUSED(result);
+ })
+ .addFinallyFunction([finallyCalledOnce]() {
+ QVERIFY(*finallyCalledOnce);
+ *finallyCalledOnce = false;
+ QWASMDONE();
+ });
+
+ g_testSupport["resolve"].call<void>("promise3", std::string("Data 3"));
+ g_testSupport["resolve"].call<void>("promise1", std::string("Data 1"));
+ g_testSupport["resolve"].call<void>("promise2", std::string("Data 2"));
+ }
+ QVERIFY(QTest::qWaitFor([]() { return g_Done; }));
+ QVERIFY(QTest::qWaitFor([]() { return qstdweb::Promise::State::numInstances() == 0; }));
+}
+
+void tst_QWasmPromise::allWithFinallyAndThrow()
+{
+ init();
+ QSKIP("Throw not supported");
+ {
+ auto promise1 = qstdweb::Promise(g_testSupport, "makeTestPromise", std::string("promise1"));
+ auto promise2 = qstdweb::Promise(g_testSupport, "makeTestPromise", std::string("promise2"));
+ auto promise3 = qstdweb::Promise(g_testSupport, "makeTestPromise", std::string("promise3"));
+ auto finallyCalledOnce = std::make_shared<bool>(true);
+
+ qstdweb::Promise(
+ {promise1, promise2, promise3})
+ .addThenFunction([](emscripten::val result) {
+ Q_UNUSED(result);
+ EM_ASM({
+ throw "This breaks it all!!!";
+ });
+ })
+ .addCatchFunction([](emscripten::val) { ; })
+ .addFinallyFunction([finallyCalledOnce]() {
+ QVERIFY(*finallyCalledOnce);
+ *finallyCalledOnce = false;
+ QWASMDONE();
+ });
+
+ g_testSupport["resolve"].call<void>("promise3", std::string("Data 3"));
+ g_testSupport["resolve"].call<void>("promise1", std::string("Data 1"));
+ g_testSupport["resolve"].call<void>("promise2", std::string("Data 2"));
+ }
+
+ QVERIFY(QTest::qWaitFor([]() { return g_Done; }));
+ QVERIFY(QTest::qWaitFor([]() { return qstdweb::Promise::State::numInstances() == 0; }));
+}
+
+QTEST_MAIN(tst_QWasmPromise)
+#include "tst_qwasmpromise.moc"
diff --git a/tests/manual/wasm/qstdweb/CMakeLists.txt b/tests/manual/wasm/qstdweb/CMakeLists.txt
index 8904abc94b2..46a04a6cdb3 100644
--- a/tests/manual/wasm/qstdweb/CMakeLists.txt
+++ b/tests/manual/wasm/qstdweb/CMakeLists.txt
@@ -1,28 +1,5 @@
# Copyright (C) 2024 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
-qt_internal_add_manual_test(promise_auto
- SOURCES
- promise_main.cpp
- ../qtwasmtestlib/qtwasmtestlib.cpp
- LIBRARIES
- Qt::Core
- Qt::CorePrivate
-)
-
-include_directories(../qtwasmtestlib/)
-
-add_custom_command(
- TARGET promise_auto POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy
- ${CMAKE_CURRENT_SOURCE_DIR}/promise_auto.html
- ${CMAKE_CURRENT_BINARY_DIR}/promise_auto.html)
-
-add_custom_command(
- TARGET promise_auto POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy
- ${CMAKE_CURRENT_SOURCE_DIR}/../qtwasmtestlib/qtwasmtestlib.js
- ${CMAKE_CURRENT_BINARY_DIR}/qtwasmtestlib.js)
-
qt_internal_add_manual_test(files_auto
SOURCES
files_main.cpp
diff --git a/tests/manual/wasm/qstdweb/promise_auto.html b/tests/manual/wasm/qstdweb/promise_auto.html
deleted file mode 100644
index 94a8dbb88a2..00000000000
--- a/tests/manual/wasm/qstdweb/promise_auto.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!doctype html>
-<script type="text/javascript" src="qtwasmtestlib.js"></script>
-<script type="text/javascript" src="promise_auto.js"></script>
-<script>
- window.onload = () => {
- runTestCase(promise_auto_entry, document.getElementById("log"));
- };
-</script>
-<p>Running promise auto test.</p>
-<div id="log"></div>
diff --git a/tests/manual/wasm/qstdweb/promise_main.cpp b/tests/manual/wasm/qstdweb/promise_main.cpp
deleted file mode 100644
index 395e815cf95..00000000000
--- a/tests/manual/wasm/qstdweb/promise_main.cpp
+++ /dev/null
@@ -1,488 +0,0 @@
-// 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/QDebug>
-#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();
-
- bool *thenCalled = new bool(false);
- qstdweb::Promise::make(m_testSupport, "makeTestPromise", {
- .thenFunc = [thenCalled] (val result) {
- Q_UNUSED(result);
- *thenCalled = true;
- },
- .finallyFunc = [thenCalled]() {
- QWASMVERIFY(*thenCalled);
- delete 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"