Repository: chaijs/chai
Pull request #1131 (2018-01-26 12:43:17)

.lengthOf for Maps and Sets
As described in [#1110](https://github.com/chaijs/chai/issues/1110), this PR adds support for Map and Set to .lengthOf and chains such as .above, .below, .least, .most and  .within.
I have not added alias 'size' to .lengthOf this time so as not to fix some exist test cases (Levenshtein distance between 'size' and 'pizza' used in the test cases is close). Will you give me some feedback on the above?
Feel free to point out possible mistakes. Thanks!

codecov[bot]: # [Codecov](https://codecov.io/gh/chaijs/chai/pull/1131?src=pr&el=h1) Report
> Merging [#1131](https://codecov.io/gh/chaijs/chai/pull/1131?src=pr&el=desc) into [master](https://codecov.io/gh/chaijs/chai/commit/eebe484d04e0dd0eece518a037b36958ff97d388?src=pr&el=desc) will **increase** coverage by `0.04%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/chaijs/chai/pull/1131/graphs/tree.svg?token=J8Fz3KwOQq&src=pr&width=650&height=150)](https://codecov.io/gh/chaijs/chai/pull/1131?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master    #1131      +/-   ##
==========================================
+ Coverage   93.69%   93.73%   +0.04%     
==========================================
  Files          32       32              
  Lines        1649     1676      +27     
  Branches      396      404       +8     
==========================================
+ Hits         1545     1571      +26     
- Misses        104      105       +1
```


| [Impacted Files](https://codecov.io/gh/chaijs/chai/pull/1131?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [lib/chai/core/assertions.js](https://codecov.io/gh/chaijs/chai/pull/1131/diff?src=pr&el=tree#diff-bGliL2NoYWkvY29yZS9hc3NlcnRpb25zLmpz) | `99.39% <100%> (+0.02%)` | :arrow_up: |
| [lib/chai/utils/overwriteProperty.js](https://codecov.io/gh/chaijs/chai/pull/1131/diff?src=pr&el=tree#diff-bGliL2NoYWkvdXRpbHMvb3ZlcndyaXRlUHJvcGVydHkuanM=) | `90.9% <0%> (-4.55%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/chaijs/chai/pull/1131?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/chaijs/chai/pull/1131?src=pr&el=footer). Last update [eebe484...bbdc3e1](https://codecov.io/gh/chaijs/chai/pull/1131?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

meeber: @asbish Oh nooo we've been foiled again by pizza. Thanks so much for working on this. It's going to be awhile until I can review; working crazy hours this week and then going on vacay next week. I'll try to carve out some time.
asbish: @meeber Thank you so mush for your review!
I have fixed, including the commit of the indentation in assertions.js at 2124
Following your suggestion have made the documentation much clearer and easier to read:smile:
meeber: LGTM! Looking for second review from @chaijs/chai 

Patch:
diff --git a/lib/chai/core/assertions.js b/lib/chai/core/assertions.js
index a7ed337..63db676 100644
--- a/lib/chai/core/assertions.js
+++ b/lib/chai/core/assertions.js
@@ -1103,8 +1103,8 @@ module.exports = function (chai, _) {
    *     expect(2).to.equal(2); // Recommended
    *     expect(2).to.be.above(1); // Not recommended
    *
-   * Add `.lengthOf` earlier in the chain to assert that the value of the
-   * target's `length` property is greater than the given number `n`.
+   * Add `.lengthOf` earlier in the chain to assert that the target's `length`
+   * or `size` is greater than the given number `n`.
    *
    *     expect('foo').to.have.lengthOf(3); // Recommended
    *     expect('foo').to.have.lengthOf.above(2); // Not recommended
@@ -1148,7 +1148,7 @@ module.exports = function (chai, _) {
       , errorMessage
       , shouldThrow = true;
 
-    if (doLength) {
+    if (doLength && objType !== 'map' && objType !== 'set') {
       new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
     }
 
@@ -1168,13 +1168,20 @@ module.exports = function (chai, _) {
     }
 
     if (doLength) {
-      var len = obj.length;
+      var descriptor = 'length'
+        , itemsCount;
+      if (objType === 'map' || objType === 'set') {
+        descriptor = 'size';
+        itemsCount = obj.size;
+      } else {
+        itemsCount = obj.length;
+      }
       this.assert(
-          len > n
-        , 'expected #{this} to have a length above #{exp} but got #{act}'
-        , 'expected #{this} to not have a length above #{exp}'
+          itemsCount > n
+        , 'expected #{this} to have a ' + descriptor + ' above #{exp} but got #{act}'
+        , 'expected #{this} to not have a ' + descriptor + ' above #{exp}'
         , n
-        , len
+        , itemsCount
       );
     } else {
       this.assert(
@@ -1201,9 +1208,8 @@ module.exports = function (chai, _) {
    *     expect(2).to.be.at.least(1); // Not recommended
    *     expect(2).to.be.at.least(2); // Not recommended
    *
-   * Add `.lengthOf` earlier in the chain to assert that the value of the
-   * target's `length` property is greater than or equal to the given number
-   * `n`.
+   * Add `.lengthOf` earlier in the chain to assert that the target's `length`
+   * or `size` is greater than or equal to the given number `n`.
    *
    *     expect('foo').to.have.lengthOf(3); // Recommended
    *     expect('foo').to.have.lengthOf.at.least(2); // Not recommended
@@ -1245,7 +1251,7 @@ module.exports = function (chai, _) {
       , errorMessage
       , shouldThrow = true;
 
-    if (doLength) {
+    if (doLength && objType !== 'map' && objType !== 'set') {
       new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
     }
 
@@ -1265,13 +1271,20 @@ module.exports = function (chai, _) {
     }
 
     if (doLength) {
-      var len = obj.length;
+      var descriptor = 'length'
+        , itemsCount;
+      if (objType === 'map' || objType === 'set') {
+        descriptor = 'size';
+        itemsCount = obj.size;
+      } else {
+        itemsCount = obj.length;
+      }
       this.assert(
-          len >= n
-        , 'expected #{this} to have a length at least #{exp} but got #{act}'
-        , 'expected #{this} to have a length below #{exp}'
+          itemsCount >= n
+        , 'expected #{this} to have a ' + descriptor + ' at least #{exp} but got #{act}'
+        , 'expected #{this} to have a ' + descriptor + ' below #{exp}'
         , n
-        , len
+        , itemsCount
       );
     } else {
       this.assert(
@@ -1296,8 +1309,8 @@ module.exports = function (chai, _) {
    *     expect(1).to.equal(1); // Recommended
    *     expect(1).to.be.below(2); // Not recommended
    *
-   * Add `.lengthOf` earlier in the chain to assert that the value of the
-   * target's `length` property is less than the given number `n`.
+   * Add `.lengthOf` earlier in the chain to assert that the target's `length`
+   * or `size` is less than the given number `n`.
    *
    *     expect('foo').to.have.lengthOf(3); // Recommended
    *     expect('foo').to.have.lengthOf.below(4); // Not recommended
@@ -1341,7 +1354,7 @@ module.exports = function (chai, _) {
       , errorMessage
       , shouldThrow = true;
 
-    if (doLength) {
+    if (doLength && objType !== 'map' && objType !== 'set') {
       new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
     }
 
@@ -1361,13 +1374,20 @@ module.exports = function (chai, _) {
     }
 
     if (doLength) {
-      var len = obj.length;
+      var descriptor = 'length'
+        , itemsCount;
+      if (objType === 'map' || objType === 'set') {
+        descriptor = 'size';
+        itemsCount = obj.size;
+      } else {
+        itemsCount = obj.length;
+      }
       this.assert(
-          len < n
-        , 'expected #{this} to have a length below #{exp} but got #{act}'
-        , 'expected #{this} to not have a length below #{exp}'
+          itemsCount < n
+        , 'expected #{this} to have a ' + descriptor + ' below #{exp} but got #{act}'
+        , 'expected #{this} to not have a ' + descriptor + ' below #{exp}'
         , n
-        , len
+        , itemsCount
       );
     } else {
       this.assert(
@@ -1394,8 +1414,8 @@ module.exports = function (chai, _) {
    *     expect(1).to.be.at.most(2); // Not recommended
    *     expect(1).to.be.at.most(1); // Not recommended
    *
-   * Add `.lengthOf` earlier in the chain to assert that the value of the
-   * target's `length` property is less than or equal to the given number `n`.
+   * Add `.lengthOf` earlier in the chain to assert that the target's `length`
+   * or `size` is less than or equal to the given number `n`.
    *
    *     expect('foo').to.have.lengthOf(3); // Recommended
    *     expect('foo').to.have.lengthOf.at.most(4); // Not recommended
@@ -1437,7 +1457,7 @@ module.exports = function (chai, _) {
       , errorMessage
       , shouldThrow = true;
 
-    if (doLength) {
+    if (doLength && objType !== 'map' && objType !== 'set') {
       new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
     }
 
@@ -1457,13 +1477,20 @@ module.exports = function (chai, _) {
     }
 
     if (doLength) {
-      var len = obj.length;
+      var descriptor = 'length'
+        , itemsCount;
+      if (objType === 'map' || objType === 'set') {
+        descriptor = 'size';
+        itemsCount = obj.size;
+      } else {
+        itemsCount = obj.length;
+      }
       this.assert(
-          len <= n
-        , 'expected #{this} to have a length at most #{exp} but got #{act}'
-        , 'expected #{this} to have a length above #{exp}'
+          itemsCount <= n
+        , 'expected #{this} to have a ' + descriptor + ' at most #{exp} but got #{act}'
+        , 'expected #{this} to have a ' + descriptor + ' above #{exp}'
         , n
-        , len
+        , itemsCount
       );
     } else {
       this.assert(
@@ -1491,9 +1518,9 @@ module.exports = function (chai, _) {
    *     expect(2).to.be.within(2, 3); // Not recommended
    *     expect(2).to.be.within(1, 2); // Not recommended
    *
-   * Add `.lengthOf` earlier in the chain to assert that the value of the
-   * target's `length` property is greater than or equal to the given number
-   * `start`, and less than or equal to the given number `finish`.
+   * Add `.lengthOf` earlier in the chain to assert that the target's `length`
+   * or `size` is greater than or equal to the given number `start`, and less
+   * than or equal to the given number `finish`.
    *
    *     expect('foo').to.have.lengthOf(3); // Recommended
    *     expect('foo').to.have.lengthOf.within(2, 4); // Not recommended
@@ -1537,7 +1564,7 @@ module.exports = function (chai, _) {
           ? start.toUTCString() + '..' + finish.toUTCString()
           : start + '..' + finish;
 
-    if (doLength) {
+    if (doLength && objType !== 'map' && objType !== 'set') {
       new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
     }
 
@@ -1557,11 +1584,18 @@ module.exports = function (chai, _) {
     }
 
     if (doLength) {
-      var len = obj.length;
+      var descriptor = 'length'
+        , itemsCount;
+      if (objType === 'map' || objType === 'set') {
+        descriptor = 'size';
+        itemsCount = obj.size;
+      } else {
+        itemsCount = obj.length;
+      }
       this.assert(
-          len >= start && len <= finish
-        , 'expected #{this} to have a length within ' + range
-        , 'expected #{this} to not have a length within ' + range
+          itemsCount >= start && itemsCount <= finish
+        , 'expected #{this} to have a ' + descriptor + ' within ' + range
+        , 'expected #{this} to not have a ' + descriptor + ' within ' + range
       );
     } else {
       this.assert(
@@ -2009,11 +2043,13 @@ module.exports = function (chai, _) {
   /**
    * ### .lengthOf(n[, msg])
    *
-   * Asserts that the target's `length` property is equal to the given number
+   * Asserts that the target's `length` or `size` is equal to the given number
    * `n`.
    *
    *     expect([1, 2, 3]).to.have.lengthOf(3);
    *     expect('foo').to.have.lengthOf(3);
+   *     expect(new Set([1, 2, 3])).to.have.lengthOf(3);
+   *     expect(new Map([['a', 1], ['b', 2], ['c', 3]])).to.have.lengthOf(3);
    *
    * Add `.not` earlier in the chain to negate `.lengthOf`. However, it's often
    * best to assert that the target's `length` property is equal to its expected
@@ -2069,17 +2105,29 @@ module.exports = function (chai, _) {
   function assertLength (n, msg) {
     if (msg) flag(this, 'message', msg);
     var obj = flag(this, 'object')
+      , objType = _.type(obj).toLowerCase()
       , flagMsg = flag(this, 'message')
-      , ssfi = flag(this, 'ssfi');
-    new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
-    var len = obj.length;
+      , ssfi = flag(this, 'ssfi')
+      , descriptor = 'length'
+      , itemsCount;
+
+    switch (objType) {
+      case 'map':
+      case 'set':
+        descriptor = 'size';
+        itemsCount = obj.size;
+        break;
+      default:
+        new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
+        itemsCount = obj.length;
+    }
 
     this.assert(
-        len == n
-      , 'expected #{this} to have a length of #{exp} but got #{act}'
-      , 'expected #{this} to not have a length of #{act}'
+        itemsCount == n
+      , 'expected #{this} to have a ' + descriptor + ' of #{exp} but got #{act}'
+      , 'expected #{this} to not have a ' + descriptor + ' of #{act}'
       , n
-      , len
+      , itemsCount
     );
   }
 
diff --git a/lib/chai/interface/assert.js b/lib/chai/interface/assert.js
index 5f46c80..9c0ab0a 100644
--- a/lib/chai/interface/assert.js
+++ b/lib/chai/interface/assert.js
@@ -1664,10 +1664,12 @@ module.exports = function (chai, util) {
   /**
    * ### .lengthOf(object, length, [message])
    *
-   * Asserts that `object` has a `length` property with the expected value.
+   * Asserts that `object` has a `length` or `size` with the expected value.
    *
    *     assert.lengthOf([1,2,3], 3, 'array has length of 3');
    *     assert.lengthOf('foobar', 6, 'string has length of 6');
+   *     assert.lengthOf(new Set([1,2,3]), 3, 'set has size of 3');
+   *     assert.lengthOf(new Map([['a',1],['b',2],['c',3]]), 3, 'map has size of 3');
    *
    * @name lengthOf
    * @param {Mixed} object


Test patch:
diff --git a/test/assert.js b/test/assert.js
index 10e1621..934d8d9 100644
--- a/test/assert.js
+++ b/test/assert.js
@@ -1388,6 +1388,34 @@ describe('assert', function () {
     err(function () {
       assert.lengthOf(1, 5);
      }, "expected 1 to have property \'length\'");
+
+    if (typeof Map === 'function') {
+      assert.lengthOf(new Map, 0);
+
+      var map = new Map;
+      map.set('a', 1);
+      map.set('b', 2);
+
+      assert.lengthOf(map, 2);
+
+      err(function(){
+        assert.lengthOf(map, 3, 'blah');
+      }, "blah: expected {} to have a size of 3 but got 2");
+    }
+
+    if (typeof Set === 'function') {
+      assert.lengthOf(new Set, 0);
+
+      var set = new Set;
+      set.add(1);
+      set.add(2);
+
+      assert.lengthOf(set, 2);
+
+      err(function(){
+        assert.lengthOf(set, 3, 'blah');
+      }, "blah: expected {} to have a size of 3 but got 2");
+    }
   });
 
   it('match', function () {
diff --git a/test/expect.js b/test/expect.js
index 062f803..3a33f7f 100644
--- a/test/expect.js
+++ b/test/expect.js
@@ -558,6 +558,48 @@ describe('expect', function () {
     err(function () {
       expect(1).to.have.lengthOf.within(5, 7, 'blah');
     }, "blah: expected 1 to have property 'length'");
+
+    if (typeof Map === 'function') {
+      expect(new Map).to.have.length.within(0, 0);
+      expect(new Map).to.have.lengthOf.within(0, 0);
+
+      var map = new Map;
+      map.set('a', 1);
+      map.set('b', 2);
+      map.set('c', 3);
+
+      expect(map).to.have.length.within(2, 4);
+      expect(map).to.have.lengthOf.within(2, 4);
+
+      err(function () {
+        expect(map).to.have.length.within(5, 7, 'blah');
+      }, "blah: expected {} to have a size within 5..7");
+
+      err(function () {
+        expect(map).to.have.lengthOf.within(5, 7, 'blah');
+      }, "blah: expected {} to have a size within 5..7");
+    }
+
+    if (typeof Set === 'function') {
+      expect(new Set).to.have.length.within(0, 0);
+      expect(new Set).to.have.lengthOf.within(0, 0);
+
+      var set = new Set;
+      set.add(1);
+      set.add(2);
+      set.add(3);
+
+      expect(set).to.have.length.within(2, 4);
+      expect(set).to.have.lengthOf.within(2, 4);
+
+      err(function () {
+        expect(set).to.have.length.within(5, 7, 'blah');
+      }, "blah: expected {} to have a size within 5..7");
+
+      err(function () {
+        expect(set).to.have.lengthOf.within(5, 7, 'blah');
+      }, "blah: expected {} to have a size within 5..7");
+    }
   });
 
   it('within(start, finish) (dates)', function(){
@@ -691,6 +733,48 @@ describe('expect', function () {
     err(function () {
       expect(1).to.have.lengthOf.above(0, 'blah');
     }, "blah: expected 1 to have property 'length'");
+
+    if (typeof Map === 'function') {
+      expect(new Map).to.have.length.above(-1);
+      expect(new Map).to.have.lengthOf.above(-1);
+
+      var map = new Map;
+      map.set('a', 1);
+      map.set('b', 2);
+      map.set('c', 3);
+
+      expect(map).to.have.length.above(2);
+      expect(map).to.have.lengthOf.above(2);
+
+      err(function () {
+        expect(map).to.have.length.above(5, 'blah');
+      }, "blah: expected {} to have a size above 5 but got 3");
+
+      err(function () {
+        expect(map).to.have.lengthOf.above(5, 'blah');
+      }, "blah: expected {} to have a size above 5 but got 3");
+    }
+
+    if (typeof Set === 'function') {
+      expect(new Set).to.have.length.above(-1);
+      expect(new Set).to.have.lengthOf.above(-1);
+
+      var set = new Set;
+      set.add(1);
+      set.add(2);
+      set.add(3);
+
+      expect(set).to.have.length.above(2);
+      expect(set).to.have.lengthOf.above(2);
+
+      err(function () {
+        expect(set).to.have.length.above(5, 'blah');
+      }, "blah: expected {} to have a size above 5 but got 3");
+
+      err(function () {
+        expect(set).to.have.lengthOf.above(5, 'blah');
+      }, "blah: expected {} to have a size above 5 but got 3");
+    }
   });
 
   it('above(n) (dates)', function(){
@@ -816,6 +900,48 @@ describe('expect', function () {
     err(function () {
       expect(1).to.have.lengthOf.at.least(0, 'blah');
     }, "blah: expected 1 to have property 'length'");
+
+    if (typeof Map === 'function') {
+      expect(new Map).to.have.length.of.at.least(0);
+      expect(new Map).to.have.lengthOf.at.least(0);
+
+      var map = new Map;
+      map.set('a', 1);
+      map.set('b', 2);
+      map.set('c', 3);
+
+      expect(map).to.have.length.of.at.least(3);
+      expect(map).to.have.lengthOf.at.least(3);
+
+      err(function () {
+        expect(map).to.have.length.of.at.least(4, 'blah');
+      }, "blah: expected {} to have a size at least 4 but got 3");
+
+      err(function () {
+        expect(map).to.have.lengthOf.at.least(4, 'blah');
+      }, "blah: expected {} to have a size at least 4 but got 3");
+    }
+
+    if (typeof Set === 'function') {
+      expect(new Set).to.have.length.of.at.least(0);
+      expect(new Set).to.have.lengthOf.at.least(0);
+
+      var set = new Set;
+      set.add(1);
+      set.add(2);
+      set.add(3);
+
+      expect(set).to.have.length.of.at.least(3);
+      expect(set).to.have.lengthOf.at.least(3);
+
+      err(function () {
+        expect(set).to.have.length.of.at.least(4, 'blah');
+      }, "blah: expected {} to have a size at least 4 but got 3");
+
+      err(function () {
+        expect(set).to.have.lengthOf.at.least(4, 'blah');
+      }, "blah: expected {} to have a size at least 4 but got 3");
+    }
   });
 
   it('below(n)', function(){
@@ -895,6 +1021,48 @@ describe('expect', function () {
     err(function () {
       expect(1).to.have.lengthOf.below(0, 'blah');
     }, "blah: expected 1 to have property 'length'");
+
+    if (typeof Map === 'function') {
+      expect(new Map).to.have.length.below(1);
+      expect(new Map).to.have.lengthOf.below(1);
+
+      var map = new Map;
+      map.set('a', 1);
+      map.set('b', 2);
+      map.set('c', 3);
+
+      expect(map).to.have.length.below(4);
+      expect(map).to.have.lengthOf.below(4);
+
+      err(function () {
+        expect(map).to.have.length.below(2, 'blah');
+      }, "blah: expected {} to have a size below 2 but got 3");
+
+      err(function () {
+        expect(map).to.have.lengthOf.below(2, 'blah');
+      }, "blah: expected {} to have a size below 2 but got 3");
+    }
+
+    if (typeof Set === 'function') {
+      expect(new Set).to.have.length.below(1);
+      expect(new Set).to.have.lengthOf.below(1);
+
+      var set = new Set;
+      set.add(1);
+      set.add(2);
+      set.add(3);
+
+      expect(set).to.have.length.below(4);
+      expect(set).to.have.lengthOf.below(4);
+
+      err(function () {
+        expect(set).to.have.length.below(2, 'blah');
+      }, "blah: expected {} to have a size below 2 but got 3");
+
+      err(function () {
+        expect(set).to.have.lengthOf.below(2, 'blah');
+      }, "blah: expected {} to have a size below 2 but got 3");
+    }
   });
 
   it('below(n) (dates)', function(){
@@ -1024,6 +1192,48 @@ describe('expect', function () {
     err(function () {
       expect(1).to.have.lengthOf.at.most(0, 'blah');
     }, "blah: expected 1 to have property 'length'");
+
+    if (typeof Map === 'function') {
+      expect(new Map).to.have.length.of.at.most(0);
+      expect(new Map).to.have.lengthOf.at.most(0);
+
+      var map = new Map;
+      map.set('a', 1);
+      map.set('b', 2);
+      map.set('c', 3);
+
+      expect(map).to.have.length.of.at.most(3);
+      expect(map).to.have.lengthOf.at.most(3);
+
+      err(function () {
+        expect(map).to.have.length.of.at.most(2, 'blah');
+      }, "blah: expected {} to have a size at most 2 but got 3");
+
+      err(function () {
+        expect(map).to.have.lengthOf.at.most(2, 'blah');
+      }, "blah: expected {} to have a size at most 2 but got 3");
+    }
+
+    if (typeof Set === 'function') {
+      expect(new Set).to.have.length.of.at.most(0);
+      expect(new Set).to.have.lengthOf.at.most(0);
+
+      var set = new Set;
+      set.add(1);
+      set.add(2);
+      set.add(3);
+
+      expect(set).to.have.length.of.at.most(3);
+      expect(set).to.have.lengthOf.at.most(3);
+
+      err(function () {
+        expect(set).to.have.length.of.at.most(2, 'blah');
+      }, "blah: expected {} to have a size at most 2 but got 3");
+
+      err(function () {
+        expect(set).to.have.lengthOf.at.most(2, 'blah');
+      }, "blah: expected {} to have a size at most 2 but got 3");
+    }
   });
 
   it('most(n) (dates)', function(){
@@ -1128,6 +1338,48 @@ describe('expect', function () {
     err(function(){
       expect('asd').to.not.have.lengthOf(3, 'blah');
     }, "blah: expected 'asd' to not have a length of 3");
+
+    if (typeof Map === 'function') {
+      expect(new Map).to.have.length(0);
+      expect(new Map).to.have.lengthOf(0);
+
+      var map = new Map;
+      map.set('a', 1);
+      map.set('b', 2);
+      map.set('c', 3);
+
+      expect(map).to.have.length(3);
+      expect(map).to.have.lengthOf(3);
+
+      err(function(){
+        expect(map).to.not.have.length(3, 'blah');
+      }, "blah: expected {} to not have a size of 3");
+
+      err(function(){
+        expect(map).to.not.have.lengthOf(3, 'blah');
+      }, "blah: expected {} to not have a size of 3");
+    }
+
+    if (typeof Set === 'function') {
+      expect(new Set).to.have.length(0);
+      expect(new Set).to.have.lengthOf(0);
+
+      var set = new Set;
+      set.add(1);
+      set.add(2);
+      set.add(3);
+
+      expect(set).to.have.length(3);
+      expect(set).to.have.lengthOf(3);
+
+      err(function(){
+        expect(set).to.not.have.length(3, 'blah');
+      }, "blah: expected {} to not have a size of 3");
+
+      err(function(){
+        expect(set).to.not.have.lengthOf(3, 'blah');;
+      }, "blah: expected {} to not have a size of 3");
+    }
   });
 
   it('eql(val)', function(){
diff --git a/test/should.js b/test/should.js
index 064c9bc..0bfe44d 100644
--- a/test/should.js
+++ b/test/should.js
@@ -560,6 +560,48 @@ describe('should', function() {
     err(function () {
       (1).should.have.lengthOf.within(5,7, 'blah');
     }, "blah: expected 1 to have property 'length'");
+
+    if (typeof Map === 'function') {
+      (new Map).should.have.length.within(0, 0);
+      (new Map).should.have.lengthOf.within(0, 0);
+
+      var map = new Map;
+      map.set('a', 1);
+      map.set('b', 2);
+      map.set('c', 3);
+
+      map.should.have.length.within(2, 4);
+      map.should.have.lengthOf.within(2, 4);
+
+      err(function () {
+        map.should.have.length.within(5, 7, 'blah');
+      }, "blah: expected {} to have a size within 5..7");
+
+      err(function () {
+        map.should.have.lengthOf.within(5, 7, 'blah');
+      }, "blah: expected {} to have a size within 5..7");
+    }
+
+    if (typeof Set === 'function') {
+      (new Set).should.have.length.within(0, 0);
+      (new Set).should.have.lengthOf.within(0, 0);
+
+      var set = new Set;
+      set.add(1);
+      set.add(2);
+      set.add(3);
+
+      set.should.have.length.within(2, 4);
+      set.should.have.lengthOf.within(2, 4);
+
+      err(function () {
+        set.should.have.length.within(5, 7, 'blah');
+      }, "blah: expected {} to have a size within 5..7");
+
+      err(function () {
+        set.should.have.lengthOf.within(5, 7, 'blah');
+      }, "blah: expected {} to have a size within 5..7");
+    }
   });
 
   it('within(start, finish) (dates)', function(){
@@ -665,6 +707,48 @@ describe('should', function() {
     err(function () {
       (1).should.have.lengthOf.above(0, 'blah');
     }, "blah: expected 1 to have property 'length'");
+
+    if (typeof Map === 'function') {
+      (new Map).should.have.length.above(-1);
+      (new Map).should.have.lengthOf.above(-1);
+
+      var map = new Map;
+      map.set('a', 1);
+      map.set('b', 2);
+      map.set('c', 3);
+
+      map.should.have.length.above(2);
+      map.should.have.lengthOf.above(2);
+
+      err(function () {
+        map.should.have.length.above(5, 'blah');
+      }, "blah: expected {} to have a size above 5 but got 3");
+
+      err(function () {
+        map.should.have.lengthOf.above(5, 'blah');
+      }, "blah: expected {} to have a size above 5 but got 3");
+    }
+
+    if (typeof Set === 'function') {
+      (new Set).should.have.length.above(-1);
+      (new Set).should.have.lengthOf.above(-1);
+
+      var set = new Set;
+      set.add(1);
+      set.add(2);
+      set.add(3);
+
+      set.should.have.length.above(2);
+      set.should.have.lengthOf.above(2);
+
+      err(function () {
+        set.should.have.length.above(5, 'blah');
+      }, "blah: expected {} to have a size above 5 but got 3");
+
+      err(function () {
+        set.should.have.lengthOf.above(5, 'blah');
+      }, "blah: expected {} to have a size above 5 but got 3");
+    }
   });
 
   it('above(n) (dates)', function(){
@@ -745,6 +829,48 @@ describe('should', function() {
     err(function () {
       (1).should.not.be.at.least(null, 'blah');
     }, "blah: the argument to least must be a number");
+
+    if (typeof Map === 'function') {
+      (new Map).should.have.length.of.at.least(0);
+      (new Map).should.have.lengthOf.at.least(0);
+
+      var map = new Map;
+      map.set('a', 1);
+      map.set('b', 2);
+      map.set('c', 3);
+
+      map.should.have.length.of.at.least(3);
+      map.should.have.lengthOf.at.least(3);
+
+      err(function () {
+        map.should.have.length.of.at.least(4, 'blah');
+      }, "blah: expected {} to have a size at least 4 but got 3");
+
+      err(function () {
+        map.should.have.lengthOf.at.least(4, 'blah');
+      }, "blah: expected {} to have a size at least 4 but got 3");
+    }
+
+    if (typeof Set === 'function') {
+      (new Set).should.have.length.of.at.least(0);
+      (new Set).should.have.lengthOf.at.least(0);
+
+      var set = new Set;
+      set.add(1);
+      set.add(2);
+      set.add(3);
+
+      set.should.have.length.of.at.least(3);
+      set.should.have.lengthOf.at.least(3);
+
+      err(function () {
+        set.should.have.length.of.at.least(4, 'blah');
+      }, "blah: expected {} to have a size at least 4 but got 3");
+
+      err(function () {
+        set.should.have.lengthOf.at.least(4, 'blah');
+      }, "blah: expected {} to have a size at least 4 but got 3");
+    }
   });
 
   it('below(n)', function(){
@@ -792,6 +918,48 @@ describe('should', function() {
     err(function () {
       (1).should.have.lengthOf.below(0, 'blah');
     }, "blah: expected 1 to have property 'length'");
+
+    if (typeof Map === 'function') {
+      (new Map).should.have.length.below(1);
+      (new Map).should.have.lengthOf.below(1);
+
+      var map = new Map;
+      map.set('a', 1);
+      map.set('b', 2);
+      map.set('c', 3);
+
+      map.should.have.length.below(4);
+      map.should.have.lengthOf.below(4);
+
+      err(function () {
+        map.should.have.length.below(2, 'blah');
+      }, "blah: expected {} to have a size below 2 but got 3");
+
+      err(function () {
+        map.should.have.lengthOf.below(2, 'blah');
+      }, "blah: expected {} to have a size below 2 but got 3");
+    }
+
+    if (typeof Set === 'function') {
+      (new Set).should.have.length.below(1);
+      (new Set).should.have.lengthOf.below(1);
+
+      var set = new Set;
+      set.add(1);
+      set.add(2);
+      set.add(3);
+
+      set.should.have.length.below(4);
+      set.should.have.lengthOf.below(4);
+
+      err(function () {
+        set.should.have.length.below(2, 'blah');
+      }, "blah: expected {} to have a size below 2 but got 3");
+
+      err(function () {
+        set.should.have.lengthOf.below(2, 'blah');
+      }, "blah: expected {} to have a size below 2 but got 3");
+    }
   });
 
   it('below(n) (dates)', function(){
@@ -880,6 +1048,48 @@ describe('should', function() {
     err(function () {
       (1).should.have.lengthOf.at.most(0, 'blah');
     }, "blah: expected 1 to have property 'length'");
+
+    if (typeof Map === 'function') {
+      (new Map).should.have.length.of.at.most(0);
+      (new Map).should.have.lengthOf.at.most(0);
+
+      var map = new Map;
+      map.set('a', 1);
+      map.set('b', 2);
+      map.set('c', 3);
+
+      map.should.have.length.of.at.most(3);
+      map.should.have.lengthOf.at.most(3);
+
+      err(function () {
+        map.should.have.length.of.at.most(2, 'blah');
+      }, "blah: expected {} to have a size at most 2 but got 3");
+
+      err(function () {
+        map.should.have.lengthOf.at.most(2, 'blah');
+      }, "blah: expected {} to have a size at most 2 but got 3");
+    }
+
+    if (typeof Set === 'function') {
+      (new Set).should.have.length.of.at.most(0);
+      (new Set).should.have.lengthOf.at.most(0);
+
+      var set = new Set;
+      set.add(1);
+      set.add(2);
+      set.add(3);
+
+      set.should.have.length.of.at.most(3);
+      set.should.have.lengthOf.at.most(3);
+
+      err(function () {
+        set.should.have.length.of.at.most(2, 'blah');
+      }, "blah: expected {} to have a size at most 2 but got 3");
+
+      err(function () {
+        set.should.have.lengthOf.at.most(2, 'blah');
+      }, "blah: expected {} to have a size at most 2 but got 3");
+    }
   });
 
   it('most(n) (dates)', function(){
@@ -971,6 +1181,48 @@ describe('should', function() {
     err(function(){
       'asd'.should.not.have.lengthOf(3, 'blah');
     }, "blah: expected 'asd' to not have a length of 3");
+
+    if (typeof Map === 'function') {
+      (new Map).should.have.length(0);
+      (new Map).should.have.lengthOf(0);
+
+      var map = new Map;
+      map.set('a', 1);
+      map.set('b', 2);
+      map.set('c', 3);
+
+      map.should.have.length(3);
+      map.should.have.lengthOf(3);
+
+      err(function(){
+        map.should.not.have.length(3, 'blah');
+      }, "blah: expected {} to not have a size of 3");
+
+      err(function(){
+        map.should.not.have.lengthOf(3, 'blah');
+      }, "blah: expected {} to not have a size of 3");
+    }
+
+    if (typeof Set === 'function') {
+      (new Set).should.have.length(0);
+      (new Set).should.have.lengthOf(0);
+
+      var set = new Set;
+      set.add(1);
+      set.add(2);
+      set.add(3);
+
+      set.should.have.length(3);
+      set.should.have.lengthOf(3);
+
+      err(function(){
+        set.should.not.have.length(3, 'blah');
+      }, "blah: expected {} to not have a size of 3");
+
+      err(function(){
+        set.should.not.have.lengthOf(3, 'blah');;
+      }, "blah: expected {} to not have a size of 3");
+    }
   });
 
   it('eql(val)', function(){