Merge branch 'master' into master
commit
cf4373e441
|
@ -1,301 +1,332 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace JsonDiffPatchDotNet.UnitTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class DiffUnitTests
|
||||
{
|
||||
[Test]
|
||||
public void Diff_EmptyObjects_EmptyPatch()
|
||||
{
|
||||
var jdp = new JsonDiffPatch();
|
||||
var empty = JObject.Parse(@"{}");
|
||||
|
||||
JToken result = jdp.Diff(empty, empty);
|
||||
|
||||
Assert.IsNull(result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_EqualBooleanProperty_NoDiff()
|
||||
{
|
||||
var jdp = new JsonDiffPatch();
|
||||
var left = JObject.Parse(@"{""p"": true }");
|
||||
var right = JObject.Parse(@"{""p"": true }");
|
||||
|
||||
JToken result = jdp.Diff(left, right);
|
||||
|
||||
Assert.IsNull(result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_DiffBooleanProperty_ValidPatch()
|
||||
{
|
||||
var jdp = new JsonDiffPatch();
|
||||
var left = JObject.Parse(@"{""p"": true }");
|
||||
var right = JObject.Parse(@"{""p"": false }");
|
||||
|
||||
JToken result = jdp.Diff(left, right);
|
||||
|
||||
Assert.AreEqual(JTokenType.Object, result.Type);
|
||||
JObject obj = (JObject)result;
|
||||
Assert.IsNotNull(obj.Property("p"), "Property Name");
|
||||
Assert.AreEqual(JTokenType.Array, obj.Property("p").Value.Type, "Array Value");
|
||||
Assert.AreEqual(2, ((JArray)obj.Property("p").Value).Count, "Array Length");
|
||||
Assert.IsTrue(((JArray)obj.Property("p").Value)[0].ToObject<bool>(), "Array Old Value");
|
||||
Assert.IsFalse(((JArray)obj.Property("p").Value)[1].ToObject<bool>(), "Array New Value");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_BooleanPropertyDeleted_ValidPatch()
|
||||
{
|
||||
var jdp = new JsonDiffPatch();
|
||||
var left = JObject.Parse(@"{ ""p"": true }");
|
||||
var right = JObject.Parse(@"{ }");
|
||||
|
||||
JToken result = jdp.Diff(left, right);
|
||||
|
||||
Assert.AreEqual(JTokenType.Object, result.Type);
|
||||
JObject obj = (JObject)result;
|
||||
Assert.IsNotNull(obj.Property("p"), "Property Name");
|
||||
Assert.AreEqual(JTokenType.Array, obj.Property("p").Value.Type, "Array Value");
|
||||
Assert.AreEqual(3, ((JArray)obj.Property("p").Value).Count, "Array Length");
|
||||
Assert.IsTrue(((JArray)obj.Property("p").Value)[0].ToObject<bool>(), "Array Old Value");
|
||||
Assert.AreEqual(0, ((JArray)obj.Property("p").Value)[1].ToObject<int>(), "Array New Value");
|
||||
Assert.AreEqual(0, ((JArray)obj.Property("p").Value)[2].ToObject<int>(), "Array Deleted Indicator");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_BooleanPropertyAdded_ValidPatch()
|
||||
{
|
||||
var jdp = new JsonDiffPatch();
|
||||
var left = JObject.Parse(@"{ }");
|
||||
var right = JObject.Parse(@"{ ""p"": true }");
|
||||
|
||||
JToken result = jdp.Diff(left, right);
|
||||
|
||||
Assert.AreEqual(JTokenType.Object, result.Type);
|
||||
JObject obj = (JObject)result;
|
||||
Assert.IsNotNull(obj.Property("p"), "Property Name");
|
||||
Assert.AreEqual(JTokenType.Array, obj.Property("p").Value.Type, "Array Value");
|
||||
Assert.AreEqual(1, ((JArray)obj.Property("p").Value).Count, "Array Length");
|
||||
Assert.IsTrue(((JArray)obj.Property("p").Value)[0].ToObject<bool>(), "Array Added Value");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_EfficientStringDiff_ValidPatch()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options { TextDiff = TextDiffMode.Efficient });
|
||||
var left = JObject.Parse(@"{ ""p"": ""lp.Value.ToString().Length > _options.MinEfficientTextDiffLength"" }");
|
||||
var right = JObject.Parse(@"{ ""p"": ""blah1"" }");
|
||||
|
||||
JToken result = jdp.Diff(left, right);
|
||||
|
||||
Assert.AreEqual(JTokenType.Object, result.Type);
|
||||
JObject obj = (JObject)result;
|
||||
Assert.IsNotNull(obj.Property("p"), "Property Name");
|
||||
Assert.AreEqual(JTokenType.Array, obj.Property("p").Value.Type, "Array Value");
|
||||
Assert.AreEqual(3, ((JArray)obj.Property("p").Value).Count, "Array Length");
|
||||
Assert.AreEqual("@@ -1,64 +1,5 @@\n-lp.Value.ToString().Length %3e _options.MinEfficientTextDiffLength\n+blah1\n", ((JArray)obj.Property("p").Value)[0].ToString(), "Array Added Value");
|
||||
Assert.AreEqual(0, ((JArray)obj.Property("p").Value)[1].ToObject<int>(), "Array Added Value");
|
||||
Assert.AreEqual(2, ((JArray)obj.Property("p").Value)[2].ToObject<int>(), "Array String Diff Indicator");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_EfficientStringDiff_NoChanges()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options { TextDiff = TextDiffMode.Efficient });
|
||||
var left = JObject.Parse(@"{ ""p"": ""lp.Value.ToString().Length > _options.MinEfficientTextDiffLength"" }");
|
||||
var right = JObject.Parse(@"{ ""p"": ""lp.Value.ToString().Length > _options.MinEfficientTextDiffLength"" }");
|
||||
|
||||
JToken result = jdp.Diff(left, right);
|
||||
|
||||
Assert.IsNull(result, "No Changes");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_LeftNull_Exception()
|
||||
{
|
||||
var jdp = new JsonDiffPatch();
|
||||
var obj = JObject.Parse(@"{ }");
|
||||
|
||||
JToken result = jdp.Diff(null, obj);
|
||||
|
||||
Assert.AreEqual(JTokenType.Array, result.Type);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_RightNull_Exception()
|
||||
{
|
||||
var jdp = new JsonDiffPatch();
|
||||
var obj = JObject.Parse(@"{ }");
|
||||
|
||||
JToken result = jdp.Diff(obj, null);
|
||||
|
||||
Assert.AreEqual(JTokenType.Array, result.Type);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_EfficientArrayDiffSame_NullDiff()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
|
||||
var array = JToken.Parse(@"[1,2,3]");
|
||||
|
||||
JToken diff = jdp.Diff(array, array);
|
||||
|
||||
Assert.IsNull(diff);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_EfficientArrayDiffDifferentHeadRemoved_ValidDiff()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
|
||||
var left = JToken.Parse(@"[1,2,3,4]");
|
||||
var right = JToken.Parse(@"[2,3,4]");
|
||||
|
||||
JObject diff = jdp.Diff(left, right) as JObject;
|
||||
|
||||
Assert.IsNotNull(diff);
|
||||
Assert.AreEqual(2, diff.Properties().Count());
|
||||
Assert.IsNotNull(diff["_0"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_EfficientArrayDiffDifferentTailRemoved_ValidDiff()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
|
||||
var left = JToken.Parse(@"[1,2,3,4]");
|
||||
var right = JToken.Parse(@"[1,2,3]");
|
||||
|
||||
JObject diff = jdp.Diff(left, right) as JObject;
|
||||
|
||||
Assert.IsNotNull(diff);
|
||||
Assert.AreEqual(2, diff.Properties().Count());
|
||||
Assert.IsNotNull(diff["_3"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_EfficientArrayDiffDifferentHeadAdded_ValidDiff()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
|
||||
var left = JToken.Parse(@"[1,2,3,4]");
|
||||
var right = JToken.Parse(@"[0,1,2,3,4]");
|
||||
|
||||
JObject diff = jdp.Diff(left, right) as JObject;
|
||||
|
||||
Assert.IsNotNull(diff);
|
||||
Assert.AreEqual(2, diff.Properties().Count());
|
||||
Assert.IsNotNull(diff["0"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_EfficientArrayDiffDifferentTailAdded_ValidDiff()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
|
||||
var left = JToken.Parse(@"[1,2,3,4]");
|
||||
var right = JToken.Parse(@"[1,2,3,4,5]");
|
||||
|
||||
JObject diff = jdp.Diff(left, right) as JObject;
|
||||
|
||||
Assert.IsNotNull(diff);
|
||||
Assert.AreEqual(2, diff.Properties().Count());
|
||||
Assert.IsNotNull(diff["4"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_EfficientArrayDiffDifferentHeadTailAdded_ValidDiff()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
|
||||
var left = JToken.Parse(@"[1,2,3,4]");
|
||||
var right = JToken.Parse(@"[0,1,2,3,4,5]");
|
||||
|
||||
JObject diff = jdp.Diff(left, right) as JObject;
|
||||
|
||||
Assert.IsNotNull(diff);
|
||||
Assert.AreEqual(3, diff.Properties().Count());
|
||||
Assert.IsNotNull(diff["0"]);
|
||||
Assert.IsNotNull(diff["5"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_EfficientArrayDiffSameLengthNested_ValidDiff()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
|
||||
var left = JToken.Parse(@"[1,2,{""p"":false},4]");
|
||||
var right = JToken.Parse(@"[1,2,{""p"":true},4]");
|
||||
|
||||
JObject diff = jdp.Diff(left, right) as JObject;
|
||||
|
||||
Assert.IsNotNull(diff);
|
||||
Assert.AreEqual(2, diff.Properties().Count());
|
||||
Assert.IsNotNull(diff["2"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_EfficientArrayDiffSameWithObject_NoDiff()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
|
||||
var left = JToken.Parse(@"
|
||||
{
|
||||
""@context"": [
|
||||
""http://www.w3.org/ns/csvw"",
|
||||
{
|
||||
""@language"": ""en"",
|
||||
""@base"": ""http://example.org""
|
||||
}
|
||||
]
|
||||
}");
|
||||
var right = left.DeepClone();
|
||||
|
||||
JToken diff = jdp.Diff(left, right);
|
||||
|
||||
Assert.IsNull(diff);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_EfficientArrayDiffHugeArrays_NoStackOverflow()
|
||||
{
|
||||
const int arraySize = 1000;
|
||||
Func<int, int, JToken> hugeArrayFunc = (startIndex, count) =>
|
||||
{
|
||||
var builder = new StringBuilder("[");
|
||||
foreach (var i in Enumerable.Range(startIndex, count))
|
||||
{
|
||||
builder.Append($"{i},");
|
||||
}
|
||||
builder.Append("]");
|
||||
|
||||
return JToken.Parse(builder.ToString());
|
||||
};
|
||||
|
||||
var jdp = new JsonDiffPatch();
|
||||
var left = hugeArrayFunc(0, arraySize);
|
||||
var right = hugeArrayFunc(arraySize / 2, arraySize);
|
||||
|
||||
JToken diff = jdp.Diff(left, right);
|
||||
var restored = jdp.Patch(left, diff);
|
||||
|
||||
Assert.That(JToken.DeepEquals(restored, right));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_IntStringDiff_ValidPatch()
|
||||
{
|
||||
var jdp = new JsonDiffPatch();
|
||||
var left = JToken.Parse(@"1");
|
||||
var right = JToken.Parse(@"""hello""");
|
||||
|
||||
JToken result = jdp.Diff(left, right);
|
||||
|
||||
Assert.AreEqual(JTokenType.Array, result.Type);
|
||||
JArray array = (JArray)result;
|
||||
Assert.AreEqual(2, array.Count);
|
||||
Assert.AreEqual(left, array[0]);
|
||||
Assert.AreEqual(right, array[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace JsonDiffPatchDotNet.UnitTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class DiffUnitTests
|
||||
{
|
||||
[Test]
|
||||
public void Diff_EmptyObjects_EmptyPatch()
|
||||
{
|
||||
var jdp = new JsonDiffPatch();
|
||||
var empty = JObject.Parse(@"{}");
|
||||
|
||||
JToken result = jdp.Diff(empty, empty);
|
||||
|
||||
Assert.IsNull(result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_EqualBooleanProperty_NoDiff()
|
||||
{
|
||||
var jdp = new JsonDiffPatch();
|
||||
var left = JObject.Parse(@"{""p"": true }");
|
||||
var right = JObject.Parse(@"{""p"": true }");
|
||||
|
||||
JToken result = jdp.Diff(left, right);
|
||||
|
||||
Assert.IsNull(result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_DiffBooleanProperty_ValidPatch()
|
||||
{
|
||||
var jdp = new JsonDiffPatch();
|
||||
var left = JObject.Parse(@"{""p"": true }");
|
||||
var right = JObject.Parse(@"{""p"": false }");
|
||||
|
||||
JToken result = jdp.Diff(left, right);
|
||||
|
||||
Assert.AreEqual(JTokenType.Object, result.Type);
|
||||
JObject obj = (JObject)result;
|
||||
Assert.IsNotNull(obj.Property("p"), "Property Name");
|
||||
Assert.AreEqual(JTokenType.Array, obj.Property("p").Value.Type, "Array Value");
|
||||
Assert.AreEqual(2, ((JArray)obj.Property("p").Value).Count, "Array Length");
|
||||
Assert.IsTrue(((JArray)obj.Property("p").Value)[0].ToObject<bool>(), "Array Old Value");
|
||||
Assert.IsFalse(((JArray)obj.Property("p").Value)[1].ToObject<bool>(), "Array New Value");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_BooleanPropertyDeleted_ValidPatch()
|
||||
{
|
||||
var jdp = new JsonDiffPatch();
|
||||
var left = JObject.Parse(@"{ ""p"": true }");
|
||||
var right = JObject.Parse(@"{ }");
|
||||
|
||||
JToken result = jdp.Diff(left, right);
|
||||
|
||||
Assert.AreEqual(JTokenType.Object, result.Type);
|
||||
JObject obj = (JObject)result;
|
||||
Assert.IsNotNull(obj.Property("p"), "Property Name");
|
||||
Assert.AreEqual(JTokenType.Array, obj.Property("p").Value.Type, "Array Value");
|
||||
Assert.AreEqual(3, ((JArray)obj.Property("p").Value).Count, "Array Length");
|
||||
Assert.IsTrue(((JArray)obj.Property("p").Value)[0].ToObject<bool>(), "Array Old Value");
|
||||
Assert.AreEqual(0, ((JArray)obj.Property("p").Value)[1].ToObject<int>(), "Array New Value");
|
||||
Assert.AreEqual(0, ((JArray)obj.Property("p").Value)[2].ToObject<int>(), "Array Deleted Indicator");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_BooleanPropertyAdded_ValidPatch()
|
||||
{
|
||||
var jdp = new JsonDiffPatch();
|
||||
var left = JObject.Parse(@"{ }");
|
||||
var right = JObject.Parse(@"{ ""p"": true }");
|
||||
|
||||
JToken result = jdp.Diff(left, right);
|
||||
|
||||
Assert.AreEqual(JTokenType.Object, result.Type);
|
||||
JObject obj = (JObject)result;
|
||||
Assert.IsNotNull(obj.Property("p"), "Property Name");
|
||||
Assert.AreEqual(JTokenType.Array, obj.Property("p").Value.Type, "Array Value");
|
||||
Assert.AreEqual(1, ((JArray)obj.Property("p").Value).Count, "Array Length");
|
||||
Assert.IsTrue(((JArray)obj.Property("p").Value)[0].ToObject<bool>(), "Array Added Value");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_EfficientStringDiff_ValidPatch()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options { TextDiff = TextDiffMode.Efficient });
|
||||
var left = JObject.Parse(@"{ ""p"": ""lp.Value.ToString().Length > _options.MinEfficientTextDiffLength"" }");
|
||||
var right = JObject.Parse(@"{ ""p"": ""blah1"" }");
|
||||
|
||||
JToken result = jdp.Diff(left, right);
|
||||
|
||||
Assert.AreEqual(JTokenType.Object, result.Type);
|
||||
JObject obj = (JObject)result;
|
||||
Assert.IsNotNull(obj.Property("p"), "Property Name");
|
||||
Assert.AreEqual(JTokenType.Array, obj.Property("p").Value.Type, "Array Value");
|
||||
Assert.AreEqual(3, ((JArray)obj.Property("p").Value).Count, "Array Length");
|
||||
Assert.AreEqual("@@ -1,64 +1,5 @@\n-lp.Value.ToString().Length %3e _options.MinEfficientTextDiffLength\n+blah1\n", ((JArray)obj.Property("p").Value)[0].ToString(), "Array Added Value");
|
||||
Assert.AreEqual(0, ((JArray)obj.Property("p").Value)[1].ToObject<int>(), "Array Added Value");
|
||||
Assert.AreEqual(2, ((JArray)obj.Property("p").Value)[2].ToObject<int>(), "Array String Diff Indicator");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_EfficientStringDiff_NoChanges()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options { TextDiff = TextDiffMode.Efficient });
|
||||
var left = JObject.Parse(@"{ ""p"": ""lp.Value.ToString().Length > _options.MinEfficientTextDiffLength"" }");
|
||||
var right = JObject.Parse(@"{ ""p"": ""lp.Value.ToString().Length > _options.MinEfficientTextDiffLength"" }");
|
||||
|
||||
JToken result = jdp.Diff(left, right);
|
||||
|
||||
Assert.IsNull(result, "No Changes");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_LeftNull_Exception()
|
||||
{
|
||||
var jdp = new JsonDiffPatch();
|
||||
var obj = JObject.Parse(@"{ }");
|
||||
|
||||
JToken result = jdp.Diff(null, obj);
|
||||
|
||||
Assert.AreEqual(JTokenType.Array, result.Type);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_RightNull_Exception()
|
||||
{
|
||||
var jdp = new JsonDiffPatch();
|
||||
var obj = JObject.Parse(@"{ }");
|
||||
|
||||
JToken result = jdp.Diff(obj, null);
|
||||
|
||||
Assert.AreEqual(JTokenType.Array, result.Type);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_EfficientArrayDiffSame_NullDiff()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
|
||||
var array = JToken.Parse(@"[1,2,3]");
|
||||
|
||||
JToken diff = jdp.Diff(array, array);
|
||||
|
||||
Assert.IsNull(diff);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_EfficientArrayDiffDifferentHeadRemoved_ValidDiff()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
|
||||
var left = JToken.Parse(@"[1,2,3,4]");
|
||||
var right = JToken.Parse(@"[2,3,4]");
|
||||
|
||||
JObject diff = jdp.Diff(left, right) as JObject;
|
||||
|
||||
Assert.IsNotNull(diff);
|
||||
Assert.AreEqual(2, diff.Properties().Count());
|
||||
Assert.IsNotNull(diff["_0"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_EfficientArrayDiffDifferentTailRemoved_ValidDiff()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
|
||||
var left = JToken.Parse(@"[1,2,3,4]");
|
||||
var right = JToken.Parse(@"[1,2,3]");
|
||||
|
||||
JObject diff = jdp.Diff(left, right) as JObject;
|
||||
|
||||
Assert.IsNotNull(diff);
|
||||
Assert.AreEqual(2, diff.Properties().Count());
|
||||
Assert.IsNotNull(diff["_3"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_EfficientArrayDiffDifferentHeadAdded_ValidDiff()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
|
||||
var left = JToken.Parse(@"[1,2,3,4]");
|
||||
var right = JToken.Parse(@"[0,1,2,3,4]");
|
||||
|
||||
JObject diff = jdp.Diff(left, right) as JObject;
|
||||
|
||||
Assert.IsNotNull(diff);
|
||||
Assert.AreEqual(2, diff.Properties().Count());
|
||||
Assert.IsNotNull(diff["0"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_EfficientArrayDiffDifferentTailAdded_ValidDiff()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
|
||||
var left = JToken.Parse(@"[1,2,3,4]");
|
||||
var right = JToken.Parse(@"[1,2,3,4,5]");
|
||||
|
||||
JObject diff = jdp.Diff(left, right) as JObject;
|
||||
|
||||
Assert.IsNotNull(diff);
|
||||
Assert.AreEqual(2, diff.Properties().Count());
|
||||
Assert.IsNotNull(diff["4"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_EfficientArrayDiffDifferentHeadTailAdded_ValidDiff()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
|
||||
var left = JToken.Parse(@"[1,2,3,4]");
|
||||
var right = JToken.Parse(@"[0,1,2,3,4,5]");
|
||||
|
||||
JObject diff = jdp.Diff(left, right) as JObject;
|
||||
|
||||
Assert.IsNotNull(diff);
|
||||
Assert.AreEqual(3, diff.Properties().Count());
|
||||
Assert.IsNotNull(diff["0"]);
|
||||
Assert.IsNotNull(diff["5"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_EfficientArrayDiffSameLengthNested_ValidDiff()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient, ObjectHash = (jObj) => jObj["Id"].Value<string>() });
|
||||
var left = JToken.Parse(@"[1,2,{""Id"" : ""F12B21EF-F57D-4958-ADDC-A3F52EC25EC8"", ""p"":false},4]");
|
||||
var right = JToken.Parse(@"[1,2,{""Id"" : ""F12B21EF-F57D-4958-ADDC-A3F52EC25EC8"", ""p"":true},4]");
|
||||
|
||||
JObject diff = jdp.Diff(left, right) as JObject;
|
||||
|
||||
Assert.IsNotNull(diff);
|
||||
Assert.AreEqual(2, diff.Properties().Count());
|
||||
Assert.IsNotNull(diff["2"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_EfficientArrayDiffWithComplexObject_ValidDiff()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient, ObjectHash = (jObj) => jObj["Id"].Value<string>() });
|
||||
//var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
|
||||
var left = JToken.Parse(@"[{""Id"" : ""F12B21EF-F57D-4958-ADDC-A3F52EC25EC8"", ""p"":false}, {""Id"" : ""F12B21EF-F57D-4958-ADDC-A3F52EC25EC9"", ""p"":true}]");
|
||||
var right = JToken.Parse(@"[{""Id"" : ""F12B21EF-F57D-4958-ADDC-A3F52EC25EC8"", ""p"":true}, {""Id"" : ""F12B21EF-F57D-4958-ADDC-A3F52EC25EC10"", ""p"":false}]");
|
||||
|
||||
JObject diff = jdp.Diff(left, right) as JObject;
|
||||
|
||||
Assert.IsNotNull(diff);
|
||||
Assert.AreEqual(4, diff.Properties().Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_EfficientArrayDiffWithComplexObjectHash_ValidDiff()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient, ObjectHash = (jObj) => jObj["Id"].Value<string>() });
|
||||
var left = JToken.Parse(@"[{""Id"": ""22ff56c7-2307-414b-8a3a-9bf1cdba2095"",""city"":""São Paulo""},{""Id"":""3fca9cdb-dd9b-4b7c-afc1-587751e25bd6"",""city"":""abc""},{""Id"":""1fe6a0f9-3974-427f-81cb-6004748cb179"",""city"":""xyz""}]");
|
||||
var right = JToken.Parse(@"[{""Id"":""3fca9cdb-dd9b-4b7c-afc1-587751e25bd6"",""city"":""abc""},{""Id"":""1fe6a0f9-3974-427f-81cb-6004748cb179"",""city"":""xyz""}, {""Id"":""3fca9cdb-dd9b-4b7c-afc1-587751e25b44"",""city"":""new""}]");
|
||||
|
||||
JObject diff = jdp.Diff(left, right) as JObject;
|
||||
|
||||
Assert.IsNotNull(diff);
|
||||
Assert.AreEqual(3, diff.Properties().Count());
|
||||
Assert.IsNotNull(diff["_0"]);
|
||||
Assert.IsNotNull(diff["2"]);
|
||||
Assert.AreEqual(((JArray)diff["2"])[0].Value<string>("city"), "new");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_EfficientArrayDiffSameWithObject_NoDiff()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options { ArrayDiff = ArrayDiffMode.Efficient });
|
||||
var left = JToken.Parse(@"
|
||||
{
|
||||
""@context"": [
|
||||
""http://www.w3.org/ns/csvw"",
|
||||
{
|
||||
""@language"": ""en"",
|
||||
""@base"": ""http://example.org""
|
||||
}
|
||||
]
|
||||
}");
|
||||
var right = left.DeepClone();
|
||||
|
||||
JToken diff = jdp.Diff(left, right);
|
||||
|
||||
Assert.IsNull(diff);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_EfficientArrayDiffHugeArrays_NoStackOverflow()
|
||||
{
|
||||
const int arraySize = 1000;
|
||||
Func<int, int, JToken> hugeArrayFunc = (startIndex, count) =>
|
||||
{
|
||||
var builder = new StringBuilder("[");
|
||||
foreach (var i in Enumerable.Range(startIndex, count))
|
||||
{
|
||||
builder.Append($"{i},");
|
||||
}
|
||||
builder.Append("]");
|
||||
|
||||
return JToken.Parse(builder.ToString());
|
||||
};
|
||||
|
||||
var jdp = new JsonDiffPatch();
|
||||
var left = hugeArrayFunc(0, arraySize);
|
||||
var right = hugeArrayFunc(arraySize / 2, arraySize);
|
||||
|
||||
JToken diff = jdp.Diff(left, right);
|
||||
var restored = jdp.Patch(left, diff);
|
||||
|
||||
Assert.That(JToken.DeepEquals(restored, right));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_IntStringDiff_ValidPatch()
|
||||
{
|
||||
var jdp = new JsonDiffPatch();
|
||||
var left = JToken.Parse(@"1");
|
||||
var right = JToken.Parse(@"""hello""");
|
||||
|
||||
JToken result = jdp.Diff(left, right);
|
||||
|
||||
Assert.AreEqual(JTokenType.Array, result.Type);
|
||||
JArray array = (JArray)result;
|
||||
Assert.AreEqual(2, array.Count);
|
||||
Assert.AreEqual(left, array[0]);
|
||||
Assert.AreEqual(right, array[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ using System.Linq;
|
|||
using JsonDiffPatchDotNet.Formatters.JsonPatch;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NUnit.Framework;
|
||||
using System.Linq;
|
||||
|
||||
namespace JsonDiffPatchDotNet.UnitTests
|
||||
{
|
||||
|
@ -165,6 +166,18 @@ namespace JsonDiffPatchDotNet.UnitTests
|
|||
var paths = operations.Select(o => o.Path).ToList();
|
||||
// removal of the array item at index 1 should come before the item at index 0
|
||||
Assert.Less(paths.IndexOf("/i/a/a/1"), paths.IndexOf("/i/a/a/0"));
|
||||
|
||||
public void Format_EscapeOfJsonPointer_Success()
|
||||
{
|
||||
var left = JObject.Parse(@"{ ""a/b"": ""a"", ""a~b"": ""ab"", ""a/~b"": ""abb"",""a/b/c~"": ""abc"" }");
|
||||
var right = JObject.Parse(@"{ ""a/b"": ""ab"", ""a~b"": ""ba"", ""a/~b"": ""bba"",""a/b/c~"": ""cba"" }");
|
||||
var patch = Differ.Diff(left, right);
|
||||
var operations = Formatter.Format(patch);
|
||||
|
||||
Assert.IsTrue(operations.Any(x => x.Path.Equals("/a~1b") && x.Value.ToString().Equals("ab")));
|
||||
Assert.IsTrue(operations.Any(x => x.Path.Equals("/a~0b") && x.Value.ToString().Equals("ba")));
|
||||
Assert.IsTrue(operations.Any(x => x.Path.Equals("/a~1~0b") && x.Value.ToString().Equals("bba")));
|
||||
Assert.IsTrue(operations.Any(x => x.Path.Equals("/a~1b~1c~0") && x.Value.ToString().Equals("cba")));
|
||||
}
|
||||
|
||||
private void AssertOperation(Operation operation, string expectedOp, string expectedPath, JValue expectedValue = null)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
@ -246,6 +247,61 @@ namespace JsonDiffPatchDotNet.UnitTests
|
|||
var patched = jdp.Patch(left, patch);
|
||||
|
||||
Assert.IsTrue(JToken.DeepEquals(right.ToString(), patched.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_ExcludePaths_ValidPatch()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options { ExcludePaths = new List<string>() { "id", "nested.id" } });
|
||||
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 patched = jdp.Patch(left, patch) as JObject;
|
||||
|
||||
Assert.AreEqual(expected.ToString(), patched.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_Behaviors_IgnoreMissingProperties_ValidPatch()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options { DiffBehaviors = DiffBehavior.IgnoreMissingProperties });
|
||||
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 patched = jdp.Patch(left, patch) as JObject;
|
||||
|
||||
Assert.AreEqual(expected.ToString(), patched.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_Behaviors_IgnoreNewProperties_ValidPatch()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options { DiffBehaviors = DiffBehavior.IgnoreNewProperties });
|
||||
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 patched = jdp.Patch(left, patch) as JObject;
|
||||
|
||||
Assert.AreEqual(expected.ToString(), patched.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_ExludeAndBehaviors_ExcludeIgnoreMissingIgnoreNew_ValidPatch()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options {
|
||||
ExcludePaths = new List<string>() { "id", "nested.id" },
|
||||
DiffBehaviors = DiffBehavior.IgnoreMissingProperties | DiffBehavior.IgnoreNewProperties
|
||||
});
|
||||
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 patched = jdp.Patch(left, patch) as JObject;
|
||||
|
||||
Assert.AreEqual(expected.ToString(), patched.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,6 @@
|
|||
/// the entire left and entire right arrays are added to the patch document as a simple
|
||||
/// JSON token replace. If they are the same, then token is skipped in the patch document.
|
||||
/// </summary>
|
||||
Simple,
|
||||
Simple
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace JsonDiffPatchDotNet
|
||||
{
|
||||
public class DefaultItemMatch : ItemMatch
|
||||
{
|
||||
public DefaultItemMatch(Func<JToken, object> objectHash):base(objectHash)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace JsonDiffPatchDotNet
|
||||
{
|
||||
[Flags]
|
||||
public enum DiffBehavior
|
||||
{
|
||||
/// <summary>
|
||||
/// Default behavior
|
||||
/// </summary>
|
||||
None,
|
||||
/// <summary>
|
||||
/// If the patch document is missing properties that are in the source document, leave the existing properties in place instead of deleting them
|
||||
/// </summary>
|
||||
IgnoreMissingProperties,
|
||||
/// <summary>
|
||||
/// If the patch document contains properties that aren't defined in the source document, ignore them instead of adding them
|
||||
/// </summary>
|
||||
IgnoreNewProperties
|
||||
}
|
||||
}
|
|
@ -51,7 +51,7 @@ namespace JsonDiffPatchDotNet.Formatters.JsonPatch
|
|||
|
||||
protected override void NodeBegin(JsonFormatContext context, string key, string leftKey, DeltaType type, NodeType nodeType, bool isLast)
|
||||
{
|
||||
context.Path.Add(leftKey);
|
||||
context.Path.Add(Escape(leftKey));
|
||||
}
|
||||
|
||||
protected override void NodeEnd(JsonFormatContext context, string key, string leftKey, DeltaType type, NodeType nodeType, bool isLast)
|
||||
|
@ -64,6 +64,13 @@ namespace JsonDiffPatchDotNet.Formatters.JsonPatch
|
|||
|
||||
protected override void RootEnd(JsonFormatContext context, DeltaType type, NodeType nodeType) { }
|
||||
|
||||
private string Escape(string key)
|
||||
{
|
||||
if (string.IsNullOrEmpty(key)) return key;
|
||||
return key.Replace("~", "~0")
|
||||
.Replace("/", "~1");
|
||||
}
|
||||
|
||||
private void FormatNode(JsonFormatContext context, JToken delta, JToken left)
|
||||
{
|
||||
FormatDeltaChildren(context, delta, left);
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace JsonDiffPatchDotNet
|
||||
{
|
||||
public abstract class ItemMatch
|
||||
{
|
||||
internal Func<JToken, object> ObjectHash;
|
||||
|
||||
protected ItemMatch()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected ItemMatch(Func<JToken, object> objectHash)
|
||||
{
|
||||
ObjectHash = objectHash;
|
||||
}
|
||||
|
||||
public virtual bool Match(JToken object1, JToken object2)
|
||||
{
|
||||
return Match(object1, object2, ObjectHash);
|
||||
}
|
||||
|
||||
public virtual bool Match(JToken object1, JToken object2, Func<JToken, object> objectHash)
|
||||
{
|
||||
if(objectHash == null || object1.Type != JTokenType.Object)
|
||||
{
|
||||
return JToken.DeepEquals(object1, object2);
|
||||
}
|
||||
|
||||
var hash1 = objectHash.Invoke(object1);
|
||||
if(hash1 == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var hash2 = objectHash.Invoke(object2);
|
||||
if(hash2 == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return hash1.Equals(hash2);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -5,8 +5,8 @@
|
|||
<LangVersion>latest</LangVersion>
|
||||
<RootNamespace>JsonDiffPatchDotNet</RootNamespace>
|
||||
<AssemblyName>JsonDiffPatchDotNet</AssemblyName>
|
||||
<AssemblyVersion>2.2.0.0</AssemblyVersion>
|
||||
<FileVersion>2.2.0.0</FileVersion>
|
||||
<AssemblyVersion>2.3.0.0</AssemblyVersion>
|
||||
<FileVersion>2.3.0.0</FileVersion>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<RepositoryUrl>https://github.com/wbish/jsondiffpatch.net</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
|
@ -22,9 +22,9 @@
|
|||
<AssemblyOriginatorKeyFile>JsonDiffPatchDotNet.snk</AssemblyOriginatorKeyFile>
|
||||
<MinClientVersion>2.12</MinClientVersion>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<Version>2.2.0.0</Version>
|
||||
<Version>2.3.0.0</Version>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -1,84 +1,87 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace JsonDiffPatchDotNet
|
||||
{
|
||||
internal class Lcs
|
||||
{
|
||||
internal List<JToken> Sequence { get; set; }
|
||||
internal class Lcs
|
||||
{
|
||||
internal List<JToken> Sequence { get; set; }
|
||||
|
||||
internal List<int> Indices1 { get; set; }
|
||||
internal List<int> Indices1 { get; set; }
|
||||
|
||||
internal List<int> Indices2 { get; set; }
|
||||
internal List<int> Indices2 { get; set; }
|
||||
|
||||
private Lcs()
|
||||
{
|
||||
Sequence = new List<JToken>();
|
||||
Indices1 = new List<int>();
|
||||
Indices2 = new List<int>();
|
||||
}
|
||||
|
||||
internal static Lcs Get(List<JToken> left, List<JToken> right)
|
||||
{
|
||||
var matrix = LcsInternal(left, right);
|
||||
var result = Backtrack(matrix, left, right, left.Count, right.Count);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int[,] LcsInternal(List<JToken> left, List<JToken> right)
|
||||
{
|
||||
var arr = new int[left.Count + 1, right.Count + 1];
|
||||
|
||||
for (int i = 1; i <= left.Count; i++)
|
||||
{
|
||||
for (int j = 1; j <= right.Count; j++)
|
||||
{
|
||||
if (JToken.DeepEquals(left[i - 1], right[j - 1]))
|
||||
{
|
||||
arr[i, j] = arr[i - 1, j - 1] + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
arr[i, j] = Math.Max(arr[i - 1, j], arr[i, j - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
private static Lcs Backtrack(int[,] matrix, List<JToken> left, List<JToken> right, int li, int ri)
|
||||
private Lcs()
|
||||
{
|
||||
var result = new Lcs();
|
||||
for (int i = 1, j = 1; i <= li && j <= ri;)
|
||||
{
|
||||
// If the JSON tokens at the same position are both Objects or both Arrays, we just say they
|
||||
// are the same even if they are not, because we can package smaller deltas than an entire
|
||||
// object or array replacement by doing object to object or array to array diff.
|
||||
if (JToken.DeepEquals(left[i - 1], right[j - 1])
|
||||
|| left[i - 1].Type == JTokenType.Object && right[j - 1].Type == JTokenType.Object
|
||||
|| left[i - 1].Type == JTokenType.Array && right[j - 1].Type == JTokenType.Array)
|
||||
{
|
||||
result.Sequence.Add(left[i - 1]);
|
||||
result.Indices1.Add(i - 1);
|
||||
result.Indices2.Add(j - 1);
|
||||
i++;
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
Sequence = new List<JToken>();
|
||||
Indices1 = new List<int>();
|
||||
Indices2 = new List<int>();
|
||||
}
|
||||
|
||||
if (matrix[i, j - 1] > matrix[i - 1, j])
|
||||
internal static Lcs Get(List<JToken> left, List<JToken> right, ItemMatch match)
|
||||
{
|
||||
var matrix = LcsInternal(left, right, match);
|
||||
var result = Backtrack(matrix, left, right, left.Count, right.Count, match);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int[,] LcsInternal(List<JToken> left, List<JToken> right, ItemMatch match)
|
||||
{
|
||||
var arr = new int[left.Count + 1, right.Count + 1];
|
||||
|
||||
for (int i = 1; i <= left.Count; i++)
|
||||
{
|
||||
for (int j = 1; j <= right.Count; j++)
|
||||
{
|
||||
i++;
|
||||
if (match.Match(left[i - 1], right[j - 1]))
|
||||
{
|
||||
arr[i, j] = arr[i - 1, j - 1] + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
arr[i, j] = Math.Max(arr[i - 1, j], arr[i, j - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
private static Lcs Backtrack(int[,] matrix, List<JToken> left, List<JToken> right, int li, int ri, ItemMatch match)
|
||||
{
|
||||
var index1 = li;
|
||||
var index2 = ri;
|
||||
var result = new Lcs();
|
||||
|
||||
while (index1 != 0 && index2 != 0)
|
||||
{
|
||||
var sameLetter = match.Match(left[index1 - 1], right[index2 - 1]);
|
||||
|
||||
if (sameLetter)
|
||||
{
|
||||
result.Sequence.Add(left[index1 - 1]);
|
||||
result.Indices1.Add(index1 - 1);
|
||||
result.Indices2.Add(index2 - 1);
|
||||
--index1;
|
||||
--index2;
|
||||
}
|
||||
else
|
||||
{
|
||||
j++;
|
||||
var valueAtMatrixAbove = matrix[index1, index2 - 1];
|
||||
var valueAtMatrixLeft = matrix[index1 - 1, index2];
|
||||
if (valueAtMatrixAbove > valueAtMatrixLeft)
|
||||
{
|
||||
--index2;
|
||||
}
|
||||
else
|
||||
{
|
||||
--index1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
namespace JsonDiffPatchDotNet
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace JsonDiffPatchDotNet
|
||||
{
|
||||
public sealed class Options
|
||||
{
|
||||
{
|
||||
public Options()
|
||||
{
|
||||
ArrayDiff = ArrayDiffMode.Efficient;
|
||||
|
@ -14,15 +19,37 @@
|
|||
/// </summary>
|
||||
public ArrayDiffMode ArrayDiff { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies how string values are diffed. The default is Efficient.
|
||||
/// </summary>
|
||||
public TextDiffMode TextDiff { 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>
|
||||
/// 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>
|
||||
/// Specifies which paths to exclude from the diff patch set
|
||||
/// </summary>
|
||||
public List<string> ExcludePaths { get; set; } = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// 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; }
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue