You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

464 lines
19 KiB

  1. 'use strict';
  2. // Test helpers.
  3. function delay(fn) { setTimeout(fn, 10); }
  4. var result = (function() {
  5. var arr;
  6. var push = function() { [].push.apply(arr, arguments); };
  7. return {
  8. reset: function() { arr = []; },
  9. push: push,
  10. pushTaskname: function() { push(this.name); },
  11. get: function() { return arr; },
  12. getJoined: function() { return arr.join(''); }
  13. };
  14. }());
  15. var requireTask = require.bind(exports, '../../lib/util/task.js');
  16. exports['new Task'] = {
  17. 'create': function(test) {
  18. test.expect(1);
  19. var tasklib = requireTask();
  20. test.ok(tasklib.create() instanceof tasklib.Task, 'It should return a Task instance.');
  21. test.done();
  22. }
  23. };
  24. exports['Tasks'] = {
  25. setUp: function(done) {
  26. result.reset();
  27. this.task = requireTask().create();
  28. var task = this.task;
  29. task.registerTask('nothing', 'Do nothing.', function() {});
  30. done();
  31. },
  32. 'Task#registerTask': function(test) {
  33. test.expect(1);
  34. var task = this.task;
  35. test.ok('nothing' in task._tasks, 'It should register the passed task.');
  36. test.done();
  37. },
  38. 'Task#registerTask (alias)': function(test) {
  39. test.expect(1);
  40. var task = this.task;
  41. task.registerTask('a', 'Push task name onto result.', result.pushTaskname);
  42. task.registerTask('b', 'Push task name onto result.', result.pushTaskname);
  43. task.registerTask('c d', 'Push task name onto result.', result.pushTaskname);
  44. task.registerTask('y', ['a', 'b', 'c d']);
  45. task.registerTask('z', ['a', 'b', 'nonexistent', 'c d']);
  46. task.options({
  47. error: function() {
  48. result.push('!' + this.name);
  49. },
  50. done: function() {
  51. test.strictEqual(result.getJoined(), 'abc d!z', 'The specified tasks should have run, in-order.');
  52. test.done();
  53. }
  54. });
  55. task.run('y', 'z').start();
  56. },
  57. 'Task#isTaskAlias': function(test) {
  58. test.expect(2);
  59. var task = this.task;
  60. task.registerTask('a', 'nothing', function() {});
  61. task.registerTask('b', ['a']);
  62. test.strictEqual(task.isTaskAlias('a'), false, 'It should not be an alias.');
  63. test.strictEqual(task.isTaskAlias('b'), true, 'It should be an alias.');
  64. test.done();
  65. },
  66. 'Task#renameTask': function(test) {
  67. test.expect(4);
  68. var task = this.task;
  69. task.renameTask('nothing', 'newnothing');
  70. test.ok('newnothing' in task._tasks, 'It should rename the specified task.');
  71. test.equal('nothing' in task._tasks, false, 'It should remove the previous task.');
  72. test.doesNotThrow(function() { task.run('newnothing'); }, 'It should be accessible by its new name.');
  73. test.throws(function() { task.run('nothing'); }, 'It should not be accessible by its previous name and throw an exception.');
  74. test.done();
  75. },
  76. 'Task#run (exception handling)': function(test) {
  77. test.expect(4);
  78. var task = this.task;
  79. test.doesNotThrow(function() { task.run('nothing'); }, 'Registered tasks should be runnable.');
  80. test.throws(function() { task.run('nonexistent'); }, 'Attempting to run unregistered tasks should throw an exception.');
  81. task.options({
  82. error: result.pushTaskname
  83. });
  84. test.doesNotThrow(function() { task.run('nonexistent'); }, 'It should not throw an exception because an error handler is defined.');
  85. test.deepEqual(result.get(), [null], 'Non-nested tasks have a null name.');
  86. test.done();
  87. },
  88. 'Task#run (async failing)': function(test) {
  89. test.expect(1);
  90. var task = this.task;
  91. var results = [];
  92. task.registerTask('sync1', 'sync, gonna succeed', function() {});
  93. task.registerTask('sync2', 'sync, gonna fail', function() {
  94. return false;
  95. });
  96. task.registerTask('sync3', 'sync, gonna fail', function() {
  97. return new Error('sync3: Error');
  98. });
  99. task.registerTask('sync4', 'sync, gonna fail', function() {
  100. return new TypeError('sync4: TypeError');
  101. });
  102. task.registerTask('sync5', 'sync, gonna fail', function() {
  103. throw new Error('sync5: Error');
  104. });
  105. task.registerTask('sync6', 'sync, gonna fail', function() {
  106. throw new TypeError('sync6: TypeError');
  107. });
  108. task.registerTask('syncs', ['sync1', 'sync2', 'sync3', 'sync4', 'sync5', 'sync6']);
  109. task.registerTask('async1', 'async, gonna succeed', function() {
  110. var done = this.async();
  111. setTimeout(function() {
  112. done();
  113. }, 1);
  114. });
  115. task.registerTask('async2', 'async, gonna fail', function() {
  116. var done = this.async();
  117. setTimeout(function() {
  118. done(false);
  119. }, 1);
  120. });
  121. task.registerTask('async3', 'async, gonna fail', function() {
  122. var done = this.async();
  123. setTimeout(function() {
  124. done(new Error('async3: Error'));
  125. }, 1);
  126. });
  127. task.registerTask('async4', 'async, gonna fail', function() {
  128. var done = this.async();
  129. setTimeout(function() {
  130. done(new TypeError('async4: TypeError'));
  131. }, 1);
  132. });
  133. task.registerTask('asyncs', ['async1', 'async2', 'async3', 'async4']);
  134. task.options({
  135. error: function(e) {
  136. results.push({name: e.name, message: e.message});
  137. },
  138. done: function() {
  139. test.deepEqual(results, [
  140. {name: 'Error', message: 'Task "sync2" failed.'},
  141. {name: 'Error', message: 'sync3: Error'},
  142. {name: 'TypeError', message: 'sync4: TypeError'},
  143. {name: 'Error', message: 'sync5: Error'},
  144. {name: 'TypeError', message: 'sync6: TypeError'},
  145. {name: 'Error', message: 'Task "async2" failed.'},
  146. {name: 'Error', message: 'async3: Error'},
  147. {name: 'TypeError', message: 'async4: TypeError'}
  148. ], 'The specified tasks should have run, in-order.');
  149. test.done();
  150. }
  151. });
  152. task.run('syncs', 'asyncs').start();
  153. },
  154. 'Task#run (nested, exception handling)': function(test) {
  155. test.expect(2);
  156. var task = this.task;
  157. task.registerTask('yay', 'Run a registered task.', function() {
  158. test.doesNotThrow(function() { task.run('nothing'); }, 'Registered tasks should be runnable.');
  159. });
  160. task.registerTask('nay', 'Attempt to run an unregistered task.', function() {
  161. test.throws(function() { task.run('nonexistent'); }, 'Attempting to run unregistered tasks should throw an exception.');
  162. });
  163. task.options({
  164. done: test.done
  165. });
  166. task.run('yay', 'nay').start();
  167. },
  168. 'Task#run (signatures, queue order)': function(test) {
  169. test.expect(1);
  170. var task = this.task;
  171. task.registerTask('a', 'Push task name onto result.', result.pushTaskname);
  172. task.registerTask('b', 'Push task name onto result.', result.pushTaskname);
  173. task.registerTask('c', 'Push task name onto result.', result.pushTaskname);
  174. task.registerTask('d', 'Push task name onto result.', result.pushTaskname);
  175. task.registerTask('e', 'Push task name onto result.', result.pushTaskname);
  176. task.registerTask('f g', 'Push task name onto result.', result.pushTaskname);
  177. task.options({
  178. done: function() {
  179. test.strictEqual(result.getJoined(), 'abcdef g', 'The specified tasks should have run, in-order.');
  180. test.done();
  181. }
  182. });
  183. task.run('a').run('b', 'c').run(['d', 'e']).run('f g').start();
  184. },
  185. 'Task#run (colon separated arguments)': function(test) {
  186. test.expect(1);
  187. var task = this.task;
  188. task.registerTask('a', 'Push task name and args onto result.', function(x, y) { result.push([this.nameArgs, 1, this.name, x, y]); });
  189. task.registerTask('a:b', 'Push task name and args onto result.', function(x, y) { result.push([this.nameArgs, 2, this.name, x, y]); });
  190. task.registerTask('a:b:c', 'Push task name and args onto result.', function(x, y) { result.push([this.nameArgs, 3, this.name, x, y]); });
  191. task.options({
  192. done: function() {
  193. test.deepEqual(result.get(), [
  194. ['a', 1, 'a', undefined, undefined],
  195. ['a:x', 1, 'a', 'x', undefined],
  196. ['a:x:c', 1, 'a', 'x', 'c'],
  197. ['a:b ', 1, 'a', 'b ', undefined],
  198. ['a: b:c', 1, 'a', ' b', 'c'],
  199. ['a:x\\:y:\\:z\\:', 1, 'a', 'x:y', ':z:'],
  200. ['a:b', 2, 'a:b', undefined, undefined],
  201. ['a:b:x', 2, 'a:b', 'x', undefined],
  202. ['a:b:x:y', 2, 'a:b', 'x', 'y'],
  203. ['a:b:c ', 2, 'a:b', 'c ', undefined],
  204. ['a:b:x\\:y:\\:z\\:', 2, 'a:b', 'x:y', ':z:'],
  205. ['a:b:c', 3, 'a:b:c', undefined, undefined],
  206. ['a:b:c: d', 3, 'a:b:c', ' d', undefined],
  207. ], 'Named tasks should be called as-specified if possible, and arguments should be passed properly.');
  208. test.done();
  209. }
  210. });
  211. task.run(
  212. 'a', 'a:x', 'a:x:c', 'a:b ', 'a: b:c', 'a:x\\:y:\\:z\\:',
  213. 'a:b', 'a:b:x', 'a:b:x:y', 'a:b:c ', 'a:b:x\\:y:\\:z\\:',
  214. 'a:b:c', 'a:b:c: d'
  215. ).start();
  216. },
  217. 'Task#run (nested tasks, queue order)': function(test) {
  218. test.expect(1);
  219. var task = this.task;
  220. task.registerTask('a', 'Push task name onto result and run other tasks.', function() { result.push(this.name); task.run('b', 'e'); });
  221. task.registerTask('b', 'Push task name onto result and run other tasks.', function() { result.push(this.name); task.run('c', 'd d'); });
  222. task.registerTask('c', 'Push task name onto result.', result.pushTaskname);
  223. task.registerTask('d d', 'Push task name onto result.', result.pushTaskname);
  224. task.registerTask('e', 'Push task name onto result and run other tasks.', function() { result.push(this.name); task.run('f f'); });
  225. task.registerTask('f f', 'Push task name onto result.', result.pushTaskname);
  226. task.registerTask('g', 'Push task name onto result.', result.pushTaskname);
  227. task.options({
  228. done: function() {
  229. test.strictEqual(result.getJoined(), 'abcd def fg', 'The specified tasks should have run, in-order.');
  230. test.done();
  231. }
  232. });
  233. task.run('a', 'g').start();
  234. },
  235. 'Task#run (async, nested tasks, queue order)': function(test) {
  236. test.expect(1);
  237. var task = this.task;
  238. task.registerTask('a', 'Push task name onto result and run other tasks.', function() { result.push(this.name); task.run('b', 'e'); delay(this.async()); });
  239. task.registerTask('b', 'Push task name onto result and run other tasks.', function() { result.push(this.name); delay(this.async()); task.run('c', 'd d'); });
  240. task.registerTask('c', 'Push task name onto result.', result.pushTaskname);
  241. task.registerTask('d d', 'Push task name onto result.', result.pushTaskname);
  242. task.registerTask('e', 'Push task name onto result and run other tasks.', function() { delay(this.async()); result.push(this.name); task.run('f f'); });
  243. task.registerTask('f f', 'Push task name onto result and run other tasks.', function() { this.async()(); result.push(this.name); task.run('g'); });
  244. task.registerTask('g', 'Push task name onto result.', result.pushTaskname);
  245. task.registerTask('h', 'Push task name onto result.', result.pushTaskname);
  246. task.options({
  247. done: function() {
  248. test.strictEqual(result.getJoined(), 'abcd def fgh', 'The specified tasks should have run, in-order.');
  249. test.done();
  250. }
  251. });
  252. task.run('a', 'h').start();
  253. },
  254. 'Task#current': function(test) {
  255. test.expect(8);
  256. var task = this.task;
  257. test.deepEqual(task.current, {}, 'Should start empty.');
  258. task.registerTask('a', 'Sample task.', function() {
  259. test.equal(task.current, this, 'This and task.current should be the same object.');
  260. test.equal(task.current.nameArgs, 'a:b:c', 'Should be task name + args, as-specified.');
  261. test.equal(task.current.name, 'a', 'Should be just the task name, no args.');
  262. test.equal(typeof task.current.async, 'function', 'Should be a function.');
  263. test.deepEqual(task.current.args, ['b', 'c'], 'Should be an array of args.');
  264. test.deepEqual(task.current.flags, {b: true, c: true}, 'Should be a map of flags.');
  265. });
  266. task.options({
  267. done: function() {
  268. test.deepEqual(task.current, {}, 'Should be empty again once tasks are done.');
  269. test.done();
  270. }
  271. });
  272. task.run('a:b:c').start();
  273. },
  274. 'Task#clearQueue': function(test) {
  275. test.expect(1);
  276. var task = this.task;
  277. task.registerTask('a', 'Push task name onto result.', result.pushTaskname);
  278. task.registerTask('b', 'Push task name onto result.', result.pushTaskname);
  279. task.registerTask('c', 'Clear the queue.', function() {
  280. result.push(this.name);
  281. task.clearQueue().run('f');
  282. });
  283. task.registerTask('d', 'Push task name onto result.', result.pushTaskname);
  284. task.registerTask('e', 'Push task name onto result.', result.pushTaskname);
  285. task.registerTask('f', 'Push task name onto result.', result.pushTaskname);
  286. task.options({
  287. done: function() {
  288. test.strictEqual(result.getJoined(), 'abcf', 'The specified tasks should have run, in-order.');
  289. test.done();
  290. }
  291. });
  292. task.run('a', 'b', 'c', 'd', 'e').start();
  293. },
  294. 'Task#mark': function(test) {
  295. test.expect(1);
  296. var task = this.task;
  297. task.registerTask('a', 'Explode.', function() {
  298. throw task.taskError('whoops.');
  299. });
  300. task.registerTask('b', 'This task should never run.', result.pushTaskname);
  301. task.registerTask('c', 'This task should never run.', result.pushTaskname);
  302. task.registerTask('d', 'Push task name onto result.', result.pushTaskname);
  303. task.registerTask('e', 'Explode.', function() {
  304. throw task.taskError('whoops.');
  305. });
  306. task.registerTask('f', 'This task should never run.', result.pushTaskname);
  307. task.registerTask('g', 'Push task name onto result.', result.pushTaskname);
  308. task.registerTask('h', 'Push task name onto result.', result.pushTaskname);
  309. task.registerTask('i', 'Explode.', function() {
  310. throw task.taskError('whoops.');
  311. });
  312. task.registerTask('j', 'Run a task and push task name onto result.', function() {
  313. task.run('k');
  314. result.push(this.name);
  315. });
  316. task.registerTask('k', 'Explode.', function() {
  317. throw task.taskError('whoops.');
  318. });
  319. task.registerTask('l', 'This task should never run.', result.pushTaskname);
  320. task.registerTask('m', 'Push task name onto result.', result.pushTaskname);
  321. task.registerTask('n', 'Run a task and push task name onto result.', function() {
  322. task.run('o');
  323. result.push(this.name);
  324. });
  325. task.registerTask('o', 'Explode.', function() {
  326. throw task.taskError('whoops.');
  327. });
  328. task.registerTask('p', 'Push task name onto result.', result.pushTaskname);
  329. task.options({
  330. error: function() {
  331. result.push('!' + this.name);
  332. task.clearQueue({untilMarker: true});
  333. },
  334. done: function() {
  335. test.strictEqual(result.getJoined(), '!ad!egh!ij!kmn!op', 'The specified tasks should have run, in-order.');
  336. test.done();
  337. }
  338. });
  339. task.run('a', 'b', 'c').mark().run('d', 'e', 'f').mark().run('g', 'h', 'i').mark().run('j', 'l').mark().run('m', 'n').mark().run('p').mark().start();
  340. },
  341. 'Task#requires': function(test) {
  342. test.expect(1);
  343. var task = this.task;
  344. task.registerTask('notrun', 'This task is never run.', function() {});
  345. task.registerTask('a a', 'Push task name onto result, but fail.', function() {
  346. result.push(this.name);
  347. return false;
  348. });
  349. task.registerTask('b', 'Push task name onto result, but fail.', function() {
  350. var done = this.async();
  351. delay(function() { done(false); });
  352. result.push(this.name);
  353. });
  354. task.registerTask('c', 'Succeed.', result.pushTaskname);
  355. task.registerTask('d', 'Succeed.', result.pushTaskname);
  356. task.registerTask('e', 'Succeed because all required tasks ran and succeeded.', function() {
  357. task.requires('c', 'd');
  358. result.push(this.name);
  359. });
  360. task.registerTask('x', 'Fail because a required task never ran.', function() {
  361. task.requires('c', 'notrun', 'd');
  362. result.push(this.name);
  363. });
  364. task.registerTask('y', 'Fail because a synchronous required task has failed.', function() {
  365. task.requires('a a', 'c', 'd');
  366. result.push(this.name);
  367. });
  368. task.registerTask('z', 'Fail because an asynchronous required task has failed.', function() {
  369. task.requires('b', 'c', 'd');
  370. result.push(this.name);
  371. });
  372. task.options({
  373. error: function() {
  374. result.push('!' + this.name);
  375. },
  376. done: function() {
  377. test.strictEqual(result.getJoined(), 'a a!a ab!bcde!x!y!z', 'Tasks whose requirements have failed or are missing should not run.');
  378. test.done();
  379. }
  380. });
  381. task.run('a a', 'b', 'c', 'd', 'e', 'x', 'y', 'z').start();
  382. }
  383. };
  384. exports['Task#parseArgs'] = {
  385. setUp: function(done) {
  386. var task = requireTask().create();
  387. this.parseTest = function() {
  388. return task.parseArgs(arguments);
  389. };
  390. done();
  391. },
  392. 'arguments': function(test) {
  393. test.expect(4);
  394. test.deepEqual(this.parseTest('foo bar'), ['foo bar'], 'single argument should be converted to array.');
  395. test.deepEqual(this.parseTest('foo bar: aa : bb '), ['foo bar: aa : bb '], 'single argument should be converted to array.');
  396. test.deepEqual(this.parseTest('foo bar', 'baz', 'test 1 2 3'), ['foo bar', 'baz', 'test 1 2 3'], 'arguments should be converted to array.');
  397. test.deepEqual(this.parseTest('foo bar', 'baz:x y z', 'test 1 2 3: 4 : 5'), ['foo bar', 'baz:x y z', 'test 1 2 3: 4 : 5'], 'arguments should be converted to array.');
  398. test.done();
  399. },
  400. 'array': function(test) {
  401. test.expect(1);
  402. test.deepEqual(this.parseTest(['foo bar', 'baz:x y z', 'test 1 2 3: 4 : 5']), ['foo bar', 'baz:x y z', 'test 1 2 3: 4 : 5'], 'passed array should be used.');
  403. test.done();
  404. },
  405. 'object': function(test) {
  406. test.expect(1);
  407. var obj = {};
  408. test.deepEqual(this.parseTest(obj), [obj], 'single object should be returned as array.');
  409. test.done();
  410. },
  411. 'nothing': function(test) {
  412. test.expect(1);
  413. test.deepEqual(this.parseTest(), [], 'should return an empty array if nothing passed.');
  414. test.done();
  415. }
  416. };
  417. exports['Task#splitArgs'] = {
  418. setUp: function(done) {
  419. this.task = requireTask().create();
  420. done();
  421. },
  422. 'arguments': function(test) {
  423. test.expect(9);
  424. var task = this.task;
  425. test.deepEqual(task.splitArgs(), [], 'missing items = empty array.');
  426. test.deepEqual(task.splitArgs(''), [], 'missing items = empty array.');
  427. test.deepEqual(task.splitArgs('a'), ['a'], 'single item should be parsed.');
  428. test.deepEqual(task.splitArgs('a:b:c'), ['a', 'b', 'c'], 'mutliple items should be parsed.');
  429. test.deepEqual(task.splitArgs('a::c'), ['a', '', 'c'], 'missing items should be parsed.');
  430. test.deepEqual(task.splitArgs('::'), ['', '', ''], 'missing items should be parsed.');
  431. test.deepEqual(task.splitArgs('\\:a:\\:b\\::c\\:'), [':a', ':b:', 'c:'], 'escaped colons should be unescaped.');
  432. test.deepEqual(task.splitArgs('a\\\\:b\\\\:c'), ['a\\', 'b\\', 'c'], 'escaped backslashes should not be parsed.');
  433. test.deepEqual(task.splitArgs('\\:a\\\\:\\\\\\:b\\:\\\\:c\\\\\\:\\\\'), [':a\\', '\\:b:\\', 'c\\:\\'], 'please avoid doing this, ok?');
  434. test.done();
  435. }
  436. };