From 451838bccefdff1b63662dfabcf465fa6e6303e1 Mon Sep 17 00:00:00 2001 From: Jayce Pulsipher Date: Wed, 22 Jan 2014 01:22:44 -0700 Subject: [PATCH] initial commit --- .gitattributes | 22 +++++ .gitignore | 217 ++++++++++++++++++++++++++++++++++++++++++++++ Makefile | 5 ++ README.md | 31 +++++++ index.js | 85 ++++++++++++++++++ package.json | 31 +++++++ test/congruent.js | 122 ++++++++++++++++++++++++++ 7 files changed, 513 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README.md create mode 100644 index.js create mode 100644 package.json create mode 100644 test/congruent.js diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..412eeda --- /dev/null +++ b/.gitattributes @@ -0,0 +1,22 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Custom for Visual Studio +*.cs diff=csharp +*.sln merge=union +*.csproj merge=union +*.vbproj merge=union +*.fsproj merge=union +*.dbproj merge=union + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..13ba08a --- /dev/null +++ b/.gitignore @@ -0,0 +1,217 @@ +################# +## Eclipse +################# + +*.pydevproject +.project +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.classpath +.settings/ +.loadpath + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# PDT-specific +.buildpath + + +################# +## Visual Studio +################# + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +build/ +[Bb]in/ +[Oo]bj/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.Publish.xml +*.pubxml + +# NuGet Packages Directory +## TODO: If you have NuGet Package Restore enabled, uncomment the next line +#packages/ + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.[Pp]ublish.xml +*.pfx +*.publishsettings + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +############# +## Windows detritus +############# + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + + +############# +## Python +############# + +*.py[co] + +# Packages +*.egg +*.egg-info +dist/ +build/ +eggs/ +parts/ +var/ +sdist/ +develop-eggs/ +.installed.cfg + +# Installer logs +pip-log.txt + +# Unit test / coverage reports +.coverage +.tox + +#Translations +*.mo + +#Mr Developer +.mr.developer.cfg + +node_modules \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..17383ae --- /dev/null +++ b/Makefile @@ -0,0 +1,5 @@ + +test: + @./node_modules/.bin/mocha --reporter spec + +.PHONY: test \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..7ddcbdd --- /dev/null +++ b/README.md @@ -0,0 +1,31 @@ +# congruent + +Deep comparison of two variables + +This is different from [deep-equal](https://github.com/substack/node-deep-equal) in that it will compare +Buffers, Regular Expressions, and NaN (In my opinion, NaN should equal NaN) + +```javascript + +var congruent = require('congruent'); + +congruent([1, 2, 3], new Array(1, 2, 3)); +// true; + +congruent(NaN, NaN); +// true; + +congruent({ a: [1, 2, 3] }, { a: [1, 3, 2] }); +// false; + +``` + +## congruent(a, b, strict) + +* strict - Use strict comparison (===) between primitives (Boolean, String, Number) (default: false) + +## Installation + +```bash +npm install congruent +``` \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..d675aba --- /dev/null +++ b/index.js @@ -0,0 +1,85 @@ +var fastApply = require('fast-apply') + , isArgs = require('is-args') +; + +module.exports = congruent; + +function congruent(actual, expected, strict) { + if (actual === expected) return true; + + // isNaN test + if (actual !== actual && expected !== expected) return true; + + var actualType = typeof actual + , expectedType = typeof expected + , i + ; + + if (actualType !== 'object' && expectedType !== 'object') return strict ? actual === expected : actual == expected; + + // null is an object, but cannot have properties; stop here + if (actual === null || expected === null) return false; + + if (actualType !== expectedType) return false; + + if (actual.prototype !== expected.prototype) return false; + + if (actual instanceof Date) return actual.getTime() === expected.getTime(); + + if (actual instanceof RegExp) { + return actual.source === expected.source + && actual.lastIndex === expected.lastIndex + && actual.global === expected.global + && actual.multiline === expected.multiline + && actual.ignoreCase === expected.ignoreCase + ; + } + + if (Buffer && Buffer.isBuffer(actual)) { + if (actual.length !== expected.length) return false; + + i = actual.length; + + while (--i >= 0) { + if (actual[i] !== expected[i]) return false; + } + + return true; + } + + var actualArg = isArgs(actual) + , expectedArg = isArgs(expected) + ; + + if (actualArg || expectedArg) { + if (!actualArg || !expectedArg) return false; + actual = fastApply(Array, null, actual); + expected = fastApply(Array, null, expected); + } + + var actualKeys = Object.keys(actual) + , expectedKeys = Object.keys(expected) + , key + ; + + if (actualKeys.length !== expectedKeys.length) return false; + + actualKeys.sort(); + expectedKeys.sort(); + + i = actualKeys.length; + + while (--i >= 0) { + if (actualKeys[i] !== expectedKeys[i]) return false; + } + + i = actualKeys.length; + + while (--i >= 0) { + key = actualKeys[i]; + if (!congruent(actual[key], expected[key], strict)) return false; + } + + return true; + +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..ab9bee4 --- /dev/null +++ b/package.json @@ -0,0 +1,31 @@ +{ + "name": "congruent", + "version": "0.0.0", + "description": "Deep comparison of two variables", + "main": "index.js", + "directories": { + "test": "test" + }, + "dependencies": { + "fast-apply": "*", + "is-args": "*" + }, + "devDependencies": { + "mocha": "*", + "should": "*" + }, + "scripts": { + "test": "mocha --reporter spec" + }, + "repository": { + "type": "git", + "url": "https://github.com/JayceTDE/congruent.git" + }, + "keywords": [ + "deep", + "equal", + "compare" + ], + "author": "Jayce Pulsipher ", + "license": "MIT" +} diff --git a/test/congruent.js b/test/congruent.js new file mode 100644 index 0000000..2163725 --- /dev/null +++ b/test/congruent.js @@ -0,0 +1,122 @@ +var congruent = require('..') + , should = require('should') +; + +describe('congruent', function () { + + it('should pass all `deep-equal` tests', function () { + + congruent( + { a : [ 2, 3 ], b : [ 4 ] }, + { a : [ 2, 3 ], b : [ 4 ] } + ).should.be.true; + + congruent( + { x : 5, y : [6] }, + { x : 5, y : 6 } + ).should.be.false; + + congruent( + [ null, null, null ], + [ null, null, null ] + ).should.be.true; + + congruent( + [ { a: 3 }, { b: 4 } ], + [ { a: '3' }, { b: '4' } ], + true + ).should.be.false; + + congruent(3, 3).should.be.true; + congruent('beep', 'beep').should.be.true; + congruent('3', 3).should.be.true; + congruent('3', 3, true).should.be.false; + congruent('3', [3]).should.be.false; + + congruent( + (function(){return arguments})(1,2,3), + (function(){return arguments})(1,2,3) + ).should.be.true; + congruent( + (function(){return arguments})(1,2,3), + [1,2,3] + ).should.be.false; + congruent( + [1,2,3], + (function(){return arguments})(1,2,3) + ).should.be.false; + + var d0 = new Date(1387585278000); + var d1 = new Date('Fri Dec 20 2013 16:21:18 GMT-0800 (PST)'); + + congruent(d0, d1).should.be.true; + + }); + + it('should return true for NaN', function () { + congruent(NaN, NaN).should.be.true; + congruent({ a: NaN }, { a: NaN }).should.be.true; + + congruent(123, NaN).should.be.false; + congruent(NaN, 'abc').should.be.false; + + congruent('abc', NaN).should.be.false; + }); + + it('should compare buffers', function () { + var b1 = new Buffer('foobar') + , b2 = new Buffer('foobar') + , b3 = new Buffer('foobaz') + ; + + congruent(b1, b2).should.be.true; + congruent(b1, b3).should.be.false; + + congruent(b1, 'foobar').should.be.false; + congruent('foobar', b1).should.be.false; + }); + + it('should inspect all values of an array', function () { + var a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] + , b = a.slice() + , c = a .slice() + ; + + c[7] = 3; + + congruent(a, b).should.be.true; + congruent(a, c).should.be.false; + + congruent('abc', a).should.be.false; + }); + + it('should compare regular expressions', function () { + + var a = /abc/gi + , b = new RegExp('abc', 'gi') + , c = /abc/gim + , d = /def/gi + , e = /abc/gi + ; + + e.test('foo abc bar'); + + congruent(a, b).should.be.true; + congruent(a, c).should.be.false; + congruent(a, d).should.be.false; + congruent(a, e).should.be.false; + + }); + + it('should compare null and undefined', function () { + congruent(null, null).should.be.true; + congruent(undefined, undefined).should.be.true; + + congruent(null, undefined).should.be.false; + congruent(null, false).should.be.false; + + congruent({ a: 1 }, null).should.be.false; + congruent({ a: 1 }, undefined).should.be.false; + }); + +}); \ No newline at end of file