weichch / system-text-json-jsondiffpatch

High-performance, low-allocating JSON object diff and patch extension for System.Text.Json. Support generating patch document in RFC 6902 JSON Patch format.
MIT License
102 stars 13 forks source link
compare diff json json-diff json-patch jsondiffpatch patch rfc-6902 system-text-json

SystemTextJson.JsonDiffPatch

GitHub GitHub Workflow Status (branch) JsonDiffPatch Nuget

High-performance, low-allocating JSON object diff and patch extension for System.Text.Json.

Features

Install

JsonDiffPatch

PM> Install-Package SystemTextJson.JsonDiffPatch

xUnit Assert

PM> Install-Package SystemTextJson.JsonDiffPatch.Xunit

MSTest v2 Assert

PM> Install-Package SystemTextJson.JsonDiffPatch.MSTest

NUnit Assert

PM> Install-Package SystemTextJson.JsonDiffPatch.NUnit

Examples

Diff

// Diff JsonNode
var node1 = JsonNode.Parse("{\"foo\":\"bar\"}");
var node2 = JsonNode.Parse("{\"baz\":\"qux\", \"foo\":\"bar\"}");
var diff = node1.Diff(node2);
// Diff with options
var diff = node1.Diff(node2, new JsonDiffOptions
{
    JsonElementComparison = JsonElementComparison.Semantic
});
// Diff and convert delta into RFC 6902 JSON Patch format
var diff = node1.Diff(node2, new JsonPatchDeltaFormatter());
// Diff JSON files
var diff = JsonDiffPatcher.DiffFile(file1, file2);
// Diff Span<byte>
var diff = JsonDiffPatcher.Diff(span1, span2);
// Diff streams
var diff = JsonDiffPatcher.Diff(stream1, stream2);
// Diff JSON strings
var diff = JsonDiffPatcher.Diff(json1, json2);
// Diff JSON readers
var diff = JsonDiffPatcher.Diff(ref reader1, ref reader2);

Patch & Unpatch

var node1 = JsonNode.Parse("{\"foo\":\"bar\"}");
var node2 = JsonNode.Parse("{\"baz\":\"qux\", \"foo\":\"bar\"}");
var diff = node1.Diff(node2);
// In-place patch
JsonDiffPatcher.Patch(ref node1, diff);
// Clone & patch
var patched = node1.PatchNew(diff);
// In-place unpatch
JsonDiffPatcher.ReversePatch(ref node1, diff);
// Clone & unpatch
var patched = node1.ReversePatchNew(diff);

DeepEquals

// JsonDocument
var doc1 = JsonDocument.Parse("{\"foo\":1}");
var doc2 = JsonDocument.Parse("{\"foo\":1.0}");
var equal = doc1.DeepEquals(doc2);
var textEqual = doc1.DeepEquals(doc2, JsonElementComparison.RawText);
var semanticEqual = doc1.DeepEquals(doc2, JsonElementComparison.Semantic);

// JsonNode
var node1 = JsonNode.Parse("{\"foo\":1}");
var node2 = JsonNode.Parse("{\"foo\":1.0}");
var equal = node1.DeepEquals(node2);
var textEqual = node1.DeepEquals(node2, JsonElementComparison.RawText);
var semanticEqual = node1.DeepEquals(node2, JsonElementComparison.Semantic);

Default Options

// Default diff options
JsonDiffPatcher.DefaultOptions = () => new JsonDiffOptions
{
    JsonElementComparison = JsonElementComparison.Semantic
};

// Default comparison mode for DeepEquals
JsonDiffPatcher.DefaultComparison = JsonElementComparison.Semantic;

Semantic Value Comparison

var node1 = JsonNode.Parse("\"2019-11-27\"");
var node2 = JsonNode.Parse("\"2019-11-27T00:00:00.000\"");
// dateCompare is 0
var dateCompare = JsonValueComparer.Compare(node1, node2);

var node3 = JsonNode.Parse("1");
var node4 = JsonNode.Parse("1.00");
// numCompare is 0
var numCompare = JsonValueComparer.Compare(node3, node4);

Assert (Unit Testing)

var expected = JsonNode.Parse("{\"foo\":\"bar\"}");
var actual = JsonNode.Parse("{\"baz\":\"qux\", \"foo\":\"bar3\"}");

// xUnit
JsonAssert.Equal(expected, actual);
actual.ShouldEqual(expected);
JsonAssert.NotEqual(expected, actual);
actual.ShouldNotEqual(expected);

// MSTest
JsonAssert.AreEqual(expected, actual);
Assert.That.JsonAreEqual(expected, actual);
JsonAssert.AreNotEqual(expected, actual);
Assert.That.JsonAreNotEqual(expected, actual);

// NUnit
JsonAssert.AreEqual(expected, actual);
Assert.That(actual, JsonIs.EqualTo(expected));
JsonAssert.AreNotEqual(expected, actual);
Assert.That(actual, JsonIs.NotEqualTo(expected));

Example output (when output is enabled):

JsonAssert.Equal() failure.
Expected:
{
  "foo": "bar"
}
Actual:
{
  "baz": "qux",
  "foo": "bar"
}
Delta:
{
  "foo": [
    "bar",
    "bar3"
  ],
  "baz": [
    "qux"
  ]
}

Benchmark

See detailed benchmark results.