Skip to content

Commit

Permalink
Add match.every and match.some (#1624) (#1661)
Browse files Browse the repository at this point in the history
* Add match.every (#1624)

Added new matcher - match.every, which matches on an object or
iterable if all of the properties (or elements, respectively) match
the given predicate.

* Add match.some (#1624)

Added new matcher - match.some, which matches on an object or
iterable if some of the properties (or elements, respectively) match
the given predicate.
  • Loading branch information
nivsherf authored and mroderick committed Jan 21, 2018
1 parent 781429d commit c5dfaae
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 1 deletion.
7 changes: 7 additions & 0 deletions docs/release-source/release/matchers.md
Expand Up @@ -239,6 +239,13 @@ sinon.match.hasNested("a.b.c");
var actual = { "a": { "b": { "c": 3 } } };
```

#### `sinon.match.every(matcher)`

Requires **every** element of an `Array`, `Set` or `Map`, or alternatively **every** value of an `Object` to match the given `matcher`.

#### `sinon.match.some(matcher)`

Requires **any** element of an `Array`, `Set` or `Map`, or alternatively **any** value of an `Object` to match the given `matcher`.

## Combining matchers

Expand Down
36 changes: 36 additions & 0 deletions lib/sinon/match.js
Expand Up @@ -243,6 +243,42 @@ match.hasNested = function (property, value) {
}, message);
};

match.every = function (predicate) {
if (!isMatcher(predicate)) {
throw new TypeError("Matcher expected");
}

return match(function (actual) {
if (typeOf(actual) === "object") {
return every(Object.keys(actual), function (key) {
return predicate.test(actual[key]);
});
}

return !!actual && typeOf(actual.forEach) === "function" && every(actual, function (element) {
return predicate.test(element);
});
}, "every(" + predicate.message + ")");
};

match.some = function (predicate) {
if (!isMatcher(predicate)) {
throw new TypeError("Matcher expected");
}

return match(function (actual) {
if (typeOf(actual) === "object") {
return !every(Object.keys(actual), function (key) {
return !predicate.test(actual[key]);
});
}

return !!actual && typeOf(actual.forEach) === "function" && !every(actual, function (element) {
return !predicate.test(element);
});
}, "some(" + predicate.message + ")");
};

match.array = match.typeOf("array");

match.array.deepEquals = function (expectation) {
Expand Down
150 changes: 149 additions & 1 deletion test/match-test.js
@@ -1,6 +1,8 @@
"use strict";

var assert = require("referee").assert;
var referee = require("referee");
var assert = referee.assert;
var refute = referee.refute;
var sinonMatch = require("../lib/sinon/match");

function propertyMatcherTests(matcher, additionalTests) {
Expand Down Expand Up @@ -615,6 +617,152 @@ describe("sinonMatch", function () {
});
});

describe(".every", function () {
it("throws if given argument is not a matcher", function () {
assert.exception(function () {
sinonMatch.every({});
}, "TypeError");
assert.exception(function () {
sinonMatch.every(123);
}, "TypeError");
assert.exception(function () {
sinonMatch.every("123");
}, "TypeError");
});

it("returns matcher", function () {
var every = sinonMatch.every(sinonMatch.any);

assert(sinonMatch.isMatcher(every));
});

it("wraps the given matcher message with an \"every()\"", function () {
var every = sinonMatch.every(sinonMatch.number);

assert.equals(every.toString(), "every(typeOf(\"number\"))");
});

it("fails to match anything that is not an object or an iterable", function () {
var every = sinonMatch.every(sinonMatch.any);

refute(every.test(1));
refute(every.test("a"));
refute(every.test(null));
refute(every.test(function () {}));
});

it("matches an object if the predicate is true for every property", function () {
var every = sinonMatch.every(sinonMatch.number);

assert(every.test({a: 1, b: 2}));
});

it("fails if the predicate is false for some of the object properties", function () {
var every = sinonMatch.every(sinonMatch.number);

refute(every.test({a: 1, b: "b"}));
});

it("matches an array if the predicate is true for every element", function () {
var every = sinonMatch.every(sinonMatch.number);

assert(every.test([1, 2]));
});

it("fails if the predicate is false for some of the array elements", function () {
var every = sinonMatch.every(sinonMatch.number);

refute(every.test([1, "b"]));
});

if (typeof Set === "function") {
it("matches an iterable if the predicate is true for every element", function () {
var every = sinonMatch.every(sinonMatch.number);

assert(every.test(new Set([1, 2])));
});

it("fails if the predicate is false for some of the iterable elements", function () {
var every = sinonMatch.every(sinonMatch.number);

refute(every.test(new Set([1, "b"])));
});
}
});

describe(".some", function () {
it("throws if given argument is not a matcher", function () {
assert.exception(function () {
sinonMatch.some({});
}, "TypeError");
assert.exception(function () {
sinonMatch.some(123);
}, "TypeError");
assert.exception(function () {
sinonMatch.some("123");
}, "TypeError");
});

it("returns matcher", function () {
var some = sinonMatch.some(sinonMatch.any);

assert(sinonMatch.isMatcher(some));
});

it("wraps the given matcher message with an \"some()\"", function () {
var some = sinonMatch.some(sinonMatch.number);

assert.equals(some.toString(), "some(typeOf(\"number\"))");
});

it("fails to match anything that is not an object or an iterable", function () {
var some = sinonMatch.some(sinonMatch.any);

refute(some.test(1));
refute(some.test("a"));
refute(some.test(null));
refute(some.test(function () {}));
});

it("matches an object if the predicate is true for some of the properties", function () {
var some = sinonMatch.some(sinonMatch.number);

assert(some.test({a: 1, b: "b"}));
});

it("fails if the predicate is false for all of the object properties", function () {
var some = sinonMatch.some(sinonMatch.number);

refute(some.test({a: "a", b: "b"}));
});

it("matches an array if the predicate is true for some element", function () {
var some = sinonMatch.some(sinonMatch.number);

assert(some.test([1, "b"]));
});

it("fails if the predicate is false for all of the array elements", function () {
var some = sinonMatch.some(sinonMatch.number);

refute(some.test(["a", "b"]));
});

if (typeof Set === "function") {
it("matches an iterable if the predicate is true for some element", function () {
var some = sinonMatch.some(sinonMatch.number);

assert(some.test(new Set([1, "b"])));
});

it("fails if the predicate is false for all of the iterable elements", function () {
var some = sinonMatch.some(sinonMatch.number);

refute(some.test(new Set(["a", "b"])));
});
}
});

describe(".bool", function () {
it("is typeOf boolean matcher", function () {
var bool = sinonMatch.bool;
Expand Down

0 comments on commit c5dfaae

Please sign in to comment.