@@ -72,6 +72,53 @@ def test_if_the_most_relevant_error_is_anyOf_it_is_traversed(self):
7272 best = self .best_match_of (instance = {"foo" : {"bar" : 12 }}, schema = schema )
7373 self .assertEqual (best .validator_value , "array" )
7474
75+ def test_anyOf_traversal_for_single_shallower_errors_better_match (self ):
76+ """
77+ Traverse the context of an anyOf error with the only subschema,
78+ and select the most relevant error.
79+ """
80+
81+ schema = {
82+ "anyOf" : [
83+ {
84+ "properties" : {
85+ "foo" : {
86+ "minProperties" : 2 ,
87+ "properties" : {"bar" : {"type" : "object" }},
88+ },
89+ },
90+ },
91+ ],
92+ }
93+ best = self .best_match_of (instance = {"foo" : {"bar" : []}}, schema = schema )
94+ self .assertEqual (best .validator , "minProperties" )
95+
96+ def test_anyOf_traversal_least_relevant_among_most_relevant_errors (self ):
97+ """
98+ Traverse the context of an anyOf error, and select
99+ the *least* relevant error among the most relevant errors
100+ in each separate subschema.
101+
102+ I.e. since only one of the schemas must match, we look for the most
103+ specific one, and choose the most relevant error produced by it.
104+ """
105+
106+ schema = {
107+ "anyOf" : [
108+ {"type" : "string" },
109+ {
110+ "properties" : {
111+ "foo" : {
112+ "minProperties" : 2 ,
113+ "properties" : {"bar" : {"type" : "object" }},
114+ },
115+ },
116+ },
117+ ],
118+ }
119+ best = self .best_match_of (instance = {"foo" : {"bar" : []}}, schema = schema )
120+ self .assertEqual (best .validator , "minProperties" )
121+
75122 def test_no_anyOf_traversal_for_equally_relevant_errors (self ):
76123 """
77124 We don't traverse into an anyOf (as above) if all of its context errors
@@ -88,6 +135,53 @@ def test_no_anyOf_traversal_for_equally_relevant_errors(self):
88135 best = self .best_match_of (instance = [], schema = schema )
89136 self .assertEqual (best .validator , "anyOf" )
90137
138+ def test_no_anyOf_traversal_for_two_properties_sibling_errors (self ):
139+ """
140+ We don't traverse into an anyOf if all of its context errors
141+ seem to be equally "wrong" against the instance.
142+ """
143+
144+ schema = {
145+ "anyOf" : [
146+ {"properties" : {"foo" : {"type" : "string" }}},
147+ {"properties" : {"bar" : {"type" : "string" }}},
148+ ],
149+ }
150+ best = self .best_match_of (instance = {"foo" : 1 , "bar" : 1 }, schema = schema )
151+ self .assertEqual (best .validator , "anyOf" )
152+
153+ def test_no_anyOf_traversal_for_two_items_sibling_errors (self ):
154+ """
155+ We don't traverse into an anyOf if all of its context errors
156+ seem to be equally "wrong" against the instance.
157+ """
158+
159+ schema = {
160+ "anyOf" : [
161+ {
162+ "type" : "array" ,
163+ "items" : {
164+ "$ref" : "#/$defs/int_array" ,
165+ },
166+ },
167+ {
168+ "$ref" : "#/$defs/int_array" ,
169+ },
170+ ],
171+ "$defs" : {
172+ "int_array" : {
173+ "type" : "array" ,
174+ "items" : {
175+ "type" : "integer" ,
176+ },
177+ },
178+ },
179+ }
180+ best = self .best_match_of (instance = ["not an int" , 0 ], schema = schema )
181+ self .assertEqual (best .validator , "anyOf" )
182+ best = self .best_match_of (instance = [0 , "not an int" ], schema = schema )
183+ self .assertEqual (best .validator , "anyOf" )
184+
91185 def test_anyOf_traversal_for_single_equally_relevant_error (self ):
92186 """
93187 We *do* traverse anyOf with a single nested error, even though it is
@@ -102,7 +196,7 @@ def test_anyOf_traversal_for_single_equally_relevant_error(self):
102196 best = self .best_match_of (instance = [], schema = schema )
103197 self .assertEqual (best .validator , "type" )
104198
105- def test_anyOf_traversal_for_single_sibling_errors (self ):
199+ def test_anyOf_traversal_for_single_sibling_errors_choose_first (self ):
106200 """
107201 We *do* traverse anyOf with a single subschema that fails multiple
108202 times (e.g. on multiple items).
@@ -113,8 +207,9 @@ def test_anyOf_traversal_for_single_sibling_errors(self):
113207 {"items" : {"const" : 37 }},
114208 ],
115209 }
116- best = self .best_match_of (instance = [12 , 12 ], schema = schema )
210+ best = self .best_match_of (instance = [12 , 13 ], schema = schema )
117211 self .assertEqual (best .validator , "const" )
212+ self .assertEqual (best .instance , 12 )
118213
119214 def test_anyOf_traversal_for_non_type_matching_sibling_errors (self ):
120215 """
@@ -154,6 +249,53 @@ def test_if_the_most_relevant_error_is_oneOf_it_is_traversed(self):
154249 best = self .best_match_of (instance = {"foo" : {"bar" : 12 }}, schema = schema )
155250 self .assertEqual (best .validator_value , "array" )
156251
252+ def test_oneOf_traversal_for_single_shallower_errors_better_match (self ):
253+ """
254+ Traverse the context of an oneOf error with the only subschema,
255+ and select the most relevant error.
256+ """
257+
258+ schema = {
259+ "oneOf" : [
260+ {
261+ "properties" : {
262+ "foo" : {
263+ "minProperties" : 2 ,
264+ "properties" : {"bar" : {"type" : "object" }},
265+ },
266+ },
267+ },
268+ ],
269+ }
270+ best = self .best_match_of (instance = {"foo" : {"bar" : []}}, schema = schema )
271+ self .assertEqual (best .validator , "minProperties" )
272+
273+ def test_oneOf_traversal_least_relevant_among_most_relevant_errors (self ):
274+ """
275+ Traverse the context of an oneOf error, and select
276+ the *least* relevant error among the most relevant errors
277+ in each separate subschema.
278+
279+ I.e. since only one of the schemas must match, we look for the most
280+ specific one, and choose the most relevant error produced by it.
281+ """
282+
283+ schema = {
284+ "oneOf" : [
285+ {"type" : "string" },
286+ {
287+ "properties" : {
288+ "foo" : {
289+ "minProperties" : 2 ,
290+ "properties" : {"bar" : {"type" : "object" }},
291+ },
292+ },
293+ },
294+ ],
295+ }
296+ best = self .best_match_of (instance = {"foo" : {"bar" : []}}, schema = schema )
297+ self .assertEqual (best .validator , "minProperties" )
298+
157299 def test_no_oneOf_traversal_for_equally_relevant_errors (self ):
158300 """
159301 We don't traverse into an oneOf (as above) if all of its context errors
@@ -170,6 +312,53 @@ def test_no_oneOf_traversal_for_equally_relevant_errors(self):
170312 best = self .best_match_of (instance = [], schema = schema )
171313 self .assertEqual (best .validator , "oneOf" )
172314
315+ def test_no_oneOf_traversal_for_two_properties_sibling_errors (self ):
316+ """
317+ We don't traverse into an oneOf if all of its context errors
318+ seem to be equally "wrong" against the instance.
319+ """
320+
321+ schema = {
322+ "oneOf" : [
323+ {"properties" : {"foo" : {"type" : "string" }}},
324+ {"properties" : {"bar" : {"type" : "string" }}},
325+ ],
326+ }
327+ best = self .best_match_of (instance = {"foo" : 1 , "bar" : 1 }, schema = schema )
328+ self .assertEqual (best .validator , "oneOf" )
329+
330+ def test_no_oneOf_traversal_for_two_items_sibling_errors (self ):
331+ """
332+ We don't traverse into an anyOf if all of its context errors
333+ seem to be equally "wrong" against the instance.
334+ """
335+
336+ schema = {
337+ "oneOf" : [
338+ {
339+ "type" : "array" ,
340+ "items" : {
341+ "$ref" : "#/$defs/int_array" ,
342+ },
343+ },
344+ {
345+ "$ref" : "#/$defs/int_array" ,
346+ },
347+ ],
348+ "$defs" : {
349+ "int_array" : {
350+ "type" : "array" ,
351+ "items" : {
352+ "type" : "integer" ,
353+ },
354+ },
355+ },
356+ }
357+ best = self .best_match_of (instance = ["not an int" , 0 ], schema = schema )
358+ self .assertEqual (best .validator , "oneOf" )
359+ best = self .best_match_of (instance = [0 , "not an int" ], schema = schema )
360+ self .assertEqual (best .validator , "oneOf" )
361+
173362 def test_oneOf_traversal_for_single_equally_relevant_error (self ):
174363 """
175364 We *do* traverse oneOf with a single nested error, even though it is
@@ -184,7 +373,7 @@ def test_oneOf_traversal_for_single_equally_relevant_error(self):
184373 best = self .best_match_of (instance = [], schema = schema )
185374 self .assertEqual (best .validator , "type" )
186375
187- def test_oneOf_traversal_for_single_sibling_errors (self ):
376+ def test_oneOf_traversal_for_single_sibling_errors_choose_first (self ):
188377 """
189378 We *do* traverse oneOf with a single subschema that fails multiple
190379 times (e.g. on multiple items).
@@ -195,8 +384,9 @@ def test_oneOf_traversal_for_single_sibling_errors(self):
195384 {"items" : {"const" : 37 }},
196385 ],
197386 }
198- best = self .best_match_of (instance = [12 , 12 ], schema = schema )
387+ best = self .best_match_of (instance = [12 , 13 ], schema = schema )
199388 self .assertEqual (best .validator , "const" )
389+ self .assertEqual (best .instance , 12 )
200390
201391 def test_oneOf_traversal_for_non_type_matching_sibling_errors (self ):
202392 """
0 commit comments