aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorValery Kotov <kotov.valery@gmail.com>2015-07-16 19:35:55 +0300
committerSimon Hausmann <simon.hausmann@qt.io>2018-10-11 08:27:48 +0000
commitf47c87e75fb94f1b322157fa663ac8b87a4dbd22 (patch)
treeccd08e635759641095544f3a9ce3d41a516f5b84
parent54fdc4de7963437642704c2bcf339979aa4f8734 (diff)
QML Engine: Support for JavaScript Promises
Support for JavaScript Promises. Change-Id: I90ce328b35f3bdf3fd666a8829f22b5d56b6f861 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
-rw-r--r--src/qml/jsruntime/jsruntime.pri6
-rw-r--r--src/qml/jsruntime/qv4engine.cpp42
-rw-r--r--src/qml/jsruntime/qv4engine_p.h14
-rw-r--r--src/qml/jsruntime/qv4global_p.h6
-rw-r--r--src/qml/jsruntime/qv4promiseobject.cpp979
-rw-r--r--src/qml/jsruntime/qv4promiseobject_p.h263
-rw-r--r--tests/auto/qml/ecmascripttests/TestExpectations146
m---------tests/auto/qml/ecmascripttests/test2620
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp1
-rw-r--r--tests/auto/qml/qml.pro1
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-all-empty-input.qml58
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-all-invoke-then-method.qml65
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-all-noniterable-input.qml59
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-all-reject-reject-is-last.qml83
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-all-reject-reject-is-mid.qml83
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-all-resolve.qml86
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-async-reject-with-value.qml72
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-async-resolve-with-value.qml72
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-executor-function-extensible.qml56
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-executor-reject.qml64
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-executor-resolve.qml67
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-executor-throw-exception.qml59
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-get-length.qml43
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-race-empty-input.qml52
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-race-resolve-1st-in-executor-function.qml62
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-race-resolve-1st.qml57
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-race-resolve-2nd.qml75
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-reject-catch.qml57
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-reject-with-value.qml55
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-resolve-function-length.qml55
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-resolve-is-a-function.qml43
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-resolve-with-array.qml55
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-resolve-with-empty.qml54
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-resolve-with-promise.qml65
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-resolve-with-value.qml55
-rw-r--r--tests/auto/qml/qqmlpromise/data/then-fulfilled-non-callable.qml93
-rw-r--r--tests/auto/qml/qqmlpromise/data/then-reject-chaining.qml63
-rw-r--r--tests/auto/qml/qqmlpromise/data/then-reject-non-callable.qml72
-rw-r--r--tests/auto/qml/qqmlpromise/data/then-resolve-chaining.qml59
-rw-r--r--tests/auto/qml/qqmlpromise/data/then-resolve-multiple-then.qml65
-rw-r--r--tests/auto/qml/qqmlpromise/qqmlpromise.pro46
-rw-r--r--tests/auto/qml/qqmlpromise/tst_qqmlpromise.cpp276
42 files changed, 3536 insertions, 148 deletions
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri
index 2a338c6792..5ec55b960b 100644
--- a/src/qml/jsruntime/jsruntime.pri
+++ b/src/qml/jsruntime/jsruntime.pri
@@ -56,7 +56,8 @@ SOURCES += \
$$PWD/qv4mapobject.cpp \
$$PWD/qv4mapiterator.cpp \
$$PWD/qv4estable.cpp \
- $$PWD/qv4module.cpp
+ $$PWD/qv4module.cpp \
+ $$PWD/qv4promiseobject.cpp
qtConfig(qml-debug): SOURCES += $$PWD/qv4profiling.cpp
@@ -126,7 +127,8 @@ HEADERS += \
$$PWD/qv4mapiterator_p.h \
$$PWD/qv4estable_p.h \
$$PWD/qv4vtable_p.h \
- $$PWD/qv4module_p.h
+ $$PWD/qv4module_p.h \
+ $$PWD/qv4promiseobject_p.h
qtConfig(qml-sequence-object) {
HEADERS += \
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 8f64c84eae..129bb20019 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -101,6 +101,7 @@
#include "qv4memberdata_p.h"
#include "qv4arraybuffer_p.h"
#include "qv4dataview_p.h"
+#include "qv4promiseobject_p.h"
#include "qv4typedarray_p.h"
#include <private/qv8engine_p.h>
#include <private/qjsvalue_p.h>
@@ -520,6 +521,14 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
jsObjects[SetProto] = memoryManager->allocate<SetPrototype>();
static_cast<SetPrototype *>(setPrototype())->init(this, setCtor());
+ //
+ // promises
+ //
+
+ jsObjects[Promise_Ctor] = memoryManager->allocate<PromiseCtor>(global);
+ jsObjects[PromiseProto] = memoryManager->allocate<PromisePrototype>();
+ static_cast<PromisePrototype *>(promisePrototype())->init(this, promiseCtor());
+
// typed arrays
jsObjects[SharedArrayBuffer_Ctor] = memoryManager->allocate<SharedArrayBufferCtor>(global);
@@ -570,6 +579,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
globalObject->defineDefaultProperty(QStringLiteral("SyntaxError"), *syntaxErrorCtor());
globalObject->defineDefaultProperty(QStringLiteral("TypeError"), *typeErrorCtor());
globalObject->defineDefaultProperty(QStringLiteral("URIError"), *uRIErrorCtor());
+ globalObject->defineDefaultProperty(QStringLiteral("Promise"), *promiseCtor());
globalObject->defineDefaultProperty(QStringLiteral("SharedArrayBuffer"), *sharedArrayBufferCtor());
globalObject->defineDefaultProperty(QStringLiteral("ArrayBuffer"), *arrayBufferCtor());
@@ -876,6 +886,38 @@ Heap::Object *ExecutionEngine::newURIErrorObject(const Value &message)
return ErrorObject::create<URIErrorObject>(this, message, uRIErrorCtor());
}
+Heap::PromiseObject *ExecutionEngine::newPromiseObject()
+{
+ if (!m_reactionHandler) {
+ m_reactionHandler.reset(new Promise::ReactionHandler);
+ }
+
+ Scope scope(this);
+ Scoped<PromiseObject> object(scope, memoryManager->allocate<PromiseObject>(this));
+ return object->d();
+}
+
+Heap::Object *ExecutionEngine::newPromiseObject(const QV4::FunctionObject *thisObject, const QV4::PromiseCapability *capability)
+{
+ if (!m_reactionHandler) {
+ m_reactionHandler.reset(new Promise::ReactionHandler);
+ }
+
+ Scope scope(this);
+ Scoped<CapabilitiesExecutorWrapper> executor(scope, memoryManager->allocate<CapabilitiesExecutorWrapper>());
+ executor->d()->capabilities.set(this, capability->d());
+ executor->insertMember(id_length(), Primitive::fromInt32(2), Attr_NotWritable|Attr_NotEnumerable);
+
+ ScopedObject object(scope, thisObject->callAsConstructor(executor, 1));
+ return object->d();
+}
+
+Promise::ReactionHandler *ExecutionEngine::getPromiseReactionHandler()
+{
+ Q_ASSERT(m_reactionHandler);
+ return m_reactionHandler.data();
+}
+
Heap::Object *ExecutionEngine::newVariantObject(const QVariant &v)
{
return memoryManager->allocate<VariantObject>(v);
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 276efe6e13..928c9f4947 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -94,6 +94,9 @@ struct Module;
struct Function;
+namespace Promise {
+class ReactionHandler;
+};
struct Q_QML_EXPORT ExecutionEngine : public EngineBase
{
@@ -158,6 +161,7 @@ public:
SyntaxErrorProto,
TypeErrorProto,
URIErrorProto,
+ PromiseProto,
VariantProto,
#if QT_CONFIG(qml_sequence_object)
SequenceProto,
@@ -197,6 +201,7 @@ public:
TypeError_Ctor,
URIError_Ctor,
SharedArrayBuffer_Ctor,
+ Promise_Ctor,
ArrayBuffer_Ctor,
DataView_Ctor,
WeakSet_Ctor,
@@ -236,6 +241,7 @@ public:
FunctionObject *typeErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + TypeError_Ctor); }
FunctionObject *uRIErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + URIError_Ctor); }
FunctionObject *sharedArrayBufferCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + SharedArrayBuffer_Ctor); }
+ FunctionObject *promiseCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Promise_Ctor); }
FunctionObject *arrayBufferCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + ArrayBuffer_Ctor); }
FunctionObject *dataViewCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + DataView_Ctor); }
FunctionObject *weakSetCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + WeakSet_Ctor); }
@@ -266,6 +272,7 @@ public:
Object *syntaxErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + SyntaxErrorProto); }
Object *typeErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + TypeErrorProto); }
Object *uRIErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + URIErrorProto); }
+ Object *promisePrototype() const { return reinterpret_cast<Object *>(jsObjects + PromiseProto); }
Object *variantPrototype() const { return reinterpret_cast<Object *>(jsObjects + VariantProto); }
#if QT_CONFIG(qml_sequence_object)
Object *sequencePrototype() const { return reinterpret_cast<Object *>(jsObjects + SequenceProto); }
@@ -523,6 +530,10 @@ public:
Heap::Object *newRangeErrorObject(const QString &message);
Heap::Object *newURIErrorObject(const Value &message);
+ Heap::PromiseObject *newPromiseObject();
+ Heap::Object *newPromiseObject(const QV4::FunctionObject *thisObject, const QV4::PromiseCapability *capability);
+ Promise::ReactionHandler *getPromiseReactionHandler();
+
Heap::Object *newVariantObject(const QVariant &v);
Heap::Object *newForInIteratorObject(Object *o);
@@ -611,6 +622,9 @@ private:
QScopedPointer<QV4::Profiling::Profiler> m_profiler;
#endif
int jitCallCountThreshold;
+
+ // used by generated Promise objects to handle 'then' events
+ QScopedPointer<QV4::Promise::ReactionHandler> m_reactionHandler;
};
// This is a trick to tell the code generators that functions taking a NoThrowContext won't
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index eab519720f..95a87820fb 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -198,6 +198,9 @@ namespace Heap {
struct MapObject;
struct SetObject;
+ struct PromiseObject;
+ struct PromiseCapability;
+
template <typename T, size_t> struct Pointer;
}
@@ -248,6 +251,9 @@ struct TypedArray;
struct MapObject;
struct SetMapObject;
+struct PromiseObject;
+struct PromiseCapability;
+
// ReturnedValue is used to return values from runtime methods
// the type has to be a primitive type (no struct or union), so that the compiler
// will return it in a register on all platforms.
diff --git a/src/qml/jsruntime/qv4promiseobject.cpp b/src/qml/jsruntime/qv4promiseobject.cpp
new file mode 100644
index 0000000000..a955e5eb6a
--- /dev/null
+++ b/src/qml/jsruntime/qv4promiseobject.cpp
@@ -0,0 +1,979 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QCoreApplication>
+
+#include <private/qv4promiseobject_p.h>
+#include <private/qv4symbol_p.h>
+#include "qv4jscall_p.h"
+
+using namespace QV4;
+using namespace QV4::Promise;
+
+DEFINE_OBJECT_VTABLE(PromiseReaction);
+DEFINE_OBJECT_VTABLE(PromiseCtor);
+DEFINE_OBJECT_VTABLE(PromiseObject);
+DEFINE_OBJECT_VTABLE(PromiseCapability);
+DEFINE_OBJECT_VTABLE(PromiseExecutionState);
+
+DEFINE_OBJECT_VTABLE(CapabilitiesExecutorWrapper);
+DEFINE_OBJECT_VTABLE(ResolveElementWrapper);
+DEFINE_OBJECT_VTABLE(ResolveWrapper);
+DEFINE_OBJECT_VTABLE(RejectWrapper);
+
+
+namespace {
+
+bool isPromise(const Value &object)
+{
+ return object.as<PromiseObject>() != nullptr;
+}
+
+bool isCallable(const Value &object)
+{
+ return object.as<FunctionObject>() != nullptr;
+}
+
+void insertIdLengthTag(Scope& scope, Heap::FunctionObject* function)
+{
+ ScopedFunctionObject scopedFunction(scope, function);
+ scopedFunction->insertMember(scope.engine->id_length(), Primitive::fromInt32(1), Attr_NotWritable|Attr_NotEnumerable);
+}
+
+void dropException(QV4::ExecutionEngine* e)
+{
+ e->hasException = false;
+}
+}
+
+QT_BEGIN_NAMESPACE
+namespace QV4 {
+namespace Promise {
+
+const int PROMISE_REACTION_EVENT = QEvent::registerEventType();
+
+struct ReactionEvent : public QEvent
+{
+ ReactionEvent(ExecutionEngine *e, const Value *reaction_, const Value *resolution_)
+ : QEvent(QEvent::Type(PROMISE_REACTION_EVENT)),
+ reaction{e, *reaction_},
+ resolution{e, *resolution_}
+ {}
+
+ QV4::PersistentValue reaction;
+ QV4::PersistentValue resolution;
+};
+
+} // namespace Promise
+} // namespace QV4
+QT_END_NAMESPACE
+
+ReactionHandler::ReactionHandler(QObject *parent)
+ : QObject(parent)
+{}
+
+ReactionHandler::~ReactionHandler()
+{}
+
+void ReactionHandler::addReaction(ExecutionEngine *e, const Value *reaction, const Value *value)
+{
+ QCoreApplication::postEvent(this, new ReactionEvent(e, reaction, value));
+}
+
+void ReactionHandler::customEvent(QEvent *event)
+{
+ if (event)
+ {
+ const int type = event->type();
+ if (type == PROMISE_REACTION_EVENT)
+ executeReaction(static_cast<ReactionEvent*>(event));
+ }
+}
+
+void ReactionHandler::executeReaction(ReactionEvent *event)
+{
+ Scope scope(event->reaction.engine());
+
+ Scoped<QV4::PromiseReaction> ro(scope, event->reaction.as<QV4::PromiseReaction>());
+ Scoped<QV4::PromiseCapability> capability(scope, ro->d()->capability);
+
+ ScopedValue resolution(scope, event->resolution.value());
+ ScopedValue promise(scope, capability->d()->promise);
+
+ if (ro->d()->type == Heap::PromiseReaction::Function) {
+ ScopedFunctionObject handler(scope, ro->d()->handler.as<QV4::FunctionObject>());
+ ScopedValue result(scope, handler->call(promise, resolution, 1));
+
+ ScopedFunctionObject reaction(scope);
+ if (scope.hasException()) {
+ reaction = capability->d()->reject.as<QV4::FunctionObject>();
+ } else {
+ reaction = capability->d()->resolve.as<QV4::FunctionObject>();
+ }
+
+ reaction->call(promise, result, 1);
+ } else {
+ ScopedFunctionObject reaction(scope);
+ if (ro->d()->type == Heap::PromiseReaction::Identity) {
+ reaction = capability->d()->resolve.as<QV4::FunctionObject>();
+ } else {
+ reaction = capability->d()->reject.as<QV4::FunctionObject>();
+ }
+
+ reaction->call(promise, resolution, 1);
+ }
+}
+
+namespace {
+
+class FunctionBuilder {
+public:
+ static Heap::FunctionObject *makeResolveFunction(ExecutionEngine* e, QV4::Heap::PromiseObject *promise) {
+ Scope scope(e);
+ Scoped<QV4::ResolveWrapper> resolveWrapper(scope, e->memoryManager->allocate<QV4::ResolveWrapper>());
+
+ insertIdLengthTag(scope, resolveWrapper->d());
+ resolveWrapper->d()->promise.set(e, promise);
+
+ return resolveWrapper->d();
+ }
+
+ static Heap::FunctionObject *makeRejectFunction(ExecutionEngine* e, QV4::Heap::PromiseObject *promise) {
+ Scope scope(e);
+ Scoped<QV4::RejectWrapper> rejectWrapper(scope, e->memoryManager->allocate<QV4::RejectWrapper>());
+
+ insertIdLengthTag(scope, rejectWrapper->d());
+ rejectWrapper->d()->promise.set(e, promise);
+
+ return rejectWrapper->d();
+ }
+
+ static Heap::FunctionObject *makeResolveElementFunction(ExecutionEngine* e, uint index, Heap::PromiseExecutionState *executionState)
+ {
+ Scope scope(e);
+ Scoped<QV4::ResolveElementWrapper> resolveElementWrapper(scope, e->memoryManager->allocate<QV4::ResolveElementWrapper>());
+
+ resolveElementWrapper->d()->index = index;
+ resolveElementWrapper->d()->alreadyResolved = false;
+ resolveElementWrapper->d()->state.set(e, executionState);
+
+ insertIdLengthTag(scope, resolveElementWrapper->d());
+
+ return resolveElementWrapper->d();
+ }
+};
+
+}
+
+void Heap::PromiseObject::setState(PromiseObject::State state)
+{
+ this->state = state;
+}
+
+bool Heap::PromiseObject::isSettled() const
+{
+ return (state != Pending);
+}
+
+bool Heap::PromiseObject::isPending() const
+{
+ return (state == Pending);
+}
+
+bool Heap::PromiseObject::isFulfilled() const
+{
+ return (state == Fulfilled);
+}
+
+bool Heap::PromiseObject::isRejected() const
+{
+ return (state == Rejected);
+}
+
+void Heap::PromiseObject::triggerFullfillReactions(ExecutionEngine *e)
+{
+ Scope scope(e);
+ ScopedArrayObject a(scope, fulfillReactions);
+ if (a->arrayData()) {
+ Scoped<QV4::ArrayData> ad(scope, a->arrayData());
+ const uint sz = ad->length();
+ ScopedValue value(scope, resolution);
+ for (uint i = 0; i < sz; i++) {
+ Scoped<QV4::PromiseReaction> r(scope, ad->get(i));
+ r->d()->triggerWithValue(scope.engine, value);
+ }
+ }
+}
+
+void Heap::PromiseObject::triggerRejectReactions(ExecutionEngine *e)
+{
+ Scope scope(e);
+ ScopedArrayObject a(scope, rejectReactions);
+ if (a->arrayData()) {
+ Scoped<QV4::ArrayData> ad(scope, a->arrayData());
+ const uint sz = ad->d()->length();
+ ScopedValue value(scope, resolution);
+ for (uint i = 0; i < sz; i++) {
+ Scoped<QV4::PromiseReaction> r(scope, ad->d()->get(i));
+ r->d()->triggerWithValue(scope.engine, value);
+ }
+ }
+}
+
+Heap::PromiseReaction *Heap::PromiseReaction::createFulfillReaction(ExecutionEngine* e,
+ const QV4::PromiseCapability *capability, const QV4::FunctionObject *onFulfilled)
+{
+ Scope scope(e);
+ Scoped<QV4::PromiseReaction> fulfillReaction(scope, e->memoryManager->allocate<QV4::PromiseReaction>());
+ fulfillReaction->d()->capability.set(e, capability->d());
+
+ if (onFulfilled) {
+ QV4::ScopedFunctionObject scopedFullfillReaction(scope, onFulfilled);
+ if (!scopedFullfillReaction) {
+ fulfillReaction->d()->type = PromiseReaction::Identity;
+ } else {
+ fulfillReaction->d()->type = PromiseReaction::Function;
+ fulfillReaction->d()->handler.set(e, scopedFullfillReaction);
+ }
+ } else {
+ fulfillReaction->d()->type = PromiseReaction::Identity;
+ }
+
+ return fulfillReaction->d();
+}
+
+Heap::PromiseReaction *Heap::PromiseReaction::createRejectReaction(ExecutionEngine* e,
+ const QV4::PromiseCapability *capability, const QV4::FunctionObject *onRejected)
+{
+ Scope scope(e);
+ Scoped<QV4::PromiseReaction> rejectReaction(scope, e->memoryManager->allocate<QV4::PromiseReaction>());
+ rejectReaction->d()->capability.set(e, capability->d());
+
+ if (onRejected) {
+ ScopedFunctionObject scopedRejectReaction(scope, onRejected);
+ if (!scopedRejectReaction) {
+ rejectReaction->d()->type = PromiseReaction::Thrower;
+ } else {
+ rejectReaction->d()->type = PromiseReaction::Function;
+ rejectReaction->d()->handler.set(e, scopedRejectReaction);
+ }
+ } else {
+ rejectReaction->d()->type = PromiseReaction::Thrower;
+ }
+
+ return rejectReaction->d();
+}
+
+void Heap::PromiseReaction::triggerWithValue(ExecutionEngine *e, const Value *value)
+{
+ Scope scope(e);
+ auto handler = e->getPromiseReactionHandler();
+ ScopedValue reaction(scope, Value::fromHeapObject(this));
+ handler->addReaction(e, reaction, value);
+}
+
+void Heap::PromiseCtor::init(QV4::ExecutionContext *scope)
+{
+ Heap::FunctionObject::init(scope, QStringLiteral("Promise"));
+}
+
+void Heap::PromiseObject::init(ExecutionEngine *e)
+{
+ Heap::Object::init();
+
+ {
+ Heap::ArrayObject* a = e->newArrayObject();
+ fulfillReactions.set(e, a);
+ }
+
+ {
+ Heap::ArrayObject* a = e->newArrayObject();
+ rejectReactions.set(e, a);
+ }
+}
+
+void Heap::CapabilitiesExecutorWrapper::init()
+{
+ Heap::FunctionObject::init();
+}
+
+void Heap::CapabilitiesExecutorWrapper::destroy()
+{
+ Heap::FunctionObject::destroy();
+}
+
+void Heap::PromiseExecutionState::init()
+{
+ index = 0;
+ remainingElementCount = 0;
+}
+
+void Heap::ResolveElementWrapper::init()
+{
+ index = 0;
+ alreadyResolved = false;
+
+ Heap::FunctionObject::init();
+}
+
+void Heap::ResolveWrapper::init()
+{
+ alreadyResolved = false;
+ Heap::FunctionObject::init();
+}
+
+void Heap::RejectWrapper::init()
+{
+ alreadyResolved = false;
+ Heap::FunctionObject::init();
+}
+
+
+ReturnedValue PromiseCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *)
+{
+ Scope scope(f);
+
+ if (argc != 1)
+ THROW_TYPE_ERROR();
+
+ ScopedFunctionObject executor(scope, argv[0].as<const FunctionObject>());
+ if (!executor)
+ THROW_TYPE_ERROR();
+
+ Scoped<PromiseObject> a(scope, scope.engine->newPromiseObject());
+ if (scope.engine->hasException)
+ return Encode::undefined();
+
+ a->d()->state = Heap::PromiseObject::Pending;
+
+ ScopedFunctionObject resolve(scope, FunctionBuilder::makeResolveFunction(scope.engine, a->d()));
+ ScopedFunctionObject reject(scope, FunctionBuilder::makeRejectFunction(scope.engine, a->d()));
+
+ JSCallData jsCallData(scope, 2);
+ jsCallData->args[0] = resolve;
+ jsCallData->args[1] = reject;
+ jsCallData->thisObject = a;
+
+ executor->call(jsCallData);
+
+ if (scope.engine->hasException) {
+ a->d()->state = Heap::PromiseObject::Rejected;
+ a->d()->resolution.set(scope.engine, Value::fromReturnedValue(scope.engine->catchException()));
+ }
+
+ return a->asReturnedValue();
+}
+
+ReturnedValue PromiseCtor::virtualCall(const FunctionObject *f, const Value *, const Value *, int)
+{
+ Scope scope(f);
+ THROW_TYPE_ERROR();
+}
+
+ReturnedValue PromiseCtor::method_resolve(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ Scope scope(f);
+ ExecutionEngine* e = scope.engine;
+ if (!thisObject || !thisObject->isObject())
+ THROW_TYPE_ERROR();
+
+ ScopedValue argument(scope);
+ if (argc < 1) {
+ argument = Encode::undefined();
+ } else {
+ argument = argv[0];
+ }
+
+ if (isPromise(argument) && argument->isObject()) {
+ ScopedObject so(scope, thisObject);
+ ScopedObject constructor(scope, argument->objectValue()->get(e->id_constructor()));
+ if (so->d() == constructor->d())
+ return argument->asReturnedValue();
+ }
+
+ Scoped<PromiseCapability> capability(scope, e->memoryManager->allocate<QV4::PromiseCapability>());
+
+ ScopedObject newPromise(scope, e->newPromiseObject(thisObject->as<const FunctionObject>(), capability));
+ if (!newPromise || !isCallable(capability->d()->resolve) || !isCallable(capability->d()->reject))
+ THROW_TYPE_ERROR();
+
+ ScopedValue undefined(scope, Value::undefinedValue());
+ ScopedFunctionObject resolve(scope, capability->d()->resolve);
+ resolve->call(undefined, argument, 1);
+
+ return newPromise.asReturnedValue();
+}
+
+ReturnedValue PromiseCtor::method_reject(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ Scope scope(f);
+ ExecutionEngine *e = scope.engine;
+
+ if (!thisObject || !thisObject->isObject())
+ THROW_TYPE_ERROR();
+
+ ScopedValue argument(scope);
+ if (argc < 1) {
+ argument = Encode::undefined();
+ } else {
+ argument = argv[0];
+ }
+
+ Scoped<PromiseCapability> capability(scope, e->memoryManager->allocate<QV4::PromiseCapability>());
+
+ ScopedObject newPromise(scope, e->newPromiseObject(thisObject->as<const FunctionObject>(), capability));
+ if (!newPromise || !isCallable(capability->d()->resolve) || !isCallable(capability->d()->reject))
+ THROW_TYPE_ERROR();
+
+ ScopedValue undefined(scope, Value::undefinedValue());
+ ScopedFunctionObject reject(scope, capability->d()->reject.as<const FunctionObject>());
+ reject->call(undefined, argument, 1);
+
+ return newPromise.asReturnedValue();
+}
+
+ReturnedValue PromiseCtor::method_all(const FunctionObject *f, const Value *thisObject, const Value *argv, int)
+{
+ Scope scope(f);
+ ExecutionEngine* e = scope.engine;
+
+ if (!thisObject || !thisObject->isObject())
+ THROW_TYPE_ERROR();
+
+ ScopedString resolveName(scope, e->newIdentifier(QStringLiteral("resolve")));
+ ScopedString thenName(scope, e->newIdentifier(QStringLiteral("then")));
+
+ Scoped<PromiseCapability> capability(scope, e->memoryManager->allocate<QV4::PromiseCapability>());
+
+ ScopedObject newPromise(scope, e->newPromiseObject(thisObject->as<FunctionObject>(), capability));
+ if (!newPromise || !isCallable(capability->d()->resolve) || !isCallable(capability->d()->reject)) {
+ if (scope.hasException()) {
+ return e->exceptionValue->asReturnedValue();
+ } else {
+ THROW_TYPE_ERROR();
+ }
+ }
+ capability->d()->promise.set(e, newPromise);
+
+ ScopedFunctionObject reject(scope, capability->d()->reject);
+
+ ScopedObject itemsObject(scope, argv);
+ ScopedObject iteratorObject(scope, Runtime::method_getIterator(e, itemsObject, true));
+ if (!iteratorObject || scope.hasException()) {
+ ScopedObject error(scope);
+ if (scope.hasException()) {
+ error = e->exceptionValue;
+ dropException(e);
+ } else {
+ error = e->newTypeErrorObject(QStringLiteral("Type error"));
+ }
+ reject->call(newPromise, error, 1);
+ return newPromise.asReturnedValue();
+ }
+
+ Scoped<QV4::PromiseExecutionState> executionState(scope, e->memoryManager->allocate<QV4::PromiseExecutionState>());
+ executionState->d()->remainingElementCount = 1;
+ executionState->d()->capability.set(e, capability);
+
+ Scoped<QV4::ArrayObject> results(scope, e->newArrayObject(0));
+ executionState->d()->values.set(e, results);
+
+ ScopedValue doneValue(scope);
+ uint index = 0;
+ for (;;) {
+ Scope scope(e);
+ ScopedValue nextValue(scope);
+ doneValue = Value::fromReturnedValue(Runtime::method_iteratorNext(e, iteratorObject, nextValue));
+
+ if (doneValue->toBoolean())
+ break;
+
+ ScopedObject nextObject(scope);
+ if (nextValue->isObject()) {
+ nextObject = *nextValue;
+ } else if (nextValue->isBoolean()) {
+ nextObject = e->newBooleanObject(nextValue->toBoolean());
+ } else if (nextValue->isInteger() || nextValue->isDouble()) {
+ nextObject = e->newNumberObject(nextValue->toInteger());
+ } else if (nextValue->isString()) {
+ ScopedString scopedString(scope, nextValue->toString(scope.engine));
+ nextObject = e->newStringObject(scopedString);
+ }
+
+ ScopedFunctionObject resolve(scope, thisObject->as<Object>()->get(resolveName));
+ if (!resolve || scope.hasException()) {
+ ScopedValue completion(scope);
+ if (!scope.hasException()) {
+ completion = e->newTypeErrorObject(QStringLiteral("Type error"));
+ } else {
+ completion = e->exceptionValue->asReturnedValue();
+ dropException(e);
+ }
+
+ if (!doneValue->toBoolean())
+ completion = Runtime::method_iteratorClose(e, iteratorObject, doneValue);
+
+ reject->call(newPromise, completion, 1);
+ return newPromise.asReturnedValue();
+ }
+
+ ScopedObject nextPromise(scope, Value::fromReturnedValue(resolve->call(thisObject, nextValue, 1)));
+ if (!nextPromise || scope.hasException()) {
+ ScopedValue completion(scope, Runtime::method_iteratorClose(e, iteratorObject, doneValue));
+ if (scope.hasException()) {
+ completion = e->exceptionValue->asReturnedValue();
+ dropException(e);
+ }
+ reject->call(newPromise, completion, 1);
+ return newPromise.asReturnedValue();
+ }
+
+ executionState->d()->remainingElementCount++;
+
+ ScopedFunctionObject then(scope, nextPromise->get(thenName));
+ if (!then || scope.hasException()) {
+ ScopedValue completion(scope);
+ if (!scope.hasException()) {
+ completion = e->newTypeErrorObject(QStringLiteral("Type error"));
+ } else {
+ completion = e->exceptionValue->asReturnedValue();
+ dropException(e);
+ }
+
+ if (!doneValue->toBoolean())
+ completion = Runtime::method_iteratorClose(scope.engine, iteratorObject, doneValue);
+
+ reject->call(newPromise, completion, 1);
+ return newPromise.asReturnedValue();
+ }
+
+ ScopedFunctionObject resolveElement(scope, FunctionBuilder::makeResolveElementFunction(e, index, executionState->d()));
+
+ JSCallData jsCallData(scope, 2);
+ jsCallData->args[0] = resolveElement;
+ jsCallData->args[1] = reject;
+ jsCallData->thisObject = nextPromise;
+
+ then->call(jsCallData);
+ if (scope.hasException()) {
+ ScopedValue completion(scope, e->exceptionValue->asReturnedValue());
+ dropException(e);
+
+ if (!doneValue->toBoolean())
+ completion = Runtime::method_iteratorClose(scope.engine, iteratorObject, doneValue);
+
+ reject->call(newPromise, completion, 1);
+ return newPromise.asReturnedValue();
+ }
+
+ index++;
+ }
+
+ // empty list
+ executionState->d()->remainingElementCount--;
+ if (executionState->d()->remainingElementCount == 0) {
+ const FunctionObject *resolve = capability->d()->resolve.as<FunctionObject>();
+ if (!resolve)
+ THROW_TYPE_ERROR();
+
+ ScopedValue values(scope, executionState->d()->values);
+ resolve->call(newPromise, values, 1);
+ if (scope.hasException()) {
+ dropException(e);
+ reject->call(newPromise, scope.engine->exceptionValue, 1);
+ }
+ }
+
+ return newPromise.asReturnedValue();
+}
+
+ReturnedValue PromiseCtor::method_race(const FunctionObject *f, const Value *thisObject, const Value *argv, int)
+{
+ Scope scope(f);
+ ExecutionEngine* e = scope.engine;
+
+ if (!thisObject || !thisObject->isObject())
+ THROW_TYPE_ERROR();
+
+ ScopedString resolveName(scope, e->newIdentifier(QStringLiteral("resolve")));
+ ScopedString thenName(scope, e->newIdentifier(QStringLiteral("then")));
+
+ Scoped<PromiseCapability> capability(scope, scope.engine->memoryManager->allocate<QV4::PromiseCapability>());
+
+ ScopedObject newPromise(scope, e->newPromiseObject(thisObject->as<FunctionObject>(), capability));
+ if (!newPromise || !isCallable(capability->d()->resolve) || !isCallable(capability->d()->reject))
+ THROW_TYPE_ERROR();
+ capability->d()->promise.set(scope.engine, newPromise);
+
+ ScopedFunctionObject reject(scope, capability->d()->reject);
+
+ ScopedObject itemsObject(scope, argv);
+ ScopedObject iteratorObject(scope, Runtime::method_getIterator(e, itemsObject, true));
+ if (!iteratorObject) {
+ ScopedObject error(scope, e->newTypeErrorObject(QStringLiteral("Type error")));
+ reject->call(newPromise, error, 1);
+ return newPromise.asReturnedValue();
+ }
+
+ ScopedValue doneValue(scope);
+ for (;;) {
+ Scope scope(e);
+ ScopedValue nextValue(scope);
+ doneValue = Value::fromReturnedValue(Runtime::method_iteratorNext(e, iteratorObject, nextValue));
+
+ if (scope.hasException()) {
+ ScopedValue completion(scope, Runtime::method_iteratorClose(e, iteratorObject, doneValue));
+ if (scope.hasException()) {
+ completion = e->exceptionValue->asReturnedValue();
+ dropException(e);
+ }
+ reject->call(newPromise, completion, 1);
+ return newPromise.asReturnedValue();
+ }
+
+ if (doneValue->toBoolean())
+ break;
+
+ ScopedObject nextObject(scope);
+ if (nextValue->isObject()) {
+ nextObject = *nextValue;
+ } else if (nextValue->isBoolean()) {
+ nextObject = scope.engine->newBooleanObject(nextValue->toBoolean());
+ } else if (nextValue->isInteger() || nextValue->isDouble()) {
+ nextObject = scope.engine->newNumberObject(nextValue->toInteger());
+ } else if (nextValue->isString()) {
+ ScopedString scopedString(scope, nextValue->toString(scope.engine));
+ nextObject = scope.engine->newStringObject(scopedString);
+ }
+
+ ScopedFunctionObject resolve(scope, thisObject->as<FunctionObject>()->get(resolveName));
+ if (!resolve || scope.hasException()) {
+ ScopedValue completion(scope);
+ if (!scope.hasException()) {
+ completion = e->newTypeErrorObject(QStringLiteral("Type error"));
+ } else {
+ completion = e->exceptionValue->asReturnedValue();
+ dropException(e);
+ }
+
+ if (!doneValue->toBoolean())
+ completion = Runtime::method_iteratorClose(e, iteratorObject, doneValue);
+
+ reject->call(newPromise, completion, 1);
+ return newPromise.asReturnedValue();
+ }
+
+ ScopedObject nextPromise(scope, Value::fromReturnedValue(resolve->call(thisObject, nextValue, 1)));
+ if (!nextPromise || scope.hasException()) {
+ ScopedValue completion(scope, Runtime::method_iteratorClose(e, iteratorObject, doneValue));
+ if (scope.hasException()) {
+ completion = e->exceptionValue->asReturnedValue();
+ dropException(e);
+ }
+ reject->call(newPromise, completion, 1);
+ return newPromise.asReturnedValue();
+ }
+
+ ScopedFunctionObject then(scope, nextPromise->get(thenName));
+ if (!then || scope.hasException()) {
+ ScopedValue completion(scope);
+ if (!scope.hasException()) {
+ completion = e->newTypeErrorObject(QStringLiteral("Type error"));
+ } else {
+ completion = e->exceptionValue->asReturnedValue();
+ dropException(e);
+ }
+
+ if (!doneValue->toBoolean())
+ completion = Runtime::method_iteratorClose(e, iteratorObject, doneValue);
+
+ reject->call(newPromise, completion, 1);
+ return newPromise.asReturnedValue();
+ }
+
+ ScopedFunctionObject resolveOriginalPromise(scope, capability->d()->resolve);
+
+ JSCallData jsCallData(scope, 2);
+ jsCallData->args[0] = resolveOriginalPromise;
+ jsCallData->args[1] = reject;
+ jsCallData->thisObject = nextPromise;
+
+ then->call(jsCallData);
+ if (scope.hasException()) {
+ ScopedValue completion(scope, e->exceptionValue->asReturnedValue());
+ dropException(e);
+
+ if (!doneValue->toBoolean())
+ completion = Runtime::method_iteratorClose(e, iteratorObject, doneValue);
+
+ reject->call(newPromise, completion, 1);
+ return newPromise.asReturnedValue();
+ }
+ }
+
+ return newPromise.asReturnedValue();
+}
+
+void PromisePrototype::init(ExecutionEngine *engine, Object *ctor)
+{
+ Scope scope(engine);
+ ScopedObject o(scope);
+
+ ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(1));
+ ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
+
+ ctor->defineDefaultProperty(QStringLiteral("resolve"), PromiseCtor::method_resolve, 1);
+ ctor->defineDefaultProperty(QStringLiteral("reject"), PromiseCtor::method_reject, 1);
+ ctor->defineDefaultProperty(QStringLiteral("all"), PromiseCtor::method_all, 1);
+ ctor->defineDefaultProperty(QStringLiteral("race"), PromiseCtor::method_race, 1);
+ ctor->addSymbolSpecies();
+
+ defineDefaultProperty(engine->id_constructor(), (o = ctor));
+
+ ScopedString val(scope, engine->newString(QLatin1String("Promise")));
+ defineReadonlyConfigurableProperty(engine->symbol_toStringTag(), val);
+
+ defineDefaultProperty(QStringLiteral("then"), method_then, 2);
+ defineDefaultProperty(QStringLiteral("catch"), method_catch, 1);
+}
+
+ReturnedValue PromisePrototype::method_then(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ Scope scope(f);
+ ExecutionEngine* e = scope.engine;
+
+ Scoped<QV4::PromiseObject> promise(scope, thisObject);
+ if (!promise)
+ THROW_TYPE_ERROR();
+
+ ScopedFunctionObject onFulfilled(scope);
+ if (argc >= 1) {
+ onFulfilled = argv[0];
+ } else {
+ onFulfilled = Encode::undefined();
+ }
+
+ ScopedFunctionObject onRejected(scope);
+ if (argc >= 2) {
+ onRejected = argv[1];
+ } else {
+ onRejected = Encode::undefined();
+ }
+
+ Scoped<PromiseCapability> capability(scope, e->memoryManager->allocate<PromiseCapability>());
+
+ ScopedFunctionObject constructor(scope, promise->get(e->id_constructor()));
+ if (!constructor || scope.hasException())
+ THROW_TYPE_ERROR();
+
+ ScopedObject nextPromise(scope, e->newPromiseObject(constructor, capability));
+ capability->d()->promise.set(scope.engine, nextPromise);
+
+ Scoped<PromiseReaction> fulfillReaction(scope, Heap::PromiseReaction::createFulfillReaction(scope.engine, capability, onFulfilled));
+ Scoped<PromiseReaction> rejectReaction(scope, Heap::PromiseReaction::createRejectReaction(scope.engine, capability, onRejected));
+
+ ScopedValue resolution(scope, promise->d()->resolution);
+ if (promise->d()->isPending()) {
+ {
+ ScopedArrayObject a(scope, promise->d()->fulfillReactions);
+ ScopedValue newValue(scope, fulfillReaction->d());
+ a->push_back(newValue);
+ }
+
+ {
+ ScopedArrayObject a(scope, promise->d()->rejectReactions);
+ ScopedValue newValue(scope, rejectReaction->d());
+ a->push_back(newValue);
+ }
+ } else if (promise->d()->isFulfilled()) {
+ fulfillReaction->as<QV4::PromiseReaction>()->d()->triggerWithValue(e, resolution);
+ } else if (promise->d()->isRejected()) {
+ rejectReaction->as<QV4::PromiseReaction>()->d()->triggerWithValue(e, resolution);
+ } else {
+ Q_ASSERT(false);
+ THROW_GENERIC_ERROR("Should never be thrown. Unknown promise state");
+ }
+
+ return nextPromise->asReturnedValue();
+}
+
+ReturnedValue PromisePrototype::method_catch(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ Scope scope(f);
+ Scoped<Object> promise(scope);
+ if (thisObject->isObject()) {
+ promise.setPointer(thisObject->as<Object>());
+ } else if (thisObject->isBoolean()) {
+ promise = scope.engine->newBooleanObject(thisObject->toBoolean());
+ } else if (thisObject->isInteger() || thisObject->isDouble()) {
+ promise = scope.engine->newNumberObject(thisObject->toInteger());
+ } else if (thisObject->isString()) {
+ ScopedString scopedString(scope, thisObject->toString(scope.engine));
+ promise = scope.engine->newStringObject(scopedString);
+ } else {
+ THROW_TYPE_ERROR();
+ }
+
+ ScopedValue onRejected(scope);
+ if (argc < 1) {
+ onRejected = Encode::undefined();
+ } else {
+ onRejected = argv[0];
+ }
+
+ JSCallData jsCallData(scope, 2);
+ jsCallData->args[0] = Encode::undefined();
+ jsCallData->args[1] = onRejected;
+ jsCallData->thisObject = promise;
+
+ ScopedString thenName(scope, scope.engine->newIdentifier(QStringLiteral("then")));
+ ScopedFunctionObject then(scope, promise->get(thenName));
+ if (!then || scope.hasException())
+ THROW_TYPE_ERROR();
+
+ return then->call(jsCallData);
+}
+
+ReturnedValue CapabilitiesExecutorWrapper::virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ Q_UNUSED(thisObject);
+
+ Scope scope(f);
+ const CapabilitiesExecutorWrapper* self = static_cast<const CapabilitiesExecutorWrapper*>(f);
+ Heap::PromiseCapability *capabilities = self->d()->capabilities;
+
+ if (!capabilities->resolve.isUndefined() || !capabilities->reject.isUndefined())
+ THROW_TYPE_ERROR();
+
+ if (argc >= 1 && !argv[0].isUndefined())
+ capabilities->resolve.set(scope.engine, argv[0]);
+
+ if (argc >= 2 && !argv[1].isUndefined())
+ capabilities->reject.set(scope.engine, argv[1]);
+
+ // TODO: return?
+ return Encode::undefined();
+}
+
+ReturnedValue ResolveElementWrapper::virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ Q_UNUSED(thisObject);
+
+ Scope scope(f);
+ const ResolveElementWrapper* self = static_cast<const ResolveElementWrapper*>(f);
+
+ if (self->d()->alreadyResolved)
+ return Encode::undefined();
+
+ ScopedValue value(scope);
+ if (argc == 1) {
+ value = argv[0];
+ } else {
+ value = Encode::undefined();
+ }
+
+ Scoped<PromiseExecutionState> so(scope, self->d()->state);
+ self->d()->alreadyResolved = true;
+
+ ScopedObject values(scope, so->d()->values);
+ values->arraySet(self->d()->index, value);
+
+ so->d()->remainingElementCount--;
+ if (so->d()->remainingElementCount == 0) {
+ Scoped<PromiseCapability> capability(scope, so->d()->capability);
+ ScopedValue promise(scope, capability->d()->promise);
+ ScopedFunctionObject resolve(scope, capability->d()->resolve.as<QV4::FunctionObject>());
+ resolve->call(promise, values, 1);
+ }
+
+ return Encode::undefined();
+}
+
+ReturnedValue ResolveWrapper::virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ Q_UNUSED(thisObject);
+
+ Scope scope(f);
+ const ResolveWrapper *self = static_cast<const ResolveWrapper*>(f);
+
+ Scoped<PromiseObject> promise(scope, self->d()->promise);
+ if (self->d()->alreadyResolved || !promise->d()->isPending())
+ return Encode::undefined();
+
+ ScopedValue value(scope);
+ if (argc == 1) {
+ value = argv[0];
+ } else {
+ value = Encode::undefined();
+ }
+
+ self->d()->alreadyResolved = true;
+ promise->d()->setState(Heap::PromiseObject::Fulfilled);
+ promise->d()->resolution.set(scope.engine, value);
+
+ promise->d()->triggerFullfillReactions(scope.engine);
+
+ return Encode::undefined();
+}
+
+ReturnedValue RejectWrapper::virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ Q_UNUSED(thisObject);
+
+ Scope scope(f);
+ const RejectWrapper *self = static_cast<const RejectWrapper*>(f);
+
+ Scoped<PromiseObject> promise(scope, self->d()->promise);
+ if (self->d()->alreadyResolved || !promise->d()->isPending())
+ return Encode::undefined();
+
+ ScopedValue value(scope);
+ if (argc == 1) {
+ value = argv[0];
+ } else {
+ value = Encode::undefined();
+ }
+
+ self->d()->alreadyResolved = true;
+ promise->d()->setState(Heap::PromiseObject::Rejected);
+ promise->d()->resolution.set(scope.engine, value);
+
+ promise->d()->triggerRejectReactions(scope.engine);
+
+ return Encode::undefined();
+}
diff --git a/src/qml/jsruntime/qv4promiseobject_p.h b/src/qml/jsruntime/qv4promiseobject_p.h
new file mode 100644
index 0000000000..80f7183074
--- /dev/null
+++ b/src/qml/jsruntime/qv4promiseobject_p.h
@@ -0,0 +1,263 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4PROMISEOBJECT_H
+#define QV4PROMISEOBJECT_H
+
+#include "qv4object_p.h"
+#include "qv4functionobject_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct PromiseCapability;
+
+namespace Promise {
+
+struct ReactionEvent;
+
+class ReactionHandler : public QObject
+{
+ Q_OBJECT
+
+public:
+ ReactionHandler(QObject *parent = nullptr);
+ virtual ~ReactionHandler();
+
+ void addReaction(ExecutionEngine *e, const Value *reaction, const Value *value);
+
+protected:
+ void customEvent(QEvent *event);
+ void executeReaction(ReactionEvent *event);
+};
+
+} // Promise
+
+namespace Heap {
+
+struct PromiseCtor : FunctionObject {
+ void init(QV4::ExecutionContext *scope);
+};
+
+#define PromiseObjectMembers(class, Member) \
+ Member(class, HeapValue, HeapValue, resolution) \
+ Member(class, HeapValue, HeapValue, fulfillReactions) \
+ Member(class, HeapValue, HeapValue, rejectReactions)
+
+DECLARE_HEAP_OBJECT(PromiseObject, Object) {
+ DECLARE_MARKOBJECTS(PromiseObject)
+ void init(ExecutionEngine *e);
+
+ enum State {
+ Pending,
+ Fulfilled,
+ Rejected
+ };
+
+ void setState(State);
+ bool isSettled() const;
+ bool isPending() const;
+ bool isFulfilled() const;
+ bool isRejected() const;
+
+ State state;
+
+ void triggerFullfillReactions(ExecutionEngine *e);
+ void triggerRejectReactions(ExecutionEngine *e);
+};
+
+#define PromiseCapabilityMembers(class, Member) \
+ Member(class, HeapValue, HeapValue, promise) \
+ Member(class, HeapValue, HeapValue, resolve) \
+ Member(class, HeapValue, HeapValue, reject)
+
+DECLARE_HEAP_OBJECT(PromiseCapability, Object) {
+ DECLARE_MARKOBJECTS(PromiseCapability)
+};
+
+#define PromiseReactionMembers(class, Member) \
+ Member(class, HeapValue, HeapValue, handler) \
+ Member(class, Pointer, PromiseCapability*, capability)
+
+DECLARE_HEAP_OBJECT(PromiseReaction, Object) {
+ DECLARE_MARKOBJECTS(PromiseReaction)
+
+ static Heap::PromiseReaction *createFulfillReaction(ExecutionEngine* e, const QV4::PromiseCapability *capability, const QV4::FunctionObject *onFulfilled);
+ static Heap::PromiseReaction *createRejectReaction(ExecutionEngine* e, const QV4::PromiseCapability *capability, const QV4::FunctionObject *onRejected);
+
+ void triggerWithValue(ExecutionEngine *e, const Value *value);
+
+ enum Type {
+ Function,
+ Identity,
+ Thrower
+ };
+
+ Type type;
+
+ friend class ReactionHandler;
+};
+
+#define CapabilitiesExecutorWrapperMembers(class, Member) \
+ Member(class, Pointer, PromiseCapability*, capabilities)
+
+DECLARE_HEAP_OBJECT(CapabilitiesExecutorWrapper, FunctionObject) {
+ DECLARE_MARKOBJECTS(CapabilitiesExecutorWrapper)
+ void init();
+ void destroy();
+};
+
+#define PromiseExecutionStateMembers(class, Member) \
+ Member(class, HeapValue, HeapValue, values) \
+ Member(class, HeapValue, HeapValue, capability)
+
+DECLARE_HEAP_OBJECT(PromiseExecutionState, FunctionObject) {
+ DECLARE_MARKOBJECTS(PromiseExecutionState)
+ void init();
+
+ uint index;
+ uint remainingElementCount;
+};
+
+#define ResolveElementWrapperMembers(class, Member) \
+ Member(class, HeapValue, HeapValue, state)
+
+DECLARE_HEAP_OBJECT(ResolveElementWrapper, FunctionObject) {
+ DECLARE_MARKOBJECTS(ResolveElementWrapper)
+ void init();
+
+ uint index;
+ bool alreadyResolved;
+};
+
+#define ResolveWrapperMembers(class, Member) \
+ Member(class, Pointer, PromiseObject*, promise)
+
+DECLARE_HEAP_OBJECT(ResolveWrapper, FunctionObject) {
+ DECLARE_MARKOBJECTS(ResolveWrapper)
+ void init();
+
+ bool alreadyResolved;
+};
+
+#define RejectWrapperMembers(class, Member) \
+ Member(class, Pointer, PromiseObject*, promise)
+
+DECLARE_HEAP_OBJECT(RejectWrapper, FunctionObject) {
+ DECLARE_MARKOBJECTS(RejectWrapper)
+ void init();
+
+ bool alreadyResolved;
+};
+
+} // Heap
+
+struct PromiseReaction : Object
+{
+ V4_OBJECT2(PromiseReaction, Object)
+};
+
+struct PromiseCapability : Object
+{
+ V4_OBJECT2(PromiseCapability, Object)
+};
+
+struct PromiseExecutionState : Object
+{
+ V4_OBJECT2(PromiseExecutionState, Object)
+};
+
+struct Q_QML_PRIVATE_EXPORT PromiseObject : Object
+{
+ V4_OBJECT2(PromiseObject, Object)
+ V4_NEEDS_DESTROY
+ V4_PROTOTYPE(promisePrototype)
+};
+
+struct PromiseCtor: FunctionObject
+{
+ V4_OBJECT2(PromiseCtor, FunctionObject)
+
+ static ReturnedValue virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *);
+ static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+
+ static ReturnedValue method_resolve(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_reject(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+
+ static ReturnedValue method_all(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_race(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+};
+
+struct PromisePrototype : Object
+{
+ void init(ExecutionEngine *engine, Object *ctor);
+
+ static ReturnedValue method_then(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_catch(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+};
+
+struct CapabilitiesExecutorWrapper: FunctionObject {
+ V4_OBJECT2(CapabilitiesExecutorWrapper, FunctionObject)
+
+ static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+};
+
+struct ResolveElementWrapper : FunctionObject {
+ V4_OBJECT2(ResolveElementWrapper, FunctionObject)
+
+ static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+};
+
+struct ResolveWrapper : FunctionObject {
+ V4_OBJECT2(ResolveWrapper, FunctionObject)
+
+ static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+};
+
+struct RejectWrapper : FunctionObject {
+ V4_OBJECT2(RejectWrapper, FunctionObject)
+
+ static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+};
+
+} // QV4
+
+QT_END_NAMESPACE
+
+#endif // QV4PROMISEOBJECT_H
diff --git a/tests/auto/qml/ecmascripttests/TestExpectations b/tests/auto/qml/ecmascripttests/TestExpectations
index f5a31856b1..1613888e77 100644
--- a/tests/auto/qml/ecmascripttests/TestExpectations
+++ b/tests/auto/qml/ecmascripttests/TestExpectations
@@ -154,7 +154,6 @@ built-ins/Function/prototype/toString/async-method-class-expression.js fails
built-ins/Function/prototype/toString/async-method-class-statement-static.js fails
built-ins/Function/prototype/toString/async-method-class-statement.js fails
built-ins/Function/prototype/toString/async-method-object.js fails
-built-ins/Function/prototype/toString/intrinsics.js fails
built-ins/Function/prototype/toString/method-computed-property-name.js fails
built-ins/JSON/parse/revived-proxy-revoked.js fails
built-ins/JSON/parse/revived-proxy.js fails
@@ -178,156 +177,14 @@ built-ins/Object/prototype/toString/proxy-function.js fails
built-ins/Object/prototype/valueOf/S15.2.4.4_A14.js fails
built-ins/Object/values/getter-adding-key.js fails
built-ins/Object/values/observable-operations.js fails
-built-ins/Promise/S25.4.3.1_A1.1_T1.js fails
-built-ins/Promise/S25.4.3.1_A2.1_T1.js fails
-built-ins/Promise/S25.4.3.1_A2.2_T1.js fails
-built-ins/Promise/S25.4.3.1_A3.1_T1.js fails
-built-ins/Promise/Symbol.species/length.js fails
-built-ins/Promise/Symbol.species/prop-desc.js fails
-built-ins/Promise/Symbol.species/return-value.js fails
-built-ins/Promise/Symbol.species/symbol-species-name.js fails
-built-ins/Promise/Symbol.species/symbol-species.js fails
-built-ins/Promise/all/S25.4.4.1_A1.1_T1.js fails
-built-ins/Promise/all/S25.4.4.1_A2.1_T1.js fails
-built-ins/Promise/all/S25.4.4.1_A4.1_T1.js fails
-built-ins/Promise/all/S25.4.4.1_A6.1_T1.js fails
-built-ins/Promise/all/call-resolve-element-after-return.js fails
-built-ins/Promise/all/call-resolve-element-items.js fails
-built-ins/Promise/all/call-resolve-element.js fails
-built-ins/Promise/all/capability-executor-called-twice.js fails
-built-ins/Promise/all/capability-executor-not-callable.js fails
-built-ins/Promise/all/capability-resolve-throws-no-close.js fails
-built-ins/Promise/all/ctx-ctor-throws.js fails
built-ins/Promise/all/ctx-ctor.js fails
-built-ins/Promise/all/ctx-non-ctor.js fails
-built-ins/Promise/all/ctx-non-object.js fails
-built-ins/Promise/all/invoke-resolve-error-close.js fails
-built-ins/Promise/all/invoke-resolve-get-error-close.js fails
-built-ins/Promise/all/invoke-resolve-return.js fails
-built-ins/Promise/all/invoke-resolve.js fails
-built-ins/Promise/all/invoke-then-error-close.js fails
-built-ins/Promise/all/invoke-then-get-error-close.js fails
-built-ins/Promise/all/invoke-then.js fails
-built-ins/Promise/all/iter-next-val-err-no-close.js fails
-built-ins/Promise/all/iter-step-err-no-close.js fails
-built-ins/Promise/all/length.js fails
-built-ins/Promise/all/name.js fails
-built-ins/Promise/all/new-resolve-function.js fails
-built-ins/Promise/all/prop-desc.js fails
-built-ins/Promise/all/resolve-before-loop-exit-from-same.js fails
-built-ins/Promise/all/resolve-before-loop-exit.js fails
-built-ins/Promise/all/resolve-element-function-extensible.js fails
-built-ins/Promise/all/resolve-element-function-length.js fails
-built-ins/Promise/all/resolve-element-function-name.js fails
-built-ins/Promise/all/resolve-element-function-nonconstructor.js fails
-built-ins/Promise/all/resolve-element-function-prototype.js fails
-built-ins/Promise/all/resolve-from-same-thenable.js fails
-built-ins/Promise/all/same-reject-function.js fails
-built-ins/Promise/all/species-get-error.js fails
-built-ins/Promise/exec-args.js fails
-built-ins/Promise/executor-function-extensible.js fails
-built-ins/Promise/executor-function-length.js fails
-built-ins/Promise/executor-function-name.js fails
-built-ins/Promise/executor-function-nonconstructor.js fails
-built-ins/Promise/executor-function-prototype.js fails
-built-ins/Promise/length.js fails
-built-ins/Promise/name.js fails
-built-ins/Promise/prototype/S25.4.4.2_A1.1_T1.js fails
-built-ins/Promise/prototype/S25.4.5_A3.1_T1.js fails
-built-ins/Promise/prototype/Symbol.toStringTag.js fails
-built-ins/Promise/prototype/catch/S25.4.5.1_A1.1_T1.js fails
-built-ins/Promise/prototype/catch/S25.4.5.1_A2.1_T1.js fails
-built-ins/Promise/prototype/catch/invokes-then.js fails
-built-ins/Promise/prototype/catch/length.js fails
-built-ins/Promise/prototype/catch/name.js fails
-built-ins/Promise/prototype/catch/prop-desc.js fails
-built-ins/Promise/prototype/catch/this-value-non-object.js fails
built-ins/Promise/prototype/catch/this-value-obj-coercible.js fails
-built-ins/Promise/prototype/catch/this-value-then-not-callable.js fails
-built-ins/Promise/prototype/catch/this-value-then-poisoned.js fails
-built-ins/Promise/prototype/catch/this-value-then-throws.js fails
-built-ins/Promise/prototype/no-promise-state.js fails
-built-ins/Promise/prototype/prop-desc.js fails
-built-ins/Promise/prototype/proto.js fails
-built-ins/Promise/prototype/then/S25.4.5.3_A1.1_T1.js fails
-built-ins/Promise/prototype/then/S25.4.5.3_A1.1_T2.js fails
-built-ins/Promise/prototype/then/S25.4.5.3_A2.1_T1.js fails
-built-ins/Promise/prototype/then/S25.4.5.3_A2.1_T2.js fails
built-ins/Promise/prototype/then/capability-executor-called-twice.js fails
built-ins/Promise/prototype/then/capability-executor-not-callable.js fails
-built-ins/Promise/prototype/then/context-check-on-entry.js fails
built-ins/Promise/prototype/then/ctor-custom.js fails
-built-ins/Promise/prototype/then/ctor-null.js fails
-built-ins/Promise/prototype/then/ctor-poisoned.js fails
-built-ins/Promise/prototype/then/ctor-throws.js fails
-built-ins/Promise/prototype/then/ctor-undef.js fails
-built-ins/Promise/prototype/then/length.js fails
-built-ins/Promise/prototype/then/name.js fails
-built-ins/Promise/prototype/then/prop-desc.js fails
-built-ins/Promise/race/S25.4.4.3_A1.1_T1.js fails
-built-ins/Promise/race/S25.4.4.3_A2.1_T1.js fails
-built-ins/Promise/race/S25.4.4.3_A3.1_T1.js fails
-built-ins/Promise/race/S25.4.4.3_A3.1_T2.js fails
-built-ins/Promise/race/capability-executor-called-twice.js fails
-built-ins/Promise/race/capability-executor-not-callable.js fails
-built-ins/Promise/race/ctx-ctor-throws.js fails
built-ins/Promise/race/ctx-ctor.js fails
-built-ins/Promise/race/ctx-non-ctor.js fails
-built-ins/Promise/race/ctx-non-object.js fails
-built-ins/Promise/race/invoke-resolve-error-close.js fails
-built-ins/Promise/race/invoke-resolve-get-error-close.js fails
-built-ins/Promise/race/invoke-resolve-return.js fails
-built-ins/Promise/race/invoke-resolve.js fails
-built-ins/Promise/race/invoke-then-error-close.js fails
-built-ins/Promise/race/invoke-then-get-error-close.js fails
-built-ins/Promise/race/invoke-then.js fails
-built-ins/Promise/race/iter-next-val-err-no-close.js fails
-built-ins/Promise/race/iter-step-err-no-close.js fails
-built-ins/Promise/race/length.js fails
-built-ins/Promise/race/name.js fails
-built-ins/Promise/race/prop-desc.js fails
-built-ins/Promise/race/same-reject-function.js fails
-built-ins/Promise/race/same-resolve-function.js fails
-built-ins/Promise/race/species-get-error.js fails
-built-ins/Promise/reject-function-extensible.js fails
-built-ins/Promise/reject-function-length.js fails
-built-ins/Promise/reject-function-name.js fails
-built-ins/Promise/reject-function-nonconstructor.js fails
-built-ins/Promise/reject-function-prototype.js fails
-built-ins/Promise/reject/S25.4.4.4_A1.1_T1.js fails
-built-ins/Promise/reject/S25.4.4.4_A3.1_T1.js fails
-built-ins/Promise/reject/capability-executor-called-twice.js fails
-built-ins/Promise/reject/capability-executor-not-callable.js fails
-built-ins/Promise/reject/capability-invocation-error.js fails
-built-ins/Promise/reject/capability-invocation.js fails
-built-ins/Promise/reject/ctx-ctor-throws.js fails
built-ins/Promise/reject/ctx-ctor.js fails
-built-ins/Promise/reject/ctx-non-ctor.js fails
-built-ins/Promise/reject/ctx-non-object.js fails
-built-ins/Promise/reject/length.js fails
-built-ins/Promise/reject/name.js fails
-built-ins/Promise/reject/prop-desc.js fails
-built-ins/Promise/resolve-function-extensible.js fails
-built-ins/Promise/resolve-function-length.js fails
-built-ins/Promise/resolve-function-name.js fails
-built-ins/Promise/resolve-function-nonconstructor.js fails
-built-ins/Promise/resolve-function-prototype.js fails
-built-ins/Promise/resolve/S25.4.4.5_A1.1_T1.js fails
-built-ins/Promise/resolve/S25.4.4.5_A2.1_T1.js fails
-built-ins/Promise/resolve/arg-uniq-ctor.js fails
-built-ins/Promise/resolve/capability-executor-called-twice.js fails
-built-ins/Promise/resolve/capability-executor-not-callable.js fails
-built-ins/Promise/resolve/capability-invocation-error.js fails
-built-ins/Promise/resolve/context-non-object-with-promise.js fails
-built-ins/Promise/resolve/ctx-ctor-throws.js fails
built-ins/Promise/resolve/ctx-ctor.js fails
-built-ins/Promise/resolve/ctx-non-ctor.js fails
-built-ins/Promise/resolve/ctx-non-object.js fails
-built-ins/Promise/resolve/length.js fails
-built-ins/Promise/resolve/name.js fails
-built-ins/Promise/resolve/prop-desc.js fails
-built-ins/Promise/resolve/resolve-from-promise-capability.js fails
-built-ins/Promise/resolve/resolve-prms-cstm-then.js fails
built-ins/Proxy/ownKeys/return-duplicate-entries-throws.js fails
built-ins/Proxy/ownKeys/return-duplicate-symbol-entries-throws.js fails
built-ins/RegExp/S15.10.2.12_A2_T1.js fails
@@ -371,7 +228,6 @@ built-ins/String/raw/return-the-string-value-from-template.js fails
built-ins/String/raw/special-characters.js fails
built-ins/String/raw/template-substitutions-are-appended-on-same-index.js fails
built-ins/String/raw/zero-literal-segments.js fails
-built-ins/Symbol/species/builtin-getter-name.js fails
built-ins/TypedArray/from/arylk-get-length-error.js fails
built-ins/TypedArray/from/arylk-to-length-error.js fails
built-ins/TypedArray/from/iter-access-error.js fails
@@ -786,8 +642,6 @@ language/statements/class/scope-static-gen-meth-paramsbody-var-open.js fails
language/statements/class/scope-static-meth-paramsbody-var-open.js fails
language/statements/class/scope-static-setter-paramsbody-var-open.js fails
language/statements/class/subclass/bound-function.js fails
-language/statements/class/subclass/builtin-objects/Promise/regular-subclassing.js fails
-language/statements/class/subclass/builtin-objects/Promise/super-must-be-called.js fails
language/statements/class/subclass/default-constructor-spread-override.js fails
language/statements/for-in/head-lhs-let.js sloppyFails
language/statements/for-in/head-var-bound-names-let.js sloppyFails
diff --git a/tests/auto/qml/ecmascripttests/test262 b/tests/auto/qml/ecmascripttests/test262
-Subproject 6b0c42c63c2492bd0a7a96d3179d122b5f71793
+Subproject 3c69133cc419840c1be34638039cd8c48a7ef58
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index 92696c7e76..be62908772 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -986,6 +986,7 @@ void tst_QJSEngine::globalObjectProperties_enumerate()
<< "Reflect"
<< "Proxy"
<< "Atomics"
+ << "Promise"
;
QSet<QString> actualNames;
{
diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro
index 4d9e5c23c5..05d63daedf 100644
--- a/tests/auto/qml/qml.pro
+++ b/tests/auto/qml/qml.pro
@@ -26,6 +26,7 @@ PUBLICTESTS += \
qqmlnotifier \
qqmlqt \
qqmlxmlhttprequest \
+ qqmlpromise \
qtqmlmodules \
qquickfolderlistmodel \
qqmlapplicationengine \
diff --git a/tests/auto/qml/qqmlpromise/data/promise-all-empty-input.qml b/tests/auto/qml/qqmlpromise/data/promise-all-empty-input.qml
new file mode 100644
index 0000000000..43ccf24965
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-all-empty-input.qml
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.4
+
+QtObject {
+ property bool wasTestSuccessful: false
+
+ property var promise: Promise.all([]);
+
+ Component.onCompleted: {
+ promise.then(function(value) {
+ if (value.length !== 0) {
+ return;
+ }
+
+ wasTestSuccessful = true
+
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-all-invoke-then-method.qml b/tests/auto/qml/qqmlpromise/data/promise-all-invoke-then-method.qml
new file mode 100644
index 0000000000..ec59c47130
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-all-invoke-then-method.qml
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.4
+
+QtObject {
+ property int callCount: 0
+ property bool wasTestSuccessful: false
+
+ property var promise1: new Promise(function() {})
+ property var promise2: new Promise(function() {})
+ property var promise3: new Promise(function() {})
+
+ Component.onCompleted: {
+ promise1.then = null
+ console.log(promise1.then)
+
+ // TODO: This assinment works in JS scope but does not work
+ // in QML scope
+ promise1.then = promise2.then = promise3.then = function(a, b) {
+ console.log("then was called")
+ callCount++;
+ }
+
+ Promise.all([promise1, promise2, promise3])
+
+ console.log("callCount " + callCount)
+ wasTestSuccessful = (callCount === 3)
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-all-noniterable-input.qml b/tests/auto/qml/qqmlpromise/data/promise-all-noniterable-input.qml
new file mode 100644
index 0000000000..a9bdbf2fb7
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-all-noniterable-input.qml
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.4
+
+QtObject {
+ property bool wasTestSuccessful: false
+
+ property var nonIterable: 3
+ property var promise: Promise.all(nonIterable);
+
+ Component.onCompleted: {
+ promise.then(function() {
+ throw new Error("Should never be called")
+ }, function(err) {
+ if (!(err instanceof TypeError)) {
+ throw new Error("Should reject with TypeError")
+ return;
+ }
+
+ wasTestSuccessful = true
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-all-reject-reject-is-last.qml b/tests/auto/qml/qqmlpromise/data/promise-all-reject-reject-is-last.qml
new file mode 100644
index 0000000000..0d3d31d494
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-all-reject-reject-is-last.qml
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.4
+
+QtObject {
+ // TODO!
+
+ property int resolveValue: 5
+ property int rejectValue: 10
+ property int resultValue: rejectValue
+ property bool wasTestSuccessful: false
+
+
+ property var delayedEvent: Timer {
+ interval: 0
+ property var handler: null
+ onTriggered: {
+ if (handler) {
+ handler();
+ }
+ }
+ }
+
+ function postEvent(event, value) {
+ delayedEvent.handler = function() { event(value) }
+ delayedEvent.restart();
+ }
+
+ property var promise1: Promise.resolve(resolveValue);
+ property int promise2: resolveValue
+ property var promise3: new Promise(function (resolve, reject) {
+ postEvent(resolve, resolveValue)
+ })
+ property var promise4: Promise.reject(rejectValue)
+
+ Component.onCompleted: {
+ Promise.all([promise1, promise2, promise3, promise4]).then(function() {
+ throw new Error("Should never be called")
+ }, function(value) {
+ if (value !== rejectValue) {
+ return;
+ }
+
+ wasTestSuccessful = true
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-all-reject-reject-is-mid.qml b/tests/auto/qml/qqmlpromise/data/promise-all-reject-reject-is-mid.qml
new file mode 100644
index 0000000000..67ca95971c
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-all-reject-reject-is-mid.qml
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.4
+
+QtObject {
+ // TODO!
+
+ property int resolveValue: 5
+ property int rejectValue: 10
+ property int resultValue: rejectValue
+ property bool wasTestSuccessful: false
+
+
+ property var delayedEvent: Timer {
+ interval: 0
+ property var handler: null
+ onTriggered: {
+ if (handler) {
+ handler();
+ }
+ }
+ }
+
+ function postEvent(event, value) {
+ delayedEvent.handler = function() { event(value) }
+ delayedEvent.restart();
+ }
+
+ property var promise1: Promise.resolve(resolveValue);
+ property int promise2: resolveValue
+ property var promise3: Promise.reject(rejectValue)
+ property var promise4: new Promise(function (resolve, reject) {
+ postEvent(resolve, resolveValue)
+ })
+
+ Component.onCompleted: {
+ Promise.all([promise1, promise2, promise3, promise4]).then(function() {
+ throw new Error("Should never be called")
+ }, function(value) {
+ if (value !== rejectValue) {
+ return;
+ }
+
+ wasTestSuccessful = true
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-all-resolve.qml b/tests/auto/qml/qqmlpromise/data/promise-all-resolve.qml
new file mode 100644
index 0000000000..1996b7f9c8
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-all-resolve.qml
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.4
+
+QtObject {
+ property int resolveValue: 5
+ property var resultValue: [resolveValue, resolveValue, resolveValue]
+ property bool wasTestSuccessful: false
+
+
+ property var delayedEvent: Timer {
+ interval: 0
+ property var handler: null
+ onTriggered: {
+ if (handler) {
+ handler();
+ }
+ }
+ }
+
+ function postEvent(event, value) {
+ delayedEvent.handler = function() { event(value) }
+ delayedEvent.restart();
+ }
+
+ property var promise1: Promise.resolve(resolveValue);
+ property int promise2: resolveValue
+ property var promise3: new Promise(function (resolve, reject) {
+ postEvent(resolve, resolveValue)
+ })
+
+ Component.onCompleted: {
+ Promise.all([promise1, promise2, promise3]).then(function(value) {
+ if (value.length !== resultValue.length) {
+ return;
+ }
+
+ for (var i in value) {
+ if (value[i] !== resultValue[i]) {
+ return;
+ }
+ }
+
+ wasTestSuccessful = true
+
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-async-reject-with-value.qml b/tests/auto/qml/qqmlpromise/data/promise-async-reject-with-value.qml
new file mode 100644
index 0000000000..4c54ad3fc7
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-async-reject-with-value.qml
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.4
+
+QtObject {
+ property int rejectValue: 5
+ property bool wasTestSuccessful: false
+
+
+ property var delayedExecutor: Timer {
+ interval: 0
+ property var executor: null
+ onTriggered: {
+ if (executor) {
+ executor();
+ }
+ }
+ }
+
+ property var promise: new Promise(function (resolve, reject) {
+ delayedExecutor.executor = function() {
+ reject(rejectValue)
+ }
+ delayedExecutor.restart();
+ })
+
+ Component.onCompleted: {
+ promise.then(function() {
+ throw new Error("Should never be called")
+ }, function(value) {
+ if (value === rejectValue) {
+ wasTestSuccessful = true
+ }
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-async-resolve-with-value.qml b/tests/auto/qml/qqmlpromise/data/promise-async-resolve-with-value.qml
new file mode 100644
index 0000000000..a491394a30
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-async-resolve-with-value.qml
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.4
+
+QtObject {
+ property int resolveValue: 5
+ property bool wasTestSuccessful: false
+
+
+ property var delayedExecutor: Timer {
+ interval: 0
+ property var executor: null
+ onTriggered: {
+ if (executor) {
+ executor();
+ }
+ }
+ }
+
+ property var promise: new Promise(function (resolve, reject) {
+ delayedExecutor.executor = function() {
+ resolve(resolveValue)
+ }
+ delayedExecutor.restart();
+ })
+
+ Component.onCompleted: {
+ promise.then(function(value) {
+ if (value === resolveValue) {
+ wasTestSuccessful = true
+ }
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-executor-function-extensible.qml b/tests/auto/qml/qqmlpromise/data/promise-executor-function-extensible.qml
new file mode 100644
index 0000000000..e2a264dd3c
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-executor-function-extensible.qml
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property bool wasTestSuccessful: false
+
+ property var executorFunction: null
+
+ function notPromise(executor) {
+ executorFunction = executor;
+ executor(function() {}, function() {});
+ }
+
+ Component.onCompleted: {
+ Promise.resolve.call(notPromise);
+ wasTestSuccessful = executorFunction !== null &&
+ Object.isExtensible(executorFunction);
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-executor-reject.qml b/tests/auto/qml/qqmlpromise/data/promise-executor-reject.qml
new file mode 100644
index 0000000000..4e609ae4a4
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-executor-reject.qml
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property string resolution: "reject promise";
+
+ property bool wasExecutorCalled: false
+ property bool wasPromiseRejected: false
+ property bool wasPromiseTypeReturnedByThen: false;
+ property bool wasResolutionForwardedCorrectly: false;
+
+ Component.onCompleted: {
+ var promise = new Promise(function(resolve, reject) {
+ wasExecutorCalled = true;
+ reject(resolution);
+ });
+
+ var res = promise.then(function(result) {
+ wasPromiseRejected = false;
+ }, function(err) {
+ wasPromiseRejected = true;
+ wasResolutionForwardedCorrectly = (err === resolution);
+ });
+
+ wasPromiseTypeReturnedByThen = (typeof res === 'Promise');
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-executor-resolve.qml b/tests/auto/qml/qqmlpromise/data/promise-executor-resolve.qml
new file mode 100644
index 0000000000..659636d6a8
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-executor-resolve.qml
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property string resolution: "fullfill promise";
+
+ property bool wasExecutorCalled: false
+ property bool wasPromiseResolved: false
+ property bool wasPromiseTypeReturnedByThen: false
+ property bool wasResolutionForwardedCorrectly: false
+ property bool wasNewPromiseObjectCreatedByThen: false
+
+ Component.onCompleted: {
+ var promise = new Promise(function(resolve, reject) {
+ wasExecutorCalled = true;
+ resolve(resolution);
+ });
+
+ var res = promise.then(function(result) {
+ wasPromiseResolved = true;
+ wasResolutionForwardedCorrectly = (result === resolution);
+ }, function(err) {
+ wasPromiseResolved = false;
+ });
+
+ wasPromiseTypeReturnedByThen = (typeof res === 'Promise');
+ console.debug("typeof res: " + (typeof res)) // TODO: remove
+ wasNewPromiseObjectCreatedByThen = (res !== promise);
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-executor-throw-exception.qml b/tests/auto/qml/qqmlpromise/data/promise-executor-throw-exception.qml
new file mode 100644
index 0000000000..9e912635d6
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-executor-throw-exception.qml
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property bool wasTestSuccessful: false
+
+ property var errorObject: { text: "Exception should not escape executor" }
+
+ property var promise: new Promise(function() {
+ throw errorObject
+ })
+
+ Component.onCompleted: {
+ promise.then(function() {
+ throw new Error("Should never be called")
+ }, function(error) {
+ if (error === errorObject) {
+ wasTestSuccessful = true
+ }
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-get-length.qml b/tests/auto/qml/qqmlpromise/data/promise-get-length.qml
new file mode 100644
index 0000000000..d42bc61179
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-get-length.qml
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property bool wasTestSuccessful: (Promise.length === 1)
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-race-empty-input.qml b/tests/auto/qml/qqmlpromise/data/promise-race-empty-input.qml
new file mode 100644
index 0000000000..188b1c2f15
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-race-empty-input.qml
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.4
+
+QtObject {
+ property bool wasTestSuccessful: true
+
+ Component.onCompleted: {
+ Promise.race([]).then(function(value) {
+ wasTestSuccessful = false
+ throw new Error("Should never be called")
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-race-resolve-1st-in-executor-function.qml b/tests/auto/qml/qqmlpromise/data/promise-race-resolve-1st-in-executor-function.qml
new file mode 100644
index 0000000000..1d6e47b87e
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-race-resolve-1st-in-executor-function.qml
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.4
+
+QtObject {
+ property int resolveValue: 33
+
+ property var promise: new Promise(function (resolve, reject) {
+ resolve(resolveValue)
+ })
+
+ property var resolvedPromiseArray: [promise, Promise.resolve(resolveValue + 5)]
+ property bool wasTestSuccessful: false
+
+ Component.onCompleted: {
+ Promise.race(resolvedPromiseArray).then(function(value) {
+ if (value !== resolveValue) {
+ return;
+ }
+
+ wasTestSuccessful = true
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-race-resolve-1st.qml b/tests/auto/qml/qqmlpromise/data/promise-race-resolve-1st.qml
new file mode 100644
index 0000000000..bd7b3a4026
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-race-resolve-1st.qml
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.4
+
+QtObject {
+ property int resolveValue: 33
+ property var resolvedPromiseArray: [Promise.resolve(resolveValue), Promise.resolve(resolveValue + 5)]
+ property bool wasTestSuccessful: false
+
+ Component.onCompleted: {
+ Promise.race(resolvedPromiseArray).then(function(value) {
+ if (value !== resolveValue) {
+ return;
+ }
+
+ wasTestSuccessful = true
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-race-resolve-2nd.qml b/tests/auto/qml/qqmlpromise/data/promise-race-resolve-2nd.qml
new file mode 100644
index 0000000000..e4c1b98acc
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-race-resolve-2nd.qml
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.4
+
+QtObject {
+ property int resolveValue: 33
+
+ property var delayedExecutor: Timer {
+ interval: 0
+ property var executor: null
+ onTriggered: {
+ if (executor) {
+ executor();
+ }
+ }
+ }
+
+ property var promise: new Promise(function (resolve, reject) {
+ delayedExecutor.executor = function() {
+ resolve(resolveValue + 5)
+ }
+ delayedExecutor.restart();
+ })
+
+ property var resolvedPromiseArray: [promise, Promise.resolve(resolveValue)]
+ property bool wasTestSuccessful: false
+
+ Component.onCompleted: {
+ Promise.race(resolvedPromiseArray).then(function(value) {
+ if (value !== resolveValue) {
+ return;
+ }
+
+ wasTestSuccessful = true
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-reject-catch.qml b/tests/auto/qml/qqmlpromise/data/promise-reject-catch.qml
new file mode 100644
index 0000000000..a83d2670ba
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-reject-catch.qml
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property int rejectValue: 5
+ property var promise: Promise.reject(rejectValue)
+ property bool wasTestSuccessful: false
+
+ Component.onCompleted: {
+ promise.then(function() {
+ throw new Error("Should never be called")
+ }).then(function() {
+ throw new Error("Should never be called")
+ }).catch(function(value) {
+ if (value === rejectValue) {
+ wasTestSuccessful = true
+ }
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-reject-with-value.qml b/tests/auto/qml/qqmlpromise/data/promise-reject-with-value.qml
new file mode 100644
index 0000000000..6b81e83643
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-reject-with-value.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property int rejectValue: 5
+ property var promise: Promise.reject(rejectValue)
+ property bool wasTestSuccessful: false
+
+ Component.onCompleted: {
+ promise.then(function() {
+ throw new Error("Should never be called")
+ }, function(value) {
+ if (value === rejectValue) {
+ wasTestSuccessful = true
+ }
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-resolve-function-length.qml b/tests/auto/qml/qqmlpromise/data/promise-resolve-function-length.qml
new file mode 100644
index 0000000000..40d35e5a3b
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-resolve-function-length.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property var resolveFunction
+ property var promise: new Promise(function(resolve, reject) {
+ resolveFunction = resolve
+ })
+
+ property bool wasTestSuccessful: (typeof resolveFunction === "function" &&
+ typeof resolveFunction.length !== "undefined" &&
+ resolveFunction.length === 1)
+
+ Component.onCompleted: {
+ // TODO: Function length field should be NotWritabel & NotEnumerable & Configurable
+ console.log(Object.getOwnPropertyDescriptor(resolveFunction, "length").configurable)
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-resolve-is-a-function.qml b/tests/auto/qml/qqmlpromise/data/promise-resolve-is-a-function.qml
new file mode 100644
index 0000000000..fbdcc0f8e9
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-resolve-is-a-function.qml
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property bool wasTestSuccessful: (typeof Promise.resolve === "function")
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-resolve-with-array.qml b/tests/auto/qml/qqmlpromise/data/promise-resolve-with-array.qml
new file mode 100644
index 0000000000..04d2209907
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-resolve-with-array.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property var resolveValue: [1, 2, 3]
+ property var promise: Promise.resolve(resolveValue)
+ property bool wasTestSuccessful: false
+
+ Component.onCompleted: {
+ promise.then(function(value) {
+ if (value === resolveValue) {
+ wasTestSuccessful = true
+ }
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-resolve-with-empty.qml b/tests/auto/qml/qqmlpromise/data/promise-resolve-with-empty.qml
new file mode 100644
index 0000000000..61c7bf17a6
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-resolve-with-empty.qml
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property var promise: Promise.resolve()
+ property bool wasTestSuccessful: false
+
+ Component.onCompleted: {
+ promise.then(function(value) {
+ if (typeof value === "undefined") {
+ wasTestSuccessful = true
+ }
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-resolve-with-promise.qml b/tests/auto/qml/qqmlpromise/data/promise-resolve-with-promise.qml
new file mode 100644
index 0000000000..65b39508ad
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-resolve-with-promise.qml
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property int resolveValue: 5
+ property var originalPromise: Promise.resolve(resolveValue)
+
+ property var castPromise: Promise.resolve(originalPromise)
+ property bool wasTestSuccessful: false
+
+ Component.onCompleted: {
+ if (castPromise !== originalPromise) {
+ console.log("resolve did not return original promise")
+ return;
+ }
+
+ castPromise.then(function(value) {
+ if (value !== resolveValue) {
+ console.log("resolved values are not the same")
+ return;
+ }
+
+ wasTestSuccessful = true
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-resolve-with-value.qml b/tests/auto/qml/qqmlpromise/data/promise-resolve-with-value.qml
new file mode 100644
index 0000000000..a1294cf9a6
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-resolve-with-value.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property int resolveValue: 5
+ property var promise: Promise.resolve(resolveValue)
+ property bool wasTestSuccessful: false
+
+ Component.onCompleted: {
+ promise.then(function(value) {
+ if (value === resolveValue) {
+ wasTestSuccessful = true
+ }
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/then-fulfilled-non-callable.qml b/tests/auto/qml/qqmlpromise/data/then-fulfilled-non-callable.qml
new file mode 100644
index 0000000000..ee7e3ed7be
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/then-fulfilled-non-callable.qml
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property int resolveValue: 5
+
+ property bool promise1WasResolved: false
+ property bool promise2WasResolved: false
+ property bool promise3WasResolved: false
+ property bool promise4WasResolved: true
+
+ property bool wasTestSuccessful: promise1WasResolved && promise2WasResolved &&
+ promise3WasResolved && promise4WasResolved
+
+ // TODO: Should this work as well?
+ // property Promise promise
+ property var promise1: new Promise(function (resolve, reject) {
+ resolve(resolveValue)
+ })
+ property var promise2: new Promise(function (resolve, reject) {
+ resolve(resolveValue)
+ })
+ property var promise3: new Promise(function (resolve, reject) {
+ resolve(resolveValue)
+ })
+ property var promise4: new Promise(function (resolve, reject) {
+ resolve(resolveValue)
+ })
+
+ Component.onCompleted: {
+ promise1.then().then(function (result) {
+ promise1WasResolved = (result === resolveValue);
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ promise2.then(3, 5).then(function (result) {
+ promise2WasResolved = (result === resolveValue);
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ promise3.then(null, function() {
+ throw new Error("Should never be called")
+ }).then(function (result) {
+ promise3WasResolved = (result === resolveValue);
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ /*
+ promise4.then(undefined, undefined).then(function (result) {
+ promise4WasResolved = (result === resolveValue);
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ */
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/then-reject-chaining.qml b/tests/auto/qml/qqmlpromise/data/then-reject-chaining.qml
new file mode 100644
index 0000000000..645ae9b07c
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/then-reject-chaining.qml
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property int rejectValue: 1
+ property int expectedValue: rejectValue + 2;
+ property bool wasTestSuccessful: false
+
+ Component.onCompleted: {
+ var promise = new Promise(function(resolve, reject) {
+ reject(rejectValue);
+ });
+
+ promise.then(function() {
+ throw new Error("Should never be called")
+ }, function(val) {
+ return val + 2;
+ }).then(function(val) {
+ if (val === expectedValue) {
+ wasTestSuccessful = true
+ }
+ }, function() {
+ throw new Error("Should never be called")
+ });
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/then-reject-non-callable.qml b/tests/auto/qml/qqmlpromise/data/then-reject-non-callable.qml
new file mode 100644
index 0000000000..df708c6218
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/then-reject-non-callable.qml
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property int rejectValue: 5
+
+ property bool promise1WasRejected: false
+ property bool promise2WasRejected: false
+
+ property bool wasTestSuccessful: promise1WasRejected && promise2WasRejected
+
+ // TODO: Should this work as well?
+ // property Promise promise
+ property var promise1: new Promise(function (resolve, reject) {
+ reject(rejectValue)
+ })
+ property var promise2: new Promise(function (resolve, reject) {
+ reject(rejectValue)
+ })
+
+ Component.onCompleted: {
+ promise1.then().then(function() {
+ promise1WasRejected = false
+ throw new Error("Should never be called")
+ }, function (result) {
+ promise1WasRejected = (result === rejectValue);
+ })
+ promise2.then(3, 5).then(function() {
+ promise2WasRejected = false
+ throw new Error("Should never be called")
+ }, function (result) {
+ promise2WasRejected = (result === rejectValue);
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/then-resolve-chaining.qml b/tests/auto/qml/qqmlpromise/data/then-resolve-chaining.qml
new file mode 100644
index 0000000000..d65e9c86ac
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/then-resolve-chaining.qml
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property int resolveValue: 1
+ property int expectedValue: resolveValue + 2;
+ property bool wasTestSuccessful: false
+
+ Component.onCompleted: {
+ var promise = new Promise(function(resolve, reject) {
+ resolve(resolveValue);
+ });
+
+ promise.then(function(val) {
+ return val + 2;
+ }).then(function(val) {
+ if (val === expectedValue) {
+ wasTestSuccessful = true;
+ }
+ });
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/then-resolve-multiple-then.qml b/tests/auto/qml/qqmlpromise/data/then-resolve-multiple-then.qml
new file mode 100644
index 0000000000..48000d5ddc
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/then-resolve-multiple-then.qml
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property int resolveValue: 5
+
+ property bool was1stCallSucessfull: false
+ property bool was2ndCallSucessfull: false
+
+ property bool wasTestSuccessful: was1stCallSucessfull && was2ndCallSucessfull
+
+ property var promise: new Promise(function (resolve, reject) {
+ resolve(resolveValue)
+ })
+
+ Component.onCompleted: {
+ promise.then(function (result) {
+ was1stCallSucessfull = (result === resolveValue);
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ promise.then(function (result) {
+ was2ndCallSucessfull = (result === resolveValue);
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/qqmlpromise.pro b/tests/auto/qml/qqmlpromise/qqmlpromise.pro
new file mode 100644
index 0000000000..7cdb02cd61
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/qqmlpromise.pro
@@ -0,0 +1,46 @@
+CONFIG += testcase
+TARGET = tst_qqmlpromise
+macos:CONFIG -= app_bundle
+
+SOURCES += tst_qqmlpromise.cpp
+
+OTHER_FILES +=
+
+include (../../shared/util.pri)
+
+TESTDATA = data/*
+
+QT += core-private gui-private qml-private testlib
+DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
+
+DISTFILES += \
+ data/then-fulfilled-non-callable.qml \
+ data/then-reject-non-callable.qml \
+ data/then-resolve-multiple-then.qml \
+ data/then-resolve-chaining.qml \
+ data/then-reject-chaining.qml \
+ data/promise-resolve-with-value.qml \
+ data/promise-resolve-with-promise.qml \
+ data/promise-reject-with-value.qml \
+ data/promise-executor-resolve.qml \
+ data/promise-get-length.qml \
+ data/promise-executor-reject.qml \
+ data/promise-reject-catch.qml \
+ data/promise-async-resolve-with-value.qml \
+ data/promise-async-reject-with-value.qml \
+ data/promise-all-resolve.qml \
+ data/promise-all-empty-input.qml \
+ data/promise-resolve-with-array.qml \
+ data/promise-all-reject-reject-is-last.qml \
+ data/promise-all-reject-reject-is-mid.qml \
+ data/promise-race-resolve-1st.qml \
+ data/promise-race-empty-input.qml \
+ data/promise-race-resolve-2nd.qml \
+ data/promise-race-resolve-1st-in-executor-function.qml \
+ data/promise-resolve-is-a-function.qml \
+ data/promise-resolve-function-length.qml \
+ data/promise-all-invoke-then-method.qml \
+ data/promise-resolve-with-empty.qml \
+ data/promise-executor-throw-exception.qml \
+ data/promise-executor-function-extensible.qml \
+ data/promise-all-noniterable-input.qml
diff --git a/tests/auto/qml/qqmlpromise/tst_qqmlpromise.cpp b/tests/auto/qml/qqmlpromise/tst_qqmlpromise.cpp
new file mode 100644
index 0000000000..0f4bb5cdcc
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/tst_qqmlpromise.cpp
@@ -0,0 +1,276 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QString>
+#include <QtTest>
+#include <QQmlEngine>
+#include <QQmlComponent>
+#include <QDebug>
+#include <QScopedPointer>
+#include "../../shared/util.h"
+
+class tst_qqmlpromise : public QQmlDataTest
+{
+ Q_OBJECT
+
+public:
+ tst_qqmlpromise() {}
+
+private slots:
+ void promise_all_empty_input();
+ void promise_all_noniterable_input();
+// void promise_all_invoke_then_method();
+ void promise_all_resolve();
+ void promise_all_reject_reject_is_last();
+ void promise_all_reject_reject_is_mid();
+ void promise_get_length();
+ void promise_executor_function_extensible();
+ void promise_executor_reject();
+ void promise_executor_resolve();
+ void promise_executor_throw_exception();
+ void promise_async_resolve_with_value();
+ void promise_async_reject_with_value();
+ void promise_resolve_with_value();
+ void promise_resolve_function_length();
+ void promise_resolve_is_a_function();
+ void promise_resolve_with_array();
+ void promise_resolve_with_empty();
+ void promise_resolve_with_promise();
+ void promise_race_empty_input();
+ void promise_race_resolve_1st_in_executor_function();
+ void promise_race_resolve_1st();
+ void promise_race_resolve_2nd();
+ void promise_reject_with_value();
+ void promise_reject_catch();
+ void then_resolve_chaining();
+ void then_reject_chaining();
+ void then_fulfilled_non_callable();
+ void then_reject_non_callable();
+ void then_resolve_multiple_then();
+
+private:
+ void execute_test(QString testName);
+};
+
+void tst_qqmlpromise::promise_all_empty_input()
+{
+ execute_test("promise-all-empty-input.qml");
+}
+
+void tst_qqmlpromise::promise_all_noniterable_input()
+{
+ execute_test("promise-all-noniterable-input.qml");
+}
+
+// TODO: Fix the test
+//void tst_qqmlpromise::promise_all_invoke_then_method()
+//{
+// execute_test("promise-all-invoke-then-method.qml");
+//}
+
+void tst_qqmlpromise::promise_all_resolve()
+{
+ execute_test("promise-all-resolve.qml");
+}
+
+void tst_qqmlpromise::promise_all_reject_reject_is_last()
+{
+ execute_test("promise-all-reject-reject-is-last.qml");
+}
+
+void tst_qqmlpromise::promise_all_reject_reject_is_mid()
+{
+ execute_test("promise-all-reject-reject-is-mid.qml");
+}
+
+void tst_qqmlpromise::promise_get_length()
+{
+ execute_test("promise-get-length.qml");
+}
+
+void tst_qqmlpromise::promise_executor_resolve()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("promise-executor-resolve.qml"));
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
+ component.completeCreate();
+
+ QTRY_COMPARE(object->property("wasExecutorCalled").toBool(), true);
+ QTRY_COMPARE(object->property("wasPromiseResolved").toBool(), true);
+ // TODO: now "object" type is returned. fix
+ // QCOMPARE(object->property("wasPromiseTypeReturnedByThen").toBool(), true);
+ QTRY_COMPARE(object->property("wasResolutionForwardedCorrectly").toBool(), true);
+ QTRY_COMPARE(object->property("wasNewPromiseObjectCreatedByThen").toBool(), true);
+}
+
+void tst_qqmlpromise::promise_executor_throw_exception()
+{
+ execute_test("promise-executor-throw-exception.qml");
+}
+
+void tst_qqmlpromise::promise_async_resolve_with_value()
+{
+ execute_test("promise-async-resolve-with-value.qml");
+}
+
+void tst_qqmlpromise::promise_async_reject_with_value()
+{
+ execute_test("promise-async-reject-with-value.qml");
+}
+
+void tst_qqmlpromise::promise_resolve_with_value()
+{
+ execute_test("promise-resolve-with-value.qml");
+}
+
+void tst_qqmlpromise::promise_resolve_function_length()
+{
+ execute_test("promise-resolve-function-length.qml");
+}
+
+void tst_qqmlpromise::promise_resolve_is_a_function()
+{
+ execute_test("promise-resolve-is-a-function.qml");
+}
+
+void tst_qqmlpromise::promise_resolve_with_array()
+{
+ execute_test("promise-resolve-with-array.qml");
+}
+
+void tst_qqmlpromise::promise_resolve_with_empty()
+{
+ execute_test("promise-resolve-with-empty.qml");
+}
+
+void tst_qqmlpromise::promise_resolve_with_promise()
+{
+ execute_test("promise-resolve-with-promise.qml");
+}
+
+void tst_qqmlpromise::promise_race_empty_input()
+{
+ execute_test("promise-race-empty-input.qml");
+}
+
+void tst_qqmlpromise::promise_race_resolve_1st_in_executor_function()
+{
+ execute_test("promise-race-resolve-1st-in-executor-function.qml");
+}
+
+void tst_qqmlpromise::promise_race_resolve_1st()
+{
+ execute_test("promise-race-resolve-1st.qml");
+}
+
+void tst_qqmlpromise::promise_race_resolve_2nd()
+{
+ execute_test("promise-race-resolve-2nd.qml");
+}
+
+void tst_qqmlpromise::promise_reject_with_value()
+{
+ execute_test("promise-reject-with-value.qml");
+}
+
+void tst_qqmlpromise::promise_reject_catch()
+{
+ execute_test("promise-reject-catch.qml");
+}
+
+void tst_qqmlpromise::promise_executor_function_extensible()
+{
+ execute_test("promise-executor-function-extensible.qml");
+}
+
+void tst_qqmlpromise::promise_executor_reject()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("promise-executor-reject.qml"));
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
+ component.completeCreate();
+
+ QTRY_COMPARE(object->property("wasExecutorCalled").toBool(), true);
+ QTRY_COMPARE(object->property("wasPromiseRejected").toBool(), true);
+ // TODO: now "object" type is returned. fix
+ // QCOMPARE(object->property("wasPromiseTypeReturnedByThen").toBool(), true);
+ QTRY_COMPARE(object->property("wasResolutionForwardedCorrectly").toBool(), true);
+}
+
+void tst_qqmlpromise::then_resolve_chaining()
+{
+ execute_test("then-resolve-chaining.qml");
+}
+
+void tst_qqmlpromise::then_reject_chaining()
+{
+ execute_test("then-reject-chaining.qml");
+}
+
+void tst_qqmlpromise::then_fulfilled_non_callable()
+{
+ execute_test("then-fulfilled-non-callable.qml");
+}
+
+void tst_qqmlpromise::then_reject_non_callable()
+{
+ execute_test("then-reject-non-callable.qml");
+}
+
+void tst_qqmlpromise::then_resolve_multiple_then()
+{
+ execute_test("then-resolve-multiple-then.qml");
+}
+
+void tst_qqmlpromise::execute_test(QString testName)
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl(testName));
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
+ component.completeCreate();
+
+ QTRY_COMPARE(object->property("wasTestSuccessful").toBool(), true);
+}
+
+
+QTEST_MAIN(tst_qqmlpromise)
+
+#include "tst_qqmlpromise.moc"