Skip to content

Commit 4ee8e9e

Browse files
committed
- adds unit test for Cast operation handler & cast path item handler
- adds support for query parameters when in navigation properties Signed-off-by: Vincent Biret <vibiret@microsoft.com>
1 parent 7eee372 commit 4ee8e9e

File tree

4 files changed

+228
-6
lines changed

4 files changed

+228
-6
lines changed

src/Microsoft.OpenApi.OData.Reader/Operation/ODataTypeCastGetOperationHandler.cs

Lines changed: 155 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@
77
using System.Collections.Generic;
88
using System.Linq;
99
using Microsoft.OData.Edm;
10+
using Microsoft.OpenApi.Any;
1011
using Microsoft.OpenApi.Models;
1112
using Microsoft.OpenApi.OData.Common;
1213
using Microsoft.OpenApi.OData.Edm;
1314
using Microsoft.OpenApi.OData.Generator;
15+
using Microsoft.OpenApi.OData.Vocabulary.Capabilities;
1416

1517
namespace Microsoft.OpenApi.OData.Operation;
1618

@@ -28,6 +30,8 @@ internal class ODataTypeCastGetOperationHandler : OperationHandler
2830
/// </summary>
2931
internal ODataSegment LastSecondSegment { get; set; }
3032

33+
private NavigationPropertyRestriction restriction;
34+
private IEdmNavigationProperty navigationProperty;
3135
private IEdmEntityType parentEntityType;
3236
private IEdmEntityType targetEntityType;
3337
private const int SecondLastSegmentIndex = 2;
@@ -42,6 +46,30 @@ protected override void Initialize(ODataContext context, ODataPath path)
4246
LastSecondSegment = path.Segments.ElementAt(count - SecondLastSegmentIndex);
4347

4448
parentEntityType = LastSecondSegment.EntityType;
49+
if(LastSecondSegment is ODataNavigationPropertySegment navigationPropertySegment)
50+
{
51+
navigationProperty = navigationPropertySegment.NavigationProperty;
52+
var navigationPropertyPath = string.Join("/",
53+
Path.Segments.Where(s => !(s is ODataKeySegment || s is ODataNavigationSourceSegment
54+
|| s is ODataStreamContentSegment || s is ODataStreamPropertySegment)).Select(e => e.Identifier));
55+
56+
if(path.FirstSegment is ODataNavigationSourceSegment navigationSourceSegment)
57+
{
58+
NavigationRestrictionsType navigation = navigationSourceSegment.NavigationSource switch {
59+
IEdmEntitySet entitySet => Context.Model.GetRecord<NavigationRestrictionsType>(entitySet, CapabilitiesConstants.NavigationRestrictions),
60+
IEdmSingleton singleton => Context.Model.GetRecord<NavigationRestrictionsType>(singleton, CapabilitiesConstants.NavigationRestrictions),
61+
_ => null
62+
};
63+
64+
if (navigation?.RestrictedProperties != null)
65+
{
66+
restriction = navigation.RestrictedProperties.FirstOrDefault(r => r.NavigationProperty != null && r.NavigationProperty == navigationPropertyPath);
67+
}
68+
}
69+
}
70+
//TODO previous segment is a key
71+
//TODO previous segment is a single nav property
72+
//TODO previous segment is an entity set
4573
if(path.Last() is ODataTypeCastSegment oDataTypeCastSegment)
4674
{
4775
targetEntityType = oDataTypeCastSegment.EntityType;
@@ -140,7 +168,130 @@ protected override void SetResponses(OpenApiOperation operation)
140168

141169
base.SetResponses(operation);
142170
}
143-
//TODO query parameters?
144-
//TODO extensions?
145-
}
146-
//TODO unit tests
171+
/// <inheritdoc/>
172+
protected override void SetTags(OpenApiOperation operation)
173+
{
174+
IList<string> items = new List<string>
175+
{
176+
parentEntityType.Name,
177+
targetEntityType.Name,
178+
};
179+
180+
string name = string.Join(".", items);
181+
OpenApiTag tag = new()
182+
{
183+
Name = name
184+
};
185+
tag.Extensions.Add(Constants.xMsTocType, new OpenApiString("page"));
186+
operation.Tags.Add(tag);
187+
188+
Context.AppendTag(tag);
189+
190+
base.SetTags(operation);
191+
}
192+
/// <inheritdoc/>
193+
protected override void SetParameters(OpenApiOperation operation)
194+
{
195+
base.SetParameters(operation);
196+
197+
if(navigationProperty != null) {
198+
if (navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many)
199+
{
200+
// Need to verify that TopSupported or others should be applied to navigation source.
201+
// So, how about for the navigation property.
202+
OpenApiParameter parameter = Context.CreateTop(navigationProperty);
203+
if (parameter != null)
204+
{
205+
operation.Parameters.Add(parameter);
206+
}
207+
208+
parameter = Context.CreateSkip(navigationProperty);
209+
if (parameter != null)
210+
{
211+
operation.Parameters.Add(parameter);
212+
}
213+
214+
parameter = Context.CreateSearch(navigationProperty);
215+
if (parameter != null)
216+
{
217+
operation.Parameters.Add(parameter);
218+
}
219+
220+
parameter = Context.CreateFilter(navigationProperty);
221+
if (parameter != null)
222+
{
223+
operation.Parameters.Add(parameter);
224+
}
225+
226+
parameter = Context.CreateCount(navigationProperty);
227+
if (parameter != null)
228+
{
229+
operation.Parameters.Add(parameter);
230+
}
231+
232+
parameter = Context.CreateOrderBy(navigationProperty);
233+
if (parameter != null)
234+
{
235+
operation.Parameters.Add(parameter);
236+
}
237+
238+
parameter = Context.CreateSelect(navigationProperty);
239+
if (parameter != null)
240+
{
241+
operation.Parameters.Add(parameter);
242+
}
243+
244+
parameter = Context.CreateExpand(navigationProperty);
245+
if (parameter != null)
246+
{
247+
operation.Parameters.Add(parameter);
248+
}
249+
}
250+
else
251+
{
252+
OpenApiParameter parameter = Context.CreateSelect(navigationProperty);
253+
if (parameter != null)
254+
{
255+
operation.Parameters.Add(parameter);
256+
}
257+
258+
parameter = Context.CreateExpand(navigationProperty);
259+
if (parameter != null)
260+
{
261+
operation.Parameters.Add(parameter);
262+
}
263+
}
264+
}
265+
}
266+
267+
protected override void SetSecurity(OpenApiOperation operation)
268+
{
269+
if (restriction == null || restriction.ReadRestrictions == null)
270+
{
271+
return;
272+
}
273+
274+
ReadRestrictionsBase readBase = restriction.ReadRestrictions;
275+
276+
operation.Security = Context.CreateSecurityRequirements(readBase.Permissions).ToList();
277+
}
278+
279+
protected override void SetExtensions(OpenApiOperation operation)
280+
{
281+
if (Context.Settings.EnablePagination)
282+
{
283+
if (navigationProperty != null && navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many)
284+
{
285+
OpenApiObject extension = new()
286+
{
287+
{ "nextLinkName", new OpenApiString("@odata.nextLink")},
288+
{ "operationName", new OpenApiString(Context.Settings.PageableOperationName)}
289+
};
290+
291+
operation.Extensions.Add(Constants.xMsPageable, extension);
292+
}
293+
}
294+
295+
base.SetExtensions(operation);
296+
}
297+
}

src/Microsoft.OpenApi.OData.Reader/PathItem/ODataTypeCastPathItemHandler.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,3 @@ protected override void SetOperations(OpenApiPathItem item)
2222
AddOperation(item, OperationType.Get);
2323
}
2424
}
25-
26-
//TODO unit test for the ODataTypeCastPathItemHandler
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// ------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation. All rights reserved.
3+
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
4+
// ------------------------------------------------------------
5+
6+
using System.Linq;
7+
using Microsoft.OData.Edm;
8+
using Microsoft.OpenApi.Extensions;
9+
using Microsoft.OpenApi.OData.Edm;
10+
using Microsoft.OpenApi.OData.PathItem.Tests;
11+
using Microsoft.OpenApi.OData.Tests;
12+
using Xunit;
13+
14+
namespace Microsoft.OpenApi.OData.Operation.Tests;
15+
public class ODataTypeCastGetOperationHandlerTests
16+
{
17+
private readonly ODataTypeCastGetOperationHandler _operationHandler = new ();
18+
19+
[Theory]
20+
[InlineData(true)]
21+
[InlineData(false)]
22+
public void CreateODataTypeCastGetOperationReturnsCorrectOperation(bool enableOperationId)
23+
{
24+
// Arrange
25+
IEdmModel model = EdmModelHelper.TripServiceModel;
26+
OpenApiConvertSettings settings = new()
27+
{
28+
EnableOperationId = enableOperationId
29+
};
30+
ODataContext context = new(model, settings);
31+
IEdmEntitySet people = model.EntityContainer.FindEntitySet("People");
32+
Assert.NotNull(people);
33+
34+
IEdmEntityType person = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Person");
35+
IEdmEntityType employee = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Employee");
36+
IEdmNavigationProperty navProperty = person.DeclaredNavigationProperties().First(c => c.Name == "Friends");
37+
ODataPath path = new(new ODataNavigationSourceSegment(people),
38+
new ODataKeySegment(people.EntityType()),
39+
new ODataNavigationPropertySegment(navProperty),
40+
new ODataTypeCastSegment(employee));
41+
42+
// Act
43+
var operation = _operationHandler.CreateOperation(context, path);
44+
45+
// Assert
46+
Assert.NotNull(operation);
47+
Assert.Equal("Get the items of type Microsoft.OData.Service.Sample.TrippinInMemory.Models.Employee in the Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person collection", operation.Summary);
48+
Assert.NotNull(operation.Tags);
49+
var tag = Assert.Single(operation.Tags);
50+
Assert.Equal("Person.Employee", tag.Name);
51+
52+
Assert.NotNull(operation.Parameters);
53+
Assert.Equal(9, operation.Parameters.Count);
54+
55+
Assert.Null(operation.RequestBody);
56+
57+
Assert.Equal(2, operation.Responses.Count);
58+
Assert.Equal(new string[] { "200", "default" }, operation.Responses.Select(e => e.Key));
59+
60+
if (enableOperationId)
61+
{
62+
Assert.Equal("Get.Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person.As.Microsoft.OData.Service.Sample.TrippinInMemory.Models.Employee", operation.OperationId);
63+
}
64+
else
65+
{
66+
Assert.Null(operation.OperationId);
67+
}
68+
}
69+
//TODO test on entity set
70+
//TODO test on cast cast key
71+
//TODO test on cast on single nav property
72+
}

test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/PathItemHandlerProviderTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public class PathItemHandlerProviderTests
2222
[InlineData(ODataPathKind.MediaEntity, typeof(MediaEntityPathItemHandler))]
2323
[InlineData(ODataPathKind.Metadata, typeof(MetadataPathItemHandler))]
2424
[InlineData(ODataPathKind.DollarCount, typeof(DollarCountPathItemHandler))]
25+
[InlineData(ODataPathKind.TypeCast, typeof(ODataTypeCastPathItemHandler))]
2526
public void GetHandlerReturnsCorrectHandlerType(ODataPathKind pathKind, Type handlerType)
2627
{
2728
// Arrange

0 commit comments

Comments
 (0)