From 94e29295173d87c6645f467de5f611ac4b83f4c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Tue, 13 May 2014 19:10:14 +0200 Subject: [PATCH 1/4] Add Must.prototype.permutationOf Assert the array have the same members, possibly in a different order. --- lib/assertions.js | 34 +++++++++++++++++++++++++++++++ test/assertions_test.js | 44 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/lib/assertions.js b/lib/assertions.js index f3faaec..86cb891 100644 --- a/lib/assertions.js +++ b/lib/assertions.js @@ -558,6 +558,40 @@ exports.include = function(expected) { */ exports.contain = exports.include +/** + * Assert the array is a permutation of another array. + * + * This mean the array must have all of the expected members, + * any duplicated items must be duplicated too. + * + * Members are compared using strict equal. + * + * @example + * [1, 1, 2, 3].must.be.a.permutationOf([3, 2, 1, 1]) // pass + * [1, 1, 2, 3].must.be.a.permutationOf([3, 2, 1]) // fail + * [1, 2, 3].must.be.a.permutationOf([2,3]) // fail + * + * @method members + * @param expected + */ +exports.permutationOf = function(expected) { + var result = isPermutationOf(this.actual, expected) + + insist.call(this, result, "be a permutation of", expected, { diffable: true }) +} + +function isPermutationOf(actual, expected) { + if (!Array.isArray(actual) || !Array.isArray(expected)) return false + if (actual.length !== expected.length) return false + + actual = actual.slice().sort() + expected = expected.slice().sort() + for (var i = 0; i < actual.length; i++) { + if (actual[i] !== expected[i]) return false + } + return true +} + /** * Assert object matches the given regular expression. * diff --git a/test/assertions_test.js b/test/assertions_test.js index 3f6f258..e00bb13 100644 --- a/test/assertions_test.js +++ b/test/assertions_test.js @@ -1684,6 +1684,50 @@ describe("Must.prototype.contain", function() { }) }) +describe("Must.prototype.permutationOf", function() { + it("must pass if given array have same members", function() { + assertPass(function() { [1, 2, 3].must.be.a.permutationOf([3, 2, 1]) }) + }) + + it("must fail if given array does not have same members", function() { + assertFail(function() { [1, 2, 3].must.be.a.permutationOf([1]) }) + }) + + it("must fail if given array is missing duplicated members", function() { + assertFail(function() { [1, 2].must.be.a.permutationOf([2, 1, 1]) }) + }) + + it("must fail if given array have extra duplicated members", function() { + assertFail(function() { [1, 1, 2].must.be.a.permutationOf([2, 1]) }) + }) + + it("must pass if given array have same duplicated members", function() { + assertPass(function() { [1, 1, 2].must.be.a.permutationOf([2, 1, 1]) }) + }) + + mustThrowAssertionError(function() { [1, 2, 3].must.be.a.permutationOf([1, 2]) }, { + actual: [1, 2, 3], + expected: [1, 2], + diffable: true, + message: "[1,2,3] must be a permutation of [1,2]" + }) + + describe(".not", function() { + function not() { [1, 2, 3].must.not.be.a.permutationOf([1, 2, 3]) } + + it("must invert the assertion", function() { + assertFail(not) + }) + + mustThrowAssertionError(not, { + actual: [1, 2, 3], + expected: [1, 2, 3], + diffable: true, + message: "[1,2,3] must not be a permutation of [1,2,3]" + }) + }) +}) + describe("Must.prototype.match", function() { describe("given String and RegExp", function() { var literal = "Year 2014 might be like 1984." From 5bd5528dbad694ba32e2a3ba6206051126943d93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andri=20M=C3=B6ll?= Date: Wed, 28 May 2014 19:05:55 +0300 Subject: [PATCH 2/4] Add more tests for Must.prototype.permutationOf. --- test/assertions_test.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/test/assertions_test.js b/test/assertions_test.js index e00bb13..9eed40d 100644 --- a/test/assertions_test.js +++ b/test/assertions_test.js @@ -1685,7 +1685,7 @@ describe("Must.prototype.contain", function() { }) describe("Must.prototype.permutationOf", function() { - it("must pass if given array have same members", function() { + it("must pass if given array has same members", function() { assertPass(function() { [1, 2, 3].must.be.a.permutationOf([3, 2, 1]) }) }) @@ -1697,15 +1697,25 @@ describe("Must.prototype.permutationOf", function() { assertFail(function() { [1, 2].must.be.a.permutationOf([2, 1, 1]) }) }) - it("must fail if given array have extra duplicated members", function() { + it("must fail if given array has extra duplicated members", function() { assertFail(function() { [1, 1, 2].must.be.a.permutationOf([2, 1]) }) }) - it("must pass if given array have same duplicated members", function() { + it("must pass if given array has same duplicated members", function() { assertPass(function() { [1, 1, 2].must.be.a.permutationOf([2, 1, 1]) }) }) - mustThrowAssertionError(function() { [1, 2, 3].must.be.a.permutationOf([1, 2]) }, { + it("must pass if both arrays empty", function() { + assertPass(function() { [].must.be.a.permutationOf([]) }) + }) + + it("must fail if given array has member of different type", function() { + assertFail(function() { [1].must.be.a.permutationOf(["1"]) }) + }) + + mustThrowAssertionError(function() { + [1, 2, 3].must.be.a.permutationOf([1, 2]) + }, { actual: [1, 2, 3], expected: [1, 2], diffable: true, From dd91a58a9b1b3f16e8b1a7f9b783f7bd6f83767c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andri=20M=C3=B6ll?= Date: Wed, 28 May 2014 19:06:18 +0300 Subject: [PATCH 3/4] Tweak style. --- lib/assertions.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/assertions.js b/lib/assertions.js index 86cb891..d24f9cf 100644 --- a/lib/assertions.js +++ b/lib/assertions.js @@ -576,8 +576,7 @@ exports.contain = exports.include */ exports.permutationOf = function(expected) { var result = isPermutationOf(this.actual, expected) - - insist.call(this, result, "be a permutation of", expected, { diffable: true }) + insist.call(this, result, "be a permutation of", expected, {diffable: true}) } function isPermutationOf(actual, expected) { @@ -589,6 +588,7 @@ function isPermutationOf(actual, expected) { for (var i = 0; i < actual.length; i++) { if (actual[i] !== expected[i]) return false } + return true } From 9112d36daf27f79eac69c6971bbbe76cd471d863 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andri=20M=C3=B6ll?= Date: Wed, 28 May 2014 19:19:17 +0300 Subject: [PATCH 4/4] Document Must.prototype.permutationOf. --- CHANGELOG.md | 7 +++++++ README.md | 1 + doc/API.md | 15 +++++++++++++++ lib/assertions.js | 16 +++++++--------- 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4630251..521a773 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## Unreleased +- Adds [`permutationOf`] to assert that two arrays contain the same elements. + Thanks, [Miroslav Bajtoš][@bajtos]! + +[`permutationOf`]: https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.permutationOf +[@bajtos]: http://about.me/bajtos + ## 0.11.0 (Feb 13, 2014) - Works on other JavaScript engines besides V8 by not assuming `Error.captureStackTrace`. Thanks, [Dmitry Starostin][@incrop]! diff --git a/README.md b/README.md index 8696072..a5d2fc8 100644 --- a/README.md +++ b/README.md @@ -233,6 +233,7 @@ Must.js, please see the [Must.js API Documentation][api]. - [own](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.own)(property, [value]) - [ownKeys](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.ownKeys)(keys) - [ownProperty](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.ownProperty)(property, [value]) +- [permutationOf](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.permutationOf)(expected) - [property](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.property)(property, [value]) - [regexp](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.regexp)() - [string](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.string)() diff --git a/doc/API.md b/doc/API.md index 52b5878..759d61d 100644 --- a/doc/API.md +++ b/doc/API.md @@ -47,6 +47,7 @@ Must.js API Documentation - [own](#Must.prototype.own)(property, [value]) - [ownKeys](#Must.prototype.ownKeys)(keys) - [ownProperty](#Must.prototype.ownProperty)(property, [value]) +- [permutationOf](#Must.prototype.permutationOf)(expected) - [property](#Must.prototype.property)(property, [value]) - [regexp](#Must.prototype.regexp)() - [string](#Must.prototype.string)() @@ -594,6 +595,20 @@ Optionally assert it *equals* (`===`) to `value`. ({life: 42, love: 69}).must.have.ownProperty("love", 69) ``` + +### Must.prototype.permutationOf(expected) +Assert that an array is a permutation of the given array. + +An array is a permutation of another if they both have the same elements +(including the same number of duplicates) regardless of their order. +Elements are checked with strict equals (`===`). + +**Examples**: +```javascript +[1, 1, 2, 3].must.be.a.permutationOf([3, 2, 1, 1]) +[7, 8, 8, 9].must.not.be.a.permutationOf([9, 8, 7]) +``` + ### Must.prototype.property(property, [value]) Assert that an object has property `property`. diff --git a/lib/assertions.js b/lib/assertions.js index d24f9cf..72a1058 100644 --- a/lib/assertions.js +++ b/lib/assertions.js @@ -559,19 +559,17 @@ exports.include = function(expected) { exports.contain = exports.include /** - * Assert the array is a permutation of another array. + * Assert that an array is a permutation of the given array. * - * This mean the array must have all of the expected members, - * any duplicated items must be duplicated too. - * - * Members are compared using strict equal. + * An array is a permutation of another if they both have the same elements + * (including the same number of duplicates) regardless of their order. + * Elements are checked with strict equals (`===`). * * @example - * [1, 1, 2, 3].must.be.a.permutationOf([3, 2, 1, 1]) // pass - * [1, 1, 2, 3].must.be.a.permutationOf([3, 2, 1]) // fail - * [1, 2, 3].must.be.a.permutationOf([2,3]) // fail + * [1, 1, 2, 3].must.be.a.permutationOf([3, 2, 1, 1]) + * [7, 8, 8, 9].must.not.be.a.permutationOf([9, 8, 7]) * - * @method members + * @method permutationOf * @param expected */ exports.permutationOf = function(expected) {