Skip to content

Commit

Permalink
refactor(test): moved logic outside individual tests
Browse files Browse the repository at this point in the history
  • Loading branch information
jenspots committed Mar 30, 2024
1 parent f623f4e commit 9798436
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 74 deletions.
39 changes: 21 additions & 18 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,18 @@ import formatsPretty from "@rdfjs/formats/pretty.js";
import Serializer from "@rdfjs/serializer-turtle";
import { Validator } from "shacl-engine";

class ValidateArguments {
path: string;
incoming: Stream<string>;
outgoing: Writer<string>;
report?: Writer<string>;
}

export async function validate(
path: string,
reader: Stream<string>,
writer: Writer<string>,
error?: Writer<string>,
args: ValidateArguments,
): Promise<() => Promise<void>> {
const { path, incoming, outgoing, report } = args;

// Initialize the shared serializer.
const prefixes = new PrefixMapFactory().prefixMap();
prefixes.set("ex", rdf.namedNode("http://example.org#"));
Expand All @@ -22,7 +28,7 @@ export async function validate(
rdf.formats.import(formatsPretty);

// Create shape stream.
const res = await rdf.fetch("./tests/shacl/point.ttl");
const res = await rdf.fetch(path);
const shapes = await res.dataset();

// Parse input stream using shape stream.
Expand All @@ -32,31 +38,28 @@ export async function validate(
return async () => {
// Anything that passes through this processor and identifies with a
// specific shape should match the SHACL definition.
reader.on("data", async (data) => {
incoming.on("data", async (data) => {
// Parse data into a dataset.
const rawStream = Readable.from(data);
const quadStream = parser.import(rawStream);
const dataset = await rdf.dataset().import(quadStream);

// Run through validator.
const report = await validator.validate({ dataset });
const reportRaw = serializer.transform(report.dataset);
const result = await validator.validate({ dataset });
const resultRaw = serializer.transform(result.dataset);

// Pass through data if valid.
if (report.conforms) {
await writer.push(data);
}

// Send report if error channel is given.
if (error) {
await error.push(reportRaw);
if (result.conforms) {
await outgoing.push(data);
} else if (report) {
await report.push(resultRaw);
}
});

// If the input stream closes itself, so should the output streams.
reader.on("end", () => {
writer.end();
error?.end();
incoming.on("end", () => {
outgoing.end();
report?.end();
});
};
}
Empty file added tests/data/square.report.ttl
Empty file.
7 changes: 7 additions & 0 deletions tests/data/square.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@prefix ex: <http://example.org#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

ex:SomeSquare a ex:Square;
ex:x "0"^^xsd:integer;
ex:y "0"^^xsd:integer;
ex:size "1"^^xsd:integer.
130 changes: 74 additions & 56 deletions tests/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,79 +1,97 @@
import { validate } from "../src";
import { SimpleStream } from "@ajuvercr/js-runner";
import { describe, test, expect } from "vitest";
import { describe, test, expect, beforeEach } from "vitest";
import * as fs from "fs";

describe("shacl", () => {
// Valid point.
const valid = fs.readFileSync("./tests/data/valid.ttl").toString();
const validReport = fs
.readFileSync("./tests/data/valid.report.ttl")
.toString();
// Channel which streams incoming RDF.
let incoming: SimpleStream<string>;

// Invalid point.
const invalid = fs.readFileSync("./tests/data/invalid.ttl").toString();
const invalidReport = fs
.readFileSync("./tests/data/invalid.report.ttl")
.toString();
// Output channel, if successful.
let outgoing: SimpleStream<string>;
let outgoingData: string;

// SHACL data.
const shapePath = "./tests/shacl/point.ttl";
// Reporting channel, if invalid shape is found.
let report: SimpleStream<string>;
let reportData: string;

test("successful", async () => {
expect.assertions(2);
// Valid point.
const validRdfData = fs.readFileSync("./tests/data/valid.ttl").toString();

// Function parameters.
const incoming = new SimpleStream<string>();
const outgoing = new SimpleStream<string>();
const report = new SimpleStream<string>();
// Invalid point.
const invalidRdfData = fs.readFileSync("./tests/data/invalid.ttl").toString();
const invalidRdfReport = fs
.readFileSync("./tests/data/invalid.report.ttl")
.toString();

outgoing.on("data", (data) => {
expect(data).toEqual(valid);
});
const unknownRdfData = fs.readFileSync("./tests/data/square.ttl").toString();

report.on("data", (data) => {
expect(data).toEqual(validReport);
});
// SHACL data.
const shaclPath = "./tests/shacl/point.ttl";

// Initialize and execute the function.
const func = await validate(shapePath, incoming, outgoing, report);
await func();
// Utility function which waits for all streams to settle.
async function endAll(): Promise<void> {
await incoming.end();
await outgoing.end();
await report.end();
}

// Send point into the pipeline.
await incoming.push(valid);
beforeEach(async () => {
// Reset and start the streams.
incoming = new SimpleStream<string>();
outgoing = new SimpleStream<string>();
report = new SimpleStream<string>();

// Finish testing.
await incoming.end();
await outgoing.end();
await report.end();
// Reset the data itself.
outgoingData = "";
reportData = "";

// Reinitialize the data handlers.
outgoing.on("data", (data) => {
outgoingData += data;
});

test("invalid", async () => {
expect.assertions(1);
report.on("data", (data) => {
reportData += data;
});

// Restart the processor, which is the same for each test.
const func = await validate({
path: shaclPath,
incoming,
outgoing,
report,
});
await func();
});

describe("shacl", () => {
test("successful", async () => {
expect.assertions(2);

await incoming.push(validRdfData);
await endAll();

expect(outgoingData).toEqual(validRdfData);
expect(reportData).toEqual("");
});

// Function parameters.
const incoming = new SimpleStream<string>();
const outgoing = new SimpleStream<string>();
const error = new SimpleStream<string>();
test("invalid", async () => {
expect.assertions(2);

outgoing.on("data", () => {
expect(true).toBeFalsy();
});
await incoming.push(invalidRdfData);
await endAll();

error.on("data", (data) => {
expect(data).toEqual(invalidReport);
});
expect(outgoingData).toEqual("");
expect(reportData).toEqual(invalidRdfReport);
});

// Initialize and execute the function.
const func = await validate(shapePath, incoming, outgoing, error);
await func();
test("unknown", async () => {
expect.assertions(2);

// Send point into the pipeline.
await incoming.push(invalid);
await incoming.push(unknownRdfData);
await endAll();

// Finish testing.
await incoming.end();
await outgoing.end();
await error.end();
expect(outgoingData).toEqual(unknownRdfData);
expect(reportData).toEqual("");
});
});

0 comments on commit 9798436

Please sign in to comment.