a zip code crypto-currency system good for red ONLY

index.js 66KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514
  1. // Load modules
  2. var Fs = require('fs');
  3. var Path = require('path');
  4. var Code = require('code');
  5. var Hoek = require('../lib');
  6. var Lab = require('lab');
  7. // Declare internals
  8. var internals = {};
  9. // Test shortcuts
  10. var lab = exports.lab = Lab.script();
  11. var describe = lab.experiment;
  12. var it = lab.test;
  13. var expect = Code.expect;
  14. var nestedObj = {
  15. v: [7, 8, 9],
  16. w: /^something$/igm,
  17. x: {
  18. a: [1, 2, 3],
  19. b: 123456,
  20. c: new Date(),
  21. d: /hi/igm,
  22. e: /hello/
  23. },
  24. y: 'y',
  25. z: new Date(1378775452757)
  26. };
  27. var dupsArray = [nestedObj, { z: 'z' }, nestedObj];
  28. var reducedDupsArray = [nestedObj, { z: 'z' }];
  29. describe('clone()', function () {
  30. it('clones a nested object', function (done) {
  31. var a = nestedObj;
  32. var b = Hoek.clone(a);
  33. expect(a).to.deep.equal(b);
  34. expect(a.z.getTime()).to.equal(b.z.getTime());
  35. done();
  36. });
  37. it('clones a null object', function (done) {
  38. var b = Hoek.clone(null);
  39. expect(b).to.equal(null);
  40. done();
  41. });
  42. it('should not convert undefined properties to null', function (done) {
  43. var obj = { something: undefined };
  44. var b = Hoek.clone(obj);
  45. expect(typeof b.something).to.equal('undefined');
  46. done();
  47. });
  48. it('should not throw on circular reference', function (done) {
  49. var a = {};
  50. a.x = a;
  51. var test = function () {
  52. var b = Hoek.clone(a);
  53. };
  54. expect(test).to.not.throw();
  55. done();
  56. });
  57. it('clones circular reference', function (done) {
  58. var x = {
  59. 'z': new Date()
  60. };
  61. x.y = x;
  62. var b = Hoek.clone(x);
  63. expect(Object.keys(b.y)).to.deep.equal(Object.keys(x));
  64. expect(b.z).to.not.equal(x.z);
  65. expect(b.y).to.not.equal(x.y);
  66. expect(b.y.z).to.not.equal(x.y.z);
  67. expect(b.y).to.equal(b);
  68. expect(b.y.y.y.y).to.equal(b);
  69. done();
  70. });
  71. it('clones an object with a null prototype', function (done) {
  72. var obj = Object.create(null);
  73. var b = Hoek.clone(obj);
  74. expect(b).to.deep.equal(obj);
  75. done();
  76. });
  77. it('clones deeply nested object', function (done) {
  78. var a = {
  79. x: {
  80. y: {
  81. a: [1, 2, 3],
  82. b: 123456,
  83. c: new Date(),
  84. d: /hi/igm,
  85. e: /hello/
  86. }
  87. }
  88. };
  89. var b = Hoek.clone(a);
  90. expect(a).to.deep.equal(b);
  91. expect(a.x.y.c.getTime()).to.equal(b.x.y.c.getTime());
  92. done();
  93. });
  94. it('clones arrays', function (done) {
  95. var a = [1, 2, 3];
  96. var b = Hoek.clone(a);
  97. expect(a).to.deep.equal(b);
  98. done();
  99. });
  100. it('performs actual copy for shallow keys (no pass by reference)', function (done) {
  101. var x = Hoek.clone(nestedObj);
  102. var y = Hoek.clone(nestedObj);
  103. // Date
  104. expect(x.z).to.not.equal(nestedObj.z);
  105. expect(x.z).to.not.equal(y.z);
  106. // Regex
  107. expect(x.w).to.not.equal(nestedObj.w);
  108. expect(x.w).to.not.equal(y.w);
  109. // Array
  110. expect(x.v).to.not.equal(nestedObj.v);
  111. expect(x.v).to.not.equal(y.v);
  112. // Immutable(s)
  113. x.y = 5;
  114. expect(x.y).to.not.equal(nestedObj.y);
  115. expect(x.y).to.not.equal(y.y);
  116. done();
  117. });
  118. it('performs actual copy for deep keys (no pass by reference)', function (done) {
  119. var x = Hoek.clone(nestedObj);
  120. var y = Hoek.clone(nestedObj);
  121. expect(x.x.c).to.not.equal(nestedObj.x.c);
  122. expect(x.x.c).to.not.equal(y.x.c);
  123. expect(x.x.c.getTime()).to.equal(nestedObj.x.c.getTime());
  124. expect(x.x.c.getTime()).to.equal(y.x.c.getTime());
  125. done();
  126. });
  127. it('copies functions with properties', function (done) {
  128. var a = {
  129. x: function () {
  130. return 1;
  131. },
  132. y: {}
  133. };
  134. a.x.z = 'string in function';
  135. a.x.v = function () {
  136. return 2;
  137. };
  138. a.y.u = a.x;
  139. var b = Hoek.clone(a);
  140. expect(b.x()).to.equal(1);
  141. expect(b.x.v()).to.equal(2);
  142. expect(b.y.u).to.equal(b.x);
  143. expect(b.x.z).to.equal('string in function');
  144. done();
  145. });
  146. it('should copy a buffer', function (done) {
  147. var tls = {
  148. key: new Buffer([1, 2, 3, 4, 5]),
  149. cert: new Buffer([1, 2, 3, 4, 5, 6, 10])
  150. };
  151. var copiedTls = Hoek.clone(tls);
  152. expect(Buffer.isBuffer(copiedTls.key)).to.equal(true);
  153. expect(JSON.stringify(copiedTls.key)).to.equal(JSON.stringify(tls.key));
  154. expect(Buffer.isBuffer(copiedTls.cert)).to.equal(true);
  155. expect(JSON.stringify(copiedTls.cert)).to.equal(JSON.stringify(tls.cert));
  156. done();
  157. });
  158. it('clones an object with a prototype', function (done) {
  159. var Obj = function () {
  160. this.a = 5;
  161. };
  162. Obj.prototype.b = function () {
  163. return 'c';
  164. };
  165. var a = new Obj();
  166. var b = Hoek.clone(a);
  167. expect(b.a).to.equal(5);
  168. expect(b.b()).to.equal('c');
  169. expect(a).to.deep.equal(b);
  170. done();
  171. });
  172. it('reuses cloned Date object', function (done) {
  173. var obj = {
  174. a: new Date()
  175. };
  176. obj.b = obj.a;
  177. var copy = Hoek.clone(obj);
  178. expect(copy.a).to.equal(copy.b);
  179. done();
  180. });
  181. it('shallow copies an object with a prototype and isImmutable flag', function (done) {
  182. var Obj = function () {
  183. this.value = 5;
  184. };
  185. Obj.prototype.b = function () {
  186. return 'c';
  187. };
  188. Obj.prototype.isImmutable = true;
  189. var obj = {
  190. a: new Obj()
  191. };
  192. var copy = Hoek.clone(obj);
  193. expect(obj.a.value).to.equal(5);
  194. expect(copy.a.value).to.equal(5);
  195. expect(copy.a.b()).to.equal('c');
  196. expect(obj.a).to.equal(copy.a);
  197. done();
  198. });
  199. it('clones an object with property getter without executing it', function (done) {
  200. var obj = {};
  201. var value = 1;
  202. var execCount = 0;
  203. Object.defineProperty(obj, 'test', {
  204. enumerable: true,
  205. configurable: true,
  206. get: function () {
  207. ++execCount;
  208. return value;
  209. }
  210. });
  211. var copy = Hoek.clone(obj);
  212. expect(execCount).to.equal(0);
  213. expect(copy.test).to.equal(1);
  214. expect(execCount).to.equal(1);
  215. done();
  216. });
  217. it('clones an object with property getter and setter', function (done) {
  218. var obj = {
  219. _test: 0
  220. };
  221. Object.defineProperty(obj, 'test', {
  222. enumerable: true,
  223. configurable: true,
  224. get: function () {
  225. return this._test;
  226. },
  227. set: function (value) {
  228. this._test = value - 1;
  229. }
  230. });
  231. var copy = Hoek.clone(obj);
  232. expect(copy.test).to.equal(0);
  233. copy.test = 5;
  234. expect(copy.test).to.equal(4);
  235. done();
  236. });
  237. it('clones an object with only property setter', function (done) {
  238. var obj = {
  239. _test: 0
  240. };
  241. Object.defineProperty(obj, 'test', {
  242. enumerable: true,
  243. configurable: true,
  244. set: function (value) {
  245. this._test = value - 1;
  246. }
  247. });
  248. var copy = Hoek.clone(obj);
  249. expect(copy._test).to.equal(0);
  250. copy.test = 5;
  251. expect(copy._test).to.equal(4);
  252. done();
  253. });
  254. it('clones an object with non-enumerable properties', function (done) {
  255. var obj = {
  256. _test: 0
  257. };
  258. Object.defineProperty(obj, 'test', {
  259. enumerable: false,
  260. configurable: true,
  261. set: function (value) {
  262. this._test = value - 1;
  263. }
  264. });
  265. var copy = Hoek.clone(obj);
  266. expect(copy._test).to.equal(0);
  267. copy.test = 5;
  268. expect(copy._test).to.equal(4);
  269. done();
  270. });
  271. it('clones an object where getOwnPropertyDescriptor returns undefined', function (done) {
  272. var oldGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
  273. var obj = { a: 'b' };
  274. Object.getOwnPropertyDescriptor = function () {
  275. return undefined;
  276. };
  277. var copy = Hoek.clone(obj);
  278. Object.getOwnPropertyDescriptor = oldGetOwnPropertyDescriptor;
  279. expect(copy).to.deep.equal(obj);
  280. done();
  281. });
  282. });
  283. describe('merge()', function () {
  284. it('deep copies source items', function (done) {
  285. var target = {
  286. b: 3,
  287. d: []
  288. };
  289. var source = {
  290. c: {
  291. d: 1
  292. },
  293. d: [{ e: 1 }]
  294. };
  295. Hoek.merge(target, source);
  296. expect(target.c).to.not.equal(source.c);
  297. expect(target.c).to.deep.equal(source.c);
  298. expect(target.d).to.not.equal(source.d);
  299. expect(target.d[0]).to.not.equal(source.d[0]);
  300. expect(target.d).to.deep.equal(source.d);
  301. done();
  302. });
  303. it('merges array over an object', function (done) {
  304. var a = {
  305. x: ['n', 'm']
  306. };
  307. var b = {
  308. x: {
  309. n: '1',
  310. m: '2'
  311. }
  312. };
  313. Hoek.merge(b, a);
  314. expect(a.x[0]).to.equal('n');
  315. expect(a.x.n).to.not.exist();
  316. done();
  317. });
  318. it('merges object over an array', function (done) {
  319. var a = {
  320. x: ['n', 'm']
  321. };
  322. var b = {
  323. x: {
  324. n: '1',
  325. m: '2'
  326. }
  327. };
  328. Hoek.merge(a, b);
  329. expect(a.x.n).to.equal('1');
  330. expect(a.x[0]).to.not.exist();
  331. done();
  332. });
  333. it('does not throw if source is null', function (done) {
  334. var a = {};
  335. var b = null;
  336. var c = null;
  337. expect(function () {
  338. c = Hoek.merge(a, b);
  339. }).to.not.throw();
  340. expect(c).to.equal(a);
  341. done();
  342. });
  343. it('does not throw if source is undefined', function (done) {
  344. var a = {};
  345. var b;
  346. var c = null;
  347. expect(function () {
  348. c = Hoek.merge(a, b);
  349. }).to.not.throw();
  350. expect(c).to.equal(a);
  351. done();
  352. });
  353. it('throws if source is not an object', function (done) {
  354. expect(function () {
  355. var a = {};
  356. var b = 0;
  357. Hoek.merge(a, b);
  358. }).to.throw('Invalid source value: must be null, undefined, or an object');
  359. done();
  360. });
  361. it('throws if target is not an object', function (done) {
  362. expect(function () {
  363. var a = 0;
  364. var b = {};
  365. Hoek.merge(a, b);
  366. }).to.throw('Invalid target value: must be an object');
  367. done();
  368. });
  369. it('throws if target is not an array and source is', function (done) {
  370. expect(function () {
  371. var a = {};
  372. var b = [1, 2];
  373. Hoek.merge(a, b);
  374. }).to.throw('Cannot merge array onto an object');
  375. done();
  376. });
  377. it('returns the same object when merging arrays', function (done) {
  378. var a = [];
  379. var b = [1, 2];
  380. expect(Hoek.merge(a, b)).to.equal(a);
  381. done();
  382. });
  383. it('combines an empty object with a non-empty object', function (done) {
  384. var a = {};
  385. var b = nestedObj;
  386. var c = Hoek.merge(a, b);
  387. expect(a).to.deep.equal(b);
  388. expect(c).to.deep.equal(b);
  389. done();
  390. });
  391. it('overrides values in target', function (done) {
  392. var a = { x: 1, y: 2, z: 3, v: 5, t: 'test', m: 'abc' };
  393. var b = { x: null, z: 4, v: 0, t: { u: 6 }, m: '123' };
  394. var c = Hoek.merge(a, b);
  395. expect(c.x).to.equal(null);
  396. expect(c.y).to.equal(2);
  397. expect(c.z).to.equal(4);
  398. expect(c.v).to.equal(0);
  399. expect(c.m).to.equal('123');
  400. expect(c.t).to.deep.equal({ u: 6 });
  401. done();
  402. });
  403. it('overrides values in target (flip)', function (done) {
  404. var a = { x: 1, y: 2, z: 3, v: 5, t: 'test', m: 'abc' };
  405. var b = { x: null, z: 4, v: 0, t: { u: 6 }, m: '123' };
  406. var d = Hoek.merge(b, a);
  407. expect(d.x).to.equal(1);
  408. expect(d.y).to.equal(2);
  409. expect(d.z).to.equal(3);
  410. expect(d.v).to.equal(5);
  411. expect(d.m).to.equal('abc');
  412. expect(d.t).to.deep.equal('test');
  413. done();
  414. });
  415. it('retains Date properties', function (done) {
  416. var a = { x: new Date(1378776452757) };
  417. var b = Hoek.merge({}, a);
  418. expect(a.x.getTime()).to.equal(b.x.getTime());
  419. done();
  420. });
  421. it('retains Date properties when merging keys', function (done) {
  422. var a = { x: new Date(1378776452757) };
  423. var b = Hoek.merge({ x: {} }, a);
  424. expect(a.x.getTime()).to.equal(b.x.getTime());
  425. done();
  426. });
  427. it('overrides Buffer', function (done) {
  428. var a = { x: new Buffer('abc') };
  429. var b = Hoek.merge({ x: {} }, a);
  430. expect(a.x.toString()).to.equal('abc');
  431. done();
  432. });
  433. });
  434. describe('applyToDefaults()', function () {
  435. var defaults = {
  436. a: 1,
  437. b: 2,
  438. c: {
  439. d: 3,
  440. e: [5, 6]
  441. },
  442. f: 6,
  443. g: 'test'
  444. };
  445. it('throws when target is null', function (done) {
  446. expect(function () {
  447. Hoek.applyToDefaults(null, {});
  448. }).to.throw('Invalid defaults value: must be an object');
  449. done();
  450. });
  451. it('returns null if options is false', function (done) {
  452. var result = Hoek.applyToDefaults(defaults, false);
  453. expect(result).to.equal(null);
  454. done();
  455. });
  456. it('returns null if options is null', function (done) {
  457. var result = Hoek.applyToDefaults(defaults, null);
  458. expect(result).to.equal(null);
  459. done();
  460. });
  461. it('returns null if options is undefined', function (done) {
  462. var result = Hoek.applyToDefaults(defaults, undefined);
  463. expect(result).to.equal(null);
  464. done();
  465. });
  466. it('returns a copy of defaults if options is true', function (done) {
  467. var result = Hoek.applyToDefaults(defaults, true);
  468. expect(result).to.deep.equal(defaults);
  469. done();
  470. });
  471. it('applies object to defaults', function (done) {
  472. var obj = {
  473. a: null,
  474. c: {
  475. e: [4]
  476. },
  477. f: 0,
  478. g: {
  479. h: 5
  480. }
  481. };
  482. var result = Hoek.applyToDefaults(defaults, obj);
  483. expect(result.c.e).to.deep.equal([4]);
  484. expect(result.a).to.equal(1);
  485. expect(result.b).to.equal(2);
  486. expect(result.f).to.equal(0);
  487. expect(result.g).to.deep.equal({ h: 5 });
  488. done();
  489. });
  490. it('applies object to defaults with null', function (done) {
  491. var obj = {
  492. a: null,
  493. c: {
  494. e: [4]
  495. },
  496. f: 0,
  497. g: {
  498. h: 5
  499. }
  500. };
  501. var result = Hoek.applyToDefaults(defaults, obj, true);
  502. expect(result.c.e).to.deep.equal([4]);
  503. expect(result.a).to.equal(null);
  504. expect(result.b).to.equal(2);
  505. expect(result.f).to.equal(0);
  506. expect(result.g).to.deep.equal({ h: 5 });
  507. done();
  508. });
  509. });
  510. describe('cloneWithShallow()', function () {
  511. it('deep clones except for listed keys', function (done) {
  512. var source = {
  513. a: {
  514. b: 5
  515. },
  516. c: {
  517. d: 6
  518. }
  519. };
  520. var copy = Hoek.cloneWithShallow(source, ['c']);
  521. expect(copy).to.deep.equal(source);
  522. expect(copy).to.not.equal(source);
  523. expect(copy.a).to.not.equal(source.a);
  524. expect(copy.b).to.equal(source.b);
  525. done();
  526. });
  527. it('returns immutable value', function (done) {
  528. expect(Hoek.cloneWithShallow(5)).to.equal(5);
  529. done();
  530. });
  531. it('returns null value', function (done) {
  532. expect(Hoek.cloneWithShallow(null)).to.equal(null);
  533. done();
  534. });
  535. it('returns undefined value', function (done) {
  536. expect(Hoek.cloneWithShallow(undefined)).to.equal(undefined);
  537. done();
  538. });
  539. it('deep clones except for listed keys (including missing keys)', function (done) {
  540. var source = {
  541. a: {
  542. b: 5
  543. },
  544. c: {
  545. d: 6
  546. }
  547. };
  548. var copy = Hoek.cloneWithShallow(source, ['c', 'v']);
  549. expect(copy).to.deep.equal(source);
  550. expect(copy).to.not.equal(source);
  551. expect(copy.a).to.not.equal(source.a);
  552. expect(copy.b).to.equal(source.b);
  553. done();
  554. });
  555. });
  556. describe('applyToDefaultsWithShallow()', function () {
  557. it('shallow copies the listed keys from options without merging', function (done) {
  558. var defaults = {
  559. a: {
  560. b: 5,
  561. e: 3
  562. },
  563. c: {
  564. d: 7,
  565. g: 1
  566. }
  567. };
  568. var options = {
  569. a: {
  570. b: 4
  571. },
  572. c: {
  573. d: 6,
  574. f: 7
  575. }
  576. };
  577. var merged = Hoek.applyToDefaultsWithShallow(defaults, options, ['a']);
  578. expect(merged).to.deep.equal({ a: { b: 4 }, c: { d: 6, g: 1, f: 7 } });
  579. expect(merged.a).to.equal(options.a);
  580. expect(merged.a).to.not.equal(defaults.a);
  581. expect(merged.c).to.not.equal(options.c);
  582. expect(merged.c).to.not.equal(defaults.c);
  583. done();
  584. });
  585. it('shallow copies the nested keys (override)', function (done) {
  586. var defaults = {
  587. a: {
  588. b: 5
  589. },
  590. c: {
  591. d: 7,
  592. g: 1
  593. }
  594. };
  595. var options = {
  596. a: {
  597. b: 4
  598. },
  599. c: {
  600. d: 6,
  601. g: {
  602. h: 8
  603. }
  604. }
  605. };
  606. var merged = Hoek.applyToDefaultsWithShallow(defaults, options, ['c.g']);
  607. expect(merged).to.deep.equal({ a: { b: 4 }, c: { d: 6, g: { h: 8 } } });
  608. expect(merged.c.g).to.equal(options.c.g);
  609. done();
  610. });
  611. it('shallow copies the nested keys (missing)', function (done) {
  612. var defaults = {
  613. a: {
  614. b: 5
  615. }
  616. };
  617. var options = {
  618. a: {
  619. b: 4
  620. },
  621. c: {
  622. g: {
  623. h: 8
  624. }
  625. }
  626. };
  627. var merged = Hoek.applyToDefaultsWithShallow(defaults, options, ['c.g']);
  628. expect(merged).to.deep.equal({ a: { b: 4 }, c: { g: { h: 8 } } });
  629. expect(merged.c.g).to.equal(options.c.g);
  630. done();
  631. });
  632. it('shallow copies the nested keys (override)', function (done) {
  633. var defaults = {
  634. a: {
  635. b: 5
  636. },
  637. c: {
  638. g: {
  639. d: 7
  640. }
  641. }
  642. };
  643. var options = {
  644. a: {
  645. b: 4
  646. },
  647. c: {
  648. g: {
  649. h: 8
  650. }
  651. }
  652. };
  653. var merged = Hoek.applyToDefaultsWithShallow(defaults, options, ['c.g']);
  654. expect(merged).to.deep.equal({ a: { b: 4 }, c: { g: { h: 8 } } });
  655. expect(merged.c.g).to.equal(options.c.g);
  656. done();
  657. });
  658. it('shallow copies the nested keys (deeper)', function (done) {
  659. var defaults = {
  660. a: {
  661. b: 5
  662. }
  663. };
  664. var options = {
  665. a: {
  666. b: 4
  667. },
  668. c: {
  669. g: {
  670. r: {
  671. h: 8
  672. }
  673. }
  674. }
  675. };
  676. var merged = Hoek.applyToDefaultsWithShallow(defaults, options, ['c.g.r']);
  677. expect(merged).to.deep.equal({ a: { b: 4 }, c: { g: { r: { h: 8 } } } });
  678. expect(merged.c.g.r).to.equal(options.c.g.r);
  679. done();
  680. });
  681. it('shallow copies the nested keys (not present)', function (done) {
  682. var defaults = {
  683. a: {
  684. b: 5
  685. }
  686. };
  687. var options = {
  688. a: {
  689. b: 4
  690. },
  691. c: {
  692. g: {
  693. r: {
  694. h: 8
  695. }
  696. }
  697. }
  698. };
  699. var merged = Hoek.applyToDefaultsWithShallow(defaults, options, ['x.y']);
  700. expect(merged).to.deep.equal({ a: { b: 4 }, c: { g: { r: { h: 8 } } } });
  701. done();
  702. });
  703. it('shallow copies the listed keys in the defaults', function (done) {
  704. var defaults = {
  705. a: {
  706. b: 1
  707. }
  708. };
  709. var merged = Hoek.applyToDefaultsWithShallow(defaults, {}, ['a']);
  710. expect(merged.a).to.equal(defaults.a);
  711. done();
  712. });
  713. it('shallow copies the listed keys in the defaults (true)', function (done) {
  714. var defaults = {
  715. a: {
  716. b: 1
  717. }
  718. };
  719. var merged = Hoek.applyToDefaultsWithShallow(defaults, true, ['a']);
  720. expect(merged.a).to.equal(defaults.a);
  721. done();
  722. });
  723. it('returns null on false', function (done) {
  724. var defaults = {
  725. a: {
  726. b: 1
  727. }
  728. };
  729. var merged = Hoek.applyToDefaultsWithShallow(defaults, false, ['a']);
  730. expect(merged).to.equal(null);
  731. done();
  732. });
  733. it('throws on missing defaults', function (done) {
  734. expect(function () {
  735. Hoek.applyToDefaultsWithShallow(null, {}, ['a']);
  736. }).to.throw('Invalid defaults value: must be an object');
  737. done();
  738. });
  739. it('throws on invalid defaults', function (done) {
  740. expect(function () {
  741. Hoek.applyToDefaultsWithShallow('abc', {}, ['a']);
  742. }).to.throw('Invalid defaults value: must be an object');
  743. done();
  744. });
  745. it('throws on invalid options', function (done) {
  746. expect(function () {
  747. Hoek.applyToDefaultsWithShallow({}, 'abc', ['a']);
  748. }).to.throw('Invalid options value: must be true, falsy or an object');
  749. done();
  750. });
  751. it('throws on missing keys', function (done) {
  752. expect(function () {
  753. Hoek.applyToDefaultsWithShallow({}, true);
  754. }).to.throw('Invalid keys');
  755. done();
  756. });
  757. it('throws on invalid keys', function (done) {
  758. expect(function () {
  759. Hoek.applyToDefaultsWithShallow({}, true, 'a');
  760. }).to.throw('Invalid keys');
  761. done();
  762. });
  763. });
  764. describe('deepEqual()', function () {
  765. it('compares simple values', function (done) {
  766. expect(Hoek.deepEqual('x', 'x')).to.be.true();
  767. expect(Hoek.deepEqual('x', 'y')).to.be.false();
  768. expect(Hoek.deepEqual('x1', 'x')).to.be.false();
  769. expect(Hoek.deepEqual(-0, +0)).to.be.false();
  770. expect(Hoek.deepEqual(-0, -0)).to.be.true();
  771. expect(Hoek.deepEqual(+0, +0)).to.be.true();
  772. expect(Hoek.deepEqual(+0, -0)).to.be.false();
  773. expect(Hoek.deepEqual(1, 1)).to.be.true();
  774. expect(Hoek.deepEqual(0, 0)).to.be.true();
  775. expect(Hoek.deepEqual(-1, 1)).to.be.false();
  776. expect(Hoek.deepEqual(NaN, 0)).to.be.false();
  777. expect(Hoek.deepEqual(NaN, NaN)).to.be.true();
  778. done();
  779. });
  780. it('compares different types', function (done) {
  781. expect(Hoek.deepEqual([], 5)).to.be.false();
  782. expect(Hoek.deepEqual(5, [])).to.be.false();
  783. expect(Hoek.deepEqual({}, null)).to.be.false();
  784. expect(Hoek.deepEqual(null, {})).to.be.false();
  785. expect(Hoek.deepEqual('abc', {})).to.be.false();
  786. expect(Hoek.deepEqual({}, 'abc')).to.be.false();
  787. done();
  788. });
  789. it('compares empty structures', function (done) {
  790. expect(Hoek.deepEqual([], [])).to.be.true();
  791. expect(Hoek.deepEqual({}, {})).to.be.true();
  792. expect(Hoek.deepEqual([], {})).to.be.false();
  793. done();
  794. });
  795. it('compares empty arguments object', function (done) {
  796. var compare = function () {
  797. expect(Hoek.deepEqual([], arguments)).to.be.false();
  798. };
  799. compare();
  800. done();
  801. });
  802. it('compares empty arguments objects', function (done) {
  803. var compare = function () {
  804. var arg1 = arguments;
  805. var inner = function () {
  806. expect(Hoek.deepEqual(arg1, arguments)).to.be.false(); // callee is not the same
  807. };
  808. inner();
  809. };
  810. compare();
  811. done();
  812. });
  813. it('compares dates', function (done) {
  814. expect(Hoek.deepEqual(new Date(2015, 1, 1), new Date(2015, 1, 1))).to.be.true();
  815. expect(Hoek.deepEqual(new Date(100), new Date(101))).to.be.false();
  816. expect(Hoek.deepEqual(new Date(), {})).to.be.false();
  817. done();
  818. });
  819. it('compares regular expressions', function (done) {
  820. expect(Hoek.deepEqual(/\s/, new RegExp('\\\s'))).to.be.true();
  821. expect(Hoek.deepEqual(/\s/g, /\s/g)).to.be.true();
  822. expect(Hoek.deepEqual(/a/, {})).to.be.false();
  823. expect(Hoek.deepEqual(/\s/g, /\s/i)).to.be.false();
  824. expect(Hoek.deepEqual(/a/g, /b/g)).to.be.false();
  825. done();
  826. });
  827. it('compares arrays', function (done) {
  828. expect(Hoek.deepEqual([[1]], [[1]])).to.be.true();
  829. expect(Hoek.deepEqual([1, 2, 3], [1, 2, 3])).to.be.true();
  830. expect(Hoek.deepEqual([1, 2, 3], [1, 3, 2])).to.be.false();
  831. expect(Hoek.deepEqual([1, 2, 3], [1, 2])).to.be.false();
  832. expect(Hoek.deepEqual([1], [1])).to.be.true();
  833. done();
  834. });
  835. it('compares buffers', function (done) {
  836. expect(Hoek.deepEqual(new Buffer([1, 2, 3]), new Buffer([1, 2, 3]))).to.be.true();
  837. expect(Hoek.deepEqual(new Buffer([1, 2, 3]), new Buffer([1, 3, 2]))).to.be.false();
  838. expect(Hoek.deepEqual(new Buffer([1, 2, 3]), new Buffer([1, 2]))).to.be.false();
  839. expect(Hoek.deepEqual(new Buffer([1, 2, 3]), {})).to.be.false();
  840. expect(Hoek.deepEqual(new Buffer([1, 2, 3]), [1, 2, 3])).to.be.false();
  841. done();
  842. });
  843. it('compares objects', function (done) {
  844. expect(Hoek.deepEqual({ a: 1, b: 2, c: 3 }, { a: 1, b: 2, c: 3 })).to.be.true();
  845. expect(Hoek.deepEqual({ foo: 'bar' }, { foo: 'baz' })).to.be.false();
  846. expect(Hoek.deepEqual({ foo: { bar: 'foo' } }, { foo: { bar: 'baz' } })).to.be.false();
  847. done();
  848. });
  849. it('handles circular dependency', function (done) {
  850. var a = {};
  851. a.x = a;
  852. var b = Hoek.clone(a);
  853. expect(Hoek.deepEqual(a, b)).to.be.true();
  854. done();
  855. });
  856. it('compares an object with property getter without executing it', function (done) {
  857. var obj = {};
  858. var value = 1;
  859. var execCount = 0;
  860. Object.defineProperty(obj, 'test', {
  861. enumerable: true,
  862. configurable: true,
  863. get: function () {
  864. ++execCount;
  865. return value;
  866. }
  867. });
  868. var copy = Hoek.clone(obj);
  869. expect(Hoek.deepEqual(obj, copy)).to.be.true();
  870. expect(execCount).to.equal(0);
  871. expect(copy.test).to.equal(1);
  872. expect(execCount).to.equal(1);
  873. done();
  874. });
  875. it('compares objects with property getters', function (done) {
  876. var obj = {};
  877. Object.defineProperty(obj, 'test', {
  878. enumerable: true,
  879. configurable: true,
  880. get: function () {
  881. return 1;
  882. }
  883. });
  884. var ref = {};
  885. Object.defineProperty(ref, 'test', {
  886. enumerable: true,
  887. configurable: true,
  888. get: function () {
  889. return 2;
  890. }
  891. });
  892. expect(Hoek.deepEqual(obj, ref)).to.be.false();
  893. done();
  894. });
  895. it('compares object prototypes', function (done) {
  896. var Obj = function () {
  897. this.a = 5;
  898. };
  899. Obj.prototype.b = function () {
  900. return this.a;
  901. };
  902. var Ref = function () {
  903. this.a = 5;
  904. };
  905. Ref.prototype.b = function () {
  906. return this.a;
  907. };
  908. expect(Hoek.deepEqual(new Obj(), new Ref())).to.be.false();
  909. expect(Hoek.deepEqual(new Obj(), new Obj())).to.be.true();
  910. expect(Hoek.deepEqual(new Ref(), new Ref())).to.be.true();
  911. done();
  912. });
  913. it('compares plain objects', function (done) {
  914. var a = Object.create(null);
  915. var b = Object.create(null);
  916. a.b = 'c';
  917. b.b = 'c';
  918. expect(Hoek.deepEqual(a, b)).to.be.true();
  919. expect(Hoek.deepEqual(a, { b: 'c' })).to.be.false();
  920. done();
  921. });
  922. it('compares an object with an empty object', function (done) {
  923. var a = { a: 1, b: 2 };
  924. expect(Hoek.deepEqual({}, a)).to.be.false();
  925. expect(Hoek.deepEqual(a, {})).to.be.false();
  926. done();
  927. });
  928. it('compares an object ignoring the prototype', function (done) {
  929. var a = Object.create(null);
  930. var b = {};
  931. expect(Hoek.deepEqual(a, b, { prototype: false })).to.be.true();
  932. done();
  933. });
  934. it('compares an object ignoring the prototype recursively', function (done) {
  935. var a = [Object.create(null)];
  936. var b = [{}];
  937. expect(Hoek.deepEqual(a, b, { prototype: false })).to.be.true();
  938. done();
  939. });
  940. });
  941. describe('unique()', function () {
  942. it('ensures uniqueness within array of objects based on subkey', function (done) {
  943. var a = Hoek.unique(dupsArray, 'x');
  944. expect(a).to.deep.equal(reducedDupsArray);
  945. done();
  946. });
  947. it('removes duplicated without key', function (done) {
  948. expect(Hoek.unique([1, 2, 3, 4, 2, 1, 5])).to.deep.equal([1, 2, 3, 4, 5]);
  949. done();
  950. });
  951. });
  952. describe('mapToObject()', function () {
  953. it('returns null on null array', function (done) {
  954. var a = Hoek.mapToObject(null);
  955. expect(a).to.equal(null);
  956. done();
  957. });
  958. it('converts basic array to existential object', function (done) {
  959. var keys = [1, 2, 3, 4];
  960. var a = Hoek.mapToObject(keys);
  961. for (var i in keys) {
  962. expect(a[keys[i]]).to.equal(true);
  963. }
  964. done();
  965. });
  966. it('converts array of objects to existential object', function (done) {
  967. var keys = [{ x: 1 }, { x: 2 }, { x: 3 }, { y: 4 }];
  968. var subkey = 'x';
  969. var a = Hoek.mapToObject(keys, subkey);
  970. expect(a).to.deep.equal({ 1: true, 2: true, 3: true });
  971. done();
  972. });
  973. });
  974. describe('intersect()', function () {
  975. it('returns the common objects of two arrays', function (done) {
  976. var array1 = [1, 2, 3, 4, 4, 5, 5];
  977. var array2 = [5, 4, 5, 6, 7];
  978. var common = Hoek.intersect(array1, array2);
  979. expect(common.length).to.equal(2);
  980. done();
  981. });
  982. it('returns just the first common object of two arrays', function (done) {
  983. var array1 = [1, 2, 3, 4, 4, 5, 5];
  984. var array2 = [5, 4, 5, 6, 7];
  985. var common = Hoek.intersect(array1, array2, true);
  986. expect(common).to.equal(5);
  987. done();
  988. });
  989. it('returns null when no common and returning just the first common object of two arrays', function (done) {
  990. var array1 = [1, 2, 3, 4, 4, 5, 5];
  991. var array2 = [6, 7];
  992. var common = Hoek.intersect(array1, array2, true);
  993. expect(common).to.equal(null);
  994. done();
  995. });
  996. it('returns an empty array if either input is null', function (done) {
  997. expect(Hoek.intersect([1], null).length).to.equal(0);
  998. expect(Hoek.intersect(null, [1]).length).to.equal(0);
  999. done();
  1000. });
  1001. it('returns the common objects of object and array', function (done) {
  1002. var array1 = [1, 2, 3, 4, 4, 5, 5];
  1003. var array2 = [5, 4, 5, 6, 7];
  1004. var common = Hoek.intersect(Hoek.mapToObject(array1), array2);
  1005. expect(common.length).to.equal(2);
  1006. done();
  1007. });
  1008. });
  1009. describe('contain()', function () {
  1010. it('tests strings', function (done) {
  1011. expect(Hoek.contain('abc', 'ab')).to.be.true();
  1012. expect(Hoek.contain('abc', 'abc', { only: true })).to.be.true();
  1013. expect(Hoek.contain('aaa', 'a', { only: true })).to.be.true();
  1014. expect(Hoek.contain('abc', 'b', { once: true })).to.be.true();
  1015. expect(Hoek.contain('abc', ['a', 'c'])).to.be.true();
  1016. expect(Hoek.contain('abc', ['a', 'd'], { part: true })).to.be.true();
  1017. expect(Hoek.contain('abc', 'ac')).to.be.false();
  1018. expect(Hoek.contain('abcd', 'abc', { only: true })).to.be.false();
  1019. expect(Hoek.contain('aab', 'a', { only: true })).to.be.false();
  1020. expect(Hoek.contain('abb', 'b', { once: true })).to.be.false();
  1021. expect(Hoek.contain('abc', ['a', 'd'])).to.be.false();
  1022. expect(Hoek.contain('abc', ['ab', 'bc'])).to.be.false(); // Overlapping values not supported
  1023. done();
  1024. });
  1025. it('tests arrays', function (done) {
  1026. expect(Hoek.contain([1, 2, 3], 1)).to.be.true();
  1027. expect(Hoek.contain([{ a: 1 }], { a: 1 }, { deep: true })).to.be.true();
  1028. expect(Hoek.contain([1, 2, 3], [1, 2])).to.be.true();
  1029. expect(Hoek.contain([{ a: 1 }], [{ a: 1 }], { deep: true })).to.be.true();
  1030. expect(Hoek.contain([1, 1, 2], [1, 2], { only: true })).to.be.true();
  1031. expect(Hoek.contain([1, 2], [1, 2], { once: true })).to.be.true();
  1032. expect(Hoek.contain([1, 2, 3], [1, 4], { part: true })).to.be.true();
  1033. expect(Hoek.contain([[1], [2]], [[1]], { deep: true })).to.be.true();
  1034. expect(Hoek.contain([1, 2, 3], 4)).to.be.false();
  1035. expect(Hoek.contain([{ a: 1 }], { a: 2 }, { deep: true })).to.be.false();
  1036. expect(Hoek.contain([{ a: 1 }], { a: 1 })).to.be.false();
  1037. expect(Hoek.contain([1, 2, 3], [4, 5])).to.be.false();
  1038. expect(Hoek.contain([[3], [2]], [[1]])).to.be.false();
  1039. expect(Hoek.contain([[1], [2]], [[1]])).to.be.false();
  1040. expect(Hoek.contain([{ a: 1 }], [{ a: 2 }], { deep: true })).to.be.false();
  1041. expect(Hoek.contain([1, 3, 2], [1, 2], { only: true })).to.be.false();
  1042. expect(Hoek.contain([1, 2, 2], [1, 2], { once: true })).to.be.false();
  1043. expect(Hoek.contain([0, 2, 3], [1, 4], { part: true })).to.be.false();
  1044. done();
  1045. });
  1046. it('tests objects', function (done) {
  1047. expect(Hoek.contain({ a: 1, b: 2, c: 3 }, 'a')).to.be.true();
  1048. expect(Hoek.contain({ a: 1, b: 2, c: 3 }, ['a', 'c'])).to.be.true();
  1049. expect(Hoek.contain({ a: 1, b: 2, c: 3 }, ['a', 'b', 'c'], { only: true })).to.be.true();
  1050. expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1 })).to.be.true();
  1051. expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1, c: 3 })).to.be.true();
  1052. expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1, d: 4 }, { part: true })).to.be.true();
  1053. expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1, b: 2, c: 3 }, { only: true })).to.be.true();
  1054. expect(Hoek.contain({ a: [1], b: [2], c: [3] }, { a: [1], c: [3] }, { deep: true })).to.be.true();
  1055. expect(Hoek.contain({ a: [{ b: 1 }, { c: 2 }, { d: 3, e: 4 }] }, { a: [{ b: 1 }, { d: 3 }] }, { deep: true })).to.be.true();
  1056. expect(Hoek.contain({ a: [{ b: 1 }, { c: 2 }, { d: 3, e: 4 }] }, { a: [{ b: 1 }, { d: 3 }] }, { deep: true, part: true })).to.be.true();
  1057. expect(Hoek.contain({ a: [{ b: 1 }, { c: 2 }, { d: 3, e: 4 }] }, { a: [{ b: 1 }, { d: 3 }] }, { deep: true, part: false })).to.be.false();
  1058. expect(Hoek.contain({ a: [{ b: 1 }, { c: 2 }, { d: 3, e: 4 }] }, { a: [{ b: 1 }, { d: 3 }] }, { deep: true, only: true })).to.be.false();
  1059. expect(Hoek.contain({ a: [{ b: 1 }, { c: 2 }, { d: 3, e: 4 }] }, { a: [{ b: 1 }, { d: 3 }] }, { deep: true, only: false })).to.be.true();
  1060. expect(Hoek.contain({ a: 1, b: 2, c: 3 }, 'd')).to.be.false();
  1061. expect(Hoek.contain({ a: 1, b: 2, c: 3 }, ['a', 'd'])).to.be.false();
  1062. expect(Hoek.contain({ a: 1, b: 2, c: 3, d: 4 }, ['a', 'b', 'c'], { only: true })).to.be.false();
  1063. expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 2 })).to.be.false();
  1064. expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 2, b: 2 }, { part: true })).to.be.false(); // part does not ignore bad value
  1065. expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1, d: 3 })).to.be.false();
  1066. expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1, d: 4 })).to.be.false();
  1067. expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1, b: 2 }, { only: true })).to.be.false();
  1068. expect(Hoek.contain({ a: [1], b: [2], c: [3] }, { a: [1], c: [3] })).to.be.false();
  1069. expect(Hoek.contain({ a: { b: { c: 1, d: 2 } } }, { a: { b: { c: 1 } } })).to.be.false();
  1070. expect(Hoek.contain({ a: { b: { c: 1, d: 2 } } }, { a: { b: { c: 1 } } }, { deep: true })).to.be.true();
  1071. expect(Hoek.contain({ a: { b: { c: 1, d: 2 } } }, { a: { b: { c: 1 } } }, { deep: true, only: true })).to.be.false();
  1072. expect(Hoek.contain({ a: { b: { c: 1, d: 2 } } }, { a: { b: { c: 1 } } }, { deep: true, only: false })).to.be.true();
  1073. expect(Hoek.contain({ a: { b: { c: 1, d: 2 } } }, { a: { b: { c: 1 } } }, { deep: true, part: true })).to.be.true();
  1074. expect(Hoek.contain({ a: { b: { c: 1, d: 2 } } }, { a: { b: { c: 1 } } }, { deep: true, part: false })).to.be.false();
  1075. // Getter check
  1076. var Foo = function (bar) {
  1077. this.bar = bar;
  1078. };
  1079. Object.defineProperty(Foo.prototype, 'baz', {
  1080. enumerable: true,
  1081. get: function () {
  1082. return this.bar;
  1083. }
  1084. });
  1085. expect(Hoek.contain({ a: new Foo('b') }, { a: new Foo('b') }, { deep: true })).to.be.true();
  1086. expect(Hoek.contain({ a: new Foo('b') }, { a: new Foo('b') }, { deep: true, part: true })).to.be.true();
  1087. expect(Hoek.contain({ a: new Foo('b') }, { a: { baz: 'b' } }, { deep: true })).to.be.true();
  1088. expect(Hoek.contain({ a: new Foo('b') }, { a: { baz: 'b' } }, { deep: true, only: true })).to.be.false();
  1089. expect(Hoek.contain({ a: new Foo('b') }, { a: { baz: 'b' } }, { deep: true, part: false })).to.be.false();
  1090. expect(Hoek.contain({ a: new Foo('b') }, { a: { baz: 'b' } }, { deep: true, part: true })).to.be.true();
  1091. done();
  1092. });
  1093. });
  1094. describe('flatten()', function () {
  1095. it('returns a flat array', function (done) {
  1096. var result = Hoek.flatten([1, 2, [3, 4, [5, 6], [7], 8], [9], [10, [11, 12]], 13]);
  1097. expect(result.length).to.equal(13);
  1098. expect(result).to.deep.equal([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]);
  1099. done();
  1100. });
  1101. });
  1102. describe('reach()', function () {
  1103. var obj = {
  1104. a: {
  1105. b: {
  1106. c: {
  1107. d: 1,
  1108. e: 2
  1109. },
  1110. f: 'hello'
  1111. },
  1112. g: {
  1113. h: 3
  1114. }
  1115. },
  1116. i: function () { },
  1117. j: null,
  1118. k: [4, 8, 9, 1]
  1119. };
  1120. obj.i.x = 5;
  1121. it('returns object itself', function (done) {
  1122. expect(Hoek.reach(obj, null)).to.equal(obj);
  1123. expect(Hoek.reach(obj, false)).to.equal(obj);
  1124. expect(Hoek.reach(obj)).to.equal(obj);
  1125. done();
  1126. });
  1127. it('returns first value of array', function (done) {
  1128. expect(Hoek.reach(obj, 'k.0')).to.equal(4);
  1129. done();
  1130. });
  1131. it('returns last value of array using negative index', function (done) {
  1132. expect(Hoek.reach(obj, 'k.-2')).to.equal(9);
  1133. done();
  1134. });
  1135. it('returns a valid member', function (done) {
  1136. expect(Hoek.reach(obj, 'a.b.c.d')).to.equal(1);
  1137. done();
  1138. });
  1139. it('returns a valid member with separator override', function (done) {
  1140. expect(Hoek.reach(obj, 'a/b/c/d', '/')).to.equal(1);
  1141. done();
  1142. });
  1143. it('returns undefined on null object', function (done) {
  1144. expect(Hoek.reach(null, 'a.b.c.d')).to.equal(undefined);
  1145. done();
  1146. });
  1147. it('returns undefined on missing object member', function (done) {
  1148. expect(Hoek.reach(obj, 'a.b.c.d.x')).to.equal(undefined);
  1149. done();
  1150. });
  1151. it('returns undefined on missing function member', function (done) {
  1152. expect(Hoek.reach(obj, 'i.y', { functions: true })).to.equal(undefined);
  1153. done();
  1154. });
  1155. it('throws on missing member in strict mode', function (done) {
  1156. expect(function () {
  1157. Hoek.reach(obj, 'a.b.c.o.x', { strict: true });
  1158. }).to.throw('Missing segment o in reach path a.b.c.o.x');
  1159. done();
  1160. });
  1161. it('returns undefined on invalid member', function (done) {
  1162. expect(Hoek.reach(obj, 'a.b.c.d-.x')).to.equal(undefined);
  1163. done();
  1164. });
  1165. it('returns function member', function (done) {
  1166. expect(typeof Hoek.reach(obj, 'i')).to.equal('function');
  1167. done();
  1168. });
  1169. it('returns function property', function (done) {
  1170. expect(Hoek.reach(obj, 'i.x')).to.equal(5);
  1171. done();
  1172. });
  1173. it('returns null', function (done) {
  1174. expect(Hoek.reach(obj, 'j')).to.equal(null);
  1175. done();
  1176. });
  1177. it('throws on function property when functions not allowed', function (done) {
  1178. expect(function () {
  1179. Hoek.reach(obj, 'i.x', { functions: false });
  1180. }).to.throw('Invalid segment x in reach path i.x');
  1181. done();
  1182. });
  1183. it('will return a default value if property is not found', function (done) {
  1184. expect(Hoek.reach(obj, 'a.b.q', { default: 'defaultValue' })).to.equal('defaultValue');
  1185. done();
  1186. });
  1187. it('will return a default value if path is not found', function (done) {
  1188. expect(Hoek.reach(obj, 'q', { default: 'defaultValue' })).to.equal('defaultValue');
  1189. done();
  1190. });
  1191. it('allows a falsey value to be used as the default value', function (done) {
  1192. expect(Hoek.reach(obj, 'q', { default: '' })).to.equal('');
  1193. done();
  1194. });
  1195. });
  1196. describe('reachTemplate()', function () {
  1197. it('applies object to template', function (done) {
  1198. var obj = {
  1199. a: {
  1200. b: {
  1201. c: {
  1202. d: 1
  1203. }
  1204. }
  1205. },
  1206. j: null,
  1207. k: [4, 8, 9, 1]
  1208. };
  1209. var template = '{k.0}:{k.-2}:{a.b.c.d}:{x.y}:{j}';
  1210. expect(Hoek.reachTemplate(obj, template)).to.equal('4:9:1::');
  1211. done();
  1212. });
  1213. it('applies object to template (options)', function (done) {
  1214. var obj = {
  1215. a: {
  1216. b: {
  1217. c: {
  1218. d: 1
  1219. }
  1220. }
  1221. },
  1222. j: null,
  1223. k: [4, 8, 9, 1]
  1224. };
  1225. var template = '{k/0}:{k/-2}:{a/b/c/d}:{x/y}:{j}';
  1226. expect(Hoek.reachTemplate(obj, template, '/')).to.equal('4:9:1::');
  1227. done();
  1228. });
  1229. });
  1230. describe('callStack()', function () {
  1231. it('returns the full call stack', function (done) {
  1232. var stack = Hoek.callStack();
  1233. expect(stack[0][0]).to.contain('index.js');
  1234. expect(stack[0][2]).to.equal(26);
  1235. done();
  1236. });
  1237. });
  1238. describe('displayStack ()', function () {
  1239. it('returns the full call stack for display', function (done) {
  1240. var stack = Hoek.displayStack();
  1241. expect(stack[0]).to.contain(Path.normalize('/test/index.js') + ':');
  1242. done();
  1243. });
  1244. it('includes constructor functions correctly', function (done) {
  1245. var Something = function (next) {
  1246. next();
  1247. };
  1248. var something = new Something(function () {
  1249. var stack = Hoek.displayStack();
  1250. expect(stack[1]).to.contain('new Something');
  1251. done();
  1252. });
  1253. });
  1254. });
  1255. describe('abort()', function () {
  1256. it('exits process when not in test mode', function (done) {
  1257. var env = process.env.NODE_ENV;
  1258. var write = process.stdout.write;
  1259. var exit = process.exit;
  1260. process.env.NODE_ENV = 'nottatest';
  1261. process.stdout.write = function () { };
  1262. process.exit = function (state) {
  1263. process.exit = exit;
  1264. process.env.NODE_ENV = env;
  1265. process.stdout.write = write;
  1266. expect(state).to.equal(1);
  1267. done();
  1268. };
  1269. Hoek.abort('Boom');
  1270. });
  1271. it('throws when not in test mode and abortThrow is true', function (done) {
  1272. var env = process.env.NODE_ENV;
  1273. process.env.NODE_ENV = 'nottatest';
  1274. Hoek.abortThrow = true;
  1275. var fn = function () {
  1276. Hoek.abort('my error message');
  1277. };
  1278. expect(fn).to.throw('my error message');
  1279. Hoek.abortThrow = false;
  1280. process.env.NODE_ENV = env;
  1281. done();
  1282. });
  1283. it('respects hideStack argument', function (done) {
  1284. var env = process.env.NODE_ENV;
  1285. var write = process.stdout.write;
  1286. var exit = process.exit;
  1287. var output = '';
  1288. process.exit = function () { };
  1289. process.env.NODE_ENV = '';
  1290. process.stdout.write = function (message) {
  1291. output = message;
  1292. };
  1293. Hoek.abort('my error message', true);
  1294. process.env.NODE_ENV = env;
  1295. process.stdout.write = write;
  1296. process.exit = exit;
  1297. expect(output).to.equal('ABORT: my error message\n\t\n');
  1298. done();
  1299. });
  1300. it('throws in test mode', function (done) {
  1301. var env = process.env.NODE_ENV;
  1302. process.env.NODE_ENV = 'test';
  1303. expect(function () {
  1304. Hoek.abort('my error message', true);
  1305. }).to.throw('my error message');
  1306. process.env.NODE_ENV = env;
  1307. done();
  1308. });
  1309. it('throws in test mode with default message', function (done) {
  1310. var env = process.env.NODE_ENV;
  1311. process.env.NODE_ENV = 'test';
  1312. expect(function () {
  1313. Hoek.abort('', true);
  1314. }).to.throw('Unknown error');
  1315. process.env.NODE_ENV = env;
  1316. done();
  1317. });
  1318. it('defaults to showing stack', function (done) {
  1319. var env = process.env.NODE_ENV;
  1320. var write = process.stdout.write;
  1321. var exit = process.exit;
  1322. var output = '';
  1323. process.exit = function () { };
  1324. process.env.NODE_ENV = '';
  1325. process.stdout.write = function (message) {
  1326. output = message;
  1327. };
  1328. Hoek.abort('my error message');
  1329. process.env.NODE_ENV = env;
  1330. process.stdout.write = write;
  1331. process.exit = exit;
  1332. expect(output).to.contain('index.js');
  1333. done();
  1334. });
  1335. });
  1336. describe('assert()', function () {
  1337. it('throws an Error when using assert in a test', function (done) {
  1338. var fn = function () {
  1339. Hoek.assert(false, 'my error message');
  1340. };
  1341. expect(fn).to.throw('my error message');
  1342. done();
  1343. });
  1344. it('throws an Error when using assert in a test with no message', function (done) {
  1345. var fn = function () {
  1346. Hoek.assert(false);
  1347. };
  1348. expect(fn).to.throw('Unknown error');
  1349. done();
  1350. });
  1351. it('throws an Error when using assert in a test with multipart message', function (done) {
  1352. var fn = function () {
  1353. Hoek.assert(false, 'This', 'is', 'my message');
  1354. };
  1355. expect(fn).to.throw('This is my message');
  1356. done();
  1357. });
  1358. it('throws an Error when using assert in a test with multipart message (empty)', function (done) {
  1359. var fn = function () {
  1360. Hoek.assert(false, 'This', 'is', '', 'my message');
  1361. };
  1362. expect(fn).to.throw('This is my message');
  1363. done();
  1364. });
  1365. it('throws an Error when using assert in a test with object message', function (done) {
  1366. var fn = function () {
  1367. Hoek.assert(false, 'This', 'is', { spinal: 'tap' });
  1368. };
  1369. expect(fn).to.throw('This is {"spinal":"tap"}');
  1370. done();
  1371. });
  1372. it('throws an Error when using assert in a test with multipart string and error messages', function (done) {
  1373. var fn = function () {
  1374. Hoek.assert(false, 'This', 'is', new Error('spinal'), new Error('tap'));
  1375. };
  1376. expect(fn).to.throw('This is spinal tap');
  1377. done();
  1378. });
  1379. it('throws an Error when using assert in a test with error object message', function (done) {
  1380. var fn = function () {
  1381. Hoek.assert(false, new Error('This is spinal tap'));
  1382. };
  1383. expect(fn).to.throw('This is spinal tap');
  1384. done();
  1385. });
  1386. it('throws the same Error that is passed to it if there is only one error passed', function (done) {
  1387. var error = new Error('ruh roh');
  1388. var error2 = new Error('ruh roh');
  1389. var fn = function () {
  1390. Hoek.assert(false, error);
  1391. };
  1392. try {
  1393. fn();
  1394. } catch (err) {
  1395. expect(error).to.equal(error); // should be the same reference
  1396. expect(error).to.not.equal(error2); // error with the same message should not match
  1397. }
  1398. done();
  1399. });
  1400. });
  1401. describe('Timer', function () {
  1402. it('returns time elapsed', function (done) {
  1403. var timer = new Hoek.Timer();
  1404. setTimeout(function () {
  1405. expect(timer.elapsed()).to.be.above(9);
  1406. done();
  1407. }, 12);
  1408. });
  1409. });
  1410. describe('Bench', function () {
  1411. it('returns time elapsed', function (done) {
  1412. var timer = new Hoek.Bench();
  1413. setTimeout(function () {
  1414. expect(timer.elapsed()).to.be.above(9);
  1415. done();
  1416. }, 12);
  1417. });
  1418. });
  1419. describe('escapeRegex()', function () {
  1420. it('escapes all special regular expression characters', function (done) {
  1421. var a = Hoek.escapeRegex('4^f$s.4*5+-_?%=#!:@|~\\/`"(>)[<]d{}s,');
  1422. expect(a).to.equal('4\\^f\\$s\\.4\\*5\\+\\-_\\?%\\=#\\!\\:@\\|~\\\\\\/`"\\(>\\)\\[<\\]d\\{\\}s\\,');
  1423. done();
  1424. });
  1425. });
  1426. describe('Base64Url', function () {
  1427. var base64str = 'AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0-P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn-AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq-wsbKztLW2t7i5uru8vb6_wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t_g4eLj5OXm5-jp6uvs7e7v8PHy8_T19vf4-fr7_P3-_w';
  1428. 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');
  1429. describe('base64urlEncode()', function () {
  1430. it('should base64 URL-safe a string', function (done) {
  1431. expect(Hoek.base64urlEncode(str)).to.equal(base64str);
  1432. done();
  1433. });
  1434. it('encodes a buffer', function (done) {
  1435. expect(Hoek.base64urlEncode(new Buffer(str, 'binary'))).to.equal(base64str);
  1436. done();
  1437. });
  1438. it('should base64 URL-safe a hex string', function (done) {
  1439. var buffer = new Buffer(str, 'binary');
  1440. expect(Hoek.base64urlEncode(buffer.toString('hex'), 'hex')).to.equal(base64str);
  1441. done();
  1442. });
  1443. it('works on larger input strings', function (done) {
  1444. var input = Fs.readFileSync(Path.join(__dirname, 'index.js')).toString();
  1445. var encoded = Hoek.base64urlEncode(input);
  1446. expect(encoded).to.not.contain('+');
  1447. expect(encoded).to.not.contain('/');
  1448. var decoded = Hoek.base64urlDecode(encoded);
  1449. expect(decoded).to.equal(input);
  1450. done();
  1451. });
  1452. });
  1453. describe('base64urlDecode()', function () {
  1454. it('should un-base64 URL-safe a string', function (done) {
  1455. expect(Hoek.base64urlDecode(base64str)).to.equal(str);
  1456. done();
  1457. });
  1458. it('should un-base64 URL-safe a string into hex', function (done) {
  1459. expect(Hoek.base64urlDecode(base64str, 'hex')).to.equal(new Buffer(str, 'binary').toString('hex'));
  1460. done();
  1461. });
  1462. it('should un-base64 URL-safe a string and return a buffer', function (done) {
  1463. var buf = Hoek.base64urlDecode(base64str, 'buffer');
  1464. expect(buf instanceof Buffer).to.equal(true);
  1465. expect(buf.toString('binary')).to.equal(str);
  1466. done();
  1467. });
  1468. it('returns error on undefined input', function (done) {
  1469. expect(Hoek.base64urlDecode().message).to.exist();
  1470. done();
  1471. });
  1472. it('returns error on invalid input', function (done) {
  1473. expect(Hoek.base64urlDecode('*').message).to.exist();
  1474. done();
  1475. });
  1476. });
  1477. });
  1478. describe('escapeHeaderAttribute()', function () {
  1479. it('should not alter ascii values', function (done) {
  1480. var a = Hoek.escapeHeaderAttribute('My Value');
  1481. expect(a).to.equal('My Value');
  1482. done();
  1483. });
  1484. it('escapes all special HTTP header attribute characters', function (done) {
  1485. var a = Hoek.escapeHeaderAttribute('I said go!!!#"' + String.fromCharCode(92));
  1486. expect(a).to.equal('I said go!!!#\\"\\\\');
  1487. done();
  1488. });
  1489. it('throws on large unicode characters', function (done) {
  1490. var fn = function () {
  1491. Hoek.escapeHeaderAttribute('this is a test' + String.fromCharCode(500) + String.fromCharCode(300));
  1492. };
  1493. expect(fn).to.throw(Error);
  1494. done();
  1495. });
  1496. it('throws on CRLF to prevent response splitting', function (done) {
  1497. var fn = function () {
  1498. Hoek.escapeHeaderAttribute('this is a test\r\n');
  1499. };
  1500. expect(fn).to.throw(Error);
  1501. done();
  1502. });
  1503. });
  1504. describe('escapeHtml()', function () {
  1505. it('escapes all special HTML characters', function (done) {
  1506. var a = Hoek.escapeHtml('&<>"\'`');
  1507. expect(a).to.equal('&amp;&lt;&gt;&quot;&#x27;&#x60;');
  1508. done();
  1509. });
  1510. it('returns empty string on falsy input', function (done) {
  1511. var a = Hoek.escapeHtml('');
  1512. expect(a).to.equal('');
  1513. done();
  1514. });
  1515. it('returns unchanged string on no reserved input', function (done) {
  1516. var a = Hoek.escapeHtml('abc');
  1517. expect(a).to.equal('abc');
  1518. done();
  1519. });
  1520. });
  1521. describe('nextTick()', function () {
  1522. it('calls the provided callback on nextTick', function (done) {
  1523. var a = 0;
  1524. var inc = function (step, next) {
  1525. a += step;
  1526. next();
  1527. };
  1528. var ticked = Hoek.nextTick(inc);
  1529. ticked(5, function () {
  1530. expect(a).to.equal(6);
  1531. done();
  1532. });
  1533. expect(a).to.equal(0);
  1534. inc(1, function () {
  1535. expect(a).to.equal(1);
  1536. });
  1537. });
  1538. });
  1539. describe('once()', function () {
  1540. it('allows function to only execute once', function (done) {
  1541. var gen = 0;
  1542. var add = function (x) {
  1543. gen += x;
  1544. };
  1545. add(5);
  1546. expect(gen).to.equal(5);
  1547. add = Hoek.once(add);
  1548. add(5);
  1549. expect(gen).to.equal(10);
  1550. add(5);
  1551. expect(gen).to.equal(10);
  1552. done();
  1553. });
  1554. it('double once wraps one time', function (done) {
  1555. var method = function () { };
  1556. method = Hoek.once(method);
  1557. method.x = 1;
  1558. method = Hoek.once(method);
  1559. expect(method.x).to.equal(1);
  1560. done();
  1561. });
  1562. });
  1563. describe('isAbsoltePath()', function () {
  1564. it('identifies if path is absolute on Unix without node support', { parallel: false }, function (done) {
  1565. var orig = Path.isAbsolute;
  1566. Path.isAbsolute = undefined;
  1567. expect(Hoek.isAbsolutePath('')).to.equal(false);
  1568. expect(Hoek.isAbsolutePath('a')).to.equal(false);
  1569. expect(Hoek.isAbsolutePath('./a')).to.equal(false);
  1570. expect(Hoek.isAbsolutePath('/a')).to.equal(true);
  1571. expect(Hoek.isAbsolutePath('/')).to.equal(true);
  1572. Path.isAbsolute = orig;
  1573. done();
  1574. });
  1575. it('identifies if path is absolute with fake node support', { parallel: false }, function (done) {
  1576. var orig = Path.isAbsolute;
  1577. Path.isAbsolute = function (path) {
  1578. return path[0] === '/';
  1579. };
  1580. expect(Hoek.isAbsolutePath('', 'linux')).to.equal(false);
  1581. expect(Hoek.isAbsolutePath('a', 'linux')).to.equal(false);
  1582. expect(Hoek.isAbsolutePath('./a', 'linux')).to.equal(false);
  1583. expect(Hoek.isAbsolutePath('/a', 'linux')).to.equal(true);
  1584. expect(Hoek.isAbsolutePath('/', 'linux')).to.equal(true);
  1585. Path.isAbsolute = orig;
  1586. done();
  1587. });
  1588. it('identifies if path is absolute on Windows without node support', { parallel: false }, function (done) {
  1589. var orig = Path.isAbsolute;
  1590. Path.isAbsolute = undefined;
  1591. expect(Hoek.isAbsolutePath('//server/file', 'win32')).to.equal(true);
  1592. expect(Hoek.isAbsolutePath('//server/file', 'win32')).to.equal(true);
  1593. expect(Hoek.isAbsolutePath('\\\\server\\file', 'win32')).to.equal(true);
  1594. expect(Hoek.isAbsolutePath('C:/Users/', 'win32')).to.equal(true);
  1595. expect(Hoek.isAbsolutePath('C:\\Users\\', 'win32')).to.equal(true);
  1596. expect(Hoek.isAbsolutePath('C:cwd/another', 'win32')).to.equal(false);
  1597. expect(Hoek.isAbsolutePath('C:cwd\\another', 'win32')).to.equal(false);
  1598. expect(Hoek.isAbsolutePath('directory/directory', 'win32')).to.equal(false);
  1599. expect(Hoek.isAbsolutePath('directory\\directory', 'win32')).to.equal(false);
  1600. Path.isAbsolute = orig;
  1601. done();
  1602. });
  1603. });
  1604. describe('isInteger()', function () {
  1605. it('validates integers', function (done) {
  1606. expect(Hoek.isInteger(0)).to.equal(true);
  1607. expect(Hoek.isInteger(1)).to.equal(true);
  1608. expect(Hoek.isInteger(1394035612500)).to.equal(true);
  1609. expect(Hoek.isInteger('0')).to.equal(false);
  1610. expect(Hoek.isInteger(1.0)).to.equal(true);
  1611. expect(Hoek.isInteger(1.1)).to.equal(false);
  1612. done();
  1613. });
  1614. });
  1615. describe('ignore()', function () {
  1616. it('exists', function (done) {
  1617. expect(Hoek.ignore).to.exist();
  1618. expect(typeof Hoek.ignore).to.equal('function');
  1619. done();
  1620. });
  1621. });
  1622. describe('inherits()', function () {
  1623. it('exists', function (done) {
  1624. expect(Hoek.inherits).to.exist();
  1625. expect(typeof Hoek.inherits).to.equal('function');
  1626. done();
  1627. });
  1628. });
  1629. describe('format()', function () {
  1630. it('exists', function (done) {
  1631. expect(Hoek.format).to.exist();
  1632. expect(typeof Hoek.format).to.equal('function');
  1633. done();
  1634. });
  1635. it('is a reference to Util.format', function (done) {
  1636. expect(Hoek.format('hello %s', 'world')).to.equal('hello world');
  1637. done();
  1638. });
  1639. });
  1640. describe('transform()', function () {
  1641. var source = {
  1642. address: {
  1643. one: '123 main street',
  1644. two: 'PO Box 1234'
  1645. },
  1646. zip: {
  1647. code: 3321232,
  1648. province: null
  1649. },
  1650. title: 'Warehouse',
  1651. state: 'CA'
  1652. };
  1653. var sourcesArray = [{
  1654. address: {
  1655. one: '123 main street',
  1656. two: 'PO Box 1234'
  1657. },
  1658. zip: {
  1659. code: 3321232,
  1660. province: null
  1661. },
  1662. title: 'Warehouse',
  1663. state: 'CA'
  1664. }, {
  1665. address: {
  1666. one: '456 market street',
  1667. two: 'PO Box 5678'
  1668. },
  1669. zip: {
  1670. code: 9876,
  1671. province: null
  1672. },
  1673. title: 'Garage',
  1674. state: 'NY'
  1675. }];
  1676. it('transforms an object based on the input object', function (done) {
  1677. var result = Hoek.transform(source, {
  1678. 'person.address.lineOne': 'address.one',
  1679. 'person.address.lineTwo': 'address.two',
  1680. 'title': 'title',
  1681. 'person.address.region': 'state',
  1682. 'person.address.zip': 'zip.code',
  1683. 'person.address.location': 'zip.province'
  1684. });
  1685. expect(result).to.deep.equal({
  1686. person: {
  1687. address: {
  1688. lineOne: '123 main street',
  1689. lineTwo: 'PO Box 1234',
  1690. region: 'CA',
  1691. zip: 3321232,
  1692. location: null
  1693. }
  1694. },
  1695. title: 'Warehouse'
  1696. });
  1697. done();
  1698. });
  1699. it('transforms an array of objects based on the input object', function (done) {
  1700. var result = Hoek.transform(sourcesArray, {
  1701. 'person.address.lineOne': 'address.one',
  1702. 'person.address.lineTwo': 'address.two',
  1703. 'title': 'title',
  1704. 'person.address.region': 'state',
  1705. 'person.address.zip': 'zip.code',
  1706. 'person.address.location': 'zip.province'
  1707. });
  1708. expect(result).to.deep.equal([
  1709. {
  1710. person: {
  1711. address: {
  1712. lineOne: '123 main street',
  1713. lineTwo: 'PO Box 1234',
  1714. region: 'CA',
  1715. zip: 3321232,
  1716. location: null
  1717. }
  1718. },
  1719. title: 'Warehouse'
  1720. },
  1721. {
  1722. person: {
  1723. address: {
  1724. lineOne: '456 market street',
  1725. lineTwo: 'PO Box 5678',
  1726. region: 'NY',
  1727. zip: 9876,
  1728. location: null
  1729. }
  1730. },
  1731. title: 'Garage'
  1732. }
  1733. ]);
  1734. done();
  1735. });
  1736. it('uses the reach options passed into it', function (done) {
  1737. var schema = {
  1738. 'person.address.lineOne': 'address-one',
  1739. 'person.address.lineTwo': 'address-two',
  1740. 'title': 'title',
  1741. 'person.address.region': 'state',
  1742. 'person.prefix': 'person-title',
  1743. 'person.zip': 'zip-code'
  1744. };
  1745. var options = {
  1746. separator: '-',
  1747. default: 'unknown'
  1748. };
  1749. var result = Hoek.transform(source, schema, options);
  1750. expect(result).to.deep.equal({
  1751. person: {
  1752. address: {
  1753. lineOne: '123 main street',
  1754. lineTwo: 'PO Box 1234',
  1755. region: 'CA'
  1756. },
  1757. prefix: 'unknown',
  1758. zip: 3321232
  1759. },
  1760. title: 'Warehouse'
  1761. });
  1762. done();
  1763. });
  1764. it('works to create shallow objects', function (done) {
  1765. var result = Hoek.transform(source, {
  1766. lineOne: 'address.one',
  1767. lineTwo: 'address.two',
  1768. title: 'title',
  1769. region: 'state',
  1770. province: 'zip.province'
  1771. });
  1772. expect(result).to.deep.equal({
  1773. lineOne: '123 main street',
  1774. lineTwo: 'PO Box 1234',
  1775. title: 'Warehouse',
  1776. region: 'CA',
  1777. province: null
  1778. });
  1779. done();
  1780. });
  1781. it('only allows strings in the map', function (done) {
  1782. expect(function () {
  1783. var result = Hoek.transform(source, {
  1784. lineOne: {}
  1785. });
  1786. }).to.throw('All mappings must be "." delineated strings');
  1787. done();
  1788. });
  1789. it('throws an error on invalid arguments', function (done) {
  1790. expect(function () {
  1791. var result = Hoek.transform(NaN, {});
  1792. }).to.throw('Invalid source object: must be null, undefined, an object, or an array');
  1793. done();
  1794. });
  1795. it('is safe to pass null', function (done) {
  1796. var result = Hoek.transform(null, {});
  1797. expect(result).to.deep.equal({});
  1798. done();
  1799. });
  1800. it('is safe to pass undefined', function (done) {
  1801. var result = Hoek.transform(undefined, {});
  1802. expect(result).to.deep.equal({});
  1803. done();
  1804. });
  1805. });
  1806. describe('uniqueFilename()', function () {
  1807. it('generates a random file path', function (done) {
  1808. var result = Hoek.uniqueFilename('./test/modules');
  1809. expect(result).to.exist();
  1810. expect(result).to.be.a.string();
  1811. expect(result).to.contain('test/modules');
  1812. done();
  1813. });
  1814. it('is random enough to use in fast loops', function (done) {
  1815. var results = [];
  1816. for (var i = 0; i < 10; ++i) {
  1817. results[i] = Hoek.uniqueFilename('./test/modules');
  1818. }
  1819. var filter = results.filter(function (item, index, array) {
  1820. return array.indexOf(item) === index;
  1821. });
  1822. expect(filter.length).to.equal(10);
  1823. expect(results.length).to.equal(10);
  1824. done();
  1825. });
  1826. it('combines the random elements with a supplied character', function (done) {
  1827. var result = Hoek.uniqueFilename('./test', 'txt');
  1828. expect(result).to.contain('test/');
  1829. expect(result).to.contain('.txt');
  1830. done();
  1831. });
  1832. it('accepts extensions with a "." in it', function (done) {
  1833. var result = Hoek.uniqueFilename('./test', '.mp3');
  1834. expect(result).to.contain('test/');
  1835. expect(result).to.contain('.mp3');
  1836. done();
  1837. });
  1838. });
  1839. describe('stringify()', function (done) {
  1840. it('converts object to string', function (done) {
  1841. var obj = { a: 1 };
  1842. expect(Hoek.stringify(obj)).to.equal('{"a":1}');
  1843. done();
  1844. });
  1845. it('returns error in result string', function (done) {
  1846. var obj = { a: 1 };
  1847. obj.b = obj;
  1848. expect(Hoek.stringify(obj)).to.equal('[Cannot display object: Converting circular structure to JSON]');
  1849. done();
  1850. });
  1851. });
  1852. describe('shallow()', function (done) {
  1853. it('shallow copies an object', function (done) {
  1854. var obj = {
  1855. a: 5,
  1856. b: {
  1857. c: 6
  1858. }
  1859. };
  1860. var shallow = Hoek.shallow(obj);
  1861. expect(shallow).to.not.equal(obj);
  1862. expect(shallow).to.deep.equal(obj);
  1863. expect(shallow.b).to.equal(obj.b);
  1864. done();
  1865. });
  1866. });