From d527e7560b8d135f794c8e2382d2e3e15610e4f3 Mon Sep 17 00:00:00 2001 From: ehoogerbeets Date: Wed, 6 Apr 2016 01:33:07 -0700 Subject: [PATCH] Added equalIgnoringOrder assertion --- lib/assert.js | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++ lib/types.js | 1 + 2 files changed, 65 insertions(+) diff --git a/lib/assert.js b/lib/assert.js index 55ef74493..ff2872a34 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -352,3 +352,67 @@ assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) { }; assert.ifError = function (err) { if (err) {throw err;}}; + + +/** + * Return true if every element in the expected array also exists in the the actual + * array. The actual array may contain more elements that are not in the expected + * array. This implementation is very simple and not very efficient (Order(n^2)) so + * do not call this to compare large arrays. + * + * @param {Array.} actual The actual array to test + * @param {Array.} expected The array to test against + * @returns True if every element of the expected array exists in the actual array. + */ +function isEqualIgnoringOrder(actual, expected) { + var found = false; + for (var i = 0; i < expected.length; i++) { + var found = false; + for (var j = 0; j < actual.length; j++) { + try { + if (_deepEqual(actual[j], expected[i])) { + found = true; + break; + } + } catch (ignored) { + } + } + if (!found) { + return false; + } + } + return true; +} + +function isArray(object) { + return typeof(object) === 'object' && Object.prototype.toString.call(object) === '[object Array]'; +}; + +/** + * Performs a deep comparison of arrays, ignoring the order of the + * elements of the array. Essentially, this ensure that they have the same + * contents, possibly in a different order. Each of the elements of the + * array is compared with a deep equals. If this is called with objects + * that are not arrays, the assertion fails. + * + * @example // passing assertions + * assert.equalIgnoringOrder([5, 2, 8, 3], [2, 4, 5, 9]); + * assert.equalIgnoringOrder(["apples", "bananas", "oranges"], ["oranges", "apples", "bananas"]); + * + * @param {Object} actual The actual value + * @param {Object} expected The expected value + * @throws ArgumentsError + * @throws AssertionError + */ +assert.equalIgnoringOrder = function(actual, expected, message) { + if (!isArray(expected)) { + fail("Invalid expected argument to equalIgnoringOrder."); + } else if (isArray(actual)) { + if (isEqualIgnoringOrder(actual, expected) === false) { + fail(actual, expected, message, "equalIgnoringOrder", assert.equalIgnoringOrder); + } + } else { + fail(actual, expected, message, "equalIgnoringOrder", assert.equalIgnoringOrder); + } + return; +}; diff --git a/lib/types.js b/lib/types.js index 879edd8b3..3992b2d6b 100644 --- a/lib/types.js +++ b/lib/types.js @@ -149,6 +149,7 @@ exports.test = function (name, start, options, callback) { ok: wrapAssert('ok', 'ok', 2), same: wrapAssert('same', 'deepEqual', 3), equals: wrapAssert('equals', 'equal', 3), + equalIgnoringOrder: wrapAssert('equalIgnoringOrder', 'equalIgnoringOrder', 3), expect: function (num) { expecting = num; },