checks: test MapChecks, add isEmpty, isNotEmpty

100% coverage
diff --git a/pkgs/checks/lib/src/extensions/map.dart b/pkgs/checks/lib/src/extensions/map.dart
index e13cf84..b47b64d 100644
--- a/pkgs/checks/lib/src/extensions/map.dart
+++ b/pkgs/checks/lib/src/extensions/map.dart
@@ -13,6 +13,20 @@
   Check<Iterable<V>> get values => has((m) => m.values, 'values');
   Check<int> get length => has((m) => m.length, 'length');
 
+  void isEmpty() {
+    context.expect(() => const ['is empty'], (actual) {
+      if (actual.isEmpty) return null;
+      return Rejection(actual: literal(actual), which: ['is not empty']);
+    });
+  }
+
+  void isNotEmpty() {
+    context.expect(() => const ['is not empty'], (actual) {
+      if (actual.isNotEmpty) return null;
+      return Rejection(actual: literal(actual), which: ['is not empty']);
+    });
+  }
+
   /// Expects that the map contains [key] according to [Map.containsKey].
   void containsKey(K key) {
     context.expect(() => ['contains key ${literal(key)}'], (actual) {
diff --git a/pkgs/checks/test/extensions/map_test.dart b/pkgs/checks/test/extensions/map_test.dart
new file mode 100644
index 0000000..e02320a
--- /dev/null
+++ b/pkgs/checks/test/extensions/map_test.dart
@@ -0,0 +1,91 @@
+// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:checks/checks.dart';
+import 'package:checks/context.dart';
+import 'package:test/scaffolding.dart';
+
+import '../test_shared.dart';
+
+const _testMap = {
+  'a': 1,
+  'b': 2,
+};
+
+const _testMapString = '{a: 1, b: 2}';
+
+void main() {
+  test('length', () {
+    checkThat(_testMap).length.equals(2);
+  });
+  test('entries', () {
+    checkThat(_testMap).entries.any(
+          (p0) => p0
+            ..has((p0) => p0.key, 'key').equals('a')
+            ..has((p0) => p0.value, 'value').equals(1),
+        );
+  });
+  test('keys', () {
+    checkThat(_testMap).keys.contains('a');
+  });
+  test('values', () {
+    checkThat(_testMap).values.contains(1);
+  });
+
+  test('isEmpty', () {
+    checkThat(<String, int>{}).isEmpty();
+    checkThat(
+      softCheck<Map<String, int>>(_testMap, (p0) => p0.isEmpty()),
+    ).isARejection(actual: _testMapString, which: ['is not empty']);
+  });
+
+  test('isNotEmpty', () {
+    checkThat(_testMap).isNotEmpty();
+    checkThat(
+      softCheck<Map<String, int>>({}, (p0) => p0.isNotEmpty()),
+    ).isARejection(actual: '{}', which: ['is not empty']);
+  });
+
+  test('containsKey', () {
+    checkThat(_testMap).containsKey('a');
+
+    checkThat(
+      softCheck<Map<String, int>>(_testMap, (p0) => p0.containsKey('c')),
+    ).isARejection(
+      actual: _testMapString,
+      which: ["does not contain key 'c'"],
+    );
+  });
+  test('containsKeyThat', () {
+    checkThat(_testMap).containsKeyThat((p0) => p0.equals('a'));
+    checkThat(
+      softCheck<Map<String, int>>(
+        _testMap,
+        (p0) => p0.containsKeyThat((p1) => p1.equals('c')),
+      ),
+    ).isARejection(
+      actual: _testMapString,
+      which: ['Contains no matching key'],
+    );
+  });
+  test('containsValue', () {
+    checkThat(_testMap).containsValue(1);
+    checkThat(
+      softCheck<Map<String, int>>(_testMap, (p0) => p0.containsValue(3)),
+    ).isARejection(
+      actual: _testMapString,
+      which: ['does not contain value <3>'],
+    );
+  });
+  test('containsValueThat', () {
+    checkThat(_testMap).containsValueThat((p0) => p0.equals(1));
+    checkThat(
+      softCheck<Map<String, int>>(
+          _testMap, (p0) => p0.containsValueThat((p1) => p1.equals(3))),
+    ).isARejection(
+      actual: _testMapString,
+      which: ['Contains no matching value'],
+    );
+  });
+}