Rewrite isEmpty and isNotEmpty to just access the isEmpty/isNotEmpty.

Adapt the unit tests and add a small regression test for
https://code.google.com/p/dart/issues/detail?id=21562 to check that
`expect(null, isNot(isEmpty))` fails.

BUG=21792, 21562
diff --git a/CHANGELOG.md b/CHANGELOG.md
index aaf5a4d..ff36756 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,11 @@
+## 0.11.4
+
+* Remove the type checks in the `isEmpty` and `isNotEmpty` matchers and simply
+  access the `isEmpty` respectively `isNotEmpty` fields. This allows them to
+  work with custom collections. See [Issue
+  21792](https://code.google.com/p/dart/issues/detail?id=21792) and [Issue
+  21562](https://code.google.com/p/dart/issues/detail?id=21562)
+
 ## 0.11.3+1
 
 * Fix the `prints` matcher test on dart2js.
diff --git a/lib/src/core_matchers.dart b/lib/src/core_matchers.dart
index c2c1e84..a8ae365 100644
--- a/lib/src/core_matchers.dart
+++ b/lib/src/core_matchers.dart
@@ -8,29 +8,24 @@
 import 'interfaces.dart';
 import 'util.dart';
 
-/// Returns a matcher that matches empty strings, maps or iterables
-/// (including collections) using the isEmpty property.
+/// Returns a matcher that matches the isEmpty property.
 const Matcher isEmpty = const _Empty();
 
 class _Empty extends Matcher {
   const _Empty();
-  bool matches(item, Map matchState) {
-    return (item is Map || item is Iterable || item is String) && item.isEmpty;
-  }
+
+  bool matches(item, Map matchState) => item.isEmpty;
+
   Description describe(Description description) => description.add('empty');
 }
 
-/// Returns a matcher that matches non-empty strings, maps or iterables
-/// (including collections) using the isNotEmpty property.
+/// Returns a matcher that matches the isNotEmpty property.
 const Matcher isNotEmpty = const _NotEmpty();
 
 class _NotEmpty extends Matcher {
   const _NotEmpty();
 
-  bool matches(item, Map matchState) {
-    return (item is Map || item is Iterable || item is String) &&
-      item.isNotEmpty;
-  }
+  bool matches(item, Map matchState) => item.isNotEmpty;
 
   Description describe(Description description) => description.add('non-empty');
 }
diff --git a/pubspec.yaml b/pubspec.yaml
index 388d060..fe137e6 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: matcher
-version: 0.11.3+1
+version: 0.11.4
 author: Dart Team <misc@dartlang.org>
 description: Support for specifying test expectations
 homepage: https://github.com/dart-lang/matcher
diff --git a/test/string_matchers_test.dart b/test/string_matchers_test.dart
index ba96713..e2efadf 100644
--- a/test/string_matchers_test.dart
+++ b/test/string_matchers_test.dart
@@ -19,15 +19,24 @@
 
   test('isEmpty', () {
     shouldPass('', isEmpty);
-    shouldFail(null, isEmpty, "Expected: empty Actual: <null>");
-    shouldFail(0, isEmpty, "Expected: empty Actual: <0>");
-    shouldFail('a', isEmpty, "Expected: empty Actual: 'a'");
+    shouldFail(null, isEmpty, startsWith("Expected: empty  Actual: <null>"));
+    shouldFail(0, isEmpty, startsWith("Expected: empty  Actual: <0>"));
+    shouldFail('a', isEmpty, startsWith("Expected: empty  Actual: 'a'"));
+  });
+
+  // Regression test for: https://code.google.com/p/dart/issues/detail?id=21562
+  test('isNot(isEmpty)', () {
+    shouldPass('a', isNot(isEmpty));
+    shouldFail('', isNot(isEmpty), 'Expected: not empty Actual: \'\'');
+    shouldFail(null, isNot(isEmpty),
+      startsWith('Expected: not empty  Actual: <null>'));
   });
 
   test('isNotEmpty', () {
-    shouldFail('', isNotEmpty, "Expected: non-empty Actual: ''");
-    shouldFail(null, isNotEmpty, "Expected: non-empty Actual: <null>");
-    shouldFail(0, isNotEmpty, "Expected: non-empty Actual: <0>");
+    shouldFail('', isNotEmpty, startsWith("Expected: non-empty  Actual: ''"));
+    shouldFail(null, isNotEmpty,
+        startsWith("Expected: non-empty  Actual: <null>"));
+    shouldFail(0, isNotEmpty, startsWith("Expected: non-empty  Actual: <0>"));
     shouldPass('a', isNotEmpty);
   });