@noeldemartin/solid-utils 0.0.0-next.f9716490938d6dbabb0920bc834315c53ccd2505 → 0.1.1-next.1f0cf6ccc237588ae655211348e94eba9ba16c8d
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/.nvmrc +1 -0
- package/.semaphore/semaphore.yml +1 -1
- package/dist/noeldemartin-solid-utils.cjs.js +1 -1
- package/dist/noeldemartin-solid-utils.cjs.js.map +1 -1
- package/dist/noeldemartin-solid-utils.d.ts +19 -0
- package/dist/noeldemartin-solid-utils.esm.js +1 -1
- package/dist/noeldemartin-solid-utils.esm.js.map +1 -1
- package/noeldemartin.config.js +4 -2
- package/package.json +10 -8
- package/src/helpers/identifiers.ts +56 -0
- package/src/helpers/index.ts +1 -0
- package/src/helpers/interop.ts +4 -2
- package/src/helpers/io.ts +25 -1
- package/src/helpers/jsonld.ts +4 -0
- package/src/helpers/testing.ts +92 -16
- package/src/plugins/chai/assertions.ts +11 -2
- package/src/plugins/cypress/types.d.ts +1 -0
- package/src/plugins/jest/matchers.ts +47 -32
- package/src/plugins/jest/types.d.ts +1 -0
package/src/helpers/testing.ts
CHANGED
|
@@ -1,25 +1,54 @@
|
|
|
1
|
-
import { pull } from '@noeldemartin/utils';
|
|
1
|
+
import { Error, arrayRemove, pull } from '@noeldemartin/utils';
|
|
2
|
+
import type { JsonLD } from '@/helpers/jsonld';
|
|
2
3
|
import type { Quad, Quad_Object } from 'rdf-js';
|
|
3
4
|
|
|
4
|
-
import { quadToTurtle, sparqlToQuadsSync, turtleToQuadsSync } from './io';
|
|
5
|
+
import { jsonldToQuads, quadToTurtle, quadsToTurtle, sparqlToQuadsSync, turtleToQuadsSync } from './io';
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
let patternsRegExpsIndex: Record<string, RegExp> = {};
|
|
8
|
+
const builtInPatterns: Record<string, string> = {
|
|
9
|
+
'%uuid%': '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}',
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
class ExpectedQuadAssertionError extends Error {
|
|
13
|
+
|
|
14
|
+
constructor(public readonly expectedQuad: Quad) {
|
|
15
|
+
super(`Couldn't find the following triple: ${quadToTurtle(expectedQuad)}`);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function assertExpectedQuadsExist(expectedQuads: Quad[], actualQuads: Quad[]): void {
|
|
21
|
+
for (const expectedQuad of expectedQuads) {
|
|
22
|
+
const matchingQuad = actualQuads.find(actualQuad => quadEquals(expectedQuad, actualQuad));
|
|
23
|
+
|
|
24
|
+
if (!matchingQuad)
|
|
25
|
+
throw new ExpectedQuadAssertionError(expectedQuad);
|
|
26
|
+
|
|
27
|
+
arrayRemove(actualQuads, matchingQuad);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
7
30
|
|
|
8
31
|
function containsPatterns(value: string): boolean {
|
|
9
|
-
return /\[\[([^\]]+)\]\]/.test(value);
|
|
32
|
+
return /\[\[(.*\]\[)?([^\]]+)\]\]/.test(value);
|
|
10
33
|
}
|
|
11
34
|
|
|
12
35
|
function quadValueEquals(expected: string, actual: string): boolean {
|
|
13
36
|
if (!containsPatterns(expected))
|
|
14
37
|
return expected === actual;
|
|
15
38
|
|
|
16
|
-
|
|
17
|
-
|
|
39
|
+
const patternAliases = [];
|
|
40
|
+
|
|
41
|
+
if (!(expected in patternsRegExpsIndex)) {
|
|
42
|
+
const patternMatches = expected.matchAll(/\[\[((.*?)\]\[)?([^\]]+)\]\]/g);
|
|
18
43
|
const patterns: string[] = [];
|
|
19
44
|
let expectedRegExp = expected;
|
|
20
45
|
|
|
21
46
|
for (const patternMatch of patternMatches) {
|
|
22
|
-
|
|
47
|
+
if (patternMatch[2]) {
|
|
48
|
+
patternAliases.push(patternMatch[2]);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
patterns.push(patternMatch[3]);
|
|
23
52
|
|
|
24
53
|
expectedRegExp = expectedRegExp.replace(patternMatch[0], `%PATTERN${patterns.length - 1}%`);
|
|
25
54
|
}
|
|
@@ -27,13 +56,13 @@ function quadValueEquals(expected: string, actual: string): boolean {
|
|
|
27
56
|
expectedRegExp = expectedRegExp.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
|
|
28
57
|
|
|
29
58
|
for (const [patternIndex, pattern] of Object.entries(patterns)) {
|
|
30
|
-
expectedRegExp = expectedRegExp.replace(`%PATTERN${patternIndex}%`, pattern);
|
|
59
|
+
expectedRegExp = expectedRegExp.replace(`%PATTERN${patternIndex}%`, builtInPatterns[pattern] ?? pattern);
|
|
31
60
|
}
|
|
32
61
|
|
|
33
|
-
|
|
62
|
+
patternsRegExpsIndex[expected] = new RegExp(expectedRegExp);
|
|
34
63
|
}
|
|
35
64
|
|
|
36
|
-
return
|
|
65
|
+
return patternsRegExpsIndex[expected].test(actual);
|
|
37
66
|
}
|
|
38
67
|
|
|
39
68
|
function quadObjectEquals(expected: Quad_Object, actual: Quad_Object): boolean {
|
|
@@ -59,6 +88,10 @@ function quadEquals(expected: Quad, actual: Quad): boolean {
|
|
|
59
88
|
&& quadValueEquals(expected.predicate.value, actual.predicate.value);
|
|
60
89
|
}
|
|
61
90
|
|
|
91
|
+
function resetPatterns(): void {
|
|
92
|
+
patternsRegExpsIndex = {};
|
|
93
|
+
}
|
|
94
|
+
|
|
62
95
|
export interface EqualityResult {
|
|
63
96
|
success: boolean;
|
|
64
97
|
message: string;
|
|
@@ -66,8 +99,39 @@ export interface EqualityResult {
|
|
|
66
99
|
actual: string;
|
|
67
100
|
}
|
|
68
101
|
|
|
102
|
+
export async function jsonldEquals(expected: JsonLD, actual: JsonLD): Promise<EqualityResult> {
|
|
103
|
+
// TODO catch parsing errors and improve message.
|
|
104
|
+
resetPatterns();
|
|
105
|
+
|
|
106
|
+
const expectedQuads = await jsonldToQuads(expected);
|
|
107
|
+
const actualQuads = await jsonldToQuads(actual);
|
|
108
|
+
const expectedTurtle = quadsToTurtle(expectedQuads);
|
|
109
|
+
const actualTurtle = quadsToTurtle(actualQuads);
|
|
110
|
+
const result = (success: boolean, message: string) => ({
|
|
111
|
+
success,
|
|
112
|
+
message,
|
|
113
|
+
expected: expectedTurtle,
|
|
114
|
+
actual: actualTurtle,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
if (expectedQuads.length !== actualQuads.length)
|
|
118
|
+
return result(false, `Expected ${expectedQuads.length} triples, found ${actualQuads.length}.`);
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
assertExpectedQuadsExist(expectedQuads, actualQuads);
|
|
122
|
+
} catch (error) {
|
|
123
|
+
if (!(error instanceof ExpectedQuadAssertionError))
|
|
124
|
+
throw error;
|
|
125
|
+
|
|
126
|
+
return result(false, error.message);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return result(true, 'jsonld matches');
|
|
130
|
+
}
|
|
131
|
+
|
|
69
132
|
export function sparqlEquals(expected: string, actual: string): EqualityResult {
|
|
70
133
|
// TODO catch parsing errors and improve message.
|
|
134
|
+
resetPatterns();
|
|
71
135
|
|
|
72
136
|
const expectedOperations = sparqlToQuadsSync(expected, { normalizeBlankNodes: true });
|
|
73
137
|
const actualOperations = sparqlToQuadsSync(actual, { normalizeBlankNodes: true });
|
|
@@ -83,9 +147,16 @@ export function sparqlEquals(expected: string, actual: string): EqualityResult {
|
|
|
83
147
|
if (expectedQuads.length !== actualQuads.length)
|
|
84
148
|
return result(false, `Expected ${expectedQuads.length} ${operation} triples, found ${actualQuads.length}.`);
|
|
85
149
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
150
|
+
try {
|
|
151
|
+
assertExpectedQuadsExist(expectedQuads, actualQuads);
|
|
152
|
+
} catch (error) {
|
|
153
|
+
if (!(error instanceof ExpectedQuadAssertionError))
|
|
154
|
+
throw error;
|
|
155
|
+
|
|
156
|
+
return result(
|
|
157
|
+
false,
|
|
158
|
+
`Couldn't find the following ${operation} triple: ${quadToTurtle(error.expectedQuad)}`,
|
|
159
|
+
);
|
|
89
160
|
}
|
|
90
161
|
}
|
|
91
162
|
|
|
@@ -98,6 +169,7 @@ export function sparqlEquals(expected: string, actual: string): EqualityResult {
|
|
|
98
169
|
|
|
99
170
|
export function turtleEquals(expected: string, actual: string): EqualityResult {
|
|
100
171
|
// TODO catch parsing errors and improve message.
|
|
172
|
+
resetPatterns();
|
|
101
173
|
|
|
102
174
|
const expectedQuads = turtleToQuadsSync(expected, { normalizeBlankNodes: true });
|
|
103
175
|
const actualQuads = turtleToQuadsSync(actual, { normalizeBlankNodes: true });
|
|
@@ -106,9 +178,13 @@ export function turtleEquals(expected: string, actual: string): EqualityResult {
|
|
|
106
178
|
if (expectedQuads.length !== actualQuads.length)
|
|
107
179
|
return result(false, `Expected ${expectedQuads.length} triples, found ${actualQuads.length}.`);
|
|
108
180
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
181
|
+
try {
|
|
182
|
+
assertExpectedQuadsExist(expectedQuads, actualQuads);
|
|
183
|
+
} catch (error) {
|
|
184
|
+
if (!(error instanceof ExpectedQuadAssertionError))
|
|
185
|
+
throw error;
|
|
186
|
+
|
|
187
|
+
return result(false, error.message);
|
|
112
188
|
}
|
|
113
189
|
|
|
114
190
|
return result(true, 'turtle matches');
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { sparqlEquals } from '@/helpers/testing';
|
|
1
|
+
import { sparqlEquals, turtleEquals } from '@/helpers/testing';
|
|
2
2
|
|
|
3
3
|
type CustomAssertions = {
|
|
4
4
|
[assertion in keyof typeof assertions]: typeof assertions[assertion];
|
|
@@ -17,6 +17,15 @@ declare global {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
const assertions: Record<string, (this: Chai.AssertionStatic, ...args: any[]) => void> = {
|
|
20
|
+
turtle(graph: string): void {
|
|
21
|
+
const self = this as unknown as Chai.AssertionStatic;
|
|
22
|
+
const actual = self._obj;
|
|
23
|
+
const assert = self.assert.bind(this);
|
|
24
|
+
const expected = graph;
|
|
25
|
+
const result = turtleEquals(expected, actual);
|
|
26
|
+
|
|
27
|
+
assert(result.success, result.message, '', result.expected, result.actual);
|
|
28
|
+
},
|
|
20
29
|
sparql(query: string): void {
|
|
21
30
|
const self = this as unknown as Chai.AssertionStatic;
|
|
22
31
|
const actual = self._obj;
|
|
@@ -24,7 +33,7 @@ const assertions: Record<string, (this: Chai.AssertionStatic, ...args: any[]) =>
|
|
|
24
33
|
const expected = query;
|
|
25
34
|
const result = sparqlEquals(expected, actual);
|
|
26
35
|
|
|
27
|
-
assert(result.success, result.message, expected, actual);
|
|
36
|
+
assert(result.success, result.message, '', result.expected, result.actual);
|
|
28
37
|
},
|
|
29
38
|
};
|
|
30
39
|
|
|
@@ -1,41 +1,56 @@
|
|
|
1
|
-
import diff from 'jest-diff';
|
|
2
|
-
|
|
3
1
|
import { normalizeSparql } from '@/helpers/io';
|
|
4
|
-
import { sparqlEquals } from '@/helpers/testing';
|
|
2
|
+
import { jsonldEquals, sparqlEquals } from '@/helpers/testing';
|
|
3
|
+
import type { EqualityResult } from '@/helpers/testing';
|
|
4
|
+
|
|
5
|
+
interface FormatResultOptions {
|
|
6
|
+
context: jest.MatcherContext;
|
|
7
|
+
hint: string;
|
|
8
|
+
expected: unknown;
|
|
9
|
+
received: unknown;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function formatResult(result: EqualityResult, options: FormatResultOptions) {
|
|
13
|
+
const pass = result.success;
|
|
14
|
+
const utils = options.context.utils;
|
|
15
|
+
const message = pass
|
|
16
|
+
? () => [
|
|
17
|
+
result.message,
|
|
18
|
+
utils.matcherHint(options.hint),
|
|
19
|
+
[
|
|
20
|
+
`Expected: not ${utils.printExpected(options.expected)}`,
|
|
21
|
+
`Received: ${utils.printReceived(options.received)}`,
|
|
22
|
+
].join('\n'),
|
|
23
|
+
].join('\n\n')
|
|
24
|
+
: () => {
|
|
25
|
+
return [
|
|
26
|
+
result.message,
|
|
27
|
+
utils.matcherHint(options.hint),
|
|
28
|
+
].join('\n\n');
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
return { pass, message };
|
|
32
|
+
}
|
|
5
33
|
|
|
6
34
|
const matchers: jest.ExpectExtendMap = {
|
|
35
|
+
async toEqualJsonLD(received, expected) {
|
|
36
|
+
const result = await jsonldEquals(expected, received);
|
|
37
|
+
|
|
38
|
+
return formatResult(result, {
|
|
39
|
+
context: this,
|
|
40
|
+
hint: 'toEqualJsonLD',
|
|
41
|
+
expected,
|
|
42
|
+
received,
|
|
43
|
+
});
|
|
44
|
+
},
|
|
7
45
|
toEqualSparql(received, expected) {
|
|
8
46
|
const result = sparqlEquals(expected, received);
|
|
9
|
-
const pass = result.success;
|
|
10
|
-
const normalizedReceived = normalizeSparql(received);
|
|
11
|
-
const normalizedExpected = normalizeSparql(expected);
|
|
12
|
-
const message = pass
|
|
13
|
-
? () => [
|
|
14
|
-
result.message,
|
|
15
|
-
this.utils.matcherHint('toEqualSparql'),
|
|
16
|
-
[
|
|
17
|
-
`Expected: not ${this.utils.printExpected(normalizedExpected)}`,
|
|
18
|
-
`Received: ${this.utils.printReceived(normalizedReceived)}`,
|
|
19
|
-
].join('\n'),
|
|
20
|
-
].join('\n\n')
|
|
21
|
-
: () => {
|
|
22
|
-
const diffString = diff(normalizedExpected, normalizedReceived, {
|
|
23
|
-
expand: this.expand,
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
return [
|
|
27
|
-
result.message,
|
|
28
|
-
this.utils.matcherHint('toEqualJsonLD'),
|
|
29
|
-
diffString && diffString.includes('- Expect')
|
|
30
|
-
? `Difference:\n\n${diffString}`
|
|
31
|
-
: [
|
|
32
|
-
`Expected: ${this.utils.printExpected(normalizedExpected)}`,
|
|
33
|
-
`Received: ${this.utils.printReceived(normalizedReceived)}`,
|
|
34
|
-
].join('\n'),
|
|
35
|
-
].join('\n\n');
|
|
36
|
-
};
|
|
37
47
|
|
|
38
|
-
return
|
|
48
|
+
return formatResult(result, {
|
|
49
|
+
context: this,
|
|
50
|
+
hint: 'toEqualSparql',
|
|
51
|
+
expected: normalizeSparql(expected),
|
|
52
|
+
received: normalizeSparql(received),
|
|
53
|
+
});
|
|
39
54
|
},
|
|
40
55
|
};
|
|
41
56
|
|