json-diff-rfc6902
Version:
This framework is to compare two JSON data and generate the Patch
154 lines (122 loc) • 3.95 kB
JavaScript
var jdr = require('../JSON-Diff');
var fs = require('fs');
var assert = require('assert');
var n_pathlogic = 21;
for (var i = 1; i <= n_pathlogic; i++) {
//Assert
describe('EqualJson', function() {
console.log("Processing test case " + i);
var root = "./" + i + "/";
var f_old = require(root + "old.json");
var f_new = require(root + "new.json");
var expect_patch = require(root + "expected.json");
var jdr_patch = require(root + "jdr_patch.json");
var fjp_new = require(root + "fjp_new.json");
var jdr_new = require(root + "jdr_new.json");
it('Case ' + i + ': generate expected patch', function() {
var equalPatch = deepCompare(jdr_patch, expect_patch);
assert.equal(equalPatch, true);
});
it('Case ' + i + ': FJP apply to get the same JSON', function() {
var equalJson = deepCompare(fjp_new, f_new);
assert.equal(equalJson, true);
});
it('Case ' + i + ': Our apply to get the same JSON', function() {
var equalJsonApp = deepCompare(jdr_new, f_new);
assert.equal(equalJsonApp, true);
});
});
}
// Compare two JSON are same or not
function deepCompare () {
var i, l, leftChain, rightChain;
function compare2Objects (x, y) {
var p;
// remember that NaN === NaN returns false
// and isNaN(undefined) returns true
if (isNaN(x) && isNaN(y) && typeof x === 'number' && typeof y === 'number') {
return true;
}
// Compare primitives and functions.
// Check if both arguments link to the same object.
// Especially useful on step when comparing prototypes
if (x === y) {
return true;
}
// Works in case when functions are created in constructor.
// Comparing dates is a common scenario. Another built-ins?
// We can even handle functions passed across iframes
if ((typeof x === 'function' && typeof y === 'function') ||
(x instanceof Date && y instanceof Date) ||
(x instanceof RegExp && y instanceof RegExp) ||
(x instanceof String && y instanceof String) ||
(x instanceof Number && y instanceof Number)) {
return x.toString() === y.toString();
}
// At last checking prototypes as good a we can
if (!(x instanceof Object && y instanceof Object)) {
return false;
}
if (x.isPrototypeOf(y) || y.isPrototypeOf(x)) {
return false;
}
if (x.constructor !== y.constructor) {
return false;
}
if (x.prototype !== y.prototype) {
return false;
}
// Check for infinitive linking loops
if (leftChain.indexOf(x) > -1 || rightChain.indexOf(y) > -1) {
return false;
}
// Quick checking of one object beeing a subset of another.
// todo: cache the structure of arguments[0] for performance
for (p in y) {
if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
return false;
}
else if (typeof y[p] !== typeof x[p]) {
return false;
}
}
for (p in x) {
if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
return false;
}
else if (typeof y[p] !== typeof x[p]) {
return false;
}
switch (typeof (x[p])) {
case 'object':
case 'function':
leftChain.push(x);
rightChain.push(y);
if (!compare2Objects (x[p], y[p])) {
return false;
}
leftChain.pop();
rightChain.pop();
break;
default:
if (x[p] !== y[p]) {
return false;
}
break;
}
}
return true;
}
if (arguments.length < 1) {
return true; //Die silently? Don't know how to handle such case, please help...
// throw "Need two or more arguments to compare";
}
for (i = 1, l = arguments.length; i < l; i++) {
leftChain = []; //Todo: this can be cached
rightChain = [];
if (!compare2Objects(arguments[0], arguments[i])) {
return false;
}
}
return true;
}