diff --git a/test/built-ins/Promise/any/ctx-ctor-throws.js b/test/built-ins/Promise/any/ctx-ctor-throws.js index b3e567acb5..a6e0d07868 100644 --- a/test/built-ins/Promise/any/ctx-ctor-throws.js +++ b/test/built-ins/Promise/any/ctx-ctor-throws.js @@ -12,6 +12,7 @@ info: | ... 7. Let promise be ? Construct(C, « executor »). + features: [Promise.any] ---*/ diff --git a/test/built-ins/Promise/any/ctx-non-ctor.js b/test/built-ins/Promise/any/ctx-non-ctor.js index f9de14efcd..6703d9eae6 100644 --- a/test/built-ins/Promise/any/ctx-non-ctor.js +++ b/test/built-ins/Promise/any/ctx-non-ctor.js @@ -12,9 +12,34 @@ info: | NewPromiseCapability ( C ) 1. If IsConstructor(C) is false, throw a TypeError exception. + features: [Promise.any] ---*/ assert.throws(TypeError, function() { Promise.any.call(eval); }); + +assert.throws(TypeError, function() { + Promise.any.call(undefined, []); +}); + +assert.throws(TypeError, function() { + Promise.any.call(null, []); +}); + +assert.throws(TypeError, function() { + Promise.any.call(86, []); +}); + +assert.throws(TypeError, function() { + Promise.any.call('string', []); +}); + +assert.throws(TypeError, function() { + Promise.any.call(true, []); +}); + +assert.throws(TypeError, function() { + Promise.any.call(Symbol(), []); +}); diff --git a/test/built-ins/Promise/any/ctx-non-object.js b/test/built-ins/Promise/any/ctx-non-object.js deleted file mode 100644 index 1031e25728..0000000000 --- a/test/built-ins/Promise/any/ctx-non-object.js +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (C) 2019 Sergey Rubanov. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. - -/*--- -description: > - Promise.any invoked on a non-object value -esid: sec-promise.any -info: | - 1. Let C be the this value. - 2. If Type(C) is not Object, throw a TypeError exception. -features: [Promise.any, Symbol] ----*/ - -assert.throws(TypeError, function() { - Promise.any.call(undefined, []); -}); - -assert.throws(TypeError, function() { - Promise.any.call(null, []); -}); - -assert.throws(TypeError, function() { - Promise.any.call(86, []); -}); - -assert.throws(TypeError, function() { - Promise.any.call('string', []); -}); - -assert.throws(TypeError, function() { - Promise.any.call(true, []); -}); - -assert.throws(TypeError, function() { - Promise.any.call(Symbol(), []); -}); diff --git a/test/built-ins/Promise/any/does-not-perform-species-get-of-custom.js b/test/built-ins/Promise/any/does-not-perform-species-get-of-custom.js new file mode 100644 index 0000000000..42f85f6b70 --- /dev/null +++ b/test/built-ins/Promise/any/does-not-perform-species-get-of-custom.js @@ -0,0 +1,32 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-promise.any +description: > + Promise.any() does not retrieve `Symbol.species` property of the "`this` value" +info: | + 1. Let C be the this value. + 2. Let promiseCapability be ? NewPromiseCapability(C). + ... + + NewPromiseCapability ( C ) + + 1. If IsConstructor(C) is false, throw a TypeError exception. + 2. NOTE: C is assumed to be a constructor function that supports the parameter conventions of the Promise constructor (see 25.6.3.1). + ... + +flags: [async] +features: [Promise.any, Symbol.species] +---*/ + +class C extends Promise { + static get [Symbol.species]() { + throw new Test262Error('Getter for Symbol.species called'); + } + static resolve() { + throw new Test262Error('C.resolve was reached'); + } +} + +Promise.any.call(C, [1]).then(() => $DONE(), $DONE); diff --git a/test/built-ins/Promise/any/does-not-perform-species-get-of-promise.js b/test/built-ins/Promise/any/does-not-perform-species-get-of-promise.js new file mode 100644 index 0000000000..7e1597cd1d --- /dev/null +++ b/test/built-ins/Promise/any/does-not-perform-species-get-of-promise.js @@ -0,0 +1,29 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-promise.any +description: > + Promise.any() does not retrieve `Symbol.species` property of the "`this` value". +info: | + 1. Let C be the this value. + 2. Let promiseCapability be ? NewPromiseCapability(C). + ... + + NewPromiseCapability ( C ) + + 1. If IsConstructor(C) is false, throw a TypeError exception. + 2. NOTE: C is assumed to be a constructor function that supports the parameter conventions of the Promise constructor (see 25.6.3.1). + ... + +flags: [async] +features: [Promise.any, Symbol.species] +---*/ + +Object.defineProperty(Promise, Symbol.species, { + get() { + throw new Test262Error('Getter for Symbol.species called'); + } +}); + +Promise.any([1]).then(() => $DONE(), $DONE); diff --git a/test/built-ins/Promise/any/empty-iterable-rejects.js b/test/built-ins/Promise/any/empty-iterable-rejects.js deleted file mode 100644 index 9d0d92ac41..0000000000 --- a/test/built-ins/Promise/any/empty-iterable-rejects.js +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (C) 2019 Sergey Rubanov. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. - -/*--- -description: Promise.any([]) rejects immediately -esid: sec-promise.any -flags: [async] -includes: [promiseHelper.js] -features: [AggregateError, Promise.any] ----*/ - -Promise.any([]) - .then( - () => $DONE('The promise should be rejected, but was resolved'), - error => { - assert(error instanceof AggregateError); - assert.sameValue(error.errors.length, 0); - $DONE() - } - ); diff --git a/test/built-ins/Promise/any/invoke-resolve-not-callable-rejects-with-typerror.js b/test/built-ins/Promise/any/invoke-resolve-not-callable-rejects-with-typerror.js new file mode 100644 index 0000000000..798812ce1b --- /dev/null +++ b/test/built-ins/Promise/any/invoke-resolve-not-callable-rejects-with-typerror.js @@ -0,0 +1,28 @@ +// Copyright (C) 2019 Sergey Rubanov. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + If the constructor's `resolve` method is not callable, reject with a TypeError. +esid: sec-promise.any +info: | + 5. Let result be PerformPromiseAny(iteratorRecord, C, promiseCapability). + + Runtime Semantics: PerformPromiseAny + + 6. Let promiseResolve be ? Get(constructor, "resolve"). + 7. If ! IsCallable(promiseResolve) is false, throw a TypeError exception. + +flags: [async] +features: [Promise.any] +---*/ + +Promise.resolve = null; + +Promise.any([1]) + .then( + () => $DONE('The promise should not be resolved.'), + error => { + assert(error instanceof TypeError); + } + ).then($DONE, $DONE); diff --git a/test/built-ins/Promise/any/invoke-resolve-on-promises-every-iteration-of-custom.js b/test/built-ins/Promise/any/invoke-resolve-on-promises-every-iteration-of-custom.js new file mode 100644 index 0000000000..226039ff42 --- /dev/null +++ b/test/built-ins/Promise/any/invoke-resolve-on-promises-every-iteration-of-custom.js @@ -0,0 +1,50 @@ +// Copyright (C) 2019 Sergey Rubanov. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Invocation of the constructor's `resolve` method for iterable with promise values +esid: sec-promise.any +info: | + 5. Let result be PerformPromiseAny(iteratorRecord, C, promiseCapability). + + Runtime Semantics: PerformPromiseAny + + 8. Repeat + ... + i. Let nextPromise be ? Call(promiseResolve, constructor, « nextValue »). + +flags: [async] +features: [Promise.any] +---*/ +class Custom extends Promise {} + +let customs = [ + new Custom(resolve => resolve()), + new Custom(resolve => resolve()), + new Custom(resolve => resolve()), +]; +let cresolveCallCount = 0; +let presolveCallCount = 0; +let boundCustomResolve = Custom.resolve.bind(Custom); +let boundPromiseResolve = Promise.resolve.bind(Promise); + +Custom.resolve = function(...args) { + cresolveCallCount += 1; + return boundCustomResolve(...args); +}; + +Promise.resolve = function(...args) { + presolveCallCount += 1; + return boundPromiseResolve(...args); +}; + +Promise.any.call(Custom, customs) + .then(() => { + assert.sameValue(presolveCallCount, 0, '`Promise.resolve` is never invoked'); + assert.sameValue(cresolveCallCount, 3, '`Custom.resolve` invoked once for every iterated promise'); + }, (error) => { + $DONE(error); + } + ).then($DONE, $DONE); + diff --git a/test/built-ins/Promise/any/invoke-resolve-on-promises-every-iteration-of-promise.js b/test/built-ins/Promise/any/invoke-resolve-on-promises-every-iteration-of-promise.js new file mode 100644 index 0000000000..4e90baa691 --- /dev/null +++ b/test/built-ins/Promise/any/invoke-resolve-on-promises-every-iteration-of-promise.js @@ -0,0 +1,41 @@ +// Copyright (C) 2019 Sergey Rubanov. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Invocation of the constructor's `resolve` method for iterable with promise values +esid: sec-promise.any +info: | + 5. Let result be PerformPromiseAny(iteratorRecord, C, promiseCapability). + + Runtime Semantics: PerformPromiseAny + + 8. Repeat + ... + i. Let nextPromise be ? Call(promiseResolve, constructor, « nextValue »). + +flags: [async] +features: [Promise.any] +---*/ + +let promises = [ + new Promise(resolve => resolve()), + new Promise(resolve => resolve()), + new Promise(resolve => resolve()), +]; +let callCount = 0; +let boundPromiseResolve = Promise.resolve.bind(Promise); + +Promise.resolve = function(...args) { + callCount += 1; + return boundPromiseResolve(...args); +}; + +Promise.any(promises) + .then(() => { + assert.sameValue(callCount, 3, '`then` invoked once for every iterated promise'); + }, (error) => { + $DONE(error); + } + ).then($DONE, $DONE); + diff --git a/test/built-ins/Promise/any/invoke-resolve-on-values-every-iteration-of-custom.js b/test/built-ins/Promise/any/invoke-resolve-on-values-every-iteration-of-custom.js new file mode 100644 index 0000000000..9b03b8a019 --- /dev/null +++ b/test/built-ins/Promise/any/invoke-resolve-on-values-every-iteration-of-custom.js @@ -0,0 +1,46 @@ +// Copyright (C) 2019 Sergey Rubanov. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Invocation of the constructor's `resolve` method for iterable with non-promise values +esid: sec-promise.any +info: | + 5. Let result be PerformPromiseAny(iteratorRecord, C, promiseCapability). + + Runtime Semantics: PerformPromiseAny + + 8. Repeat + ... + i. Let nextPromise be ? Call(promiseResolve, constructor, « nextValue »). + +flags: [async] +features: [Promise.any] +---*/ +class Custom extends Promise {} + +let values = [1, 2, 3]; +let cresolveCallCount = 0; +let presolveCallCount = 0; +let boundCustomResolve = Custom.resolve.bind(Custom); +let boundPromiseResolve = Promise.resolve.bind(Promise); + +Custom.resolve = function(...args) { + cresolveCallCount += 1; + return boundCustomResolve(...args); +}; + +Promise.resolve = function(...args) { + presolveCallCount += 1; + return boundPromiseResolve(...args); +}; + +Promise.any.call(Custom, values) + .then(() => { + assert.sameValue(presolveCallCount, 0, '`Promise.resolve` is never invoked'); + assert.sameValue(cresolveCallCount, 3, '`Custom.resolve` invoked once for every iterated promise'); + }, (error) => { + $DONE(error); + } + ).then($DONE, $DONE); + diff --git a/test/built-ins/Promise/any/invoke-resolve-on-values-every-iteration-of-promise.js b/test/built-ins/Promise/any/invoke-resolve-on-values-every-iteration-of-promise.js new file mode 100644 index 0000000000..2b5629045d --- /dev/null +++ b/test/built-ins/Promise/any/invoke-resolve-on-values-every-iteration-of-promise.js @@ -0,0 +1,37 @@ +// Copyright (C) 2019 Sergey Rubanov. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Invocation of the constructor's `resolve` method for iterable with non-promise values +esid: sec-promise.any +info: | + 5. Let result be PerformPromiseAny(iteratorRecord, C, promiseCapability). + + Runtime Semantics: PerformPromiseAny + + 8. Repeat + ... + i. Let nextPromise be ? Call(promiseResolve, constructor, « nextValue »). + +flags: [async] +features: [Promise.any] +---*/ + +let values = [1, 2, 3]; +let callCount = 0; +let boundPromiseResolve = Promise.resolve.bind(Promise); + +Promise.resolve = function(...args) { + callCount += 1; + return boundPromiseResolve(...args); +}; + +Promise.any(values) + .then(() => { + assert.sameValue(callCount, 3, '`Promise.resolve` invoked once for every iterated value'); + }, (error) => { + $DONE(error); + } + ).then($DONE, $DONE); + diff --git a/test/built-ins/Promise/any/invoke-resolve.js b/test/built-ins/Promise/any/invoke-resolve.js index 99daf2054f..60119c33a4 100644 --- a/test/built-ins/Promise/any/invoke-resolve.js +++ b/test/built-ins/Promise/any/invoke-resolve.js @@ -10,46 +10,22 @@ info: | Runtime Semantics: PerformPromiseAny - 6. Repeat + 8. Repeat ... i. Let nextPromise be ? Call(promiseResolve, constructor, « nextValue »). ... - z. Perform ? Invoke(nextPromise, "then", « resolveElement, rejectElement »). + r. Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], rejectElement »). + flags: [async] features: [Promise.any] ---*/ -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; +let boundPromiseResolve = Promise.resolve.bind(Promise); -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' - ); +Promise.resolve = function(...args) { + assert.sameValue(args.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); + return boundPromiseResolve(...args); }; -Promise.any([p1, p2, p3]) - .then(function() { - assert.sameValue( - callCount, 3, '`resolve` invoked once for each iterated value' - ); - $DONE(); - }, $DONE); +Promise.any([1]).then(() => $DONE(), $DONE); diff --git a/test/built-ins/Promise/any/invoke-then-on-promises-every-iteration.js b/test/built-ins/Promise/any/invoke-then-on-promises-every-iteration.js new file mode 100644 index 0000000000..accb7c75be --- /dev/null +++ b/test/built-ins/Promise/any/invoke-then-on-promises-every-iteration.js @@ -0,0 +1,45 @@ +// Copyright (C) 2019 Sergey Rubanov. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Invocation of the instance's `then` method +esid: sec-promise.any +info: | + 5. Let result be PerformPromiseAny(iteratorRecord, C, promiseCapability). + 6. If result is an abrupt completion, then + a. If iteratorRecord.[[Done]] is false, set result to IteratorClose(iteratorRecord, result). + b. IfAbruptRejectPromise(result, promiseCapability). + + Runtime Semantics: PerformPromiseAny + + r. Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], rejectElement »). + +flags: [async] +features: [Promise.any] +---*/ + +let promises = [ + new Promise(resolve => resolve()), + new Promise(resolve => resolve()), + new Promise(resolve => resolve()), +]; +let callCount = 0; + +promises.forEach(promise => { + let boundThen = promise.then.bind(promise); + promise.then = function(...args) { + assert.sameValue(this, promises[callCount]); + callCount += 1; + return boundThen(...args); + }; +}); + +Promise.any(promises) + .then(() => { + assert.sameValue(callCount, 3, '`then` invoked once for every iterated value'); + }, (error) => { + $DONE(error); + // $DONE('The promise should not be rejected'); + } + ).then($DONE, $DONE); diff --git a/test/built-ins/Promise/any/invoke-then.js b/test/built-ins/Promise/any/invoke-then.js index 95a630b11b..3de9219962 100644 --- a/test/built-ins/Promise/any/invoke-then.js +++ b/test/built-ins/Promise/any/invoke-then.js @@ -19,39 +19,16 @@ flags: [async] features: [Promise.any] ---*/ -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; +let promise = new Promise(() => {}); +let boundThen = promise.then.bind(promise); -p1.then = p2.then = p3.then = function(a, b) { - assert.sameValue(typeof a, 'function', 'type of first argument'); - assert.sameValue( - a.length, - 1, - 'The length property of a promise resolve function is 1.' - ); - assert.sameValue(typeof b, 'function', 'type of second argument'); - assert.sameValue( - b.length, - 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.then = function(resolver, rejectElement) { + assert.sameValue(this, promise); + assert.sameValue(typeof resolver, 'function'); + assert.sameValue(resolver.length, 1, 'resolver.length is 1'); + assert.sameValue(typeof rejectElement, 'function'); + assert.sameValue(rejectElement.length, 1, 'rejectElement.length is 0'); + return boundThen(resolver, rejectElement); }; -Promise.any([p1, p2, p3]) - .then(function() { - assert.sameValue(callCount, 3, '`then` invoked once for every iterated value'); - $DONE(); - }, $DONE); +Promise.any([promise]).then(() => $DONE(), $DONE); diff --git a/test/built-ins/Promise/any/iter-arg-is-empty-iterable-reject.js b/test/built-ins/Promise/any/iter-arg-is-empty-iterable-reject.js new file mode 100644 index 0000000000..42edfcec92 --- /dev/null +++ b/test/built-ins/Promise/any/iter-arg-is-empty-iterable-reject.js @@ -0,0 +1,39 @@ +// Copyright (C) 2019 Sergey Rubanov. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-promise.any +description: > + Promise.any([]) rejects with AggregateError, empty errors array. +info: | + Runtime Semantics: PerformPromiseAny ( iteratorRecord, constructor, resultCapability ) + + ... + 3. Let errors be a new empty List. + ... + 8. Repeat, + a. Let next be IteratorStep(iteratorRecord). + b. If next is an abrupt completion, set iteratorRecord.[[Done]] to true. + c. ReturnIfAbrupt(next). + d. If next is false, then + i. Set iteratorRecord.[[Done]] to true. + ii. Set remainingElementsCount.[[Value]] to remainingElementsCount.[[Value]] - 1. + iii. If remainingElementsCount.[[Value]] is 0, then + 1. Let error be a newly created AggregateError object. + 2. Set error.[[AggregateErrors]] to errors. + 3. Return ThrowCompletion(error). + ... + +flags: [async] +features: [AggregateError, Promise.any] +---*/ + +Promise.any([]) + .then( + () => $DONE('The promise should be rejected, but was resolved'), + error => { + assert.sameValue(Object.getPrototypeOf(error), AggregateError.prototype); + assert(error instanceof AggregateError); + assert.sameValue(error.errors.length, 0); + } + ).then($DONE, $DONE); diff --git a/test/built-ins/Promise/any/iter-arg-is-empty-string-reject.js b/test/built-ins/Promise/any/iter-arg-is-empty-string-reject.js new file mode 100644 index 0000000000..7f780fa95c --- /dev/null +++ b/test/built-ins/Promise/any/iter-arg-is-empty-string-reject.js @@ -0,0 +1,39 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-promise.any +description: > + Promise.any('') rejects with AggregateError, empty errors array. +info: | + Runtime Semantics: PerformPromiseAny ( iteratorRecord, constructor, resultCapability ) + + ... + 3. Let errors be a new empty List. + ... + 8. Repeat, + a. Let next be IteratorStep(iteratorRecord). + b. If next is an abrupt completion, set iteratorRecord.[[Done]] to true. + c. ReturnIfAbrupt(next). + d. If next is false, then + i. Set iteratorRecord.[[Done]] to true. + ii. Set remainingElementsCount.[[Value]] to remainingElementsCount.[[Value]] - 1. + iii. If remainingElementsCount.[[Value]] is 0, then + 1. Let error be a newly created AggregateError object. + 2. Set error.[[AggregateErrors]] to errors. + 3. Return ThrowCompletion(error). + ... + +features: [AggregateError, Promise.any] +flags: [async] +---*/ + +Promise.any('') + .then( + () => $DONE('The promise should be rejected, but was resolved'), + error => { + assert.sameValue(Object.getPrototypeOf(error), AggregateError.prototype); + assert(error instanceof AggregateError); + assert.sameValue(error.errors.length, 0); + } + ).then($DONE, $DONE); diff --git a/test/built-ins/Promise/any/iter-arg-is-false-reject.js b/test/built-ins/Promise/any/iter-arg-is-false-reject.js index 5ba6712ddc..a78cc40a17 100644 --- a/test/built-ins/Promise/any/iter-arg-is-false-reject.js +++ b/test/built-ins/Promise/any/iter-arg-is-false-reject.js @@ -4,13 +4,13 @@ /*--- esid: sec-promise.any description: > - Reject when argument is `false` + Promise.any(false) rejects with TypeError. info: | Promise.any ( iterable ) ... - 4. Let iteratorRecord be GetIterator(iterable). - 5. IfAbruptRejectPromise(iteratorRecord, promiseCapability). + 3. Let iteratorRecord be GetIterator(iterable). + 4. IfAbruptRejectPromise(iteratorRecord, promiseCapability). ... #sec-getiterator diff --git a/test/built-ins/Promise/any/iter-arg-is-null-reject.js b/test/built-ins/Promise/any/iter-arg-is-null-reject.js index a2ee093b21..89ffd99e49 100644 --- a/test/built-ins/Promise/any/iter-arg-is-null-reject.js +++ b/test/built-ins/Promise/any/iter-arg-is-null-reject.js @@ -4,13 +4,13 @@ /*--- esid: sec-promise.any description: > - Reject when argument is `null` + Promise.any(null) rejects with TypeError. info: | Promise.any ( iterable ) ... - 4. Let iteratorRecord be GetIterator(iterable). - 5. IfAbruptRejectPromise(iteratorRecord, promiseCapability). + 3. Let iteratorRecord be GetIterator(iterable). + 4. IfAbruptRejectPromise(iteratorRecord, promiseCapability). ... #sec-getiterator diff --git a/test/built-ins/Promise/any/iter-arg-is-number-reject.js b/test/built-ins/Promise/any/iter-arg-is-number-reject.js index 0d648ed139..866b364ea8 100644 --- a/test/built-ins/Promise/any/iter-arg-is-number-reject.js +++ b/test/built-ins/Promise/any/iter-arg-is-number-reject.js @@ -4,13 +4,13 @@ /*--- esid: sec-promise.any description: > - Reject when argument is a number + Promise.any(number) rejects with TypeError. info: | Promise.any ( iterable ) ... - 4. Let iteratorRecord be GetIterator(iterable). - 5. IfAbruptRejectPromise(iteratorRecord, promiseCapability). + 3. Let iteratorRecord be GetIterator(iterable). + 4. IfAbruptRejectPromise(iteratorRecord, promiseCapability). ... #sec-getiterator diff --git a/test/built-ins/Promise/any/iter-arg-is-poisoned.js b/test/built-ins/Promise/any/iter-arg-is-poisoned.js index ad003f0955..230de97bf4 100644 --- a/test/built-ins/Promise/any/iter-arg-is-poisoned.js +++ b/test/built-ins/Promise/any/iter-arg-is-poisoned.js @@ -4,13 +4,13 @@ /*--- esid: sec-promise.any description: > - Reject with abrupt completion from GetIterator + Promise.any(poisoned iterable) rejects with whatever error is thrown. info: | Promise.any ( iterable ) ... - 4. Let iteratorRecord be GetIterator(iterable). - 5. IfAbruptRejectPromise(iteratorRecord, promiseCapability). + 3. Let iteratorRecord be GetIterator(iterable). + 4. IfAbruptRejectPromise(iteratorRecord, promiseCapability). ... #sec-getiterator @@ -24,18 +24,18 @@ flags: [async] ---*/ var poison = []; -var error = new Test262Error(); Object.defineProperty(poison, Symbol.iterator, { get() { - throw error; + throw new Test262Error(); } }); try { - Promise.any(poison).then(function() { + Promise.any(poison).then(() => { $DONE('The promise should be rejected, but was resolved'); - }, function(err) { - assert.sameValue(err, error); + }, (error) => { + assert.sameValue(Object.getPrototypeOf(error), Test262Error.prototype); + assert(error instanceof Test262Error); }).then($DONE, $DONE); } catch (error) { $DONE(`The promise should be rejected, but threw an exception: ${error.message}`); diff --git a/test/built-ins/Promise/any/iter-arg-is-string-resolve.js b/test/built-ins/Promise/any/iter-arg-is-string-resolve.js index 60bfe98837..4c8ccf62c0 100644 --- a/test/built-ins/Promise/any/iter-arg-is-string-resolve.js +++ b/test/built-ins/Promise/any/iter-arg-is-string-resolve.js @@ -4,13 +4,13 @@ /*--- esid: sec-promise.any description: > - Resolve when argument is a string + Promise.any('non-empty-string') resolves with the first character in the non-empty string info: | Promise.any ( iterable ) ... - 4. Let iteratorRecord be GetIterator(iterable). - 5. IfAbruptRejectPromise(iteratorRecord, promiseCapability). + 3. Let iteratorRecord be GetIterator(iterable). + 4. IfAbruptRejectPromise(iteratorRecord, promiseCapability). ... #sec-getiterator @@ -25,9 +25,10 @@ flags: [async] ---*/ try { - Promise.any('').then(function(v) { - assert.sameValue(v.length, 0); - }, function(error) { + Promise.any('xyz').then(v => { + assert.sameValue(v, 'x'); + assert.sameValue(v.length, 1); + }, error => { $DONE(`The promise should be resolved, but was rejected with error: ${error.message}`); }).then($DONE, $DONE); } catch (error) { diff --git a/test/built-ins/Promise/any/iter-arg-is-symbol-reject.js b/test/built-ins/Promise/any/iter-arg-is-symbol-reject.js index c391f51f57..afd082f926 100644 --- a/test/built-ins/Promise/any/iter-arg-is-symbol-reject.js +++ b/test/built-ins/Promise/any/iter-arg-is-symbol-reject.js @@ -4,13 +4,13 @@ /*--- esid: sec-promise.any description: > - Reject when argument is a symbol + Promise.any(Symbol()) rejects with TypeError. info: | Promise.any ( iterable ) ... - 4. Let iteratorRecord be GetIterator(iterable). - 5. IfAbruptRejectPromise(iteratorRecord, promiseCapability). + 3. Let iteratorRecord be GetIterator(iterable). + 4. IfAbruptRejectPromise(iteratorRecord, promiseCapability). ... GetIterator ( obj [ , hint [ , method ] ] ) diff --git a/test/built-ins/Promise/any/iter-arg-is-true-reject.js b/test/built-ins/Promise/any/iter-arg-is-true-reject.js index 58dc0024f6..6c996ed4d6 100644 --- a/test/built-ins/Promise/any/iter-arg-is-true-reject.js +++ b/test/built-ins/Promise/any/iter-arg-is-true-reject.js @@ -4,13 +4,13 @@ /*--- esid: sec-promise.any description: > - Reject when argument is `true` + Promise.any(true) rejects with TypeError. info: | Promise.any ( iterable ) ... - 4. Let iteratorRecord be GetIterator(iterable). - 5. IfAbruptRejectPromise(iteratorRecord, promiseCapability). + 3. Let iteratorRecord be GetIterator(iterable). + 4. IfAbruptRejectPromise(iteratorRecord, promiseCapability). ... GetIterator ( obj [ , hint [ , method ] ] ) diff --git a/test/built-ins/Promise/any/iter-arg-is-undefined-reject.js b/test/built-ins/Promise/any/iter-arg-is-undefined-reject.js index f044a8885c..06b526b42c 100644 --- a/test/built-ins/Promise/any/iter-arg-is-undefined-reject.js +++ b/test/built-ins/Promise/any/iter-arg-is-undefined-reject.js @@ -4,13 +4,13 @@ /*--- esid: sec-promise.any description: > - Reject when argument is `undefined` + Promise.any(undefined) rejects with TypeError. info: | Promise.any ( iterable ) ... - 4. Let iteratorRecord be GetIterator(iterable). - 5. IfAbruptRejectPromise(iteratorRecord, promiseCapability). + 3. Let iteratorRecord be GetIterator(iterable). + 4. IfAbruptRejectPromise(iteratorRecord, promiseCapability). ... GetIterator ( obj [ , hint [ , method ] ] ) diff --git a/test/built-ins/Promise/any/iter-step-err-no-close.js b/test/built-ins/Promise/any/iter-step-err-no-close.js new file mode 100644 index 0000000000..686d07e724 --- /dev/null +++ b/test/built-ins/Promise/any/iter-step-err-no-close.js @@ -0,0 +1,60 @@ +// Copyright (C) 2019 Leo Balter, 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-promise.any +description: > + Error when advancing the provided iterable (not closing iterator) +info: | + Promise.any ( iterable ) + + 5. Let result be PerformPromiseAny(iteratorRecord, C, promiseCapability). + 6. If result is an abrupt completion, then + a. If iteratorRecord.[[Done]] is false, set result to IteratorClose(iteratorRecord, result). + b. IfAbruptRejectPromise(result, promiseCapability). + + Runtime Semantics: PerformPromiseAny + + 8. Repeat + a. Let next be IteratorStep(iteratorRecord). + b. If next is an abrupt completion, set iteratorRecord.[[done]] to true. + c. ReturnIfAbrupt(next). + +flags: [async] +features: [Promise.any, Symbol.iterator] +---*/ + +let returnCount = 0; +let poisonedDone = {}; +let error = new Test262Error(); +Object.defineProperties(poisonedDone, { + done: { + get() { + throw error; + } + }, + value: { + get() {} + } +}); +let iterStepThrows = { + [Symbol.iterator]() { + return { + next() { + return poisonedDone; + }, + return() { + returnCount += 1; + return {}; + } + }; + } +}; + +Promise.any(iterStepThrows).then( + () => { + $DONE('The promise should be rejected.'); +}, (reason) => { + assert.sameValue(reason, error); + assert.sameValue(returnCount, 0); +}).then($DONE, $DONE); diff --git a/test/built-ins/Promise/any/iter-step-err-reject.js b/test/built-ins/Promise/any/iter-step-err-reject.js new file mode 100644 index 0000000000..3cea43a434 --- /dev/null +++ b/test/built-ins/Promise/any/iter-step-err-reject.js @@ -0,0 +1,56 @@ +// Copyright (C) 2019 Leo Balter, 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-promise.any +description: > + Error when advancing the provided iterable (rejecting promise) +info: | + Promise.any ( iterable ) + + 5. Let result be PerformPromiseAny(iteratorRecord, C, promiseCapability). + 6. If result is an abrupt completion, then + a. If iteratorRecord.[[Done]] is false, set result to IteratorClose(iteratorRecord, result). + b. IfAbruptRejectPromise(result, promiseCapability). + + Runtime Semantics: PerformPromiseAny + + 8. Repeat + a. Let next be IteratorStep(iteratorRecord). + b. If next is an abrupt completion, set iteratorRecord.[[done]] to true. + c. ReturnIfAbrupt(next). + +flags: [async] +features: [Promise.any, Symbol.iterator] +---*/ + +let poisonedDone = {}; +let error = new Test262Error(); +Object.defineProperties(poisonedDone, { + done: { + get() { + throw error; + } + }, + value: { + get() { + $DONE('The `value` property should not be accessed.'); + } + } +}); +let iterStepThrows = { + [Symbol.iterator]() { + return { + next() { + return poisonedDone; + } + }; + } +}; + +Promise.any(iterStepThrows).then( + () => { + $DONE('The promise should be rejected.'); +}, (reason) => { + assert.sameValue(reason, error); +}).then($DONE, $DONE); diff --git a/test/built-ins/Promise/any/new-reject-function.js b/test/built-ins/Promise/any/new-reject-function.js new file mode 100644 index 0000000000..b73cc82882 --- /dev/null +++ b/test/built-ins/Promise/any/new-reject-function.js @@ -0,0 +1,51 @@ +// Copyright (C) 2019 Leo Balter, 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-performpromiseany +description: > + Each Promise.any element is called with a new Promise.any Reject Element function. +info: | + Runtime Semantics: PerformPromiseAny ( iteratorRecord, constructor, resultCapability ) + + ... + k. Let rejectElement be ! CreateBuiltinFunction(steps, « [[AlreadyCalled]], [[Index]], [[Errors]], [[Capability]], [[RemainingElements]] »). + ... + r. Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], rejectElement »). + ... + +features: [Promise.any] +---*/ + +function rejectFunction() {} + +function Constructor(executor) { + executor(rejectFunction, $ERROR); +} +Constructor.resolve = function(v) { + return v; +}; + +var callCount1 = 0; +var callCount2 = 0; +var p1OnRejected; + +var p1 = { + then(_, onRejected) { + callCount1 += 1; + p1OnRejected = onRejected; + assert.notSameValue(onRejected, rejectFunction, 'p1.then'); + } +}; +var p2 = { + then(_, onRejected) { + callCount2 += 1; + assert.notSameValue(onRejected, rejectFunction, 'p2.then'); + assert.notSameValue(onRejected, p1OnRejected, 'p1.onRejected != p2.onRejected'); + } +}; + +Promise.any.call(Constructor, [p1, p2]); +assert.sameValue(callCount1, 1, 'p1.then call count'); +assert.sameValue(callCount2, 1, 'p2.then call count'); + diff --git a/test/built-ins/Promise/any/reject-all-mixed.js b/test/built-ins/Promise/any/reject-all-mixed.js new file mode 100644 index 0000000000..a4531e885f --- /dev/null +++ b/test/built-ins/Promise/any/reject-all-mixed.js @@ -0,0 +1,26 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-promise.any +description: > + Promise.any rejection reasons from various rejections are all present +flags: [async] +features: [Promise.any] +---*/ + +let rejections = [ + Promise.reject('a'), + new Promise((_, reject) => reject('b')), + Promise.all([Promise.reject('c')]), + Promise.resolve(Promise.reject('d')), +]; + +Promise.any(rejections) + .then( + () => $DONE('The promise should be rejected, but was resolved'), + error => { + assert.sameValue(error.errors.length, rejections.length); + assert.sameValue(error.errors.join(''), 'abcd'); + } + ).then($DONE, $DONE); diff --git a/test/built-ins/Promise/any/reject-deferred.js b/test/built-ins/Promise/any/reject-deferred.js new file mode 100644 index 0000000000..3382a6d2d8 --- /dev/null +++ b/test/built-ins/Promise/any/reject-deferred.js @@ -0,0 +1,31 @@ +// Copyright (C) 2019 Leo Balter, 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-promise.any +description: Rejecting through deferred invocation of the provided resolving function +info: | + ... + 5. Let result be PerformPromiseAny(iteratorRecord, C, promiseCapability). + ... + + +flags: [async] +features: [AggregateError, Promise.any] +---*/ + +var rejection = {}; +var thenable = { + then(_, reject) { + new Promise((resolve) => resolve()) + .then(() => reject(rejection)); + } +}; + +Promise.any([thenable]) + .then(() => { + $DONE('The promise should be rejected.'); + }, (aggregate) => { + assert(aggregate instanceof AggregateError); + assert.sameValue(aggregate.errors.length, 1); + assert.sameValue(aggregate.errors[0], rejection); + }).then($DONE, $DONE); diff --git a/test/built-ins/Promise/any/reject-element-function-extensible.js b/test/built-ins/Promise/any/reject-element-function-extensible.js new file mode 100644 index 0000000000..030bc36835 --- /dev/null +++ b/test/built-ins/Promise/any/reject-element-function-extensible.js @@ -0,0 +1,29 @@ +// Copyright (C) 2019 Leo Balter, 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-promise.any-reject-element-functions +description: The [[Extensible]] slot of Promise.any Reject Element functions +info: | + 17 ECMAScript Standard Built-in Objects: + Unless specified otherwise, the [[Extensible]] internal slot + of a built-in object initially has the value true. +features: [Promise.any] +---*/ + +var rejectElementFunction; +var thenable = { + then(_, reject) { + rejectElementFunction = reject; + } +}; + +function NotPromise(executor) { + executor(function() {}, function() {}); +} +NotPromise.resolve = function(v) { + return v; +}; +Promise.any.call(NotPromise, [thenable]); + +assert(Object.isExtensible(rejectElementFunction)); diff --git a/test/built-ins/Promise/any/reject-element-function-length.js b/test/built-ins/Promise/any/reject-element-function-length.js new file mode 100644 index 0000000000..15437ff73c --- /dev/null +++ b/test/built-ins/Promise/any/reject-element-function-length.js @@ -0,0 +1,40 @@ +// Copyright (C) 2019 Leo Balter, 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-promise.any-reject-element-functions +description: The `length` property of Promise.any Reject Element functions +info: | + The length property of a Promise.any Reject Element function is 1. + + 17 ECMAScript Standard Built-in Objects: + Unless otherwise specified, the length property of a built-in Function + object has the attributes { [[Writable]]: false, [[Enumerable]]: false, + [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [Promise.any] +---*/ + +var rejectElementFunction; +var thenable = { + then(_, reject) { + rejectElementFunction = reject; + } +}; + +function NotPromise(executor) { + executor(function() {}, function() {}); +} +NotPromise.resolve = function(v) { + return v; +}; +Promise.any.call(NotPromise, [thenable]); + +assert.sameValue(rejectElementFunction.length, 1); + +verifyProperty(rejectElementFunction, 'length', { + value: 1, + enumerable: false, + writable: false, + configurable: true, +}); diff --git a/test/built-ins/Promise/any/reject-element-function-name.js b/test/built-ins/Promise/any/reject-element-function-name.js new file mode 100644 index 0000000000..9487836134 --- /dev/null +++ b/test/built-ins/Promise/any/reject-element-function-name.js @@ -0,0 +1,39 @@ +// Copyright (C) 2019 Leo Balter, 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-promise.any-reject-element-functions +description: The `name` property of Promise.any Reject Element functions +info: | + A promise resolve function is an anonymous built-in function. + + 17 ECMAScript Standard Built-in Objects: + Every built-in function object, including constructors, has a `name` + property whose value is a String. Functions that are identified as + anonymous functions use the empty string as the value of the `name` + property. + Unless otherwise specified, the `name` property of a built-in function + object has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*, + [[Configurable]]: *true* }. +includes: [propertyHelper.js] +features: [Promise.any] +---*/ + +var rejectElementFunction; +var thenable = { + then(_, reject) { + rejectElementFunction = reject; + } +}; + +function NotPromise(executor) { + executor(function() {}, function() {}); +} +NotPromise.resolve = function(v) { + return v; +}; +Promise.any.call(NotPromise, [thenable]); + +verifyProperty(rejectElementFunction, "name", { + value: "", writable: false, enumerable: false, configurable: true +}); diff --git a/test/built-ins/Promise/any/reject-element-function-nonconstructor.js b/test/built-ins/Promise/any/reject-element-function-nonconstructor.js new file mode 100644 index 0000000000..687e96c8bb --- /dev/null +++ b/test/built-ins/Promise/any/reject-element-function-nonconstructor.js @@ -0,0 +1,33 @@ +// Copyright (C) 2019 Leo Balter, 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-promise.any-reject-element-functions +description: Promise.any Reject Element functions are not constructors +info: | + 17 ECMAScript Standard Built-in Objects: + Built-in function objects that are not identified as constructors do not + implement the [[Construct]] internal method unless otherwise specified + in the description of a particular function. +features: [Promise.any] +---*/ + +var rejectElementFunction; +var thenable = { + then(_, reject) { + rejectElementFunction = reject; + } +}; + +function NotPromise(executor) { + executor(function() {}, function() {}); +} +NotPromise.resolve = function(v) { + return v; +}; +Promise.any.call(NotPromise, [thenable]); + +assert.sameValue(Object.prototype.hasOwnProperty.call(rejectElementFunction, 'prototype'), false); +assert.throws(TypeError, function() { + new rejectElementFunction(); +}); diff --git a/test/built-ins/Promise/any/reject-element-function-prototype.js b/test/built-ins/Promise/any/reject-element-function-prototype.js new file mode 100644 index 0000000000..b2e1369be6 --- /dev/null +++ b/test/built-ins/Promise/any/reject-element-function-prototype.js @@ -0,0 +1,31 @@ +// Copyright (C) 2019 Leo Balter, 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-promise.any-reject-element-functions +description: The [[Prototype]] of Promise.any Reject Element functions +info: | + 17 ECMAScript Standard Built-in Objects: + Unless otherwise specified every built-in function and every built-in + constructor has the Function prototype object, which is the initial + value of the expression Function.prototype (19.2.3), as the value of + its [[Prototype]] internal slot. +features: [Promise.any] +---*/ + +var rejectElementFunction; +var thenable = { + then(_, reject) { + rejectElementFunction = reject; + } +}; + +function NotPromise(executor) { + executor(function() {}, function() {}); +} +NotPromise.resolve = function(v) { + return v; +}; +Promise.any.call(NotPromise, [thenable]); + +assert.sameValue(Object.getPrototypeOf(rejectElementFunction), Function.prototype); diff --git a/test/built-ins/Promise/any/resolve-ignores-late-rejection-deferred.js b/test/built-ins/Promise/any/resolve-ignores-late-rejection-deferred.js new file mode 100644 index 0000000000..2d83ff3137 --- /dev/null +++ b/test/built-ins/Promise/any/resolve-ignores-late-rejection-deferred.js @@ -0,0 +1,41 @@ +// Copyright (C) 2019 Leo Balter, 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Resolved promises ignore rejections through deferred invocation of the + provided resolving function +esid: sec-promise.any +info: | + 5. Let result be PerformPromiseAny(iteratorRecord, C, promiseCapability). + + Runtime Semantics: PerformPromiseAny + + 8. Repeat + ... + r. Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], rejectElement »). + +flags: [async] +features: [Promise.any] +---*/ + +var resolver = { + then(resolve) { + new Promise((resolve) => resolve()) + .then(() => resolve(42)); + } +}; +var lateRejector = { + then(resolve, reject) { + new Promise((resolve) => resolve()) + .then(() => { + resolve(9); + reject(); + }); + } +}; + +Promise.any([resolver, lateRejector]) + .then(resolution => { + assert.sameValue(resolution, 42); + }).then($DONE, $DONE); diff --git a/test/built-ins/Promise/any/resolve-ignores-late-rejection.js b/test/built-ins/Promise/any/resolve-ignores-late-rejection.js new file mode 100644 index 0000000000..64955007af --- /dev/null +++ b/test/built-ins/Promise/any/resolve-ignores-late-rejection.js @@ -0,0 +1,37 @@ +// Copyright (C) 2019 Leo Balter, 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Resolved promises ignore rejections through immediate invocation of the + provided resolving function +esid: sec-promise.any +info: | + 5. Let result be PerformPromiseAny(iteratorRecord, C, promiseCapability). + + Runtime Semantics: PerformPromiseAny + + 8. Repeat + ... + r. Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], rejectElement »). + +flags: [async] +features: [Promise.any] +---*/ + +var resolver = { + then(resolve) { + resolve(42); + } +}; +var lateRejector = { + then(resolve, reject) { + resolve(33); + reject(); + } +}; + +Promise.any([resolver, lateRejector]) + .then(resolution => { + assert.sameValue(resolution, 42); + }).then($DONE, $DONE); diff --git a/test/built-ins/Promise/any/resolve-one-mixed.js b/test/built-ins/Promise/any/resolve-one-mixed.js new file mode 100644 index 0000000000..b33ea0b31c --- /dev/null +++ b/test/built-ins/Promise/any/resolve-one-mixed.js @@ -0,0 +1,22 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-promise.any +description: > + Promise.any resolves with the first item that does not reject. +flags: [async] +features: [Promise.any] +---*/ + +let fulfillables = [ + Promise.reject('a'), + new Promise((resolve, reject) => reject('b')), + Promise.all([Promise.reject('c')]), + Promise.resolve(Promise.reject('d').catch(v => v)), +]; + +Promise.any(fulfillables) + .then((resolution) => { + assert.sameValue(resolution, 'd'); + }).then($DONE, $DONE); diff --git a/test/built-ins/Promise/any/species-get-error.js b/test/built-ins/Promise/any/species-get-error.js deleted file mode 100644 index 1957172c48..0000000000 --- a/test/built-ins/Promise/any/species-get-error.js +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (C) 2019 Sergey Rubanov. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. - -/*--- -description: > - Promise.any() does not retrieve `Symbol.species` property of the `this` value -esid: sec-promise.any -info: | - 1. Let C be the this value. - 2. If Type(C) is not Object, throw a TypeError exception. - 3. Let promiseCapability be ? NewPromiseCapability(C). - ... -features: [Promise.any, Symbol.species] ----*/ - -function C(executor) { - executor(function() {}, function() {}); -} -Object.defineProperty(C, Symbol.species, { - get() { - throw new Test262Error('Getter for Symbol.species called'); - } -}); - -C.resolve = function() { - throw new Test262Error(); -}; - -Promise.any.call(C, []);