Skip to content

Commit 089124b

Browse files
Add remaining OpenAPI tests
1 parent 1d2e277 commit 089124b

File tree

7 files changed

+392
-3
lines changed

7 files changed

+392
-3
lines changed

src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/Transformers/ApiExplorerTransformer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ private void UpdateDescriptionToMarkdown(
157157

158158
if ( !string.IsNullOrEmpty( notice ) )
159159
{
160-
if ( description[^1] != '.' )
160+
if ( description.Length > 0 && description[^1] != '.' )
161161
{
162162
description.Append( '.' );
163163
}
@@ -172,7 +172,7 @@ private void UpdateDescriptionToMarkdown(
172172

173173
if ( !string.IsNullOrEmpty( notice ) )
174174
{
175-
if ( description[^1] != '.' )
175+
if ( description.Length > 0 && description[^1] != '.' )
176176
{
177177
description.Append( '.' );
178178
}

src/AspNetCore/WebApi/test/Asp.Versioning.OpenApi.Tests/Asp.Versioning.OpenApi.Tests.csproj

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,40 @@
33
<PropertyGroup>
44
<TargetFramework>$(DefaultTargetFramework)</TargetFramework>
55
<RootNamespace>Asp.Versioning.OpenApi</RootNamespace>
6+
<AssemblyTitle>Test API</AssemblyTitle>
7+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
68
</PropertyGroup>
79

810
<ItemGroup>
9-
<ProjectReference Include="..\..\src\Asp.Versioning.OpenApi\Asp.Versioning.OpenApi.csproj" />
11+
<ProjectReference Include="..\..\src\Asp.Versioning.OpenApi\Asp.Versioning.OpenApi.csproj" />
1012
</ItemGroup>
1113

14+
<ItemGroup>
15+
<GeneratedFile Include="$(BaseIntermediateOutputPath)FilePath.g.cs" />
16+
</ItemGroup>
17+
18+
<ItemGroup>
19+
<Compile Include="@(GeneratedFile)" Visible="false" />
20+
</ItemGroup>
21+
22+
<ItemGroup>
23+
<None Include="Content\**\*.*" CopyToOutputDirectory="Always" />
24+
</ItemGroup>
25+
26+
<Target Name="GenerateFilePaths" BeforeTargets="Compile" Condition=" '$(DesignTimeBuild)' == 'true' OR '$(BuildingProject)' == 'true' ">
27+
28+
<ItemGroup>
29+
<Code Include="namespace $(RootNamespace)%3B" />
30+
<Code Include="%20" />
31+
<Code Include="/// &lt;summary&gt;Provides file paths generated by the current project. This class was code-generated.&lt;/summary&gt;" />
32+
<Code Include="internal static class FilePath" />
33+
<Code Include="{" />
34+
<Code Include="%20%20%20%20public const string XmlCommentFile = @&quot;$(MSBuildProjectDirectory)\$(OutputPath)$(AssemblyName).xml&quot;%3B" />
35+
<Code Include="}" />
36+
</ItemGroup>
37+
38+
<WriteLinesToFile File="@(GeneratedFile)" Lines="@(Code)" Overwrite="true" />
39+
40+
</Target>
41+
1242
</Project>
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
{
2+
"openapi": "3.1.1",
3+
"info": {
4+
"title": "Test API | v1",
5+
"description": " The API will be sunset on 2/10/2026.\r\n\r\n### Links\r\n\r\n- [Versioning Policy](policy.html)\r\n",
6+
"version": "1.0"
7+
},
8+
"servers": [
9+
{
10+
"url": "http://localhost/"
11+
}
12+
],
13+
"paths": {
14+
"/Test": {
15+
"get": {
16+
"tags": [
17+
"Test"
18+
],
19+
"summary": "",
20+
"description": "",
21+
"parameters": [
22+
{
23+
"name": "id",
24+
"in": "query",
25+
"description": "",
26+
"schema": {
27+
"pattern": "^-?(?:0|[1-9]\\d*)$",
28+
"type": [
29+
"integer",
30+
"string"
31+
],
32+
"format": "int32"
33+
}
34+
},
35+
{
36+
"name": "api-version",
37+
"in": "query",
38+
"description": "The requested API version",
39+
"required": true,
40+
"schema": {
41+
"type": "string",
42+
"default": "1.0"
43+
}
44+
}
45+
],
46+
"responses": {
47+
"200": {
48+
"description": "OK",
49+
"content": {
50+
"text/plain": {
51+
"schema": {
52+
"pattern": "^-?(?:0|[1-9]\\d*)$",
53+
"type": [
54+
"integer",
55+
"string"
56+
],
57+
"format": "int32"
58+
}
59+
},
60+
"application/json": {
61+
"schema": {
62+
"pattern": "^-?(?:0|[1-9]\\d*)$",
63+
"type": [
64+
"integer",
65+
"string"
66+
],
67+
"format": "int32"
68+
}
69+
},
70+
"text/json": {
71+
"schema": {
72+
"pattern": "^-?(?:0|[1-9]\\d*)$",
73+
"type": [
74+
"integer",
75+
"string"
76+
],
77+
"format": "int32"
78+
}
79+
}
80+
}
81+
}
82+
}
83+
}
84+
}
85+
},
86+
"tags": [
87+
{
88+
"name": "Test"
89+
}
90+
],
91+
"x-api-versioning": [
92+
{
93+
"title": "Versioning Policy",
94+
"type": "text/html",
95+
"rel": "sunset",
96+
"url": "policy.html"
97+
}
98+
]
99+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
3+
#pragma warning disable SA1629
4+
5+
namespace Asp.Versioning.OpenApi.Simulators;
6+
7+
public static class MinimalApi
8+
{
9+
/// <summary>
10+
/// Test
11+
/// </summary>
12+
/// <description>A test API.</description>
13+
/// <param name="id">A test parameter.</param>
14+
/// <returns>The original identifier.</returns>
15+
/// <response code="200">Pass</response>
16+
/// <response code="400">Fail</response>
17+
public static int Get( int id ) => id;
18+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
3+
#pragma warning disable CA1822
4+
#pragma warning disable SA1629
5+
6+
namespace Asp.Versioning.OpenApi.Simulators;
7+
8+
using Microsoft.AspNetCore.Mvc;
9+
10+
[ApiVersion( 1.0 )]
11+
[ApiController]
12+
[Route( "[controller]" )]
13+
public class TestController : ControllerBase
14+
{
15+
/// <summary>
16+
/// Test
17+
/// </summary>
18+
/// <description>A test API.</description>
19+
/// <param name="id">A test parameter.</param>
20+
/// <returns>The original identifier.</returns>
21+
/// <response code="200">Pass</response>
22+
/// <response code="400">Fail</response>
23+
[HttpGet]
24+
public int Get( int id ) => id;
25+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
3+
namespace Asp.Versioning.OpenApi.Transformers;
4+
5+
using Asp.Versioning.OpenApi.Simulators;
6+
using Microsoft.AspNetCore.Builder;
7+
using Microsoft.AspNetCore.Http;
8+
using Microsoft.AspNetCore.TestHost;
9+
using Microsoft.Extensions.DependencyInjection;
10+
using System.Collections.Generic;
11+
using System.Net.Http.Json;
12+
using System.Text.Json.Nodes;
13+
14+
public class AcceptanceTest
15+
{
16+
[Fact]
17+
public async Task minimal_api_should_generate_expected_open_api_document()
18+
{
19+
// arrange
20+
var builder = WebApplication.CreateBuilder();
21+
22+
builder.WebHost.UseTestServer();
23+
builder.Services.AddControllers()
24+
.AddApplicationPart( GetType().Assembly );
25+
builder.Services.AddApiVersioning( options => AddSunsetPolicy( options ) )
26+
.AddMvc()
27+
.AddApiExplorer( options => options.GroupNameFormat = "'v'VVV" )
28+
.AddOpenApi();
29+
30+
var app = builder.Build();
31+
var api = app.NewVersionedApi( "Test" )
32+
.MapGroup( "/test" )
33+
.HasApiVersion( 1.0 );
34+
35+
api.MapGet( "{id:int}", MinimalApi.Get ).Produces<int>().Produces( 400 );
36+
app.MapOpenApi().WithDocumentPerVersion();
37+
38+
var cancellationToken = TestContext.Current.CancellationToken;
39+
using var stream = File.OpenRead( Path.Combine( AppContext.BaseDirectory, "Content", "v1.json" ) );
40+
var expected = await JsonNode.ParseAsync( stream, default, default, cancellationToken );
41+
42+
await app.StartAsync( cancellationToken );
43+
44+
using var client = app.GetTestClient();
45+
46+
// act
47+
var actual = await client.GetFromJsonAsync<JsonNode>( "/openapi/v1.json", cancellationToken );
48+
49+
// assert
50+
JsonNode.DeepEquals( actual, expected ).Should().BeTrue();
51+
}
52+
53+
[Fact]
54+
public async Task controller_should_generate_expected_open_api_document()
55+
{
56+
// arrange
57+
var builder = WebApplication.CreateBuilder();
58+
59+
builder.WebHost.UseTestServer();
60+
builder.Services.AddControllers()
61+
.AddApplicationPart( GetType().Assembly );
62+
builder.Services.AddApiVersioning( options => AddSunsetPolicy( options ) )
63+
.AddMvc()
64+
.AddApiExplorer( options => options.GroupNameFormat = "'v'VVV" )
65+
.AddOpenApi();
66+
67+
var app = builder.Build();
68+
69+
app.MapControllers();
70+
app.MapOpenApi().WithDocumentPerVersion();
71+
72+
var cancellationToken = TestContext.Current.CancellationToken;
73+
using var stream = File.OpenRead( Path.Combine( AppContext.BaseDirectory, "Content", "v1.json" ) );
74+
var expected = await JsonNode.ParseAsync( stream, default, default, cancellationToken );
75+
76+
await app.StartAsync( cancellationToken );
77+
78+
using var client = app.GetTestClient();
79+
80+
// act
81+
var actual = await client.GetFromJsonAsync<JsonNode>( "/openapi/v1.json", cancellationToken );
82+
83+
// assert
84+
JsonNode.DeepEquals( actual, expected ).Should().BeTrue();
85+
}
86+
87+
private static ApiVersioningOptions AddSunsetPolicy( ApiVersioningOptions options )
88+
{
89+
options.Policies.Sunset( 1.0 )
90+
.Effective( 2026, 2, 10 )
91+
.Link( "policy.html" )
92+
.Title( "Versioning Policy" )
93+
.Type( "text/html" );
94+
95+
return options;
96+
}
97+
}

0 commit comments

Comments
 (0)