@@ -464,6 +464,188 @@ await VerifyOpenApiDocument(builder, document =>
464464 } ) ;
465465 }
466466
467+ [ Fact ]
468+ public async Task GetOpenApiRequestBody_HandlesNullableParameterWithAllOf ( )
469+ {
470+ // Arrange
471+ var builder = CreateBuilder ( ) ;
472+
473+ // Act
474+ #nullable enable
475+ builder . MapPost ( "/api/nullable-todo" , ( Todo ? todo ) => { } ) ;
476+ builder . MapPost ( "/api/nullable-point" , ( Point ? point ) => { } ) ;
477+ #nullable restore
478+
479+ // Assert
480+ await VerifyOpenApiDocument ( builder , document =>
481+ {
482+ // Verify nullable Todo parameter
483+ var todoOperation = document . Paths [ "/api/nullable-todo" ] . Operations [ HttpMethod . Post ] ;
484+ var todoRequestBody = todoOperation . RequestBody ;
485+ var todoContent = Assert . Single ( todoRequestBody . Content ) ;
486+ Assert . Equal ( "application/json" , todoContent . Key ) ;
487+ var todoSchema = todoContent . Value . Schema ;
488+ Assert . NotNull ( todoSchema . AllOf ) ;
489+ Assert . Equal ( 2 , todoSchema . AllOf . Count ) ;
490+ Assert . Collection ( todoSchema . AllOf ,
491+ item =>
492+ {
493+ Assert . NotNull ( item ) ;
494+ Assert . Equal ( JsonSchemaType . Null , item . Type ) ;
495+ } ,
496+ item =>
497+ {
498+ Assert . NotNull ( item ) ;
499+ Assert . Equal ( JsonSchemaType . Object , item . Type ) ;
500+ Assert . Collection ( item . Properties ,
501+ property =>
502+ {
503+ Assert . Equal ( "id" , property . Key ) ;
504+ Assert . Equal ( JsonSchemaType . Integer , property . Value . Type ) ;
505+ Assert . Equal ( "int32" , property . Value . Format ) ;
506+ } ,
507+ property =>
508+ {
509+ Assert . Equal ( "title" , property . Key ) ;
510+ Assert . Equal ( JsonSchemaType . String | JsonSchemaType . Null , property . Value . Type ) ;
511+ } ,
512+ property =>
513+ {
514+ Assert . Equal ( "completed" , property . Key ) ;
515+ Assert . Equal ( JsonSchemaType . Boolean , property . Value . Type ) ;
516+ } ,
517+ property =>
518+ {
519+ Assert . Equal ( "createdAt" , property . Key ) ;
520+ Assert . Equal ( JsonSchemaType . String , property . Value . Type ) ;
521+ Assert . Equal ( "date-time" , property . Value . Format ) ;
522+ } ) ;
523+ } ) ;
524+
525+ // Verify nullable Point parameter
526+ var pointOperation = document . Paths [ "/api/nullable-point" ] . Operations [ HttpMethod . Post ] ;
527+ var pointRequestBody = pointOperation . RequestBody ;
528+ var pointContent = Assert . Single ( pointRequestBody . Content ) ;
529+ Assert . Equal ( "application/json" , pointContent . Key ) ;
530+ var pointSchema = pointContent . Value . Schema ;
531+ Assert . NotNull ( pointSchema . AllOf ) ;
532+ Assert . Equal ( 2 , pointSchema . AllOf . Count ) ;
533+ Assert . Collection ( pointSchema . AllOf ,
534+ item =>
535+ {
536+ Assert . NotNull ( item ) ;
537+ Assert . Equal ( JsonSchemaType . Null , item . Type ) ;
538+ } ,
539+ item =>
540+ {
541+ Assert . NotNull ( item ) ;
542+ Assert . Equal ( JsonSchemaType . Object , item . Type ) ;
543+ Assert . Collection ( item . Properties ,
544+ property =>
545+ {
546+ Assert . Equal ( "x" , property . Key ) ;
547+ Assert . Equal ( JsonSchemaType . Integer , property . Value . Type ) ;
548+ Assert . Equal ( "int32" , property . Value . Format ) ;
549+ } ,
550+ property =>
551+ {
552+ Assert . Equal ( "y" , property . Key ) ;
553+ Assert . Equal ( JsonSchemaType . Integer , property . Value . Type ) ;
554+ Assert . Equal ( "int32" , property . Value . Format ) ;
555+ } ) ;
556+ } ) ;
557+
558+ Assert . Equal ( [ "Point" , "Todo" ] , [ .. document . Components . Schemas . Keys ] ) ;
559+ Assert . Collection ( document . Components . Schemas . Values ,
560+ item => Assert . Equal ( JsonSchemaType . Object , item . Type ) ,
561+ item => Assert . Equal ( JsonSchemaType . Object , item . Type ) ) ;
562+ } ) ;
563+ }
564+
565+ [ Fact ]
566+ public async Task GetOpenApiRequestBody_HandlesNullableCollectionParametersWithAllOf ( )
567+ {
568+ // Arrange
569+ var builder = CreateBuilder ( ) ;
570+
571+ // Act
572+ #nullable enable
573+ builder . MapPost ( "/api/nullable-array" , ( Todo [ ] ? todos ) => { } ) ;
574+ builder . MapPost ( "/api/nullable-list" , ( List < Todo > ? todoList ) => { } ) ;
575+ builder . MapPost ( "/api/nullable-enumerable" , ( IEnumerable < Todo > ? todoEnumerable ) => { } ) ;
576+ #nullable restore
577+
578+ // Assert
579+ await VerifyOpenApiDocument ( builder , document =>
580+ {
581+ // Verify nullable array parameter - verify actual behavior with AllOf
582+ var arrayOperation = document . Paths [ "/api/nullable-array" ] . Operations [ HttpMethod . Post ] ;
583+ var arrayRequestBody = arrayOperation . RequestBody ;
584+ var arrayContent = Assert . Single ( arrayRequestBody . Content ) ;
585+ Assert . Equal ( "application/json" , arrayContent . Key ) ;
586+ var arraySchema = arrayContent . Value . Schema ;
587+ Assert . NotNull ( arraySchema . AllOf ) ; // AllOf IS used for nullable collections
588+ Assert . Equal ( 2 , arraySchema . AllOf . Count ) ;
589+ Assert . Collection ( arraySchema . AllOf ,
590+ item =>
591+ {
592+ Assert . NotNull ( item ) ;
593+ Assert . Equal ( JsonSchemaType . Null , item . Type ) ;
594+ } ,
595+ item =>
596+ {
597+ Assert . NotNull ( item ) ;
598+ Assert . Equal ( JsonSchemaType . Array , item . Type ) ;
599+ Assert . NotNull ( item . Items ) ;
600+ Assert . Equal ( "Todo" , ( ( OpenApiSchemaReference ) item . Items ) . Reference . Id ) ;
601+ } ) ;
602+
603+ // Verify nullable List parameter - verify actual behavior with AllOf
604+ var listOperation = document . Paths [ "/api/nullable-list" ] . Operations [ HttpMethod . Post ] ;
605+ var listRequestBody = listOperation . RequestBody ;
606+ var listContent = Assert . Single ( listRequestBody . Content ) ;
607+ Assert . Equal ( "application/json" , listContent . Key ) ;
608+ var listSchema = listContent . Value . Schema ;
609+ Assert . NotNull ( listSchema . AllOf ) ; // AllOf IS used for nullable collections
610+ Assert . Equal ( 2 , listSchema . AllOf . Count ) ;
611+ Assert . Collection ( listSchema . AllOf ,
612+ item =>
613+ {
614+ Assert . NotNull ( item ) ;
615+ Assert . Equal ( JsonSchemaType . Null , item . Type ) ;
616+ } ,
617+ item =>
618+ {
619+ Assert . NotNull ( item ) ;
620+ Assert . Equal ( JsonSchemaType . Array , item . Type ) ;
621+ Assert . NotNull ( item . Items ) ;
622+ Assert . Equal ( "Todo" , ( ( OpenApiSchemaReference ) item . Items ) . Reference . Id ) ;
623+ } ) ;
624+
625+ // Verify nullable IEnumerable parameter - verify actual behavior with AllOf
626+ var enumerableOperation = document . Paths [ "/api/nullable-enumerable" ] . Operations [ HttpMethod . Post ] ;
627+ var enumerableRequestBody = enumerableOperation . RequestBody ;
628+ var enumerableContent = Assert . Single ( enumerableRequestBody . Content ) ;
629+ Assert . Equal ( "application/json" , enumerableContent . Key ) ;
630+ var enumerableSchema = enumerableContent . Value . Schema ;
631+ Assert . NotNull ( enumerableSchema . AllOf ) ; // AllOf IS used for nullable collections
632+ Assert . Equal ( 2 , enumerableSchema . AllOf . Count ) ;
633+ Assert . Collection ( enumerableSchema . AllOf ,
634+ item =>
635+ {
636+ Assert . NotNull ( item ) ;
637+ Assert . Equal ( JsonSchemaType . Null , item . Type ) ;
638+ } ,
639+ item =>
640+ {
641+ Assert . NotNull ( item ) ;
642+ Assert . Equal ( JsonSchemaType . Array , item . Type ) ;
643+ Assert . NotNull ( item . Items ) ;
644+ Assert . Equal ( "Todo" , ( ( OpenApiSchemaReference ) item . Items ) . Reference . Id ) ;
645+ } ) ;
646+ } ) ;
647+ }
648+
467649 [ Fact ]
468650 public async Task SupportsNestedTypes ( )
469651 {
0 commit comments