@@ -413,6 +413,148 @@ func TestValidate_WhitespaceSchemaName_OAS3(t *testing.T) {
413413 assert .True (t , foundError , "Should have error about whitespace-only schema name" )
414414}
415415
416+ // ========================================
417+ // Schema Type "null" Validation Tests (OAS 3.0 vs 3.1+)
418+ // ========================================
419+
420+ // TestValidate_NullType_OAS30_Rejected verifies that schemas declaring
421+ // type: "null" are rejected in OAS 3.0.x, where the only valid types are
422+ // array, boolean, integer, number, object, string. Nullability in 3.0 is
423+ // expressed via "nullable: true". See issue #362.
424+ func TestValidate_NullType_OAS30_Rejected (t * testing.T ) {
425+ tests := []struct {
426+ name string
427+ version string
428+ oasVersion parser.OASVersion
429+ }{
430+ {"OAS 3.0.0" , "3.0.0" , parser .OASVersion300 },
431+ {"OAS 3.0.1" , "3.0.1" , parser .OASVersion301 },
432+ {"OAS 3.0.2" , "3.0.2" , parser .OASVersion302 },
433+ {"OAS 3.0.3" , "3.0.3" , parser .OASVersion303 },
434+ {"OAS 3.0.4" , "3.0.4" , parser .OASVersion304 },
435+ }
436+
437+ for _ , tt := range tests {
438+ t .Run (tt .name , func (t * testing.T ) {
439+ doc := & parser.OAS3Document {
440+ OpenAPI : tt .version ,
441+ Info : & parser.Info {
442+ Title : "Test API" ,
443+ Version : "1.0.0" ,
444+ },
445+ Paths : map [string ]* parser.PathItem {},
446+ Components : & parser.Components {
447+ Schemas : map [string ]* parser.Schema {
448+ "BadNull" : {
449+ Type : "null" ,
450+ },
451+ },
452+ },
453+ }
454+
455+ parseResult := & parser.ParseResult {
456+ Version : tt .version ,
457+ OASVersion : tt .oasVersion ,
458+ Document : doc ,
459+ }
460+
461+ v := New ()
462+ result , err := v .ValidateParsed (* parseResult )
463+ require .NoError (t , err )
464+
465+ foundNullTypeError := false
466+ for _ , e := range result .Errors {
467+ if strings .Contains (e .Path , "components.schemas.BadNull" ) &&
468+ strings .Contains (e .Message , `"null" is not a valid type for OpenAPI 3.0` ) {
469+ foundNullTypeError = true
470+ assert .Equal (t , "type" , e .Field , "Error should set Field to 'type'" )
471+ assert .Equal (t , "null" , e .Value , "Error should set Value to 'null'" )
472+ assert .Contains (t , e .SpecRef , "spec.openapis.org/oas/v3.0.0.html#data-types" ,
473+ "Error should reference OAS 3.0 data-types spec section" )
474+ break
475+ }
476+ }
477+ assert .True (t , foundNullTypeError ,
478+ "Expected error about 'null' not being a valid OAS 3.0 type, got errors: %v" ,
479+ result .Errors )
480+ assert .False (t , result .Valid , "Document should be invalid" )
481+ })
482+ }
483+ }
484+
485+ // TestValidate_NullType_OAS31_Allowed verifies that schemas declaring
486+ // type: "null" are accepted in OAS 3.1+ (JSON Schema 2020-12).
487+ func TestValidate_NullType_OAS31_Allowed (t * testing.T ) {
488+ doc := & parser.OAS3Document {
489+ OpenAPI : "3.1.0" ,
490+ Info : & parser.Info {
491+ Title : "Test API" ,
492+ Version : "1.0.0" ,
493+ },
494+ Paths : map [string ]* parser.PathItem {},
495+ Components : & parser.Components {
496+ Schemas : map [string ]* parser.Schema {
497+ "NullSchema" : {
498+ Type : "null" ,
499+ },
500+ },
501+ },
502+ }
503+
504+ parseResult := & parser.ParseResult {
505+ Version : "3.1.0" ,
506+ OASVersion : parser .OASVersion310 ,
507+ Document : doc ,
508+ }
509+
510+ v := New ()
511+ result , err := v .ValidateParsed (* parseResult )
512+ require .NoError (t , err )
513+
514+ // No error about "null" being invalid should be present under OAS 3.1.
515+ for _ , e := range result .Errors {
516+ if strings .Contains (e .Message , `"null" is not a valid type for OpenAPI 3.0` ) {
517+ t .Errorf ("Unexpected OAS 3.0 null-type error under OAS 3.1: %s" , e .String ())
518+ }
519+ }
520+ }
521+
522+ // TestValidate_StringType_OAS30_Allowed is a regression guard ensuring that
523+ // the OAS 3.0 null-type rejection does not flag other legitimate types.
524+ func TestValidate_StringType_OAS30_Allowed (t * testing.T ) {
525+ doc := & parser.OAS3Document {
526+ OpenAPI : "3.0.0" ,
527+ Info : & parser.Info {
528+ Title : "Test API" ,
529+ Version : "1.0.0" ,
530+ },
531+ Paths : map [string ]* parser.PathItem {},
532+ Components : & parser.Components {
533+ Schemas : map [string ]* parser.Schema {
534+ "Plain" : {
535+ Type : "string" ,
536+ },
537+ },
538+ },
539+ }
540+
541+ parseResult := & parser.ParseResult {
542+ Version : "3.0.0" ,
543+ OASVersion : parser .OASVersion300 ,
544+ Document : doc ,
545+ }
546+
547+ v := New ()
548+ result , err := v .ValidateParsed (* parseResult )
549+ require .NoError (t , err )
550+
551+ for _ , e := range result .Errors {
552+ if strings .Contains (e .Path , "components.schemas.Plain" ) {
553+ t .Errorf ("Unexpected error for valid string schema under OAS 3.0: %s" , e .String ())
554+ }
555+ }
556+ }
557+
416558// TestValidate_ValidSchemaNames tests that valid schema names pass validation
417559func TestValidate_ValidSchemaNames (t * testing.T ) {
418560 tests := []struct {
0 commit comments