Skip to content

Commit bcf1f18

Browse files
author
Bart Koelman
committed
Improved unittests for populating IJsonApiRequest in middleware
1 parent 1b8bcb0 commit bcf1f18

File tree

2 files changed

+106
-232
lines changed

2 files changed

+106
-232
lines changed

test/UnitTests/Middleware/JsonApiMiddlewareTests.cs

-186
This file was deleted.

test/UnitTests/Middleware/JsonApiRequestTests.cs

+106-46
Original file line numberDiff line numberDiff line change
@@ -17,71 +17,104 @@
1717
using TestBuildingBlocks;
1818
using Xunit;
1919

20+
#pragma warning disable AV1561 // Signature contains too many parameters
21+
2022
namespace UnitTests.Middleware
2123
{
2224
public sealed class JsonApiRequestTests
2325
{
26+
// @formatter:wrap_lines false
2427
[Theory]
25-
[InlineData("HEAD", "/todoItems", true, EndpointKind.Primary, null, true)]
26-
[InlineData("HEAD", "/todoItems/1", false, EndpointKind.Primary, null, true)]
27-
[InlineData("HEAD", "/todoItems/1/owner", false, EndpointKind.Secondary, null, true)]
28-
[InlineData("HEAD", "/todoItems/1/tags", true, EndpointKind.Secondary, null, true)]
29-
[InlineData("HEAD", "/todoItems/1/relationships/owner", false, EndpointKind.Relationship, null, true)]
30-
[InlineData("HEAD", "/todoItems/1/relationships/tags", true, EndpointKind.Relationship, null, true)]
31-
[InlineData("GET", "/todoItems", true, EndpointKind.Primary, null, true)]
32-
[InlineData("GET", "/todoItems/1", false, EndpointKind.Primary, null, true)]
33-
[InlineData("GET", "/todoItems/1/owner", false, EndpointKind.Secondary, null, true)]
34-
[InlineData("GET", "/todoItems/1/tags", true, EndpointKind.Secondary, null, true)]
35-
[InlineData("GET", "/todoItems/1/relationships/owner", false, EndpointKind.Relationship, null, true)]
36-
[InlineData("GET", "/todoItems/1/relationships/tags", true, EndpointKind.Relationship, null, true)]
37-
[InlineData("POST", "/todoItems", false, EndpointKind.Primary, WriteOperationKind.CreateResource, false)]
38-
[InlineData("POST", "/todoItems/1/relationships/tags", true, EndpointKind.Relationship, WriteOperationKind.AddToRelationship, false)]
39-
[InlineData("PATCH", "/todoItems/1", false, EndpointKind.Primary, WriteOperationKind.UpdateResource, false)]
40-
[InlineData("PATCH", "/todoItems/1/relationships/owner", false, EndpointKind.Relationship, WriteOperationKind.SetRelationship, false)]
41-
[InlineData("PATCH", "/todoItems/1/relationships/tags", true, EndpointKind.Relationship, WriteOperationKind.SetRelationship, false)]
42-
[InlineData("DELETE", "/todoItems/1", false, EndpointKind.Primary, WriteOperationKind.DeleteResource, false)]
43-
[InlineData("DELETE", "/todoItems/1/relationships/tags", true, EndpointKind.Relationship, WriteOperationKind.RemoveFromRelationship, false)]
44-
public async Task Sets_request_properties_correctly(string requestMethod, string requestPath, bool expectIsCollection, EndpointKind expectKind,
45-
WriteOperationKind? expectWriteOperation, bool expectIsReadOnly)
28+
[InlineData("HEAD", "/todoItems", EndpointKind.Primary, null, "todoItems", null, null, IsCollection.Yes, IsReadOnly.Yes, null)]
29+
[InlineData("HEAD", "/people/1", EndpointKind.Primary, "1", "people", null, null, IsCollection.No, IsReadOnly.Yes, null)]
30+
[InlineData("HEAD", "/todoItems/2/owner", EndpointKind.Secondary, "2", "todoItems", "people", "owner", IsCollection.No, IsReadOnly.Yes, null)]
31+
[InlineData("HEAD", "/todoItems/3/tags", EndpointKind.Secondary, "3", "todoItems", "itemTags", "tags", IsCollection.Yes, IsReadOnly.Yes, null)]
32+
[InlineData("HEAD", "/todoItems/ABC/relationships/owner", EndpointKind.Relationship, "ABC", "todoItems", "people", "owner", IsCollection.No, IsReadOnly.Yes, null)]
33+
[InlineData("HEAD", "/todoItems/ABC/relationships/tags", EndpointKind.Relationship, "ABC", "todoItems", "itemTags", "tags", IsCollection.Yes, IsReadOnly.Yes, null)]
34+
[InlineData("GET", "/todoItems", EndpointKind.Primary, null, "todoItems", null, null, IsCollection.Yes, IsReadOnly.Yes, null)]
35+
[InlineData("GET", "/todoItems/-1", EndpointKind.Primary, "-1", "todoItems", null, null, IsCollection.No, IsReadOnly.Yes, null)]
36+
[InlineData("GET", "/todoItems/1/owner", EndpointKind.Secondary, "1", "todoItems", "people", "owner", IsCollection.No, IsReadOnly.Yes, null)]
37+
[InlineData("GET", "/todoItems/1/tags", EndpointKind.Secondary, "1", "todoItems", "itemTags", "tags", IsCollection.Yes, IsReadOnly.Yes, null)]
38+
[InlineData("GET", "/todoItems/1/relationships/owner", EndpointKind.Relationship, "1", "todoItems", "people", "owner", IsCollection.No, IsReadOnly.Yes, null)]
39+
[InlineData("GET", "/todoItems/1/relationships/tags", EndpointKind.Relationship, "1", "todoItems", "itemTags", "tags", IsCollection.Yes, IsReadOnly.Yes, null)]
40+
[InlineData("POST", "/todoItems", EndpointKind.Primary, null, "todoItems", null, null, IsCollection.No, IsReadOnly.No, WriteOperationKind.CreateResource)]
41+
[InlineData("POST", "/todoItems/1/relationships/tags", EndpointKind.Relationship, "1", "todoItems", "itemTags", "tags", IsCollection.Yes, IsReadOnly.No, WriteOperationKind.AddToRelationship)]
42+
[InlineData("PATCH", "/itemTags/1", EndpointKind.Primary, "1", "itemTags", null, null, IsCollection.No, IsReadOnly.No, WriteOperationKind.UpdateResource)]
43+
[InlineData("PATCH", "/todoItems/1/relationships/owner", EndpointKind.Relationship, "1", "todoItems", "people", "owner", IsCollection.No, IsReadOnly.No, WriteOperationKind.SetRelationship)]
44+
[InlineData("PATCH", "/todoItems/1/relationships/tags", EndpointKind.Relationship, "1", "todoItems", "itemTags", "tags", IsCollection.Yes, IsReadOnly.No, WriteOperationKind.SetRelationship)]
45+
[InlineData("DELETE", "/todoItems/1", EndpointKind.Primary, "1", "todoItems", null, null, IsCollection.No, IsReadOnly.No, WriteOperationKind.DeleteResource)]
46+
[InlineData("DELETE", "/todoItems/1/relationships/tags", EndpointKind.Relationship, "1", "todoItems", "itemTags", "tags", IsCollection.Yes, IsReadOnly.No, WriteOperationKind.RemoveFromRelationship)]
47+
[InlineData("POST", "/operations", EndpointKind.AtomicOperations, null, null, null, null, IsCollection.No, IsReadOnly.No, null)]
48+
// @formatter:wrap_lines restore
49+
public async Task Sets_request_properties_correctly(string requestMethod, string requestPath, EndpointKind expectKind, string? expectPrimaryId,
50+
string? expectPrimaryResourceType, string? expectSecondaryResourceType, string? expectRelationshipName, IsCollection expectIsCollection,
51+
IsReadOnly expectIsReadOnly, WriteOperationKind? expectWriteOperation)
4652
{
4753
// Arrange
48-
var options = new JsonApiOptions
49-
{
50-
UseRelativeLinks = true
51-
};
52-
53-
var graphBuilder = new ResourceGraphBuilder(options, NullLoggerFactory.Instance);
54-
graphBuilder.Add<TodoItem, int>();
55-
graphBuilder.Add<Person, int>();
56-
graphBuilder.Add<Tag, int>();
54+
var options = new JsonApiOptions();
55+
var request = new JsonApiRequest();
5756

58-
IResourceGraph resourceGraph = graphBuilder.Build();
57+
// @formatter:keep_existing_linebreaks true
5958

60-
var controllerResourceMappingMock = new Mock<IControllerResourceMapping>();
59+
IResourceGraph resourceGraph = new ResourceGraphBuilder(options, NullLoggerFactory.Instance)
60+
.Add<TodoItem, int>()
61+
.Add<Person, int>()
62+
.Add<ItemTag, int>()
63+
.Build();
6164

62-
ResourceType todoItemType = resourceGraph.GetResourceType<TodoItem>();
63-
controllerResourceMappingMock.Setup(mapping => mapping.GetResourceTypeForController(It.IsAny<Type>())).Returns(todoItemType);
65+
// @formatter:keep_existing_linebreaks restore
6466

6567
var httpContext = new DefaultHttpContext();
66-
SetupRoutes(httpContext, requestMethod, requestPath);
67-
68-
var request = new JsonApiRequest();
68+
IControllerResourceMapping controllerResourceMapping = SetupRoutes(httpContext, resourceGraph, requestMethod, requestPath);
6969

70-
var middleware = new JsonApiMiddleware(_ => Task.CompletedTask, new HttpContextAccessor());
70+
var middleware = new JsonApiMiddleware(_ => Task.CompletedTask, new HttpContextAccessor
71+
{
72+
HttpContext = httpContext
73+
});
7174

7275
// Act
73-
await middleware.InvokeAsync(httpContext, controllerResourceMappingMock.Object, options, request, NullLogger<JsonApiMiddleware>.Instance);
76+
await middleware.InvokeAsync(httpContext, controllerResourceMapping, options, request, NullLogger<JsonApiMiddleware>.Instance);
7477

7578
// Assert
76-
request.IsCollection.Should().Be(expectIsCollection);
7779
request.Kind.Should().Be(expectKind);
80+
request.PrimaryId.Should().Be(expectPrimaryId);
81+
82+
if (expectPrimaryResourceType == null)
83+
{
84+
request.PrimaryResourceType.Should().BeNull();
85+
}
86+
else
87+
{
88+
request.PrimaryResourceType.ShouldNotBeNull();
89+
request.PrimaryResourceType.PublicName.Should().Be(expectPrimaryResourceType);
90+
}
91+
92+
if (expectSecondaryResourceType == null)
93+
{
94+
request.SecondaryResourceType.Should().BeNull();
95+
}
96+
else
97+
{
98+
request.SecondaryResourceType.ShouldNotBeNull();
99+
request.SecondaryResourceType.PublicName.Should().Be(expectSecondaryResourceType);
100+
}
101+
102+
if (expectRelationshipName == null)
103+
{
104+
request.Relationship.Should().BeNull();
105+
}
106+
else
107+
{
108+
request.Relationship.ShouldNotBeNull();
109+
request.Relationship.PublicName.Should().Be(expectRelationshipName);
110+
}
111+
112+
request.IsCollection.Should().Be(expectIsCollection == IsCollection.Yes);
113+
request.IsReadOnly.Should().Be(expectIsReadOnly == IsReadOnly.Yes);
78114
request.WriteOperation.Should().Be(expectWriteOperation);
79-
request.IsReadOnly.Should().Be(expectIsReadOnly);
80-
request.PrimaryResourceType.ShouldNotBeNull();
81-
request.PrimaryResourceType.PublicName.Should().Be("todoItems");
82115
}
83116

84-
private static void SetupRoutes(HttpContext httpContext, string requestMethod, string requestPath)
117+
private static IControllerResourceMapping SetupRoutes(HttpContext httpContext, IResourceGraph resourceGraph, string requestMethod, string requestPath)
85118
{
86119
httpContext.Request.Method = requestMethod;
87120

@@ -110,6 +143,10 @@ private static void SetupRoutes(HttpContext httpContext, string requestMethod, s
110143
{
111144
feature.RouteValues["action"] = "Relationship";
112145
}
146+
else if (pathSegments.Contains("operations"))
147+
{
148+
feature.RouteValues["action"] = "PostOperations";
149+
}
113150

114151
httpContext.Features.Set<IRouteValuesFeature>(feature);
115152

@@ -118,7 +155,30 @@ private static void SetupRoutes(HttpContext httpContext, string requestMethod, s
118155
ControllerTypeInfo = (TypeInfo)typeof(object)
119156
};
120157

158+
var controllerResourceMappingMock = new Mock<IControllerResourceMapping>();
159+
160+
controllerResourceMappingMock.Setup(mapping => mapping.GetResourceTypeForController(It.IsAny<Type>())).Returns(() =>
161+
{
162+
return pathSegments.Length > 0
163+
? resourceGraph.GetResourceTypes().FirstOrDefault(resourceType => resourceType.PublicName == pathSegments[0])
164+
: null;
165+
});
166+
121167
httpContext.SetEndpoint(new Endpoint(_ => Task.CompletedTask, new EndpointMetadataCollection(controllerActionDescriptor), null));
168+
169+
return controllerResourceMappingMock.Object;
170+
}
171+
172+
public enum IsReadOnly
173+
{
174+
Yes,
175+
No
176+
}
177+
178+
public enum IsCollection
179+
{
180+
Yes,
181+
No
122182
}
123183

124184
[UsedImplicitly(ImplicitUseTargetFlags.Itself)]
@@ -127,7 +187,7 @@ private sealed class Person : Identifiable<int>
127187
}
128188

129189
[UsedImplicitly(ImplicitUseTargetFlags.Members)]
130-
private sealed class Tag : Identifiable<int>
190+
private sealed class ItemTag : Identifiable<int>
131191
{
132192
[HasMany]
133193
public ISet<TodoItem> TodoItems { get; set; } = new HashSet<TodoItem>();
@@ -140,7 +200,7 @@ private sealed class TodoItem : Identifiable<int>
140200
public Person? Owner { get; set; }
141201

142202
[HasMany]
143-
public ISet<Tag> Tags { get; set; } = new HashSet<Tag>();
203+
public ISet<ItemTag> Tags { get; set; } = new HashSet<ItemTag>();
144204
}
145205
}
146206
}

0 commit comments

Comments
 (0)