+ Reflect.preventExtensions(proxy),
+ false,
+ );
+ });
+
+ it("[[PreventExtensions]] succeeds if the underlying object is non·extensible and has a constant length", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ Object.defineProperty(underlying, "length", {
+ configurable: false,
+ writable: false,
+ });
+ Object.preventExtensions(underlying);
+ assertStrictEquals(
+ Reflect.preventExtensions(proxy),
+ true,
+ );
+ });
+
+ it("[[SetPrototypeOf]] fails to change the prototype", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.setPrototypeOf(proxy, {}),
+ false,
+ );
+ });
+
+ it("[[SetPrototypeOf]] succeeds keeping the prototype the same", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.setPrototypeOf(proxy, underlying),
+ true,
+ );
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(denseProxy.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(denseProxy.name, "denseProxy");
+ });
+ });
+
+ describe("~[]", () => {
+ it("[[DefineProperty]] allows changes when the property is not an index property or length", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ const newValue = Symbol();
+ proxy.etaoin = newValue;
+ assertStrictEquals(
+ proxy.etaoin,
+ newValue,
+ );
+ });
+
+ it("[[DefineProperty]] allows changing nothing when the property is not an own property", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.defineProperty(
+ proxy,
+ "0",
+ {
+ configurable: true,
+ enumerable: true,
+ writable: false,
+ value: undefined,
+ },
+ ),
+ true,
+ );
+ assertStrictEquals(
+ Reflect.defineProperty(
+ proxy,
+ "2",
+ {
+ configurable: true,
+ enumerable: true,
+ writable: false,
+ value: undefined,
+ },
+ ),
+ true,
+ );
+ /* test nonconfigurable versions too */
+ Object.freeze(underlying);
+ Object.defineProperty(proxy, "0", { configurable: false });
+ Object.defineProperty(proxy, "2", { configurable: false });
+ assertStrictEquals(
+ Reflect.defineProperty(
+ proxy,
+ "0",
+ Object.getOwnPropertyDescriptor(proxy, "0"),
+ ),
+ true,
+ );
+ assertStrictEquals(
+ Reflect.defineProperty(
+ proxy,
+ "2",
+ Object.getOwnPropertyDescriptor(proxy, "2"),
+ ),
+ true,
+ );
+ });
+
+ it("[[DefineProperty]] allows changing nothing when the property is a data index property", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.defineProperty(
+ proxy,
+ "1",
+ {
+ configurable: true,
+ enumerable: true,
+ writable: false,
+ value: underlying[1],
+ },
+ ),
+ true,
+ );
+ /* test nonconfigurable versions too */
+ Object.freeze(underlying);
+ Object.defineProperty(proxy, "1", { configurable: false });
+ assertStrictEquals(
+ Reflect.defineProperty(
+ proxy,
+ "1",
+ Object.getOwnPropertyDescriptor(proxy, "1"),
+ ),
+ true,
+ );
+ });
+
+ it("[[DefineProperty]] allows changing nothing when the property is an accessor index property", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.defineProperty(
+ proxy,
+ "3",
+ {
+ configurable: true,
+ enumerable: true,
+ writable: false,
+ value: underlying[3],
+ },
+ ),
+ true,
+ );
+ /* test nonconfigurable versions too */
+ Object.freeze(underlying);
+ Object.defineProperty(proxy, "1", { configurable: false });
+ assertStrictEquals(
+ Reflect.defineProperty(
+ proxy,
+ "1",
+ Object.getOwnPropertyDescriptor(proxy, "1"),
+ ),
+ true,
+ );
+ });
+
+ it("[[DefineProperty]] does not allow a change in enumerablility on index properties", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ for (let i = 0; i < 4; ++i) {
+ assertStrictEquals(
+ Reflect.defineProperty(proxy, i, { enumerable: false }),
+ false,
+ );
+ }
+ });
+
+ it("[[DefineProperty]] does not allow a change in value on index properties", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ for (let i = 0; i < 4; ++i) {
+ assertStrictEquals(
+ Reflect.defineProperty(proxy, i, { value: "new value" })
+ && (() => {
+ throw i;
+ })(),
+ false,
+ );
+ }
+ });
+
+ it("[[DefineProperty]] does not allow a change in getter on index properties", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ for (let i = 0; i < 4; ++i) {
+ assertStrictEquals(
+ Reflect.defineProperty(proxy, i, {
+ get: () => underlying[i],
+ }) && (() => {
+ throw i;
+ })(),
+ false,
+ );
+ }
+ });
+
+ it("[[DefineProperty]] does not allow a change in setter on index properties", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ for (let i = 0; i < 4; ++i) {
+ assertStrictEquals(
+ Reflect.defineProperty(proxy, i, { set: () => undefined }),
+ false,
+ );
+ }
+ });
+
+ it("[[DefineProperty]] does not allow a change in configurability on index properties if the property in the underlying object may change", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ Object.defineProperty(underlying, "length", {
+ configurable: false,
+ writable: false,
+ });
+ for (let i = 0; i < 4; ++i) {
+ assertStrictEquals(
+ Reflect.defineProperty(proxy, i, { configurable: false }),
+ false,
+ );
+ }
+ });
+
+ it("[[DefineProperty]] does not allow a change in configurability on index properties if the length of the underlying object may change", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ Object.seal(underlying);
+ for (let i = 0; i < 4; ++i) {
+ assertStrictEquals(
+ Reflect.defineProperty(proxy, i, { configurable: false }),
+ false,
+ );
+ }
+ });
+
+ it("[[DefineProperty]] allows a change in configurability on index properties when it is safe to do so", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ Object.defineProperty(underlying, "length", {
+ configurable: false,
+ writable: false,
+ });
+ Object.defineProperty(underlying, "1", {
+ configurable: false,
+ writable: false,
+ });
+ Object.defineProperty(underlying, "3", { configurable: false });
+ Object.preventExtensions(underlying);
+ for (let i = 0; i < 4; ++i) {
+ assertStrictEquals(
+ Reflect.defineProperty(proxy, i, { configurable: false }),
+ true,
+ );
+ }
+ });
+
+ it("[[Delete]] is allowed when the property is not an index property or length", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ proxy.a = "etaoin";
+ assertStrictEquals(
+ Reflect.deleteProperty(proxy, "a"),
+ true,
+ );
+ assertStrictEquals(
+ Reflect.has(proxy, "a"),
+ false,
+ );
+ });
+
+ it("[[Delete]] is forbidden for index properties less than the length", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ for (let i = 0; i < 4; ++i) {
+ assertStrictEquals(
+ Reflect.deleteProperty(proxy, i),
+ false,
+ );
+ }
+ });
+
+ it("[[Delete]] is allowed for index properties greater than or equal to the length", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.deleteProperty(proxy, "4"),
+ true,
+ );
+ assertStrictEquals(
+ Reflect.deleteProperty(proxy, "5"),
+ true,
+ );
+ });
+
+ it("[[GetOwnProperty]] gives the value of an index property as a data property by default", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertEquals(
+ Object.getOwnPropertyDescriptor(proxy, 1),
+ {
+ configurable: true,
+ enumerable: true,
+ value: underlying[1],
+ writable: false,
+ },
+ );
+ assertEquals(
+ Object.getOwnPropertyDescriptor(proxy, 3),
+ {
+ configurable: true,
+ enumerable: true,
+ value: underlying[3],
+ writable: false,
+ },
+ );
+ /* test nonconfigurable data properties too */
+ Object.freeze(underlying);
+ Object.defineProperty(proxy, "1", { configurable: false });
+ assertEquals(
+ Object.getOwnPropertyDescriptor(proxy, 1),
+ {
+ configurable: false,
+ enumerable: true,
+ value: underlying[1],
+ writable: false,
+ },
+ );
+ });
+
+ it("[[GetOwnProperty]] gives a value of undefined if the underlying object does not have an index property as an own property", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertEquals(
+ Object.getOwnPropertyDescriptor(proxy, 0),
+ {
+ configurable: true,
+ enumerable: true,
+ value: undefined,
+ writable: false,
+ },
+ );
+ assertEquals(
+ Object.getOwnPropertyDescriptor(proxy, 2),
+ {
+ configurable: true,
+ enumerable: true,
+ value: undefined,
+ writable: false,
+ },
+ );
+ });
+
+ it("[[GetOwnProperty]] gives a value of undefined for index properties less than the length", () => {
+ const underlying = makeUnderlying();
+ underlying.length = 0;
+ const proxy = denseProxy(underlying);
+ for (let i = 0; i < 4; ++i) {
+ assertStrictEquals(
+ Object.getOwnPropertyDescriptor(proxy, i),
+ undefined,
+ );
+ }
+ });
+
+ it("[[GetOwnProperty]] gives a getter when the underlying object has a getter and an index property is not configurable", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ Object.freeze(underlying);
+ Object.defineProperty(proxy, "3", { configurable: false });
+ const descriptor = Object.getOwnPropertyDescriptor(proxy, 3);
+ assertEquals(
+ descriptor,
+ {
+ configurable: false,
+ enumerable: true,
+ get: descriptor.get,
+ set: undefined,
+ },
+ );
+ });
+
+ describe("[[GetOwnProperty]].get.length", () => {
+ it("[[Get]] returns the correct length", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ Object.freeze(underlying);
+ Object.defineProperty(proxy, "3", { configurable: false });
+ assertStrictEquals(
+ Object.getOwnPropertyDescriptor(
+ proxy,
+ "3",
+ ).get.length,
+ 0,
+ );
+ });
+ });
+
+ describe("[[GetOwnProperty]].get.name", () => {
+ it("[[Get]] returns the correct name", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ Object.freeze(underlying);
+ Object.defineProperty(proxy, "3", { configurable: false });
+ assertStrictEquals(
+ Object.getOwnPropertyDescriptor(
+ proxy,
+ "3",
+ ).get.name,
+ "get 3",
+ );
+ });
+ });
+
+ it("[[HasProperty]] works when the property is not an index property or length", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ proxy.a = "etaoin";
+ Object.getPrototypeOf(underlying).b = "shrdlu";
+ assertStrictEquals(
+ Reflect.has(proxy, "a"),
+ true,
+ );
+ assertStrictEquals(
+ Reflect.has(proxy, "b"),
+ true,
+ );
+ assertStrictEquals(
+ Reflect.has(proxy, "z"),
+ false,
+ );
+ });
+
+ it("[[HasProperty]] works for index properties less than the length", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ for (let i = 0; i < 4; ++i) {
+ assertStrictEquals(
+ Reflect.has(proxy, i),
+ true,
+ );
+ }
+ delete underlying.length;
+ for (let i = 0; i < 4; ++i) {
+ assertStrictEquals(
+ Reflect.has(proxy, i),
+ Reflect.has(underlying, i),
+ );
+ }
+ });
+
+ it("[[HasProperty]] works for index properties greater than or equal to the length", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.has(proxy, "4"),
+ false,
+ );
+ assertStrictEquals(
+ Reflect.has(proxy, "5"),
+ false,
+ );
+ underlying[4] = "inherited now";
+ assertStrictEquals(
+ Reflect.has(proxy, "4"),
+ true,
+ );
+ });
+ });
+
+ describe("~length", () => {
+ it("[[DefineProperty]] allows changing nothing", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.defineProperty(
+ proxy,
+ "length",
+ {
+ configurable: true,
+ enumerable: false,
+ writable: false,
+ value: underlying.length >>> 0,
+ },
+ ),
+ true,
+ );
+ /* test nonconfigurable versions too */
+ Object.freeze(underlying);
+ Object.defineProperty(proxy, "length", { configurable: false });
+ assertStrictEquals(
+ Reflect.defineProperty(
+ proxy,
+ "length",
+ Object.getOwnPropertyDescriptor(proxy, "length"),
+ ),
+ true,
+ );
+ });
+
+ it("[[DefineProperty]] does not allow a change in enumerablility", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.defineProperty(proxy, "length", { enumerable: true }),
+ false,
+ );
+ });
+
+ it("[[DefineProperty]] does not allow a change in value", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.defineProperty(proxy, "length", { value: 0 }),
+ false,
+ );
+ });
+
+ it("[[DefineProperty]] does not allow a change in getter", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.defineProperty(proxy, "length", {
+ get: () => underlying.length >>> 0,
+ }),
+ false,
+ );
+ });
+
+ it("[[DefineProperty]] does not allow a change in setter", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.defineProperty(proxy, "length", { set: () => {} }),
+ false,
+ );
+ });
+
+ it("[[DefineProperty]] does not allow a change in configurability if the length of the underlying object may change", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.defineProperty(proxy, "length", {
+ configurable: false,
+ }),
+ false,
+ );
+ Object.defineProperty(underlying, "length", {
+ configurable: false,
+ get: () => 0,
+ });
+ assertStrictEquals(
+ Reflect.defineProperty(proxy, "length", {
+ configurable: false,
+ }),
+ false,
+ );
+ });
+
+ it("[[DefineProperty]] allows a change in configurability when it is safe to do so", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ Object.defineProperty(underlying, "length", {
+ configurable: false,
+ writable: false,
+ });
+ assertStrictEquals(
+ Reflect.defineProperty(proxy, "length", {
+ configurable: false,
+ }),
+ true,
+ );
+ });
+
+ it("[[Delete]] is forbidden", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.deleteProperty(
+ proxy,
+ "length",
+ ),
+ false,
+ );
+ });
+
+ it("[[GetOwnProperty]] gives the value as a data property", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertEquals(
+ Object.getOwnPropertyDescriptor(proxy, "length"),
+ {
+ configurable: true,
+ enumerable: false,
+ value: underlying.length >>> 0,
+ writable: false,
+ },
+ );
+ /* test nonconfigurable data properties too */
+ Object.freeze(underlying);
+ Object.defineProperty(proxy, "length", { configurable: false });
+ assertEquals(
+ Object.getOwnPropertyDescriptor(proxy, "length"),
+ {
+ configurable: false,
+ enumerable: false,
+ value: underlying.length >>> 0,
+ writable: false,
+ },
+ );
+ });
+
+ it("[[GetOwnProperty]] gives 0 if the underlying object does not have the property as an own property", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ delete underlying.length;
+ Object.getPrototypeOf(underlying).length = 3;
+ assertEquals(
+ Object.getOwnPropertyDescriptor(proxy, "length"),
+ {
+ configurable: true,
+ enumerable: false,
+ value: 0,
+ writable: false,
+ },
+ );
+ });
+
+ it("[[HasProperty]] is always true", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.has(proxy, "length"),
+ true,
+ );
+ delete underlying.length;
+ assertStrictEquals(
+ Reflect.has(proxy, "length"),
+ true,
+ );
+ });
+ });
+});
+
+describe("fill", () => {
+ it("[[Call]] fills", () => {
+ assertEquals(
+ fill({ 1: "failure", length: 3 }, "success"),
+ { 0: "success", 1: "success", 2: "success", length: 3 },
+ );
+ });
+
+ it("[[Call]] can fill a range", () => {
+ assertEquals(
+ fill({ 1: "failure", length: 4 }, "success", 1, 3),
+ { 1: "success", 2: "success", length: 4 },
+ );
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new fill([], null));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(fill.length, 2);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(fill.name, "fill");
+ });
+ });
+});
+
+describe("filter", () => {
+ it("[[Call]] filters", () => {
+ assertEquals(
+ filter(["failure", "success", ,], function ($) {
+ return !$ || $ == this;
+ }, "success"),
+ ["success"],