1- // Copyright (c) Microsoft Corporation. All rights reserved.
1+ // Copyright (c) Microsoft Corporation. All rights reserved.
22// Licensed under the MIT license.
33
44using System . Collections . Generic ;
@@ -133,7 +133,11 @@ public async Task SerializeSchemaReferenceAsV31JsonWorks(bool produceTerseOutput
133133 WriteOnly = false ,
134134 Deprecated = true ,
135135 Default = JsonValue . Create ( "reference default" ) ,
136- Examples = new List < JsonNode > { JsonValue . Create ( "reference example" ) }
136+ Examples = new List < JsonNode > { JsonValue . Create ( "reference example" ) } ,
137+ Extensions = new Dictionary < string , IOpenApiExtension >
138+ {
139+ [ "x-custom" ] = new JsonNodeExtension ( JsonValue . Create ( "custom value" ) )
140+ }
137141 } ;
138142
139143 var outputStringWriter = new StringWriter ( CultureInfo . InvariantCulture ) ;
@@ -152,7 +156,7 @@ public async Task SerializeSchemaReferenceAsV31JsonWorks(bool produceTerseOutput
152156 [ InlineData ( false ) ]
153157 public async Task SerializeSchemaReferenceAsV3JsonWorks ( bool produceTerseOutput )
154158 {
155- // Arrange
159+ // Arrange - Extensions should NOT appear in v3.0 output
156160 var reference = new OpenApiSchemaReference ( "Pet" , null )
157161 {
158162 Title = "Reference Title" ,
@@ -161,7 +165,11 @@ public async Task SerializeSchemaReferenceAsV3JsonWorks(bool produceTerseOutput)
161165 WriteOnly = false ,
162166 Deprecated = true ,
163167 Default = JsonValue . Create ( "reference default" ) ,
164- Examples = new List < JsonNode > { JsonValue . Create ( "reference example" ) }
168+ Examples = new List < JsonNode > { JsonValue . Create ( "reference example" ) } ,
169+ Extensions = new Dictionary < string , IOpenApiExtension >
170+ {
171+ [ "x-custom" ] = new JsonNodeExtension ( JsonValue . Create ( "custom value" ) )
172+ }
165173 } ;
166174
167175 var outputStringWriter = new StringWriter ( CultureInfo . InvariantCulture ) ;
@@ -175,6 +183,38 @@ public async Task SerializeSchemaReferenceAsV3JsonWorks(bool produceTerseOutput)
175183 await Verifier . Verify ( outputStringWriter ) . UseParameters ( produceTerseOutput ) ;
176184 }
177185
186+ [ Theory ]
187+ [ InlineData ( true ) ]
188+ [ InlineData ( false ) ]
189+ public async Task SerializeSchemaReferenceAsV2JsonWorks ( bool produceTerseOutput )
190+ {
191+ // Arrange - Extensions should NOT appear in v2 output
192+ var reference = new OpenApiSchemaReference ( "Pet" , null )
193+ {
194+ Title = "Reference Title" ,
195+ Description = "Reference Description" ,
196+ ReadOnly = true ,
197+ WriteOnly = false ,
198+ Deprecated = true ,
199+ Default = JsonValue . Create ( "reference default" ) ,
200+ Examples = new List < JsonNode > { JsonValue . Create ( "reference example" ) } ,
201+ Extensions = new Dictionary < string , IOpenApiExtension >
202+ {
203+ [ "x-custom" ] = new JsonNodeExtension ( JsonValue . Create ( "custom value" ) )
204+ }
205+ } ;
206+
207+ var outputStringWriter = new StringWriter ( CultureInfo . InvariantCulture ) ;
208+ var writer = new OpenApiJsonWriter ( outputStringWriter , new OpenApiJsonWriterSettings { Terse = produceTerseOutput } ) ;
209+
210+ // Act
211+ reference . SerializeAsV2 ( writer ) ;
212+ await writer . FlushAsync ( ) ;
213+
214+ // Assert
215+ await Verifier . Verify ( outputStringWriter ) . UseParameters ( produceTerseOutput ) ;
216+ }
217+
178218 [ Fact ]
179219 public void ParseSchemaReferenceWithAnnotationsWorks ( )
180220 {
@@ -256,5 +296,120 @@ public void ParseSchemaReferenceWithAnnotationsWorks()
256296 Assert . Equal ( "Original Pet Title" , targetSchema . Title ) ;
257297 Assert . Equal ( "Original Pet Description" , targetSchema . Description ) ;
258298 }
299+
300+ [ Fact ]
301+ public void ParseSchemaReferenceWithExtensionsWorks ( )
302+ {
303+ // Arrange
304+ var jsonContent = @"{
305+ ""openapi"": ""3.1.0"",
306+ ""info"": {
307+ ""title"": ""Test API"",
308+ ""version"": ""1.0.0""
309+ },
310+ ""paths"": {
311+ ""/test"": {
312+ ""get"": {
313+ ""responses"": {
314+ ""200"": {
315+ ""description"": ""OK"",
316+ ""content"": {
317+ ""application/json"": {
318+ ""schema"": {
319+ ""$ref"": ""#/components/schemas/Pet"",
320+ ""description"": ""A pet object"",
321+ ""x-custom-extension"": ""custom value"",
322+ ""x-another-extension"": 42
323+ }
324+ }
325+ }
326+ }
327+ }
328+ }
329+ }
330+ },
331+ ""components"": {
332+ ""schemas"": {
333+ ""Pet"": {
334+ ""type"": ""object"",
335+ ""properties"": {
336+ ""name"": {
337+ ""type"": ""string""
338+ }
339+ }
340+ }
341+ }
342+ }
343+ }" ;
344+
345+ // Act
346+ var readResult = OpenApiDocument . Parse ( jsonContent , "json" ) ;
347+ var document = readResult . Document ;
348+
349+ // Assert
350+ Assert . NotNull ( document ) ;
351+ Assert . Empty ( readResult . Diagnostic . Errors ) ;
352+
353+ var schema = document . Paths [ "/test" ] . Operations [ HttpMethod . Get ]
354+ . Responses [ "200" ] . Content [ "application/json" ] . Schema ;
355+
356+ Assert . IsType < OpenApiSchemaReference > ( schema ) ;
357+ var schemaRef = ( OpenApiSchemaReference ) schema ;
358+
359+ // Test that reference-level extensions are parsed
360+ Assert . NotNull ( schemaRef . Extensions ) ;
361+ Assert . Contains ( "x-custom-extension" , schemaRef . Extensions . Keys ) ;
362+ Assert . Contains ( "x-another-extension" , schemaRef . Extensions . Keys ) ;
363+ }
364+
365+ [ Fact ]
366+ public async Task SchemaReferenceExtensionsNotWrittenInV30 ( )
367+ {
368+ // Arrange
369+ var reference = new OpenApiSchemaReference ( "Pet" , null )
370+ {
371+ Description = "Local description" ,
372+ Extensions = new Dictionary < string , IOpenApiExtension >
373+ {
374+ [ "x-custom" ] = new JsonNodeExtension ( JsonValue . Create ( "custom value" ) )
375+ }
376+ } ;
377+
378+ var outputStringWriter = new StringWriter ( CultureInfo . InvariantCulture ) ;
379+ var writer = new OpenApiJsonWriter ( outputStringWriter , new OpenApiJsonWriterSettings { Terse = true } ) ;
380+
381+ // Act
382+ reference . SerializeAsV3 ( writer ) ;
383+ await writer . FlushAsync ( ) ;
384+ var output = outputStringWriter . ToString ( ) ;
385+
386+ // Assert: In v3.0, ONLY $ref should appear - no description, no extensions
387+ Assert . Equal ( @"{""$ref"":""#/components/schemas/Pet""}" , output ) ;
388+ }
389+
390+ [ Fact ]
391+ public async Task SchemaReferenceExtensionsNotWrittenInV2 ( )
392+ {
393+ // Arrange
394+ var reference = new OpenApiSchemaReference ( "Pet" , null )
395+ {
396+ Description = "Local description" ,
397+ Extensions = new Dictionary < string , IOpenApiExtension >
398+ {
399+ [ "x-custom" ] = new JsonNodeExtension ( JsonValue . Create ( "custom value" ) )
400+ }
401+ } ;
402+
403+ var outputStringWriter = new StringWriter ( CultureInfo . InvariantCulture ) ;
404+ var writer = new OpenApiJsonWriter ( outputStringWriter , new OpenApiJsonWriterSettings { Terse = true } ) ;
405+
406+ // Act
407+ reference . SerializeAsV2 ( writer ) ;
408+ await writer . FlushAsync ( ) ;
409+ var output = outputStringWriter . ToString ( ) ;
410+
411+ // Assert: In v2, ONLY $ref should appear - no description, no extensions
412+ Assert . Equal ( @"{""$ref"":""#/definitions/Pet""}" , output ) ;
413+ }
259414 }
260415}
0 commit comments