[
{
"name": "one of each: an addition, a removal, a change and an untouched record",
"args": [
[{ "id": 1, "name": "Ada", "team": "core" }, { "id": 2, "name": "Grace", "team": "ops" }, { "id": 3, "name": "Linus", "team": "core" }],
[{ "id": 1, "name": "Ada", "team": "core" }, { "id": 3, "name": "Linus", "team": "kernel" }, { "id": 4, "name": "Barbara", "team": "ops" }],
"id"
],
"expect": {
"added": [{ "id": 4, "name": "Barbara", "team": "ops" }],
"removed": [{ "id": 2, "name": "Grace", "team": "ops" }],
"changed": [{ "key": "3", "before": { "id": 3, "name": "Linus", "team": "core" }, "after": { "id": 3, "name": "Linus", "team": "kernel" }, "fields": ["team"] }],
"unchanged": 1
}
},
{
"name": "identical lists: nothing added, removed or changed",
"args": [[{ "k": "a", "v": 1 }, { "k": "b", "v": 2 }], [{ "k": "a", "v": 1 }, { "k": "b", "v": 2 }], "k"],
"expect": { "added": [], "removed": [], "changed": [], "unchanged": 2 }
},
{
"name": "reordering is not a change",
"args": [[{ "k": "a", "v": 1 }, { "k": "b", "v": 2 }], [{ "k": "b", "v": 2 }, { "k": "a", "v": 1 }], "k"],
"expect": { "added": [], "removed": [], "changed": [], "unchanged": 2 }
},
{
"name": "from nothing: everything is added, in after's order",
"args": [[], [{ "k": "b" }, { "k": "a" }], "k"],
"expect": { "added": [{ "k": "b" }, { "k": "a" }], "removed": [], "changed": [], "unchanged": 0 }
},
{
"name": "to nothing: everything is removed, in before's order",
"args": [[{ "k": "b" }, { "k": "a" }], [], "k"],
"expect": { "added": [], "removed": [{ "k": "b" }, { "k": "a" }], "changed": [], "unchanged": 0 }
},
{
"name": "changed fields are sorted by code point, including a field added and a field removed",
"args": [[{ "id": "x", "b": 1, "a": 1, "old": true }], [{ "id": "x", "new": 5, "b": 2, "a": 1 }], "id"],
"expect": { "added": [], "removed": [], "changed": [{ "key": "x", "before": { "id": "x", "b": 1, "a": 1, "old": true }, "after": { "id": "x", "new": 5, "b": 2, "a": 1 }, "fields": ["b", "new", "old"] }], "unchanged": 0 }
},
{
"name": "changed records follow after's order",
"args": [[{ "k": "a", "v": 1 }, { "k": "b", "v": 1 }], [{ "k": "b", "v": 2 }, { "k": "a", "v": 2 }], "k"],
"expect": {
"added": [], "removed": [],
"changed": [
{ "key": "b", "before": { "k": "b", "v": 1 }, "after": { "k": "b", "v": 2 }, "fields": ["v"] },
{ "key": "a", "before": { "k": "a", "v": 1 }, "after": { "k": "a", "v": 2 }, "fields": ["v"] }
],
"unchanged": 0
}
},
{
"name": "1 and 1.0 are the same number, so a float round trip is not a change",
"args": [[{ "k": "a", "qty": 1 }], [{ "k": "a", "qty": 1.0 }], "k"],
"expect": { "added": [], "removed": [], "changed": [], "unchanged": 1 }
},
{
"name": "a number that became a string did change",
"args": [[{ "k": "a", "qty": 1 }], [{ "k": "a", "qty": "1" }], "k"],
"expect": { "added": [], "removed": [], "changed": [{ "key": "a", "before": { "k": "a", "qty": 1 }, "after": { "k": "a", "qty": "1" }, "fields": ["qty"] }], "unchanged": 0 }
},
{
"name": "true is not 1",
"args": [[{ "k": "a", "on": 1 }], [{ "k": "a", "on": true }], "k"],
"expect": { "added": [], "removed": [], "changed": [{ "key": "a", "before": { "k": "a", "on": 1 }, "after": { "k": "a", "on": true }, "fields": ["on"] }], "unchanged": 0 }
},
{
"name": "a null field and a missing field are the same, so dropping nulls is not a change",
"args": [[{ "k": "a", "note": null, "meta": { "x": null, "y": 1 } }], [{ "k": "a", "meta": { "y": 1 } }], "k"],
"expect": { "added": [], "removed": [], "changed": [], "unchanged": 1 }
},
{
"name": "nested lists and maps are compared deeply; list order matters",
"args": [[{ "k": "a", "tags": ["x", "y"], "addr": { "city": "Leeds" } }], [{ "k": "a", "tags": ["y", "x"], "addr": { "city": "Leeds" } }], "k"],
"expect": { "added": [], "removed": [], "changed": [{ "key": "a", "before": { "k": "a", "tags": ["x", "y"], "addr": { "city": "Leeds" } }, "after": { "k": "a", "tags": ["y", "x"], "addr": { "city": "Leeds" } }, "fields": ["tags"] }], "unchanged": 0 }
},
{
"name": "a key of 1 and a key of \"1\" match; the key field itself is reported as changed type",
"args": [[{ "id": 1, "v": "a" }], [{ "id": "1", "v": "a" }], "id"],
"expect": { "added": [], "removed": [], "changed": [{ "key": "1", "before": { "id": 1, "v": "a" }, "after": { "id": "1", "v": "a" }, "fields": ["id"] }], "unchanged": 0 }
},
{
"name": "a duplicate key in before is an error, not a guess",
"args": [[{ "k": "a" }, { "k": "a" }], [], "k"],
"expectError": "duplicate key \"a\" in before"
},
{
"name": "a duplicate key in after is an error",
"args": [[], [{ "k": 7 }, { "k": 7 }], "k"],
"expectError": "duplicate key \"7\" in after"
},
{
"name": "a record with no value at the key is an error",
"args": [[{ "k": "a" }], [{ "v": 1 }], "k"],
"expectError": "record 0 in after has no value at \"k\""
},
{
"name": "a fractional key is an error",
"args": [[{ "k": 1.5 }], [], "k"],
"expectError": "cannot diff by the fractional number"
},
{
"name": "an empty key name is an error",
"args": [[], [], ""],
"expectError": "needs a non-empty key name"
}
]