1- using System . Collections . Generic ;
1+ using System . Collections ;
2+ using System . Collections . Generic ;
23using System . Text . Json . Serialization ;
34using System . Text . Json . Serialization . Metadata ;
45using SystemTextJsonPatch . Exceptions ;
6+ using SystemTextJsonPatch . Operations ;
57using Xunit ;
68
79namespace SystemTextJsonPatch . IntegrationTests ;
@@ -130,11 +132,13 @@ private class Address
130132 private class IntDictionary
131133 {
132134 public IDictionary < string , int > DictionaryOfStringToInteger { get ; } = new Dictionary < string , int > ( ) ;
135+ public IDictionary NonGenericDictionary { get ; } = new NonGenericDictionary ( ) ;
133136 }
134137
135138 private class CustomerDictionary
136139 {
137- public IDictionary < int , Customer > DictionaryOfStringToCustomer { get ; } = new Dictionary < int , Customer > ( ) ;
140+ public IDictionary < int , Customer > DictionaryOfIntegerToCustomer { get ; } = new Dictionary < int , Customer > ( ) ;
141+ public IDictionary NonGenericDictionary { get ; } = new NonGenericDictionary ( ) ;
138142 }
139143
140144#if NET7_0_OR_GREATER
@@ -165,9 +169,9 @@ public void TestPocoObjectSucceeds()
165169 var key1 = 100 ;
166170 var value1 = new Customer ( ) { Name = "James" } ;
167171 var model = new CustomerDictionary ( ) ;
168- model . DictionaryOfStringToCustomer [ key1 ] = value1 ;
172+ model . DictionaryOfIntegerToCustomer [ key1 ] = value1 ;
169173 var patchDocument = new JsonPatchDocument ( ) ;
170- patchDocument . Test ( $ "/DictionaryOfStringToCustomer /{ key1 } /Name", "James" ) ;
174+ patchDocument . Test ( $ "/DictionaryOfIntegerToCustomer /{ key1 } /Name", "James" ) ;
171175
172176 // Act & Assert
173177 patchDocument . ApplyTo ( model ) ;
@@ -180,9 +184,9 @@ public void TestPocoObjectFailsWhenTestValueIsNotEqualToObjectValue()
180184 var key1 = 100 ;
181185 var value1 = new Customer ( ) { Name = "James" } ;
182186 var model = new CustomerDictionary ( ) ;
183- model . DictionaryOfStringToCustomer [ key1 ] = value1 ;
187+ model . DictionaryOfIntegerToCustomer [ key1 ] = value1 ;
184188 var patchDocument = new JsonPatchDocument ( ) ;
185- patchDocument . Test ( $ "/DictionaryOfStringToCustomer /{ key1 } /Name", "Mike" ) ;
189+ patchDocument . Test ( $ "/DictionaryOfIntegerToCustomer /{ key1 } /Name", "Mike" ) ;
186190
187191 // Act
188192 var exception = Assert . Throws < JsonPatchTestOperationException > ( ( ) => { patchDocument . ApplyTo ( model ) ; } ) ;
@@ -200,19 +204,19 @@ public void AddPocoObjectSucceeds()
200204 var key2 = 200 ;
201205 var value2 = new Customer ( ) { Name = "Mike" } ;
202206 var model = new CustomerDictionary ( ) ;
203- model . DictionaryOfStringToCustomer [ key1 ] = value1 ;
207+ model . DictionaryOfIntegerToCustomer [ key1 ] = value1 ;
204208 var patchDocument = new JsonPatchDocument ( ) ;
205- patchDocument . Add ( $ "/DictionaryOfStringToCustomer /{ key2 } ", value2 ) ;
209+ patchDocument . Add ( $ "/DictionaryOfIntegerToCustomer /{ key2 } ", value2 ) ;
206210
207211 // Act
208212 patchDocument . ApplyTo ( model ) ;
209213
210214 // Assert
211- Assert . Equal ( 2 , model . DictionaryOfStringToCustomer . Count ) ;
212- var actualValue1 = model . DictionaryOfStringToCustomer [ key1 ] ;
215+ Assert . Equal ( 2 , model . DictionaryOfIntegerToCustomer . Count ) ;
216+ var actualValue1 = model . DictionaryOfIntegerToCustomer [ key1 ] ;
213217 Assert . NotNull ( actualValue1 ) ;
214218 Assert . Equal ( "James" , actualValue1 . Name ) ;
215- var actualValue2 = model . DictionaryOfStringToCustomer [ key2 ] ;
219+ var actualValue2 = model . DictionaryOfIntegerToCustomer [ key2 ] ;
216220 Assert . NotNull ( actualValue2 ) ;
217221 Assert . Equal ( "Mike" , actualValue2 . Name ) ;
218222 }
@@ -226,17 +230,17 @@ public void AddReplacesPocoObjectSucceeds()
226230 var key2 = 200 ;
227231 var value2 = new Customer ( ) { Name = "Mike" } ;
228232 var model = new CustomerDictionary ( ) ;
229- model . DictionaryOfStringToCustomer [ key1 ] = value1 ;
230- model . DictionaryOfStringToCustomer [ key2 ] = value2 ;
233+ model . DictionaryOfIntegerToCustomer [ key1 ] = value1 ;
234+ model . DictionaryOfIntegerToCustomer [ key2 ] = value2 ;
231235 var patchDocument = new JsonPatchDocument ( ) ;
232- patchDocument . Add ( $ "/DictionaryOfStringToCustomer /{ key1 } /Name", "James" ) ;
236+ patchDocument . Add ( $ "/DictionaryOfIntegerToCustomer /{ key1 } /Name", "James" ) ;
233237
234238 // Act
235239 patchDocument . ApplyTo ( model ) ;
236240
237241 // Assert
238- Assert . Equal ( 2 , model . DictionaryOfStringToCustomer . Count ) ;
239- var actualValue1 = model . DictionaryOfStringToCustomer [ key1 ] ;
242+ Assert . Equal ( 2 , model . DictionaryOfIntegerToCustomer . Count ) ;
243+ var actualValue1 = model . DictionaryOfIntegerToCustomer [ key1 ] ;
240244 Assert . NotNull ( actualValue1 ) ;
241245 Assert . Equal ( "James" , actualValue1 . Name ) ;
242246 }
@@ -271,16 +275,16 @@ public void RemovePocoObjectSucceeds()
271275 var key2 = 200 ;
272276 var value2 = new Customer ( ) { Name = "Mike" } ;
273277 var model = new CustomerDictionary ( ) ;
274- model . DictionaryOfStringToCustomer [ key1 ] = value1 ;
275- model . DictionaryOfStringToCustomer [ key2 ] = value2 ;
278+ model . DictionaryOfIntegerToCustomer [ key1 ] = value1 ;
279+ model . DictionaryOfIntegerToCustomer [ key2 ] = value2 ;
276280 var patchDocument = new JsonPatchDocument ( ) ;
277- patchDocument . Remove ( $ "/DictionaryOfStringToCustomer /{ key1 } /Name") ;
281+ patchDocument . Remove ( $ "/DictionaryOfIntegerToCustomer /{ key1 } /Name") ;
278282
279283 // Act
280284 patchDocument . ApplyTo ( model ) ;
281285
282286 // Assert
283- var actualValue1 = model . DictionaryOfStringToCustomer [ key1 ] ;
287+ var actualValue1 = model . DictionaryOfIntegerToCustomer [ key1 ] ;
284288 Assert . Null ( actualValue1 . Name ) ;
285289 }
286290
@@ -293,16 +297,16 @@ public void MovePocoObjectSucceeds()
293297 var key2 = 200 ;
294298 var value2 = new Customer ( ) { Name = "Mike" } ;
295299 var model = new CustomerDictionary ( ) ;
296- model . DictionaryOfStringToCustomer [ key1 ] = value1 ;
297- model . DictionaryOfStringToCustomer [ key2 ] = value2 ;
300+ model . DictionaryOfIntegerToCustomer [ key1 ] = value1 ;
301+ model . DictionaryOfIntegerToCustomer [ key2 ] = value2 ;
298302 var patchDocument = new JsonPatchDocument ( ) ;
299- patchDocument . Move ( $ "/DictionaryOfStringToCustomer /{ key1 } /Name", $ "/DictionaryOfStringToCustomer /{ key2 } /Name") ;
303+ patchDocument . Move ( $ "/DictionaryOfIntegerToCustomer /{ key1 } /Name", $ "/DictionaryOfIntegerToCustomer /{ key2 } /Name") ;
300304
301305 // Act
302306 patchDocument . ApplyTo ( model ) ;
303307
304308 // Assert
305- var actualValue2 = model . DictionaryOfStringToCustomer [ key2 ] ;
309+ var actualValue2 = model . DictionaryOfIntegerToCustomer [ key2 ] ;
306310 Assert . NotNull ( actualValue2 ) ;
307311 Assert . Equal ( "James" , actualValue2 . Name ) ;
308312 }
@@ -316,17 +320,17 @@ public void CopyPocoObjectSucceeds()
316320 var key2 = 200 ;
317321 var value2 = new Customer ( ) { Name = "Mike" } ;
318322 var model = new CustomerDictionary ( ) ;
319- model . DictionaryOfStringToCustomer [ key1 ] = value1 ;
320- model . DictionaryOfStringToCustomer [ key2 ] = value2 ;
323+ model . DictionaryOfIntegerToCustomer [ key1 ] = value1 ;
324+ model . DictionaryOfIntegerToCustomer [ key2 ] = value2 ;
321325 var patchDocument = new JsonPatchDocument ( ) ;
322- patchDocument . Copy ( $ "/DictionaryOfStringToCustomer /{ key1 } /Name", $ "/DictionaryOfStringToCustomer /{ key2 } /Name") ;
326+ patchDocument . Copy ( $ "/DictionaryOfIntegerToCustomer /{ key1 } /Name", $ "/DictionaryOfIntegerToCustomer /{ key2 } /Name") ;
323327
324328 // Act
325329 patchDocument . ApplyTo ( model ) ;
326330
327331 // Assert
328- Assert . Equal ( 2 , model . DictionaryOfStringToCustomer . Count ) ;
329- var actualValue2 = model . DictionaryOfStringToCustomer [ key2 ] ;
332+ Assert . Equal ( 2 , model . DictionaryOfIntegerToCustomer . Count ) ;
333+ var actualValue2 = model . DictionaryOfIntegerToCustomer [ key2 ] ;
330334 Assert . NotNull ( actualValue2 ) ;
331335 Assert . Equal ( "James" , actualValue2 . Name ) ;
332336 }
@@ -340,17 +344,17 @@ public void ReplacePocoObjectSucceeds()
340344 var key2 = 200 ;
341345 var value2 = new Customer ( ) { Name = "Mike" } ;
342346 var model = new CustomerDictionary ( ) ;
343- model . DictionaryOfStringToCustomer [ key1 ] = value1 ;
344- model . DictionaryOfStringToCustomer [ key2 ] = value2 ;
347+ model . DictionaryOfIntegerToCustomer [ key1 ] = value1 ;
348+ model . DictionaryOfIntegerToCustomer [ key2 ] = value2 ;
345349 var patchDocument = new JsonPatchDocument ( ) ;
346- patchDocument . Replace ( $ "/DictionaryOfStringToCustomer /{ key1 } /Name", "James" ) ;
350+ patchDocument . Replace ( $ "/DictionaryOfIntegerToCustomer /{ key1 } /Name", "James" ) ;
347351
348352 // Act
349353 patchDocument . ApplyTo ( model ) ;
350354
351355 // Assert
352- Assert . Equal ( 2 , model . DictionaryOfStringToCustomer . Count ) ;
353- var actualValue1 = model . DictionaryOfStringToCustomer [ key1 ] ;
356+ Assert . Equal ( 2 , model . DictionaryOfIntegerToCustomer . Count ) ;
357+ var actualValue1 = model . DictionaryOfIntegerToCustomer [ key1 ] ;
354358 Assert . NotNull ( actualValue1 ) ;
355359 Assert . Equal ( "James" , actualValue1 . Name ) ;
356360 }
@@ -379,4 +383,118 @@ public void ReplacePocoObjectWithEscapingSucceeds()
379383 Assert . Equal ( 300 , actualValue1 ) ;
380384 Assert . Equal ( 200 , actualValue2 ) ;
381385 }
386+
387+ [ Theory ]
388+ [ InlineData ( "test" , "DictionaryOfStringToInteger" ) ]
389+ [ InlineData ( "move" , "DictionaryOfStringToInteger" ) ]
390+ [ InlineData ( "copy" , "DictionaryOfStringToInteger" ) ]
391+ [ InlineData ( "test" , "NonGenericDictionary" ) ]
392+ [ InlineData ( "move" , "NonGenericDictionary" ) ]
393+ [ InlineData ( "copy" , "NonGenericDictionary" ) ]
394+ public void ReadIntegerValueOfMissingKeyThrowsJsonPatchExceptionWithDefaultErrorReporter ( string op , string dictionaryPropertyName )
395+ {
396+ // Arrange
397+ var model = new IntDictionary ( ) ;
398+ var missingKey = "eight" ;
399+ var operation = new Operation < IntDictionary > (
400+ op ,
401+ path : $ "/{ dictionaryPropertyName } /{ missingKey } ",
402+ from : $ "/{ dictionaryPropertyName } /{ missingKey } ",
403+ value : 8 ) ;
404+
405+ var patchDocument = new JsonPatchDocument < IntDictionary > ( ) ;
406+ patchDocument . Operations . Add ( operation ) ;
407+
408+ // Act
409+ var exception = Assert . Throws < JsonPatchException > ( ( ) => { patchDocument . ApplyTo ( model ) ; } ) ;
410+
411+ // Assert
412+ Assert . Equal ( $ "The target location specified by path segment '{ missingKey } ' was not found.", exception . Message ) ;
413+ }
414+
415+ [ Theory ]
416+ [ InlineData ( "test" , "DictionaryOfStringToInteger" ) ]
417+ [ InlineData ( "move" , "DictionaryOfStringToInteger" ) ]
418+ [ InlineData ( "copy" , "DictionaryOfStringToInteger" ) ]
419+ [ InlineData ( "test" , "NonGenericDictionary" ) ]
420+ [ InlineData ( "move" , "NonGenericDictionary" ) ]
421+ [ InlineData ( "copy" , "NonGenericDictionary" ) ]
422+ public void ReadIntegerValueOfMissingKeyDoesNotThrowExceptionWithCustomErrorReporter ( string op , string dictionaryPropertyName )
423+ {
424+ // Arrange
425+ var patchErrorLogger = new TestErrorLogger < DictionaryTest > ( ) ;
426+ var model = new IntDictionary ( ) ;
427+ var missingKey = "eight" ;
428+ var operation = new Operation < IntDictionary > (
429+ op ,
430+ path : $ "/{ dictionaryPropertyName } /{ missingKey } ",
431+ from : $ "/{ dictionaryPropertyName } /{ missingKey } ",
432+ value : 8 ) ;
433+
434+ var patchDocument = new JsonPatchDocument < IntDictionary > ( ) ;
435+ patchDocument . Operations . Add ( operation ) ;
436+
437+ // Act
438+ patchDocument . ApplyTo ( model , patchErrorLogger . LogErrorMessage ) ;
439+
440+ // Assert
441+ Assert . Equal ( $ "The target location specified by path segment '{ missingKey } ' was not found.", patchErrorLogger . ErrorMessage ) ;
442+ }
443+
444+ [ Theory ]
445+ [ InlineData ( "test" , "DictionaryOfIntegerToCustomer" ) ]
446+ [ InlineData ( "move" , "DictionaryOfIntegerToCustomer" ) ]
447+ [ InlineData ( "copy" , "DictionaryOfIntegerToCustomer" ) ]
448+ [ InlineData ( "test" , "NonGenericDictionary" ) ]
449+ [ InlineData ( "move" , "NonGenericDictionary" ) ]
450+ [ InlineData ( "copy" , "NonGenericDictionary" ) ]
451+ public void ReadPocoObjectValueOfMissingKeyThrowsJsonPatchExceptionWithDefaultErrorReporter ( string op , string dictionaryPropertyName )
452+ {
453+ // Arrange
454+ var model = new CustomerDictionary ( ) ;
455+ var missingKey = 8 ;
456+ var operation = new Operation < CustomerDictionary > (
457+ op ,
458+ path : $ "/{ dictionaryPropertyName } /{ missingKey } /Address/City",
459+ from : $ "/{ dictionaryPropertyName } /{ missingKey } /Address/City",
460+ value : "Nowhere" ) ;
461+
462+ var patchDocument = new JsonPatchDocument < CustomerDictionary > ( ) ;
463+ patchDocument . Operations . Add ( operation ) ;
464+
465+ // Act
466+ var exception = Assert . Throws < JsonPatchException > ( ( ) => { patchDocument . ApplyTo ( model ) ; } ) ;
467+
468+ // Assert
469+ Assert . Equal ( $ "The target location specified by path segment '{ missingKey } ' was not found.", exception . Message ) ;
470+ }
471+
472+ [ Theory ]
473+ [ InlineData ( "test" , "DictionaryOfIntegerToCustomer" ) ]
474+ [ InlineData ( "move" , "DictionaryOfIntegerToCustomer" ) ]
475+ [ InlineData ( "copy" , "DictionaryOfIntegerToCustomer" ) ]
476+ [ InlineData ( "test" , "NonGenericDictionary" ) ]
477+ [ InlineData ( "move" , "NonGenericDictionary" ) ]
478+ [ InlineData ( "copy" , "NonGenericDictionary" ) ]
479+ public void ReadPocoObjectValueOfMissingKeyDoesNotThrowExceptionWithCustomErrorReporter ( string op , string dictionaryPropertyName )
480+ {
481+ // Arrange
482+ var patchErrorLogger = new TestErrorLogger < DictionaryTest > ( ) ;
483+ var model = new CustomerDictionary ( ) ;
484+ var missingKey = 8 ;
485+ var operation = new Operation < CustomerDictionary > (
486+ op ,
487+ path : $ "/{ dictionaryPropertyName } /{ missingKey } /Address/City",
488+ from : $ "/{ dictionaryPropertyName } /{ missingKey } /Address/City",
489+ value : "Nowhere" ) ;
490+
491+ var patchDocument = new JsonPatchDocument < CustomerDictionary > ( ) ;
492+ patchDocument . Operations . Add ( operation ) ;
493+
494+ // Act
495+ patchDocument . ApplyTo ( model , patchErrorLogger . LogErrorMessage ) ;
496+
497+ // Assert
498+ Assert . Equal ( $ "The target location specified by path segment '{ missingKey } ' was not found.", patchErrorLogger . ErrorMessage ) ;
499+ }
382500}
0 commit comments