PageRenderTime 56ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/node_modules/grunt/node_modules/findup-sync/node_modules/lodash/test/test-build.js

https://bitbucket.org/biojazzard/gantry-eboracast
JavaScript | 1324 lines | 988 code | 172 blank | 164 comment | 124 complexity | 245a6cc51df9ddbf20331e1382205d1d MD5 | raw file
Possible License(s): MIT, JSON, BSD-2-Clause, Unlicense, GPL-2.0, WTFPL, LGPL-3.0, Apache-2.0, 0BSD, BSD-3-Clause, CC-BY-SA-3.0
  1. #!/usr/bin/env node
  2. ;(function(undefined) {
  3. 'use strict';
  4. /** Load modules */
  5. var fs = require('fs'),
  6. path = require('path'),
  7. vm = require('vm'),
  8. build = require('../build.js'),
  9. minify = require('../build/minify'),
  10. _ = require('../lodash.js');
  11. /** The unit testing framework */
  12. var QUnit = (
  13. global.addEventListener || (global.addEventListener = Function.prototype),
  14. global.QUnit = require('../vendor/qunit/qunit/qunit.js'),
  15. require('../vendor/qunit-clib/qunit-clib.js'),
  16. global.addEventListener === Function.prototype && delete global.addEventListener,
  17. global.QUnit
  18. );
  19. /** The time limit for the tests to run (milliseconds) */
  20. var timeLimit = process.argv.reduce(function(result, value, index) {
  21. if (/--time-limit/.test(value)) {
  22. return parseInt(process.argv[index + 1].replace(/(\d+h)?(\d+m)?(\d+s)?/, function(match, h, m, s) {
  23. return ((parseInt(h) || 0) * 3600000) +
  24. ((parseInt(m) || 0) * 60000) +
  25. ((parseInt(s) || 0) * 1000);
  26. })) || result;
  27. }
  28. return result;
  29. }, 0);
  30. /** Used to associate aliases with their real names */
  31. var aliasToRealMap = {
  32. 'all': 'every',
  33. 'any': 'some',
  34. 'collect': 'map',
  35. 'detect': 'find',
  36. 'drop': 'rest',
  37. 'each': 'forEach',
  38. 'extend': 'assign',
  39. 'foldl': 'reduce',
  40. 'foldr': 'reduceRight',
  41. 'head': 'first',
  42. 'include': 'contains',
  43. 'inject': 'reduce',
  44. 'methods': 'functions',
  45. 'select': 'filter',
  46. 'tail': 'rest',
  47. 'take': 'first',
  48. 'unique': 'uniq'
  49. };
  50. /** Used to associate real names with their aliases */
  51. var realToAliasMap = {
  52. 'assign': ['extend'],
  53. 'contains': ['include'],
  54. 'every': ['all'],
  55. 'filter': ['select'],
  56. 'find': ['detect'],
  57. 'first': ['head', 'take'],
  58. 'forEach': ['each'],
  59. 'functions': ['methods'],
  60. 'map': ['collect'],
  61. 'reduce': ['foldl', 'inject'],
  62. 'reduceRight': ['foldr'],
  63. 'rest': ['drop', 'tail'],
  64. 'some': ['any'],
  65. 'uniq': ['unique']
  66. };
  67. /** List of all Lo-Dash methods */
  68. var allMethods = _.functions(_)
  69. .filter(function(methodName) { return !/^_/.test(methodName); })
  70. .concat('chain')
  71. .sort();
  72. /** List of "Arrays" category methods */
  73. var arraysMethods = [
  74. 'compact',
  75. 'difference',
  76. 'drop',
  77. 'first',
  78. 'flatten',
  79. 'head',
  80. 'indexOf',
  81. 'initial',
  82. 'intersection',
  83. 'last',
  84. 'lastIndexOf',
  85. 'object',
  86. 'range',
  87. 'rest',
  88. 'sortedIndex',
  89. 'tail',
  90. 'take',
  91. 'union',
  92. 'uniq',
  93. 'unique',
  94. 'without',
  95. 'zip'
  96. ];
  97. /** List of "Chaining" category methods */
  98. var chainingMethods = [
  99. 'mixin',
  100. 'tap',
  101. 'value'
  102. ];
  103. /** List of "Collections" category methods */
  104. var collectionsMethods = [
  105. 'all',
  106. 'any',
  107. 'at',
  108. 'collect',
  109. 'contains',
  110. 'countBy',
  111. 'detect',
  112. 'each',
  113. 'every',
  114. 'filter',
  115. 'find',
  116. 'foldl',
  117. 'foldr',
  118. 'forEach',
  119. 'groupBy',
  120. 'include',
  121. 'inject',
  122. 'invoke',
  123. 'map',
  124. 'max',
  125. 'min',
  126. 'pluck',
  127. 'reduce',
  128. 'reduceRight',
  129. 'reject',
  130. 'select',
  131. 'shuffle',
  132. 'size',
  133. 'some',
  134. 'sortBy',
  135. 'toArray',
  136. 'where'
  137. ];
  138. /** List of "Functions" category methods */
  139. var functionsMethods = [
  140. 'after',
  141. 'bind',
  142. 'bindAll',
  143. 'bindKey',
  144. 'compose',
  145. 'debounce',
  146. 'defer',
  147. 'delay',
  148. 'memoize',
  149. 'once',
  150. 'partial',
  151. 'partialRight',
  152. 'throttle',
  153. 'wrap'
  154. ];
  155. /** List of "Objects" category methods */
  156. var objectsMethods = [
  157. 'assign',
  158. 'clone',
  159. 'cloneDeep',
  160. 'defaults',
  161. 'extend',
  162. 'forIn',
  163. 'forOwn',
  164. 'functions',
  165. 'has',
  166. 'invert',
  167. 'isArguments',
  168. 'isArray',
  169. 'isBoolean',
  170. 'isDate',
  171. 'isElement',
  172. 'isEmpty',
  173. 'isEqual',
  174. 'isFinite',
  175. 'isFunction',
  176. 'isNaN',
  177. 'isNull',
  178. 'isNumber',
  179. 'isObject',
  180. 'isPlainObject',
  181. 'isRegExp',
  182. 'isString',
  183. 'isUndefined',
  184. 'keys',
  185. 'methods',
  186. 'merge',
  187. 'omit',
  188. 'pairs',
  189. 'pick',
  190. 'values'
  191. ];
  192. /** List of "Utilities" category methods */
  193. var utilityMethods = [
  194. 'escape',
  195. 'identity',
  196. 'noConflict',
  197. 'random',
  198. 'result',
  199. 'template',
  200. 'times',
  201. 'unescape',
  202. 'uniqueId'
  203. ];
  204. /** List of Backbone's Lo-Dash dependencies */
  205. var backboneDependencies = [
  206. 'bind',
  207. 'bindAll',
  208. 'chain',
  209. 'clone',
  210. 'contains',
  211. 'countBy',
  212. 'defaults',
  213. 'escape',
  214. 'every',
  215. 'extend',
  216. 'filter',
  217. 'find',
  218. 'first',
  219. 'forEach',
  220. 'groupBy',
  221. 'has',
  222. 'indexOf',
  223. 'initial',
  224. 'invoke',
  225. 'isArray',
  226. 'isEmpty',
  227. 'isEqual',
  228. 'isFunction',
  229. 'isObject',
  230. 'isRegExp',
  231. 'isString',
  232. 'keys',
  233. 'last',
  234. 'lastIndexOf',
  235. 'map',
  236. 'max',
  237. 'min',
  238. 'mixin',
  239. 'once',
  240. 'pick',
  241. 'reduce',
  242. 'reduceRight',
  243. 'reject',
  244. 'rest',
  245. 'result',
  246. 'shuffle',
  247. 'size',
  248. 'some',
  249. 'sortBy',
  250. 'sortedIndex',
  251. 'toArray',
  252. 'uniqueId',
  253. 'value',
  254. 'without'
  255. ];
  256. /** List of methods used by Underscore */
  257. var underscoreMethods = _.without.apply(_, [allMethods].concat([
  258. 'at',
  259. 'bindKey',
  260. 'cloneDeep',
  261. 'forIn',
  262. 'forOwn',
  263. 'isPlainObject',
  264. 'merge',
  265. 'partialRight'
  266. ]));
  267. /*--------------------------------------------------------------------------*/
  268. /**
  269. * Creates a context object to use with `vm.runInContext`.
  270. *
  271. * @private
  272. * @returns {Object} Returns a new context object.
  273. */
  274. function createContext() {
  275. return vm.createContext({
  276. 'clearTimeout': clearTimeout,
  277. 'setTimeout': setTimeout
  278. });
  279. }
  280. /**
  281. * Expands a list of method names to include real and alias names.
  282. *
  283. * @private
  284. * @param {Array} methodNames The array of method names to expand.
  285. * @returns {Array} Returns a new array of expanded method names.
  286. */
  287. function expandMethodNames(methodNames) {
  288. return methodNames.reduce(function(result, methodName) {
  289. var realName = getRealName(methodName);
  290. result.push.apply(result, [realName].concat(getAliases(realName)));
  291. return result;
  292. }, []);
  293. }
  294. /**
  295. * Gets the aliases associated with a given function name.
  296. *
  297. * @private
  298. * @param {String} funcName The name of the function to get aliases for.
  299. * @returns {Array} Returns an array of aliases.
  300. */
  301. function getAliases(funcName) {
  302. return realToAliasMap[funcName] || [];
  303. }
  304. /**
  305. * Gets the names of methods belonging to the given `category`.
  306. *
  307. * @private
  308. * @param {String} category The category to filter by.
  309. * @returns {Array} Returns a new array of method names belonging to the given category.
  310. */
  311. function getMethodsByCategory(category) {
  312. switch (category) {
  313. case 'Arrays':
  314. return arraysMethods.slice();
  315. case 'Chaining':
  316. return chainingMethods.slice();
  317. case 'Collections':
  318. return collectionsMethods.slice();
  319. case 'Functions':
  320. return functionsMethods.slice();
  321. case 'Objects':
  322. return objectsMethods.slice();
  323. case 'Utilities':
  324. return utilityMethods.slice();
  325. }
  326. return [];
  327. }
  328. /**
  329. * Gets the real name, not alias, of a given function name.
  330. *
  331. * @private
  332. * @param {String} funcName The name of the function to resolve.
  333. * @returns {String} Returns the real name.
  334. */
  335. function getRealName(funcName) {
  336. return aliasToRealMap[funcName] || funcName;
  337. }
  338. /**
  339. * Tests if a given method on the `lodash` object can be called successfully.
  340. *
  341. * @private
  342. * @param {Object} lodash The built Lo-Dash object.
  343. * @param {String} methodName The name of the Lo-Dash method to test.
  344. * @param {String} message The unit test message.
  345. */
  346. function testMethod(lodash, methodName, message) {
  347. var pass = true,
  348. array = [['a', 1], ['b', 2], ['c', 3]],
  349. object = { 'a': 1, 'b': 2, 'c': 3 },
  350. noop = function() {},
  351. string = 'abc',
  352. template = '<%= a %>',
  353. func = lodash[methodName];
  354. try {
  355. if (arraysMethods.indexOf(methodName) > -1) {
  356. if (/(?:indexOf|sortedIndex|without)$/i.test(methodName)) {
  357. func(array, string);
  358. } else if (/^(?:difference|intersection|union|uniq|zip)/.test(methodName)) {
  359. func(array, array);
  360. } else if (methodName == 'range') {
  361. func(2, 4);
  362. } else {
  363. func(array);
  364. }
  365. }
  366. else if (chainingMethods.indexOf(methodName) > -1) {
  367. if (methodName == 'chain') {
  368. lodash.chain(array);
  369. lodash(array).chain();
  370. }
  371. else if (methodName == 'mixin') {
  372. lodash.mixin({});
  373. }
  374. else {
  375. lodash(array)[methodName](noop);
  376. }
  377. }
  378. else if (collectionsMethods.indexOf(methodName) > -1) {
  379. if (/^(?:count|group|sort)By$/.test(methodName)) {
  380. func(array, noop);
  381. func(array, string);
  382. func(object, noop);
  383. func(object, string);
  384. }
  385. else if (/^(?:size|toArray)$/.test(methodName)) {
  386. func(array);
  387. func(object);
  388. }
  389. else if (methodName == 'at') {
  390. func(array, 0, 2);
  391. func(object, 'a', 'c');
  392. }
  393. else if (methodName == 'invoke') {
  394. func(array, 'slice');
  395. func(object, 'toFixed');
  396. }
  397. else if (methodName == 'where') {
  398. func(array, object);
  399. func(object, object);
  400. }
  401. else {
  402. func(array, noop, object);
  403. func(object, noop, object);
  404. }
  405. }
  406. else if (functionsMethods.indexOf(methodName) > -1) {
  407. if (methodName == 'after') {
  408. func(1, noop);
  409. } else if (methodName == 'bindAll') {
  410. func({ 'noop': noop });
  411. } else if (methodName == 'bindKey') {
  412. func(lodash, 'identity', array, string);
  413. } else if (/^(?:bind|partial(?:Right)?)$/.test(methodName)) {
  414. func(noop, object, array, string);
  415. } else if (/^(?:compose|memoize|wrap)$/.test(methodName)) {
  416. func(noop, noop);
  417. } else if (/^(?:debounce|throttle)$/.test(methodName)) {
  418. func(noop, 100);
  419. } else {
  420. func(noop);
  421. }
  422. }
  423. else if (objectsMethods.indexOf(methodName) > -1) {
  424. if (methodName == 'clone') {
  425. func(object);
  426. func(object, true);
  427. }
  428. else if (/^(?:defaults|extend|merge)$/.test(methodName)) {
  429. func({}, object);
  430. } else if (/^(?:forIn|forOwn)$/.test(methodName)) {
  431. func(object, noop);
  432. } else if (/^(?:omit|pick)$/.test(methodName)) {
  433. func(object, 'b');
  434. } else if (methodName == 'has') {
  435. func(object, string);
  436. } else {
  437. func(object);
  438. }
  439. }
  440. else if (utilityMethods.indexOf(methodName) > -1) {
  441. if (methodName == 'result') {
  442. func(object, 'b');
  443. } else if (methodName == 'template') {
  444. func(template, object);
  445. func(template, null, { 'imports': object })(object);
  446. } else if (methodName == 'times') {
  447. func(2, noop, object);
  448. } else {
  449. func(string, object);
  450. }
  451. }
  452. }
  453. catch(e) {
  454. console.log(e);
  455. pass = false;
  456. }
  457. ok(pass, '_.' + methodName + ': ' + message);
  458. }
  459. /*--------------------------------------------------------------------------*/
  460. QUnit.module('minified AMD snippet');
  461. (function() {
  462. var start = _.once(QUnit.start);
  463. asyncTest('`lodash`', function() {
  464. build(['-s'], function(data) {
  465. // used by r.js build optimizer
  466. var defineHasRegExp = /typeof\s+define\s*==(=)?\s*['"]function['"]\s*&&\s*typeof\s+define\.amd\s*==(=)?\s*['"]object['"]\s*&&\s*define\.amd/g,
  467. basename = path.basename(data.outputPath, '.js');
  468. ok(!!defineHasRegExp.exec(data.source), basename);
  469. start();
  470. });
  471. });
  472. }());
  473. /*--------------------------------------------------------------------------*/
  474. QUnit.module('template builds');
  475. (function() {
  476. var templatePath = __dirname + '/template';
  477. asyncTest('`lodash template=*.jst`', function() {
  478. var start = _.after(2, _.once(QUnit.start));
  479. build(['-s', 'template=' + templatePath + '/*.jst'], function(data) {
  480. var basename = path.basename(data.outputPath, '.js'),
  481. context = createContext();
  482. var object = {
  483. 'a': { 'people': ['moe', 'larry', 'curly'] },
  484. 'b': { 'epithet': 'stooge' },
  485. 'c': { 'name': 'ES6' }
  486. };
  487. context._ = _;
  488. vm.runInContext(data.source, context);
  489. equal(_.templates.a(object.a).replace(/[\r\n]+/g, ''), '<ul><li>moe</li><li>larry</li><li>curly</li></ul>', basename);
  490. equal(_.templates.b(object.b), 'Hello stooge.', basename);
  491. equal(_.templates.c(object.c), 'Hello ES6!', basename);
  492. delete _.templates;
  493. start();
  494. });
  495. });
  496. var commands = [
  497. '',
  498. 'moduleId=underscore'
  499. ];
  500. commands.forEach(function(command) {
  501. var expectedId = /underscore/.test(command) ? 'underscore' : 'lodash';
  502. asyncTest('`lodash template=*.jst exports=amd' + (command ? ' ' + command : '') + '`', function() {
  503. var start = _.after(2, _.once(QUnit.start));
  504. build(['-s', 'template=' + templatePath + '/*.jst', 'exports=amd'].concat(command || []), function(data) {
  505. var moduleId,
  506. basename = path.basename(data.outputPath, '.js'),
  507. context = createContext();
  508. context.define = function(requires, factory) {
  509. factory(_);
  510. moduleId = requires[0];
  511. };
  512. context.define.amd = {};
  513. vm.runInContext(data.source, context);
  514. equal(moduleId, expectedId, basename);
  515. ok('a' in _.templates && 'b' in _.templates, basename);
  516. equal(_.templates.a({ 'people': ['moe', 'larry'] }), '<ul>\n<li>moe</li><li>larry</li>\n</ul>', basename);
  517. delete _.templates;
  518. start();
  519. });
  520. });
  521. asyncTest('`lodash settings=...' + (command ? ' ' + command : '') + '`', function() {
  522. var start = _.after(2, _.once(QUnit.start));
  523. build(['-s', 'template=' + templatePath + '/*.tpl', 'settings={interpolate:/{{([\\s\\S]+?)}}/}'].concat(command || []), function(data) {
  524. var moduleId,
  525. basename = path.basename(data.outputPath, '.js'),
  526. context = createContext();
  527. var object = {
  528. 'd': { 'name': 'Mustache' }
  529. };
  530. context.define = function(requires, factory) {
  531. factory(_);
  532. moduleId = requires[0];
  533. };
  534. context.define.amd = {};
  535. vm.runInContext(data.source, context);
  536. equal(moduleId, expectedId, basename);
  537. equal(_.templates.d(object.d), 'Hello Mustache!', basename);
  538. delete _.templates;
  539. start();
  540. });
  541. });
  542. });
  543. }());
  544. /*--------------------------------------------------------------------------*/
  545. QUnit.module('independent builds');
  546. (function() {
  547. var reCustom = /Custom Build/,
  548. reLicense = /^\/\**\s+\* @license[\s\S]+?\*\/\n/;
  549. asyncTest('debug only', function() {
  550. var start = _.once(QUnit.start);
  551. build(['-d', '-s'], function(data) {
  552. equal(path.basename(data.outputPath, '.js'), 'lodash');
  553. start();
  554. });
  555. });
  556. asyncTest('debug custom', function() {
  557. var start = _.once(QUnit.start);
  558. build(['-d', '-s', 'backbone'], function(data) {
  559. equal(path.basename(data.outputPath, '.js'), 'lodash.custom');
  560. var comment = data.source.match(reLicense);
  561. ok(reCustom.test(comment));
  562. start();
  563. });
  564. });
  565. asyncTest('minified only', function() {
  566. var start = _.once(QUnit.start);
  567. build(['-m', '-s'], function(data) {
  568. equal(path.basename(data.outputPath, '.js'), 'lodash.min');
  569. start();
  570. });
  571. });
  572. asyncTest('minified custom', function() {
  573. var start = _.once(QUnit.start);
  574. build(['-m', '-s', 'backbone'], function(data) {
  575. equal(path.basename(data.outputPath, '.js'), 'lodash.custom.min');
  576. var comment = data.source.match(reLicense);
  577. ok(reCustom.test(comment));
  578. start();
  579. });
  580. });
  581. }());
  582. /*--------------------------------------------------------------------------*/
  583. QUnit.module('source maps');
  584. (function() {
  585. var mapCommands = [
  586. '-p',
  587. '-p custom.map',
  588. '--source-map',
  589. '--source-map custom.map'
  590. ];
  591. var outputCommands = [
  592. '',
  593. '-o foo.js',
  594. '-m -o bar.js'
  595. ];
  596. mapCommands.forEach(function(mapCommand) {
  597. outputCommands.forEach(function(outputCommand) {
  598. asyncTest('`lodash ' + mapCommand + (outputCommand ? ' ' + outputCommand : '') + '`', function() {
  599. var callback = _.once(function(data) {
  600. var basename = path.basename(data.outputPath, '.js'),
  601. comment = (/(\s*\/\/.*\s*|\s*\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/\s*)$/.exec(data.source) || [])[0],
  602. sources = /foo.js/.test(outputCommand) ? ['foo.js'] : ['lodash' + (outputCommand.length ? '' : '.custom') + '.js'],
  603. sourceMap = JSON.parse(data.sourceMap),
  604. sourceMapURL = (/\w+(?=\.map$)/.exec(mapCommand) || [basename])[0];
  605. ok(RegExp('/\\*\\n//@ sourceMappingURL=' + sourceMapURL + '.map\\n\\*/').test(comment), basename);
  606. equal(sourceMap.file, basename + '.js', basename);
  607. deepEqual(sourceMap.sources, sources, basename);
  608. QUnit.start();
  609. });
  610. outputCommand = outputCommand ? outputCommand.split(' ') : [];
  611. if (outputCommand.indexOf('-m') < 0) {
  612. callback = _.after(2, callback);
  613. }
  614. build(['-s'].concat(mapCommand.split(' '), outputCommand), callback);
  615. });
  616. });
  617. });
  618. }());
  619. /*--------------------------------------------------------------------------*/
  620. QUnit.module('strict modifier');
  621. (function() {
  622. var object = Object.freeze({
  623. 'a': _.identity,
  624. 'b': undefined
  625. });
  626. var modes = [
  627. 'non-strict',
  628. 'strict'
  629. ];
  630. modes.forEach(function(strictMode, index) {
  631. asyncTest(strictMode + ' should ' + (index ? 'error': 'silently fail') + ' attempting to overwrite read-only properties', function() {
  632. var commands = ['-s', 'include=bindAll,defaults,extend'],
  633. start = _.after(2, _.once(QUnit.start));
  634. if (index) {
  635. commands.push('strict');
  636. }
  637. build(commands, function(data) {
  638. var basename = path.basename(data.outputPath, '.js'),
  639. context = createContext();
  640. vm.runInContext(data.source, context);
  641. var lodash = context._;
  642. var actual = _.every([
  643. function() { lodash.bindAll(object); },
  644. function() { lodash.extend(object, { 'a': 1 }); },
  645. function() { lodash.defaults(object, { 'b': 2 }); }
  646. ], function(fn) {
  647. var pass = !index;
  648. try {
  649. fn();
  650. } catch(e) {
  651. pass = !!index;
  652. }
  653. return pass;
  654. });
  655. ok(actual, basename);
  656. start();
  657. });
  658. });
  659. });
  660. }());
  661. /*--------------------------------------------------------------------------*/
  662. QUnit.module('underscore chaining methods');
  663. (function() {
  664. var commands = [
  665. 'backbone',
  666. 'underscore'
  667. ];
  668. commands.forEach(function(command) {
  669. asyncTest('`lodash ' + command +'`', function() {
  670. var start = _.after(2, _.once(QUnit.start));
  671. build(['-s', command], function(data) {
  672. var basename = path.basename(data.outputPath, '.js'),
  673. context = createContext();
  674. vm.runInContext(data.source, context);
  675. var lodash = context._;
  676. ok(lodash.chain(1) instanceof lodash, '_.chain: ' + basename);
  677. ok(lodash(1).chain() instanceof lodash, '_#chain: ' + basename);
  678. var wrapped = lodash(1);
  679. strictEqual(wrapped.identity(), 1, '_(...) wrapped values are not chainable by default: ' + basename);
  680. equal(String(wrapped) === '1', false, '_#toString should not be implemented: ' + basename);
  681. equal(Number(wrapped) === 1 , false, '_#valueOf should not be implemented: ' + basename);
  682. wrapped.chain();
  683. ok(wrapped.has('x') instanceof lodash, '_#has returns wrapped values when chaining: ' + basename);
  684. ok(wrapped.join() instanceof lodash, '_#join returns wrapped values when chaining: ' + basename);
  685. wrapped = lodash([1, 2, 3]);
  686. ok(wrapped.pop() instanceof lodash, '_#pop returns wrapped values: ' + basename);
  687. ok(wrapped.shift() instanceof lodash, '_#shift returns wrapped values: ' + basename);
  688. deepEqual(wrapped.splice(0, 0).value(), [2], '_#splice returns wrapper: ' + basename);
  689. start();
  690. });
  691. });
  692. });
  693. }());
  694. /*--------------------------------------------------------------------------*/
  695. QUnit.module('underscore modifier');
  696. (function() {
  697. asyncTest('modified methods should work correctly', function() {
  698. var start = _.after(2, _.once(QUnit.start));
  699. build(['-s', 'underscore'], function(data) {
  700. var last,
  701. array = [{ 'a': 1, 'b': 2 }, { 'a': 2, 'b': 2 }],
  702. basename = path.basename(data.outputPath, '.js'),
  703. context = createContext();
  704. vm.runInContext(data.source, context);
  705. var lodash = context._;
  706. var object = {
  707. 'fn': lodash.bind(function(foo) {
  708. return foo + this.bar;
  709. }, { 'bar': 1 }, 1)
  710. };
  711. equal(object.fn(), 2, '_.bind: ' + basename);
  712. var actual = lodash.clone('a', function() {
  713. return this.a;
  714. }, { 'a': 'A' });
  715. equal(actual, 'a', '_.clone should ignore `callback` and `thisArg`: ' + basename);
  716. strictEqual(lodash.clone(array, true)[0], array[0], '_.clone should ignore `deep`: ' + basename);
  717. strictEqual(lodash.contains({ 'a': 1, 'b': 2 }, 1), true, '_.contains should work with objects: ' + basename);
  718. strictEqual(lodash.contains([1, 2, 3], 1, 2), true, '_.contains should ignore `fromIndex`: ' + basename);
  719. strictEqual(lodash.every([true, false, true]), false, '_.every: ' + basename);
  720. function Foo() {}
  721. Foo.prototype = { 'a': 1 };
  722. actual = lodash.defaults({ 'a': null }, { 'a': 1 });
  723. strictEqual(actual.a, 1, '_.defaults should overwrite `null` values: ' + basename);
  724. deepEqual(lodash.defaults({}, new Foo), Foo.prototype, '_.defaults should assign inherited `source` properties: ' + basename);
  725. deepEqual(lodash.extend({}, new Foo), Foo.prototype, '_.extend should assign inherited `source` properties: ' + basename);
  726. actual = lodash.extend({}, { 'a': 0 }, function(a, b) {
  727. return this[b];
  728. }, [2]);
  729. strictEqual(actual.a, 0, '_.extend should ignore `callback` and `thisArg`: ' + basename);
  730. actual = lodash.find(array, function(value) {
  731. return 'a' in value;
  732. });
  733. equal(actual, _.first(array), '_.find: ' + basename);
  734. actual = lodash.forEach(array, function(value) {
  735. last = value;
  736. return false;
  737. });
  738. equal(last, _.last(array), '_.forEach should not exit early: ' + basename);
  739. equal(actual, undefined, '_.forEach should return `undefined`: ' + basename);
  740. object = { 'length': 0, 'splice': Array.prototype.splice };
  741. equal(lodash.isEmpty(object), false, '_.isEmpty should return `false` for jQuery/MooTools DOM query collections: ' + basename);
  742. object = { 'a': 1, 'b': 2, 'c': 3 };
  743. equal(lodash.isEqual(object, { 'a': 1, 'b': 0, 'c': 3 }), false, '_.isEqual: ' + basename);
  744. actual = lodash.isEqual('a', 'b', function(a, b) {
  745. return this[a] == this[b];
  746. }, { 'a': 1, 'b': 1 });
  747. strictEqual(actual, false, '_.isEqual should ignore `callback` and `thisArg`: ' + basename);
  748. equal(lodash.max('abc'), -Infinity, '_.max should return `-Infinity` for strings: ' + basename);
  749. equal(lodash.min('abc'), Infinity, '_.min should return `Infinity` for strings: ' + basename);
  750. // avoid issues comparing objects with `deepEqual`
  751. object = { 'a': 1, 'b': 2, 'c': 3 };
  752. actual = lodash.omit(object, function(value) { return value == 3; });
  753. deepEqual(_.keys(actual).sort(), ['a', 'b', 'c'], '_.omit should not accept a `callback`: ' + basename);
  754. actual = lodash.pick(object, function(value) { return value != 3; });
  755. deepEqual(_.keys(actual), [], '_.pick should not accept a `callback`: ' + basename);
  756. strictEqual(lodash.result(), null, '_.result should return `null` for falsey `object` arguments: ' + basename);
  757. strictEqual(lodash.some([false, true, false]), true, '_.some: ' + basename);
  758. equal(lodash.template('${a}', object), '${a}', '_.template should ignore ES6 delimiters: ' + basename);
  759. equal('imports' in lodash.templateSettings, false, '_.templateSettings should not have an "imports" property: ' + basename);
  760. strictEqual(lodash.uniqueId(0), '1', '_.uniqueId should ignore a prefix of `0`: ' + basename);
  761. var collection = [{ 'a': { 'b': 1, 'c': 2 } }];
  762. deepEqual(lodash.where(collection, { 'a': { 'b': 1 } }), [], '_.where performs shallow comparisons: ' + basename);
  763. collection = [{ 'a': 1 }, { 'a': 1 }];
  764. deepEqual(lodash.where(collection, { 'a': 1 }, true), collection[0], '_.where supports a `first` argument: ' + basename);
  765. deepEqual(lodash.where(collection, {}, true), null, '_.where should return `null` when passed `first` and falsey `properties`: ' + basename);
  766. deepEqual(lodash.findWhere(collection, { 'a': 1 }), collection[0], '_.findWhere: ' + basename);
  767. strictEqual(lodash.findWhere(collection, {}), null, '_.findWhere should return `null` for falsey `properties`: ' + basename);
  768. start();
  769. });
  770. });
  771. asyncTest('should not have any Lo-Dash-only methods', function() {
  772. var start = _.after(2, _.once(QUnit.start));
  773. build(['-s', 'underscore'], function(data) {
  774. var basename = path.basename(data.outputPath, '.js'),
  775. context = createContext();
  776. vm.runInContext(data.source, context);
  777. var lodash = context._;
  778. _.each([
  779. 'assign',
  780. 'at',
  781. 'bindKey',
  782. 'forIn',
  783. 'forOwn',
  784. 'isPlainObject',
  785. 'merge',
  786. 'partialRight'
  787. ], function(methodName) {
  788. equal(lodash[methodName], undefined, '_.' + methodName + ' should not exist: ' + basename);
  789. });
  790. start();
  791. });
  792. });
  793. asyncTest('`lodash underscore include=findWhere`', function() {
  794. var start = _.after(2, _.once(QUnit.start));
  795. build(['-s', 'underscore', 'include=findWhere'], function(data) {
  796. var basename = path.basename(data.outputPath, '.js'),
  797. context = createContext();
  798. vm.runInContext(data.source, context);
  799. var lodash = context._;
  800. var collection = [{ 'a': 1 }, { 'a': 1 }];
  801. deepEqual(lodash.findWhere(collection, { 'a': 1 }), collection[0], '_.findWhere: ' + basename);
  802. start();
  803. });
  804. });
  805. asyncTest('`lodash underscore include=partial`', function() {
  806. var start = _.after(2, _.once(QUnit.start));
  807. build(['-s', 'underscore', 'include=partial'], function(data) {
  808. var basename = path.basename(data.outputPath, '.js'),
  809. context = createContext();
  810. vm.runInContext(data.source, context);
  811. var lodash = context._;
  812. equal(lodash.partial(_.identity, 2)(), 2, '_.partial: ' + basename);
  813. start();
  814. });
  815. });
  816. asyncTest('`lodash underscore plus=clone`', function() {
  817. var start = _.after(2, _.once(QUnit.start));
  818. build(['-s', 'underscore', 'plus=clone'], function(data) {
  819. var array = [{ 'value': 1 }],
  820. basename = path.basename(data.outputPath, '.js'),
  821. context = createContext();
  822. vm.runInContext(data.source, context);
  823. var lodash = context._,
  824. clone = lodash.clone(array, true);
  825. ok(_.isEqual(array, clone), basename);
  826. notEqual(array[0], clone[0], basename);
  827. start();
  828. });
  829. });
  830. }());
  831. /*--------------------------------------------------------------------------*/
  832. QUnit.module('exports command');
  833. (function() {
  834. var commands = [
  835. 'exports=amd',
  836. 'exports=commonjs',
  837. 'exports=global',
  838. 'exports=node',
  839. 'exports=none'
  840. ];
  841. commands.forEach(function(command, index) {
  842. asyncTest('`lodash ' + command +'`', function() {
  843. var start = _.after(2, _.once(QUnit.start));
  844. build(['-s', command], function(data) {
  845. var basename = path.basename(data.outputPath, '.js'),
  846. context = createContext(),
  847. pass = false,
  848. source = data.source;
  849. switch(index) {
  850. case 0:
  851. context.define = function(fn) {
  852. pass = true;
  853. context._ = fn();
  854. };
  855. context.define.amd = {};
  856. vm.runInContext(source, context);
  857. ok(pass, basename);
  858. break;
  859. case 1:
  860. context.exports = {};
  861. vm.runInContext(source, context);
  862. ok(_.isFunction(context.exports._), basename);
  863. strictEqual(context._, undefined, basename);
  864. break;
  865. case 2:
  866. vm.runInContext(source, context);
  867. ok(_.isFunction(context._), basename);
  868. break;
  869. case 3:
  870. context.exports = {};
  871. context.module = { 'exports': context.exports };
  872. vm.runInContext(source, context);
  873. ok(_.isFunction(context.module.exports), basename);
  874. strictEqual(context._, undefined, basename);
  875. break;
  876. case 4:
  877. vm.runInContext(source, context);
  878. strictEqual(context._, undefined, basename);
  879. }
  880. start();
  881. });
  882. });
  883. });
  884. }());
  885. /*--------------------------------------------------------------------------*/
  886. QUnit.module('iife command');
  887. (function() {
  888. var commands = [
  889. 'iife=this["lodash"]=(function(window,undefined){%output%;return lodash}(this))',
  890. 'iife=define(function(window,undefined){return function(){%output%;return lodash}}(this));'
  891. ];
  892. commands.forEach(function(command) {
  893. asyncTest('`lodash ' + command +'`', function() {
  894. var start = _.after(2, _.once(QUnit.start));
  895. build(['-s', 'exports=none', command], function(data) {
  896. var basename = path.basename(data.outputPath, '.js'),
  897. context = createContext();
  898. context.define = function(func) {
  899. context.lodash = func();
  900. };
  901. try {
  902. vm.runInContext(data.source, context);
  903. } catch(e) {
  904. console.log(e);
  905. }
  906. var lodash = context.lodash || {};
  907. ok(_.isString(lodash.VERSION), basename);
  908. start();
  909. });
  910. });
  911. });
  912. }());
  913. /*--------------------------------------------------------------------------*/
  914. QUnit.module('output options');
  915. (function() {
  916. var commands = [
  917. '-o a.js',
  918. '--output a.js'
  919. ];
  920. commands.forEach(function(command, index) {
  921. asyncTest('`lodash ' + command +'`', function() {
  922. var counter = -1,
  923. start = _.after(2, _.once(QUnit.start));
  924. build(['-s'].concat(command.split(' ')), function(data) {
  925. equal(path.basename(data.outputPath, '.js'), (++counter ? 'a.min' : 'a'), command);
  926. start();
  927. });
  928. });
  929. });
  930. }());
  931. /*--------------------------------------------------------------------------*/
  932. QUnit.module('stdout options');
  933. (function() {
  934. var commands = [
  935. '-c',
  936. '-c -d',
  937. '--stdout',
  938. ];
  939. commands.forEach(function(command, index) {
  940. asyncTest('`lodash ' + command +'`', function() {
  941. var written,
  942. start = _.once(QUnit.start),
  943. write = process.stdout.write;
  944. process.stdout.write = function(string) {
  945. written = string;
  946. };
  947. build(['exports=', 'include='].concat(command.split(' ')), function(data) {
  948. process.stdout.write = write;
  949. equal(written, data.source);
  950. equal(arguments.length, 1);
  951. start();
  952. });
  953. });
  954. });
  955. }());
  956. /*--------------------------------------------------------------------------*/
  957. QUnit.module('mobile build');
  958. (function() {
  959. asyncTest('`lodash mobile`', function() {
  960. var start = _.after(2, _.once(QUnit.start));
  961. build(['-s', 'mobile'], function(data) {
  962. var basename = path.basename(data.outputPath, '.js'),
  963. context = createContext();
  964. try {
  965. vm.runInContext(data.source, context);
  966. } catch(e) {
  967. console.log(e);
  968. }
  969. var array = [1, 2, 3],
  970. object1 = [{ 'a': 1 }],
  971. object2 = [{ 'b': 2 }],
  972. object3 = [{ 'a': 1, 'b': 2 }],
  973. circular1 = { 'a': 1 },
  974. circular2 = { 'a': 1 },
  975. lodash = context._;
  976. circular1.b = circular1;
  977. circular2.b = circular2;
  978. deepEqual(lodash.merge(object1, object2), object3, basename);
  979. deepEqual(lodash.sortBy([3, 2, 1], _.identity), array, basename);
  980. strictEqual(lodash.isEqual(circular1, circular2), true, basename);
  981. var actual = lodash.cloneDeep(circular1);
  982. ok(actual != circular1 && actual.b == actual, basename);
  983. start();
  984. });
  985. });
  986. asyncTest('`lodash csp`', function() {
  987. var sources = [];
  988. var check = _.after(2, _.once(function() {
  989. equal(sources[0], sources[1]);
  990. QUnit.start();
  991. }));
  992. var callback = function(data) {
  993. // remove copyright header and append source
  994. sources.push(data.source.replace(/^\/\**[\s\S]+?\*\/\n/, ''));
  995. check();
  996. };
  997. build(['-s', '-d', 'csp'], callback);
  998. build(['-s', '-d', 'mobile'], callback);
  999. });
  1000. }());
  1001. /*--------------------------------------------------------------------------*/
  1002. QUnit.module('lodash build');
  1003. (function() {
  1004. var commands = [
  1005. 'backbone',
  1006. 'csp',
  1007. 'legacy',
  1008. 'mobile',
  1009. 'modern',
  1010. 'strict',
  1011. 'underscore',
  1012. 'category=arrays',
  1013. 'category=chaining',
  1014. 'category=collections',
  1015. 'category=functions',
  1016. 'category=objects',
  1017. 'category=utilities',
  1018. 'exclude=union,uniq,zip',
  1019. 'include=each,filter,map',
  1020. 'include=once plus=bind,Chaining',
  1021. 'category=collections,functions',
  1022. 'backbone legacy category=utilities minus=first,last',
  1023. 'legacy include=defer',
  1024. 'legacy underscore',
  1025. 'underscore include=debounce,throttle plus=after minus=throttle',
  1026. 'underscore mobile strict category=functions exports=amd,global plus=pick,uniq',
  1027. ]
  1028. .concat(
  1029. allMethods.map(function(methodName) {
  1030. return 'include=' + methodName;
  1031. })
  1032. );
  1033. commands.forEach(function(origCommand) {
  1034. _.times(4, function(index) {
  1035. var command = origCommand;
  1036. if (index == 1) {
  1037. if (/legacy|mobile/.test(command)) {
  1038. return;
  1039. }
  1040. command = 'mobile ' + command;
  1041. }
  1042. if (index == 2) {
  1043. if (/legacy|modern/.test(command)) {
  1044. return;
  1045. }
  1046. command = 'modern ' + command;
  1047. }
  1048. if (index == 3) {
  1049. if (/category|legacy|underscore/.test(command)) {
  1050. return;
  1051. }
  1052. command = 'underscore ' + command;
  1053. }
  1054. asyncTest('`lodash ' + command +'`', function() {
  1055. var start = _.after(2, _.once(QUnit.start));
  1056. build(['--silent'].concat(command.split(' ')), function(data) {
  1057. var methodNames,
  1058. basename = path.basename(data.outputPath, '.js'),
  1059. context = createContext(),
  1060. isUnderscore = /backbone|underscore/.test(command),
  1061. exposeAssign = !isUnderscore;
  1062. try {
  1063. vm.runInContext(data.source, context);
  1064. } catch(e) {
  1065. console.log(e);
  1066. }
  1067. // add method names explicitly
  1068. if (/include/.test(command)) {
  1069. methodNames = command.match(/include=(\S*)/)[1].split(/, */);
  1070. }
  1071. // add method names required by Backbone and Underscore builds
  1072. if (/backbone/.test(command) && !methodNames) {
  1073. methodNames = backboneDependencies.slice();
  1074. }
  1075. if (isUnderscore) {
  1076. if (methodNames) {
  1077. exposeAssign = methodNames.indexOf('assign') > -1;
  1078. } else {
  1079. methodNames = underscoreMethods.slice();
  1080. }
  1081. }
  1082. // add method names explicitly by category
  1083. if (/category/.test(command)) {
  1084. // resolve method names belonging to each category (case-insensitive)
  1085. methodNames = command.match(/category=(\S*)/)[1].split(/, */).reduce(function(result, category) {
  1086. var capitalized = category[0].toUpperCase() + category.toLowerCase().slice(1);
  1087. return result.concat(getMethodsByCategory(capitalized));
  1088. }, methodNames || []);
  1089. }
  1090. // init `methodNames` if it hasn't been inited
  1091. if (!methodNames) {
  1092. methodNames = allMethods.slice();
  1093. }
  1094. if (/plus/.test(command)) {
  1095. methodNames = methodNames.concat(command.match(/plus=(\S*)/)[1].split(/, */));
  1096. }
  1097. if (/minus/.test(command)) {
  1098. methodNames = _.without.apply(_, [methodNames]
  1099. .concat(expandMethodNames(command.match(/minus=(\S*)/)[1].split(/, */))));
  1100. }
  1101. if (/exclude/.test(command)) {
  1102. methodNames = _.without.apply(_, [methodNames]
  1103. .concat(expandMethodNames(command.match(/exclude=(\S*)/)[1].split(/, */))));
  1104. }
  1105. // expand aliases and categories to real method names
  1106. methodNames = expandMethodNames(methodNames).reduce(function(result, methodName) {
  1107. return result.concat(methodName, getMethodsByCategory(methodName));
  1108. }, []);
  1109. // remove nonexistent and duplicate method names
  1110. methodNames = _.uniq(_.intersection(allMethods, expandMethodNames(methodNames)));
  1111. if (!exposeAssign) {
  1112. methodNames = _.without(methodNames, 'assign');
  1113. }
  1114. var lodash = context._ || {};
  1115. methodNames.forEach(function(methodName) {
  1116. testMethod(lodash, methodName, basename);
  1117. });
  1118. start();
  1119. });
  1120. });
  1121. });
  1122. });
  1123. }());
  1124. /*--------------------------------------------------------------------------*/
  1125. if (timeLimit > 0) {
  1126. setTimeout(function() {
  1127. process.exit(QUnit.config.stats.bad ? 1 : 0);
  1128. }, timeLimit);
  1129. }
  1130. // explicitly call `QUnit.start()` for Narwhal, Node.js, Rhino, and RingoJS
  1131. if (!global.document) {
  1132. QUnit.start();
  1133. }
  1134. }());