1
+ package smirnov.oleg.json.schema.assertions.`object`
2
+
3
+ import io.kotest.assertions.asClue
4
+ import io.kotest.assertions.throwables.shouldThrow
5
+ import io.kotest.core.spec.style.FunSpec
6
+ import io.kotest.matchers.collections.shouldContainExactly
7
+ import io.kotest.matchers.collections.shouldHaveSize
8
+ import io.kotest.matchers.shouldBe
9
+ import kotlinx.serialization.json.JsonPrimitive
10
+ import kotlinx.serialization.json.buildJsonObject
11
+ import smirnov.oleg.json.pointer.JsonPointer
12
+ import smirnov.oleg.json.schema.JsonSchema
13
+ import smirnov.oleg.json.schema.KEY
14
+ import smirnov.oleg.json.schema.ValidationError
15
+
16
+ @Suppress(" unused" )
17
+ class JsonSchemaPropertiesValidationsTest : FunSpec () {
18
+ init {
19
+ JsonSchema .fromDescription(
20
+ """
21
+ {
22
+ "${KEY } schema": "http://json-schema.org/draft-07/schema#",
23
+ "properties": {
24
+ "prop1": {
25
+ "type": "number"
26
+ }
27
+ }
28
+ }
29
+ """ .trimIndent()
30
+ ).also { schema ->
31
+ test(" object passes properties validation" ) {
32
+ val jsonObject = buildJsonObject {
33
+ put(" prop1" , JsonPrimitive (42 ))
34
+ put(" prop2" , JsonPrimitive (" test" ))
35
+ }
36
+ val errors = mutableListOf<ValidationError >()
37
+ val valid = schema.validate(jsonObject, errors::add)
38
+ jsonObject.asClue {
39
+ valid shouldBe true
40
+ errors shouldHaveSize 0
41
+ }
42
+ }
43
+
44
+ test(" object fails properties validation" ) {
45
+ val jsonObject = buildJsonObject {
46
+ put(" prop1" , JsonPrimitive (" test" ))
47
+ }
48
+ val errors = mutableListOf<ValidationError >()
49
+ val valid = schema.validate(jsonObject, errors::add)
50
+ jsonObject.asClue {
51
+ valid shouldBe false
52
+ errors.shouldContainExactly(
53
+ ValidationError (
54
+ schemaPath = JsonPointer (" /properties/prop1/type" ),
55
+ objectPath = JsonPointer (" /prop1" ),
56
+ message = " element is not a number" ,
57
+ )
58
+ )
59
+ }
60
+ }
61
+ }
62
+
63
+ JsonSchema .fromDescription(
64
+ """
65
+ {
66
+ "${KEY } schema": "http://json-schema.org/draft-07/schema#",
67
+ "patternProperties": {
68
+ "^foo\\d$": {
69
+ "type": "number"
70
+ }
71
+ }
72
+ }
73
+ """ .trimIndent()
74
+ ).also { schema ->
75
+ test(" object passes patternProperties validation" ) {
76
+ val jsonObject = buildJsonObject {
77
+ put(" foo1" , JsonPrimitive (42 ))
78
+ put(" foo2" , JsonPrimitive (42.5 ))
79
+ put(" test" , JsonPrimitive (" string" ))
80
+ }
81
+ val errors = mutableListOf<ValidationError >()
82
+ val valid = schema.validate(jsonObject, errors::add)
83
+ jsonObject.asClue {
84
+ valid shouldBe true
85
+ errors shouldHaveSize 0
86
+ }
87
+ }
88
+
89
+ test(" object fails patternProperties validation" ) {
90
+ val jsonObject = buildJsonObject {
91
+ put(" foo1" , JsonPrimitive (" test" ))
92
+ }
93
+ val errors = mutableListOf<ValidationError >()
94
+ val valid = schema.validate(jsonObject, errors::add)
95
+ jsonObject.asClue {
96
+ valid shouldBe false
97
+ errors.shouldContainExactly(
98
+ ValidationError (
99
+ schemaPath = JsonPointer (" /patternProperties/^foo\\ d\$ /type" ),
100
+ objectPath = JsonPointer (" /foo1" ),
101
+ message = " element is not a number" ,
102
+ )
103
+ )
104
+ }
105
+ }
106
+ }
107
+
108
+ JsonSchema .fromDescription(
109
+ """
110
+ {
111
+ "${KEY } schema": "http://json-schema.org/draft-07/schema#",
112
+ "additionalProperties": {
113
+ "type": "number"
114
+ }
115
+ }
116
+ """ .trimIndent()
117
+ ).also { schema ->
118
+ test(" object passes additionalProperties validation" ) {
119
+ val jsonObject = buildJsonObject {
120
+ put(" foo1" , JsonPrimitive (42 ))
121
+ put(" foo2" , JsonPrimitive (42.5 ))
122
+ }
123
+ val errors = mutableListOf<ValidationError >()
124
+ val valid = schema.validate(jsonObject, errors::add)
125
+ jsonObject.asClue {
126
+ valid shouldBe true
127
+ errors shouldHaveSize 0
128
+ }
129
+ }
130
+
131
+ test(" object fails additionalProperties validation" ) {
132
+ val jsonObject = buildJsonObject {
133
+ put(" foo1" , JsonPrimitive (" test" ))
134
+ }
135
+ val errors = mutableListOf<ValidationError >()
136
+ val valid = schema.validate(jsonObject, errors::add)
137
+ jsonObject.asClue {
138
+ valid shouldBe false
139
+ errors.shouldContainExactly(
140
+ ValidationError (
141
+ schemaPath = JsonPointer (" /additionalProperties/type" ),
142
+ objectPath = JsonPointer (" /foo1" ),
143
+ message = " element is not a number" ,
144
+ )
145
+ )
146
+ }
147
+ }
148
+ }
149
+
150
+ JsonSchema .fromDescription(
151
+ """
152
+ {
153
+ "${KEY } schema": "http://json-schema.org/draft-07/schema#",
154
+ "properties": {
155
+ "test": {
156
+ "type": "string"
157
+ }
158
+ },
159
+ "patternProperties": {
160
+ "^foo\\d$": {
161
+ "type": "number"
162
+ }
163
+ },
164
+ "additionalProperties": false
165
+ }
166
+ """ .trimIndent()
167
+ ).also { schema ->
168
+ test(" false additionalProperties reports all unknown properties" ) {
169
+ val jsonObject = buildJsonObject {
170
+ put(" test" , JsonPrimitive (" value" ))
171
+ put(" foo2" , JsonPrimitive (42.5 ))
172
+ put(" unknown" , JsonPrimitive (42.5 ))
173
+ }
174
+
175
+ val errors = mutableListOf<ValidationError >()
176
+ val valid = schema.validate(jsonObject, errors::add)
177
+ jsonObject.asClue {
178
+ valid shouldBe false
179
+ errors.shouldContainExactly(
180
+ ValidationError (
181
+ schemaPath = JsonPointer (" /additionalProperties" ),
182
+ objectPath = JsonPointer (" /unknown" ),
183
+ message = " all values fail against the false schema" ,
184
+ )
185
+ )
186
+ }
187
+ }
188
+
189
+ notAnObjectPasses(schema)
190
+ }
191
+
192
+ JsonSchema .fromDescription(
193
+ """
194
+ {
195
+ "${KEY } schema": "http://json-schema.org/draft-07/schema#",
196
+ "properties": {},
197
+ "patternProperties": {}
198
+ }
199
+ """ .trimIndent()
200
+ ).also { schema ->
201
+ test(" object passes schema with empty properties and patternProperties" ) {
202
+ val jsonObject = buildJsonObject {
203
+ put(" test" , JsonPrimitive (" value" ))
204
+ put(" foo2" , JsonPrimitive (42.5 ))
205
+ put(" unknown" , JsonPrimitive (42.5 ))
206
+ }
207
+ val errors = mutableListOf<ValidationError >()
208
+ val valid = schema.validate(jsonObject, errors::add)
209
+ jsonObject.asClue {
210
+ valid shouldBe true
211
+ errors shouldHaveSize 0
212
+ }
213
+ }
214
+ }
215
+
216
+ test(" reports invalid regular expression" ) {
217
+ shouldThrow<IllegalArgumentException > {
218
+ JsonSchema .fromDescription(
219
+ """
220
+ {
221
+ "${KEY } schema": "http://json-schema.org/draft-07/schema#",
222
+ "patternProperties": {
223
+ "*^foo\\d$": {
224
+ "type": "number"
225
+ }
226
+ }
227
+ }
228
+ """ .trimIndent()
229
+ )
230
+ }.message shouldBe " *^foo\\ d\$ must be a valid regular expression"
231
+ }
232
+ }
233
+ }
0 commit comments