@@ -1004,6 +1004,115 @@ await VerifyOpenApiDocument(builder, document =>
10041004 } ) ;
10051005 }
10061006
1007+ // Test for: https://github.com/dotnet/aspnetcore/issues/63503
1008+ [ Fact ]
1009+ public async Task HandlesCircularReferencesRegardlessOfPropertyOrder_SelfFirst ( )
1010+ {
1011+ var builder = CreateBuilder ( ) ;
1012+ builder . MapPost ( "/" , ( DirectCircularModelSelfFirst dto ) => { } ) ;
1013+
1014+ // Assert
1015+ await VerifyOpenApiDocument ( builder , document =>
1016+ {
1017+ var schema = document . Components . Schemas [ "DirectCircularModelSelfFirst" ] ;
1018+ Assert . Equal ( JsonSchemaType . Object , schema . Type ) ;
1019+ Assert . Collection ( schema . Properties ,
1020+ property =>
1021+ {
1022+ Assert . Equal ( "self" , property . Key ) ;
1023+ var reference = Assert . IsType < OpenApiSchemaReference > ( property . Value ) ;
1024+ Assert . Equal ( "#/components/schemas/DirectCircularModelSelfFirst" , reference . Reference . ReferenceV3 ) ;
1025+ } ,
1026+ property =>
1027+ {
1028+ Assert . Equal ( "referenced" , property . Key ) ;
1029+ var reference = Assert . IsType < OpenApiSchemaReference > ( property . Value ) ;
1030+ } ) ;
1031+
1032+ // Verify that it does not result in an empty schema for a referenced schema
1033+ var referencedSchema = document . Components . Schemas [ "ReferencedModel" ] ;
1034+ Assert . NotEmpty ( referencedSchema . Properties ) ;
1035+ var idProperty = Assert . Single ( referencedSchema . Properties ) ;
1036+ Assert . Equal ( "id" , idProperty . Key ) ;
1037+ var idPropertySchema = Assert . IsType < OpenApiSchema > ( idProperty . Value ) ;
1038+ Assert . Equal ( JsonSchemaType . Integer , idPropertySchema . Type ) ;
1039+ } ) ;
1040+ }
1041+
1042+ // Test for: https://github.com/dotnet/aspnetcore/issues/63503
1043+ [ Fact ]
1044+ public async Task HandlesCircularReferencesRegardlessOfPropertyOrder_SelfLast ( )
1045+ {
1046+ var builder = CreateBuilder ( ) ;
1047+ builder . MapPost ( "/" , ( DirectCircularModelSelfLast dto ) => { } ) ;
1048+
1049+ await VerifyOpenApiDocument ( builder , document =>
1050+ {
1051+ var schema = document . Components . Schemas [ "DirectCircularModelSelfLast" ] ;
1052+ Assert . Equal ( JsonSchemaType . Object , schema . Type ) ;
1053+ Assert . Collection ( schema . Properties ,
1054+ property =>
1055+ {
1056+ Assert . Equal ( "referenced" , property . Key ) ;
1057+ var reference = Assert . IsType < OpenApiSchemaReference > ( property . Value ) ;
1058+ } ,
1059+ property =>
1060+ {
1061+ Assert . Equal ( "self" , property . Key ) ;
1062+ var reference = Assert . IsType < OpenApiSchemaReference > ( property . Value ) ;
1063+ Assert . Equal ( "#/components/schemas/DirectCircularModelSelfLast" , reference . Reference . ReferenceV3 ) ;
1064+ } ) ;
1065+
1066+ // Verify that it does not result in an empty schema for a referenced schema
1067+ var referencedSchema = document . Components . Schemas [ "ReferencedModel" ] ;
1068+ Assert . NotEmpty ( referencedSchema . Properties ) ;
1069+ var idProperty = Assert . Single ( referencedSchema . Properties ) ;
1070+ Assert . Equal ( "id" , idProperty . Key ) ;
1071+ var idPropertySchema = Assert . IsType < OpenApiSchema > ( idProperty . Value ) ;
1072+ Assert . Equal ( JsonSchemaType . Integer , idPropertySchema . Type ) ;
1073+ } ) ;
1074+ }
1075+
1076+ // Test for: https://github.com/dotnet/aspnetcore/issues/63503
1077+ [ Fact ]
1078+ public async Task HandlesCircularReferencesRegardlessOfPropertyOrder_MultipleSelf ( )
1079+ {
1080+ var builder = CreateBuilder ( ) ;
1081+ builder . MapPost ( "/" , ( DirectCircularModelMultiple dto ) => { } ) ;
1082+
1083+ await VerifyOpenApiDocument ( builder , document =>
1084+ {
1085+ var schema = document . Components . Schemas [ "DirectCircularModelMultiple" ] ;
1086+ Assert . Equal ( JsonSchemaType . Object , schema . Type ) ;
1087+ Assert . Collection ( schema . Properties ,
1088+ property =>
1089+ {
1090+ Assert . Equal ( "selfFirst" , property . Key ) ;
1091+ var reference = Assert . IsType < OpenApiSchemaReference > ( property . Value ) ;
1092+ Assert . Equal ( "#/components/schemas/DirectCircularModelMultiple" , reference . Reference . ReferenceV3 ) ;
1093+ } ,
1094+ property =>
1095+ {
1096+ Assert . Equal ( "referenced" , property . Key ) ;
1097+ var reference = Assert . IsType < OpenApiSchemaReference > ( property . Value ) ;
1098+ } ,
1099+ property =>
1100+ {
1101+ Assert . Equal ( "selfLast" , property . Key ) ;
1102+ var reference = Assert . IsType < OpenApiSchemaReference > ( property . Value ) ;
1103+ Assert . Equal ( "#/components/schemas/DirectCircularModelMultiple" , reference . Reference . ReferenceV3 ) ;
1104+ } ) ;
1105+
1106+ // Verify that it does not result in an empty schema for a referenced schema
1107+ var referencedSchema = document . Components . Schemas [ "ReferencedModel" ] ;
1108+ Assert . NotEmpty ( referencedSchema . Properties ) ;
1109+ var idProperty = Assert . Single ( referencedSchema . Properties ) ;
1110+ Assert . Equal ( "id" , idProperty . Key ) ;
1111+ var idPropertySchema = Assert . IsType < OpenApiSchema > ( idProperty . Value ) ;
1112+ Assert . Equal ( JsonSchemaType . Integer , idPropertySchema . Type ) ;
1113+ } ) ;
1114+ }
1115+
10071116 // Test models for issue 61194
10081117 private class Config
10091118 {
@@ -1060,5 +1169,30 @@ public sealed class RefUser
10601169 public string Name { get ; set ; } = "" ;
10611170 public string Email { get ; set ; } = "" ;
10621171 }
1172+
1173+ // Test models for issue 63503
1174+ private class DirectCircularModelSelfFirst
1175+ {
1176+ public DirectCircularModelSelfFirst Self { get ; set ; } = null ! ;
1177+ public ReferencedModel Referenced { get ; set ; } = null ! ;
1178+ }
1179+
1180+ private class DirectCircularModelSelfLast
1181+ {
1182+ public ReferencedModel Referenced { get ; set ; } = null ! ;
1183+ public DirectCircularModelSelfLast Self { get ; set ; } = null ! ;
1184+ }
1185+
1186+ private class DirectCircularModelMultiple
1187+ {
1188+ public DirectCircularModelMultiple SelfFirst { get ; set ; } = null ! ;
1189+ public ReferencedModel Referenced { get ; set ; } = null ! ;
1190+ public DirectCircularModelMultiple SelfLast { get ; set ; } = null ! ;
1191+ }
1192+
1193+ private class ReferencedModel
1194+ {
1195+ public int Id { get ; set ; }
1196+ }
10631197}
10641198#nullable restore
0 commit comments