From 2bb1003ab17a05dfcd7e7ab6424b1b4a7c9b5168 Mon Sep 17 00:00:00 2001 From: Mike Pennisi Date: Mon, 22 Jun 2015 17:16:17 -0400 Subject: [PATCH] Extend test coverage for Promise built-in --- .../Promise/Symbol.species/prop-desc.js | 25 ++++++ .../Promise/Symbol.species/return-value.js | 14 ++++ test/built-ins/Promise/all/ctx-ctor.js | 37 ++++++++ test/built-ins/Promise/all/ctx-non-ctor.js | 20 +++++ test/built-ins/Promise/all/ctx-non-object.js | 36 ++++++++ .../Promise/all/invoke-resolve-get-error.js | 37 ++++++++ test/built-ins/Promise/all/invoke-resolve.js | 52 ++++++++++++ .../Promise/all/invoke-then-error.js | 38 +++++++++ test/built-ins/Promise/all/invoke-then.js | 55 ++++++++++++ test/built-ins/Promise/all/iter-close.js | 46 ++++++++++ .../Promise/all/iter-next-val-err.js | 51 +++++++++++ .../Promise/all/species-get-error.js | 25 ++++++ test/built-ins/Promise/exec-args.js | 33 ++++++++ .../Promise/prototype/catch/invokes-then.js | 52 ++++++++++++ .../Promise/prototype/then/ctor-custom.js | 49 +++++++++++ .../Promise/prototype/then/ctor-null.js | 20 +++++ ...{S25.4.5.3_A3.1_T1.js => ctor-poisoned.js} | 0 .../Promise/prototype/then/ctor-undef.js | 20 +++++ .../then/on-fulfilled-return-poisoned-then.js | 46 ++++++++++ .../on-fulfilled-return-prms-fulfilled.js | 70 ++++++++++++++++ ...filled-return-prms-pending-to-fulfilled.js | 84 +++++++++++++++++++ ...lfilled-return-prms-pending-to-rejected.js | 84 +++++++++++++++++++ .../then/on-fulfilled-return-prms-rejected.js | 70 ++++++++++++++++ .../then/on-fulfilled-return-self.js | 41 +++++++++ .../then/on-fulfilled-return-thenable.js | 70 ++++++++++++++++ .../prototype/then/on-fulfilled-throw.js | 57 +++++++++++++ .../then/on-rejected-return-value.js | 33 ++++++++ .../prototype/then/on-rejected-throw.js | 33 ++++++++ test/built-ins/Promise/race/ctx-ctor.js | 37 ++++++++ test/built-ins/Promise/race/ctx-non-ctor.js | 20 +++++ test/built-ins/Promise/race/ctx-non-object.js | 36 ++++++++ .../Promise/race/invoke-resolve-get-error.js | 36 ++++++++ test/built-ins/Promise/race/invoke-resolve.js | 51 +++++++++++ .../Promise/race/invoke-then-error.js | 37 ++++++++ test/built-ins/Promise/race/invoke-then.js | 55 ++++++++++++ .../Promise/race/iter-next-val-err.js | 50 +++++++++++ .../Promise/race/species-get-error.js | 25 ++++++ test/built-ins/Promise/reject/ctx-ctor.js | 34 ++++++++ test/built-ins/Promise/reject/ctx-non-ctor.js | 16 ++++ .../Promise/reject/ctx-non-object.js | 36 ++++++++ .../Promise/resolve/arg-non-thenable.js | 29 +++++++ .../Promise/resolve/arg-poisoned-then.js | 35 ++++++++ .../Promise/resolve/arg-uniq-ctor.js | 27 ++++++ test/built-ins/Promise/resolve/ctx-ctor.js | 34 ++++++++ .../built-ins/Promise/resolve/ctx-non-ctor.js | 16 ++++ .../Promise/resolve/ctx-non-object.js | 36 ++++++++ 46 files changed, 1808 insertions(+) create mode 100644 test/built-ins/Promise/Symbol.species/prop-desc.js create mode 100644 test/built-ins/Promise/Symbol.species/return-value.js create mode 100644 test/built-ins/Promise/all/ctx-ctor.js create mode 100644 test/built-ins/Promise/all/ctx-non-ctor.js create mode 100644 test/built-ins/Promise/all/ctx-non-object.js create mode 100644 test/built-ins/Promise/all/invoke-resolve-get-error.js create mode 100644 test/built-ins/Promise/all/invoke-resolve.js create mode 100644 test/built-ins/Promise/all/invoke-then-error.js create mode 100644 test/built-ins/Promise/all/invoke-then.js create mode 100644 test/built-ins/Promise/all/iter-close.js create mode 100644 test/built-ins/Promise/all/iter-next-val-err.js create mode 100644 test/built-ins/Promise/all/species-get-error.js create mode 100644 test/built-ins/Promise/exec-args.js create mode 100644 test/built-ins/Promise/prototype/catch/invokes-then.js create mode 100644 test/built-ins/Promise/prototype/then/ctor-custom.js create mode 100644 test/built-ins/Promise/prototype/then/ctor-null.js rename test/built-ins/Promise/prototype/then/{S25.4.5.3_A3.1_T1.js => ctor-poisoned.js} (100%) create mode 100644 test/built-ins/Promise/prototype/then/ctor-undef.js create mode 100644 test/built-ins/Promise/prototype/then/on-fulfilled-return-poisoned-then.js create mode 100644 test/built-ins/Promise/prototype/then/on-fulfilled-return-prms-fulfilled.js create mode 100644 test/built-ins/Promise/prototype/then/on-fulfilled-return-prms-pending-to-fulfilled.js create mode 100644 test/built-ins/Promise/prototype/then/on-fulfilled-return-prms-pending-to-rejected.js create mode 100644 test/built-ins/Promise/prototype/then/on-fulfilled-return-prms-rejected.js create mode 100644 test/built-ins/Promise/prototype/then/on-fulfilled-return-self.js create mode 100644 test/built-ins/Promise/prototype/then/on-fulfilled-return-thenable.js create mode 100644 test/built-ins/Promise/prototype/then/on-fulfilled-throw.js create mode 100644 test/built-ins/Promise/prototype/then/on-rejected-return-value.js create mode 100644 test/built-ins/Promise/prototype/then/on-rejected-throw.js create mode 100644 test/built-ins/Promise/race/ctx-ctor.js create mode 100644 test/built-ins/Promise/race/ctx-non-ctor.js create mode 100644 test/built-ins/Promise/race/ctx-non-object.js create mode 100644 test/built-ins/Promise/race/invoke-resolve-get-error.js create mode 100644 test/built-ins/Promise/race/invoke-resolve.js create mode 100644 test/built-ins/Promise/race/invoke-then-error.js create mode 100644 test/built-ins/Promise/race/invoke-then.js create mode 100644 test/built-ins/Promise/race/iter-next-val-err.js create mode 100644 test/built-ins/Promise/race/species-get-error.js create mode 100644 test/built-ins/Promise/reject/ctx-ctor.js create mode 100644 test/built-ins/Promise/reject/ctx-non-ctor.js create mode 100644 test/built-ins/Promise/reject/ctx-non-object.js create mode 100644 test/built-ins/Promise/resolve/arg-non-thenable.js create mode 100644 test/built-ins/Promise/resolve/arg-poisoned-then.js create mode 100644 test/built-ins/Promise/resolve/arg-uniq-ctor.js create mode 100644 test/built-ins/Promise/resolve/ctx-ctor.js create mode 100644 test/built-ins/Promise/resolve/ctx-non-ctor.js create mode 100644 test/built-ins/Promise/resolve/ctx-non-object.js diff --git a/test/built-ins/Promise/Symbol.species/prop-desc.js b/test/built-ins/Promise/Symbol.species/prop-desc.js new file mode 100644 index 0000000000..3f0770773e --- /dev/null +++ b/test/built-ins/Promise/Symbol.species/prop-desc.js @@ -0,0 +1,25 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 25.4.4.6 +description: Promise `Symbol.species` property +info: > + Promise[@@species] is an accessor property whose set accessor function is + undefined. + + ES6 Section 17: + + Every accessor property described in clauses 18 through 26 and in Annex B.2 + has the attributes {[[Enumerable]]: false, [[Configurable]]: true } unless + otherwise specified. +features: [Symbol.species] +includes: [propertyHelper.js] +---*/ + +var desc = Object.getOwnPropertyDescriptor(Promise, Symbol.species); + +assert.sameValue(desc.set, undefined); +assert.sameValue(typeof desc.get, 'function'); + +verifyNotEnumerable(Promise, Symbol.species); +verifyConfigurable(Promise, Symbol.species); diff --git a/test/built-ins/Promise/Symbol.species/return-value.js b/test/built-ins/Promise/Symbol.species/return-value.js new file mode 100644 index 0000000000..f2d8aaeb5a --- /dev/null +++ b/test/built-ins/Promise/Symbol.species/return-value.js @@ -0,0 +1,14 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 25.4.4.6 +description: Promise `Symbol.species` accessor function return value +info: > + 1. Return the this value. +features: [Symbol.species] +---*/ + +var desc = Object.getOwnPropertyDescriptor(Promise, Symbol.species); +var thisValue = {}; + +assert.sameValue(desc.get.call(thisValue), thisValue); diff --git a/test/built-ins/Promise/all/ctx-ctor.js b/test/built-ins/Promise/all/ctx-ctor.js new file mode 100644 index 0000000000..83c0d53e99 --- /dev/null +++ b/test/built-ins/Promise/all/ctx-ctor.js @@ -0,0 +1,37 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + `Promise.all` invoked on a constructor value +es6id: 25.4.4.1 +info: > + 1. Let C be the this value. + [...] + 6. Let promiseCapability be NewPromiseCapability(C). + [...] + 10. Let iteratorRecord be Record {[[iterator]]: iterator, [[done]]: false}. + 11. Let result be PerformPromiseAll(iteratorRecord, C, promiseCapability). + [...] + 13. Return Completion(result). +features: [class] +---*/ + +var executor = null; +var callCount = 0; + +class SubPromise extends Promise { + constructor(a) { + super(a); + executor = a; + callCount += 1; + } +} + +var instance = Promise.all.call(SubPromise); + +assert.sameValue(instance.constructor, SubPromise); +assert.sameValue(instance instanceof SubPromise, true); + +assert.sameValue(callCount, 1); +assert.sameValue(typeof executor, 'function'); diff --git a/test/built-ins/Promise/all/ctx-non-ctor.js b/test/built-ins/Promise/all/ctx-non-ctor.js new file mode 100644 index 0000000000..89c885b3ba --- /dev/null +++ b/test/built-ins/Promise/all/ctx-non-ctor.js @@ -0,0 +1,20 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + `Promise.all` invoked on a non-constructor value +es6id: 25.4.4.1 +info: > + [...] + 6. Let promiseCapability be NewPromiseCapability(C). + 7. ReturnIfAbrupt(promiseCapability). + + 25.4.1.5 NewPromiseCapability ( C ) + + 1. If IsConstructor(C) is false, throw a TypeError exception. +---*/ + +assert.throws(TypeError, function() { + Promise.all.call(eval); +}); diff --git a/test/built-ins/Promise/all/ctx-non-object.js b/test/built-ins/Promise/all/ctx-non-object.js new file mode 100644 index 0000000000..d909bb7623 --- /dev/null +++ b/test/built-ins/Promise/all/ctx-non-object.js @@ -0,0 +1,36 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + `Promise.all` invoked on a non-object value +es6id: 25.4.4.1 +info: > + 1. Let C be the this value. + 2. If Type(C) is not Object, throw a TypeError exception. +features: [Symbol] +---*/ + +assert.throws(TypeError, function() { + Promise.all.call(undefined, []); +}); + +assert.throws(TypeError, function() { + Promise.all.call(null, []); +}); + +assert.throws(TypeError, function() { + Promise.all.call(86, []); +}); + +assert.throws(TypeError, function() { + Promise.all.call('string', []); +}); + +assert.throws(TypeError, function() { + Promise.all.call(true, []); +}); + +assert.throws(TypeError, function() { + Promise.all.call(Symbol(), []); +}); diff --git a/test/built-ins/Promise/all/invoke-resolve-get-error.js b/test/built-ins/Promise/all/invoke-resolve-get-error.js new file mode 100644 index 0000000000..d7b7a092ca --- /dev/null +++ b/test/built-ins/Promise/all/invoke-resolve-get-error.js @@ -0,0 +1,37 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Error retrieving the constructor's `resolve` method +es6id: 25.4.4.1 +info: > + 11. Let result be PerformPromiseAll(iteratorRecord, C, promiseCapability). + 12. If result is an abrupt completion, + a. If iteratorRecord.[[done]] is false, let result be + IteratorClose(iterator, result). + b. IfAbruptRejectPromise(result, promiseCapability). + + [...] + + 25.4.4.1.1 Runtime Semantics: PerformPromiseAll + + [...] + 6. Repeat + [...] + i. Let nextPromise be Invoke(constructor, "resolve", «nextValue»). + j. ReturnIfAbrupt(nextPromise ). +---*/ + +var error = new Test262Error(); +Object.defineProperty(Promise, 'resolve', { + get: function() { + throw error; + } +}); + +Promise.all([new Promise(function() {})]).then(function() { + $ERROR('The promise should be rejected'); +}, function(reason) { + assert.sameValue(reason, error); +}).then($DONE, $DONE); diff --git a/test/built-ins/Promise/all/invoke-resolve.js b/test/built-ins/Promise/all/invoke-resolve.js new file mode 100644 index 0000000000..64ef8f2ca9 --- /dev/null +++ b/test/built-ins/Promise/all/invoke-resolve.js @@ -0,0 +1,52 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Invocation of the constructor's `resolve` method +es6id: 25.4.4.1 +info: > + 11. Let result be PerformPromiseAll(iteratorRecord, C, promiseCapability). + + [...] + + 25.4.4.1.1 Runtime Semantics: PerformPromiseAll + + [...] + 6. Repeat + [...] + i. Let nextPromise be Invoke(constructor, "resolve", «nextValue»). +---*/ + +var p1 = new Promise(function() {}); +var p2 = new Promise(function() {}); +var p3 = new Promise(function() {}); +var resolve = Promise.resolve; +var callCount = 0; +var current = p1; +var next = p2; +var afterNext = p3; + +Promise.resolve = function(nextValue) { + assert.sameValue( + nextValue, current, '`resolve` invoked with next iterated value' + ); + assert.sameValue( + arguments.length, 1, '`resolve` invoked with a single argument' + ); + assert.sameValue(this, Promise, '`this` value is the constructor'); + + current = next; + next = afterNext; + afterNext = null; + + callCount += 1; + + return resolve.apply(Promise, arguments); +}; + +Promise.all([p1, p2, p3]); + +assert.sameValue( + callCount, 3, '`resolve` invoked once for each iterated value' +); diff --git a/test/built-ins/Promise/all/invoke-then-error.js b/test/built-ins/Promise/all/invoke-then-error.js new file mode 100644 index 0000000000..957093f2b5 --- /dev/null +++ b/test/built-ins/Promise/all/invoke-then-error.js @@ -0,0 +1,38 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Error thrown when invoking the instance's `then` method +es6id: 25.4.4.1 +info: > + 11. Let result be PerformPromiseAll(iteratorRecord, C, promiseCapability). + 12. If result is an abrupt completion, + a. If iteratorRecord.[[done]] is false, let result be + IteratorClose(iterator, result). + b. IfAbruptRejectPromise(result, promiseCapability). + + [...] + + 25.4.4.1.1 Runtime Semantics: PerformPromiseAll + + [...] + 6. Repeat + [...] + r. Let result be Invoke(nextPromise, "then", «resolveElement, + resultCapability.[[Reject]]»). + s. ReturnIfAbrupt(result). +---*/ + +var promise = new Promise(function() {}); +var error = new Test262Error(); + +promise.then = function() { + throw error; +}; + +Promise.all([promise]).then(function() { + $ERROR('The promise should be rejected'); +}, function(reason) { + assert.sameValue(reason, error); +}).then($DONE, $DONE); diff --git a/test/built-ins/Promise/all/invoke-then.js b/test/built-ins/Promise/all/invoke-then.js new file mode 100644 index 0000000000..e641889642 --- /dev/null +++ b/test/built-ins/Promise/all/invoke-then.js @@ -0,0 +1,55 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Invocation of the instance's `then` method +es6id: 25.4.4.1 +info: > + 11. Let result be PerformPromiseAll(iteratorRecord, C, promiseCapability). + + [...] + + 25.4.4.1.1 Runtime Semantics: PerformPromiseAll + + [...] + 6. Repeat + [...] + r. Let result be Invoke(nextPromise, "then", «resolveElement, + resultCapability.[[Reject]]»). +---*/ + +var p1 = new Promise(function() {}); +var p2 = new Promise(function() {}); +var p3 = new Promise(function() {}); +var callCount = 0; +var currentThis = p1; +var nextThis = p2; +var afterNextThis = p3; + +p1.then = p2.then = p3.then = function(a, b) { + assert.sameValue(typeof a, 'function', 'type of first argument'); + assert.sameValue( + a.length, + 1, + 'ES6 25.4.1.3.2: The length property of a promise resolve function is 1.' + ); + assert.sameValue(typeof b, 'function', 'type of second argument'); + assert.sameValue( + b.length, + 1, + 'ES6 25.4.1.3.1: The length property of a promise reject function is 1.' + ); + assert.sameValue(arguments.length, 2, '`then` invoked with two arguments'); + assert.sameValue(this, currentThis, '`this` value'); + + currentThis = nextThis; + nextThis = afterNextThis; + afterNextThis = null; + + callCount += 1; +}; + +Promise.all([p1, p2, p3]); + +assert.sameValue(callCount, 3, '`then` invoked once for every iterated value'); diff --git a/test/built-ins/Promise/all/iter-close.js b/test/built-ins/Promise/all/iter-close.js new file mode 100644 index 0000000000..9496ca7de9 --- /dev/null +++ b/test/built-ins/Promise/all/iter-close.js @@ -0,0 +1,46 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Explicit iterator closing in response to error +es6id: 25.4.4.1 +info: > + 11. Let result be PerformPromiseAll(iteratorRecord, C, promiseCapability). + 12. If result is an abrupt completion, + a. If iteratorRecord.[[done]] is false, let result be + IteratorClose(iterator, result). + b. IfAbruptRejectPromise(result, promiseCapability). + + [...] + + 25.4.4.1.1 Runtime Semantics: PerformPromiseAll + + [...] + 6. Repeat + [...] + i. Let nextPromise be Invoke(constructor, "resolve", «nextValue»). + j. ReturnIfAbrupt(nextPromise ). +features: [Symbol.iterator] +---*/ + +var iterDoneSpy = {}; +var callCount = 0; +iterDoneSpy[Symbol.iterator] = function() { + return { + next: function() { + return { value: null, done: false }; + }, + return: function() { + callCount += 1; + } + }; +}; + +Promise.resolve = function() { + throw new Error(); +}; + +Promise.all(iterDoneSpy); + +assert.sameValue(callCount, 1); diff --git a/test/built-ins/Promise/all/iter-next-val-err.js b/test/built-ins/Promise/all/iter-next-val-err.js new file mode 100644 index 0000000000..902e7823e8 --- /dev/null +++ b/test/built-ins/Promise/all/iter-next-val-err.js @@ -0,0 +1,51 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Error when accessing an iterator result's `value` property +es6id: 25.4.4.1 +info: > + 11. Let result be PerformPromiseAll(iteratorRecord, C, promiseCapability). + 12. If result is an abrupt completion, + a. If iteratorRecord.[[done]] is false, let result be + IteratorClose(iterator, result). + b. IfAbruptRejectPromise(result, promiseCapability). + + [...] + + 25.4.4.1.1 Runtime Semantics: PerformPromiseAll + + [...] + 6. Repeat + [...] + e. Let nextValue be IteratorValue(next). + f. If nextValue is an abrupt completion, set iteratorRecord.[[done]] to + true. + g. ReturnIfAbrupt(nextValue). +features: [Symbol.iterator] +---*/ + +var iterNextValThrows = {}; +var poisonedVal = { + done: false +}; +var error = new Test262Error(); +Object.defineProperty(poisonedVal, 'value', { + get: function() { + throw error; + } +}); +iterNextValThrows[Symbol.iterator] = function() { + return { + next: function() { + return poisonedVal; + } + }; +}; + +Promise.all(iterNextValThrows).then(function() { + $ERROR('The promise should be rejected.'); +}, function(reason) { + assert.sameValue(reason, error); +}).then($DONE, $DONE); diff --git a/test/built-ins/Promise/all/species-get-error.js b/test/built-ins/Promise/all/species-get-error.js new file mode 100644 index 0000000000..2deb108382 --- /dev/null +++ b/test/built-ins/Promise/all/species-get-error.js @@ -0,0 +1,25 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Error thrown when retrieving `Symbol.species` property of the `this` value +es6id: 25.4.4.1 +info: > + 1. Let C be the this value. + 2. If Type(C) is not Object, throw a TypeError exception. + 3. Let S be Get(C, @@species). + 4. ReturnIfAbrupt(S). +features: [Symbol.species] +---*/ + +var C = {}; +Object.defineProperty(C, Symbol.species, { + get: function() { + throw new Test262Error(); + } +}); + +assert.throws(Test262Error, function() { + Promise.all.call(C); +}); diff --git a/test/built-ins/Promise/exec-args.js b/test/built-ins/Promise/exec-args.js new file mode 100644 index 0000000000..524c1edaa2 --- /dev/null +++ b/test/built-ins/Promise/exec-args.js @@ -0,0 +1,33 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +es6id: 25.4.3.1 +description: Promise executor is invoked synchronously +info: > + 9. Let completion be Call(executor, undefined, + «resolvingFunctions.[[Resolve]], resolvingFunctions.[[Reject]]»). + + 25.4.1.3.2 Promise Resolve Functions + + The length property of a promise resolve function is 1. + + 25.4.1.3.1 Promise Reject Functions + + The length property of a promise reject function is 1. +---*/ + +var callCount = 0; +var resolve, reject, argCount; + +new Promise(function(a, b) { + resolve = a; + reject = b; + argCount = arguments.length; +}); + +assert.sameValue(typeof resolve, 'function', 'type of first argument'); +assert.sameValue(resolve.length, 1, 'length of first argument'); +assert.sameValue(typeof reject, 'function', 'type of second argument'); +assert.sameValue(reject.length, 1, 'length of second argument'); +assert.sameValue(argCount, 2); diff --git a/test/built-ins/Promise/prototype/catch/invokes-then.js b/test/built-ins/Promise/prototype/catch/invokes-then.js new file mode 100644 index 0000000000..8c05f64578 --- /dev/null +++ b/test/built-ins/Promise/prototype/catch/invokes-then.js @@ -0,0 +1,52 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 25.4.5.1 +description: Promise.prototype.catch invokes `then` method +info: > + 1. Let promise be the this value. + 2. Return Invoke(promise, "then", «undefined, onRejected»). +---*/ + +var target = {}; +var returnValue = {}; +var callCount = 0; +var thisValue = null; +var argCount = null; +var firstArg = null; +var secondArg = null; +var result = null; + +target.then = function(a, b) { + callCount += 1; + + thisValue = this; + argCount = arguments.length; + firstArg = a; + secondArg = b; + + return returnValue; +}; + +result = Promise.prototype.catch.call(target, 1, 2, 3); + +assert.sameValue(callCount, 1, 'Invokes `then` method exactly once'); +assert.sameValue( + thisValue, + target, + 'Invokes `then` method with the instance as the `this` value' +); +assert.sameValue( + argCount, 2, 'Invokes `then` method with exactly two single arguments' +); +assert.sameValue( + firstArg, + undefined, + 'Invokes `then` method with `undefined` as the first argument' +); +assert.sameValue( + secondArg, 1, 'Invokes `then` method with the provided argument' +); +assert.sameValue( + result, returnValue, 'Returns the result of the invocation of `then`' +); diff --git a/test/built-ins/Promise/prototype/then/ctor-custom.js b/test/built-ins/Promise/prototype/then/ctor-custom.js new file mode 100644 index 0000000000..246d7914ab --- /dev/null +++ b/test/built-ins/Promise/prototype/then/ctor-custom.js @@ -0,0 +1,49 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 25.4.5.3 +description: The constructor defined by Symbol.species takes precedence +info: > + 1. Let promise be the this value. + 2. If IsPromise(promise) is false, throw a TypeError exception. + 3. Let C be SpeciesConstructor(promise, %Promise%). + 4. ReturnIfAbrupt(C). + 5. Let resultCapability be NewPromiseCapability(C). +features: [Symbol.species, class] +---*/ + +var callCount = 0; +var thisValue, firstArg, argLength, getCapabilitiesExecutor; +var executor = function() {}; +var p1 = new Promise(function() {}); +var SpeciesConstructor = class extends Promise { + constructor(a) { + super(a); + callCount += 1; + thisValue = this; + getCapabilitiesExecutor = a; + argLength = arguments.length; + } +}; +var p2; + +p1.constructor = function() {}; +p1.constructor[Symbol.species] = SpeciesConstructor; + +p2 = p1.then(); + +assert.sameValue(callCount, 1, 'The constructor is invoked exactly once'); +assert(thisValue instanceof SpeciesConstructor); +assert.sameValue( + argLength, 1, 'The constructor is invoked with a single argument' +); +assert.sameValue(typeof getCapabilitiesExecutor, 'function'); +assert.sameValue( + getCapabilitiesExecutor.length, + 2, + 'ES6 25.4.1.5.1: The length property of a GetCapabilitiesExecutor function is 2.' +); +assert( + p2 instanceof SpeciesConstructor, + 'The returned object is an instance of the constructor' +); diff --git a/test/built-ins/Promise/prototype/then/ctor-null.js b/test/built-ins/Promise/prototype/then/ctor-null.js new file mode 100644 index 0000000000..11f4eca545 --- /dev/null +++ b/test/built-ins/Promise/prototype/then/ctor-null.js @@ -0,0 +1,20 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 25.4.5.3 +description: > + A TypeError is thrown when the `this` value has a non-object `constructor` property +info: > + 1. Let promise be the this value. + 2. If IsPromise(promise) is false, throw a TypeError exception. + 3. Let C be SpeciesConstructor(promise, %Promise%). + 4. ReturnIfAbrupt(C). + 5. Let resultCapability be NewPromiseCapability(C). +---*/ + +var p = new Promise(function() {}); +p.constructor = null; + +assert.throws(TypeError, function() { + p.then(); +}); diff --git a/test/built-ins/Promise/prototype/then/S25.4.5.3_A3.1_T1.js b/test/built-ins/Promise/prototype/then/ctor-poisoned.js similarity index 100% rename from test/built-ins/Promise/prototype/then/S25.4.5.3_A3.1_T1.js rename to test/built-ins/Promise/prototype/then/ctor-poisoned.js diff --git a/test/built-ins/Promise/prototype/then/ctor-undef.js b/test/built-ins/Promise/prototype/then/ctor-undef.js new file mode 100644 index 0000000000..eae1c4c1d1 --- /dev/null +++ b/test/built-ins/Promise/prototype/then/ctor-undef.js @@ -0,0 +1,20 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 25.4.5.3 +description: > + The Promise built-in is used when the `this` value has no `constructor` property +info: > + 1. Let promise be the this value. + 2. If IsPromise(promise) is false, throw a TypeError exception. + 3. Let C be SpeciesConstructor(promise, %Promise%). + 4. ReturnIfAbrupt(C). + 5. Let resultCapability be NewPromiseCapability(C). +---*/ + +var p1 = new Promise(function() {}); +delete p1.constructor; + +var p2 = p1.then(); + +assert(p2 instanceof Promise); diff --git a/test/built-ins/Promise/prototype/then/on-fulfilled-return-poisoned-then.js b/test/built-ins/Promise/prototype/then/on-fulfilled-return-poisoned-then.js new file mode 100644 index 0000000000..1b6fcb0c63 --- /dev/null +++ b/test/built-ins/Promise/prototype/then/on-fulfilled-return-poisoned-then.js @@ -0,0 +1,46 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 25.4.5.3 +description: > + Access error for the `then` property of the object returned from the "on fulfilled" handler +info: > + 7. Return PerformPromiseThen(promise, onFulfilled, onRejected, + resultCapability). + + 25.4.5.3.1 PerformPromiseThen + + [...] + 8. Else if the value of promise's [[PromiseState]] internal slot is + "fulfilled", + a. Let value be the value of promise's [[PromiseResult]] internal slot. + b. Perform EnqueueJob("PromiseJobs", PromiseReactionJob, + «fulfillReaction, value»). + + 25.4.1.3.2 Promise Resolve Functions + + [...] + 8. Let then be Get(resolution, "then"). + 9. If then is an abrupt completion, then + a. Return RejectPromise(promise, then.[[value]]). +---*/ + +var poisonedThen = {}; +var error = new Test262Error(); +Object.defineProperty(poisonedThen, 'then', { + get: function() { + throw error; + } +}); + +var p = new Promise(function(r) { r(); }); + +p.then(function() { + return poisonedThen; +}).then(function() { + $DONE('The promise should not be fulfilled'); +}, function(reason) { + assert.sameValue(reason, error); + + $DONE(); +}); diff --git a/test/built-ins/Promise/prototype/then/on-fulfilled-return-prms-fulfilled.js b/test/built-ins/Promise/prototype/then/on-fulfilled-return-prms-fulfilled.js new file mode 100644 index 0000000000..4e63f8502d --- /dev/null +++ b/test/built-ins/Promise/prototype/then/on-fulfilled-return-prms-fulfilled.js @@ -0,0 +1,70 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 25.4.5.3 +description: The return value of the `onFulfilled` method is a fulfilled promise +info: > + 7. Return PerformPromiseThen(promise, onFulfilled, onRejected, + resultCapability). + + 25.4.5.3.1 PerformPromiseThen + + [...] + 8. Else if the value of promise's [[PromiseState]] internal slot is + "fulfilled", + a. Let value be the value of promise's [[PromiseResult]] internal slot. + b. Perform EnqueueJob("PromiseJobs", PromiseReactionJob, + «fulfillReaction, value»). + + 25.4.1.3.2 Promise Resolve Functions + + [...] + 8. Let then be Get(resolution, "then"). + 9. If then is an abrupt completion, then + a. Return RejectPromise(promise, then.[[value]]). + 10. Let thenAction be then.[[value]]. + 11. If IsCallable(thenAction) is false, then + a. Return FulfillPromise(promise, resolution). + 12. Perform EnqueueJob ("PromiseJobs", PromiseResolveThenableJob, «promise, + resolution, thenAction») + 13. Return undefined. +---*/ + +var executor1Counter = 0; +var thenCounter = 0; +var executor2Counter = 0; +var promise = new Promise(function(resolve) { + resolve(); + + assert.sameValue(executor1Counter, 0); + assert.sameValue(thenCounter, 0); + assert.sameValue(executor2Counter, 0); + + executor1Counter += 1; + }); + +promise.then(function() { + assert.sameValue(executor1Counter, 1); + assert.sameValue(thenCounter, 0); + assert.sameValue(executor2Counter, 0); + + thenCounter += 1; + + return new Promise(function(resolve) { + resolve(); + + assert.sameValue(executor1Counter, 1); + assert.sameValue(thenCounter, 1); + assert.sameValue(executor2Counter, 0); + + executor2Counter += 1; + }); + }).then(function() { + assert.sameValue(executor1Counter, 1); + assert.sameValue(thenCounter, 1); + assert.sameValue(executor2Counter, 1); + + $DONE(); + }, function() { + $DONE('The promise should not be rejected'); + }); diff --git a/test/built-ins/Promise/prototype/then/on-fulfilled-return-prms-pending-to-fulfilled.js b/test/built-ins/Promise/prototype/then/on-fulfilled-return-prms-pending-to-fulfilled.js new file mode 100644 index 0000000000..ff0791c5e3 --- /dev/null +++ b/test/built-ins/Promise/prototype/then/on-fulfilled-return-prms-pending-to-fulfilled.js @@ -0,0 +1,84 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 25.4.5.3 +description: The return value of the `onFulfilled` method is a pending promise +info: > + 7. Return PerformPromiseThen(promise, onFulfilled, onRejected, + resultCapability). + + 25.4.5.3.1 PerformPromiseThen + + [...] + 8. Else if the value of promise's [[PromiseState]] internal slot is + "fulfilled", + a. Let value be the value of promise's [[PromiseResult]] internal slot. + b. Perform EnqueueJob("PromiseJobs", PromiseReactionJob, + «fulfillReaction, value»). + + 25.4.1.3.2 Promise Resolve Functions + + [...] + 8. Let then be Get(resolution, "then"). + 9. If then is an abrupt completion, then + a. Return RejectPromise(promise, then.[[value]]). + 10. Let thenAction be then.[[value]]. + 11. If IsCallable(thenAction) is false, then + a. Return FulfillPromise(promise, resolution). + 12. Perform EnqueueJob ("PromiseJobs", PromiseResolveThenableJob, «promise, + resolution, thenAction») + 13. Return undefined. +---*/ + +var executor1Counter = 0; +var then1Counter = 0; +var executor2Counter = 0; +var then2Counter = 0; +var promise = new Promise(function(resolve) { + resolve(); + + assert.sameValue(executor1Counter, 0); + assert.sameValue(then1Counter, 0); + assert.sameValue(executor2Counter, 0); + assert.sameValue(then2Counter, 0); + + executor1Counter += 1; + }); + +promise.then(function() { + assert.sameValue(executor1Counter, 1); + assert.sameValue(then1Counter, 0); + assert.sameValue(executor2Counter, 0); + assert.sameValue(then2Counter, 0); + + then1Counter += 1; + + return new Promise(function(resolve) { + promise.then(function() { + resolve(); + + assert.sameValue(executor1Counter, 1); + assert.sameValue(then1Counter, 1); + assert.sameValue(executor2Counter, 1); + assert.sameValue(then2Counter, 0); + + then2Counter += 1; + }); + + assert.sameValue(executor1Counter, 1); + assert.sameValue(then1Counter, 1); + assert.sameValue(executor2Counter, 0); + assert.sameValue(then2Counter, 0); + + executor2Counter += 1; + }); + }).then(function() { + assert.sameValue(executor1Counter, 1); + assert.sameValue(then1Counter, 1); + assert.sameValue(executor2Counter, 1); + assert.sameValue(then2Counter, 1); + + $DONE(); + }, function() { + $DONE('The promise should not be rejected'); + }); diff --git a/test/built-ins/Promise/prototype/then/on-fulfilled-return-prms-pending-to-rejected.js b/test/built-ins/Promise/prototype/then/on-fulfilled-return-prms-pending-to-rejected.js new file mode 100644 index 0000000000..2b3613c7be --- /dev/null +++ b/test/built-ins/Promise/prototype/then/on-fulfilled-return-prms-pending-to-rejected.js @@ -0,0 +1,84 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 25.4.5.3 +description: The return value of the `onFulfilled` method is a pending promise +info: > + 7. Return PerformPromiseThen(promise, onFulfilled, onRejected, + resultCapability). + + 25.4.5.3.1 PerformPromiseThen + + [...] + 8. Else if the value of promise's [[PromiseState]] internal slot is + "fulfilled", + a. Let value be the value of promise's [[PromiseResult]] internal slot. + b. Perform EnqueueJob("PromiseJobs", PromiseReactionJob, + «fulfillReaction, value»). + + 25.4.1.3.2 Promise Resolve Functions + + [...] + 8. Let then be Get(resolution, "then"). + 9. If then is an abrupt completion, then + a. Return RejectPromise(promise, then.[[value]]). + 10. Let thenAction be then.[[value]]. + 11. If IsCallable(thenAction) is false, then + a. Return FulfillPromise(promise, resolution). + 12. Perform EnqueueJob ("PromiseJobs", PromiseResolveThenableJob, «promise, + resolution, thenAction») + 13. Return undefined. +---*/ + +var executor1Counter = 0; +var then1Counter = 0; +var executor2Counter = 0; +var then2Counter = 0; +var promise = new Promise(function(resolve) { + resolve(); + + assert.sameValue(executor1Counter, 0); + assert.sameValue(then1Counter, 0); + assert.sameValue(executor2Counter, 0); + assert.sameValue(then2Counter, 0); + + executor1Counter += 1; + }); + +promise.then(function() { + assert.sameValue(executor1Counter, 1); + assert.sameValue(then1Counter, 0); + assert.sameValue(executor2Counter, 0); + assert.sameValue(then2Counter, 0); + + then1Counter += 1; + + return new Promise(function(_, reject) { + promise.then(function() { + reject(); + + assert.sameValue(executor1Counter, 1); + assert.sameValue(then1Counter, 1); + assert.sameValue(executor2Counter, 1); + assert.sameValue(then2Counter, 0); + + then2Counter += 1; + }); + + assert.sameValue(executor1Counter, 1); + assert.sameValue(then1Counter, 1); + assert.sameValue(executor2Counter, 0); + assert.sameValue(then2Counter, 0); + + executor2Counter += 1; + }); + }).then(function() { + $DONE('The promise should not be fulfilled'); + }, function() { + assert.sameValue(executor1Counter, 1); + assert.sameValue(then1Counter, 1); + assert.sameValue(executor2Counter, 1); + assert.sameValue(then2Counter, 1); + + $DONE(); + }); diff --git a/test/built-ins/Promise/prototype/then/on-fulfilled-return-prms-rejected.js b/test/built-ins/Promise/prototype/then/on-fulfilled-return-prms-rejected.js new file mode 100644 index 0000000000..47948dc480 --- /dev/null +++ b/test/built-ins/Promise/prototype/then/on-fulfilled-return-prms-rejected.js @@ -0,0 +1,70 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 25.4.5.3 +description: The return value of the `onFulfilled` method is a rejected promise +info: > + 7. Return PerformPromiseThen(promise, onFulfilled, onRejected, + resultCapability). + + 25.4.5.3.1 PerformPromiseThen + + [...] + 8. Else if the value of promise's [[PromiseState]] internal slot is + "fulfilled", + a. Let value be the value of promise's [[PromiseResult]] internal slot. + b. Perform EnqueueJob("PromiseJobs", PromiseReactionJob, + «fulfillReaction, value»). + + 25.4.1.3.2 Promise Resolve Functions + + [...] + 8. Let then be Get(resolution, "then"). + 9. If then is an abrupt completion, then + a. Return RejectPromise(promise, then.[[value]]). + 10. Let thenAction be then.[[value]]. + 11. If IsCallable(thenAction) is false, then + a. Return FulfillPromise(promise, resolution). + 12. Perform EnqueueJob ("PromiseJobs", PromiseResolveThenableJob, «promise, + resolution, thenAction») + 13. Return undefined. +---*/ + +var executor1Counter = 0; +var thenCounter = 0; +var executor2Counter = 0; +var promise = new Promise(function(resolve) { + resolve(); + + assert.sameValue(executor1Counter, 0); + assert.sameValue(thenCounter, 0); + assert.sameValue(executor2Counter, 0); + + executor1Counter += 1; + }); + +promise.then(function() { + assert.sameValue(executor1Counter, 1); + assert.sameValue(thenCounter, 0); + assert.sameValue(executor2Counter, 0); + + thenCounter += 1; + + return new Promise(function(_, reject) { + reject(); + + assert.sameValue(executor1Counter, 1); + assert.sameValue(thenCounter, 1); + assert.sameValue(executor2Counter, 0); + + executor2Counter += 1; + }); + }).then(function() { + $DONE('The promise should not be fulfilled'); + }, function() { + assert.sameValue(executor1Counter, 1); + assert.sameValue(thenCounter, 1); + assert.sameValue(executor2Counter, 1); + + $DONE(); + }); diff --git a/test/built-ins/Promise/prototype/then/on-fulfilled-return-self.js b/test/built-ins/Promise/prototype/then/on-fulfilled-return-self.js new file mode 100644 index 0000000000..42e2588ef4 --- /dev/null +++ b/test/built-ins/Promise/prototype/then/on-fulfilled-return-self.js @@ -0,0 +1,41 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 25.4.5.3 +description: The return value of the `onFulfilled` method is a "thenable" object +info: > + 7. Return PerformPromiseThen(promise, onFulfilled, onRejected, + resultCapability). + + 25.4.5.3.1 PerformPromiseThen + + [...] + 8. Else if the value of promise's [[PromiseState]] internal slot is + "fulfilled", + a. Let value be the value of promise's [[PromiseResult]] internal slot. + b. Perform EnqueueJob("PromiseJobs", PromiseReactionJob, + «fulfillReaction, value»). + + 25.4.1.3.2 Promise Resolve Functions + + [...] + 6. If SameValue(resolution, promise) is true, then + a. Let selfResolutionError be a newly created TypeError object. + b. Return RejectPromise(promise, selfResolutionError). +---*/ + +var promise1 = new Promise(function(resolve) { + resolve(); +}); + +var promise2 = promise1.then(function() { + return promise2; +}); + +promise2.then(function() { + $DONE('This promise should not be resolved'); +}, function(reason) { + assert.sameValue(reason.constructor, TypeError); + + $DONE(); +}); diff --git a/test/built-ins/Promise/prototype/then/on-fulfilled-return-thenable.js b/test/built-ins/Promise/prototype/then/on-fulfilled-return-thenable.js new file mode 100644 index 0000000000..1a7974b718 --- /dev/null +++ b/test/built-ins/Promise/prototype/then/on-fulfilled-return-thenable.js @@ -0,0 +1,70 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 25.4.5.3 +description: The return value of the `onFulfilled` method is a "thenable" object +info: > + 7. Return PerformPromiseThen(promise, onFulfilled, onRejected, + resultCapability). + + 25.4.5.3.1 PerformPromiseThen + + [...] + 8. Else if the value of promise's [[PromiseState]] internal slot is + "fulfilled", + a. Let value be the value of promise's [[PromiseResult]] internal slot. + b. Perform EnqueueJob("PromiseJobs", PromiseReactionJob, + «fulfillReaction, value»). + + 25.4.1.3.2 Promise Resolve Functions + + [...] + 8. Let then be Get(resolution, "then"). + 9. If then is an abrupt completion, then + a. Return RejectPromise(promise, then.[[value]]). + 10. Let thenAction be then.[[value]]. + 11. If IsCallable(thenAction) is false, then + a. Return FulfillPromise(promise, resolution). + 12. Perform EnqueueJob ("PromiseJobs", PromiseResolveThenableJob, «promise, + resolution, thenAction») + 13. Return undefined. +---*/ + +var callCount = 0; +var promise = new Promise(function(resolve) { + resolve(); +}); + +var thenable = { + then: function(resolve, reject) { + assert.sameValue( + this, thenable, 'method invoked with correct `this` value' + ); + assert.sameValue(typeof resolve, 'function', 'type of first argument'); + assert.sameValue( + resolve.length, + 1, + 'ES6 25.4.1.3.2: The length property of a promise resolve function is 1.' + ); + assert.sameValue(typeof reject, 'function', 'type of second argument'); + assert.sameValue( + reject.length, + 1, + 'ES6 25.4.1.3.1: The length property of a promise reject function is 1.' + ); + assert.sameValue(arguments.length, 2, 'total number of arguments'); + resolve(); + + callCount += 1; + } +}; + +promise.then(function() { + return thenable; +}).then(function() { + assert.sameValue(callCount, 1); + + $DONE(); +}, function() { + $DONE('This promise should not be rejected'); +}); diff --git a/test/built-ins/Promise/prototype/then/on-fulfilled-throw.js b/test/built-ins/Promise/prototype/then/on-fulfilled-throw.js new file mode 100644 index 0000000000..434cd57953 --- /dev/null +++ b/test/built-ins/Promise/prototype/then/on-fulfilled-throw.js @@ -0,0 +1,57 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 25.4.5.3 +description: The `onFulfilled` method throws an error +info: > + 7. Return PerformPromiseThen(promise, onFulfilled, onRejected, + resultCapability). + + 25.4.5.3.1 PerformPromiseThen + + [...] + 8. Else if the value of promise's [[PromiseState]] internal slot is + "fulfilled", + a. Let value be the value of promise's [[PromiseResult]] internal slot. + b. Perform EnqueueJob("PromiseJobs", PromiseReactionJob, + «fulfillReaction, value»). + + 25.4.1.3.2 Promise Resolve Functions + + [...] + 8. Let then be Get(resolution, "then"). + 9. If then is an abrupt completion, then + a. Return RejectPromise(promise, then.[[value]]). + 10. Let thenAction be then.[[value]]. + 11. If IsCallable(thenAction) is false, then + a. Return FulfillPromise(promise, resolution). + 12. Perform EnqueueJob ("PromiseJobs", PromiseResolveThenableJob, «promise, + resolution, thenAction») + 13. Return undefined. + + 25.4.2.2 PromiseResolveThenableJob + + 2. Let thenCallResult be Call(then, thenable, + «resolvingFunctions.[[Resolve]], resolvingFunctions.[[Reject]]»). + 3. If thenCallResult is an abrupt completion, + a. Let status be Call(resolvingFunctions.[[Reject]], undefined, + «thenCallResult.[[value]]»). + b. NextJob Completion(status). +---*/ + +var error = new Test262Error(); +var promiseFulfilled = false; +var promiseRejected = false; +var promise = new Promise(function(resolve) { + resolve(); + }); + +promise.then(function() { + throw error; + }).then(function() { + $DONE('This promise should not be fulfilled'); + }, function(reason) { + assert.sameValue(reason, error); + + $DONE(); + }); diff --git a/test/built-ins/Promise/prototype/then/on-rejected-return-value.js b/test/built-ins/Promise/prototype/then/on-rejected-return-value.js new file mode 100644 index 0000000000..14f7c2df91 --- /dev/null +++ b/test/built-ins/Promise/prototype/then/on-rejected-return-value.js @@ -0,0 +1,33 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 25.4.5.3 +description: The return value of the `onRejected` method +info: > + 7. Return PerformPromiseThen(promise, onFulfilled, onRejected, + resultCapability). + + 25.4.5.3.1 PerformPromiseThen + + [...] + 9. Else if the value of promise's [[PromiseState]] internal slot is + "rejected", + a. Let reason be the value of promise's [[PromiseResult]] internal slot. + b. Perform EnqueueJob("PromiseJobs", PromiseReactionJob, + «rejectReaction, reason»). +---*/ + +var returnVal = {}; +var promise = new Promise(function(_, reject) { + reject(); +}); + +promise.then(null, function() { + return returnVal; +}).then(function(result) { + assert.sameValue(result, returnVal); + + $DONE(); +}, function() { + $DONE('The promise should not be rejected'); +}); diff --git a/test/built-ins/Promise/prototype/then/on-rejected-throw.js b/test/built-ins/Promise/prototype/then/on-rejected-throw.js new file mode 100644 index 0000000000..b218329cff --- /dev/null +++ b/test/built-ins/Promise/prototype/then/on-rejected-throw.js @@ -0,0 +1,33 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 25.4.5.3 +description: The `onRejected` method throws an error +info: > + 7. Return PerformPromiseThen(promise, onFulfilled, onRejected, + resultCapability). + + 25.4.5.3.1 PerformPromiseThen + + [...] + 9. Else if the value of promise's [[PromiseState]] internal slot is + "rejected", + a. Let reason be the value of promise's [[PromiseResult]] internal slot. + b. Perform EnqueueJob("PromiseJobs", PromiseReactionJob, + «rejectReaction, reason»). +---*/ + +var error = new Test262Error(); +var promise = new Promise(function(_, reject) { + reject(); +}); + +promise.then(null, function() { + throw error; + }).then(function(result) { + $DONE('This promise should not be fulfilled'); + }, function(reason) { + assert.sameValue(reason, error); + + $DONE(); + }); diff --git a/test/built-ins/Promise/race/ctx-ctor.js b/test/built-ins/Promise/race/ctx-ctor.js new file mode 100644 index 0000000000..4f8c161772 --- /dev/null +++ b/test/built-ins/Promise/race/ctx-ctor.js @@ -0,0 +1,37 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + `Promise.race` invoked on a constructor value +es6id: 25.4.4.3 +info: > + 1. Let C be the this value. + [...] + 6. Let promiseCapability be NewPromiseCapability(C). + [...] + 10. Let iteratorRecord be Record {[[iterator]]: iterator, [[done]]: false}. + 11. Let result be PerformPromiseRace(iteratorRecord, promiseCapability, C). + [...] + 13. Return Completion(result). +features: [class] +---*/ + +var executor = null; +var callCount = 0; + +class SubPromise extends Promise { + constructor(a) { + super(a); + executor = a; + callCount += 1; + } +} + +var instance = Promise.race.call(SubPromise); + +assert.sameValue(instance.constructor, SubPromise); +assert.sameValue(instance instanceof SubPromise, true); + +assert.sameValue(callCount, 1); +assert.sameValue(typeof executor, 'function'); diff --git a/test/built-ins/Promise/race/ctx-non-ctor.js b/test/built-ins/Promise/race/ctx-non-ctor.js new file mode 100644 index 0000000000..542c07674a --- /dev/null +++ b/test/built-ins/Promise/race/ctx-non-ctor.js @@ -0,0 +1,20 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + `Promise.race` invoked on a non-constructor value +es6id: 25.4.4.3 +info: > + [...] + 6. Let promiseCapability be NewPromiseCapability(C). + 7. ReturnIfAbrupt(promiseCapability). + + 25.4.1.5 NewPromiseCapability ( C ) + + 1. If IsConstructor(C) is false, throw a TypeError exception. +---*/ + +assert.throws(TypeError, function() { + Promise.race.call(eval); +}); diff --git a/test/built-ins/Promise/race/ctx-non-object.js b/test/built-ins/Promise/race/ctx-non-object.js new file mode 100644 index 0000000000..b21f956413 --- /dev/null +++ b/test/built-ins/Promise/race/ctx-non-object.js @@ -0,0 +1,36 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + `Promise.race` invoked on a non-object value +es6id: 25.4.4.3 +info: > + 1. Let C be the this value. + 2. If Type(C) is not Object, throw a TypeError exception. +features: [Symbol] +---*/ + +assert.throws(TypeError, function() { + Promise.race.call(undefined, []); +}); + +assert.throws(TypeError, function() { + Promise.race.call(null, []); +}); + +assert.throws(TypeError, function() { + Promise.race.call(86, []); +}); + +assert.throws(TypeError, function() { + Promise.race.call('string', []); +}); + +assert.throws(TypeError, function() { + Promise.race.call(true, []); +}); + +assert.throws(TypeError, function() { + Promise.race.call(Symbol(), []); +}); diff --git a/test/built-ins/Promise/race/invoke-resolve-get-error.js b/test/built-ins/Promise/race/invoke-resolve-get-error.js new file mode 100644 index 0000000000..2ed029d5e9 --- /dev/null +++ b/test/built-ins/Promise/race/invoke-resolve-get-error.js @@ -0,0 +1,36 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Error retrieving the constructor's `resolve` method +es6id: 25.4.4.3 +info: > + 11. Let result be PerformPromiseRace(iteratorRecord, C, promiseCapability). + 12. If result is an abrupt completion, + a. If iteratorRecord.[[done]] is false, let result be + IteratorClose(iterator, result). + b. IfAbruptRejectPromise(result, promiseCapability). + + [...] + + 25.4.4.3.1 Runtime Semantics: PerformPromiseRace + + 1. Repeat + [...] + h. Let nextPromise be Invoke(C, "resolve", «nextValue»). + i. ReturnIfAbrupt(nextPromise). +---*/ + +var error = new Test262Error(); +Object.defineProperty(Promise, 'resolve', { + get: function() { + throw error; + } +}); + +Promise.race([new Promise(function() {})]).then(function() { + $ERROR('The promise should be rejected'); +}, function(reason) { + assert.sameValue(reason, error); +}).then($DONE, $DONE); diff --git a/test/built-ins/Promise/race/invoke-resolve.js b/test/built-ins/Promise/race/invoke-resolve.js new file mode 100644 index 0000000000..b7107f03e9 --- /dev/null +++ b/test/built-ins/Promise/race/invoke-resolve.js @@ -0,0 +1,51 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Invocation of the constructor's `resolve` method +es6id: 25.4.4.3 +info: > + 11. Let result be PerformPromiseRace(iteratorRecord, C, promiseCapability). + + [...] + + 25.4.4.3.1 Runtime Semantics: PerformPromiseRace + + 1. Repeat + [...] + h. Let nextPromise be Invoke(C, "resolve", «nextValue»). +---*/ + +var p1 = new Promise(function() {}); +var p2 = new Promise(function() {}); +var p3 = new Promise(function() {}); +var resolve = Promise.resolve; +var callCount = 0; +var current = p1; +var next = p2; +var afterNext = p3; + +Promise.resolve = function(nextValue) { + assert.sameValue( + nextValue, current, '`resolve` invoked with next iterated value' + ); + assert.sameValue( + arguments.length, 1, '`resolve` invoked with a single argument' + ); + assert.sameValue(this, Promise, '`this` value set to the constructor'); + + current = next; + next = afterNext; + afterNext = null; + + callCount += 1; + + return resolve.apply(Promise, arguments); +}; + +Promise.race([p1, p2, p3]); + +assert.sameValue( + callCount, 3, '`resolve` invoked once for each iterated value' +); diff --git a/test/built-ins/Promise/race/invoke-then-error.js b/test/built-ins/Promise/race/invoke-then-error.js new file mode 100644 index 0000000000..b2f79f5343 --- /dev/null +++ b/test/built-ins/Promise/race/invoke-then-error.js @@ -0,0 +1,37 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Error thrown when invoking the instance's `then` method +es6id: 25.4.4.3 +info: > + 11. Let result be PerformPromiseRace(iteratorRecord, C, promiseCapability). + 12. If result is an abrupt completion, + a. If iteratorRecord.[[done]] is false, let result be + IteratorClose(iterator, result). + b. IfAbruptRejectPromise(result, promiseCapability). + + [...] + + 25.4.4.3.1 Runtime Semantics: PerformPromiseRace + + 1. Repeat + [...] + j. Let result be Invoke(nextPromise, "then", + «promiseCapability.[[Resolve]], promiseCapability.[[Reject]]»). + k. ReturnIfAbrupt(result). +---*/ + +var promise = new Promise(function() {}); +var error = new Test262Error(); + +promise.then = function() { + throw error; +}; + +Promise.race([promise]).then(function() { + $ERROR('The promise should be rejected'); +}, function(reason) { + assert.sameValue(reason, error); +}).then($DONE, $DONE); diff --git a/test/built-ins/Promise/race/invoke-then.js b/test/built-ins/Promise/race/invoke-then.js new file mode 100644 index 0000000000..4d1db6d56e --- /dev/null +++ b/test/built-ins/Promise/race/invoke-then.js @@ -0,0 +1,55 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Invocation of the instance's `then` method +es6id: 25.4.4.3 +info: > + 11. Let result be PerformPromiseRace(iteratorRecord, C, promiseCapability). + + [...] + + 25.4.4.3.1 Runtime Semantics: PerformPromiseRace + + 1. Repeat + [...] + j. Let result be Invoke(nextPromise, "then", + «promiseCapability.[[Resolve]], promiseCapability.[[Reject]]»). + k. ReturnIfAbrupt(result). +---*/ + +var p1 = new Promise(function() {}); +var p2 = new Promise(function() {}); +var p3 = new Promise(function() {}); +var callCount = 0; +var currentThis = p1; +var nextThis = p2; +var afterNextThis = p3; + +p1.then = p2.then = p3.then = function(a, b) { + assert.sameValue(typeof a, 'function', 'type of first argument'); + assert.sameValue( + a.length, + 1, + 'ES6 25.4.1.3.2: The length property of a promise resolve function is 1.' + ); + assert.sameValue(typeof b, 'function', 'type of second argument'); + assert.sameValue( + b.length, + 1, + 'ES6 25.4.1.3.1: The length property of a promise reject function is 1.' + ); + assert.sameValue(arguments.length, 2, '`then` invoked with two arguments'); + assert.sameValue(this, currentThis, '`this` value'); + + currentThis = nextThis; + nextThis = afterNextThis; + afterNextThis = null; + + callCount += 1; +}; + +Promise.race([p1, p2, p3]); + +assert.sameValue(callCount, 3, '`then` invoked once for every iterated value'); diff --git a/test/built-ins/Promise/race/iter-next-val-err.js b/test/built-ins/Promise/race/iter-next-val-err.js new file mode 100644 index 0000000000..eca773a9e6 --- /dev/null +++ b/test/built-ins/Promise/race/iter-next-val-err.js @@ -0,0 +1,50 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Error when accessing an iterator result's `value` property +es6id: 25.4.4.3 +info: > + 11. Let result be PerformPromiseRace(iteratorRecord, C, promiseCapability). + 12. If result is an abrupt completion, + a. If iteratorRecord.[[done]] is false, let result be + IteratorClose(iterator, result). + b. IfAbruptRejectPromise(result, promiseCapability). + + [...] + + 25.4.4.3.1 Runtime Semantics: PerformPromiseRace + + 1. Repeat + [...] + e. Let nextValue be IteratorValue(next). + f. If nextValue is an abrupt completion, set iteratorRecord.[[done]] to + true. + g. ReturnIfAbrupt(nextValue). +features: [Symbol.iterator] +---*/ + +var iterNextValThrows = {}; +var poisonedVal = { + done: false +}; +var error = new Test262Error(); +Object.defineProperty(poisonedVal, 'value', { + get: function() { + throw error; + } +}); +iterNextValThrows[Symbol.iterator] = function() { + return { + next: function() { + return poisonedVal; + } + }; +}; + +Promise.race(iterNextValThrows).then(function() { + $ERROR('The promise should be rejected.'); +}, function(reason) { + assert.sameValue(reason, error); +}).then($DONE, $DONE); diff --git a/test/built-ins/Promise/race/species-get-error.js b/test/built-ins/Promise/race/species-get-error.js new file mode 100644 index 0000000000..78b01acf15 --- /dev/null +++ b/test/built-ins/Promise/race/species-get-error.js @@ -0,0 +1,25 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Error thrown when retrieving `Symbol.species` property of the `this` value +es6id: 25.4.4.3 +info: > + 1. Let C be the this value. + 2. If Type(C) is not Object, throw a TypeError exception. + 3. Let S be Get(C, @@species). + 4. ReturnIfAbrupt(S). +features: [Symbol.species] +---*/ + +var C = {}; +Object.defineProperty(C, Symbol.species, { + get: function() { + throw new Test262Error(); + } +}); + +assert.throws(Test262Error, function() { + Promise.race.call(C); +}); diff --git a/test/built-ins/Promise/reject/ctx-ctor.js b/test/built-ins/Promise/reject/ctx-ctor.js new file mode 100644 index 0000000000..a270a2fa54 --- /dev/null +++ b/test/built-ins/Promise/reject/ctx-ctor.js @@ -0,0 +1,34 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + `Promise.reject` invoked on a constructor value +es6id: 25.4.4.5 +info: > + 1. Let C be the this value. + [...] + 3. Let promiseCapability be NewPromiseCapability(C). + [...] + 7. Return promiseCapability.[[Promise]]. +features: [class] +---*/ + +var executor = null; +var callCount = 0; + +class SubPromise extends Promise { + constructor(a) { + super(a); + executor = a; + callCount += 1; + } +} + +var instance = Promise.reject.call(SubPromise); + +assert.sameValue(instance.constructor, SubPromise); +assert.sameValue(instance instanceof SubPromise, true); + +assert.sameValue(callCount, 1); +assert.sameValue(typeof executor, 'function'); diff --git a/test/built-ins/Promise/reject/ctx-non-ctor.js b/test/built-ins/Promise/reject/ctx-non-ctor.js new file mode 100644 index 0000000000..a01eb4da20 --- /dev/null +++ b/test/built-ins/Promise/reject/ctx-non-ctor.js @@ -0,0 +1,16 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + `Promise.reject` invoked on a non-constructor value +es6id: 25.4.4.4 +info: > + [...] + 3. Let promiseCapability be NewPromiseCapability(C). + 4. ReturnIfAbrupt(promiseCapability). +---*/ + +assert.throws(TypeError, function() { + Promise.reject.call(eval); +}); diff --git a/test/built-ins/Promise/reject/ctx-non-object.js b/test/built-ins/Promise/reject/ctx-non-object.js new file mode 100644 index 0000000000..0f37e09b98 --- /dev/null +++ b/test/built-ins/Promise/reject/ctx-non-object.js @@ -0,0 +1,36 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + `Promise.resolve` invoked on a non-object value +es6id: 25.4.4.4 +info: > + 1. Let C be the this value. + 2. If Type(C) is not Object, throw a TypeError exception. +features: [Symbol] +---*/ + +assert.throws(TypeError, function() { + Promise.reject.call(undefined, []); +}); + +assert.throws(TypeError, function() { + Promise.reject.call(null, []); +}); + +assert.throws(TypeError, function() { + Promise.reject.call(86, []); +}); + +assert.throws(TypeError, function() { + Promise.reject.call('string', []); +}); + +assert.throws(TypeError, function() { + Promise.reject.call(true, []); +}); + +assert.throws(TypeError, function() { + Promise.reject.call(Symbol(), []); +}); diff --git a/test/built-ins/Promise/resolve/arg-non-thenable.js b/test/built-ins/Promise/resolve/arg-non-thenable.js new file mode 100644 index 0000000000..2aa032efac --- /dev/null +++ b/test/built-ins/Promise/resolve/arg-non-thenable.js @@ -0,0 +1,29 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + `Promise.resolve` invoked with an object whose `then` property is not callable +es6id: 25.4.4.5 +info: > + 6. Let resolveResult be Call(promiseCapability.[[Resolve]], undefined, + «x»). + + [...] + + 25.4.1.3.2 Promise Resolve Functions + + 11. If IsCallable(thenAction) is false, then + a. Return FulfillPromise(promise, resolution). + 12. Perform EnqueueJob ("PromiseJobs", PromiseResolveThenableJob, + «promise, resolution, thenAction») + 13. Return undefined. +---*/ + +var nonThenable = { + then: null +}; + +Promise.resolve(nonThenable).then(function(value) { + assert.sameValue(value, nonThenable); +}).then($DONE, $DONE); diff --git a/test/built-ins/Promise/resolve/arg-poisoned-then.js b/test/built-ins/Promise/resolve/arg-poisoned-then.js new file mode 100644 index 0000000000..085e1455a7 --- /dev/null +++ b/test/built-ins/Promise/resolve/arg-poisoned-then.js @@ -0,0 +1,35 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + `Promise.resolve` invoked with an object with a "poisoned" `then` property +es6id: 25.4.4.5 +info: > + 6. Let resolveResult be Call(promiseCapability.[[Resolve]], undefined, + «x»). + + [...] + + 25.4.1.3.2 Promise Resolve Functions + + 8. Let then be Get(resolution, "then"). + 9. If then is an abrupt completion, then + a. Return RejectPromise(promise, then.[[value]]). +---*/ + +var poisonedThen = {}; +var err = new Test262Error(); +Object.defineProperty(poisonedThen, 'then', { + get: function() { + throw err; + } +}); + +Promise.resolve(poisonedThen).then(function() { + $ERROR( + 'Promise should be rejected when retrieving `then` property throws an error' + ); +}, function(reason) { + assert.sameValue(reason, err); +}).then($DONE, $DONE); diff --git a/test/built-ins/Promise/resolve/arg-uniq-ctor.js b/test/built-ins/Promise/resolve/arg-uniq-ctor.js new file mode 100644 index 0000000000..dcab56e1d7 --- /dev/null +++ b/test/built-ins/Promise/resolve/arg-uniq-ctor.js @@ -0,0 +1,27 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + `Promise.resolve` invoked with a Promise with a unique constructor +es6id: 25.4.4.5 +info: > + 1. Let C be the this value. + [...] + 3. If IsPromise(x) is true, + a. Let xConstructor be Get(x, "constructor"). + b. ReturnIfAbrupt(xConstructor). + c. If SameValue(xConstructor, C) is true, return x. + 4. Let promiseCapability be NewPromiseCapability(C). + [...] + 8. Return promiseCapability.[[Promise]]. +---*/ + +var promise1 = new Promise(function() {}); +var promise2; + +promise1.constructor = null; + +promise2 = Promise.resolve(promise1); + +assert.sameValue(promise1 === promise2, false); diff --git a/test/built-ins/Promise/resolve/ctx-ctor.js b/test/built-ins/Promise/resolve/ctx-ctor.js new file mode 100644 index 0000000000..f1772d8119 --- /dev/null +++ b/test/built-ins/Promise/resolve/ctx-ctor.js @@ -0,0 +1,34 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + `Promise.resolve` invoked on a constructor value +es6id: 25.4.4.5 +info: > + 1. Let C be the this value. + [...] + 4. Let promiseCapability be NewPromiseCapability(C). + [...] + 8. Return promiseCapability.[[Promise]]. +features: [class] +---*/ + +var executor = null; +var callCount = 0; + +class SubPromise extends Promise { + constructor(a) { + super(a); + executor = a; + callCount += 1; + } +} + +var instance = Promise.resolve.call(SubPromise); + +assert.sameValue(instance.constructor, SubPromise); +assert.sameValue(instance instanceof SubPromise, true); + +assert.sameValue(callCount, 1); +assert.sameValue(typeof executor, 'function'); diff --git a/test/built-ins/Promise/resolve/ctx-non-ctor.js b/test/built-ins/Promise/resolve/ctx-non-ctor.js new file mode 100644 index 0000000000..84cde055d4 --- /dev/null +++ b/test/built-ins/Promise/resolve/ctx-non-ctor.js @@ -0,0 +1,16 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + `Promise.resolve` invoked on a non-constructor value +es6id: 25.4.4.5 +info: > + [...] + 4. Let promiseCapability be NewPromiseCapability(C). + 5. ReturnIfAbrupt(promiseCapability). +---*/ + +assert.throws(TypeError, function() { + Promise.resolve.call(eval); +}); diff --git a/test/built-ins/Promise/resolve/ctx-non-object.js b/test/built-ins/Promise/resolve/ctx-non-object.js new file mode 100644 index 0000000000..439cb34e92 --- /dev/null +++ b/test/built-ins/Promise/resolve/ctx-non-object.js @@ -0,0 +1,36 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + `Promise.resolve` invoked on a non-object value +es6id: 25.4.4.5 +info: > + 1. Let C be the this value. + 2. If Type(C) is not Object, throw a TypeError exception. +features: [Symbol] +---*/ + +assert.throws(TypeError, function() { + Promise.resolve.call(undefined, []); +}); + +assert.throws(TypeError, function() { + Promise.resolve.call(null, []); +}); + +assert.throws(TypeError, function() { + Promise.resolve.call(86, []); +}); + +assert.throws(TypeError, function() { + Promise.resolve.call('string', []); +}); + +assert.throws(TypeError, function() { + Promise.resolve.call(true, []); +}); + +assert.throws(TypeError, function() { + Promise.resolve.call(Symbol(), []); +});