Compare sets order-independently in pkg/matcher.
Also release matcher 0.10.1.
R=kevmoo@google.com
BUG= https://code.google.com/p/dart/issues/detail?id=19376
Review URL: https://codereview.chromium.org//327213003
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart/pkg/matcher@37286 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 98cd9f4..3852190 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.10.1
+
+* Compare sets order-independently when using `equals()`.
+
## 0.10.0+3
* Removed `@deprecated` annotation on matchers due to
diff --git a/lib/src/core_matchers.dart b/lib/src/core_matchers.dart
index 356476b..cb76d68 100644
--- a/lib/src/core_matchers.dart
+++ b/lib/src/core_matchers.dart
@@ -85,7 +85,7 @@
///
/// For [Iterable]s and [Map]s, this will recursively match the elements. To
/// handle cyclic structures a recursion depth [limit] can be provided. The
-/// default limit is 100.
+/// default limit is 100. [Set]s will be compared order-independently.
Matcher equals(expected, [int limit=100]) =>
expected is String
? new _StringEqualsMatcher(expected)
@@ -124,6 +124,26 @@
}
}
+ List _compareSets(Set expected, actual, matcher, depth, location) {
+ if (actual is! Iterable) return ['is not Iterable', location];
+ actual = actual.toSet();
+
+ for (var expectedElement in expected) {
+ if (actual.every((actualElement) =>
+ matcher(expectedElement, actualElement, location, depth) != null)) {
+ return ['does not contain $expectedElement', location];
+ }
+ }
+
+ if (actual.length > expected.length) {
+ return ['larger than expected', location];
+ } else if (actual.length < expected.length) {
+ return ['smaller than expected', location];
+ } else {
+ return null;
+ }
+ }
+
List _recursiveMatch(expected, actual, String location, int depth) {
// If the expected value is a matcher, try to match it.
if (expected is Matcher) {
@@ -146,37 +166,38 @@
if (depth > _limit) return ['recursion depth limit exceeded', location];
// If _limit is 1 we can only recurse one level into object.
- bool canRecurse = depth == 0 || _limit > 1;
+ if (depth == 0 || _limit > 1) {
+ if (expected is Set) {
+ return _compareSets(expected, actual, _recursiveMatch, depth + 1,
+ location);
+ } else if (expected is Iterable) {
+ return _compareIterables(expected, actual, _recursiveMatch, depth + 1,
+ location);
+ } else if (expected is Map) {
+ if (actual is! Map) return ['expected a map', location];
- if (expected is Iterable && canRecurse) {
- return _compareIterables(expected, actual, _recursiveMatch, depth + 1,
- location);
- }
-
- if (expected is Map && canRecurse) {
- if (actual is! Map) return ['expected a map', location];
-
- var err = (expected.length == actual.length) ? '' :
- 'has different length and ';
- for (var key in expected.keys) {
- if (!actual.containsKey(key)) {
- return ["${err}is missing map key '$key'", location];
+ var err = (expected.length == actual.length) ? '' :
+ 'has different length and ';
+ for (var key in expected.keys) {
+ if (!actual.containsKey(key)) {
+ return ["${err}is missing map key '$key'", location];
+ }
}
- }
- for (var key in actual.keys) {
- if (!expected.containsKey(key)) {
- return ["${err}has extra map key '$key'", location];
+ for (var key in actual.keys) {
+ if (!expected.containsKey(key)) {
+ return ["${err}has extra map key '$key'", location];
+ }
}
- }
- for (var key in expected.keys) {
- var rp = _recursiveMatch(expected[key], actual[key],
- "${location}['${key}']", depth + 1);
- if (rp != null) return rp;
- }
+ for (var key in expected.keys) {
+ var rp = _recursiveMatch(expected[key], actual[key],
+ "${location}['${key}']", depth + 1);
+ if (rp != null) return rp;
+ }
- return null;
+ return null;
+ }
}
var description = new StringDescription();
diff --git a/pubspec.yaml b/pubspec.yaml
index 87ab0cf..becc452 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
name: matcher
-version: 0.10.0+3
+version: 0.10.1
author: Dart Team <misc@dartlang.org>
description: Support for specifying test expectations
homepage: http://www.dartlang.org
diff --git a/test/core_matchers_test.dart b/test/core_matchers_test.dart
index 3f694f3..c7644a2 100644
--- a/test/core_matchers_test.dart
+++ b/test/core_matchers_test.dart
@@ -47,6 +47,24 @@
shouldPass(a, equals(b));
});
+ test('equals with a set', () {
+ var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ var set1 = numbers.toSet();
+ numbers.shuffle();
+ var set2 = numbers.toSet();
+
+ shouldPass(set2, equals(set1));
+ shouldPass(numbers, equals(set1));
+ shouldFail([1, 2, 3, 4, 5, 6, 7, 8, 9], equals(set1),
+ "Expected: ?:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n"
+ " Actual: [1, 2, 3, 4, 5, 6, 7, 8, 9]\n"
+ " Which: does not contain 10");
+ shouldFail([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], equals(set1),
+ "Expected: ?:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n"
+ " Actual: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]\n"
+ " Which: larger than expected");
+ });
+
test('anything', () {
var a = new Map();
shouldPass(0, anything);