12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513 |
- // Load modules
- var Fs = require('fs');
- var Path = require('path');
- var Code = require('code');
- var Hoek = require('../lib');
- var Lab = require('lab');
- // Declare internals
- var internals = {};
- // Test shortcuts
- var lab = exports.lab = Lab.script();
- var describe = lab.experiment;
- var it = lab.test;
- var expect = Code.expect;
- var nestedObj = {
- v: [7, 8, 9],
- w: /^something$/igm,
- x: {
- a: [1, 2, 3],
- b: 123456,
- c: new Date(),
- d: /hi/igm,
- e: /hello/
- },
- y: 'y',
- z: new Date(1378775452757)
- };
- var dupsArray = [nestedObj, { z: 'z' }, nestedObj];
- var reducedDupsArray = [nestedObj, { z: 'z' }];
- describe('clone()', function () {
- it('clones a nested object', function (done) {
- var a = nestedObj;
- var b = Hoek.clone(a);
- expect(a).to.deep.equal(b);
- expect(a.z.getTime()).to.equal(b.z.getTime());
- done();
- });
- it('clones a null object', function (done) {
- var b = Hoek.clone(null);
- expect(b).to.equal(null);
- done();
- });
- it('should not convert undefined properties to null', function (done) {
- var obj = { something: undefined };
- var b = Hoek.clone(obj);
- expect(typeof b.something).to.equal('undefined');
- done();
- });
- it('should not throw on circular reference', function (done) {
- var a = {};
- a.x = a;
- var test = function () {
- var b = Hoek.clone(a);
- };
- expect(test).to.not.throw();
- done();
- });
- it('clones circular reference', function (done) {
- var x = {
- 'z': new Date()
- };
- x.y = x;
- var b = Hoek.clone(x);
- expect(Object.keys(b.y)).to.deep.equal(Object.keys(x));
- expect(b.z).to.not.equal(x.z);
- expect(b.y).to.not.equal(x.y);
- expect(b.y.z).to.not.equal(x.y.z);
- expect(b.y).to.equal(b);
- expect(b.y.y.y.y).to.equal(b);
- done();
- });
- it('clones an object with a null prototype', function (done) {
- var obj = Object.create(null);
- var b = Hoek.clone(obj);
- expect(b).to.deep.equal(obj);
- done();
- });
- it('clones deeply nested object', function (done) {
- var a = {
- x: {
- y: {
- a: [1, 2, 3],
- b: 123456,
- c: new Date(),
- d: /hi/igm,
- e: /hello/
- }
- }
- };
- var b = Hoek.clone(a);
- expect(a).to.deep.equal(b);
- expect(a.x.y.c.getTime()).to.equal(b.x.y.c.getTime());
- done();
- });
- it('clones arrays', function (done) {
- var a = [1, 2, 3];
- var b = Hoek.clone(a);
- expect(a).to.deep.equal(b);
- done();
- });
- it('performs actual copy for shallow keys (no pass by reference)', function (done) {
- var x = Hoek.clone(nestedObj);
- var y = Hoek.clone(nestedObj);
- // Date
- expect(x.z).to.not.equal(nestedObj.z);
- expect(x.z).to.not.equal(y.z);
- // Regex
- expect(x.w).to.not.equal(nestedObj.w);
- expect(x.w).to.not.equal(y.w);
- // Array
- expect(x.v).to.not.equal(nestedObj.v);
- expect(x.v).to.not.equal(y.v);
- // Immutable(s)
- x.y = 5;
- expect(x.y).to.not.equal(nestedObj.y);
- expect(x.y).to.not.equal(y.y);
- done();
- });
- it('performs actual copy for deep keys (no pass by reference)', function (done) {
- var x = Hoek.clone(nestedObj);
- var y = Hoek.clone(nestedObj);
- expect(x.x.c).to.not.equal(nestedObj.x.c);
- expect(x.x.c).to.not.equal(y.x.c);
- expect(x.x.c.getTime()).to.equal(nestedObj.x.c.getTime());
- expect(x.x.c.getTime()).to.equal(y.x.c.getTime());
- done();
- });
- it('copies functions with properties', function (done) {
- var a = {
- x: function () {
- return 1;
- },
- y: {}
- };
- a.x.z = 'string in function';
- a.x.v = function () {
- return 2;
- };
- a.y.u = a.x;
- var b = Hoek.clone(a);
- expect(b.x()).to.equal(1);
- expect(b.x.v()).to.equal(2);
- expect(b.y.u).to.equal(b.x);
- expect(b.x.z).to.equal('string in function');
- done();
- });
- it('should copy a buffer', function (done) {
- var tls = {
- key: new Buffer([1, 2, 3, 4, 5]),
- cert: new Buffer([1, 2, 3, 4, 5, 6, 10])
- };
- var copiedTls = Hoek.clone(tls);
- expect(Buffer.isBuffer(copiedTls.key)).to.equal(true);
- expect(JSON.stringify(copiedTls.key)).to.equal(JSON.stringify(tls.key));
- expect(Buffer.isBuffer(copiedTls.cert)).to.equal(true);
- expect(JSON.stringify(copiedTls.cert)).to.equal(JSON.stringify(tls.cert));
- done();
- });
- it('clones an object with a prototype', function (done) {
- var Obj = function () {
- this.a = 5;
- };
- Obj.prototype.b = function () {
- return 'c';
- };
- var a = new Obj();
- var b = Hoek.clone(a);
- expect(b.a).to.equal(5);
- expect(b.b()).to.equal('c');
- expect(a).to.deep.equal(b);
- done();
- });
- it('reuses cloned Date object', function (done) {
- var obj = {
- a: new Date()
- };
- obj.b = obj.a;
- var copy = Hoek.clone(obj);
- expect(copy.a).to.equal(copy.b);
- done();
- });
- it('shallow copies an object with a prototype and isImmutable flag', function (done) {
- var Obj = function () {
- this.value = 5;
- };
- Obj.prototype.b = function () {
- return 'c';
- };
- Obj.prototype.isImmutable = true;
- var obj = {
- a: new Obj()
- };
- var copy = Hoek.clone(obj);
- expect(obj.a.value).to.equal(5);
- expect(copy.a.value).to.equal(5);
- expect(copy.a.b()).to.equal('c');
- expect(obj.a).to.equal(copy.a);
- done();
- });
- it('clones an object with property getter without executing it', function (done) {
- var obj = {};
- var value = 1;
- var execCount = 0;
- Object.defineProperty(obj, 'test', {
- enumerable: true,
- configurable: true,
- get: function () {
- ++execCount;
- return value;
- }
- });
- var copy = Hoek.clone(obj);
- expect(execCount).to.equal(0);
- expect(copy.test).to.equal(1);
- expect(execCount).to.equal(1);
- done();
- });
- it('clones an object with property getter and setter', function (done) {
- var obj = {
- _test: 0
- };
- Object.defineProperty(obj, 'test', {
- enumerable: true,
- configurable: true,
- get: function () {
- return this._test;
- },
- set: function (value) {
- this._test = value - 1;
- }
- });
- var copy = Hoek.clone(obj);
- expect(copy.test).to.equal(0);
- copy.test = 5;
- expect(copy.test).to.equal(4);
- done();
- });
- it('clones an object with only property setter', function (done) {
- var obj = {
- _test: 0
- };
- Object.defineProperty(obj, 'test', {
- enumerable: true,
- configurable: true,
- set: function (value) {
- this._test = value - 1;
- }
- });
- var copy = Hoek.clone(obj);
- expect(copy._test).to.equal(0);
- copy.test = 5;
- expect(copy._test).to.equal(4);
- done();
- });
- it('clones an object with non-enumerable properties', function (done) {
- var obj = {
- _test: 0
- };
- Object.defineProperty(obj, 'test', {
- enumerable: false,
- configurable: true,
- set: function (value) {
- this._test = value - 1;
- }
- });
- var copy = Hoek.clone(obj);
- expect(copy._test).to.equal(0);
- copy.test = 5;
- expect(copy._test).to.equal(4);
- done();
- });
- it('clones an object where getOwnPropertyDescriptor returns undefined', function (done) {
- var oldGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
- var obj = { a: 'b' };
- Object.getOwnPropertyDescriptor = function () {
- return undefined;
- };
- var copy = Hoek.clone(obj);
- Object.getOwnPropertyDescriptor = oldGetOwnPropertyDescriptor;
- expect(copy).to.deep.equal(obj);
- done();
- });
- });
- describe('merge()', function () {
- it('deep copies source items', function (done) {
- var target = {
- b: 3,
- d: []
- };
- var source = {
- c: {
- d: 1
- },
- d: [{ e: 1 }]
- };
- Hoek.merge(target, source);
- expect(target.c).to.not.equal(source.c);
- expect(target.c).to.deep.equal(source.c);
- expect(target.d).to.not.equal(source.d);
- expect(target.d[0]).to.not.equal(source.d[0]);
- expect(target.d).to.deep.equal(source.d);
- done();
- });
- it('merges array over an object', function (done) {
- var a = {
- x: ['n', 'm']
- };
- var b = {
- x: {
- n: '1',
- m: '2'
- }
- };
- Hoek.merge(b, a);
- expect(a.x[0]).to.equal('n');
- expect(a.x.n).to.not.exist();
- done();
- });
- it('merges object over an array', function (done) {
- var a = {
- x: ['n', 'm']
- };
- var b = {
- x: {
- n: '1',
- m: '2'
- }
- };
- Hoek.merge(a, b);
- expect(a.x.n).to.equal('1');
- expect(a.x[0]).to.not.exist();
- done();
- });
- it('does not throw if source is null', function (done) {
- var a = {};
- var b = null;
- var c = null;
- expect(function () {
- c = Hoek.merge(a, b);
- }).to.not.throw();
- expect(c).to.equal(a);
- done();
- });
- it('does not throw if source is undefined', function (done) {
- var a = {};
- var b;
- var c = null;
- expect(function () {
- c = Hoek.merge(a, b);
- }).to.not.throw();
- expect(c).to.equal(a);
- done();
- });
- it('throws if source is not an object', function (done) {
- expect(function () {
- var a = {};
- var b = 0;
- Hoek.merge(a, b);
- }).to.throw('Invalid source value: must be null, undefined, or an object');
- done();
- });
- it('throws if target is not an object', function (done) {
- expect(function () {
- var a = 0;
- var b = {};
- Hoek.merge(a, b);
- }).to.throw('Invalid target value: must be an object');
- done();
- });
- it('throws if target is not an array and source is', function (done) {
- expect(function () {
- var a = {};
- var b = [1, 2];
- Hoek.merge(a, b);
- }).to.throw('Cannot merge array onto an object');
- done();
- });
- it('returns the same object when merging arrays', function (done) {
- var a = [];
- var b = [1, 2];
- expect(Hoek.merge(a, b)).to.equal(a);
- done();
- });
- it('combines an empty object with a non-empty object', function (done) {
- var a = {};
- var b = nestedObj;
- var c = Hoek.merge(a, b);
- expect(a).to.deep.equal(b);
- expect(c).to.deep.equal(b);
- done();
- });
- it('overrides values in target', function (done) {
- var a = { x: 1, y: 2, z: 3, v: 5, t: 'test', m: 'abc' };
- var b = { x: null, z: 4, v: 0, t: { u: 6 }, m: '123' };
- var c = Hoek.merge(a, b);
- expect(c.x).to.equal(null);
- expect(c.y).to.equal(2);
- expect(c.z).to.equal(4);
- expect(c.v).to.equal(0);
- expect(c.m).to.equal('123');
- expect(c.t).to.deep.equal({ u: 6 });
- done();
- });
- it('overrides values in target (flip)', function (done) {
- var a = { x: 1, y: 2, z: 3, v: 5, t: 'test', m: 'abc' };
- var b = { x: null, z: 4, v: 0, t: { u: 6 }, m: '123' };
- var d = Hoek.merge(b, a);
- expect(d.x).to.equal(1);
- expect(d.y).to.equal(2);
- expect(d.z).to.equal(3);
- expect(d.v).to.equal(5);
- expect(d.m).to.equal('abc');
- expect(d.t).to.deep.equal('test');
- done();
- });
- it('retains Date properties', function (done) {
- var a = { x: new Date(1378776452757) };
- var b = Hoek.merge({}, a);
- expect(a.x.getTime()).to.equal(b.x.getTime());
- done();
- });
- it('retains Date properties when merging keys', function (done) {
- var a = { x: new Date(1378776452757) };
- var b = Hoek.merge({ x: {} }, a);
- expect(a.x.getTime()).to.equal(b.x.getTime());
- done();
- });
- it('overrides Buffer', function (done) {
- var a = { x: new Buffer('abc') };
- var b = Hoek.merge({ x: {} }, a);
- expect(a.x.toString()).to.equal('abc');
- done();
- });
- });
- describe('applyToDefaults()', function () {
- var defaults = {
- a: 1,
- b: 2,
- c: {
- d: 3,
- e: [5, 6]
- },
- f: 6,
- g: 'test'
- };
- it('throws when target is null', function (done) {
- expect(function () {
- Hoek.applyToDefaults(null, {});
- }).to.throw('Invalid defaults value: must be an object');
- done();
- });
- it('returns null if options is false', function (done) {
- var result = Hoek.applyToDefaults(defaults, false);
- expect(result).to.equal(null);
- done();
- });
- it('returns null if options is null', function (done) {
- var result = Hoek.applyToDefaults(defaults, null);
- expect(result).to.equal(null);
- done();
- });
- it('returns null if options is undefined', function (done) {
- var result = Hoek.applyToDefaults(defaults, undefined);
- expect(result).to.equal(null);
- done();
- });
- it('returns a copy of defaults if options is true', function (done) {
- var result = Hoek.applyToDefaults(defaults, true);
- expect(result).to.deep.equal(defaults);
- done();
- });
- it('applies object to defaults', function (done) {
- var obj = {
- a: null,
- c: {
- e: [4]
- },
- f: 0,
- g: {
- h: 5
- }
- };
- var result = Hoek.applyToDefaults(defaults, obj);
- expect(result.c.e).to.deep.equal([4]);
- expect(result.a).to.equal(1);
- expect(result.b).to.equal(2);
- expect(result.f).to.equal(0);
- expect(result.g).to.deep.equal({ h: 5 });
- done();
- });
- it('applies object to defaults with null', function (done) {
- var obj = {
- a: null,
- c: {
- e: [4]
- },
- f: 0,
- g: {
- h: 5
- }
- };
- var result = Hoek.applyToDefaults(defaults, obj, true);
- expect(result.c.e).to.deep.equal([4]);
- expect(result.a).to.equal(null);
- expect(result.b).to.equal(2);
- expect(result.f).to.equal(0);
- expect(result.g).to.deep.equal({ h: 5 });
- done();
- });
- });
- describe('cloneWithShallow()', function () {
- it('deep clones except for listed keys', function (done) {
- var source = {
- a: {
- b: 5
- },
- c: {
- d: 6
- }
- };
- var copy = Hoek.cloneWithShallow(source, ['c']);
- expect(copy).to.deep.equal(source);
- expect(copy).to.not.equal(source);
- expect(copy.a).to.not.equal(source.a);
- expect(copy.b).to.equal(source.b);
- done();
- });
- it('returns immutable value', function (done) {
- expect(Hoek.cloneWithShallow(5)).to.equal(5);
- done();
- });
- it('returns null value', function (done) {
- expect(Hoek.cloneWithShallow(null)).to.equal(null);
- done();
- });
- it('returns undefined value', function (done) {
- expect(Hoek.cloneWithShallow(undefined)).to.equal(undefined);
- done();
- });
- it('deep clones except for listed keys (including missing keys)', function (done) {
- var source = {
- a: {
- b: 5
- },
- c: {
- d: 6
- }
- };
- var copy = Hoek.cloneWithShallow(source, ['c', 'v']);
- expect(copy).to.deep.equal(source);
- expect(copy).to.not.equal(source);
- expect(copy.a).to.not.equal(source.a);
- expect(copy.b).to.equal(source.b);
- done();
- });
- });
- describe('applyToDefaultsWithShallow()', function () {
- it('shallow copies the listed keys from options without merging', function (done) {
- var defaults = {
- a: {
- b: 5,
- e: 3
- },
- c: {
- d: 7,
- g: 1
- }
- };
- var options = {
- a: {
- b: 4
- },
- c: {
- d: 6,
- f: 7
- }
- };
- var merged = Hoek.applyToDefaultsWithShallow(defaults, options, ['a']);
- expect(merged).to.deep.equal({ a: { b: 4 }, c: { d: 6, g: 1, f: 7 } });
- expect(merged.a).to.equal(options.a);
- expect(merged.a).to.not.equal(defaults.a);
- expect(merged.c).to.not.equal(options.c);
- expect(merged.c).to.not.equal(defaults.c);
- done();
- });
- it('shallow copies the nested keys (override)', function (done) {
- var defaults = {
- a: {
- b: 5
- },
- c: {
- d: 7,
- g: 1
- }
- };
- var options = {
- a: {
- b: 4
- },
- c: {
- d: 6,
- g: {
- h: 8
- }
- }
- };
- var merged = Hoek.applyToDefaultsWithShallow(defaults, options, ['c.g']);
- expect(merged).to.deep.equal({ a: { b: 4 }, c: { d: 6, g: { h: 8 } } });
- expect(merged.c.g).to.equal(options.c.g);
- done();
- });
- it('shallow copies the nested keys (missing)', function (done) {
- var defaults = {
- a: {
- b: 5
- }
- };
- var options = {
- a: {
- b: 4
- },
- c: {
- g: {
- h: 8
- }
- }
- };
- var merged = Hoek.applyToDefaultsWithShallow(defaults, options, ['c.g']);
- expect(merged).to.deep.equal({ a: { b: 4 }, c: { g: { h: 8 } } });
- expect(merged.c.g).to.equal(options.c.g);
- done();
- });
- it('shallow copies the nested keys (override)', function (done) {
- var defaults = {
- a: {
- b: 5
- },
- c: {
- g: {
- d: 7
- }
- }
- };
- var options = {
- a: {
- b: 4
- },
- c: {
- g: {
- h: 8
- }
- }
- };
- var merged = Hoek.applyToDefaultsWithShallow(defaults, options, ['c.g']);
- expect(merged).to.deep.equal({ a: { b: 4 }, c: { g: { h: 8 } } });
- expect(merged.c.g).to.equal(options.c.g);
- done();
- });
- it('shallow copies the nested keys (deeper)', function (done) {
- var defaults = {
- a: {
- b: 5
- }
- };
- var options = {
- a: {
- b: 4
- },
- c: {
- g: {
- r: {
- h: 8
- }
- }
- }
- };
- var merged = Hoek.applyToDefaultsWithShallow(defaults, options, ['c.g.r']);
- expect(merged).to.deep.equal({ a: { b: 4 }, c: { g: { r: { h: 8 } } } });
- expect(merged.c.g.r).to.equal(options.c.g.r);
- done();
- });
- it('shallow copies the nested keys (not present)', function (done) {
- var defaults = {
- a: {
- b: 5
- }
- };
- var options = {
- a: {
- b: 4
- },
- c: {
- g: {
- r: {
- h: 8
- }
- }
- }
- };
- var merged = Hoek.applyToDefaultsWithShallow(defaults, options, ['x.y']);
- expect(merged).to.deep.equal({ a: { b: 4 }, c: { g: { r: { h: 8 } } } });
- done();
- });
- it('shallow copies the listed keys in the defaults', function (done) {
- var defaults = {
- a: {
- b: 1
- }
- };
- var merged = Hoek.applyToDefaultsWithShallow(defaults, {}, ['a']);
- expect(merged.a).to.equal(defaults.a);
- done();
- });
- it('shallow copies the listed keys in the defaults (true)', function (done) {
- var defaults = {
- a: {
- b: 1
- }
- };
- var merged = Hoek.applyToDefaultsWithShallow(defaults, true, ['a']);
- expect(merged.a).to.equal(defaults.a);
- done();
- });
- it('returns null on false', function (done) {
- var defaults = {
- a: {
- b: 1
- }
- };
- var merged = Hoek.applyToDefaultsWithShallow(defaults, false, ['a']);
- expect(merged).to.equal(null);
- done();
- });
- it('throws on missing defaults', function (done) {
- expect(function () {
- Hoek.applyToDefaultsWithShallow(null, {}, ['a']);
- }).to.throw('Invalid defaults value: must be an object');
- done();
- });
- it('throws on invalid defaults', function (done) {
- expect(function () {
- Hoek.applyToDefaultsWithShallow('abc', {}, ['a']);
- }).to.throw('Invalid defaults value: must be an object');
- done();
- });
- it('throws on invalid options', function (done) {
- expect(function () {
- Hoek.applyToDefaultsWithShallow({}, 'abc', ['a']);
- }).to.throw('Invalid options value: must be true, falsy or an object');
- done();
- });
- it('throws on missing keys', function (done) {
- expect(function () {
- Hoek.applyToDefaultsWithShallow({}, true);
- }).to.throw('Invalid keys');
- done();
- });
- it('throws on invalid keys', function (done) {
- expect(function () {
- Hoek.applyToDefaultsWithShallow({}, true, 'a');
- }).to.throw('Invalid keys');
- done();
- });
- });
- describe('deepEqual()', function () {
- it('compares simple values', function (done) {
- expect(Hoek.deepEqual('x', 'x')).to.be.true();
- expect(Hoek.deepEqual('x', 'y')).to.be.false();
- expect(Hoek.deepEqual('x1', 'x')).to.be.false();
- expect(Hoek.deepEqual(-0, +0)).to.be.false();
- expect(Hoek.deepEqual(-0, -0)).to.be.true();
- expect(Hoek.deepEqual(+0, +0)).to.be.true();
- expect(Hoek.deepEqual(+0, -0)).to.be.false();
- expect(Hoek.deepEqual(1, 1)).to.be.true();
- expect(Hoek.deepEqual(0, 0)).to.be.true();
- expect(Hoek.deepEqual(-1, 1)).to.be.false();
- expect(Hoek.deepEqual(NaN, 0)).to.be.false();
- expect(Hoek.deepEqual(NaN, NaN)).to.be.true();
- done();
- });
- it('compares different types', function (done) {
- expect(Hoek.deepEqual([], 5)).to.be.false();
- expect(Hoek.deepEqual(5, [])).to.be.false();
- expect(Hoek.deepEqual({}, null)).to.be.false();
- expect(Hoek.deepEqual(null, {})).to.be.false();
- expect(Hoek.deepEqual('abc', {})).to.be.false();
- expect(Hoek.deepEqual({}, 'abc')).to.be.false();
- done();
- });
- it('compares empty structures', function (done) {
- expect(Hoek.deepEqual([], [])).to.be.true();
- expect(Hoek.deepEqual({}, {})).to.be.true();
- expect(Hoek.deepEqual([], {})).to.be.false();
- done();
- });
- it('compares empty arguments object', function (done) {
- var compare = function () {
- expect(Hoek.deepEqual([], arguments)).to.be.false();
- };
- compare();
- done();
- });
- it('compares empty arguments objects', function (done) {
- var compare = function () {
- var arg1 = arguments;
- var inner = function () {
- expect(Hoek.deepEqual(arg1, arguments)).to.be.false(); // callee is not the same
- };
- inner();
- };
- compare();
- done();
- });
- it('compares dates', function (done) {
- expect(Hoek.deepEqual(new Date(2015, 1, 1), new Date(2015, 1, 1))).to.be.true();
- expect(Hoek.deepEqual(new Date(100), new Date(101))).to.be.false();
- expect(Hoek.deepEqual(new Date(), {})).to.be.false();
- done();
- });
- it('compares regular expressions', function (done) {
- expect(Hoek.deepEqual(/\s/, new RegExp('\\\s'))).to.be.true();
- expect(Hoek.deepEqual(/\s/g, /\s/g)).to.be.true();
- expect(Hoek.deepEqual(/a/, {})).to.be.false();
- expect(Hoek.deepEqual(/\s/g, /\s/i)).to.be.false();
- expect(Hoek.deepEqual(/a/g, /b/g)).to.be.false();
- done();
- });
- it('compares arrays', function (done) {
- expect(Hoek.deepEqual([[1]], [[1]])).to.be.true();
- expect(Hoek.deepEqual([1, 2, 3], [1, 2, 3])).to.be.true();
- expect(Hoek.deepEqual([1, 2, 3], [1, 3, 2])).to.be.false();
- expect(Hoek.deepEqual([1, 2, 3], [1, 2])).to.be.false();
- expect(Hoek.deepEqual([1], [1])).to.be.true();
- done();
- });
- it('compares buffers', function (done) {
- expect(Hoek.deepEqual(new Buffer([1, 2, 3]), new Buffer([1, 2, 3]))).to.be.true();
- expect(Hoek.deepEqual(new Buffer([1, 2, 3]), new Buffer([1, 3, 2]))).to.be.false();
- expect(Hoek.deepEqual(new Buffer([1, 2, 3]), new Buffer([1, 2]))).to.be.false();
- expect(Hoek.deepEqual(new Buffer([1, 2, 3]), {})).to.be.false();
- expect(Hoek.deepEqual(new Buffer([1, 2, 3]), [1, 2, 3])).to.be.false();
- done();
- });
- it('compares objects', function (done) {
- expect(Hoek.deepEqual({ a: 1, b: 2, c: 3 }, { a: 1, b: 2, c: 3 })).to.be.true();
- expect(Hoek.deepEqual({ foo: 'bar' }, { foo: 'baz' })).to.be.false();
- expect(Hoek.deepEqual({ foo: { bar: 'foo' } }, { foo: { bar: 'baz' } })).to.be.false();
- done();
- });
- it('handles circular dependency', function (done) {
- var a = {};
- a.x = a;
- var b = Hoek.clone(a);
- expect(Hoek.deepEqual(a, b)).to.be.true();
- done();
- });
- it('compares an object with property getter without executing it', function (done) {
- var obj = {};
- var value = 1;
- var execCount = 0;
- Object.defineProperty(obj, 'test', {
- enumerable: true,
- configurable: true,
- get: function () {
- ++execCount;
- return value;
- }
- });
- var copy = Hoek.clone(obj);
- expect(Hoek.deepEqual(obj, copy)).to.be.true();
- expect(execCount).to.equal(0);
- expect(copy.test).to.equal(1);
- expect(execCount).to.equal(1);
- done();
- });
- it('compares objects with property getters', function (done) {
- var obj = {};
- Object.defineProperty(obj, 'test', {
- enumerable: true,
- configurable: true,
- get: function () {
- return 1;
- }
- });
- var ref = {};
- Object.defineProperty(ref, 'test', {
- enumerable: true,
- configurable: true,
- get: function () {
- return 2;
- }
- });
- expect(Hoek.deepEqual(obj, ref)).to.be.false();
- done();
- });
- it('compares object prototypes', function (done) {
- var Obj = function () {
- this.a = 5;
- };
- Obj.prototype.b = function () {
- return this.a;
- };
- var Ref = function () {
- this.a = 5;
- };
- Ref.prototype.b = function () {
- return this.a;
- };
- expect(Hoek.deepEqual(new Obj(), new Ref())).to.be.false();
- expect(Hoek.deepEqual(new Obj(), new Obj())).to.be.true();
- expect(Hoek.deepEqual(new Ref(), new Ref())).to.be.true();
- done();
- });
- it('compares plain objects', function (done) {
- var a = Object.create(null);
- var b = Object.create(null);
- a.b = 'c';
- b.b = 'c';
- expect(Hoek.deepEqual(a, b)).to.be.true();
- expect(Hoek.deepEqual(a, { b: 'c' })).to.be.false();
- done();
- });
- it('compares an object with an empty object', function (done) {
- var a = { a: 1, b: 2 };
- expect(Hoek.deepEqual({}, a)).to.be.false();
- expect(Hoek.deepEqual(a, {})).to.be.false();
- done();
- });
- it('compares an object ignoring the prototype', function (done) {
- var a = Object.create(null);
- var b = {};
- expect(Hoek.deepEqual(a, b, { prototype: false })).to.be.true();
- done();
- });
- it('compares an object ignoring the prototype recursively', function (done) {
- var a = [Object.create(null)];
- var b = [{}];
- expect(Hoek.deepEqual(a, b, { prototype: false })).to.be.true();
- done();
- });
- });
- describe('unique()', function () {
- it('ensures uniqueness within array of objects based on subkey', function (done) {
- var a = Hoek.unique(dupsArray, 'x');
- expect(a).to.deep.equal(reducedDupsArray);
- done();
- });
- it('removes duplicated without key', function (done) {
- expect(Hoek.unique([1, 2, 3, 4, 2, 1, 5])).to.deep.equal([1, 2, 3, 4, 5]);
- done();
- });
- });
- describe('mapToObject()', function () {
- it('returns null on null array', function (done) {
- var a = Hoek.mapToObject(null);
- expect(a).to.equal(null);
- done();
- });
- it('converts basic array to existential object', function (done) {
- var keys = [1, 2, 3, 4];
- var a = Hoek.mapToObject(keys);
- for (var i in keys) {
- expect(a[keys[i]]).to.equal(true);
- }
- done();
- });
- it('converts array of objects to existential object', function (done) {
- var keys = [{ x: 1 }, { x: 2 }, { x: 3 }, { y: 4 }];
- var subkey = 'x';
- var a = Hoek.mapToObject(keys, subkey);
- expect(a).to.deep.equal({ 1: true, 2: true, 3: true });
- done();
- });
- });
- describe('intersect()', function () {
- it('returns the common objects of two arrays', function (done) {
- var array1 = [1, 2, 3, 4, 4, 5, 5];
- var array2 = [5, 4, 5, 6, 7];
- var common = Hoek.intersect(array1, array2);
- expect(common.length).to.equal(2);
- done();
- });
- it('returns just the first common object of two arrays', function (done) {
- var array1 = [1, 2, 3, 4, 4, 5, 5];
- var array2 = [5, 4, 5, 6, 7];
- var common = Hoek.intersect(array1, array2, true);
- expect(common).to.equal(5);
- done();
- });
- it('returns null when no common and returning just the first common object of two arrays', function (done) {
- var array1 = [1, 2, 3, 4, 4, 5, 5];
- var array2 = [6, 7];
- var common = Hoek.intersect(array1, array2, true);
- expect(common).to.equal(null);
- done();
- });
- it('returns an empty array if either input is null', function (done) {
- expect(Hoek.intersect([1], null).length).to.equal(0);
- expect(Hoek.intersect(null, [1]).length).to.equal(0);
- done();
- });
- it('returns the common objects of object and array', function (done) {
- var array1 = [1, 2, 3, 4, 4, 5, 5];
- var array2 = [5, 4, 5, 6, 7];
- var common = Hoek.intersect(Hoek.mapToObject(array1), array2);
- expect(common.length).to.equal(2);
- done();
- });
- });
- describe('contain()', function () {
- it('tests strings', function (done) {
- expect(Hoek.contain('abc', 'ab')).to.be.true();
- expect(Hoek.contain('abc', 'abc', { only: true })).to.be.true();
- expect(Hoek.contain('aaa', 'a', { only: true })).to.be.true();
- expect(Hoek.contain('abc', 'b', { once: true })).to.be.true();
- expect(Hoek.contain('abc', ['a', 'c'])).to.be.true();
- expect(Hoek.contain('abc', ['a', 'd'], { part: true })).to.be.true();
- expect(Hoek.contain('abc', 'ac')).to.be.false();
- expect(Hoek.contain('abcd', 'abc', { only: true })).to.be.false();
- expect(Hoek.contain('aab', 'a', { only: true })).to.be.false();
- expect(Hoek.contain('abb', 'b', { once: true })).to.be.false();
- expect(Hoek.contain('abc', ['a', 'd'])).to.be.false();
- expect(Hoek.contain('abc', ['ab', 'bc'])).to.be.false(); // Overlapping values not supported
- done();
- });
- it('tests arrays', function (done) {
- expect(Hoek.contain([1, 2, 3], 1)).to.be.true();
- expect(Hoek.contain([{ a: 1 }], { a: 1 }, { deep: true })).to.be.true();
- expect(Hoek.contain([1, 2, 3], [1, 2])).to.be.true();
- expect(Hoek.contain([{ a: 1 }], [{ a: 1 }], { deep: true })).to.be.true();
- expect(Hoek.contain([1, 1, 2], [1, 2], { only: true })).to.be.true();
- expect(Hoek.contain([1, 2], [1, 2], { once: true })).to.be.true();
- expect(Hoek.contain([1, 2, 3], [1, 4], { part: true })).to.be.true();
- expect(Hoek.contain([[1], [2]], [[1]], { deep: true })).to.be.true();
- expect(Hoek.contain([1, 2, 3], 4)).to.be.false();
- expect(Hoek.contain([{ a: 1 }], { a: 2 }, { deep: true })).to.be.false();
- expect(Hoek.contain([{ a: 1 }], { a: 1 })).to.be.false();
- expect(Hoek.contain([1, 2, 3], [4, 5])).to.be.false();
- expect(Hoek.contain([[3], [2]], [[1]])).to.be.false();
- expect(Hoek.contain([[1], [2]], [[1]])).to.be.false();
- expect(Hoek.contain([{ a: 1 }], [{ a: 2 }], { deep: true })).to.be.false();
- expect(Hoek.contain([1, 3, 2], [1, 2], { only: true })).to.be.false();
- expect(Hoek.contain([1, 2, 2], [1, 2], { once: true })).to.be.false();
- expect(Hoek.contain([0, 2, 3], [1, 4], { part: true })).to.be.false();
- done();
- });
- it('tests objects', function (done) {
- expect(Hoek.contain({ a: 1, b: 2, c: 3 }, 'a')).to.be.true();
- expect(Hoek.contain({ a: 1, b: 2, c: 3 }, ['a', 'c'])).to.be.true();
- expect(Hoek.contain({ a: 1, b: 2, c: 3 }, ['a', 'b', 'c'], { only: true })).to.be.true();
- expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1 })).to.be.true();
- expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1, c: 3 })).to.be.true();
- expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1, d: 4 }, { part: true })).to.be.true();
- expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1, b: 2, c: 3 }, { only: true })).to.be.true();
- expect(Hoek.contain({ a: [1], b: [2], c: [3] }, { a: [1], c: [3] }, { deep: true })).to.be.true();
- expect(Hoek.contain({ a: [{ b: 1 }, { c: 2 }, { d: 3, e: 4 }] }, { a: [{ b: 1 }, { d: 3 }] }, { deep: true })).to.be.true();
- expect(Hoek.contain({ a: [{ b: 1 }, { c: 2 }, { d: 3, e: 4 }] }, { a: [{ b: 1 }, { d: 3 }] }, { deep: true, part: true })).to.be.true();
- expect(Hoek.contain({ a: [{ b: 1 }, { c: 2 }, { d: 3, e: 4 }] }, { a: [{ b: 1 }, { d: 3 }] }, { deep: true, part: false })).to.be.false();
- expect(Hoek.contain({ a: [{ b: 1 }, { c: 2 }, { d: 3, e: 4 }] }, { a: [{ b: 1 }, { d: 3 }] }, { deep: true, only: true })).to.be.false();
- expect(Hoek.contain({ a: [{ b: 1 }, { c: 2 }, { d: 3, e: 4 }] }, { a: [{ b: 1 }, { d: 3 }] }, { deep: true, only: false })).to.be.true();
- expect(Hoek.contain({ a: 1, b: 2, c: 3 }, 'd')).to.be.false();
- expect(Hoek.contain({ a: 1, b: 2, c: 3 }, ['a', 'd'])).to.be.false();
- expect(Hoek.contain({ a: 1, b: 2, c: 3, d: 4 }, ['a', 'b', 'c'], { only: true })).to.be.false();
- expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 2 })).to.be.false();
- expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 2, b: 2 }, { part: true })).to.be.false(); // part does not ignore bad value
- expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1, d: 3 })).to.be.false();
- expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1, d: 4 })).to.be.false();
- expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1, b: 2 }, { only: true })).to.be.false();
- expect(Hoek.contain({ a: [1], b: [2], c: [3] }, { a: [1], c: [3] })).to.be.false();
- expect(Hoek.contain({ a: { b: { c: 1, d: 2 } } }, { a: { b: { c: 1 } } })).to.be.false();
- expect(Hoek.contain({ a: { b: { c: 1, d: 2 } } }, { a: { b: { c: 1 } } }, { deep: true })).to.be.true();
- expect(Hoek.contain({ a: { b: { c: 1, d: 2 } } }, { a: { b: { c: 1 } } }, { deep: true, only: true })).to.be.false();
- expect(Hoek.contain({ a: { b: { c: 1, d: 2 } } }, { a: { b: { c: 1 } } }, { deep: true, only: false })).to.be.true();
- expect(Hoek.contain({ a: { b: { c: 1, d: 2 } } }, { a: { b: { c: 1 } } }, { deep: true, part: true })).to.be.true();
- expect(Hoek.contain({ a: { b: { c: 1, d: 2 } } }, { a: { b: { c: 1 } } }, { deep: true, part: false })).to.be.false();
- // Getter check
- var Foo = function (bar) {
- this.bar = bar;
- };
- Object.defineProperty(Foo.prototype, 'baz', {
- enumerable: true,
- get: function () {
- return this.bar;
- }
- });
- expect(Hoek.contain({ a: new Foo('b') }, { a: new Foo('b') }, { deep: true })).to.be.true();
- expect(Hoek.contain({ a: new Foo('b') }, { a: new Foo('b') }, { deep: true, part: true })).to.be.true();
- expect(Hoek.contain({ a: new Foo('b') }, { a: { baz: 'b' } }, { deep: true })).to.be.true();
- expect(Hoek.contain({ a: new Foo('b') }, { a: { baz: 'b' } }, { deep: true, only: true })).to.be.false();
- expect(Hoek.contain({ a: new Foo('b') }, { a: { baz: 'b' } }, { deep: true, part: false })).to.be.false();
- expect(Hoek.contain({ a: new Foo('b') }, { a: { baz: 'b' } }, { deep: true, part: true })).to.be.true();
- done();
- });
- });
- describe('flatten()', function () {
- it('returns a flat array', function (done) {
- var result = Hoek.flatten([1, 2, [3, 4, [5, 6], [7], 8], [9], [10, [11, 12]], 13]);
- expect(result.length).to.equal(13);
- expect(result).to.deep.equal([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]);
- done();
- });
- });
- describe('reach()', function () {
- var obj = {
- a: {
- b: {
- c: {
- d: 1,
- e: 2
- },
- f: 'hello'
- },
- g: {
- h: 3
- }
- },
- i: function () { },
- j: null,
- k: [4, 8, 9, 1]
- };
- obj.i.x = 5;
- it('returns object itself', function (done) {
- expect(Hoek.reach(obj, null)).to.equal(obj);
- expect(Hoek.reach(obj, false)).to.equal(obj);
- expect(Hoek.reach(obj)).to.equal(obj);
- done();
- });
- it('returns first value of array', function (done) {
- expect(Hoek.reach(obj, 'k.0')).to.equal(4);
- done();
- });
- it('returns last value of array using negative index', function (done) {
- expect(Hoek.reach(obj, 'k.-2')).to.equal(9);
- done();
- });
- it('returns a valid member', function (done) {
- expect(Hoek.reach(obj, 'a.b.c.d')).to.equal(1);
- done();
- });
- it('returns a valid member with separator override', function (done) {
- expect(Hoek.reach(obj, 'a/b/c/d', '/')).to.equal(1);
- done();
- });
- it('returns undefined on null object', function (done) {
- expect(Hoek.reach(null, 'a.b.c.d')).to.equal(undefined);
- done();
- });
- it('returns undefined on missing object member', function (done) {
- expect(Hoek.reach(obj, 'a.b.c.d.x')).to.equal(undefined);
- done();
- });
- it('returns undefined on missing function member', function (done) {
- expect(Hoek.reach(obj, 'i.y', { functions: true })).to.equal(undefined);
- done();
- });
- it('throws on missing member in strict mode', function (done) {
- expect(function () {
- Hoek.reach(obj, 'a.b.c.o.x', { strict: true });
- }).to.throw('Missing segment o in reach path a.b.c.o.x');
- done();
- });
- it('returns undefined on invalid member', function (done) {
- expect(Hoek.reach(obj, 'a.b.c.d-.x')).to.equal(undefined);
- done();
- });
- it('returns function member', function (done) {
- expect(typeof Hoek.reach(obj, 'i')).to.equal('function');
- done();
- });
- it('returns function property', function (done) {
- expect(Hoek.reach(obj, 'i.x')).to.equal(5);
- done();
- });
- it('returns null', function (done) {
- expect(Hoek.reach(obj, 'j')).to.equal(null);
- done();
- });
- it('throws on function property when functions not allowed', function (done) {
- expect(function () {
- Hoek.reach(obj, 'i.x', { functions: false });
- }).to.throw('Invalid segment x in reach path i.x');
- done();
- });
- it('will return a default value if property is not found', function (done) {
- expect(Hoek.reach(obj, 'a.b.q', { default: 'defaultValue' })).to.equal('defaultValue');
- done();
- });
- it('will return a default value if path is not found', function (done) {
- expect(Hoek.reach(obj, 'q', { default: 'defaultValue' })).to.equal('defaultValue');
- done();
- });
- it('allows a falsey value to be used as the default value', function (done) {
- expect(Hoek.reach(obj, 'q', { default: '' })).to.equal('');
- done();
- });
- });
- describe('reachTemplate()', function () {
- it('applies object to template', function (done) {
- var obj = {
- a: {
- b: {
- c: {
- d: 1
- }
- }
- },
- j: null,
- k: [4, 8, 9, 1]
- };
- var template = '{k.0}:{k.-2}:{a.b.c.d}:{x.y}:{j}';
- expect(Hoek.reachTemplate(obj, template)).to.equal('4:9:1::');
- done();
- });
- it('applies object to template (options)', function (done) {
- var obj = {
- a: {
- b: {
- c: {
- d: 1
- }
- }
- },
- j: null,
- k: [4, 8, 9, 1]
- };
- var template = '{k/0}:{k/-2}:{a/b/c/d}:{x/y}:{j}';
- expect(Hoek.reachTemplate(obj, template, '/')).to.equal('4:9:1::');
- done();
- });
- });
- describe('callStack()', function () {
- it('returns the full call stack', function (done) {
- var stack = Hoek.callStack();
- expect(stack[0][0]).to.contain('index.js');
- expect(stack[0][2]).to.equal(26);
- done();
- });
- });
- describe('displayStack ()', function () {
- it('returns the full call stack for display', function (done) {
- var stack = Hoek.displayStack();
- expect(stack[0]).to.contain(Path.normalize('/test/index.js') + ':');
- done();
- });
- it('includes constructor functions correctly', function (done) {
- var Something = function (next) {
- next();
- };
- var something = new Something(function () {
- var stack = Hoek.displayStack();
- expect(stack[1]).to.contain('new Something');
- done();
- });
- });
- });
- describe('abort()', function () {
- it('exits process when not in test mode', function (done) {
- var env = process.env.NODE_ENV;
- var write = process.stdout.write;
- var exit = process.exit;
- process.env.NODE_ENV = 'nottatest';
- process.stdout.write = function () { };
- process.exit = function (state) {
- process.exit = exit;
- process.env.NODE_ENV = env;
- process.stdout.write = write;
- expect(state).to.equal(1);
- done();
- };
- Hoek.abort('Boom');
- });
- it('throws when not in test mode and abortThrow is true', function (done) {
- var env = process.env.NODE_ENV;
- process.env.NODE_ENV = 'nottatest';
- Hoek.abortThrow = true;
- var fn = function () {
- Hoek.abort('my error message');
- };
- expect(fn).to.throw('my error message');
- Hoek.abortThrow = false;
- process.env.NODE_ENV = env;
- done();
- });
- it('respects hideStack argument', function (done) {
- var env = process.env.NODE_ENV;
- var write = process.stdout.write;
- var exit = process.exit;
- var output = '';
- process.exit = function () { };
- process.env.NODE_ENV = '';
- process.stdout.write = function (message) {
- output = message;
- };
- Hoek.abort('my error message', true);
- process.env.NODE_ENV = env;
- process.stdout.write = write;
- process.exit = exit;
- expect(output).to.equal('ABORT: my error message\n\t\n');
- done();
- });
- it('throws in test mode', function (done) {
- var env = process.env.NODE_ENV;
- process.env.NODE_ENV = 'test';
- expect(function () {
- Hoek.abort('my error message', true);
- }).to.throw('my error message');
- process.env.NODE_ENV = env;
- done();
- });
- it('throws in test mode with default message', function (done) {
- var env = process.env.NODE_ENV;
- process.env.NODE_ENV = 'test';
- expect(function () {
- Hoek.abort('', true);
- }).to.throw('Unknown error');
- process.env.NODE_ENV = env;
- done();
- });
- it('defaults to showing stack', function (done) {
- var env = process.env.NODE_ENV;
- var write = process.stdout.write;
- var exit = process.exit;
- var output = '';
- process.exit = function () { };
- process.env.NODE_ENV = '';
- process.stdout.write = function (message) {
- output = message;
- };
- Hoek.abort('my error message');
- process.env.NODE_ENV = env;
- process.stdout.write = write;
- process.exit = exit;
- expect(output).to.contain('index.js');
- done();
- });
- });
- describe('assert()', function () {
- it('throws an Error when using assert in a test', function (done) {
- var fn = function () {
- Hoek.assert(false, 'my error message');
- };
- expect(fn).to.throw('my error message');
- done();
- });
- it('throws an Error when using assert in a test with no message', function (done) {
- var fn = function () {
- Hoek.assert(false);
- };
- expect(fn).to.throw('Unknown error');
- done();
- });
- it('throws an Error when using assert in a test with multipart message', function (done) {
- var fn = function () {
- Hoek.assert(false, 'This', 'is', 'my message');
- };
- expect(fn).to.throw('This is my message');
- done();
- });
- it('throws an Error when using assert in a test with multipart message (empty)', function (done) {
- var fn = function () {
- Hoek.assert(false, 'This', 'is', '', 'my message');
- };
- expect(fn).to.throw('This is my message');
- done();
- });
- it('throws an Error when using assert in a test with object message', function (done) {
- var fn = function () {
- Hoek.assert(false, 'This', 'is', { spinal: 'tap' });
- };
- expect(fn).to.throw('This is {"spinal":"tap"}');
- done();
- });
- it('throws an Error when using assert in a test with multipart string and error messages', function (done) {
- var fn = function () {
- Hoek.assert(false, 'This', 'is', new Error('spinal'), new Error('tap'));
- };
- expect(fn).to.throw('This is spinal tap');
- done();
- });
- it('throws an Error when using assert in a test with error object message', function (done) {
- var fn = function () {
- Hoek.assert(false, new Error('This is spinal tap'));
- };
- expect(fn).to.throw('This is spinal tap');
- done();
- });
- it('throws the same Error that is passed to it if there is only one error passed', function (done) {
- var error = new Error('ruh roh');
- var error2 = new Error('ruh roh');
- var fn = function () {
- Hoek.assert(false, error);
- };
- try {
- fn();
- } catch (err) {
- expect(error).to.equal(error); // should be the same reference
- expect(error).to.not.equal(error2); // error with the same message should not match
- }
- done();
- });
- });
- describe('Timer', function () {
- it('returns time elapsed', function (done) {
- var timer = new Hoek.Timer();
- setTimeout(function () {
- expect(timer.elapsed()).to.be.above(9);
- done();
- }, 12);
- });
- });
- describe('Bench', function () {
- it('returns time elapsed', function (done) {
- var timer = new Hoek.Bench();
- setTimeout(function () {
- expect(timer.elapsed()).to.be.above(9);
- done();
- }, 12);
- });
- });
- describe('escapeRegex()', function () {
- it('escapes all special regular expression characters', function (done) {
- var a = Hoek.escapeRegex('4^f$s.4*5+-_?%=#!:@|~\\/`"(>)[<]d{}s,');
- expect(a).to.equal('4\\^f\\$s\\.4\\*5\\+\\-_\\?%\\=#\\!\\:@\\|~\\\\\\/`"\\(>\\)\\[<\\]d\\{\\}s\\,');
- done();
- });
- });
- describe('Base64Url', function () {
- var base64str = 'AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0-P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn-AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq-wsbKztLW2t7i5uru8vb6_wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t_g4eLj5OXm5-jp6uvs7e7v8PHy8_T19vf4-fr7_P3-_w';
- var str = unescape('%00%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%20%21%22%23%24%25%26%27%28%29*+%2C-./0123456789%3A%3B%3C%3D%3E%3F@ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D%7E%7F%80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF');
- describe('base64urlEncode()', function () {
- it('should base64 URL-safe a string', function (done) {
- expect(Hoek.base64urlEncode(str)).to.equal(base64str);
- done();
- });
- it('encodes a buffer', function (done) {
- expect(Hoek.base64urlEncode(new Buffer(str, 'binary'))).to.equal(base64str);
- done();
- });
- it('should base64 URL-safe a hex string', function (done) {
- var buffer = new Buffer(str, 'binary');
- expect(Hoek.base64urlEncode(buffer.toString('hex'), 'hex')).to.equal(base64str);
- done();
- });
- it('works on larger input strings', function (done) {
- var input = Fs.readFileSync(Path.join(__dirname, 'index.js')).toString();
- var encoded = Hoek.base64urlEncode(input);
- expect(encoded).to.not.contain('+');
- expect(encoded).to.not.contain('/');
- var decoded = Hoek.base64urlDecode(encoded);
- expect(decoded).to.equal(input);
- done();
- });
- });
- describe('base64urlDecode()', function () {
- it('should un-base64 URL-safe a string', function (done) {
- expect(Hoek.base64urlDecode(base64str)).to.equal(str);
- done();
- });
- it('should un-base64 URL-safe a string into hex', function (done) {
- expect(Hoek.base64urlDecode(base64str, 'hex')).to.equal(new Buffer(str, 'binary').toString('hex'));
- done();
- });
- it('should un-base64 URL-safe a string and return a buffer', function (done) {
- var buf = Hoek.base64urlDecode(base64str, 'buffer');
- expect(buf instanceof Buffer).to.equal(true);
- expect(buf.toString('binary')).to.equal(str);
- done();
- });
- it('returns error on undefined input', function (done) {
- expect(Hoek.base64urlDecode().message).to.exist();
- done();
- });
- it('returns error on invalid input', function (done) {
- expect(Hoek.base64urlDecode('*').message).to.exist();
- done();
- });
- });
- });
- describe('escapeHeaderAttribute()', function () {
- it('should not alter ascii values', function (done) {
- var a = Hoek.escapeHeaderAttribute('My Value');
- expect(a).to.equal('My Value');
- done();
- });
- it('escapes all special HTTP header attribute characters', function (done) {
- var a = Hoek.escapeHeaderAttribute('I said go!!!#"' + String.fromCharCode(92));
- expect(a).to.equal('I said go!!!#\\"\\\\');
- done();
- });
- it('throws on large unicode characters', function (done) {
- var fn = function () {
- Hoek.escapeHeaderAttribute('this is a test' + String.fromCharCode(500) + String.fromCharCode(300));
- };
- expect(fn).to.throw(Error);
- done();
- });
- it('throws on CRLF to prevent response splitting', function (done) {
- var fn = function () {
- Hoek.escapeHeaderAttribute('this is a test\r\n');
- };
- expect(fn).to.throw(Error);
- done();
- });
- });
- describe('escapeHtml()', function () {
- it('escapes all special HTML characters', function (done) {
- var a = Hoek.escapeHtml('&<>"\'`');
- expect(a).to.equal('&<>"'`');
- done();
- });
- it('returns empty string on falsy input', function (done) {
- var a = Hoek.escapeHtml('');
- expect(a).to.equal('');
- done();
- });
- it('returns unchanged string on no reserved input', function (done) {
- var a = Hoek.escapeHtml('abc');
- expect(a).to.equal('abc');
- done();
- });
- });
- describe('nextTick()', function () {
- it('calls the provided callback on nextTick', function (done) {
- var a = 0;
- var inc = function (step, next) {
- a += step;
- next();
- };
- var ticked = Hoek.nextTick(inc);
- ticked(5, function () {
- expect(a).to.equal(6);
- done();
- });
- expect(a).to.equal(0);
- inc(1, function () {
- expect(a).to.equal(1);
- });
- });
- });
- describe('once()', function () {
- it('allows function to only execute once', function (done) {
- var gen = 0;
- var add = function (x) {
- gen += x;
- };
- add(5);
- expect(gen).to.equal(5);
- add = Hoek.once(add);
- add(5);
- expect(gen).to.equal(10);
- add(5);
- expect(gen).to.equal(10);
- done();
- });
- it('double once wraps one time', function (done) {
- var method = function () { };
- method = Hoek.once(method);
- method.x = 1;
- method = Hoek.once(method);
- expect(method.x).to.equal(1);
- done();
- });
- });
- describe('isAbsoltePath()', function () {
- it('identifies if path is absolute on Unix without node support', { parallel: false }, function (done) {
- var orig = Path.isAbsolute;
- Path.isAbsolute = undefined;
- expect(Hoek.isAbsolutePath('')).to.equal(false);
- expect(Hoek.isAbsolutePath('a')).to.equal(false);
- expect(Hoek.isAbsolutePath('./a')).to.equal(false);
- expect(Hoek.isAbsolutePath('/a')).to.equal(true);
- expect(Hoek.isAbsolutePath('/')).to.equal(true);
- Path.isAbsolute = orig;
- done();
- });
- it('identifies if path is absolute with fake node support', { parallel: false }, function (done) {
- var orig = Path.isAbsolute;
- Path.isAbsolute = function (path) {
- return path[0] === '/';
- };
- expect(Hoek.isAbsolutePath('', 'linux')).to.equal(false);
- expect(Hoek.isAbsolutePath('a', 'linux')).to.equal(false);
- expect(Hoek.isAbsolutePath('./a', 'linux')).to.equal(false);
- expect(Hoek.isAbsolutePath('/a', 'linux')).to.equal(true);
- expect(Hoek.isAbsolutePath('/', 'linux')).to.equal(true);
- Path.isAbsolute = orig;
- done();
- });
- it('identifies if path is absolute on Windows without node support', { parallel: false }, function (done) {
- var orig = Path.isAbsolute;
- Path.isAbsolute = undefined;
- expect(Hoek.isAbsolutePath('//server/file', 'win32')).to.equal(true);
- expect(Hoek.isAbsolutePath('//server/file', 'win32')).to.equal(true);
- expect(Hoek.isAbsolutePath('\\\\server\\file', 'win32')).to.equal(true);
- expect(Hoek.isAbsolutePath('C:/Users/', 'win32')).to.equal(true);
- expect(Hoek.isAbsolutePath('C:\\Users\\', 'win32')).to.equal(true);
- expect(Hoek.isAbsolutePath('C:cwd/another', 'win32')).to.equal(false);
- expect(Hoek.isAbsolutePath('C:cwd\\another', 'win32')).to.equal(false);
- expect(Hoek.isAbsolutePath('directory/directory', 'win32')).to.equal(false);
- expect(Hoek.isAbsolutePath('directory\\directory', 'win32')).to.equal(false);
- Path.isAbsolute = orig;
- done();
- });
- });
- describe('isInteger()', function () {
- it('validates integers', function (done) {
- expect(Hoek.isInteger(0)).to.equal(true);
- expect(Hoek.isInteger(1)).to.equal(true);
- expect(Hoek.isInteger(1394035612500)).to.equal(true);
- expect(Hoek.isInteger('0')).to.equal(false);
- expect(Hoek.isInteger(1.0)).to.equal(true);
- expect(Hoek.isInteger(1.1)).to.equal(false);
- done();
- });
- });
- describe('ignore()', function () {
- it('exists', function (done) {
- expect(Hoek.ignore).to.exist();
- expect(typeof Hoek.ignore).to.equal('function');
- done();
- });
- });
- describe('inherits()', function () {
- it('exists', function (done) {
- expect(Hoek.inherits).to.exist();
- expect(typeof Hoek.inherits).to.equal('function');
- done();
- });
- });
- describe('format()', function () {
- it('exists', function (done) {
- expect(Hoek.format).to.exist();
- expect(typeof Hoek.format).to.equal('function');
- done();
- });
- it('is a reference to Util.format', function (done) {
- expect(Hoek.format('hello %s', 'world')).to.equal('hello world');
- done();
- });
- });
- describe('transform()', function () {
- var source = {
- address: {
- one: '123 main street',
- two: 'PO Box 1234'
- },
- zip: {
- code: 3321232,
- province: null
- },
- title: 'Warehouse',
- state: 'CA'
- };
- var sourcesArray = [{
- address: {
- one: '123 main street',
- two: 'PO Box 1234'
- },
- zip: {
- code: 3321232,
- province: null
- },
- title: 'Warehouse',
- state: 'CA'
- }, {
- address: {
- one: '456 market street',
- two: 'PO Box 5678'
- },
- zip: {
- code: 9876,
- province: null
- },
- title: 'Garage',
- state: 'NY'
- }];
- it('transforms an object based on the input object', function (done) {
- var result = Hoek.transform(source, {
- 'person.address.lineOne': 'address.one',
- 'person.address.lineTwo': 'address.two',
- 'title': 'title',
- 'person.address.region': 'state',
- 'person.address.zip': 'zip.code',
- 'person.address.location': 'zip.province'
- });
- expect(result).to.deep.equal({
- person: {
- address: {
- lineOne: '123 main street',
- lineTwo: 'PO Box 1234',
- region: 'CA',
- zip: 3321232,
- location: null
- }
- },
- title: 'Warehouse'
- });
- done();
- });
- it('transforms an array of objects based on the input object', function (done) {
- var result = Hoek.transform(sourcesArray, {
- 'person.address.lineOne': 'address.one',
- 'person.address.lineTwo': 'address.two',
- 'title': 'title',
- 'person.address.region': 'state',
- 'person.address.zip': 'zip.code',
- 'person.address.location': 'zip.province'
- });
- expect(result).to.deep.equal([
- {
- person: {
- address: {
- lineOne: '123 main street',
- lineTwo: 'PO Box 1234',
- region: 'CA',
- zip: 3321232,
- location: null
- }
- },
- title: 'Warehouse'
- },
- {
- person: {
- address: {
- lineOne: '456 market street',
- lineTwo: 'PO Box 5678',
- region: 'NY',
- zip: 9876,
- location: null
- }
- },
- title: 'Garage'
- }
- ]);
- done();
- });
- it('uses the reach options passed into it', function (done) {
- var schema = {
- 'person.address.lineOne': 'address-one',
- 'person.address.lineTwo': 'address-two',
- 'title': 'title',
- 'person.address.region': 'state',
- 'person.prefix': 'person-title',
- 'person.zip': 'zip-code'
- };
- var options = {
- separator: '-',
- default: 'unknown'
- };
- var result = Hoek.transform(source, schema, options);
- expect(result).to.deep.equal({
- person: {
- address: {
- lineOne: '123 main street',
- lineTwo: 'PO Box 1234',
- region: 'CA'
- },
- prefix: 'unknown',
- zip: 3321232
- },
- title: 'Warehouse'
- });
- done();
- });
- it('works to create shallow objects', function (done) {
- var result = Hoek.transform(source, {
- lineOne: 'address.one',
- lineTwo: 'address.two',
- title: 'title',
- region: 'state',
- province: 'zip.province'
- });
- expect(result).to.deep.equal({
- lineOne: '123 main street',
- lineTwo: 'PO Box 1234',
- title: 'Warehouse',
- region: 'CA',
- province: null
- });
- done();
- });
- it('only allows strings in the map', function (done) {
- expect(function () {
- var result = Hoek.transform(source, {
- lineOne: {}
- });
- }).to.throw('All mappings must be "." delineated strings');
- done();
- });
- it('throws an error on invalid arguments', function (done) {
- expect(function () {
- var result = Hoek.transform(NaN, {});
- }).to.throw('Invalid source object: must be null, undefined, an object, or an array');
- done();
- });
- it('is safe to pass null', function (done) {
- var result = Hoek.transform(null, {});
- expect(result).to.deep.equal({});
- done();
- });
- it('is safe to pass undefined', function (done) {
- var result = Hoek.transform(undefined, {});
- expect(result).to.deep.equal({});
- done();
- });
- });
- describe('uniqueFilename()', function () {
- it('generates a random file path', function (done) {
- var result = Hoek.uniqueFilename('./test/modules');
- expect(result).to.exist();
- expect(result).to.be.a.string();
- expect(result).to.contain('test/modules');
- done();
- });
- it('is random enough to use in fast loops', function (done) {
- var results = [];
- for (var i = 0; i < 10; ++i) {
- results[i] = Hoek.uniqueFilename('./test/modules');
- }
- var filter = results.filter(function (item, index, array) {
- return array.indexOf(item) === index;
- });
- expect(filter.length).to.equal(10);
- expect(results.length).to.equal(10);
- done();
- });
- it('combines the random elements with a supplied character', function (done) {
- var result = Hoek.uniqueFilename('./test', 'txt');
- expect(result).to.contain('test/');
- expect(result).to.contain('.txt');
- done();
- });
- it('accepts extensions with a "." in it', function (done) {
- var result = Hoek.uniqueFilename('./test', '.mp3');
- expect(result).to.contain('test/');
- expect(result).to.contain('.mp3');
- done();
- });
- });
- describe('stringify()', function (done) {
- it('converts object to string', function (done) {
- var obj = { a: 1 };
- expect(Hoek.stringify(obj)).to.equal('{"a":1}');
- done();
- });
- it('returns error in result string', function (done) {
- var obj = { a: 1 };
- obj.b = obj;
- expect(Hoek.stringify(obj)).to.equal('[Cannot display object: Converting circular structure to JSON]');
- done();
- });
- });
- describe('shallow()', function (done) {
- it('shallow copies an object', function (done) {
- var obj = {
- a: 5,
- b: {
- c: 6
- }
- };
- var shallow = Hoek.shallow(obj);
- expect(shallow).to.not.equal(obj);
- expect(shallow).to.deep.equal(obj);
- expect(shallow.b).to.equal(obj.b);
- done();
- });
- });
|