Merge branch 'rel/1.1.1' into dev

Conflicts:
	NuGet.config
	src/Microsoft.AspNetCore.JsonPatch/project.json
	test/Microsoft.AspNetCore.JsonPatch.Test/project.json
This commit is contained in:
Kiran Challa 2017-01-26 14:02:29 -08:00
commit b240929cf4
2 changed files with 136 additions and 9 deletions

View File

@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
} }
PositionInfo positionInfo; PositionInfo positionInfo;
if (!TryGetPositionInfo(list, segment, out positionInfo, out errorMessage)) if (!TryGetPositionInfo(list, segment, OperationType.Add, out positionInfo, out errorMessage))
{ {
return false; return false;
} }
@ -68,7 +68,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
} }
PositionInfo positionInfo; PositionInfo positionInfo;
if (!TryGetPositionInfo(list, segment, out positionInfo, out errorMessage)) if (!TryGetPositionInfo(list, segment, OperationType.Get, out positionInfo, out errorMessage))
{ {
value = null; value = null;
return false; return false;
@ -102,7 +102,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
} }
PositionInfo positionInfo; PositionInfo positionInfo;
if (!TryGetPositionInfo(list, segment, out positionInfo, out errorMessage)) if (!TryGetPositionInfo(list, segment, OperationType.Remove, out positionInfo, out errorMessage))
{ {
return false; return false;
} }
@ -136,7 +136,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
} }
PositionInfo positionInfo; PositionInfo positionInfo;
if (!TryGetPositionInfo(list, segment, out positionInfo, out errorMessage)) if (!TryGetPositionInfo(list, segment, OperationType.Replace, out positionInfo, out errorMessage))
{ {
return false; return false;
} }
@ -243,7 +243,12 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
} }
} }
private bool TryGetPositionInfo(IList list, string segment, out PositionInfo positionInfo, out string errorMessage) private bool TryGetPositionInfo(
IList list,
string segment,
OperationType operationType,
out PositionInfo positionInfo,
out string errorMessage)
{ {
if (segment == "-") if (segment == "-")
{ {
@ -261,16 +266,24 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
errorMessage = null; errorMessage = null;
return true; return true;
} }
// As per JSON Patch spec, for Add operation the index value representing the number of elements is valid,
// where as for other operations like Remove, Replace, Move and Copy the target index MUST exist.
else if (position == list.Count && operationType == OperationType.Add)
{
positionInfo = new PositionInfo(PositionType.EndOfList, -1);
errorMessage = null;
return true;
}
else else
{ {
positionInfo = default(PositionInfo); positionInfo = new PositionInfo(PositionType.OutOfBounds, position);
errorMessage = Resources.FormatIndexOutOfBounds(segment); errorMessage = Resources.FormatIndexOutOfBounds(segment);
return false; return false;
} }
} }
else else
{ {
positionInfo = default(PositionInfo); positionInfo = new PositionInfo(PositionType.Invalid, -1);
errorMessage = Resources.FormatInvalidIndexValue(segment); errorMessage = Resources.FormatInvalidIndexValue(segment);
return false; return false;
} }
@ -295,5 +308,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
Invalid, // Ex: not an integer Invalid, // Ex: not an integer
OutOfBounds OutOfBounds
} }
private enum OperationType
{
Add,
Remove,
Get,
Replace
}
} }
} }

View File

@ -55,12 +55,31 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
message); message);
} }
[Fact]
public void Add_WithIndexSameAsNumberOfElements_Works()
{
// Arrange
var resolver = new Mock<IContractResolver>(MockBehavior.Strict);
var targetObject = new List<string>() { "James", "Mike" };
var listAdapter = new ListAdapter();
string message = null;
var position = targetObject.Count.ToString();
// Act
var addStatus = listAdapter.TryAdd(targetObject, position, resolver.Object, "Rob", out message);
// Assert
Assert.Null(message);
Assert.True(addStatus);
Assert.Equal(3, targetObject.Count);
Assert.Equal(new List<string>() { "James", "Mike", "Rob" }, targetObject);
}
[Theory] [Theory]
[InlineData("-1")] [InlineData("-1")]
[InlineData("-2")] [InlineData("-2")]
[InlineData("2")]
[InlineData("3")] [InlineData("3")]
public void Patch_WithOutOfBoundsIndex_Fails(string position) public void Add_WithOutOfBoundsIndex_Fails(string position)
{ {
// Arrange // Arrange
var resolver = new Mock<IContractResolver>(MockBehavior.Strict); var resolver = new Mock<IContractResolver>(MockBehavior.Strict);
@ -225,6 +244,93 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
Assert.Equal(expected, targetObject); Assert.Equal(expected, targetObject);
} }
[Theory]
[InlineData(new int[] { }, "0")]
[InlineData(new[] { 10, 20 }, "-1")]
[InlineData(new[] { 10, 20 }, "2")]
public void Get_IndexOutOfBounds(int[] input, string position)
{
// Arrange
var resolver = new Mock<IContractResolver>(MockBehavior.Strict);
var targetObject = new List<int>(input);
var listAdapter = new ListAdapter();
string message = null;
object value = null;
// Act
var getStatus = listAdapter.TryGet(targetObject, position, resolver.Object, out value, out message);
// Assert
Assert.False(getStatus);
Assert.Equal(
string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", position),
message);
}
[Theory]
[InlineData(new[] { 10, 20 }, "0", 10)]
[InlineData(new[] { 10, 20 }, "1", 20)]
[InlineData(new[] { 10 }, "0", 10)]
public void Get(int[] input, string position, object expected)
{
// Arrange
var resolver = new Mock<IContractResolver>(MockBehavior.Strict);
var targetObject = new List<int>(input);
var listAdapter = new ListAdapter();
string message = null;
object value = null;
// Act
var getStatus = listAdapter.TryGet(targetObject, position, resolver.Object, out value, out message);
// Assert
Assert.True(getStatus);
Assert.Equal(expected, value);
Assert.Equal(new List<int>(input), targetObject);
}
[Theory]
[InlineData(new int[] { }, "0")]
[InlineData(new[] { 10, 20 }, "-1")]
[InlineData(new[] { 10, 20 }, "2")]
public void Remove_IndexOutOfBounds(int[] input, string position)
{
// Arrange
var resolver = new Mock<IContractResolver>(MockBehavior.Strict);
var targetObject = new List<int>(input);
var listAdapter = new ListAdapter();
string message = null;
// Act
var removeStatus = listAdapter.TryRemove(targetObject, position, resolver.Object, out message);
// Assert
Assert.False(removeStatus);
Assert.Equal(
string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", position),
message);
}
[Theory]
[InlineData(new[] { 10, 20 }, "0", new[] { 20 })]
[InlineData(new[] { 10, 20 }, "1", new[] { 10 })]
[InlineData(new[] { 10 }, "0", new int[] { })]
public void Remove(int[] input, string position, int[] expected)
{
// Arrange
var resolver = new Mock<IContractResolver>(MockBehavior.Strict);
var targetObject = new List<int>(input);
var listAdapter = new ListAdapter();
string message = null;
// Act
var removeStatus = listAdapter.TryRemove(targetObject, position, resolver.Object, out message);
// Assert
Assert.True(removeStatus);
Assert.Equal(new List<int>(expected), targetObject);
}
[Fact] [Fact]
public void Replace_NonCompatibleType_Fails() public void Replace_NonCompatibleType_Fails()
{ {