index.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. 'use strict';
  2. var legacyLog = require('../');
  3. var Log = legacyLog.Log;
  4. // Helper for testing stdout
  5. var hooker = require('hooker');
  6. function stdoutEqual(test, callback, expected) {
  7. var actual = '';
  8. // Hook process.stdout.write
  9. hooker.hook(process.stdout, 'write', {
  10. // This gets executed before the original process.stdout.write.
  11. pre: function(result) {
  12. // Concatenate uncolored result onto actual.
  13. actual += result;
  14. // Prevent the original process.stdout.write from executing.
  15. return hooker.preempt();
  16. },
  17. });
  18. // Execute the logging code to be tested.
  19. callback();
  20. // Restore process.stdout.write to its original value.
  21. stdoutUnmute();
  22. // Actually test the actually-logged stdout string to the expected value.
  23. // test.equal(legacyLog.uncolor(actual), expected);
  24. test.equal(actual, expected);
  25. }
  26. // Outright mute stdout.
  27. function stdoutMute() {
  28. hooker.hook(process.stdout, 'write', {
  29. pre: function() {
  30. return hooker.preempt();
  31. },
  32. });
  33. }
  34. // Unmute stdout.
  35. function stdoutUnmute() {
  36. hooker.unhook(process.stdout, 'write');
  37. }
  38. // Helper function: repeat('a', 3) -> 'aaa', repeat('a', 3, '-') -> 'a-a-a'
  39. function repeat(str, n, separator) {
  40. var result = str;
  41. for (var i = 1; i < n; i++) {
  42. result += (separator || '') + str;
  43. }
  44. return result;
  45. }
  46. var fooBuffer = new Buffer('foo');
  47. exports['Log instance'] = {
  48. setUp: function(done) {
  49. this.grunt = {fail: {errorcount: 0}};
  50. done();
  51. },
  52. 'write': function(test) {
  53. test.expect(4);
  54. var log = new Log();
  55. stdoutEqual(test, function() { log.write(''); }, '');
  56. stdoutEqual(test, function() { log.write('foo'); }, 'foo');
  57. stdoutEqual(test, function() { log.write('%s', 'foo'); }, 'foo');
  58. stdoutEqual(test, function() { log.write(fooBuffer); }, 'foo');
  59. test.done();
  60. },
  61. 'writeln': function(test) {
  62. test.expect(4);
  63. var log = new Log();
  64. stdoutEqual(test, function() { log.writeln(); }, '\n');
  65. stdoutEqual(test, function() { log.writeln('foo'); }, 'foo\n');
  66. stdoutEqual(test, function() { log.writeln('%s', 'foo'); }, 'foo\n');
  67. stdoutEqual(test, function() { log.writeln(fooBuffer); }, 'foo\n');
  68. test.done();
  69. },
  70. 'warn': function(test) {
  71. test.expect(5);
  72. var log = new Log({grunt: this.grunt});
  73. stdoutEqual(test, function() { log.warn(); }, 'ERROR'.red + '\n');
  74. stdoutEqual(test, function() { log.warn('foo'); }, '>> '.red + 'foo\n');
  75. stdoutEqual(test, function() { log.warn('%s', 'foo'); }, '>> '.red + 'foo\n');
  76. stdoutEqual(test, function() { log.warn(fooBuffer); }, '>> '.red + 'foo\n');
  77. test.equal(this.grunt.fail.errorcount, 0);
  78. test.done();
  79. },
  80. 'error': function(test) {
  81. test.expect(5);
  82. var log = new Log({grunt: this.grunt});
  83. stdoutEqual(test, function() { log.error(); }, 'ERROR'.red + '\n');
  84. stdoutEqual(test, function() { log.error('foo'); }, '>> '.red + 'foo\n');
  85. stdoutEqual(test, function() { log.error('%s', 'foo'); }, '>> '.red + 'foo\n');
  86. stdoutEqual(test, function() { log.error(fooBuffer); }, '>> '.red + 'foo\n');
  87. test.equal(this.grunt.fail.errorcount, 4);
  88. test.done();
  89. },
  90. 'ok': function(test) {
  91. test.expect(4);
  92. var log = new Log({grunt: this.grunt});
  93. stdoutEqual(test, function() { log.ok(); }, 'OK'.green + '\n');
  94. stdoutEqual(test, function() { log.ok('foo'); }, '>> '.green + 'foo\n');
  95. stdoutEqual(test, function() { log.ok('%s', 'foo'); }, '>> '.green + 'foo\n');
  96. stdoutEqual(test, function() { log.ok(fooBuffer); }, '>> '.green + 'foo\n');
  97. test.done();
  98. },
  99. 'errorlns': function(test) {
  100. test.expect(2);
  101. var log = new Log({grunt: this.grunt});
  102. stdoutEqual(test, function() {
  103. log.errorlns(repeat('foo', 30, ' '));
  104. }, '>> '.red + repeat('foo', 19, ' ') +
  105. '\n>> '.red + repeat('foo', 11, ' ') + '\n');
  106. test.equal(this.grunt.fail.errorcount, 1);
  107. test.done();
  108. },
  109. 'oklns': function(test) {
  110. test.expect(1);
  111. var log = new Log();
  112. stdoutEqual(test, function() {
  113. log.oklns(repeat('foo', 30, ' '));
  114. }, '>> '.green + repeat('foo', 19, ' ') +
  115. '\n>> '.green + repeat('foo', 11, ' ') + '\n');
  116. test.done();
  117. },
  118. 'success': function(test) {
  119. test.expect(4);
  120. var log = new Log();
  121. stdoutEqual(test, function() { log.success(); }, ''.green + '\n');
  122. stdoutEqual(test, function() { log.success('foo'); }, 'foo'.green + '\n');
  123. stdoutEqual(test, function() { log.success('%s', 'foo'); }, 'foo'.green + '\n');
  124. stdoutEqual(test, function() { log.success(fooBuffer); }, 'foo'.green + '\n');
  125. test.done();
  126. },
  127. 'fail': function(test) {
  128. test.expect(4);
  129. var log = new Log();
  130. stdoutEqual(test, function() { log.fail(); }, ''.red + '\n');
  131. stdoutEqual(test, function() { log.fail('foo'); }, 'foo'.red + '\n');
  132. stdoutEqual(test, function() { log.fail('%s', 'foo'); }, 'foo'.red + '\n');
  133. stdoutEqual(test, function() { log.fail(fooBuffer); }, 'foo'.red + '\n');
  134. test.done();
  135. },
  136. 'header': function(test) {
  137. test.expect(5);
  138. var log = new Log();
  139. stdoutEqual(test, function() { log.header(); }, ''.underline + '\n');
  140. stdoutEqual(test, function() { log.header(); }, '\n' + ''.underline + '\n');
  141. stdoutEqual(test, function() { log.header('foo'); }, '\n' + 'foo'.underline + '\n');
  142. stdoutEqual(test, function() { log.header('%s', 'foo'); }, '\n' + 'foo'.underline + '\n');
  143. stdoutEqual(test, function() { log.header(fooBuffer); }, '\n' + 'foo'.underline + '\n');
  144. test.done();
  145. },
  146. 'subhead': function(test) {
  147. test.expect(5);
  148. var log = new Log();
  149. stdoutEqual(test, function() { log.subhead(); }, ''.bold + '\n');
  150. stdoutEqual(test, function() { log.subhead(); }, '\n' + ''.bold + '\n');
  151. stdoutEqual(test, function() { log.subhead('foo'); }, '\n' + 'foo'.bold + '\n');
  152. stdoutEqual(test, function() { log.subhead('%s', 'foo'); }, '\n' + 'foo'.bold + '\n');
  153. stdoutEqual(test, function() { log.subhead(fooBuffer); }, '\n' + 'foo'.bold + '\n');
  154. test.done();
  155. },
  156. 'writetableln': function(test) {
  157. test.expect(1);
  158. var log = new Log();
  159. stdoutEqual(test, function() {
  160. log.writetableln([10], [repeat('foo', 10)]);
  161. }, 'foofoofoof\noofoofoofo\nofoofoofoo\n');
  162. test.done();
  163. },
  164. 'writelns': function(test) {
  165. test.expect(1);
  166. var log = new Log();
  167. stdoutEqual(test, function() {
  168. log.writelns(repeat('foo', 30, ' '));
  169. }, repeat('foo', 20, ' ') + '\n' +
  170. repeat('foo', 10, ' ') + '\n');
  171. test.done();
  172. },
  173. 'writeflags': function(test) {
  174. test.expect(3);
  175. var log = new Log();
  176. stdoutEqual(test, function() {
  177. log.writeflags(['a', 'b']);
  178. }, 'Flags: ' + 'a'.cyan + ', ' + 'b'.cyan + '\n');
  179. stdoutEqual(test, function() {
  180. log.writeflags(['a', 'b'], 'Prefix');
  181. }, 'Prefix: ' + 'a'.cyan + ', ' + 'b'.cyan + '\n');
  182. stdoutEqual(test, function() {
  183. log.writeflags({a: true, b: false, c: 0, d: null}, 'Prefix');
  184. }, 'Prefix: ' + 'a'.cyan + ', ' + 'b=false'.cyan + ', ' + 'c=0'.cyan + ', ' + 'd=null'.cyan + '\n');
  185. test.done();
  186. },
  187. 'always': function(test) {
  188. test.expect(3);
  189. var log = new Log();
  190. test.strictEqual(log.always, log);
  191. test.strictEqual(log.verbose.always, log);
  192. test.strictEqual(log.notverbose.always, log);
  193. test.done();
  194. },
  195. 'or': function(test) {
  196. test.expect(2);
  197. var log = new Log();
  198. test.strictEqual(log.verbose.or, log.notverbose);
  199. test.strictEqual(log.notverbose.or, log.verbose);
  200. test.done();
  201. },
  202. 'hasLogged': function(test) {
  203. // Should only be true if output has been written!
  204. test.expect(24);
  205. var log = new Log();
  206. test.equal(log.hasLogged, false);
  207. test.equal(log.verbose.hasLogged, false);
  208. test.equal(log.notverbose.hasLogged, false);
  209. log.write('');
  210. test.equal(log.hasLogged, true);
  211. test.equal(log.verbose.hasLogged, true);
  212. test.equal(log.notverbose.hasLogged, true);
  213. log = new Log({verbose: true});
  214. log.verbose.write('');
  215. test.equal(log.hasLogged, true);
  216. test.equal(log.verbose.hasLogged, true);
  217. test.equal(log.notverbose.hasLogged, true);
  218. log = new Log();
  219. log.notverbose.write('');
  220. test.equal(log.hasLogged, true);
  221. test.equal(log.verbose.hasLogged, true);
  222. test.equal(log.notverbose.hasLogged, true);
  223. stdoutMute();
  224. log = new Log({debug: true});
  225. log.debug('');
  226. test.equal(log.hasLogged, true);
  227. test.equal(log.verbose.hasLogged, true);
  228. test.equal(log.notverbose.hasLogged, true);
  229. stdoutUnmute();
  230. // The following should be false since there's a verbose mismatch!
  231. log = new Log();
  232. log.verbose.write('');
  233. test.equal(log.hasLogged, false);
  234. test.equal(log.verbose.hasLogged, false);
  235. test.equal(log.notverbose.hasLogged, false);
  236. log = new Log({verbose: true});
  237. log.notverbose.write('');
  238. test.equal(log.hasLogged, false);
  239. test.equal(log.verbose.hasLogged, false);
  240. test.equal(log.notverbose.hasLogged, false);
  241. // The following should be false since there's a debug mismatch!
  242. log = new Log();
  243. log.debug('');
  244. test.equal(log.hasLogged, false);
  245. test.equal(log.verbose.hasLogged, false);
  246. test.equal(log.notverbose.hasLogged, false);
  247. test.done();
  248. },
  249. 'muted': function(test) {
  250. test.expect(30);
  251. var log = new Log();
  252. test.equal(log.muted, false);
  253. test.equal(log.verbose.muted, false);
  254. test.equal(log.notverbose.muted, false);
  255. test.equal(log.options.muted, false);
  256. test.equal(log.verbose.options.muted, false);
  257. test.equal(log.notverbose.options.muted, false);
  258. log.muted = true;
  259. test.equal(log.muted, true);
  260. test.equal(log.verbose.muted, true);
  261. test.equal(log.notverbose.muted, true);
  262. test.equal(log.options.muted, true);
  263. test.equal(log.verbose.options.muted, true);
  264. test.equal(log.notverbose.options.muted, true);
  265. log.muted = false;
  266. test.equal(log.muted, false);
  267. test.equal(log.verbose.muted, false);
  268. test.equal(log.notverbose.muted, false);
  269. test.equal(log.options.muted, false);
  270. test.equal(log.verbose.options.muted, false);
  271. test.equal(log.notverbose.options.muted, false);
  272. log.options.muted = true;
  273. test.equal(log.muted, true);
  274. test.equal(log.verbose.muted, true);
  275. test.equal(log.notverbose.muted, true);
  276. test.equal(log.options.muted, true);
  277. test.equal(log.verbose.options.muted, true);
  278. test.equal(log.notverbose.options.muted, true);
  279. log.options.muted = false;
  280. test.equal(log.muted, false);
  281. test.equal(log.verbose.muted, false);
  282. test.equal(log.notverbose.muted, false);
  283. test.equal(log.options.muted, false);
  284. test.equal(log.verbose.options.muted, false);
  285. test.equal(log.notverbose.options.muted, false);
  286. test.done();
  287. },
  288. 'verbose': function(test) {
  289. test.expect(15);
  290. var log = new Log();
  291. log.muted = true;
  292. // Test verbose methods to make sure they always return the verbose object.
  293. test.strictEqual(log.verbose.write(''), log.verbose);
  294. test.strictEqual(log.verbose.writeln(''), log.verbose);
  295. test.strictEqual(log.verbose.warn(''), log.verbose);
  296. test.strictEqual(log.verbose.error(''), log.verbose);
  297. test.strictEqual(log.verbose.ok(''), log.verbose);
  298. test.strictEqual(log.verbose.errorlns(''), log.verbose);
  299. test.strictEqual(log.verbose.oklns(''), log.verbose);
  300. test.strictEqual(log.verbose.success(''), log.verbose);
  301. test.strictEqual(log.verbose.fail(''), log.verbose);
  302. test.strictEqual(log.verbose.header(''), log.verbose);
  303. test.strictEqual(log.verbose.subhead(''), log.verbose);
  304. test.strictEqual(log.verbose.debug(''), log.verbose);
  305. test.strictEqual(log.verbose.writetableln([]), log.verbose);
  306. test.strictEqual(log.verbose.writelns(''), log.verbose);
  307. test.strictEqual(log.verbose.writeflags([]), log.verbose);
  308. test.done();
  309. },
  310. 'notverbose': function(test) {
  311. test.expect(15);
  312. var log = new Log();
  313. log.muted = true;
  314. // Test notverbose methods to make sure they always return the notverbose object.
  315. test.strictEqual(log.notverbose.write(''), log.notverbose);
  316. test.strictEqual(log.notverbose.writeln(''), log.notverbose);
  317. test.strictEqual(log.notverbose.warn(''), log.notverbose);
  318. test.strictEqual(log.notverbose.error(''), log.notverbose);
  319. test.strictEqual(log.notverbose.ok(''), log.notverbose);
  320. test.strictEqual(log.notverbose.errorlns(''), log.notverbose);
  321. test.strictEqual(log.notverbose.oklns(''), log.notverbose);
  322. test.strictEqual(log.notverbose.success(''), log.notverbose);
  323. test.strictEqual(log.notverbose.fail(''), log.notverbose);
  324. test.strictEqual(log.notverbose.header(''), log.notverbose);
  325. test.strictEqual(log.notverbose.subhead(''), log.notverbose);
  326. test.strictEqual(log.notverbose.debug(''), log.notverbose);
  327. test.strictEqual(log.notverbose.writetableln([]), log.notverbose);
  328. test.strictEqual(log.notverbose.writelns(''), log.notverbose);
  329. test.strictEqual(log.notverbose.writeflags([]), log.notverbose);
  330. test.done();
  331. },
  332. 'options.debug = true': function(test) {
  333. test.expect(4);
  334. var log = new Log({debug: true});
  335. stdoutEqual(test, function() { log.debug(); }, '[D] ' + ''.magenta + '\n');
  336. stdoutEqual(test, function() { log.debug('foo'); }, '[D] ' + 'foo'.magenta + '\n');
  337. stdoutEqual(test, function() { log.debug('%s', 'foo'); }, '[D] ' + 'foo'.magenta + '\n');
  338. stdoutEqual(test, function() { log.debug(fooBuffer); }, '[D] ' + 'foo'.magenta + '\n');
  339. test.done();
  340. },
  341. 'options.verbose = false': function(test) {
  342. test.expect(7);
  343. var log = new Log({verbose: false});
  344. stdoutEqual(test, function() { log.notverbose.write('foo'); }, 'foo');
  345. stdoutEqual(test, function() { log.notverbose.write('%s', 'foo'); }, 'foo');
  346. stdoutEqual(test, function() { log.notverbose.write(fooBuffer); }, 'foo');
  347. stdoutEqual(test, function() { log.verbose.write('foo'); }, '');
  348. stdoutEqual(test, function() { log.verbose.write('%s', 'foo'); }, '');
  349. stdoutEqual(test, function() { log.verbose.write(fooBuffer); }, '');
  350. stdoutEqual(test, function() { log.verbose.write('a').or.write('b'); }, 'b');
  351. test.done();
  352. },
  353. 'options.verbose = true': function(test) {
  354. test.expect(7);
  355. var log = new Log({verbose: true});
  356. stdoutEqual(test, function() { log.verbose.write('foo'); }, 'foo');
  357. stdoutEqual(test, function() { log.verbose.write('%s', 'foo'); }, 'foo');
  358. stdoutEqual(test, function() { log.verbose.write(fooBuffer); }, 'foo');
  359. stdoutEqual(test, function() { log.notverbose.write('foo'); }, '');
  360. stdoutEqual(test, function() { log.notverbose.write('%s', 'foo'); }, '');
  361. stdoutEqual(test, function() { log.notverbose.write(fooBuffer); }, '');
  362. stdoutEqual(test, function() { log.notverbose.write('a').or.write('b'); }, 'b');
  363. test.done();
  364. },
  365. 'options.debug = false': function(test) {
  366. test.expect(1);
  367. var log = new Log({debug: false});
  368. stdoutEqual(test, function() { log.debug('foo'); }, '');
  369. test.done();
  370. },
  371. 'options.color = true': function(test) {
  372. test.expect(1);
  373. var log = new Log({color: true});
  374. stdoutEqual(test, function() { log.write('foo'.blue + 'bar'.underline); }, 'foo'.blue + 'bar'.underline);
  375. test.done();
  376. },
  377. 'options.color = false': function(test) {
  378. test.expect(1);
  379. var log = new Log({color: false});
  380. stdoutEqual(test, function() { log.write('foo'.blue + 'bar'.underline); }, 'foobar');
  381. test.done();
  382. },
  383. 'perma-bind this when passing grunt in (backcompat)': function(test) {
  384. test.expect(43);
  385. var log = new Log({grunt: this.grunt});
  386. stdoutMute();
  387. [
  388. 'write',
  389. 'writeln',
  390. 'warn',
  391. 'error',
  392. 'ok',
  393. 'errorlns',
  394. 'oklns',
  395. 'success',
  396. 'fail',
  397. 'header',
  398. 'subhead',
  399. 'debug',
  400. ].forEach(function(method) {
  401. var fn = log[method];
  402. var verboseFn = log.verbose[method];
  403. var notVerboseFn = log.notverbose[method];
  404. test.equal(fn(), log, 'Should return log if invoked in a way where this is not log.');
  405. test.equal(verboseFn(), log.verbose, 'Should return log.verbose if invoked in a way where this is not log.');
  406. test.equal(notVerboseFn(), log.notverbose, 'Should return log.notverbose if invoked in a way where this is not log.');
  407. });
  408. test.doesNotThrow(function() { var fn = log.writetableln; fn([]); }, 'Should not throw if invoked in a way where this is not log.');
  409. test.doesNotThrow(function() { var fn = log.writelns; fn([]); }, 'Should not throw if invoked in a way where this is not log.');
  410. test.doesNotThrow(function() { var fn = log.writeflags; fn([]); }, 'Should not throw if invoked in a way where this is not log.');
  411. test.doesNotThrow(function() { var fn = log.wordlist; fn([]); }, 'Should not throw if invoked in a way where this is not log.');
  412. test.doesNotThrow(function() { var fn = log.uncolor; fn(''); }, 'Should not throw if invoked in a way where this is not log.');
  413. test.doesNotThrow(function() { var fn = log.wraptext; fn(1,''); }, 'Should not throw if invoked in a way where this is not log.');
  414. test.doesNotThrow(function() { var fn = log.table; fn([],''); }, 'Should not throw if invoked in a way where this is not log.');
  415. stdoutUnmute();
  416. test.done();
  417. },
  418. };
  419. exports['Helpers'] = {
  420. 'uncolor': function(test) {
  421. test.expect(2);
  422. var log = new Log();
  423. test.ok(log.uncolor);
  424. test.strictEqual(log.uncolor, legacyLog.uncolor);
  425. test.done();
  426. },
  427. 'wordlist': function(test) {
  428. test.expect(2);
  429. var log = new Log();
  430. test.ok(log.wordlist);
  431. test.strictEqual(log.wordlist, legacyLog.wordlist);
  432. test.done();
  433. },
  434. 'wraptext': function(test) {
  435. test.expect(2);
  436. var log = new Log();
  437. test.ok(log.wraptext);
  438. test.strictEqual(log.wraptext, legacyLog.wraptext);
  439. test.done();
  440. },
  441. 'table': function(test) {
  442. test.expect(2);
  443. var log = new Log();
  444. test.ok(log.table);
  445. test.strictEqual(log.table, legacyLog.table);
  446. test.done();
  447. },
  448. };