import { assert } from "./assert.js";
{
const o = {};
let dups = false;
const r = [o, o].sort((a, b) => { if (a === b) dups = true; return 0; });
assert(dups, true);
assert(r.length, 2);
assert(r[0] === o, true);
assert(r[1] === o, true);
}
{
const seen = [];
[1, 1].sort((a, b) => { seen.push(a, b); return 0; });
assert(seen.length, 2);
assert(seen[0], 1);
assert(seen[1], 1);
}
{
const o = {};
let dups = false;
const r = [o, o].toSorted((a, b) => { if (a === b) dups = true; return 0; });
assert(dups, true);
assert(r.length, 2);
assert(r[0] === o, true);
}
{
const o = {};
let err;
try {
[o, o].sort(() => { throw new RangeError("boom"); });
} catch (e) {
err = e;
}
assert(err instanceof RangeError, true);
assert(err.message, "boom");
}
{
const o = {};
let calls = 0;
const r = new Array(100).fill(o).sort((x, y) => {
if (x === o && y === o) calls++;
return 0;
});
assert(calls >= 99, true);
assert(r.length, 100);
assert(r.every(v => v === o), true);
}
{
function calls(arr) {
let n = 0;
Array.prototype.sort.call(arr, () => { n++; return 0; });
return n;
}
const s = "abc";
const sym = Symbol("s");
const o = {};
assert(calls([s, s]), 1, "same string");
assert(calls([NaN, NaN]), 1, "same NaN");
assert(calls([1n, 1n]), 1, "same bigint");
assert(calls([sym, sym]), 1, "same symbol");
assert(calls([true, true]), 1, "same boolean");
assert(calls([null, null]), 1, "same null");
assert(calls([o, o]), 1, "same object");
assert(calls([o, o, o]), 2, "three identical objects");
assert(calls({ length: 2, 0: o, 1: o }), 1, "array-like");
}
{
let n = 0;
const cmp = () => { n++; return 0; };
n = 0;
assert([undefined, undefined].sort(cmp).length, 2);
assert(n, 0, "two undefined");
n = 0;
const mixed = [undefined, 1].sort(cmp);
assert(n, 0, "undefined and a value");
assert(mixed[0], 1);
assert(mixed[1], undefined);
n = 0;
const holes = new Array(3);
holes[0] = 1;
holes.sort(cmp);
assert(n, 0, "holes");
assert(holes[0], 1);
assert(1 in holes, false);
}
{
for (const Ctor of [Int8Array, Uint8Array, Int32Array, Float64Array]) {
let n = 0;
const t = new Ctor([1, 1, 1]);
t.sort(() => { n++; return 0; });
assert(n, 2, Ctor.name);
n = 0;
new Ctor([1, 1, 1]).toSorted(() => { n++; return 0; });
assert(n, 2, Ctor.name + " toSorted");
}
let n = 0;
new BigInt64Array([1n, 1n, 1n]).sort(() => { n++; return 0; });
assert(n, 2, "BigInt64Array");
}
{
{
const a = [3, 1, 3, 1, 3, 1, 3, 1];
let calls = 0;
a.sort((x, y) => {
calls++;
if (calls === 2) a.length = 3;
return x - y;
});
assert(calls > 0, true);
assert(a.length, 8);
assert(a.join(","), "1,1,1,1,3,3,3,3");
}
{
const a = [2, 2, 2, 2];
let calls = 0;
a.sort((x, y) => {
if (++calls === 1) a.push(1, 1);
return x - y;
});
assert(a.length, 6);
assert(a.every(v => v === 1 || v === 2), true);
}
{
const a = [1, 1, 1, 1, 1];
a.sort((x, y) => {
delete a[4];
return x - y;
});
assert(a.length, 5);
}
{
const a = [1, 1, 2, 2, 3, 3];
let calls = 0;
const out = a.sort((x, y) => {
if (++calls === 3) a.reverse();
return x - y;
});
assert(out, a);
assert(a.length, 6);
}
{
const a = [2, 2, 1, 1];
let depth = 0;
a.sort(function cmp(x, y) {
if (depth === 0) {
depth++;
a.slice().sort(cmp);
depth--;
}
return x - y;
});
assert(a.join(","), "1,1,2,2");
}
}
{
const mk = () => [{ i: 0 }, { i: 1 }, { i: 2 }, { i: 3 }];
const order = a => a.map(v => v.i).join(",");
assert(order(mk().sort(() => NaN)), "0,1,2,3");
assert(order(mk().sort(() => undefined)), "0,1,2,3");
assert(order(mk().sort(() => "")), "0,1,2,3");
assert(order(mk().sort(() => null)), "0,1,2,3");
assert(order(mk().sort(() => -0)), "0,1,2,3");
assert(order(mk().sort(() => "0")), "0,1,2,3");
assert(order(mk().sort(() => false)), "0,1,2,3");
assert(order(mk().sort(() => 0.5)), "3,2,1,0");
assert(order(mk().sort(() => "-1")), "0,1,2,3");
for (const bad of [null, 1, "x", true, {}, Symbol()]) {
let threw = false;
try {
mk().sort(bad);
} catch (e) {
threw = e instanceof TypeError;
}
assert(threw, true, String(bad));
}
assert(mk().sort(undefined).length, 4);
}
{
const n = 2000;
const a = [];
for (let i = 0; i < n; i++)
a.push({ key: i % 3, i });
let calls = 0;
a.sort((x, y) => { calls++; return x.key - y.key; });
assert(calls > 0, true);
assert(a.length, n);
for (let i = 1; i < n; i++) {
assert(a[i - 1].key <= a[i].key, true, `order at ${i}`);
if (a[i - 1].key === a[i].key)
assert(a[i - 1].i < a[i].i, true, `stability at ${i}`);
}
const same = {};
const b = new Array(n).fill(same);
let same_calls = 0;
b.sort(() => { same_calls++; return 0; });
assert(same_calls > 0, true);
assert(b.length, n);
assert(b.every(v => v === same), true);
}