]> Lady’s Gitweb - Pisces/commitdiff
Add arraylike functions and collection unit tests
authorLady <redacted>
Sat, 23 Jul 2022 02:42:47 +0000 (19:42 -0700)
committerLady <redacted>
Fri, 12 May 2023 03:56:47 +0000 (20:56 -0700)
collection.js
collection.test.js [new file with mode: 0644]

index 10172e643b29fbe5b0dc741f531fc28d1f9f4875..20b6feffb32caf1e458b2a662d42021f81f1cc8f 100644 (file)
@@ -7,8 +7,27 @@
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
 
-import { MAX_SAFE_INTEGER } from "./numeric.js";
-import { isObject, sameValue } from "./object.js";
+import { call, makeCallable } from "./function.js";
+import {
+  floor,
+  isIntegralNumber,
+  isNan,
+  max,
+  MAXIMUM_SAFE_INTEGRAL_NUMBER,
+  min,
+} from "./numeric.js";
+import { sameValue, type } from "./value.js";
+
+export const {
+  /** Returns an array of the provided values. */
+  of: array,
+
+  /** Returns whether the provided value is an array. */
+  isArray,
+
+  /** Returns an array created from the provided arraylike. */
+  from: toArray,
+} = Array;
 
 /**
  * Returns -0 if the provided argument is "-0"; returns a number
@@ -19,7 +38,7 @@ import { isObject, sameValue } from "./object.js";
  * above 2^53 − 1 are not safe nor valid integer indices.
  */
 export const canonicalNumericIndexString = ($) => {
-  if (typeof $ != "string") {
+  if (typeof $ !== "string") {
     return undefined;
   } else if ($ === "-0") {
     return -0;
@@ -29,12 +48,142 @@ export const canonicalNumericIndexString = ($) => {
   }
 };
 
-/** Returns whether the provided value is an array index. */
-export const isArrayIndex = ($) => {
+/**
+ * Returns the result of catenating the provided arraylikes, returning
+ * a new collection according to the algorithm of Array::concat.
+ */
+export const catenate = makeCallable(Array.prototype.concat);
+
+/**
+ * Copies the items in the provided object to a new location according
+ * to the algorithm of Array::copyWithin.
+ */
+export const copyWithin = makeCallable(Array.prototype.copyWithin);
+
+/**
+ * Fills the provided object with the provided value using the
+ * algorithm of Array::fill.
+ */
+export const fill = makeCallable(Array.prototype.fill);
+
+/**
+ * Returns the result of filtering the provided object with the
+ * provided callback, using the algorithm of Array::filter.
+ */
+export const filter = makeCallable(Array.prototype.filter);
+
+/**
+ * Returns the first index in the provided object whose value satisfies
+ * the provided callback using the algorithm of Array::findIndex.
+ */
+export const findIndex = makeCallable(Array.prototype.findIndex);
+
+/**
+ * Returns the first indexed entry in the provided object whose value
+ * satisfies the provided callback.
+ *
+ * If a third argument is supplied, it will be used as the this value
+ * of the callback.
+ */
+export const findIndexedEntry = (
+  $,
+  callback,
+  thisArg = undefined,
+) => {
+  let result = undefined;
+  findItem($, (kValue, k, O) => {
+    if (call(callback, thisArg, [kValue, k, O])) {
+      // The callback succeeded.
+      result = [k, kValue];
+      return true;
+    } else {
+      // The callback failed.
+      return false;
+    }
+  });
+  return result;
+};
+
+/**
+ * Returns the first indexed value in the provided object which
+ * satisfies the provided callback, using the algorithm of Array::find.
+ */
+export const findItem = makeCallable(Array.prototype.find);
+
+/**
+ * Returns the result of flatmapping the provided value with the
+ * provided callback using the algorithm of Array::flatMap.
+ */
+export const flatmap = makeCallable(Array.prototype.flatMap);
+
+/**
+ * Returns the result of flattening the provided object using the
+ * algorithm of Array::flat.
+ */
+export const flatten = makeCallable(Array.prototype.flat);
+
+/**
+ * Returns the first index of the provided object with a value
+ * equivalent to the provided value according to the algorithm of
+ * Array::indexOf.
+ */
+export const getFirstIndex = makeCallable(Array.prototype.indexOf);
+
+/**
+ * Returns the item on the provided object at the provided index using
+ * the algorithm of Array::at.
+ */
+export const getItem = makeCallable(Array.prototype.at);
+
+/**
+ * Returns the last index of the provided object with a value
+ * equivalent to the provided value according to the algorithm of
+ * Array::lastIndexOf.
+ */
+export const getLastIndex = makeCallable(Array.prototype.lastIndexOf);
+
+/**
+ * Returns whether every indexed value in the provided object satisfies
+ * the provided function, using the algorithm of Array::every.
+ */
+export const hasEvery = makeCallable(Array.prototype.every);
+
+/**
+ * Returns whether the provided object has an indexed value which
+ * satisfies the provided function, using the algorithm of Array::some.
+ */
+export const hasSome = makeCallable(Array.prototype.some);
+
+/**
+ * Returns whether the provided object has an indexed value equivalent
+ * to the provided value according to the algorithm of Array::includes.
+ *
+ * > ☡ This algorithm treats missing values as `undefined` rather than
+ * > skipping them.
+ */
+export const includes = makeCallable(Array.prototype.includes);
+
+/**
+ * Returns an iterator over the indexed entries in the provided value
+ * according to the algorithm of Array::entries.
+ */
+export const indexedEntries = makeCallable(Array.prototype.entries);
+
+/**
+ * Returns an iterator over the indices in the provided value according
+ * to the algorithm of Array::keys.
+ */
+export const indices = makeCallable(Array.prototype.keys);
+
+/** Returns whether the provided value is an array index string. */
+export const isArrayIndexString = ($) => {
   const value = canonicalNumericIndexString($);
   if (value !== undefined) {
-    return sameValue(value, 0) || value > 0 && value < -1 >>> 0;
+    // The provided value is a canonical numeric index string.
+    return sameValue(value, 0) || value > 0 && value < -1 >>> 0 &&
+        value === toLength(value);
   } else {
+    // The provided value is not a canonical numeric index string.
     return false;
   }
 };
@@ -48,14 +197,13 @@ export const isArrayIndex = ($) => {
  *
  * - It requires the provided value to be a proper object.
  *
- * - It requires the `length` property to be an integer corresponding
- *   to an integer index.
+ * - It requires the `length` property to be an integer index.
  *
  * - It requires the object to be concat‐spreadable, meaning it must
  *   either be an array or have `[Symbol.isConcatSpreadable]` be true.
  */
 export const isCollection = ($) => {
-  if (!(isObject($) && "length" in $)) {
+  if (!(type($) === "object" && "length" in $)) {
     // The provided value is not an object or does not have a `length`.
     return false;
   } else {
@@ -76,46 +224,99 @@ export const isCollection = ($) => {
  * collections.
  */
 export const isConcatSpreadable = ($) => {
-  if (!isObject($)) {
+  if (type($) !== "object") {
     // The provided value is not an object.
     return false;
   } else {
     // The provided value is an object.
-    return !!($[Symbol.isConcatSpreadable] ?? Array.isArray($));
+    const spreadable = $[Symbol.isConcatSpreadable];
+    return spreadable !== undefined ? !!spreadable : isArray($);
   }
 };
 
-/** Returns whether the provided value is an integer index. */
-export const isIntegerIndex = ($) => {
+/** Returns whether the provided value is an integer index string. */
+export const isIntegerIndexString = ($) => {
   const value = canonicalNumericIndexString($);
-  if (value !== undefined) {
+  if (value !== undefined && isIntegralNumber(value)) {
+    // The provided value is a canonical numeric index string.
     return sameValue(value, 0) ||
-      value > 0 && value <= MAX_SAFE_INTEGER;
+      value > 0 && value <= MAXIMUM_SAFE_INTEGRAL_NUMBER &&
+        value === toLength(value);
   } else {
+    // The provided value is not a canonical numeric index string.
     return false;
   }
 };
 
+/**
+ * Returns an iterator over the items in the provided value according
+ * to the algorithm of Array::values.
+ */
+export const items = makeCallable(Array.prototype.values);
+
 /**
  * Returns the length of the provided arraylike object.
  *
  * Will throw if the provided object is not arraylike.
  *
- * This produces larger lengths than can actually be stored in arrays,
- * because no such restrictions exist on arraylike methods. Use
- * `isIndex` to determine if a value is an actual array index.
+ * This can produce larger lengths than can actually be stored in
+ * arrays, because no such restrictions exist on arraylike methods.
  */
-export const lengthOfArrayLike = ({ length }) => {
-  return toLength(length);
-};
+export const lengthOfArrayLike = ({ length }) => toLength(length);
+
+/**
+ * Returns the result of mapping the provided value with the provided
+ * callback using the algorithm of Array::map.
+ */
+export const map = makeCallable(Array.prototype.map);
+
+/** Pops from the provided value using the algorithm of Array::pop. */
+export const pop = makeCallable(Array.prototype.pop);
 
 /**
- * Converts the provided value to an array index, or throws an error if
- * it is out of range.
+ * Pushes onto the provided value using the algorithm of Array::push.
+ */
+export const push = makeCallable(Array.prototype.push);
+
+/**
+ * Returns the result of reducing the provided value with the provided
+ * callback, using the algorithm of Array::reduce.
+ */
+export const reduce = makeCallable(Array.prototype.reduce);
+
+/**
+ * Reverses the provided value using the algorithm of Array::reverse.
+ */
+export const reverse = makeCallable(Array.prototype.reverse);
+
+/** Shifts the provided value using the algorithm of Array::shift. */
+export const shift = makeCallable(Array.prototype.shift);
+
+/**
+ * Returns a slice of the provided value using the algorithm of
+ * Array::slice.
+ */
+export const slice = makeCallable(Array.prototype.slice);
+
+/**
+ * Sorts the provided value in‐place using the algorithm of
+ * Array::sort.
+ */
+export const sort = makeCallable(Array.prototype.sort);
+
+/**
+ * Splices into and out of the provided value using the algorithm of
+ * Array::splice.
+ */
+export const splice = makeCallable(Array.prototype.splice);
+
+/**
+ * Returns the result of converting the provided value to an array
+ * index, or throws an error if it is out of range.
  */
 export const toIndex = ($) => {
-  const integer = Math.floor($);
-  if (isNaN(integer) || integer == 0) {
+  const integer = floor($);
+  if (isNan(integer) || integer == 0) {
     // The value is zero·like.
     return 0;
   } else {
@@ -131,10 +332,15 @@ export const toIndex = ($) => {
   }
 };
 
-/** Converts the provided value to a length. */
+/** Returns the result of converting the provided value to a length. */
 export const toLength = ($) => {
-  const len = Math.floor($);
-  return isNaN(len) || len == 0
+  const len = floor($);
+  return isNan(len) || len == 0
     ? 0
-    : Math.max(Math.min(len, MAX_SAFE_INTEGER), 0);
+    : max(min(len, MAXIMUM_SAFE_INTEGRAL_NUMBER), 0);
 };
+
+/**
+ * Unshifts the provided value using the algorithm of Array::unshift.
+ */
+export const unshift = makeCallable(Array.prototype.unshift);
diff --git a/collection.test.js b/collection.test.js
new file mode 100644 (file)
index 0000000..b490572
--- /dev/null
@@ -0,0 +1,401 @@
+// ♓🌟 Piscēs ∷ collection.test.js
+// ====================================================================
+//
+// Copyright © 2022 Lady [@ Lady’s Computer].
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
+
+import {
+  assertEquals,
+  assertSpyCall,
+  assertSpyCalls,
+  assertStrictEquals,
+  assertThrows,
+  describe,
+  it,
+  spy,
+} from "./dev-deps.js";
+import {
+  canonicalNumericIndexString,
+  findIndexedEntry,
+  isArrayIndexString,
+  isCollection,
+  isConcatSpreadable,
+  isIntegerIndexString,
+  lengthOfArrayLike,
+  toIndex,
+  toLength,
+} from "./collection.js";
+
+describe("canonicalNumericIndexString", () => {
+  it("[[Call]] returns undefined for nonstrings", () => {
+    assertStrictEquals(canonicalNumericIndexString(1), void {});
+  });
+
+  it("[[Call]] returns undefined for noncanonical strings", () => {
+    assertStrictEquals(canonicalNumericIndexString(""), void {});
+    assertStrictEquals(canonicalNumericIndexString("01"), void {});
+    assertStrictEquals(
+      canonicalNumericIndexString("9007199254740993"),
+      void {},
+    );
+  });
+
+  it('[[Call]] returns -0 for "-0"', () => {
+    assertStrictEquals(canonicalNumericIndexString("-0"), -0);
+  });
+
+  it("[[Call]] returns the corresponding number for canonical strings", () => {
+    assertStrictEquals(canonicalNumericIndexString("0"), 0);
+    assertStrictEquals(canonicalNumericIndexString("-0.25"), -0.25);
+    assertStrictEquals(
+      canonicalNumericIndexString("9007199254740992"),
+      9007199254740992,
+    );
+    assertStrictEquals(canonicalNumericIndexString("NaN"), 0 / 0);
+    assertStrictEquals(canonicalNumericIndexString("Infinity"), 1 / 0);
+    assertStrictEquals(
+      canonicalNumericIndexString("-Infinity"),
+      -1 / 0,
+    );
+  });
+});
+
+describe("findIndexedEntry", () => {
+  it("[[Call]] returns undefined if no matching entry exists", () => {
+    assertStrictEquals(findIndexedEntry([], () => true), void {});
+    assertStrictEquals(findIndexedEntry([1], () => false), void {});
+  });
+
+  it("[[Call]] returns an entry for the first match", () => {
+    assertEquals(
+      findIndexedEntry([, true, false], ($) => $ ?? true),
+      [0, void {}],
+    );
+    assertEquals(
+      findIndexedEntry(["failure", "success"], ($) => $ == "success"),
+      [1, "success"],
+    );
+  });
+
+  it("[[Call]] works on arraylike objects", () => {
+    assertEquals(
+      findIndexedEntry({ 1: "success", length: 2 }, ($) => $),
+      [1, "success"],
+    );
+    assertEquals(
+      findIndexedEntry({ 1: "failure", length: 1 }, ($) => $),
+      void {},
+    );
+  });
+
+  it("[[Call]] only gets the value once", () => {
+    const get1 = spy(() => true);
+    findIndexedEntry({
+      get 1() {
+        return get1();
+      },
+      length: 2,
+    }, ($) => $);
+    assertSpyCalls(get1, 1);
+  });
+
+  it("[[Call]] passes the value, index, and this value to the callback", () => {
+    const arr = ["failure", "success", "success"];
+    const callback = spy(($) => $ === "success");
+    const thisArg = {};
+    findIndexedEntry(arr, callback, thisArg);
+    assertSpyCalls(callback, 2);
+    assertSpyCall(callback, 0, {
+      args: ["failure", 0, arr],
+      self: thisArg,
+    });
+    assertSpyCall(callback, 1, {
+      args: ["success", 1, arr],
+      self: thisArg,
+    });
+  });
+});
+
+describe("isArrayIndexString", () => {
+  it("[[Call]] returns false for nonstrings", () => {
+    assertStrictEquals(isArrayIndexString(1), false);
+  });
+
+  it("[[Call]] returns false for noncanonical strings", () => {
+    assertStrictEquals(isArrayIndexString(""), false);
+    assertStrictEquals(isArrayIndexString("01"), false);
+    assertStrictEquals(isArrayIndexString("9007199254740993"), false);
+  });
+
+  it("[[Call]] returns false for nonfinite numbers", () => {
+    assertStrictEquals(isArrayIndexString("NaN"), false);
+    assertStrictEquals(isArrayIndexString("Infinity"), false);
+    assertStrictEquals(isArrayIndexString("-Infinity"), false);
+  });
+
+  it("[[Call]] returns false for negative numbers", () => {
+    assertStrictEquals(isArrayIndexString("-0"), false);
+    assertStrictEquals(isArrayIndexString("-1"), false);
+  });
+
+  it("[[Call]] returns false for nonintegers", () => {
+    assertStrictEquals(isArrayIndexString("0.25"), false);
+    assertStrictEquals(isArrayIndexString("1.1"), false);
+  });
+
+  it("[[Call]] returns false for numbers greater than or equal to -1 >>> 0", () => {
+    assertStrictEquals(isArrayIndexString(String(-1 >>> 0)), false);
+    assertStrictEquals(
+      isArrayIndexString(String((-1 >>> 0) + 1)),
+      false,
+    );
+  });
+
+  it("[[Call]] returns true for array lengths less than -1 >>> 0", () => {
+    assertStrictEquals(isArrayIndexString("0"), true);
+    assertStrictEquals(
+      isArrayIndexString(String((-1 >>> 0) - 1)),
+      true,
+    );
+  });
+});
+
+describe("isCollection", () => {
+  it("[[Call]] returns false for primitives", () => {
+    assertStrictEquals(isCollection("failure"), false);
+  });
+
+  it("[[Call]] returns false if length throws", () => {
+    assertStrictEquals(
+      isCollection({
+        get length() {
+          throw void {};
+        },
+      }),
+      false,
+    );
+  });
+
+  it("[[Call]] returns false if length is not an integer index and cannot be converted to one", () => {
+    assertStrictEquals(
+      isCollection({ length: -1, [Symbol.isConcatSpreadable]: true }),
+      false,
+    );
+    assertStrictEquals(
+      isCollection({
+        length: Infinity,
+        [Symbol.isConcatSpreadable]: true,
+      }),
+      false,
+    );
+    assertStrictEquals(
+      isCollection({
+        length: 9007199254740992,
+        [Symbol.isConcatSpreadable]: true,
+      }),
+      false,
+    );
+  });
+
+  it("[[Call]] returns true if length is an integer index and the object is concat spreadable", () => {
+    assertStrictEquals(
+      isCollection({ length: 1, [Symbol.isConcatSpreadable]: true }),
+      true,
+    );
+    assertStrictEquals(
+      isCollection({ length: 0, [Symbol.isConcatSpreadable]: true }),
+      true,
+    );
+    assertStrictEquals(
+      isCollection({
+        length: 9007199254740991,
+        [Symbol.isConcatSpreadable]: true,
+      }),
+      true,
+    );
+  });
+
+  it("[[Call]] returns true if length can be converted to an index without throwing an error and the object is concat spreadable", () => {
+    assertStrictEquals(
+      isCollection({ length: -0, [Symbol.isConcatSpreadable]: true }),
+      true,
+    );
+    assertStrictEquals(
+      isCollection({ length: NaN, [Symbol.isConcatSpreadable]: true }),
+      true,
+    );
+  });
+});
+
+describe("isConcatSpreadable", () => {
+  it("[[Call]] returns false for primitives", () => {
+    assertStrictEquals(isConcatSpreadable("failure"), false);
+  });
+
+  it("[[Call]] returns false if [Symbol.isConcatSpreadable] is null or false", () => {
+    assertStrictEquals(
+      isConcatSpreadable(
+        Object.assign([], { [Symbol.isConcatSpreadable]: null }),
+      ),
+      false,
+    );
+    assertStrictEquals(
+      isConcatSpreadable(
+        Object.assign([], { [Symbol.isConcatSpreadable]: false }),
+      ),
+      false,
+    );
+  });
+
+  it("[[Call]] returns true if [Symbol.isConcatSpreadable] is undefined and the object is an array", () => {
+    assertStrictEquals(
+      isConcatSpreadable(
+        Object.assign([], { [Symbol.isConcatSpreadable]: undefined }),
+      ),
+      true,
+    );
+  });
+
+  it("[[Call]] returns true if [Symbol.isConcatSpreadable] is true", () => {
+    assertStrictEquals(
+      isConcatSpreadable({ [Symbol.isConcatSpreadable]: true }),
+      true,
+    );
+  });
+});
+
+describe("isIntegerIndexString", () => {
+  it("[[Call]] returns false for nonstrings", () => {
+    assertStrictEquals(isIntegerIndexString(1), false);
+  });
+
+  it("[[Call]] returns false for noncanonical strings", () => {
+    assertStrictEquals(isIntegerIndexString(""), false);
+    assertStrictEquals(isIntegerIndexString("01"), false);
+    assertStrictEquals(
+      isIntegerIndexString("9007199254740993"),
+      false,
+    );
+  });
+
+  it("[[Call]] returns false for nonfinite numbers", () => {
+    assertStrictEquals(isIntegerIndexString("NaN"), false);
+    assertStrictEquals(isIntegerIndexString("Infinity"), false);
+    assertStrictEquals(isIntegerIndexString("-Infinity"), false);
+  });
+
+  it("[[Call]] returns false for negative numbers", () => {
+    assertStrictEquals(isIntegerIndexString("-0"), false);
+    assertStrictEquals(isIntegerIndexString("-1"), false);
+  });
+
+  it("[[Call]] returns false for nonintegers", () => {
+    assertStrictEquals(isIntegerIndexString("0.25"), false);
+    assertStrictEquals(isIntegerIndexString("1.1"), false);
+  });
+
+  it("[[Call]] returns false for numbers greater than or equal to 2 ** 53", () => {
+    assertStrictEquals(
+      isIntegerIndexString("9007199254740992"),
+      false,
+    );
+  });
+
+  it("[[Call]] returns true for safe canonical integer strings", () => {
+    assertStrictEquals(isIntegerIndexString("0"), true);
+    assertStrictEquals(isIntegerIndexString("9007199254740991"), true);
+  });
+});
+
+describe("lengthOfArrayLike", () => {
+  it("[[Call]] returns the length", () => {
+    assertStrictEquals(
+      lengthOfArrayLike({ length: 9007199254740991 }),
+      9007199254740991,
+    );
+  });
+
+  it("[[Call]] returns a non·nan result", () => {
+    assertStrictEquals(lengthOfArrayLike({ length: NaN }), 0);
+    assertStrictEquals(lengthOfArrayLike({ length: "failure" }), 0);
+  });
+
+  it("[[Call]] returns an integral result", () => {
+    assertStrictEquals(lengthOfArrayLike({ length: 0.25 }), 0);
+    assertStrictEquals(lengthOfArrayLike({ length: 1.1 }), 1);
+  });
+
+  it("[[Call]] returns a result greater than or equal to zero", () => {
+    assertStrictEquals(lengthOfArrayLike({ length: -0 }), 0);
+    assertStrictEquals(lengthOfArrayLike({ length: -1 }), 0);
+    assertStrictEquals(lengthOfArrayLike({ length: -Infinity }), 0);
+  });
+
+  it("[[Call]] returns a result less than 2 ** 53", () => {
+    assertStrictEquals(
+      lengthOfArrayLike({ length: 9007199254740992 }),
+      9007199254740991,
+    );
+    assertStrictEquals(
+      lengthOfArrayLike({ length: Infinity }),
+      9007199254740991,
+    );
+  });
+});
+
+describe("toIndex", () => {
+  it("[[Call]] returns an index", () => {
+    assertStrictEquals(toIndex(9007199254740991), 9007199254740991);
+  });
+
+  it("[[Call]] returns zero for a zerolike result", () => {
+    assertStrictEquals(toIndex(NaN), 0);
+    assertStrictEquals(toIndex("failure"), 0);
+    assertStrictEquals(toIndex(-0), 0);
+  });
+
+  it("[[Call]] rounds down to the nearest integer", () => {
+    assertStrictEquals(toIndex(0.25), 0);
+    assertStrictEquals(toIndex(1.1), 1);
+  });
+
+  it("[[Call]] throws when provided a negative number", () => {
+    assertThrows(() => toIndex(-1));
+    assertThrows(() => toIndex(-Infinity));
+  });
+
+  it("[[Call]] throws when provided a number greater than or equal to 2 ** 53", () => {
+    assertThrows(() => toIndex(9007199254740992));
+    assertThrows(() => toIndex(Infinity));
+  });
+});
+
+describe("toLength", () => {
+  it("[[Call]] returns a length", () => {
+    assertStrictEquals(toLength(9007199254740991), 9007199254740991);
+  });
+
+  it("[[Call]] returns a non·nan result", () => {
+    assertStrictEquals(toLength(NaN), 0);
+    assertStrictEquals(toLength("failure"), 0);
+  });
+
+  it("[[Call]] returns an integral result", () => {
+    assertStrictEquals(toLength(0.25), 0);
+    assertStrictEquals(toLength(1.1), 1);
+  });
+
+  it("[[Call]] returns a result greater than or equal to zero", () => {
+    assertStrictEquals(toLength(-0), 0);
+    assertStrictEquals(toLength(-1), 0);
+    assertStrictEquals(toLength(-Infinity), 0);
+  });
+
+  it("[[Call]] returns a result less than 2 ** 53", () => {
+    assertStrictEquals(toLength(9007199254740992), 9007199254740991);
+    assertStrictEquals(toLength(Infinity), 9007199254740991);
+  });
+});
This page took 0.038198 seconds and 4 git commands to generate.