diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2018-10-12 01:00:07 +0200 |
---|---|---|
committer | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2018-10-12 01:00:07 +0200 |
commit | 8092a4e247a69ea5a9f21d16a619b562b9558d2d (patch) | |
tree | 7746770b3799d03c2467caa6073d981735ca03ee | |
parent | 9b87533da07a6c978fb80aa99223921c343df01e (diff) | |
parent | b8f4005f132c26b842387e1ae5f492594dc03d86 (diff) |
Merge remote-tracking branch 'origin/5.12' into dev
Change-Id: I0ad1a3aa3a211ef86c4baf605361de860266dde1
52 files changed, 3692 insertions, 161 deletions
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp index 3dfb755936..8c92b4b170 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp @@ -154,10 +154,9 @@ const QV4::Object *collectProperty(const QV4::ScopedValue &value, QV4::Execution int numProperties = 0; QV4::ObjectIterator it(scope, o, QV4::ObjectIterator::EnumerableOnly); QV4::PropertyAttributes attrs; - QV4::ScopedProperty p(scope); QV4::ScopedPropertyKey name(scope); while (true) { - name = it.next(p, &attrs); + name = it.next(nullptr, &attrs); if (!name->isValid()) break; ++numProperties; @@ -340,8 +339,36 @@ QV4::ReturnedValue QV4DataCollector::getValue(Ref ref) return array->get(ref, nullptr); } +class CapturePreventer +{ +public: + CapturePreventer(QV4::ExecutionEngine *engine) + { + if (QQmlEngine *e = engine->qmlEngine()) { + m_engine = QQmlEnginePrivate::get(e); + m_capture = m_engine->propertyCapture; + m_engine->propertyCapture = nullptr; + } + } + + ~CapturePreventer() + { + if (m_engine && m_capture) { + Q_ASSERT(!m_engine->propertyCapture); + m_engine->propertyCapture = m_capture; + } + } + +private: + QQmlEnginePrivate *m_engine = nullptr; + QQmlPropertyCapture *m_capture = nullptr; +}; + QJsonArray QV4DataCollector::collectProperties(const QV4::Object *object) { + CapturePreventer capturePreventer(engine()); + Q_UNUSED(capturePreventer); + QJsonArray res; QV4::Scope scope(engine()); diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 321cf21c54..19e960bb57 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -1222,6 +1222,8 @@ bool Codegen::visit(ArrayMemberExpression *ast) return false; } Reference index = expression(ast->expression); + if (hasError) + return false; _expr.setResult(Reference::fromSubscript(base, index)); return false; } 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 3d6a13d794..3b4574c18b 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/src/qmltest/doc/src/qtquicktest-index.qdoc b/src/qmltest/doc/src/qtquicktest-index.qdoc index 700bddc8d5..0a89066d47 100644 --- a/src/qmltest/doc/src/qtquicktest-index.qdoc +++ b/src/qmltest/doc/src/qtquicktest-index.qdoc @@ -57,6 +57,11 @@ to be executed. See the documentation for the \l [QML] TestCase and \l [QML] SignalSpy types for more information on writing test cases. + \note There is no binary compatibility guarantee for the Qt Quick Test + module. This means that an application that uses Qt Quick Test is + only guaranteed to work with the Qt version it was developed against. + However, source compatibility is guaranteed. + \section1 Running Tests Test cases are launched by a C++ harness that consists of diff --git a/src/quick/items/qquickrendercontrol.cpp b/src/quick/items/qquickrendercontrol.cpp index ec74660d96..025acefec2 100644 --- a/src/quick/items/qquickrendercontrol.cpp +++ b/src/quick/items/qquickrendercontrol.cpp @@ -312,9 +312,6 @@ bool QQuickRenderControl::sync() void QQuickRenderControl::invalidate() { Q_D(QQuickRenderControl); - if (!d->initialized) - return; - if (!d->window) return; @@ -322,6 +319,9 @@ void QQuickRenderControl::invalidate() cd->fireAboutToStop(); cd->cleanupNodesOnShutdown(); + if (!d->initialized) + return; + // We must invalidate since the context can potentially be destroyed by the // application right after returning from this function. Invalidating is // also essential to allow a subsequent initialize() to succeed. diff --git a/src/quick/qtquick2.cpp b/src/quick/qtquick2.cpp index 24467a3701..63f3b91b82 100644 --- a/src/quick/qtquick2.cpp +++ b/src/quick/qtquick2.cpp @@ -55,11 +55,6 @@ #include <qqmlproperty.h> #include <QtCore/QPointer> -static void initResources() -{ - Q_INIT_RESOURCE(scenegraph); -} - QT_BEGIN_NAMESPACE #if !QT_CONFIG(qml_debug) @@ -185,8 +180,6 @@ void QQmlQtQuick2DebugStatesDelegate::resetBindingForInvalidProperty(QObject *ob void QQmlQtQuick2Module::defineModule() { - initResources(); - QQuick_initializeProviders(); QQuickUtilModule::defineModule(); diff --git a/src/quick/scenegraph/qsgdefaultcontext.cpp b/src/quick/scenegraph/qsgdefaultcontext.cpp index 9a0ac66690..1124bf1727 100644 --- a/src/quick/scenegraph/qsgdefaultcontext.cpp +++ b/src/quick/scenegraph/qsgdefaultcontext.cpp @@ -290,3 +290,10 @@ QSGRendererInterface::ShaderSourceTypes QSGDefaultContext::shaderSourceType() co } QT_END_NAMESPACE + +static void initResources() +{ + Q_INIT_RESOURCE(scenegraph); +} + +Q_CONSTRUCTOR_FUNCTION(initResources) diff --git a/tests/auto/qml/debugger/qqmldebugjs/data/breakOnAnchor.qml b/tests/auto/qml/debugger/qqmldebugjs/data/breakOnAnchor.qml new file mode 100644 index 0000000000..72a8c9559c --- /dev/null +++ b/tests/auto/qml/debugger/qqmldebugjs/data/breakOnAnchor.qml @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** 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-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.11 + + +Item { + visible: true + Text { + anchors.centerIn: parent + text: "bla" + MouseArea { + anchors.fill: parent + } + } + + Timer { + interval: 100; + running: true; + onTriggered: { + Qt.quit(); + } + } +} diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs.pro b/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs.pro index b9d5f116dc..8fef435d98 100644 --- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs.pro +++ b/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs.pro @@ -21,4 +21,5 @@ OTHER_FILES += data/test.qml data/test.js \ data/stepAction.qml \ data/breakpointRelocation.qml \ data/createComponent.qml \ - data/encodeQmlScope.qml + data/encodeQmlScope.qml \ + data/breakOnAnchor.qml diff --git a/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp index c090be2633..941303d3ef 100644 --- a/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp +++ b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp @@ -127,6 +127,7 @@ const char *CHANGEBREAKPOINT_QMLFILE = "changeBreakpoint.qml"; const char *STEPACTION_QMLFILE = "stepAction.qml"; const char *BREAKPOINTRELOCATION_QMLFILE = "breakpointRelocation.qml"; const char *ENCODEQMLSCOPE_QMLFILE = "encodeQmlScope.qml"; +const char *BREAKONANCHOR_QMLFILE = "breakOnAnchor.qml"; #define VARIANTMAPINIT \ QString obj("{}"); \ @@ -224,6 +225,7 @@ private slots: void getScripts(); void encodeQmlScope(); + void breakOnAnchor(); private: ConnectResult init(bool qmlscene, const QString &qmlFile = QString(TEST_QMLFILE), @@ -1602,6 +1604,43 @@ void tst_QQmlDebugJS::encodeQmlScope() QCOMPARE(numReceivedScopes, numExpectedScopes); } +void tst_QQmlDebugJS::breakOnAnchor() +{ + QString file(BREAKONANCHOR_QMLFILE); + QCOMPARE(init(true, file), ConnectSuccess); + + int breaks = 0; + bool stopped = false; + QObject::connect(m_client, &QJSDebugClient::stopped, this, [&]() { + stopped = true; + ++breaks; + m_client->evaluate("this", 0, -1); + }); + + QObject::connect(m_client, &QJSDebugClient::result, this, [&]() { + if (stopped) { + m_client->continueDebugging(QJSDebugClient::Continue); + stopped = false; + } + }); + + QObject::connect(m_client, &QJSDebugClient::failure, this, [&]() { + qWarning() << "received failure" << m_client->response; + }); + + m_client->setBreakpoint(file, 34); + m_client->setBreakpoint(file, 37); + + QTRY_COMPARE(m_process->state(), QProcess::Running); + + m_client->connect(); + + QTRY_COMPARE(m_process->state(), QProcess::NotRunning); + QCOMPARE(m_process->exitStatus(), QProcess::NormalExit); + + QCOMPARE(breaks, 2); +} + QList<QQmlDebugClient *> tst_QQmlDebugJS::createClients() { m_client = new QJSDebugClient(m_connection); 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" diff --git a/tests/auto/qml/v4misc/tst_v4misc.cpp b/tests/auto/qml/v4misc/tst_v4misc.cpp index 22ff9c43fc..21a826850b 100644 --- a/tests/auto/qml/v4misc/tst_v4misc.cpp +++ b/tests/auto/qml/v4misc/tst_v4misc.cpp @@ -37,6 +37,9 @@ class tst_v4misc: public QObject private slots: void tdzOptimizations_data(); void tdzOptimizations(); + + void parserMisc_data(); + void parserMisc(); }; void tst_v4misc::tdzOptimizations_data() @@ -102,6 +105,23 @@ void tst_v4misc::tdzOptimizations() } +void tst_v4misc::parserMisc_data() +{ + QTest::addColumn<QString>("error"); + + QTest::newRow("8[++i][+++i]") << QString("ReferenceError: Prefix ++ operator applied to value that is not a reference."); +} + +void tst_v4misc::parserMisc() +{ + QFETCH(QString, error); + + QJSEngine engine; + QJSValue result = engine.evaluate(QString::fromUtf8(QTest::currentDataTag())); + QVERIFY(result.isError()); + QCOMPARE(result.toString(), error); +} + QTEST_MAIN(tst_v4misc); #include "tst_v4misc.moc" |