-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTestRfc8927.java
More file actions
598 lines (495 loc) · 22.9 KB
/
TestRfc8927.java
File metadata and controls
598 lines (495 loc) · 22.9 KB
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
package json.java21.jtd;
import jdk.sandbox.java.util.json.Json;
import jdk.sandbox.java.util.json.JsonValue;
import jdk.sandbox.java.util.json.JsonNumber;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/// Comprehensive RFC 8927 compliance tests
/// - Ref schema validation with definitions
/// - Timestamp format validation (RFC 3339)
/// - Integer range validation for all types
/// - Error path information (instancePath and schemaPath)
/// - Multiple error collection
/// - Discriminator tag exemption
public class TestRfc8927 extends JtdTestBase {
/// Test ref schema resolution with valid definitions
/// RFC 8927 Section 3.3.2: Ref schemas must resolve against definitions
@Test
public void testRefSchemaValid() throws Exception {
JsonValue schema = Json.parse("{\"ref\": \"address\", \"definitions\": {\"address\": {\"type\": \"string\"}}}");
JsonValue validData = Json.parse("\"123 Main St\"");
Jtd validator = new Jtd();
Jtd.Result result = validator.validate(schema, validData);
assertThat(result.isValid()).isTrue();
assertThat(result.errors()).isEmpty();
LOG.fine(() -> "Ref schema valid test - schema: " + schema + ", data: " + validData);
}
/// Counter-test: Ref schema with invalid definition reference
/// Should fail when ref points to non-existent definition
@Test
public void testRefSchemaInvalidDefinition() throws Exception {
JsonValue schema = Json.parse("{\"ref\": \"nonexistent\", \"definitions\": {\"address\": {\"type\": \"string\"}}}");
JsonValue data = Json.parse("\"anything\"");
Jtd validator = new Jtd();
Jtd.Result result = validator.validate(schema, data);
assertThat(result.isValid())
.as("Ref schema should fail when definition doesn't exist, but implementation is broken")
.isFalse();
assertThat(result.errors()).isNotEmpty();
}
/// Test timestamp format validation (RFC 3339)
/// RFC 8927 Section 3.3.3: timestamp must follow RFC 3339 format
@Test
public void testTimestampValid() throws Exception {
JsonValue schema = Json.parse("{\"type\": \"timestamp\"}");
// Valid RFC 3339 timestamps
String[] validTimestamps = {
"\"2023-12-25T10:30:00Z\"",
"\"2023-12-25T10:30:00.123Z\"",
"\"2023-12-25T10:30:00+00:00\"",
"\"2023-12-25T10:30:00-05:00\""
};
Jtd validator = new Jtd();
for (String timestamp : validTimestamps) {
JsonValue validData = Json.parse(timestamp);
Jtd.Result result = validator.validate(schema, validData);
assertThat(result.isValid()).isTrue();
LOG.fine(() -> "Timestamp valid test - data: " + validData);
}
}
/// Counter-test: Invalid timestamp formats
/// Should reject non-RFC 3339 timestamp strings
@Test
public void testTimestampInvalid() throws Exception {
JsonValue schema = Json.parse("{\"type\": \"timestamp\"}");
// Invalid timestamp formats
String[] invalidTimestamps = {
"\"2023-12-25\"", // Date only
"\"10:30:00\"", // Time only
"\"2023/12/25T10:30:00Z\"", // Wrong date separator
"\"2023-12-25 10:30:00\"", // Space instead of T
"\"not-a-timestamp\"", // Completely invalid
"\"123\"", // Number as string
"123" // Number
};
Jtd validator = new Jtd();
for (String timestamp : invalidTimestamps) {
JsonValue invalidData = Json.parse(timestamp);
Jtd.Result result = validator.validate(schema, invalidData);
assertThat(result.isValid())
.as("Timestamp should reject invalid RFC 3339 format: " + invalidData)
.isFalse();
assertThat(result.errors()).isNotEmpty();
}
}
/// Test integer type range validation
/// RFC 8927 Table 2: Specific ranges for each integer type
@Test
public void testIntegerRangesValid() throws Exception {
// Test valid ranges for each integer type
testIntegerTypeRange("int8", "-128", "127", "0");
testIntegerTypeRange("uint8", "0", "255", "128");
testIntegerTypeRange("int16", "-32768", "32767", "0");
testIntegerTypeRange("uint16", "0", "65535", "32768");
testIntegerTypeRange("int32", "-2147483648", "2147483647", "0");
testIntegerTypeRange("uint32", "0", "4294967295", "2147483648");
}
/// Counter-test: Integer values outside valid ranges
/// Should reject values that exceed type ranges
@Test
public void testIntegerRangesInvalid() throws Exception {
// Test invalid ranges for each integer type
testIntegerTypeInvalid("int8", "-129", "128"); // Below min, above max
testIntegerTypeInvalid("uint8", "-1", "256"); // Below min, above max
testIntegerTypeInvalid("int16", "-32769", "32768"); // Below min, above max
testIntegerTypeInvalid("uint16", "-1", "65536"); // Below min, above max
testIntegerTypeInvalid("int32", "-2147483649", "2147483648"); // Below min, above max
testIntegerTypeInvalid("uint32", "-1", "4294967296"); // Below min, above max
}
/// Helper method to test valid integer ranges
private void testIntegerTypeRange(String type, String min, String max, String middle) throws Exception {
JsonValue schema = Json.parse("{\"type\": \"" + type + "\"}");
Jtd validator = new Jtd();
// Test minimum, maximum, and middle values
String[] validValues = {min, max, middle};
for (String value : validValues) {
JsonValue validData = Json.parse(value);
Jtd.Result result = validator.validate(schema, validData);
assertThat(result.isValid()).isTrue();
LOG.fine(() -> "Integer range valid test - type: " + type + ", value: " + value);
}
}
/// Helper method to test invalid integer ranges
private void testIntegerTypeInvalid(String type, String belowMin, String aboveMax) throws Exception {
JsonValue schema = Json.parse("{\"type\": \"" + type + "\"}");
Jtd validator = new Jtd();
// Test values below minimum and above maximum
String[] invalidValues = {belowMin, aboveMax};
for (String value : invalidValues) {
JsonValue invalidData = Json.parse(value);
Jtd.Result result = validator.validate(schema, invalidData);
assertThat(result.isValid())
.as("Integer type \"" + type + "\" should reject value \"" + value + "\" as out of range")
.isFalse();
assertThat(result.errors()).isNotEmpty();
}
}
/// Test error path information (instancePath and schemaPath)
/// RFC 8927 Section 3.2: All errors must include instancePath and schemaPath
@Test
public void testErrorPathInformation() throws Exception {
JsonValue schema = Json.parse("{\"properties\": {\"name\": {\"type\": \"string\"}, \"age\": {\"type\": \"int32\"}}}");
JsonValue invalidData = Json.parse("{\"name\": 123, \"age\": \"not-a-number\"}");
Jtd validator = new Jtd();
Jtd.Result result = validator.validate(schema, invalidData);
assertThat(result.isValid()).isFalse();
assertThat(result.errors()).isNotEmpty();
// Each error should have path information (currently only message is implemented)
for (String error : result.errors()) {
assertThat(error).isNotNull();
LOG.fine(() -> "Error path test: " + error);
}
}
/// Test multiple error collection
/// Should collect all validation errors, not just the first one
@Test
public void testMultipleErrorCollection() throws Exception {
JsonValue schema = Json.parse("{\"elements\": {\"type\": \"string\"}}");
JsonValue invalidData = Json.parse("[123, 456, \"valid\", 789]");
Jtd validator = new Jtd();
Jtd.Result result = validator.validate(schema, invalidData);
assertThat(result.isValid()).isFalse();
// Should collect errors for all invalid elements (123, 456, 789)
// Note: This test assumes the implementation collects multiple errors
// If it returns early, this test will help identify that issue
assertThat(result.errors()).isNotEmpty();
LOG.fine(() -> "Multiple error collection test - errors count: " + result.errors().size());
// Log all errors for debugging
for (String error : result.errors()) {
LOG.fine(() -> "Multiple error: " + error);
}
}
/// Test discriminator tag exemption
/// RFC 8927 §2.2.8: Only the discriminator field itself is exempt from additionalProperties enforcement
@Test
public void testDiscriminatorTagExemption() throws Exception {
JsonValue schema = Json.parse("{\"discriminator\": \"type\", \"mapping\": {\"person\": {\"properties\": {\"name\": {\"type\": \"string\"}}}}}");
// Valid data with discriminator and no additional properties
JsonValue validData1 = Json.parse("{\"type\": \"person\", \"name\": \"John\"}");
// Data with discriminator and additional properties (only discriminator field should be exempt)
JsonValue invalidData2 = Json.parse("{\"type\": \"person\", \"name\": \"John\", \"extra\": \"not_allowed\"}");
Jtd validator = new Jtd();
// First should be valid - no additional properties
Jtd.Result result1 = validator.validate(schema, validData1);
assertThat(result1.isValid()).isTrue();
// Second should be invalid - extra field is not exempt, only discriminator field is
Jtd.Result result2 = validator.validate(schema, invalidData2);
assertThat(result2.isValid()).isFalse();
assertThat(result2.errors()).anySatisfy(error -> assertThat(error).contains("extra"));
LOG.fine(() -> "Discriminator tag exemption test - valid: " + validData1 + ", invalid: " + invalidData2);
}
/// Counter-test: Discriminator with invalid mapping
/// Should fail when discriminator value is not in mapping
@Test
public void testDiscriminatorInvalidMapping() throws Exception {
JsonValue schema = Json.parse("{\"discriminator\": \"type\", \"mapping\": {\"person\": {\"properties\": {\"name\": {\"type\": \"string\"}}}}}");
JsonValue invalidData = Json.parse("{\"type\": \"invalid\", \"name\": \"John\"}");
Jtd validator = new Jtd();
Jtd.Result result = validator.validate(schema, invalidData);
assertThat(result.isValid()).isFalse();
assertThat(result.errors()).isNotEmpty();
LOG.fine(() -> "Discriminator invalid mapping test - errors: " + result.errors());
}
/// Test float type validation
/// RFC 8927 Section 3.3.3: float32 and float64 validation
@Test
public void testFloatTypesValid() throws Exception {
JsonValue schema32 = Json.parse("{\"type\": \"float32\"}");
JsonValue schema64 = Json.parse("{\"type\": \"float64\"}");
// Valid float values
String[] validFloats = {"1.5", "-3.14", "0", "123.456", "1e10", "-1.5e-3"};
Jtd validator = new Jtd();
for (String floatValue : validFloats) {
JsonValue validData = Json.parse(floatValue);
Jtd.Result result32 = validator.validate(schema32, validData);
Jtd.Result result64 = validator.validate(schema64, validData);
assertThat(result32.isValid()).isTrue();
assertThat(result64.isValid()).isTrue();
LOG.fine(() -> "Float types valid test - value: " + floatValue);
}
}
/// Counter-test: Invalid float values
/// Should reject non-numeric values for float types
@Test
public void testFloatTypesInvalid() throws Exception {
JsonValue schema = Json.parse("{\"type\": \"float32\"}");
// Invalid values for float
String[] invalidValues = {"\"not-a-float\"", "\"123\"", "true", "false", "null"};
Jtd validator = new Jtd();
for (String invalidValue : invalidValues) {
JsonValue invalidData = Json.parse(invalidValue);
Jtd.Result result = validator.validate(schema, invalidData);
assertThat(result.isValid()).isFalse();
assertThat(result.errors()).isNotEmpty();
LOG.fine(() -> "Float types invalid test - value: " + invalidValue + ", errors: " + result.errors());
}
}
/// Test boolean type validation
/// RFC 8927 Section 3.3.3: boolean type validation
@Test
public void testBooleanTypeValid() throws Exception {
JsonValue schema = Json.parse("{\"type\": \"boolean\"}");
Jtd validator = new Jtd();
// Valid boolean values
JsonValue trueValue = Json.parse("true");
JsonValue falseValue = Json.parse("false");
Jtd.Result result1 = validator.validate(schema, trueValue);
Jtd.Result result2 = validator.validate(schema, falseValue);
assertThat(result1.isValid()).isTrue();
assertThat(result2.isValid()).isTrue();
LOG.fine(() -> "Boolean type valid test - true: " + trueValue + ", false: " + falseValue);
}
/// Counter-test: Invalid boolean values
/// Should reject non-boolean values
@Test
public void testBooleanTypeInvalid() throws Exception {
JsonValue schema = Json.parse("{\"type\": \"boolean\"}");
// Invalid values for boolean
String[] invalidValues = {"\"true\"", "\"false\"", "1", "0", "\"yes\"", "\"no\"", "null"};
Jtd validator = new Jtd();
for (String invalidValue : invalidValues) {
JsonValue invalidData = Json.parse(invalidValue);
Jtd.Result result = validator.validate(schema, invalidData);
assertThat(result.isValid()).isFalse();
assertThat(result.errors()).isNotEmpty();
LOG.fine(() -> "Boolean type invalid test - value: " + invalidValue + ", errors: " + result.errors());
}
}
/// Test nullable default behavior - non-nullable schemas must reject null
@Test
public void testNonNullableBooleanRejectsNull() throws Exception {
JsonValue schema = Json.parse("{\"type\":\"boolean\"}");
JsonValue instance = Json.parse("null");
Jtd.Result result = new Jtd().validate(schema, instance);
assertThat(result.isValid()).isFalse();
assertThat(result.errors()).anySatisfy(err -> assertThat(err).contains("expected boolean"));
}
/// Test nullable boolean accepts null when explicitly nullable
@Test
public void testNullableBooleanAcceptsNull() throws Exception {
JsonValue schema = Json.parse("{\"type\":\"boolean\",\"nullable\":true}");
JsonValue instance = Json.parse("null");
Jtd.Result result = new Jtd().validate(schema, instance);
assertThat(result.isValid()).isTrue();
}
/// Test timestamp validation with leap second
@Test
public void testTimestampLeapSecond() throws Exception {
JsonValue schema = Json.parse("{\"type\":\"timestamp\"}");
JsonValue instance = Json.parse("\"1990-12-31T23:59:60Z\"");
Jtd.Result result = new Jtd().validate(schema, instance);
assertThat(result.isValid()).isTrue();
}
/// Test timestamp validation with timezone offset
@Test
public void testTimestampWithTimezoneOffset() throws Exception {
JsonValue schema = Json.parse("{\"type\":\"timestamp\"}");
JsonValue instance = Json.parse("\"1990-12-31T15:59:60-08:00\"");
Jtd.Result result = new Jtd().validate(schema, instance);
assertThat(result.isValid()).isTrue();
}
/// Test nested ref schema resolution
@Test
public void testRefSchemaNested() throws Exception {
JsonValue schema = Json.parse("""
{
"definitions": {
"id": {"type": "string"},
"user": {"properties": {"id": {"ref": "id"}}}
},
"ref": "user"
}""");
JsonValue instance = Json.parse("{\"id\":\"abc123\"}");
Jtd.Result result = new Jtd().validate(schema, instance);
assertThat(result.isValid()).isTrue();
}
/// Test recursive ref schema resolution
@Test
public void testRefSchemaRecursive() throws Exception {
JsonValue schema = Json.parse("""
{
"definitions": {
"node": {
"properties": {
"value": {"type":"string"},
"next": {"nullable": true, "ref": "node"}
}
}
},
"ref": "node"
}""");
JsonValue instance = Json.parse("{\"value\":\"root\",\"next\":{\"value\":\"child\",\"next\":null}}");
Jtd.Result result = new Jtd().validate(schema, instance);
assertThat(result.isValid()).isTrue();
}
/// Test recursive ref schema validation - should reject invalid nested data
/// "ref schema - recursive schema, bad" from JTD specification test suite
@Test
public void testRefSchemaRecursiveBad() throws Exception {
JsonValue schema = Json.parse("""
{
"definitions": {
"root": {
"elements": {
"ref": "root"
}
}
},
"ref": "root"
}""");
// This should be invalid - nested array contains mixed types (arrays and strings)
JsonValue instance = Json.parse("[[],[[]],[[[],[\"a\"]]]]");
LOG.info(() -> "Testing recursive ref schema validation - should reject mixed types");
LOG.fine(() -> "Schema: " + schema);
LOG.fine(() -> "Instance: " + instance);
Jtd validator = new Jtd();
Jtd.Result result = validator.validate(schema, instance);
LOG.fine(() -> "Validation result: " + (result.isValid() ? "VALID" : "INVALID"));
if (!result.isValid()) {
LOG.fine(() -> "ERRORS: " + result.errors());
}
// This should be invalid according to RFC 8927 (recursive elements should be homogeneous)
assertThat(result.isValid())
.as("Recursive ref should reject heterogeneous nested data")
.isFalse();
}
/// Micro test to debug int32 validation with decimal values
/// Should reject non-integer values like 3.14 for int32 type
@Test
public void testInt32RejectsDecimal() throws Exception {
JsonValue schema = Json.parse("{\"type\": \"int32\"}");
JsonValue decimalValue = JsonNumber.of(new java.math.BigDecimal("3.14"));
LOG.info(() -> "Testing int32 validation against decimal value 3.14");
LOG.fine(() -> "Schema: " + schema);
LOG.fine(() -> "Instance: " + decimalValue);
Jtd validator = new Jtd();
Jtd.Result result = validator.validate(schema, decimalValue);
LOG.fine(() -> "Validation result: " + (result.isValid() ? "VALID" : "INVALID"));
if (!result.isValid()) {
LOG.fine(() -> "ERRORS: " + result.errors());
}
// This should be invalid - int32 should reject decimal values
assertThat(result.isValid())
.as("int32 should reject decimal value 3.14")
.isFalse();
assertThat(result.errors())
.as("Should have validation errors for decimal value")
.isNotEmpty();
}
/// Test that integer types accept valid integer representations with trailing zeros
/// RFC 8927 §2.2.3.1: "An integer value is a number without a fractional component"
/// Values like 3.0, 3.000 are valid integers despite positive scale
@Test
public void testIntegerTypesAcceptTrailingZeros() throws Exception {
JsonValue schema = Json.parse("{\"type\": \"int32\"}");
// Valid integer representations with trailing zeros
JsonValue[] validIntegers = {
JsonNumber.of(new java.math.BigDecimal("3.0")),
JsonNumber.of(new java.math.BigDecimal("3.000")),
JsonNumber.of(new java.math.BigDecimal("42.00")),
JsonNumber.of(new java.math.BigDecimal("0.0"))
};
Jtd validator = new Jtd();
for (JsonValue validValue : validIntegers) {
Jtd.Result result = validator.validate(schema, validValue);
LOG.fine(() -> "Testing int32 with valid integer representation: " + validValue);
assertThat(result.isValid())
.as("int32 should accept integer representation %s", validValue)
.isTrue();
assertThat(result.errors())
.as("Should have no validation errors for integer representation %s", validValue)
.isEmpty();
}
}
/// Test that integer types reject values with actual fractional components
/// RFC 8927 §2.2.3.1: "An integer value is a number without a fractional component"
@Test
public void testIntegerTypesRejectFractionalComponents() throws Exception {
JsonValue schema = Json.parse("{\"type\": \"int32\"}");
// Invalid values with actual fractional components
JsonValue[] invalidValues = {
JsonNumber.of(new java.math.BigDecimal("3.1")),
JsonNumber.of(new java.math.BigDecimal("3.0001")),
JsonNumber.of(new java.math.BigDecimal("3.14")),
JsonNumber.of(new java.math.BigDecimal("0.1"))
};
Jtd validator = new Jtd();
for (JsonValue invalidValue : invalidValues) {
Jtd.Result result = validator.validate(schema, invalidValue);
LOG.fine(() -> "Testing int32 with fractional value: " + invalidValue);
assertThat(result.isValid())
.as("int32 should reject fractional value %s", invalidValue)
.isFalse();
assertThat(result.errors())
.as("Should have validation errors for fractional value %s", invalidValue)
.isNotEmpty();
}
}
/// Test for Issue #91: additionalProperties should default to false when no properties defined
/// Empty properties schema should reject additional properties
@Test
public void testAdditionalPropertiesDefaultsToFalse() throws Exception {
JsonValue schema = Json.parse("{\"elements\": {\"properties\": {}}}");
JsonValue invalidData = Json.parse("[{\"extraProperty\":\"extra-value\"}]");
Jtd validator = new Jtd();
Jtd.Result result = validator.validate(schema, invalidData);
// This should fail validation because additionalProperties defaults to false
assertThat(result.isValid())
.as("Empty properties schema should reject additional properties by default")
.isFalse();
assertThat(result.errors())
.as("Should have validation error for additional property")
.isNotEmpty();
}
/// Test case from JtdExhaustiveTest property test failure
/// Schema: {"elements":{"properties":{"alpha":{"discriminator":"alpha","mapping":{"type1":{"type":"boolean"}}}}}}
/// Document: [{"alpha":{"alpha":"type1"}},{"alpha":{"alpha":"type1"}}]
/// This should pass validation but currently fails with "expected boolean, got JsonObjectImpl"
@Test
public void testDiscriminatorInElementsSchema() throws Exception {
JsonValue schema = Json.parse("""
{
"elements": {
"properties": {
"alpha": {
"discriminator": "alpha",
"mapping": {
"type1": {"type": "boolean"}
}
}
}
}
}
""");
JsonValue document = Json.parse("""
[
{"alpha": {"alpha": "type1"}},
{"alpha": {"alpha": "type1"}}
]
""");
LOG.info(() -> "Testing discriminator in elements schema - property test failure case");
LOG.fine(() -> "Schema: " + schema);
LOG.fine(() -> "Document: " + document);
Jtd validator = new Jtd();
Jtd.Result result = validator.validate(schema, document);
LOG.fine(() -> "Validation result: " + (result.isValid() ? "VALID" : "INVALID"));
if (!result.isValid()) {
LOG.fine(() -> "Errors: " + result.errors());
}
// This should be valid according to the property test expectation
// but currently fails with "expected boolean, got JsonObjectImpl"
assertThat(result.isValid())
.as("Discriminator in elements schema should validate the property test case")
.isTrue();
}
}