@noeldemartin/solid-utils 0.5.0 → 0.6.0-next.70fba2db4562da63a3ae210c80936d148acfc0de
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/io-CMHtz5bu.js +401 -0
- package/dist/io-CMHtz5bu.js.map +1 -0
- package/dist/noeldemartin-solid-utils.d.ts +13 -65
- package/dist/noeldemartin-solid-utils.js +224 -0
- package/dist/noeldemartin-solid-utils.js.map +1 -0
- package/dist/testing.d.ts +45 -0
- package/dist/testing.js +157 -0
- package/dist/testing.js.map +1 -0
- package/package.json +58 -63
- package/src/errors/UnauthorizedError.ts +1 -3
- package/src/errors/UnsuccessfulNetworkRequestError.ts +2 -2
- package/src/helpers/auth.test.ts +221 -0
- package/src/helpers/auth.ts +28 -27
- package/src/helpers/identifiers.test.ts +76 -0
- package/src/helpers/identifiers.ts +14 -17
- package/src/helpers/index.ts +0 -1
- package/src/helpers/interop.ts +23 -16
- package/src/helpers/io.test.ts +228 -0
- package/src/helpers/io.ts +57 -77
- package/src/helpers/jsonld.ts +6 -6
- package/src/helpers/vocabs.ts +3 -6
- package/src/helpers/wac.test.ts +64 -0
- package/src/helpers/wac.ts +10 -6
- package/src/index.ts +3 -0
- package/src/models/SolidDocument.test.ts +77 -0
- package/src/models/SolidDocument.ts +14 -18
- package/src/models/SolidStore.ts +22 -12
- package/src/models/SolidThing.ts +5 -7
- package/src/models/index.ts +2 -0
- package/src/{helpers/testing.ts → testing/helpers.ts} +24 -27
- package/src/testing/hepers.test.ts +329 -0
- package/src/testing/index.ts +2 -2
- package/src/testing/vitest/index.ts +15 -0
- package/src/testing/vitest/matchers.ts +68 -0
- package/src/types/n3.d.ts +0 -2
- package/.github/workflows/ci.yml +0 -16
- package/.nvmrc +0 -1
- package/CHANGELOG.md +0 -70
- package/dist/noeldemartin-solid-utils.cjs.js +0 -2
- package/dist/noeldemartin-solid-utils.cjs.js.map +0 -1
- package/dist/noeldemartin-solid-utils.esm.js +0 -2
- package/dist/noeldemartin-solid-utils.esm.js.map +0 -1
- package/dist/noeldemartin-solid-utils.umd.js +0 -90
- package/dist/noeldemartin-solid-utils.umd.js.map +0 -1
- package/noeldemartin.config.js +0 -9
- package/src/main.ts +0 -5
- package/src/plugins/chai/assertions.ts +0 -40
- package/src/plugins/chai/index.ts +0 -5
- package/src/plugins/cypress/types.d.ts +0 -15
- package/src/plugins/index.ts +0 -2
- package/src/plugins/jest/index.ts +0 -5
- package/src/plugins/jest/matchers.ts +0 -65
- package/src/plugins/jest/types.d.ts +0 -14
- package/src/testing/ResponseStub.ts +0 -46
- package/src/testing/mocking.ts +0 -33
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import SolidDocument from '@noeldemartin/solid-utils/models/SolidDocument';
|
|
4
|
+
import { turtleToQuadsSync } from '@noeldemartin/solid-utils/helpers';
|
|
5
|
+
|
|
6
|
+
describe('SolidDocument', () => {
|
|
7
|
+
|
|
8
|
+
it('Identifies storage documents', () => {
|
|
9
|
+
const hasStorageHeader = (link: string) => {
|
|
10
|
+
const document = new SolidDocument('', [], new Headers({ Link: link }));
|
|
11
|
+
|
|
12
|
+
return document.isStorage();
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/* eslint-disable max-len */
|
|
16
|
+
expect(hasStorageHeader('')).toBe(false);
|
|
17
|
+
expect(hasStorageHeader('<http://www.w3.org/ns/pim/space#Storage>; rel="type"')).toBe(true);
|
|
18
|
+
expect(hasStorageHeader('<http://www.w3.org/ns/pim/space#Storage>; rel="something-else"; rel="type"')).toBe(
|
|
19
|
+
true,
|
|
20
|
+
);
|
|
21
|
+
expect(
|
|
22
|
+
hasStorageHeader(
|
|
23
|
+
'<http://www.w3.org/ns/pim/space#Storage>; rel="something-else", <http://example.com>; rel="type"',
|
|
24
|
+
),
|
|
25
|
+
).toBe(false);
|
|
26
|
+
/* eslint-enable max-len */
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('Parses last modified from header', () => {
|
|
30
|
+
const document = new SolidDocument('', [], new Headers({ 'Last-Modified': 'Fri, 03 Sept 2021 16:09:12 GMT' }));
|
|
31
|
+
|
|
32
|
+
expect(document.getLastModified()).toEqual(new Date(1630685352000));
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('Parses last modified from document purl:modified', () => {
|
|
36
|
+
const document = new SolidDocument(
|
|
37
|
+
'https://pod.example.org/my-document',
|
|
38
|
+
turtleToQuadsSync(
|
|
39
|
+
`
|
|
40
|
+
<./fallback>
|
|
41
|
+
<http://purl.org/dc/terms/modified>
|
|
42
|
+
"2021-09-03T16:23:25.000Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
|
|
43
|
+
|
|
44
|
+
<>
|
|
45
|
+
<http://purl.org/dc/terms/modified>
|
|
46
|
+
"2021-09-03T16:09:12.000Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
|
|
47
|
+
`,
|
|
48
|
+
{ baseIRI: 'https://pod.example.org/my-document' },
|
|
49
|
+
),
|
|
50
|
+
new Headers({ 'Last-Modified': 'invalid date' }),
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
expect(document.getLastModified()).toEqual(new Date(1630685352000));
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('Parses last modified from any purl date', () => {
|
|
57
|
+
const document = new SolidDocument(
|
|
58
|
+
'https://pod.example.org/my-document',
|
|
59
|
+
turtleToQuadsSync(
|
|
60
|
+
`
|
|
61
|
+
<./fallback-one>
|
|
62
|
+
<http://purl.org/dc/terms/modified>
|
|
63
|
+
"2021-05-03T16:09:12.000Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
|
|
64
|
+
|
|
65
|
+
<./fallback-two>
|
|
66
|
+
<http://purl.org/dc/terms/created>
|
|
67
|
+
"2021-09-03T16:09:12.000Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
|
|
68
|
+
`,
|
|
69
|
+
{ baseIRI: 'https://pod.example.org/my-document' },
|
|
70
|
+
),
|
|
71
|
+
new Headers({ 'Last-Modified': 'invalid date' }),
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
expect(document.getLastModified()).toEqual(new Date(1630685352000));
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { arrayFilter, parseDate, stringMatch } from '@noeldemartin/utils';
|
|
2
|
-
import type { Quad } from '
|
|
2
|
+
import type { Quad } from '@rdfjs/types';
|
|
3
3
|
|
|
4
|
-
import { expandIRI } from '
|
|
4
|
+
import { expandIRI } from '@noeldemartin/solid-utils/helpers/vocabs';
|
|
5
5
|
|
|
6
6
|
import SolidStore from './SolidStore';
|
|
7
7
|
|
|
@@ -25,16 +25,13 @@ export default class SolidDocument extends SolidStore {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
public isACPResource(): boolean {
|
|
28
|
-
return !!this.headers
|
|
28
|
+
return !!this.headers
|
|
29
|
+
.get('Link')
|
|
29
30
|
?.match(/<http:\/\/www\.w3\.org\/ns\/solid\/acp#AccessControlResource>;[^,]+rel="type"/);
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
public isPersonalProfile(): boolean {
|
|
33
|
-
return !!this.statement(
|
|
34
|
-
this.url,
|
|
35
|
-
expandIRI('rdf:type'),
|
|
36
|
-
expandIRI('foaf:PersonalProfileDocument'),
|
|
37
|
-
);
|
|
34
|
+
return !!this.statement(this.url, expandIRI('rdf:type'), expandIRI('foaf:PersonalProfileDocument'));
|
|
38
35
|
}
|
|
39
36
|
|
|
40
37
|
public isStorage(): boolean {
|
|
@@ -54,10 +51,12 @@ export default class SolidDocument extends SolidStore {
|
|
|
54
51
|
}
|
|
55
52
|
|
|
56
53
|
public getLastModified(): Date | null {
|
|
57
|
-
return
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
??
|
|
54
|
+
return (
|
|
55
|
+
parseDate(this.headers.get('last-modified')) ??
|
|
56
|
+
parseDate(this.statement(this.url, 'purl:modified')?.object.value) ??
|
|
57
|
+
this.getLatestDocumentDate() ??
|
|
58
|
+
null
|
|
59
|
+
);
|
|
61
60
|
}
|
|
62
61
|
|
|
63
62
|
protected expandIRI(iri: string): string {
|
|
@@ -65,14 +64,11 @@ export default class SolidDocument extends SolidStore {
|
|
|
65
64
|
}
|
|
66
65
|
|
|
67
66
|
private getLatestDocumentDate(): Date | null {
|
|
68
|
-
const dates = [
|
|
69
|
-
|
|
70
|
-
...this.statements(undefined, 'purl:created'),
|
|
71
|
-
]
|
|
72
|
-
.map(statement => parseDate(statement.object.value))
|
|
67
|
+
const dates = [...this.statements(undefined, 'purl:modified'), ...this.statements(undefined, 'purl:created')]
|
|
68
|
+
.map((statement) => parseDate(statement.object.value))
|
|
73
69
|
.filter((date): date is Date => date !== null);
|
|
74
70
|
|
|
75
|
-
return dates.length > 0 ? dates.reduce((a, b) => a > b ? a : b) : null;
|
|
71
|
+
return dates.length > 0 ? dates.reduce((a, b) => (a > b ? a : b)) : null;
|
|
76
72
|
}
|
|
77
73
|
|
|
78
74
|
private getPermissionsFromWAC(type: string): SolidDocumentPermission[] {
|
package/src/models/SolidStore.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import type { Quad } from '
|
|
1
|
+
import type { BlankNode, Literal, NamedNode, Quad, Variable } from '@rdfjs/types';
|
|
2
2
|
|
|
3
|
-
import { expandIRI } from '
|
|
3
|
+
import { expandIRI } from '@noeldemartin/solid-utils/helpers/vocabs';
|
|
4
4
|
|
|
5
5
|
import SolidThing from './SolidThing';
|
|
6
6
|
|
|
7
|
+
export type Term = NamedNode | Literal | BlankNode | Quad | Variable;
|
|
8
|
+
|
|
7
9
|
export default class SolidStore {
|
|
8
10
|
|
|
9
11
|
private quads: Quad[];
|
|
@@ -24,21 +26,21 @@ export default class SolidStore {
|
|
|
24
26
|
this.quads.push(...quads);
|
|
25
27
|
}
|
|
26
28
|
|
|
27
|
-
public statements(subject?: string, predicate?: string, object?: string): Quad[] {
|
|
29
|
+
public statements(subject?: Term | string, predicate?: Term | string, object?: Term | string): Quad[] {
|
|
28
30
|
return this.quads.filter(
|
|
29
|
-
statement =>
|
|
30
|
-
(!object || statement.object
|
|
31
|
-
(!subject || statement.subject
|
|
32
|
-
(!predicate || statement.predicate
|
|
31
|
+
(statement) =>
|
|
32
|
+
(!object || this.termMatches(statement.object, object)) &&
|
|
33
|
+
(!subject || this.termMatches(statement.subject, subject)) &&
|
|
34
|
+
(!predicate || this.termMatches(statement.predicate, predicate)),
|
|
33
35
|
);
|
|
34
36
|
}
|
|
35
37
|
|
|
36
|
-
public statement(subject?: string, predicate?: string, object?: string): Quad | null {
|
|
38
|
+
public statement(subject?: Term | string, predicate?: Term | string, object?: Term | string): Quad | null {
|
|
37
39
|
const statement = this.quads.find(
|
|
38
|
-
|
|
39
|
-
(!object ||
|
|
40
|
-
(!subject ||
|
|
41
|
-
(!predicate ||
|
|
40
|
+
(_statement) =>
|
|
41
|
+
(!object || this.termMatches(_statement.object, object)) &&
|
|
42
|
+
(!subject || this.termMatches(_statement.subject, subject)) &&
|
|
43
|
+
(!predicate || this.termMatches(_statement.predicate, predicate)),
|
|
42
44
|
);
|
|
43
45
|
|
|
44
46
|
return statement ?? null;
|
|
@@ -58,4 +60,12 @@ export default class SolidStore {
|
|
|
58
60
|
return expandIRI(iri);
|
|
59
61
|
}
|
|
60
62
|
|
|
63
|
+
protected termMatches(term: Term, value: Term | string): boolean {
|
|
64
|
+
if (typeof value === 'string') {
|
|
65
|
+
return this.expandIRI(value) === term.value;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return term.termType === term.termType && term.value === value.value;
|
|
69
|
+
}
|
|
70
|
+
|
|
61
71
|
}
|
package/src/models/SolidThing.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { Quad } from '
|
|
1
|
+
import type { Quad } from '@rdfjs/types';
|
|
2
2
|
|
|
3
|
-
import { expandIRI } from '
|
|
3
|
+
import { expandIRI } from '@noeldemartin/solid-utils/helpers/vocabs';
|
|
4
4
|
|
|
5
5
|
export default class SolidThing {
|
|
6
6
|
|
|
@@ -13,15 +13,13 @@ export default class SolidThing {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
public value(property: string): string | undefined {
|
|
16
|
-
return this.quads
|
|
17
|
-
.find(quad => quad.predicate.value === expandIRI(property))
|
|
18
|
-
?.object.value;
|
|
16
|
+
return this.quads.find((quad) => quad.predicate.value === expandIRI(property))?.object.value;
|
|
19
17
|
}
|
|
20
18
|
|
|
21
19
|
public values(property: string): string[] {
|
|
22
20
|
return this.quads
|
|
23
|
-
.filter(quad => quad.predicate.value === expandIRI(property))
|
|
24
|
-
.map(quad => quad.object.value);
|
|
21
|
+
.filter((quad) => quad.predicate.value === expandIRI(property))
|
|
22
|
+
.map((quad) => quad.object.value);
|
|
25
23
|
}
|
|
26
24
|
|
|
27
25
|
}
|
package/src/models/index.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import { JSError, arrayRemove, pull, stringMatchAll } from '@noeldemartin/utils';
|
|
2
|
-
import type {
|
|
3
|
-
import type { Quad, Quad_Object } from 'rdf-js';
|
|
2
|
+
import type { Quad, Quad_Object } from '@rdfjs/types';
|
|
4
3
|
|
|
5
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
jsonldToQuads,
|
|
6
|
+
quadToTurtle,
|
|
7
|
+
quadsToTurtle,
|
|
8
|
+
sparqlToQuadsSync,
|
|
9
|
+
turtleToQuadsSync,
|
|
10
|
+
} from '@noeldemartin/solid-utils/helpers/io';
|
|
11
|
+
import type { JsonLD } from '@noeldemartin/solid-utils/helpers/jsonld';
|
|
6
12
|
|
|
7
13
|
let patternsRegExpsIndex: Record<string, RegExp> = {};
|
|
8
14
|
const builtInPatterns: Record<string, string> = {
|
|
@@ -19,10 +25,9 @@ class ExpectedQuadAssertionError extends JSError {
|
|
|
19
25
|
|
|
20
26
|
function assertExpectedQuadsExist(expectedQuads: Quad[], actualQuads: Quad[]): void {
|
|
21
27
|
for (const expectedQuad of expectedQuads) {
|
|
22
|
-
const matchingQuad = actualQuads.find(actualQuad => quadEquals(expectedQuad, actualQuad));
|
|
28
|
+
const matchingQuad = actualQuads.find((actualQuad) => quadEquals(expectedQuad, actualQuad));
|
|
23
29
|
|
|
24
|
-
if (!matchingQuad)
|
|
25
|
-
throw new ExpectedQuadAssertionError(expectedQuad);
|
|
30
|
+
if (!matchingQuad) throw new ExpectedQuadAssertionError(expectedQuad);
|
|
26
31
|
|
|
27
32
|
arrayRemove(actualQuads, matchingQuad);
|
|
28
33
|
}
|
|
@@ -34,10 +39,7 @@ function containsPatterns(value: string): boolean {
|
|
|
34
39
|
|
|
35
40
|
function createPatternRegexp(expected: string): RegExp {
|
|
36
41
|
const patternAliases = [];
|
|
37
|
-
const patternMatches = stringMatchAll<4, 1 | 2>(
|
|
38
|
-
expected,
|
|
39
|
-
/\[\[((.*?)\]\[)?([^\]]+)\]\]/g,
|
|
40
|
-
);
|
|
42
|
+
const patternMatches = stringMatchAll<4, 1 | 2>(expected, /\[\[((.*?)\]\[)?([^\]]+)\]\]/g);
|
|
41
43
|
const patterns: string[] = [];
|
|
42
44
|
let expectedRegExp = expected;
|
|
43
45
|
|
|
@@ -65,12 +67,10 @@ function quadValueEquals(expected: string, actual: string): boolean {
|
|
|
65
67
|
}
|
|
66
68
|
|
|
67
69
|
function quadObjectEquals(expected: Quad_Object, actual: Quad_Object): boolean {
|
|
68
|
-
if (expected.termType !== actual.termType)
|
|
69
|
-
return false;
|
|
70
|
+
if (expected.termType !== actual.termType) return false;
|
|
70
71
|
|
|
71
72
|
if (expected.termType === 'Literal' && actual.termType === 'Literal') {
|
|
72
|
-
if (expected.datatype.value !== actual.datatype.value)
|
|
73
|
-
return false;
|
|
73
|
+
if (expected.datatype.value !== actual.datatype.value) return false;
|
|
74
74
|
|
|
75
75
|
if (!containsPatterns(expected.value))
|
|
76
76
|
return expected.datatype.value === 'http://www.w3.org/2001/XMLSchema#dateTime'
|
|
@@ -82,9 +82,11 @@ function quadObjectEquals(expected: Quad_Object, actual: Quad_Object): boolean {
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
function quadEquals(expected: Quad, actual: Quad): boolean {
|
|
85
|
-
return
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
return (
|
|
86
|
+
quadObjectEquals(expected.object, actual.object) &&
|
|
87
|
+
quadValueEquals(expected.subject.value, actual.subject.value) &&
|
|
88
|
+
quadValueEquals(expected.predicate.value, actual.predicate.value)
|
|
89
|
+
);
|
|
88
90
|
}
|
|
89
91
|
|
|
90
92
|
function resetPatterns(): void {
|
|
@@ -119,8 +121,7 @@ export async function jsonldEquals(expected: JsonLD, actual: JsonLD): Promise<Eq
|
|
|
119
121
|
try {
|
|
120
122
|
assertExpectedQuadsExist(expectedQuads, actualQuads);
|
|
121
123
|
} catch (error) {
|
|
122
|
-
if (!(error instanceof ExpectedQuadAssertionError))
|
|
123
|
-
throw error;
|
|
124
|
+
if (!(error instanceof ExpectedQuadAssertionError)) throw error;
|
|
124
125
|
|
|
125
126
|
return result(false, error.message);
|
|
126
127
|
}
|
|
@@ -137,8 +138,7 @@ export function sparqlEquals(expected: string, actual: string): EqualityResult {
|
|
|
137
138
|
const result = (success: boolean, message: string) => ({ success, message, expected, actual });
|
|
138
139
|
|
|
139
140
|
for (const operation of Object.keys(expectedOperations)) {
|
|
140
|
-
if (!(operation in actualOperations))
|
|
141
|
-
return result(false, `Couldn't find expected ${operation} operation.`);
|
|
141
|
+
if (!(operation in actualOperations)) return result(false, `Couldn't find expected ${operation} operation.`);
|
|
142
142
|
|
|
143
143
|
const expectedQuads = pull(expectedOperations, operation);
|
|
144
144
|
const actualQuads = pull(actualOperations, operation);
|
|
@@ -149,8 +149,7 @@ export function sparqlEquals(expected: string, actual: string): EqualityResult {
|
|
|
149
149
|
try {
|
|
150
150
|
assertExpectedQuadsExist(expectedQuads, actualQuads);
|
|
151
151
|
} catch (error) {
|
|
152
|
-
if (!(error instanceof ExpectedQuadAssertionError))
|
|
153
|
-
throw error;
|
|
152
|
+
if (!(error instanceof ExpectedQuadAssertionError)) throw error;
|
|
154
153
|
|
|
155
154
|
return result(
|
|
156
155
|
false,
|
|
@@ -160,8 +159,7 @@ export function sparqlEquals(expected: string, actual: string): EqualityResult {
|
|
|
160
159
|
}
|
|
161
160
|
|
|
162
161
|
const unexpectedOperation = Object.keys(actualOperations)[0] ?? null;
|
|
163
|
-
if (unexpectedOperation)
|
|
164
|
-
return result(false, `Did not expect to find ${unexpectedOperation} triples.`);
|
|
162
|
+
if (unexpectedOperation) return result(false, `Did not expect to find ${unexpectedOperation} triples.`);
|
|
165
163
|
|
|
166
164
|
return result(true, 'sparql matches');
|
|
167
165
|
}
|
|
@@ -180,8 +178,7 @@ export function turtleEquals(expected: string, actual: string): EqualityResult {
|
|
|
180
178
|
try {
|
|
181
179
|
assertExpectedQuadsExist(expectedQuads, actualQuads);
|
|
182
180
|
} catch (error) {
|
|
183
|
-
if (!(error instanceof ExpectedQuadAssertionError))
|
|
184
|
-
throw error;
|
|
181
|
+
if (!(error instanceof ExpectedQuadAssertionError)) throw error;
|
|
185
182
|
|
|
186
183
|
return result(false, error.message);
|
|
187
184
|
}
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { sparqlEquals, turtleEquals } from './helpers';
|
|
4
|
+
|
|
5
|
+
describe('Testing helpers', () => {
|
|
6
|
+
|
|
7
|
+
it('Compares sparql', () => {
|
|
8
|
+
// Arrange
|
|
9
|
+
const expected = 'INSERT DATA { <#me> a <http://xmlns.com/foaf/0.1/Person> . }';
|
|
10
|
+
const actual = 'INSERT DATA { <#me> a <http://xmlns.com/foaf/0.1/Person> . }';
|
|
11
|
+
|
|
12
|
+
// Act
|
|
13
|
+
const result = sparqlEquals(expected, actual);
|
|
14
|
+
|
|
15
|
+
// Assert
|
|
16
|
+
expect(result.success).toBe(true);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('Compares sparql operations', () => {
|
|
20
|
+
// Arrange
|
|
21
|
+
const expected = `
|
|
22
|
+
INSERT DATA { <#me> <http://xmlns.com/foaf/0.1/name> "Amy Doe" . } ;
|
|
23
|
+
DELETE DATA { <#me> <http://xmlns.com/foaf/0.1/name> "John Doe" . }
|
|
24
|
+
`;
|
|
25
|
+
const actual = 'INSERT DATA { <#me> <http://xmlns.com/foaf/0.1/name> "Amy Doe" . }';
|
|
26
|
+
|
|
27
|
+
// Act
|
|
28
|
+
const result = sparqlEquals(expected, actual);
|
|
29
|
+
|
|
30
|
+
// Assert
|
|
31
|
+
expect(result.success).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('Compares sparql triples', () => {
|
|
35
|
+
// Arrange
|
|
36
|
+
const expected = 'INSERT DATA { <#me> a <http://xmlns.com/foaf/0.1/Person> . }';
|
|
37
|
+
const actual = 'INSERT DATA { <#me> <http://xmlns.com/foaf/0.1/name> "Amy Doe" . }';
|
|
38
|
+
|
|
39
|
+
// Act
|
|
40
|
+
const result = sparqlEquals(expected, actual);
|
|
41
|
+
|
|
42
|
+
// Assert
|
|
43
|
+
expect(result.success).toBe(false);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('Compares expanded ordered lists in Turtle', () => {
|
|
47
|
+
// Arrange
|
|
48
|
+
const expected = `
|
|
49
|
+
@prefix schema: <https://schema.org/> .
|
|
50
|
+
|
|
51
|
+
<#ramen>
|
|
52
|
+
a schema:Recipe ;
|
|
53
|
+
schema:name "Ramen" ;
|
|
54
|
+
schema:recipeIngredient ( "Broth" "Noodles" ) .
|
|
55
|
+
`;
|
|
56
|
+
const actual = `
|
|
57
|
+
@prefix schema: <https://schema.org/> .
|
|
58
|
+
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
|
59
|
+
|
|
60
|
+
<#ramen>
|
|
61
|
+
a schema:Recipe ;
|
|
62
|
+
schema:name "Ramen" ;
|
|
63
|
+
schema:recipeIngredient _:b0 .
|
|
64
|
+
|
|
65
|
+
_:b0
|
|
66
|
+
rdf:first "Broth" ;
|
|
67
|
+
rdf:rest _:b1 .
|
|
68
|
+
|
|
69
|
+
_:b1
|
|
70
|
+
rdf:first "Noodles" ;
|
|
71
|
+
rdf:rest rdf:nil .
|
|
72
|
+
`;
|
|
73
|
+
|
|
74
|
+
// Act
|
|
75
|
+
const result = turtleEquals(expected, actual);
|
|
76
|
+
|
|
77
|
+
// Assert
|
|
78
|
+
expect(result.success).toBe(true);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('Compares different ordered lists in Turtle', () => {
|
|
82
|
+
// Arrange
|
|
83
|
+
const expected = `
|
|
84
|
+
@prefix schema: <https://schema.org/> .
|
|
85
|
+
|
|
86
|
+
<#ramen>
|
|
87
|
+
a schema:Recipe ;
|
|
88
|
+
schema:name "Ramen" ;
|
|
89
|
+
schema:recipeIngredient ( "Broth" "Noodles" ) .
|
|
90
|
+
`;
|
|
91
|
+
const actual = `
|
|
92
|
+
@prefix schema: <https://schema.org/> .
|
|
93
|
+
|
|
94
|
+
<#ramen>
|
|
95
|
+
a schema:Recipe ;
|
|
96
|
+
schema:name "Ramen" ;
|
|
97
|
+
schema:recipeIngredient ( "Noodles" "Broth" ) .
|
|
98
|
+
`;
|
|
99
|
+
|
|
100
|
+
// Act
|
|
101
|
+
const result = turtleEquals(expected, actual);
|
|
102
|
+
|
|
103
|
+
// Assert
|
|
104
|
+
expect(result.success).toBe(false);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('Compares different unordered lists in Turtle', () => {
|
|
108
|
+
// Arrange
|
|
109
|
+
const expected = `
|
|
110
|
+
@prefix schema: <https://schema.org/> .
|
|
111
|
+
|
|
112
|
+
<#ramen>
|
|
113
|
+
a schema:Recipe ;
|
|
114
|
+
schema:name "Ramen" ;
|
|
115
|
+
schema:recipeIngredient "Broth", "Noodles" .
|
|
116
|
+
`;
|
|
117
|
+
const actual = `
|
|
118
|
+
@prefix schema: <https://schema.org/> .
|
|
119
|
+
|
|
120
|
+
<#ramen>
|
|
121
|
+
a schema:Recipe ;
|
|
122
|
+
schema:name "Ramen" ;
|
|
123
|
+
schema:recipeIngredient "Noodles", "Broth" .
|
|
124
|
+
`;
|
|
125
|
+
|
|
126
|
+
// Act
|
|
127
|
+
const result = turtleEquals(expected, actual);
|
|
128
|
+
|
|
129
|
+
// Assert
|
|
130
|
+
expect(result.success).toBe(true);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('Compares sparql using regex patterns', () => {
|
|
134
|
+
// Arrange
|
|
135
|
+
const expected = `
|
|
136
|
+
INSERT DATA {
|
|
137
|
+
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
|
|
138
|
+
@prefix foaf: <http://xmlns.com/foaf/> .
|
|
139
|
+
@prefix purl: <http://purl.org/dc/terms/> .
|
|
140
|
+
|
|
141
|
+
<#me>
|
|
142
|
+
foaf:name "[[.*]] Doe" ;
|
|
143
|
+
foaf:age 42 .
|
|
144
|
+
|
|
145
|
+
<#something-[[.*]]>
|
|
146
|
+
purl:created "[[.*]]"^^xsd:dateTime ;
|
|
147
|
+
purl:modified "2021-01-16T[[.*]]"^^xsd:dateTime ;
|
|
148
|
+
purl:available "2021-01-16T12:34:56Z"^^xsd:dateTime .
|
|
149
|
+
}
|
|
150
|
+
`;
|
|
151
|
+
const actual = `
|
|
152
|
+
INSERT DATA {
|
|
153
|
+
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
|
|
154
|
+
@prefix foaf: <http://xmlns.com/foaf/> .
|
|
155
|
+
@prefix purl: <http://purl.org/dc/terms/> .
|
|
156
|
+
|
|
157
|
+
<#me>
|
|
158
|
+
foaf:name "John Doe" ;
|
|
159
|
+
foaf:age 42 .
|
|
160
|
+
|
|
161
|
+
<#something-123456>
|
|
162
|
+
purl:created "2021-01-16T12:12:50.123Z"^^xsd:dateTime ;
|
|
163
|
+
purl:modified "2021-01-16T12:12:50.123Z"^^xsd:dateTime ;
|
|
164
|
+
purl:available "2021-01-16T12:34:56.000Z"^^xsd:dateTime .
|
|
165
|
+
}
|
|
166
|
+
`;
|
|
167
|
+
|
|
168
|
+
// Act
|
|
169
|
+
const result = sparqlEquals(expected, actual);
|
|
170
|
+
|
|
171
|
+
// Assert
|
|
172
|
+
expect(result.success).toBe(true);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('supports aliases in regex patterns', () => {
|
|
176
|
+
// Arrange
|
|
177
|
+
const expected = `
|
|
178
|
+
@prefix schema: <https://schema.org/> .
|
|
179
|
+
|
|
180
|
+
<#ramen>
|
|
181
|
+
a schema:Recipe ;
|
|
182
|
+
schema:name "Ramen" ;
|
|
183
|
+
schema:recipeInstructions <#[[step-1][.*]]>, <#[[step-2][.*]]> .
|
|
184
|
+
|
|
185
|
+
<#[[step-1][.*]]>
|
|
186
|
+
a schema:HowToStep ;
|
|
187
|
+
schema:text "Boil the noodles" .
|
|
188
|
+
|
|
189
|
+
<#[[step-2][.*]]>
|
|
190
|
+
a schema:HowToStep ;
|
|
191
|
+
schema:text "Dip them into the broth" .
|
|
192
|
+
`;
|
|
193
|
+
const actual = `
|
|
194
|
+
@prefix schema: <https://schema.org/> .
|
|
195
|
+
|
|
196
|
+
<#ramen>
|
|
197
|
+
a schema:Recipe ;
|
|
198
|
+
schema:name "Ramen" ;
|
|
199
|
+
schema:recipeInstructions <#ramen-step-1>, <#ramen-step-2> .
|
|
200
|
+
|
|
201
|
+
<#ramen-step-1>
|
|
202
|
+
a schema:HowToStep ;
|
|
203
|
+
schema:text "Boil the noodles" .
|
|
204
|
+
|
|
205
|
+
<#ramen-step-2>
|
|
206
|
+
a schema:HowToStep ;
|
|
207
|
+
schema:text "Dip them into the broth" .
|
|
208
|
+
`;
|
|
209
|
+
|
|
210
|
+
// Act
|
|
211
|
+
const result = turtleEquals(expected, actual);
|
|
212
|
+
|
|
213
|
+
// Assert
|
|
214
|
+
expect(result.success).toBe(true);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it('counts matching triples only once', () => {
|
|
218
|
+
// Arrange
|
|
219
|
+
const expected = `
|
|
220
|
+
@prefix schema: <https://schema.org/> .
|
|
221
|
+
|
|
222
|
+
<#ramen>
|
|
223
|
+
a schema:Recipe ;
|
|
224
|
+
schema:name "Ramen", "Ramen" .
|
|
225
|
+
`;
|
|
226
|
+
const actual = `
|
|
227
|
+
@prefix schema: <https://schema.org/> .
|
|
228
|
+
|
|
229
|
+
<#ramen>
|
|
230
|
+
a schema:Recipe ;
|
|
231
|
+
schema:name "Ramen" ;
|
|
232
|
+
schema:description "is life" .
|
|
233
|
+
`;
|
|
234
|
+
|
|
235
|
+
// Act
|
|
236
|
+
const result = turtleEquals(expected, actual);
|
|
237
|
+
|
|
238
|
+
// Assert
|
|
239
|
+
expect(result.success).toBe(false);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it('allows regex patterns to be mixed up', () => {
|
|
243
|
+
// Arrange
|
|
244
|
+
const expected = `
|
|
245
|
+
@prefix schema: <https://schema.org/> .
|
|
246
|
+
|
|
247
|
+
<#[[instruction-1][.*]]-operation-[[operation-1][.*]]> schema:object <#[[instruction-1][.*]]> .
|
|
248
|
+
<#[[instruction-1][.*]]-metadata> schema:object <#[[instruction-1][.*]]> .
|
|
249
|
+
`;
|
|
250
|
+
const actual = `
|
|
251
|
+
@prefix schema: <https://schema.org/> .
|
|
252
|
+
|
|
253
|
+
<#ramen-step-1-metadata> schema:object <#ramen> .
|
|
254
|
+
<#ramen-step-1-operation-1> schema:object <#ramen> .
|
|
255
|
+
`;
|
|
256
|
+
|
|
257
|
+
// Act
|
|
258
|
+
const result = turtleEquals(expected, actual);
|
|
259
|
+
|
|
260
|
+
// Assert
|
|
261
|
+
expect(result.success).toBe(true);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
it('matches built-in patterns', () => {
|
|
265
|
+
// Arrange
|
|
266
|
+
const expected = `
|
|
267
|
+
@prefix schema: <https://schema.org/> .
|
|
268
|
+
|
|
269
|
+
<#[[foobar][%uuid%]]> schema:description "Lorem ipsum" .
|
|
270
|
+
<#[[%uuid%]]> schema:description "Dolor sit amet" .
|
|
271
|
+
`;
|
|
272
|
+
const actual = `
|
|
273
|
+
@prefix schema: <https://schema.org/> .
|
|
274
|
+
|
|
275
|
+
<#20421db7-0c7d-419c-b27e-2c9b3cc026b3> schema:description "Lorem ipsum" .
|
|
276
|
+
<#d4b41533-dd5d-4a66-9d3f-316f80f135b2> schema:description "Dolor sit amet" .
|
|
277
|
+
`;
|
|
278
|
+
|
|
279
|
+
// Act
|
|
280
|
+
const result = turtleEquals(expected, actual);
|
|
281
|
+
|
|
282
|
+
// Assert
|
|
283
|
+
expect(result.success).toBe(true);
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
// TODO
|
|
287
|
+
it.skip('aliases match regex patterns', () => {
|
|
288
|
+
// Arrange
|
|
289
|
+
const expected = `
|
|
290
|
+
@prefix schema: <https://schema.org/> .
|
|
291
|
+
|
|
292
|
+
<#ramen>
|
|
293
|
+
a schema:Recipe ;
|
|
294
|
+
schema:name "Ramen" ;
|
|
295
|
+
schema:recipeInstructions <#[[step-1][.*]]>, <#[[step-2][.*]]> .
|
|
296
|
+
|
|
297
|
+
<#[[step-1][.*]]>
|
|
298
|
+
a schema:HowToStep ;
|
|
299
|
+
schema:text "Boil the noodles" .
|
|
300
|
+
|
|
301
|
+
<#[[step-2][.*]]>
|
|
302
|
+
a schema:HowToStep ;
|
|
303
|
+
schema:text "Dip them into the broth" .
|
|
304
|
+
`;
|
|
305
|
+
const actual = `
|
|
306
|
+
@prefix schema: <https://schema.org/> .
|
|
307
|
+
|
|
308
|
+
<#ramen>
|
|
309
|
+
a schema:Recipe ;
|
|
310
|
+
schema:name "Ramen" ;
|
|
311
|
+
schema:recipeInstructions <#ramen-step-1>, <#ramen-step-2> .
|
|
312
|
+
|
|
313
|
+
<#ramen-step-1>
|
|
314
|
+
a schema:HowToStep ;
|
|
315
|
+
schema:text "Boil the noodles" .
|
|
316
|
+
|
|
317
|
+
<#ramen-step-3>
|
|
318
|
+
a schema:HowToStep ;
|
|
319
|
+
schema:text "Dip them into the broth" .
|
|
320
|
+
`;
|
|
321
|
+
|
|
322
|
+
// Act
|
|
323
|
+
const result = turtleEquals(expected, actual);
|
|
324
|
+
|
|
325
|
+
// Assert
|
|
326
|
+
expect(result.success).toBe(false);
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
});
|