[Pkg-javascript-commits] [node-deep-eql] 01/04: Imported Upstream version 1.0.0

Sruthi Chandran srud-guest at moszumanska.debian.org
Wed Oct 12 18:02:36 UTC 2016


This is an automated email from the git hooks/post-receive script.

srud-guest pushed a commit to branch master
in repository node-deep-eql.

commit a572597a6467cd2417184640146d2d83cc827586
Author: Syam G Krishnan <sgk at riseup.net>
Date:   Tue Oct 11 22:40:15 2016 +0530

    Imported Upstream version 1.0.0
---
 .gitignore                   |  21 ++
 .travis.yml                  |  29 ++
 LICENSE                      |  19 ++
 README.md                    | 104 +++++++
 bench/.eslintrc              |  17 ++
 bench/index.js               | 125 +++++++++
 component.json               |  19 ++
 index.js                     | 425 ++++++++++++++++++++++++++++
 karma.conf.js                |  96 +++++++
 package.json                 |  88 ++++++
 test/.eslintrc               |  19 ++
 test/index.js                | 455 ++++++++++++++++++++++++++++++
 test/new-ecmascript-types.js | 651 +++++++++++++++++++++++++++++++++++++++++++
 13 files changed, 2068 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a7fb08c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,21 @@
+lib-cov
+*.seed
+*.log
+*.csv
+*.dat
+*.out
+*.pid
+*.gz
+
+pids
+logs
+results
+build
+components
+
+node_modules
+npm-debug.log
+
+coverage/
+
+deep-eql.js
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..852354b
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,29 @@
+sudo: false
+language: node_js
+addons:
+  sauce_connect: true
+cache:
+  directories:
+  - node_modules
+node_js:
+ - 0.10 # to be removed 2016-10-31
+ - 0.12 # to be removed 2016-12-31
+ - 4 # to be removed 2018-04-01
+ - 6 # to be removed 2019-04-01
+ - lts/* # safety net; don't remove
+ - node # safety net; don't remove
+before_install:
+- npm i -g npm
+script:
+- npm t
+after_success:
+- npm run upload-coverage
+- travis-after-all && npm run semantic-release
+env:
+  global:
+  - SAUCE_CONNECT_READY_FILE=/tmp/sauce-connect-ready
+  - LOGS_DIR=/tmp/chai-build/logs
+  - secure: fOmukdZc9lwl/tfer01TAoPCcpafNbr1ZvUnjKmiP/r1cC2RWpF1JlYITtioLlvadzCTwi88SBzQLIi1/qCSao7vSsup5oC05brgUOR9uD7VE9IfIpyV5bthT/sX3IKNeIFKlow4H1f8RLlweqtor5AyHlG5cXOJybQMyAAfkWo=
+  - secure: XC9Uz7J9Yflf7NuSFAkWq2yb3UksnKe83l3npLhYWN/uNk74ukh1z3o+OcJ4ujNsMx+/AcKjlJPmu8ghrjxCo6ocWBNz2+TR2UOZjukS96BOAOvOTgJqEv6nGW7HNVhpDYZEPbhM2d67UnoAX3aZFDZdug2EHD2GFJYYD7LZpnM=
+  - secure: LsutIKfCxltpyJSW0h+L8EDQYC+Rh7w48ZBbbJq+jS19ejQTPfojvvw5NcucpNh0P+x27PikRGKNOAAUuPqZSA9l9OFPoPVxgUI8r8E7Kl6D0pi6hCz5bX+dG0VaI078GpaflsyOVjiiW844sR7IXpP1w3GP2fI1DBXOBUbsWNQ=
+  - secure: EqyK5QPQZ7eHu7RbRjj/1MJywBbsn7EiJXHm9jjDnsuLkMEhrBdV5bYsIEDIROIsOSl8OBw208rrIUNO73aSvfQgkCJMN3Mtjfqh/Yn1We90k0Gy9KZMsiheD/3qjsOQxQPludlU58EDlEItTVLb2Clfs7Qfv7M5p3xl54OCaN8=
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..7ea799f
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2013 Jake Luer <jake at alogicalparadox.com> (http://alogicalparadox.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d48520e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,104 @@
+<h1 align=center>
+  <a href="http://chaijs.com" title="Chai Documentation">
+    <img alt="ChaiJS" src="http://chaijs.com/img/chai-logo.png"/> deep-eql
+  </a>
+</h1>
+
+<p align=center>
+  Improved deep equality testing for [node](http://nodejs.org) and the browser.
+</p>
+
+<p align=center>
+  <a href="./LICENSE">
+    <img
+      alt="license:mit"
+      src="https://img.shields.io/badge/license-mit-green.svg?style=flat-square"
+    />
+  </a><a href="https://github.com/chaijs/deep-eql/releases">
+    <img
+      alt="tag:?"
+      src="https://img.shields.io/github/tag/chaijs/deep-eql.svg?style=flat-square"
+    />
+  </a><a href="https://travis-ci.org/chaijs/deep-eql">
+    <img
+      alt="build:?"
+      src="https://img.shields.io/travis/chaijs/deep-eql/master.svg?style=flat-square"
+    />
+  </a><a href="https://coveralls.io/r/chaijs/deep-eql">
+    <img
+      alt="coverage:?"
+      src="https://img.shields.io/coveralls/chaijs/deep-eql/master.svg?style=flat-square"
+    />
+  </a><a href="https://www.npmjs.com/packages/deep-eql">
+    <img
+      alt="code quality:?"
+      src="https://img.shields.io/codacy/6de187aa62274dbea6e69a3c27e798da.svg?style=flat-square"
+    />
+  </a><a href="https://www.npmjs.com/packages/deep-eql">
+    <img
+      alt="dependencies:?"
+      src="https://img.shields.io/npm/dm/deep-eql.svg?style=flat-square"
+    />
+  </a><a href="">
+    <img
+      alt="devDependencies:?"
+      src="https://img.shields.io/david/chaijs/deep-eql.svg?style=flat-square"
+    />
+  </a>
+  <br/>
+  <a href="https://saucelabs.com/u/chaijs-deep-eql">
+    <img
+      alt="Selenium Test Status"
+      src="https://saucelabs.com/browser-matrix/chaijs-deep-eql.svg"
+    />
+  </a>
+  <br>
+  <a href="https://chai-slack.herokuapp.com/">
+    <img
+      alt="Join the Slack chat"
+      src="https://img.shields.io/badge/slack-join%20chat-E2206F.svg?style=flat-square"
+    />
+  </a>
+  <a href="https://gitter.im/chaijs/deep-eql">
+    <img
+      alt="Join the Gitter chat"
+      src="https://img.shields.io/badge/gitter-join%20chat-D0104D.svg?style=flat-square"
+    />
+  </a>
+</p>
+
+## What is Deep-Eql?
+
+Deep Eql is a module which you can use to determine if two objects are "deeply" equal - that is, rather than having referential equality (`a === b`), this module checks an object's keys recursively, until it finds primitives to check for referential equality. For more on equality in JavaScript, read [the comparison operators article on mdn](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators).
+
+As an example, take the following:
+
+```js
+1 === 1 // These are primitives, they hold the same reference - they are strictly equal
+1 == '1' // These are two different primitives, through type coercion they hold the same value - they are loosely equal
+{ a: 1 } !== { a: 1 } // These are two different objects, they hold different references and so are not strictly equal - even though they hold the same values inside
+{ a: 1 } != { a: 1 } // They have the same type, meaning loose equality performs the same check as strict equality - they are still not equal.
+
+deepEql({ a: 1 }, { a: 1 }) === true // deepEql can determine that they share the same keys and those keys share the same values, therefore they are deeply equal!
+```
+
+## Installation
+
+### Node.js
+
+`deep-eql` is available on [npm](http://npmjs.org).
+
+    $ npm install deep-eql
+
+## Usage
+
+The primary export of `deep-eql` is function that can be given two objects to compare. It will always return a boolean which can be used to determine if two objects are deeply equal.
+
+### Rules
+
+- Strict equality for non-traversable nodes according to [egal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
+  - `eql(NaN, NaN).should.be.true;`
+  - `eql(-0, +0).should.be.false;`
+- Arguments are not Arrays:
+  - `eql([], arguments).should.be.false;`
+  - `eql([], Array.prototype.slice.call(arguments)).should.be.true;`
diff --git a/bench/.eslintrc b/bench/.eslintrc
new file mode 100644
index 0000000..acc6682
--- /dev/null
+++ b/bench/.eslintrc
@@ -0,0 +1,17 @@
+{
+  "extends": [ "strict/test" ],
+  "env": {
+    "node": true,
+    "browser": true,
+    "es6": true
+  },
+  "rules": {
+    "no-new-wrappers": 0,
+    "no-array-constructor": 0,
+    "no-new-object": 0,
+    "no-empty-function": 0,
+    "no-undefined": 0,
+    "no-console": 0,
+    "id-length": 0
+  }
+}
diff --git a/bench/index.js b/bench/index.js
new file mode 100644
index 0000000..72699a7
--- /dev/null
+++ b/bench/index.js
@@ -0,0 +1,125 @@
+'use strict';
+var deepEql = require('../');
+var lodashDeepEql = require('lodash.isequal');
+var assertDeepeql = require('assert').deepEql;
+var kewlrDeepeql = require('kewlr').chai;
+var inspect = require('util').inspect;
+var Benchmark = require('benchmark');
+var benches = [];
+var mapObjRefA = {};
+var mapObjRefB = {};
+function getArguments() {
+  return arguments;
+}
+var fixtures = {
+  'equal references           ': [ mapObjRefA, mapObjRefA ],
+  'string literal             ': [ 'abc', 'abc' ],
+  'array literal              ': [ [ 1, 2, 3 ], [ 1, 2, 3 ] ],
+  'boolean literal            ': [ true, true ],
+  'object literal             ': [ { a: 1 }, { a: 1 } ],
+  'object from null           ': [ Object.create(null), Object.create(null) ],
+  'regex literal              ': [ /^abc$/, /^abc$/ ],
+  'number literal             ': [ 1, 1 ],
+  'null                       ': [ null, null ],
+  'undefined                  ': [ undefined, undefined ],
+  'buffer                     ': [ new Buffer('hello world'), new Buffer('hello world') ],
+  'date                       ': [ new Date(123), new Date(123) ],
+  'map                        ': [ new Map().set('a', 1), new Map().set('a', 1) ],
+  'map (complex)              ': [
+    new Map().set(mapObjRefA, new Map().set(mapObjRefB, 1)),
+    new Map().set(mapObjRefA, new Map().set(mapObjRefB, 1)),
+  ],
+  'regex constructor          ': [ new RegExp('abc'), new RegExp('abc') ],
+  'set                        ': [ new Set().add(1), new Set().add(1) ],
+  'string constructor         ': [ new String(), new String() ],
+  'arguments                  ': [ getArguments(1, 2, 3), getArguments(1, 2, 3) ],
+
+  /* Failing benchmarks */
+  'string literal (differing) ': [ 'abc', 'cba', false ],
+  'array literal (differing)  ': [ [ 1, 2, 3 ], [ 4, 5, 6 ], false ],
+  'boolean literal (differing)': [ true, false, false ],
+  'object literal (differing) ': [ { a: 1 }, { a: 2 }, false ],
+  'regex literal (differing)  ': [ /^abc$/, /^def$/, false ],
+  'number literal (differing) ': [ 1, 2, false ],
+  'null & undefined           ': [ null, undefined, false ],
+  'buffer (differing)         ': [ new Buffer(123), new Buffer(456), false ],
+  'date (differing)           ': [ new Date(123), new Date(456), false ],
+  'error                      ': [ new Error(''), new Error(''), false ],
+  'map (differing)            ': [ new Map().set('a', 1), new Map().set('a', 2), false ],
+  'regex ctor (differing)     ': [ new RegExp('abc'), new RegExp('def'), false ],
+  'set (differing)            ': [ new Set().add(1), new Set().add(2), false ],
+  'string ctor (differing)    ': [ new String('abc'), new String('def'), false ],
+  'weakmap                    ': [ new WeakMap(), new WeakMap(), false ],
+  'weakset                    ': [ new WeakSet(), new WeakSet(), false ],
+  'arguments (differing)      ': [ getArguments(1, 2, 3), getArguments(4, 5, 6), false ],
+  'function                   ': [ function () {}, function () {}, false ],
+  'promise                    ': [ Promise.resolve(), Promise.resolve(), false ],
+};
+try {
+  fixtures['arrow function (differing) '] = [
+    eval('() => {}'), // eslint-disable-line no-eval
+    eval('() => {}'), // eslint-disable-line no-eval
+    false,
+  ];
+} catch (error) {
+  console.error('cannot benchmark arrow functions');
+}
+try {
+  fixtures['generator func (differing) '] = [
+    eval('function * generator() {}; generator'), // eslint-disable-line no-eval
+    eval('function * generator() {}; generator'), // eslint-disable-line no-eval
+    false,
+  ];
+} catch (error) {
+  console.error('cannot benchmark generator functions');
+}
+
+function prepareBenchMark(test, name, assert) {
+  assert = assert || deepEql;
+  var leftHand = test[0];
+  var rightHand = test[1];
+  var expectedResult = Boolean(2 in test ? test[2] : true);
+  var invocationString = 'deepEql(' + inspect(leftHand) + ', ' + inspect(rightHand) + ') === ' + expectedResult;
+  benches.push(new Benchmark(name, {
+    fn: function () {
+      if (assert(leftHand, rightHand) !== expectedResult) {
+        throw new Error('failing test: ' + invocationString);
+      }
+    },
+    onCycle: function (event) {
+      process.stdout.clearLine();
+      process.stdout.cursorTo(0);
+      process.stdout.write(event.target.toString());
+    },
+  }));
+}
+
+var filter = process.argv.slice(2).filter(function (arg) {
+  return arg[0] !== '-';
+})[0] || '';
+var lodash = process.argv.indexOf('--lodash') !== -1;
+var nodeassert = process.argv.indexOf('--nodeassert') !== -1;
+var kewlr = process.argv.indexOf('--kewlr') !== -1;
+Object.keys(fixtures).filter(function (key) {
+  return key.indexOf(filter) !== -1;
+}).forEach(function (testName) {
+  prepareBenchMark(fixtures[testName], testName + '         ');
+  if (lodash) {
+    prepareBenchMark(fixtures[testName], testName + ' (lodash)', lodashDeepEql);
+  }
+  if (nodeassert) {
+    prepareBenchMark(fixtures[testName], testName + '   (node)', assertDeepeql);
+  }
+  if (kewlr) {
+    prepareBenchMark(fixtures[testName], testName + '  (kewlr)', kewlrDeepeql);
+  }
+});
+Benchmark.invoke(benches, {
+  name: 'run',
+  onCycle: function onCycle() {
+    console.log('');
+  },
+  onComplete: function onComplete() {
+    console.log('~Fin~');
+  },
+});
diff --git a/component.json b/component.json
new file mode 100644
index 0000000..f97f1a1
--- /dev/null
+++ b/component.json
@@ -0,0 +1,19 @@
+{
+    "name": "deep-eql"
+  , "repo": "chaijs/deep-eql"
+  , "version": "0.1.3"
+  , "description": "Improved deep equality testing for Node.js and the browser."
+  , "license": "MIT"
+  , "keywords": [
+    ]
+  , "main": "lib/eql.js"
+  , "scripts": [
+        "lib/eql.js"
+    ]
+  , "dependencies": {
+        "chaijs/type-detect": "0.1.1"
+    }
+  , "development": {
+        "chaijs/simple-assert": "1.0.0"
+    }
+}
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..81ee234
--- /dev/null
+++ b/index.js
@@ -0,0 +1,425 @@
+'use strict';
+/* globals Symbol: true, Uint8Array: true, WeakMap: true */
+/*!
+ * deep-eql
+ * Copyright(c) 2013 Jake Luer <jake at alogicalparadox.com>
+ * MIT Licensed
+ */
+
+/*!
+ * Module dependencies
+ */
+
+var type = require('type-detect');
+function FakeMap() {
+  this.clear();
+}
+FakeMap.prototype = {
+  clear: function clearMap() {
+    this.keys = [];
+    this.values = [];
+    return this;
+  },
+  set: function setMap(key, value) {
+    var index = this.keys.indexOf(key);
+    if (index >= 0) {
+      this.values[index] = value;
+    } else {
+      this.keys.push(key);
+      this.values.push(value);
+    }
+    return this;
+  },
+  get: function getMap(key) {
+    return this.values[this.keys.indexOf(key)];
+  },
+  delete: function deleteMap(key) {
+    var index = this.keys.indexOf(key);
+    if (index >= 0) {
+      this.values = this.values.slice(0, index).concat(this.values.slice(index + 1));
+      this.keys = this.keys.slice(0, index).concat(this.keys.slice(index + 1));
+    }
+    return this;
+  },
+};
+
+var MemoizeMap = null;
+if (typeof WeakMap === 'function') {
+  MemoizeMap = WeakMap;
+} else {
+  MemoizeMap = FakeMap;
+}
+
+/*!
+ * Check to see if the MemoizeMap has recorded a result of the two operands
+ *
+ * @param {Mixed} leftHandOperand
+ * @param {Mixed} rightHandOperand
+ * @param {MemoizeMap} memoizeMap
+ * @returns {Boolean|null} result
+*/
+function memoizeCompare(leftHandOperand, rightHandOperand, memoizeMap) {
+  if (!memoizeMap) {
+    return null;
+  }
+  var leftHandMap = memoizeMap.get(leftHandOperand);
+  if (leftHandMap) {
+    var result = leftHandMap.get(rightHandOperand);
+    if (typeof result === 'boolean') {
+      return result;
+    }
+  }
+  return null;
+}
+
+/*!
+ * Set the result of the equality into the MemoizeMap
+ *
+ * @param {Mixed} leftHandOperand
+ * @param {Mixed} rightHandOperand
+ * @param {MemoizeMap} memoizeMap
+ * @param {Boolean} result
+*/
+function memoizeSet(leftHandOperand, rightHandOperand, memoizeMap, result) {
+  if (!memoizeMap || typeof leftHandOperand !== 'object' || typeof rightHandOperand !== 'object') {
+    return;
+  }
+  var leftHandMap = memoizeMap.get(leftHandOperand);
+  if (leftHandMap) {
+    leftHandMap.set(rightHandOperand, result);
+  } else {
+    leftHandMap = new MemoizeMap();
+    leftHandMap.set(rightHandOperand, result);
+    memoizeMap.set(leftHandOperand, leftHandMap);
+  }
+}
+
+/*!
+ * Primary Export
+ */
+
+module.exports = deepEqual;
+module.exports.MemoizeMap = MemoizeMap;
+
+/**
+ * Assert deeply nested sameValue equality between two objects of any type.
+ *
+ * @param {Mixed} leftHandOperand
+ * @param {Mixed} rightHandOperand
+ * @param {Object} [options] (optional) Additional options
+ * @param {Array} [options.comparator] (optional) Override default algorithm, determining custom equality.
+ * @param {Array} [options.memoize] (optional) Provide a custom memoization object which will cache the results of
+    complex objects for a speed boost. By passing `false` you can disable memoization, but this will cause circular
+    references to blow the stack.
+ * @return {Boolean} equal match
+ */
+function deepEqual(leftHandOperand, rightHandOperand, options) {
+  // Equal references (except for Numbers) can be returned early
+  if (leftHandOperand === rightHandOperand) {
+    // Handle +-0 cases
+    return leftHandOperand !== 0 || 1 / leftHandOperand === 1 / rightHandOperand;
+  }
+
+  // handle NaN cases
+  if (
+    leftHandOperand !== leftHandOperand && // eslint-disable-line no-self-compare
+    rightHandOperand !== rightHandOperand // eslint-disable-line no-self-compare
+  ) {
+    return true;
+  }
+
+  // Primitives/null/undefined can be checked for referential equality; returning early
+  if (
+    typeof leftHandOperand !== 'object' ||
+    leftHandOperand === null ||
+    leftHandOperand === undefined // eslint-disable-line no-undefined
+  ) {
+    return leftHandOperand === rightHandOperand;
+  }
+
+  // Deeper comparisons are pushed through to a larger function
+  return extensiveDeepEqual(leftHandOperand, rightHandOperand, options);
+}
+
+/*!
+ * The main logic of the `deepEqual` function.
+ *
+ * @param {Mixed} leftHandOperand
+ * @param {Mixed} rightHandOperand
+ * @param {Object} [options] (optional) Additional options
+ * @param {Array} [options.comparator] (optional) Override default algorithm, determining custom equality.
+ * @param {Array} [options.memoize] (optional) Provide a custom memoization object which will cache the results of
+    complex objects for a speed boost. By passing `false` you can disable memoization, but this will cause circular
+    references to blow the stack.
+ * @return {Boolean} equal match
+*/
+function extensiveDeepEqual(leftHandOperand, rightHandOperand, options) {
+  options = options || {};
+  options.memoize = options.memoize === false ? false : options.memoize || new MemoizeMap();
+  var comparator = options && options.comparator;
+
+  var memoizeResult = memoizeCompare(leftHandOperand, rightHandOperand, options.memoize);
+  if (memoizeResult !== null) {
+    return memoizeResult;
+  }
+
+  var comparatorResult = comparator && comparator(leftHandOperand, rightHandOperand);
+  if (comparatorResult === false || comparatorResult === true) {
+    memoizeSet(leftHandOperand, rightHandOperand, options.memoize, comparatorResult);
+    memoizeSet(rightHandOperand, leftHandOperand, options.memoize, comparatorResult);
+    return comparatorResult;
+  }
+
+  var leftHandType = type(leftHandOperand);
+  if (leftHandType !== type(rightHandOperand)) {
+    memoizeSet(leftHandOperand, rightHandOperand, options.memoize, false);
+    memoizeSet(rightHandOperand, leftHandOperand, options.memoize, false);
+    return false;
+  }
+
+  // Temporarily set the operands in the memoize object to prevent blowing the stack
+  memoizeSet(leftHandOperand, rightHandOperand, options.memoize, false);
+  memoizeSet(rightHandOperand, leftHandOperand, options.memoize, false);
+
+  var result = extensiveDeepEqualByType(leftHandOperand, rightHandOperand, leftHandType, options);
+  memoizeSet(leftHandOperand, rightHandOperand, options.memoize, result);
+  memoizeSet(rightHandOperand, leftHandOperand, options.memoize, result);
+  return result;
+}
+
+function extensiveDeepEqualByType(leftHandOperand, rightHandOperand, leftHandType, options) {
+  switch (leftHandType) {
+    case 'String':
+    case 'Number':
+    case 'Boolean':
+    case 'Date':
+      // If these types are their instance types (e.g. `new Number`) then re-deepEqual against their values
+      return deepEqual(leftHandOperand.valueOf(), rightHandOperand.valueOf());
+    case 'Promise':
+    case 'Symbol':
+    case 'function':
+    case 'WeakMap':
+    case 'WeakSet':
+    case 'Error':
+      return leftHandOperand === rightHandOperand;
+    case 'Arguments':
+    case 'Int8Array':
+    case 'Uint8Array':
+    case 'Uint8ClampedArray':
+    case 'Int16Array':
+    case 'Uint16Array':
+    case 'Int32Array':
+    case 'Uint32Array':
+    case 'Float32Array':
+    case 'Float64Array':
+    case 'Array':
+      return iterableEqual(leftHandOperand, rightHandOperand, options);
+    case 'RegExp':
+      return regexpEqual(leftHandOperand, rightHandOperand);
+    case 'Generator':
+      return generatorEqual(leftHandOperand, rightHandOperand, options);
+    case 'DataView':
+      return iterableEqual(new Uint8Array(leftHandOperand.buffer), new Uint8Array(rightHandOperand.buffer), options);
+    case 'ArrayBuffer':
+      return iterableEqual(new Uint8Array(leftHandOperand), new Uint8Array(rightHandOperand), options);
+    case 'Set':
+      return entriesEqual(leftHandOperand, rightHandOperand, options);
+    case 'Map':
+      return entriesEqual(leftHandOperand, rightHandOperand, options);
+    default:
+      return objectEqual(leftHandOperand, rightHandOperand, options);
+  }
+}
+
+/*!
+ * Compare two Regular Expressions for equality.
+ *
+ * @param {RegExp} leftHandOperand
+ * @param {RegExp} rightHandOperand
+ * @return {Boolean} result
+ */
+
+function regexpEqual(leftHandOperand, rightHandOperand) {
+  return leftHandOperand.toString() === rightHandOperand.toString();
+}
+
+/*!
+ * Compare two Sets/Maps for equality. Faster than other equality functions.
+ *
+ * @param {Set} leftHandOperand
+ * @param {Set} rightHandOperand
+ * @param {Object} [options] (Optional)
+ * @return {Boolean} result
+ */
+
+function entriesEqual(leftHandOperand, rightHandOperand, options) {
+  // IE11 doesn't support Set#entries or Set#@@iterator, so we need manually populate using Set#forEach
+  if (leftHandOperand.size !== rightHandOperand.size) {
+    return false;
+  }
+  if (leftHandOperand.size === 0) {
+    return true;
+  }
+  var leftHandItems = [];
+  var rightHandItems = [];
+  leftHandOperand.forEach(function gatherEntries(key, value) {
+    leftHandItems.push([ key, value ]);
+  });
+  rightHandOperand.forEach(function gatherEntries(key, value) {
+    rightHandItems.push([ key, value ]);
+  });
+  return iterableEqual(leftHandItems.sort(), rightHandItems.sort(), options);
+}
+
+/*!
+ * Simple equality for flat iterable objects such as Arrays, TypedArrays or Node.js buffers.
+ *
+ * @param {Iterable} leftHandOperand
+ * @param {Iterable} rightHandOperand
+ * @param {Object} [options] (Optional)
+ * @return {Boolean} result
+ */
+
+function iterableEqual(leftHandOperand, rightHandOperand, options) {
+  var length = leftHandOperand.length;
+  if (length !== rightHandOperand.length) {
+    return false;
+  }
+  if (length === 0) {
+    return true;
+  }
+  var index = -1;
+  while (++index < length) {
+    if (deepEqual(leftHandOperand[index], rightHandOperand[index], options) === false) {
+      return false;
+    }
+  }
+  return true;
+}
+
+/*!
+ * Simple equality for generator objects such as those returned by generator functions.
+ *
+ * @param {Iterable} leftHandOperand
+ * @param {Iterable} rightHandOperand
+ * @param {Object} [options] (Optional)
+ * @return {Boolean} result
+ */
+
+function generatorEqual(leftHandOperand, rightHandOperand, options) {
+  return iterableEqual(getGeneratorEntries(leftHandOperand), getGeneratorEntries(rightHandOperand), options);
+}
+
+/*!
+ * Determine if the given object has an @@iterator function.
+ *
+ * @param {Object} target
+ * @return {Boolean} `true` if the object has an @@iterator function.
+ */
+function hasIteratorFunction(target) {
+  return typeof Symbol !== 'undefined' &&
+    typeof target === 'object' &&
+    typeof Symbol.iterator !== 'undefined' &&
+    typeof target[Symbol.iterator] === 'function';
+}
+
+/*!
+ * Gets all iterator entries from the given Object. If the Object has no @@iterator function, returns an empty array.
+ * This will consume the iterator - which could have side effects depending on the @@iterator implementation.
+ *
+ * @param {Object} target
+ * @returns {Array} an array of entries from the @@iterator function
+ */
+function getIteratorEntries(target) {
+  if (hasIteratorFunction(target)) {
+    try {
+      return getGeneratorEntries(target[Symbol.iterator]());
+    } catch (iteratorError) {
+      return [];
+    }
+  }
+  return [];
+}
+
+/*!
+ * Gets all entries from a Generator. This will consume the generator - which could have side effects.
+ *
+ * @param {Generator} target
+ * @returns {Array} an array of entries from the Generator.
+ */
+function getGeneratorEntries(generator) {
+  var generatorResult = generator.next();
+  var accumulator = [ generatorResult.value ];
+  while (generatorResult.done === false) {
+    generatorResult = generator.next();
+    accumulator.push(generatorResult.value);
+  }
+  return accumulator;
+}
+
+/*!
+ * Determines if two objects have matching values, given a set of keys. Defers to deepEqual for the equality check of
+ * each key. If any value of the given key is not equal, the function will return false (early).
+ *
+ * @param {Mixed} leftHandOperand
+ * @param {Mixed} rightHandOperand
+ * @param {Array} keys An array of keys to compare the values of leftHandOperand and rightHandOperand against
+ * @param {Object} [options] (Optional)
+ * @return {Boolean} result
+ */
+function keysEqual(leftHandOperand, rightHandOperand, keys, options) {
+  var length = keys.length;
+  if (length === 0) {
+    return true;
+  }
+  for (var i = 0; i < length; i += 1) {
+    if (deepEqual(leftHandOperand[keys[i]], rightHandOperand[keys[i]], options) === false) {
+      return false;
+    }
+  }
+  return true;
+}
+
+/*!
+ * Recursively check the equality of two Objects. Once basic sameness has been established it will defer to `deepEqual`
+ * for each enumerable key in the object.
+ *
+ * @param {Mixed} leftHandOperand
+ * @param {Mixed} rightHandOperand
+ * @param {Object} [options] (Optional)
+ * @return {Boolean} result
+ */
+
+function objectEqual(leftHandOperand, rightHandOperand, options) {
+  if (Object.getPrototypeOf(leftHandOperand) !== Object.getPrototypeOf(rightHandOperand)) {
+    return false;
+  }
+
+  var leftHandKeys = Object.keys(leftHandOperand);
+  var rightHandKeys = Object.keys(rightHandOperand);
+  if (leftHandKeys.length && leftHandKeys.length === rightHandKeys.length) {
+    leftHandKeys.sort();
+    rightHandKeys.sort();
+    if (iterableEqual(leftHandKeys, rightHandKeys) === false) {
+      return false;
+    }
+    return keysEqual(leftHandOperand, rightHandOperand, leftHandKeys, options);
+  }
+
+  var leftHandEntries = getIteratorEntries(leftHandOperand);
+  var rightHandEntries = getIteratorEntries(rightHandOperand);
+  if (leftHandEntries.length && leftHandEntries.length === rightHandEntries.length) {
+    leftHandEntries.sort();
+    rightHandEntries.sort();
+    return iterableEqual(leftHandEntries, rightHandEntries, options);
+  }
+
+  if (leftHandKeys.length === 0 &&
+      leftHandEntries.length === 0 &&
+      rightHandKeys.length === 0 &&
+      rightHandEntries.length === 0) {
+    return true;
+  }
+
+  return false;
+}
diff --git a/karma.conf.js b/karma.conf.js
new file mode 100644
index 0000000..e7a9848
--- /dev/null
+++ b/karma.conf.js
@@ -0,0 +1,96 @@
+'use strict';
+var packageJson = require('./package.json');
+var defaultTimeout = 120000;
+var browserifyIstanbul = require('browserify-istanbul');
+module.exports = function configureKarma(config) {
+  var localBrowsers = [
+    'PhantomJS',
+  ];
+  var sauceLabsBrowsers = {
+    SauceChromeLatest: {
+      base: 'SauceLabs',
+      browserName: 'Chrome',
+    },
+    SauceFirefoxLatest: {
+      base: 'SauceLabs',
+      browserName: 'Firefox',
+    },
+    SauceSafariLatest: {
+      base: 'SauceLabs',
+      browserName: 'Safari',
+      platform: 'OS X 10.11',
+    },
+    SauceInternetExplorerLatest: {
+      base: 'SauceLabs',
+      browserName: 'Internet Explorer',
+    },
+    SauceInternetExplorerOldestSupported: {
+      base: 'SauceLabs',
+      browserName: 'Internet Explorer',
+      version: 9,
+    },
+    SauceEdgeLatest: {
+      base: 'SauceLabs',
+      browserName: 'MicrosoftEdge',
+    },
+    SauceAndroidLatest: {
+      base: 'SauceLabs',
+      browserName: 'Android',
+    },
+  };
+  config.set({
+    basePath: '',
+    browsers: localBrowsers,
+    logLevel: process.env.npm_config_debug ? config.LOG_DEBUG : config.LOG_INFO,
+    frameworks: [ 'browserify', 'mocha' ],
+    files: [ 'test/*.js' ],
+    exclude: [],
+    preprocessors: {
+      'test/*.js': [ 'browserify' ],
+    },
+    browserify: {
+      debug: true,
+      bare: true,
+      transform: [
+        browserifyIstanbul({ ignore: [ '**/node_modules/**', '**/test/**' ] }),
+      ],
+    },
+    reporters: [ 'progress', 'coverage' ],
+    coverageReporter: {
+      type: 'lcov',
+      dir: 'coverage',
+    },
+    port: 9876,
+    colors: true,
+    concurrency: 3,
+    autoWatch: false,
+    captureTimeout: defaultTimeout,
+    browserDisconnectTimeout: defaultTimeout,
+    browserNoActivityTimeout: defaultTimeout,
+    singleRun: true,
+  });
+
+  if (process.env.SAUCE_ACCESS_KEY && process.env.SAUCE_USERNAME) {
+    var branch = process.env.TRAVIS_BRANCH || 'local';
+    var build = 'localbuild';
+    if (process.env.TRAVIS_JOB_NUMBER) {
+      build = 'travis@' + process.env.TRAVIS_JOB_NUMBER;
+    }
+    config.reporters.push('saucelabs');
+    config.set({
+      customLaunchers: sauceLabsBrowsers,
+      browsers: localBrowsers.concat(Object.keys(sauceLabsBrowsers)),
+      sauceLabs: {
+        testName: packageJson.name,
+        tunnelIdentifier: process.env.TRAVIS_JOB_NUMBER || new Date().getTime(),
+        recordVideo: true,
+        startConnect: ('TRAVIS' in process.env) === false,
+        tags: [
+          'typeDetect_' + packageJson.version,
+          process.env.SAUCE_USERNAME + '@' + branch,
+          build,
+        ],
+      },
+    });
+  }
+};
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..6654c23
--- /dev/null
+++ b/package.json
@@ -0,0 +1,88 @@
+{
+  "name": "deep-eql",
+  "description": "Improved deep equality testing for Node.js and the browser.",
+  "keywords": [
+    "chai util",
+    "deep equal",
+    "object equal",
+    "testing"
+  ],
+  "license": "MIT",
+  "author": "Jake Luer <jake at alogicalparadox.com>",
+  "contributors": [
+    "Keith Cirkel (https://github.com/keithamus)",
+    "dougluce (https://github.com/dougluce)",
+    "Lorenz Leutgeb (https://github.com/flowlo)"
+  ],
+  "main": "./index",
+  "files": [
+    "index.js",
+    "deep-eql.js"
+  ],
+  "repository": {
+    "type": "git",
+    "url": "git at github.com:chaijs/deep-eql.git"
+  },
+  "scripts": {
+    "bench": "node bench",
+    "build": "browserify $npm_pakcage_main --standalone deepEqual -o deep-eql.js",
+    "lint": "eslint --ignore-path .gitignore .",
+    "prepublish": "npm run build",
+    "semantic-release": "semantic-release pre && npm publish && semantic-release post",
+    "pretest": "npm run lint",
+    "test": "npm run test:node && npm run test:browser",
+    "test:node": "istanbul cover _mocha",
+    "test:browser": "karma start --singleRun=true",
+    "watch": "karma start --auto-watch --singleRun=false",
+    "upload-coverage": "lcov-result-merger 'coverage/**/lcov.info' | coveralls; exit 0"
+  },
+  "config": {
+    "ghooks": {
+      "commit-msg": "validate-commit-msg"
+    }
+  },
+  "eslintConfig": {
+    "extends": [
+      "strict/es5"
+    ],
+    "rules": {
+      "complexity": 0,
+      "spaced-comment": 0,
+      "no-use-before-define": 0
+    }
+  },
+  "dependencies": {
+    "type-detect": "^3.0.0"
+  },
+  "devDependencies": {
+    "benchmark": "^2.1.0",
+    "browserify": "^13.0.0",
+    "browserify-istanbul": "^1.0.0",
+    "component": "*",
+    "coveralls": "2.11.8",
+    "eslint": "^2.4.0",
+    "eslint-config-strict": "^8.5.0",
+    "eslint-plugin-filenames": "^0.2.0",
+    "ghooks": "^1.0.1",
+    "istanbul": "^0.4.2",
+    "karma": "^0.13.22",
+    "karma-browserify": "^5.0.2",
+    "karma-coverage": "^0.5.5",
+    "karma-mocha": "^0.2.2",
+    "karma-phantomjs-launcher": "^1.0.0",
+    "karma-sauce-launcher": "^0.3.1",
+    "kewlr": "^0.3.1",
+    "lcov-result-merger": "^1.0.2",
+    "lodash.isequal": "^4.4.0",
+    "mocha": "^2.4.5",
+    "phantomjs-prebuilt": "^2.1.5",
+    "semantic-release": "^4.3.5",
+    "simple-assert": "^1.0.0",
+    "travis-after-all": "^1.4.4",
+    "validate-commit-msg": "^2.3.1",
+    "watchify": "^3.7.0"
+  },
+  "engines": {
+    "node": "*"
+  }
+}
diff --git a/test/.eslintrc b/test/.eslintrc
new file mode 100644
index 0000000..edffc56
--- /dev/null
+++ b/test/.eslintrc
@@ -0,0 +1,19 @@
+{
+  "extends": [ "strict/test" ],
+  "env": {
+    "node": true,
+    "browser": true,
+    "es6": true,
+    "mocha": true
+  },
+  "rules": {
+    "no-new-wrappers": 0,
+    "no-array-constructor": 0,
+    "no-new-object": 0,
+    "no-empty-function": 0,
+    "no-undefined": 0,
+    "complexity": 0,
+    "max-statements": 0,
+    "id-match": 0
+  }
+}
diff --git a/test/index.js b/test/index.js
new file mode 100644
index 0000000..825f897
--- /dev/null
+++ b/test/index.js
@@ -0,0 +1,455 @@
+'use strict';
+var assert = require('simple-assert');
+var eql = require('..');
+var MemoizeMap = require('..').MemoizeMap;
+describe('Generic', function () {
+
+  describe('strings', function () {
+
+    it('returns true for same values', function () {
+      assert(eql('x', 'x'), 'eql("x", "x")');
+    });
+
+    it('returns true for different instances with same values', function () {
+      assert(eql(new String('x'), new String('x')), 'eql(new String("x"), new String("x"))');
+    });
+
+    it('returns false for literal vs instance with same value', function () {
+      assert(eql('x', new String('x')) === false, 'eql("x", new String("x")) === false');
+      assert(eql(new String('x'), 'x') === false, 'eql(new String("x"), "x") === false');
+    });
+
+    it('returns false for different instances with different values', function () {
+      assert(eql(new String('x'), new String('y')) === false,
+        'eql(new String("x"), new String("y")) === false');
+    });
+
+    it('returns false for different values', function () {
+      assert(eql('x', 'y') === false, 'eql("x", "y") === false');
+    });
+
+  });
+
+  describe('booleans', function () {
+
+    it('returns true for same values', function () {
+      assert(eql(true, true), 'eql(true, true)');
+    });
+
+    it('returns true for instances with same value', function () {
+      assert(eql(new Boolean(true), new Boolean(true)), 'eql(new Boolean(true), new Boolean(true))');
+    });
+
+    it('returns false for literal vs instance with same value', function () {
+      assert(eql(true, new Boolean(true)) === false, 'eql(true, new Boolean(true)) === false');
+    });
+
+    it('returns false for literal vs instance with different values', function () {
+      assert(eql(false, new Boolean(true)) === false, 'eql(false, new Boolean(true)) === false');
+      assert(eql(new Boolean(false), true) === false, 'eql(new Boolean(false), true) === false');
+    });
+
+    it('returns false for instances with different values', function () {
+      assert(eql(new Boolean(false), new Boolean(true)) === false,
+      'eql(new Boolean(false), new Boolean(true)) === false');
+      assert(eql(new Boolean(true), new Boolean(false)) === false,
+      'eql(new Boolean(true), new Boolean(false)) === false');
+    });
+
+    it('returns false for different values', function () {
+      assert(eql(true, false) === false, 'eql(true, false) === false');
+      assert(eql(true, Boolean(false)) === false, 'eql(true, Boolean(false)) === false');
+    });
+
+  });
+
+  describe('null', function () {
+
+    it('returns true for two nulls', function () {
+      assert(eql(null, null), 'eql(null, null)');
+    });
+
+    it('returns false for null, undefined', function () {
+      assert(eql(null, undefined) === false, 'eql(null, undefined) === false');
+    });
+
+  });
+
+  describe('undefined', function () {
+
+    it('returns true for two undefineds', function () {
+      assert(eql(undefined, undefined), 'eql(undefined, undefined)');
+    });
+
+    it('returns false for undefined, null', function () {
+      assert(eql(undefined, null) === false, 'eql(undefined, null) === false');
+    });
+
+  });
+
+  describe('numbers', function () {
+
+    it('returns true for same values', function () {
+      assert(eql(-0, -0), 'eql(-0, -0)');
+      assert(eql(+0, +0), 'eql(+0, +0)');
+      assert(eql(0, 0), 'eql(0, 0)');
+      assert(eql(1, 1), 'eql(1, 1)');
+      assert(eql(Infinity, Infinity), 'eql(Infinity, Infinity)');
+      assert(eql(-Infinity, -Infinity), 'eql(-Infinity, -Infinity)');
+    });
+
+    it('returns false for literal vs instance with same value', function () {
+      assert(eql(1, new Number(1)) === false, 'eql(1, new Number(1)) === false');
+    });
+
+    it('returns true NaN vs NaN', function () {
+      assert(eql(NaN, NaN), 'eql(NaN, NaN)');
+    });
+
+    it('returns true for NaN instances', function () {
+      assert(eql(new Number(NaN), new Number(NaN)), 'eql(new Number(NaN), new Number(NaN))');
+    });
+
+    it('returns false on numbers with different signs', function () {
+      assert(eql(-1, 1) === false, 'eql(-1, 1) === false');
+      assert(eql(-0, +0) === false, 'eql(-0, +0) === false');
+      assert(eql(-Infinity, Infinity) === false, 'eql(-Infinity, +Infinity) === false');
+    });
+
+    it('returns false on instances with different signs', function () {
+      assert(eql(new Number(-1), new Number(1)) === false, 'eql(new Number(-1), new Number(1)) === false');
+      assert(eql(new Number(-0), new Number(+0)) === false, 'eql(new Number(-0), new Number(+0)) === false');
+      assert(eql(new Number(-Infinity), new Number(Infinity)) === false,
+        'eql(new Number(-Infinity), new Number(+Infinity)) === false');
+    });
+
+  });
+
+  describe('dates', function () {
+
+    it('returns true given two dates with the same time', function () {
+      var dateA = new Date();
+      assert(eql(dateA, new Date(dateA.getTime())), 'eql(dateA, new Date(dateA.getTime()))');
+    });
+
+    it('returns true given two invalid dates', function () {
+      assert(eql(new Date(NaN), new Date(NaN)), 'eql(new Date(NaN), new Date(NaN))');
+    });
+
+    it('returns false given two dates with the different times', function () {
+      var dateA = new Date();
+      assert(eql(dateA, new Date(dateA.getTime() + 1)) === false,
+        'eql(dateA, new Date(dateA.getTime() + 1)) === false');
+    });
+
+  });
+
+  describe('regexp', function () {
+
+    it('returns true given two regexes with the same source', function () {
+      assert(eql(/\s/, /\s/), 'eql(/\\s/, /\\s/)');
+      assert(eql(/\s/, new RegExp('\\s')), 'eql(/\\s/, new RegExp("\\s"))');
+    });
+
+    it('returns false given two regexes with different source', function () {
+      assert(eql(/^$/, /^/) === false, 'eql(/^$/, /^/) === false');
+      assert(eql(/^$/, new RegExp('^')) === false, 'eql(/^$/, new RegExp("^"))');
+    });
+
+    it('returns false given two regexes with different flags', function () {
+      assert(eql(/^/m, /^/i) === false, 'eql(/^/m, /^/i) === false');
+    });
+
+  });
+
+  describe('empty types', function () {
+
+    it('returns true on two empty objects', function () {
+      assert(eql({}, {}), 'eql({}, {})');
+    });
+
+    it('returns true on two empty arrays', function () {
+      assert(eql([], []), 'eql([], [])');
+    });
+
+    it('returns false on different types', function () {
+      assert(eql([], {}) === false, 'eql([], {}) === false');
+    });
+
+  });
+
+  describe('class instances', function () {
+
+    it('returns true given two empty class instances', function () {
+      function BaseA() {}
+      assert(eql(new BaseA(), new BaseA()), 'eql(new BaseA(), new BaseA())');
+    });
+
+    it('returns true given two class instances with same properties', function () {
+      function BaseA(prop) {
+        this.prop = prop;
+      }
+      assert(eql(new BaseA(1), new BaseA(1)), 'eql(new BaseA(1), new BaseA(1))');
+    });
+
+    it('returns false given two class instances with different properties', function () {
+      function BaseA(prop) {
+        this.prop = prop;
+      }
+      assert(eql(new BaseA(1), new BaseA(2)) === false, 'eql(new BaseA(1), new BaseA(2)) === false');
+    });
+
+    it('returns false given two different empty class instances', function () {
+      function BaseA() {}
+      function BaseB() {}
+      assert(eql(new BaseA(), new BaseB()) === false, 'eql(new BaseA(), new BaseB()) === false');
+    });
+
+  });
+
+  describe('arguments', function () {
+    function getArguments() {
+      return arguments;
+    }
+
+    it('returns true given two arguments', function () {
+      var argumentsA = getArguments();
+      var argumentsB = getArguments();
+      assert(eql(argumentsA, argumentsB), 'eql(argumentsA, argumentsB)');
+    });
+
+    it('returns true given two arguments with same properties', function () {
+      var argumentsA = getArguments(1, 2);
+      var argumentsB = getArguments(1, 2);
+      assert(eql(argumentsA, argumentsB), 'eql(argumentsA, argumentsB)');
+    });
+
+    it('returns false given two arguments with different properties', function () {
+      var argumentsA = getArguments(1, 2);
+      var argumentsB = getArguments(3, 4);
+      assert(eql(argumentsA, argumentsB) === false, 'eql(argumentsA, argumentsB) === false');
+    });
+
+    it('returns false given an array', function () {
+      assert(eql([], arguments) === false, 'eql([], arguments) === false');
+    });
+
+    it('returns false given an object', function () {
+      assert(eql({}, arguments) === false, 'eql({}, arguments) === false');
+    });
+
+  });
+
+  describe('arrays', function () {
+
+    it('returns true with arrays containing same literals', function () {
+      assert(eql([ 1, 2, 3 ], [ 1, 2, 3 ]), 'eql([ 1, 2, 3 ], [ 1, 2, 3 ])');
+      assert(eql([ 'a', 'b', 'c' ], [ 'a', 'b', 'c' ]), 'eql([ "a", "b", "c" ], [ "a", "b", "c" ])');
+    });
+
+    it('returns true given literal or constructor', function () {
+      assert(eql([ 1, 2, 3 ], new Array(1, 2, 3)), 'eql([ 1, 2, 3 ], new Array(1, 2, 3))');
+    });
+
+    it('returns false with arrays containing literals in different order', function () {
+      assert(eql([ 3, 2, 1 ], [ 1, 2, 3 ]) === false, 'eql([ 3, 2, 1 ], [ 1, 2, 3 ]) === false');
+    });
+
+    it('returns false for arrays of different length', function () {
+      assert(eql(new Array(1), new Array(100)) === false, 'eql(new Array(1), new Array(100)) === false');
+    });
+
+  });
+
+  describe('objects', function () {
+
+    it('returns true with objects containing same literals', function () {
+      assert(eql({ foo: 1, bar: 2 }, { foo: 1, bar: 2 }), 'eql({ foo: 1, bar: 2 }, { foo: 1, bar: 2 })');
+      assert(eql({ foo: 'baz' }, { foo: 'baz' }), 'eql({ foo: "baz" }, { foo: "baz" })');
+    });
+
+    it('returns true for deeply nested objects', function () {
+      assert(eql({ foo: { bar: 'foo' } }, { foo: { bar: 'foo' } }),
+        'eql({ foo: { bar: "foo" }}, { foo: { bar: "foo" }})');
+    });
+
+    it('returns true with objects with same circular reference', function () {
+      var objectA = { foo: 1 };
+      var objectB = { foo: 1 };
+      var objectC = { a: objectA, b: objectB };
+      objectA.bar = objectC;
+      objectB.bar = objectC;
+      assert(eql(objectA, objectB) === true,
+        'eql({ foo: 1, bar: objectC }, { foo: 1, bar: objectC }) === true');
+    });
+
+    it('returns false with objects containing different literals', function () {
+      assert(eql({ foo: 1, bar: 1 }, { foo: 1, bar: 2 }) === false,
+        'eql({ foo: 1, bar: 2 }, { foo: 1, bar: 2 }) === false');
+      assert(eql({ foo: 'bar' }, { foo: 'baz' }) === false, 'eql({ foo: "bar" }, { foo: "baz" }) === false');
+      assert(eql({ foo: { bar: 'foo' } }, { foo: { bar: 'baz' } }) === false,
+        'eql({ foo: { bar: "foo" }}, { foo: { bar: "baz" }}) === false');
+    });
+
+    it('returns false with objects containing different keys', function () {
+      assert(eql({ foo: 1, bar: 1 }, { foo: 1, baz: 2 }) === false,
+        'eql({ foo: 1, bar: 2 }, { foo: 1, baz: 2 }) === false');
+      assert(eql({ foo: 'bar' }, { bar: 'baz' }) === false, 'eql({ foo: "bar" }, { foo: "baz" }) === false');
+    });
+
+    it('returns false with recursive objects of differing values', function () {
+      var objectA = { foo: 1 };
+      var objectB = { foo: 1 };
+      objectA.bar = objectB;
+      objectB.bar = objectA;
+      assert(eql(objectA, objectB) === false,
+        'eql({ foo: 1, bar: -> }, { foo: 1, bar: <- }) === false');
+    });
+
+  });
+
+  describe('functions', function () {
+
+    it('returns true for same functions', function () {
+      function foo() {}
+      assert(eql(foo, foo), 'eql(function foo() {}, function foo() {})');
+    });
+
+    it('returns false for different functions', function () {
+      assert(eql(function foo() {}, function bar() {}) === false,
+        'eql(function foo() {}, function bar() {}) === false');
+    });
+
+  });
+
+  describe('errors', function () {
+
+    it('returns true for same errors', function () {
+      var error = new Error('foo');
+      assert(eql(error, error), 'eql(error, error)');
+    });
+
+    it('returns false for different errors', function () {
+      assert(eql(new Error('foo'), new Error('foo')) === false,
+        'eql(new Error("foo"), new Error("foo")) === false');
+    });
+
+  });
+
+});
+
+describe('Memoize', function () {
+
+  it('returns true if MemoizeMap says so', function () {
+    var memoizeMap = new MemoizeMap();
+    var valueAMap = new MemoizeMap();
+    var valueA = {};
+    var valueB = { not: 'equal' };
+    valueAMap.set(valueB, true);
+    memoizeMap.set(valueA, valueAMap);
+    assert(eql(valueA, valueB, { memoize: memoizeMap }) === true,
+      'eql({}, {not:"equal"}, <memoizeMap>) === true');
+  });
+
+  it('returns false if MemoizeMap says so', function () {
+    var memoizeMap = new MemoizeMap();
+    var valueAMap = new MemoizeMap();
+    var valueA = {};
+    var valueB = {};
+    valueAMap.set(valueB, false);
+    memoizeMap.set(valueA, valueAMap);
+    assert(eql(valueA, valueB, { memoize: memoizeMap }) === false,
+      'eql({}, {}, <memoizeMap>) === false');
+  });
+
+  it('resorts to default behaviour if MemoizeMap has no answer (same objects)', function () {
+    var memoizeMap = new MemoizeMap();
+    var valueAMap = new MemoizeMap();
+    var valueA = {};
+    var valueB = {};
+    memoizeMap.set(valueA, valueAMap);
+    assert(eql(valueA, valueB, { memoize: memoizeMap }) === true,
+      'eql({}, {}, <memoizeMap>) === true');
+  });
+
+  it('resorts to default behaviour if MemoizeMap has no answer (different objects)', function () {
+    var memoizeMap = new MemoizeMap();
+    var valueAMap = new MemoizeMap();
+    var valueA = {};
+    var valueB = { not: 'equal' };
+    memoizeMap.set(valueA, valueAMap);
+    assert(eql(valueA, valueB, { memoize: memoizeMap }) === false,
+      'eql({}, {}, <memoizeMap>) === false');
+  });
+
+});
+
+describe('Comparator', function () {
+  function specialComparator(left, right) {
+    return left['@@specialValue'] === right['@@specialValue'];
+  }
+  function Matcher(func) {
+    this.func = func;
+  }
+  function matcherComparator(left, right) {
+    if (left instanceof Matcher) {
+      return left.func(right);
+    } else if (right instanceof Matcher) {
+      return right.func(left);
+    }
+    return null;
+  }
+  function falseComparator() {
+    return false;
+  }
+  function nullComparator() {
+    return null;
+  }
+
+  it('returns true if Comparator says so', function () {
+    var valueA = { '@@specialValue': 1, a: 1 };
+    var valueB = { '@@specialValue': 1, a: 2 };
+    assert(eql(valueA, valueB, { comparator: specialComparator }) === true,
+      'eql({@@specialValue:1,a:1}, {@@specialValue:1,a:2}, <comparator>) === true');
+  });
+
+  it('returns true if Comparator says so even on primitives', function () {
+    var valueA = {
+      a: new Matcher(function (value) {
+        return typeof value === 'number';
+      }),
+    };
+    var valueB = { a: 1 };
+    assert(eql(valueA, valueB, { comparator: matcherComparator }) === true,
+      'eql({a:value => typeof value === "number"}, {a:1}, <comparator>) === true');
+  });
+
+  it('returns true if Comparator says so (deep-equality)', function () {
+    var valueA = { a: { '@@specialValue': 1, a: 1 }, b: 1 };
+    var valueB = { a: { '@@specialValue': 1, a: 2 }, b: 1 };
+    assert(eql(valueA, valueB, { comparator: specialComparator }) === true,
+      'eql({a:{@@specialValue:1,a:1},b:1}, {a:{@@specialValue:2,a:2},b:1}, <comparator>) === true');
+  });
+
+  it('returns false if Comparator returns false (same objects)', function () {
+    var valueA = { a: 1 };
+    var valueB = { a: 1 };
+    assert(eql(valueA, valueB, { comparator: falseComparator }) === false,
+      'eql({}, {}, <falseComparator>) === false');
+  });
+
+  it('resorts to deep-eql if Comparator returns null (same objects)', function () {
+    var valueA = { a: 1 };
+    var valueB = { a: 1 };
+    assert(eql(valueA, valueB, { comparator: nullComparator }) === true,
+      'eql({}, {}, <nullComparator>) === true');
+  });
+
+  it('resorts to deep-eql behaviour if Comparator returns null (different objects)', function () {
+    var valueA = { a: 1 };
+    var valueB = { a: 2 };
+    assert(eql(valueA, valueB, { comparator: nullComparator }) === false,
+      'eql({}, {}, <nullComparator>) === false');
+  });
+
+});
diff --git a/test/new-ecmascript-types.js b/test/new-ecmascript-types.js
new file mode 100644
index 0000000..96f343c
--- /dev/null
+++ b/test/new-ecmascript-types.js
@@ -0,0 +1,651 @@
+'use strict';
+/* eslint-disable no-eval */
+var assert = require('simple-assert');
+var eql = require('..');
+var emptyFunction = Function.prototype;
+var symbolExists = typeof Symbol === 'function';
+var setExists = typeof Set === 'function';
+var mapExists = typeof Map === 'function';
+var symbolAndMapExist = symbolExists && mapExists;
+var symbolAndSetExist = symbolExists && setExists;
+var supportGenerators = false;
+var supportArrows = false;
+try {
+  eval('function * foo () {}; foo');
+  supportGenerators = true;
+} catch (error) {
+  supportGenerators = false;
+}
+try {
+  eval('() => {}');
+  supportArrows = true;
+} catch (error) {
+  supportArrows = false;
+}
+
+function describeIf(condition) {
+  return condition ? describe : describe.skip;
+}
+describe('ES2015 Specific', function () {
+
+  describeIf(symbolExists && typeof String.prototype[Symbol.iterator] === 'function')('string iterator', function () {
+
+    it('returns true for Strings with same entries', function () {
+      assert(eql('abc'[Symbol.iterator](), 'abc'[Symbol.iterator]()),
+        'eql("abc"[Symbol.iterator](), "abc"[Symbol.iterator]())');
+    });
+
+    it('returns false for Strings with different entries', function () {
+      assert(eql('abc'[Symbol.iterator](), 'def'[Symbol.iterator]()) === false,
+        'eql("abc"[Symbol.iterator](), "def"[Symbol.iterator]()) === false');
+    });
+
+  });
+
+  describeIf(symbolExists && typeof Array.prototype[Symbol.iterator] === 'function')('array iterator', function () {
+
+    it('returns true for Arrays with same entries', function () {
+      assert(eql([ 1, 2, 3 ][Symbol.iterator](), [ 1, 2, 3 ][Symbol.iterator]()),
+        'eql([ 1, 2, 3 ][Symbol.iterator](), [ 1, 2, 3 ][Symbol.iterator]())');
+    });
+
+    it('returns false for Arrays with different entries', function () {
+      assert(eql([ 1, 2, 3 ][Symbol.iterator](), [ 4, 5, 6 ][Symbol.iterator]()) === false,
+        'eql([ 1, 2, 3 ][Symbol.iterator](), [ 4, 5, 6 ][Symbol.iterator]()) === false');
+    });
+
+  });
+
+  describeIf(typeof Array.prototype.entries === 'function')('array iterator (entries)', function () {
+
+    it('returns true for Arrays with same entries', function () {
+      assert(eql([ 1, 2, 3 ].entries(), [ 1, 2, 3 ].entries()),
+        'eql([ 1, 2, 3 ].entries(), [ 1, 2, 3 ].entries())');
+    });
+
+    it('returns false for Arrays with different entries', function () {
+      assert(eql([ 1, 2, 3 ].entries(), [ 4, 5, 6 ].entries()) === false,
+        'eql([ 1, 2, 3 ].entries(), [ 4, 5, 6 ].entries()) === false');
+    });
+
+  });
+
+  describeIf(mapExists)('maps', function () {
+
+    it('returns true for Maps with same entries', function () {
+      var mapA = new Map();
+      var mapB = new Map();
+      mapA.set('a', 1);
+      mapA.set('b', 2);
+      mapA.set('c', 3);
+      mapB.set('c', 3);
+      mapB.set('b', 2);
+      mapB.set('a', 1);
+      assert(eql(mapA, mapB), 'eql(Map { a => 1, b => 2, c => 3 }, Map { a => 1, b => 2, c => 3 })');
+    });
+
+    it('returns false for Maps with different entries', function () {
+      var mapA = new Map();
+      var mapB = new Map();
+      mapA.set('a', 1);
+      mapB.set('a', 1);
+      mapA.set('b', 2);
+      mapB.set('b', 2);
+      mapA.set('c', 3);
+      mapB.set('c', 3);
+      assert(eql(mapA, mapB), 'eql(Map { a => 1, b => 2, c => 3 }, Map { a => 1, b => 2, c => 3 })');
+    });
+
+  });
+
+  describeIf(symbolAndMapExist && typeof Map.prototype[Symbol.iterator] === 'function')('map iterator', function () {
+
+    it('returns true for Map iterators with same entries', function () {
+      var mapA = new Map();
+      var mapB = new Map();
+      mapA.set('a', 1);
+      mapB.set('a', 1);
+      mapA.set('b', 2);
+      mapB.set('b', 2);
+      mapA.set('c', 3);
+      mapB.set('c', 3);
+      assert(eql(mapA[Symbol.iterator](), mapB[Symbol.iterator]()),
+        'eql(Map { a => 1, b => 2, c => 3 }[Symbol.iterator](), Map { a => 1, b => 2, c => 3 }[Symbol.iterator]())');
+    });
+
+    it('returns false for Map iterators with different entries', function () {
+      var mapA = new Map();
+      var mapB = new Map();
+      mapA.set('a', 1);
+      mapB.set('a', 2);
+      mapA.set('b', 3);
+      mapB.set('b', 4);
+      mapA.set('c', 5);
+      mapB.set('c', 6);
+      assert(eql(mapA[Symbol.iterator](), mapB[Symbol.iterator]()) === false,
+        'eql(Map { a => 1, b => 3, c => 5 }[Symbol.iterator](), ' +
+        'Map { a => 2, b => 4, c => 6 }[Symbol.iterator]()) === false');
+    });
+
+  });
+
+  describeIf(mapExists && typeof Map.prototype.entries === 'function')('map iterator (entries)', function () {
+
+    it('returns true for Map iterators with same entries', function () {
+      var mapA = new Map();
+      var mapB = new Map();
+      mapA.set('a', 1);
+      mapB.set('a', 1);
+      mapA.set('b', 2);
+      mapB.set('b', 2);
+      mapA.set('c', 3);
+      mapB.set('c', 3);
+      assert(eql(mapA.entries(), mapB.entries()),
+        'eql(Map { a => 1, b => 2, c => 3 }.entries(), Map { a => 1, b => 2, c => 3 }.entries())');
+    });
+
+    it('returns false for Map iterators with different entries', function () {
+      var mapA = new Map();
+      var mapB = new Map();
+      mapA.set('a', 1);
+      mapB.set('a', 2);
+      mapA.set('b', 3);
+      mapB.set('b', 4);
+      mapA.set('c', 5);
+      mapB.set('c', 6);
+      assert(eql(mapA.entries(), mapB.entries()) === false,
+        'eql(Map { a => 1, b => 3, c => 5 }.entries(), ' +
+        'Map { a => 2, b => 4, c => 6 }.entries()) === false');
+    });
+
+  });
+
+  describeIf(typeof WeakMap === 'function')('weakmaps', function () {
+
+    it('returns true for same WeakMaps', function () {
+      var weakMap = new WeakMap();
+      assert(eql(weakMap, weakMap), 'eql(weakMap, weakMap)');
+    });
+
+    it('returns false for different WeakMaps', function () {
+      assert(eql(new WeakMap(), new WeakMap()) === false,
+        'eql(new WeakMap(), new WeakMap()) === false');
+    });
+
+  });
+
+  describeIf(setExists)('sets', function () {
+
+    it('returns true for Sets with same entries', function () {
+      var setA = new Set();
+      var setB = new Set();
+      setA.add('a');
+      setA.add('b');
+      setA.add('c');
+      setB.add('a');
+      setB.add('b');
+      setB.add('c');
+      assert(eql(setA, setB), 'eql(Set { "a", "b", "c" }, Set { "a", "b", "c" })');
+    });
+
+    it('returns true for Sets with same entries in different order', function () {
+      var setA = new Set();
+      var setB = new Set();
+      setA.add('a');
+      setA.add('b');
+      setA.add('c');
+      setB.add('b');
+      setB.add('c');
+      setB.add('a');
+      assert(eql(setA, setB), 'eql(Set { "a", "b", "c" }, Set { "b", "c", "a" })');
+    });
+
+    it('returns true for Sets with nested entries', function () {
+      var setA = new Set();
+      var setB = new Set();
+      setA.add([ [], [], [] ]);
+      setB.add([ [], [], [] ]);
+      assert(eql(setA, setB) === true, 'eql(Set [ [], [], [] ], Set [ [], [], [] ]) === true');
+    });
+
+    it('returns true for Sets with same circular references', function () {
+      var setA = new Set();
+      var setB = new Set();
+      var setC = new Set();
+      setA.add(setC);
+      setB.add(setC);
+      setC.add(setA);
+      setC.add(setB);
+      assert(eql(setA, setB) === true, 'eql(Set { setC }, Set { setC }) === true');
+    });
+
+    it('returns false for Sets with different entries', function () {
+      var setA = new Set();
+      var setB = new Set();
+      setA.add('a');
+      setA.add('b');
+      setA.add('c');
+      setB.add('d');
+      setB.add('e');
+      setB.add('f');
+      assert(eql(setA, setB) === false, 'eql(Set { "a", "b", "c" }, Set { "d", "e", "f" }) === false');
+    });
+
+    it('returns false for Sets with different circular references', function () {
+      var setA = new Set();
+      var setB = new Set();
+      setA.add(setB);
+      setB.add(setA);
+      assert(eql(setA, setB) === false, 'eql(Set { -> }, Set { <- }) === false');
+    });
+
+  });
+
+  describeIf(symbolAndSetExist && typeof Set.prototype[Symbol.iterator] === 'function')('set iterator', function () {
+
+    it('returns true for Sets with same entries', function () {
+      var setA = new Set();
+      var setB = new Set();
+      setA.add('a');
+      setA.add('b');
+      setA.add('c');
+      setB.add('c');
+      setB.add('b');
+      setB.add('a');
+      assert(eql(setA[Symbol.iterator](), setB[Symbol.iterator]()),
+        'eql(Set { "a", "b", "c" }[Symbol.iterator](), Set { "a", "b", "c" }[Symbol.iterator]())');
+    });
+
+    it('returns false for Sets with different entries', function () {
+      var setA = new Set();
+      var setB = new Set();
+      setA.add('a');
+      setA.add('b');
+      setA.add('c');
+      setB.add('d');
+      setB.add('e');
+      setB.add('f');
+      assert(eql(setA[Symbol.iterator](), setB[Symbol.iterator]()) === false,
+        'eql(Set { "a", "b", "c" }[Symbol.iterator](), Set { "d", "e", "f" }[Symbol.iterator]()) === false');
+    });
+
+  });
+
+  describeIf(setExists && typeof Set.prototype.entries === 'function')('set iterator (entries)', function () {
+
+    it('returns true for Sets with same entries', function () {
+      var setA = new Set();
+      var setB = new Set();
+      setA.add('a');
+      setA.add('b');
+      setA.add('c');
+      setB.add('c');
+      setB.add('b');
+      setB.add('a');
+      assert(eql(setA.entries(), setB.entries()),
+        'eql(Set { "a", "b", "c" }.entries(), Set { "a", "b", "c" }.entries())');
+    });
+
+    it('returns false for Sets with different entries', function () {
+      var setA = new Set();
+      var setB = new Set();
+      setA.add('a');
+      setA.add('b');
+      setA.add('c');
+      setB.add('d');
+      setB.add('e');
+      setB.add('f');
+      assert(eql(setA.entries(), setB.entries()) === false,
+        'eql(Set { "a", "b", "c" }.entries(), Set { "d", "e", "f" }.entries()) === false');
+    });
+
+  });
+
+  describeIf(typeof WeakSet === 'function')('weaksets', function () {
+
+    it('returns true for same WeakSets', function () {
+      var weakSet = new WeakSet();
+      assert(eql(weakSet, weakSet), 'eql(weakSet, weakSet)');
+    });
+
+    it('returns false for different WeakSets', function () {
+      assert(eql(new WeakSet(), new WeakSet()) === false,
+        'eql(new WeakSet(), new WeakSet()) === false');
+    });
+
+  });
+
+  describeIf(typeof Symbol === 'function')('symbol', function () {
+
+    it('returns true for the same symbols', function () {
+      var sym = Symbol();
+      assert(eql(sym, sym), 'eql(sym, sym)');
+      assert(eql(Symbol.iterator, Symbol.iterator), 'eql(Symbol.iterator, Symbol.iterator)');
+    });
+
+    it('returns false for different symbols', function () {
+      assert(eql(Symbol(), Symbol()) === false, 'eql(Symbol(), Symbol()) === false');
+    });
+
+  });
+
+  describeIf(typeof Promise === 'function')('promise', function () {
+
+    it('returns true for the same promises', function () {
+      var promiseResolve = Promise.resolve();
+      var promiseReject = Promise.reject();
+      var promisePending = new Promise(emptyFunction);
+      assert(eql(promiseResolve, promiseResolve), 'eql(promiseResolve, promiseResolve)');
+      assert(eql(promiseReject, promiseReject), 'eql(promiseReject, promiseReject)');
+      assert(eql(promisePending, promisePending), 'eql(promisePending, promisePending)');
+    });
+
+
+    it('returns false for different promises', function () {
+      assert(eql(Promise.resolve(), Promise.resolve()) === false,
+        'eql(Promise.resolve(), Promise.resolve()) === false');
+      assert(eql(Promise.reject(), Promise.reject()) === false,
+        'eql(Promise.reject(), Promise.reject()) === false');
+      assert(eql(new Promise(emptyFunction), new Promise(emptyFunction)) === false,
+        'eql(new Promise(emptyFunction), new Promise(emptyFunction)) === false');
+    });
+
+  });
+
+  describeIf(typeof Int8Array === 'function')('int8array', function () {
+
+    it('returns true for arrays with same values', function () {
+      assert(eql(new Int8Array(1, 2, 3, 4), new Int8Array(1, 2, 3, 4)),
+        'eql(new Int8Array(1, 2, 3, 4), new Int8Array(1, 2, 3, 4))');
+    });
+
+    it('returns false for arrays with different values', function () {
+      assert(eql(new Int8Array(1, 2, 3, 4), new Int8Array(5, 6, 7, 8)) === false,
+        'eql(new Int8Array(1, 2, 3, 4), new Int8Array(5, 6, 7, 8)) === false');
+      assert(eql(new Int8Array(1, 2, 3, 4), new Int8Array(4, 2, 3, 4)) === false,
+        'eql(new Int8Array(1, 2, 3, 4), new Int8Array(4, 2, 3, 4)) === false');
+    });
+
+  });
+
+  describeIf(typeof Uint8Array === 'function')('uint8array', function () {
+
+    it('returns true for arrays with same values', function () {
+      assert(eql(new Uint8Array(1, 2, 3, 4), new Uint8Array(1, 2, 3, 4)),
+        'eql(new Uint8Array(1, 2, 3, 4), new Uint8Array(1, 2, 3, 4))');
+    });
+
+    it('returns false for arrays with different values', function () {
+      assert(eql(new Uint8Array(1, 2, 3, 4), new Uint8Array(5, 6, 7, 8)) === false,
+        'eql(new Uint8Array(1, 2, 3, 4), new Uint8Array(5, 6, 7, 8)) === false');
+      assert(eql(new Uint8Array(1, 2, 3, 4), new Uint8Array(4, 2, 3, 4)) === false,
+        'eql(new Uint8Array(1, 2, 3, 4), new Uint8Array(4, 2, 3, 4)) === false');
+    });
+
+  });
+
+  describeIf(typeof Uint8ClampedArray === 'function')('uint8clampedarray', function () {
+
+    it('returns true for arrays with same values', function () {
+      assert(eql(new Uint8ClampedArray(1, 2, 3, 4), new Uint8ClampedArray(1, 2, 3, 4)),
+        'eql(new Uint8ClampedArray(1, 2, 3, 4), new Uint8ClampedArray(1, 2, 3, 4))');
+    });
+
+    it('returns false for arrays with different values', function () {
+      assert(eql(new Uint8ClampedArray(1, 2, 3, 4), new Uint8ClampedArray(5, 6, 7, 8)) === false,
+        'eql(new Uint8ClampedArray(1, 2, 3, 4), new Uint8ClampedArray(5, 6, 7, 8)) === false');
+      assert(eql(new Uint8ClampedArray(1, 2, 3, 4), new Uint8ClampedArray(4, 2, 3, 4)) === false,
+        'eql(new Uint8ClampedArray(1, 2, 3, 4), new Uint8ClampedArray(4, 2, 3, 4)) === false');
+    });
+
+  });
+
+  describeIf(typeof Int16Array === 'function')('int16array', function () {
+
+    it('returns true for arrays with same values', function () {
+      assert(eql(new Int16Array(1, 2, 3, 4), new Int16Array(1, 2, 3, 4)),
+        'eql(new Int16Array(1, 2, 3, 4), new Int16Array(1, 2, 3, 4))');
+    });
+
+    it('returns false for arrays with different values', function () {
+      assert(eql(new Int16Array(1, 2, 3, 4), new Int16Array(5, 6, 7, 8)) === false,
+        'eql(new Int16Array(1, 2, 3, 4), new Int16Array(5, 6, 7, 8)) === false');
+      assert(eql(new Int16Array(1, 2, 3, 4), new Int16Array(4, 2, 3, 4)) === false,
+        'eql(new Int16Array(1, 2, 3, 4), new Int16Array(4, 2, 3, 4)) === false');
+    });
+
+  });
+
+  describeIf(typeof Uint16Array === 'function')('uint16array', function () {
+
+    it('returns true for arrays with same values', function () {
+      assert(eql(new Uint16Array(1, 2, 3, 4), new Uint16Array(1, 2, 3, 4)),
+        'eql(new Uint16Array(1, 2, 3, 4), new Uint16Array(1, 2, 3, 4))');
+    });
+
+    it('returns false for arrays with different values', function () {
+      assert(eql(new Uint16Array(1, 2, 3, 4), new Uint16Array(5, 6, 7, 8)) === false,
+        'eql(new Uint16Array(1, 2, 3, 4), new Uint16Array(5, 6, 7, 8)) === false');
+      assert(eql(new Uint16Array(1, 2, 3, 4), new Uint16Array(4, 2, 3, 4)) === false,
+        'eql(new Uint16Array(1, 2, 3, 4), new Uint16Array(4, 2, 3, 4)) === false');
+    });
+
+  });
+
+  describeIf(typeof Int32Array === 'function')('int32array', function () {
+
+    it('returns true for arrays with same values', function () {
+      assert(eql(new Int32Array(1, 2, 3, 4), new Int32Array(1, 2, 3, 4)),
+        'eql(new Int32Array(1, 2, 3, 4), new Int32Array(1, 2, 3, 4))');
+    });
+
+    it('returns false for arrays with different values', function () {
+      assert(eql(new Int32Array(1, 2, 3, 4), new Int32Array(5, 6, 7, 8)) === false,
+        'eql(new Int32Array(1, 2, 3, 4), new Int32Array(5, 6, 7, 8)) === false');
+      assert(eql(new Int32Array(1, 2, 3, 4), new Int32Array(4, 2, 3, 4)) === false,
+        'eql(new Int32Array(1, 2, 3, 4), new Int32Array(4, 2, 3, 4)) === false');
+    });
+
+  });
+
+  describeIf(typeof Uint32Array === 'function')('uint32array', function () {
+
+    it('returns true for arrays with same values', function () {
+      assert(eql(new Uint32Array(1, 2, 3, 4), new Uint32Array(1, 2, 3, 4)),
+        'eql(new Uint32Array(1, 2, 3, 4), new Uint32Array(1, 2, 3, 4))');
+    });
+
+    it('returns false for arrays with different values', function () {
+      assert(eql(new Uint32Array(1, 2, 3, 4), new Uint32Array(5, 6, 7, 8)) === false,
+        'eql(new Uint32Array(1, 2, 3, 4), new Uint32Array(5, 6, 7, 8)) === false');
+      assert(eql(new Uint32Array(1, 2, 3, 4), new Uint32Array(4, 2, 3, 4)) === false,
+        'eql(new Uint32Array(1, 2, 3, 4), new Uint32Array(4, 2, 3, 4)) === false');
+    });
+
+  });
+
+  describeIf(typeof Float32Array === 'function')('float32array', function () {
+
+    it('returns true for arrays with same values', function () {
+      assert(eql(new Float32Array(1, 2, 3, 4), new Float32Array(1, 2, 3, 4)),
+        'eql(new Float32Array(1, 2, 3, 4), new Float32Array(1, 2, 3, 4))');
+    });
+
+    it('returns false for arrays with different values', function () {
+      assert(eql(new Float32Array(1, 2, 3, 4), new Float32Array(5, 6, 7, 8)) === false,
+        'eql(new Float32Array(1, 2, 3, 4), new Float32Array(5, 6, 7, 8)) === false');
+      assert(eql(new Float32Array(1, 2, 3, 4), new Float32Array(4, 2, 3, 4)) === false,
+        'eql(new Float32Array(1, 2, 3, 4), new Float32Array(4, 2, 3, 4)) === false');
+    });
+
+  });
+
+  describeIf(typeof Float64Array === 'function')('float64array', function () {
+
+    it('returns true for arrays with same values', function () {
+      assert(eql(new Float64Array(1, 2, 3, 4), new Float64Array(1, 2, 3, 4)),
+        'eql(new Float64Array(1, 2, 3, 4), new Float64Array(1, 2, 3, 4))');
+    });
+
+    it('returns false for arrays with different values', function () {
+      assert(eql(new Float64Array(1, 2, 3, 4), new Float64Array(5, 6, 7, 8)) === false,
+        'eql(new Float64Array(1, 2, 3, 4), new Float64Array(5, 6, 7, 8)) === false');
+      assert(eql(new Float64Array(1, 2, 3, 4), new Float64Array(4, 2, 3, 4)) === false,
+        'eql(new Float64Array(1, 2, 3, 4), new Float64Array(4, 2, 3, 4)) === false');
+    });
+
+  });
+
+  describeIf(typeof DataView === 'function')('dataview', function () {
+
+    it('returns true for arrays with same values', function () {
+      var dataViewA = new DataView(new ArrayBuffer(4));
+      dataViewA.setUint8(0, 1);
+      dataViewA.setUint8(1, 2);
+      dataViewA.setUint8(2, 3);
+      dataViewA.setUint8(3, 4);
+      var dataViewB = new DataView(new ArrayBuffer(4));
+      dataViewB.setUint8(0, 1);
+      dataViewB.setUint8(1, 2);
+      dataViewB.setUint8(2, 3);
+      dataViewB.setUint8(3, 4);
+      assert(eql(dataViewA, dataViewB),
+        'eql(dataViewA, dataViewB)');
+    });
+
+    it('returns false for arrays with different lengths', function () {
+      assert(eql(new DataView(new ArrayBuffer(4)), new DataView(new ArrayBuffer(1))) === false,
+        'eql(new DataView(new ArrayBuffer(4)), new DataView(new ArrayBuffer(1))) === false');
+    });
+
+    it('returns false for arrays with different values', function () {
+      var dataViewA = new DataView(new ArrayBuffer(4));
+      dataViewA.setUint8(0, 1);
+      dataViewA.setUint8(1, 2);
+      dataViewA.setUint8(2, 3);
+      dataViewA.setUint8(3, 4);
+      var dataViewB = new DataView(new ArrayBuffer(4));
+      dataViewB.setUint8(0, 5);
+      dataViewB.setUint8(1, 6);
+      dataViewB.setUint8(2, 7);
+      dataViewB.setUint8(3, 8);
+      assert(eql(dataViewA, dataViewB) === false,
+        'eql(dataViewA, dataViewB) === false');
+    });
+
+  });
+
+  describeIf(typeof ArrayBuffer === 'function')('arraybuffer', function () {
+
+    it('returns true for arrays with same values', function () {
+      assert(eql(new ArrayBuffer(1), new ArrayBuffer(1)),
+        'eql(new ArrayBuffer(1), new ArrayBuffer(1)))');
+    });
+
+    it('returns false for arrays with different lengths', function () {
+      assert(eql(new ArrayBuffer(1), new ArrayBuffer(4)) === false,
+        'eql(new ArrayBuffer(1), new ArrayBuffer(4)) === false');
+    });
+
+    it('returns false for arrays with different values', function () {
+      var dataViewA = new DataView(new ArrayBuffer(4));
+      dataViewA.setUint8(0, 1);
+      dataViewA.setUint8(1, 2);
+      dataViewA.setUint8(2, 3);
+      dataViewA.setUint8(3, 4);
+      var dataViewB = new DataView(new ArrayBuffer(4));
+      dataViewB.setUint8(0, 5);
+      dataViewB.setUint8(1, 6);
+      dataViewB.setUint8(2, 7);
+      dataViewB.setUint8(3, 8);
+      assert(eql(dataViewA.buffer, dataViewB.buffer) === false,
+        'eql(dataViewA.buffer, dataViewB.buffer) === false');
+    });
+
+  });
+
+  describeIf(supportArrows)('arrow function', function () {
+
+    it('returns true for same arrow functions', function () {
+      var arrow = eval('() => {}');
+      assert(eql(arrow, arrow),
+        'eql(arrow, arrow)');
+    });
+
+    it('returns false for different arrow functions', function () {
+      assert(eql(eval('() => {}'), eval('() => {}')) === false,
+        'eql(() => {}, () => {}) === false');
+    });
+
+  });
+
+  describeIf(supportGenerators)('generator function', function () {
+
+    it('returns true for same arrow functions', function () {
+      var generator = eval('function * generator() {}; generator');
+      assert(eql(generator, generator),
+        'eql(generator, generator)');
+    });
+
+    it('returns false for different arrow functions', function () {
+      assert(eql(eval('function * generator() {}; generator'), eval('function * generator() {}; generator')) === false,
+        'eql(function * generator() {}, function * generator() {}) === false');
+    });
+
+  });
+
+  describeIf(supportGenerators)('generator', function () {
+
+    it('returns true for same generator function calls', function () {
+      var generator = eval('function * generator() { yield 1; yield 2; }; generator');
+      assert(eql(generator(), generator()),
+        'eql(generator(), generator())');
+    });
+
+    it('returns true for different generator function calls that return same results', function () {
+      var generatorA = eval('function * generatorA() { yield 1; yield 2; }; generatorA');
+      var generatorB = eval('function * generatorB() { yield 1; yield 2; }; generatorB');
+      assert(eql(generatorA(), generatorB()),
+        'eql(generatorA(), generatorB())');
+    });
+
+    it('returns true for different generator function calls are at level of iteration with same results', function () {
+      var generatorA = eval('function * generatorA() { yield 1; yield 2; yield 3; }; generatorA');
+      var generatorB = eval('function * generatorB() { yield 6; yield 2; yield 3; }; generatorB');
+      var generatorAIterator = generatorA();
+      var generatorBIterator = generatorB();
+      generatorAIterator.next();
+      generatorBIterator.next();
+      assert(eql(generatorAIterator, generatorBIterator),
+        'eql(generatorAIterator, generatorBIterator');
+    });
+
+    it('returns false for same generator function calls that return different results', function () {
+      var generator = eval('var set = 0; function * generator() { yield set++; }; generator');
+      assert(eql(generator(), generator()) === false,
+        'eql(generator(), generator()) === false');
+    });
+
+    it('returns false for generators at different stages of iteration', function () {
+      var generatorA = eval('function * generatorA() { yield 1; yield 2; }; generatorA');
+      var generatorB = eval('function * generatorB() { yield 1; yield 2; }; generatorB');
+      var generatorBIterator = generatorB();
+      generatorBIterator.next();
+      assert(eql(generatorA(), generatorBIterator) === false,
+        'eql(generatorA(), generatorBIterator) === false');
+    });
+
+    it('returns false for generators if one is done', function () {
+      var generatorA = eval('function * generatorA() { yield 1; yield 2; }; generatorA');
+      var generatorB = eval('function * generatorB() { yield 1; yield 2; }; generatorB');
+      var generatorBIterator = generatorB();
+      generatorBIterator.next();
+      generatorBIterator.next();
+      generatorBIterator.next();
+      assert(eql(generatorA(), generatorBIterator) === false,
+        'eql(generatorA(), generatorBIterator) === false');
+    });
+
+  });
+
+});

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-deep-eql.git



More information about the Pkg-javascript-commits mailing list