You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

328 lines
12 KiB

import { namedNode } from "@ldo/rdf-utils";
import jsonldDatasetProxy, {
BasicLdSet,
_getUnderlyingNode,
} from "../src/index.js";
import { createDataset } from "@ldo/dataset";
describe("BasicLdSet", () => {
describe("constructor and add", () => {
test("should add primitive values correctly", () => {
const set = new BasicLdSet<number>();
expect(set.size).toBe(0);
set.add(1);
expect(set.size).toBe(1);
expect(set.has(1)).toBe(true);
// Duplicate primitives should not increase size.
set.add(1);
expect(set.size).toBe(1);
});
test('should add objects with "@id" as string correctly', () => {
const obj1 = { "@id": "testId" };
const set = new BasicLdSet();
set.add(obj1);
expect(set.has(obj1)).toBe(true);
expect(set.size).toBe(1);
// A different object with the same "@id" should be considered a duplicate.
const obj2 = { "@id": "testId" };
set.add(obj2);
expect(set.size).toBe(1);
});
test('should add objects with "@id" as an object correctly', () => {
// In this case the object’s "@id" is a string already.
const obj1 = { "@id": "testIdObj" };
const set = new BasicLdSet();
set.add(obj1);
expect(set.has(obj1)).toBe(true);
expect(set.size).toBe(1);
// A different object with an equivalent "@id" should not increase the size.
const obj2 = { "@id": "testIdObj" };
set.add(obj2);
expect(set.size).toBe(1);
});
test("should add LinkedDataObject", () => {
// In this case the object’s "@id" is a string already.
const obj1 = jsonldDatasetProxy(createDataset(), {}).fromSubject(
namedNode("testIdObj"),
);
const set = new BasicLdSet();
set.add(obj1);
expect(set.has(obj1)).toBe(true);
expect(set.size).toBe(1);
// A different object with an equivalent "@id" should not increase the size.
const obj2 = { "@id": "testIdObj" };
set.add(obj2);
expect(set.size).toBe(1);
});
test("should add objects with underlying nodes correctly", () => {
// Here we simulate a case where the object has a NamedNode stored as its "@id"
// which in turn yields its .value.
const obj1 = { "@id": namedNode("testIdObj") };
const set = new BasicLdSet();
set.add(obj1);
expect(set.has(obj1)).toBe(true);
expect(set.size).toBe(1);
// A different object with an equivalent "@id".value should not increase the size.
const obj2 = { "@id": "testIdObj" };
set.add(obj2);
expect(set.size).toBe(1);
});
test('should treat objects with no "@id" as unique even if same reference', () => {
// When an object does not have "@id" (or _getUnderlyingNode),
// the hashFn falls back to generating a new blank node each time.
const obj = {};
const set = new BasicLdSet();
set.add(obj);
// Adding the same object twice produces two different hash keys.
set.add(obj);
expect(set.size).toBe(2);
});
test("should initialize with iterable values", () => {
const set = new BasicLdSet<number>([1, 2, 3, 3]);
expect(set.size).toBe(3);
expect([...set]).toEqual([1, 2, 3]);
});
});
describe("clear", () => {
test("should clear all elements", () => {
const set = new BasicLdSet<number>([1, 2, 3]);
expect(set.size).toBe(3);
set.clear();
expect(set.size).toBe(0);
expect([...set]).toEqual([]);
});
});
describe("delete", () => {
test("should delete an existing element and return true", () => {
const set = new BasicLdSet<number>([1, 2, 3]);
expect(set.delete(2)).toBe(true);
expect(set.has(2)).toBe(false);
expect(set.size).toBe(2);
});
test("should return false when deleting a non-existent element", () => {
const set = new BasicLdSet<number>([1, 2, 3]);
expect(set.delete(4)).toBe(false);
expect(set.size).toBe(3);
});
});
describe("has", () => {
test("should correctly identify the presence of elements", () => {
const set = new BasicLdSet<number>([1, 2, 3]);
expect(set.has(1)).toBe(true);
expect(set.has(4)).toBe(false);
});
});
describe("iteration functions", () => {
test("every should return true if all elements satisfy the predicate", () => {
const set = new BasicLdSet<number>([2, 4, 6]);
const result = set.every((num) => num % 2 === 0);
expect(result).toBe(true);
});
test("every should return false if any element fails the predicate", () => {
const set = new BasicLdSet<number>([2, 3, 6]);
const result = set.every((num) => num % 2 === 0);
expect(result).toBe(false);
});
test("some should return true if any element satisfies the predicate", () => {
const set = new BasicLdSet<number>([1, 3, 4]);
const result = set.some((num) => num % 2 === 0);
expect(result).toBe(true);
});
test("some should return false if no element satisfies the predicate", () => {
const set = new BasicLdSet<number>([1, 3, 5]);
const result = set.some((num) => num % 2 === 0);
expect(result).toBe(false);
});
test("forEach should call the callback for each element", () => {
const set = new BasicLdSet<number>([1, 2, 3]);
const mockFn = jest.fn();
set.forEach((value, value2, collection) => {
expect(collection).toBe(set);
expect(value).toBe(value2);
mockFn(value);
});
expect(mockFn).toHaveBeenCalledTimes(3);
expect(mockFn).toHaveBeenCalledWith(1);
expect(mockFn).toHaveBeenCalledWith(2);
expect(mockFn).toHaveBeenCalledWith(3);
});
test("map should return an array with mapped values", () => {
const set = new BasicLdSet<number>([1, 2, 3]);
const result = set.map((num) => num * 2);
expect(result).toEqual([2, 4, 6]);
});
test("filter should return a new set with filtered elements", () => {
const set = new BasicLdSet<number>([1, 2, 3, 4]);
const filtered = set.filter((num) => num % 2 === 0);
expect(filtered.size).toBe(2);
expect(filtered.has(2)).toBe(true);
expect(filtered.has(4)).toBe(true);
});
test("reduce should work without an initial value", () => {
const set = new BasicLdSet<number>([1, 2, 3, 4]);
const result = set.reduce((acc, curr) => acc + curr);
expect(result).toBe(10);
});
test("reduce should work with an initial value", () => {
const set = new BasicLdSet<number>([1, 2, 3, 4]);
const result = set.reduce((acc, curr) => acc + curr, 10);
expect(result).toBe(20);
});
test("reduce should throw an error for an empty set without an initial value", () => {
const set = new BasicLdSet<number>();
expect(() => {
set.reduce((acc, curr) => acc + curr);
}).toThrow("Reduce of empty collection with no initial value");
});
test("toArray and toJSON should return an array of elements", () => {
const elements = [1, 2, 3];
const set = new BasicLdSet<number>(elements);
expect(set.toArray()).toEqual(elements);
expect(set.toJSON()).toEqual(elements);
});
});
describe("set operations", () => {
test("difference should return elements in the first set not present in the second", () => {
const set1 = new BasicLdSet<number>([1, 2, 3, 4]);
const set2 = new Set<number>([3, 4, 5]);
const diff = set1.difference(set2);
expect(diff.size).toBe(2);
expect(diff.has(1)).toBe(true);
expect(diff.has(2)).toBe(true);
});
test("intersection should return only the common elements", () => {
const set1 = new BasicLdSet<number>([1, 2, 3, 4]);
const set2 = new BasicLdSet<number>([3, 4, 5]);
const inter = set1.intersection(set2);
expect(inter.size).toBe(2);
expect(inter.has(3)).toBe(true);
expect(inter.has(4)).toBe(true);
const inter2 = set2.intersection(set1);
expect(inter2.size).toBe(2);
expect(inter2.has(3)).toBe(true);
expect(inter2.has(4)).toBe(true);
});
test("isDisjointFrom should return true if the sets have no common elements", () => {
const set1 = new BasicLdSet<number>([1, 2]);
const set2 = new BasicLdSet<number>([3, 4, 5]);
expect(set1.isDisjointFrom(set2)).toBe(true);
expect(set2.isDisjointFrom(set1)).toBe(true);
});
test("isDisjointFrom should return false if the sets share elements", () => {
const set1 = new BasicLdSet<number>([1, 2]);
const set2 = new Set<number>([2, 3]);
expect(set1.isDisjointFrom(set2)).toBe(false);
});
test("isSubsetOf should return true when the set is a subset of another", () => {
const set1 = new BasicLdSet<number>([1, 2]);
const set2 = new BasicLdSet<number>([1, 2, 3]);
expect(set1.isSubsetOf(set2)).toBe(true);
expect(set2.isSubsetOf(set1)).toBe(false);
});
test("isSubsetOf should return false when the set is not a subset of another", () => {
const set1 = new BasicLdSet<number>([1, 2, 4]);
const set2 = new Set<number>([1, 2, 3]);
expect(set1.isSubsetOf(set2)).toBe(false);
});
test("isSupersetOf should return true when the set is a superset of another", () => {
const set1 = new BasicLdSet<number>([1, 2, 3]);
const set2 = new Set<number>([1, 2]);
expect(set1.isSupersetOf(set2)).toBe(true);
});
test("isSupersetOf should return false when the set is larger", () => {
const set1 = new BasicLdSet<number>([1, 2]);
const set2 = new BasicLdSet<number>([1, 2, 3]);
expect(set1.isSupersetOf(set2)).toBe(false);
});
test("isSupersetOf should return false when the set is not a superset of another", () => {
const set1 = new BasicLdSet<number>([1, 2, 5]);
const set2 = new BasicLdSet<number>([1, 2, 3]);
expect(set1.isSupersetOf(set2)).toBe(false);
});
test("symmetricDifference should return the symmetric difference of two sets", () => {
const set1 = new BasicLdSet<number>([1, 2, 3]);
const set2 = new Set<number>([2, 3, 4]);
const symDiff = set1.symmetricDifference(set2);
expect(symDiff.size).toBe(2);
expect(symDiff.has(1)).toBe(true);
expect(symDiff.has(4)).toBe(true);
});
test("union should return the union of two sets", () => {
const set1 = new BasicLdSet<number>([1, 2]);
const set2 = new Set<number>([2, 3]);
const union = set1.union(set2);
expect(union.size).toBe(3);
expect(union.has(1)).toBe(true);
expect(union.has(2)).toBe(true);
expect(union.has(3)).toBe(true);
});
});
describe("iterator methods", () => {
test("entries returns pairs [value, value]", () => {
const set = new BasicLdSet<number>([1, 2, 3]);
const entries = Array.from(set.entries());
expect(entries).toEqual([
[1, 1],
[2, 2],
[3, 3],
]);
});
test("keys returns all values", () => {
const set = new BasicLdSet<number>([1, 2, 3]);
const keys = Array.from(set.keys());
expect(keys).toEqual([1, 2, 3]);
});
test("values returns all values", () => {
const set = new BasicLdSet<number>([1, 2, 3]);
const values = Array.from(set.values());
expect(values).toEqual([1, 2, 3]);
});
test("iterator returns all values", () => {
const set = new BasicLdSet<number>([1, 2, 3]);
const iterated = [...set];
expect(iterated).toEqual([1, 2, 3]);
});
test("toStringTag returns 'BasicLdSet'", () => {
const set = new BasicLdSet<number>();
expect(Object.prototype.toString.call(set)).toBe("[object BasicLdSet]");
expect(set[Symbol.toStringTag]).toBe("BasicLdSet");
});
});
});