Combine ExpandoObjectAdapter and DictionaryAdapter (#106)
Use JsonDictionaryContract in the DictionaryAdapter and combine with ExpandoObjectAdapter
This commit is contained in:
parent
3d6a8615de
commit
0f51c56c3f
|
|
@ -1,111 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace Microsoft.AspNetCore.JsonPatch.Internal
|
||||
{
|
||||
public class DictionaryAdapter : IAdapter
|
||||
{
|
||||
public bool TryAdd(
|
||||
object target,
|
||||
string segment,
|
||||
IContractResolver contractResolver,
|
||||
object value,
|
||||
out string errorMessage)
|
||||
{
|
||||
var dictionary = (IDictionary)target;
|
||||
|
||||
// As per JsonPatch spec, if a key already exists, adding should replace the existing value
|
||||
dictionary[segment] = value;
|
||||
|
||||
errorMessage = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryGet(
|
||||
object target,
|
||||
string segment,
|
||||
IContractResolver contractResolver,
|
||||
out object value,
|
||||
out string errorMessage)
|
||||
{
|
||||
var dictionary = (IDictionary)target;
|
||||
|
||||
value = dictionary[segment];
|
||||
errorMessage = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryRemove(
|
||||
object target,
|
||||
string segment,
|
||||
IContractResolver contractResolver,
|
||||
out string errorMessage)
|
||||
{
|
||||
var dictionary = (IDictionary)target;
|
||||
|
||||
// As per JsonPatch spec, the target location must exist for remove to be successful
|
||||
if (!dictionary.Contains(segment))
|
||||
{
|
||||
errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment);
|
||||
return false;
|
||||
}
|
||||
|
||||
dictionary.Remove(segment);
|
||||
errorMessage = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryReplace(
|
||||
object target,
|
||||
string segment,
|
||||
IContractResolver contractResolver,
|
||||
object value,
|
||||
out string errorMessage)
|
||||
{
|
||||
var dictionary = (IDictionary)target;
|
||||
|
||||
// As per JsonPatch spec, the target location must exist for remove to be successful
|
||||
if (!dictionary.Contains(segment))
|
||||
{
|
||||
errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment);
|
||||
return false;
|
||||
}
|
||||
|
||||
dictionary[segment] = value;
|
||||
errorMessage = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryTraverse(
|
||||
object target,
|
||||
string segment,
|
||||
IContractResolver contractResolver,
|
||||
out object nextTarget,
|
||||
out string errorMessage)
|
||||
{
|
||||
var dictionary = target as IDictionary;
|
||||
if (dictionary == null)
|
||||
{
|
||||
nextTarget = null;
|
||||
errorMessage = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dictionary.Contains(segment))
|
||||
{
|
||||
nextTarget = dictionary[segment];
|
||||
errorMessage = null;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
nextTarget = null;
|
||||
errorMessage = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,12 +2,11 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace Microsoft.AspNetCore.JsonPatch.Internal
|
||||
{
|
||||
public class ExpandoObjectAdapter : IAdapter
|
||||
public class DictionaryAdapter<TKey, TValue> : IAdapter
|
||||
{
|
||||
public bool TryAdd(
|
||||
object target,
|
||||
|
|
@ -18,11 +17,20 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
|
|||
{
|
||||
var contract = (JsonDictionaryContract)contractResolver.ResolveContract(target.GetType());
|
||||
var key = contract.DictionaryKeyResolver(segment);
|
||||
var dictionary = (IDictionary<string, object>)target;
|
||||
var dictionary = (IDictionary<TKey, TValue>)target;
|
||||
|
||||
// As per JsonPatch spec, if a key already exists, adding should replace the existing value
|
||||
dictionary[key] = ConvertValue(dictionary, key, value);
|
||||
if (!TryConvertKey(key, out var convertedKey, out errorMessage))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!TryConvertValue(value, out var convertedValue, out errorMessage))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
dictionary[convertedKey] = convertedValue;
|
||||
errorMessage = null;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -36,10 +44,22 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
|
|||
{
|
||||
var contract = (JsonDictionaryContract)contractResolver.ResolveContract(target.GetType());
|
||||
var key = contract.DictionaryKeyResolver(segment);
|
||||
var dictionary = (IDictionary<string, object>)target;
|
||||
var dictionary = (IDictionary<TKey, TValue>)target;
|
||||
|
||||
value = dictionary[key];
|
||||
if (!TryConvertKey(key, out var convertedKey, out errorMessage))
|
||||
{
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!dictionary.ContainsKey(convertedKey))
|
||||
{
|
||||
value = null;
|
||||
errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment);
|
||||
return false;
|
||||
}
|
||||
|
||||
value = dictionary[convertedKey];
|
||||
errorMessage = null;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -52,16 +72,21 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
|
|||
{
|
||||
var contract = (JsonDictionaryContract)contractResolver.ResolveContract(target.GetType());
|
||||
var key = contract.DictionaryKeyResolver(segment);
|
||||
var dictionary = (IDictionary<string, object>)target;
|
||||
var dictionary = (IDictionary<TKey, TValue>)target;
|
||||
|
||||
if (!TryConvertKey(key, out var convertedKey, out errorMessage))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// As per JsonPatch spec, the target location must exist for remove to be successful
|
||||
if (!dictionary.ContainsKey(key))
|
||||
if (!dictionary.ContainsKey(convertedKey))
|
||||
{
|
||||
errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment);
|
||||
return false;
|
||||
}
|
||||
|
||||
dictionary.Remove(key);
|
||||
dictionary.Remove(convertedKey);
|
||||
|
||||
errorMessage = null;
|
||||
return true;
|
||||
|
|
@ -76,16 +101,26 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
|
|||
{
|
||||
var contract = (JsonDictionaryContract)contractResolver.ResolveContract(target.GetType());
|
||||
var key = contract.DictionaryKeyResolver(segment);
|
||||
var dictionary = (IDictionary<string, object>)target;
|
||||
var dictionary = (IDictionary<TKey, TValue>)target;
|
||||
|
||||
if (!TryConvertKey(key, out var convertedKey, out errorMessage))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// As per JsonPatch spec, the target location must exist for remove to be successful
|
||||
if (!dictionary.ContainsKey(key))
|
||||
if (!dictionary.ContainsKey(convertedKey))
|
||||
{
|
||||
errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment);
|
||||
return false;
|
||||
}
|
||||
|
||||
dictionary[key] = ConvertValue(dictionary, key, value);
|
||||
if (!TryConvertValue(value, out var convertedValue, out errorMessage))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
dictionary[convertedKey] = convertedValue;
|
||||
|
||||
errorMessage = null;
|
||||
return true;
|
||||
|
|
@ -98,21 +133,19 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
|
|||
out object nextTarget,
|
||||
out string errorMessage)
|
||||
{
|
||||
var expandoObject = target as ExpandoObject;
|
||||
if (expandoObject == null)
|
||||
var contract = (JsonDictionaryContract)contractResolver.ResolveContract(target.GetType());
|
||||
var key = contract.DictionaryKeyResolver(segment);
|
||||
var dictionary = (IDictionary<TKey, TValue>)target;
|
||||
|
||||
if (!TryConvertKey(key, out var convertedKey, out errorMessage))
|
||||
{
|
||||
errorMessage = null;
|
||||
nextTarget = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
var contract = (JsonDictionaryContract)contractResolver.ResolveContract(target.GetType());
|
||||
var key = contract.DictionaryKeyResolver(segment);
|
||||
var dictionary = (IDictionary<string, object>)expandoObject;
|
||||
|
||||
if (dictionary.ContainsKey(key))
|
||||
if (dictionary.ContainsKey(convertedKey))
|
||||
{
|
||||
nextTarget = dictionary[key];
|
||||
nextTarget = dictionary[convertedKey];
|
||||
errorMessage = null;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -124,20 +157,38 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
|
|||
}
|
||||
}
|
||||
|
||||
private object ConvertValue(IDictionary<string, object> dictionary, string key, object newValue)
|
||||
private bool TryConvertKey(string key, out TKey convertedKey, out string errorMessage)
|
||||
{
|
||||
if (dictionary.TryGetValue(key, out var existingValue))
|
||||
var conversionResult = ConversionResultProvider.ConvertTo(key, typeof(TKey));
|
||||
if (conversionResult.CanBeConverted)
|
||||
{
|
||||
if (existingValue != null)
|
||||
{
|
||||
var conversionResult = ConversionResultProvider.ConvertTo(newValue, existingValue.GetType());
|
||||
if (conversionResult.CanBeConverted)
|
||||
{
|
||||
return conversionResult.ConvertedInstance;
|
||||
}
|
||||
}
|
||||
errorMessage = null;
|
||||
convertedKey = (TKey)conversionResult.ConvertedInstance;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
errorMessage = Resources.FormatInvalidPathSegment(key);
|
||||
convertedKey = default(TKey);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryConvertValue(object value, out TValue convertedValue, out string errorMessage)
|
||||
{
|
||||
var conversionResult = ConversionResultProvider.ConvertTo(value, typeof(TValue));
|
||||
if (conversionResult.CanBeConverted)
|
||||
{
|
||||
errorMessage = null;
|
||||
convertedValue = (TValue)conversionResult.ConvertedInstance;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
errorMessage = Resources.FormatInvalidValueForProperty(value);
|
||||
convertedValue = default(TValue);
|
||||
return false;
|
||||
}
|
||||
return newValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,9 @@
|
|||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using Microsoft.AspNetCore.JsonPatch.Adapters;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace Microsoft.AspNetCore.JsonPatch.Internal
|
||||
|
|
@ -49,22 +51,21 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
|
|||
|
||||
private IAdapter SelectAdapater(object targetObject)
|
||||
{
|
||||
if (targetObject is ExpandoObject)
|
||||
{
|
||||
return new ExpandoObjectAdapter();
|
||||
}
|
||||
else if (targetObject is IDynamicMetaObjectProvider)
|
||||
{
|
||||
return new DynamicObjectAdapter();
|
||||
}
|
||||
else if (targetObject is IDictionary)
|
||||
{
|
||||
return new DictionaryAdapter();
|
||||
}
|
||||
else if (targetObject is IList)
|
||||
var jsonContract = _contractResolver.ResolveContract(targetObject.GetType());
|
||||
|
||||
if (targetObject is IList)
|
||||
{
|
||||
return new ListAdapter();
|
||||
}
|
||||
else if (jsonContract is JsonDictionaryContract jsonDictionaryContract)
|
||||
{
|
||||
var type = typeof(DictionaryAdapter<,>).MakeGenericType(jsonDictionaryContract.DictionaryKeyType, jsonDictionaryContract.DictionaryValueType);
|
||||
return (IAdapter)Activator.CreateInstance(type);
|
||||
}
|
||||
else if (jsonContract is JsonDynamicContract)
|
||||
{
|
||||
return new DynamicObjectAdapter();
|
||||
}
|
||||
else
|
||||
{
|
||||
return new PocoAdapter();
|
||||
|
|
|
|||
|
|
@ -37,18 +37,8 @@ namespace Microsoft.AspNetCore.JsonPatch
|
|||
// Create from list of operations
|
||||
public JsonPatchDocument(List<Operation<TModel>> operations, IContractResolver contractResolver)
|
||||
{
|
||||
if (operations == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(operations));
|
||||
}
|
||||
|
||||
if (contractResolver == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(contractResolver));
|
||||
}
|
||||
|
||||
Operations = operations;
|
||||
ContractResolver = contractResolver;
|
||||
Operations = operations ?? throw new ArgumentNullException(nameof(operations));
|
||||
ContractResolver = contractResolver ?? throw new ArgumentNullException(nameof(contractResolver));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -206,6 +206,20 @@ namespace Microsoft.AspNetCore.JsonPatch
|
|||
internal static string FormatPatchNotSupportedForNonGenericLists(object p0)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("PatchNotSupportedForNonGenericLists"), p0);
|
||||
|
||||
/// <summary>
|
||||
/// The provided path segment '{0}' cannot be converted to the target type.
|
||||
/// </summary>
|
||||
internal static string InvalidPathSegment
|
||||
{
|
||||
get => GetString("InvalidPathSegment");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The provided path segment '{0}' cannot be converted to the target type.
|
||||
/// </summary>
|
||||
internal static string FormatInvalidPathSegment(object p0)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("InvalidPathSegment"), p0);
|
||||
|
||||
/// <summary>
|
||||
/// The target location specified by path segment '{0}' was not found.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -144,6 +144,9 @@
|
|||
<data name="InvalidJsonPatchOperation" xml:space="preserve">
|
||||
<value>Invalid JsonPatch operation '{0}'.</value>
|
||||
</data>
|
||||
<data name="InvalidPathSegment" xml:space="preserve">
|
||||
<value>The provided path segment '{0}' cannot be converted to the target type.</value>
|
||||
</data>
|
||||
<data name="InvalidValueForPath" xml:space="preserve">
|
||||
<value>The provided string '{0}' is an invalid path.</value>
|
||||
</data>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Moq;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -15,33 +14,83 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
|
|||
public void Add_KeyWhichAlreadyExists_ReplacesExistingValue()
|
||||
{
|
||||
// Arrange
|
||||
var nameKey = "Name";
|
||||
var dictionary = new Dictionary<string, object>(StringComparer.Ordinal);
|
||||
dictionary[nameKey] = "Mike";
|
||||
var dictionaryAdapter = new DictionaryAdapter();
|
||||
var resolver = new Mock<IContractResolver>(MockBehavior.Strict);
|
||||
var key = "Status";
|
||||
var dictionary = new Dictionary<string, int>(StringComparer.Ordinal);
|
||||
dictionary[key] = 404;
|
||||
var dictionaryAdapter = new DictionaryAdapter<string, int>();
|
||||
var resolver = new DefaultContractResolver();
|
||||
|
||||
// Act
|
||||
var addStatus = dictionaryAdapter.TryAdd(dictionary, nameKey, resolver.Object, "James", out var message);
|
||||
var addStatus = dictionaryAdapter.TryAdd(dictionary, key, resolver, 200, out var message);
|
||||
|
||||
// Assert
|
||||
Assert.True(addStatus);
|
||||
Assert.True(string.IsNullOrEmpty(message), "Expected no error message");
|
||||
Assert.Single(dictionary);
|
||||
Assert.Equal("James", dictionary[nameKey]);
|
||||
Assert.Equal(200, dictionary[key]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Add_IntKeyWhichAlreadyExists_ReplacesExistingValue()
|
||||
{
|
||||
// Arrange
|
||||
var intKey = 1;
|
||||
var dictionary = new Dictionary<int, object>();
|
||||
dictionary[intKey] = "Mike";
|
||||
var dictionaryAdapter = new DictionaryAdapter<int, object>();
|
||||
var resolver = new DefaultContractResolver();
|
||||
|
||||
// Act
|
||||
var addStatus = dictionaryAdapter.TryAdd(dictionary, intKey.ToString(), resolver, "James", out var message);
|
||||
|
||||
// Assert
|
||||
Assert.True(addStatus);
|
||||
Assert.True(string.IsNullOrEmpty(message), "Expected no error message");
|
||||
Assert.Single(dictionary);
|
||||
Assert.Equal("James", dictionary[intKey]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetInvalidKey_ThrowsInvalidPathSegmentException()
|
||||
{
|
||||
// Arrange
|
||||
var dictionaryAdapter = new DictionaryAdapter<int, object>();
|
||||
var resolver = new DefaultContractResolver();
|
||||
var key = 1;
|
||||
var dictionary = new Dictionary<int, object>();
|
||||
|
||||
// Act
|
||||
var addStatus = dictionaryAdapter.TryAdd(dictionary, key.ToString(), resolver, "James", out var message);
|
||||
|
||||
// Assert
|
||||
Assert.True(addStatus);
|
||||
Assert.True(string.IsNullOrEmpty(message), "Expected no error message");
|
||||
Assert.Single(dictionary);
|
||||
Assert.Equal("James", dictionary[key]);
|
||||
|
||||
// Act
|
||||
var guidKey = new Guid();
|
||||
var getStatus = dictionaryAdapter.TryGet(dictionary, guidKey.ToString(), resolver, out var outValue, out message);
|
||||
|
||||
// Assert
|
||||
Assert.False(getStatus);
|
||||
Assert.Equal(
|
||||
string.Format("The provided path segment '{0}' cannot be converted to the target type.", guidKey.ToString()),
|
||||
message);
|
||||
Assert.Null(outValue);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Get_UsingCaseSensitiveKey_FailureScenario()
|
||||
{
|
||||
// Arrange
|
||||
var dictionaryAdapter = new DictionaryAdapter();
|
||||
var resolver = new Mock<IContractResolver>(MockBehavior.Strict);
|
||||
var dictionaryAdapter = new DictionaryAdapter<string, object>();
|
||||
var resolver = new DefaultContractResolver();
|
||||
var nameKey = "Name";
|
||||
var dictionary = new Dictionary<string, object>(StringComparer.Ordinal);
|
||||
|
||||
// Act
|
||||
var addStatus = dictionaryAdapter.TryAdd(dictionary, nameKey, resolver.Object, "James", out var message);
|
||||
var addStatus = dictionaryAdapter.TryAdd(dictionary, nameKey, resolver, "James", out var message);
|
||||
|
||||
// Assert
|
||||
Assert.True(addStatus);
|
||||
|
|
@ -50,11 +99,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
|
|||
Assert.Equal("James", dictionary[nameKey]);
|
||||
|
||||
// Act
|
||||
addStatus = dictionaryAdapter.TryGet(dictionary, nameKey.ToUpper(), resolver.Object, out var outValue, out message);
|
||||
var getStatus = dictionaryAdapter.TryGet(dictionary, nameKey.ToUpper(), resolver, out var outValue, out message);
|
||||
|
||||
// Assert
|
||||
Assert.True(addStatus);
|
||||
Assert.True(string.IsNullOrEmpty(message), "Expected no error message");
|
||||
Assert.False(getStatus);
|
||||
Assert.Equal(
|
||||
string.Format("The target location specified by path segment '{0}' was not found.", nameKey.ToUpper()),
|
||||
message);
|
||||
Assert.Null(outValue);
|
||||
}
|
||||
|
||||
|
|
@ -62,13 +113,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
|
|||
public void Get_UsingCaseSensitiveKey_SuccessScenario()
|
||||
{
|
||||
// Arrange
|
||||
var dictionaryAdapter = new DictionaryAdapter();
|
||||
var resolver = new Mock<IContractResolver>(MockBehavior.Strict);
|
||||
var dictionaryAdapter = new DictionaryAdapter<string, object>();
|
||||
var resolver = new DefaultContractResolver();
|
||||
var nameKey = "Name";
|
||||
var dictionary = new Dictionary<string, object>(StringComparer.Ordinal);
|
||||
|
||||
// Act
|
||||
var addStatus = dictionaryAdapter.TryAdd(dictionary, nameKey, resolver.Object, "James", out var message);
|
||||
var addStatus = dictionaryAdapter.TryAdd(dictionary, nameKey, resolver, "James", out var message);
|
||||
|
||||
// Assert
|
||||
Assert.True(addStatus);
|
||||
|
|
@ -77,7 +128,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
|
|||
Assert.Equal("James", dictionary[nameKey]);
|
||||
|
||||
// Act
|
||||
addStatus = dictionaryAdapter.TryGet(dictionary, nameKey, resolver.Object, out var outValue, out message);
|
||||
addStatus = dictionaryAdapter.TryGet(dictionary, nameKey, resolver, out var outValue, out message);
|
||||
|
||||
// Assert
|
||||
Assert.True(addStatus);
|
||||
|
|
@ -92,11 +143,11 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
|
|||
var nameKey = "Name";
|
||||
var dictionary = new Dictionary<string, object>(StringComparer.Ordinal);
|
||||
dictionary.Add(nameKey, "Mike");
|
||||
var dictionaryAdapter = new DictionaryAdapter();
|
||||
var resolver = new Mock<IContractResolver>(MockBehavior.Strict);
|
||||
var dictionaryAdapter = new DictionaryAdapter<string, object>();
|
||||
var resolver = new DefaultContractResolver();
|
||||
|
||||
// Act
|
||||
var replaceStatus = dictionaryAdapter.TryReplace(dictionary, nameKey, resolver.Object, "James", out var message);
|
||||
var replaceStatus = dictionaryAdapter.TryReplace(dictionary, nameKey, resolver, "James", out var message);
|
||||
|
||||
// Assert
|
||||
Assert.True(replaceStatus);
|
||||
|
|
@ -105,17 +156,58 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
|
|||
Assert.Equal("James", dictionary[nameKey]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReplacingExistingItem_WithGuidKey()
|
||||
{
|
||||
// Arrange
|
||||
var guidKey = new Guid();
|
||||
var dictionary = new Dictionary<Guid, object>();
|
||||
dictionary.Add(guidKey, "Mike");
|
||||
var dictionaryAdapter = new DictionaryAdapter<Guid, object>();
|
||||
var resolver = new DefaultContractResolver();
|
||||
|
||||
// Act
|
||||
var replaceStatus = dictionaryAdapter.TryReplace(dictionary, guidKey.ToString(), resolver, "James", out var message);
|
||||
|
||||
// Assert
|
||||
Assert.True(replaceStatus);
|
||||
Assert.True(string.IsNullOrEmpty(message), "Expected no error message");
|
||||
Assert.Single(dictionary);
|
||||
Assert.Equal("James", dictionary[guidKey]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReplacingWithInvalidValue_ThrowsInvalidValueForPropertyException()
|
||||
{
|
||||
// Arrange
|
||||
var guidKey = new Guid();
|
||||
var dictionary = new Dictionary<Guid, int>();
|
||||
dictionary.Add(guidKey, 5);
|
||||
var dictionaryAdapter = new DictionaryAdapter<Guid, int>();
|
||||
var resolver = new DefaultContractResolver();
|
||||
|
||||
// Act
|
||||
var replaceStatus = dictionaryAdapter.TryReplace(dictionary, guidKey.ToString(), resolver, "test", out var message);
|
||||
|
||||
// Assert
|
||||
Assert.False(replaceStatus);
|
||||
Assert.Equal(
|
||||
string.Format("The value '{0}' is invalid for target location.", "test"),
|
||||
message);
|
||||
Assert.Equal(5, dictionary[guidKey]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Replace_NonExistingKey_Fails()
|
||||
{
|
||||
// Arrange
|
||||
var nameKey = "Name";
|
||||
var dictionary = new Dictionary<string, object>(StringComparer.Ordinal);
|
||||
var dictionaryAdapter = new DictionaryAdapter();
|
||||
var resolver = new Mock<IContractResolver>(MockBehavior.Strict);
|
||||
var dictionaryAdapter = new DictionaryAdapter<string, object>();
|
||||
var resolver = new DefaultContractResolver();
|
||||
|
||||
// Act
|
||||
var replaceStatus = dictionaryAdapter.TryReplace(dictionary, nameKey, resolver.Object, "Mike", out var message);
|
||||
var replaceStatus = dictionaryAdapter.TryReplace(dictionary, nameKey, resolver, "Mike", out var message);
|
||||
|
||||
// Assert
|
||||
Assert.False(replaceStatus);
|
||||
|
|
@ -131,11 +223,11 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
|
|||
// Arrange
|
||||
var nameKey = "Name";
|
||||
var dictionary = new Dictionary<string, object>(StringComparer.Ordinal);
|
||||
var dictionaryAdapter = new DictionaryAdapter();
|
||||
var resolver = new Mock<IContractResolver>(MockBehavior.Strict);
|
||||
var dictionaryAdapter = new DictionaryAdapter<string, object>();
|
||||
var resolver = new DefaultContractResolver();
|
||||
|
||||
// Act
|
||||
var removeStatus = dictionaryAdapter.TryRemove(dictionary, nameKey, resolver.Object, out var message);
|
||||
var removeStatus = dictionaryAdapter.TryRemove(dictionary, nameKey, resolver, out var message);
|
||||
|
||||
// Assert
|
||||
Assert.False(removeStatus);
|
||||
|
|
@ -152,11 +244,30 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
|
|||
var nameKey = "Name";
|
||||
var dictionary = new Dictionary<string, object>(StringComparer.Ordinal);
|
||||
dictionary[nameKey] = "James";
|
||||
var dictionaryAdapter = new DictionaryAdapter();
|
||||
var resolver = new Mock<IContractResolver>(MockBehavior.Strict);
|
||||
var dictionaryAdapter = new DictionaryAdapter<string, object>();
|
||||
var resolver = new DefaultContractResolver();
|
||||
|
||||
// Act
|
||||
var removeStatus = dictionaryAdapter.TryRemove(dictionary, nameKey, resolver.Object, out var message);
|
||||
var removeStatus = dictionaryAdapter.TryRemove(dictionary, nameKey, resolver, out var message);
|
||||
|
||||
//Assert
|
||||
Assert.True(removeStatus);
|
||||
Assert.True(string.IsNullOrEmpty(message), "Expected no error message");
|
||||
Assert.Empty(dictionary);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Remove_RemovesFromDictionary_WithUriKey()
|
||||
{
|
||||
// Arrange
|
||||
var uriKey = new Uri("http://www.test.com/name");
|
||||
var dictionary = new Dictionary<Uri, object>();
|
||||
dictionary[uriKey] = "James";
|
||||
var dictionaryAdapter = new DictionaryAdapter<Uri, object>();
|
||||
var resolver = new DefaultContractResolver();
|
||||
|
||||
// Act
|
||||
var removeStatus = dictionaryAdapter.TryRemove(dictionary, uriKey.ToString(), resolver, out var message);
|
||||
|
||||
//Assert
|
||||
Assert.True(removeStatus);
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Dynamic;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.JsonPatch.Internal
|
||||
|
|
@ -26,11 +24,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
|
|||
var patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Replace("GuidValue", newGuid);
|
||||
|
||||
// serialize & deserialize
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserizalized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserizalized.ApplyTo(doc);
|
||||
patchDoc.ApplyTo(doc);
|
||||
|
||||
Assert.Equal(newGuid, doc.GuidValue);
|
||||
}
|
||||
|
|
@ -46,11 +40,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
|
|||
var patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Replace("GuidValue", newGuid);
|
||||
|
||||
// serialize & deserialize
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserizalized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserizalized.ApplyTo(doc);
|
||||
patchDoc.ApplyTo(doc);
|
||||
|
||||
Assert.Equal(newGuid, doc.GuidValue);
|
||||
}
|
||||
|
|
@ -71,11 +61,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
|
|||
var patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Replace("nestedobject/GuidValue", newGuid);
|
||||
|
||||
// serialize & deserialize
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserizalized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserizalized.ApplyTo(doc);
|
||||
patchDoc.ApplyTo(doc);
|
||||
|
||||
Assert.Equal(newGuid, doc.NestedObject.GuidValue);
|
||||
}
|
||||
|
|
@ -99,11 +85,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
|
|||
var patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Replace("SimpleDTO", newDTO);
|
||||
|
||||
// serialize & deserialize
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
patchDoc.ApplyTo(doc);
|
||||
|
||||
Assert.Equal(1, doc.SimpleDTO.DoubleValue);
|
||||
Assert.Equal(0, doc.SimpleDTO.IntegerValue);
|
||||
|
|
@ -120,10 +102,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
|
|||
var patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Replace("IntegerList/0", 5);
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
patchDoc.ApplyTo(doc);
|
||||
|
||||
Assert.Equal(new List<int>() { 5, 2, 3 }, doc.IntegerList);
|
||||
}
|
||||
|
|
@ -138,10 +117,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
|
|||
var patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Replace("IntegerList", new List<int>() { 4, 5, 6 });
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
patchDoc.ApplyTo(doc);
|
||||
|
||||
Assert.Equal(new List<int>() { 4, 5, 6 }, doc.IntegerList);
|
||||
}
|
||||
|
|
@ -159,10 +135,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
|
|||
var patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Replace("SimpleDTOList/0/IntegerList/0", 4);
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
patchDoc.ApplyTo(doc);
|
||||
|
||||
Assert.Equal(4, doc.SimpleDTOList[0].IntegerList[0]);
|
||||
}
|
||||
|
|
@ -180,10 +153,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
|
|||
var patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Replace("SimpleDTOList/0/IntegerList/-", 4);
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
patchDoc.ApplyTo(doc);
|
||||
|
||||
Assert.Equal(4, doc.SimpleDTOList[0].IntegerList[2]);
|
||||
}
|
||||
|
|
@ -198,10 +168,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
|
|||
var patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Replace("IntegerList", new List<int>() { 4, 5, 6 });
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
patchDoc.ApplyTo(doc);
|
||||
|
||||
Assert.Equal(new List<int>() { 4, 5, 6 }, doc.IntegerList);
|
||||
}
|
||||
|
|
@ -216,10 +183,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
|
|||
var patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Replace("IntegerList", new Collection<int>() { 4, 5, 6 });
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
patchDoc.ApplyTo(doc);
|
||||
|
||||
Assert.Equal(new List<int>() { 4, 5, 6 }, doc.IntegerList);
|
||||
}
|
||||
|
|
@ -234,9 +198,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
|
|||
var patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Replace("IntegerList/-", 5);
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
deserialized.ApplyTo(doc);
|
||||
patchDoc.ApplyTo(doc);
|
||||
|
||||
Assert.Equal(new List<int>() { 1, 2, 5 }, doc.IntegerList);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
|
@ -87,7 +88,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
|
|||
Assert.True(visitStatus);
|
||||
Assert.True(string.IsNullOrEmpty(message), "Expected no error message");
|
||||
Assert.Same(expectedTargetObject, targetObject);
|
||||
Assert.IsType<DictionaryAdapter>(adapter);
|
||||
Assert.Equal(typeof(DictionaryAdapter<string, string>), adapter.GetType());
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> ReturnsExpandoAdapterData
|
||||
|
|
@ -107,7 +108,8 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
|
|||
public void Visit_ValidPathToExpandoObject_ReturnsExpandoAdapter(object targetObject, string path, object expectedTargetObject)
|
||||
{
|
||||
// Arrange
|
||||
var visitor = new ObjectVisitor(new ParsedPath(path), new DefaultContractResolver());
|
||||
var contractResolver = new DefaultContractResolver();
|
||||
var visitor = new ObjectVisitor(new ParsedPath(path), contractResolver);
|
||||
|
||||
// Act
|
||||
var visitStatus = visitor.TryVisit(ref targetObject, out var adapter, out var message);
|
||||
|
|
@ -116,7 +118,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
|
|||
Assert.True(visitStatus);
|
||||
Assert.True(string.IsNullOrEmpty(message), "Expected no error message");
|
||||
Assert.Same(expectedTargetObject, targetObject);
|
||||
Assert.IsType<ExpandoObjectAdapter>(adapter);
|
||||
Assert.Same(typeof(DictionaryAdapter<string, object>), adapter.GetType());
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> ReturnsPocoAdapterData
|
||||
|
|
|
|||
Loading…
Reference in New Issue