Repositorio del curso CCOM4030 el semestre B91 del proyecto Artesanías con el Instituto de Cultura

test.js 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. var deepEqual = require('deep-equal');
  2. var defined = require('defined');
  3. var path = require('path');
  4. var inherits = require('inherits');
  5. var EventEmitter = require('events').EventEmitter;
  6. var has = require('has');
  7. var trim = require('string.prototype.trim');
  8. var bind = require('function-bind');
  9. var forEach = require('for-each');
  10. var isEnumerable = bind.call(Function.call, Object.prototype.propertyIsEnumerable);
  11. var toLowerCase = bind.call(Function.call, String.prototype.toLowerCase);
  12. module.exports = Test;
  13. var nextTick = typeof setImmediate !== 'undefined'
  14. ? setImmediate
  15. : process.nextTick;
  16. var safeSetTimeout = setTimeout;
  17. var safeClearTimeout = clearTimeout;
  18. inherits(Test, EventEmitter);
  19. var getTestArgs = function (name_, opts_, cb_) {
  20. var name = '(anonymous)';
  21. var opts = {};
  22. var cb;
  23. for (var i = 0; i < arguments.length; i++) {
  24. var arg = arguments[i];
  25. var t = typeof arg;
  26. if (t === 'string') {
  27. name = arg;
  28. } else if (t === 'object') {
  29. opts = arg || opts;
  30. } else if (t === 'function') {
  31. cb = arg;
  32. }
  33. }
  34. return { name: name, opts: opts, cb: cb };
  35. };
  36. function Test(name_, opts_, cb_) {
  37. if (! (this instanceof Test)) {
  38. return new Test(name_, opts_, cb_);
  39. }
  40. var args = getTestArgs(name_, opts_, cb_);
  41. this.readable = true;
  42. this.name = args.name || '(anonymous)';
  43. this.assertCount = 0;
  44. this.pendingCount = 0;
  45. this._skip = args.opts.skip || false;
  46. this._todo = args.opts.todo || false;
  47. this._timeout = args.opts.timeout;
  48. this._plan = undefined;
  49. this._cb = args.cb;
  50. this._progeny = [];
  51. this._ok = true;
  52. var depthEnvVar = process.env.NODE_TAPE_OBJECT_PRINT_DEPTH;
  53. if (args.opts.objectPrintDepth) {
  54. this._objectPrintDepth = args.opts.objectPrintDepth;
  55. } else if (depthEnvVar) {
  56. if (toLowerCase(depthEnvVar) === 'infinity') {
  57. this._objectPrintDepth = Infinity;
  58. } else {
  59. this._objectPrintDepth = depthEnvVar;
  60. }
  61. } else {
  62. this._objectPrintDepth = 5;
  63. }
  64. for (var prop in this) {
  65. this[prop] = (function bind(self, val) {
  66. if (typeof val === 'function') {
  67. return function bound() {
  68. return val.apply(self, arguments);
  69. };
  70. }
  71. return val;
  72. })(this, this[prop]);
  73. }
  74. }
  75. Test.prototype.run = function () {
  76. this.emit('prerun');
  77. if (!this._cb || this._skip) {
  78. return this._end();
  79. }
  80. if (this._timeout != null) {
  81. this.timeoutAfter(this._timeout);
  82. }
  83. this._cb(this);
  84. this.emit('run');
  85. };
  86. Test.prototype.test = function (name, opts, cb) {
  87. var self = this;
  88. var t = new Test(name, opts, cb);
  89. this._progeny.push(t);
  90. this.pendingCount++;
  91. this.emit('test', t);
  92. t.on('prerun', function () {
  93. self.assertCount++;
  94. });
  95. if (!self._pendingAsserts()) {
  96. nextTick(function () {
  97. self._end();
  98. });
  99. }
  100. nextTick(function () {
  101. if (!self._plan && self.pendingCount == self._progeny.length) {
  102. self._end();
  103. }
  104. });
  105. };
  106. Test.prototype.comment = function (msg) {
  107. var that = this;
  108. forEach(trim(msg).split('\n'), function (aMsg) {
  109. that.emit('result', trim(aMsg).replace(/^#\s*/, ''));
  110. });
  111. };
  112. Test.prototype.plan = function (n) {
  113. this._plan = n;
  114. this.emit('plan', n);
  115. };
  116. Test.prototype.timeoutAfter = function (ms) {
  117. if (!ms) throw new Error('timeoutAfter requires a timespan');
  118. var self = this;
  119. var timeout = safeSetTimeout(function () {
  120. self.fail('test timed out after ' + ms + 'ms');
  121. self.end();
  122. }, ms);
  123. this.once('end', function () {
  124. safeClearTimeout(timeout);
  125. });
  126. };
  127. Test.prototype.end = function (err) {
  128. var self = this;
  129. if (arguments.length >= 1 && !!err) {
  130. this.ifError(err);
  131. }
  132. if (this.calledEnd) {
  133. this.fail('.end() called twice');
  134. }
  135. this.calledEnd = true;
  136. this._end();
  137. };
  138. Test.prototype._end = function (err) {
  139. var self = this;
  140. if (this._progeny.length) {
  141. var t = this._progeny.shift();
  142. t.on('end', function () { self._end(); });
  143. t.run();
  144. return;
  145. }
  146. if (!this.ended) this.emit('end');
  147. var pendingAsserts = this._pendingAsserts();
  148. if (!this._planError && this._plan !== undefined && pendingAsserts) {
  149. this._planError = true;
  150. this.fail('plan != count', {
  151. expected : this._plan,
  152. actual : this.assertCount
  153. });
  154. }
  155. this.ended = true;
  156. };
  157. Test.prototype._exit = function () {
  158. if (this._plan !== undefined &&
  159. !this._planError && this.assertCount !== this._plan) {
  160. this._planError = true;
  161. this.fail('plan != count', {
  162. expected : this._plan,
  163. actual : this.assertCount,
  164. exiting : true
  165. });
  166. } else if (!this.ended) {
  167. this.fail('test exited without ending', {
  168. exiting: true
  169. });
  170. }
  171. };
  172. Test.prototype._pendingAsserts = function () {
  173. if (this._plan === undefined) {
  174. return 1;
  175. }
  176. return this._plan - (this._progeny.length + this.assertCount);
  177. };
  178. Test.prototype._assert = function assert(ok, opts) {
  179. var self = this;
  180. var extra = opts.extra || {};
  181. ok = !!ok || !!extra.skip;
  182. var res = {
  183. id: self.assertCount++,
  184. ok: ok,
  185. skip: defined(extra.skip, opts.skip),
  186. todo: defined(extra.todo, opts.todo, self._todo),
  187. name: defined(extra.message, opts.message, '(unnamed assert)'),
  188. operator: defined(extra.operator, opts.operator),
  189. objectPrintDepth: self._objectPrintDepth
  190. };
  191. if (has(opts, 'actual') || has(extra, 'actual')) {
  192. res.actual = defined(extra.actual, opts.actual);
  193. }
  194. if (has(opts, 'expected') || has(extra, 'expected')) {
  195. res.expected = defined(extra.expected, opts.expected);
  196. }
  197. this._ok = !!(this._ok && ok);
  198. if (!ok && !res.todo) {
  199. res.error = defined(extra.error, opts.error, new Error(res.name));
  200. }
  201. if (!ok) {
  202. var e = new Error('exception');
  203. var err = (e.stack || '').split('\n');
  204. var dir = __dirname + path.sep;
  205. for (var i = 0; i < err.length; i++) {
  206. /*
  207. Stack trace lines may resemble one of the following. We need
  208. to should correctly extract a function name (if any) and
  209. path / line no. for each line.
  210. at myFunction (/path/to/file.js:123:45)
  211. at myFunction (/path/to/file.other-ext:123:45)
  212. at myFunction (/path to/file.js:123:45)
  213. at myFunction (C:\path\to\file.js:123:45)
  214. at myFunction (/path/to/file.js:123)
  215. at Test.<anonymous> (/path/to/file.js:123:45)
  216. at Test.bound [as run] (/path/to/file.js:123:45)
  217. at /path/to/file.js:123:45
  218. Regex has three parts. First is non-capturing group for 'at '
  219. (plus anything preceding it).
  220. /^(?:[^\s]*\s*\bat\s+)/
  221. Second captures function call description (optional). This is
  222. not necessarily a valid JS function name, but just what the
  223. stack trace is using to represent a function call. It may look
  224. like `<anonymous>` or 'Test.bound [as run]'.
  225. For our purposes, we assume that, if there is a function
  226. name, it's everything leading up to the first open
  227. parentheses (trimmed) before our pathname.
  228. /(?:(.*)\s+\()?/
  229. Last part captures file path plus line no (and optional
  230. column no).
  231. /((?:\/|[a-zA-Z]:\\)[^:\)]+:(\d+)(?::(\d+))?)/
  232. */
  233. var re = /^(?:[^\s]*\s*\bat\s+)(?:(.*)\s+\()?((?:\/|[a-zA-Z]:\\)[^:\)]+:(\d+)(?::(\d+))?)/;
  234. var m = re.exec(err[i]);
  235. if (!m) {
  236. continue;
  237. }
  238. var callDescription = m[1] || '<anonymous>';
  239. var filePath = m[2];
  240. if (filePath.slice(0, dir.length) === dir) {
  241. continue;
  242. }
  243. // Function call description may not (just) be a function name.
  244. // Try to extract function name by looking at first "word" only.
  245. res.functionName = callDescription.split(/\s+/)[0];
  246. res.file = filePath;
  247. res.line = Number(m[3]);
  248. if (m[4]) res.column = Number(m[4]);
  249. res.at = callDescription + ' (' + filePath + ')';
  250. break;
  251. }
  252. }
  253. self.emit('result', res);
  254. var pendingAsserts = self._pendingAsserts();
  255. if (!pendingAsserts) {
  256. if (extra.exiting) {
  257. self._end();
  258. } else {
  259. nextTick(function () {
  260. self._end();
  261. });
  262. }
  263. }
  264. if (!self._planError && pendingAsserts < 0) {
  265. self._planError = true;
  266. self.fail('plan != count', {
  267. expected : self._plan,
  268. actual : self._plan - pendingAsserts
  269. });
  270. }
  271. };
  272. Test.prototype.fail = function (msg, extra) {
  273. this._assert(false, {
  274. message : msg,
  275. operator : 'fail',
  276. extra : extra
  277. });
  278. };
  279. Test.prototype.pass = function (msg, extra) {
  280. this._assert(true, {
  281. message : msg,
  282. operator : 'pass',
  283. extra : extra
  284. });
  285. };
  286. Test.prototype.skip = function (msg, extra) {
  287. this._assert(true, {
  288. message : msg,
  289. operator : 'skip',
  290. skip : true,
  291. extra : extra
  292. });
  293. };
  294. function assert(value, msg, extra) {
  295. this._assert(value, {
  296. message : defined(msg, 'should be truthy'),
  297. operator : 'ok',
  298. expected : true,
  299. actual : value,
  300. extra : extra
  301. });
  302. }
  303. Test.prototype.ok
  304. = Test.prototype['true']
  305. = Test.prototype.assert
  306. = assert;
  307. function notOK(value, msg, extra) {
  308. this._assert(!value, {
  309. message : defined(msg, 'should be falsy'),
  310. operator : 'notOk',
  311. expected : false,
  312. actual : value,
  313. extra : extra
  314. });
  315. }
  316. Test.prototype.notOk
  317. = Test.prototype['false']
  318. = Test.prototype.notok
  319. = notOK;
  320. function error(err, msg, extra) {
  321. this._assert(!err, {
  322. message : defined(msg, String(err)),
  323. operator : 'error',
  324. actual : err,
  325. extra : extra
  326. });
  327. }
  328. Test.prototype.error
  329. = Test.prototype.ifError
  330. = Test.prototype.ifErr
  331. = Test.prototype.iferror
  332. = error;
  333. function equal(a, b, msg, extra) {
  334. this._assert(a === b, {
  335. message : defined(msg, 'should be equal'),
  336. operator : 'equal',
  337. actual : a,
  338. expected : b,
  339. extra : extra
  340. });
  341. }
  342. Test.prototype.equal
  343. = Test.prototype.equals
  344. = Test.prototype.isEqual
  345. = Test.prototype.is
  346. = Test.prototype.strictEqual
  347. = Test.prototype.strictEquals
  348. = equal;
  349. function notEqual(a, b, msg, extra) {
  350. this._assert(a !== b, {
  351. message : defined(msg, 'should not be equal'),
  352. operator : 'notEqual',
  353. actual : a,
  354. expected : b,
  355. extra : extra
  356. });
  357. }
  358. Test.prototype.notEqual
  359. = Test.prototype.notEquals
  360. = Test.prototype.notStrictEqual
  361. = Test.prototype.notStrictEquals
  362. = Test.prototype.isNotEqual
  363. = Test.prototype.isNot
  364. = Test.prototype.not
  365. = Test.prototype.doesNotEqual
  366. = Test.prototype.isInequal
  367. = notEqual;
  368. function tapeDeepEqual(a, b, msg, extra) {
  369. this._assert(deepEqual(a, b, { strict: true }), {
  370. message : defined(msg, 'should be equivalent'),
  371. operator : 'deepEqual',
  372. actual : a,
  373. expected : b,
  374. extra : extra
  375. });
  376. }
  377. Test.prototype.deepEqual
  378. = Test.prototype.deepEquals
  379. = Test.prototype.isEquivalent
  380. = Test.prototype.same
  381. = tapeDeepEqual;
  382. function deepLooseEqual(a, b, msg, extra) {
  383. this._assert(deepEqual(a, b), {
  384. message : defined(msg, 'should be equivalent'),
  385. operator : 'deepLooseEqual',
  386. actual : a,
  387. expected : b,
  388. extra : extra
  389. });
  390. }
  391. Test.prototype.deepLooseEqual
  392. = Test.prototype.looseEqual
  393. = Test.prototype.looseEquals
  394. = deepLooseEqual;
  395. function notDeepEqual(a, b, msg, extra) {
  396. this._assert(!deepEqual(a, b, { strict: true }), {
  397. message : defined(msg, 'should not be equivalent'),
  398. operator : 'notDeepEqual',
  399. actual : a,
  400. expected : b,
  401. extra : extra
  402. });
  403. }
  404. Test.prototype.notDeepEqual
  405. = Test.prototype.notDeepEquals
  406. = Test.prototype.notEquivalent
  407. = Test.prototype.notDeeply
  408. = Test.prototype.notSame
  409. = Test.prototype.isNotDeepEqual
  410. = Test.prototype.isNotDeeply
  411. = Test.prototype.isNotEquivalent
  412. = Test.prototype.isInequivalent
  413. = notDeepEqual;
  414. function notDeepLooseEqual(a, b, msg, extra) {
  415. this._assert(!deepEqual(a, b), {
  416. message : defined(msg, 'should be equivalent'),
  417. operator : 'notDeepLooseEqual',
  418. actual : a,
  419. expected : b,
  420. extra : extra
  421. });
  422. }
  423. Test.prototype.notDeepLooseEqual
  424. = Test.prototype.notLooseEqual
  425. = Test.prototype.notLooseEquals
  426. = notDeepLooseEqual;
  427. Test.prototype['throws'] = function (fn, expected, msg, extra) {
  428. if (typeof expected === 'string') {
  429. msg = expected;
  430. expected = undefined;
  431. }
  432. var caught = undefined;
  433. try {
  434. fn();
  435. } catch (err) {
  436. caught = { error : err };
  437. if ((err != null) && (!isEnumerable(err, 'message') || !has(err, 'message'))) {
  438. var message = err.message;
  439. delete err.message;
  440. err.message = message;
  441. }
  442. }
  443. var passed = caught;
  444. if (expected instanceof RegExp) {
  445. passed = expected.test(caught && caught.error);
  446. expected = String(expected);
  447. }
  448. if (typeof expected === 'function' && caught) {
  449. passed = caught.error instanceof expected;
  450. caught.error = caught.error.constructor;
  451. }
  452. this._assert(typeof fn === 'function' && passed, {
  453. message : defined(msg, 'should throw'),
  454. operator : 'throws',
  455. actual : caught && caught.error,
  456. expected : expected,
  457. error: !passed && caught && caught.error,
  458. extra : extra
  459. });
  460. };
  461. Test.prototype.doesNotThrow = function (fn, expected, msg, extra) {
  462. if (typeof expected === 'string') {
  463. msg = expected;
  464. expected = undefined;
  465. }
  466. var caught = undefined;
  467. try {
  468. fn();
  469. }
  470. catch (err) {
  471. caught = { error : err };
  472. }
  473. this._assert(!caught, {
  474. message : defined(msg, 'should not throw'),
  475. operator : 'throws',
  476. actual : caught && caught.error,
  477. expected : expected,
  478. error : caught && caught.error,
  479. extra : extra
  480. });
  481. };
  482. Test.skip = function (name_, _opts, _cb) {
  483. var args = getTestArgs.apply(null, arguments);
  484. args.opts.skip = true;
  485. return Test(args.name, args.opts, args.cb);
  486. };
  487. // vim: set softtabstop=4 shiftwidth=4: