-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathexamples.test.ts
More file actions
114 lines (90 loc) · 3.15 KB
/
examples.test.ts
File metadata and controls
114 lines (90 loc) · 3.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import { expect, describe, it } from "vitest";
import { schemaExtensions } from "../../test/extensions.js";
import { schemas } from "./index.js";
import type { JSONSchema } from "../describe.js";
// loads schemas into global hyperjump json schema validator
import "../../test/hyperjump.js";
const idsOfSchemasAllowedToOmitExamples = new Set([
"schema:ethdebug/format/type",
"schema:ethdebug/format/type/complex",
"schema:ethdebug/format/type/elementary",
"schema:ethdebug/format/pointer/region",
"schema:ethdebug/format/pointer/collection",
]);
describe("Examples", () => {
for (const [id, schema] of Object.entries(schemas)) {
testSchema({ id, schema });
}
});
function testSchema(options: { id: string; schema: JSONSchema }): void {
const { id, schema } = options;
const { title } = schema;
const exampledDefinitionNames = definitionsWithExamples(schema);
const hasOwnExamples = schema.examples && schema.examples.length > 0;
const hasDefinitionsWithExamples = exampledDefinitionNames.length > 0;
const hasExamples = hasOwnExamples || hasDefinitionsWithExamples;
const allowedToOmitExamples = idsOfSchemasAllowedToOmitExamples.has(id);
describe(title || id, () => {
(allowedToOmitExamples ? it.skip : it)("has examples", () => {
expect(hasExamples).toBe(true);
});
if (!hasExamples) {
return;
}
testExamples({ id, schema });
if (hasDefinitionsWithExamples) {
describe("$defs", () => {
for (const name of exampledDefinitionNames) {
testSchema({
id: `${id}#/$defs/${name}`,
schema: schema!.$defs![name] as JSONSchema,
});
}
});
}
});
}
function testExamples(options: { id: string; schema: JSONSchema }): void {
const { id, schema } = options;
const { examples = [] } = schema;
for (const [index, example] of examples.entries()) {
describe(`example #${index}`, () => {
it(`is a valid ${schema.title || id}`, async () => {
await expect(example).toValidate({ schema: { id } });
});
const testedParentSchemas = new Set<string>();
// function to test parent schemas recursively
const testParentSchemas = (schemaId: string) => {
testedParentSchemas.add(schemaId);
const parentSchemaIds =
schemaExtensions[schemaId]?.extends || new Set<string>();
for (const parentSchemaId of parentSchemaIds) {
if (testedParentSchemas.has(parentSchemaId)) {
continue;
}
it(`is also a valid ${parentSchemaId}`, async () => {
await expect(example).toValidate({
schema: { id: parentSchemaId },
});
});
// recurse to ancestors
testParentSchemas(parentSchemaId);
}
};
testParentSchemas(id);
});
}
}
function definitionsWithExamples(schema: JSONSchema): string[] {
if (!("$defs" in schema) || !schema.$defs) {
return [];
}
return Object.entries(schema.$defs).flatMap(([name, definition]) =>
typeof definition !== "boolean" &&
"examples" in definition &&
definition.examples &&
definition.examples.length > 0
? [name]
: [],
);
}