Skip to content

Commit b65bbe5

Browse files
baywetCopilot
andcommitted
test(coverage): add reader and walker edge tests
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent b8ad022 commit b65bbe5

8 files changed

Lines changed: 827 additions & 0 deletions

File tree

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#nullable enable
2+
using System;
3+
using Microsoft.OpenApi.Hidi;
4+
using Xunit;
5+
6+
namespace Microsoft.OpenApi.Hidi.Tests;
7+
8+
public class OpenApiSpecVersionHelperTests
9+
{
10+
[Theory]
11+
[InlineData("2.0", OpenApiSpecVersion.OpenApi2_0)]
12+
[InlineData("3.0", OpenApiSpecVersion.OpenApi3_0)]
13+
[InlineData("3.1", OpenApiSpecVersion.OpenApi3_1)]
14+
[InlineData("3.2", OpenApiSpecVersion.OpenApi3_2)]
15+
[InlineData("4.0", OpenApiSpecVersion.OpenApi3_2)]
16+
public void TryParseOpenApiSpecVersionReturnsExpectedVersion(string version, OpenApiSpecVersion expectedVersion)
17+
{
18+
var result = OpenApiSpecVersionHelper.TryParseOpenApiSpecVersion(version);
19+
20+
Assert.Equal(expectedVersion, result);
21+
}
22+
23+
[Theory]
24+
[InlineData(null)]
25+
[InlineData("")]
26+
[InlineData("abc")]
27+
public void TryParseOpenApiSpecVersionThrowsForInvalidValues(string? version)
28+
{
29+
Assert.Throws<InvalidOperationException>(() => OpenApiSpecVersionHelper.TryParseOpenApiSpecVersion(version!));
30+
}
31+
}

test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiFilterServiceTests.cs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,72 @@ public void ThrowsInvalidOperationExceptionInCreatePredicateWhenInvalidArguments
221221
Assert.Equal("Cannot specify both operationIds and tags at the same time.", message2);
222222
}
223223

224+
[Fact]
225+
public void ThrowsInvalidOperationExceptionWhenRequestUrlsAreCombinedWithOtherFilters()
226+
{
227+
var requestUrls = new Dictionary<string, List<string>>
228+
{
229+
["/users"] = ["GET"]
230+
};
231+
232+
var message = Assert.Throws<InvalidOperationException>(() =>
233+
OpenApiFilterService.CreatePredicate("users.user.ListUser", null, requestUrls, _openApiDocumentMock)).Message;
234+
235+
Assert.Equal("Cannot filter by Postman collection and either operationIds and tags at the same time.", message);
236+
}
237+
238+
[Fact]
239+
public void ThrowsWhenPredicateDoesNotMatchAnyPath()
240+
{
241+
var source = new OpenApiDocument
242+
{
243+
Info = new() { Title = "Test", Version = "1.0" },
244+
Paths = new()
245+
{
246+
["/test"] = new OpenApiPathItem
247+
{
248+
Operations = new()
249+
{
250+
[HttpMethod.Get] = new OpenApiOperation { OperationId = "getTest" }
251+
}
252+
}
253+
}
254+
};
255+
256+
var subset = OpenApiFilterService.CreateFilteredDocument(source, static (_, _, _) => false);
257+
258+
Assert.Empty(subset.Paths);
259+
}
260+
261+
[Fact]
262+
public void CreatePredicateMatchesAbsoluteUrlsWhenSourceHasNoServers()
263+
{
264+
var source = new OpenApiDocument
265+
{
266+
Info = new() { Title = "Test", Version = "v1" },
267+
Paths = new()
268+
{
269+
["/users"] = new OpenApiPathItem
270+
{
271+
Operations = new()
272+
{
273+
[HttpMethod.Get] = new OpenApiOperation { OperationId = "listUsers" }
274+
}
275+
}
276+
}
277+
};
278+
var requestUrls = new Dictionary<string, List<string>>
279+
{
280+
["https://graph.contoso.com/users"] = ["GET"]
281+
};
282+
283+
var predicate = OpenApiFilterService.CreatePredicate(requestUrls: requestUrls, source: source);
284+
var subset = OpenApiFilterService.CreateFilteredDocument(source, predicate);
285+
286+
Assert.Single(subset.Paths);
287+
Assert.True(subset.Paths.ContainsKey("/users"));
288+
}
289+
224290
[Fact]
225291
public async Task CopiesOverAllReferencedComponentsToTheSubsetDocumentCorrectly()
226292
{
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Net.Http;
4+
using Xunit;
5+
6+
namespace Microsoft.OpenApi.Hidi.Tests;
7+
8+
public class StatsVisitorTests
9+
{
10+
[Fact]
11+
public void GetStatisticsReportReflectsVisitedElements()
12+
{
13+
var document = new OpenApiDocument
14+
{
15+
Paths = new()
16+
{
17+
["/pets"] = new OpenApiPathItem
18+
{
19+
Operations = new()
20+
{
21+
[HttpMethod.Post] = new OpenApiOperation
22+
{
23+
Parameters =
24+
[
25+
new OpenApiParameter
26+
{
27+
Name = "expand",
28+
In = ParameterLocation.Query,
29+
Schema = new OpenApiSchema { Type = JsonSchemaType.String }
30+
}
31+
],
32+
RequestBody = new OpenApiRequestBody
33+
{
34+
Content = new Dictionary<string, IOpenApiMediaType>
35+
{
36+
["application/json"] = new OpenApiMediaType
37+
{
38+
Schema = new OpenApiSchema
39+
{
40+
Type = JsonSchemaType.Object,
41+
Properties = new Dictionary<string, IOpenApiSchema>
42+
{
43+
["name"] = new OpenApiSchema { Type = JsonSchemaType.String }
44+
}
45+
}
46+
}
47+
}
48+
},
49+
Responses = new OpenApiResponses
50+
{
51+
["200"] = new OpenApiResponse
52+
{
53+
Headers = new Dictionary<string, IOpenApiHeader>
54+
{
55+
["x-rate-limit"] = new OpenApiHeader
56+
{
57+
Schema = new OpenApiSchema { Type = JsonSchemaType.Integer }
58+
}
59+
},
60+
Links = new Dictionary<string, IOpenApiLink>
61+
{
62+
["next"] = new OpenApiLink()
63+
}
64+
}
65+
},
66+
Callbacks = new Dictionary<string, IOpenApiCallback>
67+
{
68+
["onData"] = new OpenApiCallback
69+
{
70+
PathItems = new Dictionary<RuntimeExpression, IOpenApiPathItem>
71+
{
72+
[RuntimeExpression.Build("$request.body#/callbackUrl")] = new OpenApiPathItem
73+
{
74+
Operations = new()
75+
{
76+
[HttpMethod.Post] = new OpenApiOperation
77+
{
78+
Responses = new OpenApiResponses
79+
{
80+
["202"] = new OpenApiResponse { Description = "Accepted" }
81+
}
82+
}
83+
}
84+
}
85+
}
86+
}
87+
}
88+
}
89+
}
90+
}
91+
}
92+
};
93+
94+
var visitor = new StatsVisitor();
95+
new OpenApiWalker(visitor).Walk(document);
96+
var report = visitor.GetStatisticsReport();
97+
98+
Assert.Equal(2, visitor.PathItemCount);
99+
Assert.Equal(2, visitor.OperationCount);
100+
Assert.Equal(1, visitor.ParameterCount);
101+
Assert.Equal(1, visitor.RequestBodyCount);
102+
Assert.Equal(2, visitor.ResponseCount);
103+
Assert.Equal(1, visitor.LinkCount);
104+
Assert.Equal(1, visitor.CallbackCount);
105+
Assert.Equal(4, visitor.SchemaCount);
106+
Assert.Contains("Path Items: 2", report, StringComparison.Ordinal);
107+
Assert.Contains("Callbacks: 1", report, StringComparison.Ordinal);
108+
Assert.Contains("Schemas: 4", report, StringComparison.Ordinal);
109+
}
110+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using Microsoft.Extensions.Configuration;
4+
using Microsoft.OpenApi.Hidi.Utilities;
5+
using Microsoft.OpenApi.OData;
6+
using Xunit;
7+
8+
namespace Microsoft.OpenApi.Hidi.Tests;
9+
10+
public class SettingsUtilitiesTests
11+
{
12+
[Fact]
13+
public void GetOpenApiConvertSettingsThrowsWhenConfigurationIsNull()
14+
{
15+
Assert.Throws<ArgumentNullException>(() => SettingsUtilities.GetOpenApiConvertSettings(null!, null));
16+
}
17+
18+
[Fact]
19+
public void GetOpenApiConvertSettingsUsesMetadataVersionWhenSectionIsMissing()
20+
{
21+
var configuration = new ConfigurationBuilder().AddInMemoryCollection(new Dictionary<string, string?>()).Build();
22+
23+
var settings = SettingsUtilities.GetOpenApiConvertSettings(configuration, "2.1");
24+
25+
Assert.Equal("2.1", settings.SemVerVersion);
26+
}
27+
28+
[Fact]
29+
public void GetOpenApiConvertSettingsBindsConfiguredValuesOverMetadataVersion()
30+
{
31+
var configuration = new ConfigurationBuilder()
32+
.AddInMemoryCollection(new Dictionary<string, string?>
33+
{
34+
[$"{nameof(OpenApiConvertSettings)}:{nameof(OpenApiConvertSettings.SemVerVersion)}"] = "3.0",
35+
[$"{nameof(OpenApiConvertSettings)}:{nameof(OpenApiConvertSettings.EnablePagination)}"] = bool.TrueString
36+
})
37+
.Build();
38+
39+
var settings = SettingsUtilities.GetOpenApiConvertSettings(configuration, "2.1");
40+
41+
Assert.Equal("3.0", settings.SemVerVersion);
42+
Assert.True(settings.EnablePagination);
43+
}
44+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
using System;
2+
using System.IO;
3+
using System.Net.Http;
4+
using System.Text;
5+
using Microsoft.OpenApi.Reader;
6+
using Microsoft.OpenApi.YamlReader;
7+
using Xunit;
8+
9+
namespace Microsoft.OpenApi.Readers.Tests.V2Tests;
10+
11+
public class OpenApiDocumentFixupTests
12+
{
13+
private static readonly Uri DocumentLocation = new("https://contoso.test/swagger.yaml");
14+
15+
[Fact]
16+
public void ReadCreatesServersFromHostBasePathAndSchemes()
17+
{
18+
var result = ReadDocument(
19+
"""
20+
swagger: "2.0"
21+
info:
22+
title: Sample API
23+
version: "1.0"
24+
host: api.contoso.com:443
25+
basePath: /v1/
26+
schemes:
27+
- https
28+
paths: {}
29+
""");
30+
31+
Assert.NotNull(result.Document);
32+
Assert.Empty(result.Diagnostic.Errors);
33+
var server = Assert.Single(result.Document.Servers);
34+
Assert.Equal("https://api.contoso.com/v1", server.Url);
35+
}
36+
37+
[Theory]
38+
[InlineData("https://api.contoso.com")]
39+
[InlineData("api contoso com")]
40+
public void ReadAddsDiagnosticErrorWhenHostIsInvalid(string host)
41+
{
42+
var result = ReadDocument(
43+
$$"""
44+
swagger: "2.0"
45+
info:
46+
title: Sample API
47+
version: "1.0"
48+
host: {{host}}
49+
paths: {}
50+
""");
51+
52+
Assert.NotNull(result.Document);
53+
var error = Assert.Single(result.Diagnostic.Errors);
54+
Assert.Contains("Invalid host", error.Message, StringComparison.Ordinal);
55+
Assert.Empty(result.Document.Servers);
56+
}
57+
58+
[Fact]
59+
public void ReadMovesReferencedBodyParametersToRequestBodies()
60+
{
61+
var result = ReadDocument(
62+
"""
63+
swagger: "2.0"
64+
info:
65+
title: Sample API
66+
version: "1.0"
67+
paths:
68+
/pets:
69+
post:
70+
parameters:
71+
- $ref: '#/parameters/PetBody'
72+
responses:
73+
'200':
74+
description: ok
75+
parameters:
76+
PetBody:
77+
name: pet
78+
in: body
79+
required: true
80+
schema:
81+
type: object
82+
properties:
83+
name:
84+
type: string
85+
""");
86+
87+
Assert.NotNull(result.Document);
88+
Assert.Empty(result.Diagnostic.Errors);
89+
var requestBody = Assert.IsType<OpenApiRequestBodyReference>(result.Document.Paths["/pets"].Operations[HttpMethod.Post].RequestBody);
90+
Assert.Equal("PetBody", requestBody.Reference.Id);
91+
Assert.NotNull(result.Document.Components);
92+
var componentRequestBody = Assert.IsType<OpenApiRequestBody>(result.Document.Components.RequestBodies["PetBody"]);
93+
Assert.True(componentRequestBody.Required);
94+
Assert.Contains("application/json", componentRequestBody.Content.Keys);
95+
Assert.Empty(result.Document.Paths["/pets"].Operations[HttpMethod.Post].Parameters);
96+
}
97+
98+
private static ReadResult ReadDocument(string yaml)
99+
{
100+
var settings = new OpenApiReaderSettings();
101+
settings.AddYamlReader();
102+
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(yaml));
103+
104+
return new OpenApiYamlReader().Read(stream, DocumentLocation, settings);
105+
}
106+
}

0 commit comments

Comments
 (0)