rescribet/link-lib

View on GitHub
src/__tests__/RDFStore.spec.ts

Summary

Maintainability
F
6 days
Test Coverage
import "jest";
import "./useFactory";

import rdfFactory, { createNS, NamedNode, QuadPosition, Quadruple } from "@ontologies/core";
import * as owl from "@ontologies/owl";
import * as rdf from "@ontologies/rdf";
import * as rdfs from "@ontologies/rdfs";
import * as schema from "@ontologies/schema";
import * as xsd from "@ontologies/xsd";

import ll from "../ontology/ll";
import { RDFStore } from "../RDFStore";
import RDFIndex from "../store/RDFIndex";
import { getBasicStore } from "../testUtilities";

const example = createNS("http://example.com/");
const ex = createNS("http://example.com/ns#");

const defaultGraph: NamedNode = rdfFactory.defaultGraph();

const schemaT = schema.Thing;
const thingStatements: Quadruple[] = [
    [schemaT, rdf.type, rdfs.Class, defaultGraph],
    [schemaT, rdfs.comment, rdfFactory.literal("The most generic type"), defaultGraph],
    [schemaT, rdfs.label, rdfFactory.literal("Thing."), defaultGraph],
];
const aboutIsThing: Quadruple[] = [
    [schema.AboutPage, owl.sameAs, schemaT, defaultGraph],
];
const thingIsAbout: Quadruple[] = [
    [schemaT, owl.sameAs, schema.AboutPage, defaultGraph],
];

describe("RDFStore", () => {
    describe("#addQuadruples", () => {
        it("requires an array", () => {
            const store = new RDFStore();

            expect(() => {
                store.addQuadruples("test" as any);
            }).toThrowError(TypeError);
        });

        it("works", () => {
            const store = new RDFStore();
            store.addQuadruples(thingStatements);

            const libStatements = store.getInternalStore().quads;
            expect(libStatements).toHaveLength(3);
            expect(libStatements[0]).toEqual(thingStatements[0]);
            expect(libStatements[1]).toEqual(thingStatements[1]);
            expect(libStatements[2]).toEqual(thingStatements[2]);
        });

        describe("owl:sameAs", () => {
            describe("big small", () => {
                it("equates existing data", () => {
                    const store = getBasicStore();
                    store.store.addQuadruples(aboutIsThing);
                    store.store.addQuadruples(thingStatements);
                    expect(store.store.match(schema.AboutPage, rdfs.label, rdfFactory.literal("Thing.")))
                        .toHaveLength(1);
                });

                it("equates new data", () => {
                    const store = getBasicStore();
                    store.store.addQuadruples(thingStatements);
                    store.store.addQuadruples(aboutIsThing);
                    expect(store.store.match(schema.AboutPage, rdfs.label, rdfFactory.literal("Thing.")))
                        .toHaveLength(1);
                });
            });

            describe("small big", () => {
                it("equates existing data", () => {
                    const store = getBasicStore();
                    store.store.addQuadruples(thingIsAbout);
                    store.store.addQuadruples(thingStatements);
                    expect(store.store.match(schema.AboutPage, rdfs.label, rdfFactory.literal("Thing.")))
                        .toHaveLength(1);
                });

                it("equates new data", () => {
                    const store = getBasicStore();
                    store.store.addQuadruples(thingStatements);
                    store.store.addQuadruples(thingIsAbout);
                    expect(store.store.match(schema.AboutPage, rdfs.label, rdfFactory.literal("Thing.")))
                        .toHaveLength(1);
                });
            });
        });
    });

    describe("#flush", () => {
        it("is returns the work available", () => {
            const store = new RDFStore();
            store.addQuadruples(thingStatements);
            const res = store.flush();
            expect(res.has(schemaT.value)).toBeTruthy();
            expect(res.has(schema.AboutPage.value)).toBeFalsy();
        });

        it("is returns an empty set without work", () => {
            const res = new RDFStore().flush();
            expect(res.size).toEqual(0);
        });
    });

    describe("#getInternalStore", () => {
        it("returns the store", () => {
            expect(new RDFStore().getInternalStore()).toBeInstanceOf(RDFIndex);
        });
    });

    describe("#replaceMatches", () => {
        it("replaces a statement", () => {
            const store = new RDFStore();
            store.addQuadruples(thingStatements);

            const quads: Quadruple[] = [
                [schemaT, rdfs.label, rdfFactory.literal("Thing!"), ll.ns("replace")],
            ];

            const before = store.match(schemaT, rdfs.label, null);
            expect(before).toHaveLength(1);
            expect(before[0][QuadPosition.object]).toEqual(rdfFactory.literal("Thing."));

            store.replaceMatches(quads);

            const after = store.match(schemaT, rdfs.label, null);
            expect(after).toHaveLength(1);
            expect(after[0][QuadPosition.object]).toEqual(rdfFactory.literal("Thing!", undefined, xsd.string));
        });
    });

    describe("#processDelta", () => {
        it("handles empty values", () => {
            const store = new RDFStore();

            expect(store.processDelta(new Array(1))).toEqual([]);
        });

        describe("ll:replace", () => {
            it("replaces existing", () => {
                const store = new RDFStore();

                expect(store.processDelta(new Array(1))).toEqual([]);
            });
        });

        describe("ll:remove", () => {
            it("removes one", () => {
                const store = new RDFStore();
                store.addQuadruples(thingStatements);

                expect(store.match(null, null, null)).toHaveLength(thingStatements.length);

                const statements: Quadruple[] = [
                    [schemaT, rdfs.label, rdfFactory.literal("irrelevant"), ll.ns("remove")],
                ];

                store.processDelta(statements);

                expect(store.match(null, null, null)).toHaveLength(thingStatements.length - 1);
                expect(store.match(schemaT, rdfs.label, null)).toHaveLength(0);
            });

            it("removes many", () => {
                const store = new RDFStore();
                store.addQuadruples(thingStatements);
                store.add(schemaT, rdfs.label, rdfFactory.literal("Thing gb", "en-gb"));

                expect(store.match(null, null, null)).toHaveLength(thingStatements.length + 1);

                const quads: Quadruple[] = [
                    [schemaT, rdfs.label, rdfFactory.literal("irrelevant"), ll.ns("remove")],
                ];

                store.processDelta(quads);

                expect(store.match(null, null, null)).toHaveLength(thingStatements.length - 1);
                expect(store.match(schemaT, rdfs.label, null)).toHaveLength(0);
            });
        });
    });

    describe("#getResourcePropertyRaw", () => {
        const store = new RDFStore();
        store.addQuadruples([
            [ex("a"), ex("p"), ex("x"), defaultGraph],
            [ex("a"), ex("r"), ex("y"), defaultGraph],

            [ex("b"), ex("p"), ex("xx"), defaultGraph],
            [ex("b"), ex("p"), ex("yy"), defaultGraph],
        ]);

        it("resolves empty values for single property", () => {
            expect(store.getResourcePropertyRaw(ex("none"), ex("p")))
                .toEqual([]);
        });

        it("resolves empty values for multiple properties", () => {
            expect(store.getResourcePropertyRaw(ex("none"), [ex("p"), ex("q")]))
                .toEqual([]);
        });

        it("resolves values for single property", () => {
            expect(store.getResourcePropertyRaw(ex("b"), ex("p")))
                .toEqual([
                    [ex("b"), ex("p"), ex("xx"), rdfFactory.namedNode("rdf:defaultGraph")],
                    [ex("b"), ex("p"), ex("yy"), rdfFactory.namedNode("rdf:defaultGraph")],
                ]);
        });

        it("resolves values for multiple properties one existent", () => {
            expect(store.getResourcePropertyRaw(ex("a"), [ex("p"), ex("q")]))
                .toEqual([
                    [ex("a"), ex("p"), ex("x"), rdfFactory.namedNode("rdf:defaultGraph")],
                ]);
        });

        it("resolves values for multiple properties multiple existent", () => {
            expect(store.getResourcePropertyRaw(ex("a"), [ex("r"), ex("p")]))
                .toEqual([
                  [ex("a"), ex("r"), ex("y"), rdfFactory.namedNode("rdf:defaultGraph")],
                  [ex("a"), ex("p"), ex("x"), rdfFactory.namedNode("rdf:defaultGraph")],
                ]);
        });
    });

    describe("#getResourceProperty", () => {
        it("returns undefined for type statements on unloaded resources", () => {
            const store = new RDFStore();

            expect(store.getResourceProperty(ex("1"), rdf.type)).toBeUndefined();
        });

        it("returns the type for type statements", () => {
            const store = new RDFStore();
            store.addQuadruples([
                [ex("2"), rdf.type, ex("SomeClass"), rdfFactory.namedNode("rdf:defaultGraph")],
            ]);

            expect(store.getResourceProperty(ex("2"), rdf.type))
                .toEqual(ex("SomeClass"));
        });

        it("returns undefined for other statements on unloaded resources", () => {
            const store = new RDFStore();

            expect(store.getResourceProperty(ex("1"), ex("prop"))).toBeUndefined();
        });

        it("returns the object for other statements", () => {
            const store = new RDFStore();
            store.addQuadruples([
                [ex("2"), ex("prop"), rdfFactory.literal("some prop"), defaultGraph],
            ]);

            expect(store.getResourceProperty(ex("2"), ex("prop")))
                .toEqual(rdfFactory.literal("some prop"));
        });

        it("picks the preferred language", () => {
            const store = new RDFStore();
            store.addQuadruples([
                [ex("2"), ex("prop"), rdfFactory.literal("some prop", "de"), defaultGraph],
                [ex("2"), ex("prop"), rdfFactory.literal("some prop", "nl"), defaultGraph],
                [ex("2"), ex("prop"), rdfFactory.literal("some prop", "en"), defaultGraph],
                [ex("2"), ex("prop"), rdfFactory.literal("some prop", "fr"), defaultGraph],
            ]);

            expect(store.getResourceProperty(ex("2"), ex("prop")))
                .toEqual(rdfFactory.literal("some prop", "en"));
        });
    });

    describe("#rdfFactory", () => {
        it("returns the @ontologies/core factory", () => {
            expect(new RDFStore().rdfFactory).toBe(rdfFactory);
        });

        it("throws setting the factory", () => {
            const store = new RDFStore();
            expect(() => {
                store.rdfFactory = {} as any;
            }).toThrow();
        });
    });

    describe("#removeResource", () => {
        it("removes the resource data", () => {
            const store = getBasicStore();
            const resource = example("test");
            store.store.addQuadruples([
                [resource, rdf.type, schema.Person, defaultGraph],
                [resource, schema.name, rdfFactory.literal("Name"), defaultGraph],
                [resource, schema.author, ex("3"), defaultGraph],
                [example("other"), schema.author, ex("3"), defaultGraph],
            ]);

            expect(store.store.quadsFor(resource)).toHaveLength(3);
            store.store.removeResource(resource);
            expect(store.store.quadsFor(resource)).toHaveLength(0);
        });

        describe("owl:sameAs", () => {
            describe("big small", () => {
                it("equal before", () => {
                    const store = getBasicStore();
                    store.store.addQuadruples(aboutIsThing);
                    store.store.addQuadruples(thingStatements);

                    store.store.removeResource(schema.AboutPage);

                    expect(store.store.match(schema.AboutPage, rdfs.label, rdfFactory.literal("Thing.")))
                        .toHaveLength(0);
                    expect(store.store.match(schemaT, rdfs.label, rdfFactory.literal("Thing.")))
                        .toHaveLength(0);
                });

                it("equal after", () => {
                    const store = getBasicStore();
                    store.store.addQuadruples(thingStatements);
                    store.store.addQuadruples(aboutIsThing);

                    store.store.removeResource(schemaT);

                    expect(store.store.match(schema.AboutPage, rdfs.label, rdfFactory.literal("Thing.")))
                        .toHaveLength(0);
                    expect(store.store.match(schemaT, rdfs.label, rdfFactory.literal("Thing.")))
                        .toHaveLength(0);
                });
            });

            describe("small big", () => {
                it("equal before", () => {
                    const store = getBasicStore();
                    store.store.addQuadruples(thingIsAbout);
                    store.store.addQuadruples(thingStatements);

                    store.store.removeResource(schema.AboutPage);

                    expect(store.store.match(schema.AboutPage, rdfs.label, rdfFactory.literal("Thing.")))
                        .toHaveLength(0);
                    expect(store.store.match(schemaT, rdfs.label, rdfFactory.literal("Thing.")))
                        .toHaveLength(0);
                });

                it("equal after", () => {
                    const store = getBasicStore();
                    store.store.addQuadruples(thingStatements);
                    store.store.addQuadruples(thingIsAbout);

                    store.store.removeResource(schemaT);

                    expect(store.store.match(schema.AboutPage, rdfs.label, rdfFactory.literal("Thing.")))
                        .toHaveLength(0);
                    expect(store.store.match(schemaT, rdfs.label, rdfFactory.literal("Thing.")))
                        .toHaveLength(0);
                });
            });
        });
    });

    describe("#workAvailable", () => {
        it("is zero without work", () => {
            expect(new RDFStore().workAvailable()).toEqual(0);
        });

        it("is more than zero work", () => {
            const store = new RDFStore();
            expect(store.workAvailable()).toEqual(0);
            store.addQuadruples([...thingStatements, ...aboutIsThing]);
            expect(store.workAvailable()).toEqual(2);
        });

        it("is reset after #flush()", () => {
            const store = new RDFStore();
            store.addQuadruples([...thingStatements, ...aboutIsThing]);
            expect(store.workAvailable()).toEqual(2);
            store.flush();
            expect(store.workAvailable()).toEqual(0);
        });
    });
});