17
17
using TestBuildingBlocks ;
18
18
using Xunit ;
19
19
20
+ #pragma warning disable AV1561 // Signature contains too many parameters
21
+
20
22
namespace UnitTests . Middleware
21
23
{
22
24
public sealed class JsonApiRequestTests
23
25
{
26
+ // @formatter:wrap_lines false
24
27
[ 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 )
46
52
{
47
53
// 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 ( ) ;
57
56
58
- IResourceGraph resourceGraph = graphBuilder . Build ( ) ;
57
+ // @formatter:keep_existing_linebreaks true
59
58
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 ( ) ;
61
64
62
- ResourceType todoItemType = resourceGraph . GetResourceType < TodoItem > ( ) ;
63
- controllerResourceMappingMock . Setup ( mapping => mapping . GetResourceTypeForController ( It . IsAny < Type > ( ) ) ) . Returns ( todoItemType ) ;
65
+ // @formatter:keep_existing_linebreaks restore
64
66
65
67
var httpContext = new DefaultHttpContext ( ) ;
66
- SetupRoutes ( httpContext , requestMethod , requestPath ) ;
67
-
68
- var request = new JsonApiRequest ( ) ;
68
+ IControllerResourceMapping controllerResourceMapping = SetupRoutes ( httpContext , resourceGraph , requestMethod , requestPath ) ;
69
69
70
- var middleware = new JsonApiMiddleware ( _ => Task . CompletedTask , new HttpContextAccessor ( ) ) ;
70
+ var middleware = new JsonApiMiddleware ( _ => Task . CompletedTask , new HttpContextAccessor
71
+ {
72
+ HttpContext = httpContext
73
+ } ) ;
71
74
72
75
// Act
73
- await middleware . InvokeAsync ( httpContext , controllerResourceMappingMock . Object , options , request , NullLogger < JsonApiMiddleware > . Instance ) ;
76
+ await middleware . InvokeAsync ( httpContext , controllerResourceMapping , options , request , NullLogger < JsonApiMiddleware > . Instance ) ;
74
77
75
78
// Assert
76
- request . IsCollection . Should ( ) . Be ( expectIsCollection ) ;
77
79
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 ) ;
78
114
request . WriteOperation . Should ( ) . Be ( expectWriteOperation ) ;
79
- request . IsReadOnly . Should ( ) . Be ( expectIsReadOnly ) ;
80
- request . PrimaryResourceType . ShouldNotBeNull ( ) ;
81
- request . PrimaryResourceType . PublicName . Should ( ) . Be ( "todoItems" ) ;
82
115
}
83
116
84
- private static void SetupRoutes ( HttpContext httpContext , string requestMethod , string requestPath )
117
+ private static IControllerResourceMapping SetupRoutes ( HttpContext httpContext , IResourceGraph resourceGraph , string requestMethod , string requestPath )
85
118
{
86
119
httpContext . Request . Method = requestMethod ;
87
120
@@ -110,6 +143,10 @@ private static void SetupRoutes(HttpContext httpContext, string requestMethod, s
110
143
{
111
144
feature . RouteValues [ "action" ] = "Relationship" ;
112
145
}
146
+ else if ( pathSegments . Contains ( "operations" ) )
147
+ {
148
+ feature . RouteValues [ "action" ] = "PostOperations" ;
149
+ }
113
150
114
151
httpContext . Features . Set < IRouteValuesFeature > ( feature ) ;
115
152
@@ -118,7 +155,30 @@ private static void SetupRoutes(HttpContext httpContext, string requestMethod, s
118
155
ControllerTypeInfo = ( TypeInfo ) typeof ( object )
119
156
} ;
120
157
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
+
121
167
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
122
182
}
123
183
124
184
[ UsedImplicitly ( ImplicitUseTargetFlags . Itself ) ]
@@ -127,7 +187,7 @@ private sealed class Person : Identifiable<int>
127
187
}
128
188
129
189
[ UsedImplicitly ( ImplicitUseTargetFlags . Members ) ]
130
- private sealed class Tag : Identifiable < int >
190
+ private sealed class ItemTag : Identifiable < int >
131
191
{
132
192
[ HasMany ]
133
193
public ISet < TodoItem > TodoItems { get ; set ; } = new HashSet < TodoItem > ( ) ;
@@ -140,7 +200,7 @@ private sealed class TodoItem : Identifiable<int>
140
200
public Person ? Owner { get ; set ; }
141
201
142
202
[ HasMany ]
143
- public ISet < Tag > Tags { get ; set ; } = new HashSet < Tag > ( ) ;
203
+ public ISet < ItemTag > Tags { get ; set ; } = new HashSet < ItemTag > ( ) ;
144
204
}
145
205
}
146
206
}
0 commit comments