pax_global_header00006660000000000000000000000064131540611420014507gustar00rootroot0000000000000052 comment=04d6da6518f8ddc288638ca42503752028810120 deep-eql-3.0.1/000077500000000000000000000000001315406114200132045ustar00rootroot00000000000000deep-eql-3.0.1/.gitignore000066400000000000000000000002121315406114200151670ustar00rootroot00000000000000lib-cov *.seed *.log *.csv *.dat *.out *.pid *.gz pids logs results build components node_modules npm-debug.log coverage/ deep-eql.js deep-eql-3.0.1/.travis.yml000066400000000000000000000023051315406114200153150ustar00rootroot00000000000000sudo: false language: node_js addons: sauce_connect: true cache: directories: - node_modules node_js: - 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= deep-eql-3.0.1/LICENSE000066400000000000000000000021251315406114200142110ustar00rootroot00000000000000Copyright (c) 2013 Jake Luer (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. deep-eql-3.0.1/README.md000066400000000000000000000110551315406114200144650ustar00rootroot00000000000000

ChaiJS deep-eql

Improved deep equality testing for [node](http://nodejs.org) and the browser.

license:mit tag:? build:? coverage:? code quality:? dependencies:? devDependencies:? Supported Node Version: 4+
Selenium Test Status
Join the Slack chat Join the Gitter chat

## 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. var deepEql = require("deep-eql"); 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 [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is): - `eql(NaN, NaN).should.be.true;` - `eql(-0, +0).should.be.false;` - All own and inherited enumerable properties are considered: - `eql(Object.create({ foo: { a: 1 } }), Object.create({ foo: { a: 1 } })).should.be.true;` - `eql(Object.create({ foo: { a: 1 } }), Object.create({ foo: { a: 2 } })).should.be.false;` - Arguments are not Arrays: - `eql([], arguments).should.be.false;` - `eql([], Array.prototype.slice.call(arguments)).should.be.true;` - Error objects are compared by reference (see https://github.com/chaijs/chai/issues/608): - `eql(new Error('msg'), new Error('msg')).should.be.false;` - `var err = new Error('msg'); eql(err, err).should.be.true;` deep-eql-3.0.1/bench/000077500000000000000000000000001315406114200142635ustar00rootroot00000000000000deep-eql-3.0.1/bench/.eslintrc000066400000000000000000000004721315406114200161120ustar00rootroot00000000000000{ "extends": [ "strict/test" ], "env": { "node": true, "browser": true, "es6": true }, "rules": { "no-eval": 0, "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 } } deep-eql-3.0.1/bench/index.js000066400000000000000000000116561315406114200157410ustar00rootroot00000000000000'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('() => {}'), eval('() => {}'), false, ]; } catch (error) { console.error('cannot benchmark arrow functions'); } try { fixtures['generator func (differing) '] = [ eval('(function* () {})'), eval('(function* () {})'), 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 = 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~'); }, }); deep-eql-3.0.1/component.json000066400000000000000000000006301315406114200161000ustar00rootroot00000000000000{ "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" } } deep-eql-3.0.1/index.js000066400000000000000000000350761315406114200146640ustar00rootroot00000000000000'use strict'; /* globals Symbol: false, Uint8Array: false, WeakMap: false */ /*! * deep-eql * Copyright(c) 2013 Jake Luer * MIT Licensed */ var type = require('type-detect'); function FakeMap() { this._key = 'chai/deep-eql__' + Math.random() + Date.now(); } FakeMap.prototype = { get: function getMap(key) { return key[this._key]; }, set: function setMap(key, value) { if (Object.isExtensible(key)) { Object.defineProperty(key, this._key, { value: value, configurable: true, }); } }, }; var MemoizeMap = typeof WeakMap === 'function' ? WeakMap : 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) { // Technically, WeakMap keys can *only* be objects, not primitives. if (!memoizeMap || isPrimitive(leftHandOperand) || isPrimitive(rightHandOperand)) { 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) { // Technically, WeakMap keys can *only* be objects, not primitives. if (!memoizeMap || isPrimitive(leftHandOperand) || isPrimitive(rightHandOperand)) { 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) { // If we have a comparator, we can't assume anything; so bail to its check first. if (options && options.comparator) { return extensiveDeepEqual(leftHandOperand, rightHandOperand, options); } var simpleResult = simpleEqual(leftHandOperand, rightHandOperand); if (simpleResult !== null) { return simpleResult; } // Deeper comparisons are pushed through to a larger function return extensiveDeepEqual(leftHandOperand, rightHandOperand, options); } /** * Many comparisons can be canceled out early via simple equality or primitive checks. * @param {Mixed} leftHandOperand * @param {Mixed} rightHandOperand * @return {Boolean|null} equal match */ function simpleEqual(leftHandOperand, rightHandOperand) { // 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; } // Anything that is not an 'object', i.e. symbols, functions, booleans, numbers, // strings, and undefined, can be compared by reference. if (isPrimitive(leftHandOperand) || isPrimitive(rightHandOperand)) { // Easy out b/c it would have passed the first equality check return false; } return null; } /*! * 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; // Check if a memoized result exists. var memoizeResultLeft = memoizeCompare(leftHandOperand, rightHandOperand, options.memoize); if (memoizeResultLeft !== null) { return memoizeResultLeft; } var memoizeResultRight = memoizeCompare(rightHandOperand, leftHandOperand, options.memoize); if (memoizeResultRight !== null) { return memoizeResultRight; } // If a comparator is present, use it. if (comparator) { var comparatorResult = comparator(leftHandOperand, rightHandOperand); // Comparators may return null, in which case we want to go back to default behavior. if (comparatorResult === false || comparatorResult === true) { memoizeSet(leftHandOperand, rightHandOperand, options.memoize, comparatorResult); return comparatorResult; } // To allow comparators to override *any* behavior, we ran them first. Since it didn't decide // what to do, we need to make sure to return the basic tests first before we move on. var simpleResult = simpleEqual(leftHandOperand, rightHandOperand); if (simpleResult !== null) { // Don't memoize this, it takes longer to set/retrieve than to just compare. return simpleResult; } } var leftHandType = type(leftHandOperand); if (leftHandType !== type(rightHandOperand)) { memoizeSet(leftHandOperand, rightHandOperand, options.memoize, false); return false; } // Temporarily set the operands in the memoize object to prevent blowing the stack memoizeSet(leftHandOperand, rightHandOperand, options.memoize, true); var result = extensiveDeepEqualByType(leftHandOperand, rightHandOperand, leftHandType, options); memoizeSet(leftHandOperand, rightHandOperand, 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; } /*! * Gets all own and inherited enumerable keys from a target. * * @param {Object} target * @returns {Array} an array of own and inherited enumerable keys from the target. */ function getEnumerableKeys(target) { var keys = []; for (var key in target) { keys.push(key); } return keys; } /*! * 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) { var leftHandKeys = getEnumerableKeys(leftHandOperand); var rightHandKeys = getEnumerableKeys(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; } /*! * Returns true if the argument is a primitive. * * This intentionally returns true for all objects that can be compared by reference, * including functions and symbols. * * @param {Mixed} value * @return {Boolean} result */ function isPrimitive(value) { return value === null || typeof value !== 'object'; } deep-eql-3.0.1/karma.conf.js000066400000000000000000000050701315406114200155630ustar00rootroot00000000000000'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, ], }, }); } }; deep-eql-3.0.1/package.json000066400000000000000000000046171315406114200155020ustar00rootroot00000000000000{ "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 ", "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@github.com:chaijs/deep-eql.git" }, "scripts": { "bench": "node bench", "build": "browserify $npm_package_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-underscore-dangle": 0, "no-use-before-define": 0 } }, "dependencies": { "type-detect": "^4.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": "^3.1.2", "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": ">=0.12" } } deep-eql-3.0.1/test/000077500000000000000000000000001315406114200141635ustar00rootroot00000000000000deep-eql-3.0.1/test/.eslintrc000066400000000000000000000005231315406114200160070ustar00rootroot00000000000000{ "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 } } deep-eql-3.0.1/test/index.js000066400000000000000000000456771315406114200156530ustar00rootroot00000000000000'use strict'; var assert = require('simple-assert'); var eql = require('..'); var MemoizeMap = require('..').MemoizeMap; function describeIf(condition) { return condition ? describe : describe.skip; } 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'); }); it('doesn\'t crash on weakmap key error (#33)', function () { assert(eql({}, null) === false, 'eql({}, null) === 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 true given two class instances with deeply equal bases', function () { function BaseA() {} function BaseB() {} BaseA.prototype.foo = { a: 1 }; BaseB.prototype.foo = { a: 1 }; assert(eql(new BaseA(), new BaseB()) === true, 'eql(new , new ) === true'); }); 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 class instances with deeply unequal bases', function () { function BaseA() {} function BaseB() {} BaseA.prototype.foo = { a: 1 }; BaseB.prototype.foo = { a: 2 }; assert(eql(new BaseA(), new BaseB()) === false, 'eql(new , new ) === 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 true with objects with deeply equal prototypes', function () { var objectA = Object.create({ foo: { a: 1 } }); var objectB = Object.create({ foo: { a: 1 } }); assert(eql(objectA, objectB) === true, 'eql(Object.create({ foo: { a: 1 } }), Object.create({ foo: { a: 1 } })) === 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 true with circular objects', function () { var objectA = { foo: 1 }; var objectB = { foo: 1 }; objectA.bar = objectB; objectB.bar = objectA; assert(eql(objectA, objectB) === true, 'eql({ foo: 1, bar: -> }, { foo: 1, bar: <- }) === true'); }); it('returns true with non-extensible objects', function () { var objectA = Object.preventExtensions({ foo: 1 }); var objectB = Object.preventExtensions({ foo: 1 }); assert(eql(objectA, objectB) === true, 'eql(Object.preventExtensions({ foo: 1 }), Object.preventExtensions({ foo: 1 })) === true'); }); it('returns true with sealed objects', function () { var objectA = Object.seal({ foo: 1 }); var objectB = Object.seal({ foo: 1 }); assert(eql(objectA, objectB) === true, 'eql(Object.seal({ foo: 1 }), Object.seal({ foo: 1 })) === true'); }); it('returns true with frozen objects', function () { var objectA = Object.freeze({ foo: 1 }); var objectB = Object.freeze({ foo: 1 }); assert(eql(objectA, objectB) === true, 'eql(Object.freeze({ foo: 1 }), Object.freeze({ foo: 1 })) === true'); }); it('returns false with objects with deeply unequal prototypes', function () { var objectA = Object.create({ foo: { a: 1 } }); var objectB = Object.create({ foo: { a: 2 } }); assert(eql(objectA, objectB) === false, 'eql(Object.create({ foo: { a: 1 } }), Object.create({ foo: { a: 2 } })) === 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('Node Specific', function () { describeIf(typeof Buffer === 'function')('buffers', function () { it('returns true for same buffers', function () { assert(eql(new Buffer([ 1 ]), new Buffer([ 1 ])) === true, 'eql(new Buffer([ 1 ]), new Buffer([ 1 ])) === true'); }); it('returns false for different buffers', function () { assert(eql(new Buffer([ 1 ]), new Buffer([ 2 ])) === false, 'eql(new Buffer([ 1 ]), new Buffer([ 2 ])) === 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"}, ) === 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({}, {}, ) === 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({}, {}, ) === 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({}, {}, ) === 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}, ) === 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}, ) === true'); }); it('returns true if Comparator says so even on primitives (switch arg order)', function () { var valueA = { a: 1 }; var valueB = { a: new Matcher(function (value) { return typeof value === 'number'; }), }; assert(eql(valueA, valueB, { comparator: matcherComparator }) === true, 'eql({a:1}, {a:value => typeof value === "number"}, ) === 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}, ) === 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({}, {}, ) === 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({}, {}, ) === 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({}, {}, ) === false'); }); }); deep-eql-3.0.1/test/new-ecmascript-types.js000066400000000000000000000600721315406114200206110ustar00rootroot00000000000000'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 true for circular Sets', function () { var setA = new Set(); var setB = new Set(); setA.add(setB); setB.add(setA); assert(eql(setA, setB) === true, 'eql(Set { -> }, Set { <- }) === true'); }); }); 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)'); promiseReject.catch(function () {}); }); it('returns false for different promises', function () { assert(eql(Promise.resolve(), Promise.resolve()) === false, 'eql(Promise.resolve(), Promise.resolve()) === false'); var promiseRejectA = Promise.reject(); var promiseRejectB = Promise.reject(); assert(eql(promiseRejectA, promiseRejectB) === false, 'eql(Promise.reject(), Promise.reject()) === false'); promiseRejectA.catch(function () {}); promiseRejectB.catch(function () {}); 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'); }); }); });