parent
2655acd893
commit
2deae89b37
@ -1,13 +1,21 @@ |
|||||||
import type { BlankNode, NamedNode } from "@rdfjs/types"; |
import type { BlankNode, NamedNode } from "@rdfjs/types"; |
||||||
import { _getUnderlyingNode } from "../types"; |
import { _getUnderlyingNode } from "../types"; |
||||||
|
import type { LdSet } from "../setProxy/ldSet/LdSet"; |
||||||
import type { SubjectProxy } from "../subjectProxy/SubjectProxy"; |
import type { SubjectProxy } from "../subjectProxy/SubjectProxy"; |
||||||
|
|
||||||
export type RawObject = |
export type RawObject = |
||||||
| ({ |
| ({ |
||||||
"@id"?: string | NamedNode | BlankNode; |
"@id"?: string | NamedNode | BlankNode; |
||||||
} & { |
} & { |
||||||
[key: string | symbol | number]: RawValue | RawValue[]; |
[key: string | symbol | number]: RawValue | LdSet<RawValue>; |
||||||
}) |
}) |
||||||
| SubjectProxy; |
| SubjectProxy; |
||||||
|
|
||||||
export type RawValue = string | boolean | number | RawObject | undefined; |
export type RawValue = |
||||||
|
| string |
||||||
|
| boolean |
||||||
|
| number |
||||||
|
| RawObject |
||||||
|
| NamedNode |
||||||
|
| BlankNode |
||||||
|
| undefined; |
||||||
|
@ -0,0 +1,325 @@ |
|||||||
|
import { namedNode } from "@rdfjs/data-model"; |
||||||
|
import jsonldDatasetProxy, { BasicLdSet, _getUnderlyingNode } from "../src"; |
||||||
|
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"); |
||||||
|
}); |
||||||
|
}); |
||||||
|
}); |
Loading…
Reference in new issue