Promise.race: coverage updates (#2666)

Ref #2629
This commit is contained in:
Rick Waldron 2020-06-24 14:42:40 -04:00 committed by GitHub
parent 729fa02951
commit 9dbaa95aed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 665 additions and 0 deletions

View File

@ -0,0 +1,43 @@
// Copyright (C) 2020 Rick Waldron. 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.race
info: |
Let result be PerformPromiseRace(iteratorRecord, C, promiseCapability, promiseResolve).
PerformPromiseRace
Repeat
...
i. Let nextPromise be ? Call(promiseResolve, constructor, « nextValue »).
flags: [async]
features: [class, arrow-function]
---*/
class Custom extends Promise {}
let values = [1, 1, 1];
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.race.call(Custom, values)
.then(() => {
assert.sameValue(presolveCallCount, 0, '`Promise.resolve` is never invoked');
assert.sameValue(cresolveCallCount, 3, '`Custom.resolve` invoked once for every item in iterable arg');
}, $DONE).then($DONE, $DONE);

View File

@ -0,0 +1,34 @@
// Copyright (C) 2020 Rick Waldron. 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.race
info: |
Let result be PerformPromiseRace(iteratorRecord, C, promiseCapability, promiseResolve).
PerformPromiseRace
Repeat
...
i. Let nextPromise be ? Call(promiseResolve, constructor, « nextValue »).
flags: [async]
features: [arrow-function]
---*/
let values = [1, 1, 1];
let callCount = 0;
let boundPromiseResolve = Promise.resolve.bind(Promise);
Promise.resolve = function(...args) {
callCount += 1;
return boundPromiseResolve(...args);
};
Promise.race(values)
.then(() => {
assert.sameValue(callCount, 3, '`then` invoked once for every item in iterable arg');
}, $DONE).then($DONE, $DONE);

View File

@ -0,0 +1,34 @@
// Copyright (C) 2020 Rick Waldron. 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.race
info: |
Let result be PerformPromiseRace(iteratorRecord, C, promiseCapability, promiseResolve).
PerformPromiseRace
Repeat
...
i. Let nextPromise be ? Call(promiseResolve, constructor, « nextValue »).
flags: [async]
features: [arrow-function]
---*/
let values = [1, 2, 3];
let callCount = 0;
let boundPromiseResolve = Promise.resolve.bind(Promise);
Promise.resolve = function(...args) {
callCount += 1;
return boundPromiseResolve(...args);
};
Promise.race(values)
.then(() => {
assert.sameValue(callCount, 3, '`Promise.resolve` invoked once for every item in iterable arg');
}, $DONE).then($DONE, $DONE);

View File

@ -0,0 +1,62 @@
// Copyright (C) 2020 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-performpromiserace
description: >
Promise.race does not prevent resolve from being called multiple times.
info: |
PerformPromiseRace
Repeat,
Let next be IteratorStep(iteratorRecord).
If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
ReturnIfAbrupt(next).
If next is false, then
Set iteratorRecord.[[Done]] to true.
Return resultCapability.[[Promise]].
Let nextValue be IteratorValue(next).
If nextValue is an abrupt completion, set iteratorRecord.[[Done]] to true.
ReturnIfAbrupt(nextValue).
Let nextPromise be ? Call(promiseResolve, constructor, « nextValue »).
Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], resultCapability.[[Reject]] »).
includes: [promiseHelper.js]
---*/
let callCount = 0;
let values = [];
function Constructor(executor) {
function reject(value) {
callCount += 1;
values.push(value);
}
executor(() => {
throw new Test262Error();
}, reject);
}
Constructor.resolve = function(v) {
return v;
};
let pReject;
let a = {
then(_, rejecter) {
pReject = rejecter;
}
};
assert.sameValue(callCount, 0, 'callCount before call to race()');
Promise.race.call(Constructor, [a]);
assert.sameValue(callCount, 0, 'callCount after call to race()');
pReject(1);
pReject(2);
pReject(3);
assert.sameValue(callCount, 3, 'callCount after resolving a');
checkSequence(values);

View File

@ -0,0 +1,28 @@
// Copyright (C) 2020 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-promise.race-resolve-element-functions
description: The [[Extensible]] slot of Promise.race Resolve 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.
---*/
let resolveElementFunction;
let thenable = {
then(fulfill) {
resolveElementFunction = fulfill;
}
};
function NotPromise(executor) {
executor(() => {}, () => {});
}
NotPromise.resolve = function(v) {
return v;
};
Promise.race.call(NotPromise, [thenable]);
assert(Object.isExtensible(resolveElementFunction));

View File

@ -0,0 +1,38 @@
// Copyright (C) 2020 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-promise.race-resolve-element-functions
description: The `name` property of Promise.race Resolve 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]
---*/
let resolveElementFunction;
let thenable = {
then(fulfill) {
resolveElementFunction = fulfill;
}
};
function NotPromise(executor) {
executor(() => {}, () => {});
}
NotPromise.resolve = function(v) {
return v;
};
Promise.race.call(NotPromise, [thenable]);
verifyProperty(resolveElementFunction, "name", {
value: "", writable: false, enumerable: false, configurable: true
});

View File

@ -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.race-resolve-element-functions
description: Promise.race Resolve 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.
---*/
let resolveElementFunction;
let thenable = {
then(fulfill) {
resolveElementFunction = fulfill;
}
};
function NotPromise(executor) {
executor(() => {}, () => {});
}
NotPromise.resolve = function(v) {
return v;
};
Promise.race.call(NotPromise, [thenable]);
assert.sameValue(Object.prototype.hasOwnProperty.call(resolveElementFunction, 'prototype'), false);
assert.throws(TypeError, () => {
new resolveElementFunction();
});

View File

@ -0,0 +1,30 @@
// Copyright (C) 2020 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-promise.race-resolve-element-functions
description: The [[Prototype]] of Promise.race Resolve 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.
---*/
let resolveElementFunction;
let thenable = {
then(fulfill) {
resolveElementFunction = fulfill;
}
};
function NotPromise(executor) {
executor(() => {}, () => {});
}
NotPromise.resolve = function(v) {
return v;
};
Promise.race.call(NotPromise, [thenable]);
assert.sameValue(Object.getPrototypeOf(resolveElementFunction), Function.prototype);

View File

@ -0,0 +1,59 @@
// Copyright (C) 2020 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-performpromiserace
description: >
Promise.race does not prevent resolve from being called multiple times.
info: |
PerformPromiseRace
Repeat,
Let next be IteratorStep(iteratorRecord).
If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
ReturnIfAbrupt(next).
If next is false, then
Set iteratorRecord.[[Done]] to true.
Return resultCapability.[[Promise]].
Let nextValue be IteratorValue(next).
If nextValue is an abrupt completion, set iteratorRecord.[[Done]] to true.
ReturnIfAbrupt(nextValue).
Let nextPromise be ? Call(promiseResolve, constructor, « nextValue »).
Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], resultCapability.[[Reject]] »).
includes: [promiseHelper.js]
---*/
let callCount = 0;
let values = [];
function Constructor(executor) {
function resolve(value) {
callCount += 1;
values.push(value);
}
executor(resolve, $ERROR);
}
Constructor.resolve = function(v) {
return v;
};
let pResolve;
let a = {
then(resolver, rejector) {
pResolve = resolver;
}
};
assert.sameValue(callCount, 0, 'callCount before call to race()');
Promise.race.call(Constructor, [a]);
assert.sameValue(callCount, 0, 'callCount after call to race()');
pResolve(1);
pResolve(2);
pResolve(3);
assert.sameValue(callCount, 3, 'callCount after resolving a');
checkSequence(values);

View File

@ -0,0 +1,46 @@
// Copyright (C) 2020 Rick Waldron, 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.race
info: |
Let result be PerformPromiseRace(iteratorRecord, C, promiseCapability, promiseResolve).
PerformPromiseRace
Repeat
...
Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], resultCapability.[[Reject]] »).
flags: [async]
features: [arrow-function]
includes: [promiseHelper.js]
---*/
let sequence = [1];
let lateRejector = {
then(resolve, reject) {
return new Promise((resolve) => {
sequence.push(3);
resolve();
sequence.push(4);
}).then(() => {
sequence.push(5);
resolve(9);
sequence.push(6);
reject();
sequence.push(7);
});
}
};
sequence.push(2);
Promise.race([lateRejector])
.then(resolution => {
assert.sameValue(resolution, 9);
assert.sameValue(sequence.length, 7);
checkSequence(sequence);
}).then($DONE, $DONE);

View File

@ -0,0 +1,37 @@
// Copyright (C) 2020 Rick Waldron, 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.race
info: |
Let result be PerformPromiseRace(iteratorRecord, C, promiseCapability, promiseResolve).
PerformPromiseRace
Repeat
...
Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], resultCapability.[[Reject]] »).
flags: [async]
features: [arrow-function]
---*/
let resolver = {
then(resolve) {
resolve(42);
}
};
let lateRejector = {
then(resolve, reject) {
resolve(33);
reject();
}
};
Promise.race([resolver, lateRejector])
.then(resolution => {
assert.sameValue(resolution, 42);
}).then($DONE, $DONE);

View File

@ -0,0 +1,42 @@
// Copyright (C) 2020 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-promise.race
description: Resolution ticks are set in a predictable sequence with extra then calls
info: |
PerformPromiseRace
Repeat,
Let next be IteratorStep(iteratorRecord).
If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
ReturnIfAbrupt(next).
If next is false, then
Set iteratorRecord.[[Done]] to true.
Return resultCapability.[[Promise]].
Let nextValue be IteratorValue(next).
If nextValue is an abrupt completion, set iteratorRecord.[[Done]] to true.
ReturnIfAbrupt(nextValue).
Let nextPromise be ? Call(promiseResolve, constructor, « nextValue »).
Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], resultCapability.[[Reject]] »).
flags: [async]
includes: [promiseHelper.js]
---*/
let a = new Promise(resolve => resolve({}));
let sequence = [1];
Promise.all([
Promise.race([a]).then(resolved => {
sequence.push(4);
}),
a.then(() => {
sequence.push(3);
}).then(() => {
sequence.push(5);
}),
]).then(() => {
assert.sameValue(sequence.length, 5);
checkSequence(sequence);
}).then($DONE, $DONE);
sequence.push(2);

View File

@ -0,0 +1,48 @@
// Copyright (C) 2020 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-promise.race
description: >
Resolution ticks are set in a predictable sequence of mixed fulfilled and rejected promises
info: |
PerformPromiseRace
Repeat,
Let next be IteratorStep(iteratorRecord).
If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
ReturnIfAbrupt(next).
If next is false, then
Set iteratorRecord.[[Done]] to true.
Return resultCapability.[[Promise]].
Let nextValue be IteratorValue(next).
If nextValue is an abrupt completion, set iteratorRecord.[[Done]] to true.
ReturnIfAbrupt(nextValue).
Let nextPromise be ? Call(promiseResolve, constructor, « nextValue »).
Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], resultCapability.[[Reject]] »).
flags: [async]
includes: [promiseHelper.js]
---*/
let a = Promise.reject('');
let b = new Promise(resolve => resolve(''));
let c = new Promise((_, reject) => reject(''));
let sequence = [1];
Promise.all([
a.catch(() => {
sequence.push(3);
}),
Promise.race([a, b, c]).then(() => {
// This should not be present when the final
// sequence is evaluated.
sequence.push(5);
}),
b.then(() => {
sequence.push(4);
}),
]).catch(() => {
assert.sameValue(sequence.length, 4);
checkSequence(sequence);
}).then($DONE, $DONE);
sequence.push(2);

View File

@ -0,0 +1,47 @@
// Copyright (C) 2020 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-promise.race
description: Resolution ticks are set in a predictable sequence
info: |
PerformPromiseRace
Repeat,
Let next be IteratorStep(iteratorRecord).
If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
ReturnIfAbrupt(next).
If next is false, then
Set iteratorRecord.[[Done]] to true.
Return resultCapability.[[Promise]].
Let nextValue be IteratorValue(next).
If nextValue is an abrupt completion, set iteratorRecord.[[Done]] to true.
ReturnIfAbrupt(nextValue).
Let nextPromise be ? Call(promiseResolve, constructor, « nextValue »).
Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], resultCapability.[[Reject]] »).
flags: [async]
includes: [compareArray.js,promiseHelper.js]
---*/
let a = new Promise((_, reject) => reject('a'));
let b = new Promise((_, reject) => reject('b'));
let sequence = [1];
Promise.all([
a.catch(() => {
sequence.push(3);
return checkSequence(sequence, 'Expected to be called first.');
}),
Promise.race([a, b]).catch(() => {
sequence.push(5);
return checkSequence(sequence, 'Expected to be called third.');
}),
b.catch(() => {
sequence.push(4);
return checkSequence(sequence, 'Expected to be called second.');
})
]).then(result => {
compareArray(result, [true, true, true]);
}).then($DONE, $DONE);
sequence.push(2);

View File

@ -0,0 +1,46 @@
// Copyright (C) 2020 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-promise.race
description: Resolution ticks are set in a predictable sequence
info: |
PerformPromiseRace
Repeat,
Let next be IteratorStep(iteratorRecord).
If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
ReturnIfAbrupt(next).
If next is false, then
Set iteratorRecord.[[Done]] to true.
Return resultCapability.[[Promise]].
Let nextValue be IteratorValue(next).
If nextValue is an abrupt completion, set iteratorRecord.[[Done]] to true.
ReturnIfAbrupt(nextValue).
Let nextPromise be ? Call(promiseResolve, constructor, « nextValue »).
Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], resultCapability.[[Reject]] »).
flags: [async]
includes: [compareArray.js,promiseHelper.js]
---*/
let a = new Promise(resolve => resolve('a'));
let b = new Promise(resolve => resolve('b'));
let sequence = [1];
Promise.all([
a.then(() => {
sequence.push(3);
return checkSequence(sequence, 'Expected to be called first.');
}),
Promise.race([a, b]).then(() => {
sequence.push(5);
return checkSequence(sequence, 'Expected to be called third.');
}),
b.then(() => {
sequence.push(4);
return checkSequence(sequence, 'Expected to be called second.');
})
]).then(result => {
compareArray(result, [true, true, true]);
}).then($DONE, $DONE);
sequence.push(2);

View File

@ -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.race
description: >
Resolution the first resolved promise
info: |
PerformPromiseRace
Repeat,
Let next be IteratorStep(iteratorRecord).
If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
ReturnIfAbrupt(next).
If next is false, then
Set iteratorRecord.[[Done]] to true.
Return resultCapability.[[Promise]].
Let nextValue be IteratorValue(next).
If nextValue is an abrupt completion, set iteratorRecord.[[Done]] to true.
ReturnIfAbrupt(nextValue).
Let nextPromise be ? Call(promiseResolve, constructor, « nextValue »).
Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], resultCapability.[[Reject]] »).
flags: [async]
---*/
let a = Promise.reject('a').catch((v) => v);
let b = Promise.resolve('b').then((v) => { throw v });
let c = Promise.reject('c').then((v) => { throw v; });
let d = Promise.resolve('d').finally((v) => v);
let e = Promise.reject('e').finally((v) => v);
let f = Promise.resolve('f').finally((v) => { throw v; });
let g = Promise.reject('g').finally((v) => { throw v; });
let h = Promise.reject('h').then((v) => v, () => 'j');
let i = Promise.resolve('i').then(v => v);
Promise.race([a, b, c, d, e, f, g, h, i]).then(winner => {
assert.sameValue(winner, 'a');
}).then($DONE, $DONE);