@inrupt/solid-client
Version:
Make your web apps work with Solid Pods.
153 lines (135 loc) • 5.58 kB
text/typescript
// Copyright Inrupt Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
// Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
import { jest, describe, it, expect } from "@jest/globals";
import { foaf, rdf } from "rdf-namespaces";
import { DataFactory } from "n3";
import { getTurtleParser, triplesToTurtle } from "./turtle";
describe("The Parser", () => {
it("should correctly find all triples in raw Turtle", async () => {
const parser = getTurtleParser();
const onQuadCallback = jest.fn<Parameters<typeof parser.onQuad>[0]>();
const onCompleteCallback = jest.fn();
parser.onQuad(onQuadCallback);
parser.onComplete(onCompleteCallback);
const turtle = `
@prefix : <#>.
@prefix foaf: <http://xmlns.com/foaf/0.1/>.
:someSubject a foaf:Person; foaf:name "Some name".
`;
await parser.parse(turtle, {
internal_resourceInfo: {
sourceIri: "https://example.com/some-path",
isRawData: false,
linkedResources: {},
},
});
const expectedTriple1 = DataFactory.quad(
DataFactory.namedNode("https://example.com/some-path#someSubject"),
DataFactory.namedNode(rdf.type),
DataFactory.namedNode(foaf.Person),
undefined,
);
const expectedTriple2 = DataFactory.quad(
DataFactory.namedNode("https://example.com/some-path#someSubject"),
DataFactory.namedNode(foaf.name),
DataFactory.literal("Some name"),
undefined,
);
// Our RDF parser will use a very specific implementation, which may use a
// different RDF/JS implementation than our main code. This is no problem,
// but we just need to make sure we use the RDF/JS 'quad equals' method
// instead of the generic Jest `.toEqual()`, since it's RDF-quad-equality
// we're checking, and not quad-implementation-equality.
expect(onQuadCallback).toHaveBeenCalledTimes(2);
expect(onQuadCallback.mock.calls[0][0].equals(expectedTriple1)).toBe(true);
expect(onQuadCallback.mock.calls[1][0].equals(expectedTriple2)).toBe(true);
expect(onCompleteCallback).toHaveBeenCalledTimes(1);
});
it("should reject if the Turtle is invalid", async () => {
const parser = getTurtleParser();
const onErrorCallback = jest.fn();
const onCompleteCallback = jest.fn();
parser.onError(onErrorCallback);
parser.onComplete(onCompleteCallback);
const turtle = `
@prefix : <#>.
@prefix foaf: <http://xmlns.com/foaf/0.1/>.
:arbitrarySubject a foaf:Person; foaf:name “A literal with invalid quotes”.
`;
await parser.parse(turtle, {
internal_resourceInfo: {
sourceIri: "https://example.com/some-path",
isRawData: false,
linkedResources: {},
},
});
expect(onErrorCallback).toHaveBeenCalledTimes(1);
expect(onErrorCallback.mock.calls[0][0]).toBeInstanceOf(Error);
});
});
describe("triplesToTurtle", () => {
it("should convert quads to a turtle string", async () => {
const triples = [
DataFactory.quad(
DataFactory.namedNode("https://vincentt.inrupt.net/profile/card#me"),
DataFactory.namedNode(foaf.name),
DataFactory.literal("Vincent"),
undefined,
),
];
const turtle = await triplesToTurtle(triples);
expect(turtle.trim()).toBe(
'<https://vincentt.inrupt.net/profile/card#me> <http://xmlns.com/foaf/0.1/name> "Vincent".',
);
});
it("should ignore the Graph part of the Quad", async () => {
const triples = [
DataFactory.quad(
DataFactory.namedNode("https://vincentt.inrupt.net/profile/card#me"),
DataFactory.namedNode(foaf.name),
DataFactory.literal("Vincent"),
DataFactory.namedNode("https://vincentt.inrupt.net/profile/card"),
),
];
const turtle = await triplesToTurtle(triples);
expect(turtle.trim()).toBe(
'<https://vincentt.inrupt.net/profile/card#me> <http://xmlns.com/foaf/0.1/name> "Vincent".',
);
});
it("allows to pass a prefix map", async () => {
const triples = [
DataFactory.quad(
DataFactory.namedNode("https://vincentt.inrupt.net/profile/card#me"),
DataFactory.namedNode(foaf.name),
DataFactory.literal("Vincent"),
undefined,
),
];
const turtle = await triplesToTurtle(triples, {
prefixes: { foaf: "http://xmlns.com/foaf/0.1/" },
});
expect(turtle.trim()).toContain(
"@prefix foaf: <http://xmlns.com/foaf/0.1/>",
);
expect(turtle.trim()).toContain(
'<https://vincentt.inrupt.net/profile/card#me> foaf:name "Vincent".',
);
});
});