Skip to content

Commit 3953adb

Browse files
authored
Add schema diagram tests and fix 2 bugs (#935)
* Add schema diagram tests and fix 2 bugs * update documentation generation tests * apply formatting changes --------- Co-authored-by: Logende <Logende@users.noreply.github.com>
1 parent 9881c55 commit 3953adb

7 files changed

Lines changed: 133 additions & 11 deletions

File tree

meta_configurator/src/schema/graph-representation/__tests__/schemaGraphConstructorArrays.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import {
77
generateObjectFallbackDisplayName,
88
identifyAllObjects,
99
isSchemaThatDeservesANode,
10+
populateGraph,
11+
trimGraph,
1012
} from '../schemaGraphConstructor';
1113

1214
vi.mock('@/dataformats/formatRegistry', () => ({
@@ -253,6 +255,46 @@ describe('test schema graph constructor with objects and attributes, without adv
253255
).toEqual('person');
254256
});
255257

258+
it('array of array pointing to a referenced object should create an edge to that object', () => {
259+
const nestedArraySchema: TopLevelSchema = {
260+
type: 'object',
261+
$defs: {
262+
Row: {
263+
type: 'object',
264+
properties: {
265+
value: {type: 'number'},
266+
},
267+
},
268+
},
269+
properties: {
270+
matrix: {
271+
type: 'array',
272+
items: {
273+
type: 'array',
274+
items: {$ref: '#/$defs/Row'},
275+
},
276+
},
277+
},
278+
};
279+
280+
const nestedDefs = identifyAllObjects(nestedArraySchema);
281+
const nestedGraph = new SchemaGraph([], []);
282+
populateGraph(nestedDefs, nestedGraph);
283+
trimGraph(nestedGraph);
284+
285+
const rootNode = nestedGraph.nodes.find(n => n.absolutePath.length === 0);
286+
expect(rootNode).toBeDefined();
287+
288+
const rowNode = nestedGraph.nodes.find(n => n.name === 'Row');
289+
expect(rowNode).toBeDefined();
290+
291+
// There must be an edge from root to Row driven by the nested-array property
292+
const edgeToRow = nestedGraph.edges.find(e => e.start === rootNode && e.end === rowNode);
293+
expect(edgeToRow).toBeDefined();
294+
expect(edgeToRow?.isArray).toBe(true);
295+
expect(edgeToRow?.label).toBe('matrix');
296+
});
297+
256298
it('generate attribute edges', () => {
257299
for (const node of defs.values()) {
258300
node.attributes = generateObjectAttributes(node.absolutePath, node.schema, defs);

meta_configurator/src/schema/graph-representation/__tests__/schemaGraphConstructorSpecialCases.test.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,50 @@ describe('tests for more difficult scenarios and special cases that result as a
8080
expect(graph.edges.length).toBe(2); // one edge from the root node to the array entry node and one edge from the array entry node to the enum node
8181
});
8282

83+
it('$defs node with both $ref and properties should have edge from that node to the referenced schema', () => {
84+
const schema: TopLevelSchema = {
85+
type: 'object',
86+
$defs: {
87+
Quantity: {
88+
type: 'object',
89+
properties: {
90+
Value: {type: 'number'},
91+
Unit: {type: 'string'},
92+
},
93+
},
94+
Time: {
95+
title: 'Time',
96+
$ref: '#/$defs/Quantity',
97+
properties: {
98+
Value: {minimum: 0, type: 'number'},
99+
Unit: {type: 'string'},
100+
},
101+
required: ['Unit', 'Value'],
102+
},
103+
},
104+
properties: {
105+
duration: {$ref: '#/$defs/Time'},
106+
},
107+
};
108+
109+
const defs = identifyAllObjects(schema);
110+
const graph = new SchemaGraph([], []);
111+
populateGraph(defs, graph);
112+
trimGraph(graph);
113+
114+
const timeNode = graph.nodes.find(n => n.name === 'Time');
115+
expect(timeNode).toBeDefined();
116+
117+
const quantityNode = graph.nodes.find(n => n.name === 'Quantity');
118+
expect(quantityNode).toBeDefined();
119+
120+
// Time node must have an edge pointing to Quantity (via its $ref)
121+
const edgeTimeToQuantity = graph.edges.find(
122+
e => e.start === timeNode && e.end === quantityNode
123+
);
124+
expect(edgeTimeToQuantity).toBeDefined();
125+
});
126+
83127
it('object property has a reference but also defines its own things and both nodes (referenced sub-schema and own definition of sub-schema) should be connected with an edge', () => {
84128
let schema: TopLevelSchema = {
85129
$defs: {

meta_configurator/src/schema/graph-representation/schemaGraphConstructor.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,17 @@ function resolveArrayItemNode(
576576
if (referenceObject) {
577577
itemObjectPath = referenceObject.absolutePath;
578578
}
579-
return objectDefs.get(pathToString(itemObjectPath));
579+
const itemNode = objectDefs.get(pathToString(itemObjectPath));
580+
// If the resolved item is itself an array (nested arrays), recurse until we reach
581+
// a non-array type so that e.g. array-of-array-of-Ref still produces an edge.
582+
if (
583+
itemNode &&
584+
!isSchemaThatDeservesANode(itemNode.schema) &&
585+
itemNode.schema.type === 'array'
586+
) {
587+
return resolveArrayItemNode(itemNode.absolutePath, itemNode.schema, objectDefs);
588+
}
589+
return itemNode;
580590
}
581591
}
582592
return undefined;
@@ -680,7 +690,7 @@ export function generateObjectSpecialPropertyEdges(
680690
);
681691
}
682692
if (schema.$ref) {
683-
if (isExternalRef(schema.$ref) && isExternalRef(schema.$ref)) {
693+
if (isExternalRef(schema.$ref)) {
684694
generateObjectSubSchemaEdge(
685695
node,
686696
{$ref: schema.$ref},
@@ -689,6 +699,18 @@ export function generateObjectSpecialPropertyEdges(
689699
objectDefs,
690700
graph
691701
);
702+
} else {
703+
// Internal $ref on a node that also has other keywords (e.g. properties).
704+
// In JSON Schema 2019-09+ this is equivalent to allOf:[{$ref}] combined with the
705+
// sibling keywords, so we model it as an ALL_OF edge to the referenced schema.
706+
generateObjectSubSchemaEdge(
707+
node,
708+
{$ref: schema.$ref},
709+
[...node.absolutePath, '$ref'],
710+
EdgeType.ALL_OF,
711+
objectDefs,
712+
graph
713+
);
692714
}
693715
}
694716
}

meta_configurator/src/utility/documentation/__tests__/samples/arrays.expected.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@
66
- [nestedArraysAndObjectsProperty entry](#%2Fproperties%2FnestedArraysAndObjectsProperty%2Fitems)
77

88
---
9-
### [My Schema](#root)
9+
### <a id="root"></a>[My Schema](#root)
1010
#### Properties
1111

1212
| Name | Type | Required | Description |
1313
|------|------|------|------|
14-
| numberArrayProperty | number\[\] | false | \- |
15-
| objectArrayProperty | [objectArrayProperty entry\[\]](#%2Fproperties%2FobjectArrayProperty%2Fitems) | false | \- |
16-
| nestedArraysProperty | nestedArraysProperty entry\[\] | false | \- |
17-
| nestedArraysAndObjectsProperty | [nestedArraysAndObjectsProperty entry\[\]](#%2Fproperties%2FnestedArraysAndObjectsProperty%2Fitems) | false | \- |
14+
| <a id="%2Fproperties%2FnumberArrayProperty%2Fitems"></a>numberArrayProperty | number\[\] | <span style="color:salmon">false</span> | \- |
15+
| objectArrayProperty | <u>[objectArrayProperty entry\[\]](#%2Fproperties%2FobjectArrayProperty%2Fitems)</u> | <span style="color:salmon">false</span> | \- |
16+
| <a id="%2Fproperties%2FnestedArraysProperty%2Fitems%2Fitems%2Fitems"></a>nestedArraysProperty | string\[\] | <span style="color:salmon">false</span> | \- |
17+
| nestedArraysAndObjectsProperty | <u>[nestedArraysAndObjectsProperty entry\[\]](#%2Fproperties%2FnestedArraysAndObjectsProperty%2Fitems)</u> | <span style="color:salmon">false</span> | \- |
1818

1919
#### Example
2020

@@ -45,12 +45,12 @@
4545
}
4646
```
4747
---
48-
### [objectArrayProperty entry](#%2Fproperties%2FobjectArrayProperty%2Fitems)
48+
### <a id="%2Fproperties%2FobjectArrayProperty%2Fitems"></a>[objectArrayProperty entry](#%2Fproperties%2FobjectArrayProperty%2Fitems)
4949
#### Properties
5050

5151
| Name | Type | Required | Description |
5252
|------|------|------|------|
53-
| booleanProperty | boolean | false | \- |
53+
| <a id="%2Fproperties%2FobjectArrayProperty%2Fitems%2Fproperties%2FbooleanProperty"></a>booleanProperty | boolean | <span style="color:salmon">false</span> | \- |
5454

5555
#### Example
5656

@@ -60,12 +60,12 @@
6060
}
6161
```
6262
---
63-
### [nestedArraysAndObjectsProperty entry](#%2Fproperties%2FnestedArraysAndObjectsProperty%2Fitems)
63+
### <a id="%2Fproperties%2FnestedArraysAndObjectsProperty%2Fitems"></a>[nestedArraysAndObjectsProperty entry](#%2Fproperties%2FnestedArraysAndObjectsProperty%2Fitems)
6464
#### Properties
6565

6666
| Name | Type | Required | Description |
6767
|------|------|------|------|
68-
| arrayProp | string\[\] | false | \- |
68+
| <a id="%2Fproperties%2FnestedArraysAndObjectsProperty%2Fitems%2Fproperties%2FarrayProp%2Fitems"></a>arrayProp | string\[\] | <span style="color:salmon">false</span> | \- |
6969

7070
#### Example
7171

meta_configurator/src/utility/documentation/__tests__/samples/references.expected.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,18 @@
55
- [person](#%2F%24defs%2Fperson)
66
- [person](#%2F%24defs%2Fperson)
77
- [person1](#%2F%24defs%2Fperson)
8+
- [person](#%2F%24defs%2Fperson)
9+
- [person](#%2F%24defs%2Fperson)
810
- [person](#%2F%24defs%2Fperson)
911
- [person](#%2F%24defs%2Fperson)
1012
- [person2](#%2F%24defs%2Fperson)
13+
- [person](#%2F%24defs%2Fperson)
14+
- [person](#%2F%24defs%2Fperson)
1115
- [person](#%2F%24defs%2Fperson)
1216
- [person](#%2F%24defs%2Fperson)
1317
- [person3](#%2F%24defs%2Fperson)
18+
- [person](#%2F%24defs%2Fperson)
19+
- [person](#%2F%24defs%2Fperson)
1420
- [person](#%2F%24defs%2Fperson)
1521
- [person](#%2F%24defs%2Fperson)
1622
- [person](#%2F%24defs%2Fperson)

meta_configurator/src/utility/documentation/__tests__/samples/titles.expected.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,13 @@
66
- [PersonObject](#%2F%24defs%2Fperson)
77
- [PersonObject](#%2F%24defs%2Fperson)
88
- [person1](#%2F%24defs%2Fperson)
9+
- [PersonObject](#%2F%24defs%2Fperson)
10+
- [PersonObject](#%2F%24defs%2Fperson)
911
- [PersonObject](#%2F%24defs%2Fperson)
1012
- [PersonObject](#%2F%24defs%2Fperson)
1113
- [person2](#%2F%24defs%2Fperson)
14+
- [PersonObject](#%2F%24defs%2Fperson)
15+
- [PersonObject](#%2F%24defs%2Fperson)
1216
- [PersonObject](#%2F%24defs%2Fperson)
1317
- [PersonObject](#%2F%24defs%2Fperson)
1418
- [PersonObject](#%2F%24defs%2Fperson)

meta_configurator/src/utility/documentation/__tests__/schemaToMarkdown.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ describe('schemaToMarkdown samples coverage', async () => {
7474
);
7575
const expected = cleanMarkdownContent(expectedMd.trimEnd()); // ignore trailing newline diffs
7676

77+
// print source schema path for easier debugging
78+
if (actualMd !== expected) {
79+
console.error(`Schema path: ${c.schemaPath}`);
80+
}
7781
expect(actualMd).toBe(expected);
7882
});
7983
}

0 commit comments

Comments
 (0)