Skip to content

Commit 0ee5c4e

Browse files
authored
Update ListObjectTypeVisitor to include HashSet<T> (#230)
1 parent c1441e0 commit 0ee5c4e

File tree

11 files changed

+214
-4
lines changed

11 files changed

+214
-4
lines changed

samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.Models/DummyListModel.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.Models
44
{
55
public class DummyListModel
66
{
7-
public List<DummyStringModel> ListValues { get; set; }
7+
public List<DummyStringModel> ListValues1 { get; set; }
8+
9+
public HashSet<int> ListValues2 { get; set; }
10+
11+
public ISet<DummyStringModel> ListValues3 { get; set; }
812
}
913
}

samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.V3Static/Examples/DummyListModelExample.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ public override IOpenApiExample<DummyListModel> Build(NamingStrategy namingStrat
1818
"dummy",
1919
new DummyListModel()
2020
{
21-
ListValues = new List<DummyStringModel>() { new DummyStringModel() { StringValue = "Hello World", UriValue = new Uri("https://localhost") } }
21+
ListValues1 = new List<DummyStringModel>() { new DummyStringModel() { StringValue = "Hello World", UriValue = new Uri("https://localhost") } },
22+
ListValues2 = new HashSet<int>() { 1, 2 },
23+
ListValues3 = new HashSet<DummyStringModel>() { new DummyStringModel() { StringValue = "Hello World", UriValue = new Uri("https://localhost") } },
2224
},
2325
namingStrategy
2426
));

src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/Extensions/TypeExtensions.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,16 @@ private static bool IsArrayType(this Type type)
692692
return true;
693693
}
694694

695+
if (type.IsGenericTypeOf(typeof(HashSet<>)))
696+
{
697+
return true;
698+
}
699+
700+
if (type.IsGenericTypeOf(typeof(ISet<>)))
701+
{
702+
return true;
703+
}
704+
695705
return false;
696706
}
697707

src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/Visitors/ObjectTypeVisitor.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ public override bool IsVisitable(Type type)
7878
{
7979
isVisitable = false;
8080
}
81-
8281

8382
return isVisitable;
8483
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
using System.Net.Http;
2+
using System.Threading.Tasks;
3+
4+
using FluentAssertions;
5+
6+
using Microsoft.VisualStudio.TestTools.UnitTesting;
7+
8+
using Newtonsoft.Json;
9+
using Newtonsoft.Json.Linq;
10+
11+
namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Document.Tests
12+
{
13+
[TestClass]
14+
[TestCategory(Constants.TestCategory)]
15+
public class Get_ApplicationJson_ArrayObject_Tests
16+
{
17+
private static HttpClient http = new HttpClient();
18+
19+
private JObject _doc;
20+
21+
[TestInitialize]
22+
public async Task Init()
23+
{
24+
var json = await http.GetStringAsync(Constants.OpenApiDocEndpoint).ConfigureAwait(false);
25+
this._doc = JsonConvert.DeserializeObject<JObject>(json);
26+
}
27+
28+
[DataTestMethod]
29+
[DataRow("/get-applicationjson-array", "get", "200")]
30+
public void Given_OpenApiDocument_Then_It_Should_Return_OperationResponse(string path, string operationType, string responseCode)
31+
{
32+
var responses = this._doc["paths"][path][operationType]["responses"];
33+
34+
responses[responseCode].Should().NotBeNull();
35+
}
36+
37+
[DataTestMethod]
38+
[DataRow("/get-applicationjson-array", "get", "200", "application/json")]
39+
public void Given_OpenApiDocument_Then_It_Should_Return_OperationResponseContentType(string path, string operationType, string responseCode, string contentType)
40+
{
41+
var content = this._doc["paths"][path][operationType]["responses"][responseCode]["content"];
42+
43+
content[contentType].Should().NotBeNull();
44+
}
45+
46+
[DataTestMethod]
47+
[DataRow("/get-applicationjson-array", "get", "200", "application/json", "arrayObjectModel")]
48+
public void Given_OpenApiDocument_Then_It_Should_Return_OperationResponseContentTypeSchema(string path, string operationType, string responseCode, string contentType, string reference)
49+
{
50+
var content = this._doc["paths"][path][operationType]["responses"][responseCode]["content"];
51+
52+
var @ref = content[contentType]["schema"]["$ref"];
53+
54+
@ref.Value<string>().Should().Be($"#/components/schemas/{reference}");
55+
}
56+
57+
[DataTestMethod]
58+
[DataRow("arrayObjectModel", "object")]
59+
public void Given_OpenApiDocument_Then_It_Should_Return_ComponentSchema(string @ref, string refType)
60+
{
61+
var schemas = this._doc["components"]["schemas"];
62+
63+
var schema = schemas[@ref];
64+
65+
schema.Should().NotBeNull();
66+
schema.Value<string>("type").Should().Be(refType);
67+
}
68+
69+
[DataTestMethod]
70+
[DataRow("arrayObjectModel", "object", "boolValue", "array")]
71+
[DataRow("arrayObjectModel", "object", "stringValue", "array")]
72+
[DataRow("arrayObjectModel", "object", "int32Value", "array")]
73+
[DataRow("arrayObjectModel", "object", "int64Value", "array")]
74+
[DataRow("arrayObjectModel", "object", "floatValue", "array")]
75+
[DataRow("arrayObjectModel", "object", "decimalValue", "array")]
76+
[DataRow("arrayObjectModel", "object", "stringObjectValue", "array")]
77+
[DataRow("arrayObjectModel", "object", "int32ObjectValue", "array")]
78+
public void Given_OpenApiDocument_Then_It_Should_Return_ComponentSchemaProperty(string @ref, string refType, string propertyName, string propertyType)
79+
{
80+
var properties = this._doc["components"]["schemas"][@ref]["properties"];
81+
82+
var value = properties[propertyName];
83+
84+
value.Should().NotBeNull();
85+
value.Value<string>("type").Should().Be(propertyType);
86+
}
87+
88+
[DataTestMethod]
89+
[DataRow("arrayObjectModel", "object", "boolValue", "array", "boolean")]
90+
[DataRow("arrayObjectModel", "object", "stringValue", "array", "string")]
91+
[DataRow("arrayObjectModel", "object", "int32Value", "array", "integer")]
92+
[DataRow("arrayObjectModel", "object", "int64Value", "array", "integer")]
93+
[DataRow("arrayObjectModel", "object", "floatValue", "array", "number")]
94+
[DataRow("arrayObjectModel", "object", "decimalValue", "array", "number")]
95+
public void Given_OpenApiDocument_Then_It_Should_Return_ComponentSchemaPropertyItems(string @ref, string refType, string propertyName, string propertyType, string itemType)
96+
{
97+
var items = this._doc["components"]["schemas"][@ref]["properties"][propertyName]["items"];
98+
99+
var type = items["type"];
100+
101+
type.Should().NotBeNull();
102+
type.Value<string>().Should().Be(itemType);
103+
}
104+
105+
[DataTestMethod]
106+
[DataRow("arrayObjectModel", "object", "stringObjectValue", "array", "stringObjectModel")]
107+
[DataRow("arrayObjectModel", "object", "int32ObjectValue", "array", "int32ObjectModel")]
108+
public void Given_OpenApiDocument_Then_It_Should_Return_ComponentSchemaPropertyItemReference(string @ref, string refType, string propertyName, string propertyType, string itemRef)
109+
{
110+
var items = this._doc["components"]["schemas"][@ref]["properties"][propertyName]["items"];
111+
112+
var itemReference = items["$ref"];
113+
114+
itemReference.Should().NotBeNull();
115+
itemReference.Value<string>().Should().Be($"#/components/schemas/{itemRef}");
116+
}
117+
}
118+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System.Net;
2+
using System.Threading.Tasks;
3+
4+
using Microsoft.AspNetCore.Http;
5+
using Microsoft.AspNetCore.Mvc;
6+
using Microsoft.Azure.WebJobs.Extensions.Http;
7+
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes;
8+
using Microsoft.Azure.WebJobs.Extensions.OpenApi.TestApp.Models;
9+
using Microsoft.Extensions.Logging;
10+
using Microsoft.OpenApi.Models;
11+
12+
namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.TestApp
13+
{
14+
public static class Get_ApplicationJson_ArrayObject_HttpTrigger
15+
{
16+
[FunctionName(nameof(Get_ApplicationJson_ArrayObject_HttpTrigger))]
17+
[OpenApiOperation(operationId: nameof(Get_ApplicationJson_ArrayObject_HttpTrigger.Get_ApplicationJson_ArrayObject), tags: new[] { "array" })]
18+
[OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(ArrayObjectModel), Description = "The OK response")]
19+
public static async Task<IActionResult> Get_ApplicationJson_ArrayObject(
20+
[HttpTrigger(AuthorizationLevel.Anonymous, "GET", Route = "get-applicationjson-array")] HttpRequest req,
21+
ILogger log)
22+
{
23+
var result = new OkResult();
24+
25+
return await Task.FromResult(result).ConfigureAwait(false);
26+
}
27+
}
28+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System.Collections.Generic;
2+
3+
namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.TestApp.Models
4+
{
5+
public class ArrayObjectModel
6+
{
7+
public List<bool> BoolValue { get; set; }
8+
public IList<string> StringValue { get; set; }
9+
public ICollection<int> Int32Value { get; set; }
10+
public IEnumerable<long> Int64Value { get; set; }
11+
public IReadOnlyList<float> FloatValue { get; set; }
12+
public IReadOnlyCollection<decimal> DecimalValue { get; set; }
13+
public HashSet<StringObjectModel> StringObjectValue { get; set; }
14+
public ISet<Int32ObjectModel> Int32ObjectValue { get; set; }
15+
}
16+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.TestApp.Models
2+
{
3+
public class Int32ObjectModel
4+
{
5+
public int Value { get; set; }
6+
}
7+
}

test/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Tests/Visitors/ByteArrayTypeVisitorTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.ComponentModel.DataAnnotations;
43

54
using FluentAssertions;
65

@@ -11,6 +10,7 @@
1110
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Visitors;
1211
using Microsoft.OpenApi.Any;
1312
using Microsoft.VisualStudio.TestTools.UnitTesting;
13+
1414
using Newtonsoft.Json.Serialization;
1515

1616
namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Tests.Visitors

test/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Tests/Visitors/ListObjectTypeVisitorTests.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ public void Given_Type_When_IsNavigatable_Invoked_Then_It_Should_Return_Result(T
5050
[DataRow(typeof(IEnumerable<string>), true)]
5151
[DataRow(typeof(IReadOnlyList<string>), true)]
5252
[DataRow(typeof(IReadOnlyCollection<string>), true)]
53+
[DataRow(typeof(HashSet<string>), true)]
54+
[DataRow(typeof(ISet<string>), true)]
5355
[DataRow(typeof(int), false)]
5456
public void Given_Type_When_IsVisitable_Invoked_Then_It_Should_Return_Result(Type type, bool expected)
5557
{
@@ -65,6 +67,8 @@ public void Given_Type_When_IsVisitable_Invoked_Then_It_Should_Return_Result(Typ
6567
[DataRow(typeof(IEnumerable<string>), true)]
6668
[DataRow(typeof(IReadOnlyList<string>), true)]
6769
[DataRow(typeof(IReadOnlyCollection<string>), true)]
70+
[DataRow(typeof(HashSet<string>), true)]
71+
[DataRow(typeof(ISet<string>), true)]
6872
[DataRow(typeof(int), false)]
6973
public void Given_Type_When_IsParameterVisitable_Invoked_Then_It_Should_Return_Result(Type type, bool expected)
7074
{
@@ -80,6 +84,8 @@ public void Given_Type_When_IsParameterVisitable_Invoked_Then_It_Should_Return_R
8084
[DataRow(typeof(IEnumerable<string>), true)]
8185
[DataRow(typeof(IReadOnlyList<string>), true)]
8286
[DataRow(typeof(IReadOnlyCollection<string>), true)]
87+
[DataRow(typeof(HashSet<string>), true)]
88+
[DataRow(typeof(ISet<string>), true)]
8389
[DataRow(typeof(int), false)]
8490
public void Given_Type_When_IsPayloadVisitable_Invoked_Then_It_Should_Return_Result(Type type, bool expected)
8591
{
@@ -95,12 +101,16 @@ public void Given_Type_When_IsPayloadVisitable_Invoked_Then_It_Should_Return_Res
95101
[DataRow(typeof(IEnumerable<string>), "array", null, "string", false, "string", 0)]
96102
[DataRow(typeof(IReadOnlyList<string>), "array", null, "string", false, "string", 0)]
97103
[DataRow(typeof(IReadOnlyCollection<string>), "array", null, "string", false, "string", 0)]
104+
[DataRow(typeof(HashSet<string>), "array", null, "string", false, "string", 0)]
105+
[DataRow(typeof(ISet<string>), "array", null, "string", false, "string", 0)]
98106
[DataRow(typeof(List<FakeModel>), "array", null, "object", true, "fakeModel", 1)]
99107
[DataRow(typeof(IList<FakeModel>), "array", null, "object", true, "fakeModel", 1)]
100108
[DataRow(typeof(ICollection<FakeModel>), "array", null, "object", true, "fakeModel", 1)]
101109
[DataRow(typeof(IEnumerable<FakeModel>), "array", null, "object", true, "fakeModel", 1)]
102110
[DataRow(typeof(IReadOnlyList<FakeModel>), "array", null, "object", true, "fakeModel", 1)]
103111
[DataRow(typeof(IReadOnlyCollection<FakeModel>), "array", null, "object", true, "fakeModel", 1)]
112+
[DataRow(typeof(HashSet<FakeModel>), "array", null, "object", true, "fakeModel", 1)]
113+
[DataRow(typeof(ISet<FakeModel>), "array", null, "object", true, "fakeModel", 1)]
104114
public void Given_Type_When_Visit_Invoked_Then_It_Should_Return_Result(Type listType, string dataType, string dataFormat, string itemType, bool isReferential, string referenceId, int expected)
105115
{
106116
var name = "hello";
@@ -132,12 +142,16 @@ public void Given_Type_When_Visit_Invoked_Then_It_Should_Return_Result(Type list
132142
[DataRow(typeof(IEnumerable<string>), 1)]
133143
[DataRow(typeof(IReadOnlyList<string>), 1)]
134144
[DataRow(typeof(IReadOnlyCollection<string>), 1)]
145+
[DataRow(typeof(HashSet<string>), 1)]
146+
[DataRow(typeof(ISet<string>), 1)]
135147
[DataRow(typeof(List<FakeModel>), 1)]
136148
[DataRow(typeof(IList<FakeModel>), 1)]
137149
[DataRow(typeof(ICollection<FakeModel>), 1)]
138150
[DataRow(typeof(IEnumerable<FakeModel>), 1)]
139151
[DataRow(typeof(IReadOnlyList<FakeModel>), 1)]
140152
[DataRow(typeof(IReadOnlyCollection<FakeModel>), 1)]
153+
[DataRow(typeof(HashSet<FakeModel>), 1)]
154+
[DataRow(typeof(ISet<FakeModel>), 1)]
141155
public void Given_MinLengthAttribute_When_Visit_Invoked_Then_It_Should_Return_Result(Type listType, int length)
142156
{
143157
var name = "hello";
@@ -159,12 +173,16 @@ public void Given_MinLengthAttribute_When_Visit_Invoked_Then_It_Should_Return_Re
159173
[DataRow(typeof(IEnumerable<string>), 10)]
160174
[DataRow(typeof(IReadOnlyList<string>), 10)]
161175
[DataRow(typeof(IReadOnlyCollection<string>), 10)]
176+
[DataRow(typeof(HashSet<string>), 10)]
177+
[DataRow(typeof(ISet<string>), 10)]
162178
[DataRow(typeof(List<FakeModel>), 10)]
163179
[DataRow(typeof(IList<FakeModel>), 10)]
164180
[DataRow(typeof(ICollection<FakeModel>), 10)]
165181
[DataRow(typeof(IEnumerable<FakeModel>), 10)]
166182
[DataRow(typeof(IReadOnlyList<FakeModel>), 10)]
167183
[DataRow(typeof(IReadOnlyCollection<FakeModel>), 10)]
184+
[DataRow(typeof(HashSet<FakeModel>), 10)]
185+
[DataRow(typeof(ISet<FakeModel>), 10)]
168186
public void Given_MaxLengthAttribute_When_Visit_Invoked_Then_It_Should_Return_Result(Type listType, int length)
169187
{
170188
var name = "hello";
@@ -218,12 +236,16 @@ public void Given_OpenApiSchemaVisibilityAttribute_When_Visit_Invoked_Then_It_Sh
218236
[DataRow(typeof(IEnumerable<string>), "array", null, "string", false)]
219237
[DataRow(typeof(IReadOnlyList<string>), "array", null, "string", false)]
220238
[DataRow(typeof(IReadOnlyCollection<string>), "array", null, "string", false)]
239+
[DataRow(typeof(HashSet<string>), "array", null, "string", false)]
240+
[DataRow(typeof(ISet<string>), "array", null, "string", false)]
221241
[DataRow(typeof(List<FakeModel>), "array", null, "object", true)]
222242
[DataRow(typeof(IList<FakeModel>), "array", null, "object", true)]
223243
[DataRow(typeof(ICollection<FakeModel>), "array", null, "object", true)]
224244
[DataRow(typeof(IEnumerable<FakeModel>), "array", null, "object", true)]
225245
[DataRow(typeof(IReadOnlyList<FakeModel>), "array", null, "object", true)]
226246
[DataRow(typeof(IReadOnlyCollection<FakeModel>), "array", null, "object", true)]
247+
[DataRow(typeof(HashSet<FakeModel>), "array", null, "object", true)]
248+
[DataRow(typeof(ISet<FakeModel>), "array", null, "object", true)]
227249
public void Given_Type_When_ParameterVisit_Invoked_Then_It_Should_Return_Result(Type listType, string dataType, string dataFormat, string itemType, bool isItemToBeNull)
228250
{
229251
var result = this._visitor.ParameterVisit(listType, this._strategy);
@@ -245,12 +267,16 @@ public void Given_Type_When_ParameterVisit_Invoked_Then_It_Should_Return_Result(
245267
[DataRow(typeof(IEnumerable<string>), "array", null, "string", false, null)]
246268
[DataRow(typeof(IReadOnlyList<string>), "array", null, "string", false, null)]
247269
[DataRow(typeof(IReadOnlyCollection<string>), "array", null, "string", false, null)]
270+
[DataRow(typeof(HashSet<string>), "array", null, "string", false, null)]
271+
[DataRow(typeof(ISet<string>), "array", null, "string", false, null)]
248272
[DataRow(typeof(List<FakeModel>), "array", null, "object", true, "fakeModel")]
249273
[DataRow(typeof(IList<FakeModel>), "array", null, "object", true, "fakeModel")]
250274
[DataRow(typeof(ICollection<FakeModel>), "array", null, "object", true, "fakeModel")]
251275
[DataRow(typeof(IEnumerable<FakeModel>), "array", null, "object", true, "fakeModel")]
252276
[DataRow(typeof(IReadOnlyList<FakeModel>), "array", null, "object", true, "fakeModel")]
253277
[DataRow(typeof(IReadOnlyCollection<FakeModel>), "array", null, "object", true, "fakeModel")]
278+
[DataRow(typeof(HashSet<FakeModel>), "array", null, "object", true, "fakeModel")]
279+
[DataRow(typeof(ISet<FakeModel>), "array", null, "object", true, "fakeModel")]
254280
public void Given_Type_When_PayloadVisit_Invoked_Then_It_Should_Return_Result(Type listType, string dataType, string dataFormat, string itemType, bool reference, string referenceId)
255281
{
256282
var result = this._visitor.PayloadVisit(listType, this._strategy);

0 commit comments

Comments
 (0)