1+ package json .java21 .jtd ;
2+
3+ import jdk .sandbox .java .util .json .Json ;
4+ import jdk .sandbox .java .util .json .JsonValue ;
5+ import org .junit .jupiter .api .Test ;
6+
7+ import static org .assertj .core .api .Assertions .assertThat ;
8+
9+ /// RFC 8927 compliance tests for failing JTD specification cases
10+ /// These are the exact test cases that were failing in JtdSpecIT
11+ /// with explicit multiline strings for schema and JSON documents
12+ public class TestRfc8927Compliance extends JtdTestBase {
13+
14+ /// Test ref schema with nested definitions
15+ /// "ref schema - nested ref" from JTD specification test suite
16+ /// Should resolve nested ref "bar" inside definition "foo"
17+ @ Test
18+ public void testRefSchemaNestedRef () throws Exception {
19+ // Schema with nested ref: foo references bar, bar is empty schema
20+ JsonValue schema = Json .parse ("""
21+ {
22+ "definitions": {
23+ "foo": {
24+ "ref": "bar"
25+ },
26+ "bar": {}
27+ },
28+ "ref": "foo"
29+ }
30+ """ );
31+
32+ JsonValue instance = Json .parse ("true" );
33+
34+ LOG .info (() -> "Testing ref schema - nested ref" );
35+ LOG .fine (() -> "Schema: " + schema );
36+ LOG .fine (() -> "Instance: " + instance );
37+
38+ Jtd validator = new Jtd ();
39+ Jtd .Result result = validator .validate (schema , instance );
40+
41+ LOG .fine (() -> "Validation result: " + (result .isValid () ? "VALID" : "INVALID" ));
42+ if (!result .isValid ()) {
43+ LOG .severe (() -> "ERRORS: " + result .errors ());
44+ }
45+
46+ // This should be valid according to RFC 8927
47+ assertThat (result .isValid ())
48+ .as ("Nested ref should resolve correctly" )
49+ .isTrue ();
50+ }
51+
52+ /// Test ref schema with recursive definitions
53+ /// "ref schema - recursive schema, ok" from JTD specification test suite
54+ /// Should handle recursive ref to self in elements schema
55+ @ Test
56+ public void testRefSchemaRecursive () throws Exception {
57+ // Schema with recursive ref: root references itself in elements
58+ JsonValue schema = Json .parse ("""
59+ {
60+ "definitions": {
61+ "root": {
62+ "elements": {
63+ "ref": "root"
64+ }
65+ }
66+ },
67+ "ref": "root"
68+ }
69+ """ );
70+
71+ JsonValue instance = Json .parse ("[]" );
72+
73+ LOG .info (() -> "Testing ref schema - recursive schema, ok" );
74+ LOG .fine (() -> "Schema: " + schema );
75+ LOG .fine (() -> "Instance: " + instance );
76+
77+ Jtd validator = new Jtd ();
78+ Jtd .Result result = validator .validate (schema , instance );
79+
80+ LOG .fine (() -> "Validation result: " + (result .isValid () ? "VALID" : "INVALID" ));
81+ if (!result .isValid ()) {
82+ LOG .severe (() -> "ERRORS: " + result .errors ());
83+ }
84+
85+ // This should be valid according to RFC 8927
86+ assertThat (result .isValid ())
87+ .as ("Recursive ref should resolve correctly" )
88+ .isTrue ();
89+ }
90+
91+ /// Test timestamp with leap second
92+ /// "timestamp type schema - 1990-12-31T23:59:60Z" from JTD specification test suite
93+ /// Should accept valid RFC 3339 timestamp with leap second
94+ @ Test
95+ public void testTimestampWithLeapSecond () throws Exception {
96+ JsonValue schema = Json .parse ("""
97+ {
98+ "type": "timestamp"
99+ }
100+ """ );
101+
102+ JsonValue instance = Json .parse ("\" 1990-12-31T23:59:60Z\" " );
103+
104+ LOG .info (() -> "Testing timestamp type schema - 1990-12-31T23:59:60Z" );
105+ LOG .fine (() -> "Schema: " + schema );
106+ LOG .fine (() -> "Instance: " + instance );
107+
108+ Jtd validator = new Jtd ();
109+ Jtd .Result result = validator .validate (schema , instance );
110+
111+ LOG .fine (() -> "Validation result: " + (result .isValid () ? "VALID" : "INVALID" ));
112+ if (!result .isValid ()) {
113+ LOG .severe (() -> "ERRORS: " + result .errors ());
114+ }
115+
116+ // This should be valid according to RFC 8927 (leap second support)
117+ assertThat (result .isValid ())
118+ .as ("Timestamp with leap second should be valid RFC 3339" )
119+ .isTrue ();
120+ }
121+
122+ /// Test timestamp with timezone offset
123+ /// "timestamp type schema - 1990-12-31T15:59:60-08:00" from JTD specification test suite
124+ /// Should accept valid RFC 3339 timestamp with timezone offset
125+ @ Test
126+ public void testTimestampWithTimezone () throws Exception {
127+ JsonValue schema = Json .parse ("""
128+ {
129+ "type": "timestamp"
130+ }
131+ """ );
132+
133+ JsonValue instance = Json .parse ("\" 1990-12-31T15:59:60-08:00\" " );
134+
135+ LOG .info (() -> "Testing timestamp type schema - 1990-12-31T15:59:60-08:00" );
136+ LOG .fine (() -> "Schema: " + schema );
137+ LOG .fine (() -> "Instance: " + instance );
138+
139+ Jtd validator = new Jtd ();
140+ Jtd .Result result = validator .validate (schema , instance );
141+
142+ LOG .fine (() -> "Validation result: " + (result .isValid () ? "VALID" : "INVALID" ));
143+ if (!result .isValid ()) {
144+ LOG .severe (() -> "ERRORS: " + result .errors ());
145+ }
146+
147+ // This should be valid according to RFC 8927 (timezone support)
148+ assertThat (result .isValid ())
149+ .as ("Timestamp with timezone offset should be valid RFC 3339" )
150+ .isTrue ();
151+ }
152+
153+ /// Test strict properties validation
154+ /// "strict properties - bad additional property" from JTD specification test suite
155+ /// Should reject object with additional property not in schema
156+ @ Test
157+ public void testStrictPropertiesBadAdditionalProperty () throws Exception {
158+ JsonValue schema = Json .parse ("""
159+ {
160+ "properties": {
161+ "foo": {
162+ "type": "string"
163+ }
164+ }
165+ }
166+ """ );
167+
168+ JsonValue instance = Json .parse ("""
169+ {
170+ "foo": "foo",
171+ "bar": "bar"
172+ }
173+ """ );
174+
175+ LOG .info (() -> "Testing strict properties - bad additional property" );
176+ LOG .fine (() -> "Schema: " + schema );
177+ LOG .fine (() -> "Instance: " + instance );
178+
179+ Jtd validator = new Jtd ();
180+ Jtd .Result result = validator .validate (schema , instance );
181+
182+ LOG .fine (() -> "Validation result: " + (result .isValid () ? "VALID" : "INVALID" ));
183+ if (!result .isValid ()) {
184+ LOG .fine (() -> "ERRORS: " + result .errors ());
185+ }
186+
187+ // This should be invalid according to RFC 8927 (strict by default)
188+ assertThat (result .isValid ())
189+ .as ("Object with additional property should be rejected in strict mode" )
190+ .isFalse ();
191+
192+ // Should have error about the additional property
193+ assertThat (result .errors ())
194+ .isNotEmpty ()
195+ .anySatisfy (error -> assertThat (error ).contains ("bar" ));
196+ }
197+
198+ /// Test strict optional properties validation
199+ /// "strict optionalProperties - bad additional property" from JTD specification test suite
200+ /// Should reject object with additional property not in optionalProperties
201+ @ Test
202+ public void testStrictOptionalPropertiesBadAdditionalProperty () throws Exception {
203+ JsonValue schema = Json .parse ("""
204+ {
205+ "optionalProperties": {
206+ "foo": {
207+ "type": "string"
208+ }
209+ }
210+ }
211+ """ );
212+
213+ JsonValue instance = Json .parse ("""
214+ {
215+ "foo": "foo",
216+ "bar": "bar"
217+ }
218+ """ );
219+
220+ LOG .info (() -> "Testing strict optionalProperties - bad additional property" );
221+ LOG .fine (() -> "Schema: " + schema );
222+ LOG .fine (() -> "Instance: " + instance );
223+
224+ Jtd validator = new Jtd ();
225+ Jtd .Result result = validator .validate (schema , instance );
226+
227+ LOG .fine (() -> "Validation result: " + (result .isValid () ? "VALID" : "INVALID" ));
228+ if (!result .isValid ()) {
229+ LOG .fine (() -> "ERRORS: " + result .errors ());
230+ }
231+
232+ // This should be invalid according to RFC 8927 (strict by default)
233+ assertThat (result .isValid ())
234+ .as ("Object with additional property should be rejected in strict mode" )
235+ .isFalse ();
236+
237+ // Should have error about the additional property
238+ assertThat (result .errors ())
239+ .isNotEmpty ()
240+ .anySatisfy (error -> assertThat (error ).contains ("bar" ));
241+ }
242+
243+ /// Test strict mixed properties validation
244+ /// "strict mixed properties and optionalProperties - bad additional property" from JTD specification test suite
245+ /// Should reject object with additional property not in properties or optionalProperties
246+ @ Test
247+ public void testStrictMixedPropertiesBadAdditionalProperty () throws Exception {
248+ JsonValue schema = Json .parse ("""
249+ {
250+ "properties": {
251+ "foo": {
252+ "type": "string"
253+ }
254+ },
255+ "optionalProperties": {
256+ "bar": {
257+ "type": "string"
258+ }
259+ }
260+ }
261+ """ );
262+
263+ JsonValue instance = Json .parse ("""
264+ {
265+ "foo": "foo",
266+ "bar": "bar",
267+ "baz": "baz"
268+ }
269+ """ );
270+
271+ LOG .info (() -> "Testing strict mixed properties and optionalProperties - bad additional property" );
272+ LOG .fine (() -> "Schema: " + schema );
273+ LOG .fine (() -> "Instance: " + instance );
274+
275+ Jtd validator = new Jtd ();
276+ Jtd .Result result = validator .validate (schema , instance );
277+
278+ LOG .fine (() -> "Validation result: " + (result .isValid () ? "VALID" : "INVALID" ));
279+ if (!result .isValid ()) {
280+ LOG .fine (() -> "ERRORS: " + result .errors ());
281+ }
282+
283+ // This should be invalid according to RFC 8927 (strict by default)
284+ assertThat (result .isValid ())
285+ .as ("Object with additional property should be rejected in strict mode" )
286+ .isFalse ();
287+
288+ // Should have error about the additional property
289+ assertThat (result .errors ())
290+ .isNotEmpty ()
291+ .anySatisfy (error -> assertThat (error ).contains ("baz" ));
292+ }
293+ }
0 commit comments