import { describe, it } from 'node:test';
import { expect } from 'chai';
import { spyOn } from '../../__testUtils__/spyOn.ts';
import { SetMap } from '../SetMap.ts';
describe('SetMap', () => {
it('maps exact sets regardless of insertion order', () => {
const cache = new SetMap<object, number>();
const a = {};
const b = {};
cache.set(new Set([a, b]), 0);
expect(cache.get(new Set([a, b]))).to.equal(0);
expect(cache.get(new Set([b, a]))).to.equal(0);
});
it('distinguishes sets which share members', () => {
const cache = new SetMap<object, number>();
const a = {};
const b = {};
const c = {};
cache.set(new Set([a, b]), 0);
cache.set(new Set([a, c]), 1);
cache.set(new Set([a, b, c]), 2);
cache.set(new Set([c, b]), 3);
expect(cache.get(new Set([a, b]))).to.equal(0);
expect(cache.get(new Set([a, c]))).to.equal(1);
expect(cache.get(new Set([a, b, c]))).to.equal(2);
expect(cache.get(new Set([c, b]))).to.equal(3);
});
it('maps the empty set', () => {
const cache = new SetMap<object, number>();
expect(cache.get(new Set())).to.equal(undefined);
cache.set(new Set(), 0);
expect(cache.get(new Set())).to.equal(0);
});
it('supports undefined values', () => {
const cache = new SetMap<object, undefined>();
const member = {};
cache.set(new Set([member]), undefined);
expect(cache.get(new Set([member]))).to.equal(undefined);
expect(cache.has(new Set([member]))).to.equal(true);
});
it('iterates canonical keys and values in insertion order', () => {
const cache = new SetMap<object, number>();
const a = {};
const b = {};
const first = new Set([a]);
const second = new Set([a, b]);
cache.set(first, 1);
cache.set(second, 2);
cache.set(new Set([a]), 3);
expect(cache.size).to.equal(2);
expect(Array.from(cache.keys())).to.deep.equal([first, second]);
expect(Array.from(cache.values())).to.deep.equal([3, 2]);
expect(Array.from(cache)).to.deep.equal([
[first, 3],
[second, 2],
]);
});
it('can insert values on demand', () => {
const cache = new SetMap<object, number>();
const member = {};
expect(cache.getOrInsert(new Set([member]), 0)).to.equal(0);
expect(cache.getOrInsert(new Set([member]), 1)).to.equal(0);
});
it('can compute values on demand', () => {
const cache = new SetMap<object, number>();
const member = {};
const compute = spyOn(() => 0);
expect(cache.getOrInsertComputed(new Set([member]), compute)).to.equal(0);
expect(cache.getOrInsertComputed(new Set([member]), compute)).to.equal(0);
expect(compute.callCount).to.equal(1);
});
it('does not recreate undefined values', () => {
const cache = new SetMap<object, undefined>();
const member = {};
const compute = spyOn(() => undefined);
expect(cache.getOrInsertComputed(new Set([member]), compute)).to.equal(
undefined,
);
expect(cache.getOrInsertComputed(new Set([member]), compute)).to.equal(
undefined,
);
expect(compute.callCount).to.equal(1);
});
it('updates values inserted during computation', () => {
const cache = new SetMap<object, number>();
const member = {};
expect(
cache.getOrInsertComputed(new Set([member]), (members) => {
cache.set(members, 1);
return 2;
}),
).to.equal(2);
expect(cache.get(new Set([member]))).to.equal(2);
});
});