Implement new Remove op & fix value.GetTypê issue in Add op
This commit is contained in:
parent
bf7e0f141e
commit
054b46c1cc
|
|
@ -161,7 +161,7 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
|
|||
{
|
||||
// get the actual type
|
||||
var propertyValue = container.GetValueForCaseInsensitiveKey(treeAnalysisResult.PropertyPathInParent);
|
||||
var typeOfPathProperty = value.GetType();
|
||||
var typeOfPathProperty = propertyValue.GetType();
|
||||
|
||||
if (!IsNonStringArray(typeOfPathProperty))
|
||||
{
|
||||
|
|
@ -447,101 +447,240 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
|
|||
Remove(operation.path, objectToApplyTo, operation);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Remove is used by various operations (eg: remove, move, ...), yet through different operations;
|
||||
/// This method allows code reuse yet reporting the correct operation on error
|
||||
/// This method allows code reuse yet reporting the correct operation on error. The return value
|
||||
/// contains the type of the item that has been removed (and a bool possibly signifying an error)
|
||||
/// This can be used by other methods, like replace, to ensure that we can pass in the correctly
|
||||
/// typed value to whatever method follows.
|
||||
/// </summary>
|
||||
private void Remove(
|
||||
[NotNull] string path,
|
||||
[NotNull] object objectToApplyTo,
|
||||
[NotNull] Operation operationToReport)
|
||||
private RemovedPropertyTypeResult Remove(string path, object objectToApplyTo, Operation operationToReport)
|
||||
{
|
||||
var removeFromList = false;
|
||||
var positionAsInteger = -1;
|
||||
var actualPathToProperty = path;
|
||||
// get path result
|
||||
var pathResult = GetActualPropertyPath(
|
||||
path,
|
||||
objectToApplyTo,
|
||||
operationToReport);
|
||||
|
||||
if (path.EndsWith("/-"))
|
||||
if (pathResult == null)
|
||||
{
|
||||
removeFromList = true;
|
||||
actualPathToProperty = path.Substring(0, path.Length - 2);
|
||||
return new RemovedPropertyTypeResult(null, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
positionAsInteger = GetNumericEnd(path);
|
||||
|
||||
if (positionAsInteger > -1)
|
||||
var removeFromList = pathResult.ExecuteAtEnd;
|
||||
var positionAsInteger = pathResult.NumericEnd;
|
||||
var actualPathToProperty = pathResult.PathToProperty;
|
||||
|
||||
var treeAnalysisResult = new ObjectTreeAnalysisResult(
|
||||
objectToApplyTo,
|
||||
actualPathToProperty,
|
||||
ContractResolver);
|
||||
|
||||
if (!treeAnalysisResult.IsValidPathForRemove)
|
||||
{
|
||||
LogError(new JsonPatchError(
|
||||
objectToApplyTo,
|
||||
operationToReport,
|
||||
Resources.FormatPropertyCannotBeRemoved(path)));
|
||||
return new RemovedPropertyTypeResult(null, true);
|
||||
}
|
||||
|
||||
if (treeAnalysisResult.UseDynamicLogic)
|
||||
{
|
||||
// if it's not an array, we can remove the property from
|
||||
// the dictionary. If it's an array, we need to check the position first.
|
||||
if (removeFromList || positionAsInteger > -1)
|
||||
{
|
||||
actualPathToProperty = path.Substring(0,
|
||||
path.IndexOf('/' + positionAsInteger.ToString()));
|
||||
}
|
||||
}
|
||||
var propertyValue = treeAnalysisResult.Container
|
||||
.GetValueForCaseInsensitiveKey(treeAnalysisResult.PropertyPathInParent);
|
||||
|
||||
var patchProperty = FindPropertyAndParent(objectToApplyTo, actualPathToProperty);
|
||||
// we cannot continue when the value is null, because to be able to
|
||||
// continue we need to be able to check if the array is a non-string array
|
||||
if (propertyValue == null)
|
||||
{
|
||||
LogError(new JsonPatchError(
|
||||
objectToApplyTo,
|
||||
operationToReport,
|
||||
Resources.FormatCannotDeterminePropertyType(path)));
|
||||
return new RemovedPropertyTypeResult(null, true);
|
||||
}
|
||||
|
||||
// does the target location exist?
|
||||
if (!CheckIfPropertyExists(patchProperty, objectToApplyTo, operationToReport, path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
var typeOfPathProperty = propertyValue.GetType();
|
||||
|
||||
// get the property, and remove it - in this case, for DTO's, that means setting
|
||||
// it to null or its default value; in case of an array, remove at provided index
|
||||
// or at the end.
|
||||
if (removeFromList || positionAsInteger > -1)
|
||||
{
|
||||
// what if it's an array but there's no position??
|
||||
if (IsNonStringArray(patchProperty.Property.PropertyType))
|
||||
{
|
||||
// now, get the generic type of the IList<> from Property type.
|
||||
var genericTypeOfArray = GetIListType(patchProperty.Property.PropertyType);
|
||||
if (!IsNonStringArray(typeOfPathProperty))
|
||||
{
|
||||
LogError(new JsonPatchError(
|
||||
objectToApplyTo,
|
||||
operationToReport,
|
||||
Resources.FormatInvalidIndexForArrayProperty(operationToReport.op, path)));
|
||||
return new RemovedPropertyTypeResult(null, true);
|
||||
}
|
||||
|
||||
// get value (it can be cast, we just checked that)
|
||||
var array = (IList)patchProperty.Property.ValueProvider.GetValue(patchProperty.Parent);
|
||||
// now, get the generic type of the enumerable (we'll return this type)
|
||||
var genericTypeOfArray = GetIListType(typeOfPathProperty);
|
||||
|
||||
// get the array
|
||||
var array = (IList)treeAnalysisResult.Container.GetValueForCaseInsensitiveKey(
|
||||
treeAnalysisResult.PropertyPathInParent);
|
||||
|
||||
if (array.Count == 0)
|
||||
{
|
||||
// if the array is empty, we should throw an error
|
||||
LogError(new JsonPatchError(
|
||||
objectToApplyTo,
|
||||
operationToReport,
|
||||
Resources.FormatInvalidIndexForArrayProperty(
|
||||
operationToReport.op,
|
||||
path)));
|
||||
return new RemovedPropertyTypeResult(null, true);
|
||||
}
|
||||
|
||||
if (removeFromList)
|
||||
{
|
||||
array.RemoveAt(array.Count - 1);
|
||||
treeAnalysisResult.Container.SetValueForCaseInsensitiveKey(
|
||||
treeAnalysisResult.PropertyPathInParent, array);
|
||||
|
||||
// return the type of the value that has been removed.
|
||||
return new RemovedPropertyTypeResult(genericTypeOfArray, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (positionAsInteger < array.Count)
|
||||
{
|
||||
array.RemoveAt(positionAsInteger);
|
||||
}
|
||||
else
|
||||
if (positionAsInteger >= array.Count)
|
||||
{
|
||||
LogError(new JsonPatchError(
|
||||
objectToApplyTo,
|
||||
operationToReport,
|
||||
Resources.FormatInvalidIndexForArrayProperty(operationToReport.op, path)));
|
||||
|
||||
return;
|
||||
Resources.FormatInvalidIndexForArrayProperty(
|
||||
operationToReport.op,
|
||||
path)));
|
||||
return new RemovedPropertyTypeResult(null, true);
|
||||
}
|
||||
|
||||
array.RemoveAt(positionAsInteger);
|
||||
treeAnalysisResult.Container.SetValueForCaseInsensitiveKey(
|
||||
treeAnalysisResult.PropertyPathInParent, array);
|
||||
|
||||
// return the type of the value that has been removed.
|
||||
return new RemovedPropertyTypeResult(genericTypeOfArray, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogError(new JsonPatchError(
|
||||
objectToApplyTo,
|
||||
operationToReport,
|
||||
Resources.FormatInvalidPathForArrayProperty(operationToReport.op, path)));
|
||||
// get the property
|
||||
var getResult = treeAnalysisResult.Container.GetValueForCaseInsensitiveKey(
|
||||
treeAnalysisResult.PropertyPathInParent);
|
||||
|
||||
return;
|
||||
// remove the property
|
||||
treeAnalysisResult.Container.RemoveValueForCaseInsensitiveKey(
|
||||
treeAnalysisResult.PropertyPathInParent);
|
||||
|
||||
// value is not null, we can determine the type
|
||||
if (getResult != null)
|
||||
{
|
||||
var actualType = getResult.GetType();
|
||||
return new RemovedPropertyTypeResult(actualType, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new RemovedPropertyTypeResult(null, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// setting the value to "null" will use the default value in case of value types, and
|
||||
// null in case of reference types
|
||||
object value = null;
|
||||
// not dynamic
|
||||
var patchProperty = treeAnalysisResult.JsonPatchProperty;
|
||||
|
||||
if (patchProperty.Property.PropertyType.GetTypeInfo().IsValueType
|
||||
&& Nullable.GetUnderlyingType(patchProperty.Property.PropertyType) == null)
|
||||
if (removeFromList || positionAsInteger > -1)
|
||||
{
|
||||
value = Activator.CreateInstance(patchProperty.Property.PropertyType);
|
||||
}
|
||||
if (!IsNonStringArray(patchProperty.Property.PropertyType))
|
||||
{
|
||||
LogError(new JsonPatchError(
|
||||
objectToApplyTo,
|
||||
operationToReport,
|
||||
Resources.FormatInvalidIndexForArrayProperty(operationToReport.op, path)));
|
||||
return new RemovedPropertyTypeResult(null, true);
|
||||
}
|
||||
|
||||
patchProperty.Property.ValueProvider.SetValue(patchProperty.Parent, value);
|
||||
// now, get the generic type of the IList<> from Property type.
|
||||
var genericTypeOfArray = GetIListType(patchProperty.Property.PropertyType);
|
||||
|
||||
if (!patchProperty.Property.Readable)
|
||||
{
|
||||
LogError(new JsonPatchError(
|
||||
objectToApplyTo,
|
||||
operationToReport,
|
||||
Resources.FormatCannotReadProperty(path)));
|
||||
return new RemovedPropertyTypeResult(null, true);
|
||||
}
|
||||
|
||||
var array = (IList)patchProperty.Property.ValueProvider
|
||||
.GetValue(patchProperty.Parent);
|
||||
|
||||
if (array.Count == 0)
|
||||
{
|
||||
// if the array is empty, we should throw an error
|
||||
LogError(new JsonPatchError(
|
||||
objectToApplyTo,
|
||||
operationToReport,
|
||||
Resources.FormatInvalidIndexForArrayProperty(
|
||||
operationToReport.op,
|
||||
path)));
|
||||
return new RemovedPropertyTypeResult(null, true);
|
||||
}
|
||||
|
||||
if (removeFromList)
|
||||
{
|
||||
array.RemoveAt(array.Count - 1);
|
||||
|
||||
// return the type of the value that has been removed
|
||||
return new RemovedPropertyTypeResult(genericTypeOfArray, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (positionAsInteger >= array.Count)
|
||||
{
|
||||
LogError(new JsonPatchError(
|
||||
objectToApplyTo,
|
||||
operationToReport,
|
||||
Resources.FormatInvalidIndexForArrayProperty(
|
||||
operationToReport.op,
|
||||
path)));
|
||||
return null;
|
||||
}
|
||||
|
||||
array.RemoveAt(positionAsInteger);
|
||||
|
||||
// return the type of the value that has been removed
|
||||
return new RemovedPropertyTypeResult(genericTypeOfArray, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!patchProperty.Property.Writable)
|
||||
{
|
||||
LogError(new JsonPatchError(
|
||||
objectToApplyTo,
|
||||
operationToReport,
|
||||
Resources.FormatCannotUpdateProperty(path)));
|
||||
return new RemovedPropertyTypeResult(null, true);
|
||||
}
|
||||
|
||||
// setting the value to "null" will use the default value in case of value types, and
|
||||
// null in case of reference types
|
||||
object value = null;
|
||||
|
||||
if (patchProperty.Property.PropertyType.GetTypeInfo().IsValueType
|
||||
&& Nullable.GetUnderlyingType(patchProperty.Property.PropertyType) == null)
|
||||
{
|
||||
value = Activator.CreateInstance(patchProperty.Property.PropertyType);
|
||||
}
|
||||
|
||||
patchProperty.Property.ValueProvider.SetValue(patchProperty.Parent, value);
|
||||
return new RemovedPropertyTypeResult(patchProperty.Property.PropertyType, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
// 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;
|
||||
|
||||
namespace Microsoft.AspNet.JsonPatch.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Return value for Remove operation. The combination tells us what to do next (if this operation
|
||||
/// is called from inside another operation, eg: Replace, Copy.
|
||||
///
|
||||
/// Possible combo:
|
||||
/// - ActualType contains type: operation succesfully completed, can continue when called from inside
|
||||
/// another operation
|
||||
/// - ActualType null and HasError true: operation not completed succesfully, should not be allowed to continue
|
||||
/// - ActualType null and HasError false: operation completed succesfully, but we should not be allowed to
|
||||
/// continue when called from inside another method as we could not verify the type of the removed property.
|
||||
/// This happens when the value of an item in an ExpandoObject dictionary is null.
|
||||
/// </summary>
|
||||
internal class RemovedPropertyTypeResult
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of the removed property (value)
|
||||
/// </summary>
|
||||
public Type ActualType { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// HasError: true when an error occurred, the operation didn't complete succesfully
|
||||
/// </summary>
|
||||
public bool HasError { get; set; }
|
||||
|
||||
public RemovedPropertyTypeResult(Type actualType, bool hasError)
|
||||
{
|
||||
ActualType = actualType;
|
||||
HasError = hasError;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,22 @@ namespace Microsoft.AspNet.JsonPatch
|
|||
private static readonly ResourceManager _resourceManager
|
||||
= new ResourceManager("Microsoft.AspNet.JsonPatch.Resources", typeof(Resources).GetTypeInfo().Assembly);
|
||||
|
||||
/// <summary>
|
||||
/// The type of the property at path '{0}' could not be determined.
|
||||
/// </summary>
|
||||
internal static string CannotDeterminePropertyType
|
||||
{
|
||||
get { return GetString("CannotDeterminePropertyType"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The type of the property at path '{0}' could not be determined.
|
||||
/// </summary>
|
||||
internal static string FormatCannotDeterminePropertyType(object p0)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("CannotDeterminePropertyType"), p0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The property at '{0}' could not be read.
|
||||
/// </summary>
|
||||
|
|
@ -42,6 +58,22 @@ namespace Microsoft.AspNet.JsonPatch
|
|||
return string.Format(CultureInfo.CurrentCulture, GetString("CannotUpdateProperty"), p0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The key '{0}' was not found.
|
||||
/// </summary>
|
||||
internal static string DictionaryKeyNotFound
|
||||
{
|
||||
get { return GetString("DictionaryKeyNotFound"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The key '{0}' was not found.
|
||||
/// </summary>
|
||||
internal static string FormatDictionaryKeyNotFound(object p0)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("DictionaryKeyNotFound"), p0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For operation '{0}' on array property at path '{1}', the index is larger than the array size.
|
||||
/// </summary>
|
||||
|
|
@ -58,23 +90,6 @@ namespace Microsoft.AspNet.JsonPatch
|
|||
return string.Format(CultureInfo.CurrentCulture, GetString("InvalidIndexForArrayProperty"), p0, p1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For operation '{0}' on array property at path '{1}', the index is negative.
|
||||
/// </summary>
|
||||
internal static string NegativeIndexForArrayProperty
|
||||
{
|
||||
get { return GetString("NegativeIndexForArrayProperty"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For operation '{0}' on array property at path '{1}', the index is negative.
|
||||
/// </summary>
|
||||
internal static string FormatNegativeIndexForArrayProperty(object p0, object p1)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("NegativeIndexForArrayProperty"), p0, p1);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The type '{0}' was malformed and could not be parsed.
|
||||
/// </summary>
|
||||
|
|
@ -139,6 +154,22 @@ namespace Microsoft.AspNet.JsonPatch
|
|||
return string.Format(CultureInfo.CurrentCulture, GetString("InvalidValueForProperty"), p0, p1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For operation '{0}' on array property at path '{1}', the index is negative.
|
||||
/// </summary>
|
||||
internal static string NegativeIndexForArrayProperty
|
||||
{
|
||||
get { return GetString("NegativeIndexForArrayProperty"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For operation '{0}' on array property at path '{1}', the index is negative.
|
||||
/// </summary>
|
||||
internal static string FormatNegativeIndexForArrayProperty(object p0, object p1)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("NegativeIndexForArrayProperty"), p0, p1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// '{0}' must be of type '{1}'.
|
||||
/// </summary>
|
||||
|
|
@ -203,23 +234,6 @@ namespace Microsoft.AspNet.JsonPatch
|
|||
return string.Format(CultureInfo.CurrentCulture, GetString("PropertyDoesNotExist"), p0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The key '{0}' was not found.
|
||||
/// </summary>
|
||||
internal static string DictionaryKeyNotFound
|
||||
{
|
||||
get { return GetString("DictionaryKeyNotFound"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The key '{0}' was not found.
|
||||
/// </summary>
|
||||
internal static string FormatDictionaryKeyNotFound(object p0)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("DictionaryKeyNotFound"), p0);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The test operation is not supported.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -117,6 +117,9 @@
|
|||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="CannotDeterminePropertyType" xml:space="preserve">
|
||||
<value>The type of the property at path '{0}' could not be determined.</value>
|
||||
</data>
|
||||
<data name="CannotReadProperty" xml:space="preserve">
|
||||
<value>The property at '{0}' could not be read.</value>
|
||||
</data>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,569 @@
|
|||
// 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 Microsoft.AspNet.JsonPatch.Exceptions;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.JsonPatch.Test.Dynamic
|
||||
{
|
||||
public class AddOperationTests
|
||||
{
|
||||
[Fact]
|
||||
public void AddNewPropertyShouldFailIfRootIsNotAnExpandoObject()
|
||||
{
|
||||
dynamic doc = new
|
||||
{
|
||||
Test = 1
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Add("NewInt", 1);
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
var exception = Assert.Throws<JsonPatchException>(() =>
|
||||
{
|
||||
deserialized.ApplyTo(doc);
|
||||
});
|
||||
Assert.Equal(
|
||||
"The property at path '/NewInt' could not be added.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddNewProperty()
|
||||
{
|
||||
dynamic obj = new ExpandoObject();
|
||||
obj.Test = 1;
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Add("NewInt", 1);
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(obj);
|
||||
|
||||
Assert.Equal(1, obj.NewInt);
|
||||
Assert.Equal(1, obj.Test);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddNewPropertyToNestedAnonymousObjectShouldFail()
|
||||
{
|
||||
dynamic doc = new
|
||||
{
|
||||
Test = 1,
|
||||
nested = new { }
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Add("Nested/NewInt", 1);
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
var exception = Assert.Throws<JsonPatchException>(() =>
|
||||
{
|
||||
deserialized.ApplyTo(doc);
|
||||
});
|
||||
Assert.Equal(
|
||||
"The property at path '/Nested/NewInt' could not be added.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddNewPropertyToTypedObjectShouldFail()
|
||||
{
|
||||
dynamic doc = new
|
||||
{
|
||||
Test = 1,
|
||||
nested = new NestedDTO()
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Add("Nested/NewInt", 1);
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
var exception = Assert.Throws<JsonPatchException>(() =>
|
||||
{
|
||||
deserialized.ApplyTo(doc);
|
||||
});
|
||||
Assert.Equal(
|
||||
"The property at path '/Nested/NewInt' could not be added.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddToExistingPropertyOnNestedObject()
|
||||
{
|
||||
dynamic doc = new
|
||||
{
|
||||
Test = 1,
|
||||
nested = new NestedDTO()
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Add("Nested/StringProperty", "A");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
|
||||
Assert.Equal("A", doc.nested.StringProperty);
|
||||
Assert.Equal(1, doc.Test);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddNewPropertyToExpandoOject()
|
||||
{
|
||||
dynamic doc = new
|
||||
{
|
||||
Test = 1,
|
||||
nested = new ExpandoObject()
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Add("Nested/NewInt", 1);
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
|
||||
Assert.Equal(1, doc.nested.NewInt);
|
||||
Assert.Equal(1, doc.Test);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddNewPropertyToExpandoOjectInTypedObject()
|
||||
{
|
||||
var doc = new NestedDTO()
|
||||
{
|
||||
DynamicProperty = new ExpandoObject()
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Add("DynamicProperty/NewInt", 1);
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
|
||||
Assert.Equal(1, doc.DynamicProperty.NewInt);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddNewPropertyToTypedObjectInExpandoObject()
|
||||
{
|
||||
dynamic dynamicProperty = new ExpandoObject();
|
||||
dynamicProperty.StringProperty = "A";
|
||||
|
||||
var doc = new NestedDTO()
|
||||
{
|
||||
DynamicProperty = dynamicProperty
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Add("DynamicProperty/StringProperty", "B");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
|
||||
Assert.Equal("B", doc.DynamicProperty.StringProperty);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddNewPropertyToAnonymousObjectShouldFail()
|
||||
{
|
||||
dynamic doc = new
|
||||
{
|
||||
Test = 1
|
||||
};
|
||||
|
||||
dynamic valueToAdd = new { IntValue = 1, StringValue = "test", GuidValue = Guid.NewGuid() };
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Add("ComplexProperty", valueToAdd);
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
var exception = Assert.Throws<JsonPatchException>(() =>
|
||||
{
|
||||
deserialized.ApplyTo(doc);
|
||||
});
|
||||
Assert.Equal(
|
||||
"The property at path '/ComplexProperty' could not be added.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddResultsReplaceShouldFailOnAnonymousDueToNoSetter()
|
||||
{
|
||||
var doc = new
|
||||
{
|
||||
StringProperty = "A"
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Add("StringProperty", "B");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
var exception = Assert.Throws<JsonPatchException>(() =>
|
||||
{
|
||||
deserialized.ApplyTo(doc);
|
||||
});
|
||||
Assert.Equal(
|
||||
"The property at path '/StringProperty' could not be updated.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddResultsShouldReplace()
|
||||
{
|
||||
dynamic doc = new ExpandoObject();
|
||||
doc.StringProperty = "A";
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Add("StringProperty", "B");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
|
||||
Assert.Equal("B", doc.StringProperty);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddResultsShouldReplaceInNested()
|
||||
{
|
||||
dynamic doc = new ExpandoObject();
|
||||
doc.InBetweenFirst = new ExpandoObject();
|
||||
doc.InBetweenFirst.InBetweenSecond = new ExpandoObject();
|
||||
doc.InBetweenFirst.InBetweenSecond.StringProperty = "A";
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Add("/InBetweenFirst/InBetweenSecond/StringProperty", "B");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
|
||||
Assert.Equal("B", doc.InBetweenFirst.InBetweenSecond.StringProperty);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddResultsShouldReplaceInNestedInDynamic()
|
||||
{
|
||||
dynamic doc = new ExpandoObject();
|
||||
doc.Nested = new NestedDTO();
|
||||
doc.Nested.DynamicProperty = new ExpandoObject();
|
||||
doc.Nested.DynamicProperty.InBetweenFirst = new ExpandoObject();
|
||||
doc.Nested.DynamicProperty.InBetweenFirst.InBetweenSecond = new ExpandoObject();
|
||||
doc.Nested.DynamicProperty.InBetweenFirst.InBetweenSecond.StringProperty = "A";
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Add("/Nested/DynamicProperty/InBetweenFirst/InBetweenSecond/StringProperty", "B");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
|
||||
Assert.Equal("B", doc.Nested.DynamicProperty.InBetweenFirst.InBetweenSecond.StringProperty);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShouldNotBeAbleToAddToNonExistingPropertyThatIsNotTheRoot()
|
||||
{
|
||||
//Adding to a Nonexistent Target
|
||||
//
|
||||
// An example target JSON document:
|
||||
// { "foo": "bar" }
|
||||
// A JSON Patch document:
|
||||
// [
|
||||
// { "op": "add", "path": "/baz/bat", "value": "qux" }
|
||||
// ]
|
||||
// This JSON Patch document, applied to the target JSON document above,
|
||||
// would result in an error (therefore, it would not be applied),
|
||||
// because the "add" operation's target location that references neither
|
||||
// the root of the document, nor a member of an existing object, nor a
|
||||
// member of an existing array.
|
||||
|
||||
var doc = new NestedDTO()
|
||||
{
|
||||
DynamicProperty = new ExpandoObject()
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Add("DynamicProperty/OtherProperty/IntProperty", 1);
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
var exception = Assert.Throws<JsonPatchException>(() =>
|
||||
{
|
||||
deserialized.ApplyTo(doc);
|
||||
});
|
||||
Assert.Equal(
|
||||
"The property at path '/DynamicProperty/OtherProperty/IntProperty' could not be added.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShouldNotBeAbleToAddToNonExistingPropertyInNestedPropertyThatIsNotTheRoot()
|
||||
{
|
||||
//Adding to a Nonexistent Target
|
||||
//
|
||||
// An example target JSON document:
|
||||
// { "foo": "bar" }
|
||||
// A JSON Patch document:
|
||||
// [
|
||||
// { "op": "add", "path": "/baz/bat", "value": "qux" }
|
||||
// ]
|
||||
// This JSON Patch document, applied to the target JSON document above,
|
||||
// would result in an error (therefore, it would not be applied),
|
||||
// because the "add" operation's target location that references neither
|
||||
// the root of the document, nor a member of an existing object, nor a
|
||||
// member of an existing array.
|
||||
|
||||
var doc = new
|
||||
{
|
||||
Foo = "bar"
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Add("baz/bat", "qux");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
var exception = Assert.Throws<JsonPatchException>(() =>
|
||||
{
|
||||
deserialized.ApplyTo(doc);
|
||||
});
|
||||
Assert.Equal(
|
||||
"The property at path '/baz/bat' could not be added.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShouldReplacePropertyWithDifferentCase()
|
||||
{
|
||||
dynamic doc = new ExpandoObject();
|
||||
doc.StringProperty = "A";
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Add("stringproperty", "B");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
|
||||
Assert.Equal("B", doc.StringProperty);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddToList()
|
||||
{
|
||||
var doc = new
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Add("IntegerList/0", 4);
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
|
||||
Assert.Equal(new List<int>() { 4, 1, 2, 3 }, doc.IntegerList);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddToListNegativePosition()
|
||||
{
|
||||
dynamic doc = new ExpandoObject();
|
||||
doc.IntegerList = new List<int>() { 1, 2, 3 };
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Add("IntegerList/-1", 4);
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
var exception = Assert.Throws<JsonPatchException>(() =>
|
||||
{
|
||||
deserialized.ApplyTo(doc);
|
||||
});
|
||||
Assert.Equal(
|
||||
"For operation 'add' on array property at path '/IntegerList/-1', the index is negative.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShouldAddToListWithDifferentCase()
|
||||
{
|
||||
var doc = new
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Add("integerlist/0", 4);
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
|
||||
Assert.Equal(new List<int>() { 4, 1, 2, 3 }, doc.IntegerList);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddToListInvalidPositionTooLarge()
|
||||
{
|
||||
var doc = new
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Add("IntegerList/4", 4);
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
var exception = Assert.Throws<JsonPatchException>(() =>
|
||||
{
|
||||
deserialized.ApplyTo(doc);
|
||||
});
|
||||
Assert.Equal(
|
||||
"For operation 'add' on array property at path '/IntegerList/4', the index is larger than the array size.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddToListAtEndWithSerialization()
|
||||
{
|
||||
var doc = new
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Add("IntegerList/3", 4);
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
|
||||
Assert.Equal(new List<int>() { 1, 2, 3, 4 }, doc.IntegerList);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddToListAtBeginning()
|
||||
{
|
||||
var doc = new
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Add("IntegerList/0", 4);
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
|
||||
Assert.Equal(new List<int>() { 4, 1, 2, 3 }, doc.IntegerList);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddToListInvalidPositionTooSmall()
|
||||
{
|
||||
var doc = new
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Add("IntegerList/-1", 4);
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
var exception = Assert.Throws<JsonPatchException>(() =>
|
||||
{
|
||||
deserialized.ApplyTo(doc);
|
||||
});
|
||||
Assert.Equal(
|
||||
"For operation 'add' on array property at path '/IntegerList/-1', the index is negative.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddToListAppend()
|
||||
{
|
||||
var doc = new
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Add("IntegerList/-", 4);
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
|
||||
Assert.Equal(new List<int>() { 1, 2, 3, 4 }, doc.IntegerList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
// 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.Generic;
|
||||
using Microsoft.AspNet.JsonPatch.Exceptions;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.JsonPatch.Test.Dynamic
|
||||
{
|
||||
public class AddTypedOperationTests
|
||||
{
|
||||
[Fact]
|
||||
public void AddToListNegativePosition()
|
||||
{
|
||||
var doc = new SimpleDTO()
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Add("IntegerList/-1", 4);
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
var exception = Assert.Throws<JsonPatchException>(() =>
|
||||
{
|
||||
deserialized.ApplyTo(doc);
|
||||
});
|
||||
Assert.Equal(
|
||||
"For operation 'add' on array property at path '/IntegerList/-1', the index is negative.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddToListInList()
|
||||
{
|
||||
var doc = new SimpleDTOWithNestedDTO()
|
||||
{
|
||||
ListOfSimpleDTO = new List<SimpleDTO>()
|
||||
{
|
||||
new SimpleDTO()
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Add("ListOfSimpleDTO/0/IntegerList/0", 4);
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
Assert.Equal(new List<int>() { 4, 1, 2, 3 }, doc.ListOfSimpleDTO[0].IntegerList);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddToListInListInvalidPositionTooSmall()
|
||||
{
|
||||
var doc = new SimpleDTOWithNestedDTO()
|
||||
{
|
||||
ListOfSimpleDTO = new List<SimpleDTO>()
|
||||
{
|
||||
new SimpleDTO()
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Add("ListOfSimpleDTO/-1/IntegerList/0", 4);
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
var exception = Assert.Throws<JsonPatchException>(() =>
|
||||
{
|
||||
deserialized.ApplyTo(doc);
|
||||
});
|
||||
Assert.Equal(
|
||||
"The property at path '/ListOfSimpleDTO/-1/IntegerList/0' could not be added.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddToListInListInvalidPositionTooLarge()
|
||||
{
|
||||
var doc = new SimpleDTOWithNestedDTO()
|
||||
{
|
||||
ListOfSimpleDTO = new List<SimpleDTO>()
|
||||
{
|
||||
new SimpleDTO()
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
}
|
||||
}
|
||||
};
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Add("ListOfSimpleDTO/20/IntegerList/0", 4);
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
var exception = Assert.Throws<JsonPatchException>(() =>
|
||||
{
|
||||
deserialized.ApplyTo(doc);
|
||||
});
|
||||
Assert.Equal(
|
||||
"The property at path '/ListOfSimpleDTO/20/IntegerList/0' could not be added.",
|
||||
exception.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNet.JsonPatch.Test.Dynamic
|
||||
{
|
||||
public class NestedDTO
|
||||
{
|
||||
public string StringProperty { get; set; }
|
||||
public dynamic DynamicProperty { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
// 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 Microsoft.AspNet.JsonPatch.Exceptions;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.JsonPatch.Test.Dynamic
|
||||
{
|
||||
public class PatchDocumentTests
|
||||
{
|
||||
[Fact]
|
||||
public void InvalidPathAtBeginningShouldThrowException()
|
||||
{
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
var exception = Assert.Throws<JsonPatchException>(() =>
|
||||
{
|
||||
patchDoc.Add("//NewInt", 1);
|
||||
});
|
||||
Assert.Equal(
|
||||
"The provided string '//NewInt' is an invalid path.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InvalidPathAtEndShouldThrowException()
|
||||
{
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
var exception = Assert.Throws<JsonPatchException>(() =>
|
||||
{
|
||||
patchDoc.Add("NewInt//", 1);
|
||||
});
|
||||
Assert.Equal(
|
||||
"The provided string 'NewInt//' is an invalid path.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InvalidPathWithDotShouldThrowException()
|
||||
{
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
var exception = Assert.Throws<JsonPatchException>(() =>
|
||||
{
|
||||
patchDoc.Add("NewInt.Test", 1);
|
||||
});
|
||||
Assert.Equal(
|
||||
"The provided string 'NewInt.Test' is an invalid path.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NonGenericPatchDocToGenericMustSerialize()
|
||||
{
|
||||
var doc = new SimpleDTO()
|
||||
{
|
||||
StringProperty = "A",
|
||||
AnotherStringProperty = "B"
|
||||
};
|
||||
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Copy("StringProperty", "AnotherStringProperty");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument<SimpleDTO>>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
|
||||
Assert.Equal("A", doc.AnotherStringProperty);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GenericPatchDocToNonGenericMustSerialize()
|
||||
{
|
||||
var doc = new SimpleDTO()
|
||||
{
|
||||
StringProperty = "A",
|
||||
AnotherStringProperty = "B"
|
||||
};
|
||||
|
||||
JsonPatchDocument<SimpleDTO> patchDocTyped = new JsonPatchDocument<SimpleDTO>();
|
||||
patchDocTyped.Copy<string>(o => o.StringProperty, o => o.AnotherStringProperty);
|
||||
|
||||
JsonPatchDocument patchDocUntyped = new JsonPatchDocument();
|
||||
patchDocUntyped.Copy("StringProperty", "AnotherStringProperty");
|
||||
|
||||
var serializedTyped = JsonConvert.SerializeObject(patchDocTyped);
|
||||
var serializedUntyped = JsonConvert.SerializeObject(patchDocUntyped);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serializedTyped);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
|
||||
Assert.Equal("A", doc.AnotherStringProperty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,302 @@
|
|||
// 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.Generic;
|
||||
using System.Dynamic;
|
||||
using Microsoft.AspNet.JsonPatch.Exceptions;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.JsonPatch.Test.Dynamic
|
||||
{
|
||||
public class RemoveOperationTests
|
||||
{
|
||||
[Fact]
|
||||
public void RemovePropertyShouldFailIfRootIsAnonymous()
|
||||
{
|
||||
dynamic doc = new
|
||||
{
|
||||
Test = 1
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Remove("Test");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
var exception = Assert.Throws<JsonPatchException>(() =>
|
||||
{
|
||||
deserialized.ApplyTo(doc);
|
||||
});
|
||||
Assert.Equal(
|
||||
"The property at path '/Test' could not be updated.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemovePropertyShouldFailIfItDoesntExist()
|
||||
{
|
||||
dynamic doc = new ExpandoObject();
|
||||
doc.Test = 1;
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Remove("NonExisting");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
var exception = Assert.Throws<JsonPatchException>(() =>
|
||||
{
|
||||
deserialized.ApplyTo(doc);
|
||||
});
|
||||
Assert.Equal(
|
||||
"The property at path '/NonExisting' could not be removed.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemovePropertyFromExpandoObject()
|
||||
{
|
||||
dynamic obj = new ExpandoObject();
|
||||
obj.Test = 1;
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Remove("Test");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(obj);
|
||||
|
||||
var cont = obj as IDictionary<string, object>;
|
||||
object valueFromDictionary;
|
||||
|
||||
cont.TryGetValue("Test", out valueFromDictionary);
|
||||
Assert.Null(valueFromDictionary);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemovePropertyFromExpandoObjectMixedCase()
|
||||
{
|
||||
dynamic obj = new ExpandoObject();
|
||||
obj.Test = 1;
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Remove("test");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(obj);
|
||||
|
||||
var cont = obj as IDictionary<string, object>;
|
||||
object valueFromDictionary;
|
||||
|
||||
cont.TryGetValue("Test", out valueFromDictionary);
|
||||
Assert.Null(valueFromDictionary);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveNestedPropertyFromExpandoObject()
|
||||
{
|
||||
dynamic obj = new ExpandoObject();
|
||||
obj.Test = new ExpandoObject();
|
||||
obj.Test.AnotherTest = "A";
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Remove("Test");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(obj);
|
||||
|
||||
var cont = obj as IDictionary<string, object>;
|
||||
object valueFromDictionary;
|
||||
|
||||
cont.TryGetValue("Test", out valueFromDictionary);
|
||||
Assert.Null(valueFromDictionary);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveNestedPropertyFromExpandoObjectMixedCase()
|
||||
{
|
||||
dynamic obj = new ExpandoObject();
|
||||
obj.Test = new ExpandoObject();
|
||||
obj.Test.AnotherTest = "A";
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Remove("test");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(obj);
|
||||
var cont = obj as IDictionary<string, object>;
|
||||
|
||||
object valueFromDictionary;
|
||||
cont.TryGetValue("Test", out valueFromDictionary);
|
||||
Assert.Null(valueFromDictionary);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NestedRemove()
|
||||
{
|
||||
dynamic doc = new ExpandoObject();
|
||||
doc.SimpleDTO = new SimpleDTO()
|
||||
{
|
||||
StringProperty = "A"
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Remove("SimpleDTO/StringProperty");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
Assert.Equal(null, doc.SimpleDTO.StringProperty);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NestedRemoveMixedCase()
|
||||
{
|
||||
dynamic doc = new ExpandoObject();
|
||||
doc.SimpleDTO = new SimpleDTO()
|
||||
{
|
||||
StringProperty = "A"
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Remove("Simpledto/stringProperty");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
|
||||
Assert.Equal(null, doc.SimpleDTO.StringProperty);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NestedRemoveFromList()
|
||||
{
|
||||
dynamic doc = new ExpandoObject();
|
||||
doc.SimpleDTO = new SimpleDTO()
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Remove("SimpleDTO/IntegerList/2");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
|
||||
Assert.Equal(new List<int>() { 1, 2 }, doc.SimpleDTO.IntegerList);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NestedRemoveFromListMixedCase()
|
||||
{
|
||||
dynamic doc = new ExpandoObject();
|
||||
doc.SimpleDTO = new SimpleDTO()
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Remove("SimpleDTO/Integerlist/2");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
|
||||
Assert.Equal(new List<int>() { 1, 2 }, doc.SimpleDTO.IntegerList);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NestedRemoveFromListInvalidPositionTooLarge()
|
||||
{
|
||||
dynamic doc = new ExpandoObject();
|
||||
doc.SimpleDTO = new SimpleDTO()
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Remove("SimpleDTO/IntegerList/3");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
var exception = Assert.Throws<JsonPatchException>(() =>
|
||||
{
|
||||
deserialized.ApplyTo(doc);
|
||||
});
|
||||
Assert.Equal(
|
||||
"For operation 'remove' on array property at path '/SimpleDTO/IntegerList/3', the index is larger than the array size.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NestedRemoveFromListInvalidPositionTooSmall()
|
||||
{
|
||||
dynamic doc = new ExpandoObject();
|
||||
doc.SimpleDTO = new SimpleDTO()
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Remove("SimpleDTO/IntegerList/-1");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
var exception = Assert.Throws<JsonPatchException>(() =>
|
||||
{
|
||||
deserialized.ApplyTo(doc);
|
||||
});
|
||||
Assert.Equal(
|
||||
"For operation 'remove' on array property at path '/SimpleDTO/IntegerList/-1', the index is negative.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NestedRemoveFromEndOfList()
|
||||
{
|
||||
dynamic doc = new ExpandoObject();
|
||||
doc.SimpleDTO = new SimpleDTO()
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Remove("SimpleDTO/IntegerList/-");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
Assert.Equal(new List<int>() { 1, 2 }, doc.SimpleDTO.IntegerList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,244 @@
|
|||
// 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.Generic;
|
||||
using Microsoft.AspNet.JsonPatch.Exceptions;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.JsonPatch.Test.Dynamic
|
||||
{
|
||||
public class RemoveTypedOperationTests
|
||||
{
|
||||
[Fact]
|
||||
public void Remove()
|
||||
{
|
||||
var doc = new SimpleDTO()
|
||||
{
|
||||
StringProperty = "A"
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Remove("StringProperty");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
|
||||
Assert.Equal(null, doc.StringProperty);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveFromList()
|
||||
{
|
||||
var doc = new SimpleDTO()
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Remove("IntegerList/2");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
|
||||
Assert.Equal(new List<int>() { 1, 2 }, doc.IntegerList);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveFromListInvalidPositionTooLarge()
|
||||
{
|
||||
var doc = new SimpleDTO()
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Remove("IntegerList/3");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
var exception = Assert.Throws<JsonPatchException>(() =>
|
||||
{
|
||||
deserialized.ApplyTo(doc);
|
||||
});
|
||||
Assert.Equal(
|
||||
"For operation 'remove' on array property at path '/IntegerList/3', the index is larger than the array size.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveFromListInvalidPositionTooSmall()
|
||||
{
|
||||
var doc = new SimpleDTO()
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Remove("IntegerList/-1");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
var exception = Assert.Throws<JsonPatchException>(() =>
|
||||
{
|
||||
deserialized.ApplyTo(doc);
|
||||
});
|
||||
Assert.Equal(
|
||||
"For operation 'remove' on array property at path '/IntegerList/-1', the index is negative.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveFromEndOfList()
|
||||
{
|
||||
var doc = new SimpleDTO()
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Remove("IntegerList/-");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
|
||||
Assert.Equal(new List<int>() { 1, 2 }, doc.IntegerList);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NestedRemove()
|
||||
{
|
||||
var doc = new SimpleDTOWithNestedDTO()
|
||||
{
|
||||
SimpleDTO = new SimpleDTO()
|
||||
{
|
||||
StringProperty = "A"
|
||||
}
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Remove("SimpleDTO/StringProperty");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
|
||||
Assert.Equal(null, doc.SimpleDTO.StringProperty);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NestedRemoveFromList()
|
||||
{
|
||||
var doc = new SimpleDTOWithNestedDTO()
|
||||
{
|
||||
SimpleDTO = new SimpleDTO()
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
}
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Remove("SimpleDTO/IntegerList/2");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
|
||||
Assert.Equal(new List<int>() { 1, 2 }, doc.SimpleDTO.IntegerList);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NestedRemoveFromListInvalidPositionTooLarge()
|
||||
{
|
||||
var doc = new SimpleDTOWithNestedDTO()
|
||||
{
|
||||
SimpleDTO = new SimpleDTO()
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
}
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Remove("SimpleDTO/IntegerList/3");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
var exception = Assert.Throws<JsonPatchException>(() =>
|
||||
{
|
||||
deserialized.ApplyTo(doc);
|
||||
});
|
||||
Assert.Equal(
|
||||
"For operation 'remove' on array property at path '/SimpleDTO/IntegerList/3', the index is larger than the array size.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NestedRemoveFromListInvalidPositionTooSmall()
|
||||
{
|
||||
var doc = new SimpleDTOWithNestedDTO()
|
||||
{
|
||||
SimpleDTO = new SimpleDTO()
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
}
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Remove("SimpleDTO/IntegerList/-1");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
var exception = Assert.Throws<JsonPatchException>(() =>
|
||||
{
|
||||
deserialized.ApplyTo(doc);
|
||||
});
|
||||
Assert.Equal(
|
||||
"For operation 'remove' on array property at path '/SimpleDTO/IntegerList/-1', the index is negative.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NestedRemoveFromEndOfList()
|
||||
{
|
||||
var doc = new SimpleDTOWithNestedDTO()
|
||||
{
|
||||
SimpleDTO = new SimpleDTO()
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
}
|
||||
};
|
||||
|
||||
// create patch
|
||||
JsonPatchDocument patchDoc = new JsonPatchDocument();
|
||||
patchDoc.Remove("SimpleDTO/IntegerList/-");
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);
|
||||
|
||||
deserialized.ApplyTo(doc);
|
||||
|
||||
Assert.Equal(new List<int>() { 1, 2 }, doc.SimpleDTO.IntegerList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// 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;
|
||||
|
||||
namespace Microsoft.AspNet.JsonPatch.Test.Dynamic
|
||||
{
|
||||
public class SimpleDTO
|
||||
{
|
||||
public List<SimpleDTO> SimpleDTOList { get; set; }
|
||||
public List<int> IntegerList { get; set; }
|
||||
public int IntegerValue { get; set; }
|
||||
public string StringProperty { get; set; }
|
||||
public string AnotherStringProperty { get; set; }
|
||||
public decimal DecimalValue { get; set; }
|
||||
public double DoubleValue { get; set; }
|
||||
public float FloatValue { get; set; }
|
||||
public Guid GuidValue { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
// 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.Generic;
|
||||
|
||||
namespace Microsoft.AspNet.JsonPatch.Test.Dynamic
|
||||
{
|
||||
public class SimpleDTOWithNestedDTO
|
||||
{
|
||||
public int IntegerValue { get; set; }
|
||||
public NestedDTO NestedDTO { get; set; }
|
||||
public SimpleDTO SimpleDTO { get; set; }
|
||||
public List<SimpleDTO> ListOfSimpleDTO { get; set; }
|
||||
|
||||
public SimpleDTOWithNestedDTO()
|
||||
{
|
||||
NestedDTO = new NestedDTO();
|
||||
SimpleDTO = new SimpleDTO();
|
||||
ListOfSimpleDTO = new List<SimpleDTO>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -778,7 +778,7 @@ namespace Microsoft.AspNet.JsonPatch.Test
|
|||
|
||||
// Act & Assert
|
||||
var exception = Assert.Throws<JsonPatchException>(() => { patchDoc.ApplyTo(doc); });
|
||||
Assert.Equal("Property does not exist at path '/simpledto/integerlist/-1'.", exception.Message);
|
||||
Assert.Equal("For operation 'remove' on array property at path '/simpledto/integerlist/-1', the index is negative.", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -805,7 +805,7 @@ namespace Microsoft.AspNet.JsonPatch.Test
|
|||
{
|
||||
deserialized.ApplyTo(doc);
|
||||
});
|
||||
Assert.Equal("Property does not exist at path '/simpledto/integerlist/-1'.", exception.Message);
|
||||
Assert.Equal("For operation 'remove' on array property at path '/simpledto/integerlist/-1', the index is negative.", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -830,7 +830,7 @@ namespace Microsoft.AspNet.JsonPatch.Test
|
|||
patchDoc.ApplyTo(doc, logger.LogErrorMessage);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Property does not exist at path '/simpledto/integerlist/-1'.", logger.ErrorMessage);
|
||||
Assert.Equal("For operation 'remove' on array property at path '/simpledto/integerlist/-1', the index is negative.", logger.ErrorMessage);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1319,11 +1319,10 @@ namespace Microsoft.AspNet.JsonPatch.Test
|
|||
// create patch
|
||||
var patchDoc = new JsonPatchDocument<SimpleDTOWithNestedDTO>();
|
||||
patchDoc.Replace<int>(o => o.SimpleDTO.IntegerList, 5, -1);
|
||||
|
||||
|
||||
// Act & Assert
|
||||
var exception = Assert.Throws<JsonPatchException>(() => { patchDoc.ApplyTo(doc); });
|
||||
Assert.Equal(
|
||||
"Property does not exist at path '/simpledto/integerlist/-1'.",
|
||||
Assert.Equal("For operation 'replace' on array property at path '/simpledto/integerlist/-1', the index is negative.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
|
|
@ -1349,7 +1348,7 @@ namespace Microsoft.AspNet.JsonPatch.Test
|
|||
// Act & Assert
|
||||
var exception = Assert.Throws<JsonPatchException>(() => { deserialized.ApplyTo(doc); });
|
||||
Assert.Equal(
|
||||
"Property does not exist at path '/simpledto/integerlist/-1'.",
|
||||
"For operation 'replace' on array property at path '/simpledto/integerlist/-1', the index is negative.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -577,7 +577,7 @@ namespace Microsoft.AspNet.JsonPatch.Test
|
|||
|
||||
// Act & Assert
|
||||
var exception = Assert.Throws<JsonPatchException>(() => { patchDoc.ApplyTo(doc); });
|
||||
Assert.Equal("Property does not exist at path '/integerlist/-1'.", exception.Message);
|
||||
Assert.Equal("For operation 'remove' on array property at path '/integerlist/-1', the index is negative.", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -598,7 +598,7 @@ namespace Microsoft.AspNet.JsonPatch.Test
|
|||
|
||||
// Act & Assert
|
||||
var exception = Assert.Throws<JsonPatchException>(() => { deserialized.ApplyTo(doc); });
|
||||
Assert.Equal("Property does not exist at path '/integerlist/-1'.", exception.Message);
|
||||
Assert.Equal("For operation 'remove' on array property at path '/integerlist/-1', the index is negative.", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -621,7 +621,7 @@ namespace Microsoft.AspNet.JsonPatch.Test
|
|||
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Property does not exist at path '/integerlist/-1'.", logger.ErrorMessage);
|
||||
Assert.Equal("For operation 'remove' on array property at path '/integerlist/-1', the index is negative.", logger.ErrorMessage);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1172,7 +1172,7 @@ namespace Microsoft.AspNet.JsonPatch.Test
|
|||
{
|
||||
patchDoc.ApplyTo(doc);
|
||||
});
|
||||
Assert.Equal("Property does not exist at path '/integerlist/-1'.", exception.Message);
|
||||
Assert.Equal("For operation 'replace' on array property at path '/integerlist/-1', the index is negative.", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1196,7 +1196,7 @@ namespace Microsoft.AspNet.JsonPatch.Test
|
|||
{
|
||||
deserialized.ApplyTo(doc);
|
||||
});
|
||||
Assert.Equal("Property does not exist at path '/integerlist/-1'.", exception.Message);
|
||||
Assert.Equal("For operation 'replace' on array property at path '/integerlist/-1', the index is negative.", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
Loading…
Reference in New Issue