UNPKG

deep-equal-x

Version:

node's deepEqual and deepStrictEqual algorithm.

678 lines (599 loc) 19 kB
/*jslint maxlen:80, es6:true, this:true, white:true */ /*jshint bitwise:true, camelcase:true, curly:true, eqeqeq:true, forin:true, freeze:true, futurehostile:true, latedef:true, newcap:true, nocomma:true, nonbsp:true, singleGroups:true, strict:true, undef:true, unused:true, es3:false, esnext:true, plusplus:true, maxparams:2, maxdepth:2, maxstatements:37, maxcomplexity:8 */ /*global JSON:true, expect, module, require, jasmine, describe, it, xit, returnExports*/ (function () { 'use strict'; var ifBufferSupport, ifArrayBufferSupport, ifSymbolSupport, ifMapSupport, ifSetSupport, deepEqual; if (typeof module === 'object' && module.exports) { require('es5-shim'); require('es5-shim/es5-sham'); if (typeof JSON === 'undefined') { JSON = {}; } require('json3').runInContext(null, JSON); require('es6-shim'); deepEqual = require('../../index.js'); } else { deepEqual = returnExports; } ifBufferSupport = typeof Buffer === 'function' ? it : xit; ifArrayBufferSupport = typeof ArrayBuffer === 'function' ? it : xit; ifSymbolSupport = typeof Symbol === 'function' && typeof Symbol() === 'symbol' ? it : xit; ifMapSupport = typeof Map !== 'undefined' ? it : xit; ifSetSupport = typeof Set !== 'undefined' ? it : xit; describe('deepEqual', function () { describe('7.2', function () { it('Dates', function () { expect(deepEqual(new Date(), new Date(2000, 3, 14))).toBe(false); expect( deepEqual(new Date(2000, 3, 14), new Date(2000, 3, 14)) ).toBe(true); }); }); describe('7.3', function () { it('RegExps', function () { var re1 = /a/; re1.lastIndex = 3; expect(deepEqual(/ab/, /a/)).toBe(false); expect(deepEqual(/a/g, /a/)).toBe(false); expect(deepEqual(/a/i, /a/)).toBe(false); expect(deepEqual(/a/m, /a/)).toBe(false); expect(deepEqual(/a/igm, /a/im)).toBe(false); expect(deepEqual(re1, /a/)).toBe(false); re1.lastIndex = 0; expect(deepEqual(re1, /a/)).toBe(true); expect(deepEqual(/a/, /a/)).toBe(true); expect(deepEqual(/a/g, /a/g)).toBe(true); expect(deepEqual(/a/i, /a/i)).toBe(true); expect(deepEqual(/a/m, /a/m)).toBe(true); expect(deepEqual(/a/igm, /a/igm)).toBe(true); }); }); describe('7.4', function () { it('`==` equality', function () { expect(deepEqual(4, '5')).toBe(false); expect(deepEqual(4, '4')).toBe(true); expect(deepEqual(true, 1)).toBe(true); }); }); describe('7.5', function () { it('own properties & keys (not necessarily the same order)', function () { var a1 = [1, 2, 3], a2 = [1, 2, 3]; a1.a = 'test'; a1.b = true; a2.b = true; a2.a = 'test'; expect(deepEqual({ a: 4 }, { a: 4, b: true })).toBe(false); expect(deepEqual(Object.keys(a1), Object.keys(a2))).toBe(false); expect(deepEqual({ a: 4 }, { a: 4 })).toBe(true); expect(deepEqual({ a: 4, b: '2' }, { a: 4, b: '2' })).toBe(true); expect(deepEqual([4], ['4'])).toBe(true); expect(deepEqual(['a'], { 0: 'a' })).toBe(true); expect(deepEqual({ a: 4, b: '1' }, { b: '1', a: 4 })).toBe(true); expect(deepEqual(a1, a2)).toBe(true); a1.d = 1; a2.c = 1; expect(deepEqual(a1, a2)).toBe(false); }); }); describe('instances', function () { /** * Test constructor 1. * * @private * @constructor * @param {string} first A persons first name. * @param {string} last A persons last name. */ function NameBuilder1(first, last) { this.first = first; this.last = last; } NameBuilder1.prototype = { /** * Get a string representation of the object. * * @private * @return {string} Full name. */ toString: function () { return this.first + ' ' + this.last; } }; /** * Test constructor 2. * * @private * @constructor * @param {string} first A persons first name. * @param {string} last A persons last name. */ function NameBuilder2(first, last) { this.first = first; this.last = last; } NameBuilder2.prototype = Object; it('prototype property comparison', function () { var nb1, nb2; nb1 = new NameBuilder1('John', 'Smith'); nb2 = new NameBuilder2('John', 'Smith'); expect(deepEqual(nb1, nb2)).toBe(true); expect(deepEqual('a', {})).toBe(false); NameBuilder2.prototype = NameBuilder1.prototype; nb1 = new NameBuilder1('John', 'Smith'); nb2 = new NameBuilder2('John', 'Smith'); expect(deepEqual(nb1, nb2)).toBe(true); }); }); describe('ES6 primitives', function () { it('compared to similar objects', function () { expect(deepEqual(null, {})).toBe(false); expect(deepEqual(undefined, {})).toBe(false); expect(deepEqual('a', ['a'])).toBe(false); expect(deepEqual('a', { 0: 'a' })).toBe(false); expect(deepEqual(1, {})).toBe(false); expect(deepEqual(true, {})).toBe(false); }); }); describe('ES6 symbols', function () { ifSymbolSupport('compared to similar objects', function () { var syma = Symbol('a'), symb = Symbol('b'); expect(deepEqual(syma, syma)).toBe(true); expect(deepEqual(syma, symb)).toBe(false); expect(deepEqual(syma, {})).toBe(false); }); }); describe('object wrappers', function () { it('when comparing similar objects', function () { expect(deepEqual(Object('a'), ['a'])).toBe(true); expect(deepEqual(Object('a'), { 0: 'a' })).toBe(true); expect(deepEqual(Object(1), {})).toBe(true); expect(deepEqual(Object(true), {})).toBe(true); }); }); describe('Buffer', function () { ifBufferSupport('comparing two buffers', function () { var b1 = new Buffer([1, 2, 3]), b2 = new Buffer([1, 2, 3]), b3 = new Buffer([1, 2]); expect(deepEqual(b1, b1)).toBe(true); expect(deepEqual(b1, b2)).toBe(true); expect(deepEqual(b1, b3)).toBe(false); }); }); describe('ArrayBuffer', function () { ifArrayBufferSupport('comparing two array buffers', function () { var b1 = new Int32Array([1, 2, 3]), b2 = new Int32Array([1, 2, 3]), b3 = new Int32Array([1, 2]); expect(deepEqual(b1, b1)).toBe(true); expect(deepEqual(b1, b2)).toBe(true); expect(deepEqual(b1, b3)).toBe(false); }); }); describe('Map', function () { ifMapSupport('comparing two maps', function () { var m1 = new Map(), m2 = new Map(); m1.set(1, 2); m1.set(2, 3); m2.set(1, 2); expect(deepEqual(m1, m1)).toBe(true); expect(deepEqual(m1, m2)).toBe(true); }); }); describe('Set', function () { ifSetSupport('comparing two set', function () { var s1 = new Set(), s2 = new Set(); s1.add(1); s1.add(2); s2.add(1); expect(deepEqual(s1, s1)).toBe(true); expect(deepEqual(s1, s2)).toBe(true); }); }); describe('non circular refs', function () { it('make sure stack works', function () { var b = { s: '', t: true, u: undefined, v: 1, w: null }, c = { s: '', t: true, u: undefined, v: 1, w: null }; expect(deepEqual(b, c)).toBe(true); }); }); describe('circular refs', function () { it('make sure it doesn\'t loop forever', function () { var b = { s: '', t: true, u: undefined, v: 1, w: null }, c = { s: '', t: true, u: undefined, v: 1, w: null }, gotError = false; b.b = b; c.b = c; try { deepEqual(b, c); } catch (e) { gotError = true; expect(e).toEqual(jasmine.any(RangeError)); expect(e.message).toBe('Circular object'); } expect(gotError).toBe(true); }); }); describe('reflexivity', function () { it('`arguments` objects', function () { var args = (function () { return arguments; }()); expect(deepEqual([], args)).toBe(false); expect(deepEqual(args, [])).toBe(false); }); }); describe('arguments', function () { it('comparing same type objects', function () { var args1 = (function () { return arguments; }(1, 2, 3)), args2 = (function () { return arguments; }(1, 2, 3)), args3 = (function () { return arguments; }(1, 3, 4)); expect(deepEqual(args1, args1)).toBe(true); expect(deepEqual(args1, args2)).toBe(true); expect(deepEqual(args1, args3)).toBe(false); }); }); describe('Examples from node\'s documentation', function () { it('prototypes, symbols, or non-enumerable properties', function () { // WARNING: This does not throw an AssertionError! expect(deepEqual(Error('a'), Error('b'))).toBe(true); }); }); }); // strict describe('deepStrictEqual', function () { describe('7.2', function () { it('Dates', function () { expect(deepEqual(new Date(), new Date(2000, 3, 14), true)).toBe(false); expect( deepEqual(new Date(2000, 3, 14), new Date(2000, 3, 14), true) ).toBe(true); }); }); describe('7.3', function () { it('RegExps', function () { var re1 = /a/; re1.lastIndex = 3; expect(deepEqual(/ab/, /a/, true)).toBe(false); expect(deepEqual(/a/g, /a/, true)).toBe(false); expect(deepEqual(/a/i, /a/, true)).toBe(false); expect(deepEqual(/a/m, /a/, true)).toBe(false); expect(deepEqual(/a/igm, /a/im, true)).toBe(false); expect(deepEqual(re1, /a/, true)).toBe(false); re1.lastIndex = 0; expect(deepEqual(re1, /a/, true)).toBe(true); expect(deepEqual(/a/, /a/, true)).toBe(true); expect(deepEqual(/a/g, /a/g, true)).toBe(true); expect(deepEqual(/a/i, /a/i, true)).toBe(true); expect(deepEqual(/a/m, /a/m, true)).toBe(true); expect(deepEqual(/a/igm, /a/igm, true)).toBe(true); }); }); describe('7.4', function () { it('`===` equality', function () { expect(deepEqual(4, '5', true)).toBe(false); expect(deepEqual(4, '4', true)).toBe(false); expect(deepEqual(true, 1, true)).toBe(false); }); }); describe('7.5', function () { it('own properties & keys (not necessarily the same order)', function () { var a1 = [1, 2, 3], a2 = [1, 2, 3]; a1.a = 'test'; a1.b = true; a2.b = true; a2.a = 'test'; expect(deepEqual({ a: 4 }, { a: 4, b: true }, true)).toBe(false); expect(deepEqual(Object.keys(a1), Object.keys(a2), true)).toBe(false); expect(deepEqual({ a: 4 }, { a: 4 }, true)).toBe(true); expect(deepEqual({ a: 4 }, { a: '4' }, true)).toBe(false); expect(deepEqual({ a: 4, b: '2' }, { a: 4, b: '2' }, true)).toBe(true); expect(deepEqual([4], ['4'], true)).toBe(false); expect(deepEqual(['a'], { 0: 'a' }, true)).toBe(false); expect(deepEqual({ a: 4, b: '1' }, { b: '1', a: 4 }, true)).toBe(true); expect(deepEqual(a1, a2, true)).toBe(true); a1.d = 1; a2.c = 1; expect(deepEqual(a1, a2)).toBe(false); }); }); describe('instances', function () { /** * Test constructor 1. * * @private * @constructor * @param {string} first A persons first name. * @param {string} last A persons last name. */ function NameBuilder1(first, last) { this.first = first; this.last = last; } NameBuilder1.prototype = { /** * Get a string representation of the object. * * @private * @return {string} Full name. */ toString: function () { return this.first + ' ' + this.last; } }; /** * Test constructor 2. * * @private * @constructor * @param {string} first A persons first name. * @param {string} last A persons last name. */ function NameBuilder2(first, last) { this.first = first; this.last = last; } NameBuilder2.prototype = Object; it('prototype property comparison', function () { var nb1, nb2; nb1 = new NameBuilder1('John', 'Smith'); nb2 = new NameBuilder2('John', 'Smith'); expect(deepEqual(nb1, nb2, true)).toBe(false); expect(deepEqual('a', {}, true)).toBe(false); NameBuilder2.prototype = NameBuilder1.prototype; nb1 = new NameBuilder1('John', 'Smith'); nb2 = new NameBuilder2('John', 'Smith'); expect(deepEqual(nb1, nb2, true)).toBe(true); }); }); describe('ES6 primitives', function () { it('compared to similar objects', function () { expect(deepEqual(null, {}, true)).toBe(false); expect(deepEqual(undefined, {}, true)).toBe(false); expect(deepEqual('a', ['a'], true)).toBe(false); expect(deepEqual('a', { 0: 'a' }, true)).toBe(false); expect(deepEqual(1, {}, true)).toBe(false); expect(deepEqual(true, {}, true)).toBe(false); }); }); describe('ES6 symbols', function () { ifSymbolSupport('compared to similar objects', function () { var syma = Symbol('a'), symb = Symbol('b'); expect(deepEqual(syma, syma, true)).toBe(true); expect(deepEqual(syma, symb, true)).toBe(false); expect(deepEqual(syma, {}, true)).toBe(false); }); }); describe('object wrappers', function () { it('when comparing similar objects', function () { expect(deepEqual(Object('a'), ['a'], true)).toBe(false); expect(deepEqual(Object('a'), { 0: 'a' }, true)).toBe(false); expect(deepEqual(Object(1), {}, true)).toBe(false); expect(deepEqual(Object(true), {}, true)).toBe(false); }); }); describe('non circular refs', function () { it('make sure stack works', function () { var b = { s: '', t: true, u: undefined, v: 1, w: null }, c = { s: '', t: true, u: undefined, v: 1, w: null }; expect(deepEqual(b, c, true)).toBe(true); }); }); describe('circular refs', function () { it('make sure it doesn\'t loop forever', function () { var b = { s: '', t: true, u: undefined, v: 1, w: null }, c = { s: '', t: true, u: undefined, v: 1, w: null }, gotError = false; b.b = b; c.b = c; try { deepEqual(b, c, true); } catch (e) { gotError = true; expect(e).toEqual(jasmine.any(RangeError)); expect(e.message).toBe('Circular object'); } expect(gotError).toBe(true); }); }); describe('Buffer', function () { ifBufferSupport('comparing two buffers', function () { var b1 = new Buffer([1, 2, 3]), b2 = new Buffer([1, 2, 3]), b3 = new Buffer([1, 2]); expect(deepEqual(b1, b1, true)).toBe(true); expect(deepEqual(b1, b2, true)).toBe(true); expect(deepEqual(b1, b3, true)).toBe(false); }); }); describe('ArrayBuffer', function () { ifArrayBufferSupport('comparing two array buffers', function () { var b1 = new Int32Array([1, 2, 3]), b2 = new Int32Array([1, 2, 3]), b3 = new Int32Array([1, 2]); expect(deepEqual(b1, b1, true)).toBe(true); expect(deepEqual(b1, b2, true)).toBe(true); expect(deepEqual(b1, b3, true)).toBe(false); }); }); describe('Map', function () { ifMapSupport('comparing two maps', function () { var m1 = new Map(), m2 = new Map(); m1.set(1, 2); m1.set(2, 3); m2.set(1, 2); expect(deepEqual(m1, m1, true)).toBe(true); expect(deepEqual(m1, m2, true)).toBe(true); }); }); describe('Set', function () { ifSetSupport('comparing two set', function () { var s1 = new Set(), s2 = new Set(); s1.add(1); s1.add(2); s2.add(1); expect(deepEqual(s1, s1, true)).toBe(true); expect(deepEqual(s1, s2, true)).toBe(true); }); }); describe('reflexivity', function () { it('`arguments` objects', function () { var args = (function () { return arguments; }()); expect(deepEqual([], args), true).toBe(false); expect(deepEqual(args, []), true).toBe(false); }); }); describe('arguments', function () { it('comparing same type objects', function () { var args1 = (function () { return arguments; }(1, 2, 3)), args2 = (function () { return arguments; }(1, 2, 3)), args3 = (function () { return arguments; }(1, 3, 4)); expect(deepEqual(args1, args1)).toBe(true); expect(deepEqual(args1, args2)).toBe(true); expect(deepEqual(args1, args3)).toBe(false); }); }); describe('Examples from documentation', function () { it('prototypes, symbols, or non-enumerable properties', function () { // WARNING: This does not throw an AssertionError! expect(deepEqual(Error('a'), Error('b'), true)).toBe(true); }); }); }); }());