@@ -31,6 +31,16 @@ def test_null(self, schema_type):
3131 with pytest .raises (ValidationError ):
3232 validator .validate (value )
3333
34+ @pytest .mark .parametrize ("is_nullable" , [True , False ])
35+ def test_nullable_untyped (self , is_nullable ):
36+ schema = {"nullable" : is_nullable }
37+ validator = OAS30Validator (schema )
38+ value = None
39+
40+ result = validator .validate (value )
41+
42+ assert result is None
43+
3444 @pytest .mark .parametrize (
3545 "schema_type" ,
3646 [
@@ -50,6 +60,23 @@ def test_nullable(self, schema_type):
5060
5161 assert result is None
5262
63+ def test_nullable_enum_without_none (self ):
64+ schema = {"type" : "integer" , "nullable" : True , "enum" : [1 , 2 , 3 ]}
65+ validator = OAS30Validator (schema )
66+ value = None
67+
68+ with pytest .raises (ValidationError ):
69+ validator .validate (value )
70+
71+ def test_nullable_enum_with_none (self ):
72+ schema = {"type" : "integer" , "nullable" : True , "enum" : [1 , 2 , 3 , None ]}
73+ validator = OAS30Validator (schema )
74+ value = None
75+
76+ result = validator .validate (value )
77+
78+ assert result is None
79+
5380 @pytest .mark .parametrize (
5481 "value" ,
5582 [
@@ -442,6 +469,103 @@ def test_oneof_discriminator(self, schema_type):
442469 result = validator .validate ({"discipline" : "other" })
443470 assert False
444471
472+ @pytest .mark .parametrize ("is_nullable" , [True , False ])
473+ def test_nullable_ref (self , is_nullable ):
474+ """
475+ Tests that a field that points to a schema reference is null checked based on the $ref schema rather than
476+ on this schema
477+ :param is_nullable: if the schema is marked as nullable. If not, validate an exception is raised on None
478+ """
479+ schema = {
480+ "$ref" : "#/$defs/Pet" ,
481+ "$defs" : {
482+ "NullableText" : {
483+ "type" : "string" ,
484+ "nullable" : is_nullable
485+ },
486+ "Pet" : {
487+ "properties" : {
488+ "testfield" : {"$ref" : "#/$defs/NullableText" },
489+ },
490+ }
491+ },
492+ }
493+ validator = OAS30Validator (
494+ schema ,
495+ format_checker = oas30_format_checker ,
496+ )
497+
498+ result = validator .validate ({"testfield" : "John" })
499+ assert result is None
500+
501+ if is_nullable :
502+ result = validator .validate ({"testfield" : None })
503+ assert result is None
504+ else :
505+ with pytest .raises (
506+ ValidationError ,
507+ match = "None for not nullable" ,
508+ ):
509+ validator .validate ({"testfield" : None })
510+ assert False
511+
512+
513+ @pytest .mark .parametrize (
514+ "schema_type, not_nullable_regex" ,
515+ [
516+ ("oneOf" , "None is not valid under any of the given schemas" ),
517+ ("anyOf" , "None is not valid under any of the given schemas" ),
518+ ("allOf" , "None for not nullable" )
519+ ],
520+ )
521+ @pytest .mark .parametrize ("is_nullable" , [True , False ])
522+ def test_nullable_schema_combos (self , is_nullable , schema_type , not_nullable_regex ):
523+ """
524+ This test ensures that nullablilty semantics are correct for oneOf, anyOf and allOf
525+ Specifically, nullable should checked on the children schemas
526+ :param is_nullable: if the schema is marked as nullable. If not, validate an exception is raised on None
527+ :param schema_type: the schema type to validate
528+ :param not_nullable_regex: the expected raised exception if fields are marked as not nullable
529+ """
530+ schema = {
531+ "$ref" : "#/$defs/Pet" ,
532+ "$defs" : {
533+ "NullableText" : {
534+ "type" : "string" ,
535+ "nullable" : False if schema_type == "oneOf" else is_nullable
536+ },
537+ "NullableEnum" : {
538+ "type" : "string" ,
539+ "nullable" : is_nullable ,
540+ "enum" : ["John" , "Alice" , None ]
541+ },
542+ "Pet" : {
543+ "properties" : {
544+ "testfield" : {
545+ schema_type : [
546+ {"$ref" : "#/$defs/NullableText" },
547+ {"$ref" : "#/$defs/NullableEnum" },
548+ ]
549+ }
550+ },
551+ }
552+ },
553+ }
554+ validator = OAS30Validator (
555+ schema ,
556+ format_checker = oas30_format_checker ,
557+ )
558+
559+ if is_nullable :
560+ result = validator .validate ({"testfield" : None })
561+ assert result is None
562+ else :
563+ with pytest .raises (
564+ ValidationError ,
565+ match = not_nullable_regex
566+ ):
567+ validator .validate ({"testfield" : None })
568+ assert False
445569
446570class TestOAS31ValidatorValidate :
447571 @pytest .mark .parametrize (
0 commit comments