-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathJSONSchemaTestSuite.swift
158 lines (135 loc) · 4.24 KB
/
JSONSchemaTestSuite.swift
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
import Foundation
import Testing
@testable import JSONSchema
struct JSONSchemaTestSuite {
static let fileLoader = FileLoader<[JSONSchemaTest]>(
subdirectory: "JSON-Schema-Test-Suite/tests/draft2020-12"
)
static let unsupportedFilePaths: [String] = [
"dynamicRef.json"
]
static let unsupportedTests: [(path: String, description: String, reason: String)] = [
("defs.json", "validate definition against metaschema", "Metaschema uses dynamic references"),
(
"unevaluatedItems.json", "unevaluatedItems with $dynamicRef",
"Dynamic refs not fully supported"
),
(
"unevaluatedProperies.json", "unevaluatedProperties with $dynamicRef",
"Dynamic refs not fully supported"
),
("refRemote.json", "remote HTTP ref with different URN $id", "URN support incomplete"),
("refRemote.json", "remote HTTP ref with nested absolute ref", "URN support incomplete"),
(
"vocabulary.json", "schema that uses custom metaschema with with no validation vocabulary",
"Vocabulary not supported yet"
),
]
static let flattenedArguments: [(schemaTest: JSONSchemaTest, path: URL)] = {
fileLoader.loadAllFiles()
.filter { unsupportedFilePaths.contains($0.url.lastPathComponent) == false }
.flatMap { path, schemaTests in
schemaTests.map { ($0, path) }
}
}()
static let remotes: [String: JSONValue] = RemoteLoader().loadSchemas()
@Test(arguments: flattenedArguments)
func schemaTest(_ schemaTest: JSONSchemaTest, path: URL) throws {
guard !Self.unsupportedTests.contains(where: { $0.description == schemaTest.description })
else {
return
}
let schema = try #require(
try Schema(
rawSchema: schemaTest.schema,
context: .init(dialect: .draft2020_12, remoteSchema: Self.remotes)
)
)
for testCase in schemaTest.tests {
let validationResult = schema.validate(testCase.data)
let comment: () -> Testing.Comment = {
"""
Schema Test: "\(schemaTest.description)" @ \(path)
```json
\(try! schemaTest.schema.json())
```
Test Case: "\(testCase.description)"
```json
\(try! testCase.data.json())
```
Valid?:
- Expected: \(testCase.valid)
- Recieved: \(validationResult.isValid)
Full result:
```json
\(try! validationResult.json())
```
"""
}
#expect(
testCase.valid == validationResult.isValid,
comment()
)
}
}
// This is dynamic ref related
// @Test func debugger() throws {
// let testSchema = """
// {
// "$schema": "https://json-schema.org/draft/2020-12/schema",
// "$ref": "https://json-schema.org/draft/2020-12/schema"
// }
// """
//
// let testCase = """
// {"$defs": {"foo": {"type": 1}}}
// """
//
// let rawSchema = try JSONDecoder().decode(JSONValue.self, from: testSchema.data(using: .utf8)!)
// let schema = try #require(try Schema(rawSchema: rawSchema, context: .init(dialect: .draft2020_12, remoteSchema: Self.remotes)))
// let result = try #require(try schema.validate(instance: testCase))
// dump(result)
// #expect((result.isValid) == false, "\(result)")
// }
}
struct JSONSchemaTest: Sendable, Codable {
struct Spec: Sendable, Codable {
let core: String
let quote: String?
}
struct TestCase: Sendable, Codable {
let description: String
let data: JSONValue
let valid: Bool
}
let description: String
let specification: [Spec]?
let schema: JSONValue
let tests: [TestCase]
}
extension JSONSchemaTest: CustomTestStringConvertible {
public var testDescription: String { description }
}
extension Encodable {
fileprivate func toJsonString() throws -> String {
let encoder = JSONEncoder()
encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
let data = try encoder.encode(self)
return String(decoding: data, as: UTF8.self)
}
}
extension Schema {
fileprivate func json() throws -> String {
try toJsonString()
}
}
extension JSONValue {
fileprivate func json() throws -> String {
try toJsonString()
}
}
extension ValidationResult {
fileprivate func json() throws -> String {
try toJsonString()
}
}