diff --git a/test/built-ins/DisposableStack/prototype/Symbol.toStringTag.js b/test/built-ins/DisposableStack/prototype/Symbol.toStringTag.js new file mode 100644 index 0000000000..b7b27c997d --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/Symbol.toStringTag.js @@ -0,0 +1,23 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype-@@toStringTag +description: > + `Symbol.toStringTag` property descriptor +info: | + The initial value of the @@toStringTag property is the String value + 'DisposableStack'. + + This property has the attributes { [[Writable]]: false, [[Enumerable]]: + false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [explicit-resource-management, Symbol, Symbol.toStringTag] +---*/ + +verifyProperty(DisposableStack.prototype, Symbol.toStringTag, { + value: 'DisposableStack', + writable: false, + enumerable: false, + configurable: true +}); diff --git a/test/built-ins/DisposableStack/prototype/adopt/adds-value-onDispose.js b/test/built-ins/DisposableStack/prototype/adopt/adds-value-onDispose.js new file mode 100644 index 0000000000..6f32e4c8ae --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/adopt/adds-value-onDispose.js @@ -0,0 +1,37 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.adopt +description: Adds a disposable resource to the stack +info: | + DisposableStack.prototype.adopt ( value, onDispose ) + + 1. Let disposableStack be the this value. + 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]). + 3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception. + 4. If IsCallable(onDispose) is false, throw a TypeError exception. + 5. Let closure be a new Abstract Closure with no parameters that captures value and onDispose and performs the following steps when called: + a. Perform ? Call(onDispose, undefined, « value »). + 6. Let F be CreateBuiltinFunction(closure, 0, "", « »). + 7. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], undefined, sync-dispose, F). + ... + + AddDisposableResource ( disposeCapability, V, hint [, method ] ) + + 1. If method is not present then, + ... + 2. Else, + a. Assert: V is undefined. + b. Let resource be ? CreateDisposableResource(undefined, hint, method). + 3. Append resource to disposeCapability.[[DisposableResourceStack]]. + 4. Return unused. + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); +var resource = { disposed: false }; +stack.adopt(resource, r => { r.disposed = true }); +stack.dispose(); +assert.sameValue(resource.disposed, true, 'Expected resource to have been disposed'); diff --git a/test/built-ins/DisposableStack/prototype/adopt/allows-any-value.js b/test/built-ins/DisposableStack/prototype/adopt/allows-any-value.js new file mode 100644 index 0000000000..2071285e6a --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/adopt/allows-any-value.js @@ -0,0 +1,33 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.adopt +description: Allows any 'value' +info: | + DisposableStack.prototype.adopt ( value, onDispose ) + + 1. Let disposableStack be the this value. + 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]). + 3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception. + 4. If IsCallable(onDispose) is false, throw a TypeError exception. + 5. Let closure be a new Abstract Closure with no parameters that captures value and onDispose and performs the following steps when called: + a. Perform ? Call(onDispose, undefined, « value »). + 6. Let F be CreateBuiltinFunction(closure, 0, "", « »). + 7. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], undefined, sync-dispose, F). + ... + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); +stack.adopt(null, _ => {}); +stack.adopt(undefined, _ => {}); +stack.adopt({}, _ => {}); +stack.adopt({ [Symbol.dispose]() {} }, _ => {}); +stack.adopt(() => {}, _ => {}); +stack.adopt(true, _ => {}); +stack.adopt(false, _ => {}); +stack.adopt(1, _ => {}); +stack.adopt('object', _ => {}); +stack.adopt(Symbol(), _ => {}); diff --git a/test/built-ins/DisposableStack/prototype/adopt/puts-value-onDispose-on-top-of-stack.js b/test/built-ins/DisposableStack/prototype/adopt/puts-value-onDispose-on-top-of-stack.js new file mode 100644 index 0000000000..80022163ba --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/adopt/puts-value-onDispose-on-top-of-stack.js @@ -0,0 +1,46 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.adopt +description: Adds a disposable resource to the stack +info: | + DisposableStack.prototype.adopt ( value, onDispose ) + + 1. Let disposableStack be the this value. + 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]). + 3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception. + 4. If IsCallable(onDispose) is false, throw a TypeError exception. + 5. Let closure be a new Abstract Closure with no parameters that captures value and onDispose and performs the following steps when called: + a. Perform ? Call(onDispose, undefined, « value »). + 6. Let F be CreateBuiltinFunction(closure, 0, "", « »). + 7. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], undefined, sync-dispose, F). + ... + + AddDisposableResource ( disposeCapability, V, hint [, method ] ) + + 1. If method is not present then, + ... + 2. Else, + a. Assert: V is undefined. + b. Let resource be ? CreateDisposableResource(undefined, hint, method). + 3. Append resource to disposeCapability.[[DisposableResourceStack]]. + 4. Return unused. + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); +var disposed = []; +var resource1 = {}; +function dispose1(res) { disposed.push([res, dispose1]); } +var resource2 = {}; +function dispose2(res) { disposed.push([res, dispose2]); } +stack.adopt(resource1, dispose1); +stack.adopt(resource2, dispose2); +stack.dispose(); +assert.sameValue(2, disposed.length); +assert.sameValue(disposed[0][0], resource2, 'Expected resource2 to be the first disposed resource'); +assert.sameValue(disposed[0][1], dispose2, 'Expected dispose2 to be the first onDispose invoked'); +assert.sameValue(disposed[1][0], resource1, 'Expected resource1 to be the second disposed resource'); +assert.sameValue(disposed[1][1], dispose1, 'Expected dispose1 to be the second onDispose invoked'); diff --git a/test/built-ins/DisposableStack/prototype/adopt/returns-value.js b/test/built-ins/DisposableStack/prototype/adopt/returns-value.js new file mode 100644 index 0000000000..60057b6192 --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/adopt/returns-value.js @@ -0,0 +1,20 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.adopt +description: Returns the argument provided. +info: | + DisposableStack.prototype.adopt ( value, onDispose ) + + ... + 8. Return value. + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); +var resource = {}; +assert.sameValue(stack.adopt(resource, _ => {}), resource); +assert.sameValue(stack.adopt(null, _ => {}), null); +assert.sameValue(stack.adopt(undefined, _ => {}), undefined); diff --git a/test/built-ins/DisposableStack/prototype/adopt/throws-if-onDispose-not-callable.js b/test/built-ins/DisposableStack/prototype/adopt/throws-if-onDispose-not-callable.js new file mode 100644 index 0000000000..127168b31c --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/adopt/throws-if-onDispose-not-callable.js @@ -0,0 +1,49 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.adopt +description: Throws if onDispose argument not callable +info: | + DisposableStack.prototype.adopt ( value, onDispose ) + + ... + 4. If IsCallable(onDispose) is false, throw a TypeError exception. + ... + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); +assert.throws(TypeError, function() { + stack.adopt(null, null); +}, 'null'); + +assert.throws(TypeError, function() { + stack.adopt(null, undefined); +}, 'undefined'); + +assert.throws(TypeError, function() { + stack.adopt(null, true); +}, 'true'); + +assert.throws(TypeError, function() { + stack.adopt(null, false); +}, 'false'); + +assert.throws(TypeError, function() { + stack.adopt(null, 1); +}, 'number'); + +assert.throws(TypeError, function() { + stack.adopt(null, 'object'); +}, 'string'); + +assert.throws(TypeError, function() { + stack.adopt(null, {}); +}, 'object'); + +var s = Symbol(); +assert.throws(TypeError, function() { + stack.adopt(null, s); +}, 'symbol'); diff --git a/test/built-ins/DisposableStack/prototype/constructor.js b/test/built-ins/DisposableStack/prototype/constructor.js new file mode 100644 index 0000000000..e093b36bc6 --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/constructor.js @@ -0,0 +1,31 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-properties-of-the-disposablestack-prototype-object +description: DisposableStack.prototype.constructor +info: | + DisposableStack.prototype.constructor + + Normative Optional + + The initial value of DisposableStack.prototype.constructor is the intrinsic object %DisposableStack%. + + This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. + + This section is to be treated identically to the "Annex B" of ECMA-262, but to be written in-line with the main specification. +includes: [propertyHelper.js] +features: [explicit-resource-management] +---*/ + +var actual = DisposableStack.prototype.hasOwnProperty('constructor'); + +// If implemented, it should conform to the spec text +if (actual) { + verifyProperty(DisposableStack.prototype, 'constructor', { + value: DisposableStack, + writable: true, + enumerable: false, + configurable: true + }); +} diff --git a/test/built-ins/DisposableStack/prototype/defer/adds-onDispose.js b/test/built-ins/DisposableStack/prototype/defer/adds-onDispose.js new file mode 100644 index 0000000000..df4156f03b --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/defer/adds-onDispose.js @@ -0,0 +1,34 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.defer +description: Adds an onDispose callback to the stack +info: | + DisposableStack.prototype.defer ( onDispose ) + + 1. Let disposableStack be the this value. + 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]). + 3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception. + 4. If IsCallable(onDispose) is false, throw a TypeError exception. + 5. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], undefined, sync-dispose, onDispose). + ... + + AddDisposableResource ( disposeCapability, V, hint [, method ] ) + + 1. If method is not present then, + ... + 2. Else, + a. Assert: V is undefined. + b. Let resource be ? CreateDisposableResource(undefined, hint, method). + 3. Append resource to disposeCapability.[[DisposableResourceStack]]. + 4. Return unused. + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); +var disposed = false; +stack.defer(() => { disposed = true }); +stack.dispose(); +assert.sameValue(disposed, true, 'Expected callback to have been called'); diff --git a/test/built-ins/DisposableStack/prototype/defer/puts-onDispose-on-top-of-stack.js b/test/built-ins/DisposableStack/prototype/defer/puts-onDispose-on-top-of-stack.js new file mode 100644 index 0000000000..4658c4cfe6 --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/defer/puts-onDispose-on-top-of-stack.js @@ -0,0 +1,39 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.defer +description: Adds a disposable resource to the stack +info: | + DisposableStack.prototype.defer ( onDispose ) + + 1. Let disposableStack be the this value. + 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]). + 3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception. + 4. If IsCallable(onDispose) is false, throw a TypeError exception. + 5. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], undefined, sync-dispose, onDispose). + ... + + AddDisposableResource ( disposeCapability, V, hint [, method ] ) + + 1. If method is not present then, + ... + 2. Else, + a. Assert: V is undefined. + b. Let resource be ? CreateDisposableResource(undefined, hint, method). + 3. Append resource to disposeCapability.[[DisposableResourceStack]]. + 4. Return unused. + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); +var disposed = []; +function dispose1() { disposed.push(dispose1); } +function dispose2() { disposed.push(dispose2); } +stack.defer(dispose1); +stack.defer(dispose2); +stack.dispose(); +assert.sameValue(2, disposed.length); +assert.sameValue(disposed[0], dispose2, 'Expected dispose2 to be the first onDispose invoked'); +assert.sameValue(disposed[1], dispose1, 'Expected dispose1 to be the second onDispose invoked'); diff --git a/test/built-ins/DisposableStack/prototype/defer/returns-undefined.js b/test/built-ins/DisposableStack/prototype/defer/returns-undefined.js new file mode 100644 index 0000000000..3b5a2a11a3 --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/defer/returns-undefined.js @@ -0,0 +1,17 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.defer +description: Returns the argument provided. +info: | + DisposableStack.prototype.defer ( onDispose ) + + ... + 6. Return undefined. + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); +assert.sameValue(stack.defer(_ => {}), undefined); diff --git a/test/built-ins/DisposableStack/prototype/defer/throws-if-onDispose-not-callable.js b/test/built-ins/DisposableStack/prototype/defer/throws-if-onDispose-not-callable.js new file mode 100644 index 0000000000..80fbbbbeba --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/defer/throws-if-onDispose-not-callable.js @@ -0,0 +1,49 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.defer +description: Adds a callback to the stack +info: | + DisposableStack.prototype.defer ( onDispose ) + + ... + 4. If IsCallable(onDispose) is false, throw a TypeError exception. + ... + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); +assert.throws(TypeError, function() { + stack.defer(null); +}, 'null'); + +assert.throws(TypeError, function() { + stack.defer(undefined); +}, 'undefined'); + +assert.throws(TypeError, function() { + stack.defer(true); +}, 'true'); + +assert.throws(TypeError, function() { + stack.defer(false); +}, 'false'); + +assert.throws(TypeError, function() { + stack.defer(1); +}, 'number'); + +assert.throws(TypeError, function() { + stack.defer('object'); +}, 'string'); + +assert.throws(TypeError, function() { + stack.defer({}); +}, 'object'); + +var s = Symbol(); +assert.throws(TypeError, function() { + stack.defer(s); +}, 'symbol'); diff --git a/test/built-ins/DisposableStack/prototype/dispose/disposes-resources-in-reverse-order.js b/test/built-ins/DisposableStack/prototype/dispose/disposes-resources-in-reverse-order.js new file mode 100644 index 0000000000..4ea5aeb9c5 --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/dispose/disposes-resources-in-reverse-order.js @@ -0,0 +1,69 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.dispose +description: Added resources are disposed in reverse order +info: | + UsingDeclaration : using BindingList ; + + 1. Perform ? BindingEvaluation of BindingList with argument sync-dispose. + 2. Return empty. + + BindingList : BindingList , LexicalBinding + + 1. Perform ? BindingEvaluation of BindingList with argument hint. + 2. Perform ? BindingEvaluation of LexicalBinding with argument hint. + 3. Return unused. + + LexicalBinding : BindingIdentifier Initializer + + 1. Let bindingId be StringValue of BindingIdentifier. + 2. Let lhs be ? ResolveBinding(bindingId). + 3. If IsAnonymousFunctionDefinition(Initializer) is true, then + a. Let value be NamedEvaluation of Initializer with argument bindingId. + 4. Else, + a. Let rhs be the result of evaluating Initializer. + b. Let value be ? GetValue(rhs). + 5. Return ? InitializeReferencedBinding(lhs, value, hint). + + DisposeResources ( disposeCapability, completion ) + + 1. For each resource of disposeCapability.[[DisposableResourceStack]], in reverse list order, do + a. Let result be Dispose(resource.[[ResourceValue]], resource.[[Hint]], resource.[[DisposeMethod]]). + b. If result.[[Type]] is throw, then + i. If completion.[[Type]] is throw, then + 1. Set result to result.[[Value]]. + 2. Let suppressed be completion.[[Value]]. + 3. Let error be a newly created SuppressedError object. + 4. Perform ! CreateNonEnumerableDataPropertyOrThrow(error, "error", result). + 5. Perform ! CreateNonEnumerableDataPropertyOrThrow(error, "suppressed", suppressed). + 6. Set completion to ThrowCompletion(error). + ii. Else, + 1. Set completion to result. + 2. Return completion. + + Dispose ( V, hint, method ) + + 1. If method is undefined, let result be undefined. + 2. Else, let result be ? Call(method, V). + 3. If hint is async-dispose, then + a. Perform ? Await(result). + 4. Return undefined. + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); +var disposed = []; +var resource1 = { [Symbol.dispose]() { disposed.push(resource1); } }; +var resource2 = {}; +function dispose2(res) { disposed.push(res); } +function dispose3() { disposed.push(dispose3); } +stack.use(resource1); +stack.adopt(resource2, dispose2); +stack.defer(dispose3); +stack.dispose(); +assert.sameValue(disposed[0], dispose3); +assert.sameValue(disposed[1], resource2); +assert.sameValue(disposed[2], resource1); diff --git a/test/built-ins/DisposableStack/prototype/dispose/does-not-reinvoke-disposers-if-already-disposed.js b/test/built-ins/DisposableStack/prototype/dispose/does-not-reinvoke-disposers-if-already-disposed.js new file mode 100644 index 0000000000..5d5bddb08a --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/dispose/does-not-reinvoke-disposers-if-already-disposed.js @@ -0,0 +1,54 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.dispose +description: Does not re-invoke disposal on resources after stack has already been disposed. +info: | + DisposableStack.prototype.dispose ( ) + + 1. Let disposableStack be the this value. + 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]). + 3. If disposableStack.[[DisposableState]] is disposed, return undefined. + 4. Set disposableStack.[[DisposableState]] to disposed. + 5. Return DisposeResources(disposableStack.[[DisposeCapability]], NormalCompletion(undefined)). + + DisposeResources ( disposeCapability, completion ) + + 1. For each resource of disposeCapability.[[DisposableResourceStack]], in reverse list order, do + a. Let result be Dispose(resource.[[ResourceValue]], resource.[[Hint]], resource.[[DisposeMethod]]). + b. If result.[[Type]] is throw, then + i. If completion.[[Type]] is throw, then + 1. Set result to result.[[Value]]. + 2. Let suppressed be completion.[[Value]]. + 3. Let error be a newly created SuppressedError object. + 4. Perform ! CreateNonEnumerableDataPropertyOrThrow(error, "error", result). + 5. Perform ! CreateNonEnumerableDataPropertyOrThrow(error, "suppressed", suppressed). + 6. Set completion to ThrowCompletion(error). + ii. Else, + 1. Set completion to result. + 2. Return completion. + + Dispose ( V, hint, method ) + + 1. If method is undefined, let result be undefined. + 2. Else, let result be ? Call(method, V). + 3. If hint is async-dispose, then + a. Perform ? Await(result). + 4. Return undefined. + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); +var useCount = 0; +var adoptCount = 0; +var deferCount = 0; +stack.use({ [Symbol.dispose]() { useCount++; } }); +stack.adopt({}, _ => { adoptCount++; }); +stack.defer(() => { deferCount++; }); +stack.dispose(); +stack.dispose(); +assert.sameValue(useCount, 1); +assert.sameValue(adoptCount, 1); +assert.sameValue(deferCount, 1); diff --git a/test/built-ins/DisposableStack/prototype/dispose/does-not-throw-if-already-disposed.js b/test/built-ins/DisposableStack/prototype/dispose/does-not-throw-if-already-disposed.js new file mode 100644 index 0000000000..2eb0581a9f --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/dispose/does-not-throw-if-already-disposed.js @@ -0,0 +1,45 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.dispose +description: Does not throw if already disposed. +info: | + DisposableStack.prototype.dispose ( ) + + 1. Let disposableStack be the this value. + 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]). + 3. If disposableStack.[[DisposableState]] is disposed, return undefined. + 4. Set disposableStack.[[DisposableState]] to disposed. + 5. Return DisposeResources(disposableStack.[[DisposeCapability]], NormalCompletion(undefined)). + + DisposeResources ( disposeCapability, completion ) + + 1. For each resource of disposeCapability.[[DisposableResourceStack]], in reverse list order, do + a. Let result be Dispose(resource.[[ResourceValue]], resource.[[Hint]], resource.[[DisposeMethod]]). + b. If result.[[Type]] is throw, then + i. If completion.[[Type]] is throw, then + 1. Set result to result.[[Value]]. + 2. Let suppressed be completion.[[Value]]. + 3. Let error be a newly created SuppressedError object. + 4. Perform ! CreateNonEnumerableDataPropertyOrThrow(error, "error", result). + 5. Perform ! CreateNonEnumerableDataPropertyOrThrow(error, "suppressed", suppressed). + 6. Set completion to ThrowCompletion(error). + ii. Else, + 1. Set completion to result. + 2. Return completion. + + Dispose ( V, hint, method ) + + 1. If method is undefined, let result be undefined. + 2. Else, let result be ? Call(method, V). + 3. If hint is async-dispose, then + a. Perform ? Await(result). + 4. Return undefined. + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); +stack.dispose(); +stack.dispose(); diff --git a/test/built-ins/DisposableStack/prototype/dispose/returns-undefined.js b/test/built-ins/DisposableStack/prototype/dispose/returns-undefined.js new file mode 100644 index 0000000000..f8b1365c0f --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/dispose/returns-undefined.js @@ -0,0 +1,44 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.dispose +description: Return value of dispose is undefined +info: | + DisposableStack.prototype.dispose ( ) + + 1. Let disposableStack be the this value. + 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]). + 3. If disposableStack.[[DisposableState]] is disposed, return undefined. + 4. Set disposableStack.[[DisposableState]] to disposed. + 5. Return DisposeResources(disposableStack.[[DisposeCapability]], NormalCompletion(undefined)). + + DisposeResources ( disposeCapability, completion ) + + 1. For each resource of disposeCapability.[[DisposableResourceStack]], in reverse list order, do + a. Let result be Dispose(resource.[[ResourceValue]], resource.[[Hint]], resource.[[DisposeMethod]]). + b. If result.[[Type]] is throw, then + i. If completion.[[Type]] is throw, then + 1. Set result to result.[[Value]]. + 2. Let suppressed be completion.[[Value]]. + 3. Let error be a newly created SuppressedError object. + 4. Perform ! CreateNonEnumerableDataPropertyOrThrow(error, "error", result). + 5. Perform ! CreateNonEnumerableDataPropertyOrThrow(error, "suppressed", suppressed). + 6. Set completion to ThrowCompletion(error). + ii. Else, + 1. Set completion to result. + 2. Return completion. + + Dispose ( V, hint, method ) + + 1. If method is undefined, let result be undefined. + 2. Else, let result be ? Call(method, V). + 3. If hint is async-dispose, then + a. Perform ? Await(result). + 4. Return undefined. + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); +assert.sameValue(stack.dispose(), undefined); diff --git a/test/built-ins/DisposableStack/prototype/dispose/sets-state-to-disposed.js b/test/built-ins/DisposableStack/prototype/dispose/sets-state-to-disposed.js new file mode 100644 index 0000000000..105f6988a6 --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/dispose/sets-state-to-disposed.js @@ -0,0 +1,48 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.dispose +description: Sets the [[DisposableState]] internal slot to disposed +info: | + DisposableStack.prototype.dispose ( ) + + 1. Let disposableStack be the this value. + 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]). + 3. If disposableStack.[[DisposableState]] is disposed, return undefined. + 4. Set disposableStack.[[DisposableState]] to disposed. + 5. Return DisposeResources(disposableStack.[[DisposeCapability]], NormalCompletion(undefined)). + + DisposeResources ( disposeCapability, completion ) + + 1. For each resource of disposeCapability.[[DisposableResourceStack]], in reverse list order, do + a. Let result be Dispose(resource.[[ResourceValue]], resource.[[Hint]], resource.[[DisposeMethod]]). + b. If result.[[Type]] is throw, then + i. If completion.[[Type]] is throw, then + 1. Set result to result.[[Value]]. + 2. Let suppressed be completion.[[Value]]. + 3. Let error be a newly created SuppressedError object. + 4. Perform ! CreateNonEnumerableDataPropertyOrThrow(error, "error", result). + 5. Perform ! CreateNonEnumerableDataPropertyOrThrow(error, "suppressed", suppressed). + 6. Set completion to ThrowCompletion(error). + ii. Else, + 1. Set completion to result. + 2. Return completion. + + Dispose ( V, hint, method ) + + 1. If method is undefined, let result be undefined. + 2. Else, let result be ? Call(method, V). + 3. If hint is async-dispose, then + a. Perform ? Await(result). + 4. Return undefined. + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); +var wasDisposed = stack.disposed; +stack.dispose(); +var isDisposed = stack.disposed; +assert.sameValue(wasDisposed, false); +assert.sameValue(isDisposed, true); diff --git a/test/built-ins/DisposableStack/prototype/dispose/throws-error-as-is-if-only-one-error-during-disposal.js b/test/built-ins/DisposableStack/prototype/dispose/throws-error-as-is-if-only-one-error-during-disposal.js new file mode 100644 index 0000000000..4f0e2566b8 --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/dispose/throws-error-as-is-if-only-one-error-during-disposal.js @@ -0,0 +1,49 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.dispose +description: Rethrows an error from a disposal as-is if it is the only error. +info: | + DisposableStack.prototype.dispose ( ) + + 1. Let disposableStack be the this value. + 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]). + 3. If disposableStack.[[DisposableState]] is disposed, return undefined. + 4. Set disposableStack.[[DisposableState]] to disposed. + 5. Return DisposeResources(disposableStack.[[DisposeCapability]], NormalCompletion(undefined)). + + DisposeResources ( disposeCapability, completion ) + + 1. For each resource of disposeCapability.[[DisposableResourceStack]], in reverse list order, do + a. Let result be Dispose(resource.[[ResourceValue]], resource.[[Hint]], resource.[[DisposeMethod]]). + b. If result.[[Type]] is throw, then + i. If completion.[[Type]] is throw, then + 1. Set result to result.[[Value]]. + 2. Let suppressed be completion.[[Value]]. + 3. Let error be a newly created SuppressedError object. + 4. Perform ! CreateNonEnumerableDataPropertyOrThrow(error, "error", result). + 5. Perform ! CreateNonEnumerableDataPropertyOrThrow(error, "suppressed", suppressed). + 6. Set completion to ThrowCompletion(error). + ii. Else, + 1. Set completion to result. + 2. Return completion. + + Dispose ( V, hint, method ) + + 1. If method is undefined, let result be undefined. + 2. Else, let result be ? Call(method, V). + 3. If hint is async-dispose, then + a. Perform ? Await(result). + 4. Return undefined. + +features: [explicit-resource-management] +---*/ + +class MyError extends Error {} +var stack = new DisposableStack(); +stack.defer(function () { throw new MyError(); }); +stack.defer(function () {}); +assert.throws(MyError, function () { + stack.dispose(); +}); diff --git a/test/built-ins/DisposableStack/prototype/dispose/throws-suppressederror-if-multiple-errors-during-disposal.js b/test/built-ins/DisposableStack/prototype/dispose/throws-suppressederror-if-multiple-errors-during-disposal.js new file mode 100644 index 0000000000..92bf111f06 --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/dispose/throws-suppressederror-if-multiple-errors-during-disposal.js @@ -0,0 +1,61 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.dispose +description: Throws multiple errors from a disposal nested in one or more SuppressedError instances. +info: | + DisposableStack.prototype.dispose ( ) + + 1. Let disposableStack be the this value. + 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]). + 3. If disposableStack.[[DisposableState]] is disposed, return undefined. + 4. Set disposableStack.[[DisposableState]] to disposed. + 5. Return DisposeResources(disposableStack.[[DisposeCapability]], NormalCompletion(undefined)). + + DisposeResources ( disposeCapability, completion ) + + 1. For each resource of disposeCapability.[[DisposableResourceStack]], in reverse list order, do + a. Let result be Dispose(resource.[[ResourceValue]], resource.[[Hint]], resource.[[DisposeMethod]]). + b. If result.[[Type]] is throw, then + i. If completion.[[Type]] is throw, then + 1. Set result to result.[[Value]]. + 2. Let suppressed be completion.[[Value]]. + 3. Let error be a newly created SuppressedError object. + 4. Perform ! CreateNonEnumerableDataPropertyOrThrow(error, "error", result). + 5. Perform ! CreateNonEnumerableDataPropertyOrThrow(error, "suppressed", suppressed). + 6. Set completion to ThrowCompletion(error). + ii. Else, + 1. Set completion to result. + 2. Return completion. + + Dispose ( V, hint, method ) + + 1. If method is undefined, let result be undefined. + 2. Else, let result be ? Call(method, V). + 3. If hint is async-dispose, then + a. Perform ? Await(result). + 4. Return undefined. + +features: [explicit-resource-management] +---*/ + +class MyError extends Error {} +var error1 = new MyError(); +var error2 = new MyError(); +var error3 = new MyError(); +var stack = new DisposableStack(); +stack.defer(function () { throw error1; }); +stack.defer(function () { throw error2; }); +stack.defer(function () { throw error3; }); +try { + stack.dispose(); + assert(false, 'Expected stack.dispose() to have thrown an error.'); +} +catch (e) { + assert(e instanceof SuppressedError, "Expected stack.dispose() to have thrown a SuppressedError"); + assert.sameValue(e.error, error1, "Expected the outermost suppressing error to have been 'error1'"); + assert(e.suppressed instanceof SuppressedError, "Expected the outermost suppressed error to have been a SuppressedError"); + assert.sameValue(e.suppressed.error, error2, "Expected the innermost suppressing error to have been 'error2'"); + assert.sameValue(e.suppressed.suppressed, error3, "Expected the innermost suppressed error to have been 'error3'"); +} diff --git a/test/built-ins/DisposableStack/prototype/disposed/returns-false-when-not-disposed.js b/test/built-ins/DisposableStack/prototype/disposed/returns-false-when-not-disposed.js new file mode 100644 index 0000000000..ec81ef40dd --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/disposed/returns-false-when-not-disposed.js @@ -0,0 +1,19 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-get-disposablestack.prototype.disposed +description: > + Returns `false` when the DisposableStack has not yet been disposed. +info: | + get DisposableStack.prototype.disposed + + ... + 3. If disposableStack.[[DisposableState]] is disposed, return true. + 4. Otherwise, return false. + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); + +assert.sameValue(stack.disposed, false); diff --git a/test/built-ins/DisposableStack/prototype/disposed/returns-true-when-disposed.js b/test/built-ins/DisposableStack/prototype/disposed/returns-true-when-disposed.js new file mode 100644 index 0000000000..47757d655d --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/disposed/returns-true-when-disposed.js @@ -0,0 +1,19 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-get-disposablestack.prototype.disposed +description: > + Returns `true` after the DisposableStack has been disposed. +info: | + get DisposableStack.prototype.disposed + + ... + 3. If disposableStack.[[DisposableState]] is disposed, return true. + 4. Otherwise, return false. + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); +stack.dispose(); +assert.sameValue(stack.disposed, true); diff --git a/test/built-ins/DisposableStack/prototype/move/does-not-dispose-resources.js b/test/built-ins/DisposableStack/prototype/move/does-not-dispose-resources.js new file mode 100644 index 0000000000..892c803237 --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/move/does-not-dispose-resources.js @@ -0,0 +1,27 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.move +description: Resources in the stack are not disposed when move is called. +info: | + DisposableStack.prototype.move ( ) + + 1. Let disposableStack be the this value. + 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]). + 3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception. + 4. Let newDisposableStack be ? OrdinaryCreateFromConstructor(%DisposableStack%, "%DisposableStack.prototype%", « [[DisposableState]], [[DisposeCapability]] »). + 5. Set newDisposableStack.[[DisposableState]] to pending. + 6. Set newDisposableStack.[[DisposeCapability]] to disposableStack.[[DisposeCapability]]. + 7. Set disposableStack.[[DisposeCapability]] to NewDisposeCapability(). + 8. Set disposableStack.[[DisposableState]] to disposed. + 9. Return newDisposableStack. + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); +var disposed = false; +stack.defer(() => { disposed = true; }); +stack.move(); +assert.sameValue(disposed, false); diff --git a/test/built-ins/DisposableStack/prototype/move/returns-new-disposablestack-that-contains-moved-resources.js b/test/built-ins/DisposableStack/prototype/move/returns-new-disposablestack-that-contains-moved-resources.js new file mode 100644 index 0000000000..e9135809a3 --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/move/returns-new-disposablestack-that-contains-moved-resources.js @@ -0,0 +1,36 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.move +description: Returns a new DisposableStack that contains the resources originally contained in this stack. +info: | + DisposableStack.prototype.move ( ) + + 1. Let disposableStack be the this value. + 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]). + 3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception. + 4. Let newDisposableStack be ? OrdinaryCreateFromConstructor(%DisposableStack%, "%DisposableStack.prototype%", « [[DisposableState]], [[DisposeCapability]] »). + 5. Set newDisposableStack.[[DisposableState]] to pending. + 6. Set newDisposableStack.[[DisposeCapability]] to disposableStack.[[DisposeCapability]]. + 7. Set disposableStack.[[DisposeCapability]] to NewDisposeCapability(). + 8. Set disposableStack.[[DisposableState]] to disposed. + 9. Return newDisposableStack. + +includes: [deepEqual.js] +features: [explicit-resource-management] +---*/ + +var stack1 = new DisposableStack(); +var disposed = []; +stack1.defer(() => { disposed.push(1); }); +stack1.defer(() => { disposed.push(2); }); + +var stack2 = stack1.move(); + +var wasDisposed = disposed.slice(); +stack2.dispose(); +var isDisposed = disposed.slice(); + +assert.deepEqual(wasDisposed, []); +assert.deepEqual(isDisposed, [2, 1]); diff --git a/test/built-ins/DisposableStack/prototype/move/returns-new-disposablestack-that-is-still-pending.js b/test/built-ins/DisposableStack/prototype/move/returns-new-disposablestack-that-is-still-pending.js new file mode 100644 index 0000000000..cec6eb586f --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/move/returns-new-disposablestack-that-is-still-pending.js @@ -0,0 +1,25 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.move +description: Returns a new DisposableStack that is still pending +info: | + DisposableStack.prototype.move ( ) + + 1. Let disposableStack be the this value. + 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]). + 3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception. + 4. Let newDisposableStack be ? OrdinaryCreateFromConstructor(%DisposableStack%, "%DisposableStack.prototype%", « [[DisposableState]], [[DisposeCapability]] »). + 5. Set newDisposableStack.[[DisposableState]] to pending. + 6. Set newDisposableStack.[[DisposeCapability]] to disposableStack.[[DisposeCapability]]. + 7. Set disposableStack.[[DisposeCapability]] to NewDisposeCapability(). + 8. Set disposableStack.[[DisposableState]] to disposed. + 9. Return newDisposableStack. + +features: [explicit-resource-management] +---*/ + +var stack1 = new DisposableStack(); +var stack2 = stack1.move(); +assert.sameValue(stack2.disposed, false); diff --git a/test/built-ins/DisposableStack/prototype/move/returns-new-disposablestack.js b/test/built-ins/DisposableStack/prototype/move/returns-new-disposablestack.js new file mode 100644 index 0000000000..fdaeb89d57 --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/move/returns-new-disposablestack.js @@ -0,0 +1,26 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.move +description: Returns a new DisposableStack +info: | + DisposableStack.prototype.move ( ) + + 1. Let disposableStack be the this value. + 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]). + 3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception. + 4. Let newDisposableStack be ? OrdinaryCreateFromConstructor(%DisposableStack%, "%DisposableStack.prototype%", « [[DisposableState]], [[DisposeCapability]] »). + 5. Set newDisposableStack.[[DisposableState]] to pending. + 6. Set newDisposableStack.[[DisposeCapability]] to disposableStack.[[DisposeCapability]]. + 7. Set disposableStack.[[DisposeCapability]] to NewDisposeCapability(). + 8. Set disposableStack.[[DisposableState]] to disposed. + 9. Return newDisposableStack. + +features: [explicit-resource-management] +---*/ + +var stack1 = new DisposableStack(); +var stack2 = stack1.move(); +assert(stack2 !== stack1, 'Expected stack2 to not be the same reference as stack1'); +assert(stack2 instanceof DisposableStack, 'Expected stack2 to be an instance of DisposableStack'); diff --git a/test/built-ins/DisposableStack/prototype/move/sets-state-to-disposed.js b/test/built-ins/DisposableStack/prototype/move/sets-state-to-disposed.js new file mode 100644 index 0000000000..c600eb4444 --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/move/sets-state-to-disposed.js @@ -0,0 +1,28 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.move +description: The stack's [[DisposableState]] internal slot is set to disposed. +info: | + DisposableStack.prototype.move ( ) + + 1. Let disposableStack be the this value. + 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]). + 3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception. + 4. Let newDisposableStack be ? OrdinaryCreateFromConstructor(%DisposableStack%, "%DisposableStack.prototype%", « [[DisposableState]], [[DisposeCapability]] »). + 5. Set newDisposableStack.[[DisposableState]] to pending. + 6. Set newDisposableStack.[[DisposeCapability]] to disposableStack.[[DisposeCapability]]. + 7. Set disposableStack.[[DisposeCapability]] to NewDisposeCapability(). + 8. Set disposableStack.[[DisposableState]] to disposed. + 9. Return newDisposableStack. + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); +var wasDisposed = stack.disposed; +stack.move(); +var isDisposed = stack.disposed; +assert.sameValue(wasDisposed, false); +assert.sameValue(isDisposed, true); diff --git a/test/built-ins/DisposableStack/prototype/move/still-returns-new-disposablestack-when-subclassed.js b/test/built-ins/DisposableStack/prototype/move/still-returns-new-disposablestack-when-subclassed.js new file mode 100644 index 0000000000..944b0d9c8c --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/move/still-returns-new-disposablestack-when-subclassed.js @@ -0,0 +1,28 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.move +description: Returns a new %DisposableStack%, even when subclassed +info: | + DisposableStack.prototype.move ( ) + + 1. Let disposableStack be the this value. + 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]). + 3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception. + 4. Let newDisposableStack be ? OrdinaryCreateFromConstructor(%DisposableStack%, "%DisposableStack.prototype%", « [[DisposableState]], [[DisposeCapability]] »). + 5. Set newDisposableStack.[[DisposableState]] to pending. + 6. Set newDisposableStack.[[DisposeCapability]] to disposableStack.[[DisposeCapability]]. + 7. Set disposableStack.[[DisposeCapability]] to NewDisposeCapability(). + 8. Set disposableStack.[[DisposableState]] to disposed. + 9. Return newDisposableStack. + +features: [explicit-resource-management] +---*/ + +class MyDisposableStack extends DisposableStack {} + +var stack1 = new MyDisposableStack(); +var stack2 = stack1.move(); +assert(stack2 instanceof DisposableStack, 'Expected stack2 to be an instance of DisposableStack'); +assert(!(stack2 instanceof MyDisposableStack), 'Expected stack2 to not be an instance of MyDisposableStack'); diff --git a/test/built-ins/DisposableStack/prototype/move/throws-if-disposed.js b/test/built-ins/DisposableStack/prototype/move/throws-if-disposed.js new file mode 100644 index 0000000000..4d22834463 --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/move/throws-if-disposed.js @@ -0,0 +1,23 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.move +description: Throws a ReferenceError if this is disposed. +info: | + DisposableStack.prototype.move ( value ) + + 1. Let disposableStack be the this value. + 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]). + 3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception. + ... + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); +stack.dispose(); + +assert.throws(ReferenceError, function() { + stack.move(); +}, 'undefined'); diff --git a/test/built-ins/DisposableStack/prototype/use/Symbol.dispose-getter.js b/test/built-ins/DisposableStack/prototype/use/Symbol.dispose-getter.js new file mode 100644 index 0000000000..245a0a9f8d --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/use/Symbol.dispose-getter.js @@ -0,0 +1,43 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.use +description: Invokes [Symbol.dispose] getter +info: | + DisposableStack.prototype.use ( value ) + + 1. Let disposableStack be the this value. + 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]). + 3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception. + 4. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], value, sync-dispose). + ... + + AddDisposableResource ( disposeCapability, V, hint [, method ] ) + + 1. If method is not present then, + a. If V is either null or undefined and hint is sync-dispose, then + i. Return unused + b. Let resource be ? CreateDisposableResource(V, hint). + 2. Else, + ... + 3. Append resource to disposeCapability.[[DisposableResourceStack]]. + 4. Return unused. + +features: [explicit-resource-management] +---*/ + +var resource = { + disposed: false, + get [Symbol.dispose]() { + return function() { + this.disposed = true; + }; + } +}; + +var stack = new DisposableStack(); +stack.use(resource); +stack.dispose(); + +assert.sameValue(resource.disposed, true, 'Expected resource to have been disposed'); diff --git a/test/built-ins/DisposableStack/prototype/use/adds-value.js b/test/built-ins/DisposableStack/prototype/use/adds-value.js new file mode 100644 index 0000000000..278e050bb9 --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/use/adds-value.js @@ -0,0 +1,39 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.use +description: Adds a disposable resource to the stack +info: | + DisposableStack.prototype.use ( value ) + + 1. Let disposableStack be the this value. + 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]). + 3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception. + 4. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], value, sync-dispose). + ... + + AddDisposableResource ( disposeCapability, V, hint [, method ] ) + + 1. If method is not present then, + a. If V is either null or undefined and hint is sync-dispose, then + i. Return unused + b. Let resource be ? CreateDisposableResource(V, hint). + 2. Else, + ... + 3. Append resource to disposeCapability.[[DisposableResourceStack]]. + 4. Return unused. + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); +var resource = { + disposed: false, + [Symbol.dispose]() { + this.disposed = true; + } +}; +stack.use(resource); +stack.dispose(); +assert.sameValue(resource.disposed, true, 'Expected resource to have been disposed'); diff --git a/test/built-ins/DisposableStack/prototype/use/allows-null-value.js b/test/built-ins/DisposableStack/prototype/use/allows-null-value.js new file mode 100644 index 0000000000..f4c4de6b4a --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/use/allows-null-value.js @@ -0,0 +1,28 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.use +description: Does not throw when argument is 'null' +info: | + DisposableStack.prototype.use ( value ) + + 1. Let disposableStack be the this value. + 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]). + 3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception. + 4. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], value, sync-dispose). + ... + + AddDisposableResource ( disposeCapability, V, hint [, method ] ) + + 1. If method is not present then, + a. If V is either null or undefined and hint is sync-dispose, then + i. Return unused + ... + ... + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); +stack.use(null); diff --git a/test/built-ins/DisposableStack/prototype/use/allows-undefined-value.js b/test/built-ins/DisposableStack/prototype/use/allows-undefined-value.js new file mode 100644 index 0000000000..83bccd60f5 --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/use/allows-undefined-value.js @@ -0,0 +1,28 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.use +description: Does not throw when argument is 'undefined' +info: | + DisposableStack.prototype.use ( value ) + + 1. Let disposableStack be the this value. + 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]). + 3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception. + 4. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], value, sync-dispose). + ... + + AddDisposableResource ( disposeCapability, V, hint [, method ] ) + + 1. If method is not present then, + a. If V is either null or undefined and hint is sync-dispose, then + i. Return unused + ... + ... + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); +stack.use(undefined); diff --git a/test/built-ins/DisposableStack/prototype/use/gets-value-Symbol.dispose-property-once.js b/test/built-ins/DisposableStack/prototype/use/gets-value-Symbol.dispose-property-once.js new file mode 100644 index 0000000000..2bde670433 --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/use/gets-value-Symbol.dispose-property-once.js @@ -0,0 +1,61 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.use +description: Only reads `[Symbol.dispose]` method once, when added. +info: | + DisposableStack.prototype.use ( value ) + + 1. Let disposableStack be the this value. + 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]). + 3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception. + 4. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], value, sync-dispose). + ... + + AddDisposableResource ( disposeCapability, V, hint [, method ] ) + + 1. If method is not present then, + a. If V is either null or undefined and hint is sync-dispose, then + i. Return unused + b. Let resource be ? CreateDisposableResource(V, hint). + ... + + CreateDisposableResource ( V, hint [ , method ] ) + + 1. If method is not present, then + a. If V is either null or undefined, then + i. Set V to undefined + ii. Set method to undefined + b. Else, + i. If Type(V) is not Object, throw a TypeError exception. + ii. Set method to ? GetDisposeMethod(V, hint). + iii. If method is undefined, throw a TypeError exception. + 2. Else, + a. ... + 3. Return the DisposableResource Record { [[ResourceValue]]: V, [[Hint]]: hint, [[DisposeMethod]]: method }. + + GetDisposeMethod ( V, hint ) + + 1. If hint is async-dispose, then + a. Let method be ? GetMethod(V, @@asyncDispose). + b. If method is undefined, then + i. Set method to ? GetMethod(V, @@dispose). + 2. Else, + a. Let method be ? GetMethod(V, @@dispose). + 3. Return method. + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); +var resource = { + disposeReadCount: 0, + get [Symbol.dispose]() { + this.disposeReadCount++; + return function() { }; + } +}; +stack.use(resource); +stack.dispose(); +assert.sameValue(resource.disposeReadCount, 1, 'Expected [Symbol.dispose] to have been read only once'); diff --git a/test/built-ins/DisposableStack/prototype/use/puts-value-on-top-of-stack.js b/test/built-ins/DisposableStack/prototype/use/puts-value-on-top-of-stack.js new file mode 100644 index 0000000000..bc8472b013 --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/use/puts-value-on-top-of-stack.js @@ -0,0 +1,47 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.use +description: Puts value on the top of the dispose stack +info: | + DisposableStack.prototype.use ( value ) + + 1. Let disposableStack be the this value. + 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]). + 3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception. + 4. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], value, sync-dispose). + ... + + AddDisposableResource ( disposeCapability, V, hint [, method ] ) + + 1. If method is not present then, + a. If V is either null or undefined and hint is sync-dispose, then + i. Return unused + b. Let resource be ? CreateDisposableResource(V, hint). + 2. Else, + ... + 3. Append resource to disposeCapability.[[DisposableResourceStack]]. + 4. Return unused. + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); +var disposed = []; +var resource1 = { + [Symbol.dispose]() { + disposed.push(this); + } +}; +var resource2 = { + [Symbol.dispose]() { + disposed.push(this); + } +}; +stack.use(resource1); +stack.use(resource2); +stack.dispose(); +assert.sameValue(2, disposed.length); +assert.sameValue(disposed[0], resource2, 'Expected resource2 to be the first disposed resource'); +assert.sameValue(disposed[1], resource1, 'Expected resource1 to be the second disposed resource'); diff --git a/test/built-ins/DisposableStack/prototype/use/returns-value.js b/test/built-ins/DisposableStack/prototype/use/returns-value.js new file mode 100644 index 0000000000..ecd53f279c --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/use/returns-value.js @@ -0,0 +1,20 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.use +description: Returns the argument provided. +info: | + DisposableStack.prototype.use ( value ) + + ... + 5. Return value. + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); +var resource = { [Symbol.dispose]() { } }; +assert.sameValue(stack.use(resource), resource); +assert.sameValue(stack.use(null), null); +assert.sameValue(stack.use(undefined), undefined); diff --git a/test/built-ins/DisposableStack/prototype/use/throws-if-disposed.js b/test/built-ins/DisposableStack/prototype/use/throws-if-disposed.js new file mode 100644 index 0000000000..bd4d7a4a6c --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/use/throws-if-disposed.js @@ -0,0 +1,56 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.use +description: Throws a ReferenceError if this is disposed. +info: | + DisposableStack.prototype.use ( value ) + + 1. Let disposableStack be the this value. + 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]). + 3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception. + ... + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); +stack.dispose(); + +assert.throws(ReferenceError, function() { + stack.use(undefined); +}, 'undefined'); + +assert.throws(ReferenceError, function() { + stack.use(null); +}, 'null'); + +assert.throws(ReferenceError, function() { + stack.use(true); +}, 'true'); + +assert.throws(ReferenceError, function() { + stack.use(false); +}, 'false'); + +assert.throws(ReferenceError, function() { + stack.use(1); +}, 'number'); + +assert.throws(ReferenceError, function() { + stack.use('object'); +}, 'string'); + +var s = Symbol(); +assert.throws(ReferenceError, function() { + stack.use(s); +}, 'symbol'); + +assert.throws(ReferenceError, function() { + stack.use({}); +}, 'non disposable object'); + +assert.throws(ReferenceError, function() { + stack.use({ [Symbol.dispose]() {} }); +}, 'disposable object'); diff --git a/test/built-ins/DisposableStack/prototype/use/throws-if-value-Symbol.dispose-property-is-null.js b/test/built-ins/DisposableStack/prototype/use/throws-if-value-Symbol.dispose-property-is-null.js new file mode 100644 index 0000000000..a410ad295a --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/use/throws-if-value-Symbol.dispose-property-is-null.js @@ -0,0 +1,58 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.use +description: Throws if the argument has a null-valued Symbol.dispose property. +info: | + DisposableStack.prototype.use ( value ) + + 1. Let disposableStack be the this value. + 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]). + 3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception. + 4. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], value, sync-dispose). + ... + + AddDisposableResource ( disposeCapability, V, hint [, method ] ) + + 1. If method is not present then, + a. If V is either null or undefined and hint is sync-dispose, then + i. Return unused + b. Let resource be ? CreateDisposableResource(V, hint). + ... + + CreateDisposableResource ( V, hint [ , method ] ) + + 1. If method is not present, then + a. If V is either null or undefined, then + i. Set V to undefined + ii. Set method to undefined + b. Else, + i. If Type(V) is not Object, throw a TypeError exception. + ii. Set method to ? GetDisposeMethod(V, hint). + iii. If method is undefined, throw a TypeError exception. + ... + + GetDisposeMethod ( V, hint ) + + 1. If hint is async-dispose, then + a. Let method be ? GetMethod(V, @@asyncDispose). + b. If method is undefined, then + i. Set method to ? GetMethod(V, @@dispose). + 2. Else, + a. Let method be ? GetMethod(V, @@dispose). + 3. Return method. + + GetMethod ( V, P ) + + 1. Let func be ? GetV(V, P). + 2. If func is either undefined or null, return undefined. + 3. ... + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); +assert.throws(TypeError, function() { + stack.use({ [Symbol.dispose]: null }); +}, 'true'); diff --git a/test/built-ins/DisposableStack/prototype/use/throws-if-value-Symbol.dispose-property-is-undefined.js b/test/built-ins/DisposableStack/prototype/use/throws-if-value-Symbol.dispose-property-is-undefined.js new file mode 100644 index 0000000000..361e6dff05 --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/use/throws-if-value-Symbol.dispose-property-is-undefined.js @@ -0,0 +1,58 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.use +description: Throws if the argument has an undefined-valued Symbol.dispose property. +info: | + DisposableStack.prototype.use ( value ) + + 1. Let disposableStack be the this value. + 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]). + 3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception. + 4. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], value, sync-dispose). + ... + + AddDisposableResource ( disposeCapability, V, hint [, method ] ) + + 1. If method is not present then, + a. If V is either null or undefined and hint is sync-dispose, then + i. Return unused + b. Let resource be ? CreateDisposableResource(V, hint). + ... + + CreateDisposableResource ( V, hint [ , method ] ) + + 1. If method is not present, then + a. If V is either null or undefined, then + i. Set V to undefined + ii. Set method to undefined + b. Else, + i. If Type(V) is not Object, throw a TypeError exception. + ii. Set method to ? GetDisposeMethod(V, hint). + iii. If method is undefined, throw a TypeError exception. + ... + + GetDisposeMethod ( V, hint ) + + 1. If hint is async-dispose, then + a. Let method be ? GetMethod(V, @@asyncDispose). + b. If method is undefined, then + i. Set method to ? GetMethod(V, @@dispose). + 2. Else, + a. Let method be ? GetMethod(V, @@dispose). + 3. Return method. + + GetMethod ( V, P ) + + 1. Let func be ? GetV(V, P). + 2. If func is either undefined or null, return undefined. + 3. ... + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); +assert.throws(TypeError, function() { + stack.use({ [Symbol.dispose]: undefined }); +}, 'true'); diff --git a/test/built-ins/DisposableStack/prototype/use/throws-if-value-Symbol.dispose-property-not-callable.js b/test/built-ins/DisposableStack/prototype/use/throws-if-value-Symbol.dispose-property-not-callable.js new file mode 100644 index 0000000000..2fd597cf4d --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/use/throws-if-value-Symbol.dispose-property-not-callable.js @@ -0,0 +1,78 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.use +description: Throws if the argument has a non-null, non-undefined, non-callable Symbol.dispose property. +info: | + DisposableStack.prototype.use ( value ) + + 1. Let disposableStack be the this value. + 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]). + 3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception. + 4. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], value, sync-dispose). + ... + + AddDisposableResource ( disposeCapability, V, hint [, method ] ) + + 1. If method is not present then, + a. If V is either null or undefined and hint is sync-dispose, then + i. Return unused + b. Let resource be ? CreateDisposableResource(V, hint). + ... + + CreateDisposableResource ( V, hint [ , method ] ) + + 1. If method is not present, then + a. If V is either null or undefined, then + i. Set V to undefined + ii. Set method to undefined + b. Else, + i. If Type(V) is not Object, throw a TypeError exception. + ii. Set method to ? GetDisposeMethod(V, hint). + iii. If method is undefined, throw a TypeError exception. + 2. Else, + a. ... + 3. Return the DisposableResource Record { [[ResourceValue]]: V, [[Hint]]: hint, [[DisposeMethod]]: method }. + + GetDisposeMethod ( V, hint ) + + 1. If hint is async-dispose, then + a. Let method be ? GetMethod(V, @@asyncDispose). + b. If method is undefined, then + i. Set method to ? GetMethod(V, @@dispose). + 2. Else, + a. Let method be ? GetMethod(V, @@dispose). + ... + + GetMethod ( V, P ) + + 1. Let func be ? GetV(V, P). + 2. If func is either undefined or null, return undefined. + 3. If IsCallable(func) is false, throw a TypeError exception. + ... + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); +assert.throws(TypeError, function() { + stack.use({ [Symbol.dispose]: true }); +}, 'true'); + +assert.throws(TypeError, function() { + stack.use({ [Symbol.dispose]: false }); +}, 'false'); + +assert.throws(TypeError, function() { + stack.use({ [Symbol.dispose]: 1 }); +}, 'number'); + +assert.throws(TypeError, function() { + stack.use({ [Symbol.dispose]: 'object' }); +}, 'string'); + +var s = Symbol(); +assert.throws(TypeError, function() { + stack.use({ [Symbol.dispose]: s }); +}, 'symbol'); diff --git a/test/built-ins/DisposableStack/prototype/use/throws-if-value-missing-Symbol.dispose.js b/test/built-ins/DisposableStack/prototype/use/throws-if-value-missing-Symbol.dispose.js new file mode 100644 index 0000000000..45f97346c9 --- /dev/null +++ b/test/built-ins/DisposableStack/prototype/use/throws-if-value-missing-Symbol.dispose.js @@ -0,0 +1,59 @@ +// Copyright (C) 2023 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-disposablestack.prototype.use +description: Throws if the argument is an object that does not have a Symbol.dispose property. +info: | + DisposableStack.prototype.use ( value ) + + 1. Let disposableStack be the this value. + 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]). + 3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception. + 4. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], value, sync-dispose). + ... + + AddDisposableResource ( disposeCapability, V, hint [, method ] ) + + 1. If method is not present then, + a. If V is either null or undefined and hint is sync-dispose, then + i. Return unused + b. Let resource be ? CreateDisposableResource(V, hint). + ... + + CreateDisposableResource ( V, hint [ , method ] ) + + 1. If method is not present, then + a. If V is either null or undefined, then + i. Set V to undefined + ii. Set method to undefined + b. Else, + i. If Type(V) is not Object, throw a TypeError exception. + ii. Set method to ? GetDisposeMethod(V, hint). + iii. If method is undefined, throw a TypeError exception. + ... + + GetDisposeMethod ( V, hint ) + + 1. If hint is async-dispose, then + a. Let method be ? GetMethod(V, @@asyncDispose). + b. If method is undefined, then + i. Set method to ? GetMethod(V, @@dispose). + 2. Else, + a. Let method be ? GetMethod(V, @@dispose). + 3. Return method. + + GetMethod ( V, P ) + + 1. Let func be ? GetV(V, P). + 2. If func is either undefined or null, return undefined. + 3. If IsCallable(func) is false, throw a TypeError exception. + ... + +features: [explicit-resource-management] +---*/ + +var stack = new DisposableStack(); +assert.throws(TypeError, function() { + stack.use({ }); +}, 'true');