@@ -25,20 +25,22 @@ public AtomicCreateResourceWithClientGeneratedIdTests(IntegrationTestContext<Tes
2525
2626 testContext . ConfigureServices ( services =>
2727 {
28- services . AddResourceDefinition < ImplicitlyChangingTextLanguageDefinition > ( ) ;
28+ services . AddResourceDefinition < AssignIdToTextLanguageDefinition > ( ) ;
2929
3030 services . AddSingleton < ResourceDefinitionHitCounter > ( ) ;
3131 services . AddSingleton < ISystemClock , FrozenSystemClock > ( ) ;
3232 } ) ;
33-
34- var options = ( JsonApiOptions ) testContext . Factory . Services . GetRequiredService < IJsonApiOptions > ( ) ;
35- options . ClientIdGeneration = ClientIdGenerationMode . Required ;
3633 }
3734
38- [ Fact ]
39- public async Task Can_create_resource_with_client_generated_guid_ID_having_side_effects ( )
35+ [ Theory ]
36+ [ InlineData ( ClientIdGenerationMode . Allowed ) ]
37+ [ InlineData ( ClientIdGenerationMode . Required ) ]
38+ public async Task Can_create_resource_with_client_generated_guid_ID_having_side_effects ( ClientIdGenerationMode mode )
4039 {
4140 // Arrange
41+ var options = ( JsonApiOptions ) _testContext . Factory . Services . GetRequiredService < IJsonApiOptions > ( ) ;
42+ options . ClientIdGeneration = mode ;
43+
4244 TextLanguage newLanguage = _fakers . TextLanguage . Generate ( ) ;
4345 newLanguage . Id = Guid . NewGuid ( ) ;
4446
@@ -90,10 +92,15 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
9092 } ) ;
9193 }
9294
93- [ Fact ]
94- public async Task Can_create_resource_with_client_generated_string_ID_having_no_side_effects ( )
95+ [ Theory ]
96+ [ InlineData ( ClientIdGenerationMode . Allowed ) ]
97+ [ InlineData ( ClientIdGenerationMode . Required ) ]
98+ public async Task Can_create_resource_with_client_generated_guid_ID_having_no_side_effects ( ClientIdGenerationMode mode )
9599 {
96100 // Arrange
101+ var options = ( JsonApiOptions ) _testContext . Factory . Services . GetRequiredService < IJsonApiOptions > ( ) ;
102+ options . ClientIdGeneration = mode ;
103+
97104 MusicTrack newTrack = _fakers . MusicTrack . Generate ( ) ;
98105 newTrack . Id = Guid . NewGuid ( ) ;
99106
@@ -138,10 +145,72 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
138145 } ) ;
139146 }
140147
141- [ Fact ]
142- public async Task Cannot_create_resource_for_missing_client_generated_ID ( )
148+ [ Theory ]
149+ [ InlineData ( ClientIdGenerationMode . Allowed ) ]
150+ public async Task Can_create_resource_for_missing_client_generated_ID_having_side_effects ( ClientIdGenerationMode mode )
143151 {
144152 // Arrange
153+ var options = ( JsonApiOptions ) _testContext . Factory . Services . GetRequiredService < IJsonApiOptions > ( ) ;
154+ options . ClientIdGeneration = mode ;
155+
156+ string ? newIsoCode = _fakers . TextLanguage . Generate ( ) . IsoCode ;
157+
158+ var requestBody = new
159+ {
160+ atomic__operations = new [ ]
161+ {
162+ new
163+ {
164+ op = "add" ,
165+ data = new
166+ {
167+ type = "textLanguages" ,
168+ attributes = new
169+ {
170+ isoCode = newIsoCode
171+ }
172+ }
173+ }
174+ }
175+ } ;
176+
177+ const string route = "/operations" ;
178+
179+ // Act
180+ ( HttpResponseMessage httpResponse , Document responseDocument ) = await _testContext . ExecutePostAtomicAsync < Document > ( route , requestBody ) ;
181+
182+ // Assert
183+ httpResponse . ShouldHaveStatusCode ( HttpStatusCode . OK ) ;
184+
185+ string isoCode = $ "{ newIsoCode } { ImplicitlyChangingTextLanguageDefinition . Suffix } ";
186+
187+ responseDocument . Results . ShouldHaveCount ( 1 ) ;
188+
189+ responseDocument . Results [ 0 ] . Data . SingleValue . ShouldNotBeNull ( ) . With ( resource =>
190+ {
191+ resource . Type . Should ( ) . Be ( "textLanguages" ) ;
192+ resource . Attributes . ShouldContainKey ( "isoCode" ) . With ( value => value . Should ( ) . Be ( isoCode ) ) ;
193+ resource . Relationships . ShouldNotBeEmpty ( ) ;
194+ } ) ;
195+
196+ Guid newLanguageId = Guid . Parse ( responseDocument . Results [ 0 ] . Data . SingleValue ! . Id . ShouldNotBeNull ( ) ) ;
197+
198+ await _testContext . RunOnDatabaseAsync ( async dbContext =>
199+ {
200+ TextLanguage languageInDatabase = await dbContext . TextLanguages . FirstWithIdAsync ( newLanguageId ) ;
201+
202+ languageInDatabase . IsoCode . Should ( ) . Be ( isoCode ) ;
203+ } ) ;
204+ }
205+
206+ [ Theory ]
207+ [ InlineData ( ClientIdGenerationMode . Required ) ]
208+ public async Task Cannot_create_resource_for_missing_client_generated_ID ( ClientIdGenerationMode mode )
209+ {
210+ // Arrange
211+ var options = ( JsonApiOptions ) _testContext . Factory . Services . GetRequiredService < IJsonApiOptions > ( ) ;
212+ options . ClientIdGeneration = mode ;
213+
145214 string ? newIsoCode = _fakers . TextLanguage . Generate ( ) . IsoCode ;
146215
147216 var requestBody = new
@@ -182,10 +251,15 @@ public async Task Cannot_create_resource_for_missing_client_generated_ID()
182251 error . Meta . ShouldContainKey ( "requestBody" ) . With ( value => value . ShouldNotBeNull ( ) . ToString ( ) . ShouldNotBeEmpty ( ) ) ;
183252 }
184253
185- [ Fact ]
186- public async Task Cannot_create_resource_for_existing_client_generated_ID ( )
254+ [ Theory ]
255+ [ InlineData ( ClientIdGenerationMode . Allowed ) ]
256+ [ InlineData ( ClientIdGenerationMode . Required ) ]
257+ public async Task Cannot_create_resource_for_existing_client_generated_ID ( ClientIdGenerationMode mode )
187258 {
188259 // Arrange
260+ var options = ( JsonApiOptions ) _testContext . Factory . Services . GetRequiredService < IJsonApiOptions > ( ) ;
261+ options . ClientIdGeneration = mode ;
262+
189263 TextLanguage existingLanguage = _fakers . TextLanguage . Generate ( ) ;
190264 existingLanguage . Id = Guid . NewGuid ( ) ;
191265
@@ -237,10 +311,15 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
237311 error . Meta . Should ( ) . NotContainKey ( "requestBody" ) ;
238312 }
239313
240- [ Fact ]
241- public async Task Cannot_create_resource_for_incompatible_ID ( )
314+ [ Theory ]
315+ [ InlineData ( ClientIdGenerationMode . Allowed ) ]
316+ [ InlineData ( ClientIdGenerationMode . Required ) ]
317+ public async Task Cannot_create_resource_for_incompatible_ID ( ClientIdGenerationMode mode )
242318 {
243319 // Arrange
320+ var options = ( JsonApiOptions ) _testContext . Factory . Services . GetRequiredService < IJsonApiOptions > ( ) ;
321+ options . ClientIdGeneration = mode ;
322+
244323 string guid = Unknown . StringId . Guid ;
245324
246325 var requestBody = new
@@ -281,10 +360,71 @@ public async Task Cannot_create_resource_for_incompatible_ID()
281360 error . Meta . ShouldContainKey ( "requestBody" ) . With ( value => value . ShouldNotBeNull ( ) . ToString ( ) . ShouldNotBeEmpty ( ) ) ;
282361 }
283362
284- [ Fact ]
285- public async Task Cannot_create_resource_with_local_ID ( )
363+ [ Theory ]
364+ [ InlineData ( ClientIdGenerationMode . Allowed ) ]
365+ public async Task Can_create_resource_with_local_ID ( ClientIdGenerationMode mode )
366+ {
367+ // Arrange
368+ var options = ( JsonApiOptions ) _testContext . Factory . Services . GetRequiredService < IJsonApiOptions > ( ) ;
369+ options . ClientIdGeneration = mode ;
370+
371+ string newTitle = _fakers . MusicTrack . Generate ( ) . Title ;
372+
373+ var requestBody = new
374+ {
375+ atomic__operations = new [ ]
376+ {
377+ new
378+ {
379+ op = "add" ,
380+ data = new
381+ {
382+ type = "musicTracks" ,
383+ lid = "new-server-id" ,
384+ attributes = new
385+ {
386+ title = newTitle
387+ }
388+ }
389+ }
390+ }
391+ } ;
392+
393+ const string route = "/operations" ;
394+
395+ // Act
396+ ( HttpResponseMessage httpResponse , Document responseDocument ) = await _testContext . ExecutePostAtomicAsync < Document > ( route , requestBody ) ;
397+
398+ // Assert
399+ httpResponse . ShouldHaveStatusCode ( HttpStatusCode . OK ) ;
400+
401+ responseDocument . Results . ShouldHaveCount ( 1 ) ;
402+
403+ responseDocument . Results [ 0 ] . Data . SingleValue . ShouldNotBeNull ( ) . With ( resource =>
404+ {
405+ resource . Type . Should ( ) . Be ( "musicTracks" ) ;
406+ resource . Attributes . ShouldContainKey ( "title" ) . With ( value => value . Should ( ) . Be ( newTitle ) ) ;
407+ resource . Relationships . Should ( ) . BeNull ( ) ;
408+ } ) ;
409+
410+ Guid newTrackId = Guid . Parse ( responseDocument . Results [ 0 ] . Data . SingleValue ! . Id . ShouldNotBeNull ( ) ) ;
411+
412+ await _testContext . RunOnDatabaseAsync ( async dbContext =>
413+ {
414+ MusicTrack languageInDatabase = await dbContext . MusicTracks . FirstWithIdAsync ( newTrackId ) ;
415+
416+ languageInDatabase . Title . Should ( ) . Be ( newTitle ) ;
417+ } ) ;
418+ }
419+
420+ [ Theory ]
421+ [ InlineData ( ClientIdGenerationMode . Required ) ]
422+ public async Task Cannot_create_resource_with_local_ID ( ClientIdGenerationMode mode )
286423 {
287424 // Arrange
425+ var options = ( JsonApiOptions ) _testContext . Factory . Services . GetRequiredService < IJsonApiOptions > ( ) ;
426+ options . ClientIdGeneration = mode ;
427+
288428 var requestBody = new
289429 {
290430 atomic__operations = new [ ]
@@ -320,10 +460,15 @@ public async Task Cannot_create_resource_with_local_ID()
320460 error . Meta . ShouldContainKey ( "requestBody" ) . With ( value => value . ShouldNotBeNull ( ) . ToString ( ) . ShouldNotBeEmpty ( ) ) ;
321461 }
322462
323- [ Fact ]
324- public async Task Cannot_create_resource_for_ID_and_local_ID ( )
463+ [ Theory ]
464+ [ InlineData ( ClientIdGenerationMode . Allowed ) ]
465+ [ InlineData ( ClientIdGenerationMode . Required ) ]
466+ public async Task Cannot_create_resource_for_ID_and_local_ID ( ClientIdGenerationMode mode )
325467 {
326468 // Arrange
469+ var options = ( JsonApiOptions ) _testContext . Factory . Services . GetRequiredService < IJsonApiOptions > ( ) ;
470+ options . ClientIdGeneration = mode ;
471+
327472 var requestBody = new
328473 {
329474 atomic__operations = new [ ]
0 commit comments