tripledoc
Version:
Library to read, create and update documents on a Solid Pod
1,021 lines (915 loc) • 58 kB
text/typescript
import { Literal } from 'rdf-js';
import { rdf } from 'rdf-namespaces';
import { DataFactory } from './n3dataset';
import {
initialiseSubject, TripleSubject
} from './subject';
import { fetchDocument } from './document';
import { triplesToTurtle } from './turtle';
const { triple, namedNode, literal, blankNode } = DataFactory;
const mockDocument = 'https://document.com/';
const mockSubjectWithLiteralThenRef = 'https://subject1.com/';
const mockSubjectWithRefThenLiteral = 'https://subject2.com/';
const mockSubjectWithBlankNodeThenRef = 'https://document.com/#blank-node-then-ref';
const mockSubjectWithRefThenBlankNode = 'https://document.com/#ref-then-blank-node';
const mockSubjectWithLiteral = 'https://subject3.com/';
const mockSubjectWithRef = 'https://subject4.com/';
const mockSubjectWithTwoLiterals = 'https://subject5.com/';
const mockSubjectWithTwoRefs = 'https://subject6.com/';
const mockSubjectWithDateLiteral = 'https://subject7.com/';
const mockSubjectWithIntegerLiteral = 'https://subject8.com/';
const mockSubjectWithDecimalLiteral = 'https://subject9.com/';
const mockSubjectWithDifferentTypesOfLiterals = 'https://subject10.com/';
const mockSubjectWithDifferentPredicates = 'https://subject11.com/';
const mockSubjectWithLocaleStringLiteral = 'https://subject12.com/';
const mockSubjectWithLocaleAndRegularStringLiteral = 'https://subject13.com/';
const mockSubjectWithMultipleLocaleStringLiterals = 'https://subject14.com/';
const mockSubjectWithLangStringLiteral = 'https://subject15.com/';
const mockSubjectWithMultipleSameLocaleStringLiterals = 'https://subject16.com/';
const mockSubjectWithLocaleStringLiteralAndRef = 'https://subject17.com/';
const mockTypedSubject = 'https://subject7.com/';
const mockEmptySubject = 'https://empty-subject.com/';
const mockPredicate = 'https://mock-predicate.com/';
const mockPredicate2 = 'https://mock-predicate-2.com/';
const mockObjectRef = 'https://mock-object.com/';
const mockObjectRef2 = 'https://mock-object-2.com/';
const mockLiteralValue = 'Arbitrary literal value';
const mockObjectLiteral = literal(mockLiteralValue);
const mockLiteralValue2 = 'Another arbitrary literal value';
const mockObjectLiteral2 = literal(mockLiteralValue2);
const mockLiteralDateTime = new Date(0);
// '1970-01-01T01:00:00Z' is the string representation rdflib uses of Date(0):
const mockLiteralDateTimeString = '1970-01-01T00:00:00Z';
const mockObjectDateTimeLiteral = literal(mockLiteralDateTimeString, namedNode('http://www.w3.org/2001/XMLSchema#dateTime'));
const mockLiteralInteger = 1337;
const mockObjectIntegerLiteral = literal(mockLiteralInteger.toString(), namedNode('http://www.w3.org/2001/XMLSchema#integer'));
const mockLiteralDecimal = 4.2;
const mockObjectDecimalLiteral = literal(mockLiteralDecimal.toString(), namedNode('http://www.w3.org/2001/XMLSchema#decimal'));
const mockLiteralLocaleString = 'Dutch (NL)';
const mockLocale = 'nl-nl';
const mockObjectLocaleStringLiteral = literal(mockLiteralLocaleString, mockLocale);
const mockLiteralLocaleString2 = 'Dutch (NL) 2';
const mockObjectLocaleStringLiteral2 = literal(mockLiteralLocaleString2, mockLocale);
const mockLiteralLangString = 'Dutch (no country specified)';
const mockLang = 'nl';
const mockObjectLangStringLiteral = literal(mockLiteralLangString, mockLang);
const mockTypeObject = 'https://mock-type-object.com/';
const mockBlankNode = 'arbitrary-blank-node-id';
const mockTriples = [
triple(namedNode(mockSubjectWithLiteralThenRef), namedNode(mockPredicate), mockObjectLiteral),
triple(namedNode(mockSubjectWithLiteralThenRef), namedNode(mockPredicate), namedNode(mockObjectRef)),
triple(namedNode(mockSubjectWithRefThenLiteral), namedNode(mockPredicate), namedNode(mockObjectRef)),
triple(namedNode(mockSubjectWithRefThenLiteral), namedNode(mockPredicate), mockObjectLiteral),
triple(namedNode(mockSubjectWithBlankNodeThenRef), namedNode(mockPredicate), blankNode(mockBlankNode)),
triple(namedNode(mockSubjectWithBlankNodeThenRef), namedNode(mockPredicate), namedNode(mockObjectRef)),
triple(namedNode(mockSubjectWithRefThenBlankNode), namedNode(mockPredicate), namedNode(mockObjectRef)),
triple(namedNode(mockSubjectWithRefThenBlankNode), namedNode(mockPredicate), blankNode(mockBlankNode)),
triple(blankNode(mockBlankNode), namedNode(mockPredicate), namedNode(mockObjectRef)),
triple(namedNode(mockSubjectWithLiteral), namedNode(mockPredicate), mockObjectLiteral),
triple(namedNode(mockSubjectWithRef), namedNode(mockPredicate), namedNode(mockObjectRef)),
triple(namedNode(mockSubjectWithTwoLiterals), namedNode(mockPredicate), mockObjectLiteral),
triple(namedNode(mockSubjectWithTwoLiterals), namedNode(mockPredicate), mockObjectLiteral2),
triple(namedNode(mockSubjectWithTwoLiterals), namedNode(mockPredicate), namedNode(mockObjectRef)),
triple(namedNode(mockSubjectWithTwoRefs), namedNode(mockPredicate), namedNode(mockObjectRef)),
triple(namedNode(mockSubjectWithTwoRefs), namedNode(mockPredicate), namedNode(mockObjectRef2)),
triple(namedNode(mockSubjectWithTwoRefs), namedNode(mockPredicate), mockObjectLiteral),
triple(namedNode(mockTypedSubject), namedNode(rdf.type), namedNode(mockTypeObject)),
triple(namedNode(mockSubjectWithDateLiteral), namedNode(mockPredicate), mockObjectDateTimeLiteral),
triple(namedNode(mockSubjectWithDecimalLiteral), namedNode(mockPredicate), mockObjectDecimalLiteral),
triple(namedNode(mockSubjectWithIntegerLiteral), namedNode(mockPredicate), mockObjectIntegerLiteral),
triple(namedNode(mockSubjectWithDifferentTypesOfLiterals), namedNode(mockPredicate), mockObjectLiteral),
triple(namedNode(mockSubjectWithDifferentTypesOfLiterals), namedNode(mockPredicate), mockObjectLiteral2),
triple(namedNode(mockSubjectWithDifferentTypesOfLiterals), namedNode(mockPredicate), mockObjectDateTimeLiteral),
triple(namedNode(mockSubjectWithDifferentTypesOfLiterals), namedNode(mockPredicate), mockObjectDecimalLiteral),
triple(namedNode(mockSubjectWithDifferentTypesOfLiterals), namedNode(mockPredicate), mockObjectIntegerLiteral),
triple(namedNode(mockSubjectWithDifferentPredicates), namedNode(mockPredicate), mockObjectLiteral),
triple(namedNode(mockSubjectWithDifferentPredicates), namedNode(mockPredicate), namedNode(mockObjectRef)),
triple(namedNode(mockSubjectWithDifferentPredicates), namedNode(mockPredicate2), namedNode(mockObjectRef2)),
triple(namedNode(mockSubjectWithLocaleStringLiteral), namedNode(mockPredicate), mockObjectLocaleStringLiteral),
triple(namedNode(mockSubjectWithLocaleAndRegularStringLiteral), namedNode(mockPredicate), mockObjectLiteral),
triple(namedNode(mockSubjectWithLocaleAndRegularStringLiteral), namedNode(mockPredicate), mockObjectLocaleStringLiteral),
triple(namedNode(mockSubjectWithMultipleLocaleStringLiterals), namedNode(mockPredicate), mockObjectLangStringLiteral),
triple(namedNode(mockSubjectWithMultipleLocaleStringLiterals), namedNode(mockPredicate), mockObjectLocaleStringLiteral),
triple(namedNode(mockSubjectWithMultipleSameLocaleStringLiterals), namedNode(mockPredicate), mockObjectLocaleStringLiteral),
triple(namedNode(mockSubjectWithMultipleSameLocaleStringLiterals), namedNode(mockPredicate), mockObjectLocaleStringLiteral2),
triple(namedNode(mockSubjectWithLocaleStringLiteralAndRef), namedNode(mockPredicate), mockObjectLocaleStringLiteral),
triple(namedNode(mockSubjectWithLocaleStringLiteralAndRef), namedNode(mockPredicate), namedNode(mockObjectRef)),
];
const turtle = triplesToTurtle(mockTriples);
jest.mock('./pod', () => ({
get: jest.fn(() => Promise.resolve({
headers: { get: () => null },
text: jest.fn(() => Promise.resolve(turtle)),
})),
}));
async function getMockTripleDocument() {
const mockTripleDocument = await fetchDocument(mockDocument);
return mockTripleDocument;
}
describe('asRef', () => {
it('should give access to the IRI that represents this Subject', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLiteral);
expect(subject.asRef())
.toBe(mockSubjectWithLiteral);
});
it('should give access to the local ID for a Subject if it is a local Subject (i.e. a Blank Node)', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, blankNode(mockBlankNode));
expect(subject.asRef())
// N3 generates an ID based on the ID we pass.
// This is OK, as it shouldn't be used as an identifier anywhere anyway,
// because the Subject is local to this Document and can not be passed around.
.toMatch(mockBlankNode);
});
});
describe('getDocument', () => {
it('should give access to the Document that contains this Subject', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLiteral);
expect(subject.getDocument())
.toEqual(mockTripleDocument);
});
});
describe('getTriples', () => {
it('should give access to only the Triples that are relevant to this Subject', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLiteral);
expect(subject.getTriples())
.toEqual([triple(namedNode(mockSubjectWithLiteral), namedNode(mockPredicate), mockObjectLiteral)]);
});
});
describe('getLiteral', () => {
it('should return a found Literal', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLiteral);
expect(subject.getLiteral(mockPredicate))
.toBe(mockLiteralValue);
});
it('should return a found Integer Literal', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithIntegerLiteral);
expect(typeof subject.getLiteral(mockPredicate)).toBe('number');
expect((subject.getLiteral(mockPredicate))).toBe(mockLiteralInteger);
});
it('should return a found Decimal Literal', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithDecimalLiteral);
expect(typeof subject.getLiteral(mockPredicate)).toBe('number');
expect((subject.getLiteral(mockPredicate))).toBe(mockLiteralDecimal);
});
it('should return a found Date Literal', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithDateLiteral);
expect(subject.getLiteral(mockPredicate)).toBeInstanceOf(Date);
expect((subject.getLiteral(mockPredicate) as Date).getTime())
.toEqual(0);
});
it('should return null if a Reference is found instead of a Literal', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithRef);
expect(subject.getLiteral(mockPredicate))
.toBeNull();
});
it('should return null if nothing is found', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockEmptySubject);
expect(subject.getLiteral(mockPredicate))
.toBeNull();
});
it('should return the first found value if that is a Literal', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLiteralThenRef);
expect(subject.getLiteral(mockPredicate))
.toBe(mockLiteralValue);
});
it('should return the second found value if that is the first Literal', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithRefThenLiteral);
expect(subject.getLiteral(mockPredicate))
.toBe(mockLiteralValue);
});
it('should only return a single Literal', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithTwoLiterals);
expect(subject.getLiteral(mockPredicate))
.toBe(mockLiteralValue);
});
});
describe('getString', () => {
it('should return a found string Literal', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithDifferentTypesOfLiterals);
expect(subject.getString(mockPredicate))
.toBe(mockLiteralValue);
});
it('should return null if a Reference is found instead of a string Literal', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithRef);
expect(subject.getString(mockPredicate))
.toBeNull();
});
it('should return null if a non-string Literal is found', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithDateLiteral);
expect(subject.getString(mockPredicate))
.toBeNull();
});
it('should return null if a locale string Literal is found', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLocaleStringLiteral);
expect(subject.getString(mockPredicate))
.toBeNull();
});
});
describe('getLocaleString', () => {
it('should return a found locale string Literal', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLocaleStringLiteral);
expect(subject.getLocaleString(mockPredicate, mockLocale))
.toBe(mockLiteralLocaleString);
});
it('should return the desired locale string Literal when multiple are present', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithMultipleLocaleStringLiterals);
expect(subject.getLocaleString(mockPredicate, mockLocale))
.toBe(mockLiteralLocaleString);
});
it('should return the desired locale string Literal when regular strings are present as well', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLocaleAndRegularStringLiteral);
expect(subject.getLocaleString(mockPredicate, mockLocale))
.toBe(mockLiteralLocaleString);
});
it('should return null if the language matches but the full locale does not - picking the right one is left to the developer', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLocaleStringLiteral);
expect(subject.getLocaleString(mockPredicate, mockLang))
.toBeNull();
});
it('should return null if the language matches but there is no info about the locale - it is up to developer to decide whether to look for those as well', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLangStringLiteral);
expect(subject.getLocaleString(mockPredicate, mockLocale))
.toBeNull();
});
it('should return null if a non-locale-string Literal is found', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithDateLiteral);
expect(subject.getLocaleString(mockPredicate, mockLocale))
.toBeNull();
});
it('should return null if a non-locale string Literal is found', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLiteral);
expect(subject.getLocaleString(mockPredicate, mockLocale))
.toBeNull();
});
});
describe('getInteger', () => {
it('should return a found integer Literal', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithDifferentTypesOfLiterals);
expect(subject.getInteger(mockPredicate))
.toBe(mockLiteralInteger);
});
it('should return null if a Reference is found instead of a integer Literal', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithRef);
expect(subject.getInteger(mockPredicate))
.toBeNull();
});
it('should return null if a non-integer Literal is found', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithDateLiteral);
expect(subject.getString(mockPredicate))
.toBeNull();
});
});
describe('getDecimal', () => {
it('should return a found decimal Literal', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithDifferentTypesOfLiterals);
expect(subject.getDecimal(mockPredicate))
.toBe(mockLiteralDecimal);
});
it('should return null if a Reference is found instead of a decimal Literal', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithRef);
expect(subject.getDecimal(mockPredicate))
.toBeNull();
});
it('should return null if a non-decimal Literal is found', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithDateLiteral);
expect(subject.getDecimal(mockPredicate))
.toBeNull();
});
});
describe('getDate', () => {
it('should return a found Date Literal', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithDifferentTypesOfLiterals);
expect(subject.getDateTime(mockPredicate))
.toEqual(new Date(0));
});
it('should return null if a Reference is found instead of a Date Literal', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithRef);
expect(subject.getDateTime(mockPredicate))
.toBeNull();
});
it('should return null if a non-Date Literal is found', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithDecimalLiteral);
expect(subject.getDateTime(mockPredicate))
.toBeNull();
});
});
describe('getAllStrings', () => {
it('should only return string Literals', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithDifferentTypesOfLiterals);
expect(subject.getAllStrings(mockPredicate))
.toEqual([mockLiteralValue, mockLiteralValue2]);
});
it('should return an empty array if nothing is found', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockEmptySubject);
expect(subject.getAllStrings(mockPredicate))
.toEqual([]);
});
});
describe('getAllLocaleStrings', () => {
it('should only return locale string Literals that match the given locale', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithMultipleSameLocaleStringLiterals);
expect(subject.getAllLocaleStrings(mockPredicate, mockLocale))
.toEqual([mockLiteralLocaleString, mockLiteralLocaleString2]);
});
it('should return an array of object with locale string and the locale identifier when no locale is specified', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLocaleStringLiteral);
expect(subject.getAllLocaleStrings(mockPredicate))
.toEqual([ { locale: mockObjectLocaleStringLiteral.language, value: mockObjectLocaleStringLiteral.value } ]);
});
it('should not return non-locale strings when no locale is specified', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLocaleStringLiteralAndRef);
expect(subject.getAllLocaleStrings(mockPredicate))
.toEqual([ { locale: mockObjectLocaleStringLiteral.language, value: mockObjectLocaleStringLiteral.value } ]);
});
it('should return an empty array if nothing is found', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockEmptySubject);
expect(subject.getAllLocaleStrings(mockPredicate, mockLocale))
.toEqual([]);
});
});
describe('getAllIntegers', () => {
it('should only return integer Literals', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithDifferentTypesOfLiterals);
expect(subject.getAllIntegers(mockPredicate))
.toEqual([mockLiteralInteger]);
});
it('should return an empty array if nothing is found', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockEmptySubject);
expect(subject.getAllIntegers(mockPredicate))
.toEqual([]);
});
});
describe('getAllDecimals', () => {
it('should only return decimal Literals', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithDifferentTypesOfLiterals);
expect(subject.getAllDecimals(mockPredicate))
.toEqual([mockLiteralDecimal]);
});
it('should return an empty array if nothing is found', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockEmptySubject);
expect(subject.getAllDecimals(mockPredicate))
.toEqual([]);
});
});
describe('getAllDateTimes', () => {
it('should only return DateTime Literals', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithDifferentTypesOfLiterals);
expect(subject.getAllDateTimes(mockPredicate))
.toEqual([mockLiteralDateTime]);
});
it('should return an empty array if nothing is found', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockEmptySubject);
expect(subject.getAllDateTimes(mockPredicate))
.toEqual([]);
});
});
describe('getAllLiterals', () => {
it('should only return Literals', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithTwoLiterals);
expect(subject.getAllLiterals(mockPredicate))
.toEqual([mockLiteralValue, mockLiteralValue2]);
});
it('should return an empty array if nothing is found', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockEmptySubject);
expect(subject.getAllLiterals(mockPredicate))
.toEqual([]);
});
});
describe('getLocalSubject', () => {
it('should return a new TripleSubject representing a local Subject', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithBlankNodeThenRef);
const localSubject = subject.getLocalSubject(mockPredicate);
expect(localSubject).not.toBeNull();
expect((localSubject as TripleSubject).getRef(mockPredicate))
.toEqual(mockObjectRef);
});
it('should return null if a Reference is found instead of a local Subject', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithRef);
expect(subject.getLocalSubject(mockPredicate))
.toBeNull();
});
it('should return a new TripleSubject representing a local Subject, even if a Reference also matches the predicate', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithRefThenBlankNode);
const localSubject = subject.getLocalSubject(mockPredicate);
expect(localSubject).not.toBeNull();
expect((localSubject as TripleSubject).getRef(mockPredicate))
.toEqual(mockObjectRef);
});
});
describe('getAllLocalSubjects', () => {
it('should only return local Subjects (i.e. those with a Blank Node)', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithRefThenBlankNode);
const localSubjects = subject.getAllLocalSubjects(mockPredicate);
expect(localSubjects.length)
.toBe(1);
expect(localSubjects[0].getRef(mockPredicate))
.toEqual(mockObjectRef);
});
it('should return an empty array if nothing is found', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockEmptySubject);
expect(subject.getAllLocalSubjects(mockPredicate))
.toEqual([]);
});
});
describe('getRef', () => {
it('should return a found Reference', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithRef);
expect(subject.getRef(mockPredicate))
.toEqual(mockObjectRef);
});
it('should return null if a Reference is found instead of a Literal', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLiteral);
expect(subject.getRef(mockPredicate))
.toBeNull();
});
it('should return null if nothing is found', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockEmptySubject);
expect(subject.getRef(mockPredicate))
.toBeNull();
});
it('should return the first found value if that is a Reference', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithRefThenLiteral);
expect(subject.getRef(mockPredicate))
.toBe(mockObjectRef);
});
it('should return the second found value if that is the first Reference', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLiteralThenRef);
expect(subject.getRef(mockPredicate))
.toBe(mockObjectRef);
});
it('should only return a single Reference', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithTwoRefs);
expect(subject.getRef(mockPredicate))
.toBe(mockObjectRef);
});
});
describe('getType', () => {
it('should return a Subject\'s type', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockTypedSubject);
expect(subject.getType()).toEqual(mockTypeObject);
});
it('should return null if no type was defined', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockEmptySubject);
expect(subject.getType()).toBeNull();
});
});
describe('getAllRefs', () => {
it('should only return References', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithTwoRefs);
expect(subject.getAllRefs(mockPredicate))
.toEqual([mockObjectRef, mockObjectRef2]);
});
it('should return an empty array if nothing is found', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockEmptySubject);
expect(subject.getAllRefs(mockPredicate))
.toEqual([]);
});
});
describe('addLiteral', () => {
it('should produce Triples that the Document can store in the user\'s Pod', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLiteral);
subject.addLiteral(mockPredicate, 'Some literal value');
const [pendingDeletions, pendingAdditions] = subject.getPendingTriples();
expect(pendingDeletions).toEqual([]);
expect(pendingAdditions.length).toBe(1);
expect(pendingAdditions[0].object.termType).toBe('Literal');
expect(pendingAdditions[0].object.value).toBe('Some literal value');
});
it('should properly represent an integer, if given', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLiteral);
const someInteger = 1337;
subject.addLiteral(mockPredicate, someInteger);
const [pendingDeletions, pendingAdditions] = subject.getPendingTriples();
expect(pendingDeletions).toEqual([]);
expect(pendingAdditions.length).toBe(1);
expect(pendingAdditions[0].object.termType).toBe('Literal');
expect((pendingAdditions[0].object as Literal).datatype.value)
.toBe('http://www.w3.org/2001/XMLSchema#integer');
expect(pendingAdditions[0].object.value).toBe('1337');
});
it('should properly represent a decimal, if given', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLiteral);
const someDecimal = 4.2;
subject.addLiteral(mockPredicate, someDecimal);
const [pendingDeletions, pendingAdditions] = subject.getPendingTriples();
expect(pendingDeletions).toEqual([]);
expect(pendingAdditions.length).toBe(1);
expect(pendingAdditions[0].object.termType).toBe('Literal');
expect((pendingAdditions[0].object as Literal).datatype.value)
.toBe('http://www.w3.org/2001/XMLSchema#decimal');
expect(pendingAdditions[0].object.value).toBe('4.2');
});
it('should properly represent a Date, if given', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLiteral);
const someDate = new Date(71697398400000);
subject.addLiteral(mockPredicate, someDate);
const [pendingDeletions, pendingAdditions] = subject.getPendingTriples();
expect(pendingDeletions).toEqual([]);
expect(pendingAdditions.length).toBe(1);
expect(pendingAdditions[0].object.termType).toBe('Literal');
expect((pendingAdditions[0].object as Literal).datatype.value)
.toBe('http://www.w3.org/2001/XMLSchema#dateTime');
expect(pendingAdditions[0].object.value).toBe('4242-01-01T00:00:00Z');
});
});
describe('addString', () => {
it('should produce Triples that the Document can store in the user\'s Pod', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLiteral);
subject.addString(mockPredicate, 'Some string value');
const [pendingDeletions, pendingAdditions] = subject.getPendingTriples();
expect(pendingDeletions).toEqual([]);
expect(pendingAdditions.length).toBe(1);
expect(pendingAdditions[0].object.termType).toBe('Literal');
expect((pendingAdditions[0].object as Literal).datatype.value)
.toBe('http://www.w3.org/2001/XMLSchema#string');
expect(pendingAdditions[0].object.value).toBe('Some string value');
});
it('should throw an error when something other than a string was given', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLiteral);
expect(() => subject.addString(mockPredicate, 1337 as any))
.toThrowError('The given value is not a string.');
});
});
describe('addLocaleString', () => {
it('should produce Triples that the Document can store in the user\'s Pod', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLiteral);
subject.addLocaleString(mockPredicate, 'Some localised string value', 'en-GB');
const [pendingDeletions, pendingAdditions] = subject.getPendingTriples();
expect(pendingDeletions).toEqual([]);
expect(pendingAdditions.length).toBe(1);
expect(pendingAdditions[0].object.termType).toBe('Literal');
expect((pendingAdditions[0].object as Literal).datatype.value)
.toBe('http://www.w3.org/1999/02/22-rdf-syntax-ns#langString');
expect((pendingAdditions[0].object as Literal).language)
.toBe('en-gb');
expect(pendingAdditions[0].object.value).toBe('Some localised string value');
});
it('should throw an error when something other than a string was given', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLiteral);
expect(() => subject.addLocaleString(mockPredicate, 1337 as any, 'nl-NL'))
.toThrowError('The given value is not a string.');
});
});
describe('addInteger', () => {
it('should produce Triples that the Document can store in the user\'s Pod', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLiteral);
subject.addInteger(mockPredicate, 42);
const [pendingDeletions, pendingAdditions] = subject.getPendingTriples();
expect(pendingDeletions).toEqual([]);
expect(pendingAdditions.length).toBe(1);
expect(pendingAdditions[0].object.termType).toBe('Literal');
expect((pendingAdditions[0].object as Literal).datatype.value)
.toBe('http://www.w3.org/2001/XMLSchema#integer');
expect(pendingAdditions[0].object.value).toBe('42');
});
it('should throw an error when something other than a number was given', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLiteral);
expect(() => subject.addInteger(mockPredicate, new Date() as any))
.toThrowError('The given value is not an integer.');
});
it('should throw an error when a decimal number was given', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLiteral);
expect(() => subject.addInteger(mockPredicate, 13.37))
.toThrowError('The given value is not an integer.');
});
});
describe('addDecimal', () => {
it('should produce Triples that the Document can store in the user\'s Pod', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLiteral);
subject.addDecimal(mockPredicate, 13.37);
const [pendingDeletions, pendingAdditions] = subject.getPendingTriples();
expect(pendingDeletions).toEqual([]);
expect(pendingAdditions.length).toBe(1);
expect(pendingAdditions[0].object.termType).toBe('Literal');
expect((pendingAdditions[0].object as Literal).datatype.value)
.toBe('http://www.w3.org/2001/XMLSchema#decimal');
expect(pendingAdditions[0].object.value).toBe('13.37');
});
it('should store an integer as a decimal number', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLiteral);
subject.addDecimal(mockPredicate, 42);
const [pendingDeletions, pendingAdditions] = subject.getPendingTriples();
expect(pendingDeletions).toEqual([]);
expect(pendingAdditions.length).toBe(1);
expect(pendingAdditions[0].object.termType).toBe('Literal');
expect(pendingAdditions[0].object.value).toBe('42');
});
it('should throw an error when something other than a number was given', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLiteral);
expect(() => subject.addDecimal(mockPredicate, 'Not a number' as any))
.toThrowError('The given value is not a decimal.');
});
});
describe('addDateTime', () => {
it('should produce Triples that the Document can store in the user\'s Pod', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLiteral);
subject.addDateTime(mockPredicate, new Date(Date.UTC(1970, 0)));
const [pendingDeletions, pendingAdditions] = subject.getPendingTriples();
expect(pendingDeletions).toEqual([]);
expect(pendingAdditions.length).toBe(1);
expect(pendingAdditions[0].object.termType).toBe('Literal');
expect((pendingAdditions[0].object as Literal).datatype.value)
.toBe('http://www.w3.org/2001/XMLSchema#dateTime');
expect(pendingAdditions[0].object.value).toBe('1970-01-01T00:00:00Z');
});
it('should throw an error when something other than a Date was given', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLiteral);
expect(() => subject.addDateTime(mockPredicate, 'Not a Date' as any))
.toThrowError('The given value is not a DateTime.');
});
});
describe('removeLiteral', () => {
it('should produce Triples that the Document can apply to the user\'s Pod', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithTwoLiterals);
subject.removeLiteral(mockPredicate, mockLiteralValue2);
const [pendingDeletions, pendingAdditions] = subject.getPendingTriples();
expect(pendingAdditions).toEqual([]);
expect(pendingDeletions.length).toBe(1);
expect(pendingDeletions[0].object.termType).toBe('Literal');
expect(pendingDeletions[0].object.value).toBe(mockLiteralValue2);
});
it('should properly remove an integer, if given', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithIntegerLiteral);
subject.removeLiteral(mockPredicate, mockLiteralInteger);
const [pendingDeletions, pendingAdditions] = subject.getPendingTriples();
expect(pendingAdditions).toEqual([]);
expect(pendingDeletions.length).toBe(1);
expect(pendingDeletions[0].object.termType).toBe('Literal');
expect((pendingDeletions[0].object as Literal).datatype.value)
.toBe('http://www.w3.org/2001/XMLSchema#integer');
expect(pendingDeletions[0].object.value).toBe(mockLiteralInteger.toString());
});
it('should properly remove a decimal, if given', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithDecimalLiteral);
subject.removeLiteral(mockPredicate, mockLiteralDecimal);
const [pendingDeletions, pendingAdditions] = subject.getPendingTriples();
expect(pendingAdditions).toEqual([]);
expect(pendingDeletions.length).toBe(1);
expect(pendingDeletions[0].object.termType).toBe('Literal');
expect((pendingDeletions[0].object as Literal).datatype.value)
.toBe('http://www.w3.org/2001/XMLSchema#decimal');
expect(pendingDeletions[0].object.value).toBe(mockLiteralDecimal.toString());
});
it('should properly remove a Date, if given', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithDateLiteral);
subject.removeLiteral(mockPredicate, mockLiteralDateTime);
const [pendingDeletions, pendingAdditions] = subject.getPendingTriples();
expect(pendingAdditions).toEqual([]);
expect(pendingDeletions.length).toBe(1);
expect(pendingDeletions[0].object.termType).toBe('Literal');
expect((pendingDeletions[0].object as Literal).datatype.value)
.toBe('http://www.w3.org/2001/XMLSchema#dateTime');
expect(pendingDeletions[0].object.value).toBe(mockLiteralDateTimeString);
});
});
describe('removeString', () => {
it('should produce Triples that the Document can apply to the user\'s Pod', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithTwoLiterals);
subject.removeString(mockPredicate, 'Some string');
const [pendingDeletions, pendingAdditions] = subject.getPendingTriples();
expect(pendingAdditions).toEqual([]);
expect(pendingDeletions.length).toBe(1);
expect(pendingDeletions[0].object.termType).toBe('Literal');
expect((pendingDeletions[0].object as Literal).datatype.value)
.toBe('http://www.w3.org/2001/XMLSchema#string');
expect(pendingDeletions[0].object.value).toBe('Some string');
});
it('should throw an error if something other than a string was given', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithIntegerLiteral);
expect(() => subject.removeString(mockPredicate, new Date() as any))
.toThrowError('The given value is not a string.');
});
});
describe('removeLocaleString', () => {
it('should produce Triples that the Document can apply to the user\'s Pod', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithTwoLiterals);
subject.removeLocaleString(mockPredicate, 'Some string', 'en-GB');
const [pendingDeletions, pendingAdditions] = subject.getPendingTriples();
expect(pendingAdditions).toEqual([]);
expect(pendingDeletions.length).toBe(1);
expect(pendingDeletions[0].object.termType).toBe('Literal');
expect((pendingDeletions[0].object as Literal).datatype.value)
.toBe('http://www.w3.org/1999/02/22-rdf-syntax-ns#langString');
expect((pendingDeletions[0].object as Literal).language).toBe('en-gb');
expect(pendingDeletions[0].object.value).toBe('Some string');
});
it('should throw an error if something other than a string was given', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithIntegerLiteral);
expect(() => subject.removeLocaleString(mockPredicate, 42 as any, 'nl-NL'))
.toThrowError('The given value is not a string.');
});
});
describe('removeInteger', () => {
it('should produce Triples that the Document can apply to the user\'s Pod', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithIntegerLiteral);
subject.removeInteger(mockPredicate, 42);
const [pendingDeletions, pendingAdditions] = subject.getPendingTriples();
expect(pendingAdditions).toEqual([]);
expect(pendingDeletions.length).toBe(1);
expect(pendingDeletions[0].object.termType).toBe('Literal');
expect((pendingDeletions[0].object as Literal).datatype.value)
.toBe('http://www.w3.org/2001/XMLSchema#integer');
expect(pendingDeletions[0].object.value).toBe('42');
});
it('should throw an error if something other than a number was given', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithIntegerLiteral);
expect(() => subject.removeInteger(mockPredicate, 'Not a number' as any))
.toThrowError('The given value is not an integer.');
});
it('should throw an error if a non-integer number was given', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithIntegerLiteral);
expect(() => subject.removeInteger(mockPredicate, 13.37))
.toThrowError('The given value is not an integer.');
});
});
describe('removeDecimal', () => {
it('should produce Triples that the Document can apply to the user\'s Pod', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithDecimalLiteral);
subject.removeDecimal(mockPredicate, 13.37);
const [pendingDeletions, pendingAdditions] = subject.getPendingTriples();
expect(pendingAdditions).toEqual([]);
expect(pendingDeletions.length).toBe(1);
expect(pendingDeletions[0].object.termType).toBe('Literal');
expect((pendingDeletions[0].object as Literal).datatype.value)
.toBe('http://www.w3.org/2001/XMLSchema#decimal');
expect(pendingDeletions[0].object.value).toBe('13.37');
});
it('should store integers as decimals', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithDecimalLiteral);
subject.removeDecimal(mockPredicate, 42);
const [pendingDeletions, pendingAdditions] = subject.getPendingTriples();
expect(pendingAdditions).toEqual([]);
expect(pendingDeletions.length).toBe(1);
expect(pendingDeletions[0].object.termType).toBe('Literal');
expect((pendingDeletions[0].object as Literal).datatype.value)
.toBe('http://www.w3.org/2001/XMLSchema#decimal');
expect(pendingDeletions[0].object.value).toBe('42');
});
it('should throw an error if something other than a number was given', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithDecimalLiteral);
expect(() => subject.removeDecimal(mockPredicate, 'Not a number' as any))
.toThrowError('The given value is not a decimal.');
});
});
describe('removeDateTime', () => {
it('should produce Triples that the Document can apply to the user\'s Pod', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithDateLiteral);
subject.removeDateTime(mockPredicate, new Date(Date.UTC(1970, 0)));
const [pendingDeletions, pendingAdditions] = subject.getPendingTriples();
expect(pendingAdditions).toEqual([]);
expect(pendingDeletions.length).toBe(1);
expect(pendingDeletions[0].object.termType).toBe('Literal');
expect((pendingDeletions[0].object as Literal).datatype.value)
.toBe('http://www.w3.org/2001/XMLSchema#dateTime');
expect(pendingDeletions[0].object.value).toBe('1970-01-01T00:00:00Z');
});
it('should throw an error if something other than a DateTime was given', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithDateLiteral);
expect(() => subject.removeDateTime(mockPredicate, 42 as any))
.toThrowError('The given value is not a DateTime.');
});
});
describe('setLiteral', () => {
it('should remove all existing values, whether Literal or Reference', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLiteralThenRef);
subject.setLiteral(mockPredicate, mockLiteralValue2);
const [pendingDeletions, pendingAdditions] = subject.getPendingTriples();
expect(pendingDeletions).toEqual([
triple(
namedNode(mockSubjectWithLiteralThenRef),
namedNode(mockPredicate),
mockObjectLiteral,
),
triple(
namedNode(mockSubjectWithLiteralThenRef),
namedNode(mockPredicate),
namedNode(mockObjectRef),
),
]);
expect(pendingAdditions.length).toBe(1);
expect(pendingAdditions[0].object.termType).toBe('Literal');
expect(pendingAdditions[0].object.value).toBe(mockLiteralValue2);
});
});
describe('setString', () => {
it('should remove all existing values, whether Literal or Reference', async () => {
const mockTripleDocument = await getMockTripleDocument();
const subject = initialiseSubject(mockTripleDocument, mockSubjectWithLiteralThenRef);
subject.setString(mockPredicate, 'Some string');
const [pendingDeletions, pendingAdditions] = subject.getPendingTriples();
expect(pendingDeletions).toEqual([
triple(
namedNode(mockSubjectWithLiteralThenRef),
namedNode(mockPredicate),
mockObjectLiteral,
),
triple(
namedNode(mockSubjectWithLiteralThenRef),
namedNode(mockPredicate),
namedNode(mockObjectRef),
),
]);
expect(pendingAdditions.length).toBe(1);
expect(pendingAdditions[0].object.termType).toBe('Literal');
expect((pendingAdditions[0].object as Literal).datatype.value)
.toBe('http://www.w3.org/2001/XMLSchema#string');
expect(pendingAdditions[0].object.value).toBe('Some string');
});
});
describe('setLocaleString', () => {
it('should remo