From f1fb4c0ffe7b0519723cade5a4c960131150960d Mon Sep 17 00:00:00 2001 From: Andreu Botella Date: Tue, 18 Jul 2023 17:53:19 +0200 Subject: [PATCH 01/16] Add tests for AsyncContext (Stage 2) --- .../AsyncContext/Snapshot/constructor.js | 16 ++++ .../Snapshot/instance-extensible.js | 11 +++ .../Snapshot/instance-prototype.js | 20 +++++ .../Snapshot/internal-prototype.js | 16 ++++ .../AsyncContext/Snapshot/is-a-constructor.js | 12 +++ .../built-ins/AsyncContext/Snapshot/length.js | 16 ++++ test/built-ins/AsyncContext/Snapshot/name.js | 15 ++++ .../Snapshot/prototype/Symbol.toStringTag.js | 22 +++++ .../Snapshot/prototype/constructor.js | 19 ++++ .../Snapshot/prototype/descriptor.js | 16 ++++ .../prototype/run/calls-callback-with-args.js | 36 ++++++++ .../prototype/run/context-is-not-object.js | 44 ++++++++++ .../run/context-is-not-snapshot-object.js | 30 +++++++ .../run/context-is-variable-object-throws.js | 25 ++++++ .../Snapshot/prototype/run/length.js | 24 +++++ .../Snapshot/prototype/run/name.js | 24 +++++ .../prototype/run/not-a-constructor.js | 30 +++++++ ...revious-context-snapshot-after-callback.js | 59 +++++++++++++ .../prototype/run/restores-snapshot.js | 60 +++++++++++++ .../prototype/run/restores-unset-variables.js | 87 +++++++++++++++++++ ...ed-promise-does-not-resolve-in-snapshot.js | 33 +++++++ .../returns-async-callback-return-value.js | 32 +++++++ .../run/returns-callback-return-value.js | 31 +++++++ .../Snapshot/prototype/run/run.js | 23 +++++ .../run/throws-if-callback-is-not-callable.js | 53 +++++++++++ .../run/throws-if-callback-throws.js | 25 ++++++ .../Snapshot/undefined-newtarget-throws.js | 17 ++++ .../AsyncContext/Symbol.toStringTag.js | 22 +++++ ...ctor-defaultValue-defaults-to-undefined.js | 63 ++++++++++++++ .../Variable/constructor-defaultValue.js | 54 ++++++++++++ ...nstructor-name-defaults-to-empty-string.js | 66 ++++++++++++++ .../AsyncContext/Variable/constructor-name.js | 57 ++++++++++++ ...onstructor-throwing-defaultValue-getter.js | 29 +++++++ .../constructor-throwing-name-getter.js | 30 +++++++ .../constructor-throwing-name-hasproperty.js | 28 ++++++ .../constructor-throwing-name-tostring.js | 41 +++++++++ .../AsyncContext/Variable/constructor.js | 16 ++++ .../Variable/instance-extensible.js | 11 +++ .../Variable/instance-prototype.js | 20 +++++ .../Variable/internal-prototype.js | 16 ++++ .../AsyncContext/Variable/is-a-constructor.js | 12 +++ .../built-ins/AsyncContext/Variable/length.js | 16 ++++ test/built-ins/AsyncContext/Variable/name.js | 15 ++++ .../Variable/prototype/Symbol.toStringTag.js | 22 +++++ .../Variable/prototype/constructor.js | 19 ++++ .../Variable/prototype/descriptor.js | 16 ++++ .../prototype/get/context-is-not-object.js | 44 ++++++++++ .../get/context-is-not-variable-object.js | 30 +++++++ .../get/context-is-snapshot-object-throws.js | 25 ++++++ .../Variable/prototype/get/get.js | 23 +++++ .../Variable/prototype/get/length.js | 24 +++++ .../Variable/prototype/get/name.js | 24 +++++ .../prototype/get/not-a-constructor.js | 30 +++++++ .../get/returns-default-value-outside-run.js | 33 +++++++ .../get/returns-undefined-if-set-in-run.js | 28 ++++++ .../prototype/get/returns-value-set-in-run.js | 39 +++++++++ .../does-not-have-internal-slot-snapshot.js | 27 ++++++ .../name/does-not-have-internal-slot.js | 26 ++++++ .../Variable/prototype/name/length.js | 25 ++++++ .../Variable/prototype/name/name-getter.js | 31 +++++++ .../Variable/prototype/name/name.js | 29 +++++++ .../returns-name-passed-to-constructor.js | 22 +++++ .../prototype/name/this-not-object-throw.js | 51 +++++++++++ .../prototype/run/calls-callback-with-args.js | 36 ++++++++ .../prototype/run/context-is-not-object.js | 44 ++++++++++ .../run/context-is-not-variable-object.js | 30 +++++++ .../run/context-is-snapshot-object-throws.js | 25 ++++++ .../Variable/prototype/run/length.js | 24 +++++ .../Variable/prototype/run/name.js | 24 +++++ .../prototype/run/not-a-constructor.js | 30 +++++++ ...estores-context-snapshot-after-callback.js | 46 ++++++++++ ...ed-promise-does-not-resolve-in-snapshot.js | 31 +++++++ .../returns-async-callback-return-value.js | 32 +++++++ .../run/returns-callback-return-value.js | 31 +++++++ .../Variable/prototype/run/run.js | 23 +++++ .../swaps-context-snapshot-before-callback.js | 42 +++++++++ .../run/throws-if-callback-is-not-callable.js | 53 +++++++++++ .../run/throws-if-callback-throws.js | 25 ++++++ ...lated-snapshot-entries-keep-their-value.js | 72 +++++++++++++++ .../Variable/undefined-newtarget-throws.js | 21 +++++ .../FinalizationRegistry.js | 35 ++++++++ .../context-propagation/async-await.js | 34 ++++++++ .../continuation-propagation-thenable.js | 22 +++++ .../context-propagation/cross-realm.js | 49 +++++++++++ .../context-propagation/generators.js | 35 ++++++++ .../context-propagation/promise-then.js | 28 ++++++ test/built-ins/AsyncContext/proc-desc.js | 40 +++++++++ test/built-ins/AsyncContext/proto.js | 16 ++++ 88 files changed, 2708 insertions(+) create mode 100644 test/built-ins/AsyncContext/Snapshot/constructor.js create mode 100644 test/built-ins/AsyncContext/Snapshot/instance-extensible.js create mode 100644 test/built-ins/AsyncContext/Snapshot/instance-prototype.js create mode 100644 test/built-ins/AsyncContext/Snapshot/internal-prototype.js create mode 100644 test/built-ins/AsyncContext/Snapshot/is-a-constructor.js create mode 100644 test/built-ins/AsyncContext/Snapshot/length.js create mode 100644 test/built-ins/AsyncContext/Snapshot/name.js create mode 100644 test/built-ins/AsyncContext/Snapshot/prototype/Symbol.toStringTag.js create mode 100644 test/built-ins/AsyncContext/Snapshot/prototype/constructor.js create mode 100644 test/built-ins/AsyncContext/Snapshot/prototype/descriptor.js create mode 100644 test/built-ins/AsyncContext/Snapshot/prototype/run/calls-callback-with-args.js create mode 100644 test/built-ins/AsyncContext/Snapshot/prototype/run/context-is-not-object.js create mode 100644 test/built-ins/AsyncContext/Snapshot/prototype/run/context-is-not-snapshot-object.js create mode 100644 test/built-ins/AsyncContext/Snapshot/prototype/run/context-is-variable-object-throws.js create mode 100644 test/built-ins/AsyncContext/Snapshot/prototype/run/length.js create mode 100644 test/built-ins/AsyncContext/Snapshot/prototype/run/name.js create mode 100644 test/built-ins/AsyncContext/Snapshot/prototype/run/not-a-constructor.js create mode 100644 test/built-ins/AsyncContext/Snapshot/prototype/run/restores-previous-context-snapshot-after-callback.js create mode 100644 test/built-ins/AsyncContext/Snapshot/prototype/run/restores-snapshot.js create mode 100644 test/built-ins/AsyncContext/Snapshot/prototype/run/restores-unset-variables.js create mode 100644 test/built-ins/AsyncContext/Snapshot/prototype/run/returned-promise-does-not-resolve-in-snapshot.js create mode 100644 test/built-ins/AsyncContext/Snapshot/prototype/run/returns-async-callback-return-value.js create mode 100644 test/built-ins/AsyncContext/Snapshot/prototype/run/returns-callback-return-value.js create mode 100644 test/built-ins/AsyncContext/Snapshot/prototype/run/run.js create mode 100644 test/built-ins/AsyncContext/Snapshot/prototype/run/throws-if-callback-is-not-callable.js create mode 100644 test/built-ins/AsyncContext/Snapshot/prototype/run/throws-if-callback-throws.js create mode 100644 test/built-ins/AsyncContext/Snapshot/undefined-newtarget-throws.js create mode 100644 test/built-ins/AsyncContext/Symbol.toStringTag.js create mode 100644 test/built-ins/AsyncContext/Variable/constructor-defaultValue-defaults-to-undefined.js create mode 100644 test/built-ins/AsyncContext/Variable/constructor-defaultValue.js create mode 100644 test/built-ins/AsyncContext/Variable/constructor-name-defaults-to-empty-string.js create mode 100644 test/built-ins/AsyncContext/Variable/constructor-name.js create mode 100644 test/built-ins/AsyncContext/Variable/constructor-throwing-defaultValue-getter.js create mode 100644 test/built-ins/AsyncContext/Variable/constructor-throwing-name-getter.js create mode 100644 test/built-ins/AsyncContext/Variable/constructor-throwing-name-hasproperty.js create mode 100644 test/built-ins/AsyncContext/Variable/constructor-throwing-name-tostring.js create mode 100644 test/built-ins/AsyncContext/Variable/constructor.js create mode 100644 test/built-ins/AsyncContext/Variable/instance-extensible.js create mode 100644 test/built-ins/AsyncContext/Variable/instance-prototype.js create mode 100644 test/built-ins/AsyncContext/Variable/internal-prototype.js create mode 100644 test/built-ins/AsyncContext/Variable/is-a-constructor.js create mode 100644 test/built-ins/AsyncContext/Variable/length.js create mode 100644 test/built-ins/AsyncContext/Variable/name.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/Symbol.toStringTag.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/constructor.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/descriptor.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/get/context-is-not-object.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/get/context-is-not-variable-object.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/get/context-is-snapshot-object-throws.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/get/get.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/get/length.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/get/name.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/get/not-a-constructor.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/get/returns-default-value-outside-run.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/get/returns-undefined-if-set-in-run.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/get/returns-value-set-in-run.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/name/does-not-have-internal-slot-snapshot.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/name/does-not-have-internal-slot.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/name/length.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/name/name-getter.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/name/name.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/name/returns-name-passed-to-constructor.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/name/this-not-object-throw.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/run/calls-callback-with-args.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/run/context-is-not-object.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/run/context-is-not-variable-object.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/run/context-is-snapshot-object-throws.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/run/length.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/run/name.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/run/not-a-constructor.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/run/restores-context-snapshot-after-callback.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/run/returned-promise-does-not-resolve-in-snapshot.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/run/returns-async-callback-return-value.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/run/returns-callback-return-value.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/run/run.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/run/swaps-context-snapshot-before-callback.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/run/throws-if-callback-is-not-callable.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/run/throws-if-callback-throws.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/run/unrelated-snapshot-entries-keep-their-value.js create mode 100644 test/built-ins/AsyncContext/Variable/undefined-newtarget-throws.js create mode 100644 test/built-ins/AsyncContext/context-propagation/FinalizationRegistry.js create mode 100644 test/built-ins/AsyncContext/context-propagation/async-await.js create mode 100644 test/built-ins/AsyncContext/context-propagation/continuation-propagation-thenable.js create mode 100644 test/built-ins/AsyncContext/context-propagation/cross-realm.js create mode 100644 test/built-ins/AsyncContext/context-propagation/generators.js create mode 100644 test/built-ins/AsyncContext/context-propagation/promise-then.js create mode 100644 test/built-ins/AsyncContext/proc-desc.js create mode 100644 test/built-ins/AsyncContext/proto.js diff --git a/test/built-ins/AsyncContext/Snapshot/constructor.js b/test/built-ins/AsyncContext/Snapshot/constructor.js new file mode 100644 index 00000000000..4c131d56539 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/constructor.js @@ -0,0 +1,16 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot-constructor +description: > + The AsyncContext.Snapshot constructor is the %AsyncContext.Snapshot% + intrinsic object and the initial value of the Snapshot property of the + %AsyncContext% object. +features: [AsyncContext] +---*/ + +assert.sameValue( + typeof AsyncContext.Snapshot, 'function', + 'typeof AsyncContext.Snapshot is function' +); diff --git a/test/built-ins/AsyncContext/Snapshot/instance-extensible.js b/test/built-ins/AsyncContext/Snapshot/instance-extensible.js new file mode 100644 index 00000000000..be73ceead8f --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/instance-extensible.js @@ -0,0 +1,11 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot +description: Instances of AsyncContext.Snapshot are extensible +features: [AsyncContext] +---*/ + +var asyncSnapshot = new AsyncContext.Snapshot(); +assert.sameValue(Object.isExtensible(asyncSnapshot), true); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Snapshot/instance-prototype.js b/test/built-ins/AsyncContext/Snapshot/instance-prototype.js new file mode 100644 index 00000000000..8138ce53156 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/instance-prototype.js @@ -0,0 +1,20 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.prototype +description: > + The initial value of AsyncContext.Snapshot.prototype is the + AsyncContext.Snapshot prototype object. +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +assert.sameValue( + AsyncContext.Snapshot.prototype.isPrototypeOf(new AsyncContext.Snapshot()), true, + 'AsyncContext.Snapshot.prototype.isPrototypeOf(new AsyncContext.Snapshot()) returns true' +); + +verifyNotEnumerable(AsyncContext.Snapshot, 'prototype'); +verifyNotWritable(AsyncContext.Snapshot, 'prototype'); +verifyNotConfigurable(AsyncContext.Snapshot, 'prototype'); diff --git a/test/built-ins/AsyncContext/Snapshot/internal-prototype.js b/test/built-ins/AsyncContext/Snapshot/internal-prototype.js new file mode 100644 index 00000000000..42591148e18 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/internal-prototype.js @@ -0,0 +1,16 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-properties-of-the-asynccontext-snapshot-constructor +description: > + The AsyncContext.Snapshot constructor has a [[Prototype]] internal slot whose + value is %Function.prototype%. +features: [AsyncContext] +---*/ + +assert.sameValue( + Function.prototype.isPrototypeOf(AsyncContext.Snapshot), + true, + 'Function.prototype.isPrototypeOf(AsyncContext.Snapshot) returns true' +); diff --git a/test/built-ins/AsyncContext/Snapshot/is-a-constructor.js b/test/built-ins/AsyncContext/Snapshot/is-a-constructor.js new file mode 100644 index 00000000000..f13778b1b5d --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/is-a-constructor.js @@ -0,0 +1,12 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot-constructor +description: The AsyncContext.Snapshot constructor implements [[Construct]] +includes: [isConstructor.js] +features: [AsyncContext] +---*/ + +assert.sameValue(isConstructor(AsyncContext.Snapshot), true, 'isConstructor(AsyncContext.Snapshot) must return true'); +new AsyncContext.Snapshot(); diff --git a/test/built-ins/AsyncContext/Snapshot/length.js b/test/built-ins/AsyncContext/Snapshot/length.js new file mode 100644 index 00000000000..7c9283e51c5 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/length.js @@ -0,0 +1,16 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot +description: AsyncContext.Snapshot.length property descriptor +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +verifyProperty(AsyncContext.Snapshot, 'length', { + value: 0, + writable: false, + enumerable: false, + configurable: true +}); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Snapshot/name.js b/test/built-ins/AsyncContext/Snapshot/name.js new file mode 100644 index 00000000000..538190e47dc --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/name.js @@ -0,0 +1,15 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot +description: AsyncContext.Snapshot.name value and descriptor +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +assert.sameValue(AsyncContext.Snapshot.name, 'Snapshot', 'The value of AsyncContext.Snapshot.name is "Snapshot"'); + +verifyNotEnumerable(AsyncContext.Snapshot, 'name'); +verifyNotWritable(AsyncContext.Snapshot, 'name'); +verifyConfigurable(AsyncContext.Snapshot, 'name'); diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/Symbol.toStringTag.js b/test/built-ins/AsyncContext/Snapshot/prototype/Symbol.toStringTag.js new file mode 100644 index 00000000000..29e8ac4eaa5 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/prototype/Symbol.toStringTag.js @@ -0,0 +1,22 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.prototype-@@tostringtag +description: > + `Symbol.toStringTag` property descriptor +info: | + The initial value of the @@toStringTag property is the String value + "AsyncContext.Snapshot". + + This property has the attributes { [[Writable]]: false, [[Enumerable]]: + false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [AsyncContext, Symbol.toStringTag] +---*/ + +assert.sameValue(AsyncContext.Snapshot.prototype[Symbol.toStringTag], 'AsyncContext.Snapshot'); + +verifyNotEnumerable(AsyncContext.Snapshot.prototype, Symbol.toStringTag); +verifyNotWritable(AsyncContext.Snapshot.prototype, Symbol.toStringTag); +verifyConfigurable(AsyncContext.Snapshot.prototype, Symbol.toStringTag); diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/constructor.js b/test/built-ins/AsyncContext/Snapshot/prototype/constructor.js new file mode 100644 index 00000000000..776dc493049 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/prototype/constructor.js @@ -0,0 +1,19 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.prototype.constructor +description: AsyncContext.Snapshot.prototype.constructor value and descriptor +info: | + The initial value of AsyncContext.Snapshot.prototype.constructor is + %AsyncContext.Snapshot%. +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +assert.sameValue(AsyncContext.Snapshot.prototype.constructor, AsyncContext.Snapshot); +assert.sameValue((new AsyncContext.Snapshot()).constructor, AsyncContext.Snapshot); + +verifyNotEnumerable(AsyncContext.Snapshot.prototype, 'constructor'); +verifyWritable(AsyncContext.Snapshot.prototype, 'constructor'); +verifyConfigurable(AsyncContext.Snapshot.prototype, 'constructor'); diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/descriptor.js b/test/built-ins/AsyncContext/Snapshot/prototype/descriptor.js new file mode 100644 index 00000000000..a4f99f0c6bc --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/prototype/descriptor.js @@ -0,0 +1,16 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.prototype +description: AsyncContext.Snapshot.prototype property attributes. +info: | + This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, + [[Configurable]]: false }. +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +verifyNotEnumerable(AsyncContext.Snapshot, 'prototype'); +verifyNotWritable(AsyncContext.Snapshot, 'prototype'); +verifyNotConfigurable(AsyncContext.Snapshot, 'prototype'); diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/calls-callback-with-args.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/calls-callback-with-args.js new file mode 100644 index 00000000000..119e31db60c --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/calls-callback-with-args.js @@ -0,0 +1,36 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.prototype.run +description: > + Calls the first parameter as a function, passing any arguments after the + first to it. +info: | + AsyncContext.Snapshot.prototype.run ( func, ...args ) + + 4. Let result be Completion(Call(func, undefined, args)). + ... + 6. Return result. +features: [AsyncContext] +---*/ + +const asyncSnapshot = new AsyncContext.Snapshot(); + +const obj = {}; +const symbol = Symbol(); + +let called = false; + +asyncSnapshot.run(callback, 42, "bar", obj, symbol); + +assert(called, 'The `callback` function was called.'); + +function callback() { + assert.sameValue(arguments.length, 4); + assert.sameValue(arguments[0], 42); + assert.sameValue(arguments[1], "bar"); + assert.sameValue(arguments[2], obj); + assert.sameValue(arguments[3], symbol); + called = true; +} \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/context-is-not-object.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/context-is-not-object.js new file mode 100644 index 00000000000..62e2c9cd92e --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/context-is-not-object.js @@ -0,0 +1,44 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.prototype.run +description: > + Throws a TypeError if `this` is not an Object. +info: | + AsyncContext.Snapshot.prototype.run ( func, ...args ) + + 1. Let asyncSnapshot be the this value. + 2. Perform ? RequireInternalSlot(asyncSnapshot, [[AsyncSnapshotMapping]]). + ... + + RequireInternalSlot(O, internalSlot) + + 1. If O is not an Object, throw a TypeError exception. + ... +features: [AsyncContext, Symbol] +---*/ + +assert.throws(TypeError, function () { + AsyncContext.Snapshot.prototype.run.call(1); +}); + +assert.throws(TypeError, function () { + AsyncContext.Snapshot.prototype.run.call(true); +}); + +assert.throws(TypeError, function () { + AsyncContext.Snapshot.prototype.run.call(''); +}); + +assert.throws(TypeError, function () { + AsyncContext.Snapshot.prototype.run.call(null); +}); + +assert.throws(TypeError, function () { + AsyncContext.Snapshot.prototype.run.call(undefined); +}); + +assert.throws(TypeError, function () { + AsyncContext.Snapshot.prototype.run.call(Symbol()); +}); diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/context-is-not-snapshot-object.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/context-is-not-snapshot-object.js new file mode 100644 index 00000000000..17268753fd4 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/context-is-not-snapshot-object.js @@ -0,0 +1,30 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.prototype.run +description: > + Throws a TypeError if `this` does not have an [[AsyncSnapshotMapping]] + internal slot. +info: | + AsyncContext.Snapshot.prototype.run ( func, ...args ) + + 1. Let asyncContext be the this value. + 2. Perform ? RequireInternalSlot(asyncSnapshot, [[AsyncSnapshotMapping]]). + ... + + RequireInternalSlot(O, internalSlot) + + ... + 2. If O does not have an internalSlot internal slot, throw a TypeError exception. + ... +features: [AsyncContext] +---*/ + +assert.throws(TypeError, function () { + AsyncContext.Snapshot.prototype.run.call({}); +}); + +assert.throws(TypeError, function () { + AsyncContext.Snapshot.prototype.run.call([]); +}); diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/context-is-variable-object-throws.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/context-is-variable-object-throws.js new file mode 100644 index 00000000000..f7a6ebb7255 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/context-is-variable-object-throws.js @@ -0,0 +1,25 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.prototype.run +description: > + Throws a TypeError if `this` is an AsyncContext.Variable object. +info: | + AsyncContext.Snapshot.prototype.run ( func, ...args ) + + 1. Let asyncSnapshot be the this value. + 2. Perform ? RequireInternalSlot(asyncSnapshot, [[AsyncSnapshotMapping]]). + ... + + RequireInternalSlot(O, internalSlot) + + ... + 2. If O does not have an internalSlot internal slot, throw a TypeError exception. + ... +features: [AsyncContext] +---*/ + +assert.throws(TypeError, function () { + AsyncContext.Snapshot.prototype.run.call(new AsyncContext.Variable()); +}); diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/length.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/length.js new file mode 100644 index 00000000000..a4ebd58f050 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/length.js @@ -0,0 +1,24 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.prototype.run +description: > + AsyncContext.Snapshot.prototype.run.length value and descriptor. +info: | + AsyncContext.Snapshot.prototype.run ( func, ...args ) + + 17 ECMAScript Standard Built-in Objects + +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +assert.sameValue( + AsyncContext.Snapshot.prototype.run.length, 1, + 'The value of `AsyncContext.Snapshot.prototype.run.length` is `1`' +); + +verifyNotEnumerable(AsyncContext.Snapshot.prototype.run, 'length'); +verifyNotWritable(AsyncContext.Snapshot.prototype.run, 'length'); +verifyConfigurable(AsyncContext.Snapshot.prototype.run, 'length'); diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/name.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/name.js new file mode 100644 index 00000000000..3471d2b851d --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/name.js @@ -0,0 +1,24 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.prototype.run +description: > + AsyncContext.Snapshot.prototype.run.name value and descriptor. +info: | + AsyncContext.Snapshot.prototype.run ( func, ...args ) + + 17 ECMAScript Standard Built-in Objects + +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +assert.sameValue( + AsyncContext.Snapshot.prototype.run.name, 'run', + 'The value of `AsyncContext.Snapshot.prototype.run.name` is `"run"`' +); + +verifyNotEnumerable(AsyncContext.Snapshot.prototype.run, 'name'); +verifyNotWritable(AsyncContext.Snapshot.prototype.run, 'name'); +verifyConfigurable(AsyncContext.Snapshot.prototype.run, 'name'); diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/not-a-constructor.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/not-a-constructor.js new file mode 100644 index 00000000000..86fa96b3488 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/not-a-constructor.js @@ -0,0 +1,30 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-ecmascript-standard-built-in-objects +description: > + AsyncContext.Snapshot.prototype.run does not implement [[Construct]], is not + new-able +info: | + ECMAScript Function 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. + + sec-evaluatenew + + ... + 7. If IsConstructor(constructor) is false, throw a TypeError exception. + ... +includes: [isConstructor.js] +features: [Reflect.construct, AsyncContext, arrow-function] +---*/ + +assert.sameValue(isConstructor(AsyncContext.Snapshot.prototype.run), false, 'isConstructor(AsyncContext.Snapshot.prototype.run) must return false'); + +assert.throws(TypeError, () => { + let s = new AsyncContext.Snapshot(); new s.run(() => { }); +}, '`let s = new AsyncContext.Snapshot(); new s.run(() => {});` throws TypeError'); + diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/restores-previous-context-snapshot-after-callback.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/restores-previous-context-snapshot-after-callback.js new file mode 100644 index 00000000000..305c21cc84e --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/restores-previous-context-snapshot-after-callback.js @@ -0,0 +1,59 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.prototype.run +description: > + Switches back into the context snapshot active at the time of calling `run` + after calling the callback. +info: | + AsyncContext.Snapshot.prototype.run ( func, ...args ) + + 3. Let previousContextMapping be AsyncContextSwap(asyncSnapshot.[[AsyncSnapshotMapping]]). + 4. Let result be Completion(Call(func, undefined, args)). + 5. AsyncContextSwap(previousContextMapping). + 6. Return result. + + AsyncContextSwap ( snapshotMapping ) + + 1. Let agentRecord be the surrounding agent's Agent Record. + 2. Let asyncContextMapping be agentRecord.[[AsyncContextMapping]]. + 3. Set agentRecord.[[AsyncContextMapping]] to snapshotMapping. + 4. Return asyncContextMapping. +features: [AsyncContext] +---*/ + +const asyncVar1 = new AsyncContext.Variable(); +const asyncVar2 = new AsyncContext.Variable(); + +const snapshot = asyncVar1.run(42, () => new AsyncContext.Snapshot()); + +const asyncVar3 = new AsyncContext.Variable(); + +asyncVar1.run("foo", () => { + asyncVar2.run("bar", () => { + asyncVar3.run("baz", () => { + + snapshot.run(() => { }); + + assert.sameValue( + asyncVar1.get(), + "foo", + 'The value of `asyncVar1.get()` is `"foo"`' + ); + + assert.sameValue( + asyncVar2.get(), + "bar", + 'The value of `asyncVar2.get()` is `"bar"`' + ); + + assert.sameValue( + asyncVar3.get(), + "baz", + 'The value of `asyncVar3.get()` is `"baz"`' + ); + + }); + }); +}); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/restores-snapshot.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/restores-snapshot.js new file mode 100644 index 00000000000..f500e4e2eca --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/restores-snapshot.js @@ -0,0 +1,60 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.prototype.run +description: > + Restores the snapshot when calling the callback. +info: | + AsyncContext.Snapshot.prototype.run ( func, ...args ) + + 3. Let previousContextMapping be + AsyncContextSwap(asyncSnapshopt.[[AsyncSnapshotMapping]]). + 4. Let result be Completion(Call(func, undefined, args)). + + AsyncContextSwap ( snapshotMapping ) + + 1. Let agentRecord be the surrounding agent's Agent Record. + 2. Let asyncContextMapping be agentRecord.[[AsyncContextMapping]]. + 3. Set agentRecord.[[AsyncContextMapping]] to snapshotMapping. + 4. Return asyncContextMapping. +features: [AsyncContext] +---*/ + +const asyncVar1 = new AsyncContext.Variable(); +const asyncVar2 = new AsyncContext.Variable(); +const asyncVar3 = new AsyncContext.Variable(); + +let asyncSnapshot; + +asyncVar1.run("foo", () => { + asyncVar2.run("bar", () => { + asyncVar3.run("baz", () => { + + asyncSnapshot = new AsyncContext.Snapshot(); + + }); + }); +}); + +asyncSnapshot.run(() => { + + assert.sameValue( + asyncVar1.get(), + "foo", + 'The value of `asyncVar1.get()` is `"foo"`' + ); + + assert.sameValue( + asyncVar2.get(), + "bar", + 'The value of `asyncVar2.get()` is `"bar"`' + ); + + assert.sameValue( + asyncVar3.get(), + "baz", + 'The value of `asyncVar3.get()` is `"baz"`' + ); + +}); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/restores-unset-variables.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/restores-unset-variables.js new file mode 100644 index 00000000000..55ecbe09e1f --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/restores-unset-variables.js @@ -0,0 +1,87 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.prototype.run +description: > + For any AsyncContext.Variable objects that were unset in the snapshot, and + that were set in the current snapshot at the time of calling `run`, they are + unset in the context in which the callback is called. + + This happens even for AsyncContext.Variable instances that were did not yet + exist when the AsyncContext.Snapshot was created. +info: | + AsyncContext.Snapshot.prototype.run ( func, ...args ) + + 3. Let previousContextMapping be + AsyncContextSwap(asyncSnapshopt.[[AsyncSnapshotMapping]]). + 4. Let result be Completion(Call(func, undefined, args)). + 5. AsyncContextSwap(previousContextMapping). + + AsyncContextSwap ( snapshotMapping ) + + 1. Let agentRecord be the surrounding agent's Agent Record. + 2. Let asyncContextMapping be agentRecord.[[AsyncContextMapping]]. + 3. Set agentRecord.[[AsyncContextMapping]] to snapshotMapping. + 4. Return asyncContextMapping. +features: [AsyncContext] +---*/ + +const symbol = Symbol(); + +const asyncVar1 = new AsyncContext.Variable(); +const asyncVar2 = new AsyncContext.Variable({ defaultValue: symbol }); +const asyncVar3 = new AsyncContext.Variable(); + +let asyncSnapshot; + +asyncVar1.run("foo", () => { + asyncSnapshot = new AsyncContext.Snapshot(); +}); + +const newAsyncVar1 = new AsyncContext.Variable({ defaultValue: symbol }); +const newAsyncVar2 = new AsyncContext.Variable(); + +asyncVar2.run("bar", () => { + asyncVar3.run("baz", () => { + newAsyncVar1.run("fizz", () => { + newAsyncVar2.run("buzz", () => { + + asyncSnapshot.run(() => { + + assert.sameValue( + asyncVar1.get(), + "foo", + 'The value of `asyncVar1.get()` is `"foo"`' + ); + + assert.sameValue( + asyncVar2.get(), + symbol, + 'The value of `asyncVar2.get()` is `symbol`' + ); + + assert.sameValue( + asyncVar3.get(), + undefined, + 'The value of `asyncVar3.get()` is `"undefined`' + ); + + assert.sameValue( + newAsyncVar1.get(), + symbol, + 'The value of `newAsyncVar1.get()` is `symbol`' + ); + + assert.sameValue( + newAsyncVar2.get(), + undefined, + 'The value of `newAsyncVar2.get()` is `"undefined`' + ); + + }); + + }); + }); + }); +}); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/returned-promise-does-not-resolve-in-snapshot.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/returned-promise-does-not-resolve-in-snapshot.js new file mode 100644 index 00000000000..72aea03c4c5 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/returned-promise-does-not-resolve-in-snapshot.js @@ -0,0 +1,33 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.prototype.run +description: > + When it returns a promise, the async context snapshot when the promise + resolves will not be the one inside of the callback. +info: | + TODO +flags: [async] +features: [AsyncContext] +---*/ + +const asyncVar = new AsyncContext.Variable(); + +const asyncSnapshot = asyncVar.run("foo", () => new AsyncContext.Snapshot()); + +let resolve; + +asyncSnapshot.run(async () => { + assert.sameValue(asyncVar.get(), "foo"); + + await new Promise(resolveFn => { + resolve = resolveFn; + }); + + assert.sameValue(asyncVar.get(), "foo"); +}).then(() => { + assert.sameValue(asyncVar.get(), undefined); +}).then($DONE, $DONE); + +resolve(); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/returns-async-callback-return-value.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/returns-async-callback-return-value.js new file mode 100644 index 00000000000..2e744be8ffa --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/returns-async-callback-return-value.js @@ -0,0 +1,32 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.prototype.run +description: > + If the first parameter is an async function, it calls it and returns its + result value, which is a promise. +info: | + AsyncContext.Snapshot.prototype.run ( func, ...args ) + + 4 Let result be Completion(Call(func, undefined, args)). + ... + 6. Return result. +flags: [async] +includes: [asyncHelpers.js] +features: [AsyncContext] +---*/ + +const asyncSnapshot = new AsyncContext.Snapshot(); + +const obj = {}; + +asyncTest(async function () { + const ret = asyncSnapshot.run(async () => obj); + assert( + ret instanceof Promise, + 'The return value of `asyncSnapshot.run(async () => obj) is a promise' + ); + + assert.sameValue(await ret, obj, '`ret` resolves to `obj`'); +}); diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/returns-callback-return-value.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/returns-callback-return-value.js new file mode 100644 index 00000000000..4df451770e2 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/returns-callback-return-value.js @@ -0,0 +1,31 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.prototype.run +description: > + Calls the first parameter as a function, and returns its return value. +info: | + AsyncContext.Snapshot.prototype.run ( func, ...args ) + + 4. Let result be Completion(Call(func, undefined, args)). + ... + 6. Return result. +features: [AsyncContext] +---*/ + +const asyncSnapshot = new AsyncContext.Snapshot(); + +const obj = {}; + +assert.sameValue( + asyncSnapshot.run(() => obj), + obj, + 'The return value of `asyncSnapshot.run(() => obj)` is `obj`' +); + +const returnedPromise = asyncSnapshot.run(async () => obj); +assert( + returnedPromise instanceof Promise, + 'The return value of `asyncSnapshot.run(async () => obj) is a promise' +); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/run.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/run.js new file mode 100644 index 00000000000..bfa6b1176ea --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/run.js @@ -0,0 +1,23 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.prototype.run +description: > + AsyncContext.Snapshot.prototype.run ( func, ...args ) + + 17 ECMAScript Standard Built-in Objects + +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +assert.sameValue( + typeof AsyncContext.Snapshot.prototype.run, + 'function', + 'typeof AsyncContext.Snapshot.prototype.run is "function"' +); + +verifyNotEnumerable(AsyncContext.Snapshot.prototype, 'run'); +verifyWritable(AsyncContext.Snapshot.prototype, 'run'); +verifyConfigurable(AsyncContext.Snapshot.prototype, 'run'); diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/throws-if-callback-is-not-callable.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/throws-if-callback-is-not-callable.js new file mode 100644 index 00000000000..afe3c63bb3b --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/throws-if-callback-is-not-callable.js @@ -0,0 +1,53 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.prototype.run +description: > + Throws if the first parameter is not callable. +info: | + AsyncContext.Snapshot.prototype.run ( func, ...args ) + + 4. Let result be Completion(Call(func, undefined, args)). + ... + 6. Return result. + + Call ( F, V [ , argumentsList ] ) + + 2. If IsCallable(F) is false, throw a TypeError exception. +features: [AsyncContext] +---*/ + +const asyncSnapshot = new AsyncContext.Snapshot(); + +assert.throws(TypeError, () => { + asyncSnapshot.run("foo"); +}); + +assert.throws(TypeError, () => { + asyncSnapshot.run("foo", 1); +}); + +assert.throws(TypeError, () => { + asyncSnapshot.run("foo", true); +}); + +assert.throws(TypeError, () => { + asyncSnapshot.run("foo", ''); +}); + +assert.throws(TypeError, () => { + asyncSnapshot.run("foo", null); +}); + +assert.throws(TypeError, () => { + asyncSnapshot.run("foo", undefined); +}); + +assert.throws(TypeError, () => { + asyncSnapshot.run("foo", Symbol()); +}); + +assert.throws(TypeError, () => { + asyncSnapshot.run("foo", {}); +}); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/throws-if-callback-throws.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/throws-if-callback-throws.js new file mode 100644 index 00000000000..4cd94d1c309 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/throws-if-callback-throws.js @@ -0,0 +1,25 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.prototype.run +description: > + Throws if calling the first parameter throws. +info: | + AsyncContext.Snapshot.prototype.run ( func, ...args ) + + 4. Let result be Completion(Call(func, undefined, args)). + ... + 6. Return result. +features: [AsyncContext] +---*/ + +function CustomError() { } + +const asyncSnapshot = new AsyncContext.Snapshot(); + +assert.throws(CustomError, () => { + asyncSnapshot.run(() => { + throw new CustomError(); + }); +}); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Snapshot/undefined-newtarget-throws.js b/test/built-ins/AsyncContext/Snapshot/undefined-newtarget-throws.js new file mode 100644 index 00000000000..8c9ff6c50c9 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/undefined-newtarget-throws.js @@ -0,0 +1,17 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot +description: Throws a TypeError if NewTarget is undefined. +features: [AsyncContext] +---*/ + +assert.sameValue( + typeof AsyncContext.Snapshot, 'function', + 'typeof AsyncContext.Snapshot is function' +); + +assert.throws(TypeError, function() { + AsyncContext.Snapshot(); +}); diff --git a/test/built-ins/AsyncContext/Symbol.toStringTag.js b/test/built-ins/AsyncContext/Symbol.toStringTag.js new file mode 100644 index 00000000000..e10643305a5 --- /dev/null +++ b/test/built-ins/AsyncContext/Symbol.toStringTag.js @@ -0,0 +1,22 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-@@tostringtag +description: > + `Symbol.toStringTag` property descriptor +info: | + The initial value of the @@toStringTag property is the String value + "AsyncContext". + + This property has the attributes { [[Writable]]: false, [[Enumerable]]: + false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [AsyncContext, Symbol.toStringTag] +---*/ + +assert.sameValue(AsyncContext[Symbol.toStringTag], 'AsyncContext'); + +verifyNotEnumerable(AsyncContext, Symbol.toStringTag); +verifyNotWritable(AsyncContext, Symbol.toStringTag); +verifyConfigurable(AsyncContext, Symbol.toStringTag); diff --git a/test/built-ins/AsyncContext/Variable/constructor-defaultValue-defaults-to-undefined.js b/test/built-ins/AsyncContext/Variable/constructor-defaultValue-defaults-to-undefined.js new file mode 100644 index 00000000000..36e6ecb6d7d --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/constructor-defaultValue-defaults-to-undefined.js @@ -0,0 +1,63 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable +description: > + When the AsyncContext.Variable constructor is not passed an options bag + with a `defaultValue` property, it sets [[AsyncVariableDefaultValue]] to + `undefined`. +info: | + AsyncContext.Variable ( options ) + + 3. Let defaultValue be undefined. + 4. If options is an Object, then + ... + c. Set defaultValue to ? Get(options, "defaultValue"). + ... + 7. Set asyncVariable.[[AsyncVariableDefaultValue]] to defaultValue. + 8. Return asyncVariable. +features: [AsyncContext] +---*/ + +assert.sameValue( + new AsyncContext.Variable().get(), + undefined, + '`new AsyncContext.Variable().get()` returns undefined' +); + +assert.sameValue( + new AsyncContext.Variable(42).get(), + undefined, + '`new AsyncContext.Variable(42).get()` returns undefined' +); + +assert.sameValue( + new AsyncContext.Variable(null).get(), + undefined, + '`new AsyncContext.Variable(null).get()` returns undefined' +); + +assert.sameValue( + new AsyncContext.Variable(Symbol()).get(), + undefined, + '`new AsyncContext.Variable(Symbol()).get()` returns undefined' +); + +assert.sameValue( + new AsyncContext.Variable({}).get(), + undefined, + '`new AsyncContext.Variable({}).get()` returns undefined' +); + +assert.sameValue( + new AsyncContext.Variable([]).get(), + undefined, + '`new AsyncContext.Variable([]).get()` returns undefined' +); + +assert.sameValue( + new AsyncContext.Variable({ name: "foo" }).get(), + undefined, + '`new AsyncContext.Variable({ name: "foo" }).get()` returns undefined' +); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Variable/constructor-defaultValue.js b/test/built-ins/AsyncContext/Variable/constructor-defaultValue.js new file mode 100644 index 00000000000..10f43f0b5c0 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/constructor-defaultValue.js @@ -0,0 +1,54 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable +description: > + When the AsyncContext.Variable constructor is passed an options bag with + a `defaultValue` property, it sets [[AsyncVariableDefaultValue]] to that + property's value. +info: | + AsyncContext.Variable ( options ) + + 4. If options is an Object, then + ... + c. Set defaultValue to ? Get(options, "defaultValue"). + ... + 7. Set asyncVariable.[[AsyncVariableDefaultValue]] to defaultValue. + 8. Return asyncVariable. +features: [AsyncContext] +---*/ + +assert.sameValue( + new AsyncContext.Variable({ defaultValue: undefined }).get(), + undefined, + '`new AsyncContext.Variable({ defaultValue: undefined }).get()` returns `undefined`' +); + +assert.sameValue( + new AsyncContext.Variable({ defaultValue: "foo" }).get(), + 'foo', + '`new AsyncContext.Variable({ defaultValue: "foo" }).get()` returns `"foo"`' +); + +assert.sameValue( + new AsyncContext.Variable({ defaultValue: 42 }).get(), + 42, + '`new AsyncContext.Variable({ defaultValue: 42 }).get()` returns `42`' +); + +const symbol = Symbol(); + +assert.sameValue( + new AsyncContext.Variable({ defaultValue: symbol }).get(), + symbol, + '`new AsyncContext.Variable({ defaultValue: symbol }).get()` returns `symbol`' +); + +const obj = {}; + +assert.sameValue( + new AsyncContext.Variable({ defaultValue: obj }).get(), + obj, + '`new AsyncContext.Variable({ defaultValue: obj }).get()` returns `obj`' +); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Variable/constructor-name-defaults-to-empty-string.js b/test/built-ins/AsyncContext/Variable/constructor-name-defaults-to-empty-string.js new file mode 100644 index 00000000000..56e55423729 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/constructor-name-defaults-to-empty-string.js @@ -0,0 +1,66 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable +description: > + When the AsyncContext.Variable constructor is not passed an options bag + with a `name` property, it sets [[AsyncVariableName]] to the empty string. +info: | + AsyncContext.Variable ( options ) + + 2. Let nameStr be the empty String. + ... + 4. If options is an Object, then + a. Let namePresent be ? HasProperty(options, "name"). + b. If namePresent is true, then + i. Let name be ? Get(options, "name"). + ii. Set nameStr to ? ToString(name). + ... + 6. Set asyncVariable.[[AsyncVariableName]] to nameStr. + ... + 8. Return asyncVariable. +features: [AsyncContext] +---*/ + +assert.sameValue( + new AsyncContext.Variable().name, + '', + '`new AsyncContext.Variable().name` returns the empty string' +); + +assert.sameValue( + new AsyncContext.Variable(42).name, + '', + '`new AsyncContext.Variable(42).name` returns the empty string' +); + +assert.sameValue( + new AsyncContext.Variable(null).name, + '', + '`new AsyncContext.Variable(null).name` returns the empty string' +); + +assert.sameValue( + new AsyncContext.Variable(Symbol()).name, + '', + '`new AsyncContext.Variable(Symbol()).name` returns the empty string' +); + +assert.sameValue( + new AsyncContext.Variable({}).name, + '', + '`new AsyncContext.Variable({}).name` returns the empty string' +); + +assert.sameValue( + new AsyncContext.Variable([]).name, + '', + '`new AsyncContext.Variable([]).name` returns the empty string' +); + +assert.sameValue( + new AsyncContext.Variable({ defaultValue: 42 }).name, + '', + '`new AsyncContext.Variable({ defaultValue: 42 }).name` returns the empty string' +); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Variable/constructor-name.js b/test/built-ins/AsyncContext/Variable/constructor-name.js new file mode 100644 index 00000000000..71ecea0a5c3 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/constructor-name.js @@ -0,0 +1,57 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable +description: > + When the AsyncContext.Variable constructor is passed an options bag with + a `name` property, it sets [[AsyncVariableName]] to the stringification of + that property. +info: | + AsyncContext.Variable ( options ) + + 4. If options is an Object, then + a. Let namePresent be ? HasProperty(options, "name"). + b. If namePresent is true, then + i. Let name be ? Get(options, "name"). + ii. Set nameStr to ? ToString(name). + ... + 6. Set asyncVariable.[[AsyncVariableName]] to nameStr. + ... + 8. Return asyncVariable. +features: [AsyncContext] +---*/ + +function roundtripName(name) { + return new AsyncContext.Variable({ name }).name; +} + +assert.sameValue( + roundtripName("foo"), + 'foo', + '`roundtripName("foo")` returns `"foo"`' +); + +assert.sameValue( + roundtripName(42), + '42', + '`roundtripName(42)` returns `"42"`' +); + +assert.sameValue( + roundtripName(undefined), + 'undefined', + '`roundtripName(undefined)` returns `"undefined"`' +); + +const objectWithStringifier = { + toString() { + return "bar"; + } +} + +assert.sameValue( + roundtripName(objectWithStringifier), + 'bar', + '`roundtripName(objectWithStringifier)` returns `"bar"`' +); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Variable/constructor-throwing-defaultValue-getter.js b/test/built-ins/AsyncContext/Variable/constructor-throwing-defaultValue-getter.js new file mode 100644 index 00000000000..77ca27da12a --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/constructor-throwing-defaultValue-getter.js @@ -0,0 +1,29 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable +description: > + The AsyncContext.Variable constructor throws when passed an options bag + whose `defaultValue` getter throws. +info: | + AsyncContext.Variable ( options ) + + 4. If options is an Object, then + ... + c. Set defaultValue to ? Get(options, "defaultValue"). + ... +features: [AsyncContext] +---*/ + +function CustomError() { } + +const options = { + get defaultValue() { + throw new CustomError(); + } +}; + +assert.throws(CustomError, () => { + new AsyncContext.Variable(options); +}); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Variable/constructor-throwing-name-getter.js b/test/built-ins/AsyncContext/Variable/constructor-throwing-name-getter.js new file mode 100644 index 00000000000..bc869db23d6 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/constructor-throwing-name-getter.js @@ -0,0 +1,30 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable +description: > + The AsyncContext.Variable constructor throws when passed an options bag + whose `name` getter throws. +info: | + AsyncContext.Variable ( options ) + + 4. If options is an Object, then + a. Let namePresent be ? HasProperty(options, "name"). + b. If namePresent is true, then + i. Let name be ? Get(options, "name"). + ... +features: [AsyncContext] +---*/ + +function CustomError() { } + +const options = { + get name() { + throw new CustomError(); + } +}; + +assert.throws(CustomError, () => { + new AsyncContext.Variable(options); +}); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Variable/constructor-throwing-name-hasproperty.js b/test/built-ins/AsyncContext/Variable/constructor-throwing-name-hasproperty.js new file mode 100644 index 00000000000..fa16119b641 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/constructor-throwing-name-hasproperty.js @@ -0,0 +1,28 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable +description: > + The AsyncContext.Variable constructor throws when passed an options bag + where `HasProperty` of `"name"` throws. +info: | + AsyncContext.Variable ( options ) + + 4. If options is an Object, then + a. Let namePresent be ? HasProperty(options, "name"). + ... +features: [AsyncContext] +---*/ + +function CustomError() { } + +const options = new Proxy({}, { + has() { + throw new CustomError(); + } +}); + +assert.throws(CustomError, () => { + new AsyncContext.Variable(options); +}); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Variable/constructor-throwing-name-tostring.js b/test/built-ins/AsyncContext/Variable/constructor-throwing-name-tostring.js new file mode 100644 index 00000000000..89a9caf4b9e --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/constructor-throwing-name-tostring.js @@ -0,0 +1,41 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable +description: > + The AsyncContext.Variable constructor throws when passed an options bag + with a `name` property which throws when stringified. +info: | + AsyncContext.Variable ( options ) + + 4. If options is an Object, then + a. Let namePresent be ? HasProperty(options, "name"). + b. If namePresent is true, then + i. Let name be ? Get(options, "name"). + ii. Set nameStr to ? ToString(name). + ... +features: [AsyncContext] +---*/ + +assert.throws( + TypeError, + () => { + new AsyncContext.Variable({ name: Symbol() }); + }, + 'The AsyncContext.Variable constructor throws when `name` is a symbol' +); + +function CustomError() { } + +const options = { + name: { + toString() { + throw new CustomError(); + } + } +}; + +assert.throws(CustomError, () => { + new AsyncContext.Variable(options); +}); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Variable/constructor.js b/test/built-ins/AsyncContext/Variable/constructor.js new file mode 100644 index 00000000000..419383f865b --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/constructor.js @@ -0,0 +1,16 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable-constructor +description: > + The AsyncContext.Variable constructor is the %AsyncContext.Variable% + intrinsic object and the initial value of the Variable property of the + %AsyncContext% object. +features: [AsyncContext] +---*/ + +assert.sameValue( + typeof AsyncContext.Variable, 'function', + 'typeof AsyncContext.Variable is function' +); diff --git a/test/built-ins/AsyncContext/Variable/instance-extensible.js b/test/built-ins/AsyncContext/Variable/instance-extensible.js new file mode 100644 index 00000000000..6a94ccf8cd0 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/instance-extensible.js @@ -0,0 +1,11 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable +description: Instances of AsyncContext.Variable are extensible +features: [AsyncContext] +---*/ + +var asyncVariable = new AsyncContext.Variable(); +assert.sameValue(Object.isExtensible(asyncVariable), true); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Variable/instance-prototype.js b/test/built-ins/AsyncContext/Variable/instance-prototype.js new file mode 100644 index 00000000000..64407fd8334 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/instance-prototype.js @@ -0,0 +1,20 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype +description: > + The initial value of AsyncContext.Variable.prototype is the + AsyncContext.Variable prototype object. +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +assert.sameValue( + AsyncContext.Variable.prototype.isPrototypeOf(new AsyncContext.Variable()), true, + 'AsyncContext.Variable.prototype.isPrototypeOf(new AsyncContext.Variable()) returns true' +); + +verifyNotEnumerable(AsyncContext.Variable, 'prototype'); +verifyNotWritable(AsyncContext.Variable, 'prototype'); +verifyNotConfigurable(AsyncContext.Variable, 'prototype'); diff --git a/test/built-ins/AsyncContext/Variable/internal-prototype.js b/test/built-ins/AsyncContext/Variable/internal-prototype.js new file mode 100644 index 00000000000..14ca72270ef --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/internal-prototype.js @@ -0,0 +1,16 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-properties-of-the-asynccontext-variable-constructor +description: > + The AsyncContext.Variable constructor has a [[Prototype]] internal slot whose + value is %Function.prototype%. +features: [AsyncContext] +---*/ + +assert.sameValue( + Function.prototype.isPrototypeOf(AsyncContext.Variable), + true, + 'Function.prototype.isPrototypeOf(AsyncContext.Variable) returns true' +); diff --git a/test/built-ins/AsyncContext/Variable/is-a-constructor.js b/test/built-ins/AsyncContext/Variable/is-a-constructor.js new file mode 100644 index 00000000000..d7dc39e34cd --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/is-a-constructor.js @@ -0,0 +1,12 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable-constructor +description: The AsyncContext.Variable constructor implements [[Construct]] +includes: [isConstructor.js] +features: [AsyncContext] +---*/ + +assert.sameValue(isConstructor(AsyncContext.Variable), true, 'isConstructor(AsyncContext.Variable) must return true'); +new AsyncContext.Variable(); diff --git a/test/built-ins/AsyncContext/Variable/length.js b/test/built-ins/AsyncContext/Variable/length.js new file mode 100644 index 00000000000..212cdec7f5f --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/length.js @@ -0,0 +1,16 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable +description: AsyncContext.Variable.length property descriptor +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +verifyProperty(AsyncContext.Variable, 'length', { + value: 1, + writable: false, + enumerable: false, + configurable: true +}); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Variable/name.js b/test/built-ins/AsyncContext/Variable/name.js new file mode 100644 index 00000000000..dd8afe3debf --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/name.js @@ -0,0 +1,15 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable +description: AsyncContext.Variable.name value and descriptor +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +assert.sameValue(AsyncContext.Variable.name, 'Variable', 'The value of AsyncContext.Variable.name is "Variable"'); + +verifyNotEnumerable(AsyncContext.Variable, 'name'); +verifyNotWritable(AsyncContext.Variable, 'name'); +verifyConfigurable(AsyncContext.Variable, 'name'); diff --git a/test/built-ins/AsyncContext/Variable/prototype/Symbol.toStringTag.js b/test/built-ins/AsyncContext/Variable/prototype/Symbol.toStringTag.js new file mode 100644 index 00000000000..ae866bd7030 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/Symbol.toStringTag.js @@ -0,0 +1,22 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype-@@tostringtag +description: > + `Symbol.toStringTag` property descriptor +info: | + The initial value of the @@toStringTag property is the String value + "AsyncContext.Variable". + + This property has the attributes { [[Writable]]: false, [[Enumerable]]: + false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [AsyncContext, Symbol.toStringTag] +---*/ + +assert.sameValue(AsyncContext.Variable.prototype[Symbol.toStringTag], 'AsyncContext.Variable'); + +verifyNotEnumerable(AsyncContext.Variable.prototype, Symbol.toStringTag); +verifyNotWritable(AsyncContext.Variable.prototype, Symbol.toStringTag); +verifyConfigurable(AsyncContext.Variable.prototype, Symbol.toStringTag); diff --git a/test/built-ins/AsyncContext/Variable/prototype/constructor.js b/test/built-ins/AsyncContext/Variable/prototype/constructor.js new file mode 100644 index 00000000000..c4ecb1c9f00 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/constructor.js @@ -0,0 +1,19 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.constructor +description: AsyncContext.Variable.prototype.constructor value and descriptor +info: | + The initial value of AsyncContext.Variable.prototype.constructor is + %AsyncContext.Variable%. +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +assert.sameValue(AsyncContext.Variable.prototype.constructor, AsyncContext.Variable); +assert.sameValue((new AsyncContext.Variable()).constructor, AsyncContext.Variable); + +verifyNotEnumerable(AsyncContext.Variable.prototype, 'constructor'); +verifyWritable(AsyncContext.Variable.prototype, 'constructor'); +verifyConfigurable(AsyncContext.Variable.prototype, 'constructor'); diff --git a/test/built-ins/AsyncContext/Variable/prototype/descriptor.js b/test/built-ins/AsyncContext/Variable/prototype/descriptor.js new file mode 100644 index 00000000000..a646478e658 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/descriptor.js @@ -0,0 +1,16 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype +description: AsyncContext.Variable.prototype property attributes. +info: | + This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, + [[Configurable]]: false }. +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +verifyNotEnumerable(AsyncContext.Variable, 'prototype'); +verifyNotWritable(AsyncContext.Variable, 'prototype'); +verifyNotConfigurable(AsyncContext.Variable, 'prototype'); diff --git a/test/built-ins/AsyncContext/Variable/prototype/get/context-is-not-object.js b/test/built-ins/AsyncContext/Variable/prototype/get/context-is-not-object.js new file mode 100644 index 00000000000..9ee63ef13a5 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/get/context-is-not-object.js @@ -0,0 +1,44 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.get +description: > + Throws a TypeError if `this` is not an Object. +info: | + AsyncContext.Variable.prototype.get ( ) + + 1. Let asyncVariable be the this value. + 2. Perform ? RequireInternalSlot(asyncVariable, [[AsyncVariableDefaultValue]]). + ... + + RequireInternalSlot(O, internalSlot) + + 1. If O is not an Object, throw a TypeError exception. + ... +features: [AsyncContext, Symbol] +---*/ + +assert.throws(TypeError, function () { + AsyncContext.Variable.prototype.get.call(1); +}); + +assert.throws(TypeError, function () { + AsyncContext.Variable.prototype.get.call(true); +}); + +assert.throws(TypeError, function () { + AsyncContext.Variable.prototype.get.call(''); +}); + +assert.throws(TypeError, function () { + AsyncContext.Variable.prototype.get.call(null); +}); + +assert.throws(TypeError, function () { + AsyncContext.Variable.prototype.get.call(undefined); +}); + +assert.throws(TypeError, function () { + AsyncContext.Variable.prototype.get.call(Symbol()); +}); diff --git a/test/built-ins/AsyncContext/Variable/prototype/get/context-is-not-variable-object.js b/test/built-ins/AsyncContext/Variable/prototype/get/context-is-not-variable-object.js new file mode 100644 index 00000000000..bf8fdd62e6b --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/get/context-is-not-variable-object.js @@ -0,0 +1,30 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.get +description: > + Throws a TypeError if `this` does not have an [[AsyncVariableDefaultValue]] + internal slot. +info: | + AsyncContext.Variable.prototype.get ( ) + + 1. Let asyncVariable be the this value. + 2. Perform ? RequireInternalSlot(asyncVariable, [[AsyncVariableDefaultValue]]). + ... + + RequireInternalSlot(O, internalSlot) + + ... + 2. If O does not have an internalSlot internal slot, throw a TypeError exception. + ... +features: [AsyncContext] +---*/ + +assert.throws(TypeError, function () { + AsyncContext.Variable.prototype.get.call({}); +}); + +assert.throws(TypeError, function () { + AsyncContext.Variable.prototype.get.call([]); +}); diff --git a/test/built-ins/AsyncContext/Variable/prototype/get/context-is-snapshot-object-throws.js b/test/built-ins/AsyncContext/Variable/prototype/get/context-is-snapshot-object-throws.js new file mode 100644 index 00000000000..d6d8b770b8b --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/get/context-is-snapshot-object-throws.js @@ -0,0 +1,25 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.get +description: > + Throws a TypeError if `this` is an AsyncContext.Snapshot object. +info: | + AsyncContext.Variable.prototype.get ( ) + + 1. Let asyncVariable be the this value. + 2. Perform ? RequireInternalSlot(asyncVariable, [[AsyncVariableDefaultValue]]). + ... + + RequireInternalSlot(O, internalSlot) + + ... + 2. If O does not have an internalSlot internal slot, throw a TypeError exception. + ... +features: [AsyncContext] +---*/ + +assert.throws(TypeError, function () { + AsyncContext.Variable.prototype.get.call(new AsyncContext.Snapshot()); +}); diff --git a/test/built-ins/AsyncContext/Variable/prototype/get/get.js b/test/built-ins/AsyncContext/Variable/prototype/get/get.js new file mode 100644 index 00000000000..7a037736958 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/get/get.js @@ -0,0 +1,23 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.get +description: > + AsyncContext.Variable.prototype.get ( ) + + 17 ECMAScript Standard Built-in Objects + +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +assert.sameValue( + typeof AsyncContext.Variable.prototype.get, + 'function', + 'typeof AsyncContext.Variable.prototype.get is "function"' +); + +verifyNotEnumerable(AsyncContext.Variable.prototype, 'get'); +verifyWritable(AsyncContext.Variable.prototype, 'get'); +verifyConfigurable(AsyncContext.Variable.prototype, 'get'); diff --git a/test/built-ins/AsyncContext/Variable/prototype/get/length.js b/test/built-ins/AsyncContext/Variable/prototype/get/length.js new file mode 100644 index 00000000000..49d296c4ec6 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/get/length.js @@ -0,0 +1,24 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.get +description: > + AsyncContext.Variable.prototype.get.length value and descriptor. +info: | + AsyncContext.Variable.prototype.get ( ) + + 17 ECMAScript Standard Built-in Objects + +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +assert.sameValue( + AsyncContext.Variable.prototype.get.length, 0, + 'The value of `AsyncContext.Variable.prototype.get.length` is `0`' +); + +verifyNotEnumerable(AsyncContext.Variable.prototype.get, 'length'); +verifyNotWritable(AsyncContext.Variable.prototype.get, 'length'); +verifyConfigurable(AsyncContext.Variable.prototype.get, 'length'); diff --git a/test/built-ins/AsyncContext/Variable/prototype/get/name.js b/test/built-ins/AsyncContext/Variable/prototype/get/name.js new file mode 100644 index 00000000000..2e41b72e062 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/get/name.js @@ -0,0 +1,24 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.get +description: > + AsyncContext.Variable.prototype.get.name value and descriptor. +info: | + AsyncContext.Variable.prototype.get ( ) + + 17 ECMAScript Standard Built-in Objects + +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +assert.sameValue( + AsyncContext.Variable.prototype.get.name, 'get', + 'The value of `AsyncContext.Variable.prototype.get.name` is `"get"`' +); + +verifyNotEnumerable(AsyncContext.Variable.prototype.get, 'name'); +verifyNotWritable(AsyncContext.Variable.prototype.get, 'name'); +verifyConfigurable(AsyncContext.Variable.prototype.get, 'name'); diff --git a/test/built-ins/AsyncContext/Variable/prototype/get/not-a-constructor.js b/test/built-ins/AsyncContext/Variable/prototype/get/not-a-constructor.js new file mode 100644 index 00000000000..4ed1a7a51ca --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/get/not-a-constructor.js @@ -0,0 +1,30 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-ecmascript-standard-built-in-objects +description: > + AsyncContext.Variable.prototype.get does not implement [[Construct]], is not + new-able +info: | + ECMAScript Function 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. + + sec-evaluatenew + + ... + 7. If IsConstructor(constructor) is false, throw a TypeError exception. + ... +includes: [isConstructor.js] +features: [Reflect.construct, AsyncContext, arrow-function] +---*/ + +assert.sameValue(isConstructor(AsyncContext.Variable.prototype.get), false, 'isConstructor(AsyncContext.Variable.prototype.get) must return false'); + +assert.throws(TypeError, () => { + let v = new AsyncContext.Variable(); new v.get(); +}, '`let v = new AsyncContext.Variable(); new v.get();` throws TypeError'); + diff --git a/test/built-ins/AsyncContext/Variable/prototype/get/returns-default-value-outside-run.js b/test/built-ins/AsyncContext/Variable/prototype/get/returns-default-value-outside-run.js new file mode 100644 index 00000000000..dd45258bfe0 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/get/returns-default-value-outside-run.js @@ -0,0 +1,33 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.get +description: > + When called outside of any `AsyncContext.Variable.prototype.run` or + `AsyncContext.Snapshot.prototype.run` callback, it returns + [[AsyncVariableDefaultValue]]. +info: | + AsyncContext.Variable.prototype.get ( ) + + 3. Let agentRecord be the surrounding agent's Agent Record. + 4. Let asyncContextMapping be agentRecord.[[AsyncContextMapping]]. + 5. For each Async Context Mapping Record p of asyncContextMapping, do + a. If SameValueZero(p.[[AsyncContextKey]], asyncVariable) is true, return p.[[AsyncContextValue]]. + 6. Return asyncVariable.[[AsyncVariableDefaultValue]]. + + An agent record's [[AsyncContextMapping]] field is initially an empty list, + and this only changes in `AsyncContext.Variable.prototype.run` and + `AsyncContext.Snapshot.prototype.run`. +features: [AsyncContext] +---*/ + +const defaultValue = Symbol(); + +const asyncVariable = new AsyncContext.Variable({ defaultValue }); + +assert.sameValue( + asyncVariable.get(), + defaultValue, + 'The value of `asyncVariable.get()` is `defaultValue`' +) \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Variable/prototype/get/returns-undefined-if-set-in-run.js b/test/built-ins/AsyncContext/Variable/prototype/get/returns-undefined-if-set-in-run.js new file mode 100644 index 00000000000..c4316e60cc5 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/get/returns-undefined-if-set-in-run.js @@ -0,0 +1,28 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.get +description: > + When called in the callback passed to `AsyncContext.Variable.prototype.run`, + it returns the first argument to `run`, even if that is `undefined` and the + `AsyncContext.Variable` instance has a different default value. +info: | + AsyncContext.Variable.prototype.get ( ) + + 3. Let agentRecord be the surrounding agent's Agent Record. + 4. Let asyncContextMapping be agentRecord.[[AsyncContextMapping]]. + 5. For each Async Context Mapping Record p of asyncContextMapping, do + a. If SameValueZero(p.[[AsyncContextKey]], asyncVariable) is true, return p.[[AsyncContextValue]]. +features: [AsyncContext] +---*/ + +const asyncVariable = new AsyncContext.Variable({ defaultValue: 42 }); + +asyncVariable.run(undefined, () => { + assert.sameValue( + asyncVariable.get(), + undefined, + 'The value of `asyncVariable.get()` is `undefined`' + ); +}); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Variable/prototype/get/returns-value-set-in-run.js b/test/built-ins/AsyncContext/Variable/prototype/get/returns-value-set-in-run.js new file mode 100644 index 00000000000..f8818f9ee8a --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/get/returns-value-set-in-run.js @@ -0,0 +1,39 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.get +description: > + When called in the callback passed to `AsyncContext.Variable.prototype.run`, + it returns the first argument to `run`. +info: | + AsyncContext.Variable.prototype.get ( ) + + 3. Let agentRecord be the surrounding agent's Agent Record. + 4. Let asyncContextMapping be agentRecord.[[AsyncContextMapping]]. + 5. For each Async Context Mapping Record p of asyncContextMapping, do + a. If SameValueZero(p.[[AsyncContextKey]], asyncVariable) is true, return p.[[AsyncContextValue]]. + + AsyncContext.Variable.prototype.run ( value, func, ...args ) + + 4. Let asyncContextMapping be a new empty List. + ... + 7. Let p be the Async Context Mapping Record { [[AsyncContextKey]]: asyncVariable, [[AsyncContextValue]]: value }. + 8. Append p to asyncContextMapping. + 9. AsyncContextSwap(asyncContextMapping). + 10. Let result be Completion(Call(func, undefined, args)). + ... +features: [AsyncContext] +---*/ + +const value = Symbol(); + +const asyncVariable = new AsyncContext.Variable(); + +asyncVariable.run(value, () => { + assert.sameValue( + asyncVariable.get(), + value, + 'The value of `asyncVariable.get()` is `value`' + ); +}); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Variable/prototype/name/does-not-have-internal-slot-snapshot.js b/test/built-ins/AsyncContext/Variable/prototype/name/does-not-have-internal-slot-snapshot.js new file mode 100644 index 00000000000..9175c804785 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/name/does-not-have-internal-slot-snapshot.js @@ -0,0 +1,27 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.name +description: > + Throws a TypeError if `this` object does not have an [[AsyncVariableName]] + internal slot, which also applies to AsyncContext.Snapshot objects. +info: | + get AsyncContext.Variable.prototype.name + + 1. Let asyncVariable be the this value. + 2. Perform ? RequireInternalSlot(asyncVariable, [[AsyncVariableName]]). + ... +features: [AsyncContext] +---*/ + +var descriptor = Object.getOwnPropertyDescriptor(AsyncContext.Variable.prototype, 'name'); + +var asyncVariable = new AsyncContext.Variable(); + +// Does not throw +descriptor.get.call(asyncVariable); + +assert.throws(TypeError, function () { + descriptor.get.call(new AsyncContext.Snapshot()); +}); diff --git a/test/built-ins/AsyncContext/Variable/prototype/name/does-not-have-internal-slot.js b/test/built-ins/AsyncContext/Variable/prototype/name/does-not-have-internal-slot.js new file mode 100644 index 00000000000..1f0a0065c33 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/name/does-not-have-internal-slot.js @@ -0,0 +1,26 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.name +description: > + Throws a TypeError if `this` object does not have an [[AsyncVariableName]] internal slot. +info: | + get AsyncContext.Variable.prototype.name + + 1. Let asyncVariable be the this value. + 2. Perform ? RequireInternalSlot(asyncVariable, [[AsyncVariableName]]). + ... +features: [AsyncContext] +---*/ + +var descriptor = Object.getOwnPropertyDescriptor(AsyncContext.Variable.prototype, 'name'); + +var asyncVariable = new AsyncContext.Variable(); + +// Does not throw +descriptor.get.call(asyncVariable); + +assert.throws(TypeError, function () { + descriptor.get.call([]); +}); diff --git a/test/built-ins/AsyncContext/Variable/prototype/name/length.js b/test/built-ins/AsyncContext/Variable/prototype/name/length.js new file mode 100644 index 00000000000..1a4b890be29 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/name/length.js @@ -0,0 +1,25 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.name +description: > + AsyncContext.Variable.prototype.name.length value and descriptor. +info: | + get AsyncContext.Variable.prototype.name + + 17 ECMAScript Standard Built-in Objects +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +var descriptor = Object.getOwnPropertyDescriptor(AsyncContext.Variable.prototype, 'name'); + +assert.sameValue( + descriptor.get.length, 0, + 'The value of `AsyncContext.Variable.prototype.name.length` is `0`' +); + +verifyNotEnumerable(descriptor.get, 'length'); +verifyNotWritable(descriptor.get, 'length'); +verifyConfigurable(descriptor.get, 'length'); diff --git a/test/built-ins/AsyncContext/Variable/prototype/name/name-getter.js b/test/built-ins/AsyncContext/Variable/prototype/name/name-getter.js new file mode 100644 index 00000000000..e507516a775 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/name/name-getter.js @@ -0,0 +1,31 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.name +description: > + Property type and descriptor. +info: | + get AsyncContext.Variable.prototype.name + + 17 ECMAScript Standard Built-in Objects + +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +var descriptor = Object.getOwnPropertyDescriptor(AsyncContext.Variable.prototype, 'name'); + +assert.sameValue( + typeof descriptor.get, + 'function', + 'typeof descriptor.get is function' +); +assert.sameValue( + typeof descriptor.set, + 'undefined', + 'typeof descriptor.set is undefined' +); + +verifyNotEnumerable(AsyncContext.Variable.prototype, 'name'); +verifyConfigurable(AsyncContext.Variable.prototype, 'name'); diff --git a/test/built-ins/AsyncContext/Variable/prototype/name/name.js b/test/built-ins/AsyncContext/Variable/prototype/name/name.js new file mode 100644 index 00000000000..29bdbd8006f --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/name/name.js @@ -0,0 +1,29 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.name +description: > + AsyncContext.Variable.prototype.name.name value and descriptor. +info: | + get AsyncContext.Variable.prototype.name + + 17 ECMAScript Standard Built-in Objects + + Functions that are specified as get or set accessor functions of built-in + properties have "get " or "set " prepended to the property name string. + +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +var descriptor = Object.getOwnPropertyDescriptor(AsyncContext.Variable.prototype, 'name'); + +assert.sameValue(descriptor.get.name, + 'get name', + 'The value of `descriptor.get.name` is `get name`' +); + +verifyNotEnumerable(descriptor.get, 'name'); +verifyNotWritable(descriptor.get, 'name'); +verifyConfigurable(descriptor.get, 'name'); diff --git a/test/built-ins/AsyncContext/Variable/prototype/name/returns-name-passed-to-constructor.js b/test/built-ins/AsyncContext/Variable/prototype/name/returns-name-passed-to-constructor.js new file mode 100644 index 00000000000..2826bd20347 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/name/returns-name-passed-to-constructor.js @@ -0,0 +1,22 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.name +description: > + Returns the name that was passed to the AsyncContext.Variable constructor, + converted to a string. +info: | + get AsyncContext.Variable.prototype.name + + 3. Return asyncVariable.[[AsyncVariableName]]. +features: [AsyncContext] +---*/ + +const asyncVar = new AsyncContext.Variable({ name: "foo" }); + +assert.sameValue( + asyncVar.name, + "foo", + 'The value of `asyncVar.name` is `"foo"`' +); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Variable/prototype/name/this-not-object-throw.js b/test/built-ins/AsyncContext/Variable/prototype/name/this-not-object-throw.js new file mode 100644 index 00000000000..64bb60e86d5 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/name/this-not-object-throw.js @@ -0,0 +1,51 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.name +description: > + Throws a TypeError if `this` is not an Object. +info: | + get AsyncContext.Variable.prototype.name + + 1. Let asyncVariable be the this value. + 2. Perform ? RequireInternalSlot(asyncVariable, [[AsyncVariableDefaultValue]]). + ... + + RequireInternalSlot ( O, internalSlot ) + + 1. If O is not an Object, throw a TypeError exception. + ... + +features: [Symbol, AsyncContext] +---*/ + +var descriptor = Object.getOwnPropertyDescriptor(AsyncContext.Variable.prototype, 'name'); + +assert.throws(TypeError, function () { + descriptor.get.call(1); +}); + +assert.throws(TypeError, function () { + descriptor.get.call(false); +}); + +assert.throws(TypeError, function () { + descriptor.get.call(1); +}); + +assert.throws(TypeError, function () { + descriptor.get.call(''); +}); + +assert.throws(TypeError, function () { + descriptor.get.call(undefined); +}); + +assert.throws(TypeError, function () { + descriptor.get.call(null); +}); + +assert.throws(TypeError, function () { + descriptor.get.call(Symbol()); +}); diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/calls-callback-with-args.js b/test/built-ins/AsyncContext/Variable/prototype/run/calls-callback-with-args.js new file mode 100644 index 00000000000..36fe974d5df --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/run/calls-callback-with-args.js @@ -0,0 +1,36 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.run +description: > + Calls the second parameter as a function, passing any arguments after the + second to it. +info: | + AsyncContext.Variable.prototype.run ( value, func, ...args ) + + 10. Let result be Completion(Call(func, undefined, args)). + ... + 12. Return result. +features: [AsyncContext] +---*/ + +const asyncVar = new AsyncContext.Variable(); + +const obj = {}; +const symbol = Symbol(); + +let called = false; + +asyncVar.run("foo", callback, 42, "bar", obj, symbol); + +assert(called, 'The `callback` function was called.'); + +function callback() { + assert.sameValue(arguments.length, 4); + assert.sameValue(arguments[0], 42); + assert.sameValue(arguments[1], "bar"); + assert.sameValue(arguments[2], obj); + assert.sameValue(arguments[3], symbol); + called = true; +} \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/context-is-not-object.js b/test/built-ins/AsyncContext/Variable/prototype/run/context-is-not-object.js new file mode 100644 index 00000000000..0f8f611b82a --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/run/context-is-not-object.js @@ -0,0 +1,44 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.run +description: > + Throws a TypeError if `this` is not an Object. +info: | + AsyncContext.Variable.prototype.run ( value, func, ...args ) + + 1. Let asyncVariable be the this value. + 2. Perform ? RequireInternalSlot(asyncVariable, [[AsyncVariableName]]). + ... + + RequireInternalSlot(O, internalSlot) + + 1. If O is not an Object, throw a TypeError exception. + ... +features: [AsyncContext, Symbol] +---*/ + +assert.throws(TypeError, function () { + AsyncContext.Variable.prototype.run.call(1); +}); + +assert.throws(TypeError, function () { + AsyncContext.Variable.prototype.run.call(true); +}); + +assert.throws(TypeError, function () { + AsyncContext.Variable.prototype.run.call(''); +}); + +assert.throws(TypeError, function () { + AsyncContext.Variable.prototype.run.call(null); +}); + +assert.throws(TypeError, function () { + AsyncContext.Variable.prototype.run.call(undefined); +}); + +assert.throws(TypeError, function () { + AsyncContext.Variable.prototype.run.call(Symbol()); +}); diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/context-is-not-variable-object.js b/test/built-ins/AsyncContext/Variable/prototype/run/context-is-not-variable-object.js new file mode 100644 index 00000000000..0c754365f47 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/run/context-is-not-variable-object.js @@ -0,0 +1,30 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.run +description: > + Throws a TypeError if `this` does not have an [[AsyncVariableName]] internal + slot. +info: | + AsyncContext.Variable.prototype.run ( value, func, ...args ) + + 1. Let asyncVariable be the this value. + 2. Perform ? RequireInternalSlot(asyncVariable, [[AsyncVariableName]]). + ... + + RequireInternalSlot(O, internalSlot) + + ... + 2. If O does not have an internalSlot internal slot, throw a TypeError exception. + ... +features: [AsyncContext] +---*/ + +assert.throws(TypeError, function () { + AsyncContext.Variable.prototype.run.call({}); +}); + +assert.throws(TypeError, function () { + AsyncContext.Variable.prototype.run.call([]); +}); diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/context-is-snapshot-object-throws.js b/test/built-ins/AsyncContext/Variable/prototype/run/context-is-snapshot-object-throws.js new file mode 100644 index 00000000000..bac755835a9 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/run/context-is-snapshot-object-throws.js @@ -0,0 +1,25 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.run +description: > + Throws a TypeError if `this` is an AsyncContext.Snapshot object. +info: | + AsyncContext.Variable.prototype.run ( value, func, ...args ) + + 1. Let asyncVariable be the this value. + 2. Perform ? RequireInternalSlot(asyncVariable, [[AsyncVariableName]]). + ... + + RequireInternalSlot(O, internalSlot) + + ... + 2. If O does not have an internalSlot internal slot, throw a TypeError exception. + ... +features: [AsyncContext] +---*/ + +assert.throws(TypeError, function () { + AsyncContext.Variable.prototype.run.call(new AsyncContext.Snapshot()); +}); diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/length.js b/test/built-ins/AsyncContext/Variable/prototype/run/length.js new file mode 100644 index 00000000000..f1bc7b00c32 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/run/length.js @@ -0,0 +1,24 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.run +description: > + AsyncContext.Variable.prototype.run.length value and descriptor. +info: | + AsyncContext.Variable.prototype.run ( value, func, ...args ) + + 17 ECMAScript Standard Built-in Objects + +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +assert.sameValue( + AsyncContext.Variable.prototype.run.length, 2, + 'The value of `AsyncContext.Variable.prototype.run.length` is `2`' +); + +verifyNotEnumerable(AsyncContext.Variable.prototype.run, 'length'); +verifyNotWritable(AsyncContext.Variable.prototype.run, 'length'); +verifyConfigurable(AsyncContext.Variable.prototype.run, 'length'); diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/name.js b/test/built-ins/AsyncContext/Variable/prototype/run/name.js new file mode 100644 index 00000000000..1399342509b --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/run/name.js @@ -0,0 +1,24 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.run +description: > + AsyncContext.Variable.prototype.run.name value and descriptor. +info: | + AsyncContext.Variable.prototype.run ( value, func, ...args ) + + 17 ECMAScript Standard Built-in Objects + +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +assert.sameValue( + AsyncContext.Variable.prototype.run.name, 'run', + 'The value of `AsyncContext.Variable.prototype.run.name` is `"run"`' +); + +verifyNotEnumerable(AsyncContext.Variable.prototype.run, 'name'); +verifyNotWritable(AsyncContext.Variable.prototype.run, 'name'); +verifyConfigurable(AsyncContext.Variable.prototype.run, 'name'); diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/not-a-constructor.js b/test/built-ins/AsyncContext/Variable/prototype/run/not-a-constructor.js new file mode 100644 index 00000000000..e9c7d9e8ec0 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/run/not-a-constructor.js @@ -0,0 +1,30 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-ecmascript-standard-built-in-objects +description: > + AsyncContext.Variable.prototype.run does not implement [[Construct]], is not + new-able +info: | + ECMAScript Function 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. + + sec-evaluatenew + + ... + 7. If IsConstructor(constructor) is false, throw a TypeError exception. + ... +includes: [isConstructor.js] +features: [Reflect.construct, AsyncContext, arrow-function] +---*/ + +assert.sameValue(isConstructor(AsyncContext.Variable.prototype.run), false, 'isConstructor(AsyncContext.Variable.prototype.run) must return false'); + +assert.throws(TypeError, () => { + let v = new AsyncContext.Variable(); new v.run(0, () => { }); +}, '`let v = new AsyncContext.Variable(); new v.run(0, () => {});` throws TypeError'); + diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/restores-context-snapshot-after-callback.js b/test/built-ins/AsyncContext/Variable/prototype/run/restores-context-snapshot-after-callback.js new file mode 100644 index 00000000000..f33eaf29719 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/run/restores-context-snapshot-after-callback.js @@ -0,0 +1,46 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.run +description: > + Switches back into the previous context snapshot after calling the callback. +info: | + AsyncContext.Variable.prototype.run ( value, func, ...args ) + + 3. Let previousContextMapping be AsyncContextSnapshot(). + ... + 10. Let result be Completion(Call(func, undefined, args)). + 11. AsyncContextSwap(previousContextMapping). + 12. Return result. + + AsyncContextSwap ( snapshotMapping ) + + 1. Let agentRecord be the surrounding agent's Agent Record. + ... + 3. Set agentRecord.[[AsyncContextMapping]] to snapshotMapping. + + AsyncContextSnapshot ( ) + + 1. Let agentRecord be the surrounding agent's Agent Record. + 2. Return agentRecord.[[AsyncContextMapping]]. +features: [AsyncContext] +---*/ + +const asyncVar = new AsyncContext.Variable(); + +asyncVar.run("foo", () => { + asyncVar.run("42", () => { }); + + assert.sameValue( + asyncVar.get(), + "foo", + 'The value of `asyncVar.get()` inside the first `run` and after the second one should be `"foo"`' + ); +}); + +assert.sameValue( + asyncVar.get(), + undefined, + 'The value of `asyncVar.get()` after the first `run` should be `undefined`' +); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/returned-promise-does-not-resolve-in-snapshot.js b/test/built-ins/AsyncContext/Variable/prototype/run/returned-promise-does-not-resolve-in-snapshot.js new file mode 100644 index 00000000000..b04581efe5d --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/run/returned-promise-does-not-resolve-in-snapshot.js @@ -0,0 +1,31 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.run +description: > + When it returns a promise, the async context snapshot when the promise + resolves will not be the one inside of the callback. +info: | + TODO +flags: [async] +features: [AsyncContext] +---*/ + +const asyncVar = new AsyncContext.Variable(); + +let resolve; + +asyncVar.run("foo", async () => { + assert.sameValue(asyncVar.get(), "foo"); + + await new Promise(resolveFn => { + resolve = resolveFn; + }); + + assert.sameValue(asyncVar.get(), "foo"); +}).then(() => { + assert.sameValue(asyncVar.get(), undefined); +}).then($DONE, $DONE); + +resolve(); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/returns-async-callback-return-value.js b/test/built-ins/AsyncContext/Variable/prototype/run/returns-async-callback-return-value.js new file mode 100644 index 00000000000..cb189f86dae --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/run/returns-async-callback-return-value.js @@ -0,0 +1,32 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.run +description: > + If the second parameter is an async function, it calls it and returns its + result value, which is a promise. +info: | + AsyncContext.Variable.prototype.run ( value, func, ...args ) + + 10. Let result be Completion(Call(func, undefined, args)). + ... + 12. Return result. +flags: [async] +includes: [asyncHelpers.js] +features: [AsyncContext] +---*/ + +const asyncVar = new AsyncContext.Variable(); + +const obj = {}; + +asyncTest(async function () { + const ret = asyncVar.run("foo", async () => obj); + assert( + ret instanceof Promise, + 'The return value of `asyncVar.run("foo", async () => obj) is a promise' + ); + + assert.sameValue(await ret, obj, '`ret` resolves to `obj`'); +}); diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/returns-callback-return-value.js b/test/built-ins/AsyncContext/Variable/prototype/run/returns-callback-return-value.js new file mode 100644 index 00000000000..9aeda6de845 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/run/returns-callback-return-value.js @@ -0,0 +1,31 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.run +description: > + Calls the second parameter as a function, and returns its return value. +info: | + AsyncContext.Variable.prototype.run ( value, func, ...args ) + + 10. Let result be Completion(Call(func, undefined, args)). + ... + 12. Return result. +features: [AsyncContext] +---*/ + +const asyncVar = new AsyncContext.Variable(); + +const obj = {}; + +assert.sameValue( + asyncVar.run("foo", () => obj), + obj, + 'The return value of `asyncVar.run("foo", () => obj)` is `obj`' +); + +const returnedPromise = asyncVar.run("foo", async () => obj); +assert( + returnedPromise instanceof Promise, + 'The return value of `asyncVar.run("foo", async () => obj) is a promise' +); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/run.js b/test/built-ins/AsyncContext/Variable/prototype/run/run.js new file mode 100644 index 00000000000..19ba3d9660f --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/run/run.js @@ -0,0 +1,23 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.run +description: > + AsyncContext.Variable.prototype.run ( value, func, ...args ) + + 17 ECMAScript Standard Built-in Objects + +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +assert.sameValue( + typeof AsyncContext.Variable.prototype.run, + 'function', + 'typeof AsyncContext.Variable.prototype.run is "function"' +); + +verifyNotEnumerable(AsyncContext.Variable.prototype, 'run'); +verifyWritable(AsyncContext.Variable.prototype, 'run'); +verifyConfigurable(AsyncContext.Variable.prototype, 'run'); diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/swaps-context-snapshot-before-callback.js b/test/built-ins/AsyncContext/Variable/prototype/run/swaps-context-snapshot-before-callback.js new file mode 100644 index 00000000000..e32fcb22c9c --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/run/swaps-context-snapshot-before-callback.js @@ -0,0 +1,42 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.run +description: > + Switches into a context snapshot containing the given value when calling the + callback. +info: | + AsyncContext.Variable.prototype.run ( value, func, ...args ) + + 4. Let asyncContextMapping be a new empty List. + ... + 8. Append p to asyncContextMapping. + 9. AsyncContextSwap(asyncContextMapping.) + 10. Let result be Completion(Call(func, undefined, args)). + ... + + AsyncContextSwap ( snapshotMapping ) + + 1. Let agentRecord be the surrounding agent's Agent Record. + ... + 3. Set agentRecord.[[AsyncContextMapping]] to snapshotMapping. + +features: [AsyncContext] +---*/ + +const asyncVar = new AsyncContext.Variable(); + +assert.sameValue( + asyncVar.get(), + undefined, + 'The value of `asyncVar.get()` before calling `run` is `undefined`' +); + +asyncVar.run(42, () => { + assert.sameValue( + asyncVar.get(), + 42, + 'The value of `asyncVar.get()` inside the callback passed to `run` is `42`' + ); +}); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/throws-if-callback-is-not-callable.js b/test/built-ins/AsyncContext/Variable/prototype/run/throws-if-callback-is-not-callable.js new file mode 100644 index 00000000000..5a739464a30 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/run/throws-if-callback-is-not-callable.js @@ -0,0 +1,53 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.run +description: > + Throws if the second parameter is not callable. +info: | + AsyncContext.Variable.prototype.run ( value, func, ...args ) + + 10. Let result be Completion(Call(func, undefined, args)). + ... + 12. Return result. + + Call ( F, V [ , argumentsList ] ) + + 2. If IsCallable(F) is false, throw a TypeError exception. +features: [AsyncContext] +---*/ + +const asyncVar = new AsyncContext.Variable(); + +assert.throws(TypeError, () => { + asyncVar.run("foo"); +}); + +assert.throws(TypeError, () => { + asyncVar.run("foo", 1); +}); + +assert.throws(TypeError, () => { + asyncVar.run("foo", true); +}); + +assert.throws(TypeError, () => { + asyncVar.run("foo", ''); +}); + +assert.throws(TypeError, () => { + asyncVar.run("foo", null); +}); + +assert.throws(TypeError, () => { + asyncVar.run("foo", undefined); +}); + +assert.throws(TypeError, () => { + asyncVar.run("foo", Symbol()); +}); + +assert.throws(TypeError, () => { + asyncVar.run("foo", {}); +}); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/throws-if-callback-throws.js b/test/built-ins/AsyncContext/Variable/prototype/run/throws-if-callback-throws.js new file mode 100644 index 00000000000..066568be513 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/run/throws-if-callback-throws.js @@ -0,0 +1,25 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.run +description: > + Throws if calling the second parameter throws. +info: | + AsyncContext.Variable.prototype.run ( value, func, ...args ) + + 10. Let result be Completion(Call(func, undefined, args)). + ... + 12. Return result. +features: [AsyncContext] +---*/ + +function CustomError() { } + +const asyncVar = new AsyncContext.Variable(); + +assert.throws(CustomError, () => { + asyncVar.run("foo", () => { + throw new CustomError(); + }); +}); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/unrelated-snapshot-entries-keep-their-value.js b/test/built-ins/AsyncContext/Variable/prototype/run/unrelated-snapshot-entries-keep-their-value.js new file mode 100644 index 00000000000..6c750514a8a --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/run/unrelated-snapshot-entries-keep-their-value.js @@ -0,0 +1,72 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.run +description: > + Switches into a context snapshot which keeps the values of all entries not + corresponding to the current AsyncContext.Variable from the previous context + snapshot. +info: | + AsyncContext.Variable.prototype.run ( value, func, ...args ) + + 3. Let previousContextMapping be AsyncContextSnapshot(). + 4. Let asyncContextMapping be a new empty List. + 5. For each Async Context Mapping Record p of previousContextMapping, do + a. If SameValueZero(p.[[AsyncContextKey]], asyncVariable) is false, then + i. Let q be the Async Context Mapping Record + { [[AsyncContextKey]]: p.[[AsyncContextKey]], + [[AsyncContextValue]]: p.[[AsyncContextValue]] } + ii. Append q to asyncContextMapping + 6. Assert: asyncContextMapping does not contain an Async Context Mapping + Record whose [[AsyncContextKey]] is asyncVariable. + 7. Let p be the Async Context Mapping Record + { [[AsyncContextKey]]: asyncVariable, [[AsyncContextValue]]: value }. + 8. Append p to asyncContextMapping. + 9. AsyncContextSwap(asyncContextMapping) + ... + + AsyncContextSwap ( snapshotMapping ) + + 1. Let agentRecord be the surrounding agent's Agent Record. + ... + 3. Set agentRecord.[[AsyncContextMapping]] to snapshotMapping. + + AsyncContextSnapshot ( ) + + 1. Let agentRecord be the surrounding agent's Agent Record. + 2. Return agentRecord.[[AsyncContextMapping]]. +features: [AsyncContext] +---*/ + +const asyncVar1 = new AsyncContext.Variable(); +const asyncVar2 = new AsyncContext.Variable(); +const asyncVar3 = new AsyncContext.Variable(); + +const symbol1 = Symbol("symbol1"); +const symbol2 = Symbol("symbol2"); +const symbol3 = Symbol("symbol3"); +const symbol4 = Symbol("symbol4"); +const symbol5 = Symbol("symbol5"); + +asyncVar1.run(symbol1, () => { + asyncVar2.run(symbol2, () => { + asyncVar3.run(symbol3, () => { + + assert.sameValue(asyncVar1.get(), symbol1, 'asyncVar1.get() === symbol1'); + assert.sameValue(asyncVar2.get(), symbol2, 'asyncVar2.get() === symbol2'); + assert.sameValue(asyncVar3.get(), symbol3, 'asyncVar3.get() === symbol3'); + + asyncVar2.run(symbol4, () => { + asyncVar1.run(symbol5, () => { + + assert.sameValue(asyncVar1.get(), symbol5, 'asyncVar1.get() === symbol5'); + assert.sameValue(asyncVar2.get(), symbol4, 'asyncVar2.get() === symbol4'); + assert.sameValue(asyncVar3.get(), symbol3, 'asyncVar3.get() === symbol3'); + + }); + }); + + }); + }); +}); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Variable/undefined-newtarget-throws.js b/test/built-ins/AsyncContext/Variable/undefined-newtarget-throws.js new file mode 100644 index 00000000000..d18f44a0866 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/undefined-newtarget-throws.js @@ -0,0 +1,21 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable +description: Throws a TypeError if NewTarget is undefined. +features: [AsyncContext] +---*/ + +assert.sameValue( + typeof AsyncContext.Variable, 'function', + 'typeof AsyncContext.Variable is function' +); + +assert.throws(TypeError, function() { + AsyncContext.Variable(); +}); + +assert.throws(TypeError, function() { + AsyncContext.Variable({}); +}); diff --git a/test/built-ins/AsyncContext/context-propagation/FinalizationRegistry.js b/test/built-ins/AsyncContext/context-propagation/FinalizationRegistry.js new file mode 100644 index 00000000000..f1743486484 --- /dev/null +++ b/test/built-ins/AsyncContext/context-propagation/FinalizationRegistry.js @@ -0,0 +1,35 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-finalization-registry-objects +description: > + The FinalizationRegistry cleanup callback uses HostMakeJobCallback and + HostCallJobCallback, which propagate an async context snapshot. +info: | + TODO +flags: [async, non-deterministic] +features: [AsyncContext, FinalizationRegistry, host-gc-required] +---*/ + +const asyncVar = new AsyncContext.Variable(); + +function cleanupCallback() { + try { + assert.sameValue(asyncVar.get(), 42); + $DONE(); + } catch (err) { + $DONE(err); + } +} + +const registry = asyncVar.run(42, () => { + return new FinalizationRegistry(cleanupCallback); +}); + +{ + let target = {}; + registry.register(target); +} + +$262.gc(); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/context-propagation/async-await.js b/test/built-ins/AsyncContext/context-propagation/async-await.js new file mode 100644 index 00000000000..cd9226eb67a --- /dev/null +++ b/test/built-ins/AsyncContext/context-propagation/async-await.js @@ -0,0 +1,34 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +flags: [async] +features: [AsyncContext] +includes: [asyncHelpers.js] +---*/ + +const context = new AsyncContext.Variable(); + +let resolveFn; + +async function asyncCb() { + assert.sameValue(context.get(), 42); + + await new Promise(resolve => { + resolveFn = resolve; + }); + + assert.sameValue(context.get(), 42); +} + +asyncTest(() => { + assert.sameValue(context.get(), undefined); + + const promise = context.run(42, asyncCb); + + return promise.then(() => { + assert.sameValue(context.get(), undefined); + }); +}); + +resolveFn(); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/context-propagation/continuation-propagation-thenable.js b/test/built-ins/AsyncContext/context-propagation/continuation-propagation-thenable.js new file mode 100644 index 00000000000..b1f8199413c --- /dev/null +++ b/test/built-ins/AsyncContext/context-propagation/continuation-propagation-thenable.js @@ -0,0 +1,22 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +flags: [async] +features: [AsyncContext] +---*/ + +const asyncVar = new AsyncContext.Variable(); + +const expectedSymbol = Symbol("expected"); + +const thenable = { + then(cb) { + assert.sameValue(asyncVar.get(), expectedSymbol); + cb(); + } +}; + +asyncVar.run(expectedSymbol, () => { + Promise.resolve(thenable).then(() => $DONE()); +}); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/context-propagation/cross-realm.js b/test/built-ins/AsyncContext/context-propagation/cross-realm.js new file mode 100644 index 00000000000..fdd3720893f --- /dev/null +++ b/test/built-ins/AsyncContext/context-propagation/cross-realm.js @@ -0,0 +1,49 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-agents +description: > + The context snapshot is stored in a field of the agent record, so it is + preserved across realms. +info: | + TODO +features: [AsyncContext, cross-realm] +---*/ + +const realm = $262.createRealm().global; + +realm.eval(` + var asyncSnapshot; + + function wrap(cb) { + asyncSnapshot.run(cb); + } +`); + +const asyncVar1 = new AsyncContext.Variable(); +const asyncVar2 = new AsyncContext.Variable(); +const asyncVar3 = new AsyncContext.Variable(); + +asyncVar1.run(42, () => { + + realm.eval(` + asyncSnapshot = new AsyncContext.Snapshot(); + `); + + asyncVar2.run("foo", () => { + asyncVar3.run("bar", () => { + asyncVar1.run("baz", () => { + + realm.wrap(() => { + + assert.sameValue(asyncVar1.get(), 42); + assert.sameValue(asyncVar2.get(), undefined); + assert.sameValue(asyncVar3.get(), undefined); + + }); + + }); + }); + }); +}); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/context-propagation/generators.js b/test/built-ins/AsyncContext/context-propagation/generators.js new file mode 100644 index 00000000000..395a4953c9b --- /dev/null +++ b/test/built-ins/AsyncContext/context-propagation/generators.js @@ -0,0 +1,35 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +flags: [async] +features: [AsyncContext] +includes: [asyncHelpers.js] +---*/ + +// TODO: This test tests the agreed behavior in +// https://github.com/tc39/proposal-async-context/issues/18, but the proposed +// spec text does not yet implement that behavior. + +const context = new AsyncContext.Variable(); + +async function* gen(context) { + await Promise.resolve(); + assert.sameValue(context.get(), "init"); + yield; + await Promise.resolve(); + assert.sameValue(context.get(), "init"); +} + +asyncTest(async () => { + let g; + context.run('init', () => { + g = gen(context); + }); + await context.run('first iter', async () => { + await g.next(); + }); + await context.run('second iter', async () => { + await g.next(); + }); +}); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/context-propagation/promise-then.js b/test/built-ins/AsyncContext/context-propagation/promise-then.js new file mode 100644 index 00000000000..31c6a258cf8 --- /dev/null +++ b/test/built-ins/AsyncContext/context-propagation/promise-then.js @@ -0,0 +1,28 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +features: [AsyncContext] +flags: [async] +---*/ + +const asyncVar = new AsyncContext.Variable(); + +function thenCallback() { + assert.sameValue(asyncVar.get(), "then registration time"); +} + +let resolveFn; +const promise = asyncVar.run("promise creation time", () => { + return new Promise(resolve => { + resolveFn = resolve; + }); +}); + +asyncVar.run("then registration time", () => { + return promise.then(thenCallback); +}).then($DONE, $DONE); + +asyncVar.run("resolution time", () => { + resolveFn(); +}); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/proc-desc.js b/test/built-ins/AsyncContext/proc-desc.js new file mode 100644 index 00000000000..1b98ed47f35 --- /dev/null +++ b/test/built-ins/AsyncContext/proc-desc.js @@ -0,0 +1,40 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-object +description: > + Property descriptor of AsyncContext +info: | + The AsyncContext Object + + The AsyncContext object does not have a [[Construct]] internal method; it + cannot be used as a constructor with the new operator. + + The AsyncContext object does not have a [[Call]] internal method; it cannot + be invoked as a function. + + 17 ECMAScript Standard Built-in Objects: + + Every other data property described in clauses 18 through 26 and in Annex + B.2 has the attributes { [[Writable]]: true, [[Enumerable]]: false, + [[Configurable]]: true } unless otherwise specified. +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +assert.sameValue(typeof AsyncContext, "object"); + +assert.throws(TypeError, function() { + AsyncContext(); +}, "no [[Call]]"); + +assert.throws(TypeError, function() { + new AsyncContext(); +}, "no [[Construct]]"); + +verifyProperty(this, "AsyncContext", { + enumerable: false, + writable: true, + configurable: true +}); diff --git a/test/built-ins/AsyncContext/proto.js b/test/built-ins/AsyncContext/proto.js new file mode 100644 index 00000000000..134c25a8596 --- /dev/null +++ b/test/built-ins/AsyncContext/proto.js @@ -0,0 +1,16 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-object +description: > + The prototype of AsyncContext is Object.prototype +info: | + The AsyncContext Object has a [[Prototype]] internal slot whose value is + %Object.prototype%. +features: [AsyncContext] +---*/ + +const proto = Object.getPrototypeOf(AsyncContext); + +assert.sameValue(proto, Object.prototype); From 350da748a555ae654feb0f9526e665fcea0ba7e4 Mon Sep 17 00:00:00 2001 From: Andreu Botella Date: Tue, 18 Jul 2023 18:23:42 +0200 Subject: [PATCH 02/16] Fix lints --- test/built-ins/AsyncContext/Snapshot/instance-extensible.js | 2 +- test/built-ins/AsyncContext/Snapshot/is-a-constructor.js | 2 +- test/built-ins/AsyncContext/Snapshot/length.js | 2 +- .../Snapshot/prototype/run/calls-callback-with-args.js | 2 +- .../run/restores-previous-context-snapshot-after-callback.js | 2 +- .../AsyncContext/Snapshot/prototype/run/restores-snapshot.js | 2 +- .../Snapshot/prototype/run/restores-unset-variables.js | 2 +- .../run/returned-promise-does-not-resolve-in-snapshot.js | 2 +- .../Snapshot/prototype/run/returns-callback-return-value.js | 2 +- .../prototype/run/throws-if-callback-is-not-callable.js | 2 +- .../Snapshot/prototype/run/throws-if-callback-throws.js | 2 +- .../Variable/constructor-defaultValue-defaults-to-undefined.js | 2 +- .../AsyncContext/Variable/constructor-defaultValue.js | 2 +- .../Variable/constructor-name-defaults-to-empty-string.js | 2 +- test/built-ins/AsyncContext/Variable/constructor-name.js | 2 +- .../Variable/constructor-throwing-defaultValue-getter.js | 2 +- .../AsyncContext/Variable/constructor-throwing-name-getter.js | 2 +- .../Variable/constructor-throwing-name-hasproperty.js | 2 +- .../Variable/constructor-throwing-name-tostring.js | 2 +- test/built-ins/AsyncContext/Variable/instance-extensible.js | 2 +- test/built-ins/AsyncContext/Variable/is-a-constructor.js | 2 +- test/built-ins/AsyncContext/Variable/length.js | 2 +- .../prototype/get/returns-default-value-outside-run.js | 2 +- .../Variable/prototype/get/returns-undefined-if-set-in-run.js | 2 +- .../Variable/prototype/get/returns-value-set-in-run.js | 2 +- .../prototype/name/returns-name-passed-to-constructor.js | 2 +- .../Variable/prototype/run/calls-callback-with-args.js | 2 +- .../prototype/run/restores-context-snapshot-after-callback.js | 2 +- .../run/returned-promise-does-not-resolve-in-snapshot.js | 2 +- .../Variable/prototype/run/returns-callback-return-value.js | 2 +- .../prototype/run/swaps-context-snapshot-before-callback.js | 2 +- .../prototype/run/throws-if-callback-is-not-callable.js | 2 +- .../Variable/prototype/run/throws-if-callback-throws.js | 2 +- .../run/unrelated-snapshot-entries-keep-their-value.js | 2 +- .../AsyncContext/context-propagation/FinalizationRegistry.js | 2 +- test/built-ins/AsyncContext/context-propagation/async-await.js | 3 ++- .../context-propagation/continuation-propagation-thenable.js | 3 ++- test/built-ins/AsyncContext/context-propagation/cross-realm.js | 2 +- test/built-ins/AsyncContext/context-propagation/generators.js | 3 ++- .../built-ins/AsyncContext/context-propagation/promise-then.js | 3 ++- 40 files changed, 44 insertions(+), 40 deletions(-) diff --git a/test/built-ins/AsyncContext/Snapshot/instance-extensible.js b/test/built-ins/AsyncContext/Snapshot/instance-extensible.js index be73ceead8f..9ac6cbce85a 100644 --- a/test/built-ins/AsyncContext/Snapshot/instance-extensible.js +++ b/test/built-ins/AsyncContext/Snapshot/instance-extensible.js @@ -8,4 +8,4 @@ features: [AsyncContext] ---*/ var asyncSnapshot = new AsyncContext.Snapshot(); -assert.sameValue(Object.isExtensible(asyncSnapshot), true); \ No newline at end of file +assert.sameValue(Object.isExtensible(asyncSnapshot), true); diff --git a/test/built-ins/AsyncContext/Snapshot/is-a-constructor.js b/test/built-ins/AsyncContext/Snapshot/is-a-constructor.js index f13778b1b5d..d1892e08eeb 100644 --- a/test/built-ins/AsyncContext/Snapshot/is-a-constructor.js +++ b/test/built-ins/AsyncContext/Snapshot/is-a-constructor.js @@ -5,7 +5,7 @@ esid: sec-asynccontext-snapshot-constructor description: The AsyncContext.Snapshot constructor implements [[Construct]] includes: [isConstructor.js] -features: [AsyncContext] +features: [AsyncContext, Reflect.construct] ---*/ assert.sameValue(isConstructor(AsyncContext.Snapshot), true, 'isConstructor(AsyncContext.Snapshot) must return true'); diff --git a/test/built-ins/AsyncContext/Snapshot/length.js b/test/built-ins/AsyncContext/Snapshot/length.js index 7c9283e51c5..a8930bc1f57 100644 --- a/test/built-ins/AsyncContext/Snapshot/length.js +++ b/test/built-ins/AsyncContext/Snapshot/length.js @@ -13,4 +13,4 @@ verifyProperty(AsyncContext.Snapshot, 'length', { writable: false, enumerable: false, configurable: true -}); \ No newline at end of file +}); diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/calls-callback-with-args.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/calls-callback-with-args.js index 119e31db60c..ca75675d19e 100644 --- a/test/built-ins/AsyncContext/Snapshot/prototype/run/calls-callback-with-args.js +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/calls-callback-with-args.js @@ -33,4 +33,4 @@ function callback() { assert.sameValue(arguments[2], obj); assert.sameValue(arguments[3], symbol); called = true; -} \ No newline at end of file +} diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/restores-previous-context-snapshot-after-callback.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/restores-previous-context-snapshot-after-callback.js index 305c21cc84e..fe0060e9030 100644 --- a/test/built-ins/AsyncContext/Snapshot/prototype/run/restores-previous-context-snapshot-after-callback.js +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/restores-previous-context-snapshot-after-callback.js @@ -56,4 +56,4 @@ asyncVar1.run("foo", () => { }); }); -}); \ No newline at end of file +}); diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/restores-snapshot.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/restores-snapshot.js index f500e4e2eca..991786a392f 100644 --- a/test/built-ins/AsyncContext/Snapshot/prototype/run/restores-snapshot.js +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/restores-snapshot.js @@ -57,4 +57,4 @@ asyncSnapshot.run(() => { 'The value of `asyncVar3.get()` is `"baz"`' ); -}); \ No newline at end of file +}); diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/restores-unset-variables.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/restores-unset-variables.js index 55ecbe09e1f..180d5307247 100644 --- a/test/built-ins/AsyncContext/Snapshot/prototype/run/restores-unset-variables.js +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/restores-unset-variables.js @@ -84,4 +84,4 @@ asyncVar2.run("bar", () => { }); }); }); -}); \ No newline at end of file +}); diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/returned-promise-does-not-resolve-in-snapshot.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/returned-promise-does-not-resolve-in-snapshot.js index 72aea03c4c5..f8fa32a0ac1 100644 --- a/test/built-ins/AsyncContext/Snapshot/prototype/run/returned-promise-does-not-resolve-in-snapshot.js +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/returned-promise-does-not-resolve-in-snapshot.js @@ -30,4 +30,4 @@ asyncSnapshot.run(async () => { assert.sameValue(asyncVar.get(), undefined); }).then($DONE, $DONE); -resolve(); \ No newline at end of file +resolve(); diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/returns-callback-return-value.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/returns-callback-return-value.js index 4df451770e2..fc95863ab2a 100644 --- a/test/built-ins/AsyncContext/Snapshot/prototype/run/returns-callback-return-value.js +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/returns-callback-return-value.js @@ -28,4 +28,4 @@ const returnedPromise = asyncSnapshot.run(async () => obj); assert( returnedPromise instanceof Promise, 'The return value of `asyncSnapshot.run(async () => obj) is a promise' -); \ No newline at end of file +); diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/throws-if-callback-is-not-callable.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/throws-if-callback-is-not-callable.js index afe3c63bb3b..79aff0bf2f4 100644 --- a/test/built-ins/AsyncContext/Snapshot/prototype/run/throws-if-callback-is-not-callable.js +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/throws-if-callback-is-not-callable.js @@ -50,4 +50,4 @@ assert.throws(TypeError, () => { assert.throws(TypeError, () => { asyncSnapshot.run("foo", {}); -}); \ No newline at end of file +}); diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/throws-if-callback-throws.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/throws-if-callback-throws.js index 4cd94d1c309..5d864310a8f 100644 --- a/test/built-ins/AsyncContext/Snapshot/prototype/run/throws-if-callback-throws.js +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/throws-if-callback-throws.js @@ -22,4 +22,4 @@ assert.throws(CustomError, () => { asyncSnapshot.run(() => { throw new CustomError(); }); -}); \ No newline at end of file +}); diff --git a/test/built-ins/AsyncContext/Variable/constructor-defaultValue-defaults-to-undefined.js b/test/built-ins/AsyncContext/Variable/constructor-defaultValue-defaults-to-undefined.js index 36e6ecb6d7d..9cc6c54b0c7 100644 --- a/test/built-ins/AsyncContext/Variable/constructor-defaultValue-defaults-to-undefined.js +++ b/test/built-ins/AsyncContext/Variable/constructor-defaultValue-defaults-to-undefined.js @@ -60,4 +60,4 @@ assert.sameValue( new AsyncContext.Variable({ name: "foo" }).get(), undefined, '`new AsyncContext.Variable({ name: "foo" }).get()` returns undefined' -); \ No newline at end of file +); diff --git a/test/built-ins/AsyncContext/Variable/constructor-defaultValue.js b/test/built-ins/AsyncContext/Variable/constructor-defaultValue.js index 10f43f0b5c0..571df252a19 100644 --- a/test/built-ins/AsyncContext/Variable/constructor-defaultValue.js +++ b/test/built-ins/AsyncContext/Variable/constructor-defaultValue.js @@ -51,4 +51,4 @@ assert.sameValue( new AsyncContext.Variable({ defaultValue: obj }).get(), obj, '`new AsyncContext.Variable({ defaultValue: obj }).get()` returns `obj`' -); \ No newline at end of file +); diff --git a/test/built-ins/AsyncContext/Variable/constructor-name-defaults-to-empty-string.js b/test/built-ins/AsyncContext/Variable/constructor-name-defaults-to-empty-string.js index 56e55423729..6fe86071c94 100644 --- a/test/built-ins/AsyncContext/Variable/constructor-name-defaults-to-empty-string.js +++ b/test/built-ins/AsyncContext/Variable/constructor-name-defaults-to-empty-string.js @@ -63,4 +63,4 @@ assert.sameValue( new AsyncContext.Variable({ defaultValue: 42 }).name, '', '`new AsyncContext.Variable({ defaultValue: 42 }).name` returns the empty string' -); \ No newline at end of file +); diff --git a/test/built-ins/AsyncContext/Variable/constructor-name.js b/test/built-ins/AsyncContext/Variable/constructor-name.js index 71ecea0a5c3..560a144c02d 100644 --- a/test/built-ins/AsyncContext/Variable/constructor-name.js +++ b/test/built-ins/AsyncContext/Variable/constructor-name.js @@ -54,4 +54,4 @@ assert.sameValue( roundtripName(objectWithStringifier), 'bar', '`roundtripName(objectWithStringifier)` returns `"bar"`' -); \ No newline at end of file +); diff --git a/test/built-ins/AsyncContext/Variable/constructor-throwing-defaultValue-getter.js b/test/built-ins/AsyncContext/Variable/constructor-throwing-defaultValue-getter.js index 77ca27da12a..4884ab6471b 100644 --- a/test/built-ins/AsyncContext/Variable/constructor-throwing-defaultValue-getter.js +++ b/test/built-ins/AsyncContext/Variable/constructor-throwing-defaultValue-getter.js @@ -26,4 +26,4 @@ const options = { assert.throws(CustomError, () => { new AsyncContext.Variable(options); -}); \ No newline at end of file +}); diff --git a/test/built-ins/AsyncContext/Variable/constructor-throwing-name-getter.js b/test/built-ins/AsyncContext/Variable/constructor-throwing-name-getter.js index bc869db23d6..0babe5c8556 100644 --- a/test/built-ins/AsyncContext/Variable/constructor-throwing-name-getter.js +++ b/test/built-ins/AsyncContext/Variable/constructor-throwing-name-getter.js @@ -27,4 +27,4 @@ const options = { assert.throws(CustomError, () => { new AsyncContext.Variable(options); -}); \ No newline at end of file +}); diff --git a/test/built-ins/AsyncContext/Variable/constructor-throwing-name-hasproperty.js b/test/built-ins/AsyncContext/Variable/constructor-throwing-name-hasproperty.js index fa16119b641..fdf866c3929 100644 --- a/test/built-ins/AsyncContext/Variable/constructor-throwing-name-hasproperty.js +++ b/test/built-ins/AsyncContext/Variable/constructor-throwing-name-hasproperty.js @@ -25,4 +25,4 @@ const options = new Proxy({}, { assert.throws(CustomError, () => { new AsyncContext.Variable(options); -}); \ No newline at end of file +}); diff --git a/test/built-ins/AsyncContext/Variable/constructor-throwing-name-tostring.js b/test/built-ins/AsyncContext/Variable/constructor-throwing-name-tostring.js index 89a9caf4b9e..ff0271a3899 100644 --- a/test/built-ins/AsyncContext/Variable/constructor-throwing-name-tostring.js +++ b/test/built-ins/AsyncContext/Variable/constructor-throwing-name-tostring.js @@ -38,4 +38,4 @@ const options = { assert.throws(CustomError, () => { new AsyncContext.Variable(options); -}); \ No newline at end of file +}); diff --git a/test/built-ins/AsyncContext/Variable/instance-extensible.js b/test/built-ins/AsyncContext/Variable/instance-extensible.js index 6a94ccf8cd0..de52e718ab5 100644 --- a/test/built-ins/AsyncContext/Variable/instance-extensible.js +++ b/test/built-ins/AsyncContext/Variable/instance-extensible.js @@ -8,4 +8,4 @@ features: [AsyncContext] ---*/ var asyncVariable = new AsyncContext.Variable(); -assert.sameValue(Object.isExtensible(asyncVariable), true); \ No newline at end of file +assert.sameValue(Object.isExtensible(asyncVariable), true); diff --git a/test/built-ins/AsyncContext/Variable/is-a-constructor.js b/test/built-ins/AsyncContext/Variable/is-a-constructor.js index d7dc39e34cd..ae09a8d0393 100644 --- a/test/built-ins/AsyncContext/Variable/is-a-constructor.js +++ b/test/built-ins/AsyncContext/Variable/is-a-constructor.js @@ -5,7 +5,7 @@ esid: sec-asynccontext-variable-constructor description: The AsyncContext.Variable constructor implements [[Construct]] includes: [isConstructor.js] -features: [AsyncContext] +features: [AsyncContext, Reflect.construct] ---*/ assert.sameValue(isConstructor(AsyncContext.Variable), true, 'isConstructor(AsyncContext.Variable) must return true'); diff --git a/test/built-ins/AsyncContext/Variable/length.js b/test/built-ins/AsyncContext/Variable/length.js index 212cdec7f5f..028a48f37a5 100644 --- a/test/built-ins/AsyncContext/Variable/length.js +++ b/test/built-ins/AsyncContext/Variable/length.js @@ -13,4 +13,4 @@ verifyProperty(AsyncContext.Variable, 'length', { writable: false, enumerable: false, configurable: true -}); \ No newline at end of file +}); diff --git a/test/built-ins/AsyncContext/Variable/prototype/get/returns-default-value-outside-run.js b/test/built-ins/AsyncContext/Variable/prototype/get/returns-default-value-outside-run.js index dd45258bfe0..af7b86a42f3 100644 --- a/test/built-ins/AsyncContext/Variable/prototype/get/returns-default-value-outside-run.js +++ b/test/built-ins/AsyncContext/Variable/prototype/get/returns-default-value-outside-run.js @@ -30,4 +30,4 @@ assert.sameValue( asyncVariable.get(), defaultValue, 'The value of `asyncVariable.get()` is `defaultValue`' -) \ No newline at end of file +) diff --git a/test/built-ins/AsyncContext/Variable/prototype/get/returns-undefined-if-set-in-run.js b/test/built-ins/AsyncContext/Variable/prototype/get/returns-undefined-if-set-in-run.js index c4316e60cc5..771d424d030 100644 --- a/test/built-ins/AsyncContext/Variable/prototype/get/returns-undefined-if-set-in-run.js +++ b/test/built-ins/AsyncContext/Variable/prototype/get/returns-undefined-if-set-in-run.js @@ -25,4 +25,4 @@ asyncVariable.run(undefined, () => { undefined, 'The value of `asyncVariable.get()` is `undefined`' ); -}); \ No newline at end of file +}); diff --git a/test/built-ins/AsyncContext/Variable/prototype/get/returns-value-set-in-run.js b/test/built-ins/AsyncContext/Variable/prototype/get/returns-value-set-in-run.js index f8818f9ee8a..974cf9d5202 100644 --- a/test/built-ins/AsyncContext/Variable/prototype/get/returns-value-set-in-run.js +++ b/test/built-ins/AsyncContext/Variable/prototype/get/returns-value-set-in-run.js @@ -36,4 +36,4 @@ asyncVariable.run(value, () => { value, 'The value of `asyncVariable.get()` is `value`' ); -}); \ No newline at end of file +}); diff --git a/test/built-ins/AsyncContext/Variable/prototype/name/returns-name-passed-to-constructor.js b/test/built-ins/AsyncContext/Variable/prototype/name/returns-name-passed-to-constructor.js index 2826bd20347..256a66830a5 100644 --- a/test/built-ins/AsyncContext/Variable/prototype/name/returns-name-passed-to-constructor.js +++ b/test/built-ins/AsyncContext/Variable/prototype/name/returns-name-passed-to-constructor.js @@ -19,4 +19,4 @@ assert.sameValue( asyncVar.name, "foo", 'The value of `asyncVar.name` is `"foo"`' -); \ No newline at end of file +); diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/calls-callback-with-args.js b/test/built-ins/AsyncContext/Variable/prototype/run/calls-callback-with-args.js index 36fe974d5df..9ff4535fefe 100644 --- a/test/built-ins/AsyncContext/Variable/prototype/run/calls-callback-with-args.js +++ b/test/built-ins/AsyncContext/Variable/prototype/run/calls-callback-with-args.js @@ -33,4 +33,4 @@ function callback() { assert.sameValue(arguments[2], obj); assert.sameValue(arguments[3], symbol); called = true; -} \ No newline at end of file +} diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/restores-context-snapshot-after-callback.js b/test/built-ins/AsyncContext/Variable/prototype/run/restores-context-snapshot-after-callback.js index f33eaf29719..00b692905e3 100644 --- a/test/built-ins/AsyncContext/Variable/prototype/run/restores-context-snapshot-after-callback.js +++ b/test/built-ins/AsyncContext/Variable/prototype/run/restores-context-snapshot-after-callback.js @@ -43,4 +43,4 @@ assert.sameValue( asyncVar.get(), undefined, 'The value of `asyncVar.get()` after the first `run` should be `undefined`' -); \ No newline at end of file +); diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/returned-promise-does-not-resolve-in-snapshot.js b/test/built-ins/AsyncContext/Variable/prototype/run/returned-promise-does-not-resolve-in-snapshot.js index b04581efe5d..981bd4a8758 100644 --- a/test/built-ins/AsyncContext/Variable/prototype/run/returned-promise-does-not-resolve-in-snapshot.js +++ b/test/built-ins/AsyncContext/Variable/prototype/run/returned-promise-does-not-resolve-in-snapshot.js @@ -28,4 +28,4 @@ asyncVar.run("foo", async () => { assert.sameValue(asyncVar.get(), undefined); }).then($DONE, $DONE); -resolve(); \ No newline at end of file +resolve(); diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/returns-callback-return-value.js b/test/built-ins/AsyncContext/Variable/prototype/run/returns-callback-return-value.js index 9aeda6de845..b90c04040b3 100644 --- a/test/built-ins/AsyncContext/Variable/prototype/run/returns-callback-return-value.js +++ b/test/built-ins/AsyncContext/Variable/prototype/run/returns-callback-return-value.js @@ -28,4 +28,4 @@ const returnedPromise = asyncVar.run("foo", async () => obj); assert( returnedPromise instanceof Promise, 'The return value of `asyncVar.run("foo", async () => obj) is a promise' -); \ No newline at end of file +); diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/swaps-context-snapshot-before-callback.js b/test/built-ins/AsyncContext/Variable/prototype/run/swaps-context-snapshot-before-callback.js index e32fcb22c9c..43eeb7b1804 100644 --- a/test/built-ins/AsyncContext/Variable/prototype/run/swaps-context-snapshot-before-callback.js +++ b/test/built-ins/AsyncContext/Variable/prototype/run/swaps-context-snapshot-before-callback.js @@ -39,4 +39,4 @@ asyncVar.run(42, () => { 42, 'The value of `asyncVar.get()` inside the callback passed to `run` is `42`' ); -}); \ No newline at end of file +}); diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/throws-if-callback-is-not-callable.js b/test/built-ins/AsyncContext/Variable/prototype/run/throws-if-callback-is-not-callable.js index 5a739464a30..35ebdbacc18 100644 --- a/test/built-ins/AsyncContext/Variable/prototype/run/throws-if-callback-is-not-callable.js +++ b/test/built-ins/AsyncContext/Variable/prototype/run/throws-if-callback-is-not-callable.js @@ -50,4 +50,4 @@ assert.throws(TypeError, () => { assert.throws(TypeError, () => { asyncVar.run("foo", {}); -}); \ No newline at end of file +}); diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/throws-if-callback-throws.js b/test/built-ins/AsyncContext/Variable/prototype/run/throws-if-callback-throws.js index 066568be513..fcc3923b68b 100644 --- a/test/built-ins/AsyncContext/Variable/prototype/run/throws-if-callback-throws.js +++ b/test/built-ins/AsyncContext/Variable/prototype/run/throws-if-callback-throws.js @@ -22,4 +22,4 @@ assert.throws(CustomError, () => { asyncVar.run("foo", () => { throw new CustomError(); }); -}); \ No newline at end of file +}); diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/unrelated-snapshot-entries-keep-their-value.js b/test/built-ins/AsyncContext/Variable/prototype/run/unrelated-snapshot-entries-keep-their-value.js index 6c750514a8a..11b94605506 100644 --- a/test/built-ins/AsyncContext/Variable/prototype/run/unrelated-snapshot-entries-keep-their-value.js +++ b/test/built-ins/AsyncContext/Variable/prototype/run/unrelated-snapshot-entries-keep-their-value.js @@ -69,4 +69,4 @@ asyncVar1.run(symbol1, () => { }); }); -}); \ No newline at end of file +}); diff --git a/test/built-ins/AsyncContext/context-propagation/FinalizationRegistry.js b/test/built-ins/AsyncContext/context-propagation/FinalizationRegistry.js index f1743486484..5b521d64eb5 100644 --- a/test/built-ins/AsyncContext/context-propagation/FinalizationRegistry.js +++ b/test/built-ins/AsyncContext/context-propagation/FinalizationRegistry.js @@ -32,4 +32,4 @@ const registry = asyncVar.run(42, () => { registry.register(target); } -$262.gc(); \ No newline at end of file +$262.gc(); diff --git a/test/built-ins/AsyncContext/context-propagation/async-await.js b/test/built-ins/AsyncContext/context-propagation/async-await.js index cd9226eb67a..19fecbc5f69 100644 --- a/test/built-ins/AsyncContext/context-propagation/async-await.js +++ b/test/built-ins/AsyncContext/context-propagation/async-await.js @@ -2,6 +2,7 @@ // This code is governed by the BSD license found in the LICENSE file. /*--- +description: TODO flags: [async] features: [AsyncContext] includes: [asyncHelpers.js] @@ -31,4 +32,4 @@ asyncTest(() => { }); }); -resolveFn(); \ No newline at end of file +resolveFn(); diff --git a/test/built-ins/AsyncContext/context-propagation/continuation-propagation-thenable.js b/test/built-ins/AsyncContext/context-propagation/continuation-propagation-thenable.js index b1f8199413c..f681e6632af 100644 --- a/test/built-ins/AsyncContext/context-propagation/continuation-propagation-thenable.js +++ b/test/built-ins/AsyncContext/context-propagation/continuation-propagation-thenable.js @@ -2,6 +2,7 @@ // This code is governed by the BSD license found in the LICENSE file. /*--- +description: TODO flags: [async] features: [AsyncContext] ---*/ @@ -19,4 +20,4 @@ const thenable = { asyncVar.run(expectedSymbol, () => { Promise.resolve(thenable).then(() => $DONE()); -}); \ No newline at end of file +}); diff --git a/test/built-ins/AsyncContext/context-propagation/cross-realm.js b/test/built-ins/AsyncContext/context-propagation/cross-realm.js index fdd3720893f..3abb1c06426 100644 --- a/test/built-ins/AsyncContext/context-propagation/cross-realm.js +++ b/test/built-ins/AsyncContext/context-propagation/cross-realm.js @@ -46,4 +46,4 @@ asyncVar1.run(42, () => { }); }); }); -}); \ No newline at end of file +}); diff --git a/test/built-ins/AsyncContext/context-propagation/generators.js b/test/built-ins/AsyncContext/context-propagation/generators.js index 395a4953c9b..5c8cb2c2fcd 100644 --- a/test/built-ins/AsyncContext/context-propagation/generators.js +++ b/test/built-ins/AsyncContext/context-propagation/generators.js @@ -2,6 +2,7 @@ // This code is governed by the BSD license found in the LICENSE file. /*--- +description: TODO flags: [async] features: [AsyncContext] includes: [asyncHelpers.js] @@ -32,4 +33,4 @@ asyncTest(async () => { await context.run('second iter', async () => { await g.next(); }); -}); \ No newline at end of file +}); diff --git a/test/built-ins/AsyncContext/context-propagation/promise-then.js b/test/built-ins/AsyncContext/context-propagation/promise-then.js index 31c6a258cf8..d850253b148 100644 --- a/test/built-ins/AsyncContext/context-propagation/promise-then.js +++ b/test/built-ins/AsyncContext/context-propagation/promise-then.js @@ -2,6 +2,7 @@ // This code is governed by the BSD license found in the LICENSE file. /*--- +description: TODO features: [AsyncContext] flags: [async] ---*/ @@ -25,4 +26,4 @@ asyncVar.run("then registration time", () => { asyncVar.run("resolution time", () => { resolveFn(); -}); \ No newline at end of file +}); From 987a0c85f006fb99b144bfe99b3c4e9e511f0ee4 Mon Sep 17 00:00:00 2001 From: Andreu Botella Date: Tue, 18 Jul 2023 18:29:25 +0200 Subject: [PATCH 03/16] Add AsyncContext feature --- features.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/features.txt b/features.txt index b4350fea6c8..bc6015f23ac 100644 --- a/features.txt +++ b/features.txt @@ -108,6 +108,10 @@ json-parse-with-source # https://github.com/tc39/proposal-iterator-helpers iterator-helpers +# AsyncContext +# https://github.com/tc39/proposal-async-context +AsyncContext + ## Standard language features # # Language features that have been included in a published version of the From ee29d946c204e1d24aea1f534e385974073a0c51 Mon Sep 17 00:00:00 2001 From: Andreu Botella Date: Tue, 1 Aug 2023 20:24:41 +0200 Subject: [PATCH 04/16] Add some missing AsyncContext.Variable tests --- .../Variable/Symbol.toStringTag.js | 22 ++++++++++ .../AsyncContext/Variable/proc-desc.js | 40 +++++++++++++++++++ test/built-ins/AsyncContext/Variable/proto.js | 16 ++++++++ 3 files changed, 78 insertions(+) create mode 100644 test/built-ins/AsyncContext/Variable/Symbol.toStringTag.js create mode 100644 test/built-ins/AsyncContext/Variable/proc-desc.js create mode 100644 test/built-ins/AsyncContext/Variable/proto.js diff --git a/test/built-ins/AsyncContext/Variable/Symbol.toStringTag.js b/test/built-ins/AsyncContext/Variable/Symbol.toStringTag.js new file mode 100644 index 00000000000..e10643305a5 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/Symbol.toStringTag.js @@ -0,0 +1,22 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-@@tostringtag +description: > + `Symbol.toStringTag` property descriptor +info: | + The initial value of the @@toStringTag property is the String value + "AsyncContext". + + This property has the attributes { [[Writable]]: false, [[Enumerable]]: + false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [AsyncContext, Symbol.toStringTag] +---*/ + +assert.sameValue(AsyncContext[Symbol.toStringTag], 'AsyncContext'); + +verifyNotEnumerable(AsyncContext, Symbol.toStringTag); +verifyNotWritable(AsyncContext, Symbol.toStringTag); +verifyConfigurable(AsyncContext, Symbol.toStringTag); diff --git a/test/built-ins/AsyncContext/Variable/proc-desc.js b/test/built-ins/AsyncContext/Variable/proc-desc.js new file mode 100644 index 00000000000..1b98ed47f35 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/proc-desc.js @@ -0,0 +1,40 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-object +description: > + Property descriptor of AsyncContext +info: | + The AsyncContext Object + + The AsyncContext object does not have a [[Construct]] internal method; it + cannot be used as a constructor with the new operator. + + The AsyncContext object does not have a [[Call]] internal method; it cannot + be invoked as a function. + + 17 ECMAScript Standard Built-in Objects: + + Every other data property described in clauses 18 through 26 and in Annex + B.2 has the attributes { [[Writable]]: true, [[Enumerable]]: false, + [[Configurable]]: true } unless otherwise specified. +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +assert.sameValue(typeof AsyncContext, "object"); + +assert.throws(TypeError, function() { + AsyncContext(); +}, "no [[Call]]"); + +assert.throws(TypeError, function() { + new AsyncContext(); +}, "no [[Construct]]"); + +verifyProperty(this, "AsyncContext", { + enumerable: false, + writable: true, + configurable: true +}); diff --git a/test/built-ins/AsyncContext/Variable/proto.js b/test/built-ins/AsyncContext/Variable/proto.js new file mode 100644 index 00000000000..134c25a8596 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/proto.js @@ -0,0 +1,16 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-object +description: > + The prototype of AsyncContext is Object.prototype +info: | + The AsyncContext Object has a [[Prototype]] internal slot whose value is + %Object.prototype%. +features: [AsyncContext] +---*/ + +const proto = Object.getPrototypeOf(AsyncContext); + +assert.sameValue(proto, Object.prototype); From 0b59f3387e51345b84a0950256207e1047cec6a8 Mon Sep 17 00:00:00 2001 From: Andreu Botella Date: Tue, 1 Aug 2023 20:29:51 +0200 Subject: [PATCH 05/16] Add more generator tests for context propagation --- .../CreateIteratorFromClosure.js | 25 +++++++++++ .../async-generators-yield-inside-run.js | 43 +++++++++++++++++++ .../context-propagation/async-generators.js | 35 +++++++++++++++ .../generators-yield-inside-run.js | 33 ++++++++++++++ .../context-propagation/generators.js | 37 +++++++--------- 5 files changed, 151 insertions(+), 22 deletions(-) create mode 100644 test/built-ins/AsyncContext/context-propagation/CreateIteratorFromClosure.js create mode 100644 test/built-ins/AsyncContext/context-propagation/async-generators-yield-inside-run.js create mode 100644 test/built-ins/AsyncContext/context-propagation/async-generators.js create mode 100644 test/built-ins/AsyncContext/context-propagation/generators-yield-inside-run.js diff --git a/test/built-ins/AsyncContext/context-propagation/CreateIteratorFromClosure.js b/test/built-ins/AsyncContext/context-propagation/CreateIteratorFromClosure.js new file mode 100644 index 00000000000..8112cece34e --- /dev/null +++ b/test/built-ins/AsyncContext/context-propagation/CreateIteratorFromClosure.js @@ -0,0 +1,25 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: TODO +features: [AsyncContext] +---*/ + +// TODO: This test tests the behavior in +// https://github.com/tc39/proposal-async-context/pull/61 + +const asyncVar = new AsyncContext.Variable(); + +const array = []; +Object.defineProperty(array, 0, { + get() { + assert.sameValue(asyncVar.get(), "foo"); + } +}); + +const iter = asyncVar.run("foo", () => array.values()); + +asyncVar.run("bar", () => { + iter.next(); +}); diff --git a/test/built-ins/AsyncContext/context-propagation/async-generators-yield-inside-run.js b/test/built-ins/AsyncContext/context-propagation/async-generators-yield-inside-run.js new file mode 100644 index 00000000000..04150fb28f7 --- /dev/null +++ b/test/built-ins/AsyncContext/context-propagation/async-generators-yield-inside-run.js @@ -0,0 +1,43 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: TODO +flags: [async] +features: [AsyncContext] +includes: [asyncHelpers.js] +---*/ + +// TODO: This test tests the behavior in +// https://github.com/tc39/proposal-async-context/pull/61 + +const asyncVar = new AsyncContext.Variable(); + +async function* gen() { + await Promise.resolve(); + assert.sameValue(asyncVar.get(), "init"); + yield* asyncVar.run("nested-gen", async function* () { + assert.sameValue(asyncVar.get(), "nested-gen"); + await Promise.resolve(); + assert.sameValue(asyncVar.get(), "nested-gen"); + yield; + assert.sameValue(asyncVar.get(), "nested-gen"); + await Promise.resolve(); + assert.sameValue(asyncVar.get(), "nested-gen"); + }); + await Promise.resolve(); + assert.sameValue(asyncVar.get(), "init"); +} + +asyncTest(async () => { + let g; + asyncVar.run('init', () => { + g = gen(); + }); + await asyncVar.run('first iter', async () => { + await g.next(); + }); + await asyncVar.run('second iter', async () => { + await g.next(); + }); +}); diff --git a/test/built-ins/AsyncContext/context-propagation/async-generators.js b/test/built-ins/AsyncContext/context-propagation/async-generators.js new file mode 100644 index 00000000000..74e1dfc3b1e --- /dev/null +++ b/test/built-ins/AsyncContext/context-propagation/async-generators.js @@ -0,0 +1,35 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: TODO +flags: [async] +features: [AsyncContext] +includes: [asyncHelpers.js] +---*/ + +// TODO: This test tests the behavior in +// https://github.com/tc39/proposal-async-context/pull/61 + +const asyncVar = new AsyncContext.Variable(); + +async function* gen() { + await Promise.resolve(); + assert.sameValue(asyncVar.get(), "init"); + yield; + await Promise.resolve(); + assert.sameValue(asyncVar.get(), "init"); +} + +asyncTest(async () => { + let g; + asyncVar.run('init', () => { + g = gen(); + }); + await asyncVar.run('first iter', async () => { + await g.next(); + }); + await asyncVar.run('second iter', async () => { + await g.next(); + }); +}); diff --git a/test/built-ins/AsyncContext/context-propagation/generators-yield-inside-run.js b/test/built-ins/AsyncContext/context-propagation/generators-yield-inside-run.js new file mode 100644 index 00000000000..27a9315fedb --- /dev/null +++ b/test/built-ins/AsyncContext/context-propagation/generators-yield-inside-run.js @@ -0,0 +1,33 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: TODO +features: [AsyncContext] +---*/ + +// TODO: This test tests the behavior in +// https://github.com/tc39/proposal-async-context/pull/61 + +const asyncVar = new AsyncContext.Variable(); + +function* gen() { + assert.sameValue(asyncVar.get(), "init"); + yield* asyncVar.run("nested-gen", function* () { + assert.sameValue(asyncVar.get(), "nested-gen"); + yield; + assert.sameValue(asyncVar.get(), "nested-gen"); + }); + assert.sameValue(asyncVar.get(), "init"); +} + +let g; +asyncVar.run('init', () => { + g = gen(); +}); +asyncVar.run('first iter', () => { + g.next(); +}); +asyncVar.run('second iter', () => { + g.next(); +}); diff --git a/test/built-ins/AsyncContext/context-propagation/generators.js b/test/built-ins/AsyncContext/context-propagation/generators.js index 5c8cb2c2fcd..e503a3ea23a 100644 --- a/test/built-ins/AsyncContext/context-propagation/generators.js +++ b/test/built-ins/AsyncContext/context-propagation/generators.js @@ -3,34 +3,27 @@ /*--- description: TODO -flags: [async] features: [AsyncContext] -includes: [asyncHelpers.js] ---*/ -// TODO: This test tests the agreed behavior in -// https://github.com/tc39/proposal-async-context/issues/18, but the proposed -// spec text does not yet implement that behavior. +// TODO: This test tests the behavior in +// https://github.com/tc39/proposal-async-context/pull/61 -const context = new AsyncContext.Variable(); +const asyncVar = new AsyncContext.Variable(); -async function* gen(context) { - await Promise.resolve(); - assert.sameValue(context.get(), "init"); +function* gen() { + assert.sameValue(asyncVar.get(), "init"); yield; - await Promise.resolve(); - assert.sameValue(context.get(), "init"); + assert.sameValue(asyncVar.get(), "init"); } -asyncTest(async () => { - let g; - context.run('init', () => { - g = gen(context); - }); - await context.run('first iter', async () => { - await g.next(); - }); - await context.run('second iter', async () => { - await g.next(); - }); +let g; +asyncVar.run('init', () => { + g = gen(); +}); +asyncVar.run('first iter', () => { + g.next(); +}); +asyncVar.run('second iter', () => { + g.next(); }); From 6f3c8eefc03646d9614157cbbe3150310ff54542 Mon Sep 17 00:00:00 2001 From: Andreu Botella Date: Thu, 25 Jan 2024 11:09:22 +0100 Subject: [PATCH 06/16] Add `run` tests based on code review suggestions --- .../run/calls-callback-with-undefined-this.js | 20 +++++++ ...s-context-snapshot-after-callback-throw.js | 50 +++++++++++++++++ .../run/calls-callback-with-undefined-this.js | 20 +++++++ ...s-context-snapshot-after-callback-throw.js | 53 +++++++++++++++++++ 4 files changed, 143 insertions(+) create mode 100644 test/built-ins/AsyncContext/Snapshot/prototype/run/calls-callback-with-undefined-this.js create mode 100644 test/built-ins/AsyncContext/Snapshot/prototype/run/restores-previous-context-snapshot-after-callback-throw.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/run/calls-callback-with-undefined-this.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/run/restores-context-snapshot-after-callback-throw.js diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/calls-callback-with-undefined-this.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/calls-callback-with-undefined-this.js new file mode 100644 index 00000000000..555317e3889 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/calls-callback-with-undefined-this.js @@ -0,0 +1,20 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.prototype.run +description: > + Calls the second parameter as a function, with its this value being + undefined. +info: | + AsyncContext.Snapshot.prototype.run ( func, ...args ) + + 4. Let result be Completion(Call(func, undefined, args)). +features: [AsyncContext] +---*/ + +const asyncSnapshot = new AsyncContext.Snapshot(); + +asyncSnapshot.run(function () { + assert.sameValue(this, undefined); +}); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/restores-previous-context-snapshot-after-callback-throw.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/restores-previous-context-snapshot-after-callback-throw.js new file mode 100644 index 00000000000..5fcc4977dc5 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/restores-previous-context-snapshot-after-callback-throw.js @@ -0,0 +1,50 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.prototype.run +description: > + Switches back into the context snapshot active at the time of calling `run` + after calling the callback, even if it throws an exception. +info: | + AsyncContext.Snapshot.prototype.run ( func, ...args ) + + 3. Let previousContextMapping be AsyncContextSwap(asyncSnapshot.[[AsyncSnapshotMapping]]). + 4. Let result be Completion(Call(func, undefined, args)). + 5. AsyncContextSwap(previousContextMapping). + 6. Return result. + + AsyncContextSwap ( snapshotMapping ) + + 1. Let agentRecord be the surrounding agent's Agent Record. + 2. Let asyncContextMapping be agentRecord.[[AsyncContextMapping]]. + 3. Set agentRecord.[[AsyncContextMapping]] to snapshotMapping. + 4. Return asyncContextMapping. +features: [AsyncContext] +---*/ + +function CustomError() { } + +const asyncVar = new AsyncContext.Variable(); + +const snapshot = asyncVar.run(42, () => new AsyncContext.Snapshot()); + +asyncVar.run("foo", () => { + + try { + snapshot.run(() => { + throw new CustomError(); + }) + } catch (e) { + if (!(e instanceof CustomError)) { + throw e; + } + } + + assert.sameValue( + asyncVar.get(), + "foo", + 'The value of `asyncVar.get()` should be `"foo"`' + ); + +}); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/calls-callback-with-undefined-this.js b/test/built-ins/AsyncContext/Variable/prototype/run/calls-callback-with-undefined-this.js new file mode 100644 index 00000000000..75e50913e33 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/run/calls-callback-with-undefined-this.js @@ -0,0 +1,20 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.run +description: > + Calls the second parameter as a function, with its this value being + undefined. +info: | + AsyncContext.Variable.prototype.run ( value, func, ...args ) + + 10. Let result be Completion(Call(func, undefined, args)). +features: [AsyncContext] +---*/ + +const asyncVar = new AsyncContext.Variable(); + +asyncVar.run("foo", function () { + assert.sameValue(this, undefined); +}); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/restores-context-snapshot-after-callback-throw.js b/test/built-ins/AsyncContext/Variable/prototype/run/restores-context-snapshot-after-callback-throw.js new file mode 100644 index 00000000000..305872e6e07 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/run/restores-context-snapshot-after-callback-throw.js @@ -0,0 +1,53 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.run +description: > + Switches back into the previous context snapshot after calling the callback, + even if it throws an exception. +info: | + AsyncContext.Variable.prototype.run ( value, func, ...args ) + + 3. Let previousContextMapping be AsyncContextSnapshot(). + ... + 10. Let result be Completion(Call(func, undefined, args)). + 11. AsyncContextSwap(previousContextMapping). + 12. Return result. + + AsyncContextSwap ( snapshotMapping ) + + 1. Let agentRecord be the surrounding agent's Agent Record. + ... + 3. Set agentRecord.[[AsyncContextMapping]] to snapshotMapping. + + AsyncContextSnapshot ( ) + + 1. Let agentRecord be the surrounding agent's Agent Record. + 2. Return agentRecord.[[AsyncContextMapping]]. +features: [AsyncContext] +---*/ + +function CustomError() { } + +const asyncVar = new AsyncContext.Variable(); + +asyncVar.run("foo", () => { + + try { + asyncVar.run("bar", () => { + throw new CustomError(); + }) + } catch (e) { + if (!(e instanceof CustomError)) { + throw e; + } + } + + assert.sameValue( + asyncVar.get(), + "foo", + 'The value of `asyncVar.get()` inside the first `run` and after the second one should be `"foo"`' + ); + +}); \ No newline at end of file From 8e4ac00c1d000a35fa63532ead31fde3574fb681 Mon Sep 17 00:00:00 2001 From: Andreu Botella Date: Thu, 25 Jan 2024 11:16:47 +0100 Subject: [PATCH 07/16] Fix lint warnings --- .../prototype/run/calls-callback-with-undefined-this.js | 2 +- .../restores-previous-context-snapshot-after-callback-throw.js | 2 +- .../prototype/run/calls-callback-with-undefined-this.js | 2 +- .../run/restores-context-snapshot-after-callback-throw.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/calls-callback-with-undefined-this.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/calls-callback-with-undefined-this.js index 555317e3889..c5e787e4259 100644 --- a/test/built-ins/AsyncContext/Snapshot/prototype/run/calls-callback-with-undefined-this.js +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/calls-callback-with-undefined-this.js @@ -17,4 +17,4 @@ const asyncSnapshot = new AsyncContext.Snapshot(); asyncSnapshot.run(function () { assert.sameValue(this, undefined); -}); \ No newline at end of file +}); diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/restores-previous-context-snapshot-after-callback-throw.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/restores-previous-context-snapshot-after-callback-throw.js index 5fcc4977dc5..97b99ab9ef0 100644 --- a/test/built-ins/AsyncContext/Snapshot/prototype/run/restores-previous-context-snapshot-after-callback-throw.js +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/restores-previous-context-snapshot-after-callback-throw.js @@ -47,4 +47,4 @@ asyncVar.run("foo", () => { 'The value of `asyncVar.get()` should be `"foo"`' ); -}); \ No newline at end of file +}); diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/calls-callback-with-undefined-this.js b/test/built-ins/AsyncContext/Variable/prototype/run/calls-callback-with-undefined-this.js index 75e50913e33..72fc5becc96 100644 --- a/test/built-ins/AsyncContext/Variable/prototype/run/calls-callback-with-undefined-this.js +++ b/test/built-ins/AsyncContext/Variable/prototype/run/calls-callback-with-undefined-this.js @@ -17,4 +17,4 @@ const asyncVar = new AsyncContext.Variable(); asyncVar.run("foo", function () { assert.sameValue(this, undefined); -}); \ No newline at end of file +}); diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/restores-context-snapshot-after-callback-throw.js b/test/built-ins/AsyncContext/Variable/prototype/run/restores-context-snapshot-after-callback-throw.js index 305872e6e07..1cd0e7bc6c5 100644 --- a/test/built-ins/AsyncContext/Variable/prototype/run/restores-context-snapshot-after-callback-throw.js +++ b/test/built-ins/AsyncContext/Variable/prototype/run/restores-context-snapshot-after-callback-throw.js @@ -50,4 +50,4 @@ asyncVar.run("foo", () => { 'The value of `asyncVar.get()` inside the first `run` and after the second one should be `"foo"`' ); -}); \ No newline at end of file +}); From 3319cc4c8ec4b730770f1a92eadc2ed5990d0a6a Mon Sep 17 00:00:00 2001 From: Andreu Botella Date: Thu, 25 Jan 2024 11:42:44 +0100 Subject: [PATCH 08/16] Fix undefined this tests to use strict mode on the callback. --- .../Snapshot/prototype/run/calls-callback-with-undefined-this.js | 1 + .../Variable/prototype/run/calls-callback-with-undefined-this.js | 1 + 2 files changed, 2 insertions(+) diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/calls-callback-with-undefined-this.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/calls-callback-with-undefined-this.js index c5e787e4259..afdbab821fa 100644 --- a/test/built-ins/AsyncContext/Snapshot/prototype/run/calls-callback-with-undefined-this.js +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/calls-callback-with-undefined-this.js @@ -16,5 +16,6 @@ features: [AsyncContext] const asyncSnapshot = new AsyncContext.Snapshot(); asyncSnapshot.run(function () { + "use strict"; assert.sameValue(this, undefined); }); diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/calls-callback-with-undefined-this.js b/test/built-ins/AsyncContext/Variable/prototype/run/calls-callback-with-undefined-this.js index 72fc5becc96..c05b4c29452 100644 --- a/test/built-ins/AsyncContext/Variable/prototype/run/calls-callback-with-undefined-this.js +++ b/test/built-ins/AsyncContext/Variable/prototype/run/calls-callback-with-undefined-this.js @@ -16,5 +16,6 @@ features: [AsyncContext] const asyncVar = new AsyncContext.Variable(); asyncVar.run("foo", function () { + "use strict"; assert.sameValue(this, undefined); }); From 26f2a84cd37b9d1522f45fe6dadaad5b2bad065b Mon Sep 17 00:00:00 2001 From: Andreu Botella Date: Wed, 21 Feb 2024 19:06:54 +0100 Subject: [PATCH 09/16] Add and fix various tests per review suggestions --- .../constructor-throwing-name-hasproperty.js | 7 ++- ...snapshot-after-callback-returns-promise.js | 51 +++++++++++++++++++ ...-snapshot-after-callback-takes-snapshot.js | 51 +++++++++++++++++++ .../CreateIteratorFromClosure.js | 5 +- .../FinalizationRegistry.js | 13 +++-- .../async-generators-yield-inside-run.js | 3 -- .../context-propagation/async-generators.js | 5 +- .../generators-yield-inside-run.js | 3 -- .../context-propagation/generators.js | 3 -- 9 files changed, 118 insertions(+), 23 deletions(-) create mode 100644 test/built-ins/AsyncContext/Variable/prototype/run/restores-context-snapshot-after-callback-returns-promise.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype/run/restores-context-snapshot-after-callback-takes-snapshot.js diff --git a/test/built-ins/AsyncContext/Variable/constructor-throwing-name-hasproperty.js b/test/built-ins/AsyncContext/Variable/constructor-throwing-name-hasproperty.js index fdf866c3929..90adbea7a25 100644 --- a/test/built-ins/AsyncContext/Variable/constructor-throwing-name-hasproperty.js +++ b/test/built-ins/AsyncContext/Variable/constructor-throwing-name-hasproperty.js @@ -18,8 +18,11 @@ features: [AsyncContext] function CustomError() { } const options = new Proxy({}, { - has() { - throw new CustomError(); + has(target, prop) { + if (target === options && prop === "name") { + throw new CustomError(); + } + return false; } }); diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/restores-context-snapshot-after-callback-returns-promise.js b/test/built-ins/AsyncContext/Variable/prototype/run/restores-context-snapshot-after-callback-returns-promise.js new file mode 100644 index 00000000000..09b3463e494 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/run/restores-context-snapshot-after-callback-returns-promise.js @@ -0,0 +1,51 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.run +description: > + Switches back into the previous context snapshot after calling the callback. + This happens synchronously, regardless of whether the callback returns a + promise. +info: | + AsyncContext.Variable.prototype.run ( value, func, ...args ) + + 3. Let previousContextMapping be AsyncContextSnapshot(). + ... + 10. Let result be Completion(Call(func, undefined, args)). + 11. AsyncContextSwap(previousContextMapping). + 12. Return result. + + AsyncContextSwap ( snapshotMapping ) + + 1. Let agentRecord be the surrounding agent's Agent Record. + ... + 3. Set agentRecord.[[AsyncContextMapping]] to snapshotMapping. + + AsyncContextSnapshot ( ) + + 1. Let agentRecord be the surrounding agent's Agent Record. + 2. Return agentRecord.[[AsyncContextMapping]]. +features: [AsyncContext] +---*/ + +const asyncVar = new AsyncContext.Variable(); + +asyncVar.run("foo", () => { + asyncVar.run("42", () => { + // Never resolves. + return new Promise(() => { }); + }); + + assert.sameValue( + asyncVar.get(), + "foo", + 'The value of `asyncVar.get()` inside the first `run` and after the second one should be `"foo"`' + ); +}); + +assert.sameValue( + asyncVar.get(), + undefined, + 'The value of `asyncVar.get()` after the first `run` should be `undefined`' +); diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/restores-context-snapshot-after-callback-takes-snapshot.js b/test/built-ins/AsyncContext/Variable/prototype/run/restores-context-snapshot-after-callback-takes-snapshot.js new file mode 100644 index 00000000000..d73c487e5f6 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/run/restores-context-snapshot-after-callback-takes-snapshot.js @@ -0,0 +1,51 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable.prototype.run +description: > + Switches back into the previous context snapshot after calling the callback, + even when an AsyncContext.Snapshot() is created inside the callback. +info: | + AsyncContext.Variable.prototype.run ( value, func, ...args ) + + 3. Let previousContextMapping be AsyncContextSnapshot(). + ... + 10. Let result be Completion(Call(func, undefined, args)). + 11. AsyncContextSwap(previousContextMapping). + 12. Return result. + + AsyncContextSwap ( snapshotMapping ) + + 1. Let agentRecord be the surrounding agent's Agent Record. + ... + 3. Set agentRecord.[[AsyncContextMapping]] to snapshotMapping. + + AsyncContextSnapshot ( ) + + 1. Let agentRecord be the surrounding agent's Agent Record. + 2. Return agentRecord.[[AsyncContextMapping]]. +features: [AsyncContext] +---*/ + +const asyncVar = new AsyncContext.Variable(); + +let snapshot; + +asyncVar.run("foo", () => { + asyncVar.run("42", () => { + snapshot = new AsyncContext.Snapshot(); + }); + + assert.sameValue( + asyncVar.get(), + "foo", + 'The value of `asyncVar.get()` inside the first `run` and after the second one should be `"foo"`' + ); +}); + +assert.sameValue( + asyncVar.get(), + undefined, + 'The value of `asyncVar.get()` after the first `run` should be `undefined`' +); diff --git a/test/built-ins/AsyncContext/context-propagation/CreateIteratorFromClosure.js b/test/built-ins/AsyncContext/context-propagation/CreateIteratorFromClosure.js index 8112cece34e..58128989d97 100644 --- a/test/built-ins/AsyncContext/context-propagation/CreateIteratorFromClosure.js +++ b/test/built-ins/AsyncContext/context-propagation/CreateIteratorFromClosure.js @@ -6,15 +6,12 @@ description: TODO features: [AsyncContext] ---*/ -// TODO: This test tests the behavior in -// https://github.com/tc39/proposal-async-context/pull/61 - const asyncVar = new AsyncContext.Variable(); const array = []; Object.defineProperty(array, 0, { get() { - assert.sameValue(asyncVar.get(), "foo"); + assert.sameValue(asyncVar.get(), "bar"); } }); diff --git a/test/built-ins/AsyncContext/context-propagation/FinalizationRegistry.js b/test/built-ins/AsyncContext/context-propagation/FinalizationRegistry.js index 5b521d64eb5..c50f5ee29f1 100644 --- a/test/built-ins/AsyncContext/context-propagation/FinalizationRegistry.js +++ b/test/built-ins/AsyncContext/context-propagation/FinalizationRegistry.js @@ -12,24 +12,27 @@ flags: [async, non-deterministic] features: [AsyncContext, FinalizationRegistry, host-gc-required] ---*/ +// TODO: This test tests the behavior in +// https://github.com/tc39/proposal-async-context/pull/61 + const asyncVar = new AsyncContext.Variable(); function cleanupCallback() { try { - assert.sameValue(asyncVar.get(), 42); + assert.sameValue(asyncVar.get(), "bar"); $DONE(); } catch (err) { $DONE(err); } } -const registry = asyncVar.run(42, () => { +const registry = asyncVar.run("foo", () => { return new FinalizationRegistry(cleanupCallback); }); -{ +asyncVar.run("bar", () => { let target = {}; registry.register(target); -} +}); -$262.gc(); +asyncVar.run("baz", () => $262.gc()); diff --git a/test/built-ins/AsyncContext/context-propagation/async-generators-yield-inside-run.js b/test/built-ins/AsyncContext/context-propagation/async-generators-yield-inside-run.js index 04150fb28f7..68a030b780b 100644 --- a/test/built-ins/AsyncContext/context-propagation/async-generators-yield-inside-run.js +++ b/test/built-ins/AsyncContext/context-propagation/async-generators-yield-inside-run.js @@ -8,9 +8,6 @@ features: [AsyncContext] includes: [asyncHelpers.js] ---*/ -// TODO: This test tests the behavior in -// https://github.com/tc39/proposal-async-context/pull/61 - const asyncVar = new AsyncContext.Variable(); async function* gen() { diff --git a/test/built-ins/AsyncContext/context-propagation/async-generators.js b/test/built-ins/AsyncContext/context-propagation/async-generators.js index 74e1dfc3b1e..8f1d40e623b 100644 --- a/test/built-ins/AsyncContext/context-propagation/async-generators.js +++ b/test/built-ins/AsyncContext/context-propagation/async-generators.js @@ -8,15 +8,14 @@ features: [AsyncContext] includes: [asyncHelpers.js] ---*/ -// TODO: This test tests the behavior in -// https://github.com/tc39/proposal-async-context/pull/61 - const asyncVar = new AsyncContext.Variable(); async function* gen() { + assert.sameValue(asyncVar.get(), "init"); await Promise.resolve(); assert.sameValue(asyncVar.get(), "init"); yield; + assert.sameValue(asyncVar.get(), "init"); await Promise.resolve(); assert.sameValue(asyncVar.get(), "init"); } diff --git a/test/built-ins/AsyncContext/context-propagation/generators-yield-inside-run.js b/test/built-ins/AsyncContext/context-propagation/generators-yield-inside-run.js index 27a9315fedb..5551bc1454d 100644 --- a/test/built-ins/AsyncContext/context-propagation/generators-yield-inside-run.js +++ b/test/built-ins/AsyncContext/context-propagation/generators-yield-inside-run.js @@ -6,9 +6,6 @@ description: TODO features: [AsyncContext] ---*/ -// TODO: This test tests the behavior in -// https://github.com/tc39/proposal-async-context/pull/61 - const asyncVar = new AsyncContext.Variable(); function* gen() { diff --git a/test/built-ins/AsyncContext/context-propagation/generators.js b/test/built-ins/AsyncContext/context-propagation/generators.js index e503a3ea23a..3e5fa9d90b6 100644 --- a/test/built-ins/AsyncContext/context-propagation/generators.js +++ b/test/built-ins/AsyncContext/context-propagation/generators.js @@ -6,9 +6,6 @@ description: TODO features: [AsyncContext] ---*/ -// TODO: This test tests the behavior in -// https://github.com/tc39/proposal-async-context/pull/61 - const asyncVar = new AsyncContext.Variable(); function* gen() { From 7f263a4c19badf091240a4b636411f4d325e2e5a Mon Sep 17 00:00:00 2001 From: Andreu Botella Date: Thu, 22 Feb 2024 20:41:03 +0100 Subject: [PATCH 10/16] Fix proto, proc, etc. tests --- .../newtarget-prototype-is-not-object.js | 57 ++++++++++++++++++ .../AsyncContext/Snapshot/prop-desc.js | 22 +++++++ .../Snapshot/proto-from-ctor-realm.js | 58 +++++++++++++++++++ test/built-ins/AsyncContext/Snapshot/proto.js | 18 ++++++ .../prototype-from-newtarget-abrupt.js | 41 +++++++++++++ .../prototype-from-newtarget-custom.js | 44 ++++++++++++++ .../Snapshot/prototype-from-newtarget.js | 33 +++++++++++ .../prototype/{descriptor.js => prop-desc.js} | 10 ++-- .../AsyncContext/Snapshot/prototype/proto.js | 15 +++++ .../returns-new-object-from-constructor.js | 37 ++++++++++++ .../Variable/Symbol.toStringTag.js | 22 ------- .../newtarget-prototype-is-not-object.js | 57 ++++++++++++++++++ .../AsyncContext/Variable/proc-desc.js | 40 ------------- .../AsyncContext/Variable/prop-desc.js | 22 +++++++ .../Variable/proto-from-ctor-realm.js | 58 +++++++++++++++++++ test/built-ins/AsyncContext/Variable/proto.js | 18 +++--- .../prototype-from-newtarget-abrupt.js | 41 +++++++++++++ .../prototype-from-newtarget-custom.js | 44 ++++++++++++++ .../Variable/prototype-from-newtarget.js | 33 +++++++++++ .../prototype/{descriptor.js => prop-desc.js} | 10 ++-- .../AsyncContext/Variable/prototype/proto.js | 15 +++++ .../returns-new-object-from-constructor.js | 39 +++++++++++++ 22 files changed, 656 insertions(+), 78 deletions(-) create mode 100644 test/built-ins/AsyncContext/Snapshot/newtarget-prototype-is-not-object.js create mode 100644 test/built-ins/AsyncContext/Snapshot/prop-desc.js create mode 100644 test/built-ins/AsyncContext/Snapshot/proto-from-ctor-realm.js create mode 100644 test/built-ins/AsyncContext/Snapshot/proto.js create mode 100644 test/built-ins/AsyncContext/Snapshot/prototype-from-newtarget-abrupt.js create mode 100644 test/built-ins/AsyncContext/Snapshot/prototype-from-newtarget-custom.js create mode 100644 test/built-ins/AsyncContext/Snapshot/prototype-from-newtarget.js rename test/built-ins/AsyncContext/Snapshot/prototype/{descriptor.js => prop-desc.js} (61%) create mode 100644 test/built-ins/AsyncContext/Snapshot/prototype/proto.js create mode 100644 test/built-ins/AsyncContext/Snapshot/returns-new-object-from-constructor.js delete mode 100644 test/built-ins/AsyncContext/Variable/Symbol.toStringTag.js create mode 100644 test/built-ins/AsyncContext/Variable/newtarget-prototype-is-not-object.js delete mode 100644 test/built-ins/AsyncContext/Variable/proc-desc.js create mode 100644 test/built-ins/AsyncContext/Variable/prop-desc.js create mode 100644 test/built-ins/AsyncContext/Variable/proto-from-ctor-realm.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype-from-newtarget-abrupt.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype-from-newtarget-custom.js create mode 100644 test/built-ins/AsyncContext/Variable/prototype-from-newtarget.js rename test/built-ins/AsyncContext/Variable/prototype/{descriptor.js => prop-desc.js} (61%) create mode 100644 test/built-ins/AsyncContext/Variable/prototype/proto.js create mode 100644 test/built-ins/AsyncContext/Variable/returns-new-object-from-constructor.js diff --git a/test/built-ins/AsyncContext/Snapshot/newtarget-prototype-is-not-object.js b/test/built-ins/AsyncContext/Snapshot/newtarget-prototype-is-not-object.js new file mode 100644 index 00000000000..0d33745510b --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/newtarget-prototype-is-not-object.js @@ -0,0 +1,57 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot +description: > + [[Prototype]] defaults to %AsyncContext.Snapshot.prototype% if NewTarget.prototype is not an object. +info: | + AsyncContext.Snapshot ( ) + + ... + 3. Let asyncSnapshot be ? OrdinaryCreateFromConstructor(NewTarget, "%AsyncContext.Snapshot.prototype%", « [[AsyncSnapshotMapping]] »). + ... + 5. Return asyncSnapshot. + + OrdinaryCreateFromConstructor ( constructor, intrinsicDefaultProto [ , internalSlotsList ] ) + + ... + 2. Let proto be ? GetPrototypeFromConstructor(constructor, intrinsicDefaultProto). + 3. Return ObjectCreate(proto, internalSlotsList). + + GetPrototypeFromConstructor ( constructor, intrinsicDefaultProto ) + + 3. Let proto be ? Get(constructor, 'prototype'). + 4. If Type(proto) is not Object, then + a. Let realm be ? GetFunctionRealm(constructor). + b. Set proto to realm's intrinsic object named intrinsicDefaultProto. + 5. Return proto. +features: [AsyncContext, Reflect.construct, Symbol] +---*/ + +var asyncSnapshot; +function newTarget() { } + +newTarget.prototype = undefined; +asyncSnapshot = Reflect.construct(AsyncContext.Snapshot, [], newTarget); +assert.sameValue(Object.getPrototypeOf(asyncSnapshot), AsyncContext.Snapshot.prototype, 'newTarget.prototype is undefined'); + +newTarget.prototype = null; +asyncSnapshot = Reflect.construct(AsyncContext.Snapshot, [], newTarget); +assert.sameValue(Object.getPrototypeOf(asyncSnapshot), AsyncContext.Snapshot.prototype, 'newTarget.prototype is null'); + +newTarget.prototype = true; +asyncSnapshot = Reflect.construct(AsyncContext.Snapshot, [], newTarget); +assert.sameValue(Object.getPrototypeOf(asyncSnapshot), AsyncContext.Snapshot.prototype, 'newTarget.prototype is a Boolean'); + +newTarget.prototype = ''; +asyncSnapshot = Reflect.construct(AsyncContext.Snapshot, [], newTarget); +assert.sameValue(Object.getPrototypeOf(asyncSnapshot), AsyncContext.Snapshot.prototype, 'newTarget.prototype is a String'); + +newTarget.prototype = Symbol(); +asyncSnapshot = Reflect.construct(AsyncContext.Snapshot, [], newTarget); +assert.sameValue(Object.getPrototypeOf(asyncSnapshot), AsyncContext.Snapshot.prototype, 'newTarget.prototype is a Symbol'); + +newTarget.prototype = 1; +asyncSnapshot = Reflect.construct(AsyncContext.Snapshot, [], newTarget); +assert.sameValue(Object.getPrototypeOf(asyncSnapshot), AsyncContext.Snapshot.prototype, 'newTarget.prototype is a Number'); diff --git a/test/built-ins/AsyncContext/Snapshot/prop-desc.js b/test/built-ins/AsyncContext/Snapshot/prop-desc.js new file mode 100644 index 00000000000..0749287e791 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/prop-desc.js @@ -0,0 +1,22 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot-constructor +description: > + Property descriptor of AsyncContext.Snapshot +info: | + 17 ECMAScript Standard Built-in Objects: + + Every other data property described in clauses 18 through 26 and in Annex B.2 + has the attributes { [[Writable]]: true, [[Enumerable]]: false, + [[Configurable]]: true } unless otherwise specified. +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +verifyProperty(AsyncContext, 'Snapshot', { + enumerable: false, + writable: true, + configurable: true +}); diff --git a/test/built-ins/AsyncContext/Snapshot/proto-from-ctor-realm.js b/test/built-ins/AsyncContext/Snapshot/proto-from-ctor-realm.js new file mode 100644 index 00000000000..fee87a3a451 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/proto-from-ctor-realm.js @@ -0,0 +1,58 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot +description: Default [[Prototype]] value derived from realm of the newTarget +info: | + AsyncContext.Snapshot ( ) + + ... + 3. Let asyncSnapshot be ? OrdinaryCreateFromConstructor(NewTarget, "%AsyncContext.Snapshot.prototype%", « [[AsyncSnapshotMapping]] »). + ... + 5. Return asyncSnapshot. + + OrdinaryCreateFromConstructor ( constructor, intrinsicDefaultProto [ , internalSlotsList ] ) + + ... + 2. Let proto be ? GetPrototypeFromConstructor(constructor, intrinsicDefaultProto). + 3. Return ObjectCreate(proto, internalSlotsList). + + GetPrototypeFromConstructor ( constructor, intrinsicDefaultProto ) + + 3. Let proto be ? Get(constructor, 'prototype'). + 4. If Type(proto) is not Object, then + a. Let realm be ? GetFunctionRealm(constructor). + b. Set proto to realm's intrinsic object named intrinsicDefaultProto. + 5. Return proto. +features: [AsyncContext, cross-realm, Reflect, Symbol] +---*/ + +var other = $262.createRealm().global; +var newTarget = new other.Function(); +var asyncSnapshot; + +newTarget.prototype = undefined; +asyncSnapshot = Reflect.construct(AsyncContext.Snapshot, [], newTarget); +assert.sameValue(Object.getPrototypeOf(asyncSnapshot), other.AsyncContext.Snapshot.prototype, 'newTarget.prototype is undefined'); + +newTarget.prototype = null; +asyncSnapshot = Reflect.construct(AsyncContext.Snapshot, [], newTarget); +assert.sameValue(Object.getPrototypeOf(asyncSnapshot), other.AsyncContext.Snapshot.prototype, 'newTarget.prototype is null'); + +newTarget.prototype = true; +asyncSnapshot = Reflect.construct(AsyncContext.Snapshot, [], newTarget); +assert.sameValue(Object.getPrototypeOf(asyncSnapshot), other.AsyncContext.Snapshot.prototype, 'newTarget.prototype is a Boolean'); + +newTarget.prototype = ''; +asyncSnapshot = Reflect.construct(AsyncContext.Snapshot, [], newTarget); +assert.sameValue(Object.getPrototypeOf(asyncSnapshot), other.AsyncContext.Snapshot.prototype, 'newTarget.prototype is a String'); + +newTarget.prototype = Symbol(); +asyncSnapshot = Reflect.construct(AsyncContext.Snapshot, [], newTarget); +assert.sameValue(Object.getPrototypeOf(asyncSnapshot), other.AsyncContext.Snapshot.prototype, 'newTarget.prototype is a Symbol'); + +newTarget.prototype = 1; +asyncSnapshot = Reflect.construct(AsyncContext.Snapshot, [], newTarget); +assert.sameValue(Object.getPrototypeOf(asyncSnapshot), other.AsyncContext.Snapshot.prototype, 'newTarget.prototype is a Number'); + diff --git a/test/built-ins/AsyncContext/Snapshot/proto.js b/test/built-ins/AsyncContext/Snapshot/proto.js new file mode 100644 index 00000000000..c9166cafbf1 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/proto.js @@ -0,0 +1,18 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-properties-of-the-asynccontext-snapshot-constructor +description: > + The prototype of AsyncContext.Snapshot is %Function.prototype% +info: | + The value of the [[Prototype]] internal slot of the AsyncContext.Snapshot + constructor is the intrinsic object %Function.prototype%. +features: [AsyncContext] +---*/ + +assert.sameValue( + Object.getPrototypeOf(AsyncContext.Snapshot), + Function.prototype, + 'Object.getPrototypeOf(AsyncContext.Snapshot) returns the value of `Function.prototype`' +); diff --git a/test/built-ins/AsyncContext/Snapshot/prototype-from-newtarget-abrupt.js b/test/built-ins/AsyncContext/Snapshot/prototype-from-newtarget-abrupt.js new file mode 100644 index 00000000000..32a6adcf8b2 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/prototype-from-newtarget-abrupt.js @@ -0,0 +1,41 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot +description: > + Return abrupt from getting the NewTarget prototype +info: | + AsyncContext.Snapshot ( ) + + ... + 3. Let asyncSnapshot be ? OrdinaryCreateFromConstructor(NewTarget, "%AsyncContext.Snapshot.prototype%", « [[AsyncSnapshotMapping]] »). + ... + 5. Return asyncSnapshot. + + OrdinaryCreateFromConstructor ( constructor, intrinsicDefaultProto [ , internalSlotsList ] ) + + ... + 2. Let proto be ? GetPrototypeFromConstructor(constructor, intrinsicDefaultProto). + 3. Return ObjectCreate(proto, internalSlotsList). + + GetPrototypeFromConstructor ( constructor, intrinsicDefaultProto ) + + 3. Let proto be ? Get(constructor, 'prototype'). +features: [AsyncContext, Reflect.construct] +---*/ + +var calls = 0; +var newTarget = function() {}.bind(null); +Object.defineProperty(newTarget, 'prototype', { + get: function() { + calls += 1; + throw new Test262Error(); + } +}); + +assert.throws(Test262Error, function() { + Reflect.construct(AsyncContext.Snapshot, [], newTarget); +}); + +assert.sameValue(calls, 1); diff --git a/test/built-ins/AsyncContext/Snapshot/prototype-from-newtarget-custom.js b/test/built-ins/AsyncContext/Snapshot/prototype-from-newtarget-custom.js new file mode 100644 index 00000000000..7d92966267f --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/prototype-from-newtarget-custom.js @@ -0,0 +1,44 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot +description: > + The [[Prototype]] internal slot is computed from NewTarget. +info: | + AsyncContext.Snapshot ( ) + + ... + 3. Let asyncSnapshot be ? OrdinaryCreateFromConstructor(NewTarget, "%AsyncContext.Snapshot.prototype%", « [[AsyncSnapshotMapping]] »). + ... + 5. Return asyncSnapshot. + + OrdinaryCreateFromConstructor ( constructor, intrinsicDefaultProto [ , internalSlotsList ] ) + + ... + 2. Let proto be ? GetPrototypeFromConstructor(constructor, intrinsicDefaultProto). + 3. Return ObjectCreate(proto, internalSlotsList). + + GetPrototypeFromConstructor ( constructor, intrinsicDefaultProto ) + + 3. Let proto be ? Get(constructor, 'prototype'). + 4. If Type(proto) is not Object, then + a. Let realm be ? GetFunctionRealm(constructor). + b. Set proto to realm's intrinsic object named intrinsicDefaultProto. + 5. Return proto. +features: [AsyncContext, Reflect.construct] +---*/ + +var asyncSnapshot; + +asyncSnapshot = Reflect.construct(AsyncContext.Snapshot, [], Object); +assert.sameValue(Object.getPrototypeOf(asyncSnapshot), Object.prototype, 'NewTarget is built-in Object constructor'); + +var newTarget = function() {}.bind(null); +Object.defineProperty(newTarget, 'prototype', { + get: function() { + return Array.prototype; + } +}); +asyncSnapshot = Reflect.construct(AsyncContext.Snapshot, [], newTarget); +assert.sameValue(Object.getPrototypeOf(asyncSnapshot), Array.prototype, 'NewTarget is BoundFunction with accessor'); diff --git a/test/built-ins/AsyncContext/Snapshot/prototype-from-newtarget.js b/test/built-ins/AsyncContext/Snapshot/prototype-from-newtarget.js new file mode 100644 index 00000000000..09cfc2d53f5 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/prototype-from-newtarget.js @@ -0,0 +1,33 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot +description: > + The [[Prototype]] internal slot is computed from NewTarget. +info: | + AsyncContext.Snapshot ( ) + + ... + 3. Let asyncSnapshot be ? OrdinaryCreateFromConstructor(NewTarget, "%AsyncContext.Snapshot.prototype%", « [[AsyncSnapshotMapping]] »). + ... + 5. Return asyncSnapshot. + + OrdinaryCreateFromConstructor ( constructor, intrinsicDefaultProto [ , internalSlotsList ] ) + + ... + 2. Let proto be ? GetPrototypeFromConstructor(constructor, intrinsicDefaultProto). + 3. Return ObjectCreate(proto, internalSlotsList). + + GetPrototypeFromConstructor ( constructor, intrinsicDefaultProto ) + + 3. Let proto be ? Get(constructor, 'prototype'). + 4. If Type(proto) is not Object, then + a. Let realm be ? GetFunctionRealm(constructor). + b. Set proto to realm's intrinsic object named intrinsicDefaultProto. + 5. Return proto. +features: [AsyncContext] +---*/ + +var asyncSnapshot = new AsyncContext.Snapshot(); +assert.sameValue(Object.getPrototypeOf(asyncSnapshot), AsyncContext.Snapshot.prototype); diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/descriptor.js b/test/built-ins/AsyncContext/Snapshot/prototype/prop-desc.js similarity index 61% rename from test/built-ins/AsyncContext/Snapshot/prototype/descriptor.js rename to test/built-ins/AsyncContext/Snapshot/prototype/prop-desc.js index a4f99f0c6bc..5f5fbb3cd91 100644 --- a/test/built-ins/AsyncContext/Snapshot/prototype/descriptor.js +++ b/test/built-ins/AsyncContext/Snapshot/prototype/prop-desc.js @@ -1,4 +1,4 @@ -// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// Copyright (C) 2024 Igalia, S. L. All rights reserved. // This code is governed by the BSD license found in the LICENSE file. /*--- @@ -11,6 +11,8 @@ includes: [propertyHelper.js] features: [AsyncContext] ---*/ -verifyNotEnumerable(AsyncContext.Snapshot, 'prototype'); -verifyNotWritable(AsyncContext.Snapshot, 'prototype'); -verifyNotConfigurable(AsyncContext.Snapshot, 'prototype'); +verifyProperty(AsyncContext.Snapshot, 'prototype', { + writable: false, + enumerable: false, + configurable: false +}); diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/proto.js b/test/built-ins/AsyncContext/Snapshot/prototype/proto.js new file mode 100644 index 00000000000..e24338b0445 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/prototype/proto.js @@ -0,0 +1,15 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-properties-of-the-asynccontext-snapshot-prototype-object +description: | + The prototype of AsyncContext.Snapshot.prototype is Object.prototype. +info: | + The value of the [[Prototype]] internal slot of the AsyncContext.Snapshot + prototype object is the intrinsic object %Object.prototype%. +features: [AsyncContext] +---*/ + +var proto = Object.getPrototypeOf(AsyncContext.Snapshot.prototype); +assert.sameValue(proto, Object.prototype); diff --git a/test/built-ins/AsyncContext/Snapshot/returns-new-object-from-constructor.js b/test/built-ins/AsyncContext/Snapshot/returns-new-object-from-constructor.js new file mode 100644 index 00000000000..cbb54496d17 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/returns-new-object-from-constructor.js @@ -0,0 +1,37 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot +description: > + Returns a new ordinary object from the FinalizationRegistry constructor +info: | + AsyncContext.Snapshot ( ) + + ... + 3. Let asyncSnapshot be ? OrdinaryCreateFromConstructor(NewTarget, "%AsyncContext.Snapshot.prototype%", « [[AsyncSnapshotMapping]] »). + ... + 5. Return asyncSnapshot. + + OrdinaryCreateFromConstructor ( constructor, intrinsicDefaultProto [ , internalSlotsList ] ) + + ... + 2. Let proto be ? GetPrototypeFromConstructor(constructor, intrinsicDefaultProto). + 3. Return ObjectCreate(proto, internalSlotsList). +features: [AsyncContext, for-of] +---*/ + +var asyncSnapshot = new AsyncContext.Snapshot(); + +assert.sameValue(Object.getPrototypeOf(asyncSnapshot), AsyncContext.Snapshot.prototype); +assert.sameValue(asyncSnapshot instanceof AsyncContext.Snapshot, true, 'instanceof'); + +for (let key of Object.getOwnPropertyNames(asyncSnapshot)) { + assert(false, `should not set any own named properties: ${key}`); +} + +for (let key of Object.getOwnPropertySymbols(asyncSnapshot)) { + assert(false, `should not set any own symbol properties: ${String(key)}`); +} + +assert.sameValue(Object.getPrototypeOf(asyncSnapshot), AsyncContext.Snapshot.prototype); diff --git a/test/built-ins/AsyncContext/Variable/Symbol.toStringTag.js b/test/built-ins/AsyncContext/Variable/Symbol.toStringTag.js deleted file mode 100644 index e10643305a5..00000000000 --- a/test/built-ins/AsyncContext/Variable/Symbol.toStringTag.js +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (C) 2023 Igalia, S. L. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. - -/*--- -esid: sec-asynccontext-@@tostringtag -description: > - `Symbol.toStringTag` property descriptor -info: | - The initial value of the @@toStringTag property is the String value - "AsyncContext". - - This property has the attributes { [[Writable]]: false, [[Enumerable]]: - false, [[Configurable]]: true }. -includes: [propertyHelper.js] -features: [AsyncContext, Symbol.toStringTag] ----*/ - -assert.sameValue(AsyncContext[Symbol.toStringTag], 'AsyncContext'); - -verifyNotEnumerable(AsyncContext, Symbol.toStringTag); -verifyNotWritable(AsyncContext, Symbol.toStringTag); -verifyConfigurable(AsyncContext, Symbol.toStringTag); diff --git a/test/built-ins/AsyncContext/Variable/newtarget-prototype-is-not-object.js b/test/built-ins/AsyncContext/Variable/newtarget-prototype-is-not-object.js new file mode 100644 index 00000000000..3b6575ab153 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/newtarget-prototype-is-not-object.js @@ -0,0 +1,57 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable +description: > + [[Prototype]] defaults to %AsyncContext.Variable.prototype% if NewTarget.prototype is not an object. +info: | + AsyncContext.Variable ( options ) + + ... + 5. Let asyncVariable be ? OrdinaryCreateFromConstructor(NewTarget, "%AsyncContext.Variable.prototype%", « [[AsyncVariableName]], [[AsyncVariableDefaultValue]] »). + ... + 8. Return asyncVariable. + + OrdinaryCreateFromConstructor ( constructor, intrinsicDefaultProto [ , internalSlotsList ] ) + + ... + 2. Let proto be ? GetPrototypeFromConstructor(constructor, intrinsicDefaultProto). + 3. Return ObjectCreate(proto, internalSlotsList). + + GetPrototypeFromConstructor ( constructor, intrinsicDefaultProto ) + + 3. Let proto be ? Get(constructor, 'prototype'). + 4. If Type(proto) is not Object, then + a. Let realm be ? GetFunctionRealm(constructor). + b. Set proto to realm's intrinsic object named intrinsicDefaultProto. + 5. Return proto. +features: [AsyncContext, Reflect.construct, Symbol] +---*/ + +var asyncVariable; +function newTarget() { } + +newTarget.prototype = undefined; +asyncVariable = Reflect.construct(AsyncContext.Variable, [], newTarget); +assert.sameValue(Object.getPrototypeOf(asyncVariable), AsyncContext.Variable.prototype, 'newTarget.prototype is undefined'); + +newTarget.prototype = null; +asyncVariable = Reflect.construct(AsyncContext.Variable, [], newTarget); +assert.sameValue(Object.getPrototypeOf(asyncVariable), AsyncContext.Variable.prototype, 'newTarget.prototype is null'); + +newTarget.prototype = true; +asyncVariable = Reflect.construct(AsyncContext.Variable, [], newTarget); +assert.sameValue(Object.getPrototypeOf(asyncVariable), AsyncContext.Variable.prototype, 'newTarget.prototype is a Boolean'); + +newTarget.prototype = ''; +asyncVariable = Reflect.construct(AsyncContext.Variable, [], newTarget); +assert.sameValue(Object.getPrototypeOf(asyncVariable), AsyncContext.Variable.prototype, 'newTarget.prototype is a String'); + +newTarget.prototype = Symbol(); +asyncVariable = Reflect.construct(AsyncContext.Variable, [], newTarget); +assert.sameValue(Object.getPrototypeOf(asyncVariable), AsyncContext.Variable.prototype, 'newTarget.prototype is a Symbol'); + +newTarget.prototype = 1; +asyncVariable = Reflect.construct(AsyncContext.Variable, [], newTarget); +assert.sameValue(Object.getPrototypeOf(asyncVariable), AsyncContext.Variable.prototype, 'newTarget.prototype is a Number'); diff --git a/test/built-ins/AsyncContext/Variable/proc-desc.js b/test/built-ins/AsyncContext/Variable/proc-desc.js deleted file mode 100644 index 1b98ed47f35..00000000000 --- a/test/built-ins/AsyncContext/Variable/proc-desc.js +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (C) 2023 Igalia, S. L. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. - -/*--- -esid: sec-asynccontext-object -description: > - Property descriptor of AsyncContext -info: | - The AsyncContext Object - - The AsyncContext object does not have a [[Construct]] internal method; it - cannot be used as a constructor with the new operator. - - The AsyncContext object does not have a [[Call]] internal method; it cannot - be invoked as a function. - - 17 ECMAScript Standard Built-in Objects: - - Every other data property described in clauses 18 through 26 and in Annex - B.2 has the attributes { [[Writable]]: true, [[Enumerable]]: false, - [[Configurable]]: true } unless otherwise specified. -includes: [propertyHelper.js] -features: [AsyncContext] ----*/ - -assert.sameValue(typeof AsyncContext, "object"); - -assert.throws(TypeError, function() { - AsyncContext(); -}, "no [[Call]]"); - -assert.throws(TypeError, function() { - new AsyncContext(); -}, "no [[Construct]]"); - -verifyProperty(this, "AsyncContext", { - enumerable: false, - writable: true, - configurable: true -}); diff --git a/test/built-ins/AsyncContext/Variable/prop-desc.js b/test/built-ins/AsyncContext/Variable/prop-desc.js new file mode 100644 index 00000000000..288f301b533 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prop-desc.js @@ -0,0 +1,22 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable-constructor +description: > + Property descriptor of AsyncContext.Variable +info: | + 17 ECMAScript Standard Built-in Objects: + + Every other data property described in clauses 18 through 26 and in Annex B.2 + has the attributes { [[Writable]]: true, [[Enumerable]]: false, + [[Configurable]]: true } unless otherwise specified. +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +verifyProperty(AsyncContext, 'Variable', { + enumerable: false, + writable: true, + configurable: true +}); diff --git a/test/built-ins/AsyncContext/Variable/proto-from-ctor-realm.js b/test/built-ins/AsyncContext/Variable/proto-from-ctor-realm.js new file mode 100644 index 00000000000..2ad0648dd61 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/proto-from-ctor-realm.js @@ -0,0 +1,58 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable +description: Default [[Prototype]] value derived from realm of the newTarget +info: | + AsyncContext.Variable ( options ) + + ... + 5. Let asyncVariable be ? OrdinaryCreateFromConstructor(NewTarget, "%AsyncContext.Variable.prototype%", « [[AsyncVariableName]], [[AsyncVariableDefaultValue]] »). + ... + 8. Return asyncVariable. + + OrdinaryCreateFromConstructor ( constructor, intrinsicDefaultProto [ , internalSlotsList ] ) + + ... + 2. Let proto be ? GetPrototypeFromConstructor(constructor, intrinsicDefaultProto). + 3. Return ObjectCreate(proto, internalSlotsList). + + GetPrototypeFromConstructor ( constructor, intrinsicDefaultProto ) + + 3. Let proto be ? Get(constructor, 'prototype'). + 4. If Type(proto) is not Object, then + a. Let realm be ? GetFunctionRealm(constructor). + b. Set proto to realm's intrinsic object named intrinsicDefaultProto. + 5. Return proto. +features: [AsyncContext, cross-realm, Reflect, Symbol] +---*/ + +var other = $262.createRealm().global; +var newTarget = new other.Function(); +var asyncVariable; + +newTarget.prototype = undefined; +asyncVariable = Reflect.construct(AsyncContext.Variable, [], newTarget); +assert.sameValue(Object.getPrototypeOf(asyncVariable), other.AsyncContext.Variable.prototype, 'newTarget.prototype is undefined'); + +newTarget.prototype = null; +asyncVariable = Reflect.construct(AsyncContext.Variable, [], newTarget); +assert.sameValue(Object.getPrototypeOf(asyncVariable), other.AsyncContext.Variable.prototype, 'newTarget.prototype is null'); + +newTarget.prototype = true; +asyncVariable = Reflect.construct(AsyncContext.Variable, [], newTarget); +assert.sameValue(Object.getPrototypeOf(asyncVariable), other.AsyncContext.Variable.prototype, 'newTarget.prototype is a Boolean'); + +newTarget.prototype = ''; +asyncVariable = Reflect.construct(AsyncContext.Variable, [], newTarget); +assert.sameValue(Object.getPrototypeOf(asyncVariable), other.AsyncContext.Variable.prototype, 'newTarget.prototype is a String'); + +newTarget.prototype = Symbol(); +asyncVariable = Reflect.construct(AsyncContext.Variable, [], newTarget); +assert.sameValue(Object.getPrototypeOf(asyncVariable), other.AsyncContext.Variable.prototype, 'newTarget.prototype is a Symbol'); + +newTarget.prototype = 1; +asyncVariable = Reflect.construct(AsyncContext.Variable, [], newTarget); +assert.sameValue(Object.getPrototypeOf(asyncVariable), other.AsyncContext.Variable.prototype, 'newTarget.prototype is a Number'); + diff --git a/test/built-ins/AsyncContext/Variable/proto.js b/test/built-ins/AsyncContext/Variable/proto.js index 134c25a8596..50b9860e980 100644 --- a/test/built-ins/AsyncContext/Variable/proto.js +++ b/test/built-ins/AsyncContext/Variable/proto.js @@ -1,16 +1,18 @@ -// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// Copyright (C) 2024 Igalia, S. L. All rights reserved. // This code is governed by the BSD license found in the LICENSE file. /*--- -esid: sec-asynccontext-object +esid: sec-properties-of-the-asynccontext-variable-constructor description: > - The prototype of AsyncContext is Object.prototype + The prototype of AsyncContext.Variable is %Function.prototype% info: | - The AsyncContext Object has a [[Prototype]] internal slot whose value is - %Object.prototype%. + The value of the [[Prototype]] internal slot of the AsyncContext.Variable + constructor is the intrinsic object %Function.prototype%. features: [AsyncContext] ---*/ -const proto = Object.getPrototypeOf(AsyncContext); - -assert.sameValue(proto, Object.prototype); +assert.sameValue( + Object.getPrototypeOf(AsyncContext.Variable), + Function.prototype, + 'Object.getPrototypeOf(AsyncContext.Variable) returns the value of `Function.prototype`' +); diff --git a/test/built-ins/AsyncContext/Variable/prototype-from-newtarget-abrupt.js b/test/built-ins/AsyncContext/Variable/prototype-from-newtarget-abrupt.js new file mode 100644 index 00000000000..4441a1c0aaf --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype-from-newtarget-abrupt.js @@ -0,0 +1,41 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable +description: > + Return abrupt from getting the NewTarget prototype +info: | + AsyncContext.Variable ( options ) + + ... + 5. Let asyncVariable be ? OrdinaryCreateFromConstructor(NewTarget, "%AsyncContext.Variable.prototype%", « [[AsyncVariableName]], [[AsyncVariableDefaultValue]] »). + ... + 8. Return asyncVariable. + + OrdinaryCreateFromConstructor ( constructor, intrinsicDefaultProto [ , internalSlotsList ] ) + + ... + 2. Let proto be ? GetPrototypeFromConstructor(constructor, intrinsicDefaultProto). + 3. Return ObjectCreate(proto, internalSlotsList). + + GetPrototypeFromConstructor ( constructor, intrinsicDefaultProto ) + + 3. Let proto be ? Get(constructor, 'prototype'). +features: [AsyncContext, Reflect.construct] +---*/ + +var calls = 0; +var newTarget = function() {}.bind(null); +Object.defineProperty(newTarget, 'prototype', { + get: function() { + calls += 1; + throw new Test262Error(); + } +}); + +assert.throws(Test262Error, function() { + Reflect.construct(AsyncContext.Variable, [], newTarget); +}); + +assert.sameValue(calls, 1); diff --git a/test/built-ins/AsyncContext/Variable/prototype-from-newtarget-custom.js b/test/built-ins/AsyncContext/Variable/prototype-from-newtarget-custom.js new file mode 100644 index 00000000000..e719ab0f088 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype-from-newtarget-custom.js @@ -0,0 +1,44 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable +description: > + The [[Prototype]] internal slot is computed from NewTarget. +info: | + AsyncContext.Variable ( options ) + + ... + 5. Let asyncVariable be ? OrdinaryCreateFromConstructor(NewTarget, "%AsyncContext.Variable.prototype%", « [[AsyncVariableName]], [[AsyncVariableDefaultValue]] »). + ... + 8. Return asyncVariable. + + OrdinaryCreateFromConstructor ( constructor, intrinsicDefaultProto [ , internalSlotsList ] ) + + ... + 2. Let proto be ? GetPrototypeFromConstructor(constructor, intrinsicDefaultProto). + 3. Return ObjectCreate(proto, internalSlotsList). + + GetPrototypeFromConstructor ( constructor, intrinsicDefaultProto ) + + 3. Let proto be ? Get(constructor, 'prototype'). + 4. If Type(proto) is not Object, then + a. Let realm be ? GetFunctionRealm(constructor). + b. Set proto to realm's intrinsic object named intrinsicDefaultProto. + 5. Return proto. +features: [AsyncContext, Reflect.construct] +---*/ + +var asyncVariable; + +asyncVariable = Reflect.construct(AsyncContext.Variable, [], Object); +assert.sameValue(Object.getPrototypeOf(asyncVariable), Object.prototype, 'NewTarget is built-in Object constructor'); + +var newTarget = function() {}.bind(null); +Object.defineProperty(newTarget, 'prototype', { + get: function() { + return Array.prototype; + } +}); +asyncVariable = Reflect.construct(AsyncContext.Variable, [], newTarget); +assert.sameValue(Object.getPrototypeOf(asyncVariable), Array.prototype, 'NewTarget is BoundFunction with accessor'); diff --git a/test/built-ins/AsyncContext/Variable/prototype-from-newtarget.js b/test/built-ins/AsyncContext/Variable/prototype-from-newtarget.js new file mode 100644 index 00000000000..b61a4e8f813 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype-from-newtarget.js @@ -0,0 +1,33 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable +description: > + The [[Prototype]] internal slot is computed from NewTarget. +info: | + AsyncContext.Variable ( options ) + + ... + 5. Let asyncVariable be ? OrdinaryCreateFromConstructor(NewTarget, "%AsyncContext.Variable.prototype%", « [[AsyncVariableName]], [[AsyncVariableDefaultValue]] »). + ... + 8. Return asyncVariable. + + OrdinaryCreateFromConstructor ( constructor, intrinsicDefaultProto [ , internalSlotsList ] ) + + ... + 2. Let proto be ? GetPrototypeFromConstructor(constructor, intrinsicDefaultProto). + 3. Return ObjectCreate(proto, internalSlotsList). + + GetPrototypeFromConstructor ( constructor, intrinsicDefaultProto ) + + 3. Let proto be ? Get(constructor, 'prototype'). + 4. If Type(proto) is not Object, then + a. Let realm be ? GetFunctionRealm(constructor). + b. Set proto to realm's intrinsic object named intrinsicDefaultProto. + 5. Return proto. +features: [AsyncContext] +---*/ + +var asyncVariable = new AsyncContext.Variable(); +assert.sameValue(Object.getPrototypeOf(asyncVariable), AsyncContext.Variable.prototype); diff --git a/test/built-ins/AsyncContext/Variable/prototype/descriptor.js b/test/built-ins/AsyncContext/Variable/prototype/prop-desc.js similarity index 61% rename from test/built-ins/AsyncContext/Variable/prototype/descriptor.js rename to test/built-ins/AsyncContext/Variable/prototype/prop-desc.js index a646478e658..9989dd3cf51 100644 --- a/test/built-ins/AsyncContext/Variable/prototype/descriptor.js +++ b/test/built-ins/AsyncContext/Variable/prototype/prop-desc.js @@ -1,4 +1,4 @@ -// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// Copyright (C) 2024 Igalia, S. L. All rights reserved. // This code is governed by the BSD license found in the LICENSE file. /*--- @@ -11,6 +11,8 @@ includes: [propertyHelper.js] features: [AsyncContext] ---*/ -verifyNotEnumerable(AsyncContext.Variable, 'prototype'); -verifyNotWritable(AsyncContext.Variable, 'prototype'); -verifyNotConfigurable(AsyncContext.Variable, 'prototype'); +verifyProperty(AsyncContext.Variable, 'prototype', { + writable: false, + enumerable: false, + configurable: false +}); diff --git a/test/built-ins/AsyncContext/Variable/prototype/proto.js b/test/built-ins/AsyncContext/Variable/prototype/proto.js new file mode 100644 index 00000000000..1a46ae35246 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/prototype/proto.js @@ -0,0 +1,15 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-properties-of-the-asynccontext-variable-prototype-object +description: | + The prototype of AsyncContext.Variable.prototype is Object.prototype. +info: | + The value of the [[Prototype]] internal slot of the AsyncContext.Variable + prototype object is the intrinsic object %Object.prototype%. +features: [AsyncContext] +---*/ + +var proto = Object.getPrototypeOf(AsyncContext.Variable.prototype); +assert.sameValue(proto, Object.prototype); diff --git a/test/built-ins/AsyncContext/Variable/returns-new-object-from-constructor.js b/test/built-ins/AsyncContext/Variable/returns-new-object-from-constructor.js new file mode 100644 index 00000000000..bf730de8a39 --- /dev/null +++ b/test/built-ins/AsyncContext/Variable/returns-new-object-from-constructor.js @@ -0,0 +1,39 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-variable +description: > + Returns a new ordinary object from the FinalizationRegistry constructor +info: | + AsyncContext.Variable ( options ) + + ... + 5. Let asyncVariable be ? OrdinaryCreateFromConstructor(NewTarget, "%AsyncContext.Variable.prototype%", « [[AsyncVariableName]], [[AsyncVariableDefaultValue]] »). + ... + 8. Return asyncVariable. + + OrdinaryCreateFromConstructor ( constructor, intrinsicDefaultProto [ , internalSlotsList ] ) + + ... + 2. Let proto be ? GetPrototypeFromConstructor(constructor, intrinsicDefaultProto). + 3. Return ObjectCreate(proto, internalSlotsList). +features: [AsyncContext, for-of] +---*/ + +var optionsBag = {}; +var asyncVariable = new AsyncContext.Variable(optionsBag); + +assert.sameValue(Object.getPrototypeOf(asyncVariable), AsyncContext.Variable.prototype); +assert.notSameValue(asyncVariable, optionsBag, 'does not return the same object'); +assert.sameValue(asyncVariable instanceof AsyncContext.Variable, true, 'instanceof'); + +for (let key of Object.getOwnPropertyNames(asyncVariable)) { + assert(false, `should not set any own named properties: ${key}`); +} + +for (let key of Object.getOwnPropertySymbols(asyncVariable)) { + assert(false, `should not set any own symbol properties: ${String(key)}`); +} + +assert.sameValue(Object.getPrototypeOf(asyncVariable), AsyncContext.Variable.prototype); From 73a6c61fb1e7b996de8a803105666a3733022261 Mon Sep 17 00:00:00 2001 From: Andreu Botella Date: Thu, 22 Feb 2024 20:54:26 +0100 Subject: [PATCH 11/16] Fix proxy trap bug --- .../Variable/constructor-throwing-name-hasproperty.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/built-ins/AsyncContext/Variable/constructor-throwing-name-hasproperty.js b/test/built-ins/AsyncContext/Variable/constructor-throwing-name-hasproperty.js index 90adbea7a25..524338b85a7 100644 --- a/test/built-ins/AsyncContext/Variable/constructor-throwing-name-hasproperty.js +++ b/test/built-ins/AsyncContext/Variable/constructor-throwing-name-hasproperty.js @@ -18,8 +18,8 @@ features: [AsyncContext] function CustomError() { } const options = new Proxy({}, { - has(target, prop) { - if (target === options && prop === "name") { + has(_target, prop) { + if (prop === "name") { throw new CustomError(); } return false; From 5a62a149309475536198df1c4b1efb29778df388 Mon Sep 17 00:00:00 2001 From: Andreu Botella Date: Fri, 26 Jan 2024 16:32:54 +0100 Subject: [PATCH 12/16] Add tests for `AsyncContext.Snapshot.wrap` --- ...ed-promise-does-not-resolve-in-snapshot.js | 24 +++-- .../AsyncContext/Snapshot/wrap/length.js | 24 +++++ .../AsyncContext/Snapshot/wrap/name.js | 24 +++++ .../Snapshot/wrap/not-a-constructor.js | 29 ++++++ .../throws-if-callback-is-not-callable.js | 45 +++++++++ .../wrap/throws-if-callback-length-throws.js | 31 ++++++ .../wrap/throws-if-callback-name-throws.js | 27 ++++++ .../AsyncContext/Snapshot/wrap/wrap.js | 23 +++++ .../calls-callback-in-snapshot.js | 69 ++++++++++++++ .../calls-callback-with-args.js | 28 ++++++ .../calls-callback-with-this.js | 33 +++++++ .../wrap/wrapped-function/calls-callback.js | 29 ++++++ .../has-prototype-from-current-realm.js | 37 ++++++++ .../wrap/wrapped-function/is-function.js | 28 ++++++ .../Snapshot/wrap/wrapped-function/length.js | 83 ++++++++++++++++ .../Snapshot/wrap/wrapped-function/name.js | 81 ++++++++++++++++ .../wrapped-function/not-a-constructor.js | 42 +++++++++ ...s-context-snapshot-after-callback-throw.js | 56 +++++++++++ ...revious-context-snapshot-after-callback.js | 64 +++++++++++++ .../wrapped-function/restores-snapshot.js | 65 +++++++++++++ .../restores-unset-variables.js | 94 +++++++++++++++++++ ...ed-promise-does-not-resolve-in-snapshot.js | 39 ++++++++ .../returns-async-callback-return-value.js | 36 +++++++ .../returns-callback-return-value.js | 27 ++++++ .../throws-if-callback-throws.js | 29 ++++++ ...ed-promise-does-not-resolve-in-snapshot.js | 22 +++-- 26 files changed, 1070 insertions(+), 19 deletions(-) create mode 100644 test/built-ins/AsyncContext/Snapshot/wrap/length.js create mode 100644 test/built-ins/AsyncContext/Snapshot/wrap/name.js create mode 100644 test/built-ins/AsyncContext/Snapshot/wrap/not-a-constructor.js create mode 100644 test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-is-not-callable.js create mode 100644 test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-length-throws.js create mode 100644 test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-name-throws.js create mode 100644 test/built-ins/AsyncContext/Snapshot/wrap/wrap.js create mode 100644 test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback-in-snapshot.js create mode 100644 test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback-with-args.js create mode 100644 test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback-with-this.js create mode 100644 test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback.js create mode 100644 test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/has-prototype-from-current-realm.js create mode 100644 test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/is-function.js create mode 100644 test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/length.js create mode 100644 test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/name.js create mode 100644 test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/not-a-constructor.js create mode 100644 test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/restores-previous-context-snapshot-after-callback-throw.js create mode 100644 test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/restores-previous-context-snapshot-after-callback.js create mode 100644 test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/restores-snapshot.js create mode 100644 test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/restores-unset-variables.js create mode 100644 test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/returned-promise-does-not-resolve-in-snapshot.js create mode 100644 test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/returns-async-callback-return-value.js create mode 100644 test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/returns-callback-return-value.js create mode 100644 test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/throws-if-callback-throws.js diff --git a/test/built-ins/AsyncContext/Snapshot/prototype/run/returned-promise-does-not-resolve-in-snapshot.js b/test/built-ins/AsyncContext/Snapshot/prototype/run/returned-promise-does-not-resolve-in-snapshot.js index f8fa32a0ac1..c5c31d015e0 100644 --- a/test/built-ins/AsyncContext/Snapshot/prototype/run/returned-promise-does-not-resolve-in-snapshot.js +++ b/test/built-ins/AsyncContext/Snapshot/prototype/run/returned-promise-does-not-resolve-in-snapshot.js @@ -14,20 +14,24 @@ features: [AsyncContext] const asyncVar = new AsyncContext.Variable(); -const asyncSnapshot = asyncVar.run("foo", () => new AsyncContext.Snapshot()); +const asyncSnapshot = asyncVar.run("bar", () => new AsyncContext.Snapshot()); let resolve; -asyncSnapshot.run(async () => { - assert.sameValue(asyncVar.get(), "foo"); +asyncVar.run("foo", () => { - await new Promise(resolveFn => { - resolve = resolveFn; - }); + asyncSnapshot.run(async () => { + assert.sameValue(asyncVar.get(), "bar"); - assert.sameValue(asyncVar.get(), "foo"); -}).then(() => { - assert.sameValue(asyncVar.get(), undefined); -}).then($DONE, $DONE); + await new Promise(resolveFn => { + resolve = resolveFn; + }); + + assert.sameValue(asyncVar.get(), "bar"); + }).then(() => { + assert.sameValue(asyncVar.get(), "foo"); + }).then($DONE, $DONE); + +}); resolve(); diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/length.js b/test/built-ins/AsyncContext/Snapshot/wrap/length.js new file mode 100644 index 00000000000..90b23296548 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/wrap/length.js @@ -0,0 +1,24 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot-wrap +description: > + AsyncContext.Snapshot.wrap.length value and descriptor. +info: | + AsyncContext.Snapshot.wrap ( fn ) + + 17 ECMAScript Standard Built-in Objects + +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +assert.sameValue( + AsyncContext.Snapshot.wrap.length, 1, + 'The value of `AsyncContext.Snapshot.wrap.length` is `1`' +); + +verifyNotEnumerable(AsyncContext.Snapshot.wrap, 'length'); +verifyNotWritable(AsyncContext.Snapshot.wrap, 'length'); +verifyConfigurable(AsyncContext.Snapshot.wrap, 'length'); diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/name.js b/test/built-ins/AsyncContext/Snapshot/wrap/name.js new file mode 100644 index 00000000000..b6a51ee14ae --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/wrap/name.js @@ -0,0 +1,24 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot-wrap +description: > + AsyncContext.Snapshot.wrap.name value and descriptor. +info: | + AsyncContext.Snapshot.wrap ( fn ) + + 17 ECMAScript Standard Built-in Objects + +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +assert.sameValue( + AsyncContext.Snapshot.wrap.name, 'wrap', + 'The value of `AsyncContext.Snapshot.wrap.name` is `"wrap"`' +); + +verifyNotEnumerable(AsyncContext.Snapshot.wrap, 'name'); +verifyNotWritable(AsyncContext.Snapshot.wrap, 'name'); +verifyConfigurable(AsyncContext.Snapshot.wrap, 'name'); diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/not-a-constructor.js b/test/built-ins/AsyncContext/Snapshot/wrap/not-a-constructor.js new file mode 100644 index 00000000000..aaa4dea0df3 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/wrap/not-a-constructor.js @@ -0,0 +1,29 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-ecmascript-standard-built-in-objects +description: > + AsyncContext.Snapshot.wrap does not implement [[Construct]], is not new-able +info: | + ECMAScript Function 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. + + sec-evaluatenew + + ... + 7. If IsConstructor(constructor) is false, throw a TypeError exception. + ... +includes: [isConstructor.js] +features: [Reflect.construct, AsyncContext, arrow-function] +---*/ + +assert.sameValue(isConstructor(AsyncContext.Snapshot.wrap), false, 'isConstructor(AsyncContext.Snapshot.wrap) must return false'); + +assert.throws(TypeError, () => { + new AsyncContext.Snapshot.wrap(() => { }); +}, '`new AsyncContext.Snapshot.wrap(() => {})` throws TypeError'); + diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-is-not-callable.js b/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-is-not-callable.js new file mode 100644 index 00000000000..d0769c3f383 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-is-not-callable.js @@ -0,0 +1,45 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.wrap +description: > + Throws if the argument is not callable. +info: | + AsyncContext.Snapshot.wrap ( fn ) + + 1. If IsCallable(fn) is false, throw a TypeError exception. +features: [AsyncContext] +---*/ + +assert.throws(TypeError, () => { + AsyncContext.Snapshot.wrap(); +}); + +assert.throws(TypeError, () => { + AsyncContext.Snapshot.wrap(1); +}); + +assert.throws(TypeError, () => { + AsyncContext.Snapshot.wrap(true); +}); + +assert.throws(TypeError, () => { + AsyncContext.Snapshot.wrap(''); +}); + +assert.throws(TypeError, () => { + AsyncContext.Snapshot.wrap(null); +}); + +assert.throws(TypeError, () => { + AsyncContext.Snapshot.wrap(undefined); +}); + +assert.throws(TypeError, () => { + AsyncContext.Snapshot.wrap(Symbol()); +}); + +assert.throws(TypeError, () => { + AsyncContext.Snapshot.wrap({}); +}); diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-length-throws.js b/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-length-throws.js new file mode 100644 index 00000000000..1fdf66ab023 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-length-throws.js @@ -0,0 +1,31 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.wrap +description: > + Throws if getting the argument's `length` property throws. +info: | + AsyncContext.Snapshot.wrap ( fn ) + + 4. Let length be ? LengthOfArrayLike(fn). + + LengthOfArrayLike ( obj ) + + 1. Return ℝ(? ToLength(? Get(obj, "length"))). + +features: [AsyncContext] +---*/ + +function CustomError() { } + +function callback() { } +Object.defineProperty(callback, 'length', { + get() { + throw new CustomError(); + } +}); + +assert.throws(CustomError, () => { + AsyncContext.Snapshot.wrap(callback); +}); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-name-throws.js b/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-name-throws.js new file mode 100644 index 00000000000..f018867dc25 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-name-throws.js @@ -0,0 +1,27 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.wrap +description: > + Throws if getting the argument's `name` property throws. +info: | + AsyncContext.Snapshot.wrap ( fn ) + + 5. Let name be ? Get(fn, "name"). + +features: [AsyncContext] +---*/ + +function CustomError() { } + +function callback() { } +Object.defineProperty(callback, 'name', { + get() { + throw new CustomError(); + } +}); + +assert.throws(CustomError, () => { + AsyncContext.Snapshot.wrap(callback); +}); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrap.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrap.js new file mode 100644 index 00000000000..588d4bf667e --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrap.js @@ -0,0 +1,23 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot-wrap +description: > + AsyncContext.Snapshot.wrap ( fn ) + + 17 ECMAScript Standard Built-in Objects + +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +assert.sameValue( + typeof AsyncContext.Snapshot.wrap, + 'function', + 'typeof AsyncContext.Snapshot.wrap is "function"' +); + +verifyNotEnumerable(AsyncContext.Snapshot, 'wrap'); +verifyWritable(AsyncContext.Snapshot, 'wrap'); +verifyConfigurable(AsyncContext.Snapshot, 'wrap'); diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback-in-snapshot.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback-in-snapshot.js new file mode 100644 index 00000000000..9b0ef02ea54 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback-in-snapshot.js @@ -0,0 +1,69 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.wrap +description: > + Stores the current snapshot and restores it when the returned callback is + called. +info: | + AsyncContext.Snapshot.wrap ( fn ) + + 2. Let snapshot be AsyncContextSnapshot(). + 3. Let closure be a new Abstract Closure with parameters (...args) that captures fn and snapshot and performs the following steps when called: + ... + b. Let previousContextMapping be AsyncContextSwap(snapshot). + c. Let result be Completion(Call(fn, thisArgument, args)). + ... + + AsyncContextSnapshot ( ) + + 1. Let agentRecord be the surrounding agent's Agent Record. + 2. Return agentRecord.[[AsyncContextMapping]]. + + AsyncContextSwap ( snapshotMapping ) + + 1. Let agentRecord be the surrounding agent's Agent Record. + 2. Let asyncContextMapping be agentRecord.[[AsyncContextMapping]]. + 3. Set agentRecord.[[AsyncContextMapping]] to snapshotMapping. + 4. Return asyncContextMapping. +features: [AsyncContext] +---*/ + +const asyncVar1 = new AsyncContext.Variable(); +const asyncVar2 = new AsyncContext.Variable(); +const asyncVar3 = new AsyncContext.Variable(); + +function originalFunction() { + assert.sameValue( + asyncVar1.get(), + "foo", + 'The value of `asyncVar1.get()` is `"foo"`' + ); + + assert.sameValue( + asyncVar2.get(), + "bar", + 'The value of `asyncVar2.get()` is `"bar"`' + ); + + assert.sameValue( + asyncVar3.get(), + "baz", + 'The value of `asyncVar3.get()` is `"baz"`' + ); +} + +let wrappedFunction; + +asyncVar1.run("foo", () => { + asyncVar2.run("bar", () => { + asyncVar3.run("baz", () => { + + wrappedFunction = AsyncContext.Snapshot.wrap(originalFunction); + + }); + }); +}); + +wrappedFunction(); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback-with-args.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback-with-args.js new file mode 100644 index 00000000000..db94b40433b --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback-with-args.js @@ -0,0 +1,28 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.wrap +description: > + The returned function calls the passed callback with the arguments passed to + the returned function. +info: | + AsyncContext.Snapshot.wrap ( fn ) + + 3. Let closure be a new Abstract Closure with parameters (...args) that captures fn and snapshot and performs the following steps when called: + ... + c. Let result be Completion(Call(fn, thisArgument, args)). + ... + 9. Return CreateBuiltinFunction(closure, length, name, « », realm, prototype, "wrapped"). +features: [AsyncContext] +---*/ + +function callback(a, b, c) { + assert.sameValue(a, 'foo', 'The first argument must be "foo".'); + assert.sameValue(b, 'bar', 'The second argument must be "bar".'); + assert.sameValue(c, 'baz', 'The second argument must be "baz".'); +} + +const wrapped = AsyncContext.Snapshot.wrap(callback); + +wrapped('foo', 'bar', 'baz'); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback-with-this.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback-with-this.js new file mode 100644 index 00000000000..2029bf74f62 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback-with-this.js @@ -0,0 +1,33 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.wrap +description: > + The returned function calls the passed callback with the this value that the + returned function was called with. +info: | + AsyncContext.Snapshot.wrap ( fn ) + + 3. Let closure be a new Abstract Closure with parameters (...args) that captures fn and snapshot and performs the following steps when called: + a. Let thisArgument be the this value. + ... + c. Let result be Completion(Call(fn, thisArgument, args)). + ... + 9. Return CreateBuiltinFunction(closure, length, name, « », realm, prototype, "wrapped"). +features: [AsyncContext] +---*/ + +const thisValue = {}; + +function callback() { + assert.sameValue( + this, + thisValue, + 'Callback is called with `thisValue` as its this value.' + ); +} + +const wrapped = AsyncContext.Snapshot.wrap(callback); + +wrapped.apply(thisValue); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback.js new file mode 100644 index 00000000000..0ce599e2ead --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback.js @@ -0,0 +1,29 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.wrap +description: > + The returned function calls the passed callback. +info: | + AsyncContext.Snapshot.wrap ( fn ) + + 3. Let closure be a new Abstract Closure with parameters (...args) that captures fn and snapshot and performs the following steps when called: + ... + c. Let result be Completion(Call(fn, thisArgument, args)). + ... + 9. Return CreateBuiltinFunction(closure, length, name, « », realm, prototype, "wrapped"). +features: [AsyncContext] +---*/ + +let timesCalled = 0; + +function callback() { + timesCalled++; +} + +const wrapped = AsyncContext.Snapshot.wrap(callback); + +wrapped(); + +assert.sameValue(timesCalled, 1, 'The callback must be called once.'); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/has-prototype-from-current-realm.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/has-prototype-from-current-realm.js new file mode 100644 index 00000000000..30ffcf90934 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/has-prototype-from-current-realm.js @@ -0,0 +1,37 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.wrap +description: > + The returned function's prototype is the current realm's %Function.prototype% + intrinsic. +info: | + AsyncContext.Snapshot.wrap ( fn ) + + 7. Let realm be the current Realm record. + 8. Let prototype be realm.[[Intrinsics]].[[%Function.prototype%]]. + 9. Return CreateBuiltinFunction(closure, length, name, « », realm, prototype, "wrapped"). + +features: [AsyncContext] +---*/ + +const realm1 = $262.createRealm(); +const realm2 = $262.createRealm(); +const realm3 = $262.createRealm(); + +const callback = realm1.evalScript( + "(function callback() { })" +); + +realm3.global.callback = callback; +realm3.global.wrap = realm2.global.AsyncContext.Snapshot.wrap; +const wrapped = realm3.evalScript( + "globalThis.wrap(globalThis.callback)" +); + +assert.sameValue( + Object.getPrototypeOf(wrapped), + realm2.global.Function.prototype, + 'The prototype of wrapped is realm2\'s %Function.prototype%' +); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/is-function.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/is-function.js new file mode 100644 index 00000000000..eca0823192f --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/is-function.js @@ -0,0 +1,28 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.wrap +description: > + Returns a function object. +info: | + AsyncContext.Snapshot.wrap ( fn ) + + 7. Let realm be the current Realm record. + 8. Let prototype be realm.[[Intrinsics]].[[%Function.prototype%]]. + 9. Return CreateBuiltinFunction(closure, length, name, « », realm, prototype, "wrapped"). + +features: [AsyncContext] +---*/ + +function callback() { } + +const wrapped = AsyncContext.Snapshot.wrap(callback); + +assert.sameValue(typeof wrapped, 'function', 'typeof wrapped is "function"'); + +assert.sameValue( + Object.getPrototypeOf(wrapped), + Function.prototype, + 'The prototype of wrapped is %Function.prototype%' +); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/length.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/length.js new file mode 100644 index 00000000000..a042a91f43a --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/length.js @@ -0,0 +1,83 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.wrap +description: > + Returned function's `length` property. +info: | + AsyncContext.Snapshot.wrap ( fn ) + + 4. Let length be ? LengthOfArrayLike(fn). + ... + 9. Return CreateBuiltinFunction(closure, length, name, « », realm, prototype, "wrapped"). + + LengthOfArrayLike ( obj ) + + 1. Return ℝ(? ToLength(? Get(obj, "length"))). + + CreateBuiltinFunction ( behaviour, length, name, additionalInternalSlotsList [ , realm [ , prototype [ , prefix ] ] ] ) + + 10. Perform SetFunctionLength(func, length). + ... + 13. Return func. + + SetFunctionLength ( F, length ) + + 2. Perform ! DefinePropertyOrThrow(F, "length", PropertyDescriptor { [[Value]]: 𝔽(length), [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }). + +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +function callback(_a, _b) { } + +function assertLength(expected) { + const wrapped = AsyncContext.Snapshot.wrap(callback); + verifyProperty(wrapped, 'length', { + value: expected, + writable: false, + enumerable: false, + configurable: true + }); +} + +function setAndAssertLength(lengthToSet, expected) { + Object.defineProperty(callback, 'length', { + value: lengthToSet, + writable: true, + enumerable: true, + configurable: true + }); + assertLength(expected); +} + +assertLength(callback.length); + +setAndAssertLength(0, 0); + +setAndAssertLength(42, 42); + +setAndAssertLength(-42, 0); + +setAndAssertLength(Number.POSITIVE_INFINITY, Number.MAX_SAFE_INTEGER); + +setAndAssertLength(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER); + +setAndAssertLength(Number.MAX_SAFE_INTEGER + 1, Number.MAX_SAFE_INTEGER); + +setAndAssertLength(Number.MAX_SAFE_INTEGER * 120, Number.MAX_SAFE_INTEGER); + +setAndAssertLength(Number.MAX_SAFE_INTEGER - 1, Number.MAX_SAFE_INTEGER - 1); + +setAndAssertLength(-0, 0); + +setAndAssertLength(Number.NaN, 0); + +setAndAssertLength(7.2, 7); + +setAndAssertLength(7.9, 7); + +setAndAssertLength(undefined, 0); + +setAndAssertLength("42", 42); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/name.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/name.js new file mode 100644 index 00000000000..c3ae9b0f1f3 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/name.js @@ -0,0 +1,81 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.wrap +description: > + Returned function's `name` property. +info: | + AsyncContext.Snapshot.wrap ( fn ) + + 5. Let name be ? Get(fn, "name"). + 6. If name is not a String, set name to the empty String. + ... + 9. Return CreateBuiltinFunction(closure, length, name, « », realm, prototype, "wrapped"). + + CreateBuiltinFunction ( behaviour, length, name, additionalInternalSlotsList [ , realm [ , prototype [ , prefix ] ] ] ) + + 11. If prefix is not present, then + ... + 12. Else, + a. Perform SetFunctionName(func, name, prefix). + 13. Return func. + + SetFunctionName ( F, name [ , prefix ] ) + + 5. If prefix is present, then + a. Set name to the string-concatenation of prefix, the code unit 0x0020 (SPACE), and name. + ... + 6. Perform ! DefinePropertyOrThrow(F, "name", PropertyDescriptor { [[Value]]: name, [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }). + +includes: [propertyHelper.js] +features: [AsyncContext] +---*/ + +function callback() { } + +function assertName(expected) { + const wrapped = AsyncContext.Snapshot.wrap(callback); + verifyProperty(wrapped, 'name', { + value: expected, + writable: false, + enumerable: false, + configurable: true + }); +} + +function setAndAssertName(nameToSet, expected) { + Object.defineProperty(callback, 'name', { + value: nameToSet, + writable: true, + enumerable: true, + configurable: true + }); + assertName(expected); +} + +assertName("wrapped callback"); + +setAndAssertName("foo", "wrapped foo"); + +setAndAssertName(42, "wrapped "); + +setAndAssertName(undefined, "wrapped "); + +delete callback.name; +assertName("wrapped "); + +setAndAssertName(Symbol(), "wrapped "); + +setAndAssertName(new String("foo"), "wrapped "); + +setAndAssertName({}, "wrapped "); + +setAndAssertName( + { + toString() { + assert(false, "The name's toString function must not be called."); + } + }, + "wrapped " +); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/not-a-constructor.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/not-a-constructor.js new file mode 100644 index 00000000000..2e69726246e --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/not-a-constructor.js @@ -0,0 +1,42 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.wrap +description: > + The returned function is not a constructor, even if the original callback is. +info: | + ECMAScript Function 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. + + sec-evaluatenew + + ... + 7. If IsConstructor(constructor) is false, throw a TypeError exception. + ... +includes: [isConstructor.js] +features: [Reflect.construct, AsyncContext, arrow-function] +---*/ + +function Constructor() { } + +// Constructor is indeed a constructor +new Constructor(); +assert.sameValue(isConstructor(Constructor), true, 'Constructor must be a constructor'); + +// Checking that the function returned by wrap is not one. +const wrapped = AsyncContext.Snapshot.wrap(Constructor); + +assert.sameValue( + isConstructor(AsyncContext.Snapshot.wrap), + false, + 'isConstructor(wrapped) must return false' +); + +assert.throws(TypeError, () => { + new wrapped(); +}, '`new wrapped()` throws TypeError'); + diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/restores-previous-context-snapshot-after-callback-throw.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/restores-previous-context-snapshot-after-callback-throw.js new file mode 100644 index 00000000000..964eac8acf0 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/restores-previous-context-snapshot-after-callback-throw.js @@ -0,0 +1,56 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.wrap +description: > + Switches back into the context snapshot active at the time of calling the + wrapped function, after it calls the original callback, even if it throws an + exception. +info: | + AsyncContext.Snapshot.wrap ( fn ) + + 3. Let closure be a new Abstract Closure with parameters (...args) that captures fn and snapshot and performs the following steps when called: + ... + b. Let previousContextMapping be AsyncContextSwap(snapshot). + c. Let result be Completion(Call(fn, thisArgument, args)). + d. AsyncContextSwap(previousContextMapping). + ... + 9. Return CreateBuiltinFunction(closure, length, name, « », realm, prototype, "wrapped"). + + AsyncContextSwap ( snapshotMapping ) + + 1. Let agentRecord be the surrounding agent's Agent Record. + 2. Let asyncContextMapping be agentRecord.[[AsyncContextMapping]]. + 3. Set agentRecord.[[AsyncContextMapping]] to snapshotMapping. + 4. Return asyncContextMapping. +features: [AsyncContext] +---*/ + +function CustomError() { } + +const asyncVar = new AsyncContext.Variable(); + +const wrapped = asyncVar.run(42, () => { + return AsyncContext.Snapshot.wrap(() => { + throw new CustomError(); + }); +}); + +asyncVar.run("foo", () => { + + try { + wrapped(); + } catch (e) { + if (!(e instanceof CustomError)) { + throw e; + } + } + + assert.sameValue( + asyncVar.get(), + "foo", + 'The value of `asyncVar.get()` should be `"foo"`' + ); + +}); diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/restores-previous-context-snapshot-after-callback.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/restores-previous-context-snapshot-after-callback.js new file mode 100644 index 00000000000..036cfe97107 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/restores-previous-context-snapshot-after-callback.js @@ -0,0 +1,64 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.wrap +description: > + Switches back into the context snapshot active at the time of calling the + wrapped function, after it calls the original callback. +info: | + AsyncContext.Snapshot.wrap ( fn ) + + 3. Let closure be a new Abstract Closure with parameters (...args) that captures fn and snapshot and performs the following steps when called: + ... + b. Let previousContextMapping be AsyncContextSwap(snapshot). + c. Let result be Completion(Call(fn, thisArgument, args)). + d. AsyncContextSwap(previousContextMapping). + ... + 9. Return CreateBuiltinFunction(closure, length, name, « », realm, prototype, "wrapped"). + + AsyncContextSwap ( snapshotMapping ) + + 1. Let agentRecord be the surrounding agent's Agent Record. + 2. Let asyncContextMapping be agentRecord.[[AsyncContextMapping]]. + 3. Set agentRecord.[[AsyncContextMapping]] to snapshotMapping. + 4. Return asyncContextMapping. +features: [AsyncContext] +---*/ + +const asyncVar1 = new AsyncContext.Variable(); +const asyncVar2 = new AsyncContext.Variable(); + +const wrapped = asyncVar1.run(42, () => { + return AsyncContext.Snapshot.wrap(() => { }); +}); + +const asyncVar3 = new AsyncContext.Variable(); + +asyncVar1.run("foo", () => { + asyncVar2.run("bar", () => { + asyncVar3.run("baz", () => { + + wrapped(); + + assert.sameValue( + asyncVar1.get(), + "foo", + 'The value of `asyncVar1.get()` is `"foo"`' + ); + + assert.sameValue( + asyncVar2.get(), + "bar", + 'The value of `asyncVar2.get()` is `"bar"`' + ); + + assert.sameValue( + asyncVar3.get(), + "baz", + 'The value of `asyncVar3.get()` is `"baz"`' + ); + + }); + }); +}); diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/restores-snapshot.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/restores-snapshot.js new file mode 100644 index 00000000000..6c1334326d1 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/restores-snapshot.js @@ -0,0 +1,65 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.wrap +description: > + Calling the returned function restores the snapshot active when wrap was + called. +info: | + AsyncContext.Snapshot.wrap ( fn ) + + 2. Let snapshot be AsyncContextSnapshot(). + 3. Let closure be a new Abstract Closure with parameters (...args) that captures fn and snapshot and performs the following steps when called: + ... + b. Let previousContextMapping be AsyncContextSwap(snapshot). + c. Let result be Completion(Call(fn, thisArgument, args)). + ... + 9. Return CreateBuiltinFunction(closure, length, name, « », realm, prototype, "wrapped"). + + AsyncContextSwap ( snapshotMapping ) + + 1. Let agentRecord be the surrounding agent's Agent Record. + 2. Let asyncContextMapping be agentRecord.[[AsyncContextMapping]]. + 3. Set agentRecord.[[AsyncContextMapping]] to snapshotMapping. + 4. Return asyncContextMapping. +features: [AsyncContext] +---*/ + +const asyncVar1 = new AsyncContext.Variable(); +const asyncVar2 = new AsyncContext.Variable(); +const asyncVar3 = new AsyncContext.Variable(); + +function callback() { + assert.sameValue( + asyncVar1.get(), + "foo", + 'The value of `asyncVar1.get()` is `"foo"`' + ); + + assert.sameValue( + asyncVar2.get(), + "bar", + 'The value of `asyncVar2.get()` is `"bar"`' + ); + + assert.sameValue( + asyncVar3.get(), + "baz", + 'The value of `asyncVar3.get()` is `"baz"`' + ); +} + +let wrapped; + +asyncVar1.run("foo", () => { + asyncVar2.run("bar", () => { + asyncVar3.run("baz", () => { + + wrapped = AsyncContext.Snapshot.wrap(callback); + + }); + }); +}); + +wrapped(); diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/restores-unset-variables.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/restores-unset-variables.js new file mode 100644 index 00000000000..5162e9884f2 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/restores-unset-variables.js @@ -0,0 +1,94 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.wrap +description: > + For any AsyncContext.Variable objects that were unset when wrap was called, + and that were set in the current snapshot at the time of calling the wrapped + function, they are unset in the context inside the callback. + + This happens even for AsyncContext.Variable instances that were did not yet + exist when the AsyncContext.Snapshot was created. +info: | + AsyncContext.Snapshot.wrap ( fn ) + + 2. Let snapshot be AsyncContextSnapshot(). + 3. Let closure be a new Abstract Closure with parameters (...args) that captures fn and snapshot and performs the following steps when called: + ... + b. Let previousContextMapping be AsyncContextSwap(snapshot). + c. Let result be Completion(Call(fn, thisArgument, args)). + ... + 9. Return CreateBuiltinFunction(closure, length, name, « », realm, prototype, "wrapped"). + + AsyncContextSwap ( snapshotMapping ) + + 1. Let agentRecord be the surrounding agent's Agent Record. + 2. Let asyncContextMapping be agentRecord.[[AsyncContextMapping]]. + 3. Set agentRecord.[[AsyncContextMapping]] to snapshotMapping. + 4. Return asyncContextMapping. +features: [AsyncContext] +---*/ + +const symbol = Symbol(); + +const asyncVar1 = new AsyncContext.Variable(); +const asyncVar2 = new AsyncContext.Variable({ defaultValue: symbol }); +const asyncVar3 = new AsyncContext.Variable(); + +// Will only be constructed after calling `wrap`. +let newAsyncVar1; +let newAsyncVar2; + +function callback() { + assert.sameValue( + asyncVar1.get(), + "foo", + 'The value of `asyncVar1.get()` is `"foo"`' + ); + + assert.sameValue( + asyncVar2.get(), + symbol, + 'The value of `asyncVar2.get()` is `symbol`' + ); + + assert.sameValue( + asyncVar3.get(), + undefined, + 'The value of `asyncVar3.get()` is `"undefined`' + ); + + assert.sameValue( + newAsyncVar1.get(), + symbol, + 'The value of `newAsyncVar1.get()` is `symbol`' + ); + + assert.sameValue( + newAsyncVar2.get(), + undefined, + 'The value of `newAsyncVar2.get()` is `"undefined`' + ); +} + +let wrapped; + +asyncVar1.run("foo", () => { + wrapped = AsyncContext.Snapshot.wrap(callback); +}); + +newAsyncVar1 = new AsyncContext.Variable({ defaultValue: symbol }); +newAsyncVar2 = new AsyncContext.Variable(); + +asyncVar2.run("bar", () => { + asyncVar3.run("baz", () => { + newAsyncVar1.run("fizz", () => { + newAsyncVar2.run("buzz", () => { + + wrapped(); + + }); + }); + }); +}); diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/returned-promise-does-not-resolve-in-snapshot.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/returned-promise-does-not-resolve-in-snapshot.js new file mode 100644 index 00000000000..ac986f1e0cf --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/returned-promise-does-not-resolve-in-snapshot.js @@ -0,0 +1,39 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.wrap +description: > + When the function returns a promise, the async context snapshot when the + promise resolves will not be the wrapped snapshot. +info: | + TODO +flags: [async] +features: [AsyncContext] +---*/ + +const asyncVar = new AsyncContext.Variable(); + +let resolve; + +async function callback() { + assert.sameValue(asyncVar.get(), "bar"); + + await new Promise(resolveFn => { + resolve = resolveFn; + }); + + assert.sameValue(asyncVar.get(), "bar"); +} + +const wrapped = asyncVar.run("bar", () => AsyncContext.Snapshot.wrap(callback)); + +asyncVar.run("foo", () => { + + wrapped().then(() => { + assert.sameValue(asyncVar.get(), "foo"); + }).then($DONE, $DONE); + +}); + +resolve(); diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/returns-async-callback-return-value.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/returns-async-callback-return-value.js new file mode 100644 index 00000000000..9ae2507a6a8 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/returns-async-callback-return-value.js @@ -0,0 +1,36 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.wrap +description: > + If the passed callback is an async function, the returned function calls it + and returns its return value, which is a promise. +info: | + AsyncContext.Snapshot.wrap ( fn ) + + 3. Let closure be a new Abstract Closure with parameters (...args) that captures fn and snapshot and performs the following steps when called: + ... + c. Let result be Completion(Call(fn, thisArgument, args)). + ... + e. Return result. + ... + 9. Return CreateBuiltinFunction(closure, length, name, « », realm, prototype, "wrapped"). +flags: [async] +includes: [asyncHelpers.js] +features: [AsyncContext] +---*/ + +const obj = {}; + +const wrapped = AsyncContext.Snapshot.wrap(async () => obj); + +asyncTest(async function () { + const ret = wrapped(); + assert( + ret instanceof Promise, + 'The return value of `wrapped()` is a promise' + ); + + assert.sameValue(await ret, obj, '`ret` resolves to `obj`'); +}); diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/returns-callback-return-value.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/returns-callback-return-value.js new file mode 100644 index 00000000000..274773b3861 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/returns-callback-return-value.js @@ -0,0 +1,27 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.wrap +description: > + The returned function returns the value the passed callback returns. +info: | + AsyncContext.Snapshot.wrap ( fn ) + + 3. Let closure be a new Abstract Closure with parameters (...args) that captures fn and snapshot and performs the following steps when called: + ... + c. Let result be Completion(Call(fn, thisArgument, args)). + ... + e. Return result. + ... + 9. Return CreateBuiltinFunction(closure, length, name, « », realm, prototype, "wrapped"). +features: [AsyncContext] +---*/ + +function callback() { + return 42; +} + +const wrapped = AsyncContext.Snapshot.wrap(callback); + +assert.sameValue(wrapped(), 42, 'The callback must return 42.'); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/throws-if-callback-throws.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/throws-if-callback-throws.js new file mode 100644 index 00000000000..dd4f4ebd4ba --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/throws-if-callback-throws.js @@ -0,0 +1,29 @@ +// Copyright (C) 2023 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.wrap +description: > + The returned function throws if the callback throws, with the same thrown + value. +info: | + AsyncContext.Snapshot.wrap ( fn ) + + 3. Let closure be a new Abstract Closure with parameters (...args) that captures fn and snapshot and performs the following steps when called: + c. Let result be Completion(Call(fn, thisArgument, args)). + ... + e. Return result. + ... + 9. Return CreateBuiltinFunction(closure, length, name, « », realm, prototype, "wrapped"). +features: [AsyncContext] +---*/ + +function CustomError() { } + +const wrapped = AsyncContext.Snapshot.wrap(() => { + throw new CustomError(); +}); + +assert.throws(CustomError, () => { + wrapped(); +}); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Variable/prototype/run/returned-promise-does-not-resolve-in-snapshot.js b/test/built-ins/AsyncContext/Variable/prototype/run/returned-promise-does-not-resolve-in-snapshot.js index 981bd4a8758..60912444bbe 100644 --- a/test/built-ins/AsyncContext/Variable/prototype/run/returned-promise-does-not-resolve-in-snapshot.js +++ b/test/built-ins/AsyncContext/Variable/prototype/run/returned-promise-does-not-resolve-in-snapshot.js @@ -16,16 +16,20 @@ const asyncVar = new AsyncContext.Variable(); let resolve; -asyncVar.run("foo", async () => { - assert.sameValue(asyncVar.get(), "foo"); +asyncVar.run("foo", () => { - await new Promise(resolveFn => { - resolve = resolveFn; - }); + asyncVar.run("bar", async () => { + assert.sameValue(asyncVar.get(), "bar"); - assert.sameValue(asyncVar.get(), "foo"); -}).then(() => { - assert.sameValue(asyncVar.get(), undefined); -}).then($DONE, $DONE); + await new Promise(resolveFn => { + resolve = resolveFn; + }); + + assert.sameValue(asyncVar.get(), "bar"); + }).then(() => { + assert.sameValue(asyncVar.get(), "foo"); + }).then($DONE, $DONE); + +}); resolve(); From 2b7cfeb89f91bfbae69d7b6f34f3c0f4658e003d Mon Sep 17 00:00:00 2001 From: Andreu Botella Date: Fri, 23 Feb 2024 23:06:49 +0100 Subject: [PATCH 13/16] Fix lint errors --- .../Snapshot/wrap/throws-if-callback-length-throws.js | 2 +- .../Snapshot/wrap/throws-if-callback-name-throws.js | 2 +- .../wrap/wrapped-function/calls-callback-in-snapshot.js | 2 +- .../Snapshot/wrap/wrapped-function/calls-callback-with-args.js | 2 +- .../Snapshot/wrap/wrapped-function/calls-callback-with-this.js | 2 +- .../Snapshot/wrap/wrapped-function/calls-callback.js | 2 +- .../wrap/wrapped-function/has-prototype-from-current-realm.js | 2 +- .../AsyncContext/Snapshot/wrap/wrapped-function/is-function.js | 2 +- .../AsyncContext/Snapshot/wrap/wrapped-function/length.js | 2 +- .../AsyncContext/Snapshot/wrap/wrapped-function/name.js | 2 +- .../Snapshot/wrap/wrapped-function/not-a-constructor.js | 1 - .../wrap/wrapped-function/returns-callback-return-value.js | 2 +- .../Snapshot/wrap/wrapped-function/throws-if-callback-throws.js | 2 +- 13 files changed, 12 insertions(+), 13 deletions(-) diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-length-throws.js b/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-length-throws.js index 1fdf66ab023..0d9a97a7379 100644 --- a/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-length-throws.js +++ b/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-length-throws.js @@ -28,4 +28,4 @@ Object.defineProperty(callback, 'length', { assert.throws(CustomError, () => { AsyncContext.Snapshot.wrap(callback); -}); \ No newline at end of file +}); diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-name-throws.js b/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-name-throws.js index f018867dc25..811964de92d 100644 --- a/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-name-throws.js +++ b/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-name-throws.js @@ -24,4 +24,4 @@ Object.defineProperty(callback, 'name', { assert.throws(CustomError, () => { AsyncContext.Snapshot.wrap(callback); -}); \ No newline at end of file +}); diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback-in-snapshot.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback-in-snapshot.js index 9b0ef02ea54..66c79c380d2 100644 --- a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback-in-snapshot.js +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback-in-snapshot.js @@ -66,4 +66,4 @@ asyncVar1.run("foo", () => { }); }); -wrappedFunction(); \ No newline at end of file +wrappedFunction(); diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback-with-args.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback-with-args.js index db94b40433b..a9f0058b64d 100644 --- a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback-with-args.js +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback-with-args.js @@ -25,4 +25,4 @@ function callback(a, b, c) { const wrapped = AsyncContext.Snapshot.wrap(callback); -wrapped('foo', 'bar', 'baz'); \ No newline at end of file +wrapped('foo', 'bar', 'baz'); diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback-with-this.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback-with-this.js index 2029bf74f62..151cee1f4ff 100644 --- a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback-with-this.js +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback-with-this.js @@ -30,4 +30,4 @@ function callback() { const wrapped = AsyncContext.Snapshot.wrap(callback); -wrapped.apply(thisValue); \ No newline at end of file +wrapped.apply(thisValue); diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback.js index 0ce599e2ead..edfaf7010cc 100644 --- a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback.js +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/calls-callback.js @@ -26,4 +26,4 @@ const wrapped = AsyncContext.Snapshot.wrap(callback); wrapped(); -assert.sameValue(timesCalled, 1, 'The callback must be called once.'); \ No newline at end of file +assert.sameValue(timesCalled, 1, 'The callback must be called once.'); diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/has-prototype-from-current-realm.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/has-prototype-from-current-realm.js index 30ffcf90934..0e64ba88306 100644 --- a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/has-prototype-from-current-realm.js +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/has-prototype-from-current-realm.js @@ -34,4 +34,4 @@ assert.sameValue( Object.getPrototypeOf(wrapped), realm2.global.Function.prototype, 'The prototype of wrapped is realm2\'s %Function.prototype%' -); \ No newline at end of file +); diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/is-function.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/is-function.js index eca0823192f..bf440cdacf8 100644 --- a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/is-function.js +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/is-function.js @@ -25,4 +25,4 @@ assert.sameValue( Object.getPrototypeOf(wrapped), Function.prototype, 'The prototype of wrapped is %Function.prototype%' -); \ No newline at end of file +); diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/length.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/length.js index a042a91f43a..cd095052ceb 100644 --- a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/length.js +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/length.js @@ -80,4 +80,4 @@ setAndAssertLength(7.9, 7); setAndAssertLength(undefined, 0); -setAndAssertLength("42", 42); \ No newline at end of file +setAndAssertLength("42", 42); diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/name.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/name.js index c3ae9b0f1f3..b997e22ba84 100644 --- a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/name.js +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/name.js @@ -78,4 +78,4 @@ setAndAssertName( } }, "wrapped " -); \ No newline at end of file +); diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/not-a-constructor.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/not-a-constructor.js index 2e69726246e..a131bfd970a 100644 --- a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/not-a-constructor.js +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/not-a-constructor.js @@ -39,4 +39,3 @@ assert.sameValue( assert.throws(TypeError, () => { new wrapped(); }, '`new wrapped()` throws TypeError'); - diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/returns-callback-return-value.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/returns-callback-return-value.js index 274773b3861..b842fc65248 100644 --- a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/returns-callback-return-value.js +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/returns-callback-return-value.js @@ -24,4 +24,4 @@ function callback() { const wrapped = AsyncContext.Snapshot.wrap(callback); -assert.sameValue(wrapped(), 42, 'The callback must return 42.'); \ No newline at end of file +assert.sameValue(wrapped(), 42, 'The callback must return 42.'); diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/throws-if-callback-throws.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/throws-if-callback-throws.js index dd4f4ebd4ba..47ef2484aae 100644 --- a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/throws-if-callback-throws.js +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/throws-if-callback-throws.js @@ -26,4 +26,4 @@ const wrapped = AsyncContext.Snapshot.wrap(() => { assert.throws(CustomError, () => { wrapped(); -}); \ No newline at end of file +}); From 60385ae5e3f738c09bc0013b9fc55460057946b0 Mon Sep 17 00:00:00 2001 From: Andreu Botella Date: Wed, 6 Mar 2024 15:56:52 +0100 Subject: [PATCH 14/16] Update FinalizationRegistry test to construction time --- .../AsyncContext/context-propagation/FinalizationRegistry.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/built-ins/AsyncContext/context-propagation/FinalizationRegistry.js b/test/built-ins/AsyncContext/context-propagation/FinalizationRegistry.js index c50f5ee29f1..518e4e73fab 100644 --- a/test/built-ins/AsyncContext/context-propagation/FinalizationRegistry.js +++ b/test/built-ins/AsyncContext/context-propagation/FinalizationRegistry.js @@ -13,13 +13,13 @@ features: [AsyncContext, FinalizationRegistry, host-gc-required] ---*/ // TODO: This test tests the behavior in -// https://github.com/tc39/proposal-async-context/pull/61 +// https://github.com/tc39/proposal-async-context/pull/69 const asyncVar = new AsyncContext.Variable(); function cleanupCallback() { try { - assert.sameValue(asyncVar.get(), "bar"); + assert.sameValue(asyncVar.get(), "foo"); $DONE(); } catch (err) { $DONE(err); From b4801be61e35dc0e6f019738ef2833e6b826dc3f Mon Sep 17 00:00:00 2001 From: Andreu Botella Date: Wed, 6 Mar 2024 21:01:05 +0100 Subject: [PATCH 15/16] Remove todo now that tc39/proposal-async-context#69 is merged --- .../AsyncContext/context-propagation/FinalizationRegistry.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/built-ins/AsyncContext/context-propagation/FinalizationRegistry.js b/test/built-ins/AsyncContext/context-propagation/FinalizationRegistry.js index 518e4e73fab..7a13f720a09 100644 --- a/test/built-ins/AsyncContext/context-propagation/FinalizationRegistry.js +++ b/test/built-ins/AsyncContext/context-propagation/FinalizationRegistry.js @@ -12,9 +12,6 @@ flags: [async, non-deterministic] features: [AsyncContext, FinalizationRegistry, host-gc-required] ---*/ -// TODO: This test tests the behavior in -// https://github.com/tc39/proposal-async-context/pull/69 - const asyncVar = new AsyncContext.Variable(); function cleanupCallback() { From f356f3cea2308f4d5fe155141a4e2afe8c319e3e Mon Sep 17 00:00:00 2001 From: Andreu Botella Date: Fri, 3 May 2024 12:53:33 +0200 Subject: [PATCH 16/16] Update tests for wrap's name and length properties to match tc39/proposal-async-context#86 --- ...-if-callback-name-getownproperty-throws.js | 35 +++++++++ ...inherited-callback-length-getter-throws.js | 34 +++++++++ ...f-callback-length-getownproperty-throws.js | 34 +++++++++ ...f-inherited-callback-name-getter-throws.js | 34 +++++++++ ...s-if-own-callback-length-getter-throws.js} | 11 ++- ...ows-if-own-callback-name-getter-throws.js} | 9 ++- .../Snapshot/wrap/wrapped-function/length.js | 75 ++++++++++++++----- .../Snapshot/wrap/wrapped-function/name.js | 24 +++--- 8 files changed, 221 insertions(+), 35 deletions(-) create mode 100644 test/built-ins/AsyncContext/Snapshot/wrap/does-not-throw-if-callback-name-getownproperty-throws.js create mode 100644 test/built-ins/AsyncContext/Snapshot/wrap/does-not-throw-if-inherited-callback-length-getter-throws.js create mode 100644 test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-length-getownproperty-throws.js create mode 100644 test/built-ins/AsyncContext/Snapshot/wrap/throws-if-inherited-callback-name-getter-throws.js rename test/built-ins/AsyncContext/Snapshot/wrap/{throws-if-callback-length-throws.js => throws-if-own-callback-length-getter-throws.js} (57%) rename test/built-ins/AsyncContext/Snapshot/wrap/{throws-if-callback-name-throws.js => throws-if-own-callback-name-getter-throws.js} (65%) diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/does-not-throw-if-callback-name-getownproperty-throws.js b/test/built-ins/AsyncContext/Snapshot/wrap/does-not-throw-if-callback-name-getownproperty-throws.js new file mode 100644 index 00000000000..8564641c964 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/wrap/does-not-throw-if-callback-name-getownproperty-throws.js @@ -0,0 +1,35 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.wrap +description: > + Does not throw if calling HasOwnProperty on the argument's `name` + property throws. +info: | + AsyncContext.Snapshot.wrap ( fn ) + + 5. Perform ? CopyNameAndLength(wrapped, fn, "wrapped"). + + CopyNameAndLength ( F, Target[, prefix[, argCount ] ] ) + + 6. Let targetName be ? Get(Target, "name"). + +features: [AsyncContext] +---*/ + +function CustomError() { } + +function originalCallback() { } + +const proxyCallback = new Proxy(originalCallback, { + getOwnPropertyDescriptor(target, property) { + assert.sameValue(target, originalCallback); + if (property === 'length') { + return Object.getOwnPropertyDescriptor(originalCallback, 'length'); + } + throw new CustomError(); + } +}); + +AsyncContext.Snapshot.wrap(proxyCallback); diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/does-not-throw-if-inherited-callback-length-getter-throws.js b/test/built-ins/AsyncContext/Snapshot/wrap/does-not-throw-if-inherited-callback-length-getter-throws.js new file mode 100644 index 00000000000..5c2a5ea8162 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/wrap/does-not-throw-if-inherited-callback-length-getter-throws.js @@ -0,0 +1,34 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.wrap +description: > + Does not throw if getting the argument's `length` property throws, + if the property is inherited. +info: | + AsyncContext.Snapshot.wrap ( fn ) + + 5. Perform ? CopyNameAndLength(wrapped, fn, "wrapped"). + + CopyNameAndLength ( F, Target[, prefix[, argCount ] ] ) + + 3. Let targetHasLength be ? HasOwnProperty(Target, "length"). + 4. If targetHasLength is true, then + a. Let targetLen be ? Get(Target, "length"). + +features: [AsyncContext] +---*/ + +function CustomError() { } + +function callback() { } +delete callback.name; + +Object.setPrototypeOf(callback, { + get length() { + throw new CustomError(); + } +}); + +AsyncContext.Snapshot.wrap(callback); diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-length-getownproperty-throws.js b/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-length-getownproperty-throws.js new file mode 100644 index 00000000000..56e160fdec1 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-length-getownproperty-throws.js @@ -0,0 +1,34 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.wrap +description: > + Throws if calling HasOwnProperty on the argument's `length` property throws. +info: | + AsyncContext.Snapshot.wrap ( fn ) + + 5. Perform ? CopyNameAndLength(wrapped, fn, "wrapped"). + + CopyNameAndLength ( F, Target[, prefix[, argCount ] ] ) + + 3. Let targetHasLength be ? HasOwnProperty(Target, "length"). + +features: [AsyncContext] +---*/ + +function CustomError() { } + +function originalCallback() { } + +const proxyCallback = new Proxy(originalCallback, { + getOwnPropertyDescriptor(target, property) { + assert.sameValue(target, originalCallback); + assert.sameValue(property, 'length'); + throw new CustomError(); + } +}); + +assert.throws(CustomError, () => { + AsyncContext.Snapshot.wrap(proxyCallback); +}); diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-inherited-callback-name-getter-throws.js b/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-inherited-callback-name-getter-throws.js new file mode 100644 index 00000000000..968b9fcbe64 --- /dev/null +++ b/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-inherited-callback-name-getter-throws.js @@ -0,0 +1,34 @@ +// Copyright (C) 2024 Igalia, S. L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-asynccontext-snapshot.wrap +description: > + Throws if getting the argument's `length` property throws, if the + property is inherited. +info: | + AsyncContext.Snapshot.wrap ( fn ) + + 5. Perform ? CopyNameAndLength(wrapped, fn, "wrapped"). + + CopyNameAndLength ( F, Target[, prefix[, argCount ] ] ) + + 6. Let targetName be ? Get(Target, "name"). + +features: [AsyncContext] +---*/ + +function CustomError() { } + +function callback() { } +delete callback.name; + +Object.setPrototypeOf(callback, { + get name() { + throw new CustomError(); + } +}); + +assert.throws(CustomError, () => { + AsyncContext.Snapshot.wrap(callback); +}); diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-length-throws.js b/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-own-callback-length-getter-throws.js similarity index 57% rename from test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-length-throws.js rename to test/built-ins/AsyncContext/Snapshot/wrap/throws-if-own-callback-length-getter-throws.js index 0d9a97a7379..e97f4d378ea 100644 --- a/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-length-throws.js +++ b/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-own-callback-length-getter-throws.js @@ -4,15 +4,18 @@ /*--- esid: sec-asynccontext-snapshot.wrap description: > - Throws if getting the argument's `length` property throws. + Throws if getting the argument's `length` property throws, if it is + an own property. info: | AsyncContext.Snapshot.wrap ( fn ) - 4. Let length be ? LengthOfArrayLike(fn). + 5. Perform ? CopyNameAndLength(wrapped, fn, "wrapped"). - LengthOfArrayLike ( obj ) + CopyNameAndLength ( F, Target[, prefix[, argCount ] ] ) - 1. Return ℝ(? ToLength(? Get(obj, "length"))). + 3. Let targetHasLength be ? HasOwnProperty(Target, "length"). + 4. If targetHasLength is true, then + a. Let targetLen be ? Get(Target, "length"). features: [AsyncContext] ---*/ diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-name-throws.js b/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-own-callback-name-getter-throws.js similarity index 65% rename from test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-name-throws.js rename to test/built-ins/AsyncContext/Snapshot/wrap/throws-if-own-callback-name-getter-throws.js index 811964de92d..c5f6c328e3d 100644 --- a/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-callback-name-throws.js +++ b/test/built-ins/AsyncContext/Snapshot/wrap/throws-if-own-callback-name-getter-throws.js @@ -4,11 +4,16 @@ /*--- esid: sec-asynccontext-snapshot.wrap description: > - Throws if getting the argument's `name` property throws. + Throws if getting the argument's `name` property throws, if it is + an own property. info: | AsyncContext.Snapshot.wrap ( fn ) - 5. Let name be ? Get(fn, "name"). + 5. Perform ? CopyNameAndLength(wrapped, fn, "wrapped"). + + CopyNameAndLength ( F, Target[, prefix[, argCount ] ] ) + + 6. Let targetName be ? Get(Target, "name"). features: [AsyncContext] ---*/ diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/length.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/length.js index cd095052ceb..4dcd8826fc9 100644 --- a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/length.js +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/length.js @@ -8,19 +8,33 @@ description: > info: | AsyncContext.Snapshot.wrap ( fn ) - 4. Let length be ? LengthOfArrayLike(fn). - ... - 9. Return CreateBuiltinFunction(closure, length, name, « », realm, prototype, "wrapped"). - - LengthOfArrayLike ( obj ) - - 1. Return ℝ(? ToLength(? Get(obj, "length"))). - - CreateBuiltinFunction ( behaviour, length, name, additionalInternalSlotsList [ , realm [ , prototype [ , prefix ] ] ] ) - - 10. Perform SetFunctionLength(func, length). - ... - 13. Return func. + 5. Perform ? CopyNameAndLength(wrapped, fn, "wrapped"). + + CopyNameAndLength ( F, Target[, prefix[, argCount ] ] ) + + 1. If argCount is not present, set argCount to 0. + 2. Let L be 0. + 3. Let targetHasLength be ? HasOwnProperty(Target, "length"). + 4. If targetHasLength is true, then + a. Let targetLen be ? Get(Target, "length"). + b. If targetLen is a Number, then + i. If targetLen is +∞𝔽, then + 1. Set L to +∞. + ii. Else if targetLen is -∞𝔽, then + 1. Set L to 0. + iii. Else, + 1. Let targetLenAsInt be ! ToIntegerOrInfinity(targetLen). + 2. Assert: targetLenAsInt is finite. + 3. Set L to max(targetLenAsInt - argCount, 0). + 5. Perform SetFunctionLength(F, L). + + ToIntegerOrInfinity ( argument ) + + 1. Let number be ? ToNumber(argument). + 2. If number is one of NaN, +0𝔽, or -0𝔽, return 0. + 3. If number is +∞𝔽, return +∞. + 4. If number is -∞𝔽, return -∞. + 5. Return truncate(ℝ(number)). SetFunctionLength ( F, length ) @@ -60,17 +74,17 @@ setAndAssertLength(42, 42); setAndAssertLength(-42, 0); -setAndAssertLength(Number.POSITIVE_INFINITY, Number.MAX_SAFE_INTEGER); +setAndAssertLength(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY); setAndAssertLength(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER); -setAndAssertLength(Number.MAX_SAFE_INTEGER + 1, Number.MAX_SAFE_INTEGER); +setAndAssertLength(Number.MAX_SAFE_INTEGER * 120, Number.MAX_SAFE_INTEGER * 120); -setAndAssertLength(Number.MAX_SAFE_INTEGER * 120, Number.MAX_SAFE_INTEGER); +setAndAssertLength(-0, 0); -setAndAssertLength(Number.MAX_SAFE_INTEGER - 1, Number.MAX_SAFE_INTEGER - 1); +setAndAssertLength(-0.2, 0); -setAndAssertLength(-0, 0); +setAndAssertLength(Number.NEGATIVE_INFINITY, 0); setAndAssertLength(Number.NaN, 0); @@ -80,4 +94,27 @@ setAndAssertLength(7.9, 7); setAndAssertLength(undefined, 0); -setAndAssertLength("42", 42); +setAndAssertLength("42", 0); + +setAndAssertLength(Symbol(), 0); + +setAndAssertLength(42n, 0); + +setAndAssertLength(new Number(42), 0); + +setAndAssertLength({ + valueOf() { + return 42; + } +}, 0); + +delete callback.length; +assertLength(0); + +// Inherited length is ignored +Object.defineProperty( + Object.getPrototypeOf(callback), + "length", + { value: 2 } +); +assertLength(0); \ No newline at end of file diff --git a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/name.js b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/name.js index b997e22ba84..a9d0c408305 100644 --- a/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/name.js +++ b/test/built-ins/AsyncContext/Snapshot/wrap/wrapped-function/name.js @@ -8,18 +8,15 @@ description: > info: | AsyncContext.Snapshot.wrap ( fn ) - 5. Let name be ? Get(fn, "name"). - 6. If name is not a String, set name to the empty String. - ... - 9. Return CreateBuiltinFunction(closure, length, name, « », realm, prototype, "wrapped"). + 5. Perform ? CopyNameAndLength(wrapped, fn, "wrapped"). - CreateBuiltinFunction ( behaviour, length, name, additionalInternalSlotsList [ , realm [ , prototype [ , prefix ] ] ] ) + CopyNameAndLength ( F, Target[, prefix[, argCount ] ] ) - 11. If prefix is not present, then - ... - 12. Else, - a. Perform SetFunctionName(func, name, prefix). - 13. Return func. + 6. Let targetName be ? Get(Target, "name"). + 7. If targetName is not a String, set targetName to the empty String. + 8. If prefix is present, then + a. Perform SetFunctionName(F, targetName, prefix). + ... SetFunctionName ( F, name [ , prefix ] ) @@ -65,6 +62,13 @@ setAndAssertName(undefined, "wrapped "); delete callback.name; assertName("wrapped "); +Object.defineProperty( + Object.getPrototypeOf(callback), + "name", + { value: "inherited" } +); +assertName("wrapped inherited"); + setAndAssertName(Symbol(), "wrapped "); setAndAssertName(new String("foo"), "wrapped ");