1
+ import type Ajv from "../dist/core"
1
2
import _Ajv from "./ajv"
2
3
import _Ajv2019 from "./ajv2019"
3
4
import _Ajv2020 from "./ajv2020"
@@ -24,69 +25,211 @@ const remoteRefs = {
24
25
25
26
const SKIP_FORMATS = [ "idn-email" , "idn-hostname" , "iri" , "iri-reference" ]
26
27
const SKIP_FORMAT_TESTS = SKIP_FORMATS . map ( ( f ) => `optional/format/${ f } ` )
27
- const SKIP_DRAFT7 = [ "optional/content" , "optional/float-overflow" , ...SKIP_FORMAT_TESTS ]
28
+ const SKIP_DRAFT7 = [
29
+ "optional/content" ,
30
+ "optional/float-overflow" ,
31
+ "unknownKeyword" ,
32
+ ...SKIP_FORMAT_TESTS ,
33
+ ]
28
34
29
- const SKIP = {
30
- 6 : [ "optional/float-overflow" ] ,
31
- 7 : SKIP_DRAFT7 ,
32
- 2019 : SKIP_DRAFT7 , // TODO: 2 of 32 tests in recursiveRef fail
33
- 2020 : SKIP_DRAFT7 , // TODO: 2 of 32 tests in dynamicRef fail
34
- }
35
-
36
- runTest (
37
- getAjvInstances ( _Ajv , options , {
35
+ runTest ( {
36
+ instances : getAjvInstances ( _Ajv , options , {
38
37
meta : false ,
39
38
strict : false ,
40
39
ignoreKeywordsWithRef : true ,
41
40
} ) ,
42
- 6 ,
43
- require ( "./_json/draft6" )
44
- )
41
+ draft : 6 ,
42
+ tests : skipTestCases ( require ( "./_json/draft6" ) , {
43
+ ref : {
44
+ "$ref prevents a sibling $id from changing the base uri" : [
45
+ "$ref resolves to /definitions/base_foo, data does not validate" ,
46
+ "$ref resolves to /definitions/base_foo, data validates" ,
47
+ ] ,
48
+ } ,
49
+ } ) ,
50
+ remotes : {
51
+ "http://localhost:1234/ref-and-definitions.json" : require ( "./JSON-Schema-Test-Suite/remotes/ref-and-definitions.json" ) ,
52
+ } ,
53
+ skip : [ "optional/float-overflow" , "unknownKeyword" ] ,
54
+ } )
45
55
46
- runTest (
47
- getAjvInstances ( _Ajv , options , {
56
+ runTest ( {
57
+ instances : getAjvInstances ( _Ajv , options , {
48
58
strict : false ,
49
59
ignoreKeywordsWithRef : true ,
50
60
formats : toHash ( SKIP_FORMATS ) ,
51
61
} ) ,
52
- 7 ,
53
- require ( "./_json/draft7" )
54
- )
62
+ draft : 7 ,
63
+ tests : skipTestCases ( require ( "./_json/draft7" ) , {
64
+ ref : {
65
+ "$ref prevents a sibling $id from changing the base uri" : [
66
+ "$ref resolves to /definitions/base_foo, data does not validate" ,
67
+ "$ref resolves to /definitions/base_foo, data validates" ,
68
+ ] ,
69
+ } ,
70
+ } ) ,
71
+ remotes : {
72
+ "http://localhost:1234/ref-and-definitions.json" : require ( "./JSON-Schema-Test-Suite/remotes/ref-and-definitions.json" ) ,
73
+ } ,
74
+ skip : SKIP_DRAFT7 ,
75
+ } )
55
76
56
- runTest (
57
- getAjvInstances ( _Ajv2019 , options , {
77
+ runTest ( {
78
+ instances : getAjvInstances ( _Ajv2019 , options , {
58
79
strict : false ,
59
80
formats : toHash ( SKIP_FORMATS ) ,
60
81
} ) ,
61
- 2019 ,
62
- require ( "./_json/draft2019" )
63
- )
82
+ draft : 2019 ,
83
+ tests : skipTestCases ( require ( "./_json/draft2019" ) , {
84
+ recursiveRef : {
85
+ "$recursiveRef with no $recursiveAnchor in the initial target schema resource" : [
86
+ "leaf node matches: recursion uses the inner schema" ,
87
+ "leaf node does not match: recursion uses the inner schema" ,
88
+ ] ,
89
+ } ,
90
+ ref : {
91
+ "refs with relative uris and defs" : [
92
+ "invalid on inner field" ,
93
+ "invalid on outer field" ,
94
+ "valid on both fields" ,
95
+ ] ,
96
+ "relative refs with absolute uris and defs" : [
97
+ "invalid on inner field" ,
98
+ "invalid on outer field" ,
99
+ "valid on both fields" ,
100
+ ] ,
101
+ } ,
102
+ unevaluatedProperties : {
103
+ "unevaluatedProperties with if/then/else, then not defined" : [
104
+ "when if is false and has unevaluated properties" ,
105
+ ] ,
106
+ } ,
107
+ } ) ,
108
+ remotes : {
109
+ "http://localhost:1234/ref-and-defs.json" : require ( "./JSON-Schema-Test-Suite/remotes/ref-and-defs.json" ) ,
110
+ "http://localhost:1234/draft2019-09/metaschema-no-validation.json" : require ( "./JSON-Schema-Test-Suite/remotes/draft2019-09/metaschema-no-validation.json" ) ,
111
+ } ,
112
+ skip : SKIP_DRAFT7 ,
113
+ } )
64
114
65
- runTest (
66
- getAjvInstances ( _Ajv2020 , options , {
115
+ runTest ( {
116
+ instances : getAjvInstances ( _Ajv2020 , options , {
67
117
strict : false ,
68
118
formats : toHash ( SKIP_FORMATS ) ,
69
119
} ) ,
70
- 2020 ,
71
- require ( "./_json/draft2020" )
72
- )
120
+ draft : 2020 ,
121
+ tests : skipTestCases ( require ( "./_json/draft2020" ) , {
122
+ dynamicRef : {
123
+ "A $dynamicRef to a $dynamicAnchor in the same schema resource should behave like a normal $ref to an $anchor" :
124
+ [ "An array of strings is valid" ] ,
125
+ "A $dynamicRef to an $anchor in the same schema resource should behave like a normal $ref to an $anchor" :
126
+ [ "An array of strings is valid" ] ,
127
+ "A $dynamicRef should resolve to the first $dynamicAnchor still in scope that is encountered when the schema is evaluated" :
128
+ [ "An array of strings is valid" ] ,
129
+ "A $dynamicRef with intermediate scopes that don't include a matching $dynamicAnchor should not affect dynamic scope resolution" :
130
+ [ "An array of strings is valid" ] ,
131
+ "An $anchor with the same name as a $dynamicAnchor should not be used for dynamic scope resolution" :
132
+ [ "Any array is valid" ] ,
133
+ "A $dynamicRef without a matching $dynamicAnchor in the same schema resource should behave like a normal $ref to $anchor" :
134
+ [ "Any array is valid" ] ,
135
+ "A $dynamicRef with a non-matching $dynamicAnchor in the same schema resource should behave like a normal $ref to $anchor" :
136
+ [ "Any array is valid" ] ,
137
+ "A $dynamicRef that initially resolves to a schema with a matching $dynamicAnchor should resolve to the first $dynamicAnchor in the dynamic scope" :
138
+ [
139
+ "The recursive part is valid against the root" ,
140
+ "The recursive part is not valid against the root" ,
141
+ ] ,
142
+ "A $dynamicRef that initially resolves to a schema without a matching $dynamicAnchor should behave like a normal $ref to $anchor" :
143
+ [ "The recursive part doesn't need to validate against the root" ] ,
144
+ "after leaving a dynamic scope, it should not be used by a $dynamicRef" : [
145
+ "string matches /$defs/thingy, but the $dynamicRef does not stop here" ,
146
+ "first_scope is not in dynamic scope for the $dynamicRef" ,
147
+ "/then/$defs/thingy is the final stop for the $dynamicRef" ,
148
+ ] ,
149
+ "strict-tree schema, guards against misspelled properties" : [
150
+ "instance with misspelled field" ,
151
+ "instance with correct field" ,
152
+ ] ,
153
+ "tests for implementation dynamic anchor and reference link" : [
154
+ "incorrect parent schema" ,
155
+ "incorrect extended schema" ,
156
+ "correct extended schema" ,
157
+ ] ,
158
+ // duplicate
159
+ "Tests for implementation dynamic anchor and reference link. Reference should be independent of any possible ordering." :
160
+ [ "incorrect parent schema" , "incorrect extended schema" , "correct extended schema" ] ,
161
+ } ,
162
+ ref : {
163
+ "refs with relative uris and defs" : [
164
+ "invalid on inner field" ,
165
+ "invalid on outer field" ,
166
+ "valid on both fields" ,
167
+ ] ,
168
+ "relative refs with absolute uris and defs" : [
169
+ "invalid on inner field" ,
170
+ "invalid on outer field" ,
171
+ "valid on both fields" ,
172
+ ] ,
173
+ } ,
174
+ unevaluatedItems : {
175
+ "unevaluatedItems depends on adjacent contains" : [
176
+ "contains passes, second item is not evaluated" ,
177
+ ] ,
178
+ "unevaluatedItems depends on multiple nested contains" : [
179
+ "7 not evaluated, fails unevaluatedItems" ,
180
+ ] ,
181
+ "unevaluatedItems and contains interact to control item dependency relationship" : [
182
+ "only b's are invalid" ,
183
+ "only c's are invalid" ,
184
+ "only b's and c's are invalid" ,
185
+ "only a's and c's are invalid" ,
186
+ ] ,
187
+ } ,
188
+ unevaluatedProperties : {
189
+ "unevaluatedProperties with if/then/else, then not defined" : [
190
+ "when if is false and has unevaluated properties" ,
191
+ ] ,
192
+ } ,
193
+ } ) ,
194
+ remotes : {
195
+ "http://localhost:1234/ref-and-defs.json" : require ( "./JSON-Schema-Test-Suite/remotes/ref-and-defs.json" ) ,
196
+ "http://localhost:1234/draft2020-12/format-assertion-false.json" : require ( "./JSON-Schema-Test-Suite/remotes/draft2020-12/format-assertion-false.json" ) ,
197
+ "http://localhost:1234/draft2020-12/format-assertion-true.json" : require ( "./JSON-Schema-Test-Suite/remotes/draft2020-12/format-assertion-true.json" ) ,
198
+ "http://localhost:1234/draft2020-12/metaschema-no-validation.json" : require ( "./JSON-Schema-Test-Suite/remotes/draft2020-12/metaschema-no-validation.json" ) ,
199
+ } ,
200
+ skip : [ ...SKIP_DRAFT7 , "optional/format-assertion" ] ,
201
+ } )
202
+
203
+ interface TestSuite {
204
+ name : string
205
+ test : any [ ]
206
+ }
73
207
74
- function runTest ( instances , draft : number , tests ) {
208
+ interface SchemaTest {
209
+ instances : Ajv [ ]
210
+ draft : number
211
+ tests : TestSuite [ ]
212
+ skip ?: string [ ]
213
+ remotes ?: Record < string , any >
214
+ }
215
+
216
+ function runTest ( { instances, draft, tests, skip = [ ] , remotes = { } } : SchemaTest ) {
75
217
for ( const ajv of instances ) {
76
218
ajv . opts . code . source = true
77
219
if ( draft === 6 ) {
78
220
ajv . addMetaSchema ( draft6MetaSchema )
79
221
ajv . opts . defaultMeta = "http://json-schema.org/draft-06/schema#"
80
222
}
81
223
for ( const id in remoteRefs ) ajv . addSchema ( remoteRefs [ id ] , id )
224
+ for ( const id in remotes ) ajv . addSchema ( remotes [ id ] , id )
82
225
ajvFormats ( ajv )
83
226
}
84
227
85
228
jsonSchemaTest ( withStandalone ( instances ) , {
86
229
description : `JSON-Schema Test Suite draft-${ draft } : ${ instances . length } ajv instances with different options` ,
87
230
suites : { tests} ,
88
231
only : [ ] ,
89
- skip : SKIP [ draft ] ,
232
+ skip,
90
233
assert : chai . assert ,
91
234
afterError,
92
235
afterEach,
@@ -95,3 +238,37 @@ function runTest(instances, draft: number, tests) {
95
238
timeout : 30000 ,
96
239
} )
97
240
}
241
+
242
+ interface SkippedTestCases {
243
+ [ suite : string ] : {
244
+ [ test : string ] : string [ ] | true
245
+ }
246
+ }
247
+
248
+ function skipTestCases ( suites : TestSuite [ ] , skipCases : SkippedTestCases ) : TestSuite [ ] {
249
+ for ( const suiteName in skipCases ) {
250
+ const suite = suites . find ( ( { name} ) => name === suiteName )
251
+ if ( ! suite ) throw new Error ( `test suite ${ suiteName } not found` )
252
+ for ( const testName in skipCases [ suiteName ] ) {
253
+ const test = suite . test . find ( ( { description} ) => description === testName )
254
+ if ( ! test ) {
255
+ throw new Error ( `test ${ testName } not found in suite ${ suiteName } ` )
256
+ }
257
+ const skippedCases = skipCases [ suiteName ] [ testName ]
258
+ suite . test . forEach ( ( t ) => {
259
+ if ( t . description === testName ) {
260
+ if ( skippedCases === true ) {
261
+ t . skip = true
262
+ } else {
263
+ t . tests . forEach ( ( testCase : any ) => {
264
+ if ( skippedCases . includes ( testCase . description ) ) {
265
+ testCase . skip = true
266
+ }
267
+ } )
268
+ }
269
+ }
270
+ } )
271
+ }
272
+ }
273
+ return suites
274
+ }
0 commit comments