index.js 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079
  1. // Load modules
  2. var Lab = require('lab');
  3. var Hoek = require('../lib');
  4. // Declare internals
  5. var internals = {};
  6. // Test shortcuts
  7. var expect = Lab.expect;
  8. var before = Lab.before;
  9. var after = Lab.after;
  10. var describe = Lab.experiment;
  11. var it = Lab.test;
  12. describe('Hoek', function () {
  13. var nestedObj = {
  14. v: [7,8,9],
  15. w: /^something$/igm,
  16. x: {
  17. a: [1, 2, 3],
  18. b: 123456,
  19. c: new Date(),
  20. d: /hi/igm,
  21. e: /hello/
  22. },
  23. y: 'y',
  24. z: new Date()
  25. };
  26. var dupsArray = [nestedObj, { z: 'z' }, nestedObj];
  27. var reducedDupsArray = [nestedObj, { z: 'z' }];
  28. describe('#clone', function () {
  29. it('should clone a nested object', function (done) {
  30. var a = nestedObj;
  31. var b = Hoek.clone(a);
  32. expect(a).to.deep.equal(b);
  33. expect(a.z.getTime()).to.equal(b.z.getTime());
  34. done();
  35. });
  36. it('should clone a null object', function (done) {
  37. var b = Hoek.clone(null);
  38. expect(b).to.equal(null);
  39. done();
  40. });
  41. it('should not convert undefined properties to null', function (done) {
  42. var obj = { something: undefined };
  43. var b = Hoek.clone(obj);
  44. expect(typeof b.something).to.equal('undefined');
  45. done();
  46. });
  47. it('should not throw on circular reference', function (done) {
  48. var a = {};
  49. a.x = a;
  50. var test = (function () {
  51. var b = Hoek.clone(a);
  52. });
  53. expect(test).to.not.throw();
  54. done();
  55. });
  56. it('should properly clone circular reference', function (done) {
  57. var x = {
  58. 'z': new Date()
  59. };
  60. x.y = x;
  61. var b = Hoek.clone(x);
  62. expect(Object.keys(b.y)).to.deep.equal(Object.keys(x))
  63. expect(b.z).to.not.equal(x.z);
  64. expect(b.y).to.not.equal(x.y);
  65. expect(b.y.z).to.not.equal(x.y.z);
  66. expect(b.y).to.equal(b);
  67. expect(b.y.y.y.y).to.equal(b);
  68. done();
  69. });
  70. it('should properly clone deeply nested object', function (done) {
  71. var a = {
  72. x: {
  73. y: {
  74. a: [1, 2, 3],
  75. b: 123456,
  76. c: new Date(),
  77. d: /hi/igm,
  78. e: /hello/
  79. },
  80. }
  81. };
  82. var b = Hoek.clone(a);
  83. expect(a).to.deep.equal(b);
  84. expect(a.x.y.c.getTime()).to.equal(b.x.y.c.getTime());
  85. done();
  86. });
  87. it('should properly clone arrays', function (done) {
  88. var a = [1,2,3];
  89. var b = Hoek.clone(a);
  90. expect(a).to.deep.equal(b);
  91. done();
  92. });
  93. it('should perform actual copy for shallow keys (no pass by reference)', function (done) {
  94. var x = Hoek.clone(nestedObj);
  95. var y = Hoek.clone(nestedObj);
  96. // Date
  97. expect(x.z).to.not.equal(nestedObj.z);
  98. expect(x.z).to.not.equal(y.z);
  99. // Regex
  100. expect(x.w).to.not.equal(nestedObj.w);
  101. expect(x.w).to.not.equal(y.w);
  102. // Array
  103. expect(x.v).to.not.equal(nestedObj.v);
  104. expect(x.v).to.not.equal(y.v);
  105. // Immutable(s)
  106. x.y = 5;
  107. expect(x.y).to.not.equal(nestedObj.y);
  108. expect(x.y).to.not.equal(y.y);
  109. done();
  110. });
  111. it('should perform actual copy for deep keys (no pass by reference)', function (done) {
  112. var x = Hoek.clone(nestedObj);
  113. var y = Hoek.clone(nestedObj);
  114. expect(x.x.c).to.not.equal(nestedObj.x.c);
  115. expect(x.x.c).to.not.equal(y.x.c);
  116. expect(x.x.c.getTime()).to.equal(nestedObj.x.c.getTime());
  117. expect(x.x.c.getTime()).to.equal(y.x.c.getTime());
  118. done();
  119. });
  120. it('copies functions with properties', function (done) {
  121. var a = {
  122. x: function () { return 1; },
  123. y: {}
  124. };
  125. a.x.z = 'string in function';
  126. a.x.v = function () { return 2; };
  127. a.y.u = a.x;
  128. var b = Hoek.clone(a);
  129. expect(b.x()).to.equal(1);
  130. expect(b.x.v()).to.equal(2);
  131. expect(b.y.u).to.equal(b.x);
  132. expect(b.x.z).to.equal('string in function');
  133. done();
  134. });
  135. it('should copy a buffer', function(done){
  136. var tls = {
  137. key: new Buffer([1,2,3,4,5]),
  138. cert: new Buffer([1,2,3,4,5,6,10])
  139. }
  140. copiedTls = Hoek.clone(tls);
  141. expect(Buffer.isBuffer(copiedTls.key)).to.equal(true);
  142. expect(JSON.stringify(copiedTls.key)).to.equal(JSON.stringify(tls.key))
  143. expect(Buffer.isBuffer(copiedTls.cert)).to.equal(true);
  144. expect(JSON.stringify(copiedTls.cert)).to.equal(JSON.stringify(tls.cert))
  145. done();
  146. });
  147. });
  148. describe('#merge', function () {
  149. it('does not throw if source is null', function (done) {
  150. var a = {};
  151. var b = null;
  152. var c = null;
  153. expect(function () {
  154. c = Hoek.merge(a, b);
  155. }).to.not.throw();
  156. expect(c).to.equal(a);
  157. done();
  158. });
  159. it('does not throw if source is undefined', function (done) {
  160. var a = {};
  161. var b = undefined;
  162. var c = null;
  163. expect(function () {
  164. c = Hoek.merge(a, b);
  165. }).to.not.throw();
  166. expect(c).to.equal(a);
  167. done();
  168. });
  169. it('throws if source is not an object', function (done) {
  170. expect(function () {
  171. var a = {};
  172. var b = 0;
  173. Hoek.merge(a, b);
  174. }).to.throw('Invalid source value: must be null, undefined, or an object');
  175. done();
  176. });
  177. it('throws if target is not an object', function (done) {
  178. expect(function () {
  179. var a = 0;
  180. var b = {};
  181. Hoek.merge(a, b);
  182. }).to.throw('Invalid target value: must be an object');
  183. done();
  184. });
  185. it('throws if target is not an array and source is', function (done) {
  186. expect(function () {
  187. var a = {};
  188. var b = [1, 2];
  189. Hoek.merge(a, b);
  190. }).to.throw('Cannot merge array onto an object');
  191. done();
  192. });
  193. it('returns the same object when merging arrays', function (done) {
  194. var a = [];
  195. var b = [1, 2];
  196. expect(Hoek.merge(a, b)).to.equal(a);
  197. done();
  198. });
  199. it('should combine an empty object with a non-empty object', function (done) {
  200. var a = {};
  201. var b = nestedObj;
  202. var c = Hoek.merge(a, b);
  203. expect(a).to.deep.equal(b);
  204. expect(c).to.deep.equal(b);
  205. done();
  206. });
  207. it('should override values in target', function (done) {
  208. var a = { x: 1, y: 2, z: 3, v: 5, t: 'test', m: 'abc' };
  209. var b = { x: null, z: 4, v: 0, t: { u: 6 }, m: '123' };
  210. var c = Hoek.merge(a, b);
  211. expect(c.x).to.equal(null);
  212. expect(c.y).to.equal(2);
  213. expect(c.z).to.equal(4);
  214. expect(c.v).to.equal(0);
  215. expect(c.m).to.equal('123');
  216. expect(c.t).to.deep.equal({ u: 6 });
  217. done();
  218. });
  219. it('should override values in target (flip)', function (done) {
  220. var a = { x: 1, y: 2, z: 3, v: 5, t: 'test', m: 'abc' };
  221. var b = { x: null, z: 4, v: 0, t: { u: 6 }, m: '123' };
  222. var d = Hoek.merge(b, a);
  223. expect(d.x).to.equal(1);
  224. expect(d.y).to.equal(2);
  225. expect(d.z).to.equal(3);
  226. expect(d.v).to.equal(5);
  227. expect(d.m).to.equal('abc');
  228. expect(d.t).to.deep.equal('test');
  229. done();
  230. });
  231. });
  232. describe('#applyToDefaults', function () {
  233. var defaults = {
  234. a: 1,
  235. b: 2,
  236. c: {
  237. d: 3,
  238. e: [5, 6]
  239. },
  240. f: 6,
  241. g: 'test'
  242. };
  243. it('should return null if options is false', function (done) {
  244. var result = Hoek.applyToDefaults(defaults, false);
  245. expect(result).to.equal(null);
  246. done();
  247. });
  248. it('should return a copy of defaults if options is true', function (done) {
  249. var result = Hoek.applyToDefaults(defaults, true);
  250. expect(result).to.deep.equal(result);
  251. done();
  252. });
  253. it('should apply object to defaults', function (done) {
  254. var obj = {
  255. a: null,
  256. c: {
  257. e: [4]
  258. },
  259. f: 0,
  260. g: {
  261. h: 5
  262. }
  263. };
  264. var result = Hoek.applyToDefaults(defaults, obj);
  265. expect(result.c.e).to.deep.equal([4]);
  266. expect(result.a).to.equal(1);
  267. expect(result.b).to.equal(2);
  268. expect(result.f).to.equal(0);
  269. expect(result.g).to.deep.equal({ h: 5 });
  270. done();
  271. });
  272. });
  273. describe('#unique', function () {
  274. it('should ensure uniqueness within array of objects based on subkey', function (done) {
  275. var a = Hoek.unique(dupsArray, 'x');
  276. expect(a).to.deep.equal(reducedDupsArray);
  277. done();
  278. });
  279. it('removes duplicated without key', function (done) {
  280. expect(Hoek.unique([1, 2, 3, 4, 2, 1, 5])).to.deep.equal([1, 2, 3, 4, 5]);
  281. done();
  282. });
  283. });
  284. describe('#mapToObject', function () {
  285. it('should return null on null array', function (done) {
  286. var a = Hoek.mapToObject(null);
  287. expect(a).to.equal(null);
  288. done();
  289. });
  290. it('should convert basic array to existential object', function (done) {
  291. var keys = [1, 2, 3, 4];
  292. var a = Hoek.mapToObject(keys);
  293. for (var i in keys) {
  294. expect(a[keys[i]]).to.equal(true);
  295. }
  296. done();
  297. });
  298. it('should convert array of objects to existential object', function (done) {
  299. var keys = [{ x: 1 }, { x: 2 }, { x: 3 }];
  300. var subkey = 'x';
  301. var a = Hoek.mapToObject(keys, subkey);
  302. for (var i in keys) {
  303. expect(a[keys[i][subkey]]).to.equal(true);
  304. }
  305. done();
  306. });
  307. });
  308. describe('#intersect', function () {
  309. it('should return the common objects of two arrays', function (done) {
  310. var array1 = [1, 2, 3, 4, 4, 5, 5];
  311. var array2 = [5, 4, 5, 6, 7];
  312. var common = Hoek.intersect(array1, array2);
  313. expect(common.length).to.equal(2);
  314. done();
  315. });
  316. it('should return just the first common object of two arrays', function (done) {
  317. var array1 = [1, 2, 3, 4, 4, 5, 5];
  318. var array2 = [5, 4, 5, 6, 7];
  319. var common = Hoek.intersect(array1, array2, true);
  320. expect(common).to.equal(5);
  321. done();
  322. });
  323. it('should return an empty array if either input is null', function (done) {
  324. expect(Hoek.intersect([1], null).length).to.equal(0);
  325. expect(Hoek.intersect(null, [1]).length).to.equal(0);
  326. done();
  327. });
  328. it('should return the common objects of object and array', function (done) {
  329. var array1 = [1, 2, 3, 4, 4, 5, 5];
  330. var array2 = [5, 4, 5, 6, 7];
  331. var common = Hoek.intersect(Hoek.mapToObject(array1), array2);
  332. expect(common.length).to.equal(2);
  333. done();
  334. });
  335. });
  336. describe('#matchKeys', function () {
  337. it('should match the existing object keys', function (done) {
  338. var obj = {
  339. a: 1,
  340. b: 2,
  341. c: 3,
  342. d: null
  343. };
  344. expect(Hoek.matchKeys(obj, ['b', 'c', 'd', 'e'])).to.deep.equal(['b', 'c', 'd']);
  345. done();
  346. });
  347. });
  348. describe('#flatten', function () {
  349. it('should return a flat array', function (done) {
  350. var result = Hoek.flatten([1, 2, [3, 4, [5, 6], [7], 8], [9], [10, [11, 12]], 13]);
  351. expect(result.length).to.equal(13);
  352. expect(result).to.deep.equal([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]);
  353. done();
  354. });
  355. });
  356. describe('#removeKeys', function () {
  357. var objWithHiddenKeys = {
  358. location: {
  359. name: 'San Bruno'
  360. },
  361. company: {
  362. name: '@WalmartLabs'
  363. }
  364. };
  365. it('should delete params with definition\'s hide set to true', function (done) {
  366. var a = Hoek.removeKeys(objWithHiddenKeys, ['location']);
  367. expect(objWithHiddenKeys.location).to.not.exist;
  368. expect(objWithHiddenKeys.company).to.exist;
  369. done();
  370. });
  371. });
  372. describe('#reach', function () {
  373. var obj = {
  374. a: {
  375. b: {
  376. c: {
  377. d: 1,
  378. e: 2
  379. },
  380. f: 'hello'
  381. },
  382. g: {
  383. h: 3
  384. }
  385. },
  386. i: function () { }
  387. };
  388. it('returns a valid member', function (done) {
  389. expect(Hoek.reach(obj, 'a.b.c.d')).to.equal(1);
  390. done();
  391. });
  392. it('returns null on null object', function (done) {
  393. expect(Hoek.reach(null, 'a.b.c.d')).to.not.exist;
  394. done();
  395. });
  396. it('returns null on missing member', function (done) {
  397. expect(Hoek.reach(obj, 'a.b.c.d.x')).to.not.exist;
  398. done();
  399. });
  400. it('returns null on invalid member', function (done) {
  401. expect(Hoek.reach(obj, 'a.b.c.d-.x')).to.not.exist;
  402. done();
  403. });
  404. it('returns function member', function (done) {
  405. expect(typeof Hoek.reach(obj, 'i')).to.equal('function');
  406. done();
  407. });
  408. });
  409. describe('#inheritAsync', function () {
  410. it('should inherit selected methods and wrap in async call', function (done) {
  411. var proto = {
  412. a: function () {
  413. return 'a!';
  414. },
  415. b: function () {
  416. return 'b!';
  417. },
  418. c: function () {
  419. throw new Error('c!');
  420. }
  421. };
  422. var targetFunc = function () { };
  423. targetFunc.prototype.c = function () {
  424. return 'oops';
  425. };
  426. Hoek.inheritAsync(targetFunc, proto, ['a', 'c']);
  427. var target = new targetFunc();
  428. expect(typeof target.a).to.equal('function');
  429. expect(typeof target.c).to.equal('function');
  430. expect(target.b).to.not.exist;
  431. target.a(function (err, result) {
  432. expect(err).to.not.exist;
  433. expect(result).to.equal('a!');
  434. target.c(function (err, result) {
  435. expect(result).to.not.exist;
  436. expect(err.message).to.equal('c!');
  437. done();
  438. });
  439. });
  440. });
  441. });
  442. describe('#callStack', function () {
  443. it('should return the full call stack', function (done) {
  444. var stack = Hoek.callStack();
  445. expect(stack[0][0]).to.contain('index.js');
  446. expect(stack[0][2]).to.equal(30);
  447. done();
  448. });
  449. });
  450. describe('#displayStack ', function () {
  451. it('should return the full call stack for display', function (done) {
  452. var stack = Hoek.displayStack();
  453. expect(stack[0]).to.contain('test/index.js:');
  454. done();
  455. });
  456. it('should include constructor functions correctly', function (done) {
  457. var Something = function (next) {
  458. next();
  459. };
  460. var something = new Something(function () {
  461. var stack = Hoek.displayStack();
  462. expect(stack[1]).to.contain('new Something');
  463. done();
  464. });
  465. });
  466. });
  467. describe('#abort', function () {
  468. it('should exit process when not in test mode', function (done) {
  469. var env = process.env.NODE_ENV;
  470. var write = process.stdout.write;
  471. var exit = process.exit;
  472. process.env.NODE_ENV = 'nottatest';
  473. process.stdout.write = function () { };
  474. process.exit = function (state) {
  475. process.exit = exit;
  476. process.env.NODE_ENV = env;
  477. process.stdout.write = write;
  478. expect(state).to.equal(1);
  479. done();
  480. };
  481. Hoek.abort('Boom');
  482. });
  483. it('should throw when not in test mode and abortThrow is true', function (done) {
  484. var env = process.env.NODE_ENV;
  485. process.env.NODE_ENV = 'nottatest';
  486. Hoek.abortThrow = true;
  487. var fn = function () {
  488. Hoek.abort('my error message');
  489. };
  490. expect(fn).to.throw('my error message');
  491. Hoek.abortThrow = false;
  492. process.env.NODE_ENV = env;
  493. done();
  494. });
  495. it('should respect hideStack argument', function (done) {
  496. var env = process.env.NODE_ENV;
  497. var write = process.stdout.write;
  498. var exit = process.exit;
  499. var output = '';
  500. process.exit = function () { };
  501. process.env.NODE_ENV = '';
  502. process.stdout.write = function (message) {
  503. output = message;
  504. };
  505. Hoek.abort('my error message', true);
  506. process.env.NODE_ENV = env;
  507. process.stdout.write = write;
  508. process.exit = exit;
  509. expect(output).to.equal('ABORT: my error message\n\t\n');
  510. done();
  511. });
  512. it('should default to showing stack', function (done) {
  513. var env = process.env.NODE_ENV;
  514. var write = process.stdout.write;
  515. var exit = process.exit;
  516. var output = '';
  517. process.exit = function () { };
  518. process.env.NODE_ENV = '';
  519. process.stdout.write = function (message) {
  520. output = message;
  521. };
  522. Hoek.abort('my error message');
  523. process.env.NODE_ENV = env;
  524. process.stdout.write = write;
  525. process.exit = exit;
  526. expect(output).to.contain('index.js');
  527. done();
  528. });
  529. });
  530. describe('#assert', function () {
  531. it('should throw an Error when using assert in a test', function (done) {
  532. var fn = function () {
  533. Hoek.assert(false, 'my error message');
  534. };
  535. expect(fn).to.throw('my error message');
  536. done();
  537. });
  538. it('should throw an Error when using assert in a test with no message', function (done) {
  539. var fn = function () {
  540. Hoek.assert(false);
  541. };
  542. expect(fn).to.throw('Unknown error');
  543. done();
  544. });
  545. it('should throw an Error when using assert in a test with multipart message', function (done) {
  546. var fn = function () {
  547. Hoek.assert(false, 'This', 'is', 'my message');
  548. };
  549. expect(fn).to.throw('This is my message');
  550. done();
  551. });
  552. it('should throw an Error when using assert in a test with object message', function (done) {
  553. var fn = function () {
  554. Hoek.assert(false, 'This', 'is', { spinal: 'tap' });
  555. };
  556. expect(fn).to.throw('This is {"spinal":"tap"}');
  557. done();
  558. });
  559. it('should throw an Error when using assert in a test with error object message', function (done) {
  560. var fn = function () {
  561. Hoek.assert(false, new Error('This is spinal tap'));
  562. };
  563. expect(fn).to.throw('This is spinal tap');
  564. done();
  565. });
  566. });
  567. describe('#loadDirModules', function () {
  568. it('should load modules from directory', function (done) {
  569. var target = {};
  570. Hoek.loadDirModules(__dirname + '/modules', ['test2'], target);
  571. expect(target.Test1.x).to.equal(1);
  572. expect(target.Test2).to.not.exist;
  573. expect(target.Test3.z).to.equal(3);
  574. done();
  575. });
  576. it('should list modules from directory into function', function (done) {
  577. var target = {};
  578. Hoek.loadDirModules(__dirname + '/modules', ['test2'], function (path, name, capName) {
  579. target[name] = capName;
  580. });
  581. expect(target.test1).to.equal('Test1');
  582. expect(target.test2).to.not.exist;
  583. expect(target.test3).to.equal('Test3');
  584. done();
  585. });
  586. });
  587. describe('#rename', function () {
  588. it('should rename object key', function (done) {
  589. var a = { b: 'c' };
  590. Hoek.rename(a, 'b', 'x');
  591. expect(a.b).to.not.exist;
  592. expect(a.x).to.equal('c');
  593. done();
  594. });
  595. });
  596. describe('Timer', function () {
  597. it('should return time elapsed', function (done) {
  598. var timer = new Hoek.Timer();
  599. setTimeout(function () {
  600. expect(timer.elapsed()).to.be.above(9);
  601. done();
  602. }, 12);
  603. });
  604. });
  605. describe('#loadPackage', function () {
  606. it('should', function (done) {
  607. var pack = Hoek.loadPackage();
  608. expect(pack.name).to.equal('hoek');
  609. done();
  610. });
  611. });
  612. describe('#escapeRegex', function () {
  613. it('should escape all special regular expression characters', function (done) {
  614. var a = Hoek.escapeRegex('4^f$s.4*5+-_?%=#!:@|~\\/`"(>)[<]d{}s,');
  615. expect(a).to.equal('4\\^f\\$s\\.4\\*5\\+\\-_\\?%\\=#\\!\\:@\\|~\\\\\\/`"\\(>\\)\\[<\\]d\\{\\}s\\,');
  616. done();
  617. });
  618. });
  619. describe('#toss', function () {
  620. it('should call callback with new error', function (done) {
  621. var callback = function (err) {
  622. expect(err).to.exist;
  623. expect(err.message).to.equal('bug');
  624. done();
  625. };
  626. Hoek.toss(true, 'feature', callback);
  627. Hoek.toss(false, 'bug', callback);
  628. });
  629. it('should call callback with new error and no message', function (done) {
  630. Hoek.toss(false, function (err) {
  631. expect(err).to.exist;
  632. expect(err.message).to.equal('');
  633. done();
  634. });
  635. });
  636. it('should call callback with error condition', function (done) {
  637. Hoek.toss(new Error('boom'), function (err) {
  638. expect(err).to.exist;
  639. expect(err.message).to.equal('boom');
  640. done();
  641. });
  642. });
  643. it('should call callback with new error using message with error condition', function (done) {
  644. Hoek.toss(new Error('ka'), 'boom', function (err) {
  645. expect(err).to.exist;
  646. expect(err.message).to.equal('boom');
  647. done();
  648. });
  649. });
  650. it('should call callback with new error using passed error with error condition', function (done) {
  651. Hoek.toss(new Error('ka'), new Error('boom'), function (err) {
  652. expect(err).to.exist;
  653. expect(err.message).to.equal('boom');
  654. done();
  655. });
  656. });
  657. });
  658. describe('Base64Url', function () {
  659. var base64str = 'AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0-P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn-AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq-wsbKztLW2t7i5uru8vb6_wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t_g4eLj5OXm5-jp6uvs7e7v8PHy8_T19vf4-fr7_P3-_w';
  660. 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');
  661. describe('#base64urlEncode', function () {
  662. it('should base64 URL-safe a string', function (done) {
  663. expect(Hoek.base64urlEncode(str)).to.equal(base64str);
  664. done();
  665. });
  666. });
  667. describe('#base64urlDecode', function () {
  668. it('should un-base64 URL-safe a string', function (done) {
  669. expect(Hoek.base64urlDecode(base64str)).to.equal(str);
  670. done();
  671. });
  672. it('should return error on undefined input', function (done) {
  673. expect(Hoek.base64urlDecode().message).to.exist;
  674. done();
  675. });
  676. it('should return error on invalid input', function (done) {
  677. expect(Hoek.base64urlDecode('*').message).to.exist;
  678. done();
  679. });
  680. });
  681. });
  682. describe('#escapeHeaderAttribute', function () {
  683. it('should not alter ascii values', function (done) {
  684. var a = Hoek.escapeHeaderAttribute('My Value');
  685. expect(a).to.equal('My Value');
  686. done();
  687. });
  688. it('should escape all special HTTP header attribute characters', function (done) {
  689. var a = Hoek.escapeHeaderAttribute('I said go!!!#"' + String.fromCharCode(92));
  690. expect(a).to.equal('I said go!!!#\\"\\\\');
  691. done();
  692. });
  693. it('should throw on large unicode characters', function (done) {
  694. var fn = function () {
  695. Hoek.escapeHeaderAttribute('this is a test' + String.fromCharCode(500) + String.fromCharCode(300));
  696. };
  697. expect(fn).to.throw(Error);
  698. done();
  699. });
  700. it('should throw on CRLF to prevent response splitting', function (done) {
  701. var fn = function () {
  702. Hoek.escapeHeaderAttribute('this is a test\r\n');
  703. };
  704. expect(fn).to.throw(Error);
  705. done();
  706. });
  707. });
  708. describe('#escapeHtml', function () {
  709. it('should escape all special HTML characters', function (done) {
  710. var a = Hoek.escapeHtml('&<>"\'`');
  711. expect(a).to.equal('&amp;&lt;&gt;&quot;&#x27;&#x60;');
  712. done();
  713. });
  714. it('should return empty string on falsy input', function (done) {
  715. var a = Hoek.escapeHtml('');
  716. expect(a).to.equal('');
  717. done();
  718. });
  719. it('should return unchanged string on no reserved input', function (done) {
  720. var a = Hoek.escapeHtml('abc');
  721. expect(a).to.equal('abc');
  722. done();
  723. });
  724. });
  725. describe('#printEvent', function () {
  726. it('outputs event as string', function (done) {
  727. var event = {
  728. timestamp: (new Date(2013, 1, 1, 6, 30, 45, 123)).getTime(),
  729. tags: ['a', 'b', 'c'],
  730. data: { some: 'data' }
  731. };
  732. Hoek.consoleFunc = function (string) {
  733. Hoek.consoleFunc = console.log;
  734. expect(string).to.equal('130201/063045.123, a, {"some":"data"}');
  735. done();
  736. };
  737. Hoek.printEvent(event);
  738. });
  739. it('outputs JSON error', function (done) {
  740. var event = {
  741. timestamp: (new Date(2013, 1, 1, 6, 30, 45, 123)).getTime(),
  742. tags: ['a', 'b', 'c'],
  743. data: { some: 'data' }
  744. };
  745. event.data.a = event.data;
  746. Hoek.consoleFunc = function (string) {
  747. Hoek.consoleFunc = console.log;
  748. expect(string).to.equal('130201/063045.123, a, JSON Error: Converting circular structure to JSON');
  749. done();
  750. };
  751. Hoek.printEvent(event);
  752. });
  753. });
  754. describe('#nextTick', function () {
  755. it('calls the provided callback on nextTick', function (done) {
  756. var a = 0;
  757. var inc = function (step, next) {
  758. a += step;
  759. next();
  760. };
  761. var ticked = Hoek.nextTick(inc);
  762. ticked(5, function () {
  763. expect(a).to.equal(6);
  764. done();
  765. });
  766. expect(a).to.equal(0);
  767. inc(1, function () {
  768. expect(a).to.equal(1);
  769. });
  770. });
  771. });
  772. });