mirror of
https://github.com/Kir-Antipov/mc-publish.git
synced 2024-11-26 18:31:01 -05:00
bddf78c669
A set implementation which can use custom equality comparers
252 lines
7.5 KiB
TypeScript
252 lines
7.5 KiB
TypeScript
import { IGNORE_CASE_EQUALITY_COMPARER } from "@/utils/comparison/string-equality-comparer";
|
|
import { isSet, isReadOnlySet, ArraySet } from "@/utils/collections/set";
|
|
|
|
const readOnlySetLike = {
|
|
keys: () => {},
|
|
values: () => {},
|
|
entries: () => {},
|
|
has: () => {},
|
|
[Symbol.iterator]: () => {}
|
|
};
|
|
|
|
const setLike = {
|
|
...readOnlySetLike,
|
|
add: () => {},
|
|
delete: () => {},
|
|
};
|
|
|
|
describe("isSet", () => {
|
|
test("returns true for Set instances", () => {
|
|
expect(isSet(new Set())).toBe(true);
|
|
});
|
|
|
|
test("returns true for Set-like objects", () => {
|
|
expect(isSet(setLike)).toBe(true);
|
|
});
|
|
|
|
test("returns false for non-Set-like objects", () => {
|
|
expect(isSet({})).toBe(false);
|
|
});
|
|
|
|
test("returns false for null and undefined", () => {
|
|
expect(isSet(null)).toBe(false);
|
|
expect(isSet(undefined)).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("isReadOnlySet", () => {
|
|
test("returns true for Set instances", () => {
|
|
expect(isReadOnlySet(new Set())).toBe(true);
|
|
});
|
|
|
|
test("returns true for ReadOnlySet-like objects", () => {
|
|
expect(isReadOnlySet(readOnlySetLike)).toBe(true);
|
|
});
|
|
|
|
test("returns false for non-ReadOnlySet-like objects", () => {
|
|
expect(isReadOnlySet({})).toBe(false);
|
|
});
|
|
|
|
test("returns false for null and undefined", () => {
|
|
expect(isReadOnlySet(null)).toBe(false);
|
|
expect(isReadOnlySet(undefined)).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("ArraySet", () => {
|
|
describe("constructor", () => {
|
|
test("creates an empty set when no parameters are provided", () => {
|
|
const set = new ArraySet();
|
|
|
|
expect(set.size).toBe(0);
|
|
});
|
|
|
|
test("creates a set from an iterable of values", () => {
|
|
const set = new ArraySet(["one", "two"]);
|
|
|
|
expect(set.size).toBe(2);
|
|
expect(Array.from(set)).toEqual(["one", "two"])
|
|
});
|
|
|
|
test("creates a set from an iterable of entries and a custom comparer", () => {
|
|
const set = new ArraySet(["one", "two"], IGNORE_CASE_EQUALITY_COMPARER);
|
|
|
|
expect(set.size).toBe(2);
|
|
expect(set.has("ONE")).toBe(true);
|
|
expect(set.has("TWO")).toBe(true);
|
|
});
|
|
|
|
test("creates a set from an iterable of entries, and eliminates duplicates", () => {
|
|
const set = new ArraySet([1, 2, 1]);
|
|
|
|
expect(set.size).toBe(2);
|
|
expect(set.has(1)).toBe(true);
|
|
expect(set.has(2)).toBe(true);
|
|
});
|
|
|
|
test("creates a set from an iterable of entries and a custom comparer, and eliminates duplicates", () => {
|
|
const set = new ArraySet(["one", "two", "ONE"], IGNORE_CASE_EQUALITY_COMPARER);
|
|
|
|
expect(set.size).toBe(2);
|
|
expect(set.has("ONE")).toBe(true);
|
|
expect(set.has("TWO")).toBe(true);
|
|
expect(Array.from(set)).toEqual(["ONE", "two"]);
|
|
});
|
|
});
|
|
|
|
describe("add", () => {
|
|
test("adds a new key-value pair if the key is not present", () => {
|
|
const set = new ArraySet();
|
|
|
|
set.add(1);
|
|
expect(set.has(1)).toBe(true);
|
|
expect(set.size).toBe(1);
|
|
});
|
|
|
|
test("respects custom comparer when setting value by key", () => {
|
|
const set = new ArraySet(["one"], IGNORE_CASE_EQUALITY_COMPARER);
|
|
|
|
set.add("Two");
|
|
expect(set.has("two")).toBe(true);
|
|
|
|
set.add("TWO");
|
|
expect(set.has("two")).toBe(true);
|
|
|
|
expect(set.size).toBe(2);
|
|
expect(Array.from(set)).toEqual(["one", "TWO"]);
|
|
});
|
|
|
|
test("updates the value if the key is already present", () => {
|
|
const set = new ArraySet(["one"]);
|
|
|
|
set.add("one");
|
|
expect(set.has("one")).toBe(true);
|
|
expect(set.size).toBe(1);
|
|
expect(Array.from(set)).toEqual(["one"]);
|
|
});
|
|
});
|
|
|
|
describe("has", () => {
|
|
test("returns true if the key is present", () => {
|
|
const set = new ArraySet([1]);
|
|
|
|
expect(set.has(1)).toBe(true);
|
|
});
|
|
|
|
test("respects custom comparer when checking for key presence", () => {
|
|
const set = new ArraySet(["one"], IGNORE_CASE_EQUALITY_COMPARER);
|
|
|
|
expect(set.has("one")).toBe(true);
|
|
expect(set.has("One")).toBe(true);
|
|
expect(set.has("ONE")).toBe(true);
|
|
});
|
|
|
|
test("returns false if the key is not present", () => {
|
|
const set = new ArraySet();
|
|
|
|
expect(set.has(1)).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("delete", () => {
|
|
test("removes the entry with the specified key", () => {
|
|
const set = new ArraySet([1, 2]);
|
|
|
|
expect(set.delete(1)).toBe(true);
|
|
expect(set.has(1)).toBe(false);
|
|
expect(set.size).toBe(1);
|
|
});
|
|
|
|
test("respects custom comparer when deleting by key", () => {
|
|
const set = new ArraySet(["one"], IGNORE_CASE_EQUALITY_COMPARER);
|
|
|
|
expect(set.delete("One")).toBe(true);
|
|
expect(set.has("one")).toBe(false);
|
|
expect(set.delete("ONE")).toBe(false);
|
|
});
|
|
|
|
test("returns false if the key is not present", () => {
|
|
const set = new ArraySet();
|
|
|
|
expect(set.delete(1)).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("clear", () => {
|
|
test("removes all entries", () => {
|
|
const set = new ArraySet([1, 2]);
|
|
set.clear();
|
|
|
|
expect(set.size).toBe(0);
|
|
expect(set.has(1)).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("keys", () => {
|
|
test("returns an iterator over the values (ironically)", () => {
|
|
const set = new ArraySet([1, 2]);
|
|
const keys = Array.from(set.keys());
|
|
|
|
expect(keys).toEqual([1, 2]);
|
|
});
|
|
});
|
|
|
|
describe("values", () => {
|
|
test("returns an iterator over the values", () => {
|
|
const set = new ArraySet([1, 2]);
|
|
|
|
const values = Array.from(set.values());
|
|
|
|
expect(values).toEqual([1, 2]);
|
|
});
|
|
});
|
|
|
|
describe("entries", () => {
|
|
test("returns an iterator over the value-value pairs", () => {
|
|
const set = new ArraySet([1, 2]);
|
|
const entries = Array.from(set.entries());
|
|
|
|
expect(entries).toEqual([[1, 1], [2, 2]]);
|
|
});
|
|
});
|
|
|
|
describe("forEach", () => {
|
|
test("calls the specified callback function for each value", () => {
|
|
const set = new ArraySet(["one", "two"]);
|
|
const callback = jest.fn();
|
|
|
|
set.forEach(callback);
|
|
|
|
expect(callback).toHaveBeenCalledTimes(2);
|
|
expect(callback).toHaveBeenNthCalledWith(1, "one", "one", set);
|
|
expect(callback).toHaveBeenNthCalledWith(2, "two", "two", set);
|
|
});
|
|
|
|
test("binds the callback function to the provided thisArg", () => {
|
|
const set = new ArraySet([1, 2]);
|
|
const thisArg = {};
|
|
|
|
set.forEach(function (this: typeof thisArg) {
|
|
expect(this).toBe(thisArg);
|
|
}, thisArg);
|
|
});
|
|
});
|
|
|
|
describe("[Symbol.iterator]", () => {
|
|
test("returns an iterator over the values", () => {
|
|
const set = new ArraySet(["one", "two"]);
|
|
|
|
const values = Array.from(set[Symbol.iterator]());
|
|
|
|
expect(values).toEqual(["one", "two"]);
|
|
});
|
|
});
|
|
|
|
describe("[Symbol.toStringTag]", () => {
|
|
test("returns 'Set'", () => {
|
|
const set = new ArraySet();
|
|
|
|
expect(set[Symbol.toStringTag]).toBe("Set");
|
|
});
|
|
});
|
|
});
|