From 93d63969bccbf8b4471b7c7fadc875099b7668d3 Mon Sep 17 00:00:00 2001 From: Daniel Minor Date: Mon, 5 May 2025 15:20:47 -0400 Subject: [PATCH] Add upsert tests (#4454) These tests are currently being executed in SpiderMonkey as `non262` tests, and were exported using the `test262-export.py` script. Linting errors were then corrected. --- features.txt | 4 ++ .../append-new-values-normalizes-zero-key.js | 28 ++++++++++ .../Map/getOrInsert/append-new-values.js | 50 +++++++++++++++++ ...-key-is-not-present-different-key-types.js | 48 ++++++++++++++++ ...does-not-have-mapdata-internal-slot-set.js | 26 +++++++++ ...-not-have-mapdata-internal-slot-weakmap.js | 26 +++++++++ .../does-not-have-mapdata-internal-slot.js | 35 ++++++++++++ .../upsert/Map/getOrInsert/getOrInsert.js | 30 ++++++++++ test/staging/upsert/Map/getOrInsert/length.js | 22 ++++++++ test/staging/upsert/Map/getOrInsert/name.js | 22 ++++++++ .../Map/getOrInsert/not-a-constructor.js | 30 ++++++++++ ...-key-is-not-present-different-key-types.js | 41 ++++++++++++++ ...e-if-key-is-present-different-key-types.js | 56 +++++++++++++++++++ .../returns-value-normalized-zero-key.js | 26 +++++++++ .../Map/getOrInsert/this-not-object-throw.js | 42 ++++++++++++++ .../append-new-values-normalizes-zero-key.js | 29 ++++++++++ .../getOrInsertComputed/append-new-values.js | 51 +++++++++++++++++ ...-key-is-not-present-different-key-types.js | 48 ++++++++++++++++ .../getOrInsertComputed/callbackfn-throws.js | 25 +++++++++ ...ypes-function-callbackfn-does-not-throw.js | 51 +++++++++++++++++ ...-not-evaluate-callbackfn-if-key-present.js | 37 ++++++++++++ ...does-not-have-mapdata-internal-slot-set.js | 26 +++++++++ ...-not-have-mapdata-internal-slot-weakmap.js | 26 +++++++++ .../getOrInsertComputed.js | 28 ++++++++++ .../upsert/Map/getOrInsertComputed/length.js | 22 ++++++++ .../upsert/Map/getOrInsertComputed/name.js | 22 ++++++++ .../getOrInsertComputed/not-a-constructor.js | 30 ++++++++++ .../not-a-function-callbackfn-throws.js | 50 +++++++++++++++++ .../overwrites-mutation-from-callbackfn.js | 34 +++++++++++ ...-key-is-not-present-different-key-types.js | 41 ++++++++++++++ ...e-if-key-is-present-different-key-types.js | 56 +++++++++++++++++++ .../returns-value-normalized-zero-key.js | 27 +++++++++ .../this-not-object-throw.js | 42 ++++++++++++++ .../getOrInsert/adds-object-element.js | 34 +++++++++++ .../getOrInsert/adds-symbol-element.js | 32 +++++++++++ ...ot-have-weakmapdata-internal-slot-array.js | 26 +++++++++ ...-not-have-weakmapdata-internal-slot-map.js | 26 +++++++++ ...t-have-weakmapdata-internal-slot-object.js | 26 +++++++++ ...-not-have-weakmapdata-internal-slot-set.js | 26 +++++++++ ...mapdata-internal-slot-weakmap-prototype.js | 26 +++++++++ .../upsert/WeakMap/getOrInsert/getOrInsert.js | 28 ++++++++++ .../upsert/WeakMap/getOrInsert/length.js | 22 ++++++++ .../upsert/WeakMap/getOrInsert/name.js | 22 ++++++++ .../WeakMap/getOrInsert/not-a-constructor.js | 33 +++++++++++ ...-value-if-key-is-not-present-object-key.js | 30 ++++++++++ ...-value-if-key-is-not-present-symbol-key.js | 31 ++++++++++ ...urns-value-if-key-is-present-object-key.js | 32 +++++++++++ ...urns-value-if-key-is-present-symbol-key.js | 34 +++++++++++ .../getOrInsert/this-not-object-throw.js | 46 +++++++++++++++ .../throw-if-key-cannot-be-held-weakly.js | 42 ++++++++++++++ .../adds-object-element.js | 34 +++++++++++ .../adds-symbol-element.js | 32 +++++++++++ .../adds-value-different-callbackfn.js | 55 ++++++++++++++++++ .../getOrInsertComputed/callbackfn-throws.js | 25 +++++++++ ...-not-evaluate-callbackfn-if-key-present.js | 37 ++++++++++++ ...ot-have-weakmapdata-internal-slot-array.js | 25 +++++++++ ...-not-have-weakmapdata-internal-slot-map.js | 25 +++++++++ ...t-have-weakmapdata-internal-slot-object.js | 25 +++++++++ ...-not-have-weakmapdata-internal-slot-set.js | 25 +++++++++ ...mapdata-internal-slot-weakmap-prototype.js | 25 +++++++++ .../getOrInsertComputed.js | 28 ++++++++++ .../WeakMap/getOrInsertComputed/length.js | 22 ++++++++ .../WeakMap/getOrInsertComputed/name.js | 22 ++++++++ .../getOrInsertComputed/not-a-constructor.js | 33 +++++++++++ .../not-a-function-callbackfn-throws.js | 51 +++++++++++++++++ .../overwrites-mutation-from-callbackfn.js | 34 +++++++++++ ...-value-if-key-is-not-present-object-key.js | 28 ++++++++++ ...-value-if-key-is-not-present-symbol-key.js | 27 +++++++++ ...urns-value-if-key-is-present-object-key.js | 32 +++++++++++ ...urns-value-if-key-is-present-symbol-key.js | 35 ++++++++++++ .../this-not-object-throw.js | 46 +++++++++++++++ .../throw-if-key-cannot-be-held-weakly.js | 42 ++++++++++++++ 72 files changed, 2355 insertions(+) create mode 100644 test/staging/upsert/Map/getOrInsert/append-new-values-normalizes-zero-key.js create mode 100644 test/staging/upsert/Map/getOrInsert/append-new-values.js create mode 100644 test/staging/upsert/Map/getOrInsert/append-value-if-key-is-not-present-different-key-types.js create mode 100644 test/staging/upsert/Map/getOrInsert/does-not-have-mapdata-internal-slot-set.js create mode 100644 test/staging/upsert/Map/getOrInsert/does-not-have-mapdata-internal-slot-weakmap.js create mode 100644 test/staging/upsert/Map/getOrInsert/does-not-have-mapdata-internal-slot.js create mode 100644 test/staging/upsert/Map/getOrInsert/getOrInsert.js create mode 100644 test/staging/upsert/Map/getOrInsert/length.js create mode 100644 test/staging/upsert/Map/getOrInsert/name.js create mode 100644 test/staging/upsert/Map/getOrInsert/not-a-constructor.js create mode 100644 test/staging/upsert/Map/getOrInsert/returns-value-if-key-is-not-present-different-key-types.js create mode 100644 test/staging/upsert/Map/getOrInsert/returns-value-if-key-is-present-different-key-types.js create mode 100644 test/staging/upsert/Map/getOrInsert/returns-value-normalized-zero-key.js create mode 100644 test/staging/upsert/Map/getOrInsert/this-not-object-throw.js create mode 100644 test/staging/upsert/Map/getOrInsertComputed/append-new-values-normalizes-zero-key.js create mode 100644 test/staging/upsert/Map/getOrInsertComputed/append-new-values.js create mode 100644 test/staging/upsert/Map/getOrInsertComputed/append-value-if-key-is-not-present-different-key-types.js create mode 100644 test/staging/upsert/Map/getOrInsertComputed/callbackfn-throws.js create mode 100644 test/staging/upsert/Map/getOrInsertComputed/different-types-function-callbackfn-does-not-throw.js create mode 100644 test/staging/upsert/Map/getOrInsertComputed/does-not-evaluate-callbackfn-if-key-present.js create mode 100644 test/staging/upsert/Map/getOrInsertComputed/does-not-have-mapdata-internal-slot-set.js create mode 100644 test/staging/upsert/Map/getOrInsertComputed/does-not-have-mapdata-internal-slot-weakmap.js create mode 100644 test/staging/upsert/Map/getOrInsertComputed/getOrInsertComputed.js create mode 100644 test/staging/upsert/Map/getOrInsertComputed/length.js create mode 100644 test/staging/upsert/Map/getOrInsertComputed/name.js create mode 100644 test/staging/upsert/Map/getOrInsertComputed/not-a-constructor.js create mode 100644 test/staging/upsert/Map/getOrInsertComputed/not-a-function-callbackfn-throws.js create mode 100644 test/staging/upsert/Map/getOrInsertComputed/overwrites-mutation-from-callbackfn.js create mode 100644 test/staging/upsert/Map/getOrInsertComputed/returns-value-if-key-is-not-present-different-key-types.js create mode 100644 test/staging/upsert/Map/getOrInsertComputed/returns-value-if-key-is-present-different-key-types.js create mode 100644 test/staging/upsert/Map/getOrInsertComputed/returns-value-normalized-zero-key.js create mode 100644 test/staging/upsert/Map/getOrInsertComputed/this-not-object-throw.js create mode 100644 test/staging/upsert/WeakMap/getOrInsert/adds-object-element.js create mode 100644 test/staging/upsert/WeakMap/getOrInsert/adds-symbol-element.js create mode 100644 test/staging/upsert/WeakMap/getOrInsert/does-not-have-weakmapdata-internal-slot-array.js create mode 100644 test/staging/upsert/WeakMap/getOrInsert/does-not-have-weakmapdata-internal-slot-map.js create mode 100644 test/staging/upsert/WeakMap/getOrInsert/does-not-have-weakmapdata-internal-slot-object.js create mode 100644 test/staging/upsert/WeakMap/getOrInsert/does-not-have-weakmapdata-internal-slot-set.js create mode 100644 test/staging/upsert/WeakMap/getOrInsert/does-not-have-weakmapdata-internal-slot-weakmap-prototype.js create mode 100644 test/staging/upsert/WeakMap/getOrInsert/getOrInsert.js create mode 100644 test/staging/upsert/WeakMap/getOrInsert/length.js create mode 100644 test/staging/upsert/WeakMap/getOrInsert/name.js create mode 100644 test/staging/upsert/WeakMap/getOrInsert/not-a-constructor.js create mode 100644 test/staging/upsert/WeakMap/getOrInsert/returns-value-if-key-is-not-present-object-key.js create mode 100644 test/staging/upsert/WeakMap/getOrInsert/returns-value-if-key-is-not-present-symbol-key.js create mode 100644 test/staging/upsert/WeakMap/getOrInsert/returns-value-if-key-is-present-object-key.js create mode 100644 test/staging/upsert/WeakMap/getOrInsert/returns-value-if-key-is-present-symbol-key.js create mode 100644 test/staging/upsert/WeakMap/getOrInsert/this-not-object-throw.js create mode 100644 test/staging/upsert/WeakMap/getOrInsert/throw-if-key-cannot-be-held-weakly.js create mode 100644 test/staging/upsert/WeakMap/getOrInsertComputed/adds-object-element.js create mode 100644 test/staging/upsert/WeakMap/getOrInsertComputed/adds-symbol-element.js create mode 100644 test/staging/upsert/WeakMap/getOrInsertComputed/adds-value-different-callbackfn.js create mode 100644 test/staging/upsert/WeakMap/getOrInsertComputed/callbackfn-throws.js create mode 100644 test/staging/upsert/WeakMap/getOrInsertComputed/does-not-evaluate-callbackfn-if-key-present.js create mode 100644 test/staging/upsert/WeakMap/getOrInsertComputed/does-not-have-weakmapdata-internal-slot-array.js create mode 100644 test/staging/upsert/WeakMap/getOrInsertComputed/does-not-have-weakmapdata-internal-slot-map.js create mode 100644 test/staging/upsert/WeakMap/getOrInsertComputed/does-not-have-weakmapdata-internal-slot-object.js create mode 100644 test/staging/upsert/WeakMap/getOrInsertComputed/does-not-have-weakmapdata-internal-slot-set.js create mode 100644 test/staging/upsert/WeakMap/getOrInsertComputed/does-not-have-weakmapdata-internal-slot-weakmap-prototype.js create mode 100644 test/staging/upsert/WeakMap/getOrInsertComputed/getOrInsertComputed.js create mode 100644 test/staging/upsert/WeakMap/getOrInsertComputed/length.js create mode 100644 test/staging/upsert/WeakMap/getOrInsertComputed/name.js create mode 100644 test/staging/upsert/WeakMap/getOrInsertComputed/not-a-constructor.js create mode 100644 test/staging/upsert/WeakMap/getOrInsertComputed/not-a-function-callbackfn-throws.js create mode 100644 test/staging/upsert/WeakMap/getOrInsertComputed/overwrites-mutation-from-callbackfn.js create mode 100644 test/staging/upsert/WeakMap/getOrInsertComputed/returns-value-if-key-is-not-present-object-key.js create mode 100644 test/staging/upsert/WeakMap/getOrInsertComputed/returns-value-if-key-is-not-present-symbol-key.js create mode 100644 test/staging/upsert/WeakMap/getOrInsertComputed/returns-value-if-key-is-present-object-key.js create mode 100644 test/staging/upsert/WeakMap/getOrInsertComputed/returns-value-if-key-is-present-symbol-key.js create mode 100644 test/staging/upsert/WeakMap/getOrInsertComputed/this-not-object-throw.js create mode 100644 test/staging/upsert/WeakMap/getOrInsertComputed/throw-if-key-cannot-be-held-weakly.js diff --git a/features.txt b/features.txt index 95b34248e3..32b993763d 100644 --- a/features.txt +++ b/features.txt @@ -96,6 +96,10 @@ iterator-sequencing # https://github.com/tc39/proposal-canonical-tz canonical-tz +# Upsert +# https://github.com/tc39/proposal-upsert +upsert + ## Standard language features # # Language features that have been included in a published version of the diff --git a/test/staging/upsert/Map/getOrInsert/append-new-values-normalizes-zero-key.js b/test/staging/upsert/Map/getOrInsert/append-new-values-normalizes-zero-key.js new file mode 100644 index 0000000000..27cc24e814 --- /dev/null +++ b/test/staging/upsert/Map/getOrInsert/append-new-values-normalizes-zero-key.js @@ -0,0 +1,28 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2024 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Append a new value in the map normalizing +0 and -0. +info: | + Map.prototype.getOrInsert ( key , value ) + + ... + 3. Set key to CanonicalizeKeyedCollectionKey(key). + 4. For each Record { [[Key]], [[Value]] } p of M.[[MapData]], do + a. If p.[[Key]] is not empty and SameValue(p.[[Key]], key) is true, return p.[[Value]]. + 5. Let p be the Record { [[Key]]: key, [[Value]]: value }. + 6. Append p to M.[[MapData]]. + ... +features: [Symbol, upsert] +flags: [noStrict] +---*/ +var map = new Map(); +map.getOrInsert(-0, 42); +assert.sameValue(map.get(0), 42); + +map = new Map(); +map.getOrInsert(+0, 43); +assert.sameValue(map.get(0), 43); + diff --git a/test/staging/upsert/Map/getOrInsert/append-new-values.js b/test/staging/upsert/Map/getOrInsert/append-new-values.js new file mode 100644 index 0000000000..798f3be26b --- /dev/null +++ b/test/staging/upsert/Map/getOrInsert/append-new-values.js @@ -0,0 +1,50 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2024 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Append a new value as the last element of entries. +info: | + Map.prototype.getOrInsert ( key , value ) + + ... + 3. Set key to CanonicalizeKeyedCollectionKey(key). + 4. For each Record { [[Key]], [[Value]] } p of M.[[MapData]], do + a. If p.[[Key]] is not empty and SameValue(p.[[Key]], key) is true, return p.[[Value]]. + 5. Let p be the Record { [[Key]]: key, [[Value]]: value }. + 6. Append p to M.[[MapData]]. + ... +features: [Symbol, upsert] +flags: [noStrict] +---*/ +var s = Symbol(2); +var map = new Map([[4, 4], ['foo3', 3], [s, 2]]); + +map.getOrInsert(null, 42); +map.getOrInsert(1, 'valid'); + +assert.sameValue(map.size, 5); +assert.sameValue(map.get(1), 'valid'); + +var results = []; + +map.forEach(function(value, key) { + results.push({ + value: value, + key: key + }); +}); + +var result = results.pop(); +assert.sameValue(result.value, 'valid'); +assert.sameValue(result.key, 1); + +result = results.pop(); +assert.sameValue(result.value, 42); +assert.sameValue(result.key, null); + +result = results.pop(); +assert.sameValue(result.value, 2); +assert.sameValue(result.key, s); + diff --git a/test/staging/upsert/Map/getOrInsert/append-value-if-key-is-not-present-different-key-types.js b/test/staging/upsert/Map/getOrInsert/append-value-if-key-is-not-present-different-key-types.js new file mode 100644 index 0000000000..e139c10666 --- /dev/null +++ b/test/staging/upsert/Map/getOrInsert/append-value-if-key-is-not-present-different-key-types.js @@ -0,0 +1,48 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2024 Sune Eriksson Lianes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Inserts the value for the specified key on different types, when key not present. +info: | + Map.prototype.getOrInsert ( key , value ) + + ... + 5. Let p be the Record { [[Key]]: key, [[Value]]: value }. + 6. Append p to M.[[MapData]]. + ... +features: [Symbol, upsert] +flags: [noStrict] +---*/ +var map = new Map(); + +map.getOrInsert('bar', 0); +assert.sameValue(map.get('bar'), 0); + +map.getOrInsert(1, 42); +assert.sameValue(map.get(1), 42); + +map.getOrInsert(NaN, 1); +assert.sameValue(map.get(NaN), 1); + +var item = {}; +map.getOrInsert(item, 2); +assert.sameValue(map.get(item), 2); + +item = []; +map.getOrInsert(item, 3); +assert.sameValue(map.get(item), 3); + +item = Symbol('item'); +map.getOrInsert(item, 4); +assert.sameValue(map.get(item), 4); + +item = null; +map.getOrInsert(item, 5); +assert.sameValue(map.get(item), 5); + +item = undefined; +map.getOrInsert(item, 6); +assert.sameValue(map.get(item), 6); + diff --git a/test/staging/upsert/Map/getOrInsert/does-not-have-mapdata-internal-slot-set.js b/test/staging/upsert/Map/getOrInsert/does-not-have-mapdata-internal-slot-set.js new file mode 100644 index 0000000000..502dd022b3 --- /dev/null +++ b/test/staging/upsert/Map/getOrInsert/does-not-have-mapdata-internal-slot-set.js @@ -0,0 +1,26 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2024 Sune Eriksson Lianes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Throws a TypeError if `this` is a Set Object +info: | + Map.prototype.getOrInsert ( key , value ) + + ... + 1. Let M be the this value. + 2. Perform ? RequireInternalSlot(M, [[MapData]]) + ... +features: [Set, upsert] +flags: [noStrict] +---*/ +assert.throws(TypeError, function () { + Map.prototype.getOrInsert.call(new Set(), 1, 1); +}); + +assert.throws(TypeError, function () { + var map = new Map(); + map.getOrInsert.call(new Set(), 1, 1); +}); + diff --git a/test/staging/upsert/Map/getOrInsert/does-not-have-mapdata-internal-slot-weakmap.js b/test/staging/upsert/Map/getOrInsert/does-not-have-mapdata-internal-slot-weakmap.js new file mode 100644 index 0000000000..b661b72316 --- /dev/null +++ b/test/staging/upsert/Map/getOrInsert/does-not-have-mapdata-internal-slot-weakmap.js @@ -0,0 +1,26 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2024 Sune Eriksson Lianes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Throws a TypeError if `this` is a WeakMap object. +info: | + Map.prototype.getOrInsert ( key , value ) + + ... + 1. Let M be the this value. + 2. Perform ? RequireInternalSlot(M, [[MapData]]). + ... +features: [WeakMap, upsert] +flags: [noStrict] +---*/ +assert.throws(TypeError, function() { + Map.prototype.getOrInsert.call(new WeakMap(), 1, 1); +}); + +assert.throws(TypeError, function() { + var map = new Map(); + map.getOrInsert.call(new WeakMap(), 1, 1); +}); + diff --git a/test/staging/upsert/Map/getOrInsert/does-not-have-mapdata-internal-slot.js b/test/staging/upsert/Map/getOrInsert/does-not-have-mapdata-internal-slot.js new file mode 100644 index 0000000000..0de1134cab --- /dev/null +++ b/test/staging/upsert/Map/getOrInsert/does-not-have-mapdata-internal-slot.js @@ -0,0 +1,35 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2024 Sune Eriksson Lianes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Throws a TypeError if `this` object does not have a [[MapData]] internal slot. +info: | + Map.getOrInsert ( key , value ) + + ... + 1. Let M be the this value. + 2. Perform ? RequireInternalSLot(M, [[MapData]]) + ... +features: [upsert] +flags: [noStrict] +---*/ +var map = new Map(); + +assert.throws(TypeError, function () { + Map.prototype.getOrInsert.call([], 1, 1); +}); + +assert.throws(TypeError, function () { + map.getOrInsert.call([], 1, 1); +}); + +assert.throws(TypeError, function () { + Map.prototype.getOrInsert.call({}, 1, 1); +}); + +assert.throws(TypeError, function () { + map.getOrInsert.call({}, 1, 1); +}); + diff --git a/test/staging/upsert/Map/getOrInsert/getOrInsert.js b/test/staging/upsert/Map/getOrInsert/getOrInsert.js new file mode 100644 index 0000000000..363557ca45 --- /dev/null +++ b/test/staging/upsert/Map/getOrInsert/getOrInsert.js @@ -0,0 +1,30 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2024 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Property type and descriptor. +info: | + Map.prototype.getOrInsert ( key , value ) + + 17 ECMAScript Standard Built-in Objects +includes: [propertyHelper.js] +features: [upsert] +flags: [noStrict] +---*/ +assert.sameValue( + typeof Map.prototype.getOrInsert, + 'function', + '`typeof Map.prototype.getOrInsert` is `function`' +); + + +verifyProperty(Map.prototype, "getOrInsert", { + value: Map.prototype.getOrInsert, + writable: true, + enumerable: false, + configurable: true +}); + + diff --git a/test/staging/upsert/Map/getOrInsert/length.js b/test/staging/upsert/Map/getOrInsert/length.js new file mode 100644 index 0000000000..1e449d67cc --- /dev/null +++ b/test/staging/upsert/Map/getOrInsert/length.js @@ -0,0 +1,22 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2024 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Map.prototype.getOrInsert.length value and descriptor. +info: | + Map.prototype.getOrInsert ( key , value ) + + 17 ECMAScript Standard Built-in Objects +includes: [propertyHelper.js] +features: [upsert] +flags: [noStrict] +---*/ +verifyProperty(Map.prototype.getOrInsert, "length", { + value: 2, + writable: false, + enumerable: false, + configurable: true +}); + diff --git a/test/staging/upsert/Map/getOrInsert/name.js b/test/staging/upsert/Map/getOrInsert/name.js new file mode 100644 index 0000000000..1063008ee9 --- /dev/null +++ b/test/staging/upsert/Map/getOrInsert/name.js @@ -0,0 +1,22 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2024 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Map.prototype.getOrInsert.name value and descriptor. +info: | + Map.prototype.getOrInsert ( key , value ) + + 17 ECMAScript Standard Built-in Objects +includes: [propertyHelper.js] +features: [upsert] +flags: [noStrict] +---*/ +verifyProperty(Map.prototype.getOrInsert, "name", { + value: "getOrInsert", + writable: false, + enumerable: false, + configurable: true +}); + diff --git a/test/staging/upsert/Map/getOrInsert/not-a-constructor.js b/test/staging/upsert/Map/getOrInsert/not-a-constructor.js new file mode 100644 index 0000000000..ae6d0e807f --- /dev/null +++ b/test/staging/upsert/Map/getOrInsert/not-a-constructor.js @@ -0,0 +1,30 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// Copyright (C) 2024 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: proposal-upsert +description: | + Map.prototype.getOrInsert 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: [Map, Reflect.construct, arrow-function, upsert] +flags: [noStrict] +---*/ +assert.sameValue(isConstructor(Map.prototype.getOrInsert), false, 'isConstructor(Map.prototype.getOrInsert) must return false'); + +assert.throws(TypeError, () => { + let m = new Map(); new m.getOrInsert(); +}); + diff --git a/test/staging/upsert/Map/getOrInsert/returns-value-if-key-is-not-present-different-key-types.js b/test/staging/upsert/Map/getOrInsert/returns-value-if-key-is-not-present-different-key-types.js new file mode 100644 index 0000000000..632e5dfc1a --- /dev/null +++ b/test/staging/upsert/Map/getOrInsert/returns-value-if-key-is-not-present-different-key-types.js @@ -0,0 +1,41 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2024 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Returns the value from the specified key on different types, when key not present. +info: | + Map.prototype.getOrInsert ( key , value ) + + ... + 5. Let p be the Record { [[Key]]: key, [[Value]]: value }. + 6. Append p to M.[[MapData]]. + 7. Return p.[[Value]]. + ... +features: [Symbol, upsert] +flags: [noStrict] +---*/ +var map = new Map(); + +assert.sameValue(map.getOrInsert('bar', 0), 0); + +assert.sameValue(map.getOrInsert(1, 42), 42); + +assert.sameValue(map.getOrInsert(NaN, 1), 1); + +var item = {}; +assert.sameValue(map.getOrInsert(item, 2), 2); + +item = []; +assert.sameValue(map.getOrInsert(item, 3), 3); + +item = Symbol('item'); +assert.sameValue(map.getOrInsert(item, 4), 4); + +item = null; +assert.sameValue(map.getOrInsert(item, 5), 5); + +item = undefined; +assert.sameValue(map.getOrInsert(item, 6), 6); + diff --git a/test/staging/upsert/Map/getOrInsert/returns-value-if-key-is-present-different-key-types.js b/test/staging/upsert/Map/getOrInsert/returns-value-if-key-is-present-different-key-types.js new file mode 100644 index 0000000000..5fbd65bcdb --- /dev/null +++ b/test/staging/upsert/Map/getOrInsert/returns-value-if-key-is-present-different-key-types.js @@ -0,0 +1,56 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2024 Sune Eriksson Lianes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Returns the value set before getOrInsert from the specified key on different types. +info: | + Map.prototype.getOrInsert ( key , value ) + + ... + 4. For each Record { [[Key]], [[Value]] } p of M.[[MapData]], do + a. If p.[[Key]] is not empty and SameValue(p.[[Key]], key) is true, return p.[[Value]]. + ... +features: [Symbol, upsert] +flags: [noStrict] +---*/ +var map = new Map(); + +map.set('bar', 0); +assert.sameValue(map.get('bar'), map.getOrInsert('bar', 1)); +assert.sameValue(0, map.getOrInsert('bar', 1)); + +map.set(1, 42); +assert.sameValue(map.get(1), map.getOrInsert(1, 43)); +assert.sameValue(42, map.getOrInsert(1, 43)); + +map.set(NaN, 1); +assert.sameValue(map.get(NaN), map.getOrInsert(NaN, 2)); +assert.sameValue(1, map.getOrInsert(NaN, 2)); + +var item = {}; +map.set(item, 2); +assert.sameValue(map.get(item), map.getOrInsert(item, 3)); +assert.sameValue(2, map.getOrInsert(item, 3)); + +item = []; +map.set(item, 3); +assert.sameValue(map.get(item), map.getOrInsert(item, 4)); +assert.sameValue(3, map.getOrInsert(item, 4)); + +item = Symbol('item'); +map.set(item, 4); +assert.sameValue(map.get(item), map.getOrInsert(item, 5)); +assert.sameValue(4, map.getOrInsert(item, 5)); + +item = null; +map.set(item, 5); +assert.sameValue(map.get(item), map.getOrInsert(item, 6)); +assert.sameValue(5, map.getOrInsert(item, 6)); + +item = undefined; +map.set(item, 6); +assert.sameValue(map.get(item), map.getOrInsert(item, 7)); +assert.sameValue(6, map.getOrInsert(item, 7)); + diff --git a/test/staging/upsert/Map/getOrInsert/returns-value-normalized-zero-key.js b/test/staging/upsert/Map/getOrInsert/returns-value-normalized-zero-key.js new file mode 100644 index 0000000000..4d03e3e8a4 --- /dev/null +++ b/test/staging/upsert/Map/getOrInsert/returns-value-normalized-zero-key.js @@ -0,0 +1,26 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2024 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Returns the value from the specified key normalizing +0 and -0. +info: | + Map.prototype.getOrInsert ( key , value ) + + 5. Set key to CanonicalizeKeyedCollectionKey(key). + 4. For each Record { [[Key]], [[Value]] } p of M.[[MapData]], do + a. If p.[[Key]] is not empty and SameValue(p.[[Key]], key) is true, return p.[[Value]]. + ... +features: [upsert] +flags: [noStrict] +---*/ +var map = new Map(); + +map.set(+0, 42); +assert.sameValue(map.getOrInsert(-0, 1), 42); + +map = new Map(); +map.set(-0, 43); +assert.sameValue(map.getOrInsert(+0, 1), 43); + diff --git a/test/staging/upsert/Map/getOrInsert/this-not-object-throw.js b/test/staging/upsert/Map/getOrInsert/this-not-object-throw.js new file mode 100644 index 0000000000..6a00fa8f9d --- /dev/null +++ b/test/staging/upsert/Map/getOrInsert/this-not-object-throw.js @@ -0,0 +1,42 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2024 Sune Eriksson Lianes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Throws a TypeError if `this` is not an Object. +info: | + Map.prototype.getOrInsert ( key , value ) + + 1. Let M be the this value + 2. Perform ? RequireInternalSlot(M, [[MapData]]) + ... +features: [Symbol, upsert] +flags: [noStrict] +---*/ +var m = new Map(); + +assert.throws(TypeError, function () { + m.getOrInsert.call(false, 1, 1); +}); + +assert.throws(TypeError, function () { + m.getOrInsert.call(1, 1, 1); +}); + +assert.throws(TypeError, function () { + m.getOrInsert.call("", 1, 1); +}); + +assert.throws(TypeError, function () { + m.getOrInsert.call(undefined, 1, 1); +}); + +assert.throws(TypeError, function () { + m.getOrInsert.call(null, 1, 1); +}); + +assert.throws(TypeError, function () { + m.getOrInsert.call(Symbol(), 1, 1); +}); + diff --git a/test/staging/upsert/Map/getOrInsertComputed/append-new-values-normalizes-zero-key.js b/test/staging/upsert/Map/getOrInsertComputed/append-new-values-normalizes-zero-key.js new file mode 100644 index 0000000000..a66b824423 --- /dev/null +++ b/test/staging/upsert/Map/getOrInsertComputed/append-new-values-normalizes-zero-key.js @@ -0,0 +1,29 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2024 Jonas Haukenes, Mathias Ness. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Append a new value in the map normalizing +0 and -0. +info: | + Map.prototype.getOrInsertComputed ( key , callbackfn ) + + ... + 4. Set key to CanonicalizeKeyedCollectionKey(key). + 5. For each Record { [[Key]], [[Value]] } p of M.[[MapData]], do + a. If p.[[Key]] is not empty and SameValue(p.[[Key]], key) is true, return p.[[Value]]. + 6. Let value be ? Call(callbackfn, key). + 7. Let p be the Record { [[Key]]: key, [[Value]]: value }. + 8. Append p to M.[[MapData]]. + ... +features: [Symbol, arrow-function, upsert] +flags: [noStrict] +---*/ +var map = new Map(); +map.getOrInsertComputed(-0, () => 42); +assert.sameValue(map.get(0), 42); + +map = new Map(); +map.getOrInsertComputed(+0, () => 43); +assert.sameValue(map.get(0), 43); + diff --git a/test/staging/upsert/Map/getOrInsertComputed/append-new-values.js b/test/staging/upsert/Map/getOrInsertComputed/append-new-values.js new file mode 100644 index 0000000000..c530cab728 --- /dev/null +++ b/test/staging/upsert/Map/getOrInsertComputed/append-new-values.js @@ -0,0 +1,51 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2024 Jonas Haukenes, Mathias Ness. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Append a new value as the last element of entries. +info: | + Map.prototype.getOrInsertComputed ( key , callbackfn ) + + ... + 4. Set key to CanonicalizeKeyedCollectionKey(key). + 5. For each Record { [[Key]], [[Value]] } p of M.[[MapData]], do + a. If p.[[Key]] is not empty and SameValue(p.[[Key]], key) is true, return p.[[Value]]. + 6. Let value be ? Call(callbackfn, key). + 7. Let p be the Record { [[Key]]: key, [[Value]]: value }. + 8. Append p to M.[[MapData]]. + ... +features: [Symbol, arrow-function, upsert] +flags: [noStrict] +---*/ +var s = Symbol(2); +var map = new Map([[4, 4], ['foo3', 3], [s, 2]]); + +map.getOrInsertComputed(null, () => 42); +map.getOrInsertComputed(1, () => 'valid'); + +assert.sameValue(map.size, 5); +assert.sameValue(map.get(1), 'valid'); + +var results = []; + +map.forEach(function(value, key) { + results.push({ + value: value, + key: key + }); +}); + +var result = results.pop(); +assert.sameValue(result.value, 'valid'); +assert.sameValue(result.key, 1); + +result = results.pop(); +assert.sameValue(result.value, 42); +assert.sameValue(result.key, null); + +result = results.pop(); +assert.sameValue(result.value, 2); +assert.sameValue(result.key, s); + diff --git a/test/staging/upsert/Map/getOrInsertComputed/append-value-if-key-is-not-present-different-key-types.js b/test/staging/upsert/Map/getOrInsertComputed/append-value-if-key-is-not-present-different-key-types.js new file mode 100644 index 0000000000..6f1833bf54 --- /dev/null +++ b/test/staging/upsert/Map/getOrInsertComputed/append-value-if-key-is-not-present-different-key-types.js @@ -0,0 +1,48 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2024 Sune Eriksson Lianes, Mathias Ness. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Inserts the value for the specified key on different types, when key not present. +info: | + Map.prototype.getOrInsertComputed ( key , callbackfn ) + + ... + 7. Let p be the Record { [[Key]]: key, [[Value]]: value }. + 8. Append p to M.[[MapData]]. + ... +features: [Symbol, arrow-function, upsert] +flags: [noStrict] +---*/ +var map = new Map(); + +map.getOrInsertComputed('bar', () => 0); +assert.sameValue(map.get('bar'), 0); + +map.getOrInsertComputed(1, () => 42); +assert.sameValue(map.get(1), 42); + +map.getOrInsertComputed(NaN, () => 1); +assert.sameValue(map.get(NaN), 1); + +var item = {}; +map.getOrInsertComputed(item, () => 2); +assert.sameValue(map.get(item), 2); + +item = []; +map.getOrInsertComputed(item, () => 3); +assert.sameValue(map.get(item), 3); + +item = Symbol('item'); +map.getOrInsertComputed(item, () => 4); +assert.sameValue(map.get(item), 4); + +item = null; +map.getOrInsertComputed(item, () => 5); +assert.sameValue(map.get(item), 5); + +item = undefined; +map.getOrInsertComputed(item, () => 6); +assert.sameValue(map.get(item), 6); + diff --git a/test/staging/upsert/Map/getOrInsertComputed/callbackfn-throws.js b/test/staging/upsert/Map/getOrInsertComputed/callbackfn-throws.js new file mode 100644 index 0000000000..f011a0367f --- /dev/null +++ b/test/staging/upsert/Map/getOrInsertComputed/callbackfn-throws.js @@ -0,0 +1,25 @@ +// Copyright (C) 2024 Jonas Haukenes, Mathias Ness. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: proposal-upsert +description: | + Map.getOrInsertComputed throws when callbackfn throws return if abrubt completion Call(callbackfn, key) +info: | + Map.prototype.getOrInsertComputed ( key , callbackfn ) + + ... + + 6. Let value be ? Call(callbackfn, key). + ... +features: [upsert] +flags: [noStrict] +---*/ +var map = new Map(); + +assert.throws(Error, function() { + map.getOrInsertComputed(1, function() { + throw new Error('throw in callback'); + }) +}, Error); + diff --git a/test/staging/upsert/Map/getOrInsertComputed/different-types-function-callbackfn-does-not-throw.js b/test/staging/upsert/Map/getOrInsertComputed/different-types-function-callbackfn-does-not-throw.js new file mode 100644 index 0000000000..c5bc7951fc --- /dev/null +++ b/test/staging/upsert/Map/getOrInsertComputed/different-types-function-callbackfn-does-not-throw.js @@ -0,0 +1,51 @@ +// Copyright (C) 2024 Mathias Ness. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Does not throw if `callbackfn` is callable. +info: | + Map.prototype.getOrInsertComputed ( key , callbackfn ) + + ... + 3. If IsCallable(callbackfn) is false, throw a TypeError exception. + ... + +features: [arrow-function, upsert] +flags: [noStrict] +---*/ +var m = new Map(); + + +assert.sameValue( + m.getOrInsertComputed(1, function() {return 1;}) + , 1); +assert.sameValue(m.get(1), 1); + + +assert.sameValue( + m.getOrInsertComputed(2, () => 2) + , 2); +assert.sameValue(m.get(2), 2); + + +function three() {return 3;} + +assert.sameValue( + m.getOrInsertComputed(3, three) + , 3); +assert.sameValue(m.get(3), 3); + + +assert.sameValue( + m.getOrInsertComputed(4, new Function()) + , undefined); +assert.sameValue(m.get(4), undefined); + + +assert.sameValue( + m.getOrInsertComputed(5, (function() {return 5;}).bind(m)) + , 5); +assert.sameValue(m.get(5), 5); + + diff --git a/test/staging/upsert/Map/getOrInsertComputed/does-not-evaluate-callbackfn-if-key-present.js b/test/staging/upsert/Map/getOrInsertComputed/does-not-evaluate-callbackfn-if-key-present.js new file mode 100644 index 0000000000..50e4d4ada0 --- /dev/null +++ b/test/staging/upsert/Map/getOrInsertComputed/does-not-evaluate-callbackfn-if-key-present.js @@ -0,0 +1,37 @@ +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Does not evaluate the callback function if the key is already in the map. +info: | + WeakMap.prototype.getOrInsertComputed ( key, callbackfn ) + + ... + 5. For each Record { [[Key]], [[Value]] } p of M.[[WeakMapData]], do + a. If p.[[Key]] is not empty and SameValue(p.[[Key]], key) is true, return p.[[Value]]. + 6. Let value be ? Call(callbackfn, undefined, « key »). + ... +features: [WeakMap, upsert] +flags: [noStrict] +---*/ +var map = new Map([ + [1, 0] +]); + +function callback() { + throw new Error('Callbackfn should not be evaluated if key is present'); +} + +assert.sameValue(map.getOrInsertComputed(1, callback), 0); + +map.set(2, 1); +assert.sameValue(map.getOrInsertComputed(2, callback), 1); + +map.set(3, 2); +assert.sameValue(map.getOrInsertComputed(3, callback), 2); + +assert.throws(Error, function() { + map.getOrInsertComputed(4, callback)} +, Error); + diff --git a/test/staging/upsert/Map/getOrInsertComputed/does-not-have-mapdata-internal-slot-set.js b/test/staging/upsert/Map/getOrInsertComputed/does-not-have-mapdata-internal-slot-set.js new file mode 100644 index 0000000000..c4323b9653 --- /dev/null +++ b/test/staging/upsert/Map/getOrInsertComputed/does-not-have-mapdata-internal-slot-set.js @@ -0,0 +1,26 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2024 Sune Eriksson Lianes, Mathias Ness. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Throws a TypeError if `this` is a Set Object +info: | + Map.prototype.getOrInsertComputed ( key , callbackfn ) + + ... + 1. Let M be the this value. + 2. Perform ? RequireInternalSlot(M, [[MapData]]) + ... +features: [Set, arrow-function, upsert] +flags: [noStrict] +---*/ +assert.throws(TypeError, function () { + Map.prototype.getOrInsertComputed.call(new Set(), 1, () => 1); +}); + +assert.throws(TypeError, function () { + var map = new Map(); + map.getOrInsertComputed.call(new Set(), 1, () => 1); +}); + diff --git a/test/staging/upsert/Map/getOrInsertComputed/does-not-have-mapdata-internal-slot-weakmap.js b/test/staging/upsert/Map/getOrInsertComputed/does-not-have-mapdata-internal-slot-weakmap.js new file mode 100644 index 0000000000..644bedb8a3 --- /dev/null +++ b/test/staging/upsert/Map/getOrInsertComputed/does-not-have-mapdata-internal-slot-weakmap.js @@ -0,0 +1,26 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2024 Sune Eriksson Lianes, Mathias Ness. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Throws a TypeError if `this` is a WeakMap object. +info: | + Map.prototype.getOrInsertComputed ( key , callbackfn ) + + ... + 1. Let M be the this value. + 2. Perform ? RequireInternalSlot(M, [[MapData]]). + ... +features: [WeakMap, arrow-function, upsert] +flags: [noStrict] +---*/ +assert.throws(TypeError, function() { + Map.prototype.getOrInsertComputed.call(new WeakMap(), 1, () => 1); +}); + +assert.throws(TypeError, function() { + var map = new Map(); + map.getOrInsertComputed.call(new WeakMap(), 1, () => 1); +}); + diff --git a/test/staging/upsert/Map/getOrInsertComputed/getOrInsertComputed.js b/test/staging/upsert/Map/getOrInsertComputed/getOrInsertComputed.js new file mode 100644 index 0000000000..14474c76c7 --- /dev/null +++ b/test/staging/upsert/Map/getOrInsertComputed/getOrInsertComputed.js @@ -0,0 +1,28 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2024 Jonas Haukenes, Mathias Ness. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Property type and descriptor. +info: | + Map.prototype.getOrInsertComputed ( key , callbackfn ) + + 17 ECMAScript Standard Built-in Objects +includes: [propertyHelper.js] +features: [arrow-function, upsert] +flags: [noStrict] +---*/ +assert.sameValue( + typeof Map.prototype.getOrInsertComputed, + 'function', + '`typeof Map.prototype.getOrInsertComputed` is `function`' +); + +verifyProperty(Map.prototype, "getOrInsertComputed", { + value: Map.prototype.getOrInsertComputed, + writable: true, + enumerable: false, + configurable: true +}); + diff --git a/test/staging/upsert/Map/getOrInsertComputed/length.js b/test/staging/upsert/Map/getOrInsertComputed/length.js new file mode 100644 index 0000000000..c440a5895a --- /dev/null +++ b/test/staging/upsert/Map/getOrInsertComputed/length.js @@ -0,0 +1,22 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2024 Jonas Haukenes, Mathias Ness. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Map.prototype.getOrInsert.length value and descriptor. +info: | + Map.prototype.getOrInsertComputed ( key , callbackfn ) + + 17 ECMAScript Standard Built-in Objects +includes: [propertyHelper.js] +features: [upsert] +flags: [noStrict] +---*/ +verifyProperty(Map.prototype.getOrInsertComputed, "length", { + value: 2, + writable: false, + enumerable: false, + configurable: true +}); + diff --git a/test/staging/upsert/Map/getOrInsertComputed/name.js b/test/staging/upsert/Map/getOrInsertComputed/name.js new file mode 100644 index 0000000000..e03adc274a --- /dev/null +++ b/test/staging/upsert/Map/getOrInsertComputed/name.js @@ -0,0 +1,22 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2024 Jonas Haukenes, Mathias Ness. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Map.prototype.getOrInsertComputed.name value and descriptor. +info: | + Map.prototype.getOrInsertComputed ( key , callbackfn ) + + 17 ECMAScript Standard Built-in Objects +includes: [propertyHelper.js] +features: [upsert] +flags: [noStrict] +---*/ +verifyProperty(Map.prototype.getOrInsertComputed, "name", { + value: "getOrInsertComputed", + writable: false, + enumerable: false, + configurable: true +}); + diff --git a/test/staging/upsert/Map/getOrInsertComputed/not-a-constructor.js b/test/staging/upsert/Map/getOrInsertComputed/not-a-constructor.js new file mode 100644 index 0000000000..c059cb40fb --- /dev/null +++ b/test/staging/upsert/Map/getOrInsertComputed/not-a-constructor.js @@ -0,0 +1,30 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// Copyright (C) 2024 Jonas Haukenes, Mathias Ness. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: proposal-upsert +description: | + Map.prototype.getOrInsertComputed 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: [Map, Reflect.construct, arrow-function, upsert] +flags: [noStrict] +---*/ +assert.sameValue(isConstructor(Map.prototype.getOrInsertComputed), false, 'isConstructor(Map.prototype.getOrInsertComputed) must return false'); + +assert.throws(TypeError, () => { + let m = new Map(); new m.getOrInsertComputed(); +}); + diff --git a/test/staging/upsert/Map/getOrInsertComputed/not-a-function-callbackfn-throws.js b/test/staging/upsert/Map/getOrInsertComputed/not-a-function-callbackfn-throws.js new file mode 100644 index 0000000000..6adc1eeabe --- /dev/null +++ b/test/staging/upsert/Map/getOrInsertComputed/not-a-function-callbackfn-throws.js @@ -0,0 +1,50 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2024 Mathias Ness. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Throws a TypeError if `callbackfn` is not callable. +info: | + Map.prototype.getOrInsertComputed ( key , callbackfn ) + + ... + 3. If IsCallable(callbackfn) is false, throw a TypeError exception. + ... +features: [Symbol, upsert] +flags: [noStrict] +---*/ +var m = new Map(); + +assert.throws(TypeError, function () { + m.getOrInsertComputed.call(m, 1, 1); +}); + +assert.throws(TypeError, function () { + m.getOrInsertComputed.call(m, 1, ""); +}); + +assert.throws(TypeError, function () { + m.getOrInsertComputed.call(m, 1, true); +}); + +assert.throws(TypeError, function () { + m.getOrInsertComputed.call(m, 1, undefined); +}); + +assert.throws(TypeError, function () { + m.getOrInsertComputed.call(m, 1, null); +}); + +assert.throws(TypeError, function () { + m.getOrInsertComputed.call(m, 1, {}); +}); + +assert.throws(TypeError, function () { + m.getOrInsertComputed.call(m, 1, []); +}); + +assert.throws(TypeError, function () { + m.getOrInsertComputed.call(m, 1, Symbol()); +}); + diff --git a/test/staging/upsert/Map/getOrInsertComputed/overwrites-mutation-from-callbackfn.js b/test/staging/upsert/Map/getOrInsertComputed/overwrites-mutation-from-callbackfn.js new file mode 100644 index 0000000000..3a2d1b054d --- /dev/null +++ b/test/staging/upsert/Map/getOrInsertComputed/overwrites-mutation-from-callbackfn.js @@ -0,0 +1,34 @@ +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + If the callbackfn inserts a value on the given key, the value is overwritten. +info: | + WeakMap.prototype.set ( key, value ) + + ... + 6. Let value be ? Call(callbackfn, undefined, « key »). + 7. For each Record { [[Key]], [[Value]] } p of M.[[WeakMapData]], do + a. If p.[[Key]] is not empty and SameValue(p.[[Key]], key) is true, then + i. Set p.[[Value]] to value. + ii. Return value. + 8. Let p be the Record { [[Key]]: key, [[Value]]: value }. + 9. Append p to M.[[WeakMapData]]. + ... +flags: [noStrict] +features: [upsert] +---*/ +var map = new Map(); +var foo = 1; +var bar = 2; +var baz = 3; + +map.getOrInsertComputed(foo, () => {map.set(foo, 0); return 3;}); +map.getOrInsertComputed(bar, () => {map.set(bar, 1)}); +map.getOrInsertComputed(baz, () => {map.set(baz, 2); return 'string';}); + +assert.sameValue(map.get(foo), 3); +assert.sameValue(map.get(bar), undefined); +assert.sameValue(map.get(baz), 'string'); + diff --git a/test/staging/upsert/Map/getOrInsertComputed/returns-value-if-key-is-not-present-different-key-types.js b/test/staging/upsert/Map/getOrInsertComputed/returns-value-if-key-is-not-present-different-key-types.js new file mode 100644 index 0000000000..6ee7df8bca --- /dev/null +++ b/test/staging/upsert/Map/getOrInsertComputed/returns-value-if-key-is-not-present-different-key-types.js @@ -0,0 +1,41 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2024 Jonas Haukenes, Mathias Ness. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Returns the value from the specified key on different types, when key not present. +info: | + Map.prototype.getOrInsertComputed ( key , callbackfn ) + + ... + 7. Let p be the Record { [[Key]]: key, [[Value]]: value }. + 8. Append p to M.[[MapData]]. + 9. Return p.[[Value]]. + ... +features: [Symbol, arrow-function, upsert] +flags: [noStrict] +---*/ +var map = new Map(); + +assert.sameValue(map.getOrInsertComputed('bar', () => 0), 0); + +assert.sameValue(map.getOrInsertComputed(1, () => 42), 42); + +assert.sameValue(map.getOrInsertComputed(NaN, () => 1), 1); + +var item = {}; +assert.sameValue(map.getOrInsertComputed(item, () => 2), 2); + +item = []; +assert.sameValue(map.getOrInsertComputed(item, () => 3), 3); + +item = Symbol('item'); +assert.sameValue(map.getOrInsertComputed(item, () => 4), 4); + +item = null; +assert.sameValue(map.getOrInsertComputed(item, () => 5), 5); + +item = undefined; +assert.sameValue(map.getOrInsertComputed(item, () => 6), 6); + diff --git a/test/staging/upsert/Map/getOrInsertComputed/returns-value-if-key-is-present-different-key-types.js b/test/staging/upsert/Map/getOrInsertComputed/returns-value-if-key-is-present-different-key-types.js new file mode 100644 index 0000000000..92790e0645 --- /dev/null +++ b/test/staging/upsert/Map/getOrInsertComputed/returns-value-if-key-is-present-different-key-types.js @@ -0,0 +1,56 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2024 Sune Eriksson Lianes, Mathias Ness. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Returns the value set before getOrInsertComputed from the specified key on different types. +info: | + Map.prototype.getOrInsertComputed ( key , callbackfn ) + + ... + 5. For each Record { [[Key]], [[Value]] } p of M.[[MapData]], do + a. If p.[[Key]] is not empty and SameValue(p.[[Key]], key) is true, return p.[[Value]]. + ... +features: [Symbol, arrow-function, upsert] +flags: [noStrict] +---*/ +var map = new Map(); + +map.set('bar', 0); +assert.sameValue(map.get('bar'), map.getOrInsertComputed('bar', () => 1)); +assert.sameValue(0, map.getOrInsertComputed('bar', () => 1)); + +map.set(1, 42); +assert.sameValue(map.get(1), map.getOrInsertComputed(1, () => 43)); +assert.sameValue(42, map.getOrInsertComputed(1, () => 43)); + +map.set(NaN, 1); +assert.sameValue(map.get(NaN), map.getOrInsertComputed(NaN, () => 2)); +assert.sameValue(1, map.getOrInsertComputed(NaN, () => 2)); + +var item = {}; +map.set(item, 2); +assert.sameValue(map.get(item), map.getOrInsertComputed(item, () => 3)); +assert.sameValue(2, map.getOrInsertComputed(item, () => 3)); + +item = []; +map.set(item, 3); +assert.sameValue(map.get(item), map.getOrInsertComputed(item, () => 4)); +assert.sameValue(3, map.getOrInsertComputed(item, () => 4)); + +item = Symbol('item'); +map.set(item, 4); +assert.sameValue(map.get(item), map.getOrInsertComputed(item, () => 5)); +assert.sameValue(4, map.getOrInsertComputed(item, () => 5)); + +item = null; +map.set(item, 5); +assert.sameValue(map.get(item), map.getOrInsertComputed(item, () => 6)); +assert.sameValue(5, map.getOrInsertComputed(item, () => 6)); + +item = undefined; +map.set(item, 6); +assert.sameValue(map.get(item), map.getOrInsertComputed(item, () => 7)); +assert.sameValue(6, map.getOrInsertComputed(item, () => 7)); + diff --git a/test/staging/upsert/Map/getOrInsertComputed/returns-value-normalized-zero-key.js b/test/staging/upsert/Map/getOrInsertComputed/returns-value-normalized-zero-key.js new file mode 100644 index 0000000000..a08f873ef6 --- /dev/null +++ b/test/staging/upsert/Map/getOrInsertComputed/returns-value-normalized-zero-key.js @@ -0,0 +1,27 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2024 Jonas Haukenes, Mathias Ness. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Returns the value from the specified key normalizing +0 and -0. +info: | + Map.prototype.getOrInsertComputed ( key , Callbackfn ) + + 4. Set key to CanonicalizeKeyedCollectionKey(key). + 5. For each Record { [[Key]], [[Value]] } p of M.[[MapData]], do + a. If p.[[Key]] is not empty and SameValue(p.[[Key]], key) is true, return p.[[Value]]. + ... + +features: [arrow-function, upsert] +flags: [noStrict] +---*/ +var map = new Map(); + +map.set(+0, 42); +assert.sameValue(map.getOrInsertComputed(-0, () => 1), 42); + +map = new Map(); +map.set(-0, 43); +assert.sameValue(map.getOrInsertComputed(+0, () => 1), 43); + diff --git a/test/staging/upsert/Map/getOrInsertComputed/this-not-object-throw.js b/test/staging/upsert/Map/getOrInsertComputed/this-not-object-throw.js new file mode 100644 index 0000000000..a671766289 --- /dev/null +++ b/test/staging/upsert/Map/getOrInsertComputed/this-not-object-throw.js @@ -0,0 +1,42 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2024 Sune Eriksson Lianes, Mathias Ness. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Throws a TypeError if `this` is not an Object. +info: | + Map.prototype.getOrInsertComputed ( key , callbackfn ) + + 1. Let M be the this value + 2. Perform ? RequireInternalSlot(M, [[MapData]]) + ... +features: [Symbol, arrow-function, upsert] +flags: [noStrict] +---*/ +var m = new Map(); + +assert.throws(TypeError, function () { + m.getOrInsertComputed.call(false, 1, () => 1); +}); + +assert.throws(TypeError, function () { + m.getOrInsertComputed.call(1, 1, () => 1); +}); + +assert.throws(TypeError, function () { + m.getOrInsertComputed.call("", 1, () => 1); +}); + +assert.throws(TypeError, function () { + m.getOrInsertComputed.call(undefined, 1, () => 1); +}); + +assert.throws(TypeError, function () { + m.getOrInsertComputed.call(null, 1, () => 1); +}); + +assert.throws(TypeError, function () { + m.getOrInsertComputed.call(Symbol(), 1, () => 1); +}); + diff --git a/test/staging/upsert/WeakMap/getOrInsert/adds-object-element.js b/test/staging/upsert/WeakMap/getOrInsert/adds-object-element.js new file mode 100644 index 0000000000..201beb40c5 --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsert/adds-object-element.js @@ -0,0 +1,34 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Adds a value with an Object key if key is not already in the map. +info: | + WeakMap.prototype.getOrInsert ( key, value ) + + ... + 5. Let p be the Record {[[Key]]: key, [[Value]]: value}. + 6. Append p to M.[[WeakMapData]]. + ... +features: [WeakMap, upsert] +flags: [noStrict] +---*/ +var map = new WeakMap(); +var foo = {}; +var bar = {}; +var baz = {}; + +map.getOrInsert(foo, 1); +map.getOrInsert(bar, 2); +map.getOrInsert(baz, 3); + +assert.sameValue(map.has(foo), true); +assert.sameValue(map.has(bar), true); +assert.sameValue(map.has(baz), true); + +assert.sameValue(map.get(foo), 1); +assert.sameValue(map.get(bar), 2); +assert.sameValue(map.get(baz), 3); + diff --git a/test/staging/upsert/WeakMap/getOrInsert/adds-symbol-element.js b/test/staging/upsert/WeakMap/getOrInsert/adds-symbol-element.js new file mode 100644 index 0000000000..5382ae96cf --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsert/adds-symbol-element.js @@ -0,0 +1,32 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Adds a value with a Symbol key if key is not already in the map. +info: | + WeakMap.prototype.getOrInsert ( key, value ) + + ... + 5. Let p be the Record {[[Key]]: key, [[Value]]: value}. + 6. Append p to M.[[WeakMapData]]. + ... +features: [Symbol, WeakMap, symbols-as-weakmap-keys, upsert] +flags: [noStrict] +---*/ +var map = new WeakMap(); +var foo = Symbol('a description'); +var bar = Symbol('a description'); + +map.getOrInsert(foo, 1); +map.getOrInsert(bar, 2); +map.getOrInsert(Symbol.hasInstance, 3); + +assert.sameValue(map.has(bar), true, 'Regular symbol as key'); +assert.sameValue(map.get(foo), 1, "Symbols with the same description don't overwrite each other"); +assert.sameValue(map.has(Symbol.hasInstance), true, 'Well-known symbol as key'); + +assert.sameValue(map.get(bar), 2); +assert.sameValue(map.get(Symbol.hasInstance), 3); + diff --git a/test/staging/upsert/WeakMap/getOrInsert/does-not-have-weakmapdata-internal-slot-array.js b/test/staging/upsert/WeakMap/getOrInsert/does-not-have-weakmapdata-internal-slot-array.js new file mode 100644 index 0000000000..9c7310c276 --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsert/does-not-have-weakmapdata-internal-slot-array.js @@ -0,0 +1,26 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Throws TypeError if `this` doesn't have a [[WeakMapData]] internal slot. +info: | + WeakMap.prototype.getOrInsert ( key, value ) + + ... + 1. Let M be the this value. + 2. Perform ? RequireInternalSlot(M, [[WeakMapData]]). + ... +features: [upsert] +flags: [noStrict] +---*/ +assert.throws(TypeError, function() { + WeakMap.prototype.getOrInsert.call([], {}, 1); +}); + +assert.throws(TypeError, function() { + var map = new WeakMap(); + map.getOrInsert.call([], {}, 1); +}); + diff --git a/test/staging/upsert/WeakMap/getOrInsert/does-not-have-weakmapdata-internal-slot-map.js b/test/staging/upsert/WeakMap/getOrInsert/does-not-have-weakmapdata-internal-slot-map.js new file mode 100644 index 0000000000..3c5abde074 --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsert/does-not-have-weakmapdata-internal-slot-map.js @@ -0,0 +1,26 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Throws TypeError if `this` doesn't have a [[WeakMapData]] internal slot. +info: | + WeakMap.prototype.getOrInsert ( key, value ) + + ... + 1. Let M be the this value. + 2. Perform ? RequireInternalSlot(M, [[WeakMapData]]). + ... +features: [Map, upsert] +flags: [noStrict] +---*/ +assert.throws(TypeError, function() { + WeakMap.prototype.getOrInsert.call(new Map(), {}, 1); +}); + +assert.throws(TypeError, function() { + var map = new WeakMap(); + map.getOrInsert.call(new Map(), {}, 1); +}); + diff --git a/test/staging/upsert/WeakMap/getOrInsert/does-not-have-weakmapdata-internal-slot-object.js b/test/staging/upsert/WeakMap/getOrInsert/does-not-have-weakmapdata-internal-slot-object.js new file mode 100644 index 0000000000..1afd5a4717 --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsert/does-not-have-weakmapdata-internal-slot-object.js @@ -0,0 +1,26 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Throws TypeError if `this` doesn't have a [[WeakMapData]] internal slot. +info: | + WeakMap.prototype.getOrInsert ( key, value ) + + ... + 1. Let M be the this value. + 2. Perform ? RequireInternalSlot(M, [[WeakMapData]]). + ... +features: [upsert] +flags: [noStrict] +---*/ +assert.throws(TypeError, function() { + WeakMap.prototype.getOrInsert.call({}, {}, 1); +}); + +assert.throws(TypeError, function() { + var map = new WeakMap(); + map.getOrInsert.call({}, {}, 1); +}); + diff --git a/test/staging/upsert/WeakMap/getOrInsert/does-not-have-weakmapdata-internal-slot-set.js b/test/staging/upsert/WeakMap/getOrInsert/does-not-have-weakmapdata-internal-slot-set.js new file mode 100644 index 0000000000..4c38e12251 --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsert/does-not-have-weakmapdata-internal-slot-set.js @@ -0,0 +1,26 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Throws TypeError if `this` doesn't have a [[WeakMapData]] internal slot. +info: | + WeakMap.prototype.getOrInsert ( key, value ) + + ... + 1. Let M be the this value. + 2. Perform ? RequireInternalSlot(M, [[WeakMapData]]). + ... +features: [Set, upsert] +flags: [noStrict] +---*/ +assert.throws(TypeError, function() { + WeakMap.prototype.getOrInsert.call(new Set(), {}, 1); +}); + +assert.throws(TypeError, function() { + var map = new WeakMap(); + map.getOrInsert.call(new Set(), {}, 1); +}); + diff --git a/test/staging/upsert/WeakMap/getOrInsert/does-not-have-weakmapdata-internal-slot-weakmap-prototype.js b/test/staging/upsert/WeakMap/getOrInsert/does-not-have-weakmapdata-internal-slot-weakmap-prototype.js new file mode 100644 index 0000000000..9d20de72db --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsert/does-not-have-weakmapdata-internal-slot-weakmap-prototype.js @@ -0,0 +1,26 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Throws TypeError if `this` doesn't have a [[WeakMapData]] internal slot. +info: | + WeakMap.prototype.getOrInsert ( key, value ) + + ... + 1. Let M be the this value. + 2. Perform ? RequireInternalSlot(M, [[WeakMapData]]). + ... +features: [upsert] +flags: [noStrict] +---*/ +assert.throws(TypeError, function() { + WeakMap.prototype.getOrInsert.call(WeakMap.prototype, {}, 1); +}); + +assert.throws(TypeError, function() { + var map = new WeakMap(); + map.getOrInsert.call(WeakMap.prototype, {}, 1); +}); + diff --git a/test/staging/upsert/WeakMap/getOrInsert/getOrInsert.js b/test/staging/upsert/WeakMap/getOrInsert/getOrInsert.js new file mode 100644 index 0000000000..1f98c6675a --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsert/getOrInsert.js @@ -0,0 +1,28 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + WeakMap.prototype.getOrInsert property descriptor +info: | + WeakMap.prototype.getOrInsert ( key, value ) + + 17 ECMAScript Standard Built-in Objects +includes: [propertyHelper.js] +features: [upsert] +flags: [noStrict] +---*/ +assert.sameValue( + typeof WeakMap.prototype.getOrInsert, + 'function', + 'typeof WeakMap.prototype.getOrInsert is "function"' +); + +verifyProperty(WeakMap.prototype, "getOrInsert", { + value: WeakMap.prototype.getOrInsert, + writable: true, + enumerable: false, + configurable: true +}); + diff --git a/test/staging/upsert/WeakMap/getOrInsert/length.js b/test/staging/upsert/WeakMap/getOrInsert/length.js new file mode 100644 index 0000000000..400f78477d --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsert/length.js @@ -0,0 +1,22 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + WeakMap.prototype.getOrInsert.length descriptor +info: | + WeakMap.prototype.getOrInsert ( key, value ) + + 17 ECMAScript Standard Built-in Objects +includes: [propertyHelper.js] +features: [upsert] +flags: [noStrict] +---*/ +verifyProperty(WeakMap.prototype.getOrInsert, "length", { + value: 2, + writable: false, + enumerable: false, + configurable: true +}); + diff --git a/test/staging/upsert/WeakMap/getOrInsert/name.js b/test/staging/upsert/WeakMap/getOrInsert/name.js new file mode 100644 index 0000000000..ea2f71885a --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsert/name.js @@ -0,0 +1,22 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + WeakMap.prototype.getOrInsert.name descriptor +info: | + WeakMap.prototype.getOrInsert ( key, value ) + + 17 ECMAScript Standard Built-in Objects +includes: [propertyHelper.js] +features: [upsert] +flags: [noStrict] +---*/ +verifyProperty(Map.prototype.getOrInsert, "name", { + value: "getOrInsert", + writable: false, + enumerable: false, + configurable: true +}); + diff --git a/test/staging/upsert/WeakMap/getOrInsert/not-a-constructor.js b/test/staging/upsert/WeakMap/getOrInsert/not-a-constructor.js new file mode 100644 index 0000000000..5cf7f1b715 --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsert/not-a-constructor.js @@ -0,0 +1,33 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + WeakMap.prototype.getOrInsert 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, WeakMap, arrow-function, upsert] +flags: [noStrict] +---*/ +assert.sameValue( + isConstructor(WeakMap.prototype.getOrInsert), + false, + 'isConstructor(WeakMap.prototype.getOrInsert) must return false' +); + +assert.throws(TypeError, () => { + let wm = new WeakMap(); new wm.getOrInsert({}, 1); +}); + diff --git a/test/staging/upsert/WeakMap/getOrInsert/returns-value-if-key-is-not-present-object-key.js b/test/staging/upsert/WeakMap/getOrInsert/returns-value-if-key-is-not-present-object-key.js new file mode 100644 index 0000000000..3579702a41 --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsert/returns-value-if-key-is-not-present-object-key.js @@ -0,0 +1,30 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Returns the value given as parameter when key is not present. +info: | + WeakMap.prototype.getOrInsert ( key, value ) + + ... + 4. For each Record { [[Key]], [[Value]] } p of M.[[WeakMapData]], do + a. If p.[[Key]] is not empty and SameValue(p.[[Key]], key) is true, return p.[[Value]]. + 5. Let p be the Record { [[Key]]: key, [[Value]]: value }. + 6. Append p to M.[[WeakMapData]]. + 7. Return value. +features: [WeakMap, upsert] +flags: [noStrict] +---*/ +var foo = {}; +var bar = {}; +var baz = []; +var map = new WeakMap(); + +assert.sameValue(map.getOrInsert(foo, 0), 0); + +assert.sameValue(map.getOrInsert(bar, 1), 1); + +assert.sameValue(map.getOrInsert(baz, 2), 2); + diff --git a/test/staging/upsert/WeakMap/getOrInsert/returns-value-if-key-is-not-present-symbol-key.js b/test/staging/upsert/WeakMap/getOrInsert/returns-value-if-key-is-not-present-symbol-key.js new file mode 100644 index 0000000000..38e46b171d --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsert/returns-value-if-key-is-not-present-symbol-key.js @@ -0,0 +1,31 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Returns the value given as parameter when key is not present. +info: | + WeakMap.prototype.getOrInsert ( key, value ) + + ... + 4. For each Record { [[Key]], [[Value]] } p of M.[[WeakMapData]], do + a. If p.[[Key]] is not empty and SameValue(p.[[Key]], key) is true, return p.[[Value]]. + 5. Let p be the Record { [[Key]]: key, [[Value]]: value }. + 6. Append p to M.[[WeakMapData]]. + 7. Return value. +features: [Symbol, WeakMap, symbols-as-weakmap-keys, upsert] +flags: [noStrict] +---*/ +var foo = Symbol('a description'); +var bar = Symbol('a description'); +var baz = Symbol('different description'); +var map = new WeakMap(); + +assert.sameValue(map.getOrInsert(foo, 0), 0, 'Regular symbol as key, added in constructor'); + +assert.sameValue(map.getOrInsert(baz, 2), 2, 'Regular symbol as key, added with set()'); +assert.sameValue(map.getOrInsert(bar, 1), 1, "Symbols with the same description don't overwrite each other"); + +assert.sameValue(map.getOrInsert(Symbol.hasInstance, 3), 3, 'Well-known symbol as key'); + diff --git a/test/staging/upsert/WeakMap/getOrInsert/returns-value-if-key-is-present-object-key.js b/test/staging/upsert/WeakMap/getOrInsert/returns-value-if-key-is-present-object-key.js new file mode 100644 index 0000000000..dd70592b10 --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsert/returns-value-if-key-is-present-object-key.js @@ -0,0 +1,32 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Returns the value from the specified Object key +info: | + WeakMap.prototype.getOrInsert ( key, value) + + ... + 4. For each Record { [[Key]], [[Value]] } p of M.[[WeakMapData]], do + a. If p.[[Key]] is not empty and SameValue(p.[[Key]], key) is true, return p.[[Value]]. + ... +features: [WeakMap, upsert] +flags: [noStrict] +---*/ +var foo = {}; +var bar = {}; +var baz = []; +var map = new WeakMap([ + [foo, 0] +]); + +assert.sameValue(map.getOrInsert(foo, 3), 0); + +map.set(bar, 1); +assert.sameValue(map.getOrInsert(bar, 4), 1); + +map.set(baz, 2); +assert.sameValue(map.getOrInsert(baz, 5), 2); + diff --git a/test/staging/upsert/WeakMap/getOrInsert/returns-value-if-key-is-present-symbol-key.js b/test/staging/upsert/WeakMap/getOrInsert/returns-value-if-key-is-present-symbol-key.js new file mode 100644 index 0000000000..f0e8f5ea7e --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsert/returns-value-if-key-is-present-symbol-key.js @@ -0,0 +1,34 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Returns the value from the specified Symbol key +info: | + WeakMap.prototype.getOrInsert ( key, value) + + ... + 4. For each Record { [[Key]], [[Value]] } p of M.[[WeakMapData]], do + a. If p.[[Key]] is not empty and SameValue(p.[[Key]], key) is true, return p.[[Value]]. + ... +features: [Symbol, WeakMap, symbols-as-weakmap-keys, upsert] +flags: [noStrict] +---*/ +var foo = Symbol('a description'); +var bar = Symbol('a description'); +var baz = Symbol('different description'); +var map = new WeakMap([ + [foo, 0], +]); + +assert.sameValue(map.getOrInsert(foo), 0, 'Regular symbol as key, added in constructor'); + +map.set(bar, 1); +map.set(baz, 2); +assert.sameValue(map.getOrInsert(baz), 2, 'Regular symbol as key, added with set()'); +assert.sameValue(map.getOrInsert(bar), 1, "Symbols with the same description don't overwrite each other"); + +map.set(Symbol.hasInstance, 3); +assert.sameValue(map.getOrInsert(Symbol.hasInstance), 3, 'Well-known symbol as key'); + diff --git a/test/staging/upsert/WeakMap/getOrInsert/this-not-object-throw.js b/test/staging/upsert/WeakMap/getOrInsert/this-not-object-throw.js new file mode 100644 index 0000000000..c598431880 --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsert/this-not-object-throw.js @@ -0,0 +1,46 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes, Sune Eriksson Lianes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Throws a TypeError if `this` is not an Object. +info: | + WeakMap.prototype.getOrInsert ( key , value ) + + 1. Let M be the this value + 2. Perform ? RequireInternalSlot(M, [[WeakMapData]]) + ... +features: [Symbol, upsert] +flags: [noStrict] +---*/ +var m = new WeakMap(); + +assert.throws(TypeError, function () { + m.getOrInsert.call(false, {}, 1); +}); + +assert.throws(TypeError, function () { + m.getOrInsert.call(1, {}, 1); +}); + +assert.throws(TypeError, function () { + m.getOrInsert.call("", {}, 1); +}); + +assert.throws(TypeError, function () { + m.getOrInsert.call(undefined, {}, 1); +}); + +assert.throws(TypeError, function () { + m.getOrInsert.call(null, {}, 1); +}); + +assert.throws(TypeError, function () { + m.getOrInsert.call(Symbol(), {}, 1); +}); + +assert.throws(TypeError, function () { + m.getOrInsert.call('', {}, 1); +}); + diff --git a/test/staging/upsert/WeakMap/getOrInsert/throw-if-key-cannot-be-held-weakly.js b/test/staging/upsert/WeakMap/getOrInsert/throw-if-key-cannot-be-held-weakly.js new file mode 100644 index 0000000000..0fabbc8659 --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsert/throw-if-key-cannot-be-held-weakly.js @@ -0,0 +1,42 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Throws TypeError if key cannot be held weakly. +info: | + WeakMap.prototype.getOrInsert ( key, value ) + + ... + 3. If CanBeHeldWeakly(key) is false, throw a TypeError exception. + ... +features: [Symbol, WeakMap, upsert] +flags: [noStrict] +---*/ +var s = new WeakMap(); + +assert.throws(TypeError, function() { + s.getOrInsert(1, 1); +}); + +assert.throws(TypeError, function() { + s.getOrInsert(false, 1); +}); + +assert.throws(TypeError, function() { + s.getOrInsert(undefined, 1); +}); + +assert.throws(TypeError, function() { + s.getOrInsert('string', 1); +}); + +assert.throws(TypeError, function() { + s.getOrInsert(null, 1); +}); + +assert.throws(TypeError, function() { + s.getOrInsert(Symbol.for('registered symbol'), 1); +}, 'Registered symbol not allowed as WeakMap key'); + diff --git a/test/staging/upsert/WeakMap/getOrInsertComputed/adds-object-element.js b/test/staging/upsert/WeakMap/getOrInsertComputed/adds-object-element.js new file mode 100644 index 0000000000..97972faa62 --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsertComputed/adds-object-element.js @@ -0,0 +1,34 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Adds a value with an Object key if key is not already in the map. +info: | + WeakMap.prototype.getOrInsertComputed ( key, callbackfn ) + + ... + 8. Let p be the Record { [[Key]]: key, [[Value]]: value }. + 9. Append p to M.[[WeakMapData]]. + ... +features: [WeakMap, upsert] +flags: [noStrict] +---*/ +var map = new WeakMap(); +var foo = {}; +var bar = {}; +var baz = {}; + +map.getOrInsertComputed(foo, () => 1); +map.getOrInsertComputed(bar, () => 2); +map.getOrInsertComputed(baz, () => 3); + +assert.sameValue(map.has(foo), true); +assert.sameValue(map.has(bar), true); +assert.sameValue(map.has(baz), true); + +assert.sameValue(map.get(foo), 1); +assert.sameValue(map.get(bar), 2); +assert.sameValue(map.get(baz), 3); + diff --git a/test/staging/upsert/WeakMap/getOrInsertComputed/adds-symbol-element.js b/test/staging/upsert/WeakMap/getOrInsertComputed/adds-symbol-element.js new file mode 100644 index 0000000000..118f7a3285 --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsertComputed/adds-symbol-element.js @@ -0,0 +1,32 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Adds a value with a Symbol key if key is not already in the map. +info: | + WeakMap.prototype.getOrInsertComputed ( _key_, callbackfn ) + + ... + 8. Let p be the Record { [[Key]]: key, [[Value]]: value }. + 9. Append p to M.[[WeakMapData]]. + ... +features: [Symbol, WeakMap, symbols-as-weakmap-keys, upsert] +flags: [noStrict] +---*/ +var map = new WeakMap(); +var foo = Symbol('a description'); +var bar = Symbol('a description'); + +map.getOrInsertComputed(foo, () => 1); +map.getOrInsertComputed(bar, () => 2); +map.getOrInsertComputed(Symbol.hasInstance, () => 3); + +assert.sameValue(map.has(bar), true, 'Regular symbol as key'); +assert.sameValue(map.get(foo), 1, "Symbols with the same description don't overwrite each other"); +assert.sameValue(map.has(Symbol.hasInstance), true, 'Well-known symbol as key'); + +assert.sameValue(map.get(bar), 2); +assert.sameValue(map.get(Symbol.hasInstance), 3); + diff --git a/test/staging/upsert/WeakMap/getOrInsertComputed/adds-value-different-callbackfn.js b/test/staging/upsert/WeakMap/getOrInsertComputed/adds-value-different-callbackfn.js new file mode 100644 index 0000000000..d52746d33c --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsertComputed/adds-value-different-callbackfn.js @@ -0,0 +1,55 @@ +// Copyright (C) 2025 Jonas Haukenes, Mathias Ness. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Does not throw if `callbackfn` is callable. +info: | + WeakMap.prototype.getOrInsertComputed ( key , callbackfn ) + + ... + 3. If IsCallable(callbackfn) is false, throw a TypeError exception. + ... +features: [arrow-function, upsert] +flags: [noStrict] +---*/ +var bar = {}; +var baz = {}; +var foo = {}; +var foobar = {}; +var foobarbaz = {}; + +var m = new WeakMap(); + +assert.sameValue( + m.getOrInsertComputed(bar, function() {return 1;}) + , 1); +assert.sameValue(m.get(bar), 1); + + +assert.sameValue( + m.getOrInsertComputed(baz, () => 2) + , 2); +assert.sameValue(m.get(baz), 2); + + +function three() {return 3;} + +assert.sameValue( + m.getOrInsertComputed(foo, three) + , 3); +assert.sameValue(m.get(foo), 3); + + +assert.sameValue( + m.getOrInsertComputed(foobar, new Function()) + , undefined); +assert.sameValue(m.get(foobar), undefined); + + +assert.sameValue( + m.getOrInsertComputed(foobarbaz, (function() {return 5;}).bind(m)) + , 5); +assert.sameValue(m.get(foobarbaz), 5); + + diff --git a/test/staging/upsert/WeakMap/getOrInsertComputed/callbackfn-throws.js b/test/staging/upsert/WeakMap/getOrInsertComputed/callbackfn-throws.js new file mode 100644 index 0000000000..d5e0d89dd3 --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsertComputed/callbackfn-throws.js @@ -0,0 +1,25 @@ +// Copyright (C) 2024 Jonas Haukenes, Mathias Ness. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + WeakMap.getOrInsertComputed throws when callbackfn throws return if abrubt completion Call(callbackfn, key) +info: | + WeakMap.prototype.getOrInsertComputed ( key , callbackfn ) + + ... + 6. Let value be ? Call(callbackfn, undefined, key). + ... +features: [upsert] +flags: [noStrict] +---*/ +var map = new WeakMap(); + +var bar = {}; + +assert.throws(Error, function() { + map.getOrInsertComputed(bar, function() { + throw new Error('throw in callback'); + }) +}, Error); + diff --git a/test/staging/upsert/WeakMap/getOrInsertComputed/does-not-evaluate-callbackfn-if-key-present.js b/test/staging/upsert/WeakMap/getOrInsertComputed/does-not-evaluate-callbackfn-if-key-present.js new file mode 100644 index 0000000000..f3d403cbe3 --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsertComputed/does-not-evaluate-callbackfn-if-key-present.js @@ -0,0 +1,37 @@ +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Does not evaluate the callback function if the key is already in the map. +info: | + WeakMap.prototype.getOrInsertComputed ( key, callbackfn ) + + ... + 5. For each Record { [[Key]], [[Value]] } p of M.[[WeakMapData]], do + a. If p.[[Key]] is not empty and SameValue(p.[[Key]], key) is true, return p.[[Value]]. + 6. Let value be ? Call(callbackfn, undefined, « key »). + ... +features: [WeakMap, upsert] +flags: [noStrict] +---*/ +var map = new Map([ + [1, 0] +]); + +function callback() { + throw new Error('Callbackfn should not be evaluated if key is present'); +} + +assert.sameValue(map.getOrInsertComputed(1, callback), 0); + +map.set(2, 1); +assert.sameValue(map.getOrInsertComputed(2, callback), 1); + +map.set(3, 2); +assert.sameValue(map.getOrInsertComputed(3, callback), 2); + +assert.throws(Error, function() { + map.getOrInsertComputed(4, callback) +}, Error); + diff --git a/test/staging/upsert/WeakMap/getOrInsertComputed/does-not-have-weakmapdata-internal-slot-array.js b/test/staging/upsert/WeakMap/getOrInsertComputed/does-not-have-weakmapdata-internal-slot-array.js new file mode 100644 index 0000000000..5bee7861fd --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsertComputed/does-not-have-weakmapdata-internal-slot-array.js @@ -0,0 +1,25 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Throws TypeError if `this` doesn't have a [[WeakMapData]] internal slot. +info: | + WeakMap.prototype.getOrInsertComputed ( key, callbackfn ) + + ... + 2. Perform ? RequireInternalSlot(M, [[WeakMapData]]). + ... +features: [upsert] +flags: [noStrict] +---*/ +assert.throws(TypeError, function() { + WeakMap.prototype.getOrInsertComputed.call([], {}, () => 1); +}); + +assert.throws(TypeError, function() { + var map = new WeakMap(); + map.getOrInsertComputed.call([], {}, () => 1); +}); + diff --git a/test/staging/upsert/WeakMap/getOrInsertComputed/does-not-have-weakmapdata-internal-slot-map.js b/test/staging/upsert/WeakMap/getOrInsertComputed/does-not-have-weakmapdata-internal-slot-map.js new file mode 100644 index 0000000000..1b26135d33 --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsertComputed/does-not-have-weakmapdata-internal-slot-map.js @@ -0,0 +1,25 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Throws TypeError if `this` doesn't have a [[WeakMapData]] internal slot. +info: | + WeakMap.prototype.getOrInsertComputed ( key, callbackfn ) + + ... + 2. Perform ? RequireInternalSlot(M, [[WeakMapData]]). + ... +features: [Map, upsert] +flags: [noStrict] +---*/ +assert.throws(TypeError, function() { + WeakMap.prototype.getOrInsertComputed.call(new Map(), {}, () => 1); +}); + +assert.throws(TypeError, function() { + var map = new WeakMap(); + map.getOrInsertComputed.call(new Map(), {}, () => 1); +}); + diff --git a/test/staging/upsert/WeakMap/getOrInsertComputed/does-not-have-weakmapdata-internal-slot-object.js b/test/staging/upsert/WeakMap/getOrInsertComputed/does-not-have-weakmapdata-internal-slot-object.js new file mode 100644 index 0000000000..e7266603ae --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsertComputed/does-not-have-weakmapdata-internal-slot-object.js @@ -0,0 +1,25 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Throws TypeError if `this` doesn't have a [[WeakMapData]] internal slot. +info: | + WeakMap.prototype.getOrInsertComputed ( key, callbackfn ) + + ... + 2. Perform ? RequireInternalSlot(M, [[WeakMapData]]). + ... +features: [upsert] +flags: [noStrict] +---*/ +assert.throws(TypeError, function() { + WeakMap.prototype.getOrInsertComputed.call({}, {}, () => 1); +}); + +assert.throws(TypeError, function() { + var map = new WeakMap(); + map.getOrInsertComputed.call({}, {}, () => 1); +}); + diff --git a/test/staging/upsert/WeakMap/getOrInsertComputed/does-not-have-weakmapdata-internal-slot-set.js b/test/staging/upsert/WeakMap/getOrInsertComputed/does-not-have-weakmapdata-internal-slot-set.js new file mode 100644 index 0000000000..0b09ca986c --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsertComputed/does-not-have-weakmapdata-internal-slot-set.js @@ -0,0 +1,25 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Throws TypeError if `this` doesn't have a [[WeakMapData]] internal slot. +info: | + WeakMap.prototype.getOrInsertComputed ( key, callbackfn ) + + ... + 2. Perform ? RequireInternalSlot(M, [[WeakMapData]]). + ... +features: [Set, upsert] +flags: [noStrict] +---*/ +assert.throws(TypeError, function() { + WeakMap.prototype.getOrInsertComputed.call(new Set(), {}, () => 1); +}); + +assert.throws(TypeError, function() { + var map = new WeakMap(); + map.getOrInsertComputed.call(new Set(), {}, () => 1); +}); + diff --git a/test/staging/upsert/WeakMap/getOrInsertComputed/does-not-have-weakmapdata-internal-slot-weakmap-prototype.js b/test/staging/upsert/WeakMap/getOrInsertComputed/does-not-have-weakmapdata-internal-slot-weakmap-prototype.js new file mode 100644 index 0000000000..6e24218b80 --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsertComputed/does-not-have-weakmapdata-internal-slot-weakmap-prototype.js @@ -0,0 +1,25 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Throws TypeError if `this` doesn't have a [[WeakMapData]] internal slot. +info: | + WeakMap.prototype.getOrInsertComputed ( key, callbackfn ) + + ... + 2. Perform ? RequireInternalSlot(M, [[WeakMapData]]). + ... +features: [upsert] +flags: [noStrict] +---*/ +assert.throws(TypeError, function() { + WeakMap.prototype.getOrInsertComputed.call(WeakMap.prototype, {}, () => 1); +}); + +assert.throws(TypeError, function() { + var map = new WeakMap(); + map.getOrInsertComputed.call(WeakMap.prototype, {}, () => 1); +}); + diff --git a/test/staging/upsert/WeakMap/getOrInsertComputed/getOrInsertComputed.js b/test/staging/upsert/WeakMap/getOrInsertComputed/getOrInsertComputed.js new file mode 100644 index 0000000000..3e6f966737 --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsertComputed/getOrInsertComputed.js @@ -0,0 +1,28 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + WeakMap.prototype.getOrInsertComputed property descriptor +info: | + WeakMap.prototype.getOrInsertComputed ( key, callbackfn ) + + 17 ECMAScript Standard Built-in Objects +includes: [propertyHelper.js] +features: [upsert] +flags: [noStrict] +---*/ +assert.sameValue( + typeof WeakMap.prototype.getOrInsertComputed, + 'function', + 'typeof WeakMap.prototype.getOrInsertComputed is "function"' +); + +verifyProperty(WeakMap.prototype, "getOrInsertComputed", { + value: WeakMap.prototype.getOrInsertComputed, + writable: true, + enumerable: false, + configurable: true +}); + diff --git a/test/staging/upsert/WeakMap/getOrInsertComputed/length.js b/test/staging/upsert/WeakMap/getOrInsertComputed/length.js new file mode 100644 index 0000000000..171182ed16 --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsertComputed/length.js @@ -0,0 +1,22 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + WeakMap.prototype.getOrInsertComputed.length descriptor +info: | + WeakMap.prototype.getOrInsertComputed ( key, callbackfn ) + + 17 ECMAScript Standard Built-in Objects +includes: [propertyHelper.js] +features: [upsert] +flags: [noStrict] +---*/ +verifyProperty(WeakMap.prototype.getOrInsertComputed, "length", { + value: 2, + writable: false, + enumerable: false, + configurable: true +}); + diff --git a/test/staging/upsert/WeakMap/getOrInsertComputed/name.js b/test/staging/upsert/WeakMap/getOrInsertComputed/name.js new file mode 100644 index 0000000000..200c615638 --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsertComputed/name.js @@ -0,0 +1,22 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + WeakMap.prototype.getOrInsertComputed.name descriptor +info: | + WeakMap.prototype.getOrInsertComputed ( key, callbackfn ) + + 17 ECMAScript Standard Built-in Objects +includes: [propertyHelper.js] +features: [upsert] +flags: [noStrict] +---*/ +verifyProperty(Map.prototype.getOrInsertComputed, "name", { + value: "getOrInsertComputed", + writable: false, + enumerable: false, + configurable: true +}); + diff --git a/test/staging/upsert/WeakMap/getOrInsertComputed/not-a-constructor.js b/test/staging/upsert/WeakMap/getOrInsertComputed/not-a-constructor.js new file mode 100644 index 0000000000..6700293b9f --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsertComputed/not-a-constructor.js @@ -0,0 +1,33 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + WeakMap.prototype.getOrInsertComputed 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, WeakMap, arrow-function, upsert] +flags: [noStrict] +---*/ +assert.sameValue( + isConstructor(WeakMap.prototype.getOrInsertComputed), + false, + 'isConstructor(WeakMap.prototype.getOrInsertComputed) must return false' +); + +assert.throws(TypeError, () => { + let wm = new WeakMap(); new wm.getOrInsertComputed({}, () => 1); +}); + diff --git a/test/staging/upsert/WeakMap/getOrInsertComputed/not-a-function-callbackfn-throws.js b/test/staging/upsert/WeakMap/getOrInsertComputed/not-a-function-callbackfn-throws.js new file mode 100644 index 0000000000..22056cfbc5 --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsertComputed/not-a-function-callbackfn-throws.js @@ -0,0 +1,51 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes, Mathias Ness. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Throws a TypeError if `callbackfn` is not callable. +info: | + WeakMap.prototype.getOrInsertComputed ( key , callbackfn ) + + ... + 3. If IsCallable(callbackfn) is false, throw a TypeError exception. + ... +features: [Symbol, upsert] +flags: [noStrict] +---*/ +var bar = {}; +var m = new WeakMap(); + +assert.throws(TypeError, function () { + m.getOrInsertComputed.call(m, bar, 1); +}); + +assert.throws(TypeError, function () { + m.getOrInsertComputed.call(m, bar, ""); +}); + +assert.throws(TypeError, function () { + m.getOrInsertComputed.call(m, bar, true); +}); + +assert.throws(TypeError, function () { + m.getOrInsertComputed.call(m, bar, undefined); +}); + +assert.throws(TypeError, function () { + m.getOrInsertComputed.call(m, bar, null); +}); + +assert.throws(TypeError, function () { + m.getOrInsertComputed.call(m, bar, {}); +}); + +assert.throws(TypeError, function () { + m.getOrInsertComputed.call(m, bar, []); +}); + +assert.throws(TypeError, function () { + m.getOrInsertComputed.call(m, bar, Symbol()); +}); + diff --git a/test/staging/upsert/WeakMap/getOrInsertComputed/overwrites-mutation-from-callbackfn.js b/test/staging/upsert/WeakMap/getOrInsertComputed/overwrites-mutation-from-callbackfn.js new file mode 100644 index 0000000000..68fa107a0f --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsertComputed/overwrites-mutation-from-callbackfn.js @@ -0,0 +1,34 @@ +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + If the callbackfn inserts a value on the given key, the value is overwritten. +info: | + WeakMap.prototype.set ( key, value ) + + ... + 6. Let value be ? Call(callbackfn, undefined, « key »). + 7. For each Record { [[Key]], [[Value]] } p of M.[[WeakMapData]], do + a. If p.[[Key]] is not empty and SameValue(p.[[Key]], key) is true, then + i. Set p.[[Value]] to value. + ii. Return value. + 8. Let p be the Record { [[Key]]: key, [[Value]]: value }. + 9. Append p to M.[[WeakMapData]]. + ... +features: [upsert] +flags: [noStrict] +---*/ +var map = new WeakMap(); +var foo = {}; +var bar = {}; +var baz = {}; + +map.getOrInsertComputed(foo, () => {map.set(foo, 0); return 3;}); +map.getOrInsertComputed(bar, () => {map.set(bar, 1)}); +map.getOrInsertComputed(baz, () => {map.set(baz, 2); return 'string';}); + +assert.sameValue(map.get(foo), 3); +assert.sameValue(map.get(bar), undefined); +assert.sameValue(map.get(baz), 'string'); + diff --git a/test/staging/upsert/WeakMap/getOrInsertComputed/returns-value-if-key-is-not-present-object-key.js b/test/staging/upsert/WeakMap/getOrInsertComputed/returns-value-if-key-is-not-present-object-key.js new file mode 100644 index 0000000000..f35cf5065d --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsertComputed/returns-value-if-key-is-not-present-object-key.js @@ -0,0 +1,28 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Returns the value from the specified Object key +info: | + WeakMap.prototype.getOrInsertComputed ( key, callbackfn ) + + ... + 8. Let p be the Record { [[Key]]: key, [[Value]]: value }. + 9. Append p to M.[[WeakMapData]]. + 10. Return value. +features: [WeakMap, upsert] +flags: [noStrict] +---*/ +var foo = {}; +var bar = {}; +var baz = []; +var map = new WeakMap(); + +assert.sameValue(map.getOrInsertComputed(foo, () => 0), 0); + +assert.sameValue(map.getOrInsertComputed(bar, () => 1), 1); + +assert.sameValue(map.getOrInsertComputed(baz, () => 2), 2); + diff --git a/test/staging/upsert/WeakMap/getOrInsertComputed/returns-value-if-key-is-not-present-symbol-key.js b/test/staging/upsert/WeakMap/getOrInsertComputed/returns-value-if-key-is-not-present-symbol-key.js new file mode 100644 index 0000000000..dd943fe0ba --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsertComputed/returns-value-if-key-is-not-present-symbol-key.js @@ -0,0 +1,27 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Returns the value from the specified Symbol key +info: | + WeakMap.prototype.getOrInsertComputed ( key, callbackfn ) + + ... + 8. Let p be the Record { [[Key]]: key, [[Value]]: value }. + 9. Append p to M.[[WeakMapData]]. + 10. Return value. +features: [Symbol, WeakMap, symbols-as-weakmap-keys, upsert] +flags: [noStrict] +---*/ +var foo = Symbol('a description'); +var bar = Symbol('a description'); +var baz = Symbol('different description'); +var map = new WeakMap(); + +assert.sameValue(map.getOrInsertComputed(foo, () => 0), 0, 'Regular symbol as key, added in constructor'); +assert.sameValue(map.getOrInsertComputed(baz, () => 2), 2, 'Regular symbol as key, added with set()'); +assert.sameValue(map.getOrInsertComputed(bar, () => 1), 1, "Symbols with the same description don't overwrite each other"); +assert.sameValue(map.getOrInsertComputed(Symbol.hasInstance, () => 3), 3, 'Well-known symbol as key'); + diff --git a/test/staging/upsert/WeakMap/getOrInsertComputed/returns-value-if-key-is-present-object-key.js b/test/staging/upsert/WeakMap/getOrInsertComputed/returns-value-if-key-is-present-object-key.js new file mode 100644 index 0000000000..403c6ed52f --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsertComputed/returns-value-if-key-is-present-object-key.js @@ -0,0 +1,32 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Returns the value from the specified Object key +info: | + WeakMap.prototype.getOrInsertComputed ( key, callbackfn ) + + ... + 5. For each Record { [[Key]], [[Value]] } p of M.[[WeakMapData]], do + a. If p.[[Key]] is not empty and SameValue(p.[[Key]], key) is true, return p.[[Value]]. + ... +features: [WeakMap, upsert] +flags: [noStrict] +---*/ +var foo = {}; +var bar = {}; +var baz = []; +var map = new WeakMap([ + [foo, 0] +]); + +assert.sameValue(map.getOrInsertComputed(foo, () => 3), 0); + +map.set(bar, 1); +assert.sameValue(map.getOrInsertComputed(bar, () => 4), 1); + +map.set(baz, 2); +assert.sameValue(map.getOrInsertComputed(baz, () => 5), 2); + diff --git a/test/staging/upsert/WeakMap/getOrInsertComputed/returns-value-if-key-is-present-symbol-key.js b/test/staging/upsert/WeakMap/getOrInsertComputed/returns-value-if-key-is-present-symbol-key.js new file mode 100644 index 0000000000..86a4278b07 --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsertComputed/returns-value-if-key-is-present-symbol-key.js @@ -0,0 +1,35 @@ +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Returns the value from the specified Symbol key +info: | + WeakMap.prototype.getOrInsertComputed ( key, callbackfn ) + + ... + 8. Let p be the Record { [[Key]]: key, [[Value]]: value }. + 9. Append p to M.[[WeakMapData]]. + 10. Return value. + +features: [Symbol, WeakMap, symbols-as-weakmap-keys, upsert] +flags: [noStrict] +---*/ +var foo = Symbol('a description'); +var bar = Symbol('a description'); +var baz = Symbol('different description'); +var map = new WeakMap([ + [foo, 0], +]); + +assert.sameValue(map.getOrInsertComputed(foo, () => 3), 0, 'Regular symbol as key, added in constructor'); + +map.set(bar, 1); +map.set(baz, 2); +assert.sameValue(map.getOrInsertComputed(baz, () => 4), 2, 'Regular symbol as key, added with set()'); +assert.sameValue(map.getOrInsertComputed(bar, () => 5), 1, "Symbols with the same description don't overwrite each other"); + +map.set(Symbol.hasInstance, 3); +assert.sameValue(map.getOrInsertComputed(Symbol.hasInstance, () => 6), 3, 'Well-known symbol as key'); + diff --git a/test/staging/upsert/WeakMap/getOrInsertComputed/this-not-object-throw.js b/test/staging/upsert/WeakMap/getOrInsertComputed/this-not-object-throw.js new file mode 100644 index 0000000000..d7bf484dce --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsertComputed/this-not-object-throw.js @@ -0,0 +1,46 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes, Sune Eriksson Lianes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Throws a TypeError if `this` is not an Object. +info: | + WeakMap.prototype.getOrInsertComputed ( key , callbackfn ) + + 1. Let M be the this value + 2. Perform ? RequireInternalSlot(M, [[WeakMapData]]) + ... +features: [Symbol, upsert] +flags: [noStrict] +---*/ +var m = new WeakMap(); + +assert.throws(TypeError, function () { + m.getOrInsertComputed.call(false, {}, () => 1); +}); + +assert.throws(TypeError, function () { + m.getOrInsertComputed.call(1, {}, () => 1); +}); + +assert.throws(TypeError, function () { + m.getOrInsertComputed.call("", {}, () => 1); +}); + +assert.throws(TypeError, function () { + m.getOrInsertComputed.call(undefined, {}, () => 1); +}); + +assert.throws(TypeError, function () { + m.getOrInsertComputed.call(null, {}, () => 1); +}); + +assert.throws(TypeError, function () { + m.getOrInsertComputed.call(Symbol(), {}, () => 1); +}); + +assert.throws(TypeError, function () { + m.getOrInsertComputed.call('', {}, () => 1); +}); + diff --git a/test/staging/upsert/WeakMap/getOrInsertComputed/throw-if-key-cannot-be-held-weakly.js b/test/staging/upsert/WeakMap/getOrInsertComputed/throw-if-key-cannot-be-held-weakly.js new file mode 100644 index 0000000000..39473522b7 --- /dev/null +++ b/test/staging/upsert/WeakMap/getOrInsertComputed/throw-if-key-cannot-be-held-weakly.js @@ -0,0 +1,42 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// Copyright (C) 2025 Jonas Haukenes. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: proposal-upsert +description: | + Throws TypeError if key cannot be held weakly. +info: | + WeakMap.prototype.getOrInsertComputed ( key, callbackfn ) + + ... + 4. If CanBeHeldWeakly(_key_) is *false*, throw a *TypeError* exception. + ... +features: [Symbol, WeakMap, upsert] +flags: [noStrict] +---*/ +var s = new WeakMap(); + +assert.throws(TypeError, function() { + s.getOrInsertComputed(1, () => 1); +}); + +assert.throws(TypeError, function() { + s.getOrInsertComputed(false, () => 1); +}); + +assert.throws(TypeError, function() { + s.getOrInsertComputed(undefined, () => 1); +}); + +assert.throws(TypeError, function() { + s.getOrInsertComputed('string', () => 1); +}); + +assert.throws(TypeError, function() { + s.getOrInsertComputed(null, () => 1); +}); + +assert.throws(TypeError, function() { + s.getOrInsertComputed(Symbol.for('registered symbol'), () => 1); +}, 'Registered symbol not allowed as WeakMap key'); +