add PatchBehavior.PatchBehavior

pull/66/head
Newp 2023-05-28 04:53:24 +09:00
parent c2b2458823
commit 3d49c4335b
4 changed files with 343 additions and 300 deletions

View File

@ -1,252 +1,268 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json.Linq;
using NUnit.Framework;
namespace JsonDiffPatchDotNet.UnitTests
{
[TestFixture]
public class PatchUnitTests
{
[Test]
public void Patch_ObjectApplyDelete_Success()
{
var jdp = new JsonDiffPatch();
var left = JObject.Parse(@"{ ""p"" : true }");
var right = JObject.Parse(@"{ }");
var patch = jdp.Diff(left, right);
var patched = jdp.Patch(left, patch) as JObject;
Assert.IsNotNull(patched, "Patched object");
Assert.AreEqual(0, patched.Properties().Count(), "Property Deleted");
}
[Test]
public void Patch_ObjectApplyAdd_Success()
{
var jdp = new JsonDiffPatch();
var left = JObject.Parse(@"{ }");
var right = JObject.Parse(@"{ ""p"" : true }");
var patch = jdp.Diff(left, right);
var patched = jdp.Patch(left, patch) as JObject;
Assert.IsNotNull(patched, "Patched object");
Assert.AreEqual(1, patched.Properties().Count(), "Property");
Assert.AreEqual(JTokenType.Boolean, patched.Property("p").Value.Type);
Assert.IsTrue(patched.Property("p").Value.ToObject<bool>(), "Patched Property");
}
[Test]
public void Patch_ObjectApplyEdit_Success()
{
var jdp = new JsonDiffPatch();
var left = JObject.Parse(@"{ ""p"" : false }");
var right = JObject.Parse(@"{ ""p"" : true }");
var patch = jdp.Diff(left, right);
var patched = jdp.Patch(left, patch) as JObject;
Assert.IsNotNull(patched, "Patched object");
Assert.AreEqual(1, patched.Properties().Count(), "Property");
Assert.AreEqual(JTokenType.Boolean, patched.Property("p").Value.Type);
Assert.IsTrue(patched.Property("p").Value.ToObject<bool>(), "Patched Property");
}
[Test]
public void Patch_ObjectApplyEditText_Success()
{
var jdp = new JsonDiffPatch();
var left = JObject.Parse(@"{ ""p"" : ""bla1h111111111111112312weldjidjoijfoiewjfoiefjefijfoejoijfiwoejfiewjfiwejfowjwifewjfejdewdwdewqwertyqwertifwiejifoiwfei"" }");
var right = JObject.Parse(@"{ ""p"" : ""blah1"" }");
var patch = jdp.Diff(left, right);
var patched = jdp.Patch(left, patch) as JObject;
Assert.IsNotNull(patched, "Patched object");
Assert.AreEqual(1, patched.Properties().Count(), "Property");
Assert.AreEqual(JTokenType.String, patched.Property("p").Value.Type, "String Type");
Assert.AreEqual("blah1", patched.Property("p").Value.ToString(), "String value");
}
[Test]
public void Patch_ObjectApplyEditTextEfficient_Success()
{
var options = new Options { MinEfficientTextDiffLength = 1, TextDiff = TextDiffMode.Efficient };
var jdp = new JsonDiffPatch(options);
var left = JObject.Parse(@"{ ""p"" : ""The quick brown fox jumps over the lazy dog."" }");
var right = JObject.Parse(@"{ ""p"" : ""That quick brown fox jumped over a lazy dog."" }");
var patch = jdp.Diff(left, right);
var patched = jdp.Patch(left, patch) as JObject;
Assert.IsNotNull(patched, "Patched object");
Assert.AreEqual(1, patched.Properties().Count(), "Property");
Assert.AreEqual(JTokenType.String, patched.Property("p").Value.Type, "String Type");
Assert.AreEqual("That quick brown fox jumped over a lazy dog.", patched.Property("p").Value.ToString(), "String value");
}
[Test]
public void Patch_NestedObjectApplyEdit_Success()
{
var jdp = new JsonDiffPatch();
var left = JObject.Parse(@"{ ""i"": { ""p"" : false } }");
var right = JObject.Parse(@"{ ""i"": { ""p"" : true } }");
var patch = jdp.Diff(left, right);
var patched = jdp.Patch(left, patch) as JObject;
Assert.IsNotNull(patched, "Patched object");
Assert.AreEqual(1, patched.Properties().Count(), "Property");
Assert.AreEqual(JTokenType.Object, patched.Property("i").Value.Type);
Assert.AreEqual(1, ((JObject)patched.Property("i").Value).Properties().Count());
Assert.AreEqual(JTokenType.Boolean, ((JObject)patched.Property("i").Value).Property("p").Value.Type);
Assert.IsTrue(((JObject)patched.Property("i").Value).Property("p").Value.ToObject<bool>());
}
[Test]
public void Patch_NestedComplexEdit_Success()
{
var jdp = new JsonDiffPatch();
var left = JObject.Parse(@"{ ""i"": { ""1"" : 1, ""2"": 2 }, ""j"": [0, 2, 4], ""k"": [1] }");
var right = JObject.Parse(@"{ ""i"": { ""1"" : 1, ""2"": 3 }, ""j"": [0, 2, 3], ""k"": null }");
var patch = jdp.Diff(left, right);
var patched = jdp.Patch(left, patch);
Assert.AreEqual(right.ToString(), patched.ToString());
}
[Test]
public void Patch_NestedComplexEditDifferentLeft_Success()
{
var jdp = new JsonDiffPatch();
var left = JObject.Parse(@"{ ""i"": { ""1"" : 1, ""2"": 2 }, ""j"": [0, 2, 4], ""k"": [1] }");
var right = JObject.Parse(@"{ ""i"": { ""1"" : 1, ""2"": 3 }, ""j"": [0, 2, 3], ""k"": null }");
var patch = jdp.Diff(JObject.Parse(@"{ ""k"": { ""i"": [1] } }"), right);
var patched = jdp.Patch(left, patch);
Assert.AreEqual(right.ToString(), patched.ToString());
}
[Test]
public void Patch_NullLeft_Exception()
{
var jdp = new JsonDiffPatch();
var patch = JToken.Parse(@"[true]");
JToken result = jdp.Patch(null, patch);
Assert.IsNotNull(result);
Assert.AreEqual(JTokenType.Boolean, result.Type);
Assert.AreEqual(true, result.ToObject<bool>());
}
[Test]
public void Patch_ArrayPatchAdd_Success()
{
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
var left = JToken.Parse(@"[1,2,3]");
var right = JToken.Parse(@"[1,2,3,4]");
var patch = jdp.Diff(left, right);
var patched = jdp.Patch(left, patch);
Assert.AreEqual(right.ToString(), patched.ToString());
}
[Test]
public void Patch_ArrayPatchRemove_Success()
{
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
var left = JToken.Parse(@"[1,2,3]");
var right = JToken.Parse(@"[1,2]");
var patch = jdp.Diff(left, right);
var patched = jdp.Patch(left, patch);
Assert.AreEqual(right.ToString(), patched.ToString());
}
[Test]
public void Patch_ArrayPatchModify_Success()
{
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
var left = JToken.Parse(@"[1,3,{""p"":false}]");
var right = JToken.Parse(@"[1,4,{""p"": [1] }]");
var patch = jdp.Diff(left, right);
var patched = jdp.Patch(left, patch);
Assert.AreEqual(right.ToString(), patched.ToString());
}
[Test]
public void Patch_ArrayPatchComplex_Success()
{
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
var left = JToken.Parse(@"{""p"": [1,2,[1],false,""11111"",3,{""p"":false},10,10] }");
var right = JToken.Parse(@"{""p"": [1,2,[1,3],false,""11112"",3,{""p"":true},10,10] }");
var patch = jdp.Diff(left, right);
var patched = jdp.Patch(left, patch);
Assert.AreEqual(right.ToString(), patched.ToString());
}
[Test]
public void Patch_ArrayPatchMoving_Success()
{
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
var left = JToken.Parse(@"[0,1,2,3,4,5,6,7,8,9,10]");
var right = JToken.Parse(@"[10,0,1,7,2,4,5,6,88,9,3]");
var patch = JToken.Parse(@"{ ""8"": [88], ""_t"": ""a"", ""_3"": ["""", 10, 3], ""_7"": ["""", 3, 3], ""_8"": [8, 0, 0], ""_10"": ["""", 0, 3] }");
var patched = jdp.Patch(left, patch);
Assert.AreEqual(right.ToString(), patched.ToString());
}
[Test]
public void Patch_ArrayPatchMovingNonConsecutive_Success()
{
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
var left = JToken.Parse(@"[0,1,3,4,5]");
var right = JToken.Parse(@"[0,4,3,1,5]");
var patch = JToken.Parse(@"{""_t"": ""a"", ""_2"": ["""", 2, 3],""_3"": ["""", 1, 3]}");
var patched = jdp.Patch(left, patch);
Assert.AreEqual(right.ToString(), patched.ToString());
}
[Test]
public void Patch_ArrayPatchMoveDeletingNonConsecutive_Success()
{
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
var left = JToken.Parse(@"[0,1,3,4,5]");
var right = JToken.Parse(@"[0,5,3]");
var patch = JToken.Parse(@"{""_t"": ""a"", ""_1"": [ 1, 0, 0], ""_3"": [4,0, 0],""_4"": [ """", 1, 3 ]}");
var patched = jdp.Patch(left, patch);
Assert.AreEqual(right.ToString(), patched.ToString());
}
[Test]
public void Patch_Bug17EfficienText_Success()
{
var jdp = new JsonDiffPatch();
var left = JToken.Parse("{ \"key\": \"aaaa aaaaaa aaaa aaaaaaa: aaaaaaaaa aaaa aaaaaaaa aaaa: 31-aaa-2017 aaaaa aaaaa aaaaaaa aaaa aaaaaaaa aaaa: 31-aaa-2017aaaaaa aaaaaa: aaaaaaaaa aaaaaa: aaaaaa aaaaa aaaaa aaaaaaa aaaaaa: aaaaaaaaaa aaaaaaaa aaaaaaa: aaaa(aaaa aaaaaa/aaaaaaaaaaaa)-aaaaaaa(aaaaaaaaaa/aaaaaaaaaa aaaa aaaaaa)aaaaa aaaaa aaaaaaa:aaaaaa aaaaaaa: aaaaaaaa aaaaaaaaaa aaaaaaa: aaaaaaaaaaaa aaaaaaaaaa: aaaaaaaa-aaaaaaaaaaaaaaaa aaaaaaaaaa aaaaaa: aaaaaaaaaaaaaaaa aaaaaaaaaa aaaaa: aaaaaaaa aaaaa-aaaaa aaaaaaaaaa, aaaaa aaaaaaa aa aaaaaaa aaaaaaaaaaaa aaaaa aaaaaaaaaaa (aaaaaa), aaaaa a 100 aaaaa aa aaa aaaaaaa.aaa aaaa: aaaaaaaaaaaaaaaa: aaaaaaaaaaaa aaaaaaaa: aaa aaaaa aaaaa:aaaaaaa aaaaaaa: 31-aaa-2014aaaaaa aaaaa: 16-aaa-2016aaaaaa aaaaa: 30-aaa-2017aaaaaa aaaaa: 27-aaa-2017aaaaaa aaaaa: 31-aaa-2017aa aaaaaaaaaa aaaaaaaaaa, (aaaaa aa aaaa aa a 52.67 aaaaa aa aaaa aaa aaaa aaaaaa aaaaaa), aaaaa 100 aa aaaa aaaaaaa.aaaaaaa aaaaaaa: 16-aaa-2016aaaa aaaaaaa aa 100 aaaaa aa aaaa aaa aaaa aaaaaa aaa aa aaaaaaaaaa aaa aaaaaaaaaa, a 88.02 aaaaaaaaaa aa aaaa aaa aaaa aaaaaa aaaaaa.aaaaaaa aaaaaaa: 30-aaa-2017aaaa aaaaaaa aa 100 aaaaa aa aaa-aaaa aaaaaa, aaaaa aa 100 aaaaa aa aaaa aaa aaaa aaaaaa aaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaa aaa, aaaaa aa aaaa aa 65.656 aaaaa aa aaaa aaa aaaa aaaaaa aaa aa aaaaaaaaaa aaa aaaaaaaaaa aaa 34.343 aa aaaa aaa aaaa aaaaaa aaaaaa. aaaa aaa aaaa aaaaaa aaa aa aaaaaaaaaa aaa aaaaaaaaaa aa 88.02 aaaaa aa aaaa aaa aaaa aaaaaa aaaaaa.aaaaaaa aaaaaaa: 27-aaa-2017aaaa aaaaaaa aa 100 aaaaa aa aaa-aaaa aaaaaa, aaaaa\" }");
var right = JToken.Parse("{ \"key\": \"aaaa aaaaaa aaaa aaaaaaa: aaaaaaaaa aaaa aaaaaaaa aaaa: 17-aaa-2017 aaaaa aaaaa aaaaaaa aaaa aaaaaaaa aaaa: 17-aaa-2017aaaaaa aaaaaa: aaaaaaaaa aaaaaa: aaaaaa aaaaa aaaaa aaaaaaa aaaaaa: aaaaaaaaaa aaaaaaaa aaaaaaa: aaaa(aaaa aaaaaa/aaaaaaaaaaaa)-aaaaaaa(aaaaaaaaaa/aaaaaaaaaa aaaa aaaaaa)aaaaa aaaaa aaaaaaa:aaaaaa aaaaaaa: aaaaaaaa aaaaaaaaaa aaaaaaa: aaaaaaaaaaaa aaaaaaaaaa: aaaaaaaa-aaaaaaaaaaaaaaaa aaaaaaaaaa aaaaaa: aaaaaaaaaaaaaaaa aaaaaaaaaa aaaaa aaaa: -2016aaaaaaaaa aaaaaaaaaa aaaaa: aaaa aaaaaaa aa 100 aaaaa aa aaa-aaaa aaaaaa aaa, aaaaaaaa aaaaaaaaaa aa aaaaaa.aaaaaaaaa aaaaaaaaaa: aaaaaaaa-aaaaaaaaaaaaaaaa aaaaaaaaaa aaaaaa: aaaaaaaaaaaaa aaaaaaaaaa aa aaaa: -2016aaaaaaaaa aaaaaaaaaa aaaaa: aaaaaaaa aaaaa-aaaaa aaaaaaaaaa, aaaaa aaaaaaa aa aaaaaaa aaaaaaaaaaaa aaaaa aaaaaaaaaaa (aaaaaa), aaaaa a 100 aaaaa aa aaa aaaaaaa.aaa aaaa: aaaaaaaaaaaaaaaa: aaaaaaaaaaaa aaaaaaaa: aaa aaaaa aaaaa:aaaaaaa aaaaaaa: 31-aaa-2014aaaaaa aaaaa: 16-aaa-2016aaaaaa aaaaa: 30-aaa-2017aaaaaa aaaaa: 27-aaa-2017aaaaaa aaaaa: 31-aaa-2017aaaaaa aaaaa: 16-aaa-2017aa aaaaaaaaaa aaaaaaaaaa, (aaaaa aa aaaa aa a 52.67 aaaaa aa aaaa aaa aaaa aaaaaa aaaaaa), aaaaa 100 aa aaaa aaaaaaa.aaaaaaa aaaaaaa: 16-aaa-2016aaaa\" }");
JToken patch = jdp.Diff(left, right);
var patched = jdp.Patch(left, patch);
Assert.IsTrue(JToken.DeepEquals(right.ToString(), patched.ToString()));
using System.Linq;
using Newtonsoft.Json.Linq;
using NUnit.Framework;
namespace JsonDiffPatchDotNet.UnitTests
{
[TestFixture]
public class PatchUnitTests
{
[Test]
public void Patch_ObjectApplyDelete_Success()
{
var jdp = new JsonDiffPatch();
var left = JObject.Parse(@"{ ""p"" : true }");
var right = JObject.Parse(@"{ }");
var patch = jdp.Diff(left, right);
var patched = jdp.Patch(left, patch) as JObject;
Assert.IsNotNull(patched, "Patched object");
Assert.AreEqual(0, patched.Properties().Count(), "Property Deleted");
}
[Test]
public void Patch_ObjectApplyAdd_Success()
{
var jdp = new JsonDiffPatch();
var left = JObject.Parse(@"{ }");
var right = JObject.Parse(@"{ ""p"" : true }");
var patch = jdp.Diff(left, right);
var patched = jdp.Patch(left, patch) as JObject;
Assert.IsNotNull(patched, "Patched object");
Assert.AreEqual(1, patched.Properties().Count(), "Property");
Assert.AreEqual(JTokenType.Boolean, patched.Property("p").Value.Type);
Assert.IsTrue(patched.Property("p").Value.ToObject<bool>(), "Patched Property");
}
[Test]
public void Patch_ObjectApplyEdit_Success()
{
var jdp = new JsonDiffPatch();
var left = JObject.Parse(@"{ ""p"" : false }");
var right = JObject.Parse(@"{ ""p"" : true }");
var patch = jdp.Diff(left, right);
var patched = jdp.Patch(left, patch) as JObject;
Assert.IsNotNull(patched, "Patched object");
Assert.AreEqual(1, patched.Properties().Count(), "Property");
Assert.AreEqual(JTokenType.Boolean, patched.Property("p").Value.Type);
Assert.IsTrue(patched.Property("p").Value.ToObject<bool>(), "Patched Property");
}
[Test]
public void Patch_ObjectApplyEditText_Success()
{
var jdp = new JsonDiffPatch();
var left = JObject.Parse(@"{ ""p"" : ""bla1h111111111111112312weldjidjoijfoiewjfoiefjefijfoejoijfiwoejfiewjfiwejfowjwifewjfejdewdwdewqwertyqwertifwiejifoiwfei"" }");
var right = JObject.Parse(@"{ ""p"" : ""blah1"" }");
var patch = jdp.Diff(left, right);
var patched = jdp.Patch(left, patch) as JObject;
Assert.IsNotNull(patched, "Patched object");
Assert.AreEqual(1, patched.Properties().Count(), "Property");
Assert.AreEqual(JTokenType.String, patched.Property("p").Value.Type, "String Type");
Assert.AreEqual("blah1", patched.Property("p").Value.ToString(), "String value");
}
[Test]
public void Patch_ObjectApplyEditTextEfficient_Success()
{
var options = new Options { MinEfficientTextDiffLength = 1, TextDiff = TextDiffMode.Efficient };
var jdp = new JsonDiffPatch(options);
var left = JObject.Parse(@"{ ""p"" : ""The quick brown fox jumps over the lazy dog."" }");
var right = JObject.Parse(@"{ ""p"" : ""That quick brown fox jumped over a lazy dog."" }");
var patch = jdp.Diff(left, right);
var patched = jdp.Patch(left, patch) as JObject;
Assert.IsNotNull(patched, "Patched object");
Assert.AreEqual(1, patched.Properties().Count(), "Property");
Assert.AreEqual(JTokenType.String, patched.Property("p").Value.Type, "String Type");
Assert.AreEqual("That quick brown fox jumped over a lazy dog.", patched.Property("p").Value.ToString(), "String value");
}
[Test]
public void Patch_NestedObjectApplyEdit_Success()
{
var jdp = new JsonDiffPatch();
var left = JObject.Parse(@"{ ""i"": { ""p"" : false } }");
var right = JObject.Parse(@"{ ""i"": { ""p"" : true } }");
var patch = jdp.Diff(left, right);
var patched = jdp.Patch(left, patch) as JObject;
Assert.IsNotNull(patched, "Patched object");
Assert.AreEqual(1, patched.Properties().Count(), "Property");
Assert.AreEqual(JTokenType.Object, patched.Property("i").Value.Type);
Assert.AreEqual(1, ((JObject)patched.Property("i").Value).Properties().Count());
Assert.AreEqual(JTokenType.Boolean, ((JObject)patched.Property("i").Value).Property("p").Value.Type);
Assert.IsTrue(((JObject)patched.Property("i").Value).Property("p").Value.ToObject<bool>());
}
[Test]
public void Patch_NestedComplexEdit_Success()
{
var jdp = new JsonDiffPatch();
var left = JObject.Parse(@"{ ""i"": { ""1"" : 1, ""2"": 2 }, ""j"": [0, 2, 4], ""k"": [1] }");
var right = JObject.Parse(@"{ ""i"": { ""1"" : 1, ""2"": 3 }, ""j"": [0, 2, 3], ""k"": null }");
var patch = jdp.Diff(left, right);
var patched = jdp.Patch(left, patch);
Assert.AreEqual(right.ToString(), patched.ToString());
}
[Test]
public void Patch_NestedComplexEditDifferentLeft_Success()
{
var jdp = new JsonDiffPatch();
var left = JObject.Parse(@"{ ""i"": { ""1"" : 1, ""2"": 2 }, ""j"": [0, 2, 4], ""k"": [1] }");
var right = JObject.Parse(@"{ ""i"": { ""1"" : 1, ""2"": 3 }, ""j"": [0, 2, 3], ""k"": null }");
var patch = jdp.Diff(JObject.Parse(@"{ ""k"": { ""i"": [1] } }"), right);
var patched = jdp.Patch(left, patch);
Assert.AreEqual(right.ToString(), patched.ToString());
}
[Test]
public void Patch_NullLeft_Exception()
{
var jdp = new JsonDiffPatch();
var patch = JToken.Parse(@"[true]");
JToken result = jdp.Patch(null, patch);
Assert.IsNotNull(result);
Assert.AreEqual(JTokenType.Boolean, result.Type);
Assert.AreEqual(true, result.ToObject<bool>());
}
[Test]
public void Patch_NotMatchLeft_Exception()
{
var jdp = new JsonDiffPatch(new Options(){ PatchBehavior = PatchBehavior.LeftMatchValidation});
var left1 = "{\"value\": 1}";
var left2 = "{}";
var right = "{\"value\": 3}";
var diff = "{\"value\": [2,3]}"; //no match with left value
Assert.Throws<Exception>(() => jdp.Patch(left1, diff));
Assert.Throws<Exception>(() => jdp.Patch(left2, diff));
}
[Test]
public void Patch_ArrayPatchAdd_Success()
{
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
var left = JToken.Parse(@"[1,2,3]");
var right = JToken.Parse(@"[1,2,3,4]");
var patch = jdp.Diff(left, right);
var patched = jdp.Patch(left, patch);
Assert.AreEqual(right.ToString(), patched.ToString());
}
[Test]
public void Patch_ArrayPatchRemove_Success()
{
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
var left = JToken.Parse(@"[1,2,3]");
var right = JToken.Parse(@"[1,2]");
var patch = jdp.Diff(left, right);
var patched = jdp.Patch(left, patch);
Assert.AreEqual(right.ToString(), patched.ToString());
}
[Test]
public void Patch_ArrayPatchModify_Success()
{
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
var left = JToken.Parse(@"[1,3,{""p"":false}]");
var right = JToken.Parse(@"[1,4,{""p"": [1] }]");
var patch = jdp.Diff(left, right);
var patched = jdp.Patch(left, patch);
Assert.AreEqual(right.ToString(), patched.ToString());
}
[Test]
public void Patch_ArrayPatchComplex_Success()
{
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
var left = JToken.Parse(@"{""p"": [1,2,[1],false,""11111"",3,{""p"":false},10,10] }");
var right = JToken.Parse(@"{""p"": [1,2,[1,3],false,""11112"",3,{""p"":true},10,10] }");
var patch = jdp.Diff(left, right);
var patched = jdp.Patch(left, patch);
Assert.AreEqual(right.ToString(), patched.ToString());
}
[Test]
public void Patch_ArrayPatchMoving_Success()
{
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
var left = JToken.Parse(@"[0,1,2,3,4,5,6,7,8,9,10]");
var right = JToken.Parse(@"[10,0,1,7,2,4,5,6,88,9,3]");
var patch = JToken.Parse(@"{ ""8"": [88], ""_t"": ""a"", ""_3"": ["""", 10, 3], ""_7"": ["""", 3, 3], ""_8"": [8, 0, 0], ""_10"": ["""", 0, 3] }");
var patched = jdp.Patch(left, patch);
Assert.AreEqual(right.ToString(), patched.ToString());
}
[Test]
public void Patch_ArrayPatchMovingNonConsecutive_Success()
{
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
var left = JToken.Parse(@"[0,1,3,4,5]");
var right = JToken.Parse(@"[0,4,3,1,5]");
var patch = JToken.Parse(@"{""_t"": ""a"", ""_2"": ["""", 2, 3],""_3"": ["""", 1, 3]}");
var patched = jdp.Patch(left, patch);
Assert.AreEqual(right.ToString(), patched.ToString());
}
[Test]
public void Patch_ArrayPatchMoveDeletingNonConsecutive_Success()
{
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
var left = JToken.Parse(@"[0,1,3,4,5]");
var right = JToken.Parse(@"[0,5,3]");
var patch = JToken.Parse(@"{""_t"": ""a"", ""_1"": [ 1, 0, 0], ""_3"": [4,0, 0],""_4"": [ """", 1, 3 ]}");
var patched = jdp.Patch(left, patch);
Assert.AreEqual(right.ToString(), patched.ToString());
}
[Test]
public void Patch_Bug17EfficienText_Success()
{
var jdp = new JsonDiffPatch();
var left = JToken.Parse("{ \"key\": \"aaaa aaaaaa aaaa aaaaaaa: aaaaaaaaa aaaa aaaaaaaa aaaa: 31-aaa-2017 aaaaa aaaaa aaaaaaa aaaa aaaaaaaa aaaa: 31-aaa-2017aaaaaa aaaaaa: aaaaaaaaa aaaaaa: aaaaaa aaaaa aaaaa aaaaaaa aaaaaa: aaaaaaaaaa aaaaaaaa aaaaaaa: aaaa(aaaa aaaaaa/aaaaaaaaaaaa)-aaaaaaa(aaaaaaaaaa/aaaaaaaaaa aaaa aaaaaa)aaaaa aaaaa aaaaaaa:aaaaaa aaaaaaa: aaaaaaaa aaaaaaaaaa aaaaaaa: aaaaaaaaaaaa aaaaaaaaaa: aaaaaaaa-aaaaaaaaaaaaaaaa aaaaaaaaaa aaaaaa: aaaaaaaaaaaaaaaa aaaaaaaaaa aaaaa: aaaaaaaa aaaaa-aaaaa aaaaaaaaaa, aaaaa aaaaaaa aa aaaaaaa aaaaaaaaaaaa aaaaa aaaaaaaaaaa (aaaaaa), aaaaa a 100 aaaaa aa aaa aaaaaaa.aaa aaaa: aaaaaaaaaaaaaaaa: aaaaaaaaaaaa aaaaaaaa: aaa aaaaa aaaaa:aaaaaaa aaaaaaa: 31-aaa-2014aaaaaa aaaaa: 16-aaa-2016aaaaaa aaaaa: 30-aaa-2017aaaaaa aaaaa: 27-aaa-2017aaaaaa aaaaa: 31-aaa-2017aa aaaaaaaaaa aaaaaaaaaa, (aaaaa aa aaaa aa a 52.67 aaaaa aa aaaa aaa aaaa aaaaaa aaaaaa), aaaaa 100 aa aaaa aaaaaaa.aaaaaaa aaaaaaa: 16-aaa-2016aaaa aaaaaaa aa 100 aaaaa aa aaaa aaa aaaa aaaaaa aaa aa aaaaaaaaaa aaa aaaaaaaaaa, a 88.02 aaaaaaaaaa aa aaaa aaa aaaa aaaaaa aaaaaa.aaaaaaa aaaaaaa: 30-aaa-2017aaaa aaaaaaa aa 100 aaaaa aa aaa-aaaa aaaaaa, aaaaa aa 100 aaaaa aa aaaa aaa aaaa aaaaaa aaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaa aaa, aaaaa aa aaaa aa 65.656 aaaaa aa aaaa aaa aaaa aaaaaa aaa aa aaaaaaaaaa aaa aaaaaaaaaa aaa 34.343 aa aaaa aaa aaaa aaaaaa aaaaaa. aaaa aaa aaaa aaaaaa aaa aa aaaaaaaaaa aaa aaaaaaaaaa aa 88.02 aaaaa aa aaaa aaa aaaa aaaaaa aaaaaa.aaaaaaa aaaaaaa: 27-aaa-2017aaaa aaaaaaa aa 100 aaaaa aa aaa-aaaa aaaaaa, aaaaa\" }");
var right = JToken.Parse("{ \"key\": \"aaaa aaaaaa aaaa aaaaaaa: aaaaaaaaa aaaa aaaaaaaa aaaa: 17-aaa-2017 aaaaa aaaaa aaaaaaa aaaa aaaaaaaa aaaa: 17-aaa-2017aaaaaa aaaaaa: aaaaaaaaa aaaaaa: aaaaaa aaaaa aaaaa aaaaaaa aaaaaa: aaaaaaaaaa aaaaaaaa aaaaaaa: aaaa(aaaa aaaaaa/aaaaaaaaaaaa)-aaaaaaa(aaaaaaaaaa/aaaaaaaaaa aaaa aaaaaa)aaaaa aaaaa aaaaaaa:aaaaaa aaaaaaa: aaaaaaaa aaaaaaaaaa aaaaaaa: aaaaaaaaaaaa aaaaaaaaaa: aaaaaaaa-aaaaaaaaaaaaaaaa aaaaaaaaaa aaaaaa: aaaaaaaaaaaaaaaa aaaaaaaaaa aaaaa aaaa: -2016aaaaaaaaa aaaaaaaaaa aaaaa: aaaa aaaaaaa aa 100 aaaaa aa aaa-aaaa aaaaaa aaa, aaaaaaaa aaaaaaaaaa aa aaaaaa.aaaaaaaaa aaaaaaaaaa: aaaaaaaa-aaaaaaaaaaaaaaaa aaaaaaaaaa aaaaaa: aaaaaaaaaaaaa aaaaaaaaaa aa aaaa: -2016aaaaaaaaa aaaaaaaaaa aaaaa: aaaaaaaa aaaaa-aaaaa aaaaaaaaaa, aaaaa aaaaaaa aa aaaaaaa aaaaaaaaaaaa aaaaa aaaaaaaaaaa (aaaaaa), aaaaa a 100 aaaaa aa aaa aaaaaaa.aaa aaaa: aaaaaaaaaaaaaaaa: aaaaaaaaaaaa aaaaaaaa: aaa aaaaa aaaaa:aaaaaaa aaaaaaa: 31-aaa-2014aaaaaa aaaaa: 16-aaa-2016aaaaaa aaaaa: 30-aaa-2017aaaaaa aaaaa: 27-aaa-2017aaaaaa aaaaa: 31-aaa-2017aaaaaa aaaaa: 16-aaa-2017aa aaaaaaaaaa aaaaaaaaaa, (aaaaa aa aaaa aa a 52.67 aaaaa aa aaaa aaa aaaa aaaaaa aaaaaa), aaaaa 100 aa aaaa aaaaaaa.aaaaaaa aaaaaaa: 16-aaa-2016aaaa\" }");
JToken patch = jdp.Diff(left, right);
var patched = jdp.Patch(left, patch);
Assert.IsTrue(JToken.DeepEquals(right.ToString(), patched.ToString()));
}
[Test]
@ -256,7 +272,7 @@ namespace JsonDiffPatchDotNet.UnitTests
var left = JObject.Parse(@"{ ""id"": ""pid"", ""p"": ""old"", ""nested"": { ""id"":""nid"", ""p"":""old"" } }");
var right = JObject.Parse(@"{ ""id"": ""pid2"", ""p"": ""new"", ""nested"": { ""id"":""nid2"", ""p"":""new"" } }");
var expected = JObject.Parse(@"{ ""id"": ""pid"", ""p"": ""new"", ""nested"": { ""id"":""nid"", ""p"":""new"" } }");
var patch = jdp.Diff(left, right);
var patch = jdp.Diff(left, right);
var patched = jdp.Patch(left, patch) as JObject;
Assert.AreEqual(expected.ToString(), patched.ToString());
@ -269,7 +285,7 @@ namespace JsonDiffPatchDotNet.UnitTests
var left = JObject.Parse(@"{ ""id"": ""pid"", ""p"": ""old"", ""nested"": { ""id"":""nid"", ""p"":""old"" } }");
var right = JObject.Parse(@"{ ""p"": ""new"", ""nested"": { ""p"":""new"" }, ""newP"": ""new"" }");
var expected = JObject.Parse(@"{ ""id"": ""pid"", ""p"": ""new"", ""nested"": { ""id"":""nid"", ""p"":""new"" }, ""newP"": ""new"" }");
var patch = jdp.Diff(left, right);
var patch = jdp.Diff(left, right);
var patched = jdp.Patch(left, patch) as JObject;
Assert.AreEqual(expected.ToString(), patched.ToString());
@ -282,7 +298,7 @@ namespace JsonDiffPatchDotNet.UnitTests
var left = JObject.Parse(@"{ ""id"": ""pid"", ""p"": ""old"", ""nested"": { ""id"":""nid"", ""p"":""old"" } }");
var right = JObject.Parse(@"{ ""id"": ""pid2"", ""p"": ""new"", ""nested"": { ""id"":""nid2"", ""p"":""new"" }, ""newP"": ""new"" }");
var expected = JObject.Parse(@"{ ""id"": ""pid2"", ""p"": ""new"", ""nested"": { ""id"":""nid2"", ""p"":""new"" } }");
var patch = jdp.Diff(left, right);
var patch = jdp.Diff(left, right);
var patched = jdp.Patch(left, patch) as JObject;
Assert.AreEqual(expected.ToString(), patched.ToString());
@ -298,10 +314,10 @@ namespace JsonDiffPatchDotNet.UnitTests
var left = JObject.Parse(@"{ ""id"": ""pid"", ""p"": ""old"", ""nested"": { ""id"":""nid"", ""p"":""old"" } }");
var right = JObject.Parse(@"{ ""id"": ""pid2"", ""nested"": { ""id"":""nid2"" }, ""newP"": ""new"" }");
var expected = JObject.Parse(@"{ ""id"": ""pid"", ""p"": ""old"", ""nested"": { ""id"":""nid"", ""p"":""old"" } }");
var patch = jdp.Diff(left, right);
var patch = jdp.Diff(left, right);
var patched = jdp.Patch(left, patch) as JObject;
Assert.AreEqual(expected.ToString(), patched.ToString());
}
}
}
}
}

View File

@ -29,7 +29,7 @@ namespace JsonDiffPatchDotNet
/// <summary>
/// Diff two JSON objects.
///
///
/// The output is a JObject that contains enough information to represent the
/// delta between the two objects and to be able perform patch and reverse operations.
/// </summary>
@ -38,11 +38,11 @@ namespace JsonDiffPatchDotNet
/// <returns>JSON Patch Document</returns>
public JToken Diff(JToken left, JToken right)
{
var objectHash = this._options.ObjectHash;
var itemMatch = new DefaultItemMatch(objectHash);
if (left == null)
left = new JValue("");
if (right == null)
@ -75,7 +75,7 @@ namespace JsonDiffPatchDotNet
if (!itemMatch.Match(left, right))
{
return new JArray(left, right);
}
}
return null;
}
@ -111,6 +111,7 @@ namespace JsonDiffPatchDotNet
if (patch.Type == JTokenType.Array)
{
var patchArray = (JArray)patch;
if (patchArray.Count == 1) // Add
@ -120,6 +121,15 @@ namespace JsonDiffPatchDotNet
if (patchArray.Count == 2) // Replace
{
if (_options.PatchBehavior == PatchBehavior.LeftMatchValidation)
{
if (left != patchArray[1])
{
throw new Exception("abc");
}
}
return patchArray[1];
}
@ -280,7 +290,7 @@ namespace JsonDiffPatchDotNet
/// <summary>
/// Diff two JSON objects.
///
///
/// The output is a JObject that contains enough information to represent the
/// delta between the two objects and to be able perform patch and reverse operations.
/// </summary>
@ -360,7 +370,7 @@ namespace JsonDiffPatchDotNet
}
}
// Find properties that were added
// Find properties that were added
foreach (var rp in right.Properties())
{
if (left.Property(rp.Name) != null || (_options.DiffBehaviors & DiffBehavior.IgnoreNewProperties) == DiffBehavior.IgnoreNewProperties)

View File

@ -3,31 +3,31 @@ using System;
using System.Collections;
using System.Collections.Generic;
namespace JsonDiffPatchDotNet
{
public sealed class Options
{
public Options()
{
ArrayDiff = ArrayDiffMode.Efficient;
TextDiff = TextDiffMode.Efficient;
MinEfficientTextDiffLength = 50;
}
/// <summary>
/// Specifies how arrays are diffed. The default is Efficient.
/// </summary>
public ArrayDiffMode ArrayDiff { get; set; }
/// <summary>
/// Specifies how string values are diffed. The default is Efficient.
/// </summary>
public TextDiffMode TextDiff { get; set; }
/// <summary>
/// The minimum string length required to use Efficient text diff. If the minimum
/// length is not met, simple text diff will be used. The default length is 50 characters.
/// </summary>
namespace JsonDiffPatchDotNet
{
public sealed class Options
{
public Options()
{
ArrayDiff = ArrayDiffMode.Efficient;
TextDiff = TextDiffMode.Efficient;
MinEfficientTextDiffLength = 50;
}
/// <summary>
/// Specifies how arrays are diffed. The default is Efficient.
/// </summary>
public ArrayDiffMode ArrayDiff { get; set; }
/// <summary>
/// Specifies how string values are diffed. The default is Efficient.
/// </summary>
public TextDiffMode TextDiff { get; set; }
/// <summary>
/// The minimum string length required to use Efficient text diff. If the minimum
/// length is not met, simple text diff will be used. The default length is 50 characters.
/// </summary>
public long MinEfficientTextDiffLength { get; set; }
/// <summary>
@ -39,17 +39,22 @@ namespace JsonDiffPatchDotNet
/// Specifies behaviors to apply to the diff patch set
/// </summary>
public DiffBehavior DiffBehaviors { get; set; }
/// <summary>
/// for LCS to work, it needs a way to match items between previous/original (or left/right) arrays. In traditional text diff tools this is trivial, as two lines of text are compared char
/// char.
/// When no matches by reference or value are found, array diffing fallbacks to a dumb behavior: matching items by position.
/// Matching by position is not the most efficient option (eg. if an item is added at the first position, all the items below will be considered modified), but it produces expected results
/// in most trivial cases.This is good enough as soon as movements/insertions/deletions only happen near the bottom of the array.
/// This is because if 2 objects are not equal by reference(ie.the same object) both objects are considered different values, as there is no trivial solution to compare two arbitrary objects
/// in JavaScript.
/// To improve the results leveraging the power of LCS(and position move detection) you need to provide a way to compare 2 objects.
/// </summary>
public Func<JToken, object> ObjectHash { get; set; }
}
}
/// <summary>
/// for LCS to work, it needs a way to match items between previous/original (or left/right) arrays. In traditional text diff tools this is trivial, as two lines of text are compared char
/// char.
/// When no matches by reference or value are found, array diffing fallbacks to a dumb behavior: matching items by position.
/// Matching by position is not the most efficient option (eg. if an item is added at the first position, all the items below will be considered modified), but it produces expected results
/// in most trivial cases.This is good enough as soon as movements/insertions/deletions only happen near the bottom of the array.
/// This is because if 2 objects are not equal by reference(ie.the same object) both objects are considered different values, as there is no trivial solution to compare two arbitrary objects
/// in JavaScript.
/// To improve the results leveraging the power of LCS(and position move detection) you need to provide a way to compare 2 objects.
/// </summary>
public Func<JToken, object> ObjectHash { get; set; }
/// <summary>
/// Specifies behaviors to apply to the patch
/// </summary>
public PatchBehavior PatchBehavior { get; set; }
}
}

View File

@ -0,0 +1,12 @@
namespace JsonDiffPatchDotNet
{
public enum PatchBehavior
{
None,
/// <summary>
/// If left json value is not equals with patch[0] value then throw exception on patch action
/// </summary>
LeftMatchValidation
}
}