Skip to content

Commit 8e902c6

Browse files
committed
add new builtin validations and tests
1 parent eaaaf69 commit 8e902c6

File tree

6 files changed

+111
-21
lines changed

6 files changed

+111
-21
lines changed

Sources/OpenAPIKit/Validator/Validation+Builtins.swift

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ extension Validation {
252252
)
253253
}
254254

255-
/// Validate that all JSONSchema references are found in the document's
255+
/// Validate that all non-external JSONSchema references are found in the document's
256256
/// components dictionary.
257257
///
258258
/// - Important: This is included in validation by default.
@@ -274,7 +274,7 @@ extension Validation {
274274
)
275275
}
276276

277-
/// Validate that all Response references are found in the document's
277+
/// Validate that all non-external Response references are found in the document's
278278
/// components dictionary.
279279
///
280280
/// - Important: This is included in validation by default.
@@ -296,7 +296,7 @@ extension Validation {
296296
)
297297
}
298298

299-
/// Validate that all Parameter references are found in the document's
299+
/// Validate that all non-external Parameter references are found in the document's
300300
/// components dictionary.
301301
///
302302
/// - Important: This is included in validation by default.
@@ -318,7 +318,7 @@ extension Validation {
318318
)
319319
}
320320

321-
/// Validate that all Example references are found in the document's
321+
/// Validate that all non-external Example references are found in the document's
322322
/// components dictionary.
323323
///
324324
/// - Important: This is included in validation by default.
@@ -340,7 +340,7 @@ extension Validation {
340340
)
341341
}
342342

343-
/// Validate that all Request references are found in the document's
343+
/// Validate that all non-external Request references are found in the document's
344344
/// components dictionary.
345345
///
346346
/// - Important: This is included in validation by default.
@@ -362,7 +362,7 @@ extension Validation {
362362
)
363363
}
364364

365-
/// Validate that all Header references are found in the document's
365+
/// Validate that all non-external Header references are found in the document's
366366
/// components dictionary.
367367
///
368368
/// - Important: This is included in validation by default.
@@ -383,6 +383,50 @@ extension Validation {
383383
}
384384
)
385385
}
386+
387+
/// Validate that all non-external Link references are found in the document's
388+
/// components dictionary.
389+
///
390+
/// - Important: This is included in validation by default.
391+
///
392+
public static var linkReferencesAreValid: Validation<OpenAPI.Reference<OpenAPI.Link>> {
393+
.init(
394+
description: "Link reference can be found in components/links",
395+
check: { context in
396+
guard case let .internal(internalReference) = context.subject.jsonReference,
397+
case .component = internalReference else {
398+
// don't make assertions about external references
399+
// TODO: could make a stronger assertion including
400+
// internal references outside of components given
401+
// some way to resolve those references.
402+
return true
403+
}
404+
return context.document.components.contains(internalReference)
405+
}
406+
)
407+
}
408+
409+
/// Validate that all non-external PathItem references are found in the document's
410+
/// components dictionary.
411+
///
412+
/// - Important: This is included in validation by default.
413+
///
414+
public static var pathItemReferencesAreValid: Validation<OpenAPI.Reference<OpenAPI.PathItem>> {
415+
.init(
416+
description: "PathItem reference can be found in components/pathItems",
417+
check: { context in
418+
guard case let .internal(internalReference) = context.subject.jsonReference,
419+
case .component = internalReference else {
420+
// don't make assertions about external references
421+
// TODO: could make a stronger assertion including
422+
// internal references outside of components given
423+
// some way to resolve those references.
424+
return true
425+
}
426+
return context.document.components.contains(internalReference)
427+
}
428+
)
429+
}
386430

387431
/// Validate that `enum` must not be empty in the document's
388432
/// Server Variable.

Sources/OpenAPIKit/Validator/Validator.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,8 @@ public final class Validator {
195195
.init(.exampleReferencesAreValid),
196196
.init(.requestReferencesAreValid),
197197
.init(.headerReferencesAreValid),
198+
.init(.linkReferencesAreValid),
199+
.init(.pathItemReferencesAreValid),
198200
.init(.serverVarialbeEnumIsValid),
199201
.init(.serverVarialbeDefaultExistsInEnum)
200202
])

Sources/OpenAPIKit30/Validator/Validation+Builtins.swift

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ extension Validation {
243243
)
244244
}
245245

246-
/// Validate that all JSONSchema references are found in the document's
246+
/// Validate that all non-external JSONSchema references are found in the document's
247247
/// components dictionary.
248248
///
249249
/// - Important: This is included in validation by default.
@@ -265,7 +265,7 @@ extension Validation {
265265
)
266266
}
267267

268-
/// Validate that all Response references are found in the document's
268+
/// Validate that all non-external Response references are found in the document's
269269
/// components dictionary.
270270
///
271271
/// - Important: This is included in validation by default.
@@ -287,7 +287,7 @@ extension Validation {
287287
)
288288
}
289289

290-
/// Validate that all Parameter references are found in the document's
290+
/// Validate that all non-external Parameter references are found in the document's
291291
/// components dictionary.
292292
///
293293
/// - Important: This is included in validation by default.
@@ -309,7 +309,7 @@ extension Validation {
309309
)
310310
}
311311

312-
/// Validate that all Example references are found in the document's
312+
/// Validate that all non-external Example references are found in the document's
313313
/// components dictionary.
314314
///
315315
/// - Important: This is included in validation by default.
@@ -331,7 +331,7 @@ extension Validation {
331331
)
332332
}
333333

334-
/// Validate that all Request references are found in the document's
334+
/// Validate that all non-external Request references are found in the document's
335335
/// components dictionary.
336336
///
337337
/// - Important: This is included in validation by default.
@@ -353,7 +353,7 @@ extension Validation {
353353
)
354354
}
355355

356-
/// Validate that all Header references are found in the document's
356+
/// Validate that all non-external Header references are found in the document's
357357
/// components dictionary.
358358
///
359359
/// - Important: This is included in validation by default.
@@ -374,6 +374,28 @@ extension Validation {
374374
}
375375
)
376376
}
377+
378+
/// Validate that all non-external Link references are found in the document's
379+
/// components dictionary.
380+
///
381+
/// - Important: This is included in validation by default.
382+
///
383+
public static var linkReferencesAreValid: Validation<JSONReference<OpenAPI.Link>> {
384+
.init(
385+
description: "Link reference can be found in components/links",
386+
check: { context in
387+
guard case let .internal(internalReference) = context.subject,
388+
case .component = internalReference else {
389+
// don't make assertions about external references
390+
// TODO: could make a stronger assertion including
391+
// internal references outside of components given
392+
// some way to resolve those references.
393+
return true
394+
}
395+
return context.document.components.contains(internalReference)
396+
}
397+
)
398+
}
377399
}
378400

379401
/// Used by both the Path Item parameter check and the

Sources/OpenAPIKit30/Validator/Validator.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,8 @@ public final class Validator {
189189
.init(.parameterReferencesAreValid),
190190
.init(.exampleReferencesAreValid),
191191
.init(.requestReferencesAreValid),
192-
.init(.headerReferencesAreValid)
192+
.init(.headerReferencesAreValid),
193+
.init(.linkReferencesAreValid)
193194
])
194195
}
195196

Tests/OpenAPIKit30Tests/Validator/BuiltinValidationTests.swift

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -629,7 +629,8 @@ final class BuiltinValidationTests: XCTestCase {
629629
]
630630
),
631631
.xml: .init(schemaReference: .component(named: "schema1"))
632-
]
632+
],
633+
links: ["linky": .reference(.component(named: "link1"))]
633634
)
634635
]
635636
)
@@ -647,7 +648,7 @@ final class BuiltinValidationTests: XCTestCase {
647648
// NOTE this is part of default validation
648649
XCTAssertThrowsError(try document.validate()) { error in
649650
let error = error as? ValidationErrorCollection
650-
XCTAssertEqual(error?.values.count, 6)
651+
XCTAssertEqual(error?.values.count, 7)
651652
XCTAssertEqual(error?.values[0].reason, "Failed to satisfy: Parameter reference can be found in components/parameters")
652653
XCTAssertEqual(error?.values[0].codingPathString, ".paths['/hello'].get.parameters[0]")
653654
XCTAssertEqual(error?.values[1].reason, "Failed to satisfy: Request reference can be found in components/requestBodies")
@@ -660,6 +661,8 @@ final class BuiltinValidationTests: XCTestCase {
660661
XCTAssertEqual(error?.values[4].codingPathString, ".paths['/hello'].get.responses.404.content['application/json'].examples.example1")
661662
XCTAssertEqual(error?.values[5].reason, "Failed to satisfy: JSONSchema reference can be found in components/schemas")
662663
XCTAssertEqual(error?.values[5].codingPathString, ".paths['/hello'].get.responses.404.content['application/xml'].schema")
664+
XCTAssertEqual(error?.values[6].reason, "Failed to satisfy: Link reference can be found in components/links")
665+
XCTAssertEqual(error?.values[6].codingPathString, ".paths['/hello'].get.responses.404.links.linky")
663666
}
664667
}
665668

@@ -696,7 +699,8 @@ final class BuiltinValidationTests: XCTestCase {
696699
),
697700
.xml: .init(schemaReference: .component(named: "schema1")),
698701
.txt: .init(schemaReference: .external(URL(string: "https://website.com/file.json#/hello/world")!))
699-
]
702+
],
703+
links: ["linky": .reference(.component(named: "link1"))]
700704
)
701705
]
702706
)
@@ -726,6 +730,9 @@ final class BuiltinValidationTests: XCTestCase {
726730
],
727731
headers: [
728732
"header1": .init(schema: .string)
733+
],
734+
links: [
735+
"link1": .init(operationId: "op 1")
729736
]
730737
)
731738
)

Tests/OpenAPIKitTests/Validator/BuiltinValidationTests.swift

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -732,7 +732,8 @@ final class BuiltinValidationTests: XCTestCase {
732732
]
733733
),
734734
.xml: .init(schemaReference: .component(named: "schema1"))
735-
]
735+
],
736+
links: ["linky": .reference(.component(named: "link1"))]
736737
)
737738
]
738739
)
@@ -742,15 +743,16 @@ final class BuiltinValidationTests: XCTestCase {
742743
info: .init(title: "test", version: "1.0"),
743744
servers: [],
744745
paths: [
745-
"/hello": .pathItem(path)
746+
"/hello": .pathItem(path),
747+
"/world": .reference(.component(named: "path1"))
746748
],
747749
components: .noComponents
748750
)
749751

750752
// NOTE this is part of default validation
751753
XCTAssertThrowsError(try document.validate()) { error in
752754
let error = error as? ValidationErrorCollection
753-
XCTAssertEqual(error?.values.count, 6)
755+
XCTAssertEqual(error?.values.count, 8)
754756
XCTAssertEqual(error?.values[0].reason, "Failed to satisfy: Parameter reference can be found in components/parameters")
755757
XCTAssertEqual(error?.values[0].codingPathString, ".paths['/hello'].get.parameters[0]")
756758
XCTAssertEqual(error?.values[1].reason, "Failed to satisfy: Request reference can be found in components/requestBodies")
@@ -763,6 +765,10 @@ final class BuiltinValidationTests: XCTestCase {
763765
XCTAssertEqual(error?.values[4].codingPathString, ".paths['/hello'].get.responses.404.content['application/json'].examples.example1")
764766
XCTAssertEqual(error?.values[5].reason, "Failed to satisfy: JSONSchema reference can be found in components/schemas")
765767
XCTAssertEqual(error?.values[5].codingPathString, ".paths['/hello'].get.responses.404.content['application/xml'].schema")
768+
XCTAssertEqual(error?.values[6].reason, "Failed to satisfy: Link reference can be found in components/links")
769+
XCTAssertEqual(error?.values[6].codingPathString, ".paths['/hello'].get.responses.404.links.linky")
770+
XCTAssertEqual(error?.values[7].reason, "Failed to satisfy: PathItem reference can be found in components/pathItems")
771+
XCTAssertEqual(error?.values[7].codingPathString, ".paths['/world']")
766772
}
767773
}
768774

@@ -799,7 +805,8 @@ final class BuiltinValidationTests: XCTestCase {
799805
),
800806
.xml: .init(schemaReference: .component(named: "schema1")),
801807
.txt: .init(schemaReference: .external(URL(string: "https://website.com/file.json#/hello/world")!))
802-
]
808+
],
809+
links: ["linky": .reference(.component(named: "link1"))]
803810
)
804811
]
805812
)
@@ -809,7 +816,8 @@ final class BuiltinValidationTests: XCTestCase {
809816
info: .init(title: "test", version: "1.0"),
810817
servers: [],
811818
paths: [
812-
"/hello": .pathItem(path)
819+
"/hello": .pathItem(path),
820+
"/world": .reference(.component(named: "path1"))
813821
],
814822
components: .init(
815823
schemas: [
@@ -829,6 +837,12 @@ final class BuiltinValidationTests: XCTestCase {
829837
],
830838
headers: [
831839
"header1": .init(schema: .string)
840+
],
841+
links: [
842+
"link1": .init(operationId: "op 1")
843+
],
844+
pathItems: [
845+
"path1": .init()
832846
]
833847
)
834848
)

0 commit comments

Comments
 (0)