;(function() { /** Used as a safe reference for `undefined` in pre-ES5 environments. */ var undefined; /** Used to detect when a function becomes hot. */ var HOT_COUNT = 150; /** Used as the size to cover large array optimizations. */ var LARGE_ARRAY_SIZE = 200; /** Used as the `TypeError` message for "Functions" methods. */ var FUNC_ERROR_TEXT = 'Expected a function'; /** Used as the maximum memoize cache size. */ var MAX_MEMOIZE_SIZE = 500; /** Used as references for various `Number` constants. */ var MAX_SAFE_INTEGER = 9007199254740991, MAX_INTEGER = 1.7976931348623157e+308; /** Used as references for the maximum length and index of an array. */ var MAX_ARRAY_LENGTH = 4294967295, MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1; /** `Object#toString` result references. */ var funcTag = '[object Function]', numberTag = '[object Number]', objectTag = '[object Object]'; /** Used as a reference to the global object. */ var root = (typeof global == 'object' && global) || this; /** Used to store lodash to test for bad extensions/shims. */ var lodashBizarro = root.lodashBizarro; /** Used for native method references. */ var arrayProto = Array.prototype, funcProto = Function.prototype, objectProto = Object.prototype, numberProto = Number.prototype, stringProto = String.prototype; /** Method and object shortcuts. */ var phantom = root.phantom, process = root.process, amd = root.define ? define.amd : undefined, args = toArgs([1, 2, 3]), argv = process ? process.argv : undefined, defineProperty = Object.defineProperty, document = phantom ? undefined : root.document, body = root.document ? root.document.body : undefined, create = Object.create, fnToString = funcProto.toString, freeze = Object.freeze, getSymbols = Object.getOwnPropertySymbols, identity = function(value) { return value; }, noop = function() {}, objToString = objectProto.toString, params = argv, push = arrayProto.push, realm = {}, slice = arrayProto.slice, strictArgs = (function() { 'use strict'; return arguments; }(1, 2, 3)); var ArrayBuffer = root.ArrayBuffer, Buffer = root.Buffer, Map = root.Map, Promise = root.Promise, Proxy = root.Proxy, Set = root.Set, Symbol = root.Symbol, Uint8Array = root.Uint8Array, WeakMap = root.WeakMap, WeakSet = root.WeakSet; var arrayBuffer = ArrayBuffer ? new ArrayBuffer(2) : undefined, map = Map ? new Map : undefined, promise = Promise ? Promise.resolve(1) : undefined, set = Set ? new Set : undefined, symbol = Symbol ? Symbol('a') : undefined, weakMap = WeakMap ? new WeakMap : undefined, weakSet = WeakSet ? new WeakSet : undefined; /** Math helpers. */ var add = function(x, y) { return x + y; }, doubled = function(n) { return n * 2; }, isEven = function(n) { return n % 2 == 0; }, square = function(n) { return n * n; }; /** Stub functions. */ var stubA = function() { return 'a'; }, stubB = function() { return 'b'; }, stubC = function() { return 'c'; }; var stubTrue = function() { return true; }, stubFalse = function() { return false; }; var stubNaN = function() { return NaN; }, stubNull = function() { return null; }; var stubZero = function() { return 0; }, stubOne = function() { return 1; }, stubTwo = function() { return 2; }, stubThree = function() { return 3; }, stubFour = function() { return 4; }; var stubArray = function() { return []; }, stubObject = function() { return {}; }, stubString = function() { return ''; }; /** List of Latin Unicode letters. */ var burredLetters = [ // Latin-1 Supplement letters. '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7', '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', '\xcf', '\xd0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xd8', '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde', '\xdf', '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7', '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee', '\xef', '\xf0', '\xf1', '\xf2', '\xf3', '\xf4', '\xf5', '\xf6', '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xff', // Latin Extended-A letters. '\u0100', '\u0101', '\u0102', '\u0103', '\u0104', '\u0105', '\u0106', '\u0107', '\u0108', '\u0109', '\u010a', '\u010b', '\u010c', '\u010d', '\u010e', '\u010f', '\u0110', '\u0111', '\u0112', '\u0113', '\u0114', '\u0115', '\u0116', '\u0117', '\u0118', '\u0119', '\u011a', '\u011b', '\u011c', '\u011d', '\u011e', '\u011f', '\u0120', '\u0121', '\u0122', '\u0123', '\u0124', '\u0125', '\u0126', '\u0127', '\u0128', '\u0129', '\u012a', '\u012b', '\u012c', '\u012d', '\u012e', '\u012f', '\u0130', '\u0131', '\u0132', '\u0133', '\u0134', '\u0135', '\u0136', '\u0137', '\u0138', '\u0139', '\u013a', '\u013b', '\u013c', '\u013d', '\u013e', '\u013f', '\u0140', '\u0141', '\u0142', '\u0143', '\u0144', '\u0145', '\u0146', '\u0147', '\u0148', '\u0149', '\u014a', '\u014b', '\u014c', '\u014d', '\u014e', '\u014f', '\u0150', '\u0151', '\u0152', '\u0153', '\u0154', '\u0155', '\u0156', '\u0157', '\u0158', '\u0159', '\u015a', '\u015b', '\u015c', '\u015d', '\u015e', '\u015f', '\u0160', '\u0161', '\u0162', '\u0163', '\u0164', '\u0165', '\u0166', '\u0167', '\u0168', '\u0169', '\u016a', '\u016b', '\u016c', '\u016d', '\u016e', '\u016f', '\u0170', '\u0171', '\u0172', '\u0173', '\u0174', '\u0175', '\u0176', '\u0177', '\u0178', '\u0179', '\u017a', '\u017b', '\u017c', '\u017d', '\u017e', '\u017f' ]; /** List of combining diacritical marks. */ var comboMarks = [ '\u0300', '\u0301', '\u0302', '\u0303', '\u0304', '\u0305', '\u0306', '\u0307', '\u0308', '\u0309', '\u030a', '\u030b', '\u030c', '\u030d', '\u030e', '\u030f', '\u0310', '\u0311', '\u0312', '\u0313', '\u0314', '\u0315', '\u0316', '\u0317', '\u0318', '\u0319', '\u031a', '\u031b', '\u031c', '\u031d', '\u031e', '\u031f', '\u0320', '\u0321', '\u0322', '\u0323', '\u0324', '\u0325', '\u0326', '\u0327', '\u0328', '\u0329', '\u032a', '\u032b', '\u032c', '\u032d', '\u032e', '\u032f', '\u0330', '\u0331', '\u0332', '\u0333', '\u0334', '\u0335', '\u0336', '\u0337', '\u0338', '\u0339', '\u033a', '\u033b', '\u033c', '\u033d', '\u033e', '\u033f', '\u0340', '\u0341', '\u0342', '\u0343', '\u0344', '\u0345', '\u0346', '\u0347', '\u0348', '\u0349', '\u034a', '\u034b', '\u034c', '\u034d', '\u034e', '\u034f', '\u0350', '\u0351', '\u0352', '\u0353', '\u0354', '\u0355', '\u0356', '\u0357', '\u0358', '\u0359', '\u035a', '\u035b', '\u035c', '\u035d', '\u035e', '\u035f', '\u0360', '\u0361', '\u0362', '\u0363', '\u0364', '\u0365', '\u0366', '\u0367', '\u0368', '\u0369', '\u036a', '\u036b', '\u036c', '\u036d', '\u036e', '\u036f', '\ufe20', '\ufe21', '\ufe22', '\ufe23' ]; /** List of converted Latin Unicode letters. */ var deburredLetters = [ // Converted Latin-1 Supplement letters. 'A', 'A', 'A', 'A', 'A', 'A', 'Ae', 'C', 'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I', 'D', 'N', 'O', 'O', 'O', 'O', 'O', 'O', 'U', 'U', 'U', 'U', 'Y', 'Th', 'ss', 'a', 'a', 'a', 'a', 'a', 'a', 'ae', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i', 'd', 'n', 'o', 'o', 'o', 'o', 'o', 'o', 'u', 'u', 'u', 'u', 'y', 'th', 'y', // Converted Latin Extended-A letters. 'A', 'a', 'A', 'a', 'A', 'a', 'C', 'c', 'C', 'c', 'C', 'c', 'C', 'c', 'D', 'd', 'D', 'd', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'G', 'g', 'G', 'g', 'G', 'g', 'G', 'g', 'H', 'h', 'H', 'h', 'I', 'i', 'I', 'i', 'I', 'i', 'I', 'i', 'I', 'i', 'IJ', 'ij', 'J', 'j', 'K', 'k', 'k', 'L', 'l', 'L', 'l', 'L', 'l', 'L', 'l', 'L', 'l', 'N', 'n', 'N', 'n', 'N', 'n', "'n", 'N', 'n', 'O', 'o', 'O', 'o', 'O', 'o', 'Oe', 'oe', 'R', 'r', 'R', 'r', 'R', 'r', 'S', 's', 'S', 's', 'S', 's', 'S', 's', 'T', 't', 'T', 't', 'T', 't', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'W', 'w', 'Y', 'y', 'Y', 'Z', 'z', 'Z', 'z', 'Z', 'z', 's' ]; /** Used to provide falsey values to methods. */ var falsey = [, null, undefined, false, 0, NaN, '']; /** Used to specify the emoji style glyph variant of characters. */ var emojiVar = '\ufe0f'; /** Used to provide empty values to methods. */ var empties = [[], {}].concat(falsey.slice(1)); /** Used to test error objects. */ var errors = [ new Error, new EvalError, new RangeError, new ReferenceError, new SyntaxError, new TypeError, new URIError ]; /** List of fitzpatrick modifiers. */ var fitzModifiers = [ '\ud83c\udffb', '\ud83c\udffc', '\ud83c\udffd', '\ud83c\udffe', '\ud83c\udfff' ]; /** Used to provide primitive values to methods. */ var primitives = [null, undefined, false, true, 1, NaN, 'a']; /** Used to check whether methods support typed arrays. */ var typedArrays = [ 'Float32Array', 'Float64Array', 'Int8Array', 'Int16Array', 'Int32Array', 'Uint8Array', 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array' ]; /** Used to check whether methods support array views. */ var arrayViews = typedArrays.concat('DataView'); /** The file path of the lodash file to test. */ var filePath = (function() { var min = 2, result = params || []; if (phantom) { min = 0; result = params = phantom.args || require('system').args; } var last = result[result.length - 1]; result = (result.length > min && !/test(?:\.js)?$/.test(last)) ? last : '../lodash.js'; if (!amd) { try { result = require('fs').realpathSync(result); } catch (e) {} try { result = require.resolve(result); } catch (e) {} } return result; }()); /** The `ui` object. */ var ui = root.ui || (root.ui = { 'buildPath': filePath, 'loaderPath': '', 'isModularize': /\b(?:amd|commonjs|es|node|npm|(index|main)\.js)\b/.test(filePath), 'isStrict': /\bes\b/.test(filePath) || 'default' in require(filePath), 'urlParams': {} }); /** The basename of the lodash file to test. */ var basename = /[\w.-]+$/.exec(filePath)[0]; /** Used to indicate testing a modularized build. */ var isModularize = ui.isModularize; /** Detect if testing `npm` modules. */ var isNpm = isModularize && /\bnpm\b/.test([ui.buildPath, ui.urlParams.build]); /** Detect if running in PhantomJS. */ var isPhantom = phantom || (typeof callPhantom == 'function'); /** Detect if lodash is in strict mode. */ var isStrict = ui.isStrict; /*--------------------------------------------------------------------------*/ // Leak to avoid sporadic `noglobals` fails on Edge in Sauce Labs. root.msWDfn = undefined; // Assign `setTimeout` to itself to avoid being flagged as a leak. setProperty(root, 'setTimeout', setTimeout); // Exit early if going to run tests in a PhantomJS web page. if (phantom && isModularize) { var page = require('webpage').create(); page.onCallback = function(details) { var coverage = details.coverage; if (coverage) { var fs = require('fs'), cwd = fs.workingDirectory, sep = fs.separator; fs.write([cwd, 'coverage', 'coverage.json'].join(sep), JSON.stringify(coverage)); } phantom.exit(details.failed ? 1 : 0); }; page.onConsoleMessage = function(message) { console.log(message); }; page.onInitialized = function() { page.evaluate(function() { document.addEventListener('DOMContentLoaded', function() { QUnit.done(function(details) { details.coverage = window.__coverage__; callPhantom(details); }); }); }); }; page.open(filePath, function(status) { if (status != 'success') { console.log('PhantomJS failed to load page: ' + filePath); phantom.exit(1); } }); console.log('test.js invoked with arguments: ' + JSON.stringify(slice.call(params))); return; } /*--------------------------------------------------------------------------*/ /** Used to test Web Workers. */ var Worker = !(ui.isForeign || ui.isSauceLabs || isModularize) && (document && document.origin != 'null') && root.Worker; /** Used to test host objects in IE. */ try { var xml = new ActiveXObject('Microsoft.XMLDOM'); } catch (e) {} /** Poison the free variable `root` in Node.js */ try { defineProperty(global.root, 'root', { 'configurable': false, 'enumerable': false, 'get': function() { throw new ReferenceError; } }); } catch (e) {} /** Load QUnit and extras. */ var QUnit = root.QUnit || require('qunit-extras'); /** Load stable Lodash. */ var lodashStable = root.lodashStable; if (!lodashStable) { try { lodashStable = interopRequire('../node_modules/lodash/lodash.js'); } catch (e) { console.log('Error: The stable lodash dev dependency should be at least a version behind master branch.'); return; } lodashStable = lodashStable.noConflict(); } /** The `lodash` function to test. */ var _ = root._ || (root._ = interopRequire(filePath)); /** Used to test pseudo private map caches. */ var mapCaches = (function() { var MapCache = (_.memoize || lodashStable.memoize).Cache; var result = { 'Hash': new MapCache().__data__.hash.constructor, 'MapCache': MapCache }; (_.isMatchWith || lodashStable.isMatchWith)({ 'a': 1 }, { 'a': 1 }, function() { var stack = lodashStable.last(arguments); result.ListCache = stack.__data__.constructor; result.Stack = stack.constructor; }); return result; }()); /** Used to detect instrumented istanbul code coverage runs. */ var coverage = root.__coverage__ || root[lodashStable.find(lodashStable.keys(root), function(key) { return /^(?:\$\$cov_\d+\$\$)$/.test(key); })]; /** Used to test async functions. */ var asyncFunc = lodashStable.attempt(function() { return Function('return async () => {}'); }); /** Used to test generator functions. */ var genFunc = lodashStable.attempt(function() { return Function('return function*(){}'); }); /** Used to restore the `_` reference. */ var oldDash = root._; /** * Used to check for problems removing whitespace. For a whitespace reference, * see [V8's unit test](https://code.google.com/p/v8/source/browse/branches/bleeding_edge/test/mjsunit/whitespaces.js). */ var whitespace = lodashStable.filter([ // Basic whitespace characters. ' ', '\t', '\x0b', '\f', '\xa0', '\ufeff', // Line terminators. '\n', '\r', '\u2028', '\u2029', // Unicode category "Zs" space separators. '\u1680', '\u180e', '\u2000', '\u2001', '\u2002', '\u2003', '\u2004', '\u2005', '\u2006', '\u2007', '\u2008', '\u2009', '\u200a', '\u202f', '\u205f', '\u3000' ], function(chr) { return /\s/.exec(chr); }) .join(''); /** * Creates a custom error object. * * @private * @constructor * @param {string} message The error message. */ function CustomError(message) { this.name = 'CustomError'; this.message = message; } CustomError.prototype = lodashStable.create(Error.prototype, { 'constructor': CustomError }); /** * Removes all own enumerable string keyed properties from a given object. * * @private * @param {Object} object The object to empty. */ function emptyObject(object) { lodashStable.forOwn(object, function(value, key, object) { delete object[key]; }); } /** * Extracts the unwrapped value from its wrapper. * * @private * @param {Object} wrapper The wrapper to unwrap. * @returns {*} Returns the unwrapped value. */ function getUnwrappedValue(wrapper) { var index = -1, actions = wrapper.__actions__, length = actions.length, result = wrapper.__wrapped__; while (++index < length) { var args = [result], action = actions[index]; push.apply(args, action.args); result = action.func.apply(action.thisArg, args); } return result; } /** * Loads the module of `id`. If the module has an `exports.default`, the * exported default value is returned as the resolved module. * * @private * @param {string} id The identifier of the module to resolve. * @returns {*} Returns the resolved module. */ function interopRequire(id) { var result = require(id); return 'default' in result ? result['default'] : result; } /** * Sets a non-enumerable property value on `object`. * * Note: This function is used to avoid a bug in older versions of V8 where * overwriting non-enumerable built-ins makes them enumerable. * See https://code.google.com/p/v8/issues/detail?id=1623 * * @private * @param {Object} object The object modify. * @param {string} key The name of the property to set. * @param {*} value The property value. */ function setProperty(object, key, value) { try { defineProperty(object, key, { 'configurable': true, 'enumerable': false, 'writable': true, 'value': value }); } catch (e) { object[key] = value; } return object; } /** * Skips a given number of tests with a passing result. * * @private * @param {Object} assert The QUnit assert object. * @param {number} [count=1] The number of tests to skip. */ function skipAssert(assert, count) { count || (count = 1); while (count--) { assert.ok(true, 'test skipped'); } } /** * Converts `array` to an `arguments` object. * * @private * @param {Array} array The array to convert. * @returns {Object} Returns the converted `arguments` object. */ function toArgs(array) { return (function() { return arguments; }.apply(undefined, array)); } /*--------------------------------------------------------------------------*/ // Add bizarro values. (function() { if (document || (typeof require != 'function')) { return; } var nativeString = fnToString.call(toString), reToString = /toString/g; function createToString(funcName) { return lodashStable.constant(nativeString.replace(reToString, funcName)); } // Allow bypassing native checks. setProperty(funcProto, 'toString', function wrapper() { setProperty(funcProto, 'toString', fnToString); var result = lodashStable.has(this, 'toString') ? this.toString() : fnToString.call(this); setProperty(funcProto, 'toString', wrapper); return result; }); // Add prototype extensions. funcProto._method = noop; // Set bad shims. setProperty(Object, 'create', undefined); setProperty(Object, 'getOwnPropertySymbols', undefined); var _propertyIsEnumerable = objectProto.propertyIsEnumerable; setProperty(objectProto, 'propertyIsEnumerable', function(key) { return !(key == 'valueOf' && this && this.valueOf === 1) && _propertyIsEnumerable.call(this, key); }); if (Buffer) { defineProperty(root, 'Buffer', { 'configurable': true, 'enumerable': true, 'get': function get() { var caller = get.caller, name = caller ? caller.name : ''; if (!(name == 'runInContext' || name.length == 1 || /\b_\.isBuffer\b/.test(caller))) { return Buffer; } } }); } if (Map) { setProperty(root, 'Map', (function() { var count = 0; return function() { if (count++) { return new Map; } setProperty(root, 'Map', Map); return {}; }; }())); setProperty(root.Map, 'toString', createToString('Map')); } setProperty(root, 'Promise', noop); setProperty(root, 'Set', noop); setProperty(root, 'Symbol', undefined); setProperty(root, 'WeakMap', noop); // Fake `WinRTError`. setProperty(root, 'WinRTError', Error); // Clear cache so lodash can be reloaded. emptyObject(require.cache); // Load lodash and expose it to the bad extensions/shims. lodashBizarro = interopRequire(filePath); root._ = oldDash; // Restore built-in methods. setProperty(Object, 'create', create); setProperty(objectProto, 'propertyIsEnumerable', _propertyIsEnumerable); setProperty(root, 'Buffer', Buffer); if (getSymbols) { Object.getOwnPropertySymbols = getSymbols; } else { delete Object.getOwnPropertySymbols; } if (Map) { setProperty(root, 'Map', Map); } else { delete root.Map; } if (Promise) { setProperty(root, 'Promise', Promise); } else { delete root.Promise; } if (Set) { setProperty(root, 'Set', Set); } else { delete root.Set; } if (Symbol) { setProperty(root, 'Symbol', Symbol); } else { delete root.Symbol; } if (WeakMap) { setProperty(root, 'WeakMap', WeakMap); } else { delete root.WeakMap; } delete root.WinRTError; delete funcProto._method; }()); // Add other realm values from the `vm` module. lodashStable.attempt(function() { lodashStable.assign(realm, require('vm').runInNewContext([ '(function() {', ' var noop = function() {},', ' root = this;', '', ' var object = {', " 'ArrayBuffer': root.ArrayBuffer,", " 'arguments': (function() { return arguments; }(1, 2, 3)),", " 'array': [1],", " 'arrayBuffer': root.ArrayBuffer ? new root.ArrayBuffer : undefined,", " 'boolean': Object(false),", " 'date': new Date,", " 'errors': [new Error, new EvalError, new RangeError, new ReferenceError, new SyntaxError, new TypeError, new URIError],", " 'function': noop,", " 'map': root.Map ? new root.Map : undefined,", " 'nan': NaN,", " 'null': null,", " 'number': Object(0),", " 'object': { 'a': 1 },", " 'promise': root.Promise ? Promise.resolve(1) : undefined,", " 'regexp': /x/,", " 'set': root.Set ? new root.Set : undefined,", " 'string': Object('a'),", " 'symbol': root.Symbol ? root.Symbol() : undefined,", " 'undefined': undefined,", " 'weakMap': root.WeakMap ? new root.WeakMap : undefined,", " 'weakSet': root.WeakSet ? new root.WeakSet : undefined", ' };', '', " ['" + arrayViews.join("', '") + "'].forEach(function(type) {", ' var Ctor = root[type]', ' object[type] = Ctor;', ' object[type.toLowerCase()] = Ctor ? new Ctor(new ArrayBuffer(24)) : undefined;', ' });', '', ' return object;', '}());' ].join('\n'))); }); // Add other realm values from an iframe. lodashStable.attempt(function() { _._realm = realm; var iframe = document.createElement('iframe'); iframe.frameBorder = iframe.height = iframe.width = 0; body.appendChild(iframe); var idoc = (idoc = iframe.contentDocument || iframe.contentWindow).document || idoc; idoc.write([ '', '', '', '', '' ].join('\n')); idoc.close(); delete _._realm; }); // Add a web worker. lodashStable.attempt(function() { var worker = new Worker('./asset/worker.js?t=' + (+new Date)); worker.addEventListener('message', function(e) { _._VERSION = e.data || ''; }, false); worker.postMessage(ui.buildPath); }); // Expose internal modules for better code coverage. lodashStable.attempt(function() { var path = require('path'), basePath = path.dirname(filePath); if (isModularize && !(amd || isNpm)) { lodashStable.each([ 'baseEach', 'isIndex', 'isIterateeCall', 'memoizeCapped' ], function(funcName) { _['_' + funcName] = interopRequire(path.join(basePath, '_' + funcName)); }); } }); /*--------------------------------------------------------------------------*/ if (params) { console.log('Running lodash tests.'); console.log('test.js invoked with arguments: ' + JSON.stringify(slice.call(params))); } QUnit.module(basename); (function() { QUnit.test('should support loading ' + basename + ' as the "lodash" module', function(assert) { assert.expect(1); if (amd) { assert.strictEqual((lodashModule || {}).moduleName, 'lodash'); } else { skipAssert(assert); } }); QUnit.test('should support loading ' + basename + ' with the Require.js "shim" configuration option', function(assert) { assert.expect(1); if (amd && lodashStable.includes(ui.loaderPath, 'requirejs')) { assert.strictEqual((shimmedModule || {}).moduleName, 'shimmed'); } else { skipAssert(assert); } }); QUnit.test('should support loading ' + basename + ' as the "underscore" module', function(assert) { assert.expect(1); if (amd) { assert.strictEqual((underscoreModule || {}).moduleName, 'underscore'); } else { skipAssert(assert); } }); QUnit.test('should support loading ' + basename + ' in a web worker', function(assert) { assert.expect(1); var done = assert.async(); if (Worker) { var limit = 30000 / QUnit.config.asyncRetries, start = +new Date; var attempt = function() { var actual = _._VERSION; if ((new Date - start) < limit && typeof actual != 'string') { setTimeout(attempt, 16); return; } assert.strictEqual(actual, _.VERSION); done(); }; attempt(); } else { skipAssert(assert); done(); } }); QUnit.test('should not add `Function.prototype` extensions to lodash', function(assert) { assert.expect(1); if (lodashBizarro) { assert.notOk('_method' in lodashBizarro); } else { skipAssert(assert); } }); QUnit.test('should avoid non-native built-ins', function(assert) { assert.expect(6); function message(lodashMethod, nativeMethod) { return '`' + lodashMethod + '` should avoid overwritten native `' + nativeMethod + '`'; } function Foo() { this.a = 1; } Foo.prototype.b = 2; var object = { 'a': 1 }, otherObject = { 'b': 2 }, largeArray = lodashStable.times(LARGE_ARRAY_SIZE, lodashStable.constant(object)); if (lodashBizarro) { try { var actual = lodashBizarro.create(Foo.prototype); } catch (e) { actual = null; } var label = message('_.create', 'Object.create'); assert.ok(actual instanceof Foo, label); try { actual = [ lodashBizarro.difference([object, otherObject], largeArray), lodashBizarro.intersection(largeArray, [object]), lodashBizarro.uniq(largeArray) ]; } catch (e) { actual = null; } label = message('_.difference`, `_.intersection`, and `_.uniq', 'Map'); assert.deepEqual(actual, [[otherObject], [object], [object]], label); try { if (Symbol) { object[symbol] = {}; } actual = [ lodashBizarro.clone(object), lodashBizarro.cloneDeep(object) ]; } catch (e) { actual = null; } label = message('_.clone` and `_.cloneDeep', 'Object.getOwnPropertySymbols'); assert.deepEqual(actual, [object, object], label); try { // Avoid buggy symbol detection in Babel's `_typeof` helper. var symObject = setProperty(Object(symbol), 'constructor', Object); actual = [ Symbol ? lodashBizarro.clone(symObject) : {}, Symbol ? lodashBizarro.isEqual(symObject, Object(symbol)) : false, Symbol ? lodashBizarro.toString(symObject) : '' ]; } catch (e) { actual = null; } label = message('_.clone`, `_.isEqual`, and `_.toString', 'Symbol'); assert.deepEqual(actual, [{}, false, ''], label); try { var map = new lodashBizarro.memoize.Cache; actual = map.set('a', 1).get('a'); } catch (e) { actual = null; } label = message('_.memoize.Cache', 'Map'); assert.deepEqual(actual, 1, label); try { map = new (Map || Object); if (Symbol && Symbol.iterator) { map[Symbol.iterator] = null; } actual = lodashBizarro.toArray(map); } catch (e) { actual = null; } label = message('_.toArray', 'Map'); assert.deepEqual(actual, [], label); } else { skipAssert(assert, 6); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('isIndex'); (function() { var func = _._isIndex; QUnit.test('should return `true` for indexes', function(assert) { assert.expect(1); if (func) { var values = [[0], ['0'], ['1'], [3, 4], [MAX_SAFE_INTEGER - 1]], expected = lodashStable.map(values, stubTrue); var actual = lodashStable.map(values, function(args) { return func.apply(undefined, args); }); assert.deepEqual(actual, expected); } else { skipAssert(assert); } }); QUnit.test('should return `false` for non-indexes', function(assert) { assert.expect(1); if (func) { var values = [['1abc'], ['07'], ['0001'], [-1], [3, 3], [1.1], [MAX_SAFE_INTEGER]], expected = lodashStable.map(values, stubFalse); var actual = lodashStable.map(values, function(args) { return func.apply(undefined, args); }); assert.deepEqual(actual, expected); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('isIterateeCall'); (function() { var array = [1], func = _._isIterateeCall, object = { 'a': 1 }; QUnit.test('should return `true` for iteratee calls', function(assert) { assert.expect(3); function Foo() {} Foo.prototype.a = 1; if (func) { assert.strictEqual(func(1, 0, array), true); assert.strictEqual(func(1, 'a', object), true); assert.strictEqual(func(1, 'a', new Foo), true); } else { skipAssert(assert, 3); } }); QUnit.test('should return `false` for non-iteratee calls', function(assert) { assert.expect(4); if (func) { assert.strictEqual(func(2, 0, array), false); assert.strictEqual(func(1, 1.1, array), false); assert.strictEqual(func(1, 0, { 'length': MAX_SAFE_INTEGER + 1 }), false); assert.strictEqual(func(1, 'b', object), false); } else { skipAssert(assert, 4); } }); QUnit.test('should work with `NaN` values', function(assert) { assert.expect(2); if (func) { assert.strictEqual(func(NaN, 0, [NaN]), true); assert.strictEqual(func(NaN, 'a', { 'a': NaN }), true); } else { skipAssert(assert, 2); } }); QUnit.test('should not error when `index` is an object without a `toString` method', function(assert) { assert.expect(1); if (func) { try { var actual = func(1, { 'toString': null }, [1]); } catch (e) { var message = e.message; } assert.strictEqual(actual, false, message || ''); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('map caches'); (function() { var keys = [null, undefined, false, true, 1, -Infinity, NaN, {}, 'a', symbol || noop]; var pairs = lodashStable.map(keys, function(key, index) { var lastIndex = keys.length - 1; return [key, keys[lastIndex - index]]; }); function createCaches(pairs) { var largeStack = new mapCaches.Stack(pairs), length = pairs ? pairs.length : 0; lodashStable.times(LARGE_ARRAY_SIZE - length, function() { largeStack.set({}, {}); }); return { 'hashes': new mapCaches.Hash(pairs), 'list caches': new mapCaches.ListCache(pairs), 'map caches': new mapCaches.MapCache(pairs), 'stack caches': new mapCaches.Stack(pairs), 'large stacks': largeStack }; } lodashStable.forOwn(createCaches(pairs), function(cache, kind) { var isLarge = /^large/.test(kind); QUnit.test('should implement a `Map` interface for ' + kind, function(assert) { assert.expect(83); lodashStable.each(keys, function(key, index) { var value = pairs[index][1]; assert.deepEqual(cache.get(key), value); assert.strictEqual(cache.has(key), true); assert.strictEqual(cache.delete(key), true); assert.strictEqual(cache.has(key), false); assert.strictEqual(cache.get(key), undefined); assert.strictEqual(cache.delete(key), false); assert.strictEqual(cache.set(key, value), cache); assert.strictEqual(cache.has(key), true); }); assert.strictEqual(cache.size, isLarge ? LARGE_ARRAY_SIZE : keys.length); assert.strictEqual(cache.clear(), undefined); assert.ok(lodashStable.every(keys, function(key) { return !cache.has(key); })); }); }); lodashStable.forOwn(createCaches(), function(cache, kind) { QUnit.test('should support changing values of ' + kind, function(assert) { assert.expect(10); lodashStable.each(keys, function(key) { cache.set(key, 1).set(key, 2); assert.strictEqual(cache.get(key), 2); }); }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash constructor'); (function() { var values = empties.concat(true, 1, 'a'), expected = lodashStable.map(values, stubTrue); QUnit.test('should create a new instance when called without the `new` operator', function(assert) { assert.expect(1); if (!isNpm) { var actual = lodashStable.map(values, function(value) { return _(value) instanceof _; }); assert.deepEqual(actual, expected); } else { skipAssert(assert); } }); QUnit.test('should return the given `lodash` instances', function(assert) { assert.expect(1); if (!isNpm) { var actual = lodashStable.map(values, function(value) { var wrapped = _(value); return _(wrapped) === wrapped; }); assert.deepEqual(actual, expected); } else { skipAssert(assert); } }); QUnit.test('should convert foreign wrapped values to `lodash` instances', function(assert) { assert.expect(1); if (!isNpm && lodashBizarro) { var actual = lodashStable.map(values, function(value) { var wrapped = _(lodashBizarro(value)), unwrapped = wrapped.value(); return wrapped instanceof _ && ((unwrapped === value) || (unwrapped !== unwrapped && value !== value)); }); assert.deepEqual(actual, expected); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.add'); (function() { QUnit.test('should add two numbers', function(assert) { assert.expect(3); assert.strictEqual(_.add(6, 4), 10); assert.strictEqual(_.add(-6, 4), -2); assert.strictEqual(_.add(-6, -4), -10); }); QUnit.test('should not coerce arguments to numbers', function(assert) { assert.expect(2); assert.strictEqual(_.add('6', '4'), '64'); assert.strictEqual(_.add('x', 'y'), 'xy'); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.after'); (function() { function after(n, times) { var count = 0; lodashStable.times(times, _.after(n, function() { count++; })); return count; } QUnit.test('should create a function that invokes `func` after `n` calls', function(assert) { assert.expect(4); assert.strictEqual(after(5, 5), 1, 'after(n) should invoke `func` after being called `n` times'); assert.strictEqual(after(5, 4), 0, 'after(n) should not invoke `func` before being called `n` times'); assert.strictEqual(after(0, 0), 0, 'after(0) should not invoke `func` immediately'); assert.strictEqual(after(0, 1), 1, 'after(0) should invoke `func` when called once'); }); QUnit.test('should coerce `n` values of `NaN` to `0`', function(assert) { assert.expect(1); assert.strictEqual(after(NaN, 1), 1); }); QUnit.test('should use `this` binding of function', function(assert) { assert.expect(2); var after = _.after(1, function(assert) { return ++this.count; }), object = { 'after': after, 'count': 0 }; object.after(); assert.strictEqual(object.after(), 2); assert.strictEqual(object.count, 2); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.ary'); (function() { function fn(a, b, c) { return slice.call(arguments); } QUnit.test('should cap the number of arguments provided to `func`', function(assert) { assert.expect(2); var actual = lodashStable.map(['6', '8', '10'], _.ary(parseInt, 1)); assert.deepEqual(actual, [6, 8, 10]); var capped = _.ary(fn, 2); assert.deepEqual(capped('a', 'b', 'c', 'd'), ['a', 'b']); }); QUnit.test('should use `func.length` if `n` is not given', function(assert) { assert.expect(1); var capped = _.ary(fn); assert.deepEqual(capped('a', 'b', 'c', 'd'), ['a', 'b', 'c']); }); QUnit.test('should treat a negative `n` as `0`', function(assert) { assert.expect(1); var capped = _.ary(fn, -1); try { var actual = capped('a'); } catch (e) {} assert.deepEqual(actual, []); }); QUnit.test('should coerce `n` to an integer', function(assert) { assert.expect(1); var values = ['1', 1.6, 'xyz'], expected = [['a'], ['a'], []]; var actual = lodashStable.map(values, function(n) { var capped = _.ary(fn, n); return capped('a', 'b'); }); assert.deepEqual(actual, expected); }); QUnit.test('should not force a minimum argument count', function(assert) { assert.expect(1); var args = ['a', 'b', 'c'], capped = _.ary(fn, 3); var expected = lodashStable.map(args, function(arg, index) { return args.slice(0, index); }); var actual = lodashStable.map(expected, function(array) { return capped.apply(undefined, array); }); assert.deepEqual(actual, expected); }); QUnit.test('should use `this` binding of function', function(assert) { assert.expect(1); var capped = _.ary(function(a, b) { return this; }, 1), object = { 'capped': capped }; assert.strictEqual(object.capped(), object); }); QUnit.test('should use the existing `ary` if smaller', function(assert) { assert.expect(1); var capped = _.ary(_.ary(fn, 1), 2); assert.deepEqual(capped('a', 'b', 'c'), ['a']); }); QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(1); var funcs = lodashStable.map([fn], _.ary), actual = funcs[0]('a', 'b', 'c'); assert.deepEqual(actual, ['a', 'b', 'c']); }); QUnit.test('should work when combined with other methods that use metadata', function(assert) { assert.expect(2); var array = ['a', 'b', 'c'], includes = _.curry(_.rearg(_.ary(_.includes, 2), 1, 0), 2); assert.strictEqual(includes('b')(array, 2), true); if (!isNpm) { includes = _(_.includes).ary(2).rearg(1, 0).curry(2).value(); assert.strictEqual(includes('b')(array, 2), true); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.assignIn'); (function() { QUnit.test('should be aliased', function(assert) { assert.expect(1); assert.strictEqual(_.extend, _.assignIn); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.assign and lodash.assignIn'); lodashStable.each(['assign', 'assignIn'], function(methodName) { var func = _[methodName]; QUnit.test('`_.' + methodName + '` should assign source properties to `object`', function(assert) { assert.expect(1); assert.deepEqual(func({ 'a': 1 }, { 'b': 2 }), { 'a': 1, 'b': 2 }); }); QUnit.test('`_.' + methodName + '` should accept multiple sources', function(assert) { assert.expect(2); var expected = { 'a': 1, 'b': 2, 'c': 3 }; assert.deepEqual(func({ 'a': 1 }, { 'b': 2 }, { 'c': 3 }), expected); assert.deepEqual(func({ 'a': 1 }, { 'b': 2, 'c': 2 }, { 'c': 3 }), expected); }); QUnit.test('`_.' + methodName + '` should overwrite destination properties', function(assert) { assert.expect(1); var expected = { 'a': 3, 'b': 2, 'c': 1 }; assert.deepEqual(func({ 'a': 1, 'b': 2 }, expected), expected); }); QUnit.test('`_.' + methodName + '` should assign source properties with nullish values', function(assert) { assert.expect(1); var expected = { 'a': null, 'b': undefined, 'c': null }; assert.deepEqual(func({ 'a': 1, 'b': 2 }, expected), expected); }); QUnit.test('`_.' + methodName + '` should skip assignments if values are the same', function(assert) { assert.expect(1); var object = {}; var descriptor = { 'configurable': true, 'enumerable': true, 'set': function() { throw new Error; } }; var source = { 'a': 1, 'b': undefined, 'c': NaN, 'd': undefined, 'constructor': Object, 'toString': lodashStable.constant('source') }; defineProperty(object, 'a', lodashStable.assign({}, descriptor, { 'get': stubOne })); defineProperty(object, 'b', lodashStable.assign({}, descriptor, { 'get': noop })); defineProperty(object, 'c', lodashStable.assign({}, descriptor, { 'get': stubNaN })); defineProperty(object, 'constructor', lodashStable.assign({}, descriptor, { 'get': lodashStable.constant(Object) })); try { var actual = func(object, source); } catch (e) {} assert.deepEqual(actual, source); }); QUnit.test('`_.' + methodName + '` should treat sparse array sources as dense', function(assert) { assert.expect(1); var array = [1]; array[2] = 3; assert.deepEqual(func({}, array), { '0': 1, '1': undefined, '2': 3 }); }); QUnit.test('`_.' + methodName + '` should assign values of prototype objects', function(assert) { assert.expect(1); function Foo() {} Foo.prototype.a = 1; assert.deepEqual(func({}, Foo.prototype), { 'a': 1 }); }); QUnit.test('`_.' + methodName + '` should coerce string sources to objects', function(assert) { assert.expect(1); assert.deepEqual(func({}, 'a'), { '0': 'a' }); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.assignInWith'); (function() { QUnit.test('should be aliased', function(assert) { assert.expect(1); assert.strictEqual(_.extendWith, _.assignInWith); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.assignWith and lodash.assignInWith'); lodashStable.each(['assignWith', 'assignInWith'], function(methodName) { var func = _[methodName]; QUnit.test('`_.' + methodName + '` should work with a `customizer` callback', function(assert) { assert.expect(1); var actual = func({ 'a': 1, 'b': 2 }, { 'a': 3, 'c': 3 }, function(a, b) { return a === undefined ? b : a; }); assert.deepEqual(actual, { 'a': 1, 'b': 2, 'c': 3 }); }); QUnit.test('`_.' + methodName + '` should work with a `customizer` that returns `undefined`', function(assert) { assert.expect(1); var expected = { 'a': 1 }; assert.deepEqual(func({}, expected, noop), expected); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.at'); (function() { var array = ['a', 'b', 'c'], object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; QUnit.test('should return the elements corresponding to the specified keys', function(assert) { assert.expect(1); var actual = _.at(array, [0, 2]); assert.deepEqual(actual, ['a', 'c']); }); QUnit.test('should return `undefined` for nonexistent keys', function(assert) { assert.expect(1); var actual = _.at(array, [2, 4, 0]); assert.deepEqual(actual, ['c', undefined, 'a']); }); QUnit.test('should work with non-index keys on array values', function(assert) { assert.expect(1); var values = lodashStable.reject(empties, function(value) { return (value === 0) || lodashStable.isArray(value); }).concat(-1, 1.1); var array = lodashStable.transform(values, function(result, value) { result[value] = 1; }, []); var expected = lodashStable.map(values, stubOne), actual = _.at(array, values); assert.deepEqual(actual, expected); }); QUnit.test('should return an empty array when no keys are given', function(assert) { assert.expect(2); assert.deepEqual(_.at(array), []); assert.deepEqual(_.at(array, [], []), []); }); QUnit.test('should accept multiple key arguments', function(assert) { assert.expect(1); var actual = _.at(['a', 'b', 'c', 'd'], 3, 0, 2); assert.deepEqual(actual, ['d', 'a', 'c']); }); QUnit.test('should work with a falsey `object` when keys are given', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, lodashStable.constant(Array(4))); var actual = lodashStable.map(falsey, function(object) { try { return _.at(object, 0, 1, 'pop', 'push'); } catch (e) {} }); assert.deepEqual(actual, expected); }); QUnit.test('should work with an `arguments` object for `object`', function(assert) { assert.expect(1); var actual = _.at(args, [2, 0]); assert.deepEqual(actual, [3, 1]); }); QUnit.test('should work with `arguments` object as secondary arguments', function(assert) { assert.expect(1); var actual = _.at([1, 2, 3, 4, 5], args); assert.deepEqual(actual, [2, 3, 4]); }); QUnit.test('should work with an object for `object`', function(assert) { assert.expect(1); var actual = _.at(object, ['a[0].b.c', 'a[1]']); assert.deepEqual(actual, [3, 4]); }); QUnit.test('should pluck inherited property values', function(assert) { assert.expect(1); function Foo() { this.a = 1; } Foo.prototype.b = 2; var actual = _.at(new Foo, 'b'); assert.deepEqual(actual, [2]); }); QUnit.test('should work in a lazy sequence', function(assert) { assert.expect(6); if (!isNpm) { var largeArray = lodashStable.range(LARGE_ARRAY_SIZE), smallArray = array; lodashStable.each([[2], ['2'], [2, 1]], function(paths) { lodashStable.times(2, function(index) { var array = index ? largeArray : smallArray, wrapped = _(array).map(identity).at(paths); assert.deepEqual(wrapped.value(), _.at(_.map(array, identity), paths)); }); }); } else { skipAssert(assert, 6); } }); QUnit.test('should support shortcut fusion', function(assert) { assert.expect(8); if (!isNpm) { var array = lodashStable.range(LARGE_ARRAY_SIZE), count = 0, iteratee = function(value) { count++; return square(value); }, lastIndex = LARGE_ARRAY_SIZE - 1; lodashStable.each([lastIndex, lastIndex + '', LARGE_ARRAY_SIZE, []], function(n, index) { count = 0; var actual = _(array).map(iteratee).at(n).value(), expected = index < 2 ? 1 : 0; assert.strictEqual(count, expected); expected = index == 3 ? [] : [index == 2 ? undefined : square(lastIndex)]; assert.deepEqual(actual, expected); }); } else { skipAssert(assert, 8); } }); QUnit.test('work with an object for `object` when chaining', function(assert) { assert.expect(2); if (!isNpm) { var paths = ['a[0].b.c', 'a[1]'], actual = _(object).map(identity).at(paths).value(); assert.deepEqual(actual, _.at(_.map(object, identity), paths)); var indexObject = { '0': 1 }; actual = _(indexObject).at(0).value(); assert.deepEqual(actual, _.at(indexObject, 0)); } else { skipAssert(assert, 2); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.attempt'); (function() { QUnit.test('should return the result of `func`', function(assert) { assert.expect(1); assert.strictEqual(_.attempt(lodashStable.constant('x')), 'x'); }); QUnit.test('should provide additional arguments to `func`', function(assert) { assert.expect(1); var actual = _.attempt(function() { return slice.call(arguments); }, 1, 2); assert.deepEqual(actual, [1, 2]); }); QUnit.test('should return the caught error', function(assert) { assert.expect(1); var expected = lodashStable.map(errors, stubTrue); var actual = lodashStable.map(errors, function(error) { return _.attempt(function() { throw error; }) === error; }); assert.deepEqual(actual, expected); }); QUnit.test('should coerce errors to error objects', function(assert) { assert.expect(1); var actual = _.attempt(function() { throw 'x'; }); assert.ok(lodashStable.isEqual(actual, Error('x'))); }); QUnit.test('should preserve custom errors', function(assert) { assert.expect(1); var actual = _.attempt(function() { throw new CustomError('x'); }); assert.ok(actual instanceof CustomError); }); QUnit.test('should work with an error object from another realm', function(assert) { assert.expect(1); if (realm.errors) { var expected = lodashStable.map(realm.errors, stubTrue); var actual = lodashStable.map(realm.errors, function(error) { return _.attempt(function() { throw error; }) === error; }); assert.deepEqual(actual, expected); } else { skipAssert(assert); } }); QUnit.test('should return an unwrapped value when implicitly chaining', function(assert) { assert.expect(1); if (!isNpm) { assert.strictEqual(_(lodashStable.constant('x')).attempt(), 'x'); } else { skipAssert(assert); } }); QUnit.test('should return a wrapped value when explicitly chaining', function(assert) { assert.expect(1); if (!isNpm) { assert.ok(_(lodashStable.constant('x')).chain().attempt() instanceof _); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.before'); (function() { function before(n, times) { var count = 0; lodashStable.times(times, _.before(n, function() { count++; })); return count; } QUnit.test('should create a function that invokes `func` after `n` calls', function(assert) { assert.expect(4); assert.strictEqual(before(5, 4), 4, 'before(n) should invoke `func` before being called `n` times'); assert.strictEqual(before(5, 6), 4, 'before(n) should not invoke `func` after being called `n - 1` times'); assert.strictEqual(before(0, 0), 0, 'before(0) should not invoke `func` immediately'); assert.strictEqual(before(0, 1), 0, 'before(0) should not invoke `func` when called'); }); QUnit.test('should coerce `n` values of `NaN` to `0`', function(assert) { assert.expect(1); assert.strictEqual(before(NaN, 1), 0); }); QUnit.test('should use `this` binding of function', function(assert) { assert.expect(2); var before = _.before(2, function(assert) { return ++this.count; }), object = { 'before': before, 'count': 0 }; object.before(); assert.strictEqual(object.before(), 1); assert.strictEqual(object.count, 1); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.bind'); (function() { function fn() { var result = [this]; push.apply(result, arguments); return result; } QUnit.test('should bind a function to an object', function(assert) { assert.expect(1); var object = {}, bound = _.bind(fn, object); assert.deepEqual(bound('a'), [object, 'a']); }); QUnit.test('should accept a falsey `thisArg`', function(assert) { assert.expect(1); var values = lodashStable.reject(falsey.slice(1), function(value) { return value == null; }), expected = lodashStable.map(values, function(value) { return [value]; }); var actual = lodashStable.map(values, function(value) { try { var bound = _.bind(fn, value); return bound(); } catch (e) {} }); assert.ok(lodashStable.every(actual, function(value, index) { return lodashStable.isEqual(value, expected[index]); })); }); QUnit.test('should bind a function to nullish values', function(assert) { assert.expect(6); var bound = _.bind(fn, null), actual = bound('a'); assert.ok((actual[0] === null) || (actual[0] && actual[0].Array)); assert.strictEqual(actual[1], 'a'); lodashStable.times(2, function(index) { bound = index ? _.bind(fn, undefined) : _.bind(fn); actual = bound('b'); assert.ok((actual[0] === undefined) || (actual[0] && actual[0].Array)); assert.strictEqual(actual[1], 'b'); }); }); QUnit.test('should partially apply arguments ', function(assert) { assert.expect(4); var object = {}, bound = _.bind(fn, object, 'a'); assert.deepEqual(bound(), [object, 'a']); bound = _.bind(fn, object, 'a'); assert.deepEqual(bound('b'), [object, 'a', 'b']); bound = _.bind(fn, object, 'a', 'b'); assert.deepEqual(bound(), [object, 'a', 'b']); assert.deepEqual(bound('c', 'd'), [object, 'a', 'b', 'c', 'd']); }); QUnit.test('should support placeholders', function(assert) { assert.expect(4); var object = {}, ph = _.bind.placeholder, bound = _.bind(fn, object, ph, 'b', ph); assert.deepEqual(bound('a', 'c'), [object, 'a', 'b', 'c']); assert.deepEqual(bound('a'), [object, 'a', 'b', undefined]); assert.deepEqual(bound('a', 'c', 'd'), [object, 'a', 'b', 'c', 'd']); assert.deepEqual(bound(), [object, undefined, 'b', undefined]); }); QUnit.test('should use `_.placeholder` when set', function(assert) { assert.expect(1); if (!isModularize) { var _ph = _.placeholder = {}, ph = _.bind.placeholder, object = {}, bound = _.bind(fn, object, _ph, 'b', ph); assert.deepEqual(bound('a', 'c'), [object, 'a', 'b', ph, 'c']); delete _.placeholder; } else { skipAssert(assert); } }); QUnit.test('should create a function with a `length` of `0`', function(assert) { assert.expect(2); var fn = function(a, b, c) {}, bound = _.bind(fn, {}); assert.strictEqual(bound.length, 0); bound = _.bind(fn, {}, 1); assert.strictEqual(bound.length, 0); }); QUnit.test('should ignore binding when called with the `new` operator', function(assert) { assert.expect(3); function Foo() { return this; } var bound = _.bind(Foo, { 'a': 1 }), newBound = new bound; assert.strictEqual(bound().a, 1); assert.strictEqual(newBound.a, undefined); assert.ok(newBound instanceof Foo); }); QUnit.test('should handle a number of arguments when called with the `new` operator', function(assert) { assert.expect(1); function Foo() { return this; } function Bar() {} var thisArg = { 'a': 1 }, boundFoo = _.bind(Foo, thisArg), boundBar = _.bind(Bar, thisArg), count = 9, expected = lodashStable.times(count, lodashStable.constant([undefined, undefined])); var actual = lodashStable.times(count, function(index) { try { switch (index) { case 0: return [new boundFoo().a, new boundBar().a]; case 1: return [new boundFoo(1).a, new boundBar(1).a]; case 2: return [new boundFoo(1, 2).a, new boundBar(1, 2).a]; case 3: return [new boundFoo(1, 2, 3).a, new boundBar(1, 2, 3).a]; case 4: return [new boundFoo(1, 2, 3, 4).a, new boundBar(1, 2, 3, 4).a]; case 5: return [new boundFoo(1, 2, 3, 4, 5).a, new boundBar(1, 2, 3, 4, 5).a]; case 6: return [new boundFoo(1, 2, 3, 4, 5, 6).a, new boundBar(1, 2, 3, 4, 5, 6).a]; case 7: return [new boundFoo(1, 2, 3, 4, 5, 6, 7).a, new boundBar(1, 2, 3, 4, 5, 6, 7).a]; case 8: return [new boundFoo(1, 2, 3, 4, 5, 6, 7, 8).a, new boundBar(1, 2, 3, 4, 5, 6, 7, 8).a]; } } catch (e) {} }); assert.deepEqual(actual, expected); }); QUnit.test('should ensure `new bound` is an instance of `func`', function(assert) { assert.expect(2); function Foo(value) { return value && object; } var bound = _.bind(Foo), object = {}; assert.ok(new bound instanceof Foo); assert.strictEqual(new bound(true), object); }); QUnit.test('should append array arguments to partially applied arguments', function(assert) { assert.expect(1); var object = {}, bound = _.bind(fn, object, 'a'); assert.deepEqual(bound(['b'], 'c'), [object, 'a', ['b'], 'c']); }); QUnit.test('should not rebind functions', function(assert) { assert.expect(3); var object1 = {}, object2 = {}, object3 = {}; var bound1 = _.bind(fn, object1), bound2 = _.bind(bound1, object2, 'a'), bound3 = _.bind(bound1, object3, 'b'); assert.deepEqual(bound1(), [object1]); assert.deepEqual(bound2(), [object1, 'a']); assert.deepEqual(bound3(), [object1, 'b']); }); QUnit.test('should not error when instantiating bound built-ins', function(assert) { assert.expect(2); var Ctor = _.bind(Date, null), expected = new Date(2012, 4, 23, 0, 0, 0, 0); try { var actual = new Ctor(2012, 4, 23, 0, 0, 0, 0); } catch (e) {} assert.deepEqual(actual, expected); Ctor = _.bind(Date, null, 2012, 4, 23); try { actual = new Ctor(0, 0, 0, 0); } catch (e) {} assert.deepEqual(actual, expected); }); QUnit.test('should not error when calling bound class constructors with the `new` operator', function(assert) { assert.expect(1); var createCtor = lodashStable.attempt(Function, '"use strict";return class A{}'); if (typeof createCtor == 'function') { var bound = _.bind(createCtor()), count = 8, expected = lodashStable.times(count, stubTrue); var actual = lodashStable.times(count, function(index) { try { switch (index) { case 0: return !!(new bound); case 1: return !!(new bound(1)); case 2: return !!(new bound(1, 2)); case 3: return !!(new bound(1, 2, 3)); case 4: return !!(new bound(1, 2, 3, 4)); case 5: return !!(new bound(1, 2, 3, 4, 5)); case 6: return !!(new bound(1, 2, 3, 4, 5, 6)); case 7: return !!(new bound(1, 2, 3, 4, 5, 6, 7)); } } catch (e) {} }); assert.deepEqual(actual, expected); } else { skipAssert(assert); } }); QUnit.test('should return a wrapped value when chaining', function(assert) { assert.expect(2); if (!isNpm) { var object = {}, bound = _(fn).bind({}, 'a', 'b'); assert.ok(bound instanceof _); var actual = bound.value()('c'); assert.deepEqual(actual, [object, 'a', 'b', 'c']); } else { skipAssert(assert, 2); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.bindAll'); (function() { var args = toArgs(['a']); var source = { '_n0': -2, '_p0': -1, '_a': 1, '_b': 2, '_c': 3, '_d': 4, '-0': function() { return this._n0; }, '0': function() { return this._p0; }, 'a': function() { return this._a; }, 'b': function() { return this._b; }, 'c': function() { return this._c; }, 'd': function() { return this._d; } }; QUnit.test('should accept individual method names', function(assert) { assert.expect(1); var object = lodashStable.cloneDeep(source); _.bindAll(object, 'a', 'b'); var actual = lodashStable.map(['a', 'b', 'c'], function(key) { return object[key].call({}); }); assert.deepEqual(actual, [1, 2, undefined]); }); QUnit.test('should accept arrays of method names', function(assert) { assert.expect(1); var object = lodashStable.cloneDeep(source); _.bindAll(object, ['a', 'b'], ['c']); var actual = lodashStable.map(['a', 'b', 'c', 'd'], function(key) { return object[key].call({}); }); assert.deepEqual(actual, [1, 2, 3, undefined]); }); QUnit.test('should preserve the sign of `0`', function(assert) { assert.expect(1); var props = [-0, Object(-0), 0, Object(0)]; var actual = lodashStable.map(props, function(key) { var object = lodashStable.cloneDeep(source); _.bindAll(object, key); return object[lodashStable.toString(key)].call({}); }); assert.deepEqual(actual, [-2, -2, -1, -1]); }); QUnit.test('should work with an array `object`', function(assert) { assert.expect(1); var array = ['push', 'pop']; _.bindAll(array); assert.strictEqual(array.pop, arrayProto.pop); }); QUnit.test('should work with `arguments` objects as secondary arguments', function(assert) { assert.expect(1); var object = lodashStable.cloneDeep(source); _.bindAll(object, args); var actual = lodashStable.map(args, function(key) { return object[key].call({}); }); assert.deepEqual(actual, [1]); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.bindKey'); (function() { QUnit.test('should work when the target function is overwritten', function(assert) { assert.expect(2); var object = { 'user': 'fred', 'greet': function(greeting) { return this.user + ' says: ' + greeting; } }; var bound = _.bindKey(object, 'greet', 'hi'); assert.strictEqual(bound(), 'fred says: hi'); object.greet = function(greeting) { return this.user + ' says: ' + greeting + '!'; }; assert.strictEqual(bound(), 'fred says: hi!'); }); QUnit.test('should support placeholders', function(assert) { assert.expect(4); var object = { 'fn': function() { return slice.call(arguments); } }; var ph = _.bindKey.placeholder, bound = _.bindKey(object, 'fn', ph, 'b', ph); assert.deepEqual(bound('a', 'c'), ['a', 'b', 'c']); assert.deepEqual(bound('a'), ['a', 'b', undefined]); assert.deepEqual(bound('a', 'c', 'd'), ['a', 'b', 'c', 'd']); assert.deepEqual(bound(), [undefined, 'b', undefined]); }); QUnit.test('should use `_.placeholder` when set', function(assert) { assert.expect(1); if (!isModularize) { var object = { 'fn': function() { return slice.call(arguments); } }; var _ph = _.placeholder = {}, ph = _.bindKey.placeholder, bound = _.bindKey(object, 'fn', _ph, 'b', ph); assert.deepEqual(bound('a', 'c'), ['a', 'b', ph, 'c']); delete _.placeholder; } else { skipAssert(assert); } }); QUnit.test('should ensure `new bound` is an instance of `object[key]`', function(assert) { assert.expect(2); function Foo(value) { return value && object; } var object = { 'Foo': Foo }, bound = _.bindKey(object, 'Foo'); assert.ok(new bound instanceof Foo); assert.strictEqual(new bound(true), object); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('case methods'); lodashStable.each(['camel', 'kebab', 'lower', 'snake', 'start', 'upper'], function(caseName) { var methodName = caseName + 'Case', func = _[methodName]; var strings = [ 'foo bar', 'Foo bar', 'foo Bar', 'Foo Bar', 'FOO BAR', 'fooBar', '--foo-bar--', '__foo_bar__' ]; var converted = (function() { switch (caseName) { case 'camel': return 'fooBar'; case 'kebab': return 'foo-bar'; case 'lower': return 'foo bar'; case 'snake': return 'foo_bar'; case 'start': return 'Foo Bar'; case 'upper': return 'FOO BAR'; } }()); QUnit.test('`_.' + methodName + '` should convert `string` to ' + caseName + ' case', function(assert) { assert.expect(1); var actual = lodashStable.map(strings, function(string) { var expected = (caseName == 'start' && string == 'FOO BAR') ? string : converted; return func(string) === expected; }); assert.deepEqual(actual, lodashStable.map(strings, stubTrue)); }); QUnit.test('`_.' + methodName + '` should handle double-converting strings', function(assert) { assert.expect(1); var actual = lodashStable.map(strings, function(string) { var expected = (caseName == 'start' && string == 'FOO BAR') ? string : converted; return func(func(string)) === expected; }); assert.deepEqual(actual, lodashStable.map(strings, stubTrue)); }); QUnit.test('`_.' + methodName + '` should deburr letters', function(assert) { assert.expect(1); var actual = lodashStable.map(burredLetters, function(burred, index) { var letter = deburredLetters[index].replace(/['\u2019]/g, ''); if (caseName == 'start') { letter = letter == 'IJ' ? letter : lodashStable.capitalize(letter); } else if (caseName == 'upper') { letter = letter.toUpperCase(); } else { letter = letter.toLowerCase(); } return func(burred) === letter; }); assert.deepEqual(actual, lodashStable.map(burredLetters, stubTrue)); }); QUnit.test('`_.' + methodName + '` should remove contraction apostrophes', function(assert) { assert.expect(2); var postfixes = ['d', 'll', 'm', 're', 's', 't', 've']; lodashStable.each(["'", '\u2019'], function(apos) { var actual = lodashStable.map(postfixes, function(postfix) { return func('a b' + apos + postfix + ' c'); }); var expected = lodashStable.map(postfixes, function(postfix) { switch (caseName) { case 'camel': return 'aB' + postfix + 'C'; case 'kebab': return 'a-b' + postfix + '-c'; case 'lower': return 'a b' + postfix + ' c'; case 'snake': return 'a_b' + postfix + '_c'; case 'start': return 'A B' + postfix + ' C'; case 'upper': return 'A B' + postfix.toUpperCase() + ' C'; } }); assert.deepEqual(actual, expected); }); }); QUnit.test('`_.' + methodName + '` should remove Latin mathematical operators', function(assert) { assert.expect(1); var actual = lodashStable.map(['\xd7', '\xf7'], func); assert.deepEqual(actual, ['', '']); }); QUnit.test('`_.' + methodName + '` should coerce `string` to a string', function(assert) { assert.expect(2); var string = 'foo bar'; assert.strictEqual(func(Object(string)), converted); assert.strictEqual(func({ 'toString': lodashStable.constant(string) }), converted); }); QUnit.test('`_.' + methodName + '` should return an unwrapped value implicitly when chaining', function(assert) { assert.expect(1); if (!isNpm) { assert.strictEqual(_('foo bar')[methodName](), converted); } else { skipAssert(assert); } }); QUnit.test('`_.' + methodName + '` should return a wrapped value when explicitly chaining', function(assert) { assert.expect(1); if (!isNpm) { assert.ok(_('foo bar').chain()[methodName]() instanceof _); } else { skipAssert(assert); } }); }); (function() { QUnit.test('should get the original value after cycling through all case methods', function(assert) { assert.expect(1); var funcs = [_.camelCase, _.kebabCase, _.lowerCase, _.snakeCase, _.startCase, _.lowerCase, _.camelCase]; var actual = lodashStable.reduce(funcs, function(result, func) { return func(result); }, 'enable 6h format'); assert.strictEqual(actual, 'enable6HFormat'); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.camelCase'); (function() { QUnit.test('should work with numbers', function(assert) { assert.expect(6); assert.strictEqual(_.camelCase('12 feet'), '12Feet'); assert.strictEqual(_.camelCase('enable 6h format'), 'enable6HFormat'); assert.strictEqual(_.camelCase('enable 24H format'), 'enable24HFormat'); assert.strictEqual(_.camelCase('too legit 2 quit'), 'tooLegit2Quit'); assert.strictEqual(_.camelCase('walk 500 miles'), 'walk500Miles'); assert.strictEqual(_.camelCase('xhr2 request'), 'xhr2Request'); }); QUnit.test('should handle acronyms', function(assert) { assert.expect(6); lodashStable.each(['safe HTML', 'safeHTML'], function(string) { assert.strictEqual(_.camelCase(string), 'safeHtml'); }); lodashStable.each(['escape HTML entities', 'escapeHTMLEntities'], function(string) { assert.strictEqual(_.camelCase(string), 'escapeHtmlEntities'); }); lodashStable.each(['XMLHttpRequest', 'XmlHTTPRequest'], function(string) { assert.strictEqual(_.camelCase(string), 'xmlHttpRequest'); }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.capitalize'); (function() { QUnit.test('should capitalize the first character of a string', function(assert) { assert.expect(3); assert.strictEqual(_.capitalize('fred'), 'Fred'); assert.strictEqual(_.capitalize('Fred'), 'Fred'); assert.strictEqual(_.capitalize(' fred'), ' fred'); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.castArray'); (function() { QUnit.test('should wrap non-array items in an array', function(assert) { assert.expect(1); var values = falsey.concat(true, 1, 'a', { 'a': 1 }), expected = lodashStable.map(values, function(value) { return [value]; }), actual = lodashStable.map(values, _.castArray); assert.deepEqual(actual, expected); }); QUnit.test('should return array values by reference', function(assert) { assert.expect(1); var array = [1]; assert.strictEqual(_.castArray(array), array); }); QUnit.test('should return an empty array when no arguments are given', function(assert) { assert.expect(1); assert.deepEqual(_.castArray(), []); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.chain'); (function() { QUnit.test('should return a wrapped value', function(assert) { assert.expect(1); if (!isNpm) { var actual = _.chain({ 'a': 0 }); assert.ok(actual instanceof _); } else { skipAssert(assert); } }); QUnit.test('should return existing wrapped values', function(assert) { assert.expect(2); if (!isNpm) { var wrapped = _({ 'a': 0 }); assert.strictEqual(_.chain(wrapped), wrapped); assert.strictEqual(wrapped.chain(), wrapped); } else { skipAssert(assert, 2); } }); QUnit.test('should enable chaining for methods that return unwrapped values', function(assert) { assert.expect(6); if (!isNpm) { var array = ['c', 'b', 'a']; assert.ok(_.chain(array).head() instanceof _); assert.ok(_(array).chain().head() instanceof _); assert.ok(_.chain(array).isArray() instanceof _); assert.ok(_(array).chain().isArray() instanceof _); assert.ok(_.chain(array).sortBy().head() instanceof _); assert.ok(_(array).chain().sortBy().head() instanceof _); } else { skipAssert(assert, 6); } }); QUnit.test('should chain multiple methods', function(assert) { assert.expect(6); if (!isNpm) { lodashStable.times(2, function(index) { var array = ['one two three four', 'five six seven eight', 'nine ten eleven twelve'], expected = { ' ': 9, 'e': 14, 'f': 2, 'g': 1, 'h': 2, 'i': 4, 'l': 2, 'n': 6, 'o': 3, 'r': 2, 's': 2, 't': 5, 'u': 1, 'v': 4, 'w': 2, 'x': 1 }, wrapped = index ? _(array).chain() : _.chain(array); var actual = wrapped .chain() .map(function(value) { return value.split(''); }) .flatten() .reduce(function(object, chr) { object[chr] || (object[chr] = 0); object[chr]++; return object; }, {}) .value(); assert.deepEqual(actual, expected); array = [1, 2, 3, 4, 5, 6]; wrapped = index ? _(array).chain() : _.chain(array); actual = wrapped .chain() .filter(function(n) { return n % 2 != 0; }) .reject(function(n) { return n % 3 == 0; }) .sortBy(function(n) { return -n; }) .value(); assert.deepEqual(actual, [5, 1]); array = [3, 4]; wrapped = index ? _(array).chain() : _.chain(array); actual = wrapped .reverse() .concat([2, 1]) .unshift(5) .tap(function(value) { value.pop(); }) .map(square) .value(); assert.deepEqual(actual, [25, 16, 9, 4]); }); } else { skipAssert(assert, 6); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.chunk'); (function() { var array = [0, 1, 2, 3, 4, 5]; QUnit.test('should return chunked arrays', function(assert) { assert.expect(1); var actual = _.chunk(array, 3); assert.deepEqual(actual, [[0, 1, 2], [3, 4, 5]]); }); QUnit.test('should return the last chunk as remaining elements', function(assert) { assert.expect(1); var actual = _.chunk(array, 4); assert.deepEqual(actual, [[0, 1, 2, 3], [4, 5]]); }); QUnit.test('should treat falsey `size` values, except `undefined`, as `0`', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, function(value) { return value === undefined ? [[0], [1], [2], [3], [4], [5]] : []; }); var actual = lodashStable.map(falsey, function(size, index) { return index ? _.chunk(array, size) : _.chunk(array); }); assert.deepEqual(actual, expected); }); QUnit.test('should ensure the minimum `size` is `0`', function(assert) { assert.expect(1); var values = lodashStable.reject(falsey, lodashStable.isUndefined).concat(-1, -Infinity), expected = lodashStable.map(values, stubArray); var actual = lodashStable.map(values, function(n) { return _.chunk(array, n); }); assert.deepEqual(actual, expected); }); QUnit.test('should coerce `size` to an integer', function(assert) { assert.expect(1); assert.deepEqual(_.chunk(array, array.length / 4), [[0], [1], [2], [3], [4], [5]]); }); QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(1); var actual = lodashStable.map([[1, 2], [3, 4]], _.chunk); assert.deepEqual(actual, [[[1], [2]], [[3], [4]]]); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.clamp'); (function() { QUnit.test('should work with a `max`', function(assert) { assert.expect(2); assert.strictEqual(_.clamp(5, 3), 3); assert.strictEqual(_.clamp(1, 3), 1); }); QUnit.test('should clamp negative numbers', function(assert) { assert.expect(3); assert.strictEqual(_.clamp(-10, -5, 5), -5); assert.strictEqual(_.clamp(-10.2, -5.5, 5.5), -5.5); assert.strictEqual(_.clamp(-Infinity, -5, 5), -5); }); QUnit.test('should clamp positive numbers', function(assert) { assert.expect(3); assert.strictEqual(_.clamp(10, -5, 5), 5); assert.strictEqual(_.clamp(10.6, -5.6, 5.4), 5.4); assert.strictEqual(_.clamp(Infinity, -5, 5), 5); }); QUnit.test('should not alter negative numbers in range', function(assert) { assert.expect(3); assert.strictEqual(_.clamp(-4, -5, 5), -4); assert.strictEqual(_.clamp(-5, -5, 5), -5); assert.strictEqual(_.clamp(-5.5, -5.6, 5.6), -5.5); }); QUnit.test('should not alter positive numbers in range', function(assert) { assert.expect(3); assert.strictEqual(_.clamp(4, -5, 5), 4); assert.strictEqual(_.clamp(5, -5, 5), 5); assert.strictEqual(_.clamp(4.5, -5.1, 5.2), 4.5); }); QUnit.test('should not alter `0` in range', function(assert) { assert.expect(1); assert.strictEqual(1 / _.clamp(0, -5, 5), Infinity); }); QUnit.test('should clamp to `0`', function(assert) { assert.expect(1); assert.strictEqual(1 / _.clamp(-10, 0, 5), Infinity); }); QUnit.test('should not alter `-0` in range', function(assert) { assert.expect(1); assert.strictEqual(1 / _.clamp(-0, -5, 5), -Infinity); }); QUnit.test('should clamp to `-0`', function(assert) { assert.expect(1); assert.strictEqual(1 / _.clamp(-10, -0, 5), -Infinity); }); QUnit.test('should return `NaN` when `number` is `NaN`', function(assert) { assert.expect(1); assert.deepEqual(_.clamp(NaN, -5, 5), NaN); }); QUnit.test('should coerce `min` and `max` of `NaN` to `0`', function(assert) { assert.expect(2); assert.deepEqual(_.clamp(1, -5, NaN), 0); assert.deepEqual(_.clamp(-1, NaN, 5), 0); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('clone methods'); (function() { function Foo() { this.a = 1; } Foo.prototype.b = 1; Foo.c = function() {}; if (Map) { var map = new Map; map.set('a', 1); map.set('b', 2); } if (Set) { var set = new Set; set.add(1); set.add(2); } var objects = { '`arguments` objects': arguments, 'arrays': ['a', ''], 'array-like objects': { '0': 'a', 'length': 1 }, 'booleans': false, 'boolean objects': Object(false), 'date objects': new Date, 'Foo instances': new Foo, 'objects': { 'a': 0, 'b': 1, 'c': 2 }, 'objects with object values': { 'a': /a/, 'b': ['B'], 'c': { 'C': 1 } }, 'objects from another document': realm.object || {}, 'maps': map, 'null values': null, 'numbers': 0, 'number objects': Object(0), 'regexes': /a/gim, 'sets': set, 'strings': 'a', 'string objects': Object('a'), 'undefined values': undefined }; objects.arrays.length = 3; var uncloneable = { 'DOM elements': body, 'functions': Foo, 'async functions': asyncFunc, 'generator functions': genFunc, 'the `Proxy` constructor': Proxy }; lodashStable.each(errors, function(error) { uncloneable[error.name + 's'] = error; }); QUnit.test('`_.clone` should perform a shallow clone', function(assert) { assert.expect(2); var array = [{ 'a': 0 }, { 'b': 1 }], actual = _.clone(array); assert.deepEqual(actual, array); assert.ok(actual !== array && actual[0] === array[0]); }); QUnit.test('`_.cloneDeep` should deep clone objects with circular references', function(assert) { assert.expect(1); var object = { 'foo': { 'b': { 'c': { 'd': {} } } }, 'bar': {} }; object.foo.b.c.d = object; object.bar.b = object.foo.b; var actual = _.cloneDeep(object); assert.ok(actual.bar.b === actual.foo.b && actual === actual.foo.b.c.d && actual !== object); }); QUnit.test('`_.cloneDeep` should deep clone objects with lots of circular references', function(assert) { assert.expect(2); var cyclical = {}; lodashStable.times(LARGE_ARRAY_SIZE + 1, function(index) { cyclical['v' + index] = [index ? cyclical['v' + (index - 1)] : cyclical]; }); var clone = _.cloneDeep(cyclical), actual = clone['v' + LARGE_ARRAY_SIZE][0]; assert.strictEqual(actual, clone['v' + (LARGE_ARRAY_SIZE - 1)]); assert.notStrictEqual(actual, cyclical['v' + (LARGE_ARRAY_SIZE - 1)]); }); QUnit.test('`_.cloneDeepWith` should provide `stack` to `customizer`', function(assert) { assert.expect(1); var actual; _.cloneDeepWith({ 'a': 1 }, function() { actual = _.last(arguments); }); assert.ok(isNpm ? actual.constructor.name == 'Stack' : actual instanceof mapCaches.Stack ); }); lodashStable.each(['clone', 'cloneDeep'], function(methodName) { var func = _[methodName], isDeep = methodName == 'cloneDeep'; lodashStable.forOwn(objects, function(object, kind) { QUnit.test('`_.' + methodName + '` should clone ' + kind, function(assert) { assert.expect(2); var actual = func(object); assert.ok(lodashStable.isEqual(actual, object)); if (lodashStable.isObject(object)) { assert.notStrictEqual(actual, object); } else { assert.strictEqual(actual, object); } }); }); QUnit.test('`_.' + methodName + '` should clone array buffers', function(assert) { assert.expect(2); if (ArrayBuffer) { var actual = func(arrayBuffer); assert.strictEqual(actual.byteLength, arrayBuffer.byteLength); assert.notStrictEqual(actual, arrayBuffer); } else { skipAssert(assert, 2); } }); QUnit.test('`_.' + methodName + '` should clone buffers', function(assert) { assert.expect(4); if (Buffer) { var buffer = new Buffer([1, 2]), actual = func(buffer); assert.strictEqual(actual.byteLength, buffer.byteLength); assert.strictEqual(actual.inspect(), buffer.inspect()); assert.notStrictEqual(actual, buffer); buffer[0] = 2; assert.strictEqual(actual[0], isDeep ? 2 : 1); } else { skipAssert(assert, 4); } }); QUnit.test('`_.' + methodName + '` should clone `index` and `input` array properties', function(assert) { assert.expect(2); var array = /c/.exec('abcde'), actual = func(array); assert.strictEqual(actual.index, 2); assert.strictEqual(actual.input, 'abcde'); }); QUnit.test('`_.' + methodName + '` should clone `lastIndex` regexp property', function(assert) { assert.expect(1); var regexp = /c/g; regexp.exec('abcde'); assert.strictEqual(func(regexp).lastIndex, 3); }); QUnit.test('`_.' + methodName + '` should clone expando properties', function(assert) { assert.expect(1); var values = lodashStable.map([false, true, 1, 'a'], function(value) { var object = Object(value); object.a = 1; return object; }); var expected = lodashStable.map(values, stubTrue); var actual = lodashStable.map(values, function(value) { return func(value).a === 1; }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should clone prototype objects', function(assert) { assert.expect(2); var actual = func(Foo.prototype); assert.notOk(actual instanceof Foo); assert.deepEqual(actual, { 'b': 1 }); }); QUnit.test('`_.' + methodName + '` should set the `[[Prototype]]` of a clone', function(assert) { assert.expect(1); assert.ok(func(new Foo) instanceof Foo); }); QUnit.test('`_.' + methodName + '` should set the `[[Prototype]]` of a clone even when the `constructor` is incorrect', function(assert) { assert.expect(1); Foo.prototype.constructor = Object; assert.ok(func(new Foo) instanceof Foo); Foo.prototype.constructor = Foo; }); QUnit.test('`_.' + methodName + '` should ensure `value` constructor is a function before using its `[[Prototype]]`', function(assert) { assert.expect(1); Foo.prototype.constructor = null; assert.notOk(func(new Foo) instanceof Foo); Foo.prototype.constructor = Foo; }); QUnit.test('`_.' + methodName + '` should clone properties that shadow those on `Object.prototype`', function(assert) { assert.expect(2); var object = { 'constructor': objectProto.constructor, 'hasOwnProperty': objectProto.hasOwnProperty, 'isPrototypeOf': objectProto.isPrototypeOf, 'propertyIsEnumerable': objectProto.propertyIsEnumerable, 'toLocaleString': objectProto.toLocaleString, 'toString': objectProto.toString, 'valueOf': objectProto.valueOf }; var actual = func(object); assert.deepEqual(actual, object); assert.notStrictEqual(actual, object); }); QUnit.test('`_.' + methodName + '` should clone symbol properties', function(assert) { assert.expect(7); function Foo() { this[symbol] = { 'c': 1 }; } if (Symbol) { var symbol2 = Symbol('b'); Foo.prototype[symbol2] = 2; var symbol3 = Symbol('c'); defineProperty(Foo.prototype, symbol3, { 'configurable': true, 'enumerable': false, 'writable': true, 'value': 3 }); var object = { 'a': { 'b': new Foo } }; object[symbol] = { 'b': 1 }; var actual = func(object); if (isDeep) { assert.notStrictEqual(actual[symbol], object[symbol]); assert.notStrictEqual(actual.a, object.a); } else { assert.strictEqual(actual[symbol], object[symbol]); assert.strictEqual(actual.a, object.a); } assert.deepEqual(actual[symbol], object[symbol]); assert.deepEqual(getSymbols(actual.a.b), [symbol]); assert.deepEqual(actual.a.b[symbol], object.a.b[symbol]); assert.deepEqual(actual.a.b[symbol2], object.a.b[symbol2]); assert.deepEqual(actual.a.b[symbol3], object.a.b[symbol3]); } else { skipAssert(assert, 7); } }); QUnit.test('`_.' + methodName + '` should clone symbol objects', function(assert) { assert.expect(4); if (Symbol) { assert.strictEqual(func(symbol), symbol); var object = Object(symbol), actual = func(object); assert.strictEqual(typeof actual, 'object'); assert.strictEqual(typeof actual.valueOf(), 'symbol'); assert.notStrictEqual(actual, object); } else { skipAssert(assert, 4); } }); QUnit.test('`_.' + methodName + '` should not clone symbol primitives', function(assert) { assert.expect(1); if (Symbol) { assert.strictEqual(func(symbol), symbol); } else { skipAssert(assert); } }); QUnit.test('`_.' + methodName + '` should not error on DOM elements', function(assert) { assert.expect(1); if (document) { var element = document.createElement('div'); try { assert.deepEqual(func(element), {}); } catch (e) { assert.ok(false, e.message); } } else { skipAssert(assert); } }); QUnit.test('`_.' + methodName + '` should create an object from the same realm as `value`', function(assert) { assert.expect(1); var props = []; var objects = lodashStable.transform(_, function(result, value, key) { if (lodashStable.startsWith(key, '_') && lodashStable.isObject(value) && !lodashStable.isArguments(value) && !lodashStable.isElement(value) && !lodashStable.isFunction(value)) { props.push(lodashStable.capitalize(lodashStable.camelCase(key))); result.push(value); } }, []); var expected = lodashStable.map(objects, stubTrue); var actual = lodashStable.map(objects, function(object) { var Ctor = object.constructor, result = func(object); return result !== object && ((result instanceof Ctor) || !(new Ctor instanceof Ctor)); }); assert.deepEqual(actual, expected, props.join(', ')); }); QUnit.test('`_.' + methodName + '` should perform a ' + (isDeep ? 'deep' : 'shallow') + ' clone when used as an iteratee for methods like `_.map`', function(assert) { assert.expect(2); var expected = [{ 'a': [0] }, { 'b': [1] }], actual = lodashStable.map(expected, func); assert.deepEqual(actual, expected); if (isDeep) { assert.ok(actual[0] !== expected[0] && actual[0].a !== expected[0].a && actual[1].b !== expected[1].b); } else { assert.ok(actual[0] !== expected[0] && actual[0].a === expected[0].a && actual[1].b === expected[1].b); } }); QUnit.test('`_.' + methodName + '` should return a unwrapped value when chaining', function(assert) { assert.expect(2); if (!isNpm) { var object = objects.objects, actual = _(object)[methodName](); assert.deepEqual(actual, object); assert.notStrictEqual(actual, object); } else { skipAssert(assert, 2); } }); lodashStable.each(arrayViews, function(type) { QUnit.test('`_.' + methodName + '` should clone ' + type + ' values', function(assert) { assert.expect(10); var Ctor = root[type]; lodashStable.times(2, function(index) { if (Ctor) { var buffer = new ArrayBuffer(24), view = index ? new Ctor(buffer, 8, 1) : new Ctor(buffer), actual = func(view); assert.deepEqual(actual, view); assert.notStrictEqual(actual, view); assert.strictEqual(actual.buffer === view.buffer, !isDeep); assert.strictEqual(actual.byteOffset, view.byteOffset); assert.strictEqual(actual.length, view.length); } else { skipAssert(assert, 5); } }); }); }); lodashStable.forOwn(uncloneable, function(value, key) { QUnit.test('`_.' + methodName + '` should not clone ' + key, function(assert) { assert.expect(3); if (value) { var object = { 'a': value, 'b': { 'c': value } }, actual = func(object), expected = value === Foo ? { 'c': Foo.c } : {}; assert.deepEqual(actual, object); assert.notStrictEqual(actual, object); assert.deepEqual(func(value), expected); } else { skipAssert(assert, 3); } }); }); }); lodashStable.each(['cloneWith', 'cloneDeepWith'], function(methodName) { var func = _[methodName], isDeep = methodName == 'cloneDeepWith'; QUnit.test('`_.' + methodName + '` should provide correct `customizer` arguments', function(assert) { assert.expect(1); var argsList = [], object = new Foo; func(object, function() { var length = arguments.length, args = slice.call(arguments, 0, length - (length > 1 ? 1 : 0)); argsList.push(args); }); assert.deepEqual(argsList, isDeep ? [[object], [1, 'a', object]] : [[object]]); }); QUnit.test('`_.' + methodName + '` should handle cloning when `customizer` returns `undefined`', function(assert) { assert.expect(1); var actual = func({ 'a': { 'b': 'c' } }, noop); assert.deepEqual(actual, { 'a': { 'b': 'c' } }); }); lodashStable.forOwn(uncloneable, function(value, key) { QUnit.test('`_.' + methodName + '` should work with a `customizer` callback and ' + key, function(assert) { assert.expect(3); var customizer = function(value) { return lodashStable.isPlainObject(value) ? undefined : value; }; var actual = func(value, customizer); assert.strictEqual(actual, value); var object = { 'a': value, 'b': { 'c': value } }; actual = func(object, customizer); assert.deepEqual(actual, object); assert.notStrictEqual(actual, object); }); }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.compact'); (function() { var largeArray = lodashStable.range(LARGE_ARRAY_SIZE).concat(null); QUnit.test('should filter falsey values', function(assert) { assert.expect(1); var array = ['0', '1', '2']; assert.deepEqual(_.compact(falsey.concat(array)), array); }); QUnit.test('should work when in-between lazy operators', function(assert) { assert.expect(2); if (!isNpm) { var actual = _(falsey).thru(_.slice).compact().thru(_.slice).value(); assert.deepEqual(actual, []); actual = _(falsey).thru(_.slice).push(true, 1).compact().push('a').value(); assert.deepEqual(actual, [true, 1, 'a']); } else { skipAssert(assert, 2); } }); QUnit.test('should work in a lazy sequence', function(assert) { assert.expect(1); if (!isNpm) { var actual = _(largeArray).slice(1).compact().reverse().take().value(); assert.deepEqual(actual, _.take(_.compact(_.slice(largeArray, 1)).reverse())); } else { skipAssert(assert); } }); QUnit.test('should work in a lazy sequence with a custom `_.iteratee`', function(assert) { assert.expect(1); if (!isModularize) { var iteratee = _.iteratee, pass = false; _.iteratee = identity; try { var actual = _(largeArray).slice(1).compact().value(); pass = lodashStable.isEqual(actual, _.compact(_.slice(largeArray, 1))); } catch (e) {console.log(e);} assert.ok(pass); _.iteratee = iteratee; } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.concat'); (function() { QUnit.test('should shallow clone `array`', function(assert) { assert.expect(2); var array = [1, 2, 3], actual = _.concat(array); assert.deepEqual(actual, array); assert.notStrictEqual(actual, array); }); QUnit.test('should concat arrays and values', function(assert) { assert.expect(2); var array = [1], actual = _.concat(array, 2, [3], [[4]]); assert.deepEqual(actual, [1, 2, 3, [4]]); assert.deepEqual(array, [1]); }); QUnit.test('should cast non-array `array` values to arrays', function(assert) { assert.expect(2); var values = [, null, undefined, false, true, 1, NaN, 'a']; var expected = lodashStable.map(values, function(value, index) { return index ? [value] : []; }); var actual = lodashStable.map(values, function(value, index) { return index ? _.concat(value) : _.concat(); }); assert.deepEqual(actual, expected); expected = lodashStable.map(values, function(value) { return [value, 2, [3]]; }); actual = lodashStable.map(values, function(value) { return _.concat(value, [2], [[3]]); }); assert.deepEqual(actual, expected); }); QUnit.test('should treat sparse arrays as dense', function(assert) { assert.expect(3); var expected = [], actual = _.concat(Array(1), Array(1)); expected.push(undefined, undefined); assert.ok('0'in actual); assert.ok('1' in actual); assert.deepEqual(actual, expected); }); QUnit.test('should return a new wrapped array', function(assert) { assert.expect(2); if (!isNpm) { var array = [1], wrapped = _(array).concat([2, 3]), actual = wrapped.value(); assert.deepEqual(array, [1]); assert.deepEqual(actual, [1, 2, 3]); } else { skipAssert(assert, 2); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.cond'); (function() { QUnit.test('should create a conditional function', function(assert) { assert.expect(3); var cond = _.cond([ [lodashStable.matches({ 'a': 1 }), stubA], [lodashStable.matchesProperty('b', 1), stubB], [lodashStable.property('c'), stubC] ]); assert.strictEqual(cond({ 'a': 1, 'b': 2, 'c': 3 }), 'a'); assert.strictEqual(cond({ 'a': 0, 'b': 1, 'c': 2 }), 'b'); assert.strictEqual(cond({ 'a': -1, 'b': 0, 'c': 1 }), 'c'); }); QUnit.test('should provide arguments to functions', function(assert) { assert.expect(2); var args1, args2, expected = ['a', 'b', 'c']; var cond = _.cond([[ function() { args1 || (args1 = slice.call(arguments)); return true; }, function() { args2 || (args2 = slice.call(arguments)); } ]]); cond('a', 'b', 'c'); assert.deepEqual(args1, expected); assert.deepEqual(args2, expected); }); QUnit.test('should work with predicate shorthands', function(assert) { assert.expect(3); var cond = _.cond([ [{ 'a': 1 }, stubA], [['b', 1], stubB], ['c', stubC] ]); assert.strictEqual(cond({ 'a': 1, 'b': 2, 'c': 3 }), 'a'); assert.strictEqual(cond({ 'a': 0, 'b': 1, 'c': 2 }), 'b'); assert.strictEqual(cond({ 'a': -1, 'b': 0, 'c': 1 }), 'c'); }); QUnit.test('should return `undefined` when no condition is met', function(assert) { assert.expect(1); var cond = _.cond([[stubFalse, stubA]]); assert.strictEqual(cond({ 'a': 1 }), undefined); }); QUnit.test('should throw a TypeError if `pairs` is not composed of functions', function(assert) { assert.expect(2); lodashStable.each([false, true], function(value) { assert.raises(function() { _.cond([[stubTrue, value]])(); }, TypeError); }); }); QUnit.test('should use `this` binding of function for `pairs`', function(assert) { assert.expect(1); var cond = _.cond([ [function(a) { return this[a]; }, function(a, b) { return this[b]; }] ]); var object = { 'cond': cond, 'a': 1, 'b': 2 }; assert.strictEqual(object.cond('a', 'b'), 2); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.conforms'); (function() { QUnit.test('should not change behavior if `source` is modified', function(assert) { assert.expect(2); var object = { 'a': 2 }, source = { 'a': function(value) { return value > 1; } }, par = _.conforms(source); assert.strictEqual(par(object), true); source.a = function(value) { return value < 2; }; assert.strictEqual(par(object), true); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('conforms methods'); lodashStable.each(['conforms', 'conformsTo'], function(methodName) { var isConforms = methodName == 'conforms'; function conforms(source) { return isConforms ? _.conforms(source) : function(object) { return _.conformsTo(object, source); }; } QUnit.test('`_.' + methodName + '` should check if `object` conforms to `source`', function(assert) { assert.expect(2); var objects = [ { 'a': 1, 'b': 8 }, { 'a': 2, 'b': 4 }, { 'a': 3, 'b': 16 } ]; var par = conforms({ 'b': function(value) { return value > 4; } }); var actual = lodashStable.filter(objects, par); assert.deepEqual(actual, [objects[0], objects[2]]); par = conforms({ 'b': function(value) { return value > 8; }, 'a': function(value) { return value > 1; } }); actual = lodashStable.filter(objects, par); assert.deepEqual(actual, [objects[2]]); }); QUnit.test('`_.' + methodName + '` should not match by inherited `source` properties', function(assert) { assert.expect(1); function Foo() { this.a = function(value) { return value > 1; }; } Foo.prototype.b = function(value) { return value > 8; }; var objects = [ { 'a': 1, 'b': 8 }, { 'a': 2, 'b': 4 }, { 'a': 3, 'b': 16 } ]; var par = conforms(new Foo), actual = lodashStable.filter(objects, par); assert.deepEqual(actual, [objects[1], objects[2]]); }); QUnit.test('`_.' + methodName + '` should not invoke `source` predicates for missing `object` properties', function(assert) { assert.expect(2); var count = 0; var par = conforms({ 'a': function() { count++; return true; } }); assert.strictEqual(par({}), false); assert.strictEqual(count, 0); }); QUnit.test('`_.' + methodName + '` should work with a function for `object`', function(assert) { assert.expect(2); function Foo() {} Foo.a = 1; function Bar() {} Bar.a = 2; var par = conforms({ 'a': function(value) { return value > 1; } }); assert.strictEqual(par(Foo), false); assert.strictEqual(par(Bar), true); }); QUnit.test('`_.' + methodName + '` should work with a function for `source`', function(assert) { assert.expect(1); function Foo() {} Foo.a = function(value) { return value > 1; }; var objects = [{ 'a': 1 }, { 'a': 2 }], actual = lodashStable.filter(objects, conforms(Foo)); assert.deepEqual(actual, [objects[1]]); }); QUnit.test('`_.' + methodName + '` should work with a non-plain `object`', function(assert) { assert.expect(1); function Foo() { this.a = 1; } Foo.prototype.b = 2; var par = conforms({ 'b': function(value) { return value > 1; } }); assert.strictEqual(par(new Foo), true); }); QUnit.test('`_.' + methodName + '` should return `false` when `object` is nullish', function(assert) { assert.expect(1); var values = [, null, undefined], expected = lodashStable.map(values, stubFalse); var par = conforms({ 'a': function(value) { return value > 1; } }); var actual = lodashStable.map(values, function(value, index) { try { return index ? par(value) : par(); } catch (e) {} }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should return `true` when comparing an empty `source` to a nullish `object`', function(assert) { assert.expect(1); var values = [, null, undefined], expected = lodashStable.map(values, stubTrue), par = conforms({}); var actual = lodashStable.map(values, function(value, index) { try { return index ? par(value) : par(); } catch (e) {} }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should return `true` when comparing an empty `source`', function(assert) { assert.expect(1); var object = { 'a': 1 }, expected = lodashStable.map(empties, stubTrue); var actual = lodashStable.map(empties, function(value) { var par = conforms(value); return par(object); }); assert.deepEqual(actual, expected); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.constant'); (function() { QUnit.test('should create a function that returns `value`', function(assert) { assert.expect(1); var object = { 'a': 1 }, values = Array(2).concat(empties, true, 1, 'a'), constant = _.constant(object); var results = lodashStable.map(values, function(value, index) { if (index < 2) { return index ? constant.call({}) : constant(); } return constant(value); }); assert.ok(lodashStable.every(results, function(result) { return result === object; })); }); QUnit.test('should work with falsey values', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, stubTrue); var actual = lodashStable.map(falsey, function(value, index) { var constant = index ? _.constant(value) : _.constant(), result = constant(); return (result === value) || (result !== result && value !== value); }); assert.deepEqual(actual, expected); }); QUnit.test('should return a wrapped value when chaining', function(assert) { assert.expect(1); if (!isNpm) { var wrapped = _(true).constant(); assert.ok(wrapped instanceof _); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.countBy'); (function() { var array = [6.1, 4.2, 6.3]; QUnit.test('should transform keys by `iteratee`', function(assert) { assert.expect(1); var actual = _.countBy(array, Math.floor); assert.deepEqual(actual, { '4': 1, '6': 2 }); }); QUnit.test('should use `_.identity` when `iteratee` is nullish', function(assert) { assert.expect(1); var array = [4, 6, 6], values = [, null, undefined], expected = lodashStable.map(values, lodashStable.constant({ '4': 1, '6': 2 })); var actual = lodashStable.map(values, function(value, index) { return index ? _.countBy(array, value) : _.countBy(array); }); assert.deepEqual(actual, expected); }); QUnit.test('should work with `_.property` shorthands', function(assert) { assert.expect(1); var actual = _.countBy(['one', 'two', 'three'], 'length'); assert.deepEqual(actual, { '3': 2, '5': 1 }); }); QUnit.test('should only add values to own, not inherited, properties', function(assert) { assert.expect(2); var actual = _.countBy(array, function(n) { return Math.floor(n) > 4 ? 'hasOwnProperty' : 'constructor'; }); assert.deepEqual(actual.constructor, 1); assert.deepEqual(actual.hasOwnProperty, 2); }); QUnit.test('should work with a number for `iteratee`', function(assert) { assert.expect(2); var array = [ [1, 'a'], [2, 'a'], [2, 'b'] ]; assert.deepEqual(_.countBy(array, 0), { '1': 1, '2': 2 }); assert.deepEqual(_.countBy(array, 1), { 'a': 2, 'b': 1 }); }); QUnit.test('should work with an object for `collection`', function(assert) { assert.expect(1); var actual = _.countBy({ 'a': 6.1, 'b': 4.2, 'c': 6.3 }, Math.floor); assert.deepEqual(actual, { '4': 1, '6': 2 }); }); QUnit.test('should work in a lazy sequence', function(assert) { assert.expect(1); if (!isNpm) { var array = lodashStable.range(LARGE_ARRAY_SIZE).concat( lodashStable.range(Math.floor(LARGE_ARRAY_SIZE / 2), LARGE_ARRAY_SIZE), lodashStable.range(Math.floor(LARGE_ARRAY_SIZE / 1.5), LARGE_ARRAY_SIZE) ); var actual = _(array).countBy().map(square).filter(isEven).take().value(); assert.deepEqual(actual, _.take(_.filter(_.map(_.countBy(array), square), isEven))); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.create'); (function() { function Shape() { this.x = 0; this.y = 0; } function Circle() { Shape.call(this); } QUnit.test('should create an object that inherits from the given `prototype` object', function(assert) { assert.expect(3); Circle.prototype = _.create(Shape.prototype); Circle.prototype.constructor = Circle; var actual = new Circle; assert.ok(actual instanceof Circle); assert.ok(actual instanceof Shape); assert.notStrictEqual(Circle.prototype, Shape.prototype); }); QUnit.test('should assign `properties` to the created object', function(assert) { assert.expect(3); var expected = { 'constructor': Circle, 'radius': 0 }; Circle.prototype = _.create(Shape.prototype, expected); var actual = new Circle; assert.ok(actual instanceof Circle); assert.ok(actual instanceof Shape); assert.deepEqual(Circle.prototype, expected); }); QUnit.test('should assign own properties', function(assert) { assert.expect(1); function Foo() { this.a = 1; this.c = 3; } Foo.prototype.b = 2; assert.deepEqual(_.create({}, new Foo), { 'a': 1, 'c': 3 }); }); QUnit.test('should assign properties that shadow those of `prototype`', function(assert) { assert.expect(1); function Foo() { this.a = 1; } var object = _.create(new Foo, { 'a': 1 }); assert.deepEqual(lodashStable.keys(object), ['a']); }); QUnit.test('should accept a falsey `prototype`', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, stubObject); var actual = lodashStable.map(falsey, function(prototype, index) { return index ? _.create(prototype) : _.create(); }); assert.deepEqual(actual, expected); }); QUnit.test('should ignore a primitive `prototype` and use an empty object instead', function(assert) { assert.expect(1); var expected = lodashStable.map(primitives, stubTrue); var actual = lodashStable.map(primitives, function(value, index) { return lodashStable.isPlainObject(index ? _.create(value) : _.create()); }); assert.deepEqual(actual, expected); }); QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(1); var array = [{ 'a': 1 }, { 'a': 1 }, { 'a': 1 }], expected = lodashStable.map(array, stubTrue), objects = lodashStable.map(array, _.create); var actual = lodashStable.map(objects, function(object) { return object.a === 1 && !_.keys(object).length; }); assert.deepEqual(actual, expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.curry'); (function() { function fn(a, b, c, d) { return slice.call(arguments); } QUnit.test('should curry based on the number of arguments given', function(assert) { assert.expect(3); var curried = _.curry(fn), expected = [1, 2, 3, 4]; assert.deepEqual(curried(1)(2)(3)(4), expected); assert.deepEqual(curried(1, 2)(3, 4), expected); assert.deepEqual(curried(1, 2, 3, 4), expected); }); QUnit.test('should allow specifying `arity`', function(assert) { assert.expect(3); var curried = _.curry(fn, 3), expected = [1, 2, 3]; assert.deepEqual(curried(1)(2, 3), expected); assert.deepEqual(curried(1, 2)(3), expected); assert.deepEqual(curried(1, 2, 3), expected); }); QUnit.test('should coerce `arity` to an integer', function(assert) { assert.expect(2); var values = ['0', 0.6, 'xyz'], expected = lodashStable.map(values, stubArray); var actual = lodashStable.map(values, function(arity) { return _.curry(fn, arity)(); }); assert.deepEqual(actual, expected); assert.deepEqual(_.curry(fn, '2')(1)(2), [1, 2]); }); QUnit.test('should support placeholders', function(assert) { assert.expect(4); var curried = _.curry(fn), ph = curried.placeholder; assert.deepEqual(curried(1)(ph, 3)(ph, 4)(2), [1, 2, 3, 4]); assert.deepEqual(curried(ph, 2)(1)(ph, 4)(3), [1, 2, 3, 4]); assert.deepEqual(curried(ph, ph, 3)(ph, 2)(ph, 4)(1), [1, 2, 3, 4]); assert.deepEqual(curried(ph, ph, ph, 4)(ph, ph, 3)(ph, 2)(1), [1, 2, 3, 4]); }); QUnit.test('should persist placeholders', function(assert) { assert.expect(1); var curried = _.curry(fn), ph = curried.placeholder, actual = curried(ph, ph, ph, 'd')('a')(ph)('b')('c'); assert.deepEqual(actual, ['a', 'b', 'c', 'd']); }); QUnit.test('should use `_.placeholder` when set', function(assert) { assert.expect(1); if (!isModularize) { var curried = _.curry(fn), _ph = _.placeholder = {}, ph = curried.placeholder; assert.deepEqual(curried(1)(_ph, 3)(ph, 4), [1, ph, 3, 4]); delete _.placeholder; } else { skipAssert(assert); } }); QUnit.test('should provide additional arguments after reaching the target arity', function(assert) { assert.expect(3); var curried = _.curry(fn, 3); assert.deepEqual(curried(1)(2, 3, 4), [1, 2, 3, 4]); assert.deepEqual(curried(1, 2)(3, 4, 5), [1, 2, 3, 4, 5]); assert.deepEqual(curried(1, 2, 3, 4, 5, 6), [1, 2, 3, 4, 5, 6]); }); QUnit.test('should create a function with a `length` of `0`', function(assert) { assert.expect(6); lodashStable.times(2, function(index) { var curried = index ? _.curry(fn, 4) : _.curry(fn); assert.strictEqual(curried.length, 0); assert.strictEqual(curried(1).length, 0); assert.strictEqual(curried(1, 2).length, 0); }); }); QUnit.test('should ensure `new curried` is an instance of `func`', function(assert) { assert.expect(2); function Foo(value) { return value && object; } var curried = _.curry(Foo), object = {}; assert.ok(new curried(false) instanceof Foo); assert.strictEqual(new curried(true), object); }); QUnit.test('should use `this` binding of function', function(assert) { assert.expect(9); var fn = function(a, b, c) { var value = this || {}; return [value[a], value[b], value[c]]; }; var object = { 'a': 1, 'b': 2, 'c': 3 }, expected = [1, 2, 3]; assert.deepEqual(_.curry(_.bind(fn, object), 3)('a')('b')('c'), expected); assert.deepEqual(_.curry(_.bind(fn, object), 3)('a', 'b')('c'), expected); assert.deepEqual(_.curry(_.bind(fn, object), 3)('a', 'b', 'c'), expected); assert.deepEqual(_.bind(_.curry(fn), object)('a')('b')('c'), Array(3)); assert.deepEqual(_.bind(_.curry(fn), object)('a', 'b')('c'), Array(3)); assert.deepEqual(_.bind(_.curry(fn), object)('a', 'b', 'c'), expected); object.curried = _.curry(fn); assert.deepEqual(object.curried('a')('b')('c'), Array(3)); assert.deepEqual(object.curried('a', 'b')('c'), Array(3)); assert.deepEqual(object.curried('a', 'b', 'c'), expected); }); QUnit.test('should work with partialed methods', function(assert) { assert.expect(2); var curried = _.curry(fn), expected = [1, 2, 3, 4]; var a = _.partial(curried, 1), b = _.bind(a, null, 2), c = _.partialRight(b, 4), d = _.partialRight(b(3), 4); assert.deepEqual(c(3), expected); assert.deepEqual(d(), expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.curryRight'); (function() { function fn(a, b, c, d) { return slice.call(arguments); } QUnit.test('should curry based on the number of arguments given', function(assert) { assert.expect(3); var curried = _.curryRight(fn), expected = [1, 2, 3, 4]; assert.deepEqual(curried(4)(3)(2)(1), expected); assert.deepEqual(curried(3, 4)(1, 2), expected); assert.deepEqual(curried(1, 2, 3, 4), expected); }); QUnit.test('should allow specifying `arity`', function(assert) { assert.expect(3); var curried = _.curryRight(fn, 3), expected = [1, 2, 3]; assert.deepEqual(curried(3)(1, 2), expected); assert.deepEqual(curried(2, 3)(1), expected); assert.deepEqual(curried(1, 2, 3), expected); }); QUnit.test('should coerce `arity` to an integer', function(assert) { assert.expect(2); var values = ['0', 0.6, 'xyz'], expected = lodashStable.map(values, stubArray); var actual = lodashStable.map(values, function(arity) { return _.curryRight(fn, arity)(); }); assert.deepEqual(actual, expected); assert.deepEqual(_.curryRight(fn, '2')(1)(2), [2, 1]); }); QUnit.test('should support placeholders', function(assert) { assert.expect(4); var curried = _.curryRight(fn), expected = [1, 2, 3, 4], ph = curried.placeholder; assert.deepEqual(curried(4)(2, ph)(1, ph)(3), expected); assert.deepEqual(curried(3, ph)(4)(1, ph)(2), expected); assert.deepEqual(curried(ph, ph, 4)(ph, 3)(ph, 2)(1), expected); assert.deepEqual(curried(ph, ph, ph, 4)(ph, ph, 3)(ph, 2)(1), expected); }); QUnit.test('should persist placeholders', function(assert) { assert.expect(1); var curried = _.curryRight(fn), ph = curried.placeholder, actual = curried('a', ph, ph, ph)('b')(ph)('c')('d'); assert.deepEqual(actual, ['a', 'b', 'c', 'd']); }); QUnit.test('should use `_.placeholder` when set', function(assert) { assert.expect(1); if (!isModularize) { var curried = _.curryRight(fn), _ph = _.placeholder = {}, ph = curried.placeholder; assert.deepEqual(curried(4)(2, _ph)(1, ph), [1, 2, ph, 4]); delete _.placeholder; } else { skipAssert(assert); } }); QUnit.test('should provide additional arguments after reaching the target arity', function(assert) { assert.expect(3); var curried = _.curryRight(fn, 3); assert.deepEqual(curried(4)(1, 2, 3), [1, 2, 3, 4]); assert.deepEqual(curried(4, 5)(1, 2, 3), [1, 2, 3, 4, 5]); assert.deepEqual(curried(1, 2, 3, 4, 5, 6), [1, 2, 3, 4, 5, 6]); }); QUnit.test('should create a function with a `length` of `0`', function(assert) { assert.expect(6); lodashStable.times(2, function(index) { var curried = index ? _.curryRight(fn, 4) : _.curryRight(fn); assert.strictEqual(curried.length, 0); assert.strictEqual(curried(4).length, 0); assert.strictEqual(curried(3, 4).length, 0); }); }); QUnit.test('should ensure `new curried` is an instance of `func`', function(assert) { assert.expect(2); function Foo(value) { return value && object; } var curried = _.curryRight(Foo), object = {}; assert.ok(new curried(false) instanceof Foo); assert.strictEqual(new curried(true), object); }); QUnit.test('should use `this` binding of function', function(assert) { assert.expect(9); var fn = function(a, b, c) { var value = this || {}; return [value[a], value[b], value[c]]; }; var object = { 'a': 1, 'b': 2, 'c': 3 }, expected = [1, 2, 3]; assert.deepEqual(_.curryRight(_.bind(fn, object), 3)('c')('b')('a'), expected); assert.deepEqual(_.curryRight(_.bind(fn, object), 3)('b', 'c')('a'), expected); assert.deepEqual(_.curryRight(_.bind(fn, object), 3)('a', 'b', 'c'), expected); assert.deepEqual(_.bind(_.curryRight(fn), object)('c')('b')('a'), Array(3)); assert.deepEqual(_.bind(_.curryRight(fn), object)('b', 'c')('a'), Array(3)); assert.deepEqual(_.bind(_.curryRight(fn), object)('a', 'b', 'c'), expected); object.curried = _.curryRight(fn); assert.deepEqual(object.curried('c')('b')('a'), Array(3)); assert.deepEqual(object.curried('b', 'c')('a'), Array(3)); assert.deepEqual(object.curried('a', 'b', 'c'), expected); }); QUnit.test('should work with partialed methods', function(assert) { assert.expect(2); var curried = _.curryRight(fn), expected = [1, 2, 3, 4]; var a = _.partialRight(curried, 4), b = _.partialRight(a, 3), c = _.bind(b, null, 1), d = _.partial(b(2), 1); assert.deepEqual(c(2), expected); assert.deepEqual(d(), expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('curry methods'); lodashStable.each(['curry', 'curryRight'], function(methodName) { var func = _[methodName], fn = function(a, b) { return slice.call(arguments); }, isCurry = methodName == 'curry'; QUnit.test('`_.' + methodName + '` should not error on functions with the same name as lodash methods', function(assert) { assert.expect(1); function run(a, b) { return a + b; } var curried = func(run); try { var actual = curried(1)(2); } catch (e) {} assert.strictEqual(actual, 3); }); QUnit.test('`_.' + methodName + '` should work for function names that shadow those on `Object.prototype`', function(assert) { assert.expect(1); var curried = _.curry(function hasOwnProperty(a, b, c) { return [a, b, c]; }); var expected = [1, 2, 3]; assert.deepEqual(curried(1)(2)(3), expected); }); QUnit.test('`_.' + methodName + '` should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(2); var array = [fn, fn, fn], object = { 'a': fn, 'b': fn, 'c': fn }; lodashStable.each([array, object], function(collection) { var curries = lodashStable.map(collection, func), expected = lodashStable.map(collection, lodashStable.constant(isCurry ? ['a', 'b'] : ['b', 'a'])); var actual = lodashStable.map(curries, function(curried) { return curried('a')('b'); }); assert.deepEqual(actual, expected); }); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.debounce'); (function() { QUnit.test('should debounce a function', function(assert) { assert.expect(6); var done = assert.async(); var callCount = 0; var debounced = _.debounce(function(value) { ++callCount; return value; }, 32); var results = [debounced('a'), debounced('b'), debounced('c')]; assert.deepEqual(results, [undefined, undefined, undefined]); assert.strictEqual(callCount, 0); setTimeout(function() { assert.strictEqual(callCount, 1); var results = [debounced('d'), debounced('e'), debounced('f')]; assert.deepEqual(results, ['c', 'c', 'c']); assert.strictEqual(callCount, 1); }, 128); setTimeout(function() { assert.strictEqual(callCount, 2); done(); }, 256); }); QUnit.test('subsequent debounced calls return the last `func` result', function(assert) { assert.expect(2); var done = assert.async(); var debounced = _.debounce(identity, 32); debounced('a'); setTimeout(function() { assert.notEqual(debounced('b'), 'b'); }, 64); setTimeout(function() { assert.notEqual(debounced('c'), 'c'); done(); }, 128); }); QUnit.test('should not immediately call `func` when `wait` is `0`', function(assert) { assert.expect(2); var done = assert.async(); var callCount = 0, debounced = _.debounce(function() { ++callCount; }, 0); debounced(); debounced(); assert.strictEqual(callCount, 0); setTimeout(function() { assert.strictEqual(callCount, 1); done(); }, 5); }); QUnit.test('should apply default options', function(assert) { assert.expect(2); var done = assert.async(); var callCount = 0, debounced = _.debounce(function() { callCount++; }, 32, {}); debounced(); assert.strictEqual(callCount, 0); setTimeout(function() { assert.strictEqual(callCount, 1); done(); }, 64); }); QUnit.test('should support a `leading` option', function(assert) { assert.expect(4); var done = assert.async(); var callCounts = [0, 0]; var withLeading = _.debounce(function() { callCounts[0]++; }, 32, { 'leading': true }); var withLeadingAndTrailing = _.debounce(function() { callCounts[1]++; }, 32, { 'leading': true }); withLeading(); assert.strictEqual(callCounts[0], 1); withLeadingAndTrailing(); withLeadingAndTrailing(); assert.strictEqual(callCounts[1], 1); setTimeout(function() { assert.deepEqual(callCounts, [1, 2]); withLeading(); assert.strictEqual(callCounts[0], 2); done(); }, 64); }); QUnit.test('subsequent leading debounced calls return the last `func` result', function(assert) { assert.expect(2); var done = assert.async(); var debounced = _.debounce(identity, 32, { 'leading': true, 'trailing': false }), results = [debounced('a'), debounced('b')]; assert.deepEqual(results, ['a', 'a']); setTimeout(function() { var results = [debounced('c'), debounced('d')]; assert.deepEqual(results, ['c', 'c']); done(); }, 64); }); QUnit.test('should support a `trailing` option', function(assert) { assert.expect(4); var done = assert.async(); var withCount = 0, withoutCount = 0; var withTrailing = _.debounce(function() { withCount++; }, 32, { 'trailing': true }); var withoutTrailing = _.debounce(function() { withoutCount++; }, 32, { 'trailing': false }); withTrailing(); assert.strictEqual(withCount, 0); withoutTrailing(); assert.strictEqual(withoutCount, 0); setTimeout(function() { assert.strictEqual(withCount, 1); assert.strictEqual(withoutCount, 0); done(); }, 64); }); QUnit.test('should support a `maxWait` option', function(assert) { assert.expect(4); var done = assert.async(); var callCount = 0; var debounced = _.debounce(function(value) { ++callCount; return value; }, 32, { 'maxWait': 64 }); debounced(); debounced(); assert.strictEqual(callCount, 0); setTimeout(function() { assert.strictEqual(callCount, 1); debounced(); debounced(); assert.strictEqual(callCount, 1); }, 128); setTimeout(function() { assert.strictEqual(callCount, 2); done(); }, 256); }); QUnit.test('should support `maxWait` in a tight loop', function(assert) { assert.expect(1); var done = assert.async(); var limit = (argv || isPhantom) ? 1000 : 320, withCount = 0, withoutCount = 0; var withMaxWait = _.debounce(function() { withCount++; }, 64, { 'maxWait': 128 }); var withoutMaxWait = _.debounce(function() { withoutCount++; }, 96); var start = +new Date; while ((new Date - start) < limit) { withMaxWait(); withoutMaxWait(); } var actual = [Boolean(withoutCount), Boolean(withCount)]; setTimeout(function() { assert.deepEqual(actual, [false, true]); done(); }, 1); }); QUnit.test('should queue a trailing call for subsequent debounced calls after `maxWait`', function(assert) { assert.expect(1); var done = assert.async(); var callCount = 0; var debounced = _.debounce(function() { ++callCount; }, 200, { 'maxWait': 200 }); debounced(); setTimeout(debounced, 190); setTimeout(debounced, 200); setTimeout(debounced, 210); setTimeout(function() { assert.strictEqual(callCount, 2); done(); }, 500); }); QUnit.test('should cancel `maxDelayed` when `delayed` is invoked', function(assert) { assert.expect(2); var done = assert.async(); var callCount = 0; var debounced = _.debounce(function() { callCount++; }, 32, { 'maxWait': 64 }); debounced(); setTimeout(function() { debounced(); assert.strictEqual(callCount, 1); }, 128); setTimeout(function() { assert.strictEqual(callCount, 2); done(); }, 192); }); QUnit.test('should invoke the trailing call with the correct arguments and `this` binding', function(assert) { assert.expect(2); var done = assert.async(); var actual, callCount = 0, object = {}; var debounced = _.debounce(function(value) { actual = [this]; push.apply(actual, arguments); return ++callCount != 2; }, 32, { 'leading': true, 'maxWait': 64 }); while (true) { if (!debounced.call(object, 'a')) { break; } } setTimeout(function() { assert.strictEqual(callCount, 2); assert.deepEqual(actual, [object, 'a']); done(); }, 64); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.deburr'); (function() { QUnit.test('should convert Latin Unicode letters to basic Latin', function(assert) { assert.expect(1); var actual = lodashStable.map(burredLetters, _.deburr); assert.deepEqual(actual, deburredLetters); }); QUnit.test('should not deburr Latin mathematical operators', function(assert) { assert.expect(1); var operators = ['\xd7', '\xf7'], actual = lodashStable.map(operators, _.deburr); assert.deepEqual(actual, operators); }); QUnit.test('should deburr combining diacritical marks', function(assert) { assert.expect(1); var expected = lodashStable.map(comboMarks, lodashStable.constant('ei')); var actual = lodashStable.map(comboMarks, function(chr) { return _.deburr('e' + chr + 'i'); }); assert.deepEqual(actual, expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.defaults'); (function() { QUnit.test('should assign source properties if missing on `object`', function(assert) { assert.expect(1); var actual = _.defaults({ 'a': 1 }, { 'a': 2, 'b': 2 }); assert.deepEqual(actual, { 'a': 1, 'b': 2 }); }); QUnit.test('should accept multiple sources', function(assert) { assert.expect(2); var expected = { 'a': 1, 'b': 2, 'c': 3 }, actual = _.defaults({ 'a': 1, 'b': 2 }, { 'b': 3 }, { 'c': 3 }); assert.deepEqual(actual, expected); actual = _.defaults({ 'a': 1, 'b': 2 }, { 'b': 3, 'c': 3 }, { 'c': 2 }); assert.deepEqual(actual, expected); }); QUnit.test('should not overwrite `null` values', function(assert) { assert.expect(1); var actual = _.defaults({ 'a': null }, { 'a': 1 }); assert.strictEqual(actual.a, null); }); QUnit.test('should overwrite `undefined` values', function(assert) { assert.expect(1); var actual = _.defaults({ 'a': undefined }, { 'a': 1 }); assert.strictEqual(actual.a, 1); }); QUnit.test('should assign `undefined` values', function(assert) { assert.expect(1); var source = { 'a': undefined, 'b': 1 }, actual = _.defaults({}, source); assert.deepEqual(actual, { 'a': undefined, 'b': 1 }); }); QUnit.test('should assign properties that shadow those on `Object.prototype`', function(assert) { assert.expect(2); var object = { 'constructor': objectProto.constructor, 'hasOwnProperty': objectProto.hasOwnProperty, 'isPrototypeOf': objectProto.isPrototypeOf, 'propertyIsEnumerable': objectProto.propertyIsEnumerable, 'toLocaleString': objectProto.toLocaleString, 'toString': objectProto.toString, 'valueOf': objectProto.valueOf }; var source = { 'constructor': 1, 'hasOwnProperty': 2, 'isPrototypeOf': 3, 'propertyIsEnumerable': 4, 'toLocaleString': 5, 'toString': 6, 'valueOf': 7 }; var expected = lodashStable.clone(source); assert.deepEqual(_.defaults({}, source), expected); expected = lodashStable.clone(object); assert.deepEqual(_.defaults({}, object, source), expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.defaultsDeep'); (function() { QUnit.test('should deep assign source properties if missing on `object`', function(assert) { assert.expect(1); var object = { 'a': { 'b': 2 }, 'd': 4 }, source = { 'a': { 'b': 3, 'c': 3 }, 'e': 5 }, expected = { 'a': { 'b': 2, 'c': 3 }, 'd': 4, 'e': 5 }; assert.deepEqual(_.defaultsDeep(object, source), expected); }); QUnit.test('should accept multiple sources', function(assert) { assert.expect(2); var source1 = { 'a': { 'b': 3 } }, source2 = { 'a': { 'c': 3 } }, source3 = { 'a': { 'b': 3, 'c': 3 } }, source4 = { 'a': { 'c': 4 } }, expected = { 'a': { 'b': 2, 'c': 3 } }; assert.deepEqual(_.defaultsDeep({ 'a': { 'b': 2 } }, source1, source2), expected); assert.deepEqual(_.defaultsDeep({ 'a': { 'b': 2 } }, source3, source4), expected); }); QUnit.test('should not overwrite `null` values', function(assert) { assert.expect(1); var object = { 'a': { 'b': null } }, source = { 'a': { 'b': 2 } }, actual = _.defaultsDeep(object, source); assert.strictEqual(actual.a.b, null); }); QUnit.test('should not overwrite regexp values', function(assert) { assert.expect(1); var object = { 'a': { 'b': /x/ } }, source = { 'a': { 'b': /y/ } }, actual = _.defaultsDeep(object, source); assert.deepEqual(actual.a.b, /x/); }); QUnit.test('should not convert function properties to objects', function(assert) { assert.expect(2); var actual = _.defaultsDeep({}, { 'a': noop }); assert.strictEqual(actual.a, noop); actual = _.defaultsDeep({}, { 'a': { 'b': noop } }); assert.strictEqual(actual.a.b, noop); }); QUnit.test('should overwrite `undefined` values', function(assert) { assert.expect(1); var object = { 'a': { 'b': undefined } }, source = { 'a': { 'b': 2 } }, actual = _.defaultsDeep(object, source); assert.strictEqual(actual.a.b, 2); }); QUnit.test('should assign `undefined` values', function(assert) { assert.expect(1); var source = { 'a': undefined, 'b': { 'c': undefined, 'd': 1 } }, expected = lodashStable.cloneDeep(source), actual = _.defaultsDeep({}, source); assert.deepEqual(actual, expected); }); QUnit.test('should merge sources containing circular references', function(assert) { assert.expect(2); var object = { 'foo': { 'b': { 'c': { 'd': {} } } }, 'bar': { 'a': 2 } }; var source = { 'foo': { 'b': { 'c': { 'd': {} } } }, 'bar': {} }; object.foo.b.c.d = object; source.foo.b.c.d = source; source.bar.b = source.foo.b; var actual = _.defaultsDeep(object, source); assert.strictEqual(actual.bar.b, actual.foo.b); assert.strictEqual(actual.foo.b.c.d, actual.foo.b.c.d.foo.b.c.d); }); QUnit.test('should not modify sources', function(assert) { assert.expect(3); var source1 = { 'a': 1, 'b': { 'c': 2 } }, source2 = { 'b': { 'c': 3, 'd': 3 } }, actual = _.defaultsDeep({}, source1, source2); assert.deepEqual(actual, { 'a': 1, 'b': { 'c': 2, 'd': 3 } }); assert.deepEqual(source1, { 'a': 1, 'b': { 'c': 2 } }); assert.deepEqual(source2, { 'b': { 'c': 3, 'd': 3 } }); }); QUnit.test('should not attempt a merge of a string into an array', function(assert) { assert.expect(1); var actual = _.defaultsDeep({ 'a': ['abc'] }, { 'a': 'abc' }); assert.deepEqual(actual.a, ['abc']); }); QUnit.test('should not indirectly merge `Object` properties', function(assert) { assert.expect(1); _.defaultsDeep({}, { 'constructor': { 'a': 1 } }); var actual = 'a' in Object; delete Object.a; assert.notOk(actual); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.defaultTo'); (function() { QUnit.test('should return a default value if `value` is `NaN` or nullish', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, function(value) { return (value == null || value !== value) ? 1 : value; }); var actual = lodashStable.map(falsey, function(value) { return _.defaultTo(value, 1); }); assert.deepEqual(actual, expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.defer'); (function() { QUnit.test('should defer `func` execution', function(assert) { assert.expect(1); var done = assert.async(); var pass = false; _.defer(function() { pass = true; }); setTimeout(function() { assert.ok(pass); done(); }, 32); }); QUnit.test('should provide additional arguments to `func`', function(assert) { assert.expect(1); var done = assert.async(); var args; _.defer(function() { args = slice.call(arguments); }, 1, 2); setTimeout(function() { assert.deepEqual(args, [1, 2]); done(); }, 32); }); QUnit.test('should be cancelable', function(assert) { assert.expect(1); var done = assert.async(); var pass = true, timerId = _.defer(function() { pass = false; }); clearTimeout(timerId); setTimeout(function() { assert.ok(pass); done(); }, 32); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.delay'); (function() { QUnit.test('should delay `func` execution', function(assert) { assert.expect(2); var done = assert.async(); var pass = false; _.delay(function() { pass = true; }, 32); setTimeout(function() { assert.notOk(pass); }, 1); setTimeout(function() { assert.ok(pass); done(); }, 64); }); QUnit.test('should provide additional arguments to `func`', function(assert) { assert.expect(1); var done = assert.async(); var args; _.delay(function() { args = slice.call(arguments); }, 32, 1, 2); setTimeout(function() { assert.deepEqual(args, [1, 2]); done(); }, 64); }); QUnit.test('should use a default `wait` of `0`', function(assert) { assert.expect(2); var done = assert.async(); var pass = false; _.delay(function() { pass = true; }); assert.notOk(pass); setTimeout(function() { assert.ok(pass); done(); }, 0); }); QUnit.test('should be cancelable', function(assert) { assert.expect(1); var done = assert.async(); var pass = true, timerId = _.delay(function() { pass = false; }, 32); clearTimeout(timerId); setTimeout(function() { assert.ok(pass); done(); }, 64); }); QUnit.test('should work with mocked `setTimeout`', function(assert) { assert.expect(1); if (!isPhantom) { var pass = false, setTimeout = root.setTimeout; setProperty(root, 'setTimeout', function(func) { func(); }); _.delay(function() { pass = true; }, 32); setProperty(root, 'setTimeout', setTimeout); assert.ok(pass); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('difference methods'); lodashStable.each(['difference', 'differenceBy', 'differenceWith'], function(methodName) { var func = _[methodName]; QUnit.test('`_.' + methodName + '` should return the difference of two arrays', function(assert) { assert.expect(1); var actual = func([2, 1], [2, 3]); assert.deepEqual(actual, [1]); }); QUnit.test('`_.' + methodName + '` should return the difference of multiple arrays', function(assert) { assert.expect(1); var actual = func([2, 1, 2, 3], [3, 4], [3, 2]); assert.deepEqual(actual, [1]); }); QUnit.test('`_.' + methodName + '` should treat `-0` as `0`', function(assert) { assert.expect(2); var array = [-0, 0]; var actual = lodashStable.map(array, function(value) { return func(array, [value]); }); assert.deepEqual(actual, [[], []]); actual = lodashStable.map(func([-0, 1], [1]), lodashStable.toString); assert.deepEqual(actual, ['0']); }); QUnit.test('`_.' + methodName + '` should match `NaN`', function(assert) { assert.expect(1); assert.deepEqual(func([1, NaN, 3], [NaN, 5, NaN]), [1, 3]); }); QUnit.test('`_.' + methodName + '` should work with large arrays', function(assert) { assert.expect(1); var array1 = lodashStable.range(LARGE_ARRAY_SIZE + 1), array2 = lodashStable.range(LARGE_ARRAY_SIZE), a = {}, b = {}, c = {}; array1.push(a, b, c); array2.push(b, c, a); assert.deepEqual(func(array1, array2), [LARGE_ARRAY_SIZE]); }); QUnit.test('`_.' + methodName + '` should work with large arrays of `-0` as `0`', function(assert) { assert.expect(2); var array = [-0, 0]; var actual = lodashStable.map(array, function(value) { var largeArray = lodashStable.times(LARGE_ARRAY_SIZE, lodashStable.constant(value)); return func(array, largeArray); }); assert.deepEqual(actual, [[], []]); var largeArray = lodashStable.times(LARGE_ARRAY_SIZE, stubOne); actual = lodashStable.map(func([-0, 1], largeArray), lodashStable.toString); assert.deepEqual(actual, ['0']); }); QUnit.test('`_.' + methodName + '` should work with large arrays of `NaN`', function(assert) { assert.expect(1); var largeArray = lodashStable.times(LARGE_ARRAY_SIZE, stubNaN); assert.deepEqual(func([1, NaN, 3], largeArray), [1, 3]); }); QUnit.test('`_.' + methodName + '` should work with large arrays of objects', function(assert) { assert.expect(1); var object1 = {}, object2 = {}, largeArray = lodashStable.times(LARGE_ARRAY_SIZE, lodashStable.constant(object1)); assert.deepEqual(func([object1, object2], largeArray), [object2]); }); QUnit.test('`_.' + methodName + '` should ignore values that are not array-like', function(assert) { assert.expect(3); var array = [1, null, 3]; assert.deepEqual(func(args, 3, { '0': 1 }), [1, 2, 3]); assert.deepEqual(func(null, array, 1), []); assert.deepEqual(func(array, args, null), [null]); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.differenceBy'); (function() { QUnit.test('should accept an `iteratee`', function(assert) { assert.expect(2); var actual = _.differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); assert.deepEqual(actual, [1.2]); actual = _.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x'); assert.deepEqual(actual, [{ 'x': 2 }]); }); QUnit.test('should provide correct `iteratee` arguments', function(assert) { assert.expect(1); var args; _.differenceBy([2.1, 1.2], [2.3, 3.4], function() { args || (args = slice.call(arguments)); }); assert.deepEqual(args, [2.3]); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.differenceWith'); (function() { QUnit.test('should work with a `comparator`', function(assert) { assert.expect(1); var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }], actual = _.differenceWith(objects, [{ 'x': 1, 'y': 2 }], lodashStable.isEqual); assert.deepEqual(actual, [objects[1]]); }); QUnit.test('should preserve the sign of `0`', function(assert) { assert.expect(1); var array = [-0, 1], largeArray = lodashStable.times(LARGE_ARRAY_SIZE, stubOne), others = [[1], largeArray], expected = lodashStable.map(others, lodashStable.constant(['-0'])); var actual = lodashStable.map(others, function(other) { return lodashStable.map(_.differenceWith(array, other, lodashStable.eq), lodashStable.toString); }); assert.deepEqual(actual, expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.divide'); (function() { QUnit.test('should divide two numbers', function(assert) { assert.expect(3); assert.strictEqual(_.divide(6, 4), 1.5); assert.strictEqual(_.divide(-6, 4), -1.5); assert.strictEqual(_.divide(-6, -4), 1.5); }); QUnit.test('should coerce arguments to numbers', function(assert) { assert.expect(2); assert.strictEqual(_.divide('6', '4'), 1.5); assert.deepEqual(_.divide('x', 'y'), NaN); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.drop'); (function() { var array = [1, 2, 3]; QUnit.test('should drop the first two elements', function(assert) { assert.expect(1); assert.deepEqual(_.drop(array, 2), [3]); }); QUnit.test('should treat falsey `n` values, except `undefined`, as `0`', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, function(value) { return value === undefined ? [2, 3] : array; }); var actual = lodashStable.map(falsey, function(n) { return _.drop(array, n); }); assert.deepEqual(actual, expected); }); QUnit.test('should return all elements when `n` < `1`', function(assert) { assert.expect(3); lodashStable.each([0, -1, -Infinity], function(n) { assert.deepEqual(_.drop(array, n), array); }); }); QUnit.test('should return an empty array when `n` >= `length`', function(assert) { assert.expect(4); lodashStable.each([3, 4, Math.pow(2, 32), Infinity], function(n) { assert.deepEqual(_.drop(array, n), []); }); }); QUnit.test('should coerce `n` to an integer', function(assert) { assert.expect(1); assert.deepEqual(_.drop(array, 1.6), [2, 3]); }); QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(1); var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], actual = lodashStable.map(array, _.drop); assert.deepEqual(actual, [[2, 3], [5, 6], [8, 9]]); }); QUnit.test('should work in a lazy sequence', function(assert) { assert.expect(6); if (!isNpm) { var array = lodashStable.range(1, LARGE_ARRAY_SIZE + 1), predicate = function(value) { values.push(value); return isEven(value); }, values = [], actual = _(array).drop(2).drop().value(); assert.deepEqual(actual, array.slice(3)); actual = _(array).filter(predicate).drop(2).drop().value(); assert.deepEqual(values, array); assert.deepEqual(actual, _.drop(_.drop(_.filter(array, predicate), 2))); actual = _(array).drop(2).dropRight().drop().dropRight(2).value(); assert.deepEqual(actual, _.dropRight(_.drop(_.dropRight(_.drop(array, 2))), 2)); values = []; actual = _(array).drop().filter(predicate).drop(2).dropRight().drop().dropRight(2).value(); assert.deepEqual(values, array.slice(1)); assert.deepEqual(actual, _.dropRight(_.drop(_.dropRight(_.drop(_.filter(_.drop(array), predicate), 2))), 2)); } else { skipAssert(assert, 6); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.dropRight'); (function() { var array = [1, 2, 3]; QUnit.test('should drop the last two elements', function(assert) { assert.expect(1); assert.deepEqual(_.dropRight(array, 2), [1]); }); QUnit.test('should treat falsey `n` values, except `undefined`, as `0`', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, function(value) { return value === undefined ? [1, 2] : array; }); var actual = lodashStable.map(falsey, function(n) { return _.dropRight(array, n); }); assert.deepEqual(actual, expected); }); QUnit.test('should return all elements when `n` < `1`', function(assert) { assert.expect(3); lodashStable.each([0, -1, -Infinity], function(n) { assert.deepEqual(_.dropRight(array, n), array); }); }); QUnit.test('should return an empty array when `n` >= `length`', function(assert) { assert.expect(4); lodashStable.each([3, 4, Math.pow(2, 32), Infinity], function(n) { assert.deepEqual(_.dropRight(array, n), []); }); }); QUnit.test('should coerce `n` to an integer', function(assert) { assert.expect(1); assert.deepEqual(_.dropRight(array, 1.6), [1, 2]); }); QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(1); var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], actual = lodashStable.map(array, _.dropRight); assert.deepEqual(actual, [[1, 2], [4, 5], [7, 8]]); }); QUnit.test('should work in a lazy sequence', function(assert) { assert.expect(6); if (!isNpm) { var array = lodashStable.range(1, LARGE_ARRAY_SIZE + 1), predicate = function(value) { values.push(value); return isEven(value); }, values = [], actual = _(array).dropRight(2).dropRight().value(); assert.deepEqual(actual, array.slice(0, -3)); actual = _(array).filter(predicate).dropRight(2).dropRight().value(); assert.deepEqual(values, array); assert.deepEqual(actual, _.dropRight(_.dropRight(_.filter(array, predicate), 2))); actual = _(array).dropRight(2).drop().dropRight().drop(2).value(); assert.deepEqual(actual, _.drop(_.dropRight(_.drop(_.dropRight(array, 2))), 2)); values = []; actual = _(array).dropRight().filter(predicate).dropRight(2).drop().dropRight().drop(2).value(); assert.deepEqual(values, array.slice(0, -1)); assert.deepEqual(actual, _.drop(_.dropRight(_.drop(_.dropRight(_.filter(_.dropRight(array), predicate), 2))), 2)); } else { skipAssert(assert, 6); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.dropRightWhile'); (function() { var array = [1, 2, 3, 4]; var objects = [ { 'a': 0, 'b': 0 }, { 'a': 1, 'b': 1 }, { 'a': 2, 'b': 2 } ]; QUnit.test('should drop elements while `predicate` returns truthy', function(assert) { assert.expect(1); var actual = _.dropRightWhile(array, function(n) { return n > 2; }); assert.deepEqual(actual, [1, 2]); }); QUnit.test('should provide correct `predicate` arguments', function(assert) { assert.expect(1); var args; _.dropRightWhile(array, function() { args = slice.call(arguments); }); assert.deepEqual(args, [4, 3, array]); }); QUnit.test('should work with `_.matches` shorthands', function(assert) { assert.expect(1); assert.deepEqual(_.dropRightWhile(objects, { 'b': 2 }), objects.slice(0, 2)); }); QUnit.test('should work with `_.matchesProperty` shorthands', function(assert) { assert.expect(1); assert.deepEqual(_.dropRightWhile(objects, ['b', 2]), objects.slice(0, 2)); }); QUnit.test('should work with `_.property` shorthands', function(assert) { assert.expect(1); assert.deepEqual(_.dropRightWhile(objects, 'b'), objects.slice(0, 1)); }); QUnit.test('should return a wrapped value when chaining', function(assert) { assert.expect(2); if (!isNpm) { var wrapped = _(array).dropRightWhile(function(n) { return n > 2; }); assert.ok(wrapped instanceof _); assert.deepEqual(wrapped.value(), [1, 2]); } else { skipAssert(assert, 2); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.dropWhile'); (function() { var array = [1, 2, 3, 4]; var objects = [ { 'a': 2, 'b': 2 }, { 'a': 1, 'b': 1 }, { 'a': 0, 'b': 0 } ]; QUnit.test('should drop elements while `predicate` returns truthy', function(assert) { assert.expect(1); var actual = _.dropWhile(array, function(n) { return n < 3; }); assert.deepEqual(actual, [3, 4]); }); QUnit.test('should provide correct `predicate` arguments', function(assert) { assert.expect(1); var args; _.dropWhile(array, function() { args = slice.call(arguments); }); assert.deepEqual(args, [1, 0, array]); }); QUnit.test('should work with `_.matches` shorthands', function(assert) { assert.expect(1); assert.deepEqual(_.dropWhile(objects, { 'b': 2 }), objects.slice(1)); }); QUnit.test('should work with `_.matchesProperty` shorthands', function(assert) { assert.expect(1); assert.deepEqual(_.dropWhile(objects, ['b', 2]), objects.slice(1)); }); QUnit.test('should work with `_.property` shorthands', function(assert) { assert.expect(1); assert.deepEqual(_.dropWhile(objects, 'b'), objects.slice(2)); }); QUnit.test('should work in a lazy sequence', function(assert) { assert.expect(3); if (!isNpm) { var array = lodashStable.range(1, LARGE_ARRAY_SIZE + 3), predicate = function(n) { return n < 3; }, expected = _.dropWhile(array, predicate), wrapped = _(array).dropWhile(predicate); assert.deepEqual(wrapped.value(), expected); assert.deepEqual(wrapped.reverse().value(), expected.slice().reverse()); assert.strictEqual(wrapped.last(), _.last(expected)); } else { skipAssert(assert, 3); } }); QUnit.test('should work in a lazy sequence with `drop`', function(assert) { assert.expect(1); if (!isNpm) { var array = lodashStable.range(1, LARGE_ARRAY_SIZE + 3); var actual = _(array) .dropWhile(function(n) { return n == 1; }) .drop() .dropWhile(function(n) { return n == 3; }) .value(); assert.deepEqual(actual, array.slice(3)); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.endsWith'); (function() { var string = 'abc'; QUnit.test('should return `true` if a string ends with `target`', function(assert) { assert.expect(1); assert.strictEqual(_.endsWith(string, 'c'), true); }); QUnit.test('should return `false` if a string does not end with `target`', function(assert) { assert.expect(1); assert.strictEqual(_.endsWith(string, 'b'), false); }); QUnit.test('should work with a `position`', function(assert) { assert.expect(1); assert.strictEqual(_.endsWith(string, 'b', 2), true); }); QUnit.test('should work with `position` >= `length`', function(assert) { assert.expect(4); lodashStable.each([3, 5, MAX_SAFE_INTEGER, Infinity], function(position) { assert.strictEqual(_.endsWith(string, 'c', position), true); }); }); QUnit.test('should treat falsey `position` values, except `undefined`, as `0`', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, stubTrue); var actual = lodashStable.map(falsey, function(position) { return _.endsWith(string, position === undefined ? 'c' : '', position); }); assert.deepEqual(actual, expected); }); QUnit.test('should treat a negative `position` as `0`', function(assert) { assert.expect(6); lodashStable.each([-1, -3, -Infinity], function(position) { assert.ok(lodashStable.every(string, function(chr) { return !_.endsWith(string, chr, position); })); assert.strictEqual(_.endsWith(string, '', position), true); }); }); QUnit.test('should coerce `position` to an integer', function(assert) { assert.expect(1); assert.strictEqual(_.endsWith(string, 'ab', 2.2), true); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.eq'); (function() { QUnit.test('should perform a `SameValueZero` comparison of two values', function(assert) { assert.expect(11); assert.strictEqual(_.eq(), true); assert.strictEqual(_.eq(undefined), true); assert.strictEqual(_.eq(0, -0), true); assert.strictEqual(_.eq(NaN, NaN), true); assert.strictEqual(_.eq(1, 1), true); assert.strictEqual(_.eq(null, undefined), false); assert.strictEqual(_.eq(1, Object(1)), false); assert.strictEqual(_.eq(1, '1'), false); assert.strictEqual(_.eq(1, '1'), false); var object = { 'a': 1 }; assert.strictEqual(_.eq(object, object), true); assert.strictEqual(_.eq(object, { 'a': 1 }), false); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.escape'); (function() { var escaped = '&<>"'/', unescaped = '&<>"\'/'; escaped += escaped; unescaped += unescaped; QUnit.test('should escape values', function(assert) { assert.expect(1); assert.strictEqual(_.escape(unescaped), escaped); }); QUnit.test('should handle strings with nothing to escape', function(assert) { assert.expect(1); assert.strictEqual(_.escape('abc'), 'abc'); }); QUnit.test('should escape the same characters unescaped by `_.unescape`', function(assert) { assert.expect(1); assert.strictEqual(_.escape(_.unescape(escaped)), escaped); }); lodashStable.each(['`', '/'], function(chr) { QUnit.test('should not escape the "' + chr + '" character', function(assert) { assert.expect(1); assert.strictEqual(_.escape(chr), chr); }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.escapeRegExp'); (function() { var escaped = '\\^\\$\\.\\*\\+\\?\\(\\)\\[\\]\\{\\}\\|\\\\', unescaped = '^$.*+?()[]{}|\\'; QUnit.test('should escape values', function(assert) { assert.expect(1); assert.strictEqual(_.escapeRegExp(unescaped + unescaped), escaped + escaped); }); QUnit.test('should handle strings with nothing to escape', function(assert) { assert.expect(1); assert.strictEqual(_.escapeRegExp('abc'), 'abc'); }); QUnit.test('should return an empty string for empty values', function(assert) { assert.expect(1); var values = [, null, undefined, ''], expected = lodashStable.map(values, stubString); var actual = lodashStable.map(values, function(value, index) { return index ? _.escapeRegExp(value) : _.escapeRegExp(); }); assert.deepEqual(actual, expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.every'); (function() { QUnit.test('should return `true` if `predicate` returns truthy for all elements', function(assert) { assert.expect(1); assert.strictEqual(lodashStable.every([true, 1, 'a'], identity), true); }); QUnit.test('should return `true` for empty collections', function(assert) { assert.expect(1); var expected = lodashStable.map(empties, stubTrue); var actual = lodashStable.map(empties, function(value) { try { return _.every(value, identity); } catch (e) {} }); assert.deepEqual(actual, expected); }); QUnit.test('should return `false` as soon as `predicate` returns falsey', function(assert) { assert.expect(2); var count = 0; assert.strictEqual(_.every([true, null, true], function(value) { count++; return value; }), false); assert.strictEqual(count, 2); }); QUnit.test('should work with collections of `undefined` values (test in IE < 9)', function(assert) { assert.expect(1); assert.strictEqual(_.every([undefined, undefined, undefined], identity), false); }); QUnit.test('should use `_.identity` when `predicate` is nullish', function(assert) { assert.expect(2); var values = [, null, undefined], expected = lodashStable.map(values, stubFalse); var actual = lodashStable.map(values, function(value, index) { var array = [0]; return index ? _.every(array, value) : _.every(array); }); assert.deepEqual(actual, expected); expected = lodashStable.map(values, stubTrue); actual = lodashStable.map(values, function(value, index) { var array = [1]; return index ? _.every(array, value) : _.every(array); }); assert.deepEqual(actual, expected); }); QUnit.test('should work with `_.property` shorthands', function(assert) { assert.expect(2); var objects = [{ 'a': 0, 'b': 1 }, { 'a': 1, 'b': 2 }]; assert.strictEqual(_.every(objects, 'a'), false); assert.strictEqual(_.every(objects, 'b'), true); }); QUnit.test('should work with `_.matches` shorthands', function(assert) { assert.expect(2); var objects = [{ 'a': 0, 'b': 0 }, { 'a': 0, 'b': 1 }]; assert.strictEqual(_.every(objects, { 'a': 0 }), true); assert.strictEqual(_.every(objects, { 'b': 1 }), false); }); QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(1); var actual = lodashStable.map([[1]], _.every); assert.deepEqual(actual, [true]); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('strict mode checks'); lodashStable.each(['assign', 'assignIn', 'bindAll', 'defaults', 'defaultsDeep', 'merge'], function(methodName) { var func = _[methodName], isBindAll = methodName == 'bindAll'; QUnit.test('`_.' + methodName + '` should ' + (isStrict ? '' : 'not ') + 'throw strict mode errors', function(assert) { assert.expect(1); var object = freeze({ 'a': undefined, 'b': function() {} }), pass = !isStrict; try { func(object, isBindAll ? 'b' : { 'a': 1 }); } catch (e) { pass = !pass; } assert.ok(pass); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.fill'); (function() { QUnit.test('should use a default `start` of `0` and a default `end` of `length`', function(assert) { assert.expect(1); var array = [1, 2, 3]; assert.deepEqual(_.fill(array, 'a'), ['a', 'a', 'a']); }); QUnit.test('should use `undefined` for `value` if not given', function(assert) { assert.expect(2); var array = [1, 2, 3], actual = _.fill(array); assert.deepEqual(actual, Array(3)); assert.ok(lodashStable.every(actual, function(value, index) { return index in actual; })); }); QUnit.test('should work with a positive `start`', function(assert) { assert.expect(1); var array = [1, 2, 3]; assert.deepEqual(_.fill(array, 'a', 1), [1, 'a', 'a']); }); QUnit.test('should work with a `start` >= `length`', function(assert) { assert.expect(4); lodashStable.each([3, 4, Math.pow(2, 32), Infinity], function(start) { var array = [1, 2, 3]; assert.deepEqual(_.fill(array, 'a', start), [1, 2, 3]); }); }); QUnit.test('should treat falsey `start` values as `0`', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, lodashStable.constant(['a', 'a', 'a'])); var actual = lodashStable.map(falsey, function(start) { var array = [1, 2, 3]; return _.fill(array, 'a', start); }); assert.deepEqual(actual, expected); }); QUnit.test('should work with a negative `start`', function(assert) { assert.expect(1); var array = [1, 2, 3]; assert.deepEqual(_.fill(array, 'a', -1), [1, 2, 'a']); }); QUnit.test('should work with a negative `start` <= negative `length`', function(assert) { assert.expect(3); lodashStable.each([-3, -4, -Infinity], function(start) { var array = [1, 2, 3]; assert.deepEqual(_.fill(array, 'a', start), ['a', 'a', 'a']); }); }); QUnit.test('should work with `start` >= `end`', function(assert) { assert.expect(2); lodashStable.each([2, 3], function(start) { var array = [1, 2, 3]; assert.deepEqual(_.fill(array, 'a', start, 2), [1, 2, 3]); }); }); QUnit.test('should work with a positive `end`', function(assert) { assert.expect(1); var array = [1, 2, 3]; assert.deepEqual(_.fill(array, 'a', 0, 1), ['a', 2, 3]); }); QUnit.test('should work with a `end` >= `length`', function(assert) { assert.expect(4); lodashStable.each([3, 4, Math.pow(2, 32), Infinity], function(end) { var array = [1, 2, 3]; assert.deepEqual(_.fill(array, 'a', 0, end), ['a', 'a', 'a']); }); }); QUnit.test('should treat falsey `end` values, except `undefined`, as `0`', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, function(value) { return value === undefined ? ['a', 'a', 'a'] : [1, 2, 3]; }); var actual = lodashStable.map(falsey, function(end) { var array = [1, 2, 3]; return _.fill(array, 'a', 0, end); }); assert.deepEqual(actual, expected); }); QUnit.test('should work with a negative `end`', function(assert) { assert.expect(1); var array = [1, 2, 3]; assert.deepEqual(_.fill(array, 'a', 0, -1), ['a', 'a', 3]); }); QUnit.test('should work with a negative `end` <= negative `length`', function(assert) { assert.expect(3); lodashStable.each([-3, -4, -Infinity], function(end) { var array = [1, 2, 3]; assert.deepEqual(_.fill(array, 'a', 0, end), [1, 2, 3]); }); }); QUnit.test('should coerce `start` and `end` to integers', function(assert) { assert.expect(1); var positions = [[0.1, 1.6], ['0', 1], [0, '1'], ['1'], [NaN, 1], [1, NaN]]; var actual = lodashStable.map(positions, function(pos) { var array = [1, 2, 3]; return _.fill.apply(_, [array, 'a'].concat(pos)); }); assert.deepEqual(actual, [['a', 2, 3], ['a', 2, 3], ['a', 2, 3], [1, 'a', 'a'], ['a', 2, 3], [1, 2, 3]]); }); QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(1); var array = [[1, 2], [3, 4]], actual = lodashStable.map(array, _.fill); assert.deepEqual(actual, [[0, 0], [1, 1]]); }); QUnit.test('should return a wrapped value when chaining', function(assert) { assert.expect(3); if (!isNpm) { var array = [1, 2, 3], wrapped = _(array).fill('a'), actual = wrapped.value(); assert.ok(wrapped instanceof _); assert.strictEqual(actual, array); assert.deepEqual(actual, ['a', 'a', 'a']); } else { skipAssert(assert, 3); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.filter'); (function() { var array = [1, 2, 3]; QUnit.test('should return elements `predicate` returns truthy for', function(assert) { assert.expect(1); assert.deepEqual(_.filter(array, isEven), [2]); }); }()); /*--------------------------------------------------------------------------*/ lodashStable.each(['find', 'findIndex', 'findKey', 'findLast', 'findLastIndex', 'findLastKey'], function(methodName) { QUnit.module('lodash.' + methodName); var array = [1, 2, 3, 4], func = _[methodName]; var objects = [ { 'a': 0, 'b': 0 }, { 'a': 1, 'b': 1 }, { 'a': 2, 'b': 2 } ]; var expected = ({ 'find': [objects[1], undefined, objects[2]], 'findIndex': [1, -1, 2], 'findKey': ['1', undefined, '2'], 'findLast': [objects[2], undefined, objects[2]], 'findLastIndex': [2, -1, 2], 'findLastKey': ['2', undefined, '2'] })[methodName]; QUnit.test('`_.' + methodName + '` should return the found value', function(assert) { assert.expect(1); assert.strictEqual(func(objects, function(object) { return object.a; }), expected[0]); }); QUnit.test('`_.' + methodName + '` should return `' + expected[1] + '` if value is not found', function(assert) { assert.expect(1); assert.strictEqual(func(objects, function(object) { return object.a === 3; }), expected[1]); }); QUnit.test('`_.' + methodName + '` should work with `_.matches` shorthands', function(assert) { assert.expect(1); assert.strictEqual(func(objects, { 'b': 2 }), expected[2]); }); QUnit.test('`_.' + methodName + '` should work with `_.matchesProperty` shorthands', function(assert) { assert.expect(1); assert.strictEqual(func(objects, ['b', 2]), expected[2]); }); QUnit.test('`_.' + methodName + '` should work with `_.property` shorthands', function(assert) { assert.expect(1); assert.strictEqual(func(objects, 'b'), expected[0]); }); QUnit.test('`_.' + methodName + '` should return `' + expected[1] + '` for empty collections', function(assert) { assert.expect(1); var emptyValues = lodashStable.endsWith(methodName, 'Index') ? lodashStable.reject(empties, lodashStable.isPlainObject) : empties, expecting = lodashStable.map(emptyValues, lodashStable.constant(expected[1])); var actual = lodashStable.map(emptyValues, function(value) { try { return func(value, { 'a': 3 }); } catch (e) {} }); assert.deepEqual(actual, expecting); }); QUnit.test('`_.' + methodName + '` should return an unwrapped value when implicitly chaining', function(assert) { assert.expect(1); var expected = ({ 'find': 1, 'findIndex': 0, 'findKey': '0', 'findLast': 4, 'findLastIndex': 3, 'findLastKey': '3' })[methodName]; if (!isNpm) { assert.strictEqual(_(array)[methodName](), expected); } else { skipAssert(assert); } }); QUnit.test('`_.' + methodName + '` should return a wrapped value when explicitly chaining', function(assert) { assert.expect(1); if (!isNpm) { assert.ok(_(array).chain()[methodName]() instanceof _); } else { skipAssert(assert); } }); QUnit.test('`_.' + methodName + '` should not execute immediately when explicitly chaining', function(assert) { assert.expect(1); if (!isNpm) { var wrapped = _(array).chain()[methodName](); assert.strictEqual(wrapped.__wrapped__, array); } else { skipAssert(assert); } }); QUnit.test('`_.' + methodName + '` should work in a lazy sequence', function(assert) { assert.expect(2); if (!isNpm) { var largeArray = lodashStable.range(1, LARGE_ARRAY_SIZE + 1), smallArray = array; lodashStable.times(2, function(index) { var array = index ? largeArray : smallArray, wrapped = _(array).filter(isEven); assert.strictEqual(wrapped[methodName](), func(lodashStable.filter(array, isEven))); }); } else { skipAssert(assert, 2); } }); }); _.each(['find', 'findIndex', 'findLast', 'findLastIndex'], function(methodName) { var func = _[methodName]; QUnit.test('`_.' + methodName + '` should provide correct `predicate` arguments for arrays', function(assert) { assert.expect(1); var args, array = ['a']; func(array, function() { args || (args = slice.call(arguments)); }); assert.deepEqual(args, ['a', 0, array]); }); }); _.each(['find', 'findKey', 'findLast', 'findLastKey'], function(methodName) { var func = _[methodName]; QUnit.test('`_.' + methodName + '` should work with an object for `collection`', function(assert) { assert.expect(1); var actual = func({ 'a': 1, 'b': 2, 'c': 3 }, function(n) { return n < 3; }); var expected = ({ 'find': 1, 'findKey': 'a', 'findLast': 2, 'findLastKey': 'b' })[methodName]; assert.strictEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should provide correct `predicate` arguments for objects', function(assert) { assert.expect(1); var args, object = { 'a': 1 }; func(object, function() { args || (args = slice.call(arguments)); }); assert.deepEqual(args, [1, 'a', object]); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.find and lodash.findLast'); lodashStable.each(['find', 'findLast'], function(methodName) { var isFind = methodName == 'find'; QUnit.test('`_.' + methodName + '` should support shortcut fusion', function(assert) { assert.expect(3); if (!isNpm) { var findCount = 0, mapCount = 0, array = lodashStable.range(1, LARGE_ARRAY_SIZE + 1), iteratee = function(value) { mapCount++; return square(value); }, predicate = function(value) { findCount++; return isEven(value); }, actual = _(array).map(iteratee)[methodName](predicate); assert.strictEqual(findCount, isFind ? 2 : 1); assert.strictEqual(mapCount, isFind ? 2 : 1); assert.strictEqual(actual, isFind ? 4 : square(LARGE_ARRAY_SIZE)); } else { skipAssert(assert, 3); } }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.find and lodash.includes'); lodashStable.each(['includes', 'find'], function(methodName) { var func = _[methodName], isIncludes = methodName == 'includes', resolve = methodName == 'find' ? lodashStable.curry(lodashStable.eq) : identity; lodashStable.each({ 'an `arguments` object': args, 'an array': [1, 2, 3] }, function(collection, key) { var values = lodashStable.toArray(collection); QUnit.test('`_.' + methodName + '` should work with ' + key + ' and a positive `fromIndex`', function(assert) { assert.expect(1); var expected = [ isIncludes || values[2], isIncludes ? false : undefined ]; var actual = [ func(collection, resolve(values[2]), 2), func(collection, resolve(values[1]), 2) ]; assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should work with ' + key + ' and a `fromIndex` >= `length`', function(assert) { assert.expect(1); var indexes = [4, 6, Math.pow(2, 32), Infinity]; var expected = lodashStable.map(indexes, function() { var result = isIncludes ? false : undefined; return [result, result, result]; }); var actual = lodashStable.map(indexes, function(fromIndex) { return [ func(collection, resolve(1), fromIndex), func(collection, resolve(undefined), fromIndex), func(collection, resolve(''), fromIndex) ]; }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should work with ' + key + ' and treat falsey `fromIndex` values as `0`', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, lodashStable.constant(isIncludes || values[0])); var actual = lodashStable.map(falsey, function(fromIndex) { return func(collection, resolve(values[0]), fromIndex); }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should work with ' + key + ' and coerce `fromIndex` to an integer', function(assert) { assert.expect(1); var expected = [ isIncludes || values[0], isIncludes || values[0], isIncludes ? false : undefined ]; var actual = [ func(collection, resolve(values[0]), 0.1), func(collection, resolve(values[0]), NaN), func(collection, resolve(values[0]), '1') ]; assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should work with ' + key + ' and a negative `fromIndex`', function(assert) { assert.expect(1); var expected = [ isIncludes || values[2], isIncludes ? false : undefined ]; var actual = [ func(collection, resolve(values[2]), -1), func(collection, resolve(values[1]), -1) ]; assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should work with ' + key + ' and a negative `fromIndex` <= `-length`', function(assert) { assert.expect(1); var indexes = [-4, -6, -Infinity], expected = lodashStable.map(indexes, lodashStable.constant(isIncludes || values[0])); var actual = lodashStable.map(indexes, function(fromIndex) { return func(collection, resolve(values[0]), fromIndex); }); assert.deepEqual(actual, expected); }); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.findIndex and lodash.indexOf'); lodashStable.each(['findIndex', 'indexOf'], function(methodName) { var array = [1, 2, 3, 1, 2, 3], func = _[methodName], resolve = methodName == 'findIndex' ? lodashStable.curry(lodashStable.eq) : identity; QUnit.test('`_.' + methodName + '` should return the index of the first matched value', function(assert) { assert.expect(1); assert.strictEqual(func(array, resolve(3)), 2); }); QUnit.test('`_.' + methodName + '` should work with a positive `fromIndex`', function(assert) { assert.expect(1); assert.strictEqual(func(array, resolve(1), 2), 3); }); QUnit.test('`_.' + methodName + '` should work with a `fromIndex` >= `length`', function(assert) { assert.expect(1); var values = [6, 8, Math.pow(2, 32), Infinity], expected = lodashStable.map(values, lodashStable.constant([-1, -1, -1])); var actual = lodashStable.map(values, function(fromIndex) { return [ func(array, resolve(undefined), fromIndex), func(array, resolve(1), fromIndex), func(array, resolve(''), fromIndex) ]; }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should work with a negative `fromIndex`', function(assert) { assert.expect(1); assert.strictEqual(func(array, resolve(2), -3), 4); }); QUnit.test('`_.' + methodName + '` should work with a negative `fromIndex` <= `-length`', function(assert) { assert.expect(1); var values = [-6, -8, -Infinity], expected = lodashStable.map(values, stubZero); var actual = lodashStable.map(values, function(fromIndex) { return func(array, resolve(1), fromIndex); }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should treat falsey `fromIndex` values as `0`', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, stubZero); var actual = lodashStable.map(falsey, function(fromIndex) { return func(array, resolve(1), fromIndex); }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should coerce `fromIndex` to an integer', function(assert) { assert.expect(1); assert.strictEqual(func(array, resolve(2), 1.2), 1); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.findLast'); (function() { var resolve = lodashStable.curry(lodashStable.eq); lodashStable.each({ 'an `arguments` object': args, 'an array': [1, 2, 3] }, function(collection, key) { var values = lodashStable.toArray(collection); QUnit.test('should work with ' + key + ' and a positive `fromIndex`', function(assert) { assert.expect(1); var expected = [ values[1], undefined ]; var actual = [ _.findLast(collection, resolve(values[1]), 1), _.findLast(collection, resolve(values[2]), 1) ]; assert.deepEqual(actual, expected); }); QUnit.test('should work with ' + key + ' and a `fromIndex` >= `length`', function(assert) { assert.expect(1); var indexes = [4, 6, Math.pow(2, 32), Infinity]; var expected = lodashStable.map(indexes, lodashStable.constant([values[0], undefined, undefined])); var actual = lodashStable.map(indexes, function(fromIndex) { return [ _.findLast(collection, resolve(1), fromIndex), _.findLast(collection, resolve(undefined), fromIndex), _.findLast(collection, resolve(''), fromIndex) ]; }); assert.deepEqual(actual, expected); }); QUnit.test('should work with ' + key + ' and treat falsey `fromIndex` values correctly', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, function(value) { return value === undefined ? values[3] : undefined; }); var actual = lodashStable.map(falsey, function(fromIndex) { return _.findLast(collection, resolve(values[3]), fromIndex); }); assert.deepEqual(actual, expected); }); QUnit.test('should work with ' + key + ' and coerce `fromIndex` to an integer', function(assert) { assert.expect(1); var expected = [ values[0], values[0], undefined ]; var actual = [ _.findLast(collection, resolve(values[0]), 0.1), _.findLast(collection, resolve(values[0]), NaN), _.findLast(collection, resolve(values[2]), '1') ]; assert.deepEqual(actual, expected); }); QUnit.test('should work with ' + key + ' and a negative `fromIndex`', function(assert) { assert.expect(1); var expected = [ values[1], undefined ]; var actual = [ _.findLast(collection, resolve(values[1]), -2), _.findLast(collection, resolve(values[2]), -2) ]; assert.deepEqual(actual, expected); }); QUnit.test('should work with ' + key + ' and a negative `fromIndex` <= `-length`', function(assert) { assert.expect(1); var indexes = [-4, -6, -Infinity], expected = lodashStable.map(indexes, lodashStable.constant(values[0])); var actual = lodashStable.map(indexes, function(fromIndex) { return _.findLast(collection, resolve(values[0]), fromIndex); }); assert.deepEqual(actual, expected); }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.flip'); (function() { function fn() { return slice.call(arguments); } QUnit.test('should flip arguments provided to `func`', function(assert) { assert.expect(1); var flipped = _.flip(fn); assert.deepEqual(flipped('a', 'b', 'c', 'd'), ['d', 'c', 'b', 'a']); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.flatMapDepth'); (function() { var array = [1, [2, [3, [4]], 5]]; QUnit.test('should use a default `depth` of `1`', function(assert) { assert.expect(1); assert.deepEqual(_.flatMapDepth(array, identity), [1, 2, [3, [4]], 5]); }); QUnit.test('should use `_.identity` when `iteratee` is nullish', function(assert) { assert.expect(1); var values = [, null, undefined], expected = lodashStable.map(values, lodashStable.constant([1, 2, [3, [4]], 5])); var actual = lodashStable.map(values, function(value, index) { return index ? _.flatMapDepth(array, value) : _.flatMapDepth(array); }); assert.deepEqual(actual, expected); }); QUnit.test('should treat a `depth` of < `1` as a shallow clone', function(assert) { assert.expect(2); lodashStable.each([-1, 0], function(depth) { assert.deepEqual(_.flatMapDepth(array, identity, depth), [1, [2, [3, [4]], 5]]); }); }); QUnit.test('should coerce `depth` to an integer', function(assert) { assert.expect(1); assert.deepEqual(_.flatMapDepth(array, identity, 2.2), [1, 2, 3, [4], 5]); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('flatMap methods'); lodashStable.each(['flatMap', 'flatMapDeep', 'flatMapDepth'], function(methodName) { var func = _[methodName], array = [1, 2, 3, 4]; function duplicate(n) { return [n, n]; } QUnit.test('`_.' + methodName + '` should map values in `array` to a new flattened array', function(assert) { assert.expect(1); var actual = func(array, duplicate), expected = lodashStable.flatten(lodashStable.map(array, duplicate)); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should work with `_.property` shorthands', function(assert) { assert.expect(1); var objects = [{ 'a': [1, 2] }, { 'a': [3, 4] }]; assert.deepEqual(func(objects, 'a'), array); }); QUnit.test('`_.' + methodName + '` should iterate over own string keyed properties of objects', function(assert) { assert.expect(1); function Foo() { this.a = [1, 2]; } Foo.prototype.b = [3, 4]; var actual = func(new Foo, identity); assert.deepEqual(actual, [1, 2]); }); QUnit.test('`_.' + methodName + '` should use `_.identity` when `iteratee` is nullish', function(assert) { assert.expect(2); var array = [[1, 2], [3, 4]], object = { 'a': [1, 2], 'b': [3, 4] }, values = [, null, undefined], expected = lodashStable.map(values, lodashStable.constant([1, 2, 3, 4])); lodashStable.each([array, object], function(collection) { var actual = lodashStable.map(values, function(value, index) { return index ? func(collection, value) : func(collection); }); assert.deepEqual(actual, expected); }); }); QUnit.test('`_.' + methodName + '` should accept a falsey `collection`', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, stubArray); var actual = lodashStable.map(falsey, function(collection, index) { try { return index ? func(collection) : func(); } catch (e) {} }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should treat number values for `collection` as empty', function(assert) { assert.expect(1); assert.deepEqual(func(1), []); }); QUnit.test('`_.' + methodName + '` should work with objects with non-number length properties', function(assert) { assert.expect(1); var object = { 'length': [1, 2] }; assert.deepEqual(func(object, identity), [1, 2]); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.flattenDepth'); (function() { var array = [1, [2, [3, [4]], 5]]; QUnit.test('should use a default `depth` of `1`', function(assert) { assert.expect(1); assert.deepEqual(_.flattenDepth(array), [1, 2, [3, [4]], 5]); }); QUnit.test('should treat a `depth` of < `1` as a shallow clone', function(assert) { assert.expect(2); lodashStable.each([-1, 0], function(depth) { assert.deepEqual(_.flattenDepth(array, depth), [1, [2, [3, [4]], 5]]); }); }); QUnit.test('should coerce `depth` to an integer', function(assert) { assert.expect(1); assert.deepEqual(_.flattenDepth(array, 2.2), [1, 2, 3, [4], 5]); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('flatten methods'); (function() { var array = [1, [2, [3, [4]], 5]], methodNames = ['flatten', 'flattenDeep', 'flattenDepth']; QUnit.test('should flatten `arguments` objects', function(assert) { assert.expect(3); var array = [args, [args]]; assert.deepEqual(_.flatten(array), [1, 2, 3, args]); assert.deepEqual(_.flattenDeep(array), [1, 2, 3, 1, 2, 3]); assert.deepEqual(_.flattenDepth(array, 2), [1, 2, 3, 1, 2, 3]); }); QUnit.test('should treat sparse arrays as dense', function(assert) { assert.expect(6); var array = [[1, 2, 3], Array(3)], expected = [1, 2, 3]; expected.push(undefined, undefined, undefined); lodashStable.each(methodNames, function(methodName) { var actual = _[methodName](array); assert.deepEqual(actual, expected); assert.ok('4' in actual); }); }); QUnit.test('should flatten objects with a truthy `Symbol.isConcatSpreadable` value', function(assert) { assert.expect(1); if (Symbol && Symbol.isConcatSpreadable) { var object = { '0': 'a', 'length': 1 }, array = [object], expected = lodashStable.map(methodNames, lodashStable.constant(['a'])); object[Symbol.isConcatSpreadable] = true; var actual = lodashStable.map(methodNames, function(methodName) { return _[methodName](array); }); assert.deepEqual(actual, expected); } else { skipAssert(assert); } }); QUnit.test('should work with extremely large arrays', function(assert) { assert.expect(3); lodashStable.times(3, function(index) { var expected = Array(5e5); try { var func = _.flatten; if (index == 1) { func = _.flattenDeep; } else if (index == 2) { func = _.flattenDepth; } assert.deepEqual(func([expected]), expected); } catch (e) { assert.ok(false, e.message); } }); }); QUnit.test('should work with empty arrays', function(assert) { assert.expect(3); var array = [[], [[]], [[], [[[]]]]]; assert.deepEqual(_.flatten(array), [[], [], [[[]]]]); assert.deepEqual(_.flattenDeep(array), []); assert.deepEqual(_.flattenDepth(array, 2), [[[]]]); }); QUnit.test('should support flattening of nested arrays', function(assert) { assert.expect(3); assert.deepEqual(_.flatten(array), [1, 2, [3, [4]], 5]); assert.deepEqual(_.flattenDeep(array), [1, 2, 3, 4, 5]); assert.deepEqual(_.flattenDepth(array, 2), [1, 2, 3, [4], 5]); }); QUnit.test('should return an empty array for non array-like objects', function(assert) { assert.expect(3); var expected = [], nonArray = { '0': 'a' }; assert.deepEqual(_.flatten(nonArray), expected); assert.deepEqual(_.flattenDeep(nonArray), expected); assert.deepEqual(_.flattenDepth(nonArray, 2), expected); }); QUnit.test('should return a wrapped value when chaining', function(assert) { assert.expect(6); if (!isNpm) { var wrapped = _(array), actual = wrapped.flatten(); assert.ok(actual instanceof _); assert.deepEqual(actual.value(), [1, 2, [3, [4]], 5]); actual = wrapped.flattenDeep(); assert.ok(actual instanceof _); assert.deepEqual(actual.value(), [1, 2, 3, 4, 5]); actual = wrapped.flattenDepth(2); assert.ok(actual instanceof _); assert.deepEqual(actual.value(), [1, 2, 3, [4], 5]); } else { skipAssert(assert, 6); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('flow methods'); lodashStable.each(['flow', 'flowRight'], function(methodName) { var func = _[methodName], isFlow = methodName == 'flow'; QUnit.test('`_.' + methodName + '` should supply each function with the return value of the previous', function(assert) { assert.expect(1); var fixed = function(n) { return n.toFixed(1); }, combined = isFlow ? func(add, square, fixed) : func(fixed, square, add); assert.strictEqual(combined(1, 2), '9.0'); }); QUnit.test('`_.' + methodName + '` should return a new function', function(assert) { assert.expect(1); assert.notStrictEqual(func(noop), noop); }); QUnit.test('`_.' + methodName + '` should return an identity function when no arguments are given', function(assert) { assert.expect(6); _.times(2, function(index) { try { var combined = index ? func([]) : func(); assert.strictEqual(combined('a'), 'a'); } catch (e) { assert.ok(false, e.message); } assert.strictEqual(combined.length, 0); assert.notStrictEqual(combined, identity); }); }); QUnit.test('`_.' + methodName + '` should work with a curried function and `_.head`', function(assert) { assert.expect(1); var curried = _.curry(identity); var combined = isFlow ? func(_.head, curried) : func(curried, _.head); assert.strictEqual(combined([1]), 1); }); QUnit.test('`_.' + methodName + '` should support shortcut fusion', function(assert) { assert.expect(6); var filterCount, mapCount, array = lodashStable.range(LARGE_ARRAY_SIZE), iteratee = function(value) { mapCount++; return square(value); }, predicate = function(value) { filterCount++; return isEven(value); }; lodashStable.times(2, function(index) { var filter1 = _.filter, filter2 = _.curry(_.rearg(_.ary(_.filter, 2), 1, 0), 2), filter3 = (_.filter = index ? filter2 : filter1, filter2(predicate)); var map1 = _.map, map2 = _.curry(_.rearg(_.ary(_.map, 2), 1, 0), 2), map3 = (_.map = index ? map2 : map1, map2(iteratee)); var take1 = _.take, take2 = _.curry(_.rearg(_.ary(_.take, 2), 1, 0), 2), take3 = (_.take = index ? take2 : take1, take2(2)); var combined = isFlow ? func(map3, filter3, _.compact, take3) : func(take3, _.compact, filter3, map3); filterCount = mapCount = 0; assert.deepEqual(combined(array), [4, 16]); if (!isNpm && WeakMap && WeakMap.name) { assert.strictEqual(filterCount, 5, 'filterCount'); assert.strictEqual(mapCount, 5, 'mapCount'); } else { skipAssert(assert, 2); } _.filter = filter1; _.map = map1; _.take = take1; }); }); QUnit.test('`_.' + methodName + '` should work with curried functions with placeholders', function(assert) { assert.expect(1); var curried = _.curry(_.ary(_.map, 2), 2), getProp = curried(curried.placeholder, 'a'), objects = [{ 'a': 1 }, { 'a': 2 }, { 'a': 1 }]; var combined = isFlow ? func(getProp, _.uniq) : func(_.uniq, getProp); assert.deepEqual(combined(objects), [1, 2]); }); QUnit.test('`_.' + methodName + '` should return a wrapped value when chaining', function(assert) { assert.expect(1); if (!isNpm) { var wrapped = _(noop)[methodName](); assert.ok(wrapped instanceof _); } else { skipAssert(assert); } }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.forEach'); (function() { QUnit.test('should be aliased', function(assert) { assert.expect(1); assert.strictEqual(_.each, _.forEach); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.forEachRight'); (function() { QUnit.test('should be aliased', function(assert) { assert.expect(1); assert.strictEqual(_.eachRight, _.forEachRight); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('forIn methods'); lodashStable.each(['forIn', 'forInRight'], function(methodName) { var func = _[methodName]; QUnit.test('`_.' + methodName + '` iterates over inherited string keyed properties', function(assert) { assert.expect(1); function Foo() { this.a = 1; } Foo.prototype.b = 2; var keys = []; func(new Foo, function(value, key) { keys.push(key); }); assert.deepEqual(keys.sort(), ['a', 'b']); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('forOwn methods'); lodashStable.each(['forOwn', 'forOwnRight'], function(methodName) { var func = _[methodName]; QUnit.test('`_.' + methodName + '` should iterate over `length` properties', function(assert) { assert.expect(1); var object = { '0': 'zero', '1': 'one', 'length': 2 }, props = []; func(object, function(value, prop) { props.push(prop); }); assert.deepEqual(props.sort(), ['0', '1', 'length']); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('iteration methods'); (function() { var methods = [ '_baseEach', 'countBy', 'every', 'filter', 'find', 'findIndex', 'findKey', 'findLast', 'findLastIndex', 'findLastKey', 'forEach', 'forEachRight', 'forIn', 'forInRight', 'forOwn', 'forOwnRight', 'groupBy', 'keyBy', 'map', 'mapKeys', 'mapValues', 'maxBy', 'minBy', 'omitBy', 'partition', 'pickBy', 'reject', 'some' ]; var arrayMethods = [ 'findIndex', 'findLastIndex', 'maxBy', 'minBy' ]; var collectionMethods = [ '_baseEach', 'countBy', 'every', 'filter', 'find', 'findLast', 'forEach', 'forEachRight', 'groupBy', 'keyBy', 'map', 'partition', 'reduce', 'reduceRight', 'reject', 'some' ]; var forInMethods = [ 'forIn', 'forInRight', 'omitBy', 'pickBy' ]; var iterationMethods = [ '_baseEach', 'forEach', 'forEachRight', 'forIn', 'forInRight', 'forOwn', 'forOwnRight' ]; var objectMethods = [ 'findKey', 'findLastKey', 'forIn', 'forInRight', 'forOwn', 'forOwnRight', 'mapKeys', 'mapValues', 'omitBy', 'pickBy' ]; var rightMethods = [ 'findLast', 'findLastIndex', 'findLastKey', 'forEachRight', 'forInRight', 'forOwnRight' ]; var unwrappedMethods = [ 'each', 'eachRight', 'every', 'find', 'findIndex', 'findKey', 'findLast', 'findLastIndex', 'findLastKey', 'forEach', 'forEachRight', 'forIn', 'forInRight', 'forOwn', 'forOwnRight', 'max', 'maxBy', 'min', 'minBy', 'some' ]; lodashStable.each(methods, function(methodName) { var array = [1, 2, 3], func = _[methodName], isBy = /(^partition|By)$/.test(methodName), isFind = /^find/.test(methodName), isOmitPick = /^(?:omit|pick)By$/.test(methodName), isSome = methodName == 'some'; QUnit.test('`_.' + methodName + '` should provide correct iteratee arguments', function(assert) { assert.expect(1); if (func) { var args, expected = [1, 0, array]; func(array, function() { args || (args = slice.call(arguments)); }); if (lodashStable.includes(rightMethods, methodName)) { expected[0] = 3; expected[1] = 2; } if (lodashStable.includes(objectMethods, methodName)) { expected[1] += ''; } if (isBy) { expected.length = isOmitPick ? 2 : 1; } assert.deepEqual(args, expected); } else { skipAssert(assert); } }); QUnit.test('`_.' + methodName + '` should treat sparse arrays as dense', function(assert) { assert.expect(1); if (func) { var array = [1]; array[2] = 3; var expected = lodashStable.includes(objectMethods, methodName) ? [[1, '0', array], [undefined, '1', array], [3, '2', array]] : [[1, 0, array], [undefined, 1, array], [3, 2, array]]; if (isBy) { expected = lodashStable.map(expected, function(args) { return args.slice(0, isOmitPick ? 2 : 1); }); } else if (lodashStable.includes(objectMethods, methodName)) { expected = lodashStable.map(expected, function(args) { args[1] += ''; return args; }); } if (lodashStable.includes(rightMethods, methodName)) { expected.reverse(); } var argsList = []; func(array, function() { argsList.push(slice.call(arguments)); return !(isFind || isSome); }); assert.deepEqual(argsList, expected); } else { skipAssert(assert); } }); }); lodashStable.each(lodashStable.difference(methods, objectMethods), function(methodName) { var array = [1, 2, 3], func = _[methodName], isEvery = methodName == 'every'; array.a = 1; QUnit.test('`_.' + methodName + '` should not iterate custom properties on arrays', function(assert) { assert.expect(1); if (func) { var keys = []; func(array, function(value, key) { keys.push(key); return isEvery; }); assert.notOk(lodashStable.includes(keys, 'a')); } else { skipAssert(assert); } }); }); lodashStable.each(lodashStable.difference(methods, unwrappedMethods), function(methodName) { var array = [1, 2, 3], isBaseEach = methodName == '_baseEach'; QUnit.test('`_.' + methodName + '` should return a wrapped value when implicitly chaining', function(assert) { assert.expect(1); if (!(isBaseEach || isNpm)) { var wrapped = _(array)[methodName](noop); assert.ok(wrapped instanceof _); } else { skipAssert(assert); } }); }); lodashStable.each(unwrappedMethods, function(methodName) { var array = [1, 2, 3]; QUnit.test('`_.' + methodName + '` should return an unwrapped value when implicitly chaining', function(assert) { assert.expect(1); if (!isNpm) { var actual = _(array)[methodName](noop); assert.notOk(actual instanceof _); } else { skipAssert(assert); } }); QUnit.test('`_.' + methodName + '` should return a wrapped value when explicitly chaining', function(assert) { assert.expect(2); if (!isNpm) { var wrapped = _(array).chain(), actual = wrapped[methodName](noop); assert.ok(actual instanceof _); assert.notStrictEqual(actual, wrapped); } else { skipAssert(assert, 2); } }); }); lodashStable.each(lodashStable.difference(methods, arrayMethods, forInMethods), function(methodName) { var func = _[methodName]; QUnit.test('`_.' + methodName + '` iterates over own string keyed properties of objects', function(assert) { assert.expect(1); function Foo() { this.a = 1; } Foo.prototype.b = 2; if (func) { var values = []; func(new Foo, function(value) { values.push(value); }); assert.deepEqual(values, [1]); } else { skipAssert(assert); } }); }); lodashStable.each(iterationMethods, function(methodName) { var array = [1, 2, 3], func = _[methodName]; QUnit.test('`_.' + methodName + '` should return the collection', function(assert) { assert.expect(1); if (func) { assert.strictEqual(func(array, Boolean), array); } else { skipAssert(assert); } }); }); lodashStable.each(collectionMethods, function(methodName) { var func = _[methodName]; QUnit.test('`_.' + methodName + '` should use `isArrayLike` to determine whether a value is array-like', function(assert) { assert.expect(3); if (func) { var isIteratedAsObject = function(object) { var result = false; func(object, function() { result = true; }, 0); return result; }; var values = [-1, '1', 1.1, Object(1), MAX_SAFE_INTEGER + 1], expected = lodashStable.map(values, stubTrue); var actual = lodashStable.map(values, function(length) { return isIteratedAsObject({ 'length': length }); }); var Foo = function(a) {}; Foo.a = 1; assert.deepEqual(actual, expected); assert.ok(isIteratedAsObject(Foo)); assert.notOk(isIteratedAsObject({ 'length': 0 })); } else { skipAssert(assert, 3); } }); }); lodashStable.each(methods, function(methodName) { var func = _[methodName], isFind = /^find/.test(methodName), isSome = methodName == 'some', isReduce = /^reduce/.test(methodName); QUnit.test('`_.' + methodName + '` should ignore changes to `length`', function(assert) { assert.expect(1); if (func) { var count = 0, array = [1]; func(array, function() { if (++count == 1) { array.push(2); } return !(isFind || isSome); }, isReduce ? array : null); assert.strictEqual(count, 1); } else { skipAssert(assert); } }); }); lodashStable.each(lodashStable.difference(lodashStable.union(methods, collectionMethods), arrayMethods), function(methodName) { var func = _[methodName], isFind = /^find/.test(methodName), isSome = methodName == 'some', isReduce = /^reduce/.test(methodName); QUnit.test('`_.' + methodName + '` should ignore added `object` properties', function(assert) { assert.expect(1); if (func) { var count = 0, object = { 'a': 1 }; func(object, function() { if (++count == 1) { object.b = 2; } return !(isFind || isSome); }, isReduce ? object : null); assert.strictEqual(count, 1); } else { skipAssert(assert); } }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('object assignments'); lodashStable.each(['assign', 'assignIn', 'defaults', 'defaultsDeep', 'merge'], function(methodName) { var func = _[methodName], isAssign = methodName == 'assign', isDefaults = /^defaults/.test(methodName); QUnit.test('`_.' + methodName + '` should coerce primitives to objects', function(assert) { assert.expect(1); var expected = lodashStable.map(primitives, function(value) { var object = Object(value); object.a = 1; return object; }); var actual = lodashStable.map(primitives, function(value) { return func(value, { 'a': 1 }); }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should assign own ' + (isAssign ? '' : 'and inherited ') + 'string keyed source properties', function(assert) { assert.expect(1); function Foo() { this.a = 1; } Foo.prototype.b = 2; var expected = isAssign ? { 'a': 1 } : { 'a': 1, 'b': 2 }; assert.deepEqual(func({}, new Foo), expected); }); QUnit.test('`_.' + methodName + '` should not skip a trailing function source', function(assert) { assert.expect(1); function fn() {} fn.b = 2; assert.deepEqual(func({}, { 'a': 1 }, fn), { 'a': 1, 'b': 2 }); }); QUnit.test('`_.' + methodName + '` should not error on nullish sources', function(assert) { assert.expect(1); try { assert.deepEqual(func({ 'a': 1 }, undefined, { 'b': 2 }, null), { 'a': 1, 'b': 2 }); } catch (e) { assert.ok(false, e.message); } }); QUnit.test('`_.' + methodName + '` should create an object when `object` is nullish', function(assert) { assert.expect(2); var source = { 'a': 1 }, values = [null, undefined], expected = lodashStable.map(values, stubTrue); var actual = lodashStable.map(values, function(value) { var object = func(value, source); return object !== source && lodashStable.isEqual(object, source); }); assert.deepEqual(actual, expected); actual = lodashStable.map(values, function(value) { return lodashStable.isEqual(func(value), {}); }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should work as an iteratee for methods like `_.reduce`', function(assert) { assert.expect(2); var array = [{ 'a': 1 }, { 'b': 2 }, { 'c': 3 }], expected = { 'a': isDefaults ? 0 : 1, 'b': 2, 'c': 3 }; function fn() {}; fn.a = array[0]; fn.b = array[1]; fn.c = array[2]; assert.deepEqual(lodashStable.reduce(array, func, { 'a': 0 }), expected); assert.deepEqual(lodashStable.reduce(fn, func, { 'a': 0 }), expected); }); QUnit.test('`_.' + methodName + '` should not return the existing wrapped value when chaining', function(assert) { assert.expect(1); if (!isNpm) { var wrapped = _({ 'a': 1 }), actual = wrapped[methodName]({ 'b': 2 }); assert.notStrictEqual(actual, wrapped); } else { skipAssert(assert); } }); }); lodashStable.each(['assign', 'assignIn', 'merge'], function(methodName) { var func = _[methodName]; QUnit.test('`_.' + methodName + '` should not treat `object` as `source`', function(assert) { assert.expect(1); function Foo() {} Foo.prototype.a = 1; var actual = func(new Foo, { 'b': 2 }); assert.notOk(_.has(actual, 'a')); }); }); lodashStable.each(['assign', 'assignIn', 'assignInWith', 'assignWith', 'defaults', 'defaultsDeep', 'merge', 'mergeWith'], function(methodName) { var func = _[methodName]; QUnit.test('`_.' + methodName + '` should not assign values that are the same as their destinations', function(assert) { assert.expect(4); lodashStable.each(['a', ['a'], { 'a': 1 }, NaN], function(value) { var object = {}, pass = true; defineProperty(object, 'a', { 'configurable': true, 'enumerable': true, 'get': lodashStable.constant(value), 'set': function() { pass = false; } }); func(object, { 'a': value }); assert.ok(pass); }); }); }); lodashStable.each(['assignWith', 'assignInWith', 'mergeWith'], function(methodName) { var func = _[methodName], isMergeWith = methodName == 'mergeWith'; QUnit.test('`_.' + methodName + '` should provide correct `customizer` arguments', function(assert) { assert.expect(3); var args, object = { 'a': 1 }, source = { 'a': 2 }, expected = lodashStable.map([1, 2, 'a', object, source], lodashStable.cloneDeep); func(object, source, function() { args || (args = lodashStable.map(slice.call(arguments, 0, 5), lodashStable.cloneDeep)); }); assert.deepEqual(args, expected, 'primitive values'); var argsList = [], objectValue = [1, 2], sourceValue = { 'b': 2 }; object = { 'a': objectValue }; source = { 'a': sourceValue }; expected = [lodashStable.map([objectValue, sourceValue, 'a', object, source], lodashStable.cloneDeep)]; if (isMergeWith) { expected.push(lodashStable.map([undefined, 2, 'b', objectValue, sourceValue], lodashStable.cloneDeep)); } func(object, source, function() { argsList.push(lodashStable.map(slice.call(arguments, 0, 5), lodashStable.cloneDeep)); }); assert.deepEqual(argsList, expected, 'object values'); args = undefined; object = { 'a': 1 }; source = { 'b': 2 }; expected = lodashStable.map([undefined, 2, 'b', object, source], lodashStable.cloneDeep); func(object, source, function() { args || (args = lodashStable.map(slice.call(arguments, 0, 5), lodashStable.cloneDeep)); }); assert.deepEqual(args, expected, 'undefined properties'); }); QUnit.test('`_.' + methodName + '` should not treat the second argument as a `customizer` callback', function(assert) { assert.expect(2); function callback() {} callback.b = 2; var actual = func({ 'a': 1 }, callback); assert.deepEqual(actual, { 'a': 1, 'b': 2 }); actual = func({ 'a': 1 }, callback, { 'c': 3 }); assert.deepEqual(actual, { 'a': 1, 'b': 2, 'c': 3 }); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('exit early'); lodashStable.each(['_baseEach', 'forEach', 'forEachRight', 'forIn', 'forInRight', 'forOwn', 'forOwnRight', 'transform'], function(methodName) { var func = _[methodName]; QUnit.test('`_.' + methodName + '` can exit early when iterating arrays', function(assert) { assert.expect(1); if (func) { var array = [1, 2, 3], values = []; func(array, function(value, other) { values.push(lodashStable.isArray(value) ? other : value); return false; }); assert.deepEqual(values, [lodashStable.endsWith(methodName, 'Right') ? 3 : 1]); } else { skipAssert(assert); } }); QUnit.test('`_.' + methodName + '` can exit early when iterating objects', function(assert) { assert.expect(1); if (func) { var object = { 'a': 1, 'b': 2, 'c': 3 }, values = []; func(object, function(value, other) { values.push(lodashStable.isArray(value) ? other : value); return false; }); assert.strictEqual(values.length, 1); } else { skipAssert(assert); } }); }); /*--------------------------------------------------------------------------*/ QUnit.module('`__proto__` property bugs'); (function() { QUnit.test('should work with the "__proto__" key in internal data objects', function(assert) { assert.expect(4); var stringLiteral = '__proto__', stringObject = Object(stringLiteral), expected = [stringLiteral, stringObject]; var largeArray = lodashStable.times(LARGE_ARRAY_SIZE, function(count) { return isEven(count) ? stringLiteral : stringObject; }); assert.deepEqual(_.difference(largeArray, largeArray), []); assert.deepEqual(_.intersection(largeArray, largeArray), expected); assert.deepEqual(_.uniq(largeArray), expected); assert.deepEqual(_.without.apply(_, [largeArray].concat(largeArray)), []); }); QUnit.test('should treat "__proto__" as a regular key in assignments', function(assert) { assert.expect(2); var methods = [ 'assign', 'assignIn', 'defaults', 'defaultsDeep', 'merge' ]; var source = create(null); source.__proto__ = []; var expected = lodashStable.map(methods, stubFalse); var actual = lodashStable.map(methods, function(methodName) { var result = _[methodName]({}, source); return result instanceof Array; }); assert.deepEqual(actual, expected); actual = _.groupBy([{ 'a': '__proto__' }], 'a'); assert.notOk(actual instanceof Array); }); QUnit.test('should not merge "__proto__" properties', function(assert) { assert.expect(1); if (JSON) { _.merge({}, JSON.parse('{"__proto__":{"a":1}}')); var actual = 'a' in objectProto; delete objectProto.a; assert.notOk(actual); } else { skipAssert(assert); } }); QUnit.test('should not indirectly merge builtin prototype properties', function(assert) { assert.expect(2); _.merge({}, { 'toString': { 'constructor': { 'prototype': { 'a': 1 } } } }); var actual = 'a' in funcProto; delete funcProto.a; assert.notOk(actual); _.merge({}, { 'constructor': { 'prototype': { 'a': 1 } } }); actual = 'a' in objectProto; delete objectProto.a; assert.notOk(actual); }); QUnit.test('should not indirectly merge `Object` properties', function(assert) { assert.expect(1); _.merge({}, { 'constructor': { 'a': 1 } }); var actual = 'a' in Object; delete Object.a; assert.notOk(actual); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.fromPairs'); (function() { QUnit.test('should accept a two dimensional array', function(assert) { assert.expect(1); var array = [['a', 1], ['b', 2]], object = { 'a': 1, 'b': 2 }, actual = _.fromPairs(array); assert.deepEqual(actual, object); }); QUnit.test('should accept a falsey `array`', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, stubObject); var actual = lodashStable.map(falsey, function(array, index) { try { return index ? _.fromPairs(array) : _.fromPairs(); } catch (e) {} }); assert.deepEqual(actual, expected); }); QUnit.test('should not support deep paths', function(assert) { assert.expect(1); var actual = _.fromPairs([['a.b', 1]]); assert.deepEqual(actual, { 'a.b': 1 }); }); QUnit.test('should support consuming the return value of `_.toPairs`', function(assert) { assert.expect(1); var object = { 'a.b': 1 }; assert.deepEqual(_.fromPairs(_.toPairs(object)), object); }); QUnit.test('should work in a lazy sequence', function(assert) { assert.expect(1); if (!isNpm) { var array = lodashStable.times(LARGE_ARRAY_SIZE, function(index) { return ['key' + index, index]; }); var actual = _(array).fromPairs().map(square).filter(isEven).take().value(); assert.deepEqual(actual, _.take(_.filter(_.map(_.fromPairs(array), square), isEven))); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.functions'); (function() { QUnit.test('should return the function names of an object', function(assert) { assert.expect(1); var object = { 'a': 'a', 'b': identity, 'c': /x/, 'd': noop }, actual = _.functions(object).sort(); assert.deepEqual(actual, ['b', 'd']); }); QUnit.test('should not include inherited functions', function(assert) { assert.expect(1); function Foo() { this.a = identity; this.b = 'b'; } Foo.prototype.c = noop; assert.deepEqual(_.functions(new Foo), ['a']); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.groupBy'); (function() { var array = [6.1, 4.2, 6.3]; QUnit.test('should transform keys by `iteratee`', function(assert) { assert.expect(1); var actual = _.groupBy(array, Math.floor); assert.deepEqual(actual, { '4': [4.2], '6': [6.1, 6.3] }); }); QUnit.test('should use `_.identity` when `iteratee` is nullish', function(assert) { assert.expect(1); var array = [6, 4, 6], values = [, null, undefined], expected = lodashStable.map(values, lodashStable.constant({ '4': [4], '6': [6, 6] })); var actual = lodashStable.map(values, function(value, index) { return index ? _.groupBy(array, value) : _.groupBy(array); }); assert.deepEqual(actual, expected); }); QUnit.test('should work with `_.property` shorthands', function(assert) { assert.expect(1); var actual = _.groupBy(['one', 'two', 'three'], 'length'); assert.deepEqual(actual, { '3': ['one', 'two'], '5': ['three'] }); }); QUnit.test('should only add values to own, not inherited, properties', function(assert) { assert.expect(2); var actual = _.groupBy(array, function(n) { return Math.floor(n) > 4 ? 'hasOwnProperty' : 'constructor'; }); assert.deepEqual(actual.constructor, [4.2]); assert.deepEqual(actual.hasOwnProperty, [6.1, 6.3]); }); QUnit.test('should work with a number for `iteratee`', function(assert) { assert.expect(2); var array = [ [1, 'a'], [2, 'a'], [2, 'b'] ]; assert.deepEqual(_.groupBy(array, 0), { '1': [[1, 'a']], '2': [[2, 'a'], [2, 'b']] }); assert.deepEqual(_.groupBy(array, 1), { 'a': [[1, 'a'], [2, 'a']], 'b': [[2, 'b']] }); }); QUnit.test('should work with an object for `collection`', function(assert) { assert.expect(1); var actual = _.groupBy({ 'a': 6.1, 'b': 4.2, 'c': 6.3 }, Math.floor); assert.deepEqual(actual, { '4': [4.2], '6': [6.1, 6.3] }); }); QUnit.test('should work in a lazy sequence', function(assert) { assert.expect(1); if (!isNpm) { var array = lodashStable.range(LARGE_ARRAY_SIZE).concat( lodashStable.range(Math.floor(LARGE_ARRAY_SIZE / 2), LARGE_ARRAY_SIZE), lodashStable.range(Math.floor(LARGE_ARRAY_SIZE / 1.5), LARGE_ARRAY_SIZE) ); var iteratee = function(value) { value.push(value[0]); return value; }, predicate = function(value) { return isEven(value[0]); }, actual = _(array).groupBy().map(iteratee).filter(predicate).take().value(); assert.deepEqual(actual, _.take(_.filter(lodashStable.map(_.groupBy(array), iteratee), predicate))); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.gt'); (function() { QUnit.test('should return `true` if `value` > `other`', function(assert) { assert.expect(2); assert.strictEqual(_.gt(3, 1), true); assert.strictEqual(_.gt('def', 'abc'), true); }); QUnit.test('should return `false` if `value` is <= `other`', function(assert) { assert.expect(4); assert.strictEqual(_.gt(1, 3), false); assert.strictEqual(_.gt(3, 3), false); assert.strictEqual(_.gt('abc', 'def'), false); assert.strictEqual(_.gt('def', 'def'), false); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.gte'); (function() { QUnit.test('should return `true` if `value` >= `other`', function(assert) { assert.expect(4); assert.strictEqual(_.gte(3, 1), true); assert.strictEqual(_.gte(3, 3), true); assert.strictEqual(_.gte('def', 'abc'), true); assert.strictEqual(_.gte('def', 'def'), true); }); QUnit.test('should return `false` if `value` is less than `other`', function(assert) { assert.expect(2); assert.strictEqual(_.gte(1, 3), false); assert.strictEqual(_.gte('abc', 'def'), false); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('has methods'); lodashStable.each(['has', 'hasIn'], function(methodName) { var func = _[methodName], isHas = methodName == 'has', sparseArgs = toArgs([1]), sparseArray = Array(1), sparseString = Object('a'); delete sparseArgs[0]; delete sparseString[0]; QUnit.test('`_.' + methodName + '` should check for own properties', function(assert) { assert.expect(2); var object = { 'a': 1 }; lodashStable.each(['a', ['a']], function(path) { assert.strictEqual(func(object, path), true); }); }); QUnit.test('`_.' + methodName + '` should not use the `hasOwnProperty` method of `object`', function(assert) { assert.expect(1); var object = { 'hasOwnProperty': null, 'a': 1 }; assert.strictEqual(func(object, 'a'), true); }); QUnit.test('`_.' + methodName + '` should support deep paths', function(assert) { assert.expect(4); var object = { 'a': { 'b': 2 } }; lodashStable.each(['a.b', ['a', 'b']], function(path) { assert.strictEqual(func(object, path), true); }); lodashStable.each(['a.a', ['a', 'a']], function(path) { assert.strictEqual(func(object, path), false); }); }); QUnit.test('`_.' + methodName + '` should coerce `path` to a string', function(assert) { assert.expect(2); function fn() {} fn.toString = lodashStable.constant('fn'); var object = { 'null': 1 , 'undefined': 2, 'fn': 3, '[object Object]': 4 }, paths = [null, undefined, fn, {}], expected = lodashStable.map(paths, stubTrue); lodashStable.times(2, function(index) { var actual = lodashStable.map(paths, function(path) { return func(object, index ? [path] : path); }); assert.deepEqual(actual, expected); }); }); QUnit.test('`_.' + methodName + '` should work with `arguments` objects', function(assert) { assert.expect(1); assert.strictEqual(func(args, 1), true); }); QUnit.test('`_.' + methodName + '` should work with a non-string `path`', function(assert) { assert.expect(2); var array = [1, 2, 3]; lodashStable.each([1, [1]], function(path) { assert.strictEqual(func(array, path), true); }); }); QUnit.test('`_.' + methodName + '` should preserve the sign of `0`', function(assert) { assert.expect(1); var object = { '-0': 'a', '0': 'b' }, props = [-0, Object(-0), 0, Object(0)], expected = lodashStable.map(props, stubTrue); var actual = lodashStable.map(props, function(key) { return func(object, key); }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should work with a symbol `path`', function(assert) { assert.expect(2); function Foo() {} if (Symbol) { Foo.prototype[symbol] = 1; var symbol2 = Symbol('b'); defineProperty(Foo.prototype, symbol2, { 'configurable': true, 'enumerable': false, 'writable': true, 'value': 2 }); var object = isHas ? Foo.prototype : new Foo; assert.strictEqual(func(object, symbol), true); assert.strictEqual(func(object, symbol2), true); } else { skipAssert(assert, 2); } }); QUnit.test('`_.' + methodName + '` should check for a key over a path', function(assert) { assert.expect(2); var object = { 'a.b': 1 }; lodashStable.each(['a.b', ['a.b']], function(path) { assert.strictEqual(func(object, path), true); }); }); QUnit.test('`_.' + methodName + '` should return `true` for indexes of sparse values', function(assert) { assert.expect(1); var values = [sparseArgs, sparseArray, sparseString], expected = lodashStable.map(values, stubTrue); var actual = lodashStable.map(values, function(value) { return func(value, 0); }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should return `true` for indexes of sparse values with deep paths', function(assert) { assert.expect(1); var values = [sparseArgs, sparseArray, sparseString], expected = lodashStable.map(values, lodashStable.constant([true, true])); var actual = lodashStable.map(values, function(value) { return lodashStable.map(['a[0]', ['a', '0']], function(path) { return func({ 'a': value }, path); }); }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should return `' + (isHas ? 'false' : 'true') + '` for inherited properties', function(assert) { assert.expect(2); function Foo() {} Foo.prototype.a = 1; lodashStable.each(['a', ['a']], function(path) { assert.strictEqual(func(new Foo, path), !isHas); }); }); QUnit.test('`_.' + methodName + '` should return `' + (isHas ? 'false' : 'true') + '` for nested inherited properties', function(assert) { assert.expect(2); function Foo() {} Foo.prototype.a = { 'b': 1 }; lodashStable.each(['a.b', ['a', 'b']], function(path) { assert.strictEqual(func(new Foo, path), !isHas); }); }); QUnit.test('`_.' + methodName + '` should return `false` when `object` is nullish', function(assert) { assert.expect(2); var values = [null, undefined], expected = lodashStable.map(values, stubFalse); lodashStable.each(['constructor', ['constructor']], function(path) { var actual = lodashStable.map(values, function(value) { return func(value, path); }); assert.deepEqual(actual, expected); }); }); QUnit.test('`_.' + methodName + '` should return `false` for deep paths when `object` is nullish', function(assert) { assert.expect(2); var values = [null, undefined], expected = lodashStable.map(values, stubFalse); lodashStable.each(['constructor.prototype.valueOf', ['constructor', 'prototype', 'valueOf']], function(path) { var actual = lodashStable.map(values, function(value) { return func(value, path); }); assert.deepEqual(actual, expected); }); }); QUnit.test('`_.' + methodName + '` should return `false` for nullish values of nested objects', function(assert) { assert.expect(2); var values = [, null, undefined], expected = lodashStable.map(values, stubFalse); lodashStable.each(['a.b', ['a', 'b']], function(path) { var actual = lodashStable.map(values, function(value, index) { var object = index ? { 'a': value } : {}; return func(object, path); }); assert.deepEqual(actual, expected); }); }); QUnit.test('`_.' + methodName + '` should return `false` over sparse values of deep paths', function(assert) { assert.expect(1); var values = [sparseArgs, sparseArray, sparseString], expected = lodashStable.map(values, lodashStable.constant([false, false])); var actual = lodashStable.map(values, function(value) { return lodashStable.map(['a[0].b', ['a', '0', 'b']], function(path) { return func({ 'a': value }, path); }); }); assert.deepEqual(actual, expected); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.head'); (function() { var array = [1, 2, 3, 4]; QUnit.test('should return the first element', function(assert) { assert.expect(1); assert.strictEqual(_.head(array), 1); }); QUnit.test('should return `undefined` when querying empty arrays', function(assert) { assert.expect(1); arrayProto[0] = 1; assert.strictEqual(_.head([]), undefined); arrayProto.length = 0; }); QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(1); var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], actual = lodashStable.map(array, _.head); assert.deepEqual(actual, [1, 4, 7]); }); QUnit.test('should be aliased', function(assert) { assert.expect(1); assert.strictEqual(_.first, _.head); }); QUnit.test('should return an unwrapped value when implicitly chaining', function(assert) { assert.expect(2); if (!isNpm) { var wrapped = _(array); assert.strictEqual(wrapped.head(), 1); assert.strictEqual(wrapped.first(), 1); } else { skipAssert(assert, 2); } }); QUnit.test('should return a wrapped value when explicitly chaining', function(assert) { assert.expect(2); if (!isNpm) { var wrapped = _(array).chain(); assert.ok(wrapped.head() instanceof _); assert.ok(wrapped.first() instanceof _); } else { skipAssert(assert, 2); } }); QUnit.test('should not execute immediately when explicitly chaining', function(assert) { assert.expect(2); if (!isNpm) { var wrapped = _(array).chain(); assert.strictEqual(wrapped.head().__wrapped__, array); assert.strictEqual(wrapped.first().__wrapped__, array); } else { skipAssert(assert, 2); } }); QUnit.test('should work in a lazy sequence', function(assert) { assert.expect(4); if (!isNpm) { var largeArray = lodashStable.range(LARGE_ARRAY_SIZE), smallArray = array; lodashStable.each(['head', 'first'], function(methodName) { lodashStable.times(2, function(index) { var array = index ? largeArray : smallArray, actual = _(array).filter(isEven)[methodName](); assert.strictEqual(actual, _[methodName](_.filter(array, isEven))); }); }); } else { skipAssert(assert, 4); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.identity'); (function() { QUnit.test('should return the first argument given', function(assert) { assert.expect(1); var object = { 'name': 'fred' }; assert.strictEqual(_.identity(object), object); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.includes'); (function() { lodashStable.each({ 'an `arguments` object': arguments, 'an array': [1, 2, 3, 4], 'an object': { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }, 'a string': '1234' }, function(collection, key) { QUnit.test('should work with ' + key + ' and return `true` for matched values', function(assert) { assert.expect(1); assert.strictEqual(_.includes(collection, 3), true); }); QUnit.test('should work with ' + key + ' and return `false` for unmatched values', function(assert) { assert.expect(1); assert.strictEqual(_.includes(collection, 5), false); }); QUnit.test('should work with ' + key + ' and floor `position` values', function(assert) { assert.expect(1); assert.strictEqual(_.includes(collection, 2, 1.2), true); }); QUnit.test('should work with ' + key + ' and return an unwrapped value implicitly when chaining', function(assert) { assert.expect(1); if (!isNpm) { assert.strictEqual(_(collection).includes(3), true); } else { skipAssert(assert); } }); QUnit.test('should work with ' + key + ' and return a wrapped value when explicitly chaining', function(assert) { assert.expect(1); if (!isNpm) { assert.ok(_(collection).chain().includes(3) instanceof _); } else { skipAssert(assert); } }); }); lodashStable.each({ 'literal': 'abc', 'object': Object('abc') }, function(collection, key) { QUnit.test('should work with a string ' + key + ' for `collection`', function(assert) { assert.expect(2); assert.strictEqual(_.includes(collection, 'bc'), true); assert.strictEqual(_.includes(collection, 'd'), false); }); }); QUnit.test('should return `false` for empty collections', function(assert) { assert.expect(1); var expected = lodashStable.map(empties, stubFalse); var actual = lodashStable.map(empties, function(value) { try { return _.includes(value); } catch (e) {} }); assert.deepEqual(actual, expected); }); QUnit.test('should work with a string and a `fromIndex` >= `length`', function(assert) { assert.expect(1); var string = '1234', length = string.length, indexes = [4, 6, Math.pow(2, 32), Infinity]; var expected = lodashStable.map(indexes, function(index) { return [false, false, index == length]; }); var actual = lodashStable.map(indexes, function(fromIndex) { return [ _.includes(string, 1, fromIndex), _.includes(string, undefined, fromIndex), _.includes(string, '', fromIndex) ]; }); assert.deepEqual(actual, expected); }); QUnit.test('should match `NaN`', function(assert) { assert.expect(1); assert.strictEqual(_.includes([1, NaN, 3], NaN), true); }); QUnit.test('should match `-0` as `0`', function(assert) { assert.expect(2); assert.strictEqual(_.includes([-0], 0), true); assert.strictEqual(_.includes([0], -0), true); }); QUnit.test('should work as an iteratee for methods like `_.every`', function(assert) { assert.expect(1); var array = [2, 3, 1], values = [1, 2, 3]; assert.ok(lodashStable.every(values, lodashStable.partial(_.includes, array))); }); }(1, 2, 3, 4)); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.initial'); (function() { var array = [1, 2, 3]; QUnit.test('should accept a falsey `array`', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, stubArray); var actual = lodashStable.map(falsey, function(array, index) { try { return index ? _.initial(array) : _.initial(); } catch (e) {} }); assert.deepEqual(actual, expected); }); QUnit.test('should exclude last element', function(assert) { assert.expect(1); assert.deepEqual(_.initial(array), [1, 2]); }); QUnit.test('should return an empty when querying empty arrays', function(assert) { assert.expect(1); assert.deepEqual(_.initial([]), []); }); QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(1); var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], actual = lodashStable.map(array, _.initial); assert.deepEqual(actual, [[1, 2], [4, 5], [7, 8]]); }); QUnit.test('should work in a lazy sequence', function(assert) { assert.expect(4); if (!isNpm) { var array = lodashStable.range(LARGE_ARRAY_SIZE), values = []; var actual = _(array).initial().filter(function(value) { values.push(value); return false; }) .value(); assert.deepEqual(actual, []); assert.deepEqual(values, _.initial(array)); values = []; actual = _(array).filter(function(value) { values.push(value); return isEven(value); }) .initial() .value(); assert.deepEqual(actual, _.initial(lodashStable.filter(array, isEven))); assert.deepEqual(values, array); } else { skipAssert(assert, 4); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.inRange'); (function() { QUnit.test('should work with an `end`', function(assert) { assert.expect(3); assert.strictEqual(_.inRange(3, 5), true); assert.strictEqual(_.inRange(5, 5), false); assert.strictEqual(_.inRange(6, 5), false); }); QUnit.test('should work with a `start` and `end`', function(assert) { assert.expect(4); assert.strictEqual(_.inRange(1, 1, 5), true); assert.strictEqual(_.inRange(3, 1, 5), true); assert.strictEqual(_.inRange(0, 1, 5), false); assert.strictEqual(_.inRange(5, 1, 5), false); }); QUnit.test('should treat falsey `start` as `0`', function(assert) { assert.expect(13); lodashStable.each(falsey, function(value, index) { if (index) { assert.strictEqual(_.inRange(0, value), false); assert.strictEqual(_.inRange(0, value, 1), true); } else { assert.strictEqual(_.inRange(0), false); } }); }); QUnit.test('should swap `start` and `end` when `start` > `end`', function(assert) { assert.expect(2); assert.strictEqual(_.inRange(2, 5, 1), true); assert.strictEqual(_.inRange(-3, -2, -6), true); }); QUnit.test('should work with a floating point `n` value', function(assert) { assert.expect(4); assert.strictEqual(_.inRange(0.5, 5), true); assert.strictEqual(_.inRange(1.2, 1, 5), true); assert.strictEqual(_.inRange(5.2, 5), false); assert.strictEqual(_.inRange(0.5, 1, 5), false); }); QUnit.test('should coerce arguments to finite numbers', function(assert) { assert.expect(1); var actual = [ _.inRange(0, '1'), _.inRange(0, '0', 1), _.inRange(0, 0, '1'), _.inRange(0, NaN, 1), _.inRange(-1, -1, NaN) ]; assert.deepEqual(actual, lodashStable.map(actual, stubTrue)); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('intersection methods'); lodashStable.each(['intersection', 'intersectionBy', 'intersectionWith'], function(methodName) { var func = _[methodName]; QUnit.test('`_.' + methodName + '` should return the intersection of two arrays', function(assert) { assert.expect(1); var actual = func([2, 1], [2, 3]); assert.deepEqual(actual, [2]); }); QUnit.test('`_.' + methodName + '` should return the intersection of multiple arrays', function(assert) { assert.expect(1); var actual = func([2, 1, 2, 3], [3, 4], [3, 2]); assert.deepEqual(actual, [3]); }); QUnit.test('`_.' + methodName + '` should return an array of unique values', function(assert) { assert.expect(1); var actual = func([1, 1, 3, 2, 2], [5, 2, 2, 1, 4], [2, 1, 1]); assert.deepEqual(actual, [1, 2]); }); QUnit.test('`_.' + methodName + '` should work with a single array', function(assert) { assert.expect(1); var actual = func([1, 1, 3, 2, 2]); assert.deepEqual(actual, [1, 3, 2]); }); QUnit.test('`_.' + methodName + '` should work with `arguments` objects', function(assert) { assert.expect(2); var array = [0, 1, null, 3], expected = [1, 3]; assert.deepEqual(func(array, args), expected); assert.deepEqual(func(args, array), expected); }); QUnit.test('`_.' + methodName + '` should treat `-0` as `0`', function(assert) { assert.expect(1); var values = [-0, 0], expected = lodashStable.map(values, lodashStable.constant(['0'])); var actual = lodashStable.map(values, function(value) { return lodashStable.map(func(values, [value]), lodashStable.toString); }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should match `NaN`', function(assert) { assert.expect(1); var actual = func([1, NaN, 3], [NaN, 5, NaN]); assert.deepEqual(actual, [NaN]); }); QUnit.test('`_.' + methodName + '` should work with large arrays of `-0` as `0`', function(assert) { assert.expect(1); var values = [-0, 0], expected = lodashStable.map(values, lodashStable.constant(['0'])); var actual = lodashStable.map(values, function(value) { var largeArray = lodashStable.times(LARGE_ARRAY_SIZE, lodashStable.constant(value)); return lodashStable.map(func(values, largeArray), lodashStable.toString); }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should work with large arrays of `NaN`', function(assert) { assert.expect(1); var largeArray = lodashStable.times(LARGE_ARRAY_SIZE, stubNaN); assert.deepEqual(func([1, NaN, 3], largeArray), [NaN]); }); QUnit.test('`_.' + methodName + '` should work with large arrays of objects', function(assert) { assert.expect(2); var object = {}, largeArray = lodashStable.times(LARGE_ARRAY_SIZE, lodashStable.constant(object)); assert.deepEqual(func([object], largeArray), [object]); assert.deepEqual(func(lodashStable.range(LARGE_ARRAY_SIZE), [1]), [1]); }); QUnit.test('`_.' + methodName + '` should treat values that are not arrays or `arguments` objects as empty', function(assert) { assert.expect(3); var array = [0, 1, null, 3]; assert.deepEqual(func(array, 3, { '0': 1 }, null), []); assert.deepEqual(func(null, array, null, [2, 3]), []); assert.deepEqual(func(array, null, args, null), []); }); QUnit.test('`_.' + methodName + '` should return a wrapped value when chaining', function(assert) { assert.expect(2); if (!isNpm) { var wrapped = _([1, 3, 2])[methodName]([5, 2, 1, 4]); assert.ok(wrapped instanceof _); assert.deepEqual(wrapped.value(), [1, 2]); } else { skipAssert(assert, 2); } }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.intersectionBy'); (function() { QUnit.test('should accept an `iteratee`', function(assert) { assert.expect(2); var actual = _.intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor); assert.deepEqual(actual, [2.1]); actual = _.intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); assert.deepEqual(actual, [{ 'x': 1 }]); }); QUnit.test('should provide correct `iteratee` arguments', function(assert) { assert.expect(1); var args; _.intersectionBy([2.1, 1.2], [2.3, 3.4], function() { args || (args = slice.call(arguments)); }); assert.deepEqual(args, [2.3]); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.intersectionWith'); (function() { QUnit.test('should work with a `comparator`', function(assert) { assert.expect(1); var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }], others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }], actual = _.intersectionWith(objects, others, lodashStable.isEqual); assert.deepEqual(actual, [objects[0]]); }); QUnit.test('should preserve the sign of `0`', function(assert) { assert.expect(1); var array = [-0], largeArray = lodashStable.times(LARGE_ARRAY_SIZE, stubZero), others = [[0], largeArray], expected = lodashStable.map(others, lodashStable.constant(['-0'])); var actual = lodashStable.map(others, function(other) { return lodashStable.map(_.intersectionWith(array, other, lodashStable.eq), lodashStable.toString); }); assert.deepEqual(actual, expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.invert'); (function() { QUnit.test('should invert an object', function(assert) { assert.expect(2); var object = { 'a': 1, 'b': 2 }, actual = _.invert(object); assert.deepEqual(actual, { '1': 'a', '2': 'b' }); assert.deepEqual(_.invert(actual), { 'a': '1', 'b': '2' }); }); QUnit.test('should work with values that shadow keys on `Object.prototype`', function(assert) { assert.expect(1); var object = { 'a': 'hasOwnProperty', 'b': 'constructor' }; assert.deepEqual(_.invert(object), { 'hasOwnProperty': 'a', 'constructor': 'b' }); }); QUnit.test('should work with an object that has a `length` property', function(assert) { assert.expect(1); var object = { '0': 'a', '1': 'b', 'length': 2 }; assert.deepEqual(_.invert(object), { 'a': '0', 'b': '1', '2': 'length' }); }); QUnit.test('should return a wrapped value when chaining', function(assert) { assert.expect(2); if (!isNpm) { var object = { 'a': 1, 'b': 2 }, wrapped = _(object).invert(); assert.ok(wrapped instanceof _); assert.deepEqual(wrapped.value(), { '1': 'a', '2': 'b' }); } else { skipAssert(assert, 2); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.invertBy'); (function() { var object = { 'a': 1, 'b': 2, 'c': 1 }; QUnit.test('should transform keys by `iteratee`', function(assert) { assert.expect(1); var expected = { 'group1': ['a', 'c'], 'group2': ['b'] }; var actual = _.invertBy(object, function(value) { return 'group' + value; }); assert.deepEqual(actual, expected); }); QUnit.test('should use `_.identity` when `iteratee` is nullish', function(assert) { assert.expect(1); var values = [, null, undefined], expected = lodashStable.map(values, lodashStable.constant({ '1': ['a', 'c'], '2': ['b'] })); var actual = lodashStable.map(values, function(value, index) { return index ? _.invertBy(object, value) : _.invertBy(object); }); assert.deepEqual(actual, expected); }); QUnit.test('should only add multiple values to own, not inherited, properties', function(assert) { assert.expect(1); var object = { 'a': 'hasOwnProperty', 'b': 'constructor' }, expected = { 'hasOwnProperty': ['a'], 'constructor': ['b'] }; assert.ok(lodashStable.isEqual(_.invertBy(object), expected)); }); QUnit.test('should return a wrapped value when chaining', function(assert) { assert.expect(2); if (!isNpm) { var wrapped = _(object).invertBy(); assert.ok(wrapped instanceof _); assert.deepEqual(wrapped.value(), { '1': ['a', 'c'], '2': ['b'] }); } else { skipAssert(assert, 2); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.invoke'); (function() { QUnit.test('should invoke a method on `object`', function(assert) { assert.expect(1); var object = { 'a': lodashStable.constant('A') }, actual = _.invoke(object, 'a'); assert.strictEqual(actual, 'A'); }); QUnit.test('should support invoking with arguments', function(assert) { assert.expect(1); var object = { 'a': function(a, b) { return [a, b]; } }, actual = _.invoke(object, 'a', 1, 2); assert.deepEqual(actual, [1, 2]); }); QUnit.test('should not error on nullish elements', function(assert) { assert.expect(1); var values = [null, undefined], expected = lodashStable.map(values, noop); var actual = lodashStable.map(values, function(value) { try { return _.invoke(value, 'a.b', 1, 2); } catch (e) {} }); assert.deepEqual(actual, expected); }); QUnit.test('should preserve the sign of `0`', function(assert) { assert.expect(1); var object = { '-0': stubA, '0': stubB }, props = [-0, Object(-0), 0, Object(0)]; var actual = lodashStable.map(props, function(key) { return _.invoke(object, key); }); assert.deepEqual(actual, ['a', 'a', 'b', 'b']); }); QUnit.test('should support deep paths', function(assert) { assert.expect(2); var object = { 'a': { 'b': function(a, b) { return [a, b]; } } }; lodashStable.each(['a.b', ['a', 'b']], function(path) { var actual = _.invoke(object, path, 1, 2); assert.deepEqual(actual, [1, 2]); }); }); QUnit.test('should invoke deep property methods with the correct `this` binding', function(assert) { assert.expect(2); var object = { 'a': { 'b': function() { return this.c; }, 'c': 1 } }; lodashStable.each(['a.b', ['a', 'b']], function(path) { assert.deepEqual(_.invoke(object, path), 1); }); }); QUnit.test('should return an unwrapped value when implicitly chaining', function(assert) { assert.expect(1); if (!isNpm) { var object = { 'a': stubOne }; assert.strictEqual(_(object).invoke('a'), 1); } else { skipAssert(assert); } }); QUnit.test('should return a wrapped value when explicitly chaining', function(assert) { assert.expect(1); if (!isNpm) { var object = { 'a': stubOne }; assert.ok(_(object).chain().invoke('a') instanceof _); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.invokeMap'); (function() { QUnit.test('should invoke a methods on each element of `collection`', function(assert) { assert.expect(1); var array = ['a', 'b', 'c'], actual = _.invokeMap(array, 'toUpperCase'); assert.deepEqual(actual, ['A', 'B', 'C']); }); QUnit.test('should support invoking with arguments', function(assert) { assert.expect(1); var array = [function() { return slice.call(arguments); }], actual = _.invokeMap(array, 'call', null, 'a', 'b', 'c'); assert.deepEqual(actual, [['a', 'b', 'c']]); }); QUnit.test('should work with a function for `methodName`', function(assert) { assert.expect(1); var array = ['a', 'b', 'c']; var actual = _.invokeMap(array, function(left, right) { return left + this.toUpperCase() + right; }, '(', ')'); assert.deepEqual(actual, ['(A)', '(B)', '(C)']); }); QUnit.test('should work with an object for `collection`', function(assert) { assert.expect(1); var object = { 'a': 1, 'b': 2, 'c': 3 }, actual = _.invokeMap(object, 'toFixed', 1); assert.deepEqual(actual, ['1.0', '2.0', '3.0']); }); QUnit.test('should treat number values for `collection` as empty', function(assert) { assert.expect(1); assert.deepEqual(_.invokeMap(1), []); }); QUnit.test('should not error on nullish elements', function(assert) { assert.expect(1); var array = ['a', null, undefined, 'd']; try { var actual = _.invokeMap(array, 'toUpperCase'); } catch (e) {} assert.deepEqual(actual, ['A', undefined, undefined, 'D']); }); QUnit.test('should not error on elements with missing properties', function(assert) { assert.expect(1); var objects = lodashStable.map([null, undefined, stubOne], function(value) { return { 'a': value }; }); var expected = lodashStable.map(objects, function(object) { return object.a ? object.a() : undefined; }); try { var actual = _.invokeMap(objects, 'a'); } catch (e) {} assert.deepEqual(actual, expected); }); QUnit.test('should invoke deep property methods with the correct `this` binding', function(assert) { assert.expect(2); var object = { 'a': { 'b': function() { return this.c; }, 'c': 1 } }; lodashStable.each(['a.b', ['a', 'b']], function(path) { assert.deepEqual(_.invokeMap([object], path), [1]); }); }); QUnit.test('should return a wrapped value when chaining', function(assert) { assert.expect(4); if (!isNpm) { var array = ['a', 'b', 'c'], wrapped = _(array), actual = wrapped.invokeMap('toUpperCase'); assert.ok(actual instanceof _); assert.deepEqual(actual.valueOf(), ['A', 'B', 'C']); actual = wrapped.invokeMap(function(left, right) { return left + this.toUpperCase() + right; }, '(', ')'); assert.ok(actual instanceof _); assert.deepEqual(actual.valueOf(), ['(A)', '(B)', '(C)']); } else { skipAssert(assert, 4); } }); QUnit.test('should support shortcut fusion', function(assert) { assert.expect(2); if (!isNpm) { var count = 0, method = function() { count++; return this.index; }; var array = lodashStable.times(LARGE_ARRAY_SIZE, function(index) { return { 'index': index, 'method': method }; }); var actual = _(array).invokeMap('method').take(1).value(); assert.strictEqual(count, 1); assert.deepEqual(actual, [0]); } else { skipAssert(assert, 2); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isArguments'); (function() { QUnit.test('should return `true` for `arguments` objects', function(assert) { assert.expect(2); assert.strictEqual(_.isArguments(args), true); assert.strictEqual(_.isArguments(strictArgs), true); }); QUnit.test('should return `false` for non `arguments` objects', function(assert) { assert.expect(12); var expected = lodashStable.map(falsey, stubFalse); var actual = lodashStable.map(falsey, function(value, index) { return index ? _.isArguments(value) : _.isArguments(); }); assert.deepEqual(actual, expected); assert.strictEqual(_.isArguments([1, 2, 3]), false); assert.strictEqual(_.isArguments(true), false); assert.strictEqual(_.isArguments(new Date), false); assert.strictEqual(_.isArguments(new Error), false); assert.strictEqual(_.isArguments(_), false); assert.strictEqual(_.isArguments(slice), false); assert.strictEqual(_.isArguments({ '0': 1, 'callee': noop, 'length': 1 }), false); assert.strictEqual(_.isArguments(1), false); assert.strictEqual(_.isArguments(/x/), false); assert.strictEqual(_.isArguments('a'), false); assert.strictEqual(_.isArguments(symbol), false); }); QUnit.test('should work with an `arguments` object from another realm', function(assert) { assert.expect(1); if (realm.arguments) { assert.strictEqual(_.isArguments(realm.arguments), true); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isArray'); (function() { QUnit.test('should return `true` for arrays', function(assert) { assert.expect(1); assert.strictEqual(_.isArray([1, 2, 3]), true); }); QUnit.test('should return `false` for non-arrays', function(assert) { assert.expect(12); var expected = lodashStable.map(falsey, stubFalse); var actual = lodashStable.map(falsey, function(value, index) { return index ? _.isArray(value) : _.isArray(); }); assert.deepEqual(actual, expected); assert.strictEqual(_.isArray(args), false); assert.strictEqual(_.isArray(true), false); assert.strictEqual(_.isArray(new Date), false); assert.strictEqual(_.isArray(new Error), false); assert.strictEqual(_.isArray(_), false); assert.strictEqual(_.isArray(slice), false); assert.strictEqual(_.isArray({ '0': 1, 'length': 1 }), false); assert.strictEqual(_.isArray(1), false); assert.strictEqual(_.isArray(/x/), false); assert.strictEqual(_.isArray('a'), false); assert.strictEqual(_.isArray(symbol), false); }); QUnit.test('should work with an array from another realm', function(assert) { assert.expect(1); if (realm.array) { assert.strictEqual(_.isArray(realm.array), true); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isArrayBuffer'); (function() { QUnit.test('should return `true` for array buffers', function(assert) { assert.expect(1); if (ArrayBuffer) { assert.strictEqual(_.isArrayBuffer(arrayBuffer), true); } else { skipAssert(assert); } }); QUnit.test('should return `false` for non array buffers', function(assert) { assert.expect(13); var expected = lodashStable.map(falsey, stubFalse); var actual = lodashStable.map(falsey, function(value, index) { return index ? _.isArrayBuffer(value) : _.isArrayBuffer(); }); assert.deepEqual(actual, expected); assert.strictEqual(_.isArrayBuffer(args), false); assert.strictEqual(_.isArrayBuffer([1]), false); assert.strictEqual(_.isArrayBuffer(true), false); assert.strictEqual(_.isArrayBuffer(new Date), false); assert.strictEqual(_.isArrayBuffer(new Error), false); assert.strictEqual(_.isArrayBuffer(_), false); assert.strictEqual(_.isArrayBuffer(slice), false); assert.strictEqual(_.isArrayBuffer({ 'a': 1 }), false); assert.strictEqual(_.isArrayBuffer(1), false); assert.strictEqual(_.isArrayBuffer(/x/), false); assert.strictEqual(_.isArrayBuffer('a'), false); assert.strictEqual(_.isArrayBuffer(symbol), false); }); QUnit.test('should work with array buffers from another realm', function(assert) { assert.expect(1); if (realm.arrayBuffer) { assert.strictEqual(_.isArrayBuffer(realm.arrayBuffer), true); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isArrayLike'); (function() { QUnit.test('should return `true` for array-like values', function(assert) { assert.expect(1); var values = [args, [1, 2, 3], { '0': 'a', 'length': 1 }, 'a'], expected = lodashStable.map(values, stubTrue), actual = lodashStable.map(values, _.isArrayLike); assert.deepEqual(actual, expected); }); QUnit.test('should return `false` for non-arrays', function(assert) { assert.expect(12); var expected = lodashStable.map(falsey, function(value) { return value === ''; }); var actual = lodashStable.map(falsey, function(value, index) { return index ? _.isArrayLike(value) : _.isArrayLike(); }); assert.deepEqual(actual, expected); assert.strictEqual(_.isArrayLike(true), false); assert.strictEqual(_.isArrayLike(new Date), false); assert.strictEqual(_.isArrayLike(new Error), false); assert.strictEqual(_.isArrayLike(_), false); assert.strictEqual(_.isArrayLike(asyncFunc), false); assert.strictEqual(_.isArrayLike(genFunc), false); assert.strictEqual(_.isArrayLike(slice), false); assert.strictEqual(_.isArrayLike({ 'a': 1 }), false); assert.strictEqual(_.isArrayLike(1), false); assert.strictEqual(_.isArrayLike(/x/), false); assert.strictEqual(_.isArrayLike(symbol), false); }); QUnit.test('should work with an array from another realm', function(assert) { assert.expect(1); if (realm.object) { var values = [realm.arguments, realm.array, realm.string], expected = lodashStable.map(values, stubTrue), actual = lodashStable.map(values, _.isArrayLike); assert.deepEqual(actual, expected); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isBoolean'); (function() { QUnit.test('should return `true` for booleans', function(assert) { assert.expect(4); assert.strictEqual(_.isBoolean(true), true); assert.strictEqual(_.isBoolean(false), true); assert.strictEqual(_.isBoolean(Object(true)), true); assert.strictEqual(_.isBoolean(Object(false)), true); }); QUnit.test('should return `false` for non-booleans', function(assert) { assert.expect(12); var expected = lodashStable.map(falsey, function(value) { return value === false; }); var actual = lodashStable.map(falsey, function(value, index) { return index ? _.isBoolean(value) : _.isBoolean(); }); assert.deepEqual(actual, expected); assert.strictEqual(_.isBoolean(args), false); assert.strictEqual(_.isBoolean([1, 2, 3]), false); assert.strictEqual(_.isBoolean(new Date), false); assert.strictEqual(_.isBoolean(new Error), false); assert.strictEqual(_.isBoolean(_), false); assert.strictEqual(_.isBoolean(slice), false); assert.strictEqual(_.isBoolean({ 'a': 1 }), false); assert.strictEqual(_.isBoolean(1), false); assert.strictEqual(_.isBoolean(/x/), false); assert.strictEqual(_.isBoolean('a'), false); assert.strictEqual(_.isBoolean(symbol), false); }); QUnit.test('should work with a boolean from another realm', function(assert) { assert.expect(1); if (realm.boolean) { assert.strictEqual(_.isBoolean(realm.boolean), true); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isBuffer'); (function() { QUnit.test('should return `true` for buffers', function(assert) { assert.expect(1); if (Buffer) { assert.strictEqual(_.isBuffer(new Buffer(2)), true); } else { skipAssert(assert); } }); QUnit.test('should return `false` for non-buffers', function(assert) { assert.expect(13); var expected = lodashStable.map(falsey, stubFalse); var actual = lodashStable.map(falsey, function(value, index) { return index ? _.isBuffer(value) : _.isBuffer(); }); assert.deepEqual(actual, expected); assert.strictEqual(_.isBuffer(args), false); assert.strictEqual(_.isBuffer([1]), false); assert.strictEqual(_.isBuffer(true), false); assert.strictEqual(_.isBuffer(new Date), false); assert.strictEqual(_.isBuffer(new Error), false); assert.strictEqual(_.isBuffer(_), false); assert.strictEqual(_.isBuffer(slice), false); assert.strictEqual(_.isBuffer({ 'a': 1 }), false); assert.strictEqual(_.isBuffer(1), false); assert.strictEqual(_.isBuffer(/x/), false); assert.strictEqual(_.isBuffer('a'), false); assert.strictEqual(_.isBuffer(symbol), false); }); QUnit.test('should return `false` if `Buffer` is not defined', function(assert) { assert.expect(1); if (!isStrict && Buffer && lodashBizarro) { assert.strictEqual(lodashBizarro.isBuffer(new Buffer(2)), false); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isDate'); (function() { QUnit.test('should return `true` for dates', function(assert) { assert.expect(1); assert.strictEqual(_.isDate(new Date), true); }); QUnit.test('should return `false` for non-dates', function(assert) { assert.expect(12); var expected = lodashStable.map(falsey, stubFalse); var actual = lodashStable.map(falsey, function(value, index) { return index ? _.isDate(value) : _.isDate(); }); assert.deepEqual(actual, expected); assert.strictEqual(_.isDate(args), false); assert.strictEqual(_.isDate([1, 2, 3]), false); assert.strictEqual(_.isDate(true), false); assert.strictEqual(_.isDate(new Error), false); assert.strictEqual(_.isDate(_), false); assert.strictEqual(_.isDate(slice), false); assert.strictEqual(_.isDate({ 'a': 1 }), false); assert.strictEqual(_.isDate(1), false); assert.strictEqual(_.isDate(/x/), false); assert.strictEqual(_.isDate('a'), false); assert.strictEqual(_.isDate(symbol), false); }); QUnit.test('should work with a date object from another realm', function(assert) { assert.expect(1); if (realm.date) { assert.strictEqual(_.isDate(realm.date), true); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isElement'); (function() { QUnit.test('should return `true` for elements', function(assert) { assert.expect(1); if (document) { assert.strictEqual(_.isElement(body), true); } else { skipAssert(assert); } }); QUnit.test('should return `true` for non-plain objects', function(assert) { assert.expect(1); function Foo() { this.nodeType = 1; } assert.strictEqual(_.isElement(new Foo), true); }); QUnit.test('should return `false` for non DOM elements', function(assert) { assert.expect(13); var expected = lodashStable.map(falsey, stubFalse); var actual = lodashStable.map(falsey, function(value, index) { return index ? _.isElement(value) : _.isElement(); }); assert.deepEqual(actual, expected); assert.strictEqual(_.isElement(args), false); assert.strictEqual(_.isElement([1, 2, 3]), false); assert.strictEqual(_.isElement(true), false); assert.strictEqual(_.isElement(new Date), false); assert.strictEqual(_.isElement(new Error), false); assert.strictEqual(_.isElement(_), false); assert.strictEqual(_.isElement(slice), false); assert.strictEqual(_.isElement({ 'a': 1 }), false); assert.strictEqual(_.isElement(1), false); assert.strictEqual(_.isElement(/x/), false); assert.strictEqual(_.isElement('a'), false); assert.strictEqual(_.isElement(symbol), false); }); QUnit.test('should return `false` for plain objects', function(assert) { assert.expect(6); assert.strictEqual(_.isElement({ 'nodeType': 1 }), false); assert.strictEqual(_.isElement({ 'nodeType': Object(1) }), false); assert.strictEqual(_.isElement({ 'nodeType': true }), false); assert.strictEqual(_.isElement({ 'nodeType': [1] }), false); assert.strictEqual(_.isElement({ 'nodeType': '1' }), false); assert.strictEqual(_.isElement({ 'nodeType': '001' }), false); }); QUnit.test('should work with a DOM element from another realm', function(assert) { assert.expect(1); if (realm.element) { assert.strictEqual(_.isElement(realm.element), true); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isEmpty'); (function() { QUnit.test('should return `true` for empty values', function(assert) { assert.expect(10); var expected = lodashStable.map(empties, stubTrue), actual = lodashStable.map(empties, _.isEmpty); assert.deepEqual(actual, expected); assert.strictEqual(_.isEmpty(true), true); assert.strictEqual(_.isEmpty(slice), true); assert.strictEqual(_.isEmpty(1), true); assert.strictEqual(_.isEmpty(NaN), true); assert.strictEqual(_.isEmpty(/x/), true); assert.strictEqual(_.isEmpty(symbol), true); assert.strictEqual(_.isEmpty(), true); if (Buffer) { assert.strictEqual(_.isEmpty(new Buffer(0)), true); assert.strictEqual(_.isEmpty(new Buffer(1)), false); } else { skipAssert(assert, 2); } }); QUnit.test('should return `false` for non-empty values', function(assert) { assert.expect(3); assert.strictEqual(_.isEmpty([0]), false); assert.strictEqual(_.isEmpty({ 'a': 0 }), false); assert.strictEqual(_.isEmpty('a'), false); }); QUnit.test('should work with an object that has a `length` property', function(assert) { assert.expect(1); assert.strictEqual(_.isEmpty({ 'length': 0 }), false); }); QUnit.test('should work with `arguments` objects', function(assert) { assert.expect(1); assert.strictEqual(_.isEmpty(args), false); }); QUnit.test('should work with prototytpe objects', function(assert) { assert.expect(2); function Foo() {} Foo.prototype = { 'constructor': Foo }; assert.strictEqual(_.isEmpty(Foo.prototype), true); Foo.prototype.a = 1; assert.strictEqual(_.isEmpty(Foo.prototype), false); }); QUnit.test('should work with jQuery/MooTools DOM query collections', function(assert) { assert.expect(1); function Foo(elements) { push.apply(this, elements); } Foo.prototype = { 'length': 0, 'splice': arrayProto.splice }; assert.strictEqual(_.isEmpty(new Foo([])), true); }); QUnit.test('should work with maps', function(assert) { assert.expect(4); if (Map) { lodashStable.each([new Map, realm.map], function(map) { assert.strictEqual(_.isEmpty(map), true); map.set('a', 1); assert.strictEqual(_.isEmpty(map), false); map.clear(); }); } else { skipAssert(assert, 4); } }); QUnit.test('should work with sets', function(assert) { assert.expect(4); if (Set) { lodashStable.each([new Set, realm.set], function(set) { assert.strictEqual(_.isEmpty(set), true); set.add(1); assert.strictEqual(_.isEmpty(set), false); set.clear(); }); } else { skipAssert(assert, 4); } }); QUnit.test('should not treat objects with negative lengths as array-like', function(assert) { assert.expect(1); function Foo() {} Foo.prototype.length = -1; assert.strictEqual(_.isEmpty(new Foo), true); }); QUnit.test('should not treat objects with lengths larger than `MAX_SAFE_INTEGER` as array-like', function(assert) { assert.expect(1); function Foo() {} Foo.prototype.length = MAX_SAFE_INTEGER + 1; assert.strictEqual(_.isEmpty(new Foo), true); }); QUnit.test('should not treat objects with non-number lengths as array-like', function(assert) { assert.expect(1); assert.strictEqual(_.isEmpty({ 'length': '0' }), false); }); QUnit.test('should return an unwrapped value when implicitly chaining', function(assert) { assert.expect(1); if (!isNpm) { assert.strictEqual(_({}).isEmpty(), true); } else { skipAssert(assert); } }); QUnit.test('should return a wrapped value when explicitly chaining', function(assert) { assert.expect(1); if (!isNpm) { assert.ok(_({}).chain().isEmpty() instanceof _); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isEqual'); (function() { var symbol1 = Symbol ? Symbol('a') : true, symbol2 = Symbol ? Symbol('b') : false; QUnit.test('should compare primitives', function(assert) { assert.expect(1); var pairs = [ [1, 1, true], [1, Object(1), true], [1, '1', false], [1, 2, false], [-0, -0, true], [0, 0, true], [0, Object(0), true], [Object(0), Object(0), true], [-0, 0, true], [0, '0', false], [0, null, false], [NaN, NaN, true], [NaN, Object(NaN), true], [Object(NaN), Object(NaN), true], [NaN, 'a', false], [NaN, Infinity, false], ['a', 'a', true], ['a', Object('a'), true], [Object('a'), Object('a'), true], ['a', 'b', false], ['a', ['a'], false], [true, true, true], [true, Object(true), true], [Object(true), Object(true), true], [true, 1, false], [true, 'a', false], [false, false, true], [false, Object(false), true], [Object(false), Object(false), true], [false, 0, false], [false, '', false], [symbol1, symbol1, true], [symbol1, Object(symbol1), true], [Object(symbol1), Object(symbol1), true], [symbol1, symbol2, false], [null, null, true], [null, undefined, false], [null, {}, false], [null, '', false], [undefined, undefined, true], [undefined, null, false], [undefined, '', false] ]; var expected = lodashStable.map(pairs, function(pair) { return pair[2]; }); var actual = lodashStable.map(pairs, function(pair) { return _.isEqual(pair[0], pair[1]); }); assert.deepEqual(actual, expected); }); QUnit.test('should compare arrays', function(assert) { assert.expect(6); var array1 = [true, null, 1, 'a', undefined], array2 = [true, null, 1, 'a', undefined]; assert.strictEqual(_.isEqual(array1, array2), true); array1 = [[1, 2, 3], new Date(2012, 4, 23), /x/, { 'e': 1 }]; array2 = [[1, 2, 3], new Date(2012, 4, 23), /x/, { 'e': 1 }]; assert.strictEqual(_.isEqual(array1, array2), true); array1 = [1]; array1[2] = 3; array2 = [1]; array2[1] = undefined; array2[2] = 3; assert.strictEqual(_.isEqual(array1, array2), true); array1 = [Object(1), false, Object('a'), /x/, new Date(2012, 4, 23), ['a', 'b', [Object('c')]], { 'a': 1 }]; array2 = [1, Object(false), 'a', /x/, new Date(2012, 4, 23), ['a', Object('b'), ['c']], { 'a': 1 }]; assert.strictEqual(_.isEqual(array1, array2), true); array1 = [1, 2, 3]; array2 = [3, 2, 1]; assert.strictEqual(_.isEqual(array1, array2), false); array1 = [1, 2]; array2 = [1, 2, 3]; assert.strictEqual(_.isEqual(array1, array2), false); }); QUnit.test('should treat arrays with identical values but different non-index properties as equal', function(assert) { assert.expect(3); var array1 = [1, 2, 3], array2 = [1, 2, 3]; array1.every = array1.filter = array1.forEach = array1.indexOf = array1.lastIndexOf = array1.map = array1.some = array1.reduce = array1.reduceRight = null; array2.concat = array2.join = array2.pop = array2.reverse = array2.shift = array2.slice = array2.sort = array2.splice = array2.unshift = null; assert.strictEqual(_.isEqual(array1, array2), true); array1 = [1, 2, 3]; array1.a = 1; array2 = [1, 2, 3]; array2.b = 1; assert.strictEqual(_.isEqual(array1, array2), true); array1 = /c/.exec('abcde'); array2 = ['c']; assert.strictEqual(_.isEqual(array1, array2), true); }); QUnit.test('should compare sparse arrays', function(assert) { assert.expect(3); var array = Array(1); assert.strictEqual(_.isEqual(array, Array(1)), true); assert.strictEqual(_.isEqual(array, [undefined]), true); assert.strictEqual(_.isEqual(array, Array(2)), false); }); QUnit.test('should compare plain objects', function(assert) { assert.expect(5); var object1 = { 'a': true, 'b': null, 'c': 1, 'd': 'a', 'e': undefined }, object2 = { 'a': true, 'b': null, 'c': 1, 'd': 'a', 'e': undefined }; assert.strictEqual(_.isEqual(object1, object2), true); object1 = { 'a': [1, 2, 3], 'b': new Date(2012, 4, 23), 'c': /x/, 'd': { 'e': 1 } }; object2 = { 'a': [1, 2, 3], 'b': new Date(2012, 4, 23), 'c': /x/, 'd': { 'e': 1 } }; assert.strictEqual(_.isEqual(object1, object2), true); object1 = { 'a': 1, 'b': 2, 'c': 3 }; object2 = { 'a': 3, 'b': 2, 'c': 1 }; assert.strictEqual(_.isEqual(object1, object2), false); object1 = { 'a': 1, 'b': 2, 'c': 3 }; object2 = { 'd': 1, 'e': 2, 'f': 3 }; assert.strictEqual(_.isEqual(object1, object2), false); object1 = { 'a': 1, 'b': 2 }; object2 = { 'a': 1, 'b': 2, 'c': 3 }; assert.strictEqual(_.isEqual(object1, object2), false); }); QUnit.test('should compare objects regardless of key order', function(assert) { assert.expect(1); var object1 = { 'a': 1, 'b': 2, 'c': 3 }, object2 = { 'c': 3, 'a': 1, 'b': 2 }; assert.strictEqual(_.isEqual(object1, object2), true); }); QUnit.test('should compare nested objects', function(assert) { assert.expect(1); var object1 = { 'a': [1, 2, 3], 'b': true, 'c': Object(1), 'd': 'a', 'e': { 'f': ['a', Object('b'), 'c'], 'g': Object(false), 'h': new Date(2012, 4, 23), 'i': noop, 'j': 'a' } }; var object2 = { 'a': [1, Object(2), 3], 'b': Object(true), 'c': 1, 'd': Object('a'), 'e': { 'f': ['a', 'b', 'c'], 'g': false, 'h': new Date(2012, 4, 23), 'i': noop, 'j': 'a' } }; assert.strictEqual(_.isEqual(object1, object2), true); }); QUnit.test('should compare object instances', function(assert) { assert.expect(4); function Foo() { this.a = 1; } Foo.prototype.a = 1; function Bar() { this.a = 1; } Bar.prototype.a = 2; assert.strictEqual(_.isEqual(new Foo, new Foo), true); assert.strictEqual(_.isEqual(new Foo, new Bar), false); assert.strictEqual(_.isEqual({ 'a': 1 }, new Foo), false); assert.strictEqual(_.isEqual({ 'a': 2 }, new Bar), false); }); QUnit.test('should compare objects with constructor properties', function(assert) { assert.expect(5); assert.strictEqual(_.isEqual({ 'constructor': 1 }, { 'constructor': 1 }), true); assert.strictEqual(_.isEqual({ 'constructor': 1 }, { 'constructor': '1' }), false); assert.strictEqual(_.isEqual({ 'constructor': [1] }, { 'constructor': [1] }), true); assert.strictEqual(_.isEqual({ 'constructor': [1] }, { 'constructor': ['1'] }), false); assert.strictEqual(_.isEqual({ 'constructor': Object }, {}), false); }); QUnit.test('should compare arrays with circular references', function(assert) { assert.expect(4); var array1 = [], array2 = []; array1.push(array1); array2.push(array2); assert.strictEqual(_.isEqual(array1, array2), true); array1.push('b'); array2.push('b'); assert.strictEqual(_.isEqual(array1, array2), true); array1.push('c'); array2.push('d'); assert.strictEqual(_.isEqual(array1, array2), false); array1 = ['a', 'b', 'c']; array1[1] = array1; array2 = ['a', ['a', 'b', 'c'], 'c']; assert.strictEqual(_.isEqual(array1, array2), false); }); QUnit.test('should have transitive equivalence for circular references of arrays', function(assert) { assert.expect(3); var array1 = [], array2 = [array1], array3 = [array2]; array1[0] = array1; assert.strictEqual(_.isEqual(array1, array2), true); assert.strictEqual(_.isEqual(array2, array3), true); assert.strictEqual(_.isEqual(array1, array3), true); }); QUnit.test('should compare objects with circular references', function(assert) { assert.expect(4); var object1 = {}, object2 = {}; object1.a = object1; object2.a = object2; assert.strictEqual(_.isEqual(object1, object2), true); object1.b = 0; object2.b = Object(0); assert.strictEqual(_.isEqual(object1, object2), true); object1.c = Object(1); object2.c = Object(2); assert.strictEqual(_.isEqual(object1, object2), false); object1 = { 'a': 1, 'b': 2, 'c': 3 }; object1.b = object1; object2 = { 'a': 1, 'b': { 'a': 1, 'b': 2, 'c': 3 }, 'c': 3 }; assert.strictEqual(_.isEqual(object1, object2), false); }); QUnit.test('should have transitive equivalence for circular references of objects', function(assert) { assert.expect(3); var object1 = {}, object2 = { 'a': object1 }, object3 = { 'a': object2 }; object1.a = object1; assert.strictEqual(_.isEqual(object1, object2), true); assert.strictEqual(_.isEqual(object2, object3), true); assert.strictEqual(_.isEqual(object1, object3), true); }); QUnit.test('should compare objects with multiple circular references', function(assert) { assert.expect(3); var array1 = [{}], array2 = [{}]; (array1[0].a = array1).push(array1); (array2[0].a = array2).push(array2); assert.strictEqual(_.isEqual(array1, array2), true); array1[0].b = 0; array2[0].b = Object(0); assert.strictEqual(_.isEqual(array1, array2), true); array1[0].c = Object(1); array2[0].c = Object(2); assert.strictEqual(_.isEqual(array1, array2), false); }); QUnit.test('should compare objects with complex circular references', function(assert) { assert.expect(1); var object1 = { 'foo': { 'b': { 'c': { 'd': {} } } }, 'bar': { 'a': 2 } }; var object2 = { 'foo': { 'b': { 'c': { 'd': {} } } }, 'bar': { 'a': 2 } }; object1.foo.b.c.d = object1; object1.bar.b = object1.foo.b; object2.foo.b.c.d = object2; object2.bar.b = object2.foo.b; assert.strictEqual(_.isEqual(object1, object2), true); }); QUnit.test('should compare objects with shared property values', function(assert) { assert.expect(1); var object1 = { 'a': [1, 2] }; var object2 = { 'a': [1, 2], 'b': [1, 2] }; object1.b = object1.a; assert.strictEqual(_.isEqual(object1, object2), true); }); QUnit.test('should treat objects created by `Object.create(null)` like plain objects', function(assert) { assert.expect(2); function Foo() { this.a = 1; } Foo.prototype.constructor = null; var object1 = create(null); object1.a = 1; var object2 = { 'a': 1 }; assert.strictEqual(_.isEqual(object1, object2), true); assert.strictEqual(_.isEqual(new Foo, object2), false); }); QUnit.test('should avoid common type coercions', function(assert) { assert.expect(9); assert.strictEqual(_.isEqual(true, Object(false)), false); assert.strictEqual(_.isEqual(Object(false), Object(0)), false); assert.strictEqual(_.isEqual(false, Object('')), false); assert.strictEqual(_.isEqual(Object(36), Object('36')), false); assert.strictEqual(_.isEqual(0, ''), false); assert.strictEqual(_.isEqual(1, true), false); assert.strictEqual(_.isEqual(1337756400000, new Date(2012, 4, 23)), false); assert.strictEqual(_.isEqual('36', 36), false); assert.strictEqual(_.isEqual(36, '36'), false); }); QUnit.test('should compare `arguments` objects', function(assert) { assert.expect(2); var args1 = (function() { return arguments; }()), args2 = (function() { return arguments; }()), args3 = (function() { return arguments; }(1, 2)); assert.strictEqual(_.isEqual(args1, args2), true); assert.strictEqual(_.isEqual(args1, args3), false); }); QUnit.test('should treat `arguments` objects like `Object` objects', function(assert) { assert.expect(4); var object = { '0': 1, '1': 2, '2': 3 }; function Foo() {} Foo.prototype = object; assert.strictEqual(_.isEqual(args, object), true); assert.strictEqual(_.isEqual(object, args), true); assert.strictEqual(_.isEqual(args, new Foo), false); assert.strictEqual(_.isEqual(new Foo, args), false); }); QUnit.test('should compare array buffers', function(assert) { assert.expect(2); if (ArrayBuffer) { var buffer = new Int8Array([-1]).buffer; assert.strictEqual(_.isEqual(buffer, new Uint8Array([255]).buffer), true); assert.strictEqual(_.isEqual(buffer, new ArrayBuffer(1)), false); } else { skipAssert(assert, 2); } }); QUnit.test('should compare array views', function(assert) { assert.expect(2); lodashStable.times(2, function(index) { var ns = index ? realm : root; var pairs = lodashStable.map(arrayViews, function(type, viewIndex) { var otherType = arrayViews[(viewIndex + 1) % arrayViews.length], CtorA = ns[type] || function(n) { this.n = n; }, CtorB = ns[otherType] || function(n) { this.n = n; }, bufferA = ns[type] ? new ns.ArrayBuffer(8) : 8, bufferB = ns[otherType] ? new ns.ArrayBuffer(8) : 8, bufferC = ns[otherType] ? new ns.ArrayBuffer(16) : 16; return [new CtorA(bufferA), new CtorA(bufferA), new CtorB(bufferB), new CtorB(bufferC)]; }); var expected = lodashStable.map(pairs, lodashStable.constant([true, false, false])); var actual = lodashStable.map(pairs, function(pair) { return [_.isEqual(pair[0], pair[1]), _.isEqual(pair[0], pair[2]), _.isEqual(pair[2], pair[3])]; }); assert.deepEqual(actual, expected); }); }); QUnit.test('should compare buffers', function(assert) { assert.expect(3); if (Buffer) { var buffer = new Buffer([1]); assert.strictEqual(_.isEqual(buffer, new Buffer([1])), true); assert.strictEqual(_.isEqual(buffer, new Buffer([2])), false); assert.strictEqual(_.isEqual(buffer, new Uint8Array([1])), false); } else { skipAssert(assert, 3); } }); QUnit.test('should compare date objects', function(assert) { assert.expect(4); var date = new Date(2012, 4, 23); assert.strictEqual(_.isEqual(date, new Date(2012, 4, 23)), true); assert.strictEqual(_.isEqual(new Date('a'), new Date('b')), true); assert.strictEqual(_.isEqual(date, new Date(2013, 3, 25)), false); assert.strictEqual(_.isEqual(date, { 'getTime': lodashStable.constant(+date) }), false); }); QUnit.test('should compare error objects', function(assert) { assert.expect(1); var pairs = lodashStable.map([ 'Error', 'EvalError', 'RangeError', 'ReferenceError', 'SyntaxError', 'TypeError', 'URIError' ], function(type, index, errorTypes) { var otherType = errorTypes[++index % errorTypes.length], CtorA = root[type], CtorB = root[otherType]; return [new CtorA('a'), new CtorA('a'), new CtorB('a'), new CtorB('b')]; }); var expected = lodashStable.map(pairs, lodashStable.constant([true, false, false])); var actual = lodashStable.map(pairs, function(pair) { return [_.isEqual(pair[0], pair[1]), _.isEqual(pair[0], pair[2]), _.isEqual(pair[2], pair[3])]; }); assert.deepEqual(actual, expected); }); QUnit.test('should compare functions', function(assert) { assert.expect(2); function a() { return 1 + 2; } function b() { return 1 + 2; } assert.strictEqual(_.isEqual(a, a), true); assert.strictEqual(_.isEqual(a, b), false); }); QUnit.test('should compare maps', function(assert) { assert.expect(8); if (Map) { lodashStable.each([[map, new Map], [map, realm.map]], function(maps) { var map1 = maps[0], map2 = maps[1]; map1.set('a', 1); map2.set('b', 2); assert.strictEqual(_.isEqual(map1, map2), false); map1.set('b', 2); map2.set('a', 1); assert.strictEqual(_.isEqual(map1, map2), true); map1.delete('a'); map1.set('a', 1); assert.strictEqual(_.isEqual(map1, map2), true); map2.delete('a'); assert.strictEqual(_.isEqual(map1, map2), false); map1.clear(); map2.clear(); }); } else { skipAssert(assert, 8); } }); QUnit.test('should compare maps with circular references', function(assert) { assert.expect(2); if (Map) { var map1 = new Map, map2 = new Map; map1.set('a', map1); map2.set('a', map2); assert.strictEqual(_.isEqual(map1, map2), true); map1.set('b', 1); map2.set('b', 2); assert.strictEqual(_.isEqual(map1, map2), false); } else { skipAssert(assert, 2); } }); QUnit.test('should compare promises by reference', function(assert) { assert.expect(4); if (promise) { lodashStable.each([[promise, Promise.resolve(1)], [promise, realm.promise]], function(promises) { var promise1 = promises[0], promise2 = promises[1]; assert.strictEqual(_.isEqual(promise1, promise2), false); assert.strictEqual(_.isEqual(promise1, promise1), true); }); } else { skipAssert(assert, 4); } }); QUnit.test('should compare regexes', function(assert) { assert.expect(5); assert.strictEqual(_.isEqual(/x/gim, /x/gim), true); assert.strictEqual(_.isEqual(/x/gim, /x/mgi), true); assert.strictEqual(_.isEqual(/x/gi, /x/g), false); assert.strictEqual(_.isEqual(/x/, /y/), false); assert.strictEqual(_.isEqual(/x/g, { 'global': true, 'ignoreCase': false, 'multiline': false, 'source': 'x' }), false); }); QUnit.test('should compare sets', function(assert) { assert.expect(8); if (Set) { lodashStable.each([[set, new Set], [set, realm.set]], function(sets) { var set1 = sets[0], set2 = sets[1]; set1.add(1); set2.add(2); assert.strictEqual(_.isEqual(set1, set2), false); set1.add(2); set2.add(1); assert.strictEqual(_.isEqual(set1, set2), true); set1.delete(1); set1.add(1); assert.strictEqual(_.isEqual(set1, set2), true); set2.delete(1); assert.strictEqual(_.isEqual(set1, set2), false); set1.clear(); set2.clear(); }); } else { skipAssert(assert, 8); } }); QUnit.test('should compare sets with circular references', function(assert) { assert.expect(2); if (Set) { var set1 = new Set, set2 = new Set; set1.add(set1); set2.add(set2); assert.strictEqual(_.isEqual(set1, set2), true); set1.add(1); set2.add(2); assert.strictEqual(_.isEqual(set1, set2), false); } else { skipAssert(assert, 2); } }); QUnit.test('should compare symbol properties', function(assert) { assert.expect(3); if (Symbol) { var object1 = { 'a': 1 }, object2 = { 'a': 1 }; object1[symbol1] = { 'a': { 'b': 2 } }; object2[symbol1] = { 'a': { 'b': 2 } }; defineProperty(object2, symbol2, { 'configurable': true, 'enumerable': false, 'writable': true, 'value': 2 }); assert.strictEqual(_.isEqual(object1, object2), true); object2[symbol1] = { 'a': 1 }; assert.strictEqual(_.isEqual(object1, object2), false); delete object2[symbol1]; object2[Symbol('a')] = { 'a': { 'b': 2 } }; assert.strictEqual(_.isEqual(object1, object2), false); } else { skipAssert(assert, 3); } }); QUnit.test('should compare wrapped values', function(assert) { assert.expect(32); var stamp = +new Date; var values = [ [[1, 2], [1, 2], [1, 2, 3]], [true, true, false], [new Date(stamp), new Date(stamp), new Date(stamp - 100)], [{ 'a': 1, 'b': 2 }, { 'a': 1, 'b': 2 }, { 'a': 1, 'b': 1 }], [1, 1, 2], [NaN, NaN, Infinity], [/x/, /x/, /x/i], ['a', 'a', 'A'] ]; lodashStable.each(values, function(vals) { if (!isNpm) { var wrapped1 = _(vals[0]), wrapped2 = _(vals[1]), actual = wrapped1.isEqual(wrapped2); assert.strictEqual(actual, true); assert.strictEqual(_.isEqual(_(actual), _(true)), true); wrapped1 = _(vals[0]); wrapped2 = _(vals[2]); actual = wrapped1.isEqual(wrapped2); assert.strictEqual(actual, false); assert.strictEqual(_.isEqual(_(actual), _(false)), true); } else { skipAssert(assert, 4); } }); }); QUnit.test('should compare wrapped and non-wrapped values', function(assert) { assert.expect(4); if (!isNpm) { var object1 = _({ 'a': 1, 'b': 2 }), object2 = { 'a': 1, 'b': 2 }; assert.strictEqual(object1.isEqual(object2), true); assert.strictEqual(_.isEqual(object1, object2), true); object1 = _({ 'a': 1, 'b': 2 }); object2 = { 'a': 1, 'b': 1 }; assert.strictEqual(object1.isEqual(object2), false); assert.strictEqual(_.isEqual(object1, object2), false); } else { skipAssert(assert, 4); } }); QUnit.test('should work as an iteratee for `_.every`', function(assert) { assert.expect(1); var actual = lodashStable.every([1, 1, 1], lodashStable.partial(_.isEqual, 1)); assert.ok(actual); }); QUnit.test('should not error on DOM elements', function(assert) { assert.expect(1); if (document) { var element1 = document.createElement('div'), element2 = element1.cloneNode(true); try { assert.strictEqual(_.isEqual(element1, element2), false); } catch (e) { assert.ok(false, e.message); } } else { skipAssert(assert); } }); QUnit.test('should return `true` for like-objects from different documents', function(assert) { assert.expect(4); if (realm.object) { assert.strictEqual(_.isEqual([1], realm.array), true); assert.strictEqual(_.isEqual([2], realm.array), false); assert.strictEqual(_.isEqual({ 'a': 1 }, realm.object), true); assert.strictEqual(_.isEqual({ 'a': 2 }, realm.object), false); } else { skipAssert(assert, 4); } }); QUnit.test('should return `false` for objects with custom `toString` methods', function(assert) { assert.expect(1); var primitive, object = { 'toString': function() { return primitive; } }, values = [true, null, 1, 'a', undefined], expected = lodashStable.map(values, stubFalse); var actual = lodashStable.map(values, function(value) { primitive = value; return _.isEqual(object, value); }); assert.deepEqual(actual, expected); }); QUnit.test('should return an unwrapped value when implicitly chaining', function(assert) { assert.expect(1); if (!isNpm) { assert.strictEqual(_('a').isEqual('a'), true); } else { skipAssert(assert); } }); QUnit.test('should return a wrapped value when explicitly chaining', function(assert) { assert.expect(1); if (!isNpm) { assert.ok(_('a').chain().isEqual('a') instanceof _); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isEqualWith'); (function() { QUnit.test('should provide correct `customizer` arguments', function(assert) { assert.expect(1); var argsList = [], object1 = { 'a': [1, 2], 'b': null }, object2 = { 'a': [1, 2], 'b': null }; object1.b = object2; object2.b = object1; var expected = [ [object1, object2], [object1.a, object2.a, 'a', object1, object2], [object1.a[0], object2.a[0], 0, object1.a, object2.a], [object1.a[1], object2.a[1], 1, object1.a, object2.a], [object1.b, object2.b, 'b', object1.b, object2.b] ]; _.isEqualWith(object1, object2, function(assert) { var length = arguments.length, args = slice.call(arguments, 0, length - (length > 2 ? 1 : 0)); argsList.push(args); }); assert.deepEqual(argsList, expected); }); QUnit.test('should handle comparisons when `customizer` returns `undefined`', function(assert) { assert.expect(3); assert.strictEqual(_.isEqualWith('a', 'a', noop), true); assert.strictEqual(_.isEqualWith(['a'], ['a'], noop), true); assert.strictEqual(_.isEqualWith({ '0': 'a' }, { '0': 'a' }, noop), true); }); QUnit.test('should not handle comparisons when `customizer` returns `true`', function(assert) { assert.expect(3); var customizer = function(value) { return _.isString(value) || undefined; }; assert.strictEqual(_.isEqualWith('a', 'b', customizer), true); assert.strictEqual(_.isEqualWith(['a'], ['b'], customizer), true); assert.strictEqual(_.isEqualWith({ '0': 'a' }, { '0': 'b' }, customizer), true); }); QUnit.test('should not handle comparisons when `customizer` returns `false`', function(assert) { assert.expect(3); var customizer = function(value) { return _.isString(value) ? false : undefined; }; assert.strictEqual(_.isEqualWith('a', 'a', customizer), false); assert.strictEqual(_.isEqualWith(['a'], ['a'], customizer), false); assert.strictEqual(_.isEqualWith({ '0': 'a' }, { '0': 'a' }, customizer), false); }); QUnit.test('should return a boolean value even when `customizer` does not', function(assert) { assert.expect(2); var actual = _.isEqualWith('a', 'b', stubC); assert.strictEqual(actual, true); var values = _.without(falsey, undefined), expected = lodashStable.map(values, stubFalse); actual = []; lodashStable.each(values, function(value) { actual.push(_.isEqualWith('a', 'a', lodashStable.constant(value))); }); assert.deepEqual(actual, expected); }); QUnit.test('should ensure `customizer` is a function', function(assert) { assert.expect(1); var array = [1, 2, 3], eq = _.partial(_.isEqualWith, array), actual = lodashStable.map([array, [1, 0, 3]], eq); assert.deepEqual(actual, [true, false]); }); QUnit.test('should call `customizer` for values maps and sets', function(assert) { assert.expect(2); var value = { 'a': { 'b': 2 } }; if (Map) { var map1 = new Map; map1.set('a', value); var map2 = new Map; map2.set('a', value); } if (Set) { var set1 = new Set; set1.add(value); var set2 = new Set; set2.add(value); } lodashStable.each([[map1, map2], [set1, set2]], function(pair, index) { if (pair[0]) { var argsList = [], array = lodashStable.toArray(pair[0]); var expected = [ [pair[0], pair[1]], [array[0], array[0], 0, array, array], [array[0][0], array[0][0], 0, array[0], array[0]], [array[0][1], array[0][1], 1, array[0], array[0]] ]; if (index) { expected.length = 2; } _.isEqualWith(pair[0], pair[1], function() { var length = arguments.length, args = slice.call(arguments, 0, length - (length > 2 ? 1 : 0)); argsList.push(args); }); assert.deepEqual(argsList, expected, index ? 'Set' : 'Map'); } else { skipAssert(assert); } }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isError'); (function() { QUnit.test('should return `true` for error objects', function(assert) { assert.expect(1); var expected = lodashStable.map(errors, stubTrue); var actual = lodashStable.map(errors, function(error) { return _.isError(error) === true; }); assert.deepEqual(actual, expected); }); QUnit.test('should return `true` for subclassed values', function(assert) { assert.expect(1); assert.strictEqual(_.isError(new CustomError('x')), true); }); QUnit.test('should return `false` for non error objects', function(assert) { assert.expect(12); var expected = lodashStable.map(falsey, stubFalse); var actual = lodashStable.map(falsey, function(value, index) { return index ? _.isError(value) : _.isError(); }); assert.deepEqual(actual, expected); assert.strictEqual(_.isError(args), false); assert.strictEqual(_.isError([1, 2, 3]), false); assert.strictEqual(_.isError(true), false); assert.strictEqual(_.isError(new Date), false); assert.strictEqual(_.isError(_), false); assert.strictEqual(_.isError(slice), false); assert.strictEqual(_.isError({ 'a': 1 }), false); assert.strictEqual(_.isError(1), false); assert.strictEqual(_.isError(/x/), false); assert.strictEqual(_.isError('a'), false); assert.strictEqual(_.isError(symbol), false); }); QUnit.test('should return `false` for plain objects', function(assert) { assert.expect(1); assert.strictEqual(_.isError({ 'name': 'Error', 'message': '' }), false); }); QUnit.test('should work with an error object from another realm', function(assert) { assert.expect(1); if (realm.errors) { var expected = lodashStable.map(realm.errors, stubTrue); var actual = lodashStable.map(realm.errors, function(error) { return _.isError(error) === true; }); assert.deepEqual(actual, expected); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isFinite'); (function() { QUnit.test('should return `true` for finite values', function(assert) { assert.expect(1); var values = [0, 1, 3.14, -1], expected = lodashStable.map(values, stubTrue), actual = lodashStable.map(values, _.isFinite); assert.deepEqual(actual, expected); }); QUnit.test('should return `false` for non-finite values', function(assert) { assert.expect(1); var values = [NaN, Infinity, -Infinity, Object(1)], expected = lodashStable.map(values, stubFalse), actual = lodashStable.map(values, _.isFinite); assert.deepEqual(actual, expected); }); QUnit.test('should return `false` for non-numeric values', function(assert) { assert.expect(10); var values = [undefined, [], true, '', ' ', '2px'], expected = lodashStable.map(values, stubFalse), actual = lodashStable.map(values, _.isFinite); assert.deepEqual(actual, expected); assert.strictEqual(_.isFinite(args), false); assert.strictEqual(_.isFinite([1, 2, 3]), false); assert.strictEqual(_.isFinite(true), false); assert.strictEqual(_.isFinite(new Date), false); assert.strictEqual(_.isFinite(new Error), false); assert.strictEqual(_.isFinite({ 'a': 1 }), false); assert.strictEqual(_.isFinite(/x/), false); assert.strictEqual(_.isFinite('a'), false); assert.strictEqual(_.isFinite(symbol), false); }); QUnit.test('should return `false` for numeric string values', function(assert) { assert.expect(1); var values = ['2', '0', '08'], expected = lodashStable.map(values, stubFalse), actual = lodashStable.map(values, _.isFinite); assert.deepEqual(actual, expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isFunction'); (function() { QUnit.test('should return `true` for functions', function(assert) { assert.expect(2); assert.strictEqual(_.isFunction(_), true); assert.strictEqual(_.isFunction(slice), true); }); QUnit.test('should return `true` for async functions', function(assert) { assert.expect(1); assert.strictEqual(_.isFunction(asyncFunc), typeof asyncFunc == 'function'); }); QUnit.test('should return `true` for generator functions', function(assert) { assert.expect(1); assert.strictEqual(_.isFunction(genFunc), typeof genFunc == 'function'); }); QUnit.test('should return `true` for the `Proxy` constructor', function(assert) { assert.expect(1); if (Proxy) { assert.strictEqual(_.isFunction(Proxy), true); } else { skipAssert(assert); } }); QUnit.test('should return `true` for array view constructors', function(assert) { assert.expect(1); var expected = lodashStable.map(arrayViews, function(type) { return objToString.call(root[type]) == funcTag; }); var actual = lodashStable.map(arrayViews, function(type) { return _.isFunction(root[type]); }); assert.deepEqual(actual, expected); }); QUnit.test('should return `false` for non-functions', function(assert) { assert.expect(12); var expected = lodashStable.map(falsey, stubFalse); var actual = lodashStable.map(falsey, function(value, index) { return index ? _.isFunction(value) : _.isFunction(); }); assert.deepEqual(actual, expected); assert.strictEqual(_.isFunction(args), false); assert.strictEqual(_.isFunction([1, 2, 3]), false); assert.strictEqual(_.isFunction(true), false); assert.strictEqual(_.isFunction(new Date), false); assert.strictEqual(_.isFunction(new Error), false); assert.strictEqual(_.isFunction({ 'a': 1 }), false); assert.strictEqual(_.isFunction(1), false); assert.strictEqual(_.isFunction(/x/), false); assert.strictEqual(_.isFunction('a'), false); assert.strictEqual(_.isFunction(symbol), false); if (document) { assert.strictEqual(_.isFunction(document.getElementsByTagName('body')), false); } else { skipAssert(assert); } }); QUnit.test('should work with a function from another realm', function(assert) { assert.expect(1); if (realm.function) { assert.strictEqual(_.isFunction(realm.function), true); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('isInteger methods'); lodashStable.each(['isInteger', 'isSafeInteger'], function(methodName) { var func = _[methodName], isSafe = methodName == 'isSafeInteger'; QUnit.test('`_.' + methodName + '` should return `true` for integer values', function(assert) { assert.expect(2); var values = [-1, 0, 1], expected = lodashStable.map(values, stubTrue); var actual = lodashStable.map(values, function(value) { return func(value); }); assert.deepEqual(actual, expected); assert.strictEqual(func(MAX_INTEGER), !isSafe); }); QUnit.test('should return `false` for non-integer number values', function(assert) { assert.expect(1); var values = [NaN, Infinity, -Infinity, Object(1), 3.14], expected = lodashStable.map(values, stubFalse); var actual = lodashStable.map(values, function(value) { return func(value); }); assert.deepEqual(actual, expected); }); QUnit.test('should return `false` for non-numeric values', function(assert) { assert.expect(10); var expected = lodashStable.map(falsey, function(value) { return value === 0; }); var actual = lodashStable.map(falsey, function(value, index) { return index ? func(value) : func(); }); assert.deepEqual(actual, expected); assert.strictEqual(func(args), false); assert.strictEqual(func([1, 2, 3]), false); assert.strictEqual(func(true), false); assert.strictEqual(func(new Date), false); assert.strictEqual(func(new Error), false); assert.strictEqual(func({ 'a': 1 }), false); assert.strictEqual(func(/x/), false); assert.strictEqual(func('a'), false); assert.strictEqual(func(symbol), false); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isLength'); (function() { QUnit.test('should return `true` for lengths', function(assert) { assert.expect(1); var values = [0, 3, MAX_SAFE_INTEGER], expected = lodashStable.map(values, stubTrue), actual = lodashStable.map(values, _.isLength); assert.deepEqual(actual, expected); }); QUnit.test('should return `false` for non-lengths', function(assert) { assert.expect(1); var values = [-1, '1', 1.1, MAX_SAFE_INTEGER + 1], expected = lodashStable.map(values, stubFalse), actual = lodashStable.map(values, _.isLength); assert.deepEqual(actual, expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isMap'); (function() { QUnit.test('should return `true` for maps', function(assert) { assert.expect(1); if (Map) { assert.strictEqual(_.isMap(map), true); } else { skipAssert(assert); } }); QUnit.test('should return `false` for non-maps', function(assert) { assert.expect(14); var expected = lodashStable.map(falsey, stubFalse); var actual = lodashStable.map(falsey, function(value, index) { return index ? _.isMap(value) : _.isMap(); }); assert.deepEqual(actual, expected); assert.strictEqual(_.isMap(args), false); assert.strictEqual(_.isMap([1, 2, 3]), false); assert.strictEqual(_.isMap(true), false); assert.strictEqual(_.isMap(new Date), false); assert.strictEqual(_.isMap(new Error), false); assert.strictEqual(_.isMap(_), false); assert.strictEqual(_.isMap(slice), false); assert.strictEqual(_.isMap({ 'a': 1 }), false); assert.strictEqual(_.isMap(1), false); assert.strictEqual(_.isMap(/x/), false); assert.strictEqual(_.isMap('a'), false); assert.strictEqual(_.isMap(symbol), false); assert.strictEqual(_.isMap(weakMap), false); }); QUnit.test('should work for objects with a non-function `constructor` (test in IE 11)', function(assert) { assert.expect(1); var values = [false, true], expected = lodashStable.map(values, stubFalse); var actual = lodashStable.map(values, function(value) { return _.isMap({ 'constructor': value }); }); assert.deepEqual(actual, expected); }); QUnit.test('should work with maps from another realm', function(assert) { assert.expect(1); if (realm.map) { assert.strictEqual(_.isMap(realm.map), true); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isMatchWith'); (function() { QUnit.test('should provide correct `customizer` arguments', function(assert) { assert.expect(1); var argsList = [], object1 = { 'a': [1, 2], 'b': null }, object2 = { 'a': [1, 2], 'b': null }; object1.b = object2; object2.b = object1; var expected = [ [object1.a, object2.a, 'a', object1, object2], [object1.a[0], object2.a[0], 0, object1.a, object2.a], [object1.a[1], object2.a[1], 1, object1.a, object2.a], [object1.b, object2.b, 'b', object1, object2], [object1.b.a, object2.b.a, 'a', object1.b, object2.b], [object1.b.a[0], object2.b.a[0], 0, object1.b.a, object2.b.a], [object1.b.a[1], object2.b.a[1], 1, object1.b.a, object2.b.a], [object1.b.b, object2.b.b, 'b', object1.b, object2.b] ]; _.isMatchWith(object1, object2, function(assert) { argsList.push(slice.call(arguments, 0, -1)); }); assert.deepEqual(argsList, expected); }); QUnit.test('should handle comparisons when `customizer` returns `undefined`', function(assert) { assert.expect(1); assert.strictEqual(_.isMatchWith({ 'a': 1 }, { 'a': 1 }, noop), true); }); QUnit.test('should not handle comparisons when `customizer` returns `true`', function(assert) { assert.expect(2); var customizer = function(value) { return _.isString(value) || undefined; }; assert.strictEqual(_.isMatchWith(['a'], ['b'], customizer), true); assert.strictEqual(_.isMatchWith({ '0': 'a' }, { '0': 'b' }, customizer), true); }); QUnit.test('should not handle comparisons when `customizer` returns `false`', function(assert) { assert.expect(2); var customizer = function(value) { return _.isString(value) ? false : undefined; }; assert.strictEqual(_.isMatchWith(['a'], ['a'], customizer), false); assert.strictEqual(_.isMatchWith({ '0': 'a' }, { '0': 'a' }, customizer), false); }); QUnit.test('should return a boolean value even when `customizer` does not', function(assert) { assert.expect(2); var object = { 'a': 1 }, actual = _.isMatchWith(object, { 'a': 1 }, stubA); assert.strictEqual(actual, true); var expected = lodashStable.map(falsey, stubFalse); actual = []; lodashStable.each(falsey, function(value) { actual.push(_.isMatchWith(object, { 'a': 2 }, lodashStable.constant(value))); }); assert.deepEqual(actual, expected); }); QUnit.test('should provide `stack` to `customizer`', function(assert) { assert.expect(1); var actual; _.isMatchWith({ 'a': 1 }, { 'a': 1 }, function() { actual = _.last(arguments); }); assert.ok(isNpm ? actual.constructor.name == 'Stack' : actual instanceof mapCaches.Stack ); }); QUnit.test('should ensure `customizer` is a function', function(assert) { assert.expect(1); var object = { 'a': 1 }, matches = _.partial(_.isMatchWith, object), actual = lodashStable.map([object, { 'a': 2 }], matches); assert.deepEqual(actual, [true, false]); }); QUnit.test('should call `customizer` for values maps and sets', function(assert) { assert.expect(2); var value = { 'a': { 'b': 2 } }; if (Map) { var map1 = new Map; map1.set('a', value); var map2 = new Map; map2.set('a', value); } if (Set) { var set1 = new Set; set1.add(value); var set2 = new Set; set2.add(value); } lodashStable.each([[map1, map2], [set1, set2]], function(pair, index) { if (pair[0]) { var argsList = [], array = lodashStable.toArray(pair[0]), object1 = { 'a': pair[0] }, object2 = { 'a': pair[1] }; var expected = [ [pair[0], pair[1], 'a', object1, object2], [array[0], array[0], 0, array, array], [array[0][0], array[0][0], 0, array[0], array[0]], [array[0][1], array[0][1], 1, array[0], array[0]] ]; if (index) { expected.length = 2; } _.isMatchWith({ 'a': pair[0] }, { 'a': pair[1] }, function() { argsList.push(slice.call(arguments, 0, -1)); }); assert.deepEqual(argsList, expected, index ? 'Set' : 'Map'); } else { skipAssert(assert); } }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isNaN'); (function() { QUnit.test('should return `true` for NaNs', function(assert) { assert.expect(2); assert.strictEqual(_.isNaN(NaN), true); assert.strictEqual(_.isNaN(Object(NaN)), true); }); QUnit.test('should return `false` for non-NaNs', function(assert) { assert.expect(14); var expected = lodashStable.map(falsey, function(value) { return value !== value; }); var actual = lodashStable.map(falsey, function(value, index) { return index ? _.isNaN(value) : _.isNaN(); }); assert.deepEqual(actual, expected); assert.strictEqual(_.isNaN(args), false); assert.strictEqual(_.isNaN([1, 2, 3]), false); assert.strictEqual(_.isNaN(true), false); assert.strictEqual(_.isNaN(new Date), false); assert.strictEqual(_.isNaN(new Error), false); assert.strictEqual(_.isNaN(_), false); assert.strictEqual(_.isNaN(slice), false); assert.strictEqual(_.isNaN({ 'a': 1 }), false); assert.strictEqual(_.isNaN(1), false); assert.strictEqual(_.isNaN(Object(1)), false); assert.strictEqual(_.isNaN(/x/), false); assert.strictEqual(_.isNaN('a'), false); assert.strictEqual(_.isNaN(symbol), false); }); QUnit.test('should work with `NaN` from another realm', function(assert) { assert.expect(1); if (realm.object) { assert.strictEqual(_.isNaN(realm.nan), true); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isNative'); (function() { QUnit.test('should return `true` for native methods', function(assert) { assert.expect(1); var values = [Array, body && body.cloneNode, create, root.encodeURI, Promise, slice, Uint8Array], expected = lodashStable.map(values, Boolean), actual = lodashStable.map(values, _.isNative); assert.deepEqual(actual, expected); }); QUnit.test('should return `false` for non-native methods', function(assert) { assert.expect(12); var expected = lodashStable.map(falsey, stubFalse); var actual = lodashStable.map(falsey, function(value, index) { return index ? _.isNative(value) : _.isNative(); }); assert.deepEqual(actual, expected); assert.strictEqual(_.isNative(args), false); assert.strictEqual(_.isNative([1, 2, 3]), false); assert.strictEqual(_.isNative(true), false); assert.strictEqual(_.isNative(new Date), false); assert.strictEqual(_.isNative(new Error), false); assert.strictEqual(_.isNative(_), false); assert.strictEqual(_.isNative({ 'a': 1 }), false); assert.strictEqual(_.isNative(1), false); assert.strictEqual(_.isNative(/x/), false); assert.strictEqual(_.isNative('a'), false); assert.strictEqual(_.isNative(symbol), false); }); QUnit.test('should work with native functions from another realm', function(assert) { assert.expect(2); if (realm.element) { assert.strictEqual(_.isNative(realm.element.cloneNode), true); } else { skipAssert(assert); } if (realm.object) { assert.strictEqual(_.isNative(realm.object.valueOf), true); } else { skipAssert(assert); } }); QUnit.test('should throw an error if core-js is detected', function(assert) { assert.expect(1); if (!isModularize) { var lodash = _.runInContext({ '__core-js_shared__': {} }); assert.raises(function() { lodash.isNative(noop); }); } else { skipAssert(assert); } }); QUnit.test('should detect methods masquerading as native (test in Node.js)', function(assert) { assert.expect(2); if (!amd && _._baseEach) { var path = require('path'), basePath = path.dirname(filePath), uid = 'e0gvgyrad1jor', coreKey = '__core-js_shared__', fakeSrcKey = 'Symbol(src)_1.' + uid; root[coreKey] = { 'keys': { 'IE_PROTO': 'Symbol(IE_PROTO)_3.' + uid } }; emptyObject(require.cache); var baseIsNative = interopRequire(path.join(basePath, '_baseIsNative')); assert.strictEqual(baseIsNative(slice), true); slice[fakeSrcKey] = slice + ''; assert.strictEqual(baseIsNative(slice), false); delete slice[fakeSrcKey]; delete root[coreKey]; } else { skipAssert(assert, 2); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isNil'); (function() { QUnit.test('should return `true` for nullish values', function(assert) { assert.expect(3); assert.strictEqual(_.isNil(null), true); assert.strictEqual(_.isNil(), true); assert.strictEqual(_.isNil(undefined), true); }); QUnit.test('should return `false` for non-nullish values', function(assert) { assert.expect(13); var expected = lodashStable.map(falsey, function(value) { return value == null; }); var actual = lodashStable.map(falsey, function(value, index) { return index ? _.isNil(value) : _.isNil(); }); assert.deepEqual(actual, expected); assert.strictEqual(_.isNil(args), false); assert.strictEqual(_.isNil([1, 2, 3]), false); assert.strictEqual(_.isNil(true), false); assert.strictEqual(_.isNil(new Date), false); assert.strictEqual(_.isNil(new Error), false); assert.strictEqual(_.isNil(_), false); assert.strictEqual(_.isNil(slice), false); assert.strictEqual(_.isNil({ 'a': 1 }), false); assert.strictEqual(_.isNil(1), false); assert.strictEqual(_.isNil(/x/), false); assert.strictEqual(_.isNil('a'), false); if (Symbol) { assert.strictEqual(_.isNil(symbol), false); } else { skipAssert(assert); } }); QUnit.test('should work with nils from another realm', function(assert) { assert.expect(2); if (realm.object) { assert.strictEqual(_.isNil(realm.null), true); assert.strictEqual(_.isNil(realm.undefined), true); } else { skipAssert(assert, 2); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isNull'); (function() { QUnit.test('should return `true` for `null` values', function(assert) { assert.expect(1); assert.strictEqual(_.isNull(null), true); }); QUnit.test('should return `false` for non `null` values', function(assert) { assert.expect(13); var expected = lodashStable.map(falsey, function(value) { return value === null; }); var actual = lodashStable.map(falsey, function(value, index) { return index ? _.isNull(value) : _.isNull(); }); assert.deepEqual(actual, expected); assert.strictEqual(_.isNull(args), false); assert.strictEqual(_.isNull([1, 2, 3]), false); assert.strictEqual(_.isNull(true), false); assert.strictEqual(_.isNull(new Date), false); assert.strictEqual(_.isNull(new Error), false); assert.strictEqual(_.isNull(_), false); assert.strictEqual(_.isNull(slice), false); assert.strictEqual(_.isNull({ 'a': 1 }), false); assert.strictEqual(_.isNull(1), false); assert.strictEqual(_.isNull(/x/), false); assert.strictEqual(_.isNull('a'), false); assert.strictEqual(_.isNull(symbol), false); }); QUnit.test('should work with nulls from another realm', function(assert) { assert.expect(1); if (realm.object) { assert.strictEqual(_.isNull(realm.null), true); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isNumber'); (function() { QUnit.test('should return `true` for numbers', function(assert) { assert.expect(3); assert.strictEqual(_.isNumber(0), true); assert.strictEqual(_.isNumber(Object(0)), true); assert.strictEqual(_.isNumber(NaN), true); }); QUnit.test('should return `false` for non-numbers', function(assert) { assert.expect(12); var expected = lodashStable.map(falsey, function(value) { return typeof value == 'number'; }); var actual = lodashStable.map(falsey, function(value, index) { return index ? _.isNumber(value) : _.isNumber(); }); assert.deepEqual(actual, expected); assert.strictEqual(_.isNumber(args), false); assert.strictEqual(_.isNumber([1, 2, 3]), false); assert.strictEqual(_.isNumber(true), false); assert.strictEqual(_.isNumber(new Date), false); assert.strictEqual(_.isNumber(new Error), false); assert.strictEqual(_.isNumber(_), false); assert.strictEqual(_.isNumber(slice), false); assert.strictEqual(_.isNumber({ 'a': 1 }), false); assert.strictEqual(_.isNumber(/x/), false); assert.strictEqual(_.isNumber('a'), false); assert.strictEqual(_.isNumber(symbol), false); }); QUnit.test('should work with numbers from another realm', function(assert) { assert.expect(1); if (realm.number) { assert.strictEqual(_.isNumber(realm.number), true); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isObject'); (function() { QUnit.test('should return `true` for objects', function(assert) { assert.expect(13); assert.strictEqual(_.isObject(args), true); assert.strictEqual(_.isObject([1, 2, 3]), true); assert.strictEqual(_.isObject(Object(false)), true); assert.strictEqual(_.isObject(new Date), true); assert.strictEqual(_.isObject(new Error), true); assert.strictEqual(_.isObject(_), true); assert.strictEqual(_.isObject(slice), true); assert.strictEqual(_.isObject({ 'a': 1 }), true); assert.strictEqual(_.isObject(Object(0)), true); assert.strictEqual(_.isObject(/x/), true); assert.strictEqual(_.isObject(Object('a')), true); if (document) { assert.strictEqual(_.isObject(body), true); } else { skipAssert(assert); } if (Symbol) { assert.strictEqual(_.isObject(Object(symbol)), true); } else { skipAssert(assert); } }); QUnit.test('should return `false` for non-objects', function(assert) { assert.expect(1); var values = falsey.concat(true, 1, 'a', symbol), expected = lodashStable.map(values, stubFalse); var actual = lodashStable.map(values, function(value, index) { return index ? _.isObject(value) : _.isObject(); }); assert.deepEqual(actual, expected); }); QUnit.test('should work with objects from another realm', function(assert) { assert.expect(8); if (realm.element) { assert.strictEqual(_.isObject(realm.element), true); } else { skipAssert(assert); } if (realm.object) { assert.strictEqual(_.isObject(realm.boolean), true); assert.strictEqual(_.isObject(realm.date), true); assert.strictEqual(_.isObject(realm.function), true); assert.strictEqual(_.isObject(realm.number), true); assert.strictEqual(_.isObject(realm.object), true); assert.strictEqual(_.isObject(realm.regexp), true); assert.strictEqual(_.isObject(realm.string), true); } else { skipAssert(assert, 7); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isObjectLike'); (function() { QUnit.test('should return `true` for objects', function(assert) { assert.expect(9); assert.strictEqual(_.isObjectLike(args), true); assert.strictEqual(_.isObjectLike([1, 2, 3]), true); assert.strictEqual(_.isObjectLike(Object(false)), true); assert.strictEqual(_.isObjectLike(new Date), true); assert.strictEqual(_.isObjectLike(new Error), true); assert.strictEqual(_.isObjectLike({ 'a': 1 }), true); assert.strictEqual(_.isObjectLike(Object(0)), true); assert.strictEqual(_.isObjectLike(/x/), true); assert.strictEqual(_.isObjectLike(Object('a')), true); }); QUnit.test('should return `false` for non-objects', function(assert) { assert.expect(1); var values = falsey.concat(true, _, slice, 1, 'a', symbol), expected = lodashStable.map(values, stubFalse); var actual = lodashStable.map(values, function(value, index) { return index ? _.isObjectLike(value) : _.isObjectLike(); }); assert.deepEqual(actual, expected); }); QUnit.test('should work with objects from another realm', function(assert) { assert.expect(6); if (realm.object) { assert.strictEqual(_.isObjectLike(realm.boolean), true); assert.strictEqual(_.isObjectLike(realm.date), true); assert.strictEqual(_.isObjectLike(realm.number), true); assert.strictEqual(_.isObjectLike(realm.object), true); assert.strictEqual(_.isObjectLike(realm.regexp), true); assert.strictEqual(_.isObjectLike(realm.string), true); } else { skipAssert(assert, 6); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isPlainObject'); (function() { var element = document && document.createElement('div'); QUnit.test('should detect plain objects', function(assert) { assert.expect(5); function Foo(a) { this.a = 1; } assert.strictEqual(_.isPlainObject({}), true); assert.strictEqual(_.isPlainObject({ 'a': 1 }), true); assert.strictEqual(_.isPlainObject({ 'constructor': Foo }), true); assert.strictEqual(_.isPlainObject([1, 2, 3]), false); assert.strictEqual(_.isPlainObject(new Foo(1)), false); }); QUnit.test('should return `true` for objects with a `[[Prototype]]` of `null`', function(assert) { assert.expect(2); var object = create(null); assert.strictEqual(_.isPlainObject(object), true); object.constructor = objectProto.constructor; assert.strictEqual(_.isPlainObject(object), true); }); QUnit.test('should return `true` for objects with a `valueOf` property', function(assert) { assert.expect(1); assert.strictEqual(_.isPlainObject({ 'valueOf': 0 }), true); }); QUnit.test('should return `true` for objects with a writable `Symbol.toStringTag` property', function(assert) { assert.expect(1); if (Symbol && Symbol.toStringTag) { var object = {}; object[Symbol.toStringTag] = 'X'; assert.deepEqual(_.isPlainObject(object), true); } else { skipAssert(assert); } }); QUnit.test('should return `false` for objects with a custom `[[Prototype]]`', function(assert) { assert.expect(1); var object = create({ 'a': 1 }); assert.strictEqual(_.isPlainObject(object), false); }); QUnit.test('should return `false` for DOM elements', function(assert) { assert.expect(1); if (element) { assert.strictEqual(_.isPlainObject(element), false); } else { skipAssert(assert); } }); QUnit.test('should return `false` for non-Object objects', function(assert) { assert.expect(3); assert.strictEqual(_.isPlainObject(arguments), false); assert.strictEqual(_.isPlainObject(Error), false); assert.strictEqual(_.isPlainObject(Math), false); }); QUnit.test('should return `false` for non-objects', function(assert) { assert.expect(4); var expected = lodashStable.map(falsey, stubFalse); var actual = lodashStable.map(falsey, function(value, index) { return index ? _.isPlainObject(value) : _.isPlainObject(); }); assert.deepEqual(actual, expected); assert.strictEqual(_.isPlainObject(true), false); assert.strictEqual(_.isPlainObject('a'), false); assert.strictEqual(_.isPlainObject(symbol), false); }); QUnit.test('should return `false` for objects with a read-only `Symbol.toStringTag` property', function(assert) { assert.expect(1); if (Symbol && Symbol.toStringTag) { var object = {}; defineProperty(object, Symbol.toStringTag, { 'configurable': true, 'enumerable': false, 'writable': false, 'value': 'X' }); assert.deepEqual(_.isPlainObject(object), false); } else { skipAssert(assert); } }); QUnit.test('should not mutate `value`', function(assert) { assert.expect(2); if (Symbol && Symbol.toStringTag) { var proto = {}; proto[Symbol.toStringTag] = undefined; var object = create(proto); assert.strictEqual(_.isPlainObject(object), false); assert.notOk(lodashStable.has(object, Symbol.toStringTag)); } else { skipAssert(assert, 2); } }); QUnit.test('should work with objects from another realm', function(assert) { assert.expect(1); if (realm.object) { assert.strictEqual(_.isPlainObject(realm.object), true); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isRegExp'); (function() { QUnit.test('should return `true` for regexes', function(assert) { assert.expect(2); assert.strictEqual(_.isRegExp(/x/), true); assert.strictEqual(_.isRegExp(RegExp('x')), true); }); QUnit.test('should return `false` for non-regexes', function(assert) { assert.expect(12); var expected = lodashStable.map(falsey, stubFalse); var actual = lodashStable.map(falsey, function(value, index) { return index ? _.isRegExp(value) : _.isRegExp(); }); assert.deepEqual(actual, expected); assert.strictEqual(_.isRegExp(args), false); assert.strictEqual(_.isRegExp([1, 2, 3]), false); assert.strictEqual(_.isRegExp(true), false); assert.strictEqual(_.isRegExp(new Date), false); assert.strictEqual(_.isRegExp(new Error), false); assert.strictEqual(_.isRegExp(_), false); assert.strictEqual(_.isRegExp(slice), false); assert.strictEqual(_.isRegExp({ 'a': 1 }), false); assert.strictEqual(_.isRegExp(1), false); assert.strictEqual(_.isRegExp('a'), false); assert.strictEqual(_.isRegExp(symbol), false); }); QUnit.test('should work with regexes from another realm', function(assert) { assert.expect(1); if (realm.regexp) { assert.strictEqual(_.isRegExp(realm.regexp), true); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isSet'); (function() { QUnit.test('should return `true` for sets', function(assert) { assert.expect(1); if (Set) { assert.strictEqual(_.isSet(set), true); } else { skipAssert(assert); } }); QUnit.test('should return `false` for non-sets', function(assert) { assert.expect(14); var expected = lodashStable.map(falsey, stubFalse); var actual = lodashStable.map(falsey, function(value, index) { return index ? _.isSet(value) : _.isSet(); }); assert.deepEqual(actual, expected); assert.strictEqual(_.isSet(args), false); assert.strictEqual(_.isSet([1, 2, 3]), false); assert.strictEqual(_.isSet(true), false); assert.strictEqual(_.isSet(new Date), false); assert.strictEqual(_.isSet(new Error), false); assert.strictEqual(_.isSet(_), false); assert.strictEqual(_.isSet(slice), false); assert.strictEqual(_.isSet({ 'a': 1 }), false); assert.strictEqual(_.isSet(1), false); assert.strictEqual(_.isSet(/x/), false); assert.strictEqual(_.isSet('a'), false); assert.strictEqual(_.isSet(symbol), false); assert.strictEqual(_.isSet(weakSet), false); }); QUnit.test('should work for objects with a non-function `constructor` (test in IE 11)', function(assert) { assert.expect(1); var values = [false, true], expected = lodashStable.map(values, stubFalse); var actual = lodashStable.map(values, function(value) { return _.isSet({ 'constructor': value }); }); assert.deepEqual(actual, expected); }); QUnit.test('should work with weak sets from another realm', function(assert) { assert.expect(1); if (realm.set) { assert.strictEqual(_.isSet(realm.set), true); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isString'); (function() { QUnit.test('should return `true` for strings', function(assert) { assert.expect(2); assert.strictEqual(_.isString('a'), true); assert.strictEqual(_.isString(Object('a')), true); }); QUnit.test('should return `false` for non-strings', function(assert) { assert.expect(12); var expected = lodashStable.map(falsey, function(value) { return value === ''; }); var actual = lodashStable.map(falsey, function(value, index) { return index ? _.isString(value) : _.isString(); }); assert.deepEqual(actual, expected); assert.strictEqual(_.isString(args), false); assert.strictEqual(_.isString([1, 2, 3]), false); assert.strictEqual(_.isString(true), false); assert.strictEqual(_.isString(new Date), false); assert.strictEqual(_.isString(new Error), false); assert.strictEqual(_.isString(_), false); assert.strictEqual(_.isString(slice), false); assert.strictEqual(_.isString({ '0': 1, 'length': 1 }), false); assert.strictEqual(_.isString(1), false); assert.strictEqual(_.isString(/x/), false); assert.strictEqual(_.isString(symbol), false); }); QUnit.test('should work with strings from another realm', function(assert) { assert.expect(1); if (realm.string) { assert.strictEqual(_.isString(realm.string), true); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isSymbol'); (function() { QUnit.test('should return `true` for symbols', function(assert) { assert.expect(2); if (Symbol) { assert.strictEqual(_.isSymbol(symbol), true); assert.strictEqual(_.isSymbol(Object(symbol)), true); } else { skipAssert(assert, 2); } }); QUnit.test('should return `false` for non-symbols', function(assert) { assert.expect(12); var expected = lodashStable.map(falsey, stubFalse); var actual = lodashStable.map(falsey, function(value, index) { return index ? _.isSymbol(value) : _.isSymbol(); }); assert.deepEqual(actual, expected); assert.strictEqual(_.isSymbol(args), false); assert.strictEqual(_.isSymbol([1, 2, 3]), false); assert.strictEqual(_.isSymbol(true), false); assert.strictEqual(_.isSymbol(new Date), false); assert.strictEqual(_.isSymbol(new Error), false); assert.strictEqual(_.isSymbol(_), false); assert.strictEqual(_.isSymbol(slice), false); assert.strictEqual(_.isSymbol({ '0': 1, 'length': 1 }), false); assert.strictEqual(_.isSymbol(1), false); assert.strictEqual(_.isSymbol(/x/), false); assert.strictEqual(_.isSymbol('a'), false); }); QUnit.test('should work with symbols from another realm', function(assert) { assert.expect(1); if (Symbol && realm.symbol) { assert.strictEqual(_.isSymbol(realm.symbol), true); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isTypedArray'); (function() { QUnit.test('should return `true` for typed arrays', function(assert) { assert.expect(1); var expected = lodashStable.map(typedArrays, function(type) { return type in root; }); var actual = lodashStable.map(typedArrays, function(type) { var Ctor = root[type]; return Ctor ? _.isTypedArray(new Ctor(new ArrayBuffer(8))) : false; }); assert.deepEqual(actual, expected); }); QUnit.test('should return `false` for non typed arrays', function(assert) { assert.expect(13); var expected = lodashStable.map(falsey, stubFalse); var actual = lodashStable.map(falsey, function(value, index) { return index ? _.isTypedArray(value) : _.isTypedArray(); }); assert.deepEqual(actual, expected); assert.strictEqual(_.isTypedArray(args), false); assert.strictEqual(_.isTypedArray([1, 2, 3]), false); assert.strictEqual(_.isTypedArray(true), false); assert.strictEqual(_.isTypedArray(new Date), false); assert.strictEqual(_.isTypedArray(new Error), false); assert.strictEqual(_.isTypedArray(_), false); assert.strictEqual(_.isTypedArray(slice), false); assert.strictEqual(_.isTypedArray({ 'a': 1 }), false); assert.strictEqual(_.isTypedArray(1), false); assert.strictEqual(_.isTypedArray(/x/), false); assert.strictEqual(_.isTypedArray('a'), false); assert.strictEqual(_.isTypedArray(symbol), false); }); QUnit.test('should work with typed arrays from another realm', function(assert) { assert.expect(1); if (realm.object) { var props = lodashStable.invokeMap(typedArrays, 'toLowerCase'); var expected = lodashStable.map(props, function(key) { return realm[key] !== undefined; }); var actual = lodashStable.map(props, function(key) { var value = realm[key]; return value ? _.isTypedArray(value) : false; }); assert.deepEqual(actual, expected); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isUndefined'); (function() { QUnit.test('should return `true` for `undefined` values', function(assert) { assert.expect(2); assert.strictEqual(_.isUndefined(), true); assert.strictEqual(_.isUndefined(undefined), true); }); QUnit.test('should return `false` for non `undefined` values', function(assert) { assert.expect(13); var expected = lodashStable.map(falsey, function(value) { return value === undefined; }); var actual = lodashStable.map(falsey, function(value, index) { return index ? _.isUndefined(value) : _.isUndefined(); }); assert.deepEqual(actual, expected); assert.strictEqual(_.isUndefined(args), false); assert.strictEqual(_.isUndefined([1, 2, 3]), false); assert.strictEqual(_.isUndefined(true), false); assert.strictEqual(_.isUndefined(new Date), false); assert.strictEqual(_.isUndefined(new Error), false); assert.strictEqual(_.isUndefined(_), false); assert.strictEqual(_.isUndefined(slice), false); assert.strictEqual(_.isUndefined({ 'a': 1 }), false); assert.strictEqual(_.isUndefined(1), false); assert.strictEqual(_.isUndefined(/x/), false); assert.strictEqual(_.isUndefined('a'), false); if (Symbol) { assert.strictEqual(_.isUndefined(symbol), false); } else { skipAssert(assert); } }); QUnit.test('should work with `undefined` from another realm', function(assert) { assert.expect(1); if (realm.object) { assert.strictEqual(_.isUndefined(realm.undefined), true); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isWeakMap'); (function() { QUnit.test('should return `true` for weak maps', function(assert) { assert.expect(1); if (WeakMap) { assert.strictEqual(_.isWeakMap(weakMap), true); } else { skipAssert(assert); } }); QUnit.test('should return `false` for non weak maps', function(assert) { assert.expect(14); var expected = lodashStable.map(falsey, stubFalse); var actual = lodashStable.map(falsey, function(value, index) { return index ? _.isWeakMap(value) : _.isWeakMap(); }); assert.deepEqual(actual, expected); assert.strictEqual(_.isWeakMap(args), false); assert.strictEqual(_.isWeakMap([1, 2, 3]), false); assert.strictEqual(_.isWeakMap(true), false); assert.strictEqual(_.isWeakMap(new Date), false); assert.strictEqual(_.isWeakMap(new Error), false); assert.strictEqual(_.isWeakMap(_), false); assert.strictEqual(_.isWeakMap(slice), false); assert.strictEqual(_.isWeakMap({ 'a': 1 }), false); assert.strictEqual(_.isWeakMap(map), false); assert.strictEqual(_.isWeakMap(1), false); assert.strictEqual(_.isWeakMap(/x/), false); assert.strictEqual(_.isWeakMap('a'), false); assert.strictEqual(_.isWeakMap(symbol), false); }); QUnit.test('should work for objects with a non-function `constructor` (test in IE 11)', function(assert) { assert.expect(1); var values = [false, true], expected = lodashStable.map(values, stubFalse); var actual = lodashStable.map(values, function(value) { return _.isWeakMap({ 'constructor': value }); }); assert.deepEqual(actual, expected); }); QUnit.test('should work with weak maps from another realm', function(assert) { assert.expect(1); if (realm.weakMap) { assert.strictEqual(_.isWeakMap(realm.weakMap), true); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.isWeakSet'); (function() { QUnit.test('should return `true` for weak sets', function(assert) { assert.expect(1); if (WeakSet) { assert.strictEqual(_.isWeakSet(weakSet), true); } else { skipAssert(assert); } }); QUnit.test('should return `false` for non weak sets', function(assert) { assert.expect(14); var expected = lodashStable.map(falsey, stubFalse); var actual = lodashStable.map(falsey, function(value, index) { return index ? _.isWeakSet(value) : _.isWeakSet(); }); assert.deepEqual(actual, expected); assert.strictEqual(_.isWeakSet(args), false); assert.strictEqual(_.isWeakSet([1, 2, 3]), false); assert.strictEqual(_.isWeakSet(true), false); assert.strictEqual(_.isWeakSet(new Date), false); assert.strictEqual(_.isWeakSet(new Error), false); assert.strictEqual(_.isWeakSet(_), false); assert.strictEqual(_.isWeakSet(slice), false); assert.strictEqual(_.isWeakSet({ 'a': 1 }), false); assert.strictEqual(_.isWeakSet(1), false); assert.strictEqual(_.isWeakSet(/x/), false); assert.strictEqual(_.isWeakSet('a'), false); assert.strictEqual(_.isWeakSet(set), false); assert.strictEqual(_.isWeakSet(symbol), false); }); QUnit.test('should work with weak sets from another realm', function(assert) { assert.expect(1); if (realm.weakSet) { assert.strictEqual(_.isWeakSet(realm.weakSet), true); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('isType checks'); (function() { QUnit.test('should return `false` for subclassed values', function(assert) { assert.expect(7); var funcs = [ 'isArray', 'isBoolean', 'isDate', 'isFunction', 'isNumber', 'isRegExp', 'isString' ]; lodashStable.each(funcs, function(methodName) { function Foo() {} Foo.prototype = root[methodName.slice(2)].prototype; var object = new Foo; if (objToString.call(object) == objectTag) { assert.strictEqual(_[methodName](object), false, '`_.' + methodName + '` returns `false`'); } else { skipAssert(assert); } }); }); QUnit.test('should not error on host objects (test in IE)', function(assert) { assert.expect(26); var funcs = [ 'isArguments', 'isArray', 'isArrayBuffer', 'isArrayLike', 'isBoolean', 'isBuffer', 'isDate', 'isElement', 'isError', 'isFinite', 'isFunction', 'isInteger', 'isMap', 'isNaN', 'isNil', 'isNull', 'isNumber', 'isObject', 'isObjectLike', 'isRegExp', 'isSet', 'isSafeInteger', 'isString', 'isUndefined', 'isWeakMap', 'isWeakSet' ]; lodashStable.each(funcs, function(methodName) { if (xml) { _[methodName](xml); assert.ok(true, '`_.' + methodName + '` should not error'); } else { skipAssert(assert); } }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.iteratee'); (function() { QUnit.test('should provide arguments to `func`', function(assert) { assert.expect(1); var fn = function() { return slice.call(arguments); }, iteratee = _.iteratee(fn), actual = iteratee('a', 'b', 'c', 'd', 'e', 'f'); assert.deepEqual(actual, ['a', 'b', 'c', 'd', 'e', 'f']); }); QUnit.test('should return `_.identity` when `func` is nullish', function(assert) { assert.expect(1); var object = {}, values = [, null, undefined], expected = lodashStable.map(values, lodashStable.constant([!isNpm && _.identity, object])); var actual = lodashStable.map(values, function(value, index) { var identity = index ? _.iteratee(value) : _.iteratee(); return [!isNpm && identity, identity(object)]; }); assert.deepEqual(actual, expected); }); QUnit.test('should return an iteratee created by `_.matches` when `func` is an object', function(assert) { assert.expect(2); var matches = _.iteratee({ 'a': 1, 'b': 2 }); assert.strictEqual(matches({ 'a': 1, 'b': 2, 'c': 3 }), true); assert.strictEqual(matches({ 'b': 2 }), false); }); QUnit.test('should not change `_.matches` behavior if `source` is modified', function(assert) { assert.expect(9); var sources = [ { 'a': { 'b': 2, 'c': 3 } }, { 'a': 1, 'b': 2 }, { 'a': 1 } ]; lodashStable.each(sources, function(source, index) { var object = lodashStable.cloneDeep(source), matches = _.iteratee(source); assert.strictEqual(matches(object), true); if (index) { source.a = 2; source.b = 1; source.c = 3; } else { source.a.b = 1; source.a.c = 2; source.a.d = 3; } assert.strictEqual(matches(object), true); assert.strictEqual(matches(source), false); }); }); QUnit.test('should return an iteratee created by `_.matchesProperty` when `func` is an array', function(assert) { assert.expect(3); var array = ['a', undefined], matches = _.iteratee([0, 'a']); assert.strictEqual(matches(array), true); matches = _.iteratee(['0', 'a']); assert.strictEqual(matches(array), true); matches = _.iteratee([1, undefined]); assert.strictEqual(matches(array), true); }); QUnit.test('should support deep paths for `_.matchesProperty` shorthands', function(assert) { assert.expect(1); var object = { 'a': { 'b': { 'c': 1, 'd': 2 } } }, matches = _.iteratee(['a.b', { 'c': 1 }]); assert.strictEqual(matches(object), true); }); QUnit.test('should not change `_.matchesProperty` behavior if `source` is modified', function(assert) { assert.expect(9); var sources = [ { 'a': { 'b': 2, 'c': 3 } }, { 'a': 1, 'b': 2 }, { 'a': 1 } ]; lodashStable.each(sources, function(source, index) { var object = { 'a': lodashStable.cloneDeep(source) }, matches = _.iteratee(['a', source]); assert.strictEqual(matches(object), true); if (index) { source.a = 2; source.b = 1; source.c = 3; } else { source.a.b = 1; source.a.c = 2; source.a.d = 3; } assert.strictEqual(matches(object), true); assert.strictEqual(matches({ 'a': source }), false); }); }); QUnit.test('should return an iteratee created by `_.property` when `func` is a number or string', function(assert) { assert.expect(2); var array = ['a'], prop = _.iteratee(0); assert.strictEqual(prop(array), 'a'); prop = _.iteratee('0'); assert.strictEqual(prop(array), 'a'); }); QUnit.test('should support deep paths for `_.property` shorthands', function(assert) { assert.expect(1); var object = { 'a': { 'b': 2 } }, prop = _.iteratee('a.b'); assert.strictEqual(prop(object), 2); }); QUnit.test('should work with functions created by `_.partial` and `_.partialRight`', function(assert) { assert.expect(2); var fn = function() { var result = [this.a]; push.apply(result, arguments); return result; }; var expected = [1, 2, 3], object = { 'a': 1 , 'iteratee': _.iteratee(_.partial(fn, 2)) }; assert.deepEqual(object.iteratee(3), expected); object.iteratee = _.iteratee(_.partialRight(fn, 3)); assert.deepEqual(object.iteratee(2), expected); }); QUnit.test('should use internal `iteratee` if external is unavailable', function(assert) { assert.expect(1); var iteratee = _.iteratee; delete _.iteratee; assert.deepEqual(_.map([{ 'a': 1 }], 'a'), [1]); _.iteratee = iteratee; }); QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(1); var fn = function() { return this instanceof Number; }, array = [fn, fn, fn], iteratees = lodashStable.map(array, _.iteratee), expected = lodashStable.map(array, stubFalse); var actual = lodashStable.map(iteratees, function(iteratee) { return iteratee(); }); assert.deepEqual(actual, expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('custom `_.iteratee` methods'); (function() { var array = ['one', 'two', 'three'], getPropA = _.partial(_.property, 'a'), getPropB = _.partial(_.property, 'b'), getLength = _.partial(_.property, 'length'), iteratee = _.iteratee; var getSum = function() { return function(result, object) { return result + object.a; }; }; var objects = [ { 'a': 0, 'b': 0 }, { 'a': 1, 'b': 0 }, { 'a': 1, 'b': 1 } ]; QUnit.test('`_.countBy` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getLength; assert.deepEqual(_.countBy(array), { '3': 2, '5': 1 }); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.differenceBy` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getPropA; assert.deepEqual(_.differenceBy(objects, [objects[1]]), [objects[0]]); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.dropRightWhile` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getPropB; assert.deepEqual(_.dropRightWhile(objects), objects.slice(0, 2)); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.dropWhile` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getPropB; assert.deepEqual(_.dropWhile(objects.reverse()).reverse(), objects.reverse().slice(0, 2)); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.every` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getPropA; assert.strictEqual(_.every(objects.slice(1)), true); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.filter` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { var objects = [{ 'a': 0 }, { 'a': 1 }]; _.iteratee = getPropA; assert.deepEqual(_.filter(objects), [objects[1]]); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.find` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getPropA; assert.strictEqual(_.find(objects), objects[1]); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.findIndex` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getPropA; assert.strictEqual(_.findIndex(objects), 1); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.findLast` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getPropA; assert.strictEqual(_.findLast(objects), objects[2]); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.findLastIndex` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getPropA; assert.strictEqual(_.findLastIndex(objects), 2); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.findKey` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getPropB; assert.strictEqual(_.findKey(objects), '2'); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.findLastKey` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getPropB; assert.strictEqual(_.findLastKey(objects), '2'); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.groupBy` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getLength; assert.deepEqual(_.groupBy(array), { '3': ['one', 'two'], '5': ['three'] }); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.intersectionBy` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getPropA; assert.deepEqual(_.intersectionBy(objects, [objects[2]]), [objects[1]]); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.keyBy` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getLength; assert.deepEqual(_.keyBy(array), { '3': 'two', '5': 'three' }); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.map` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getPropA; assert.deepEqual(_.map(objects), [0, 1, 1]); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.mapKeys` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getPropB; assert.deepEqual(_.mapKeys({ 'a': { 'b': 2 } }), { '2': { 'b': 2 } }); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.mapValues` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getPropB; assert.deepEqual(_.mapValues({ 'a': { 'b': 2 } }), { 'a': 2 }); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.maxBy` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getPropB; assert.deepEqual(_.maxBy(objects), objects[2]); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.meanBy` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getPropA; assert.strictEqual(_.meanBy(objects), 2 / 3); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.minBy` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getPropB; assert.deepEqual(_.minBy(objects), objects[0]); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.partition` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { var objects = [{ 'a': 1 }, { 'a': 1 }, { 'b': 2 }]; _.iteratee = getPropA; assert.deepEqual(_.partition(objects), [objects.slice(0, 2), objects.slice(2)]); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.pullAllBy` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getPropA; assert.deepEqual(_.pullAllBy(objects.slice(), [{ 'a': 1, 'b': 0 }]), [objects[0]]); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.reduce` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getSum; assert.strictEqual(_.reduce(objects, undefined, 0), 2); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.reduceRight` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getSum; assert.strictEqual(_.reduceRight(objects, undefined, 0), 2); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.reject` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { var objects = [{ 'a': 0 }, { 'a': 1 }]; _.iteratee = getPropA; assert.deepEqual(_.reject(objects), [objects[0]]); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.remove` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { var objects = [{ 'a': 0 }, { 'a': 1 }]; _.iteratee = getPropA; _.remove(objects); assert.deepEqual(objects, [{ 'a': 0 }]); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.some` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getPropB; assert.strictEqual(_.some(objects), true); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.sortBy` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getPropA; assert.deepEqual(_.sortBy(objects.slice().reverse()), [objects[0], objects[2], objects[1]]); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.sortedIndexBy` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { var objects = [{ 'a': 30 }, { 'a': 50 }]; _.iteratee = getPropA; assert.strictEqual(_.sortedIndexBy(objects, { 'a': 40 }), 1); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.sortedLastIndexBy` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { var objects = [{ 'a': 30 }, { 'a': 50 }]; _.iteratee = getPropA; assert.strictEqual(_.sortedLastIndexBy(objects, { 'a': 40 }), 1); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.sumBy` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getPropB; assert.strictEqual(_.sumBy(objects), 1); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.takeRightWhile` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getPropB; assert.deepEqual(_.takeRightWhile(objects), objects.slice(2)); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.takeWhile` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getPropB; assert.deepEqual(_.takeWhile(objects.reverse()), objects.reverse().slice(2)); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.transform` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = function() { return function(result, object) { result.sum += object.a; }; }; assert.deepEqual(_.transform(objects, undefined, { 'sum': 0 }), { 'sum': 2 }); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.uniqBy` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getPropB; assert.deepEqual(_.uniqBy(objects), [objects[0], objects[2]]); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.unionBy` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getPropB; assert.deepEqual(_.unionBy(objects.slice(0, 1), [objects[2]]), [objects[0], objects[2]]); _.iteratee = iteratee; } else { skipAssert(assert); } }); QUnit.test('`_.xorBy` should use `_.iteratee` internally', function(assert) { assert.expect(1); if (!isModularize) { _.iteratee = getPropA; assert.deepEqual(_.xorBy(objects, objects.slice(1)), [objects[0]]); _.iteratee = iteratee; } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.join'); (function() { var array = ['a', 'b', 'c']; QUnit.test('should return join all array elements into a string', function(assert) { assert.expect(1); assert.strictEqual(_.join(array, '~'), 'a~b~c'); }); QUnit.test('should return an unwrapped value when implicitly chaining', function(assert) { assert.expect(2); if (!isNpm) { var wrapped = _(array); assert.strictEqual(wrapped.join('~'), 'a~b~c'); assert.strictEqual(wrapped.value(), array); } else { skipAssert(assert, 2); } }); QUnit.test('should return a wrapped value when explicitly chaining', function(assert) { assert.expect(1); if (!isNpm) { assert.ok(_(array).chain().join('~') instanceof _); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.keyBy'); (function() { var array = [ { 'dir': 'left', 'code': 97 }, { 'dir': 'right', 'code': 100 } ]; QUnit.test('should transform keys by `iteratee`', function(assert) { assert.expect(1); var expected = { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }; var actual = _.keyBy(array, function(object) { return String.fromCharCode(object.code); }); assert.deepEqual(actual, expected); }); QUnit.test('should use `_.identity` when `iteratee` is nullish', function(assert) { assert.expect(1); var array = [4, 6, 6], values = [, null, undefined], expected = lodashStable.map(values, lodashStable.constant({ '4': 4, '6': 6 })); var actual = lodashStable.map(values, function(value, index) { return index ? _.keyBy(array, value) : _.keyBy(array); }); assert.deepEqual(actual, expected); }); QUnit.test('should work with `_.property` shorthands', function(assert) { assert.expect(1); var expected = { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }, actual = _.keyBy(array, 'dir'); assert.deepEqual(actual, expected); }); QUnit.test('should only add values to own, not inherited, properties', function(assert) { assert.expect(2); var actual = _.keyBy([6.1, 4.2, 6.3], function(n) { return Math.floor(n) > 4 ? 'hasOwnProperty' : 'constructor'; }); assert.deepEqual(actual.constructor, 4.2); assert.deepEqual(actual.hasOwnProperty, 6.3); }); QUnit.test('should work with a number for `iteratee`', function(assert) { assert.expect(2); var array = [ [1, 'a'], [2, 'a'], [2, 'b'] ]; assert.deepEqual(_.keyBy(array, 0), { '1': [1, 'a'], '2': [2, 'b'] }); assert.deepEqual(_.keyBy(array, 1), { 'a': [2, 'a'], 'b': [2, 'b'] }); }); QUnit.test('should work with an object for `collection`', function(assert) { assert.expect(1); var actual = _.keyBy({ 'a': 6.1, 'b': 4.2, 'c': 6.3 }, Math.floor); assert.deepEqual(actual, { '4': 4.2, '6': 6.3 }); }); QUnit.test('should work in a lazy sequence', function(assert) { assert.expect(1); if (!isNpm) { var array = lodashStable.range(LARGE_ARRAY_SIZE).concat( lodashStable.range(Math.floor(LARGE_ARRAY_SIZE / 2), LARGE_ARRAY_SIZE), lodashStable.range(Math.floor(LARGE_ARRAY_SIZE / 1.5), LARGE_ARRAY_SIZE) ); var actual = _(array).keyBy().map(square).filter(isEven).take().value(); assert.deepEqual(actual, _.take(_.filter(_.map(_.keyBy(array), square), isEven))); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('keys methods'); lodashStable.each(['keys', 'keysIn'], function(methodName) { var func = _[methodName], isKeys = methodName == 'keys'; QUnit.test('`_.' + methodName + '` should return the string keyed property names of `object`', function(assert) { assert.expect(1); var actual = func({ 'a': 1, 'b': 1 }).sort(); assert.deepEqual(actual, ['a', 'b']); }); QUnit.test('`_.' + methodName + '` should ' + (isKeys ? 'not ' : '') + 'include inherited string keyed properties', function(assert) { assert.expect(1); function Foo() { this.a = 1; } Foo.prototype.b = 2; var expected = isKeys ? ['a'] : ['a', 'b'], actual = func(new Foo).sort(); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should treat sparse arrays as dense', function(assert) { assert.expect(1); var array = [1]; array[2] = 3; var actual = func(array).sort(); assert.deepEqual(actual, ['0', '1', '2']); }); QUnit.test('`_.' + methodName + '` should return keys for custom properties on arrays', function(assert) { assert.expect(1); var array = [1]; array.a = 1; var actual = func(array).sort(); assert.deepEqual(actual, ['0', 'a']); }); QUnit.test('`_.' + methodName + '` should ' + (isKeys ? 'not ' : '') + 'include inherited string keyed properties of arrays', function(assert) { assert.expect(1); arrayProto.a = 1; var expected = isKeys ? ['0'] : ['0', 'a'], actual = func([1]).sort(); assert.deepEqual(actual, expected); delete arrayProto.a; }); QUnit.test('`_.' + methodName + '` should work with `arguments` objects', function(assert) { assert.expect(1); var values = [args, strictArgs], expected = lodashStable.map(values, lodashStable.constant(['0', '1', '2'])); var actual = lodashStable.map(values, function(value) { return func(value).sort(); }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should return keys for custom properties on `arguments` objects', function(assert) { assert.expect(1); var values = [args, strictArgs], expected = lodashStable.map(values, lodashStable.constant(['0', '1', '2', 'a'])); var actual = lodashStable.map(values, function(value) { value.a = 1; var result = func(value).sort(); delete value.a; return result; }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should ' + (isKeys ? 'not ' : '') + 'include inherited string keyed properties of `arguments` objects', function(assert) { assert.expect(1); var values = [args, strictArgs], expected = lodashStable.map(values, lodashStable.constant(isKeys ? ['0', '1', '2'] : ['0', '1', '2', 'a'])); var actual = lodashStable.map(values, function(value) { objectProto.a = 1; var result = func(value).sort(); delete objectProto.a; return result; }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should work with string objects', function(assert) { assert.expect(1); var actual = func(Object('abc')).sort(); assert.deepEqual(actual, ['0', '1', '2']); }); QUnit.test('`_.' + methodName + '` should return keys for custom properties on string objects', function(assert) { assert.expect(1); var object = Object('a'); object.a = 1; var actual = func(object).sort(); assert.deepEqual(actual, ['0', 'a']); }); QUnit.test('`_.' + methodName + '` should ' + (isKeys ? 'not ' : '') + 'include inherited string keyed properties of string objects', function(assert) { assert.expect(1); stringProto.a = 1; var expected = isKeys ? ['0'] : ['0', 'a'], actual = func(Object('a')).sort(); assert.deepEqual(actual, expected); delete stringProto.a; }); QUnit.test('`_.' + methodName + '` should work with array-like objects', function(assert) { assert.expect(1); var object = { '0': 'a', 'length': 1 }, actual = func(object).sort(); assert.deepEqual(actual, ['0', 'length']); }); QUnit.test('`_.' + methodName + '` should coerce primitives to objects (test in IE 9)', function(assert) { assert.expect(2); var expected = lodashStable.map(primitives, function(value) { return typeof value == 'string' ? ['0'] : []; }); var actual = lodashStable.map(primitives, func); assert.deepEqual(actual, expected); // IE 9 doesn't box numbers in for-in loops. numberProto.a = 1; assert.deepEqual(func(0), isKeys ? [] : ['a']); delete numberProto.a; }); QUnit.test('`_.' + methodName + '` skips the `constructor` property on prototype objects', function(assert) { assert.expect(3); function Foo() {} Foo.prototype.a = 1; var expected = ['a']; assert.deepEqual(func(Foo.prototype), expected); Foo.prototype = { 'constructor': Foo, 'a': 1 }; assert.deepEqual(func(Foo.prototype), expected); var Fake = { 'prototype': {} }; Fake.prototype.constructor = Fake; assert.deepEqual(func(Fake.prototype), ['constructor']); }); QUnit.test('`_.' + methodName + '` should return an empty array when `object` is nullish', function(assert) { var values = [, null, undefined], expected = lodashStable.map(values, stubArray); var actual = lodashStable.map(values, function(value, index) { objectProto.a = 1; var result = index ? func(value) : func(); delete objectProto.a; return result; }); assert.deepEqual(actual, expected); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.last'); (function() { var array = [1, 2, 3, 4]; QUnit.test('should return the last element', function(assert) { assert.expect(1); assert.strictEqual(_.last(array), 4); }); QUnit.test('should return `undefined` when querying empty arrays', function(assert) { assert.expect(1); var array = []; array['-1'] = 1; assert.strictEqual(_.last([]), undefined); }); QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(1); var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], actual = lodashStable.map(array, _.last); assert.deepEqual(actual, [3, 6, 9]); }); QUnit.test('should return an unwrapped value when implicitly chaining', function(assert) { assert.expect(1); if (!isNpm) { assert.strictEqual(_(array).last(), 4); } else { skipAssert(assert); } }); QUnit.test('should return a wrapped value when explicitly chaining', function(assert) { assert.expect(1); if (!isNpm) { assert.ok(_(array).chain().last() instanceof _); } else { skipAssert(assert); } }); QUnit.test('should not execute immediately when explicitly chaining', function(assert) { assert.expect(1); if (!isNpm) { var wrapped = _(array).chain().last(); assert.strictEqual(wrapped.__wrapped__, array); } else { skipAssert(assert); } }); QUnit.test('should work in a lazy sequence', function(assert) { assert.expect(2); if (!isNpm) { var largeArray = lodashStable.range(LARGE_ARRAY_SIZE), smallArray = array; lodashStable.times(2, function(index) { var array = index ? largeArray : smallArray, wrapped = _(array).filter(isEven); assert.strictEqual(wrapped.last(), _.last(_.filter(array, isEven))); }); } else { skipAssert(assert, 2); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.lowerCase'); (function() { QUnit.test('should lowercase as space-separated words', function(assert) { assert.expect(3); assert.strictEqual(_.lowerCase('--Foo-Bar--'), 'foo bar'); assert.strictEqual(_.lowerCase('fooBar'), 'foo bar'); assert.strictEqual(_.lowerCase('__FOO_BAR__'), 'foo bar'); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.lowerFirst'); (function() { QUnit.test('should lowercase only the first character', function(assert) { assert.expect(3); assert.strictEqual(_.lowerFirst('fred'), 'fred'); assert.strictEqual(_.lowerFirst('Fred'), 'fred'); assert.strictEqual(_.lowerFirst('FRED'), 'fRED'); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.lt'); (function() { QUnit.test('should return `true` if `value` is less than `other`', function(assert) { assert.expect(2); assert.strictEqual(_.lt(1, 3), true); assert.strictEqual(_.lt('abc', 'def'), true); }); QUnit.test('should return `false` if `value` >= `other`', function(assert) { assert.expect(4); assert.strictEqual(_.lt(3, 1), false); assert.strictEqual(_.lt(3, 3), false); assert.strictEqual(_.lt('def', 'abc'), false); assert.strictEqual(_.lt('def', 'def'), false); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.lte'); (function() { QUnit.test('should return `true` if `value` is <= `other`', function(assert) { assert.expect(4); assert.strictEqual(_.lte(1, 3), true); assert.strictEqual(_.lte(3, 3), true); assert.strictEqual(_.lte('abc', 'def'), true); assert.strictEqual(_.lte('def', 'def'), true); }); QUnit.test('should return `false` if `value` > `other`', function(assert) { assert.expect(2); assert.strictEqual(_.lt(3, 1), false); assert.strictEqual(_.lt('def', 'abc'), false); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.findLastIndex and lodash.lastIndexOf'); lodashStable.each(['findLastIndex', 'lastIndexOf'], function(methodName) { var array = [1, 2, 3, 1, 2, 3], func = _[methodName], resolve = methodName == 'findLastIndex' ? lodashStable.curry(lodashStable.eq) : identity; QUnit.test('`_.' + methodName + '` should return the index of the last matched value', function(assert) { assert.expect(1); assert.strictEqual(func(array, resolve(3)), 5); }); QUnit.test('`_.' + methodName + '` should work with a positive `fromIndex`', function(assert) { assert.expect(1); assert.strictEqual(func(array, resolve(1), 2), 0); }); QUnit.test('`_.' + methodName + '` should work with a `fromIndex` >= `length`', function(assert) { assert.expect(1); var values = [6, 8, Math.pow(2, 32), Infinity], expected = lodashStable.map(values, lodashStable.constant([-1, 3, -1])); var actual = lodashStable.map(values, function(fromIndex) { return [ func(array, resolve(undefined), fromIndex), func(array, resolve(1), fromIndex), func(array, resolve(''), fromIndex) ]; }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should work with a negative `fromIndex`', function(assert) { assert.expect(1); assert.strictEqual(func(array, resolve(2), -3), 1); }); QUnit.test('`_.' + methodName + '` should work with a negative `fromIndex` <= `-length`', function(assert) { assert.expect(1); var values = [-6, -8, -Infinity], expected = lodashStable.map(values, stubZero); var actual = lodashStable.map(values, function(fromIndex) { return func(array, resolve(1), fromIndex); }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should treat falsey `fromIndex` values correctly', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, function(value) { return value === undefined ? 5 : -1; }); var actual = lodashStable.map(falsey, function(fromIndex) { return func(array, resolve(3), fromIndex); }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should coerce `fromIndex` to an integer', function(assert) { assert.expect(1); assert.strictEqual(func(array, resolve(2), 4.2), 4); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('indexOf methods'); lodashStable.each(['indexOf', 'lastIndexOf', 'sortedIndexOf', 'sortedLastIndexOf'], function(methodName) { var func = _[methodName], isIndexOf = !/last/i.test(methodName), isSorted = /^sorted/.test(methodName); QUnit.test('`_.' + methodName + '` should accept a falsey `array`', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, lodashStable.constant(-1)); var actual = lodashStable.map(falsey, function(array, index) { try { return index ? func(array) : func(); } catch (e) {} }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should return `-1` for an unmatched value', function(assert) { assert.expect(5); var array = [1, 2, 3], empty = []; assert.strictEqual(func(array, 4), -1); assert.strictEqual(func(array, 4, true), -1); assert.strictEqual(func(array, undefined, true), -1); assert.strictEqual(func(empty, undefined), -1); assert.strictEqual(func(empty, undefined, true), -1); }); QUnit.test('`_.' + methodName + '` should not match values on empty arrays', function(assert) { assert.expect(2); var array = []; array[-1] = 0; assert.strictEqual(func(array, undefined), -1); assert.strictEqual(func(array, 0, true), -1); }); QUnit.test('`_.' + methodName + '` should match `NaN`', function(assert) { assert.expect(3); var array = isSorted ? [1, 2, NaN, NaN] : [1, NaN, 3, NaN, 5, NaN]; if (isSorted) { assert.strictEqual(func(array, NaN, true), isIndexOf ? 2 : 3); skipAssert(assert, 2); } else { assert.strictEqual(func(array, NaN), isIndexOf ? 1 : 5); assert.strictEqual(func(array, NaN, 2), isIndexOf ? 3 : 1); assert.strictEqual(func(array, NaN, -2), isIndexOf ? 5 : 3); } }); QUnit.test('`_.' + methodName + '` should match `-0` as `0`', function(assert) { assert.expect(2); assert.strictEqual(func([-0], 0), 0); assert.strictEqual(func([0], -0), 0); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.map'); (function() { var array = [1, 2]; QUnit.test('should map values in `collection` to a new array', function(assert) { assert.expect(2); var object = { 'a': 1, 'b': 2 }, expected = ['1', '2']; assert.deepEqual(_.map(array, String), expected); assert.deepEqual(_.map(object, String), expected); }); QUnit.test('should work with `_.property` shorthands', function(assert) { assert.expect(1); var objects = [{ 'a': 'x' }, { 'a': 'y' }]; assert.deepEqual(_.map(objects, 'a'), ['x', 'y']); }); QUnit.test('should iterate over own string keyed properties of objects', function(assert) { assert.expect(1); function Foo() { this.a = 1; } Foo.prototype.b = 2; var actual = _.map(new Foo, identity); assert.deepEqual(actual, [1]); }); QUnit.test('should use `_.identity` when `iteratee` is nullish', function(assert) { assert.expect(2); var object = { 'a': 1, 'b': 2 }, values = [, null, undefined], expected = lodashStable.map(values, lodashStable.constant([1, 2])); lodashStable.each([array, object], function(collection) { var actual = lodashStable.map(values, function(value, index) { return index ? _.map(collection, value) : _.map(collection); }); assert.deepEqual(actual, expected); }); }); QUnit.test('should accept a falsey `collection`', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, stubArray); var actual = lodashStable.map(falsey, function(collection, index) { try { return index ? _.map(collection) : _.map(); } catch (e) {} }); assert.deepEqual(actual, expected); }); QUnit.test('should treat number values for `collection` as empty', function(assert) { assert.expect(1); assert.deepEqual(_.map(1), []); }); QUnit.test('should treat a nodelist as an array-like object', function(assert) { assert.expect(1); if (document) { var actual = _.map(document.getElementsByTagName('body'), function(element) { return element.nodeName.toLowerCase(); }); assert.deepEqual(actual, ['body']); } else { skipAssert(assert); } }); QUnit.test('should work with objects with non-number length properties', function(assert) { assert.expect(1); var value = { 'value': 'x' }, object = { 'length': { 'value': 'x' } }; assert.deepEqual(_.map(object, identity), [value]); }); QUnit.test('should return a wrapped value when chaining', function(assert) { assert.expect(1); if (!isNpm) { assert.ok(_(array).map(noop) instanceof _); } else { skipAssert(assert); } }); QUnit.test('should provide correct `predicate` arguments in a lazy sequence', function(assert) { assert.expect(5); if (!isNpm) { var args, array = lodashStable.range(LARGE_ARRAY_SIZE + 1), expected = [1, 0, _.map(array.slice(1), square)]; _(array).slice(1).map(function(value, index, array) { args || (args = slice.call(arguments)); }).value(); assert.deepEqual(args, [1, 0, array.slice(1)]); args = undefined; _(array).slice(1).map(square).map(function(value, index, array) { args || (args = slice.call(arguments)); }).value(); assert.deepEqual(args, expected); args = undefined; _(array).slice(1).map(square).map(function(value, index) { args || (args = slice.call(arguments)); }).value(); assert.deepEqual(args, expected); args = undefined; _(array).slice(1).map(square).map(function(value) { args || (args = slice.call(arguments)); }).value(); assert.deepEqual(args, [1]); args = undefined; _(array).slice(1).map(square).map(function() { args || (args = slice.call(arguments)); }).value(); assert.deepEqual(args, expected); } else { skipAssert(assert, 5); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.mapKeys'); (function() { var array = [1, 2], object = { 'a': 1, 'b': 2 }; QUnit.test('should map keys in `object` to a new object', function(assert) { assert.expect(1); var actual = _.mapKeys(object, String); assert.deepEqual(actual, { '1': 1, '2': 2 }); }); QUnit.test('should treat arrays like objects', function(assert) { assert.expect(1); var actual = _.mapKeys(array, String); assert.deepEqual(actual, { '1': 1, '2': 2 }); }); QUnit.test('should work with `_.property` shorthands', function(assert) { assert.expect(1); var actual = _.mapKeys({ 'a': { 'b': 'c' } }, 'b'); assert.deepEqual(actual, { 'c': { 'b': 'c' } }); }); QUnit.test('should use `_.identity` when `iteratee` is nullish', function(assert) { assert.expect(1); var object = { 'a': 1, 'b': 2 }, values = [, null, undefined], expected = lodashStable.map(values, lodashStable.constant({ '1': 1, '2': 2 })); var actual = lodashStable.map(values, function(value, index) { return index ? _.mapKeys(object, value) : _.mapKeys(object); }); assert.deepEqual(actual, expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.mapValues'); (function() { var array = [1, 2], object = { 'a': 1, 'b': 2 }; QUnit.test('should map values in `object` to a new object', function(assert) { assert.expect(1); var actual = _.mapValues(object, String); assert.deepEqual(actual, { 'a': '1', 'b': '2' }); }); QUnit.test('should treat arrays like objects', function(assert) { assert.expect(1); var actual = _.mapValues(array, String); assert.deepEqual(actual, { '0': '1', '1': '2' }); }); QUnit.test('should work with `_.property` shorthands', function(assert) { assert.expect(1); var actual = _.mapValues({ 'a': { 'b': 2 } }, 'b'); assert.deepEqual(actual, { 'a': 2 }); }); QUnit.test('should use `_.identity` when `iteratee` is nullish', function(assert) { assert.expect(1); var object = { 'a': 1, 'b': 2 }, values = [, null, undefined], expected = lodashStable.map(values, lodashStable.constant([true, false])); var actual = lodashStable.map(values, function(value, index) { var result = index ? _.mapValues(object, value) : _.mapValues(object); return [lodashStable.isEqual(result, object), result === object]; }); assert.deepEqual(actual, expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.mapKeys and lodash.mapValues'); lodashStable.each(['mapKeys', 'mapValues'], function(methodName) { var func = _[methodName], object = { 'a': 1, 'b': 2 }; QUnit.test('`_.' + methodName + '` should iterate over own string keyed properties of objects', function(assert) { assert.expect(1); function Foo() { this.a = 'a'; } Foo.prototype.b = 'b'; var actual = func(new Foo, function(value, key) { return key; }); assert.deepEqual(actual, { 'a': 'a' }); }); QUnit.test('`_.' + methodName + '` should accept a falsey `object`', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, stubObject); var actual = lodashStable.map(falsey, function(object, index) { try { return index ? func(object) : func(); } catch (e) {} }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should return a wrapped value when chaining', function(assert) { assert.expect(1); if (!isNpm) { assert.ok(_(object)[methodName](noop) instanceof _); } else { skipAssert(assert); } }); }); QUnit.module('lodash.matches'); (function() { QUnit.test('should not change behavior if `source` is modified', function(assert) { assert.expect(9); var sources = [ { 'a': { 'b': 2, 'c': 3 } }, { 'a': 1, 'b': 2 }, { 'a': 1 } ]; lodashStable.each(sources, function(source, index) { var object = lodashStable.cloneDeep(source), par = _.matches(source); assert.strictEqual(par(object), true); if (index) { source.a = 2; source.b = 1; source.c = 3; } else { source.a.b = 1; source.a.c = 2; source.a.d = 3; } assert.strictEqual(par(object), true); assert.strictEqual(par(source), false); }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('matches methods'); lodashStable.each(['matches', 'isMatch'], function(methodName) { var isMatches = methodName == 'matches'; function matches(source) { return isMatches ? _.matches(source) : function(object) { return _.isMatch(object, source); }; } QUnit.test('`_.' + methodName + '` should perform a deep comparison between `source` and `object`', function(assert) { assert.expect(5); var object = { 'a': 1, 'b': 2, 'c': 3 }, par = matches({ 'a': 1 }); assert.strictEqual(par(object), true); par = matches({ 'b': 1 }); assert.strictEqual(par(object), false); par = matches({ 'a': 1, 'c': 3 }); assert.strictEqual(par(object), true); par = matches({ 'c': 3, 'd': 4 }); assert.strictEqual(par(object), false); object = { 'a': { 'b': { 'c': 1, 'd': 2 }, 'e': 3 }, 'f': 4 }; par = matches({ 'a': { 'b': { 'c': 1 } } }); assert.strictEqual(par(object), true); }); QUnit.test('`_.' + methodName + '` should match inherited string keyed `object` properties', function(assert) { assert.expect(1); function Foo() { this.a = 1; } Foo.prototype.b = 2; var object = { 'a': new Foo }, par = matches({ 'a': { 'b': 2 } }); assert.strictEqual(par(object), true); }); QUnit.test('`_.' + methodName + '` should not match by inherited `source` properties', function(assert) { assert.expect(1); function Foo() { this.a = 1; } Foo.prototype.b = 2; var objects = [{ 'a': 1 }, { 'a': 1, 'b': 2 }], source = new Foo, actual = lodashStable.map(objects, matches(source)), expected = lodashStable.map(objects, stubTrue); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should compare a variety of `source` property values', function(assert) { assert.expect(2); var object1 = { 'a': false, 'b': true, 'c': '3', 'd': 4, 'e': [5], 'f': { 'g': 6 } }, object2 = { 'a': 0, 'b': 1, 'c': 3, 'd': '4', 'e': ['5'], 'f': { 'g': '6' } }, par = matches(object1); assert.strictEqual(par(object1), true); assert.strictEqual(par(object2), false); }); QUnit.test('`_.' + methodName + '` should match `-0` as `0`', function(assert) { assert.expect(2); var object1 = { 'a': -0 }, object2 = { 'a': 0 }, par = matches(object1); assert.strictEqual(par(object2), true); par = matches(object2); assert.strictEqual(par(object1), true); }); QUnit.test('`_.' + methodName + '` should compare functions by reference', function(assert) { assert.expect(3); var object1 = { 'a': lodashStable.noop }, object2 = { 'a': noop }, object3 = { 'a': {} }, par = matches(object1); assert.strictEqual(par(object1), true); assert.strictEqual(par(object2), false); assert.strictEqual(par(object3), false); }); QUnit.test('`_.' + methodName + '` should work with a function for `object`', function(assert) { assert.expect(1); function Foo() {} Foo.a = { 'b': 2, 'c': 3 }; var par = matches({ 'a': { 'b': 2 } }); assert.strictEqual(par(Foo), true); }); QUnit.test('`_.' + methodName + '` should work with a function for `source`', function(assert) { assert.expect(1); function Foo() {} Foo.a = 1; Foo.b = function() {}; Foo.c = 3; var objects = [{ 'a': 1 }, { 'a': 1, 'b': Foo.b, 'c': 3 }], actual = lodashStable.map(objects, matches(Foo)); assert.deepEqual(actual, [false, true]); }); QUnit.test('`_.' + methodName + '` should work with a non-plain `object`', function(assert) { assert.expect(1); function Foo(object) { lodashStable.assign(this, object); } var object = new Foo({ 'a': new Foo({ 'b': 2, 'c': 3 }) }), par = matches({ 'a': { 'b': 2 } }); assert.strictEqual(par(object), true); }); QUnit.test('`_.' + methodName + '` should partial match arrays', function(assert) { assert.expect(3); var objects = [{ 'a': ['b'] }, { 'a': ['c', 'd'] }], actual = lodashStable.filter(objects, matches({ 'a': ['d'] })); assert.deepEqual(actual, [objects[1]]); actual = lodashStable.filter(objects, matches({ 'a': ['b', 'd'] })); assert.deepEqual(actual, []); actual = lodashStable.filter(objects, matches({ 'a': ['d', 'b'] })); assert.deepEqual(actual, []); }); QUnit.test('`_.' + methodName + '` should partial match arrays with duplicate values', function(assert) { assert.expect(1); var objects = [{ 'a': [1, 2] }, { 'a': [2, 2] }], actual = lodashStable.filter(objects, matches({ 'a': [2, 2] })); assert.deepEqual(actual, [objects[1]]); }); QUnit.test('should partial match arrays of objects', function(assert) { assert.expect(1); var objects = [ { 'a': [{ 'b': 1, 'c': 2 }, { 'b': 4, 'c': 5, 'd': 6 }] }, { 'a': [{ 'b': 1, 'c': 2 }, { 'b': 4, 'c': 6, 'd': 7 }] } ]; var actual = lodashStable.filter(objects, matches({ 'a': [{ 'b': 1 }, { 'b': 4, 'c': 5 }] })); assert.deepEqual(actual, [objects[0]]); }); QUnit.test('`_.' + methodName + '` should partial match maps', function(assert) { assert.expect(3); if (Map) { var objects = [{ 'a': new Map }, { 'a': new Map }]; objects[0].a.set('a', 1); objects[1].a.set('a', 1); objects[1].a.set('b', 2); var map = new Map; map.set('b', 2); var actual = lodashStable.filter(objects, matches({ 'a': map })); assert.deepEqual(actual, [objects[1]]); map.delete('b'); actual = lodashStable.filter(objects, matches({ 'a': map })); assert.deepEqual(actual, objects); map.set('c', 3); actual = lodashStable.filter(objects, matches({ 'a': map })); assert.deepEqual(actual, []); } else { skipAssert(assert, 3); } }); QUnit.test('`_.' + methodName + '` should partial match sets', function(assert) { assert.expect(3); if (Set) { var objects = [{ 'a': new Set }, { 'a': new Set }]; objects[0].a.add(1); objects[1].a.add(1); objects[1].a.add(2); var set = new Set; set.add(2); var actual = lodashStable.filter(objects, matches({ 'a': set })); assert.deepEqual(actual, [objects[1]]); set.delete(2); actual = lodashStable.filter(objects, matches({ 'a': set })); assert.deepEqual(actual, objects); set.add(3); actual = lodashStable.filter(objects, matches({ 'a': set })); assert.deepEqual(actual, []); } else { skipAssert(assert, 3); } }); QUnit.test('`_.' + methodName + '` should match `undefined` values', function(assert) { assert.expect(3); var objects = [{ 'a': 1 }, { 'a': 1, 'b': 1 }, { 'a': 1, 'b': undefined }], actual = lodashStable.map(objects, matches({ 'b': undefined })), expected = [false, false, true]; assert.deepEqual(actual, expected); actual = lodashStable.map(objects, matches({ 'a': 1, 'b': undefined })); assert.deepEqual(actual, expected); objects = [{ 'a': { 'b': 2 } }, { 'a': { 'b': 2, 'c': 3 } }, { 'a': { 'b': 2, 'c': undefined } }]; actual = lodashStable.map(objects, matches({ 'a': { 'c': undefined } })); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should match `undefined` values on primitives', function(assert) { assert.expect(3); numberProto.a = 1; numberProto.b = undefined; try { var par = matches({ 'b': undefined }); assert.strictEqual(par(1), true); } catch (e) { assert.ok(false, e.message); } try { par = matches({ 'a': 1, 'b': undefined }); assert.strictEqual(par(1), true); } catch (e) { assert.ok(false, e.message); } numberProto.a = { 'b': 1, 'c': undefined }; try { par = matches({ 'a': { 'c': undefined } }); assert.strictEqual(par(1), true); } catch (e) { assert.ok(false, e.message); } delete numberProto.a; delete numberProto.b; }); QUnit.test('`_.' + methodName + '` should return `false` when `object` is nullish', function(assert) { assert.expect(1); var values = [, null, undefined], expected = lodashStable.map(values, stubFalse), par = matches({ 'a': 1 }); var actual = lodashStable.map(values, function(value, index) { try { return index ? par(value) : par(); } catch (e) {} }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should return `true` when comparing an empty `source`', function(assert) { assert.expect(1); var object = { 'a': 1 }, expected = lodashStable.map(empties, stubTrue); var actual = lodashStable.map(empties, function(value) { var par = matches(value); return par(object); }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should return `true` when comparing an empty `source` to a nullish `object`', function(assert) { assert.expect(1); var values = [, null, undefined], expected = lodashStable.map(values, stubTrue), par = matches({}); var actual = lodashStable.map(values, function(value, index) { try { return index ? par(value) : par(); } catch (e) {} }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should return `true` when comparing a `source` of empty arrays and objects', function(assert) { assert.expect(1); var objects = [{ 'a': [1], 'b': { 'c': 1 } }, { 'a': [2, 3], 'b': { 'd': 2 } }], actual = lodashStable.filter(objects, matches({ 'a': [], 'b': {} })); assert.deepEqual(actual, objects); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.matchesProperty'); (function() { QUnit.test('should create a function that performs a deep comparison between a property value and `srcValue`', function(assert) { assert.expect(6); var object = { 'a': 1, 'b': 2, 'c': 3 }, matches = _.matchesProperty('a', 1); assert.strictEqual(matches.length, 1); assert.strictEqual(matches(object), true); matches = _.matchesProperty('b', 3); assert.strictEqual(matches(object), false); matches = _.matchesProperty('a', { 'a': 1, 'c': 3 }); assert.strictEqual(matches({ 'a': object }), true); matches = _.matchesProperty('a', { 'c': 3, 'd': 4 }); assert.strictEqual(matches(object), false); object = { 'a': { 'b': { 'c': 1, 'd': 2 }, 'e': 3 }, 'f': 4 }; matches = _.matchesProperty('a', { 'b': { 'c': 1 } }); assert.strictEqual(matches(object), true); }); QUnit.test('should support deep paths', function(assert) { assert.expect(2); var object = { 'a': { 'b': 2 } }; lodashStable.each(['a.b', ['a', 'b']], function(path) { var matches = _.matchesProperty(path, 2); assert.strictEqual(matches(object), true); }); }); QUnit.test('should work with a non-string `path`', function(assert) { assert.expect(2); var array = [1, 2, 3]; lodashStable.each([1, [1]], function(path) { var matches = _.matchesProperty(path, 2); assert.strictEqual(matches(array), true); }); }); QUnit.test('should preserve the sign of `0`', function(assert) { assert.expect(1); var object1 = { '-0': 'a' }, object2 = { '0': 'b' }, pairs = [[object1, object2], [object1, object2], [object2, object1], [object2, object1]], props = [-0, Object(-0), 0, Object(0)], values = ['a', 'a', 'b', 'b'], expected = lodashStable.map(props, lodashStable.constant([true, false])); var actual = lodashStable.map(props, function(key, index) { var matches = _.matchesProperty(key, values[index]), pair = pairs[index]; return [matches(pair[0]), matches(pair[1])]; }); assert.deepEqual(actual, expected); }); QUnit.test('should coerce `path` to a string', function(assert) { assert.expect(2); function fn() {} fn.toString = lodashStable.constant('fn'); var object = { 'null': 1, 'undefined': 2, 'fn': 3, '[object Object]': 4 }, paths = [null, undefined, fn, {}], expected = lodashStable.map(paths, stubTrue); lodashStable.times(2, function(index) { var actual = lodashStable.map(paths, function(path) { var matches = _.matchesProperty(index ? [path] : path, object[path]); return matches(object); }); assert.deepEqual(actual, expected); }); }); QUnit.test('should match a key over a path', function(assert) { assert.expect(2); var object = { 'a.b': 1, 'a': { 'b': 2 } }; lodashStable.each(['a.b', ['a.b']], function(path) { var matches = _.matchesProperty(path, 1); assert.strictEqual(matches(object), true); }); }); QUnit.test('should return `false` when `object` is nullish', function(assert) { assert.expect(2); var values = [, null, undefined], expected = lodashStable.map(values, stubFalse); lodashStable.each(['constructor', ['constructor']], function(path) { var matches = _.matchesProperty(path, 1); var actual = lodashStable.map(values, function(value, index) { try { return index ? matches(value) : matches(); } catch (e) {} }); assert.deepEqual(actual, expected); }); }); QUnit.test('should return `false` for deep paths when `object` is nullish', function(assert) { assert.expect(2); var values = [, null, undefined], expected = lodashStable.map(values, stubFalse); lodashStable.each(['constructor.prototype.valueOf', ['constructor', 'prototype', 'valueOf']], function(path) { var matches = _.matchesProperty(path, 1); var actual = lodashStable.map(values, function(value, index) { try { return index ? matches(value) : matches(); } catch (e) {} }); assert.deepEqual(actual, expected); }); }); QUnit.test('should return `false` if parts of `path` are missing', function(assert) { assert.expect(4); var object = {}; lodashStable.each(['a', 'a[1].b.c', ['a'], ['a', '1', 'b', 'c']], function(path) { var matches = _.matchesProperty(path, 1); assert.strictEqual(matches(object), false); }); }); QUnit.test('should match inherited string keyed `srcValue` properties', function(assert) { assert.expect(2); function Foo() {} Foo.prototype.b = 2; var object = { 'a': new Foo }; lodashStable.each(['a', ['a']], function(path) { var matches = _.matchesProperty(path, { 'b': 2 }); assert.strictEqual(matches(object), true); }); }); QUnit.test('should not match by inherited `srcValue` properties', function(assert) { assert.expect(2); function Foo() { this.a = 1; } Foo.prototype.b = 2; var objects = [{ 'a': { 'a': 1 } }, { 'a': { 'a': 1, 'b': 2 } }], expected = lodashStable.map(objects, stubTrue); lodashStable.each(['a', ['a']], function(path) { assert.deepEqual(lodashStable.map(objects, _.matchesProperty(path, new Foo)), expected); }); }); QUnit.test('should compare a variety of values', function(assert) { assert.expect(2); var object1 = { 'a': false, 'b': true, 'c': '3', 'd': 4, 'e': [5], 'f': { 'g': 6 } }, object2 = { 'a': 0, 'b': 1, 'c': 3, 'd': '4', 'e': ['5'], 'f': { 'g': '6' } }, matches = _.matchesProperty('a', object1); assert.strictEqual(matches({ 'a': object1 }), true); assert.strictEqual(matches({ 'a': object2 }), false); }); QUnit.test('should match `-0` as `0`', function(assert) { assert.expect(2); var matches = _.matchesProperty('a', -0); assert.strictEqual(matches({ 'a': 0 }), true); matches = _.matchesProperty('a', 0); assert.strictEqual(matches({ 'a': -0 }), true); }); QUnit.test('should compare functions by reference', function(assert) { assert.expect(3); var object1 = { 'a': lodashStable.noop }, object2 = { 'a': noop }, object3 = { 'a': {} }, matches = _.matchesProperty('a', object1); assert.strictEqual(matches({ 'a': object1 }), true); assert.strictEqual(matches({ 'a': object2 }), false); assert.strictEqual(matches({ 'a': object3 }), false); }); QUnit.test('should work with a function for `srcValue`', function(assert) { assert.expect(1); function Foo() {} Foo.a = 1; Foo.b = function() {}; Foo.c = 3; var objects = [{ 'a': { 'a': 1 } }, { 'a': { 'a': 1, 'b': Foo.b, 'c': 3 } }], actual = lodashStable.map(objects, _.matchesProperty('a', Foo)); assert.deepEqual(actual, [false, true]); }); QUnit.test('should work with a non-plain `srcValue`', function(assert) { assert.expect(1); function Foo(object) { lodashStable.assign(this, object); } var object = new Foo({ 'a': new Foo({ 'b': 1, 'c': 2 }) }), matches = _.matchesProperty('a', { 'b': 1 }); assert.strictEqual(matches(object), true); }); QUnit.test('should partial match arrays', function(assert) { assert.expect(3); var objects = [{ 'a': ['b'] }, { 'a': ['c', 'd'] }], actual = lodashStable.filter(objects, _.matchesProperty('a', ['d'])); assert.deepEqual(actual, [objects[1]]); actual = lodashStable.filter(objects, _.matchesProperty('a', ['b', 'd'])); assert.deepEqual(actual, []); actual = lodashStable.filter(objects, _.matchesProperty('a', ['d', 'b'])); assert.deepEqual(actual, []); }); QUnit.test('should partial match arrays with duplicate values', function(assert) { assert.expect(1); var objects = [{ 'a': [1, 2] }, { 'a': [2, 2] }], actual = lodashStable.filter(objects, _.matchesProperty('a', [2, 2])); assert.deepEqual(actual, [objects[1]]); }); QUnit.test('should partial match arrays of objects', function(assert) { assert.expect(1); var objects = [ { 'a': [{ 'a': 1, 'b': 2 }, { 'a': 4, 'b': 5, 'c': 6 }] }, { 'a': [{ 'a': 1, 'b': 2 }, { 'a': 4, 'b': 6, 'c': 7 }] } ]; var actual = lodashStable.filter(objects, _.matchesProperty('a', [{ 'a': 1 }, { 'a': 4, 'b': 5 }])); assert.deepEqual(actual, [objects[0]]); }); QUnit.test('should partial match maps', function(assert) { assert.expect(3); if (Map) { var objects = [{ 'a': new Map }, { 'a': new Map }]; objects[0].a.set('a', 1); objects[1].a.set('a', 1); objects[1].a.set('b', 2); var map = new Map; map.set('b', 2); var actual = lodashStable.filter(objects, _.matchesProperty('a', map)); assert.deepEqual(actual, [objects[1]]); map.delete('b'); actual = lodashStable.filter(objects, _.matchesProperty('a', map)); assert.deepEqual(actual, objects); map.set('c', 3); actual = lodashStable.filter(objects, _.matchesProperty('a', map)); assert.deepEqual(actual, []); } else { skipAssert(assert, 3); } }); QUnit.test('should partial match sets', function(assert) { assert.expect(3); if (Set) { var objects = [{ 'a': new Set }, { 'a': new Set }]; objects[0].a.add(1); objects[1].a.add(1); objects[1].a.add(2); var set = new Set; set.add(2); var actual = lodashStable.filter(objects, _.matchesProperty('a', set)); assert.deepEqual(actual, [objects[1]]); set.delete(2); actual = lodashStable.filter(objects, _.matchesProperty('a', set)); assert.deepEqual(actual, objects); set.add(3); actual = lodashStable.filter(objects, _.matchesProperty('a', set)); assert.deepEqual(actual, []); } else { skipAssert(assert, 3); } }); QUnit.test('should match `undefined` values', function(assert) { assert.expect(2); var objects = [{ 'a': 1 }, { 'a': 1, 'b': 1 }, { 'a': 1, 'b': undefined }], actual = lodashStable.map(objects, _.matchesProperty('b', undefined)), expected = [false, false, true]; assert.deepEqual(actual, expected); objects = [{ 'a': { 'a': 1 } }, { 'a': { 'a': 1, 'b': 1 } }, { 'a': { 'a': 1, 'b': undefined } }]; actual = lodashStable.map(objects, _.matchesProperty('a', { 'b': undefined })); assert.deepEqual(actual, expected); }); QUnit.test('should match `undefined` values of nested objects', function(assert) { assert.expect(4); var object = { 'a': { 'b': undefined } }; lodashStable.each(['a.b', ['a', 'b']], function(path) { var matches = _.matchesProperty(path, undefined); assert.strictEqual(matches(object), true); }); lodashStable.each(['a.a', ['a', 'a']], function(path) { var matches = _.matchesProperty(path, undefined); assert.strictEqual(matches(object), false); }); }); QUnit.test('should match `undefined` values on primitives', function(assert) { assert.expect(2); numberProto.a = 1; numberProto.b = undefined; try { var matches = _.matchesProperty('b', undefined); assert.strictEqual(matches(1), true); } catch (e) { assert.ok(false, e.message); } numberProto.a = { 'b': 1, 'c': undefined }; try { matches = _.matchesProperty('a', { 'c': undefined }); assert.strictEqual(matches(1), true); } catch (e) { assert.ok(false, e.message); } delete numberProto.a; delete numberProto.b; }); QUnit.test('should return `true` when comparing a `srcValue` of empty arrays and objects', function(assert) { assert.expect(1); var objects = [{ 'a': [1], 'b': { 'c': 1 } }, { 'a': [2, 3], 'b': { 'd': 2 } }], matches = _.matchesProperty('a', { 'a': [], 'b': {} }); var actual = lodashStable.filter(objects, function(object) { return matches({ 'a': object }); }); assert.deepEqual(actual, objects); }); QUnit.test('should not change behavior if `srcValue` is modified', function(assert) { assert.expect(9); lodashStable.each([{ 'a': { 'b': 2, 'c': 3 } }, { 'a': 1, 'b': 2 }, { 'a': 1 }], function(source, index) { var object = lodashStable.cloneDeep(source), matches = _.matchesProperty('a', source); assert.strictEqual(matches({ 'a': object }), true); if (index) { source.a = 2; source.b = 1; source.c = 3; } else { source.a.b = 1; source.a.c = 2; source.a.d = 3; } assert.strictEqual(matches({ 'a': object }), true); assert.strictEqual(matches({ 'a': source }), false); }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.max'); (function() { QUnit.test('should return the largest value from a collection', function(assert) { assert.expect(1); assert.strictEqual(_.max([1, 2, 3]), 3); }); QUnit.test('should return `undefined` for empty collections', function(assert) { assert.expect(1); var values = falsey.concat([[]]), expected = lodashStable.map(values, noop); var actual = lodashStable.map(values, function(value, index) { try { return index ? _.max(value) : _.max(); } catch (e) {} }); assert.deepEqual(actual, expected); }); QUnit.test('should work with non-numeric collection values', function(assert) { assert.expect(1); assert.strictEqual(_.max(['a', 'b']), 'b'); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.mean'); (function() { QUnit.test('should return the mean of an array of numbers', function(assert) { assert.expect(1); var array = [4, 2, 8, 6]; assert.strictEqual(_.mean(array), 5); }); QUnit.test('should return `NaN` when passing empty `array` values', function(assert) { assert.expect(1); var expected = lodashStable.map(empties, stubNaN), actual = lodashStable.map(empties, _.mean); assert.deepEqual(actual, expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.meanBy'); (function() { var objects = [{ 'a': 2 }, { 'a': 3 }, { 'a': 1 }]; QUnit.test('should work with an `iteratee`', function(assert) { assert.expect(1); var actual = _.meanBy(objects, function(object) { return object.a; }); assert.deepEqual(actual, 2); }); QUnit.test('should provide correct `iteratee` arguments', function(assert) { assert.expect(1); var args; _.meanBy(objects, function() { args || (args = slice.call(arguments)); }); assert.deepEqual(args, [{ 'a': 2 }]); }); QUnit.test('should work with `_.property` shorthands', function(assert) { assert.expect(2); var arrays = [[2], [3], [1]]; assert.strictEqual(_.meanBy(arrays, 0), 2); assert.strictEqual(_.meanBy(objects, 'a'), 2); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.memoize'); (function() { function CustomCache() { this.clear(); } CustomCache.prototype = { 'clear': function() { this.__data__ = []; return this; }, 'get': function(key) { var entry = lodashStable.find(this.__data__, ['key', key]); return entry && entry.value; }, 'has': function(key) { return lodashStable.some(this.__data__, ['key', key]); }, 'set': function(key, value) { this.__data__.push({ 'key': key, 'value': value }); return this; } }; function ImmutableCache() { this.__data__ = []; } ImmutableCache.prototype = lodashStable.create(CustomCache.prototype, { 'constructor': ImmutableCache, 'clear': function() { return new ImmutableCache; }, 'set': function(key, value) { var result = new ImmutableCache; result.__data__ = this.__data__.concat({ 'key': key, 'value': value }); return result; } }); QUnit.test('should memoize results based on the first argument given', function(assert) { assert.expect(2); var memoized = _.memoize(function(a, b, c) { return a + b + c; }); assert.strictEqual(memoized(1, 2, 3), 6); assert.strictEqual(memoized(1, 3, 5), 6); }); QUnit.test('should support a `resolver`', function(assert) { assert.expect(2); var fn = function(a, b, c) { return a + b + c; }, memoized = _.memoize(fn, fn); assert.strictEqual(memoized(1, 2, 3), 6); assert.strictEqual(memoized(1, 3, 5), 9); }); QUnit.test('should use `this` binding of function for `resolver`', function(assert) { assert.expect(2); var fn = function(a, b, c) { return a + this.b + this.c; }, memoized = _.memoize(fn, fn); var object = { 'memoized': memoized, 'b': 2, 'c': 3 }; assert.strictEqual(object.memoized(1), 6); object.b = 3; object.c = 5; assert.strictEqual(object.memoized(1), 9); }); QUnit.test('should throw a TypeError if `resolve` is truthy and not a function', function(assert) { assert.expect(1); assert.raises(function() { _.memoize(noop, true); }, TypeError); }); QUnit.test('should not error if `resolver` is nullish', function(assert) { assert.expect(1); var values = [, null, undefined], expected = lodashStable.map(values, stubTrue); var actual = lodashStable.map(values, function(resolver, index) { try { return _.isFunction(index ? _.memoize(noop, resolver) : _.memoize(noop)); } catch (e) {} }); assert.deepEqual(actual, expected); }); QUnit.test('should check cache for own properties', function(assert) { assert.expect(1); var props = [ 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf' ]; var memoized = _.memoize(identity); var actual = lodashStable.map(props, function(value) { return memoized(value); }); assert.deepEqual(actual, props); }); QUnit.test('should cache the `__proto__` key', function(assert) { assert.expect(8); var array = [], key = '__proto__'; lodashStable.times(2, function(index) { var count = 0, resolver = index ? identity : undefined; var memoized = _.memoize(function() { count++; return array; }, resolver); var cache = memoized.cache; memoized(key); memoized(key); assert.strictEqual(count, 1); assert.strictEqual(cache.get(key), array); assert.notOk(cache.__data__ instanceof Array); assert.strictEqual(cache.delete(key), true); }); }); QUnit.test('should allow `_.memoize.Cache` to be customized', function(assert) { assert.expect(4); var oldCache = _.memoize.Cache; _.memoize.Cache = CustomCache; var memoized = _.memoize(function(object) { return object.id; }); var cache = memoized.cache, key1 = { 'id': 'a' }, key2 = { 'id': 'b' }; assert.strictEqual(memoized(key1), 'a'); assert.strictEqual(cache.has(key1), true); assert.strictEqual(memoized(key2), 'b'); assert.strictEqual(cache.has(key2), true); _.memoize.Cache = oldCache; }); QUnit.test('should works with an immutable `_.memoize.Cache` ', function(assert) { assert.expect(2); var oldCache = _.memoize.Cache; _.memoize.Cache = ImmutableCache; var memoized = _.memoize(function(object) { return object.id; }); var key1 = { 'id': 'a' }, key2 = { 'id': 'b' }; memoized(key1); memoized(key2); var cache = memoized.cache; assert.strictEqual(cache.has(key1), true); assert.strictEqual(cache.has(key2), true); _.memoize.Cache = oldCache; }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('memoizeCapped'); (function() { var func = _._memoizeCapped; QUnit.test('should enforce a max cache size of `MAX_MEMOIZE_SIZE`', function(assert) { assert.expect(2); if (func) { var memoized = func(identity), cache = memoized.cache; lodashStable.times(MAX_MEMOIZE_SIZE, memoized); assert.strictEqual(cache.size, MAX_MEMOIZE_SIZE); memoized(MAX_MEMOIZE_SIZE); assert.strictEqual(cache.size, 1); } else { skipAssert(assert, 2); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.merge'); (function() { QUnit.test('should merge `source` into `object`', function(assert) { assert.expect(1); var names = { 'characters': [ { 'name': 'barney' }, { 'name': 'fred' } ] }; var ages = { 'characters': [ { 'age': 36 }, { 'age': 40 } ] }; var heights = { 'characters': [ { 'height': '5\'4"' }, { 'height': '5\'5"' } ] }; var expected = { 'characters': [ { 'name': 'barney', 'age': 36, 'height': '5\'4"' }, { 'name': 'fred', 'age': 40, 'height': '5\'5"' } ] }; assert.deepEqual(_.merge(names, ages, heights), expected); }); QUnit.test('should merge sources containing circular references', function(assert) { assert.expect(2); var object = { 'foo': { 'a': 1 }, 'bar': { 'a': 2 } }; var source = { 'foo': { 'b': { 'c': { 'd': {} } } }, 'bar': {} }; source.foo.b.c.d = source; source.bar.b = source.foo.b; var actual = _.merge(object, source); assert.notStrictEqual(actual.bar.b, actual.foo.b); assert.strictEqual(actual.foo.b.c.d, actual.foo.b.c.d.foo.b.c.d); }); QUnit.test('should work with four arguments', function(assert) { assert.expect(1); var expected = { 'a': 4 }, actual = _.merge({ 'a': 1 }, { 'a': 2 }, { 'a': 3 }, expected); assert.deepEqual(actual, expected); }); QUnit.test('should merge onto function `object` values', function(assert) { assert.expect(2); function Foo() {} var source = { 'a': 1 }, actual = _.merge(Foo, source); assert.strictEqual(actual, Foo); assert.strictEqual(Foo.a, 1); }); QUnit.test('should merge first source object properties to function', function(assert) { assert.expect(1); var fn = function() {}, object = { 'prop': {} }, actual = _.merge({ 'prop': fn }, object); assert.deepEqual(actual, object); }); QUnit.test('should merge first and second source object properties to function', function(assert) { assert.expect(1); var fn = function() {}, object = { 'prop': {} }, actual = _.merge({ 'prop': fn }, { 'prop': fn }, object); assert.deepEqual(actual, object); }); QUnit.test('should not merge onto function values of sources', function(assert) { assert.expect(3); var source1 = { 'a': function() {} }, source2 = { 'a': { 'b': 2 } }, expected = { 'a': { 'b': 2 } }, actual = _.merge({}, source1, source2); assert.deepEqual(actual, expected); assert.notOk('b' in source1.a); actual = _.merge(source1, source2); assert.deepEqual(actual, expected); }); QUnit.test('should merge onto non-plain `object` values', function(assert) { assert.expect(2); function Foo() {} var object = new Foo, actual = _.merge(object, { 'a': 1 }); assert.strictEqual(actual, object); assert.strictEqual(object.a, 1); }); QUnit.test('should treat sparse array sources as dense', function(assert) { assert.expect(2); var array = [1]; array[2] = 3; var actual = _.merge([], array), expected = array.slice(); expected[1] = undefined; assert.ok('1' in actual); assert.deepEqual(actual, expected); }); QUnit.test('should merge `arguments` objects', function(assert) { assert.expect(7); var object1 = { 'value': args }, object2 = { 'value': { '3': 4 } }, expected = { '0': 1, '1': 2, '2': 3, '3': 4 }, actual = _.merge(object1, object2); assert.notOk('3' in args); assert.notOk(_.isArguments(actual.value)); assert.deepEqual(actual.value, expected); object1.value = args; actual = _.merge(object2, object1); assert.notOk(_.isArguments(actual.value)); assert.deepEqual(actual.value, expected); expected = { '0': 1, '1': 2, '2': 3 }; actual = _.merge({}, object1); assert.notOk(_.isArguments(actual.value)); assert.deepEqual(actual.value, expected); }); QUnit.test('should merge typed arrays', function(assert) { assert.expect(4); var array1 = [0], array2 = [0, 0], array3 = [0, 0, 0, 0], array4 = [0, 0, 0, 0, 0, 0, 0, 0]; var arrays = [array2, array1, array4, array3, array2, array4, array4, array3, array2], buffer = ArrayBuffer && new ArrayBuffer(8); var expected = lodashStable.map(typedArrays, function(type, index) { var array = arrays[index].slice(); array[0] = 1; return root[type] ? { 'value': array } : false; }); var actual = lodashStable.map(typedArrays, function(type) { var Ctor = root[type]; return Ctor ? _.merge({ 'value': new Ctor(buffer) }, { 'value': [1] }) : false; }); assert.ok(lodashStable.isArray(actual)); assert.deepEqual(actual, expected); expected = lodashStable.map(typedArrays, function(type, index) { var array = arrays[index].slice(); array.push(1); return root[type] ? { 'value': array } : false; }); actual = lodashStable.map(typedArrays, function(type, index) { var Ctor = root[type], array = lodashStable.range(arrays[index].length); array.push(1); return Ctor ? _.merge({ 'value': array }, { 'value': new Ctor(buffer) }) : false; }); assert.ok(lodashStable.isArray(actual)); assert.deepEqual(actual, expected); }); QUnit.test('should assign `null` values', function(assert) { assert.expect(1); var actual = _.merge({ 'a': 1 }, { 'a': null }); assert.strictEqual(actual.a, null); }); QUnit.test('should assign non array/buffer/typed-array/plain-object source values directly', function(assert) { assert.expect(1); function Foo() {} var values = [new Foo, new Boolean, new Date, Foo, new Number, new String, new RegExp], expected = lodashStable.map(values, stubTrue); var actual = lodashStable.map(values, function(value) { var object = _.merge({}, { 'a': value, 'b': { 'c': value } }); return object.a === value && object.b.c === value; }); assert.deepEqual(actual, expected); }); QUnit.test('should clone buffer source values', function(assert) { assert.expect(3); if (Buffer) { var buffer = new Buffer([1]), actual = _.merge({}, { 'value': buffer }).value; assert.ok(lodashStable.isBuffer(actual)); assert.strictEqual(actual[0], buffer[0]); assert.notStrictEqual(actual, buffer); } else { skipAssert(assert, 3); } }); QUnit.test('should deep clone array/typed-array/plain-object source values', function(assert) { assert.expect(1); var typedArray = Uint8Array ? new Uint8Array([1]) : { 'buffer': [1] }; var props = ['0', 'buffer', 'a'], values = [[{ 'a': 1 }], typedArray, { 'a': [1] }], expected = lodashStable.map(values, stubTrue); var actual = lodashStable.map(values, function(value, index) { var key = props[index], object = _.merge({}, { 'value': value }), subValue = value[key], newValue = object.value, newSubValue = newValue[key]; return ( newValue !== value && newSubValue !== subValue && lodashStable.isEqual(newValue, value) ); }); assert.deepEqual(actual, expected); }); QUnit.test('should not augment source objects', function(assert) { assert.expect(6); var source1 = { 'a': [{ 'a': 1 }] }, source2 = { 'a': [{ 'b': 2 }] }, actual = _.merge({}, source1, source2); assert.deepEqual(source1.a, [{ 'a': 1 }]); assert.deepEqual(source2.a, [{ 'b': 2 }]); assert.deepEqual(actual.a, [{ 'a': 1, 'b': 2 }]); var source1 = { 'a': [[1, 2, 3]] }, source2 = { 'a': [[3, 4]] }, actual = _.merge({}, source1, source2); assert.deepEqual(source1.a, [[1, 2, 3]]); assert.deepEqual(source2.a, [[3, 4]]); assert.deepEqual(actual.a, [[3, 4, 3]]); }); QUnit.test('should merge plain objects onto non-plain objects', function(assert) { assert.expect(4); function Foo(object) { lodashStable.assign(this, object); } var object = { 'a': 1 }, actual = _.merge(new Foo, object); assert.ok(actual instanceof Foo); assert.deepEqual(actual, new Foo(object)); actual = _.merge([new Foo], [object]); assert.ok(actual[0] instanceof Foo); assert.deepEqual(actual, [new Foo(object)]); }); QUnit.test('should not overwrite existing values with `undefined` values of object sources', function(assert) { assert.expect(1); var actual = _.merge({ 'a': 1 }, { 'a': undefined, 'b': undefined }); assert.deepEqual(actual, { 'a': 1, 'b': undefined }); }); QUnit.test('should not overwrite existing values with `undefined` values of array sources', function(assert) { assert.expect(2); var array = [1]; array[2] = 3; var actual = _.merge([4, 5, 6], array), expected = [1, 5, 3]; assert.deepEqual(actual, expected); array = [1, , 3]; array[1] = undefined; actual = _.merge([4, 5, 6], array); assert.deepEqual(actual, expected); }); QUnit.test('should skip merging when `object` and `source` are the same value', function(assert) { assert.expect(1); var object = {}, pass = true; defineProperty(object, 'a', { 'configurable': true, 'enumerable': true, 'get': function() { pass = false; }, 'set': function() { pass = false; } }); _.merge(object, object); assert.ok(pass); }); QUnit.test('should convert values to arrays when merging arrays of `source`', function(assert) { assert.expect(2); var object = { 'a': { '1': 'y', 'b': 'z', 'length': 2 } }, actual = _.merge(object, { 'a': ['x'] }); assert.deepEqual(actual, { 'a': ['x', 'y'] }); actual = _.merge({ 'a': {} }, { 'a': [] }); assert.deepEqual(actual, { 'a': [] }); }); QUnit.test('should not convert strings to arrays when merging arrays of `source`', function(assert) { assert.expect(1); var object = { 'a': 'abcde' }, actual = _.merge(object, { 'a': ['x', 'y', 'z'] }); assert.deepEqual(actual, { 'a': ['x', 'y', 'z'] }); }); QUnit.test('should not error on DOM elements', function(assert) { assert.expect(1); var object1 = { 'el': document && document.createElement('div') }, object2 = { 'el': document && document.createElement('div') }, pairs = [[{}, object1], [object1, object2]], expected = lodashStable.map(pairs, stubTrue); var actual = lodashStable.map(pairs, function(pair) { try { return _.merge(pair[0], pair[1]).el === pair[1].el; } catch (e) {} }); assert.deepEqual(actual, expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.mergeWith'); (function() { QUnit.test('should handle merging when `customizer` returns `undefined`', function(assert) { assert.expect(2); var actual = _.mergeWith({ 'a': { 'b': [1, 1] } }, { 'a': { 'b': [0] } }, noop); assert.deepEqual(actual, { 'a': { 'b': [0, 1] } }); actual = _.mergeWith([], [undefined], identity); assert.deepEqual(actual, [undefined]); }); QUnit.test('should clone sources when `customizer` returns `undefined`', function(assert) { assert.expect(1); var source1 = { 'a': { 'b': { 'c': 1 } } }, source2 = { 'a': { 'b': { 'd': 2 } } }; _.mergeWith({}, source1, source2, noop); assert.deepEqual(source1.a.b, { 'c': 1 }); }); QUnit.test('should defer to `customizer` for non `undefined` results', function(assert) { assert.expect(1); var actual = _.mergeWith({ 'a': { 'b': [0, 1] } }, { 'a': { 'b': [2] } }, function(a, b) { return lodashStable.isArray(a) ? a.concat(b) : undefined; }); assert.deepEqual(actual, { 'a': { 'b': [0, 1, 2] } }); }); QUnit.test('should provide `stack` to `customizer`', function(assert) { assert.expect(4); var actual = []; _.mergeWith({}, { 'z': 1, 'a': { 'b': 2 } }, function() { actual.push(_.last(arguments)); }); assert.strictEqual(actual.length, 3); _.each(actual, function(a) { assert.ok(isNpm ? a.constructor.name == 'Stack' : a instanceof mapCaches.Stack ); }); }); QUnit.test('should overwrite primitives with source object clones', function(assert) { assert.expect(1); var actual = _.mergeWith({ 'a': 0 }, { 'a': { 'b': ['c'] } }, function(a, b) { return lodashStable.isArray(a) ? a.concat(b) : undefined; }); assert.deepEqual(actual, { 'a': { 'b': ['c'] } }); }); QUnit.test('should pop the stack of sources for each sibling property', function(assert) { assert.expect(1); var array = ['b', 'c'], object = { 'a': ['a'] }, source = { 'a': array, 'b': array }; var actual = _.mergeWith(object, source, function(a, b) { return lodashStable.isArray(a) ? a.concat(b) : undefined; }); assert.deepEqual(actual, { 'a': ['a', 'b', 'c'], 'b': ['b', 'c'] }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.method'); (function() { QUnit.test('should create a function that calls a method of a given object', function(assert) { assert.expect(4); var object = { 'a': stubOne }; lodashStable.each(['a', ['a']], function(path) { var method = _.method(path); assert.strictEqual(method.length, 1); assert.strictEqual(method(object), 1); }); }); QUnit.test('should work with deep property values', function(assert) { assert.expect(2); var object = { 'a': { 'b': stubTwo } }; lodashStable.each(['a.b', ['a', 'b']], function(path) { var method = _.method(path); assert.strictEqual(method(object), 2); }); }); QUnit.test('should work with a non-string `path`', function(assert) { assert.expect(2); var array = lodashStable.times(3, _.constant); lodashStable.each([1, [1]], function(path) { var method = _.method(path); assert.strictEqual(method(array), 1); }); }); QUnit.test('should coerce `path` to a string', function(assert) { assert.expect(2); function fn() {} fn.toString = lodashStable.constant('fn'); var expected = [1, 2, 3, 4], object = { 'null': stubOne, 'undefined': stubTwo, 'fn': stubThree, '[object Object]': stubFour }, paths = [null, undefined, fn, {}]; lodashStable.times(2, function(index) { var actual = lodashStable.map(paths, function(path) { var method = _.method(index ? [path] : path); return method(object); }); assert.deepEqual(actual, expected); }); }); QUnit.test('should work with inherited property values', function(assert) { assert.expect(2); function Foo() {} Foo.prototype.a = stubOne; lodashStable.each(['a', ['a']], function(path) { var method = _.method(path); assert.strictEqual(method(new Foo), 1); }); }); QUnit.test('should use a key over a path', function(assert) { assert.expect(2); var object = { 'a.b': stubOne, 'a': { 'b': stubTwo } }; lodashStable.each(['a.b', ['a.b']], function(path) { var method = _.method(path); assert.strictEqual(method(object), 1); }); }); QUnit.test('should return `undefined` when `object` is nullish', function(assert) { assert.expect(2); var values = [, null, undefined], expected = lodashStable.map(values, noop); lodashStable.each(['constructor', ['constructor']], function(path) { var method = _.method(path); var actual = lodashStable.map(values, function(value, index) { return index ? method(value) : method(); }); assert.deepEqual(actual, expected); }); }); QUnit.test('should return `undefined` for deep paths when `object` is nullish', function(assert) { assert.expect(2); var values = [, null, undefined], expected = lodashStable.map(values, noop); lodashStable.each(['constructor.prototype.valueOf', ['constructor', 'prototype', 'valueOf']], function(path) { var method = _.method(path); var actual = lodashStable.map(values, function(value, index) { return index ? method(value) : method(); }); assert.deepEqual(actual, expected); }); }); QUnit.test('should return `undefined` if parts of `path` are missing', function(assert) { assert.expect(4); var object = {}; lodashStable.each(['a', 'a[1].b.c', ['a'], ['a', '1', 'b', 'c']], function(path) { var method = _.method(path); assert.strictEqual(method(object), undefined); }); }); QUnit.test('should apply partial arguments to function', function(assert) { assert.expect(2); var object = { 'fn': function() { return slice.call(arguments); } }; lodashStable.each(['fn', ['fn']], function(path) { var method = _.method(path, 1, 2, 3); assert.deepEqual(method(object), [1, 2, 3]); }); }); QUnit.test('should invoke deep property methods with the correct `this` binding', function(assert) { assert.expect(2); var object = { 'a': { 'b': function() { return this.c; }, 'c': 1 } }; lodashStable.each(['a.b', ['a', 'b']], function(path) { var method = _.method(path); assert.strictEqual(method(object), 1); }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.methodOf'); (function() { QUnit.test('should create a function that calls a method of a given key', function(assert) { assert.expect(4); var object = { 'a': stubOne }; lodashStable.each(['a', ['a']], function(path) { var methodOf = _.methodOf(object); assert.strictEqual(methodOf.length, 1); assert.strictEqual(methodOf(path), 1); }); }); QUnit.test('should work with deep property values', function(assert) { assert.expect(2); var object = { 'a': { 'b': stubTwo } }; lodashStable.each(['a.b', ['a', 'b']], function(path) { var methodOf = _.methodOf(object); assert.strictEqual(methodOf(path), 2); }); }); QUnit.test('should work with a non-string `path`', function(assert) { assert.expect(2); var array = lodashStable.times(3, _.constant); lodashStable.each([1, [1]], function(path) { var methodOf = _.methodOf(array); assert.strictEqual(methodOf(path), 1); }); }); QUnit.test('should coerce `path` to a string', function(assert) { assert.expect(2); function fn() {} fn.toString = lodashStable.constant('fn'); var expected = [1, 2, 3, 4], object = { 'null': stubOne, 'undefined': stubTwo, 'fn': stubThree, '[object Object]': stubFour }, paths = [null, undefined, fn, {}]; lodashStable.times(2, function(index) { var actual = lodashStable.map(paths, function(path) { var methodOf = _.methodOf(object); return methodOf(index ? [path] : path); }); assert.deepEqual(actual, expected); }); }); QUnit.test('should work with inherited property values', function(assert) { assert.expect(2); function Foo() {} Foo.prototype.a = stubOne; lodashStable.each(['a', ['a']], function(path) { var methodOf = _.methodOf(new Foo); assert.strictEqual(methodOf(path), 1); }); }); QUnit.test('should use a key over a path', function(assert) { assert.expect(2); var object = { 'a.b': stubOne, 'a': { 'b': stubTwo } }; lodashStable.each(['a.b', ['a.b']], function(path) { var methodOf = _.methodOf(object); assert.strictEqual(methodOf(path), 1); }); }); QUnit.test('should return `undefined` when `object` is nullish', function(assert) { assert.expect(2); var values = [, null, undefined], expected = lodashStable.map(values, noop); lodashStable.each(['constructor', ['constructor']], function(path) { var actual = lodashStable.map(values, function(value, index) { var methodOf = index ? _.methodOf() : _.methodOf(value); return methodOf(path); }); assert.deepEqual(actual, expected); }); }); QUnit.test('should return `undefined` for deep paths when `object` is nullish', function(assert) { assert.expect(2); var values = [, null, undefined], expected = lodashStable.map(values, noop); lodashStable.each(['constructor.prototype.valueOf', ['constructor', 'prototype', 'valueOf']], function(path) { var actual = lodashStable.map(values, function(value, index) { var methodOf = index ? _.methodOf() : _.methodOf(value); return methodOf(path); }); assert.deepEqual(actual, expected); }); }); QUnit.test('should return `undefined` if parts of `path` are missing', function(assert) { assert.expect(4); var object = {}, methodOf = _.methodOf(object); lodashStable.each(['a', 'a[1].b.c', ['a'], ['a', '1', 'b', 'c']], function(path) { assert.strictEqual(methodOf(path), undefined); }); }); QUnit.test('should apply partial arguments to function', function(assert) { assert.expect(2); var object = { 'fn': function() { return slice.call(arguments); } }; var methodOf = _.methodOf(object, 1, 2, 3); lodashStable.each(['fn', ['fn']], function(path) { assert.deepEqual(methodOf(path), [1, 2, 3]); }); }); QUnit.test('should invoke deep property methods with the correct `this` binding', function(assert) { assert.expect(2); var object = { 'a': { 'b': function() { return this.c; }, 'c': 1 } }, methodOf = _.methodOf(object); lodashStable.each(['a.b', ['a', 'b']], function(path) { assert.strictEqual(methodOf(path), 1); }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.min'); (function() { QUnit.test('should return the smallest value from a collection', function(assert) { assert.expect(1); assert.strictEqual(_.min([1, 2, 3]), 1); }); QUnit.test('should return `undefined` for empty collections', function(assert) { assert.expect(1); var values = falsey.concat([[]]), expected = lodashStable.map(values, noop); var actual = lodashStable.map(values, function(value, index) { try { return index ? _.min(value) : _.min(); } catch (e) {} }); assert.deepEqual(actual, expected); }); QUnit.test('should work with non-numeric collection values', function(assert) { assert.expect(1); assert.strictEqual(_.min(['a', 'b']), 'a'); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('extremum methods'); lodashStable.each(['max', 'maxBy', 'min', 'minBy'], function(methodName) { var func = _[methodName], isMax = /^max/.test(methodName); QUnit.test('`_.' + methodName + '` should work with Date objects', function(assert) { assert.expect(1); var curr = new Date, past = new Date(0); assert.strictEqual(func([curr, past]), isMax ? curr : past); }); QUnit.test('`_.' + methodName + '` should work with extremely large arrays', function(assert) { assert.expect(1); var array = lodashStable.range(0, 5e5); assert.strictEqual(func(array), isMax ? 499999 : 0); }); QUnit.test('`_.' + methodName + '` should work when chaining on an array with only one value', function(assert) { assert.expect(1); if (!isNpm) { var actual = _([40])[methodName](); assert.strictEqual(actual, 40); } else { skipAssert(assert); } }); }); lodashStable.each(['maxBy', 'minBy'], function(methodName) { var array = [1, 2, 3], func = _[methodName], isMax = methodName == 'maxBy'; QUnit.test('`_.' + methodName + '` should work with an `iteratee`', function(assert) { assert.expect(1); var actual = func(array, function(n) { return -n; }); assert.strictEqual(actual, isMax ? 1 : 3); }); QUnit.test('should work with `_.property` shorthands', function(assert) { assert.expect(2); var objects = [{ 'a': 2 }, { 'a': 3 }, { 'a': 1 }], actual = func(objects, 'a'); assert.deepEqual(actual, objects[isMax ? 1 : 2]); var arrays = [[2], [3], [1]]; actual = func(arrays, 0); assert.deepEqual(actual, arrays[isMax ? 1 : 2]); }); QUnit.test('`_.' + methodName + '` should work when `iteratee` returns +/-Infinity', function(assert) { assert.expect(1); var value = isMax ? -Infinity : Infinity, object = { 'a': value }; var actual = func([object, { 'a': value }], function(object) { return object.a; }); assert.strictEqual(actual, object); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.mixin'); (function() { function reset(wrapper) { delete wrapper.a; delete wrapper.prototype.a; delete wrapper.b; delete wrapper.prototype.b; } function Wrapper(value) { if (!(this instanceof Wrapper)) { return new Wrapper(value); } if (_.has(value, '__wrapped__')) { var actions = slice.call(value.__actions__), chain = value.__chain__; value = value.__wrapped__; } this.__wrapped__ = value; this.__actions__ = actions || []; this.__chain__ = chain || false; } Wrapper.prototype.value = function() { return getUnwrappedValue(this); }; var array = ['a'], source = { 'a': function(array) { return array[0]; }, 'b': 'B' }; QUnit.test('should mixin `source` methods into lodash', function(assert) { assert.expect(4); if (!isNpm) { _.mixin(source); assert.strictEqual(_.a(array), 'a'); assert.strictEqual(_(array).a().value(), 'a'); assert.notOk('b' in _); assert.notOk('b' in _.prototype); reset(_); } else { skipAssert(assert, 4); } }); QUnit.test('should mixin chaining methods by reference', function(assert) { assert.expect(2); if (!isNpm) { _.mixin(source); _.a = stubB; assert.strictEqual(_.a(array), 'b'); assert.strictEqual(_(array).a().value(), 'a'); reset(_); } else { skipAssert(assert, 2); } }); QUnit.test('should use a default `object` of `this`', function(assert) { assert.expect(3); var object = lodashStable.create(_); object.mixin(source); assert.strictEqual(object.a(array), 'a'); assert.notOk('a' in _); assert.notOk('a' in _.prototype); reset(_); }); QUnit.test('should accept an `object`', function(assert) { assert.expect(1); var object = {}; _.mixin(object, source); assert.strictEqual(object.a(array), 'a'); }); QUnit.test('should accept a function `object`', function(assert) { assert.expect(2); _.mixin(Wrapper, source); var wrapped = Wrapper(array), actual = wrapped.a(); assert.strictEqual(actual.value(), 'a'); assert.ok(actual instanceof Wrapper); reset(Wrapper); }); QUnit.test('should return `object`', function(assert) { assert.expect(3); var object = {}; assert.strictEqual(_.mixin(object, source), object); assert.strictEqual(_.mixin(Wrapper, source), Wrapper); assert.strictEqual(_.mixin(), _); reset(Wrapper); }); QUnit.test('should not assign inherited `source` methods', function(assert) { assert.expect(1); function Foo() {} Foo.prototype.a = noop; var object = {}; assert.strictEqual(_.mixin(object, new Foo), object); }); QUnit.test('should accept an `options`', function(assert) { assert.expect(8); function message(func, chain) { return (func === _ ? 'lodash' : 'given') + ' function should ' + (chain ? '' : 'not ') + 'chain'; } lodashStable.each([_, Wrapper], function(func) { lodashStable.each([{ 'chain': false }, { 'chain': true }], function(options) { if (!isNpm) { if (func === _) { _.mixin(source, options); } else { _.mixin(func, source, options); } var wrapped = func(array), actual = wrapped.a(); if (options.chain) { assert.strictEqual(actual.value(), 'a', message(func, true)); assert.ok(actual instanceof func, message(func, true)); } else { assert.strictEqual(actual, 'a', message(func, false)); assert.notOk(actual instanceof func, message(func, false)); } reset(func); } else { skipAssert(assert, 2); } }); }); }); QUnit.test('should not extend lodash when an `object` is given with an empty `options` object', function(assert) { assert.expect(1); _.mixin({ 'a': noop }, {}); assert.notOk('a' in _); reset(_); }); QUnit.test('should not error for non-object `options` values', function(assert) { assert.expect(2); var pass = true; try { _.mixin({}, source, 1); } catch (e) { pass = false; } assert.ok(pass); pass = true; try { _.mixin(source, 1); } catch (e) { pass = false; } assert.ok(pass); reset(_); }); QUnit.test('should not return the existing wrapped value when chaining', function(assert) { assert.expect(2); lodashStable.each([_, Wrapper], function(func) { if (!isNpm) { if (func === _) { var wrapped = _(source), actual = wrapped.mixin(); assert.strictEqual(actual.value(), _); } else { wrapped = _(func); actual = wrapped.mixin(source); assert.notStrictEqual(actual, wrapped); } reset(func); } else { skipAssert(assert); } }); }); QUnit.test('should produce methods that work in a lazy sequence', function(assert) { assert.expect(1); if (!isNpm) { _.mixin({ 'a': _.countBy, 'b': _.filter }); var array = lodashStable.range(LARGE_ARRAY_SIZE), actual = _(array).a().map(square).b(isEven).take().value(); assert.deepEqual(actual, _.take(_.b(_.map(_.a(array), square), isEven))); reset(_); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.multiply'); (function() { QUnit.test('should multiply two numbers', function(assert) { assert.expect(3); assert.strictEqual(_.multiply(6, 4), 24); assert.strictEqual(_.multiply(-6, 4), -24); assert.strictEqual(_.multiply(-6, -4), 24); }); QUnit.test('should coerce arguments to numbers', function(assert) { assert.expect(2); assert.strictEqual(_.multiply('6', '4'), 24); assert.deepEqual(_.multiply('x', 'y'), NaN); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.orderBy'); (function() { var objects = [ { 'a': 'x', 'b': 3 }, { 'a': 'y', 'b': 4 }, { 'a': 'x', 'b': 1 }, { 'a': 'y', 'b': 2 } ]; QUnit.test('should sort by a single property by a specified order', function(assert) { assert.expect(1); var actual = _.orderBy(objects, 'a', 'desc'); assert.deepEqual(actual, [objects[1], objects[3], objects[0], objects[2]]); }); QUnit.test('should sort by multiple properties by specified orders', function(assert) { assert.expect(1); var actual = _.orderBy(objects, ['a', 'b'], ['desc', 'asc']); assert.deepEqual(actual, [objects[3], objects[1], objects[2], objects[0]]); }); QUnit.test('should sort by a property in ascending order when its order is not specified', function(assert) { assert.expect(2); var expected = [objects[2], objects[0], objects[3], objects[1]], actual = _.orderBy(objects, ['a', 'b']); assert.deepEqual(actual, expected); expected = lodashStable.map(falsey, lodashStable.constant([objects[3], objects[1], objects[2], objects[0]])); actual = lodashStable.map(falsey, function(order, index) { return _.orderBy(objects, ['a', 'b'], index ? ['desc', order] : ['desc']); }); assert.deepEqual(actual, expected); }); QUnit.test('should work with `orders` specified as string objects', function(assert) { assert.expect(1); var actual = _.orderBy(objects, ['a'], [Object('desc')]); assert.deepEqual(actual, [objects[1], objects[3], objects[0], objects[2]]); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.overArgs'); (function() { function fn() { return slice.call(arguments); } QUnit.test('should transform each argument', function(assert) { assert.expect(1); var over = _.overArgs(fn, doubled, square); assert.deepEqual(over(5, 10), [10, 100]); }); QUnit.test('should use `_.identity` when a predicate is nullish', function(assert) { assert.expect(1); var over = _.overArgs(fn, undefined, null); assert.deepEqual(over('a', 'b'), ['a', 'b']); }); QUnit.test('should work with `_.property` shorthands', function(assert) { assert.expect(1); var over = _.overArgs(fn, 'b', 'a'); assert.deepEqual(over({ 'b': 2 }, { 'a': 1 }), [2, 1]); }); QUnit.test('should work with `_.matches` shorthands', function(assert) { assert.expect(1); var over = _.overArgs(fn, { 'b': 1 }, { 'a': 1 }); assert.deepEqual(over({ 'b': 2 }, { 'a': 1 }), [false, true]); }); QUnit.test('should work with `_.matchesProperty` shorthands', function(assert) { assert.expect(1); var over = _.overArgs(fn, [['b', 1], ['a', 1]]); assert.deepEqual(over({ 'b': 2 }, { 'a': 1 }), [false, true]); }); QUnit.test('should differentiate between `_.property` and `_.matchesProperty` shorthands', function(assert) { assert.expect(2); var over = _.overArgs(fn, ['a', 1]); assert.deepEqual(over({ 'a': 1 }, { '1': 2 }), [1, 2]); over = _.overArgs(fn, [['a', 1]]); assert.deepEqual(over({ 'a': 1 }), [true]); }); QUnit.test('should flatten `transforms`', function(assert) { assert.expect(1); var over = _.overArgs(fn, [doubled, square], String); assert.deepEqual(over(5, 10, 15), [10, 100, '15']); }); QUnit.test('should not transform any argument greater than the number of transforms', function(assert) { assert.expect(1); var over = _.overArgs(fn, doubled, square); assert.deepEqual(over(5, 10, 18), [10, 100, 18]); }); QUnit.test('should not transform any arguments if no transforms are given', function(assert) { assert.expect(1); var over = _.overArgs(fn); assert.deepEqual(over(5, 10, 18), [5, 10, 18]); }); QUnit.test('should not pass `undefined` if there are more transforms than arguments', function(assert) { assert.expect(1); var over = _.overArgs(fn, doubled, identity); assert.deepEqual(over(5), [10]); }); QUnit.test('should provide the correct argument to each transform', function(assert) { assert.expect(1); var argsList = [], transform = function() { argsList.push(slice.call(arguments)); }, over = _.overArgs(noop, transform, transform, transform); over('a', 'b'); assert.deepEqual(argsList, [['a'], ['b']]); }); QUnit.test('should use `this` binding of function for `transforms`', function(assert) { assert.expect(1); var over = _.overArgs(function(x) { return this[x]; }, function(x) { return this === x; }); var object = { 'over': over, 'true': 1 }; assert.strictEqual(object.over(object), 1); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.negate'); (function() { QUnit.test('should create a function that negates the result of `func`', function(assert) { assert.expect(2); var negate = _.negate(isEven); assert.strictEqual(negate(1), true); assert.strictEqual(negate(2), false); }); QUnit.test('should create a function that negates the result of `func`', function(assert) { assert.expect(2); var negate = _.negate(isEven); assert.strictEqual(negate(1), true); assert.strictEqual(negate(2), false); }); QUnit.test('should create a function that accepts multiple arguments', function(assert) { assert.expect(1); var argCount, count = 5, negate = _.negate(function() { argCount = arguments.length; }), expected = lodashStable.times(count, stubTrue); var actual = lodashStable.times(count, function(index) { switch (index) { case 0: negate(); break; case 1: negate(1); break; case 2: negate(1, 2); break; case 3: negate(1, 2, 3); break; case 4: negate(1, 2, 3, 4); } return argCount == index; }); assert.deepEqual(actual, expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.noConflict'); (function() { QUnit.test('should return the `lodash` function', function(assert) { assert.expect(2); if (!isModularize) { assert.strictEqual(_.noConflict(), oldDash); assert.notStrictEqual(root._, oldDash); root._ = oldDash; } else { skipAssert(assert, 2); } }); QUnit.test('should restore `_` only if `lodash` is the current `_` value', function(assert) { assert.expect(2); if (!isModularize) { var object = root._ = {}; assert.strictEqual(_.noConflict(), oldDash); assert.strictEqual(root._, object); root._ = oldDash; } else { skipAssert(assert, 2); } }); QUnit.test('should work with a `root` of `this`', function(assert) { assert.expect(2); if (!coverage && !document && !isModularize && realm.object) { var fs = require('fs'), vm = require('vm'), expected = {}, context = vm.createContext({ '_': expected, 'console': console }), source = fs.readFileSync(filePath, 'utf8'); vm.runInContext(source + '\nthis.lodash = this._.noConflict()', context); assert.strictEqual(context._, expected); assert.ok(context.lodash); } else { skipAssert(assert, 2); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.now'); (function() { QUnit.test('should return the number of milliseconds that have elapsed since the Unix epoch', function(assert) { assert.expect(2); var done = assert.async(); var stamp = +new Date, actual = _.now(); assert.ok(actual >= stamp); setTimeout(function() { assert.ok(_.now() > actual); done(); }, 32); }); QUnit.test('should work with mocked `Date.now`', function(assert) { assert.expect(1); var now = Date.now; Date.now = stubA; var actual = _.now(); Date.now = now; assert.strictEqual(actual, 'a'); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.nth'); (function() { var array = ['a', 'b', 'c', 'd']; QUnit.test('should get the nth element of `array`', function(assert) { assert.expect(1); var actual = lodashStable.map(array, function(value, index) { return _.nth(array, index); }); assert.deepEqual(actual, array); }); QUnit.test('should work with a negative `n`', function(assert) { assert.expect(1); var actual = lodashStable.map(lodashStable.range(1, array.length + 1), function(n) { return _.nth(array, -n); }); assert.deepEqual(actual, ['d', 'c', 'b', 'a']); }); QUnit.test('should coerce `n` to an integer', function(assert) { assert.expect(2); var values = falsey, expected = lodashStable.map(values, stubA); var actual = lodashStable.map(values, function(n) { return n ? _.nth(array, n) : _.nth(array); }); assert.deepEqual(actual, expected); values = ['1', 1.6]; expected = lodashStable.map(values, stubB); actual = lodashStable.map(values, function(n) { return _.nth(array, n); }); assert.deepEqual(actual, expected); }); QUnit.test('should return `undefined` for empty arrays', function(assert) { assert.expect(1); var values = [null, undefined, []], expected = lodashStable.map(values, noop); var actual = lodashStable.map(values, function(array) { return _.nth(array, 1); }); assert.deepEqual(actual, expected); }); QUnit.test('should return `undefined` for non-indexes', function(assert) { assert.expect(1); var array = [1, 2], values = [Infinity, array.length], expected = lodashStable.map(values, noop); array[-1] = 3; var actual = lodashStable.map(values, function(n) { return _.nth(array, n); }); assert.deepEqual(actual, expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.nthArg'); (function() { var args = ['a', 'b', 'c', 'd']; QUnit.test('should create a function that returns its nth argument', function(assert) { assert.expect(1); var actual = lodashStable.map(args, function(value, index) { var func = _.nthArg(index); return func.apply(undefined, args); }); assert.deepEqual(actual, args); }); QUnit.test('should work with a negative `n`', function(assert) { assert.expect(1); var actual = lodashStable.map(lodashStable.range(1, args.length + 1), function(n) { var func = _.nthArg(-n); return func.apply(undefined, args); }); assert.deepEqual(actual, ['d', 'c', 'b', 'a']); }); QUnit.test('should coerce `n` to an integer', function(assert) { assert.expect(2); var values = falsey, expected = lodashStable.map(values, stubA); var actual = lodashStable.map(values, function(n) { var func = n ? _.nthArg(n) : _.nthArg(); return func.apply(undefined, args); }); assert.deepEqual(actual, expected); values = ['1', 1.6]; expected = lodashStable.map(values, stubB); actual = lodashStable.map(values, function(n) { var func = _.nthArg(n); return func.apply(undefined, args); }); assert.deepEqual(actual, expected); }); QUnit.test('should return `undefined` for empty arrays', function(assert) { assert.expect(1); var func = _.nthArg(1); assert.strictEqual(func(), undefined); }); QUnit.test('should return `undefined` for non-indexes', function(assert) { assert.expect(1); var values = [Infinity, args.length], expected = lodashStable.map(values, noop); var actual = lodashStable.map(values, function(n) { var func = _.nthArg(n); return func.apply(undefined, args); }); assert.deepEqual(actual, expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.omit'); (function() { var args = toArgs(['a', 'c']), object = { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }, nested = { 'a': 1, 'b': { 'c': 2, 'd': 3 } }; QUnit.test('should flatten `paths`', function(assert) { assert.expect(2); assert.deepEqual(_.omit(object, 'a', 'c'), { 'b': 2, 'd': 4 }); assert.deepEqual(_.omit(object, ['a', 'd'], 'c'), { 'b': 2 }); }); QUnit.test('should support deep paths', function(assert) { assert.expect(1); assert.deepEqual(_.omit(nested, 'b.c'), { 'a': 1, 'b': { 'd': 3} }); }); QUnit.test('should support path arrays', function(assert) { assert.expect(1); var object = { 'a.b': 1, 'a': { 'b': 2 } }, actual = _.omit(object, [['a.b']]); assert.deepEqual(actual, { 'a': { 'b': 2 } }); }); QUnit.test('should omit a key over a path', function(assert) { assert.expect(2); var object = { 'a.b': 1, 'a': { 'b': 2 } }; lodashStable.each(['a.b', ['a.b']], function(path) { assert.deepEqual(_.omit(object, path), { 'a': { 'b': 2 } }); }); }); QUnit.test('should coerce `paths` to strings', function(assert) { assert.expect(1); assert.deepEqual(_.omit({ '0': 'a' }, 0), {}); }); QUnit.test('should return an empty object when `object` is nullish', function(assert) { assert.expect(2); lodashStable.each([null, undefined], function(value) { objectProto.a = 1; var actual = _.omit(value, 'valueOf'); delete objectProto.a; assert.deepEqual(actual, {}); }); }); QUnit.test('should work with a primitive `object`', function(assert) { assert.expect(1); stringProto.a = 1; stringProto.b = 2; assert.deepEqual(_.omit('', 'b'), { 'a': 1 }); delete stringProto.a; delete stringProto.b; }); QUnit.test('should work with `arguments` object `paths`', function(assert) { assert.expect(1); assert.deepEqual(_.omit(object, args), { 'b': 2, 'd': 4 }); }); QUnit.test('should not mutate `object`', function(assert) { assert.expect(4); lodashStable.each(['a', ['a'], 'a.b', ['a.b']], function(path) { var object = { 'a': { 'b': 2 } }; _.omit(object, path); assert.deepEqual(object, { 'a': { 'b': 2 } }); }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.omitBy'); (function() { QUnit.test('should work with a predicate argument', function(assert) { assert.expect(1); var object = { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }; var actual = _.omitBy(object, function(n) { return n != 2 && n != 4; }); assert.deepEqual(actual, { 'b': 2, 'd': 4 }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('omit methods'); lodashStable.each(['omit', 'omitBy'], function(methodName) { var expected = { 'b': 2, 'd': 4 }, func = _[methodName], object = { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }, resolve = lodashStable.nthArg(1); if (methodName == 'omitBy') { resolve = function(object, props) { props = lodashStable.castArray(props); return function(value) { return lodashStable.some(props, function(key) { key = lodashStable.isSymbol(key) ? key : lodashStable.toString(key); return object[key] === value; }); }; }; } QUnit.test('`_.' + methodName + '` should create an object with omitted string keyed properties', function(assert) { assert.expect(2); assert.deepEqual(func(object, resolve(object, 'a')), { 'b': 2, 'c': 3, 'd': 4 }); assert.deepEqual(func(object, resolve(object, ['a', 'c'])), expected); }); QUnit.test('`_.' + methodName + '` should include inherited string keyed properties', function(assert) { assert.expect(1); function Foo() {} Foo.prototype = object; assert.deepEqual(func(new Foo, resolve(object, ['a', 'c'])), expected); }); QUnit.test('`_.' + methodName + '` should preserve the sign of `0`', function(assert) { assert.expect(1); var object = { '-0': 'a', '0': 'b' }, props = [-0, Object(-0), 0, Object(0)], expected = [{ '0': 'b' }, { '0': 'b' }, { '-0': 'a' }, { '-0': 'a' }]; var actual = lodashStable.map(props, function(key) { return func(object, resolve(object, key)); }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should include symbols', function(assert) { assert.expect(3); function Foo() { this.a = 0; this[symbol] = 1; } if (Symbol) { var symbol2 = Symbol('b'); Foo.prototype[symbol2] = 2; var symbol3 = Symbol('c'); defineProperty(Foo.prototype, symbol3, { 'configurable': true, 'enumerable': false, 'writable': true, 'value': 3 }); var foo = new Foo, actual = func(foo, resolve(foo, 'a')); assert.strictEqual(actual[symbol], 1); assert.strictEqual(actual[symbol2], 2); assert.notOk(symbol3 in actual); } else { skipAssert(assert, 3); } }); QUnit.test('`_.' + methodName + '` should create an object with omitted symbols', function(assert) { assert.expect(8); function Foo() { this.a = 0; this[symbol] = 1; } if (Symbol) { var symbol2 = Symbol('b'); Foo.prototype[symbol2] = 2; var symbol3 = Symbol('c'); defineProperty(Foo.prototype, symbol3, { 'configurable': true, 'enumerable': false, 'writable': true, 'value': 3 }); var foo = new Foo, actual = func(foo, resolve(foo, symbol)); assert.strictEqual(actual.a, 0); assert.notOk(symbol in actual); assert.strictEqual(actual[symbol2], 2); assert.notOk(symbol3 in actual); actual = func(foo, resolve(foo, symbol2)); assert.strictEqual(actual.a, 0); assert.strictEqual(actual[symbol], 1); assert.notOk(symbol2 in actual); assert.notOk(symbol3 in actual); } else { skipAssert(assert, 8); } }); QUnit.test('`_.' + methodName + '` should work with an array `object`', function(assert) { assert.expect(1); var array = [1, 2, 3]; assert.deepEqual(func(array, resolve(array, ['0', '2'])), { '1': 2 }); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.once'); (function() { QUnit.test('should invoke `func` once', function(assert) { assert.expect(2); var count = 0, once = _.once(function() { return ++count; }); once(); assert.strictEqual(once(), 1); assert.strictEqual(count, 1); }); QUnit.test('should ignore recursive calls', function(assert) { assert.expect(2); var count = 0; var once = _.once(function() { once(); return ++count; }); assert.strictEqual(once(), 1); assert.strictEqual(count, 1); }); QUnit.test('should not throw more than once', function(assert) { assert.expect(2); var once = _.once(function() { throw new Error; }); assert.raises(once); once(); assert.ok(true); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.over'); (function() { QUnit.test('should create a function that invokes `iteratees`', function(assert) { assert.expect(1); var over = _.over(Math.max, Math.min); assert.deepEqual(over(1, 2, 3, 4), [4, 1]); }); QUnit.test('should use `_.identity` when a predicate is nullish', function(assert) { assert.expect(1); var over = _.over(undefined, null); assert.deepEqual(over('a', 'b', 'c'), ['a', 'a']); }); QUnit.test('should work with `_.property` shorthands', function(assert) { assert.expect(1); var over = _.over('b', 'a'); assert.deepEqual(over({ 'a': 1, 'b': 2 }), [2, 1]); }); QUnit.test('should work with `_.matches` shorthands', function(assert) { assert.expect(1); var over = _.over({ 'b': 1 }, { 'a': 1 }); assert.deepEqual(over({ 'a': 1, 'b': 2 }), [false, true]); }); QUnit.test('should work with `_.matchesProperty` shorthands', function(assert) { assert.expect(2); var over = _.over([['b', 2], ['a', 2]]); assert.deepEqual(over({ 'a': 1, 'b': 2 }), [true, false]); assert.deepEqual(over({ 'a': 2, 'b': 1 }), [false, true]); }); QUnit.test('should differentiate between `_.property` and `_.matchesProperty` shorthands', function(assert) { assert.expect(4); var over = _.over(['a', 1]); assert.deepEqual(over({ 'a': 1, '1': 2 }), [1, 2]); assert.deepEqual(over({ 'a': 2, '1': 1 }), [2, 1]); over = _.over([['a', 1]]); assert.deepEqual(over({ 'a': 1 }), [true]); assert.deepEqual(over({ 'a': 2 }), [false]); }); QUnit.test('should provide arguments to predicates', function(assert) { assert.expect(1); var over = _.over(function() { return slice.call(arguments); }); assert.deepEqual(over('a', 'b', 'c'), [['a', 'b', 'c']]); }); QUnit.test('should use `this` binding of function for `iteratees`', function(assert) { assert.expect(1); var over = _.over(function() { return this.b; }, function() { return this.a; }), object = { 'over': over, 'a': 1, 'b': 2 }; assert.deepEqual(object.over(), [2, 1]); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.overEvery'); (function() { QUnit.test('should create a function that returns `true` if all predicates return truthy', function(assert) { assert.expect(1); var over = _.overEvery(stubTrue, stubOne, stubA); assert.strictEqual(over(), true); }); QUnit.test('should return `false` as soon as a predicate returns falsey', function(assert) { assert.expect(2); var count = 0, countFalse = function() { count++; return false; }, countTrue = function() { count++; return true; }, over = _.overEvery(countTrue, countFalse, countTrue); assert.strictEqual(over(), false); assert.strictEqual(count, 2); }); QUnit.test('should use `_.identity` when a predicate is nullish', function(assert) { assert.expect(2); var over = _.overEvery(undefined, null); assert.strictEqual(over(true), true); assert.strictEqual(over(false), false); }); QUnit.test('should work with `_.property` shorthands', function(assert) { assert.expect(2); var over = _.overEvery('b', 'a'); assert.strictEqual(over({ 'a': 1, 'b': 1 }), true); assert.strictEqual(over({ 'a': 0, 'b': 1 }), false); }); QUnit.test('should work with `_.matches` shorthands', function(assert) { assert.expect(2); var over = _.overEvery({ 'b': 2 }, { 'a': 1 }); assert.strictEqual(over({ 'a': 1, 'b': 2 }), true); assert.strictEqual(over({ 'a': 0, 'b': 2 }), false); }); QUnit.test('should work with `_.matchesProperty` shorthands', function(assert) { assert.expect(2); var over = _.overEvery([['b', 2], ['a', 1]]); assert.strictEqual(over({ 'a': 1, 'b': 2 }), true); assert.strictEqual(over({ 'a': 0, 'b': 2 }), false); }); QUnit.test('should differentiate between `_.property` and `_.matchesProperty` shorthands', function(assert) { assert.expect(5); var over = _.overEvery(['a', 1]); assert.strictEqual(over({ 'a': 1, '1': 1 }), true); assert.strictEqual(over({ 'a': 1, '1': 0 }), false); assert.strictEqual(over({ 'a': 0, '1': 1 }), false); over = _.overEvery([['a', 1]]); assert.strictEqual(over({ 'a': 1 }), true); assert.strictEqual(over({ 'a': 2 }), false); }); QUnit.test('should flatten `predicates`', function(assert) { assert.expect(1); var over = _.overEvery(stubTrue, [stubFalse]); assert.strictEqual(over(), false); }); QUnit.test('should provide arguments to predicates', function(assert) { assert.expect(1); var args; var over = _.overEvery(function() { args = slice.call(arguments); }); over('a', 'b', 'c'); assert.deepEqual(args, ['a', 'b', 'c']); }); QUnit.test('should use `this` binding of function for `predicates`', function(assert) { assert.expect(2); var over = _.overEvery(function() { return this.b; }, function() { return this.a; }), object = { 'over': over, 'a': 1, 'b': 2 }; assert.strictEqual(object.over(), true); object.a = 0; assert.strictEqual(object.over(), false); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.overSome'); (function() { QUnit.test('should create a function that returns `true` if any predicates return truthy', function(assert) { assert.expect(2); var over = _.overSome(stubFalse, stubOne, stubString); assert.strictEqual(over(), true); over = _.overSome(stubNull, stubA, stubZero); assert.strictEqual(over(), true); }); QUnit.test('should return `true` as soon as `predicate` returns truthy', function(assert) { assert.expect(2); var count = 0, countFalse = function() { count++; return false; }, countTrue = function() { count++; return true; }, over = _.overSome(countFalse, countTrue, countFalse); assert.strictEqual(over(), true); assert.strictEqual(count, 2); }); QUnit.test('should return `false` if all predicates return falsey', function(assert) { assert.expect(2); var over = _.overSome(stubFalse, stubFalse, stubFalse); assert.strictEqual(over(), false); over = _.overSome(stubNull, stubZero, stubString); assert.strictEqual(over(), false); }); QUnit.test('should use `_.identity` when a predicate is nullish', function(assert) { assert.expect(2); var over = _.overSome(undefined, null); assert.strictEqual(over(true), true); assert.strictEqual(over(false), false); }); QUnit.test('should work with `_.property` shorthands', function(assert) { assert.expect(2); var over = _.overSome('b', 'a'); assert.strictEqual(over({ 'a': 1, 'b': 0 }), true); assert.strictEqual(over({ 'a': 0, 'b': 0 }), false); }); QUnit.test('should work with `_.matches` shorthands', function(assert) { assert.expect(2); var over = _.overSome({ 'b': 2 }, { 'a': 1 }); assert.strictEqual(over({ 'a': 0, 'b': 2 }), true); assert.strictEqual(over({ 'a': 0, 'b': 0 }), false); }); QUnit.test('should work with `_.matchesProperty` shorthands', function(assert) { assert.expect(2); var over = _.overSome([['b', 2], ['a', 1]]); assert.strictEqual(over({ 'a': 0, 'b': 2 }), true); assert.strictEqual(over({ 'a': 0, 'b': 0 }), false); }); QUnit.test('should differentiate between `_.property` and `_.matchesProperty` shorthands', function(assert) { assert.expect(5); var over = _.overSome(['a', 1]); assert.strictEqual(over({ 'a': 0, '1': 0 }), false); assert.strictEqual(over({ 'a': 1, '1': 0 }), true); assert.strictEqual(over({ 'a': 0, '1': 1 }), true); over = _.overSome([['a', 1]]); assert.strictEqual(over({ 'a': 1 }), true); assert.strictEqual(over({ 'a': 2 }), false); }); QUnit.test('should flatten `predicates`', function(assert) { assert.expect(1); var over = _.overSome(stubFalse, [stubTrue]); assert.strictEqual(over(), true); }); QUnit.test('should provide arguments to predicates', function(assert) { assert.expect(1); var args; var over = _.overSome(function() { args = slice.call(arguments); }); over('a', 'b', 'c'); assert.deepEqual(args, ['a', 'b', 'c']); }); QUnit.test('should use `this` binding of function for `predicates`', function(assert) { assert.expect(2); var over = _.overSome(function() { return this.b; }, function() { return this.a; }), object = { 'over': over, 'a': 1, 'b': 2 }; assert.strictEqual(object.over(), true); object.a = object.b = 0; assert.strictEqual(object.over(), false); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.pad'); (function() { var string = 'abc'; QUnit.test('should pad a string to a given length', function(assert) { assert.expect(1); var values = [, undefined], expected = lodashStable.map(values, lodashStable.constant(' abc ')); var actual = lodashStable.map(values, function(value, index) { return index ? _.pad(string, 6, value) : _.pad(string, 6); }); assert.deepEqual(actual, expected); }); QUnit.test('should truncate pad characters to fit the pad length', function(assert) { assert.expect(2); assert.strictEqual(_.pad(string, 8), ' abc '); assert.strictEqual(_.pad(string, 8, '_-'), '_-abc_-_'); }); QUnit.test('should coerce `string` to a string', function(assert) { assert.expect(1); var values = [Object(string), { 'toString': lodashStable.constant(string) }], expected = lodashStable.map(values, stubTrue); var actual = lodashStable.map(values, function(value) { return _.pad(value, 6) === ' abc '; }); assert.deepEqual(actual, expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.padEnd'); (function() { var string = 'abc'; QUnit.test('should pad a string to a given length', function(assert) { assert.expect(1); var values = [, undefined], expected = lodashStable.map(values, lodashStable.constant('abc ')); var actual = lodashStable.map(values, function(value, index) { return index ? _.padEnd(string, 6, value) : _.padEnd(string, 6); }); assert.deepEqual(actual, expected); }); QUnit.test('should truncate pad characters to fit the pad length', function(assert) { assert.expect(1); assert.strictEqual(_.padEnd(string, 6, '_-'), 'abc_-_'); }); QUnit.test('should coerce `string` to a string', function(assert) { assert.expect(1); var values = [Object(string), { 'toString': lodashStable.constant(string) }], expected = lodashStable.map(values, stubTrue); var actual = lodashStable.map(values, function(value) { return _.padEnd(value, 6) === 'abc '; }); assert.deepEqual(actual, expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.padStart'); (function() { var string = 'abc'; QUnit.test('should pad a string to a given length', function(assert) { assert.expect(1); var values = [, undefined], expected = lodashStable.map(values, lodashStable.constant(' abc')); var actual = lodashStable.map(values, function(value, index) { return index ? _.padStart(string, 6, value) : _.padStart(string, 6); }); assert.deepEqual(actual, expected); }); QUnit.test('should truncate pad characters to fit the pad length', function(assert) { assert.expect(1); assert.strictEqual(_.padStart(string, 6, '_-'), '_-_abc'); }); QUnit.test('should coerce `string` to a string', function(assert) { assert.expect(1); var values = [Object(string), { 'toString': lodashStable.constant(string) }], expected = lodashStable.map(values, stubTrue); var actual = lodashStable.map(values, function(value) { return _.padStart(value, 6) === ' abc'; }); assert.deepEqual(actual, expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('pad methods'); lodashStable.each(['pad', 'padStart', 'padEnd'], function(methodName) { var func = _[methodName], isPad = methodName == 'pad', isStart = methodName == 'padStart', string = 'abc'; QUnit.test('`_.' + methodName + '` should not pad if string is >= `length`', function(assert) { assert.expect(2); assert.strictEqual(func(string, 2), string); assert.strictEqual(func(string, 3), string); }); QUnit.test('`_.' + methodName + '` should treat negative `length` as `0`', function(assert) { assert.expect(2); lodashStable.each([0, -2], function(length) { assert.strictEqual(func(string, length), string); }); }); QUnit.test('`_.' + methodName + '` should coerce `length` to a number', function(assert) { assert.expect(2); lodashStable.each(['', '4'], function(length) { var actual = length ? (isStart ? ' abc' : 'abc ') : string; assert.strictEqual(func(string, length), actual); }); }); QUnit.test('`_.' + methodName + '` should treat nullish values as empty strings', function(assert) { assert.expect(6); lodashStable.each([undefined, '_-'], function(chars) { var expected = chars ? (isPad ? '__' : chars) : ' '; assert.strictEqual(func(null, 2, chars), expected); assert.strictEqual(func(undefined, 2, chars), expected); assert.strictEqual(func('', 2, chars), expected); }); }); QUnit.test('`_.' + methodName + '` should return `string` when `chars` coerces to an empty string', function(assert) { assert.expect(1); var values = ['', Object('')], expected = lodashStable.map(values, lodashStable.constant(string)); var actual = lodashStable.map(values, function(value) { return _.pad(string, 6, value); }); assert.deepEqual(actual, expected); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.parseInt'); (function() { QUnit.test('should accept a `radix`', function(assert) { assert.expect(1); var expected = lodashStable.range(2, 37); var actual = lodashStable.map(expected, function(radix) { return _.parseInt('10', radix); }); assert.deepEqual(actual, expected); }); QUnit.test('should use a radix of `10`, for non-hexadecimals, if `radix` is `undefined` or `0`', function(assert) { assert.expect(4); assert.strictEqual(_.parseInt('10'), 10); assert.strictEqual(_.parseInt('10', 0), 10); assert.strictEqual(_.parseInt('10', 10), 10); assert.strictEqual(_.parseInt('10', undefined), 10); }); QUnit.test('should use a radix of `16`, for hexadecimals, if `radix` is `undefined` or `0`', function(assert) { assert.expect(8); lodashStable.each(['0x20', '0X20'], function(string) { assert.strictEqual(_.parseInt(string), 32); assert.strictEqual(_.parseInt(string, 0), 32); assert.strictEqual(_.parseInt(string, 16), 32); assert.strictEqual(_.parseInt(string, undefined), 32); }); }); QUnit.test('should use a radix of `10` for string with leading zeros', function(assert) { assert.expect(2); assert.strictEqual(_.parseInt('08'), 8); assert.strictEqual(_.parseInt('08', 10), 8); }); QUnit.test('should parse strings with leading whitespace', function(assert) { assert.expect(2); var expected = [8, 8, 10, 10, 32, 32, 32, 32]; lodashStable.times(2, function(index) { var actual = [], func = (index ? (lodashBizarro || {}) : _).parseInt; if (func) { lodashStable.times(2, function(otherIndex) { var string = otherIndex ? '10' : '08'; actual.push( func(whitespace + string, 10), func(whitespace + string) ); }); lodashStable.each(['0x20', '0X20'], function(string) { actual.push( func(whitespace + string), func(whitespace + string, 16) ); }); assert.deepEqual(actual, expected); } else { skipAssert(assert); } }); }); QUnit.test('should coerce `radix` to a number', function(assert) { assert.expect(2); var object = { 'valueOf': stubZero }; assert.strictEqual(_.parseInt('08', object), 8); assert.strictEqual(_.parseInt('0x20', object), 32); }); QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(2); var strings = lodashStable.map(['6', '08', '10'], Object), actual = lodashStable.map(strings, _.parseInt); assert.deepEqual(actual, [6, 8, 10]); actual = lodashStable.map('123', _.parseInt); assert.deepEqual(actual, [1, 2, 3]); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('partial methods'); lodashStable.each(['partial', 'partialRight'], function(methodName) { var func = _[methodName], isPartial = methodName == 'partial', ph = func.placeholder; QUnit.test('`_.' + methodName + '` partially applies arguments', function(assert) { assert.expect(1); var par = func(identity, 'a'); assert.strictEqual(par(), 'a'); }); QUnit.test('`_.' + methodName + '` creates a function that can be invoked with additional arguments', function(assert) { assert.expect(1); var fn = function(a, b) { return [a, b]; }, par = func(fn, 'a'), expected = isPartial ? ['a', 'b'] : ['b', 'a']; assert.deepEqual(par('b'), expected); }); QUnit.test('`_.' + methodName + '` works when there are no partially applied arguments and the created function is invoked without additional arguments', function(assert) { assert.expect(1); var fn = function() { return arguments.length; }, par = func(fn); assert.strictEqual(par(), 0); }); QUnit.test('`_.' + methodName + '` works when there are no partially applied arguments and the created function is invoked with additional arguments', function(assert) { assert.expect(1); var par = func(identity); assert.strictEqual(par('a'), 'a'); }); QUnit.test('`_.' + methodName + '` should support placeholders', function(assert) { assert.expect(4); var fn = function() { return slice.call(arguments); }, par = func(fn, ph, 'b', ph); assert.deepEqual(par('a', 'c'), ['a', 'b', 'c']); assert.deepEqual(par('a'), ['a', 'b', undefined]); assert.deepEqual(par(), [undefined, 'b', undefined]); if (isPartial) { assert.deepEqual(par('a', 'c', 'd'), ['a', 'b', 'c', 'd']); } else { par = func(fn, ph, 'c', ph); assert.deepEqual(par('a', 'b', 'd'), ['a', 'b', 'c', 'd']); } }); QUnit.test('`_.' + methodName + '` should use `_.placeholder` when set', function(assert) { assert.expect(1); if (!isModularize) { var _ph = _.placeholder = {}, fn = function() { return slice.call(arguments); }, par = func(fn, _ph, 'b', ph), expected = isPartial ? ['a', 'b', ph, 'c'] : ['a', 'c', 'b', ph]; assert.deepEqual(par('a', 'c'), expected); delete _.placeholder; } else { skipAssert(assert); } }); QUnit.test('`_.' + methodName + '` creates a function with a `length` of `0`', function(assert) { assert.expect(1); var fn = function(a, b, c) {}, par = func(fn, 'a'); assert.strictEqual(par.length, 0); }); QUnit.test('`_.' + methodName + '` should ensure `new par` is an instance of `func`', function(assert) { assert.expect(2); function Foo(value) { return value && object; } var object = {}, par = func(Foo); assert.ok(new par instanceof Foo); assert.strictEqual(new par(true), object); }); QUnit.test('`_.' + methodName + '` should clone metadata for created functions', function(assert) { assert.expect(3); function greet(greeting, name) { return greeting + ' ' + name; } var par1 = func(greet, 'hi'), par2 = func(par1, 'barney'), par3 = func(par1, 'pebbles'); assert.strictEqual(par1('fred'), isPartial ? 'hi fred' : 'fred hi'); assert.strictEqual(par2(), isPartial ? 'hi barney' : 'barney hi'); assert.strictEqual(par3(), isPartial ? 'hi pebbles' : 'pebbles hi'); }); QUnit.test('`_.' + methodName + '` should work with curried functions', function(assert) { assert.expect(2); var fn = function(a, b, c) { return a + b + c; }, curried = _.curry(func(fn, 1), 2); assert.strictEqual(curried(2, 3), 6); assert.strictEqual(curried(2)(3), 6); }); QUnit.test('should work with placeholders and curried functions', function(assert) { assert.expect(1); var fn = function() { return slice.call(arguments); }, curried = _.curry(fn), par = func(curried, ph, 'b', ph, 'd'); assert.deepEqual(par('a', 'c'), ['a', 'b', 'c', 'd']); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.partialRight'); (function() { QUnit.test('should work as a deep `_.defaults`', function(assert) { assert.expect(1); var object = { 'a': { 'b': 2 } }, source = { 'a': { 'b': 3, 'c': 3 } }, expected = { 'a': { 'b': 2, 'c': 3 } }; var defaultsDeep = _.partialRight(_.mergeWith, function deep(value, other) { return lodashStable.isObject(value) ? _.mergeWith(value, other, deep) : value; }); assert.deepEqual(defaultsDeep(object, source), expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('methods using `createWrapper`'); (function() { function fn() { return slice.call(arguments); } var ph1 = _.bind.placeholder, ph2 = _.bindKey.placeholder, ph3 = _.partial.placeholder, ph4 = _.partialRight.placeholder; QUnit.test('should work with combinations of partial functions', function(assert) { assert.expect(1); var a = _.partial(fn), b = _.partialRight(a, 3), c = _.partial(b, 1); assert.deepEqual(c(2), [1, 2, 3]); }); QUnit.test('should work with combinations of bound and partial functions', function(assert) { assert.expect(3); var fn = function() { var result = [this.a]; push.apply(result, arguments); return result; }; var expected = [1, 2, 3, 4], object = { 'a': 1, 'fn': fn }; var a = _.bindKey(object, 'fn'), b = _.partialRight(a, 4), c = _.partial(b, 2); assert.deepEqual(c(3), expected); a = _.bind(fn, object); b = _.partialRight(a, 4); c = _.partial(b, 2); assert.deepEqual(c(3), expected); a = _.partial(fn, 2); b = _.bind(a, object); c = _.partialRight(b, 4); assert.deepEqual(c(3), expected); }); QUnit.test('should ensure `new combo` is an instance of `func`', function(assert) { assert.expect(2); function Foo(a, b, c) { return b === 0 && object; } var combo = _.partial(_.partialRight(Foo, 3), 1), object = {}; assert.ok(new combo(2) instanceof Foo); assert.strictEqual(new combo(0), object); }); QUnit.test('should work with combinations of functions with placeholders', function(assert) { assert.expect(3); var expected = [1, 2, 3, 4, 5, 6], object = { 'fn': fn }; var a = _.bindKey(object, 'fn', ph2, 2), b = _.partialRight(a, ph4, 6), c = _.partial(b, 1, ph3, 4); assert.deepEqual(c(3, 5), expected); a = _.bind(fn, object, ph1, 2); b = _.partialRight(a, ph4, 6); c = _.partial(b, 1, ph3, 4); assert.deepEqual(c(3, 5), expected); a = _.partial(fn, ph3, 2); b = _.bind(a, object, 1, ph1, 4); c = _.partialRight(b, ph4, 6); assert.deepEqual(c(3, 5), expected); }); QUnit.test('should work with combinations of functions with overlapping placeholders', function(assert) { assert.expect(3); var expected = [1, 2, 3, 4], object = { 'fn': fn }; var a = _.bindKey(object, 'fn', ph2, 2), b = _.partialRight(a, ph4, 4), c = _.partial(b, ph3, 3); assert.deepEqual(c(1), expected); a = _.bind(fn, object, ph1, 2); b = _.partialRight(a, ph4, 4); c = _.partial(b, ph3, 3); assert.deepEqual(c(1), expected); a = _.partial(fn, ph3, 2); b = _.bind(a, object, ph1, 3); c = _.partialRight(b, ph4, 4); assert.deepEqual(c(1), expected); }); QUnit.test('should work with recursively bound functions', function(assert) { assert.expect(1); var fn = function() { return this.a; }; var a = _.bind(fn, { 'a': 1 }), b = _.bind(a, { 'a': 2 }), c = _.bind(b, { 'a': 3 }); assert.strictEqual(c(), 1); }); QUnit.test('should work when hot', function(assert) { assert.expect(12); lodashStable.times(2, function(index) { var fn = function() { var result = [this]; push.apply(result, arguments); return result; }; var object = {}, bound1 = index ? _.bind(fn, object, 1) : _.bind(fn, object), expected = [object, 1, 2, 3]; var actual = _.last(lodashStable.times(HOT_COUNT, function() { var bound2 = index ? _.bind(bound1, null, 2) : _.bind(bound1); return index ? bound2(3) : bound2(1, 2, 3); })); assert.deepEqual(actual, expected); actual = _.last(lodashStable.times(HOT_COUNT, function() { var bound1 = index ? _.bind(fn, object, 1) : _.bind(fn, object), bound2 = index ? _.bind(bound1, null, 2) : _.bind(bound1); return index ? bound2(3) : bound2(1, 2, 3); })); assert.deepEqual(actual, expected); }); lodashStable.each(['curry', 'curryRight'], function(methodName, index) { var fn = function(a, b, c) { return [a, b, c]; }, curried = _[methodName](fn), expected = index ? [3, 2, 1] : [1, 2, 3]; var actual = _.last(lodashStable.times(HOT_COUNT, function() { return curried(1)(2)(3); })); assert.deepEqual(actual, expected); actual = _.last(lodashStable.times(HOT_COUNT, function() { var curried = _[methodName](fn); return curried(1)(2)(3); })); assert.deepEqual(actual, expected); }); lodashStable.each(['partial', 'partialRight'], function(methodName, index) { var func = _[methodName], fn = function() { return slice.call(arguments); }, par1 = func(fn, 1), expected = index ? [3, 2, 1] : [1, 2, 3]; var actual = _.last(lodashStable.times(HOT_COUNT, function() { var par2 = func(par1, 2); return par2(3); })); assert.deepEqual(actual, expected); actual = _.last(lodashStable.times(HOT_COUNT, function() { var par1 = func(fn, 1), par2 = func(par1, 2); return par2(3); })); assert.deepEqual(actual, expected); }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.partition'); (function() { var array = [1, 0, 1]; QUnit.test('should split elements into two groups by `predicate`', function(assert) { assert.expect(3); assert.deepEqual(_.partition([], identity), [[], []]); assert.deepEqual(_.partition(array, stubTrue), [array, []]); assert.deepEqual(_.partition(array, stubFalse), [[], array]); }); QUnit.test('should use `_.identity` when `predicate` is nullish', function(assert) { assert.expect(1); var values = [, null, undefined], expected = lodashStable.map(values, lodashStable.constant([[1, 1], [0]])); var actual = lodashStable.map(values, function(value, index) { return index ? _.partition(array, value) : _.partition(array); }); assert.deepEqual(actual, expected); }); QUnit.test('should work with `_.property` shorthands', function(assert) { assert.expect(1); var objects = [{ 'a': 1 }, { 'a': 1 }, { 'b': 2 }], actual = _.partition(objects, 'a'); assert.deepEqual(actual, [objects.slice(0, 2), objects.slice(2)]); }); QUnit.test('should work with a number for `predicate`', function(assert) { assert.expect(2); var array = [ [1, 0], [0, 1], [1, 0] ]; assert.deepEqual(_.partition(array, 0), [[array[0], array[2]], [array[1]]]); assert.deepEqual(_.partition(array, 1), [[array[1]], [array[0], array[2]]]); }); QUnit.test('should work with an object for `collection`', function(assert) { assert.expect(1); var actual = _.partition({ 'a': 1.1, 'b': 0.2, 'c': 1.3 }, Math.floor); assert.deepEqual(actual, [[1.1, 1.3], [0.2]]); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.pick'); (function() { var args = toArgs(['a', 'c']), object = { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }, nested = { 'a': 1, 'b': { 'c': 2, 'd': 3 } }; QUnit.test('should flatten `paths`', function(assert) { assert.expect(2); assert.deepEqual(_.pick(object, 'a', 'c'), { 'a': 1, 'c': 3 }); assert.deepEqual(_.pick(object, ['a', 'd'], 'c'), { 'a': 1, 'c': 3, 'd': 4 }); }); QUnit.test('should support deep paths', function(assert) { assert.expect(1); assert.deepEqual(_.pick(nested, 'b.c'), { 'b': { 'c': 2 } }); }); QUnit.test('should support path arrays', function(assert) { assert.expect(1); var object = { 'a.b': 1, 'a': { 'b': 2 } }, actual = _.pick(object, [['a.b']]); assert.deepEqual(actual, { 'a.b': 1 }); }); QUnit.test('should pick a key over a path', function(assert) { assert.expect(2); var object = { 'a.b': 1, 'a': { 'b': 2 } }; lodashStable.each(['a.b', ['a.b']], function(path) { assert.deepEqual(_.pick(object, path), { 'a.b': 1 }); }); }); QUnit.test('should coerce `paths` to strings', function(assert) { assert.expect(1); assert.deepEqual(_.pick({ '0': 'a', '1': 'b' }, 0), { '0': 'a' }); }); QUnit.test('should return an empty object when `object` is nullish', function(assert) { assert.expect(2); lodashStable.each([null, undefined], function(value) { assert.deepEqual(_.pick(value, 'valueOf'), {}); }); }); QUnit.test('should work with a primitive `object`', function(assert) { assert.expect(1); assert.deepEqual(_.pick('', 'slice'), { 'slice': ''.slice }); }); QUnit.test('should work with `arguments` object `paths`', function(assert) { assert.expect(1); assert.deepEqual(_.pick(object, args), { 'a': 1, 'c': 3 }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.pickBy'); (function() { QUnit.test('should work with a predicate argument', function(assert) { assert.expect(1); var object = { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }; var actual = _.pickBy(object, function(n) { return n == 1 || n == 3; }); assert.deepEqual(actual, { 'a': 1, 'c': 3 }); }); QUnit.test('should not treat keys with dots as deep paths', function(assert) { assert.expect(1); var object = { 'a.b.c': 1 }, actual = _.pickBy(object, stubTrue); assert.deepEqual(actual, { 'a.b.c': 1 }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('pick methods'); lodashStable.each(['pick', 'pickBy'], function(methodName) { var expected = { 'a': 1, 'c': 3 }, func = _[methodName], isPick = methodName == 'pick', object = { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }, resolve = lodashStable.nthArg(1); if (methodName == 'pickBy') { resolve = function(object, props) { props = lodashStable.castArray(props); return function(value) { return lodashStable.some(props, function(key) { key = lodashStable.isSymbol(key) ? key : lodashStable.toString(key); return object[key] === value; }); }; }; } QUnit.test('`_.' + methodName + '` should create an object of picked string keyed properties', function(assert) { assert.expect(2); assert.deepEqual(func(object, resolve(object, 'a')), { 'a': 1 }); assert.deepEqual(func(object, resolve(object, ['a', 'c'])), expected); }); QUnit.test('`_.' + methodName + '` should pick inherited string keyed properties', function(assert) { assert.expect(1); function Foo() {} Foo.prototype = object; var foo = new Foo; assert.deepEqual(func(foo, resolve(foo, ['a', 'c'])), expected); }); QUnit.test('`_.' + methodName + '` should preserve the sign of `0`', function(assert) { assert.expect(1); var object = { '-0': 'a', '0': 'b' }, props = [-0, Object(-0), 0, Object(0)], expected = [{ '-0': 'a' }, { '-0': 'a' }, { '0': 'b' }, { '0': 'b' }]; var actual = lodashStable.map(props, function(key) { return func(object, resolve(object, key)); }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should pick symbols', function(assert) { assert.expect(3); function Foo() { this[symbol] = 1; } if (Symbol) { var symbol2 = Symbol('b'); Foo.prototype[symbol2] = 2; var symbol3 = Symbol('c'); defineProperty(Foo.prototype, symbol3, { 'configurable': true, 'enumerable': false, 'writable': true, 'value': 3 }); var foo = new Foo, actual = func(foo, resolve(foo, [symbol, symbol2, symbol3])); assert.strictEqual(actual[symbol], 1); assert.strictEqual(actual[symbol2], 2); if (isPick) { assert.strictEqual(actual[symbol3], 3); } else { assert.notOk(symbol3 in actual); } } else { skipAssert(assert, 3); } }); QUnit.test('`_.' + methodName + '` should work with an array `object`', function(assert) { assert.expect(1); var array = [1, 2, 3]; assert.deepEqual(func(array, resolve(array, '1')), { '1': 2 }); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.property'); (function() { QUnit.test('should create a function that plucks a property value of a given object', function(assert) { assert.expect(4); var object = { 'a': 1 }; lodashStable.each(['a', ['a']], function(path) { var prop = _.property(path); assert.strictEqual(prop.length, 1); assert.strictEqual(prop(object), 1); }); }); QUnit.test('should pluck deep property values', function(assert) { assert.expect(2); var object = { 'a': { 'b': 2 } }; lodashStable.each(['a.b', ['a', 'b']], function(path) { var prop = _.property(path); assert.strictEqual(prop(object), 2); }); }); QUnit.test('should pluck inherited property values', function(assert) { assert.expect(2); function Foo() {} Foo.prototype.a = 1; lodashStable.each(['a', ['a']], function(path) { var prop = _.property(path); assert.strictEqual(prop(new Foo), 1); }); }); QUnit.test('should work with a non-string `path`', function(assert) { assert.expect(2); var array = [1, 2, 3]; lodashStable.each([1, [1]], function(path) { var prop = _.property(path); assert.strictEqual(prop(array), 2); }); }); QUnit.test('should preserve the sign of `0`', function(assert) { assert.expect(1); var object = { '-0': 'a', '0': 'b' }, props = [-0, Object(-0), 0, Object(0)]; var actual = lodashStable.map(props, function(key) { var prop = _.property(key); return prop(object); }); assert.deepEqual(actual, ['a', 'a', 'b', 'b']); }); QUnit.test('should coerce `path` to a string', function(assert) { assert.expect(2); function fn() {} fn.toString = lodashStable.constant('fn'); var expected = [1, 2, 3, 4], object = { 'null': 1, 'undefined': 2, 'fn': 3, '[object Object]': 4 }, paths = [null, undefined, fn, {}]; lodashStable.times(2, function(index) { var actual = lodashStable.map(paths, function(path) { var prop = _.property(index ? [path] : path); return prop(object); }); assert.deepEqual(actual, expected); }); }); QUnit.test('should pluck a key over a path', function(assert) { assert.expect(2); var object = { 'a.b': 1, 'a': { 'b': 2 } }; lodashStable.each(['a.b', ['a.b']], function(path) { var prop = _.property(path); assert.strictEqual(prop(object), 1); }); }); QUnit.test('should return `undefined` when `object` is nullish', function(assert) { assert.expect(2); var values = [, null, undefined], expected = lodashStable.map(values, noop); lodashStable.each(['constructor', ['constructor']], function(path) { var prop = _.property(path); var actual = lodashStable.map(values, function(value, index) { return index ? prop(value) : prop(); }); assert.deepEqual(actual, expected); }); }); QUnit.test('should return `undefined` for deep paths when `object` is nullish', function(assert) { assert.expect(2); var values = [, null, undefined], expected = lodashStable.map(values, noop); lodashStable.each(['constructor.prototype.valueOf', ['constructor', 'prototype', 'valueOf']], function(path) { var prop = _.property(path); var actual = lodashStable.map(values, function(value, index) { return index ? prop(value) : prop(); }); assert.deepEqual(actual, expected); }); }); QUnit.test('should return `undefined` if parts of `path` are missing', function(assert) { assert.expect(4); var object = {}; lodashStable.each(['a', 'a[1].b.c', ['a'], ['a', '1', 'b', 'c']], function(path) { var prop = _.property(path); assert.strictEqual(prop(object), undefined); }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.propertyOf'); (function() { QUnit.test('should create a function that plucks a property value of a given key', function(assert) { assert.expect(3); var object = { 'a': 1 }, propOf = _.propertyOf(object); assert.strictEqual(propOf.length, 1); lodashStable.each(['a', ['a']], function(path) { assert.strictEqual(propOf(path), 1); }); }); QUnit.test('should pluck deep property values', function(assert) { assert.expect(2); var object = { 'a': { 'b': 2 } }, propOf = _.propertyOf(object); lodashStable.each(['a.b', ['a', 'b']], function(path) { assert.strictEqual(propOf(path), 2); }); }); QUnit.test('should pluck inherited property values', function(assert) { assert.expect(2); function Foo() { this.a = 1; } Foo.prototype.b = 2; var propOf = _.propertyOf(new Foo); lodashStable.each(['b', ['b']], function(path) { assert.strictEqual(propOf(path), 2); }); }); QUnit.test('should work with a non-string `path`', function(assert) { assert.expect(2); var array = [1, 2, 3], propOf = _.propertyOf(array); lodashStable.each([1, [1]], function(path) { assert.strictEqual(propOf(path), 2); }); }); QUnit.test('should preserve the sign of `0`', function(assert) { assert.expect(1); var object = { '-0': 'a', '0': 'b' }, props = [-0, Object(-0), 0, Object(0)]; var actual = lodashStable.map(props, function(key) { var propOf = _.propertyOf(object); return propOf(key); }); assert.deepEqual(actual, ['a', 'a', 'b', 'b']); }); QUnit.test('should coerce `path` to a string', function(assert) { assert.expect(2); function fn() {} fn.toString = lodashStable.constant('fn'); var expected = [1, 2, 3, 4], object = { 'null': 1, 'undefined': 2, 'fn': 3, '[object Object]': 4 }, paths = [null, undefined, fn, {}]; lodashStable.times(2, function(index) { var actual = lodashStable.map(paths, function(path) { var propOf = _.propertyOf(object); return propOf(index ? [path] : path); }); assert.deepEqual(actual, expected); }); }); QUnit.test('should pluck a key over a path', function(assert) { assert.expect(2); var object = { 'a.b': 1, 'a': { 'b': 2 } }, propOf = _.propertyOf(object); lodashStable.each(['a.b', ['a.b']], function(path) { assert.strictEqual(propOf(path), 1); }); }); QUnit.test('should return `undefined` when `object` is nullish', function(assert) { assert.expect(2); var values = [, null, undefined], expected = lodashStable.map(values, noop); lodashStable.each(['constructor', ['constructor']], function(path) { var actual = lodashStable.map(values, function(value, index) { var propOf = index ? _.propertyOf(value) : _.propertyOf(); return propOf(path); }); assert.deepEqual(actual, expected); }); }); QUnit.test('should return `undefined` for deep paths when `object` is nullish', function(assert) { assert.expect(2); var values = [, null, undefined], expected = lodashStable.map(values, noop); lodashStable.each(['constructor.prototype.valueOf', ['constructor', 'prototype', 'valueOf']], function(path) { var actual = lodashStable.map(values, function(value, index) { var propOf = index ? _.propertyOf(value) : _.propertyOf(); return propOf(path); }); assert.deepEqual(actual, expected); }); }); QUnit.test('should return `undefined` if parts of `path` are missing', function(assert) { assert.expect(4); var propOf = _.propertyOf({}); lodashStable.each(['a', 'a[1].b.c', ['a'], ['a', '1', 'b', 'c']], function(path) { assert.strictEqual(propOf(path), undefined); }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.pullAll'); (function() { QUnit.test('should work with the same value for `array` and `values`', function(assert) { assert.expect(1); var array = [{ 'a': 1 }, { 'b': 2 }], actual = _.pullAll(array, array); assert.deepEqual(actual, []); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.pullAllBy'); (function() { QUnit.test('should accept an `iteratee`', function(assert) { assert.expect(1); var array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }]; var actual = _.pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], function(object) { return object.x; }); assert.deepEqual(actual, [{ 'x': 2 }]); }); QUnit.test('should provide correct `iteratee` arguments', function(assert) { assert.expect(1); var args, array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }]; _.pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], function() { args || (args = slice.call(arguments)); }); assert.deepEqual(args, [{ 'x': 1 }]); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.pullAllWith'); (function() { QUnit.test('should work with a `comparator`', function(assert) { assert.expect(1); var objects = [{ 'x': 1, 'y': 1 }, { 'x': 2, 'y': 2 }, { 'x': 3, 'y': 3 }], expected = [objects[0], objects[2]], actual = _.pullAllWith(objects, [{ 'x': 2, 'y': 2 }], lodashStable.isEqual); assert.deepEqual(actual, expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('pull methods'); lodashStable.each(['pull', 'pullAll', 'pullAllWith'], function(methodName) { var func = _[methodName], isPull = methodName == 'pull'; function pull(array, values) { return isPull ? func.apply(undefined, [array].concat(values)) : func(array, values); } QUnit.test('`_.' + methodName + '` should modify and return the array', function(assert) { assert.expect(2); var array = [1, 2, 3], actual = pull(array, [1, 3]); assert.strictEqual(actual, array); assert.deepEqual(array, [2]); }); QUnit.test('`_.' + methodName + '` should preserve holes in arrays', function(assert) { assert.expect(2); var array = [1, 2, 3, 4]; delete array[1]; delete array[3]; pull(array, [1]); assert.notOk('0' in array); assert.notOk('2' in array); }); QUnit.test('`_.' + methodName + '` should treat holes as `undefined`', function(assert) { assert.expect(1); var array = [1, 2, 3]; delete array[1]; pull(array, [undefined]); assert.deepEqual(array, [1, 3]); }); QUnit.test('`_.' + methodName + '` should match `NaN`', function(assert) { assert.expect(1); var array = [1, NaN, 3, NaN]; pull(array, [NaN]); assert.deepEqual(array, [1, 3]); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.pullAt'); (function() { QUnit.test('should modify the array and return removed elements', function(assert) { assert.expect(2); var array = [1, 2, 3], actual = _.pullAt(array, [0, 1]); assert.deepEqual(array, [3]); assert.deepEqual(actual, [1, 2]); }); QUnit.test('should work with unsorted indexes', function(assert) { assert.expect(2); var array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], actual = _.pullAt(array, [1, 3, 11, 7, 5, 9]); assert.deepEqual(array, [1, 3, 5, 7, 9, 11]); assert.deepEqual(actual, [2, 4, 12, 8, 6, 10]); }); QUnit.test('should work with repeated indexes', function(assert) { assert.expect(2); var array = [1, 2, 3, 4], actual = _.pullAt(array, [0, 2, 0, 1, 0, 2]); assert.deepEqual(array, [4]); assert.deepEqual(actual, [1, 3, 1, 2, 1, 3]); }); QUnit.test('should use `undefined` for nonexistent indexes', function(assert) { assert.expect(2); var array = ['a', 'b', 'c'], actual = _.pullAt(array, [2, 4, 0]); assert.deepEqual(array, ['b']); assert.deepEqual(actual, ['c', undefined, 'a']); }); QUnit.test('should flatten `indexes`', function(assert) { assert.expect(4); var array = ['a', 'b', 'c']; assert.deepEqual(_.pullAt(array, 2, 0), ['c', 'a']); assert.deepEqual(array, ['b']); array = ['a', 'b', 'c', 'd']; assert.deepEqual(_.pullAt(array, [3, 0], 2), ['d', 'a', 'c']); assert.deepEqual(array, ['b']); }); QUnit.test('should return an empty array when no indexes are given', function(assert) { assert.expect(4); var array = ['a', 'b', 'c'], actual = _.pullAt(array); assert.deepEqual(array, ['a', 'b', 'c']); assert.deepEqual(actual, []); actual = _.pullAt(array, [], []); assert.deepEqual(array, ['a', 'b', 'c']); assert.deepEqual(actual, []); }); QUnit.test('should work with non-index paths', function(assert) { assert.expect(2); var values = lodashStable.reject(empties, function(value) { return (value === 0) || lodashStable.isArray(value); }).concat(-1, 1.1); var array = lodashStable.transform(values, function(result, value) { result[value] = 1; }, []); var expected = lodashStable.map(values, stubOne), actual = _.pullAt(array, values); assert.deepEqual(actual, expected); expected = lodashStable.map(values, noop); actual = lodashStable.at(array, values); assert.deepEqual(actual, expected); }); QUnit.test('should preserve the sign of `0`', function(assert) { assert.expect(1); var props = [-0, Object(-0), 0, Object(0)]; var actual = lodashStable.map(props, function(key) { var array = [-1]; array['-0'] = -2; return _.pullAt(array, key); }); assert.deepEqual(actual, [[-2], [-2], [-1], [-1]]); }); QUnit.test('should support deep paths', function(assert) { assert.expect(3); var array = []; array.a = { 'b': 2 }; var actual = _.pullAt(array, 'a.b'); assert.deepEqual(actual, [2]); assert.deepEqual(array.a, {}); try { actual = _.pullAt(array, 'a.b.c'); } catch (e) {} assert.deepEqual(actual, [undefined]); }); QUnit.test('should work with a falsey `array` when keys are given', function(assert) { assert.expect(1); var values = falsey.slice(), expected = lodashStable.map(values, lodashStable.constant(Array(4))); var actual = lodashStable.map(values, function(array) { try { return _.pullAt(array, 0, 1, 'pop', 'push'); } catch (e) {} }); assert.deepEqual(actual, expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.random'); (function() { var array = Array(1000); QUnit.test('should return `0` or `1` when no arguments are given', function(assert) { assert.expect(1); var actual = lodashStable.uniq(lodashStable.map(array, function() { return _.random(); })).sort(); assert.deepEqual(actual, [0, 1]); }); QUnit.test('should support a `min` and `max`', function(assert) { assert.expect(1); var min = 5, max = 10; assert.ok(lodashStable.some(array, function() { var result = _.random(min, max); return result >= min && result <= max; })); }); QUnit.test('should support not providing a `max`', function(assert) { assert.expect(1); var min = 0, max = 5; assert.ok(lodashStable.some(array, function() { var result = _.random(max); return result >= min && result <= max; })); }); QUnit.test('should swap `min` and `max` when `min` > `max`', function(assert) { assert.expect(1); var min = 4, max = 2, expected = [2, 3, 4]; var actual = lodashStable.uniq(lodashStable.map(array, function() { return _.random(min, max); })).sort(); assert.deepEqual(actual, expected); }); QUnit.test('should support large integer values', function(assert) { assert.expect(2); var min = Math.pow(2, 31), max = Math.pow(2, 62); assert.ok(lodashStable.every(array, function() { var result = _.random(min, max); return result >= min && result <= max; })); assert.ok(lodashStable.some(array, function() { return _.random(MAX_INTEGER); })); }); QUnit.test('should coerce arguments to finite numbers', function(assert) { assert.expect(1); var actual = [ _.random(NaN, NaN), _.random('1', '1'), _.random(Infinity, Infinity) ]; assert.deepEqual(actual, [0, 1, MAX_INTEGER]); }); QUnit.test('should support floats', function(assert) { assert.expect(2); var min = 1.5, max = 1.6, actual = _.random(min, max); assert.ok(actual % 1); assert.ok(actual >= min && actual <= max); }); QUnit.test('should support providing a `floating`', function(assert) { assert.expect(3); var actual = _.random(true); assert.ok(actual % 1 && actual >= 0 && actual <= 1); actual = _.random(2, true); assert.ok(actual % 1 && actual >= 0 && actual <= 2); actual = _.random(2, 4, true); assert.ok(actual % 1 && actual >= 2 && actual <= 4); }); QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(1); var array = [1, 2, 3], expected = lodashStable.map(array, stubTrue), randoms = lodashStable.map(array, _.random); var actual = lodashStable.map(randoms, function(result, index) { return result >= 0 && result <= array[index] && (result % 1) == 0; }); assert.deepEqual(actual, expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('range methods'); lodashStable.each(['range', 'rangeRight'], function(methodName) { var func = _[methodName], isRange = methodName == 'range'; function resolve(range) { return isRange ? range : range.reverse(); } QUnit.test('`_.' + methodName + '` should infer the sign of `step` when only `end` is given', function(assert) { assert.expect(2); assert.deepEqual(func(4), resolve([0, 1, 2, 3])); assert.deepEqual(func(-4), resolve([0, -1, -2, -3])); }); QUnit.test('`_.' + methodName + '` should infer the sign of `step` when only `start` and `end` are given', function(assert) { assert.expect(2); assert.deepEqual(func(1, 5), resolve([1, 2, 3, 4])); assert.deepEqual(func(5, 1), resolve([5, 4, 3, 2])); }); QUnit.test('`_.' + methodName + '` should work with a `start`, `end`, and `step`', function(assert) { assert.expect(3); assert.deepEqual(func(0, -4, -1), resolve([0, -1, -2, -3])); assert.deepEqual(func(5, 1, -1), resolve([5, 4, 3, 2])); assert.deepEqual(func(0, 20, 5), resolve([0, 5, 10, 15])); }); QUnit.test('`_.' + methodName + '` should support a `step` of `0`', function(assert) { assert.expect(1); assert.deepEqual(func(1, 4, 0), [1, 1, 1]); }); QUnit.test('`_.' + methodName + '` should work with a `step` larger than `end`', function(assert) { assert.expect(1); assert.deepEqual(func(1, 5, 20), [1]); }); QUnit.test('`_.' + methodName + '` should work with a negative `step`', function(assert) { assert.expect(2); assert.deepEqual(func(0, -4, -1), resolve([0, -1, -2, -3])); assert.deepEqual(func(21, 10, -3), resolve([21, 18, 15, 12])); }); QUnit.test('`_.' + methodName + '` should support `start` of `-0`', function(assert) { assert.expect(1); var actual = func(-0, 1); assert.strictEqual(1 / actual[0], -Infinity); }); QUnit.test('`_.' + methodName + '` should treat falsey `start` as `0`', function(assert) { assert.expect(13); lodashStable.each(falsey, function(value, index) { if (index) { assert.deepEqual(func(value), []); assert.deepEqual(func(value, 1), [0]); } else { assert.deepEqual(func(), []); } }); }); QUnit.test('`_.' + methodName + '` should coerce arguments to finite numbers', function(assert) { assert.expect(1); var actual = [ func('1'), func('0', 1), func(0, 1, '1'), func(NaN), func(NaN, NaN) ]; assert.deepEqual(actual, [[0], [0], [0], [], []]); }); QUnit.test('`_.' + methodName + '` should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(2); var array = [1, 2, 3], object = { 'a': 1, 'b': 2, 'c': 3 }, expected = lodashStable.map([[0], [0, 1], [0, 1, 2]], resolve); lodashStable.each([array, object], function(collection) { var actual = lodashStable.map(collection, func); assert.deepEqual(actual, expected); }); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.rearg'); (function() { function fn() { return slice.call(arguments); } QUnit.test('should reorder arguments provided to `func`', function(assert) { assert.expect(1); var rearged = _.rearg(fn, [2, 0, 1]); assert.deepEqual(rearged('b', 'c', 'a'), ['a', 'b', 'c']); }); QUnit.test('should work with repeated indexes', function(assert) { assert.expect(1); var rearged = _.rearg(fn, [1, 1, 1]); assert.deepEqual(rearged('c', 'a', 'b'), ['a', 'a', 'a']); }); QUnit.test('should use `undefined` for nonexistent indexes', function(assert) { assert.expect(1); var rearged = _.rearg(fn, [1, 4]); assert.deepEqual(rearged('b', 'a', 'c'), ['a', undefined, 'c']); }); QUnit.test('should use `undefined` for non-index values', function(assert) { assert.expect(1); var values = lodashStable.reject(empties, function(value) { return (value === 0) || lodashStable.isArray(value); }).concat(-1, 1.1); var expected = lodashStable.map(values, lodashStable.constant([undefined, 'b', 'c'])); var actual = lodashStable.map(values, function(value) { var rearged = _.rearg(fn, [value]); return rearged('a', 'b', 'c'); }); assert.deepEqual(actual, expected); }); QUnit.test('should not rearrange arguments when no indexes are given', function(assert) { assert.expect(2); var rearged = _.rearg(fn); assert.deepEqual(rearged('a', 'b', 'c'), ['a', 'b', 'c']); rearged = _.rearg(fn, [], []); assert.deepEqual(rearged('a', 'b', 'c'), ['a', 'b', 'c']); }); QUnit.test('should accept multiple index arguments', function(assert) { assert.expect(1); var rearged = _.rearg(fn, 2, 0, 1); assert.deepEqual(rearged('b', 'c', 'a'), ['a', 'b', 'c']); }); QUnit.test('should accept multiple arrays of indexes', function(assert) { assert.expect(1); var rearged = _.rearg(fn, [2], [0, 1]); assert.deepEqual(rearged('b', 'c', 'a'), ['a', 'b', 'c']); }); QUnit.test('should work with fewer indexes than arguments', function(assert) { assert.expect(1); var rearged = _.rearg(fn, [1, 0]); assert.deepEqual(rearged('b', 'a', 'c'), ['a', 'b', 'c']); }); QUnit.test('should work on functions that have been rearged', function(assert) { assert.expect(1); var rearged1 = _.rearg(fn, 2, 1, 0), rearged2 = _.rearg(rearged1, 1, 0, 2); assert.deepEqual(rearged2('b', 'c', 'a'), ['a', 'b', 'c']); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.reduce'); (function() { var array = [1, 2, 3]; QUnit.test('should use the first element of a collection as the default `accumulator`', function(assert) { assert.expect(1); assert.strictEqual(_.reduce(array), 1); }); QUnit.test('should provide correct `iteratee` arguments when iterating an array', function(assert) { assert.expect(2); var args; _.reduce(array, function() { args || (args = slice.call(arguments)); }, 0); assert.deepEqual(args, [0, 1, 0, array]); args = undefined; _.reduce(array, function() { args || (args = slice.call(arguments)); }); assert.deepEqual(args, [1, 2, 1, array]); }); QUnit.test('should provide correct `iteratee` arguments when iterating an object', function(assert) { assert.expect(2); var args, object = { 'a': 1, 'b': 2 }, firstKey = _.head(_.keys(object)); var expected = firstKey == 'a' ? [0, 1, 'a', object] : [0, 2, 'b', object]; _.reduce(object, function() { args || (args = slice.call(arguments)); }, 0); assert.deepEqual(args, expected); args = undefined; expected = firstKey == 'a' ? [1, 2, 'b', object] : [2, 1, 'a', object]; _.reduce(object, function() { args || (args = slice.call(arguments)); }); assert.deepEqual(args, expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.reduceRight'); (function() { var array = [1, 2, 3]; QUnit.test('should use the last element of a collection as the default `accumulator`', function(assert) { assert.expect(1); assert.strictEqual(_.reduceRight(array), 3); }); QUnit.test('should provide correct `iteratee` arguments when iterating an array', function(assert) { assert.expect(2); var args; _.reduceRight(array, function() { args || (args = slice.call(arguments)); }, 0); assert.deepEqual(args, [0, 3, 2, array]); args = undefined; _.reduceRight(array, function() { args || (args = slice.call(arguments)); }); assert.deepEqual(args, [3, 2, 1, array]); }); QUnit.test('should provide correct `iteratee` arguments when iterating an object', function(assert) { assert.expect(2); var args, object = { 'a': 1, 'b': 2 }, isFIFO = lodashStable.keys(object)[0] == 'a'; var expected = isFIFO ? [0, 2, 'b', object] : [0, 1, 'a', object]; _.reduceRight(object, function() { args || (args = slice.call(arguments)); }, 0); assert.deepEqual(args, expected); args = undefined; expected = isFIFO ? [2, 1, 'a', object] : [1, 2, 'b', object]; _.reduceRight(object, function() { args || (args = slice.call(arguments)); }); assert.deepEqual(args, expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('reduce methods'); lodashStable.each(['reduce', 'reduceRight'], function(methodName) { var func = _[methodName], array = [1, 2, 3], isReduce = methodName == 'reduce'; QUnit.test('`_.' + methodName + '` should reduce a collection to a single value', function(assert) { assert.expect(1); var actual = func(['a', 'b', 'c'], function(accumulator, value) { return accumulator + value; }, ''); assert.strictEqual(actual, isReduce ? 'abc' : 'cba'); }); QUnit.test('`_.' + methodName + '` should support empty collections without an initial `accumulator` value', function(assert) { assert.expect(1); var actual = [], expected = lodashStable.map(empties, noop); lodashStable.each(empties, function(value) { try { actual.push(func(value, noop)); } catch (e) {} }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should support empty collections with an initial `accumulator` value', function(assert) { assert.expect(1); var expected = lodashStable.map(empties, lodashStable.constant('x')); var actual = lodashStable.map(empties, function(value) { try { return func(value, noop, 'x'); } catch (e) {} }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should handle an initial `accumulator` value of `undefined`', function(assert) { assert.expect(1); var actual = func([], noop, undefined); assert.strictEqual(actual, undefined); }); QUnit.test('`_.' + methodName + '` should return `undefined` for empty collections when no `accumulator` is given (test in IE > 9 and modern browsers)', function(assert) { assert.expect(2); var array = [], object = { '0': 1, 'length': 0 }; if ('__proto__' in array) { array.__proto__ = object; assert.strictEqual(func(array, noop), undefined); } else { skipAssert(assert); } assert.strictEqual(func(object, noop), undefined); }); QUnit.test('`_.' + methodName + '` should return an unwrapped value when implicitly chaining', function(assert) { assert.expect(1); if (!isNpm) { assert.strictEqual(_(array)[methodName](add), 6); } else { skipAssert(assert); } }); QUnit.test('`_.' + methodName + '` should return a wrapped value when explicitly chaining', function(assert) { assert.expect(1); if (!isNpm) { assert.ok(_(array).chain()[methodName](add) instanceof _); } else { skipAssert(assert); } }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.reject'); (function() { var array = [1, 2, 3]; QUnit.test('should return elements the `predicate` returns falsey for', function(assert) { assert.expect(1); assert.deepEqual(_.reject(array, isEven), [1, 3]); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('filter methods'); lodashStable.each(['filter', 'reject'], function(methodName) { var array = [1, 2, 3, 4], func = _[methodName], isFilter = methodName == 'filter', objects = [{ 'a': 0 }, { 'a': 1 }]; QUnit.test('`_.' + methodName + '` should not modify the resulting value from within `predicate`', function(assert) { assert.expect(1); var actual = func([0], function(value, index, array) { array[index] = 1; return isFilter; }); assert.deepEqual(actual, [0]); }); QUnit.test('`_.' + methodName + '` should work with `_.property` shorthands', function(assert) { assert.expect(1); assert.deepEqual(func(objects, 'a'), [objects[isFilter ? 1 : 0]]); }); QUnit.test('`_.' + methodName + '` should work with `_.matches` shorthands', function(assert) { assert.expect(1); assert.deepEqual(func(objects, objects[1]), [objects[isFilter ? 1 : 0]]); }); QUnit.test('`_.' + methodName + '` should not modify wrapped values', function(assert) { assert.expect(2); if (!isNpm) { var wrapped = _(array); var actual = wrapped[methodName](function(n) { return n < 3; }); assert.deepEqual(actual.value(), isFilter ? [1, 2] : [3, 4]); actual = wrapped[methodName](function(n) { return n > 2; }); assert.deepEqual(actual.value(), isFilter ? [3, 4] : [1, 2]); } else { skipAssert(assert, 2); } }); QUnit.test('`_.' + methodName + '` should work in a lazy sequence', function(assert) { assert.expect(2); if (!isNpm) { var array = lodashStable.range(LARGE_ARRAY_SIZE + 1), predicate = function(value) { return isFilter ? isEven(value) : !isEven(value); }; var object = lodashStable.zipObject(lodashStable.times(LARGE_ARRAY_SIZE, function(index) { return ['key' + index, index]; })); var actual = _(array).slice(1).map(square)[methodName](predicate).value(); assert.deepEqual(actual, _[methodName](lodashStable.map(array.slice(1), square), predicate)); actual = _(object).mapValues(square)[methodName](predicate).value(); assert.deepEqual(actual, _[methodName](lodashStable.mapValues(object, square), predicate)); } else { skipAssert(assert, 2); } }); QUnit.test('`_.' + methodName + '` should provide correct `predicate` arguments in a lazy sequence', function(assert) { assert.expect(5); if (!isNpm) { var args, array = lodashStable.range(LARGE_ARRAY_SIZE + 1), expected = [1, 0, lodashStable.map(array.slice(1), square)]; _(array).slice(1)[methodName](function(value, index, array) { args || (args = slice.call(arguments)); }).value(); assert.deepEqual(args, [1, 0, array.slice(1)]); args = undefined; _(array).slice(1).map(square)[methodName](function(value, index, array) { args || (args = slice.call(arguments)); }).value(); assert.deepEqual(args, expected); args = undefined; _(array).slice(1).map(square)[methodName](function(value, index) { args || (args = slice.call(arguments)); }).value(); assert.deepEqual(args, expected); args = undefined; _(array).slice(1).map(square)[methodName](function(value) { args || (args = slice.call(arguments)); }).value(); assert.deepEqual(args, [1]); args = undefined; _(array).slice(1).map(square)[methodName](function() { args || (args = slice.call(arguments)); }).value(); assert.deepEqual(args, expected); } else { skipAssert(assert, 5); } }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.remove'); (function() { QUnit.test('should modify the array and return removed elements', function(assert) { assert.expect(2); var array = [1, 2, 3, 4], actual = _.remove(array, isEven); assert.deepEqual(array, [1, 3]); assert.deepEqual(actual, [2, 4]); }); QUnit.test('should provide correct `predicate` arguments', function(assert) { assert.expect(1); var argsList = [], array = [1, 2, 3], clone = array.slice(); _.remove(array, function(n, index) { var args = slice.call(arguments); args[2] = args[2].slice(); argsList.push(args); return isEven(index); }); assert.deepEqual(argsList, [[1, 0, clone], [2, 1, clone], [3, 2, clone]]); }); QUnit.test('should work with `_.matches` shorthands', function(assert) { assert.expect(1); var objects = [{ 'a': 0, 'b': 1 }, { 'a': 1, 'b': 2 }]; _.remove(objects, { 'a': 1 }); assert.deepEqual(objects, [{ 'a': 0, 'b': 1 }]); }); QUnit.test('should work with `_.matchesProperty` shorthands', function(assert) { assert.expect(1); var objects = [{ 'a': 0, 'b': 1 }, { 'a': 1, 'b': 2 }]; _.remove(objects, ['a', 1]); assert.deepEqual(objects, [{ 'a': 0, 'b': 1 }]); }); QUnit.test('should work with `_.property` shorthands', function(assert) { assert.expect(1); var objects = [{ 'a': 0 }, { 'a': 1 }]; _.remove(objects, 'a'); assert.deepEqual(objects, [{ 'a': 0 }]); }); QUnit.test('should preserve holes in arrays', function(assert) { assert.expect(2); var array = [1, 2, 3, 4]; delete array[1]; delete array[3]; _.remove(array, function(n) { return n === 1; }); assert.notOk('0' in array); assert.notOk('2' in array); }); QUnit.test('should treat holes as `undefined`', function(assert) { assert.expect(1); var array = [1, 2, 3]; delete array[1]; _.remove(array, function(n) { return n == null; }); assert.deepEqual(array, [1, 3]); }); QUnit.test('should not mutate the array until all elements to remove are determined', function(assert) { assert.expect(1); var array = [1, 2, 3]; _.remove(array, function(n, index) { return isEven(index); }); assert.deepEqual(array, [2]); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.repeat'); (function() { var string = 'abc'; QUnit.test('should repeat a string `n` times', function(assert) { assert.expect(2); assert.strictEqual(_.repeat('*', 3), '***'); assert.strictEqual(_.repeat(string, 2), 'abcabc'); }); QUnit.test('should treat falsey `n` values, except `undefined`, as `0`', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, function(value) { return value === undefined ? string : ''; }); var actual = lodashStable.map(falsey, function(n, index) { return index ? _.repeat(string, n) : _.repeat(string); }); assert.deepEqual(actual, expected); }); QUnit.test('should return an empty string if `n` is <= `0`', function(assert) { assert.expect(2); assert.strictEqual(_.repeat(string, 0), ''); assert.strictEqual(_.repeat(string, -2), ''); }); QUnit.test('should coerce `n` to an integer', function(assert) { assert.expect(3); assert.strictEqual(_.repeat(string, '2'), 'abcabc'); assert.strictEqual(_.repeat(string, 2.6), 'abcabc'); assert.strictEqual(_.repeat('*', { 'valueOf': stubThree }), '***'); }); QUnit.test('should coerce `string` to a string', function(assert) { assert.expect(2); assert.strictEqual(_.repeat(Object(string), 2), 'abcabc'); assert.strictEqual(_.repeat({ 'toString': lodashStable.constant('*') }, 3), '***'); }); QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(1); var actual = lodashStable.map(['a', 'b', 'c'], _.repeat); assert.deepEqual(actual, ['a', 'b', 'c']); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.replace'); (function() { QUnit.test('should replace the matched pattern', function(assert) { assert.expect(2); var string = 'abcde'; assert.strictEqual(_.replace(string, 'de', '123'), 'abc123'); assert.strictEqual(_.replace(string, /[bd]/g, '-'), 'a-c-e'); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.result'); (function() { var object = { 'a': 1, 'b': stubB }; QUnit.test('should invoke function values', function(assert) { assert.expect(1); assert.strictEqual(_.result(object, 'b'), 'b'); }); QUnit.test('should invoke default function values', function(assert) { assert.expect(1); var actual = _.result(object, 'c', object.b); assert.strictEqual(actual, 'b'); }); QUnit.test('should invoke nested function values', function(assert) { assert.expect(2); var value = { 'a': lodashStable.constant({ 'b': stubB }) }; lodashStable.each(['a.b', ['a', 'b']], function(path) { assert.strictEqual(_.result(value, path), 'b'); }); }); QUnit.test('should invoke deep property methods with the correct `this` binding', function(assert) { assert.expect(2); var value = { 'a': { 'b': function() { return this.c; }, 'c': 1 } }; lodashStable.each(['a.b', ['a', 'b']], function(path) { assert.strictEqual(_.result(value, path), 1); }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.get and lodash.result'); lodashStable.each(['get', 'result'], function(methodName) { var func = _[methodName]; QUnit.test('`_.' + methodName + '` should get string keyed property values', function(assert) { assert.expect(2); var object = { 'a': 1 }; lodashStable.each(['a', ['a']], function(path) { assert.strictEqual(func(object, path), 1); }); }); QUnit.test('`_.' + methodName + '` should preserve the sign of `0`', function(assert) { assert.expect(1); var object = { '-0': 'a', '0': 'b' }, props = [-0, Object(-0), 0, Object(0)]; var actual = lodashStable.map(props, function(key) { return func(object, key); }); assert.deepEqual(actual, ['a', 'a', 'b', 'b']); }); QUnit.test('`_.' + methodName + '` should get symbol keyed property values', function(assert) { assert.expect(1); if (Symbol) { var object = {}; object[symbol] = 1; assert.strictEqual(func(object, symbol), 1); } else { skipAssert(assert); } }); QUnit.test('`_.' + methodName + '` should get deep property values', function(assert) { assert.expect(2); var object = { 'a': { 'b': 2 } }; lodashStable.each(['a.b', ['a', 'b']], function(path) { assert.strictEqual(func(object, path), 2); }); }); QUnit.test('`_.' + methodName + '` should get a key over a path', function(assert) { assert.expect(2); var object = { 'a.b': 1, 'a': { 'b': 2 } }; lodashStable.each(['a.b', ['a.b']], function(path) { assert.strictEqual(func(object, path), 1); }); }); QUnit.test('`_.' + methodName + '` should not coerce array paths to strings', function(assert) { assert.expect(1); var object = { 'a,b,c': 3, 'a': { 'b': { 'c': 4 } } }; assert.strictEqual(func(object, ['a', 'b', 'c']), 4); }); QUnit.test('`_.' + methodName + '` should not ignore empty brackets', function(assert) { assert.expect(1); var object = { 'a': { '': 1 } }; assert.strictEqual(func(object, 'a[]'), 1); }); QUnit.test('`_.' + methodName + '` should handle empty paths', function(assert) { assert.expect(4); lodashStable.each([['', ''], [[], ['']]], function(pair) { assert.strictEqual(func({}, pair[0]), undefined); assert.strictEqual(func({ '': 3 }, pair[1]), 3); }); }); QUnit.test('`_.' + methodName + '` should handle complex paths', function(assert) { assert.expect(2); var object = { 'a': { '-1.23': { '["b"]': { 'c': { "['d']": { '\ne\n': { 'f': { 'g': 8 } } } } } } } }; var paths = [ 'a[-1.23]["[\\"b\\"]"].c[\'[\\\'d\\\']\'][\ne\n][f].g', ['a', '-1.23', '["b"]', 'c', "['d']", '\ne\n', 'f', 'g'] ]; lodashStable.each(paths, function(path) { assert.strictEqual(func(object, path), 8); }); }); QUnit.test('`_.' + methodName + '` should return `undefined` when `object` is nullish', function(assert) { assert.expect(4); lodashStable.each(['constructor', ['constructor']], function(path) { assert.strictEqual(func(null, path), undefined); assert.strictEqual(func(undefined, path), undefined); }); }); QUnit.test('`_.' + methodName + '` should return `undefined` for deep paths when `object` is nullish', function(assert) { assert.expect(2); var values = [null, undefined], expected = lodashStable.map(values, noop), paths = ['constructor.prototype.valueOf', ['constructor', 'prototype', 'valueOf']]; lodashStable.each(paths, function(path) { var actual = lodashStable.map(values, function(value) { return func(value, path); }); assert.deepEqual(actual, expected); }); }); QUnit.test('`_.' + methodName + '` should return `undefined` if parts of `path` are missing', function(assert) { assert.expect(2); var object = { 'a': [, null] }; lodashStable.each(['a[1].b.c', ['a', '1', 'b', 'c']], function(path) { assert.strictEqual(func(object, path), undefined); }); }); QUnit.test('`_.' + methodName + '` should be able to return `null` values', function(assert) { assert.expect(2); var object = { 'a': { 'b': null } }; lodashStable.each(['a.b', ['a', 'b']], function(path) { assert.strictEqual(func(object, path), null); }); }); QUnit.test('`_.' + methodName + '` should follow `path` over non-plain objects', function(assert) { assert.expect(2); var paths = ['a.b', ['a', 'b']]; lodashStable.each(paths, function(path) { numberProto.a = { 'b': 2 }; assert.strictEqual(func(0, path), 2); delete numberProto.a; }); }); QUnit.test('`_.' + methodName + '` should return the default value for `undefined` values', function(assert) { assert.expect(2); var object = { 'a': {} }, values = empties.concat(true, new Date, 1, /x/, 'a'), expected = lodashStable.map(values, function(value) { return [value, value]; }); lodashStable.each(['a.b', ['a', 'b']], function(path) { var actual = lodashStable.map(values, function(value) { return [func(object, path, value), func(null, path, value)]; }); assert.deepEqual(actual, expected); }); }); QUnit.test('`_.' + methodName + '` should return the default value when `path` is empty', function(assert) { assert.expect(1); assert.strictEqual(func({}, [], 'a'), 'a'); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.rest'); (function() { function fn(a, b, c) { return slice.call(arguments); } QUnit.test('should apply a rest parameter to `func`', function(assert) { assert.expect(1); var rest = _.rest(fn); assert.deepEqual(rest(1, 2, 3, 4), [1, 2, [3, 4]]); }); QUnit.test('should work with `start`', function(assert) { assert.expect(1); var rest = _.rest(fn, 1); assert.deepEqual(rest(1, 2, 3, 4), [1, [2, 3, 4]]); }); QUnit.test('should treat `start` as `0` for `NaN` or negative values', function(assert) { assert.expect(1); var values = [-1, NaN, 'a'], expected = lodashStable.map(values, lodashStable.constant([[1, 2, 3, 4]])); var actual = lodashStable.map(values, function(value) { var rest = _.rest(fn, value); return rest(1, 2, 3, 4); }); assert.deepEqual(actual, expected); }); QUnit.test('should coerce `start` to an integer', function(assert) { assert.expect(1); var rest = _.rest(fn, 1.6); assert.deepEqual(rest(1, 2, 3), [1, [2, 3]]); }); QUnit.test('should use an empty array when `start` is not reached', function(assert) { assert.expect(1); var rest = _.rest(fn); assert.deepEqual(rest(1), [1, undefined, []]); }); QUnit.test('should work on functions with more than three parameters', function(assert) { assert.expect(1); var rest = _.rest(function(a, b, c, d) { return slice.call(arguments); }); assert.deepEqual(rest(1, 2, 3, 4, 5), [1, 2, 3, [4, 5]]); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.reverse'); (function() { var largeArray = lodashStable.range(LARGE_ARRAY_SIZE).concat(null), smallArray = [0, 1, 2, null]; QUnit.test('should reverse `array`', function(assert) { assert.expect(2); var array = [1, 2, 3], actual = _.reverse(array); assert.strictEqual(actual, array); assert.deepEqual(array, [3, 2, 1]); }); QUnit.test('should return the wrapped reversed `array`', function(assert) { assert.expect(6); if (!isNpm) { lodashStable.times(2, function(index) { var array = (index ? largeArray : smallArray).slice(), clone = array.slice(), wrapped = _(array).reverse(), actual = wrapped.value(); assert.ok(wrapped instanceof _); assert.strictEqual(actual, array); assert.deepEqual(actual, clone.slice().reverse()); }); } else { skipAssert(assert, 6); } }); QUnit.test('should work in a lazy sequence', function(assert) { assert.expect(4); if (!isNpm) { lodashStable.times(2, function(index) { var array = (index ? largeArray : smallArray).slice(), expected = array.slice(), actual = _(array).slice(1).reverse().value(); assert.deepEqual(actual, expected.slice(1).reverse()); assert.deepEqual(array, expected); }); } else { skipAssert(assert, 4); } }); QUnit.test('should be lazy when in a lazy sequence', function(assert) { assert.expect(3); if (!isNpm) { var spy = { 'toString': function() { throw new Error('spy was revealed'); } }; var array = largeArray.concat(spy), expected = array.slice(); try { var wrapped = _(array).slice(1).map(String).reverse(), actual = wrapped.last(); } catch (e) {} assert.ok(wrapped instanceof _); assert.strictEqual(actual, '1'); assert.deepEqual(array, expected); } else { skipAssert(assert, 3); } }); QUnit.test('should work in a hybrid sequence', function(assert) { assert.expect(8); if (!isNpm) { lodashStable.times(2, function(index) { var clone = (index ? largeArray : smallArray).slice(); lodashStable.each(['map', 'filter'], function(methodName) { var array = clone.slice(), expected = clone.slice(1, -1).reverse(), actual = _(array)[methodName](identity).thru(_.compact).reverse().value(); assert.deepEqual(actual, expected); array = clone.slice(); actual = _(array).thru(_.compact)[methodName](identity).pull(1).push(3).reverse().value(); assert.deepEqual(actual, [3].concat(expected.slice(0, -1))); }); }); } else { skipAssert(assert, 8); } }); QUnit.test('should track the `__chain__` value of a wrapper', function(assert) { assert.expect(6); if (!isNpm) { lodashStable.times(2, function(index) { var array = (index ? largeArray : smallArray).slice(), expected = array.slice().reverse(), wrapped = _(array).chain().reverse().head(); assert.ok(wrapped instanceof _); assert.strictEqual(wrapped.value(), _.head(expected)); assert.deepEqual(array, expected); }); } else { skipAssert(assert, 6); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('round methods'); lodashStable.each(['ceil', 'floor', 'round'], function(methodName) { var func = _[methodName], isCeil = methodName == 'ceil', isFloor = methodName == 'floor'; QUnit.test('`_.' + methodName + '` should return a rounded number without a precision', function(assert) { assert.expect(1); var actual = func(4.006); assert.strictEqual(actual, isCeil ? 5 : 4); }); QUnit.test('`_.' + methodName + '` should work with a precision of `0`', function(assert) { assert.expect(1); var actual = func(4.006, 0); assert.strictEqual(actual, isCeil ? 5 : 4); }); QUnit.test('`_.' + methodName + '` should work with a positive precision', function(assert) { assert.expect(2); var actual = func(4.016, 2); assert.strictEqual(actual, isFloor ? 4.01 : 4.02); actual = func(4.1, 2); assert.strictEqual(actual, 4.1); }); QUnit.test('`_.' + methodName + '` should work with a negative precision', function(assert) { assert.expect(1); var actual = func(4160, -2); assert.strictEqual(actual, isFloor ? 4100 : 4200); }); QUnit.test('`_.' + methodName + '` should coerce `precision` to an integer', function(assert) { assert.expect(3); var actual = func(4.006, NaN); assert.strictEqual(actual, isCeil ? 5 : 4); var expected = isFloor ? 4.01 : 4.02; actual = func(4.016, 2.6); assert.strictEqual(actual, expected); actual = func(4.016, '+2'); assert.strictEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should work with exponential notation and `precision`', function(assert) { assert.expect(3); var actual = func(5e1, 2); assert.deepEqual(actual, 50); actual = func('5e', 1); assert.deepEqual(actual, NaN); actual = func('5e1e1', 1); assert.deepEqual(actual, NaN); }); QUnit.test('`_.' + methodName + '` should preserve the sign of `0`', function(assert) { assert.expect(1); var values = [[0], [-0], ['0'], ['-0'], [0, 1], [-0, 1], ['0', 1], ['-0', 1]], expected = [Infinity, -Infinity, Infinity, -Infinity, Infinity, -Infinity, Infinity, -Infinity]; var actual = lodashStable.map(values, function(args) { return 1 / func.apply(undefined, args); }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should not return `NaN` for large `precision` values', function(assert) { assert.expect(1); var results = [ _.round(10.0000001, 1000), _.round(MAX_SAFE_INTEGER, 293) ]; var expected = lodashStable.map(results, stubFalse), actual = lodashStable.map(results, lodashStable.isNaN); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should return `Infinity` given `Infinity` regardless of `precision`', function(assert) { assert.expect(6); var actual = func(Infinity); assert.strictEqual(actual, Infinity); actual = func(Infinity, 0); assert.strictEqual(actual, Infinity); actual = func(Infinity, 2); assert.strictEqual(actual, Infinity); actual = func(Infinity, -2); assert.strictEqual(actual, Infinity); actual = func(Infinity, 2); assert.strictEqual(actual, isFloor ? Infinity : Infinity); actual = func(Infinity, 2); assert.strictEqual(actual, isCeil ? Infinity : Infinity); }); QUnit.test('`_.' + methodName + '` should return `-Infinity` given `-Infinity` regardless of `precision`', function(assert) { assert.expect(6); var actual = func(-Infinity); assert.strictEqual(actual, -Infinity); actual = func(-Infinity, 0); assert.strictEqual(actual, -Infinity); actual = func(-Infinity, 2); assert.strictEqual(actual, -Infinity); actual = func(-Infinity, -2); assert.strictEqual(actual, -Infinity); actual = func(-Infinity, 2); assert.strictEqual(actual, isFloor ? -Infinity : -Infinity); actual = func(-Infinity, 2); assert.strictEqual(actual, isCeil ? -Infinity : -Infinity); }); QUnit.test('`_.' + methodName + '` should return `NaN` given `NaN` regardless of `precision`', function(assert) { assert.expect(6); var actual = func(NaN); assert.deepEqual(actual, NaN); actual = func(NaN, 0); assert.deepEqual(actual, NaN); actual = func(NaN, 2); assert.deepEqual(actual, NaN); actual = func(NaN, -2); assert.deepEqual(actual, NaN); actual = func(NaN, 2); assert.deepEqual(actual, isFloor ? NaN : NaN); actual = func(NaN, 2); assert.deepEqual(actual, isCeil ? NaN : NaN); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.runInContext'); (function() { QUnit.test('should not require a fully populated `context` object', function(assert) { assert.expect(1); if (!isModularize) { var lodash = _.runInContext({ 'setTimeout': function(func) { func(); } }); var pass = false; lodash.delay(function() { pass = true; }, 32); assert.ok(pass); } else { skipAssert(assert); } }); QUnit.test('should use a zeroed `_.uniqueId` counter', function(assert) { assert.expect(3); if (!isModularize) { lodashStable.times(2, _.uniqueId); var oldId = Number(_.uniqueId()), lodash = _.runInContext(); assert.ok(_.uniqueId() > oldId); var id = lodash.uniqueId(); assert.strictEqual(id, '1'); assert.ok(id < oldId); } else { skipAssert(assert, 3); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.sample'); (function() { var array = [1, 2, 3]; QUnit.test('should return a random element', function(assert) { assert.expect(1); var actual = _.sample(array); assert.ok(lodashStable.includes(array, actual)); }); QUnit.test('should return `undefined` when sampling empty collections', function(assert) { assert.expect(1); var expected = lodashStable.map(empties, noop); var actual = lodashStable.transform(empties, function(result, value) { try { result.push(_.sample(value)); } catch (e) {} }); assert.deepEqual(actual, expected); }); QUnit.test('should sample an object', function(assert) { assert.expect(1); var object = { 'a': 1, 'b': 2, 'c': 3 }, actual = _.sample(object); assert.ok(lodashStable.includes(array, actual)); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.sampleSize'); (function() { var array = [1, 2, 3]; QUnit.test('should return an array of random elements', function(assert) { assert.expect(2); var actual = _.sampleSize(array, 2); assert.strictEqual(actual.length, 2); assert.deepEqual(lodashStable.difference(actual, array), []); }); QUnit.test('should contain elements of the collection', function(assert) { assert.expect(1); var actual = _.sampleSize(array, array.length).sort(); assert.deepEqual(actual, array); }); QUnit.test('should treat falsey `size` values, except `undefined`, as `0`', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, function(value) { return value === undefined ? ['a'] : []; }); var actual = lodashStable.map(falsey, function(size, index) { return index ? _.sampleSize(['a'], size) : _.sampleSize(['a']); }); assert.deepEqual(actual, expected); }); QUnit.test('should return an empty array when `n` < `1` or `NaN`', function(assert) { assert.expect(3); lodashStable.each([0, -1, -Infinity], function(n) { assert.deepEqual(_.sampleSize(array, n), []); }); }); QUnit.test('should return all elements when `n` >= `length`', function(assert) { assert.expect(4); lodashStable.each([3, 4, Math.pow(2, 32), Infinity], function(n) { var actual = _.sampleSize(array, n).sort(); assert.deepEqual(actual, array); }); }); QUnit.test('should coerce `n` to an integer', function(assert) { assert.expect(1); var actual = _.sampleSize(array, 1.6); assert.strictEqual(actual.length, 1); }); QUnit.test('should return an empty array for empty collections', function(assert) { assert.expect(1); var expected = lodashStable.map(empties, stubArray); var actual = lodashStable.transform(empties, function(result, value) { try { result.push(_.sampleSize(value, 1)); } catch (e) {} }); assert.deepEqual(actual, expected); }); QUnit.test('should sample an object', function(assert) { assert.expect(2); var object = { 'a': 1, 'b': 2, 'c': 3 }, actual = _.sampleSize(object, 2); assert.strictEqual(actual.length, 2); assert.deepEqual(lodashStable.difference(actual, lodashStable.values(object)), []); }); QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(1); var actual = lodashStable.map([['a']], _.sampleSize); assert.deepEqual(actual, [['a']]); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.setWith'); (function() { QUnit.test('should work with a `customizer` callback', function(assert) { assert.expect(1); var actual = _.setWith({ '0': {} }, '[0][1][2]', 3, function(value) { return lodashStable.isObject(value) ? undefined : {}; }); assert.deepEqual(actual, { '0': { '1': { '2': 3 } } }); }); QUnit.test('should work with a `customizer` that returns `undefined`', function(assert) { assert.expect(1); var actual = _.setWith({}, 'a[0].b.c', 4, noop); assert.deepEqual(actual, { 'a': [{ 'b': { 'c': 4 } }] }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('set methods'); lodashStable.each(['update', 'updateWith', 'set', 'setWith'], function(methodName) { var func = _[methodName], isUpdate = /^update/.test(methodName); var oldValue = 1, value = 2, updater = isUpdate ? lodashStable.constant(value) : value; QUnit.test('`_.' + methodName + '` should set property values', function(assert) { assert.expect(4); lodashStable.each(['a', ['a']], function(path) { var object = { 'a': oldValue }, actual = func(object, path, updater); assert.strictEqual(actual, object); assert.strictEqual(object.a, value); }); }); QUnit.test('`_.' + methodName + '` should preserve the sign of `0`', function(assert) { assert.expect(1); var props = [-0, Object(-0), 0, Object(0)], expected = lodashStable.map(props, lodashStable.constant(value)); var actual = lodashStable.map(props, function(key) { var object = { '-0': 'a', '0': 'b' }; func(object, key, updater); return object[lodashStable.toString(key)]; }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should unset symbol keyed property values', function(assert) { assert.expect(2); if (Symbol) { var object = {}; object[symbol] = 1; assert.strictEqual(_.unset(object, symbol), true); assert.notOk(symbol in object); } else { skipAssert(assert, 2); } }); QUnit.test('`_.' + methodName + '` should set deep property values', function(assert) { assert.expect(4); lodashStable.each(['a.b', ['a', 'b']], function(path) { var object = { 'a': { 'b': oldValue } }, actual = func(object, path, updater); assert.strictEqual(actual, object); assert.strictEqual(object.a.b, value); }); }); QUnit.test('`_.' + methodName + '` should set a key over a path', function(assert) { assert.expect(4); lodashStable.each(['a.b', ['a.b']], function(path) { var object = { 'a.b': oldValue }, actual = func(object, path, updater); assert.strictEqual(actual, object); assert.deepEqual(object, { 'a.b': value }); }); }); QUnit.test('`_.' + methodName + '` should not coerce array paths to strings', function(assert) { assert.expect(1); var object = { 'a,b,c': 1, 'a': { 'b': { 'c': 1 } } }; func(object, ['a', 'b', 'c'], updater); assert.strictEqual(object.a.b.c, value); }); QUnit.test('`_.' + methodName + '` should not ignore empty brackets', function(assert) { assert.expect(1); var object = {}; func(object, 'a[]', updater); assert.deepEqual(object, { 'a': { '': value } }); }); QUnit.test('`_.' + methodName + '` should handle empty paths', function(assert) { assert.expect(4); lodashStable.each([['', ''], [[], ['']]], function(pair, index) { var object = {}; func(object, pair[0], updater); assert.deepEqual(object, index ? {} : { '': value }); func(object, pair[1], updater); assert.deepEqual(object, { '': value }); }); }); QUnit.test('`_.' + methodName + '` should handle complex paths', function(assert) { assert.expect(2); var object = { 'a': { '1.23': { '["b"]': { 'c': { "['d']": { '\ne\n': { 'f': { 'g': oldValue } } } } } } } }; var paths = [ 'a[-1.23]["[\\"b\\"]"].c[\'[\\\'d\\\']\'][\ne\n][f].g', ['a', '-1.23', '["b"]', 'c', "['d']", '\ne\n', 'f', 'g'] ]; lodashStable.each(paths, function(path) { func(object, path, updater); assert.strictEqual(object.a[-1.23]['["b"]'].c["['d']"]['\ne\n'].f.g, value); object.a[-1.23]['["b"]'].c["['d']"]['\ne\n'].f.g = oldValue; }); }); QUnit.test('`_.' + methodName + '` should create parts of `path` that are missing', function(assert) { assert.expect(6); var object = {}; lodashStable.each(['a[1].b.c', ['a', '1', 'b', 'c']], function(path) { var actual = func(object, path, updater); assert.strictEqual(actual, object); assert.deepEqual(actual, { 'a': [undefined, { 'b': { 'c': value } }] }); assert.notOk('0' in object.a); delete object.a; }); }); QUnit.test('`_.' + methodName + '` should not error when `object` is nullish', function(assert) { assert.expect(1); var values = [null, undefined], expected = [[null, null], [undefined, undefined]]; var actual = lodashStable.map(values, function(value) { try { return [func(value, 'a.b', updater), func(value, ['a', 'b'], updater)]; } catch (e) { return e.message; } }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should overwrite primitives in the path', function(assert) { assert.expect(2); lodashStable.each(['a.b', ['a', 'b']], function(path) { var object = { 'a': '' }; func(object, path, updater); assert.deepEqual(object, { 'a': { 'b': 2 } }); });; }); QUnit.test('`_.' + methodName + '` should not create an array for missing non-index property names that start with numbers', function(assert) { assert.expect(1); var object = {}; func(object, ['1a', '2b', '3c'], updater); assert.deepEqual(object, { '1a': { '2b': { '3c': value } } }); }); QUnit.test('`_.' + methodName + '` should not assign values that are the same as their destinations', function(assert) { assert.expect(4); lodashStable.each(['a', ['a'], { 'a': 1 }, NaN], function(value) { var object = {}, pass = true, updater = isUpdate ? lodashStable.constant(value) : value; defineProperty(object, 'a', { 'configurable': true, 'enumerable': true, 'get': lodashStable.constant(value), 'set': function() { pass = false; } }); func(object, 'a', updater); assert.ok(pass); }); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.shuffle'); (function() { var array = [1, 2, 3], object = { 'a': 1, 'b': 2, 'c': 3 }; QUnit.test('should return a new array', function(assert) { assert.expect(1); assert.notStrictEqual(_.shuffle(array), array); }); QUnit.test('should contain the same elements after a collection is shuffled', function(assert) { assert.expect(2); assert.deepEqual(_.shuffle(array).sort(), array); assert.deepEqual(_.shuffle(object).sort(), array); }); QUnit.test('should shuffle small collections', function(assert) { assert.expect(1); var actual = lodashStable.times(1000, function(assert) { return _.shuffle([1, 2]); }); assert.deepEqual(lodashStable.sortBy(lodashStable.uniqBy(actual, String), '0'), [[1, 2], [2, 1]]); }); QUnit.test('should treat number values for `collection` as empty', function(assert) { assert.expect(1); assert.deepEqual(_.shuffle(1), []); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.size'); (function() { var array = [1, 2, 3]; QUnit.test('should return the number of own enumerable string keyed properties of an object', function(assert) { assert.expect(1); assert.strictEqual(_.size({ 'one': 1, 'two': 2, 'three': 3 }), 3); }); QUnit.test('should return the length of an array', function(assert) { assert.expect(1); assert.strictEqual(_.size(array), 3); }); QUnit.test('should accept a falsey `object`', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, stubZero); var actual = lodashStable.map(falsey, function(object, index) { try { return index ? _.size(object) : _.size(); } catch (e) {} }); assert.deepEqual(actual, expected); }); QUnit.test('should work with `arguments` objects', function(assert) { assert.expect(1); assert.strictEqual(_.size(args), 3); }); QUnit.test('should work with jQuery/MooTools DOM query collections', function(assert) { assert.expect(1); function Foo(elements) { push.apply(this, elements); } Foo.prototype = { 'length': 0, 'splice': arrayProto.splice }; assert.strictEqual(_.size(new Foo(array)), 3); }); QUnit.test('should work with maps', function(assert) { assert.expect(2); if (Map) { lodashStable.each([new Map, realm.map], function(map) { map.set('a', 1); map.set('b', 2); assert.strictEqual(_.size(map), 2); map.clear(); }); } else { skipAssert(assert, 2); } }); QUnit.test('should work with sets', function(assert) { assert.expect(2); if (Set) { lodashStable.each([new Set, realm.set], function(set) { set.add(1); set.add(2); assert.strictEqual(_.size(set), 2); set.clear(); }); } else { skipAssert(assert, 2); } }); QUnit.test('should not treat objects with negative lengths as array-like', function(assert) { assert.expect(1); assert.strictEqual(_.size({ 'length': -1 }), 1); }); QUnit.test('should not treat objects with lengths larger than `MAX_SAFE_INTEGER` as array-like', function(assert) { assert.expect(1); assert.strictEqual(_.size({ 'length': MAX_SAFE_INTEGER + 1 }), 1); }); QUnit.test('should not treat objects with non-number lengths as array-like', function(assert) { assert.expect(1); assert.strictEqual(_.size({ 'length': '0' }), 1); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.slice'); (function() { var array = [1, 2, 3]; QUnit.test('should use a default `start` of `0` and a default `end` of `length`', function(assert) { assert.expect(2); var actual = _.slice(array); assert.deepEqual(actual, array); assert.notStrictEqual(actual, array); }); QUnit.test('should work with a positive `start`', function(assert) { assert.expect(2); assert.deepEqual(_.slice(array, 1), [2, 3]); assert.deepEqual(_.slice(array, 1, 3), [2, 3]); }); QUnit.test('should work with a `start` >= `length`', function(assert) { assert.expect(4); lodashStable.each([3, 4, Math.pow(2, 32), Infinity], function(start) { assert.deepEqual(_.slice(array, start), []); }); }); QUnit.test('should treat falsey `start` values as `0`', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, lodashStable.constant(array)); var actual = lodashStable.map(falsey, function(start) { return _.slice(array, start); }); assert.deepEqual(actual, expected); }); QUnit.test('should work with a negative `start`', function(assert) { assert.expect(1); assert.deepEqual(_.slice(array, -1), [3]); }); QUnit.test('should work with a negative `start` <= negative `length`', function(assert) { assert.expect(3); lodashStable.each([-3, -4, -Infinity], function(start) { assert.deepEqual(_.slice(array, start), array); }); }); QUnit.test('should work with `start` >= `end`', function(assert) { assert.expect(2); lodashStable.each([2, 3], function(start) { assert.deepEqual(_.slice(array, start, 2), []); }); }); QUnit.test('should work with a positive `end`', function(assert) { assert.expect(1); assert.deepEqual(_.slice(array, 0, 1), [1]); }); QUnit.test('should work with a `end` >= `length`', function(assert) { assert.expect(4); lodashStable.each([3, 4, Math.pow(2, 32), Infinity], function(end) { assert.deepEqual(_.slice(array, 0, end), array); }); }); QUnit.test('should treat falsey `end` values, except `undefined`, as `0`', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, function(value) { return value === undefined ? array : []; }); var actual = lodashStable.map(falsey, function(end, index) { return index ? _.slice(array, 0, end) : _.slice(array, 0); }); assert.deepEqual(actual, expected); }); QUnit.test('should work with a negative `end`', function(assert) { assert.expect(1); assert.deepEqual(_.slice(array, 0, -1), [1, 2]); }); QUnit.test('should work with a negative `end` <= negative `length`', function(assert) { assert.expect(3); lodashStable.each([-3, -4, -Infinity], function(end) { assert.deepEqual(_.slice(array, 0, end), []); }); }); QUnit.test('should coerce `start` and `end` to integers', function(assert) { assert.expect(1); var positions = [[0.1, 1.6], ['0', 1], [0, '1'], ['1'], [NaN, 1], [1, NaN]]; var actual = lodashStable.map(positions, function(pos) { return _.slice.apply(_, [array].concat(pos)); }); assert.deepEqual(actual, [[1], [1], [1], [2, 3], [1], []]); }); QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(2); var array = [[1], [2, 3]], actual = lodashStable.map(array, _.slice); assert.deepEqual(actual, array); assert.notStrictEqual(actual, array); }); QUnit.test('should work in a lazy sequence', function(assert) { assert.expect(38); if (!isNpm) { var array = lodashStable.range(1, LARGE_ARRAY_SIZE + 1), length = array.length, wrapped = _(array); lodashStable.each(['map', 'filter'], function(methodName) { assert.deepEqual(wrapped[methodName]().slice(0, -1).value(), array.slice(0, -1)); assert.deepEqual(wrapped[methodName]().slice(1).value(), array.slice(1)); assert.deepEqual(wrapped[methodName]().slice(1, 3).value(), array.slice(1, 3)); assert.deepEqual(wrapped[methodName]().slice(-1).value(), array.slice(-1)); assert.deepEqual(wrapped[methodName]().slice(length).value(), array.slice(length)); assert.deepEqual(wrapped[methodName]().slice(3, 2).value(), array.slice(3, 2)); assert.deepEqual(wrapped[methodName]().slice(0, -length).value(), array.slice(0, -length)); assert.deepEqual(wrapped[methodName]().slice(0, null).value(), array.slice(0, null)); assert.deepEqual(wrapped[methodName]().slice(0, length).value(), array.slice(0, length)); assert.deepEqual(wrapped[methodName]().slice(-length).value(), array.slice(-length)); assert.deepEqual(wrapped[methodName]().slice(null).value(), array.slice(null)); assert.deepEqual(wrapped[methodName]().slice(0, 1).value(), array.slice(0, 1)); assert.deepEqual(wrapped[methodName]().slice(NaN, '1').value(), array.slice(NaN, '1')); assert.deepEqual(wrapped[methodName]().slice(0.1, 1.1).value(), array.slice(0.1, 1.1)); assert.deepEqual(wrapped[methodName]().slice('0', 1).value(), array.slice('0', 1)); assert.deepEqual(wrapped[methodName]().slice(0, '1').value(), array.slice(0, '1')); assert.deepEqual(wrapped[methodName]().slice('1').value(), array.slice('1')); assert.deepEqual(wrapped[methodName]().slice(NaN, 1).value(), array.slice(NaN, 1)); assert.deepEqual(wrapped[methodName]().slice(1, NaN).value(), array.slice(1, NaN)); }); } else { skipAssert(assert, 38); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.some'); (function() { QUnit.test('should return `true` if `predicate` returns truthy for any element', function(assert) { assert.expect(2); assert.strictEqual(_.some([false, 1, ''], identity), true); assert.strictEqual(_.some([null, 'a', 0], identity), true); }); QUnit.test('should return `false` for empty collections', function(assert) { assert.expect(1); var expected = lodashStable.map(empties, stubFalse); var actual = lodashStable.map(empties, function(value) { try { return _.some(value, identity); } catch (e) {} }); assert.deepEqual(actual, expected); }); QUnit.test('should return `true` as soon as `predicate` returns truthy', function(assert) { assert.expect(2); var count = 0; assert.strictEqual(_.some([null, true, null], function(value) { count++; return value; }), true); assert.strictEqual(count, 2); }); QUnit.test('should return `false` if `predicate` returns falsey for all elements', function(assert) { assert.expect(2); assert.strictEqual(_.some([false, false, false], identity), false); assert.strictEqual(_.some([null, 0, ''], identity), false); }); QUnit.test('should use `_.identity` when `predicate` is nullish', function(assert) { assert.expect(2); var values = [, null, undefined], expected = lodashStable.map(values, stubFalse); var actual = lodashStable.map(values, function(value, index) { var array = [0, 0]; return index ? _.some(array, value) : _.some(array); }); assert.deepEqual(actual, expected); expected = lodashStable.map(values, stubTrue); actual = lodashStable.map(values, function(value, index) { var array = [0, 1]; return index ? _.some(array, value) : _.some(array); }); assert.deepEqual(actual, expected); }); QUnit.test('should work with `_.property` shorthands', function(assert) { assert.expect(2); var objects = [{ 'a': 0, 'b': 0 }, { 'a': 0, 'b': 1 }]; assert.strictEqual(_.some(objects, 'a'), false); assert.strictEqual(_.some(objects, 'b'), true); }); QUnit.test('should work with `_.matches` shorthands', function(assert) { assert.expect(2); var objects = [{ 'a': 0, 'b': 0 }, { 'a': 1, 'b': 1}]; assert.strictEqual(_.some(objects, { 'a': 0 }), true); assert.strictEqual(_.some(objects, { 'b': 2 }), false); }); QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(1); var actual = lodashStable.map([[1]], _.some); assert.deepEqual(actual, [true]); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.sortBy'); (function() { var objects = [ { 'a': 'x', 'b': 3 }, { 'a': 'y', 'b': 4 }, { 'a': 'x', 'b': 1 }, { 'a': 'y', 'b': 2 } ]; QUnit.test('should sort in ascending order by `iteratee`', function(assert) { assert.expect(1); var actual = lodashStable.map(_.sortBy(objects, function(object) { return object.b; }), 'b'); assert.deepEqual(actual, [1, 2, 3, 4]); }); QUnit.test('should use `_.identity` when `iteratee` is nullish', function(assert) { assert.expect(1); var array = [3, 2, 1], values = [, null, undefined], expected = lodashStable.map(values, lodashStable.constant([1, 2, 3])); var actual = lodashStable.map(values, function(value, index) { return index ? _.sortBy(array, value) : _.sortBy(array); }); assert.deepEqual(actual, expected); }); QUnit.test('should work with `_.property` shorthands', function(assert) { assert.expect(1); var actual = lodashStable.map(_.sortBy(objects.concat(undefined), 'b'), 'b'); assert.deepEqual(actual, [1, 2, 3, 4, undefined]); }); QUnit.test('should work with an object for `collection`', function(assert) { assert.expect(1); var actual = _.sortBy({ 'a': 1, 'b': 2, 'c': 3 }, Math.sin); assert.deepEqual(actual, [3, 1, 2]); }); QUnit.test('should move `NaN`, nullish, and symbol values to the end', function(assert) { assert.expect(2); var symbol1 = Symbol ? Symbol('a') : null, symbol2 = Symbol ? Symbol('b') : null, array = [NaN, undefined, null, 4, symbol1, null, 1, symbol2, undefined, 3, NaN, 2], expected = [1, 2, 3, 4, symbol1, symbol2, null, null, undefined, undefined, NaN, NaN]; assert.deepEqual(_.sortBy(array), expected); array = [NaN, undefined, symbol1, null, 'd', null, 'a', symbol2, undefined, 'c', NaN, 'b']; expected = ['a', 'b', 'c', 'd', symbol1, symbol2, null, null, undefined, undefined, NaN, NaN]; assert.deepEqual(_.sortBy(array), expected); }); QUnit.test('should treat number values for `collection` as empty', function(assert) { assert.expect(1); assert.deepEqual(_.sortBy(1), []); }); QUnit.test('should coerce arrays returned from `iteratee`', function(assert) { assert.expect(1); var actual = _.sortBy(objects, function(object) { var result = [object.a, object.b]; result.toString = function() { return String(this[0]); }; return result; }); assert.deepEqual(actual, [objects[0], objects[2], objects[1], objects[3]]); }); QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(1); var actual = lodashStable.map([[2, 1, 3], [3, 2, 1]], _.sortBy); assert.deepEqual(actual, [[1, 2, 3], [1, 2, 3]]); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('sortBy methods'); lodashStable.each(['orderBy', 'sortBy'], function(methodName) { var func = _[methodName]; function Pair(a, b, c) { this.a = a; this.b = b; this.c = c; } var objects = [ { 'a': 'x', 'b': 3 }, { 'a': 'y', 'b': 4 }, { 'a': 'x', 'b': 1 }, { 'a': 'y', 'b': 2 } ]; var stableArray = [ new Pair(1, 1, 1), new Pair(1, 2, 1), new Pair(1, 1, 1), new Pair(1, 2, 1), new Pair(1, 3, 1), new Pair(1, 4, 1), new Pair(1, 5, 1), new Pair(1, 6, 1), new Pair(2, 1, 2), new Pair(2, 2, 2), new Pair(2, 3, 2), new Pair(2, 4, 2), new Pair(2, 5, 2), new Pair(2, 6, 2), new Pair(undefined, 1, 1), new Pair(undefined, 2, 1), new Pair(undefined, 3, 1), new Pair(undefined, 4, 1), new Pair(undefined, 5, 1), new Pair(undefined, 6, 1) ]; var stableObject = lodashStable.zipObject('abcdefghijklmnopqrst'.split(''), stableArray); QUnit.test('`_.' + methodName + '` should sort multiple properties in ascending order', function(assert) { assert.expect(1); var actual = func(objects, ['a', 'b']); assert.deepEqual(actual, [objects[2], objects[0], objects[3], objects[1]]); }); QUnit.test('`_.' + methodName + '` should support iteratees', function(assert) { assert.expect(1); var actual = func(objects, ['a', function(object) { return object.b; }]); assert.deepEqual(actual, [objects[2], objects[0], objects[3], objects[1]]); }); QUnit.test('`_.' + methodName + '` should perform a stable sort (test in IE > 8 and V8)', function(assert) { assert.expect(2); lodashStable.each([stableArray, stableObject], function(value, index) { var actual = func(value, ['a', 'c']); assert.deepEqual(actual, stableArray, index ? 'object' : 'array'); }); }); QUnit.test('`_.' + methodName + '` should not error on nullish elements', function(assert) { assert.expect(1); try { var actual = func(objects.concat(null, undefined), ['a', 'b']); } catch (e) {} assert.deepEqual(actual, [objects[2], objects[0], objects[3], objects[1], null, undefined]); }); QUnit.test('`_.' + methodName + '` should work as an iteratee for methods like `_.reduce`', function(assert) { assert.expect(3); var objects = [ { 'a': 'x', '0': 3 }, { 'a': 'y', '0': 4 }, { 'a': 'x', '0': 1 }, { 'a': 'y', '0': 2 } ]; var funcs = [func, lodashStable.partialRight(func, 'bogus')]; lodashStable.each(['a', 0, [0]], function(props, index) { var expected = lodashStable.map(funcs, lodashStable.constant( index ? [objects[2], objects[3], objects[0], objects[1]] : [objects[0], objects[2], objects[1], objects[3]] )); var actual = lodashStable.map(funcs, function(func) { return lodashStable.reduce([props], func, objects); }); assert.deepEqual(actual, expected); }); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('sortedIndex methods'); lodashStable.each(['sortedIndex', 'sortedLastIndex'], function(methodName) { var func = _[methodName], isSortedIndex = methodName == 'sortedIndex'; QUnit.test('`_.' + methodName + '` should return the insert index', function(assert) { assert.expect(1); var array = [30, 50], values = [30, 40, 50], expected = isSortedIndex ? [0, 1, 1] : [1, 1, 2]; var actual = lodashStable.map(values, function(value) { return func(array, value); }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should work with an array of strings', function(assert) { assert.expect(1); var array = ['a', 'c'], values = ['a', 'b', 'c'], expected = isSortedIndex ? [0, 1, 1] : [1, 1, 2]; var actual = lodashStable.map(values, function(value) { return func(array, value); }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should accept a nullish `array` and a `value`', function(assert) { assert.expect(1); var values = [null, undefined], expected = lodashStable.map(values, lodashStable.constant([0, 0, 0])); var actual = lodashStable.map(values, function(array) { return [func(array, 1), func(array, undefined), func(array, NaN)]; }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should align with `_.sortBy`', function(assert) { assert.expect(12); var symbol1 = Symbol ? Symbol('a') : null, symbol2 = Symbol ? Symbol('b') : null, symbol3 = Symbol ? Symbol('c') : null, expected = [1, '2', {}, symbol1, symbol2, null, undefined, NaN, NaN]; lodashStable.each([ [NaN, symbol1, null, 1, '2', {}, symbol2, NaN, undefined], ['2', null, 1, symbol1, NaN, {}, NaN, symbol2, undefined] ], function(array) { assert.deepEqual(_.sortBy(array), expected); assert.strictEqual(func(expected, 3), 2); assert.strictEqual(func(expected, symbol3), isSortedIndex ? 3 : (Symbol ? 5 : 6)); assert.strictEqual(func(expected, null), isSortedIndex ? (Symbol ? 5 : 3) : 6); assert.strictEqual(func(expected, undefined), isSortedIndex ? 6 : 7); assert.strictEqual(func(expected, NaN), isSortedIndex ? 7 : 9); }); }); QUnit.test('`_.' + methodName + '` should align with `_.sortBy` for nulls', function(assert) { assert.expect(3); var array = [null, null]; assert.strictEqual(func(array, null), isSortedIndex ? 0 : 2); assert.strictEqual(func(array, 1), 0); assert.strictEqual(func(array, 'a'), 0); }); QUnit.test('`_.' + methodName + '` should align with `_.sortBy` for symbols', function(assert) { assert.expect(3); var symbol1 = Symbol ? Symbol('a') : null, symbol2 = Symbol ? Symbol('b') : null, symbol3 = Symbol ? Symbol('c') : null, array = [symbol1, symbol2]; assert.strictEqual(func(array, symbol3), isSortedIndex ? 0 : 2); assert.strictEqual(func(array, 1), 0); assert.strictEqual(func(array, 'a'), 0); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('sortedIndexBy methods'); lodashStable.each(['sortedIndexBy', 'sortedLastIndexBy'], function(methodName) { var func = _[methodName], isSortedIndexBy = methodName == 'sortedIndexBy'; QUnit.test('`_.' + methodName + '` should provide correct `iteratee` arguments', function(assert) { assert.expect(1); var args; func([30, 50], 40, function(assert) { args || (args = slice.call(arguments)); }); assert.deepEqual(args, [40]); }); QUnit.test('`_.' + methodName + '` should work with `_.property` shorthands', function(assert) { assert.expect(1); var objects = [{ 'x': 30 }, { 'x': 50 }], actual = func(objects, { 'x': 40 }, 'x'); assert.strictEqual(actual, 1); }); QUnit.test('`_.' + methodName + '` should support arrays larger than `MAX_ARRAY_LENGTH / 2`', function(assert) { assert.expect(12); lodashStable.each([Math.ceil(MAX_ARRAY_LENGTH / 2), MAX_ARRAY_LENGTH], function(length) { var array = [], values = [MAX_ARRAY_LENGTH, NaN, undefined]; array.length = length; lodashStable.each(values, function(value) { var steps = 0; var actual = func(array, value, function(value) { steps++; return value; }); var expected = (isSortedIndexBy ? !lodashStable.isNaN(value) : lodashStable.isFinite(value)) ? 0 : Math.min(length, MAX_ARRAY_INDEX); assert.ok(steps == 32 || steps == 33); assert.strictEqual(actual, expected); }); }); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('sortedIndexOf methods'); lodashStable.each(['sortedIndexOf', 'sortedLastIndexOf'], function(methodName) { var func = _[methodName], isSortedIndexOf = methodName == 'sortedIndexOf'; QUnit.test('`_.' + methodName + '` should perform a binary search', function(assert) { assert.expect(1); var sorted = [4, 4, 5, 5, 6, 6]; assert.deepEqual(func(sorted, 5), isSortedIndexOf ? 2 : 3); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.sortedUniq'); (function() { QUnit.test('should return unique values of a sorted array', function(assert) { assert.expect(3); var expected = [1, 2, 3]; lodashStable.each([[1, 2, 3], [1, 1, 2, 2, 3], [1, 2, 3, 3, 3, 3, 3]], function(array) { assert.deepEqual(_.sortedUniq(array), expected); }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.split'); (function() { QUnit.test('should split a string by `separator`', function(assert) { assert.expect(3); var string = 'abcde'; assert.deepEqual(_.split(string, 'c'), ['ab', 'de']); assert.deepEqual(_.split(string, /[bd]/), ['a', 'c', 'e']); assert.deepEqual(_.split(string, '', 2), ['a', 'b']); }); QUnit.test('should return an array containing an empty string for empty values', function(assert) { assert.expect(1); var values = [, null, undefined, ''], expected = lodashStable.map(values, lodashStable.constant([''])); var actual = lodashStable.map(values, function(value, index) { return index ? _.split(value) : _.split(); }); assert.deepEqual(actual, expected); }); QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(1); var strings = ['abc', 'def', 'ghi'], actual = lodashStable.map(strings, _.split); assert.deepEqual(actual, [['abc'], ['def'], ['ghi']]); }); QUnit.test('should allow mixed string and array prototype methods', function(assert) { assert.expect(1); if (!isNpm) { var wrapped = _('abc'); assert.strictEqual(wrapped.split('b').join(','), 'a,c'); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.spread'); (function() { function fn(a, b, c) { return slice.call(arguments); } QUnit.test('should spread arguments to `func`', function(assert) { assert.expect(2); var spread = _.spread(fn), expected = [1, 2]; assert.deepEqual(spread([1, 2]), expected); assert.deepEqual(spread([1, 2], 3), expected); }); QUnit.test('should accept a falsey `array`', function(assert) { assert.expect(1); var spread = _.spread(stubTrue), expected = lodashStable.map(falsey, stubTrue); var actual = lodashStable.map(falsey, function(array, index) { try { return index ? spread(array) : spread(); } catch (e) {} }); assert.deepEqual(actual, expected); }); QUnit.test('should work with `start`', function(assert) { assert.expect(2); var spread = _.spread(fn, 1), expected = [1, 2, 3]; assert.deepEqual(spread(1, [2, 3]), expected); assert.deepEqual(spread(1, [2, 3], 4), expected); }); QUnit.test('should treat `start` as `0` for negative or `NaN` values', function(assert) { assert.expect(1); var values = [-1, NaN, 'a'], expected = lodashStable.map(values, lodashStable.constant([1, 2])); var actual = lodashStable.map(values, function(value) { var spread = _.spread(fn, value); return spread([1, 2]); }); assert.deepEqual(actual, expected); }); QUnit.test('should coerce `start` to an integer', function(assert) { assert.expect(2); var spread = _.spread(fn, 1.6), expected = [1, 2, 3]; assert.deepEqual(spread(1, [2, 3]), expected); assert.deepEqual(spread(1, [2, 3], 4), expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.startCase'); (function() { QUnit.test('should uppercase only the first character of each word', function(assert) { assert.expect(3); assert.strictEqual(_.startCase('--foo-bar--'), 'Foo Bar'); assert.strictEqual(_.startCase('fooBar'), 'Foo Bar'); assert.strictEqual(_.startCase('__FOO_BAR__'), 'FOO BAR'); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.startsWith'); (function() { var string = 'abc'; QUnit.test('should return `true` if a string starts with `target`', function(assert) { assert.expect(1); assert.strictEqual(_.startsWith(string, 'a'), true); }); QUnit.test('should return `false` if a string does not start with `target`', function(assert) { assert.expect(1); assert.strictEqual(_.startsWith(string, 'b'), false); }); QUnit.test('should work with a `position`', function(assert) { assert.expect(1); assert.strictEqual(_.startsWith(string, 'b', 1), true); }); QUnit.test('should work with `position` >= `length`', function(assert) { assert.expect(4); lodashStable.each([3, 5, MAX_SAFE_INTEGER, Infinity], function(position) { assert.strictEqual(_.startsWith(string, 'a', position), false); }); }); QUnit.test('should treat falsey `position` values as `0`', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, stubTrue); var actual = lodashStable.map(falsey, function(position) { return _.startsWith(string, 'a', position); }); assert.deepEqual(actual, expected); }); QUnit.test('should treat a negative `position` as `0`', function(assert) { assert.expect(6); lodashStable.each([-1, -3, -Infinity], function(position) { assert.strictEqual(_.startsWith(string, 'a', position), true); assert.strictEqual(_.startsWith(string, 'b', position), false); }); }); QUnit.test('should coerce `position` to an integer', function(assert) { assert.expect(1); assert.strictEqual(_.startsWith(string, 'bc', 1.2), true); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.startsWith and lodash.endsWith'); lodashStable.each(['startsWith', 'endsWith'], function(methodName) { var func = _[methodName], isStartsWith = methodName == 'startsWith'; var string = 'abc', chr = isStartsWith ? 'a' : 'c'; QUnit.test('`_.' + methodName + '` should coerce `string` to a string', function(assert) { assert.expect(2); assert.strictEqual(func(Object(string), chr), true); assert.strictEqual(func({ 'toString': lodashStable.constant(string) }, chr), true); }); QUnit.test('`_.' + methodName + '` should coerce `target` to a string', function(assert) { assert.expect(2); assert.strictEqual(func(string, Object(chr)), true); assert.strictEqual(func(string, { 'toString': lodashStable.constant(chr) }), true); }); QUnit.test('`_.' + methodName + '` should coerce `position` to a number', function(assert) { assert.expect(2); var position = isStartsWith ? 1 : 2; assert.strictEqual(func(string, 'b', Object(position)), true); assert.strictEqual(func(string, 'b', { 'toString': lodashStable.constant(String(position)) }), true); }); QUnit.test('should return `true` when `target` is an empty string regardless of `position`', function(assert) { assert.expect(1); var positions = [-Infinity, NaN, -3, -1, 0, 1, 2, 3, 5, MAX_SAFE_INTEGER, Infinity]; assert.ok(lodashStable.every(positions, function(position) { return func(string, '', position); })); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('stub methods'); lodashStable.each(['noop', 'stubTrue', 'stubFalse', 'stubArray', 'stubObject', 'stubString'], function(methodName) { var func = _[methodName]; var pair = ({ 'stubArray': [[], 'an empty array'], 'stubFalse': [false, '`false`'], 'stubObject': [{}, 'an empty object'], 'stubString': ['', 'an empty string'], 'stubTrue': [true, '`true`'], 'noop': [undefined, '`undefined`'] })[methodName]; var values = Array(2).concat(empties, true, 1, 'a'), expected = lodashStable.map(values, lodashStable.constant(pair[0])); QUnit.test('`_.' + methodName + '` should return ' + pair[1], function(assert) { assert.expect(1); var actual = lodashStable.map(values, function(value, index) { if (index < 2) { return index ? func.call({}) : func(); } return func(value); }); assert.deepEqual(actual, expected); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.subtract'); (function() { QUnit.test('should subtract two numbers', function(assert) { assert.expect(3); assert.strictEqual(_.subtract(6, 4), 2); assert.strictEqual(_.subtract(-6, 4), -10); assert.strictEqual(_.subtract(-6, -4), -2); }); QUnit.test('should coerce arguments to numbers', function(assert) { assert.expect(2); assert.strictEqual(_.subtract('6', '4'), 2); assert.deepEqual(_.subtract('x', 'y'), NaN); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('math operator methods'); lodashStable.each(['add', 'divide', 'multiply', 'subtract'], function(methodName) { var func = _[methodName], isAddSub = methodName == 'add' || methodName == 'subtract'; QUnit.test('`_.' + methodName + '` should return `' + (isAddSub ? 0 : 1) + '` when no arguments are given', function(assert) { assert.expect(1); assert.strictEqual(func(), isAddSub ? 0 : 1); }); QUnit.test('`_.' + methodName + '` should work with only one defined argument', function(assert) { assert.expect(3); assert.strictEqual(func(6), 6); assert.strictEqual(func(6, undefined), 6); assert.strictEqual(func(undefined, 4), 4); }); QUnit.test('`_.' + methodName + '` should preserve the sign of `0`', function(assert) { assert.expect(2); var values = [0, '0', -0, '-0'], expected = [[0, Infinity], ['0', Infinity], [-0, -Infinity], ['-0', -Infinity]]; lodashStable.times(2, function(index) { var actual = lodashStable.map(values, function(value) { var result = index ? func(undefined, value) : func(value); return [result, 1 / result]; }); assert.deepEqual(actual, expected); }); }); QUnit.test('`_.' + methodName + '` should convert objects to `NaN`', function(assert) { assert.expect(2); assert.deepEqual(func(0, {}), NaN); assert.deepEqual(func({}, 0), NaN); }); QUnit.test('`_.' + methodName + '` should convert symbols to `NaN`', function(assert) { assert.expect(2); if (Symbol) { assert.deepEqual(func(0, symbol), NaN); assert.deepEqual(func(symbol, 0), NaN); } else { skipAssert(assert, 2); } }); QUnit.test('`_.' + methodName + '` should return an unwrapped value when implicitly chaining', function(assert) { assert.expect(1); if (!isNpm) { var actual = _(1)[methodName](2); assert.notOk(actual instanceof _); } else { skipAssert(assert); } }); QUnit.test('`_.' + methodName + '` should return a wrapped value when explicitly chaining', function(assert) { assert.expect(1); if (!isNpm) { var actual = _(1).chain()[methodName](2); assert.ok(actual instanceof _); } else { skipAssert(assert); } }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.sumBy'); (function() { var array = [6, 4, 2], objects = [{ 'a': 2 }, { 'a': 3 }, { 'a': 1 }]; QUnit.test('should work with an `iteratee`', function(assert) { assert.expect(1); var actual = _.sumBy(objects, function(object) { return object.a; }); assert.deepEqual(actual, 6); }); QUnit.test('should provide correct `iteratee` arguments', function(assert) { assert.expect(1); var args; _.sumBy(array, function() { args || (args = slice.call(arguments)); }); assert.deepEqual(args, [6]); }); QUnit.test('should work with `_.property` shorthands', function(assert) { assert.expect(2); var arrays = [[2], [3], [1]]; assert.strictEqual(_.sumBy(arrays, 0), 6); assert.strictEqual(_.sumBy(objects, 'a'), 6); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('sum methods'); lodashStable.each(['sum', 'sumBy'], function(methodName) { var array = [6, 4, 2], func = _[methodName]; QUnit.test('`_.' + methodName + '` should return the sum of an array of numbers', function(assert) { assert.expect(1); assert.strictEqual(func(array), 12); }); QUnit.test('`_.' + methodName + '` should return `0` when passing empty `array` values', function(assert) { assert.expect(1); var expected = lodashStable.map(empties, stubZero); var actual = lodashStable.map(empties, function(value) { return func(value); }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should skip `undefined` values', function(assert) { assert.expect(1); assert.strictEqual(func([1, undefined]), 1); }); QUnit.test('`_.' + methodName + '` should not skip `NaN` values', function(assert) { assert.expect(1); assert.deepEqual(func([1, NaN]), NaN); }); QUnit.test('`_.' + methodName + '` should not coerce values to numbers', function(assert) { assert.expect(1); assert.strictEqual(func(['1', '2']), '12'); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.tail'); (function() { var array = [1, 2, 3]; QUnit.test('should accept a falsey `array`', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, stubArray); var actual = lodashStable.map(falsey, function(array, index) { try { return index ? _.tail(array) : _.tail(); } catch (e) {} }); assert.deepEqual(actual, expected); }); QUnit.test('should exclude the first element', function(assert) { assert.expect(1); assert.deepEqual(_.tail(array), [2, 3]); }); QUnit.test('should return an empty when querying empty arrays', function(assert) { assert.expect(1); assert.deepEqual(_.tail([]), []); }); QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(1); var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], actual = lodashStable.map(array, _.tail); assert.deepEqual(actual, [[2, 3], [5, 6], [8, 9]]); }); QUnit.test('should work in a lazy sequence', function(assert) { assert.expect(4); if (!isNpm) { var array = lodashStable.range(LARGE_ARRAY_SIZE), values = []; var actual = _(array).tail().filter(function(value) { values.push(value); return false; }) .value(); assert.deepEqual(actual, []); assert.deepEqual(values, array.slice(1)); values = []; actual = _(array).filter(function(value) { values.push(value); return isEven(value); }) .tail() .value(); assert.deepEqual(actual, _.tail(_.filter(array, isEven))); assert.deepEqual(values, array); } else { skipAssert(assert, 4); } }); QUnit.test('should not execute subsequent iteratees on an empty array in a lazy sequence', function(assert) { assert.expect(4); if (!isNpm) { var array = lodashStable.range(LARGE_ARRAY_SIZE), iteratee = function() { pass = false; }, pass = true, actual = _(array).slice(0, 1).tail().map(iteratee).value(); assert.ok(pass); assert.deepEqual(actual, []); pass = true; actual = _(array).filter().slice(0, 1).tail().map(iteratee).value(); assert.ok(pass); assert.deepEqual(actual, []); } else { skipAssert(assert, 4); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.take'); (function() { var array = [1, 2, 3]; QUnit.test('should take the first two elements', function(assert) { assert.expect(1); assert.deepEqual(_.take(array, 2), [1, 2]); }); QUnit.test('should treat falsey `n` values, except `undefined`, as `0`', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, function(value) { return value === undefined ? [1] : []; }); var actual = lodashStable.map(falsey, function(n) { return _.take(array, n); }); assert.deepEqual(actual, expected); }); QUnit.test('should return an empty array when `n` < `1`', function(assert) { assert.expect(3); lodashStable.each([0, -1, -Infinity], function(n) { assert.deepEqual(_.take(array, n), []); }); }); QUnit.test('should return all elements when `n` >= `length`', function(assert) { assert.expect(4); lodashStable.each([3, 4, Math.pow(2, 32), Infinity], function(n) { assert.deepEqual(_.take(array, n), array); }); }); QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(1); var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], actual = lodashStable.map(array, _.take); assert.deepEqual(actual, [[1], [4], [7]]); }); QUnit.test('should work in a lazy sequence', function(assert) { assert.expect(6); if (!isNpm) { var array = lodashStable.range(1, LARGE_ARRAY_SIZE + 1), predicate = function(value) { values.push(value); return isEven(value); }, values = [], actual = _(array).take(2).take().value(); assert.deepEqual(actual, _.take(_.take(array, 2))); actual = _(array).filter(predicate).take(2).take().value(); assert.deepEqual(values, [1, 2]); assert.deepEqual(actual, _.take(_.take(_.filter(array, predicate), 2))); actual = _(array).take(6).takeRight(4).take(2).takeRight().value(); assert.deepEqual(actual, _.takeRight(_.take(_.takeRight(_.take(array, 6), 4), 2))); values = []; actual = _(array).take(array.length - 1).filter(predicate).take(6).takeRight(4).take(2).takeRight().value(); assert.deepEqual(values, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]); assert.deepEqual(actual, _.takeRight(_.take(_.takeRight(_.take(_.filter(_.take(array, array.length - 1), predicate), 6), 4), 2))); } else { skipAssert(assert, 6); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.takeRight'); (function() { var array = [1, 2, 3]; QUnit.test('should take the last two elements', function(assert) { assert.expect(1); assert.deepEqual(_.takeRight(array, 2), [2, 3]); }); QUnit.test('should treat falsey `n` values, except `undefined`, as `0`', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, function(value) { return value === undefined ? [3] : []; }); var actual = lodashStable.map(falsey, function(n) { return _.takeRight(array, n); }); assert.deepEqual(actual, expected); }); QUnit.test('should return an empty array when `n` < `1`', function(assert) { assert.expect(3); lodashStable.each([0, -1, -Infinity], function(n) { assert.deepEqual(_.takeRight(array, n), []); }); }); QUnit.test('should return all elements when `n` >= `length`', function(assert) { assert.expect(4); lodashStable.each([3, 4, Math.pow(2, 32), Infinity], function(n) { assert.deepEqual(_.takeRight(array, n), array); }); }); QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(1); var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], actual = lodashStable.map(array, _.takeRight); assert.deepEqual(actual, [[3], [6], [9]]); }); QUnit.test('should work in a lazy sequence', function(assert) { assert.expect(6); if (!isNpm) { var array = lodashStable.range(LARGE_ARRAY_SIZE), predicate = function(value) { values.push(value); return isEven(value); }, values = [], actual = _(array).takeRight(2).takeRight().value(); assert.deepEqual(actual, _.takeRight(_.takeRight(array))); actual = _(array).filter(predicate).takeRight(2).takeRight().value(); assert.deepEqual(values, array); assert.deepEqual(actual, _.takeRight(_.takeRight(_.filter(array, predicate), 2))); actual = _(array).takeRight(6).take(4).takeRight(2).take().value(); assert.deepEqual(actual, _.take(_.takeRight(_.take(_.takeRight(array, 6), 4), 2))); values = []; actual = _(array).filter(predicate).takeRight(6).take(4).takeRight(2).take().value(); assert.deepEqual(values, array); assert.deepEqual(actual, _.take(_.takeRight(_.take(_.takeRight(_.filter(array, predicate), 6), 4), 2))); } else { skipAssert(assert, 6); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.takeRightWhile'); (function() { var array = [1, 2, 3, 4]; var objects = [ { 'a': 0, 'b': 0 }, { 'a': 1, 'b': 1 }, { 'a': 2, 'b': 2 } ]; QUnit.test('should take elements while `predicate` returns truthy', function(assert) { assert.expect(1); var actual = _.takeRightWhile(array, function(n) { return n > 2; }); assert.deepEqual(actual, [3, 4]); }); QUnit.test('should provide correct `predicate` arguments', function(assert) { assert.expect(1); var args; _.takeRightWhile(array, function() { args = slice.call(arguments); }); assert.deepEqual(args, [4, 3, array]); }); QUnit.test('should work with `_.matches` shorthands', function(assert) { assert.expect(1); assert.deepEqual(_.takeRightWhile(objects, { 'b': 2 }), objects.slice(2)); }); QUnit.test('should work with `_.matchesProperty` shorthands', function(assert) { assert.expect(1); assert.deepEqual(_.takeRightWhile(objects, ['b', 2]), objects.slice(2)); }); QUnit.test('should work with `_.property` shorthands', function(assert) { assert.expect(1); assert.deepEqual(_.takeRightWhile(objects, 'b'), objects.slice(1)); }); QUnit.test('should work in a lazy sequence', function(assert) { assert.expect(3); if (!isNpm) { var array = lodashStable.range(LARGE_ARRAY_SIZE), predicate = function(n) { return n > 2; }, expected = _.takeRightWhile(array, predicate), wrapped = _(array).takeRightWhile(predicate); assert.deepEqual(wrapped.value(), expected); assert.deepEqual(wrapped.reverse().value(), expected.slice().reverse()); assert.strictEqual(wrapped.last(), _.last(expected)); } else { skipAssert(assert, 3); } }); QUnit.test('should provide correct `predicate` arguments in a lazy sequence', function(assert) { assert.expect(5); if (!isNpm) { var args, array = lodashStable.range(LARGE_ARRAY_SIZE + 1); var expected = [ square(LARGE_ARRAY_SIZE), LARGE_ARRAY_SIZE - 1, lodashStable.map(array.slice(1), square) ]; _(array).slice(1).takeRightWhile(function(value, index, array) { args = slice.call(arguments); }).value(); assert.deepEqual(args, [LARGE_ARRAY_SIZE, LARGE_ARRAY_SIZE - 1, array.slice(1)]); _(array).slice(1).map(square).takeRightWhile(function(value, index, array) { args = slice.call(arguments); }).value(); assert.deepEqual(args, expected); _(array).slice(1).map(square).takeRightWhile(function(value, index) { args = slice.call(arguments); }).value(); assert.deepEqual(args, expected); _(array).slice(1).map(square).takeRightWhile(function(index) { args = slice.call(arguments); }).value(); assert.deepEqual(args, [square(LARGE_ARRAY_SIZE)]); _(array).slice(1).map(square).takeRightWhile(function() { args = slice.call(arguments); }).value(); assert.deepEqual(args, expected); } else { skipAssert(assert, 5); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.takeWhile'); (function() { var array = [1, 2, 3, 4]; var objects = [ { 'a': 2, 'b': 2 }, { 'a': 1, 'b': 1 }, { 'a': 0, 'b': 0 } ]; QUnit.test('should take elements while `predicate` returns truthy', function(assert) { assert.expect(1); var actual = _.takeWhile(array, function(n) { return n < 3; }); assert.deepEqual(actual, [1, 2]); }); QUnit.test('should provide correct `predicate` arguments', function(assert) { assert.expect(1); var args; _.takeWhile(array, function() { args = slice.call(arguments); }); assert.deepEqual(args, [1, 0, array]); }); QUnit.test('should work with `_.matches` shorthands', function(assert) { assert.expect(1); assert.deepEqual(_.takeWhile(objects, { 'b': 2 }), objects.slice(0, 1)); }); QUnit.test('should work with `_.matchesProperty` shorthands', function(assert) { assert.expect(1); assert.deepEqual(_.takeWhile(objects, ['b', 2]), objects.slice(0, 1)); }); QUnit.test('should work with `_.property` shorthands', function(assert) { assert.expect(1); assert.deepEqual(_.takeWhile(objects, 'b'), objects.slice(0, 2)); }); QUnit.test('should work in a lazy sequence', function(assert) { assert.expect(3); if (!isNpm) { var array = lodashStable.range(LARGE_ARRAY_SIZE), predicate = function(n) { return n < 3; }, expected = _.takeWhile(array, predicate), wrapped = _(array).takeWhile(predicate); assert.deepEqual(wrapped.value(), expected); assert.deepEqual(wrapped.reverse().value(), expected.slice().reverse()); assert.strictEqual(wrapped.last(), _.last(expected)); } else { skipAssert(assert, 3); } }); QUnit.test('should work in a lazy sequence with `take`', function(assert) { assert.expect(1); if (!isNpm) { var array = lodashStable.range(LARGE_ARRAY_SIZE); var actual = _(array) .takeWhile(function(n) { return n < 4; }) .take(2) .takeWhile(function(n) { return n == 0; }) .value(); assert.deepEqual(actual, [0]); } else { skipAssert(assert); } }); QUnit.test('should provide correct `predicate` arguments in a lazy sequence', function(assert) { assert.expect(5); if (!isNpm) { var args, array = lodashStable.range(LARGE_ARRAY_SIZE + 1), expected = [1, 0, lodashStable.map(array.slice(1), square)]; _(array).slice(1).takeWhile(function(value, index, array) { args = slice.call(arguments); }).value(); assert.deepEqual(args, [1, 0, array.slice(1)]); _(array).slice(1).map(square).takeWhile(function(value, index, array) { args = slice.call(arguments); }).value(); assert.deepEqual(args, expected); _(array).slice(1).map(square).takeWhile(function(value, index) { args = slice.call(arguments); }).value(); assert.deepEqual(args, expected); _(array).slice(1).map(square).takeWhile(function(value) { args = slice.call(arguments); }).value(); assert.deepEqual(args, [1]); _(array).slice(1).map(square).takeWhile(function() { args = slice.call(arguments); }).value(); assert.deepEqual(args, expected); } else { skipAssert(assert, 5); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.tap'); (function() { QUnit.test('should intercept and return the given value', function(assert) { assert.expect(2); if (!isNpm) { var intercepted, array = [1, 2, 3]; var actual = _.tap(array, function(value) { intercepted = value; }); assert.strictEqual(actual, array); assert.strictEqual(intercepted, array); } else { skipAssert(assert, 2); } }); QUnit.test('should intercept unwrapped values and return wrapped values when chaining', function(assert) { assert.expect(2); if (!isNpm) { var intercepted, array = [1, 2, 3]; var wrapped = _(array).tap(function(value) { intercepted = value; value.pop(); }); assert.ok(wrapped instanceof _); wrapped.value(); assert.strictEqual(intercepted, array); } else { skipAssert(assert, 2); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.template'); (function() { QUnit.test('should escape values in "escape" delimiters', function(assert) { assert.expect(1); var strings = ['

<%- value %>

', '

<%-value%>

', '

<%-\nvalue\n%>

'], expected = lodashStable.map(strings, lodashStable.constant('

&<>"'/

')), data = { 'value': '&<>"\'/' }; var actual = lodashStable.map(strings, function(string) { return _.template(string)(data); }); assert.deepEqual(actual, expected); }); QUnit.test('should not reference `_.escape` when "escape" delimiters are not used', function(assert) { assert.expect(1); var compiled = _.template('<%= typeof __e %>'); assert.strictEqual(compiled({}), 'undefined'); }); QUnit.test('should evaluate JavaScript in "evaluate" delimiters', function(assert) { assert.expect(1); var compiled = _.template( '' ); var data = { 'collection': { 'a': 'A', 'b': 'B' } }, actual = compiled(data); assert.strictEqual(actual, ''); }); QUnit.test('should support "evaluate" delimiters with single line comments (test production builds)', function(assert) { assert.expect(1); var compiled = _.template('<% // A code comment. %><% if (value) { %>yap<% } else { %>nope<% } %>'), data = { 'value': true }; assert.strictEqual(compiled(data), 'yap'); }); QUnit.test('should support referencing variables declared in "evaluate" delimiters from other delimiters', function(assert) { assert.expect(1); var compiled = _.template('<% var b = a; %><%= b.value %>'), data = { 'a': { 'value': 1 } }; assert.strictEqual(compiled(data), '1'); }); QUnit.test('should interpolate data properties in "interpolate" delimiters', function(assert) { assert.expect(1); var strings = ['<%= a %>BC', '<%=a%>BC', '<%=\na\n%>BC'], expected = lodashStable.map(strings, lodashStable.constant('ABC')), data = { 'a': 'A' }; var actual = lodashStable.map(strings, function(string) { return _.template(string)(data); }); assert.deepEqual(actual, expected); }); QUnit.test('should support "interpolate" delimiters with escaped values', function(assert) { assert.expect(1); var compiled = _.template('<%= a ? "a=\\"A\\"" : "" %>'), data = { 'a': true }; assert.strictEqual(compiled(data), 'a="A"'); }); QUnit.test('should support "interpolate" delimiters containing ternary operators', function(assert) { assert.expect(1); var compiled = _.template('<%= value ? value : "b" %>'), data = { 'value': 'a' }; assert.strictEqual(compiled(data), 'a'); }); QUnit.test('should support "interpolate" delimiters containing global values', function(assert) { assert.expect(1); var compiled = _.template('<%= typeof Math.abs %>'); try { var actual = compiled(); } catch (e) {} assert.strictEqual(actual, 'function'); }); QUnit.test('should support complex "interpolate" delimiters', function(assert) { assert.expect(22); lodashStable.forOwn({ '<%= a + b %>': '3', '<%= b - a %>': '1', '<%= a = b %>': '2', '<%= !a %>': 'false', '<%= ~a %>': '-2', '<%= a * b %>': '2', '<%= a / b %>': '0.5', '<%= a % b %>': '1', '<%= a >> b %>': '0', '<%= a << b %>': '4', '<%= a & b %>': '0', '<%= a ^ b %>': '3', '<%= a | b %>': '3', '<%= {}.toString.call(0) %>': numberTag, '<%= a.toFixed(2) %>': '1.00', '<%= obj["a"] %>': '1', '<%= delete a %>': 'true', '<%= "a" in obj %>': 'true', '<%= obj instanceof Object %>': 'true', '<%= new Boolean %>': 'false', '<%= typeof a %>': 'number', '<%= void a %>': '' }, function(value, key) { var compiled = _.template(key), data = { 'a': 1, 'b': 2 }; assert.strictEqual(compiled(data), value, key); }); }); QUnit.test('should support ES6 template delimiters', function(assert) { assert.expect(2); var data = { 'value': 2 }; assert.strictEqual(_.template('1${value}3')(data), '123'); assert.strictEqual(_.template('${"{" + value + "\\}"}')(data), '{2}'); }); QUnit.test('should support the "imports" option', function(assert) { assert.expect(1); var compiled = _.template('<%= a %>', { 'imports': { 'a': 1 } }); assert.strictEqual(compiled({}), '1'); }); QUnit.test('should support the "variable" options', function(assert) { assert.expect(1); var compiled = _.template( '<% _.each( data.a, function( value ) { %>' + '<%= value.valueOf() %>' + '<% }) %>', { 'variable': 'data' } ); var data = { 'a': [1, 2, 3] }; try { assert.strictEqual(compiled(data), '123'); } catch (e) { assert.ok(false, e.message); } }); QUnit.test('should support custom delimiters', function(assert) { assert.expect(2); lodashStable.times(2, function(index) { var settingsClone = lodashStable.clone(_.templateSettings); var settings = lodashStable.assign(index ? _.templateSettings : {}, { 'escape': /\{\{-([\s\S]+?)\}\}/g, 'evaluate': /\{\{([\s\S]+?)\}\}/g, 'interpolate': /\{\{=([\s\S]+?)\}\}/g }); var expected = '', compiled = _.template('', index ? null : settings), data = { 'collection': ['a & A', 'b & B'] }; assert.strictEqual(compiled(data), expected); lodashStable.assign(_.templateSettings, settingsClone); }); }); QUnit.test('should support custom delimiters containing special characters', function(assert) { assert.expect(2); lodashStable.times(2, function(index) { var settingsClone = lodashStable.clone(_.templateSettings); var settings = lodashStable.assign(index ? _.templateSettings : {}, { 'escape': /<\?-([\s\S]+?)\?>/g, 'evaluate': /<\?([\s\S]+?)\?>/g, 'interpolate': /<\?=([\s\S]+?)\?>/g }); var expected = '', compiled = _.template('', index ? null : settings), data = { 'collection': ['a & A', 'b & B'] }; assert.strictEqual(compiled(data), expected); lodashStable.assign(_.templateSettings, settingsClone); }); }); QUnit.test('should use a `with` statement by default', function(assert) { assert.expect(1); var compiled = _.template('<%= index %><%= collection[index] %><% _.each(collection, function(value, index) { %><%= index %><% }); %>'), actual = compiled({ 'index': 1, 'collection': ['a', 'b', 'c'] }); assert.strictEqual(actual, '1b012'); }); QUnit.test('should use `_.templateSettings.imports._.templateSettings`', function(assert) { assert.expect(1); var lodash = _.templateSettings.imports._, settingsClone = lodashStable.clone(lodash.templateSettings); lodash.templateSettings = lodashStable.assign(lodash.templateSettings, { 'interpolate': /\{\{=([\s\S]+?)\}\}/g }); var compiled = _.template('{{= a }}'); assert.strictEqual(compiled({ 'a': 1 }), '1'); if (settingsClone) { lodashStable.assign(lodash.templateSettings, settingsClone); } else { delete lodash.templateSettings; } }); QUnit.test('should fallback to `_.templateSettings`', function(assert) { assert.expect(1); var lodash = _.templateSettings.imports._, delimiter = _.templateSettings.interpolate; _.templateSettings.imports._ = { 'escape': lodashStable.escape }; _.templateSettings.interpolate = /\{\{=([\s\S]+?)\}\}/g; var compiled = _.template('{{= a }}'); assert.strictEqual(compiled({ 'a': 1 }), '1'); _.templateSettings.imports._ = lodash; _.templateSettings.interpolate = delimiter; }); QUnit.test('should ignore `null` delimiters', function(assert) { assert.expect(3); var delimiter = { 'escape': /\{\{-([\s\S]+?)\}\}/g, 'evaluate': /\{\{([\s\S]+?)\}\}/g, 'interpolate': /\{\{=([\s\S]+?)\}\}/g }; lodashStable.forOwn({ 'escape': '{{- a }}', 'evaluate': '{{ print(a) }}', 'interpolate': '{{= a }}' }, function(value, key) { var settings = { 'escape': null, 'evaluate': null, 'interpolate': null }; settings[key] = delimiter[key]; var expected = '1 <%- a %> <% print(a) %> <%= a %>', compiled = _.template(value + ' <%- a %> <% print(a) %> <%= a %>', settings), data = { 'a': 1 }; assert.strictEqual(compiled(data), expected); }); }); QUnit.test('should work without delimiters', function(assert) { assert.expect(1); var expected = 'abc'; assert.strictEqual(_.template(expected)({}), expected); }); QUnit.test('should work with `this` references', function(assert) { assert.expect(2); var compiled = _.template('a<%= this.String("b") %>c'); assert.strictEqual(compiled(), 'abc'); var object = { 'b': 'B' }; object.compiled = _.template('A<%= this.b %>C', { 'variable': 'obj' }); assert.strictEqual(object.compiled(), 'ABC'); }); QUnit.test('should work with backslashes', function(assert) { assert.expect(1); var compiled = _.template('<%= a %> \\b'), data = { 'a': 'A' }; assert.strictEqual(compiled(data), 'A \\b'); }); QUnit.test('should work with escaped characters in string literals', function(assert) { assert.expect(2); var compiled = _.template('<% print("\'\\n\\r\\t\\u2028\\u2029\\\\") %>'); assert.strictEqual(compiled(), "'\n\r\t\u2028\u2029\\"); var data = { 'a': 'A' }; compiled = _.template('\'\n\r\t<%= a %>\u2028\u2029\\"'); assert.strictEqual(compiled(data), '\'\n\r\tA\u2028\u2029\\"'); }); QUnit.test('should handle \\u2028 & \\u2029 characters', function(assert) { assert.expect(1); var compiled = _.template('\u2028<%= "\\u2028\\u2029" %>\u2029'); assert.strictEqual(compiled(), '\u2028\u2028\u2029\u2029'); }); QUnit.test('should work with statements containing quotes', function(assert) { assert.expect(1); var compiled = _.template("<%\ if (a == 'A' || a == \"a\") {\ %>'a',\"A\"<%\ } %>" ); var data = { 'a': 'A' }; assert.strictEqual(compiled(data), "'a',\"A\""); }); QUnit.test('should work with templates containing newlines and comments', function(assert) { assert.expect(1); var compiled = _.template('<%\n\ // A code comment.\n\ if (value) { value += 3; }\n\ %>

<%= value %>

' ); assert.strictEqual(compiled({ 'value': 3 }), '

6

'); }); QUnit.test('should tokenize delimiters', function(assert) { assert.expect(1); var compiled = _.template(''), data = { 'type': 1 }; assert.strictEqual(compiled(data), ''); }); QUnit.test('should evaluate delimiters once', function(assert) { assert.expect(1); var actual = [], compiled = _.template('<%= func("a") %><%- func("b") %><% func("c") %>'), data = { 'func': function(value) { actual.push(value); } }; compiled(data); assert.deepEqual(actual, ['a', 'b', 'c']); }); QUnit.test('should match delimiters before escaping text', function(assert) { assert.expect(1); var compiled = _.template('<<\n a \n>>', { 'evaluate': /<<(.*?)>>/g }); assert.strictEqual(compiled(), '<<\n a \n>>'); }); QUnit.test('should resolve nullish values to an empty string', function(assert) { assert.expect(3); var compiled = _.template('<%= a %><%- a %>'), data = { 'a': null }; assert.strictEqual(compiled(data), ''); data = { 'a': undefined }; assert.strictEqual(compiled(data), ''); data = { 'a': {} }; compiled = _.template('<%= a.b %><%- a.b %>'); assert.strictEqual(compiled(data), ''); }); QUnit.test('should return an empty string for empty values', function(assert) { assert.expect(1); var values = [, null, undefined, ''], expected = lodashStable.map(values, stubString), data = { 'a': 1 }; var actual = lodashStable.map(values, function(value, index) { var compiled = index ? _.template(value) : _.template(); return compiled(data); }); assert.deepEqual(actual, expected); }); QUnit.test('should parse delimiters without newlines', function(assert) { assert.expect(1); var expected = '<<\nprint("

" + (value ? "yes" : "no") + "

")\n>>', compiled = _.template(expected, { 'evaluate': /<<(.+?)>>/g }), data = { 'value': true }; assert.strictEqual(compiled(data), expected); }); QUnit.test('should support recursive calls', function(assert) { assert.expect(1); var compiled = _.template('<%= a %><% a = _.template(c)(obj) %><%= a %>'), data = { 'a': 'A', 'b': 'B', 'c': '<%= b %>' }; assert.strictEqual(compiled(data), 'AB'); }); QUnit.test('should coerce `text` to a string', function(assert) { assert.expect(1); var object = { 'toString': lodashStable.constant('<%= a %>') }, data = { 'a': 1 }; assert.strictEqual(_.template(object)(data), '1'); }); QUnit.test('should not modify the `options` object', function(assert) { assert.expect(1); var options = {}; _.template('', options); assert.deepEqual(options, {}); }); QUnit.test('should not modify `_.templateSettings` when `options` are given', function(assert) { assert.expect(2); var data = { 'a': 1 }; assert.notOk('a' in _.templateSettings); _.template('', {}, data); assert.notOk('a' in _.templateSettings); delete _.templateSettings.a; }); QUnit.test('should not error for non-object `data` and `options` values', function(assert) { assert.expect(2); _.template('')(1); assert.ok(true, '`data` value'); _.template('', 1)(1); assert.ok(true, '`options` value'); }); QUnit.test('should expose the source on compiled templates', function(assert) { assert.expect(1); var compiled = _.template('x'), values = [String(compiled), compiled.source], expected = lodashStable.map(values, stubTrue); var actual = lodashStable.map(values, function(value) { return lodashStable.includes(value, '__p'); }); assert.deepEqual(actual, expected); }); QUnit.test('should expose the source on SyntaxErrors', function(assert) { assert.expect(1); try { _.template('<% if x %>'); } catch (e) { var source = e.source; } assert.ok(lodashStable.includes(source, '__p')); }); QUnit.test('should not include sourceURLs in the source', function(assert) { assert.expect(1); var options = { 'sourceURL': '/a/b/c' }, compiled = _.template('x', options), values = [compiled.source, undefined]; try { _.template('<% if x %>', options); } catch (e) { values[1] = e.source; } var expected = lodashStable.map(values, stubFalse); var actual = lodashStable.map(values, function(value) { return lodashStable.includes(value, 'sourceURL'); }); assert.deepEqual(actual, expected); }); QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(1); var array = ['<%= a %>', '<%- b %>', '<% print(c) %>'], compiles = lodashStable.map(array, _.template), data = { 'a': 'one', 'b': '"two"', 'c': 'three' }; var actual = lodashStable.map(compiles, function(compiled) { return compiled(data); }); assert.deepEqual(actual, ['one', '"two"', 'three']); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.truncate'); (function() { var string = 'hi-diddly-ho there, neighborino'; QUnit.test('should use a default `length` of `30`', function(assert) { assert.expect(1); assert.strictEqual(_.truncate(string), 'hi-diddly-ho there, neighbo...'); }); QUnit.test('should not truncate if `string` is <= `length`', function(assert) { assert.expect(2); assert.strictEqual(_.truncate(string, { 'length': string.length }), string); assert.strictEqual(_.truncate(string, { 'length': string.length + 2 }), string); }); QUnit.test('should truncate string the given length', function(assert) { assert.expect(1); assert.strictEqual(_.truncate(string, { 'length': 24 }), 'hi-diddly-ho there, n...'); }); QUnit.test('should support a `omission` option', function(assert) { assert.expect(1); assert.strictEqual(_.truncate(string, { 'omission': ' [...]' }), 'hi-diddly-ho there, neig [...]'); }); QUnit.test('should coerce nullish `omission` values to strings', function(assert) { assert.expect(2); assert.strictEqual(_.truncate(string, { 'omission': null }), 'hi-diddly-ho there, neighbnull'); assert.strictEqual(_.truncate(string, { 'omission': undefined }), 'hi-diddly-ho there, nundefined'); }); QUnit.test('should support a `length` option', function(assert) { assert.expect(1); assert.strictEqual(_.truncate(string, { 'length': 4 }), 'h...'); }); QUnit.test('should support a `separator` option', function(assert) { assert.expect(3); assert.strictEqual(_.truncate(string, { 'length': 24, 'separator': ' ' }), 'hi-diddly-ho there,...'); assert.strictEqual(_.truncate(string, { 'length': 24, 'separator': /,? +/ }), 'hi-diddly-ho there...'); assert.strictEqual(_.truncate(string, { 'length': 24, 'separator': /,? +/g }), 'hi-diddly-ho there...'); }); QUnit.test('should treat negative `length` as `0`', function(assert) { assert.expect(2); lodashStable.each([0, -2], function(length) { assert.strictEqual(_.truncate(string, { 'length': length }), '...'); }); }); QUnit.test('should coerce `length` to an integer', function(assert) { assert.expect(4); lodashStable.each(['', NaN, 4.6, '4'], function(length, index) { var actual = index > 1 ? 'h...' : '...'; assert.strictEqual(_.truncate(string, { 'length': { 'valueOf': lodashStable.constant(length) } }), actual); }); }); QUnit.test('should coerce `string` to a string', function(assert) { assert.expect(2); assert.strictEqual(_.truncate(Object(string), { 'length': 4 }), 'h...'); assert.strictEqual(_.truncate({ 'toString': lodashStable.constant(string) }, { 'length': 5 }), 'hi...'); }); QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(1); var actual = lodashStable.map([string, string, string], _.truncate), truncated = 'hi-diddly-ho there, neighbo...'; assert.deepEqual(actual, [truncated, truncated, truncated]); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.throttle'); (function() { QUnit.test('should throttle a function', function(assert) { assert.expect(2); var done = assert.async(); var callCount = 0, throttled = _.throttle(function() { callCount++; }, 32); throttled(); throttled(); throttled(); var lastCount = callCount; assert.ok(callCount); setTimeout(function() { assert.ok(callCount > lastCount); done(); }, 64); }); QUnit.test('subsequent calls should return the result of the first call', function(assert) { assert.expect(5); var done = assert.async(); var throttled = _.throttle(identity, 32), results = [throttled('a'), throttled('b')]; assert.deepEqual(results, ['a', 'a']); setTimeout(function() { var results = [throttled('c'), throttled('d')]; assert.notEqual(results[0], 'a'); assert.notStrictEqual(results[0], undefined); assert.notEqual(results[1], 'd'); assert.notStrictEqual(results[1], undefined); done(); }, 64); }); QUnit.test('should clear timeout when `func` is called', function(assert) { assert.expect(1); var done = assert.async(); if (!isModularize) { var callCount = 0, dateCount = 0; var lodash = _.runInContext({ 'Date': { 'now': function() { return ++dateCount == 5 ? Infinity : +new Date; } } }); var throttled = lodash.throttle(function() { callCount++; }, 32); throttled(); throttled(); setTimeout(function() { assert.strictEqual(callCount, 2); done(); }, 64); } else { skipAssert(assert); done(); } }); QUnit.test('should not trigger a trailing call when invoked once', function(assert) { assert.expect(2); var done = assert.async(); var callCount = 0, throttled = _.throttle(function() { callCount++; }, 32); throttled(); assert.strictEqual(callCount, 1); setTimeout(function() { assert.strictEqual(callCount, 1); done(); }, 64); }); lodashStable.times(2, function(index) { QUnit.test('should trigger a call when invoked repeatedly' + (index ? ' and `leading` is `false`' : ''), function(assert) { assert.expect(1); var done = assert.async(); var callCount = 0, limit = (argv || isPhantom) ? 1000 : 320, options = index ? { 'leading': false } : {}, throttled = _.throttle(function() { callCount++; }, 32, options); var start = +new Date; while ((new Date - start) < limit) { throttled(); } var actual = callCount > 1; setTimeout(function() { assert.ok(actual); done(); }, 1); }); }); QUnit.test('should trigger a second throttled call as soon as possible', function(assert) { assert.expect(3); var done = assert.async(); var callCount = 0; var throttled = _.throttle(function() { callCount++; }, 128, { 'leading': false }); throttled(); setTimeout(function() { assert.strictEqual(callCount, 1); throttled(); }, 192); setTimeout(function() { assert.strictEqual(callCount, 1); }, 254); setTimeout(function() { assert.strictEqual(callCount, 2); done(); }, 384); }); QUnit.test('should apply default options', function(assert) { assert.expect(2); var done = assert.async(); var callCount = 0, throttled = _.throttle(function() { callCount++; }, 32, {}); throttled(); throttled(); assert.strictEqual(callCount, 1); setTimeout(function() { assert.strictEqual(callCount, 2); done(); }, 128); }); QUnit.test('should support a `leading` option', function(assert) { assert.expect(2); var withLeading = _.throttle(identity, 32, { 'leading': true }); assert.strictEqual(withLeading('a'), 'a'); var withoutLeading = _.throttle(identity, 32, { 'leading': false }); assert.strictEqual(withoutLeading('a'), undefined); }); QUnit.test('should support a `trailing` option', function(assert) { assert.expect(6); var done = assert.async(); var withCount = 0, withoutCount = 0; var withTrailing = _.throttle(function(value) { withCount++; return value; }, 64, { 'trailing': true }); var withoutTrailing = _.throttle(function(value) { withoutCount++; return value; }, 64, { 'trailing': false }); assert.strictEqual(withTrailing('a'), 'a'); assert.strictEqual(withTrailing('b'), 'a'); assert.strictEqual(withoutTrailing('a'), 'a'); assert.strictEqual(withoutTrailing('b'), 'a'); setTimeout(function() { assert.strictEqual(withCount, 2); assert.strictEqual(withoutCount, 1); done(); }, 256); }); QUnit.test('should not update `lastCalled`, at the end of the timeout, when `trailing` is `false`', function(assert) { assert.expect(1); var done = assert.async(); var callCount = 0; var throttled = _.throttle(function() { callCount++; }, 64, { 'trailing': false }); throttled(); throttled(); setTimeout(function() { throttled(); throttled(); }, 96); setTimeout(function() { assert.ok(callCount > 1); done(); }, 192); }); QUnit.test('should work with a system time of `0`', function(assert) { assert.expect(3); var done = assert.async(); if (!isModularize) { var callCount = 0, dateCount = 0; var lodash = _.runInContext({ 'Date': { 'now': function() { return ++dateCount < 4 ? 0 : +new Date; } } }); var throttled = lodash.throttle(function(value) { callCount++; return value; }, 32); var results = [throttled('a'), throttled('b'), throttled('c')]; assert.deepEqual(results, ['a', 'a', 'a']); assert.strictEqual(callCount, 1); setTimeout(function() { assert.strictEqual(callCount, 2); done(); }, 64); } else { skipAssert(assert, 3); done(); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.debounce and lodash.throttle'); lodashStable.each(['debounce', 'throttle'], function(methodName) { var func = _[methodName], isDebounce = methodName == 'debounce'; QUnit.test('`_.' + methodName + '` should not error for non-object `options` values', function(assert) { assert.expect(1); func(noop, 32, 1); assert.ok(true); }); QUnit.test('`_.' + methodName + '` should use a default `wait` of `0`', function(assert) { assert.expect(1); var done = assert.async(); var callCount = 0, funced = func(function() { callCount++; }); funced(); setTimeout(function() { funced(); assert.strictEqual(callCount, isDebounce ? 1 : 2); done(); }, 32); }); QUnit.test('`_.' + methodName + '` should invoke `func` with the correct `this` binding', function(assert) { assert.expect(1); var done = assert.async(); var actual = [], object = { 'funced': func(function() { actual.push(this); }, 32) }, expected = lodashStable.times(isDebounce ? 1 : 2, lodashStable.constant(object)); object.funced(); if (!isDebounce) { object.funced(); } setTimeout(function() { assert.deepEqual(actual, expected); done(); }, 64); }); QUnit.test('`_.' + methodName + '` supports recursive calls', function(assert) { assert.expect(2); var done = assert.async(); var actual = [], args = lodashStable.map(['a', 'b', 'c'], function(chr) { return [{}, chr]; }), expected = args.slice(), queue = args.slice(); var funced = func(function() { var current = [this]; push.apply(current, arguments); actual.push(current); var next = queue.shift(); if (next) { funced.call(next[0], next[1]); } }, 32); var next = queue.shift(); funced.call(next[0], next[1]); assert.deepEqual(actual, expected.slice(0, isDebounce ? 0 : 1)); setTimeout(function() { assert.deepEqual(actual, expected.slice(0, actual.length)); done(); }, 256); }); QUnit.test('`_.' + methodName + '` should work if the system time is set backwards', function(assert) { assert.expect(1); var done = assert.async(); if (!isModularize) { var callCount = 0, dateCount = 0; var lodash = _.runInContext({ 'Date': { 'now': function() { return ++dateCount == 4 ? +new Date(2012, 3, 23, 23, 27, 18) : +new Date; } } }); var funced = lodash[methodName](function() { callCount++; }, 32); funced(); setTimeout(function() { funced(); assert.strictEqual(callCount, isDebounce ? 1 : 2); done(); }, 64); } else { skipAssert(assert); done(); } }); QUnit.test('`_.' + methodName + '` should support cancelling delayed calls', function(assert) { assert.expect(1); var done = assert.async(); var callCount = 0; var funced = func(function() { callCount++; }, 32, { 'leading': false }); funced(); funced.cancel(); setTimeout(function() { assert.strictEqual(callCount, 0); done(); }, 64); }); QUnit.test('`_.' + methodName + '` should reset `lastCalled` after cancelling', function(assert) { assert.expect(3); var done = assert.async(); var callCount = 0; var funced = func(function() { return ++callCount; }, 32, { 'leading': true }); assert.strictEqual(funced(), 1); funced.cancel(); assert.strictEqual(funced(), 2); funced(); setTimeout(function() { assert.strictEqual(callCount, 3); done(); }, 64); }); QUnit.test('`_.' + methodName + '` should support flushing delayed calls', function(assert) { assert.expect(2); var done = assert.async(); var callCount = 0; var funced = func(function() { return ++callCount; }, 32, { 'leading': false }); funced(); assert.strictEqual(funced.flush(), 1); setTimeout(function() { assert.strictEqual(callCount, 1); done(); }, 64); }); QUnit.test('`_.' + methodName + '` should noop `cancel` and `flush` when nothing is queued', function(assert) { assert.expect(2); var done = assert.async(); var callCount = 0, funced = func(function() { callCount++; }, 32); funced.cancel(); assert.strictEqual(funced.flush(), undefined); setTimeout(function() { assert.strictEqual(callCount, 0); done(); }, 64); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.times'); (function() { QUnit.test('should coerce non-finite `n` values to `0`', function(assert) { assert.expect(3); lodashStable.each([-Infinity, NaN, Infinity], function(n) { assert.deepEqual(_.times(n), []); }); }); QUnit.test('should coerce `n` to an integer', function(assert) { assert.expect(1); var actual = _.times(2.6, _.identity); assert.deepEqual(actual, [0, 1]); }); QUnit.test('should provide correct `iteratee` arguments', function(assert) { assert.expect(1); var args; _.times(1, function(assert) { args || (args = slice.call(arguments)); }); assert.deepEqual(args, [0]); }); QUnit.test('should use `_.identity` when `iteratee` is nullish', function(assert) { assert.expect(1); var values = [, null, undefined], expected = lodashStable.map(values, lodashStable.constant([0, 1, 2])); var actual = lodashStable.map(values, function(value, index) { return index ? _.times(3, value) : _.times(3); }); assert.deepEqual(actual, expected); }); QUnit.test('should return an array of the results of each `iteratee` execution', function(assert) { assert.expect(1); assert.deepEqual(_.times(3, doubled), [0, 2, 4]); }); QUnit.test('should return an empty array for falsey and negative `n` values', function(assert) { assert.expect(1); var values = falsey.concat(-1, -Infinity), expected = lodashStable.map(values, stubArray); var actual = lodashStable.map(values, function(value, index) { return index ? _.times(value) : _.times(); }); assert.deepEqual(actual, expected); }); QUnit.test('should return an unwrapped value when implicitly chaining', function(assert) { assert.expect(1); if (!isNpm) { assert.deepEqual(_(3).times(), [0, 1, 2]); } else { skipAssert(assert); } }); QUnit.test('should return a wrapped value when explicitly chaining', function(assert) { assert.expect(1); if (!isNpm) { assert.ok(_(3).chain().times() instanceof _); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.toArray'); (function() { QUnit.test('should convert objects to arrays', function(assert) { assert.expect(1); assert.deepEqual(_.toArray({ 'a': 1, 'b': 2 }), [1, 2]); }); QUnit.test('should convert iterables to arrays', function(assert) { assert.expect(1); if (Symbol && Symbol.iterator) { var object = { '0': 'a', 'length': 1 }; object[Symbol.iterator] = arrayProto[Symbol.iterator]; assert.deepEqual(_.toArray(object), ['a']); } else { skipAssert(assert); } }); QUnit.test('should convert maps to arrays', function(assert) { assert.expect(1); if (Map) { var map = new Map; map.set('a', 1); map.set('b', 2); assert.deepEqual(_.toArray(map), [['a', 1], ['b', 2]]); } else { skipAssert(assert); } }); QUnit.test('should convert strings to arrays', function(assert) { assert.expect(3); assert.deepEqual(_.toArray(''), []); assert.deepEqual(_.toArray('ab'), ['a', 'b']); assert.deepEqual(_.toArray(Object('ab')), ['a', 'b']); }); QUnit.test('should work in a lazy sequence', function(assert) { assert.expect(2); if (!isNpm) { var array = lodashStable.range(LARGE_ARRAY_SIZE + 1); var object = lodashStable.zipObject(lodashStable.times(LARGE_ARRAY_SIZE, function(index) { return ['key' + index, index]; })); var actual = _(array).slice(1).map(String).toArray().value(); assert.deepEqual(actual, lodashStable.map(array.slice(1), String)); actual = _(object).toArray().slice(1).map(String).value(); assert.deepEqual(actual, _.map(_.toArray(object).slice(1), String)); } else { skipAssert(assert, 2); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.toLower'); (function() { QUnit.test('should convert whole string to lower case', function(assert) { assert.expect(3); assert.deepEqual(_.toLower('--Foo-Bar--'), '--foo-bar--'); assert.deepEqual(_.toLower('fooBar'), 'foobar'); assert.deepEqual(_.toLower('__FOO_BAR__'), '__foo_bar__'); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.toUpper'); (function() { QUnit.test('should convert whole string to upper case', function(assert) { assert.expect(3); assert.deepEqual(_.toUpper('--Foo-Bar'), '--FOO-BAR'); assert.deepEqual(_.toUpper('fooBar'), 'FOOBAR'); assert.deepEqual(_.toUpper('__FOO_BAR__'), '__FOO_BAR__'); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.slice and lodash.toArray'); lodashStable.each(['slice', 'toArray'], function(methodName) { var array = [1, 2, 3], func = _[methodName]; QUnit.test('`_.' + methodName + '` should return a dense array', function(assert) { assert.expect(3); var sparse = Array(3); sparse[1] = 2; var actual = func(sparse); assert.ok('0' in actual); assert.ok('2' in actual); assert.deepEqual(actual, sparse); }); QUnit.test('`_.' + methodName + '` should treat array-like objects like arrays', function(assert) { assert.expect(2); var object = { '0': 'a', 'length': 1 }; assert.deepEqual(func(object), ['a']); assert.deepEqual(func(args), array); }); QUnit.test('`_.' + methodName + '` should return a shallow clone of arrays', function(assert) { assert.expect(2); var actual = func(array); assert.deepEqual(actual, array); assert.notStrictEqual(actual, array); }); QUnit.test('`_.' + methodName + '` should work with a node list for `collection`', function(assert) { assert.expect(1); if (document) { try { var actual = func(document.getElementsByTagName('body')); } catch (e) {} assert.deepEqual(actual, [body]); } else { skipAssert(assert); } }); }); /*--------------------------------------------------------------------------*/ QUnit.module('toInteger methods'); lodashStable.each(['toInteger', 'toSafeInteger'], function(methodName) { var func = _[methodName], isSafe = methodName == 'toSafeInteger'; QUnit.test('`_.' + methodName + '` should convert values to integers', function(assert) { assert.expect(6); assert.strictEqual(func(-5.6), -5); assert.strictEqual(func('5.6'), 5); assert.strictEqual(func(), 0); assert.strictEqual(func(NaN), 0); var expected = isSafe ? MAX_SAFE_INTEGER : MAX_INTEGER; assert.strictEqual(func(Infinity), expected); assert.strictEqual(func(-Infinity), -expected); }); QUnit.test('`_.' + methodName + '` should support `value` of `-0`', function(assert) { assert.expect(1); assert.strictEqual(1 / func(-0), -Infinity); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.toLength'); (function() { QUnit.test('should return a valid length', function(assert) { assert.expect(4); assert.strictEqual(_.toLength(-1), 0); assert.strictEqual(_.toLength('1'), 1); assert.strictEqual(_.toLength(1.1), 1); assert.strictEqual(_.toLength(MAX_INTEGER), MAX_ARRAY_LENGTH); }); QUnit.test('should return `value` if a valid length', function(assert) { assert.expect(3); assert.strictEqual(_.toLength(0), 0); assert.strictEqual(_.toLength(3), 3); assert.strictEqual(_.toLength(MAX_ARRAY_LENGTH), MAX_ARRAY_LENGTH); }); QUnit.test('should convert `-0` to `0`', function(assert) { assert.expect(1); assert.strictEqual(1 / _.toLength(-0), Infinity); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('number coercion methods'); lodashStable.each(['toFinite', 'toInteger', 'toNumber', 'toSafeInteger'], function(methodName) { var func = _[methodName]; QUnit.test('`_.' + methodName + '` should preserve the sign of `0`', function(assert) { assert.expect(2); var values = [0, '0', -0, '-0'], expected = [[0, Infinity], [0, Infinity], [-0, -Infinity], [-0, -Infinity]]; lodashStable.times(2, function(index) { var others = lodashStable.map(values, index ? Object : identity); var actual = lodashStable.map(others, function(value) { var result = func(value); return [result, 1 / result]; }); assert.deepEqual(actual, expected); }); }); }); lodashStable.each(['toFinite', 'toInteger', 'toLength', 'toNumber', 'toSafeInteger'], function(methodName) { var func = _[methodName], isToFinite = methodName == 'toFinite', isToLength = methodName == 'toLength', isToNumber = methodName == 'toNumber', isToSafeInteger = methodName == 'toSafeInteger'; function negative(string) { return '-' + string; } function pad(string) { return whitespace + string + whitespace; } function positive(string) { return '+' + string; } QUnit.test('`_.' + methodName + '` should pass thru primitive number values', function(assert) { assert.expect(1); var values = [0, 1, NaN]; var expected = lodashStable.map(values, function(value) { return (!isToNumber && value !== value) ? 0 : value; }); var actual = lodashStable.map(values, func); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should convert number primitives and objects to numbers', function(assert) { assert.expect(1); var values = [2, 1.2, MAX_SAFE_INTEGER, MAX_INTEGER, Infinity, NaN]; var expected = lodashStable.map(values, function(value) { if (!isToNumber) { if (!isToFinite && value == 1.2) { value = 1; } else if (value == Infinity) { value = MAX_INTEGER; } else if (value !== value) { value = 0; } if (isToLength || isToSafeInteger) { value = Math.min(value, isToLength ? MAX_ARRAY_LENGTH : MAX_SAFE_INTEGER); } } var neg = isToLength ? 0 : -value; return [value, value, neg, neg]; }); var actual = lodashStable.map(values, function(value) { return [func(value), func(Object(value)), func(-value), func(Object(-value))]; }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should convert string primitives and objects to numbers', function(assert) { assert.expect(1); var transforms = [identity, pad, positive, negative]; var values = [ '10', '1.234567890', (MAX_SAFE_INTEGER + ''), '1e+308', '1e308', '1E+308', '1E308', '5e-324', '5E-324', 'Infinity', 'NaN' ]; var expected = lodashStable.map(values, function(value) { var n = +value; if (!isToNumber) { if (!isToFinite && n == 1.234567890) { n = 1; } else if (n == Infinity) { n = MAX_INTEGER; } else if ((!isToFinite && n == Number.MIN_VALUE) || n !== n) { n = 0; } if (isToLength || isToSafeInteger) { n = Math.min(n, isToLength ? MAX_ARRAY_LENGTH : MAX_SAFE_INTEGER); } } var neg = isToLength ? 0 : -n; return [n, n, n, n, n, n, neg, neg]; }); var actual = lodashStable.map(values, function(value) { return lodashStable.flatMap(transforms, function(mod) { return [func(mod(value)), func(Object(mod(value)))]; }); }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should convert binary/octal strings to numbers', function(assert) { assert.expect(1); var numbers = [42, 5349, 1715004], transforms = [identity, pad], values = ['0b101010', '0o12345', '0x1a2b3c']; var expected = lodashStable.map(numbers, function(n) { return lodashStable.times(8, lodashStable.constant(n)); }); var actual = lodashStable.map(values, function(value) { var upper = value.toUpperCase(); return lodashStable.flatMap(transforms, function(mod) { return [func(mod(value)), func(Object(mod(value))), func(mod(upper)), func(Object(mod(upper)))]; }); }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should convert invalid binary/octal strings to `' + (isToNumber ? 'NaN' : '0') + '`', function(assert) { assert.expect(1); var transforms = [identity, pad, positive, negative], values = ['0b', '0o', '0x', '0b1010102', '0o123458', '0x1a2b3x']; var expected = lodashStable.map(values, function(n) { return lodashStable.times(8, lodashStable.constant(isToNumber ? NaN : 0)); }); var actual = lodashStable.map(values, function(value) { return lodashStable.flatMap(transforms, function(mod) { return [func(mod(value)), func(Object(mod(value)))]; }); }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should convert symbols to `' + (isToNumber ? 'NaN' : '0') + '`', function(assert) { assert.expect(1); if (Symbol) { var object1 = Object(symbol), object2 = Object(symbol), values = [symbol, object1, object2], expected = lodashStable.map(values, lodashStable.constant(isToNumber ? NaN : 0)); object2.valueOf = undefined; var actual = lodashStable.map(values, func); assert.deepEqual(actual, expected); } else { skipAssert(assert); } }); QUnit.test('`_.' + methodName + '` should convert empty values to `0` or `NaN`', function(assert) { assert.expect(1); var values = falsey.concat(whitespace); var expected = lodashStable.map(values, function(value) { return (isToNumber && value !== whitespace) ? Number(value) : 0; }); var actual = lodashStable.map(values, function(value, index) { return index ? func(value) : func(); }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should coerce objects to numbers', function(assert) { assert.expect(1); var values = [ {}, [], [1], [1, 2], { 'valueOf': '1.1' }, { 'valueOf': '1.1', 'toString': lodashStable.constant('2.2') }, { 'valueOf': lodashStable.constant('1.1'), 'toString': '2.2' }, { 'valueOf': lodashStable.constant('1.1'), 'toString': lodashStable.constant('2.2') }, { 'valueOf': lodashStable.constant('-0x1a2b3c') }, { 'toString': lodashStable.constant('-0x1a2b3c') }, { 'valueOf': lodashStable.constant('0o12345') }, { 'toString': lodashStable.constant('0o12345') }, { 'valueOf': lodashStable.constant('0b101010') }, { 'toString': lodashStable.constant('0b101010') } ]; var expected = [ NaN, 0, 1, NaN, NaN, 2.2, 1.1, 1.1, NaN, NaN, 5349, 5349, 42, 42 ]; if (isToFinite) { expected = [ 0, 0, 1, 0, 0, 2.2, 1.1, 1.1, 0, 0, 5349, 5349, 42, 42 ]; } else if (!isToNumber) { expected = [ 0, 0, 1, 0, 0, 2, 1, 1, 0, 0, 5349, 5349, 42, 42 ]; } var actual = lodashStable.map(values, func); assert.deepEqual(actual, expected); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.toPairs'); (function() { QUnit.test('should be aliased', function(assert) { assert.expect(1); assert.strictEqual(_.entries, _.toPairs); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.toPairsIn'); (function() { QUnit.test('should be aliased', function(assert) { assert.expect(1); assert.strictEqual(_.entriesIn, _.toPairsIn); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('toPairs methods'); lodashStable.each(['toPairs', 'toPairsIn'], function(methodName) { var func = _[methodName], isToPairs = methodName == 'toPairs'; QUnit.test('`_.' + methodName + '` should create an array of string keyed-value pairs', function(assert) { assert.expect(1); var object = { 'a': 1, 'b': 2 }, actual = lodashStable.sortBy(func(object), 0); assert.deepEqual(actual, [['a', 1], ['b', 2]]); }); QUnit.test('`_.' + methodName + '` should ' + (isToPairs ? 'not ' : '') + 'include inherited string keyed property values', function(assert) { assert.expect(1); function Foo() { this.a = 1; } Foo.prototype.b = 2; var expected = isToPairs ? [['a', 1]] : [['a', 1], ['b', 2]], actual = lodashStable.sortBy(func(new Foo), 0); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should convert objects with a `length` property', function(assert) { assert.expect(1); var object = { '0': 'a', '1': 'b', 'length': 2 }, actual = lodashStable.sortBy(func(object), 0); assert.deepEqual(actual, [['0', 'a'], ['1', 'b'], ['length', 2]]); }); QUnit.test('`_.' + methodName + '` should convert maps', function(assert) { assert.expect(1); if (Map) { var map = new Map; map.set('a', 1); map.set('b', 2); assert.deepEqual(func(map), [['a', 1], ['b', 2]]); } else { skipAssert(assert); } }); QUnit.test('`_.' + methodName + '` should convert sets', function(assert) { assert.expect(1); if (Set) { var set = new Set; set.add(1); set.add(2); assert.deepEqual(func(set), [[1, 1], [2, 2]]); } else { skipAssert(assert); } }); QUnit.test('`_.' + methodName + '` should convert strings', function(assert) { assert.expect(2); lodashStable.each(['xo', Object('xo')], function(string) { var actual = lodashStable.sortBy(func(string), 0); assert.deepEqual(actual, [['0', 'x'], ['1', 'o']]); }); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.toPath'); (function() { QUnit.test('should convert a string to a path', function(assert) { assert.expect(2); assert.deepEqual(_.toPath('a.b.c'), ['a', 'b', 'c']); assert.deepEqual(_.toPath('a[0].b.c'), ['a', '0', 'b', 'c']); }); QUnit.test('should coerce array elements to strings', function(assert) { assert.expect(4); var array = ['a', 'b', 'c']; lodashStable.each([array, lodashStable.map(array, Object)], function(value) { var actual = _.toPath(value); assert.deepEqual(actual, array); assert.notStrictEqual(actual, array); }); }); QUnit.test('should return new path array', function(assert) { assert.expect(1); assert.notStrictEqual(_.toPath('a.b.c'), _.toPath('a.b.c')); }); QUnit.test('should not coerce symbols to strings', function(assert) { assert.expect(4); if (Symbol) { var object = Object(symbol); lodashStable.each([symbol, object, [symbol], [object]], function(value) { var actual = _.toPath(value); assert.ok(lodashStable.isSymbol(actual[0])); }); } else { skipAssert(assert, 4); } }); QUnit.test('should handle complex paths', function(assert) { assert.expect(1); var actual = _.toPath('a[-1.23]["[\\"b\\"]"].c[\'[\\\'d\\\']\'][\ne\n][f].g'); assert.deepEqual(actual, ['a', '-1.23', '["b"]', 'c', "['d']", '\ne\n', 'f', 'g']); }); QUnit.test('should handle consecutive empty brackets and dots', function(assert) { assert.expect(12); var expected = ['', 'a']; assert.deepEqual(_.toPath('.a'), expected); assert.deepEqual(_.toPath('[].a'), expected); expected = ['', '', 'a']; assert.deepEqual(_.toPath('..a'), expected); assert.deepEqual(_.toPath('[][].a'), expected); expected = ['a', '', 'b']; assert.deepEqual(_.toPath('a..b'), expected); assert.deepEqual(_.toPath('a[].b'), expected); expected = ['a', '', '', 'b']; assert.deepEqual(_.toPath('a...b'), expected); assert.deepEqual(_.toPath('a[][].b'), expected); expected = ['a', '']; assert.deepEqual(_.toPath('a.'), expected); assert.deepEqual(_.toPath('a[]'), expected); expected = ['a', '', '']; assert.deepEqual(_.toPath('a..'), expected); assert.deepEqual(_.toPath('a[][]'), expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.toPlainObject'); (function() { QUnit.test('should flatten inherited string keyed properties', function(assert) { assert.expect(1); function Foo() { this.b = 2; } Foo.prototype.c = 3; var actual = lodashStable.assign({ 'a': 1 }, _.toPlainObject(new Foo)); assert.deepEqual(actual, { 'a': 1, 'b': 2, 'c': 3 }); }); QUnit.test('should convert `arguments` objects to plain objects', function(assert) { assert.expect(1); var actual = _.toPlainObject(args), expected = { '0': 1, '1': 2, '2': 3 }; assert.deepEqual(actual, expected); }); QUnit.test('should convert arrays to plain objects', function(assert) { assert.expect(1); var actual = _.toPlainObject(['a', 'b', 'c']), expected = { '0': 'a', '1': 'b', '2': 'c' }; assert.deepEqual(actual, expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.toString'); (function() { QUnit.test('should treat nullish values as empty strings', function(assert) { assert.expect(1); var values = [, null, undefined], expected = lodashStable.map(values, stubString); var actual = lodashStable.map(values, function(value, index) { return index ? _.toString(value) : _.toString(); }); assert.deepEqual(actual, expected); }); QUnit.test('should preserve the sign of `0`', function(assert) { assert.expect(1); var values = [-0, Object(-0), 0, Object(0)], expected = ['-0', '-0', '0', '0'], actual = lodashStable.map(values, _.toString); assert.deepEqual(actual, expected); }); QUnit.test('should preserve the sign of `0` in an array', function(assert) { assert.expect(1); var values = [-0, Object(-0), 0, Object(0)]; assert.deepEqual(_.toString(values), '-0,-0,0,0'); }); QUnit.test('should not error on symbols', function(assert) { assert.expect(1); if (Symbol) { try { assert.strictEqual(_.toString(symbol), 'Symbol(a)'); } catch (e) { assert.ok(false, e.message); } } else { skipAssert(assert); } }); QUnit.test('should not error on an array of symbols', function(assert) { assert.expect(1); if (Symbol) { try { assert.strictEqual(_.toString([symbol]), 'Symbol(a)'); } catch (e) { assert.ok(false, e.message); } } else { skipAssert(assert); } }); QUnit.test('should return the `toString` result of the wrapped value', function(assert) { assert.expect(1); if (!isNpm) { var wrapped = _([1, 2, 3]); assert.strictEqual(wrapped.toString(), '1,2,3'); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.transform'); (function() { function Foo() { this.a = 1; this.b = 2; this.c = 3; } QUnit.test('should create an object with the same `[[Prototype]]` as `object` when `accumulator` is nullish', function(assert) { assert.expect(4); var accumulators = [, null, undefined], object = new Foo, expected = lodashStable.map(accumulators, stubTrue); var iteratee = function(result, value, key) { result[key] = square(value); }; var mapper = function(accumulator, index) { return index ? _.transform(object, iteratee, accumulator) : _.transform(object, iteratee); }; var results = lodashStable.map(accumulators, mapper); var actual = lodashStable.map(results, function(result) { return result instanceof Foo; }); assert.deepEqual(actual, expected); expected = lodashStable.map(accumulators, lodashStable.constant({ 'a': 1, 'b': 4, 'c': 9 })); actual = lodashStable.map(results, lodashStable.toPlainObject); assert.deepEqual(actual, expected); object = { 'a': 1, 'b': 2, 'c': 3 }; actual = lodashStable.map(accumulators, mapper); assert.deepEqual(actual, expected); object = [1, 2, 3]; expected = lodashStable.map(accumulators, lodashStable.constant([1, 4, 9])); actual = lodashStable.map(accumulators, mapper); assert.deepEqual(actual, expected); }); QUnit.test('should create regular arrays from typed arrays', function(assert) { assert.expect(1); var expected = lodashStable.map(typedArrays, stubTrue); var actual = lodashStable.map(typedArrays, function(type) { var Ctor = root[type], array = Ctor ? new Ctor(new ArrayBuffer(24)) : []; return lodashStable.isArray(_.transform(array, noop)); }); assert.deepEqual(actual, expected); }); QUnit.test('should support an `accumulator` value', function(assert) { assert.expect(6); var values = [new Foo, [1, 2, 3], { 'a': 1, 'b': 2, 'c': 3 }], expected = lodashStable.map(values, lodashStable.constant([1, 4, 9])); var actual = lodashStable.map(values, function(value) { return _.transform(value, function(result, value) { result.push(square(value)); }, []); }); assert.deepEqual(actual, expected); var object = { 'a': 1, 'b': 4, 'c': 9 }, expected = [object, { '0': 1, '1': 4, '2': 9 }, object]; actual = lodashStable.map(values, function(value) { return _.transform(value, function(result, value, key) { result[key] = square(value); }, {}); }); assert.deepEqual(actual, expected); lodashStable.each([[], {}], function(accumulator) { var actual = lodashStable.map(values, function(value) { return _.transform(value, noop, accumulator); }); assert.ok(lodashStable.every(actual, function(result) { return result === accumulator; })); assert.strictEqual(_.transform(null, null, accumulator), accumulator); }); }); QUnit.test('should treat sparse arrays as dense', function(assert) { assert.expect(1); var actual = _.transform(Array(1), function(result, value, index) { result[index] = String(value); }); assert.deepEqual(actual, ['undefined']); }); QUnit.test('should work without an `iteratee`', function(assert) { assert.expect(1); assert.ok(_.transform(new Foo) instanceof Foo); }); QUnit.test('should ensure `object` is an object before using its `[[Prototype]]`', function(assert) { assert.expect(2); var Ctors = [Boolean, Boolean, Number, Number, Number, String, String], values = [false, true, 0, 1, NaN, '', 'a'], expected = lodashStable.map(values, stubObject); var results = lodashStable.map(values, function(value) { return _.transform(value); }); assert.deepEqual(results, expected); expected = lodashStable.map(values, stubFalse); var actual = lodashStable.map(results, function(value, index) { return value instanceof Ctors[index]; }); assert.deepEqual(actual, expected); }); QUnit.test('should ensure `object` constructor is a function before using its `[[Prototype]]`', function(assert) { assert.expect(1); Foo.prototype.constructor = null; assert.notOk(_.transform(new Foo) instanceof Foo); Foo.prototype.constructor = Foo; }); QUnit.test('should create an empty object when given a falsey `object`', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, stubObject); var actual = lodashStable.map(falsey, function(object, index) { return index ? _.transform(object) : _.transform(); }); assert.deepEqual(actual, expected); }); lodashStable.each({ 'array': [1, 2, 3], 'object': { 'a': 1, 'b': 2, 'c': 3 } }, function(object, key) { QUnit.test('should provide correct `iteratee` arguments when transforming an ' + key, function(assert) { assert.expect(2); var args; _.transform(object, function() { args || (args = slice.call(arguments)); }); var first = args[0]; if (key == 'array') { assert.ok(first !== object && lodashStable.isArray(first)); assert.deepEqual(args, [first, 1, 0, object]); } else { assert.ok(first !== object && lodashStable.isPlainObject(first)); assert.deepEqual(args, [first, 1, 'a', object]); } }); }); QUnit.test('should create an object from the same realm as `object`', function(assert) { assert.expect(1); var objects = lodashStable.filter(realm, function(value) { return lodashStable.isObject(value) && !lodashStable.isElement(value); }); var expected = lodashStable.map(objects, stubTrue); var actual = lodashStable.map(objects, function(object) { var Ctor = object.constructor, result = _.transform(object); if (result === object) { return false; } if (lodashStable.isTypedArray(object)) { return result instanceof Array; } return result instanceof Ctor || !(new Ctor instanceof Ctor); }); assert.deepEqual(actual, expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('trim methods'); lodashStable.each(['trim', 'trimStart', 'trimEnd'], function(methodName, index) { var func = _[methodName], parts = []; if (index != 2) { parts.push('leading'); } if (index != 1) { parts.push('trailing'); } parts = parts.join(' and '); QUnit.test('`_.' + methodName + '` should remove ' + parts + ' whitespace', function(assert) { assert.expect(1); var string = whitespace + 'a b c' + whitespace, expected = (index == 2 ? whitespace : '') + 'a b c' + (index == 1 ? whitespace : ''); assert.strictEqual(func(string), expected); }); QUnit.test('`_.' + methodName + '` should coerce `string` to a string', function(assert) { assert.expect(1); var object = { 'toString': lodashStable.constant(whitespace + 'a b c' + whitespace) }, expected = (index == 2 ? whitespace : '') + 'a b c' + (index == 1 ? whitespace : ''); assert.strictEqual(func(object), expected); }); QUnit.test('`_.' + methodName + '` should remove ' + parts + ' `chars`', function(assert) { assert.expect(1); var string = '-_-a-b-c-_-', expected = (index == 2 ? '-_-' : '') + 'a-b-c' + (index == 1 ? '-_-' : ''); assert.strictEqual(func(string, '_-'), expected); }); QUnit.test('`_.' + methodName + '` should coerce `chars` to a string', function(assert) { assert.expect(1); var object = { 'toString': lodashStable.constant('_-') }, string = '-_-a-b-c-_-', expected = (index == 2 ? '-_-' : '') + 'a-b-c' + (index == 1 ? '-_-' : ''); assert.strictEqual(func(string, object), expected); }); QUnit.test('`_.' + methodName + '` should return an empty string for empty values and `chars`', function(assert) { assert.expect(6); lodashStable.each([null, '_-'], function(chars) { assert.strictEqual(func(null, chars), ''); assert.strictEqual(func(undefined, chars), ''); assert.strictEqual(func('', chars), ''); }); }); QUnit.test('`_.' + methodName + '` should work with `undefined` or empty string values for `chars`', function(assert) { assert.expect(2); var string = whitespace + 'a b c' + whitespace, expected = (index == 2 ? whitespace : '') + 'a b c' + (index == 1 ? whitespace : ''); assert.strictEqual(func(string, undefined), expected); assert.strictEqual(func(string, ''), string); }); QUnit.test('`_.' + methodName + '` should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(1); var string = Object(whitespace + 'a b c' + whitespace), trimmed = (index == 2 ? whitespace : '') + 'a b c' + (index == 1 ? whitespace : ''), actual = lodashStable.map([string, string, string], func); assert.deepEqual(actual, [trimmed, trimmed, trimmed]); }); QUnit.test('`_.' + methodName + '` should return an unwrapped value when implicitly chaining', function(assert) { assert.expect(1); if (!isNpm) { var string = whitespace + 'a b c' + whitespace, expected = (index == 2 ? whitespace : '') + 'a b c' + (index == 1 ? whitespace : ''); assert.strictEqual(_(string)[methodName](), expected); } else { skipAssert(assert); } }); QUnit.test('`_.' + methodName + '` should return a wrapped value when explicitly chaining', function(assert) { assert.expect(1); if (!isNpm) { var string = whitespace + 'a b c' + whitespace; assert.ok(_(string).chain()[methodName]() instanceof _); } else { skipAssert(assert); } }); }); /*--------------------------------------------------------------------------*/ QUnit.module('uncommon symbols'); (function() { var flag = '\ud83c\uddfa\ud83c\uddf8', heart = '\u2764' + emojiVar, hearts = '\ud83d\udc95', comboGlyph = '\ud83d\udc68\u200d' + heart + '\u200d\ud83d\udc8B\u200d\ud83d\udc68', hashKeycap = '#' + emojiVar + '\u20e3', leafs = '\ud83c\udf42', mic = '\ud83c\udf99', noMic = mic + '\u20e0', raisedHand = '\u270B' + emojiVar, rocket = '\ud83d\ude80', thumbsUp = '\ud83d\udc4d'; QUnit.test('should account for astral symbols', function(assert) { assert.expect(34); var allHearts = _.repeat(hearts, 10), chars = hearts + comboGlyph, string = 'A ' + leafs + ', ' + comboGlyph + ', and ' + rocket, trimChars = comboGlyph + hearts, trimString = trimChars + string + trimChars; assert.strictEqual(_.camelCase(hearts + ' the ' + leafs), hearts + 'The' + leafs); assert.strictEqual(_.camelCase(string), 'a' + leafs + comboGlyph + 'And' + rocket); assert.strictEqual(_.capitalize(rocket), rocket); assert.strictEqual(_.pad(string, 16), ' ' + string + ' '); assert.strictEqual(_.padStart(string, 16), ' ' + string); assert.strictEqual(_.padEnd(string, 16), string + ' '); assert.strictEqual(_.pad(string, 16, chars), hearts + string + chars); assert.strictEqual(_.padStart(string, 16, chars), chars + hearts + string); assert.strictEqual(_.padEnd(string, 16, chars), string + chars + hearts); assert.strictEqual(_.size(string), 13); assert.deepEqual(_.split(string, ' '), ['A', leafs + ',', comboGlyph + ',', 'and', rocket]); assert.deepEqual(_.split(string, ' ', 3), ['A', leafs + ',', comboGlyph + ',']); assert.deepEqual(_.split(string, undefined), [string]); assert.deepEqual(_.split(string, undefined, -1), [string]); assert.deepEqual(_.split(string, undefined, 0), []); var expected = ['A', ' ', leafs, ',', ' ', comboGlyph, ',', ' ', 'a', 'n', 'd', ' ', rocket]; assert.deepEqual(_.split(string, ''), expected); assert.deepEqual(_.split(string, '', 6), expected.slice(0, 6)); assert.deepEqual(_.toArray(string), expected); assert.strictEqual(_.trim(trimString, chars), string); assert.strictEqual(_.trimStart(trimString, chars), string + trimChars); assert.strictEqual(_.trimEnd(trimString, chars), trimChars + string); assert.strictEqual(_.truncate(string, { 'length': 13 }), string); assert.strictEqual(_.truncate(string, { 'length': 6 }), 'A ' + leafs + '...'); assert.deepEqual(_.words(string), ['A', leafs, comboGlyph, 'and', rocket]); assert.deepEqual(_.toArray(hashKeycap), [hashKeycap]); assert.deepEqual(_.toArray(noMic), [noMic]); lodashStable.times(2, function(index) { var separator = index ? RegExp(hearts) : hearts, options = { 'length': 4, 'separator': separator }, actual = _.truncate(string, options); assert.strictEqual(actual, 'A...'); assert.strictEqual(actual.length, 4); actual = _.truncate(allHearts, options); assert.strictEqual(actual, hearts + '...'); assert.strictEqual(actual.length, 5); }); }); QUnit.test('should account for combining diacritical marks', function(assert) { assert.expect(1); var values = lodashStable.map(comboMarks, function(mark) { return 'o' + mark; }); var expected = lodashStable.map(values, function(value) { return [1, [value], [value]]; }); var actual = lodashStable.map(values, function(value) { return [_.size(value), _.toArray(value), _.words(value)]; }); assert.deepEqual(actual, expected); }); QUnit.test('should account for fitzpatrick modifiers', function(assert) { assert.expect(1); var values = lodashStable.map(fitzModifiers, function(modifier) { return thumbsUp + modifier; }); var expected = lodashStable.map(values, function(value) { return [1, [value], [value]]; }); var actual = lodashStable.map(values, function(value) { return [_.size(value), _.toArray(value), _.words(value)]; }); assert.deepEqual(actual, expected); }); QUnit.test('should account for regional symbols', function(assert) { assert.expect(6); var pair = flag.match(/\ud83c[\udde6-\uddff]/g), regionals = pair.join(' '); assert.strictEqual(_.size(flag), 1); assert.strictEqual(_.size(regionals), 3); assert.deepEqual(_.toArray(flag), [flag]); assert.deepEqual(_.toArray(regionals), [pair[0], ' ', pair[1]]); assert.deepEqual(_.words(flag), [flag]); assert.deepEqual(_.words(regionals), [pair[0], pair[1]]); }); QUnit.test('should account for variation selectors', function(assert) { assert.expect(3); assert.strictEqual(_.size(heart), 1); assert.deepEqual(_.toArray(heart), [heart]); assert.deepEqual(_.words(heart), [heart]); }); QUnit.test('should account for variation selectors with fitzpatrick modifiers', function(assert) { assert.expect(1); var values = lodashStable.map(fitzModifiers, function(modifier) { return raisedHand + modifier; }); var expected = lodashStable.map(values, function(value) { return [1, [value], [value]]; }); var actual = lodashStable.map(values, function(value) { return [_.size(value), _.toArray(value), _.words(value)]; }); assert.deepEqual(actual, expected); }); QUnit.test('should match lone surrogates', function(assert) { assert.expect(3); var pair = hearts.split(''), surrogates = pair[0] + ' ' + pair[1]; assert.strictEqual(_.size(surrogates), 3); assert.deepEqual(_.toArray(surrogates), [pair[0], ' ', pair[1]]); assert.deepEqual(_.words(surrogates), []); }); QUnit.test('should match side by side fitzpatrick modifiers separately ', function(assert) { assert.expect(1); var string = fitzModifiers[0] + fitzModifiers[0]; assert.deepEqual(_.toArray(string), [fitzModifiers[0], fitzModifiers[0]]); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.unary'); (function() { function fn() { return slice.call(arguments); } QUnit.test('should cap the number of arguments provided to `func`', function(assert) { assert.expect(1); var actual = lodashStable.map(['6', '8', '10'], _.unary(parseInt)); assert.deepEqual(actual, [6, 8, 10]); }); QUnit.test('should not force a minimum argument count', function(assert) { assert.expect(1); var capped = _.unary(fn); assert.deepEqual(capped(), []); }); QUnit.test('should use `this` binding of function', function(assert) { assert.expect(1); var capped = _.unary(function(a, b) { return this; }), object = { 'capped': capped }; assert.strictEqual(object.capped(), object); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.unescape'); (function() { var escaped = '&<>"'/', unescaped = '&<>"\'/'; escaped += escaped; unescaped += unescaped; QUnit.test('should unescape entities in order', function(assert) { assert.expect(1); assert.strictEqual(_.unescape('&lt;'), '<'); }); QUnit.test('should unescape the proper entities', function(assert) { assert.expect(1); assert.strictEqual(_.unescape(escaped), unescaped); }); QUnit.test('should handle strings with nothing to unescape', function(assert) { assert.expect(1); assert.strictEqual(_.unescape('abc'), 'abc'); }); QUnit.test('should unescape the same characters escaped by `_.escape`', function(assert) { assert.expect(1); assert.strictEqual(_.unescape(_.escape(unescaped)), unescaped); }); lodashStable.each(['`', '/'], function(entity) { QUnit.test('should not unescape the "' + entity + '" entity', function(assert) { assert.expect(1); assert.strictEqual(_.unescape(entity), entity); }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('union methods'); lodashStable.each(['union', 'unionBy', 'unionWith'], function(methodName) { var func = _[methodName]; QUnit.test('`_.' + methodName + '` should return the union of two arrays', function(assert) { assert.expect(1); var actual = func([2], [1, 2]); assert.deepEqual(actual, [2, 1]); }); QUnit.test('`_.' + methodName + '` should return the union of multiple arrays', function(assert) { assert.expect(1); var actual = func([2], [1, 2], [2, 3]); assert.deepEqual(actual, [2, 1, 3]); }); QUnit.test('`_.' + methodName + '` should not flatten nested arrays', function(assert) { assert.expect(1); var actual = func([1, 3, 2], [1, [5]], [2, [4]]); assert.deepEqual(actual, [1, 3, 2, [5], [4]]); }); QUnit.test('`_.' + methodName + '` should ignore values that are not arrays or `arguments` objects', function(assert) { assert.expect(3); var array = [0]; assert.deepEqual(func(array, 3, { '0': 1 }, null), array); assert.deepEqual(func(null, array, null, [2, 1]), [0, 2, 1]); assert.deepEqual(func(array, null, args, null), [0, 1, 2, 3]); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.unionBy'); (function() { QUnit.test('should accept an `iteratee`', function(assert) { assert.expect(2); var actual = _.unionBy([2.1], [1.2, 2.3], Math.floor); assert.deepEqual(actual, [2.1, 1.2]); actual = _.unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); assert.deepEqual(actual, [{ 'x': 1 }, { 'x': 2 }]); }); QUnit.test('should provide correct `iteratee` arguments', function(assert) { assert.expect(1); var args; _.unionBy([2.1], [1.2, 2.3], function() { args || (args = slice.call(arguments)); }); assert.deepEqual(args, [2.1]); }); QUnit.test('should output values from the first possible array', function(assert) { assert.expect(1); var actual = _.unionBy([{ 'x': 1, 'y': 1 }], [{ 'x': 1, 'y': 2 }], 'x'); assert.deepEqual(actual, [{ 'x': 1, 'y': 1 }]); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.unionWith'); (function() { QUnit.test('should work with a `comparator`', function(assert) { assert.expect(1); var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }], others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }], actual = _.unionWith(objects, others, lodashStable.isEqual); assert.deepEqual(actual, [objects[0], objects[1], others[0]]); }); QUnit.test('should output values from the first possible array', function(assert) { assert.expect(1); var objects = [{ 'x': 1, 'y': 1 }], others = [{ 'x': 1, 'y': 2 }]; var actual = _.unionWith(objects, others, function(a, b) { return a.x == b.x; }); assert.deepEqual(actual, [{ 'x': 1, 'y': 1 }]); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('uniq methods'); lodashStable.each(['uniq', 'uniqBy', 'uniqWith', 'sortedUniq', 'sortedUniqBy'], function(methodName) { var func = _[methodName], isSorted = /^sorted/.test(methodName), objects = [{ 'a': 2 }, { 'a': 3 }, { 'a': 1 }, { 'a': 2 }, { 'a': 3 }, { 'a': 1 }]; if (isSorted) { objects = _.sortBy(objects, 'a'); } else { QUnit.test('`_.' + methodName + '` should return unique values of an unsorted array', function(assert) { assert.expect(1); var array = [2, 1, 2]; assert.deepEqual(func(array), [2, 1]); }); } QUnit.test('`_.' + methodName + '` should return unique values of a sorted array', function(assert) { assert.expect(1); var array = [1, 2, 2]; assert.deepEqual(func(array), [1, 2]); }); QUnit.test('`_.' + methodName + '` should treat object instances as unique', function(assert) { assert.expect(1); assert.deepEqual(func(objects), objects); }); QUnit.test('`_.' + methodName + '` should treat `-0` as `0`', function(assert) { assert.expect(1); var actual = lodashStable.map(func([-0, 0]), lodashStable.toString); assert.deepEqual(actual, ['0']); }); QUnit.test('`_.' + methodName + '` should match `NaN`', function(assert) { assert.expect(1); assert.deepEqual(func([NaN, NaN]), [NaN]); }); QUnit.test('`_.' + methodName + '` should work with large arrays', function(assert) { assert.expect(1); var largeArray = [], expected = [0, {}, 'a'], count = Math.ceil(LARGE_ARRAY_SIZE / expected.length); lodashStable.each(expected, function(value) { lodashStable.times(count, function() { largeArray.push(value); }); }); assert.deepEqual(func(largeArray), expected); }); QUnit.test('`_.' + methodName + '` should work with large arrays of `-0` as `0`', function(assert) { assert.expect(1); var largeArray = lodashStable.times(LARGE_ARRAY_SIZE, function(index) { return isEven(index) ? -0 : 0; }); var actual = lodashStable.map(func(largeArray), lodashStable.toString); assert.deepEqual(actual, ['0']); }); QUnit.test('`_.' + methodName + '` should work with large arrays of boolean, `NaN`, and nullish values', function(assert) { assert.expect(1); var largeArray = [], expected = [null, undefined, false, true, NaN], count = Math.ceil(LARGE_ARRAY_SIZE / expected.length); lodashStable.each(expected, function(value) { lodashStable.times(count, function() { largeArray.push(value); }); }); assert.deepEqual(func(largeArray), expected); }); QUnit.test('`_.' + methodName + '` should work with large arrays of symbols', function(assert) { assert.expect(1); if (Symbol) { var largeArray = lodashStable.times(LARGE_ARRAY_SIZE, Symbol); assert.deepEqual(func(largeArray), largeArray); } else { skipAssert(assert); } }); QUnit.test('`_.' + methodName + '` should work with large arrays of well-known symbols', function(assert) { assert.expect(1); // See http://www.ecma-international.org/ecma-262/6.0/#sec-well-known-symbols. if (Symbol) { var expected = [ Symbol.hasInstance, Symbol.isConcatSpreadable, Symbol.iterator, Symbol.match, Symbol.replace, Symbol.search, Symbol.species, Symbol.split, Symbol.toPrimitive, Symbol.toStringTag, Symbol.unscopables ]; var largeArray = [], count = Math.ceil(LARGE_ARRAY_SIZE / expected.length); expected = lodashStable.map(expected, function(symbol) { return symbol || {}; }); lodashStable.each(expected, function(value) { lodashStable.times(count, function() { largeArray.push(value); }); }); assert.deepEqual(func(largeArray), expected); } else { skipAssert(assert); } }); QUnit.test('`_.' + methodName + '` should distinguish between numbers and numeric strings', function(assert) { assert.expect(1); var largeArray = [], expected = ['2', 2, Object('2'), Object(2)], count = Math.ceil(LARGE_ARRAY_SIZE / expected.length); lodashStable.each(expected, function(value) { lodashStable.times(count, function() { largeArray.push(value); }); }); assert.deepEqual(func(largeArray), expected); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.uniq'); (function() { QUnit.test('should perform an unsorted uniq when used as an iteratee for methods like `_.map`', function(assert) { assert.expect(1); var array = [[2, 1, 2], [1, 2, 1]], actual = lodashStable.map(array, lodashStable.uniq); assert.deepEqual(actual, [[2, 1], [1, 2]]); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('uniqBy methods'); lodashStable.each(['uniqBy', 'sortedUniqBy'], function(methodName) { var func = _[methodName], isSorted = methodName == 'sortedUniqBy', objects = [{ 'a': 2 }, { 'a': 3 }, { 'a': 1 }, { 'a': 2 }, { 'a': 3 }, { 'a': 1 }]; if (isSorted) { objects = _.sortBy(objects, 'a'); } QUnit.test('`_.' + methodName + '` should work with an `iteratee`', function(assert) { assert.expect(1); var expected = isSorted ? [{ 'a': 1 }, { 'a': 2 }, { 'a': 3 }] : objects.slice(0, 3); var actual = func(objects, function(object) { return object.a; }); assert.deepEqual(actual, expected); }); QUnit.test('should work with large arrays', function(assert) { assert.expect(2); var largeArray = lodashStable.times(LARGE_ARRAY_SIZE, function() { return [1, 2]; }); var actual = func(largeArray, String); assert.strictEqual(actual[0], largeArray[0]); assert.deepEqual(actual, [[1, 2]]); }); QUnit.test('`_.' + methodName + '` should provide correct `iteratee` arguments', function(assert) { assert.expect(1); var args; func(objects, function() { args || (args = slice.call(arguments)); }); assert.deepEqual(args, [objects[0]]); }); QUnit.test('`_.' + methodName + '` should work with `_.property` shorthands', function(assert) { assert.expect(2); var expected = isSorted ? [{ 'a': 1 }, { 'a': 2 }, { 'a': 3 }] : objects.slice(0, 3), actual = func(objects, 'a'); assert.deepEqual(actual, expected); var arrays = [[2], [3], [1], [2], [3], [1]]; if (isSorted) { arrays = lodashStable.sortBy(arrays, 0); } expected = isSorted ? [[1], [2], [3]] : arrays.slice(0, 3); actual = func(arrays, 0); assert.deepEqual(actual, expected); }); lodashStable.each({ 'an array': [0, 'a'], 'an object': { '0': 'a' }, 'a number': 0, 'a string': '0' }, function(iteratee, key) { QUnit.test('`_.' + methodName + '` should work with ' + key + ' for `iteratee`', function(assert) { assert.expect(1); var actual = func([['a'], ['a'], ['b']], iteratee); assert.deepEqual(actual, [['a'], ['b']]); }); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.uniqWith'); (function() { QUnit.test('should work with a `comparator`', function(assert) { assert.expect(1); var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }], actual = _.uniqWith(objects, lodashStable.isEqual); assert.deepEqual(actual, [objects[0], objects[1]]); }); QUnit.test('should preserve the sign of `0`', function(assert) { assert.expect(1); var largeArray = lodashStable.times(LARGE_ARRAY_SIZE, function(index) { return isEven(index) ? -0 : 0; }); var arrays = [[-0, 0], largeArray], expected = lodashStable.map(arrays, lodashStable.constant(['-0'])); var actual = lodashStable.map(arrays, function(array) { return lodashStable.map(_.uniqWith(array, lodashStable.eq), lodashStable.toString); }); assert.deepEqual(actual, expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.uniqueId'); (function() { QUnit.test('should generate unique ids', function(assert) { assert.expect(1); var actual = lodashStable.times(1000, function(assert) { return _.uniqueId(); }); assert.strictEqual(lodashStable.uniq(actual).length, actual.length); }); QUnit.test('should return a string value when not providing a `prefix`', function(assert) { assert.expect(1); assert.strictEqual(typeof _.uniqueId(), 'string'); }); QUnit.test('should coerce the prefix argument to a string', function(assert) { assert.expect(1); var actual = [_.uniqueId(3), _.uniqueId(2), _.uniqueId(1)]; assert.ok(/3\d+,2\d+,1\d+/.test(actual)); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.unset'); (function() { QUnit.test('should unset property values', function(assert) { assert.expect(4); lodashStable.each(['a', ['a']], function(path) { var object = { 'a': 1, 'c': 2 }; assert.strictEqual(_.unset(object, path), true); assert.deepEqual(object, { 'c': 2 }); }); }); QUnit.test('should preserve the sign of `0`', function(assert) { assert.expect(1); var props = [-0, Object(-0), 0, Object(0)], expected = lodashStable.map(props, lodashStable.constant([true, false])); var actual = lodashStable.map(props, function(key) { var object = { '-0': 'a', '0': 'b' }; return [_.unset(object, key), lodashStable.toString(key) in object]; }); assert.deepEqual(actual, expected); }); QUnit.test('should unset symbol keyed property values', function(assert) { assert.expect(2); if (Symbol) { var object = {}; object[symbol] = 1; assert.strictEqual(_.unset(object, symbol), true); assert.notOk(symbol in object); } else { skipAssert(assert, 2); } }); QUnit.test('should unset deep property values', function(assert) { assert.expect(4); lodashStable.each(['a.b', ['a', 'b']], function(path) { var object = { 'a': { 'b': null } }; assert.strictEqual(_.unset(object, path), true); assert.deepEqual(object, { 'a': {} }); }); }); QUnit.test('should handle complex paths', function(assert) { assert.expect(4); var paths = [ 'a[-1.23]["[\\"b\\"]"].c[\'[\\\'d\\\']\'][\ne\n][f].g', ['a', '-1.23', '["b"]', 'c', "['d']", '\ne\n', 'f', 'g'] ]; lodashStable.each(paths, function(path) { var object = { 'a': { '-1.23': { '["b"]': { 'c': { "['d']": { '\ne\n': { 'f': { 'g': 8 } } } } } } } }; assert.strictEqual(_.unset(object, path), true); assert.notOk('g' in object.a[-1.23]['["b"]'].c["['d']"]['\ne\n'].f); }); }); QUnit.test('should return `true` for nonexistent paths', function(assert) { assert.expect(5); var object = { 'a': { 'b': { 'c': null } } }; lodashStable.each(['z', 'a.z', 'a.b.z', 'a.b.c.z'], function(path) { assert.strictEqual(_.unset(object, path), true); }); assert.deepEqual(object, { 'a': { 'b': { 'c': null } } }); }); QUnit.test('should not error when `object` is nullish', function(assert) { assert.expect(1); var values = [null, undefined], expected = [[true, true], [true, true]]; var actual = lodashStable.map(values, function(value) { try { return [_.unset(value, 'a.b'), _.unset(value, ['a', 'b'])]; } catch (e) { return e.message; } }); assert.deepEqual(actual, expected); }); QUnit.test('should follow `path` over non-plain objects', function(assert) { assert.expect(8); var object = { 'a': '' }, paths = ['constructor.prototype.a', ['constructor', 'prototype', 'a']]; lodashStable.each(paths, function(path) { numberProto.a = 1; var actual = _.unset(0, path); assert.strictEqual(actual, true); assert.notOk('a' in numberProto); delete numberProto.a; }); lodashStable.each(['a.replace.b', ['a', 'replace', 'b']], function(path) { stringProto.replace.b = 1; var actual = _.unset(object, path); assert.strictEqual(actual, true); assert.notOk('a' in stringProto.replace); delete stringProto.replace.b; }); }); QUnit.test('should return `false` for non-configurable properties', function(assert) { assert.expect(1); var object = {}; if (!isStrict) { defineProperty(object, 'a', { 'configurable': false, 'enumerable': true, 'writable': true, 'value': 1, }); assert.strictEqual(_.unset(object, 'a'), false); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.unzipWith'); (function() { QUnit.test('should unzip arrays combining regrouped elements with `iteratee`', function(assert) { assert.expect(1); var array = [[1, 4], [2, 5], [3, 6]]; var actual = _.unzipWith(array, function(a, b, c) { return a + b + c; }); assert.deepEqual(actual, [6, 15]); }); QUnit.test('should provide correct `iteratee` arguments', function(assert) { assert.expect(1); var args; _.unzipWith([[1, 3, 5], [2, 4, 6]], function() { args || (args = slice.call(arguments)); }); assert.deepEqual(args, [1, 2]); }); QUnit.test('should perform a basic unzip when `iteratee` is nullish', function(assert) { assert.expect(1); var array = [[1, 3], [2, 4]], values = [, null, undefined], expected = lodashStable.map(values, lodashStable.constant(_.unzip(array))); var actual = lodashStable.map(values, function(value, index) { return index ? _.unzipWith(array, value) : _.unzipWith(array); }); assert.deepEqual(actual, expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.updateWith'); (function() { QUnit.test('should work with a `customizer` callback', function(assert) { assert.expect(1); var actual = _.updateWith({ '0': {} }, '[0][1][2]', stubThree, function(value) { return lodashStable.isObject(value) ? undefined : {}; }); assert.deepEqual(actual, { '0': { '1': { '2': 3 } } }); }); QUnit.test('should work with a `customizer` that returns `undefined`', function(assert) { assert.expect(1); var actual = _.updateWith({}, 'a[0].b.c', stubFour, noop); assert.deepEqual(actual, { 'a': [{ 'b': { 'c': 4 } }] }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('update methods'); lodashStable.each(['update', 'updateWith'], function(methodName) { var func = _[methodName], oldValue = 1; QUnit.test('`_.' + methodName + '` should invoke `updater` with the value on `path` of `object`', function(assert) { assert.expect(4); var object = { 'a': [{ 'b': { 'c': oldValue } }] }, expected = oldValue + 1; lodashStable.each(['a[0].b.c', ['a', '0', 'b', 'c']], function(path) { func(object, path, function(n) { assert.strictEqual(n, oldValue); return ++n; }); assert.strictEqual(object.a[0].b.c, expected); object.a[0].b.c = oldValue; }); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.upperCase'); (function() { QUnit.test('should uppercase as space-separated words', function(assert) { assert.expect(3); assert.strictEqual(_.upperCase('--foo-bar--'), 'FOO BAR'); assert.strictEqual(_.upperCase('fooBar'), 'FOO BAR'); assert.strictEqual(_.upperCase('__foo_bar__'), 'FOO BAR'); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.upperFirst'); (function() { QUnit.test('should uppercase only the first character', function(assert) { assert.expect(3); assert.strictEqual(_.upperFirst('fred'), 'Fred'); assert.strictEqual(_.upperFirst('Fred'), 'Fred'); assert.strictEqual(_.upperFirst('FRED'), 'FRED'); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('values methods'); lodashStable.each(['values', 'valuesIn'], function(methodName) { var func = _[methodName], isValues = methodName == 'values'; QUnit.test('`_.' + methodName + '` should get string keyed values of `object`', function(assert) { assert.expect(1); var object = { 'a': 1, 'b': 2 }, actual = func(object).sort(); assert.deepEqual(actual, [1, 2]); }); QUnit.test('`_.' + methodName + '` should work with an object that has a `length` property', function(assert) { assert.expect(1); var object = { '0': 'a', '1': 'b', 'length': 2 }, actual = func(object).sort(); assert.deepEqual(actual, [2, 'a', 'b']); }); QUnit.test('`_.' + methodName + '` should ' + (isValues ? 'not ' : '') + 'include inherited string keyed property values', function(assert) { assert.expect(1); function Foo() { this.a = 1; } Foo.prototype.b = 2; var expected = isValues ? [1] : [1, 2], actual = func(new Foo).sort(); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should work with `arguments` objects', function(assert) { assert.expect(1); var values = [args, strictArgs], expected = lodashStable.map(values, lodashStable.constant([1, 2, 3])); var actual = lodashStable.map(values, function(value) { return func(value).sort(); }); assert.deepEqual(actual, expected); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.without'); (function() { QUnit.test('should return the difference of values', function(assert) { assert.expect(1); var actual = _.without([2, 1, 2, 3], 1, 2); assert.deepEqual(actual, [3]); }); QUnit.test('should use strict equality to determine the values to reject', function(assert) { assert.expect(2); var object1 = { 'a': 1 }, object2 = { 'b': 2 }, array = [object1, object2]; assert.deepEqual(_.without(array, { 'a': 1 }), array); assert.deepEqual(_.without(array, object1), [object2]); }); QUnit.test('should remove all occurrences of each value from an array', function(assert) { assert.expect(1); var array = [1, 2, 3, 1, 2, 3]; assert.deepEqual(_.without(array, 1, 2), [3, 3]); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.words'); (function() { QUnit.test('should match words containing Latin Unicode letters', function(assert) { assert.expect(1); var expected = lodashStable.map(burredLetters, function(letter) { return [letter]; }); var actual = lodashStable.map(burredLetters, function(letter) { return _.words(letter); }); assert.deepEqual(actual, expected); }); QUnit.test('should support a `pattern`', function(assert) { assert.expect(2); assert.deepEqual(_.words('abcd', /ab|cd/g), ['ab', 'cd']); assert.deepEqual(_.words('abcd', 'ab|cd'), ['ab']); }); QUnit.test('should work with compound words', function(assert) { assert.expect(12); assert.deepEqual(_.words('12ft'), ['12', 'ft']); assert.deepEqual(_.words('aeiouAreVowels'), ['aeiou', 'Are', 'Vowels']); assert.deepEqual(_.words('enable 6h format'), ['enable', '6', 'h', 'format']); assert.deepEqual(_.words('enable 24H format'), ['enable', '24', 'H', 'format']); assert.deepEqual(_.words('isISO8601'), ['is', 'ISO', '8601']); assert.deepEqual(_.words('LETTERSAeiouAreVowels'), ['LETTERS', 'Aeiou', 'Are', 'Vowels']); assert.deepEqual(_.words('tooLegit2Quit'), ['too', 'Legit', '2', 'Quit']); assert.deepEqual(_.words('walk500Miles'), ['walk', '500', 'Miles']); assert.deepEqual(_.words('xhr2Request'), ['xhr', '2', 'Request']); assert.deepEqual(_.words('XMLHttp'), ['XML', 'Http']); assert.deepEqual(_.words('XmlHTTP'), ['Xml', 'HTTP']); assert.deepEqual(_.words('XmlHttp'), ['Xml', 'Http']); }); QUnit.test('should work with compound words containing diacritical marks', function(assert) { assert.expect(3); assert.deepEqual(_.words('LETTERSÆiouAreVowels'), ['LETTERS', 'Æiou', 'Are', 'Vowels']); assert.deepEqual(_.words('æiouAreVowels'), ['æiou', 'Are', 'Vowels']); assert.deepEqual(_.words('æiou2Consonants'), ['æiou', '2', 'Consonants']); }); QUnit.test('should not treat contractions as separate words', function(assert) { assert.expect(4); var postfixes = ['d', 'll', 'm', 're', 's', 't', 've']; lodashStable.each(["'", '\u2019'], function(apos) { lodashStable.times(2, function(index) { var actual = lodashStable.map(postfixes, function(postfix) { var string = 'a b' + apos + postfix + ' c'; return _.words(string[index ? 'toUpperCase' : 'toLowerCase']()); }); var expected = lodashStable.map(postfixes, function(postfix) { var words = ['a', 'b' + apos + postfix, 'c']; return lodashStable.map(words, function(word) { return word[index ? 'toUpperCase' : 'toLowerCase'](); }); }); assert.deepEqual(actual, expected); }); }); }); QUnit.test('should not treat ordinal numbers as separate words', function(assert) { assert.expect(2); var ordinals = ['1st', '2nd', '3rd', '4th']; lodashStable.times(2, function(index) { var expected = lodashStable.map(ordinals, function(ordinal) { return [ordinal[index ? 'toUpperCase' : 'toLowerCase']()]; }); var actual = lodashStable.map(expected, function(words) { return _.words(words[0]); }); assert.deepEqual(actual, expected); }); }); QUnit.test('should not treat mathematical operators as words', function(assert) { assert.expect(1); var operators = ['\xac', '\xb1', '\xd7', '\xf7'], expected = lodashStable.map(operators, stubArray), actual = lodashStable.map(operators, _.words); assert.deepEqual(actual, expected); }); QUnit.test('should not treat punctuation as words', function(assert) { assert.expect(1); var marks = [ '\u2012', '\u2013', '\u2014', '\u2015', '\u2024', '\u2025', '\u2026', '\u205d', '\u205e' ]; var expected = lodashStable.map(marks, stubArray), actual = lodashStable.map(marks, _.words); assert.deepEqual(actual, expected); }); QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(1); var strings = lodashStable.map(['a', 'b', 'c'], Object), actual = lodashStable.map(strings, _.words); assert.deepEqual(actual, [['a'], ['b'], ['c']]); }); QUnit.test('should prevent ReDoS', function(assert) { assert.expect(2); var largeWordLen = 50000, largeWord = _.repeat('A', largeWordLen), maxMs = 1000, startTime = lodashStable.now(); assert.deepEqual(_.words(largeWord + 'ÆiouAreVowels'), [largeWord, 'Æiou', 'Are', 'Vowels']); var endTime = lodashStable.now(), timeSpent = endTime - startTime; assert.ok(timeSpent < maxMs, 'operation took ' + timeSpent + 'ms'); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.wrap'); (function() { QUnit.test('should create a wrapped function', function(assert) { assert.expect(1); var p = _.wrap(lodashStable.escape, function(func, text) { return '

' + func(text) + '

'; }); assert.strictEqual(p('fred, barney, & pebbles'), '

fred, barney, & pebbles

'); }); QUnit.test('should provide correct `wrapper` arguments', function(assert) { assert.expect(1); var args; var wrapped = _.wrap(noop, function() { args || (args = slice.call(arguments)); }); wrapped(1, 2, 3); assert.deepEqual(args, [noop, 1, 2, 3]); }); QUnit.test('should use `_.identity` when `wrapper` is nullish', function(assert) { assert.expect(1); var values = [, null, undefined], expected = lodashStable.map(values, stubA); var actual = lodashStable.map(values, function(value, index) { var wrapped = index ? _.wrap('a', value) : _.wrap('a'); return wrapped('b', 'c'); }); assert.deepEqual(actual, expected); }); QUnit.test('should use `this` binding of function', function(assert) { assert.expect(1); var p = _.wrap(lodashStable.escape, function(func) { return '

' + func(this.text) + '

'; }); var object = { 'p': p, 'text': 'fred, barney, & pebbles' }; assert.strictEqual(object.p(), '

fred, barney, & pebbles

'); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('xor methods'); lodashStable.each(['xor', 'xorBy', 'xorWith'], function(methodName) { var func = _[methodName]; QUnit.test('`_.' + methodName + '` should return the symmetric difference of two arrays', function(assert) { assert.expect(1); var actual = func([2, 1], [2, 3]); assert.deepEqual(actual, [1, 3]); }); QUnit.test('`_.' + methodName + '` should return the symmetric difference of multiple arrays', function(assert) { assert.expect(2); var actual = func([2, 1], [2, 3], [3, 4]); assert.deepEqual(actual, [1, 4]); actual = func([1, 2], [2, 1], [1, 2]); assert.deepEqual(actual, []); }); QUnit.test('`_.' + methodName + '` should return an empty array when comparing the same array', function(assert) { assert.expect(1); var array = [1], actual = func(array, array, array); assert.deepEqual(actual, []); }); QUnit.test('`_.' + methodName + '` should return an array of unique values', function(assert) { assert.expect(2); var actual = func([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]); assert.deepEqual(actual, [1, 4]); actual = func([1, 1]); assert.deepEqual(actual, [1]); }); QUnit.test('`_.' + methodName + '` should return a new array when a single array is given', function(assert) { assert.expect(1); var array = [1]; assert.notStrictEqual(func(array), array); }); QUnit.test('`_.' + methodName + '` should ignore individual secondary arguments', function(assert) { assert.expect(1); var array = [0]; assert.deepEqual(func(array, 3, null, { '0': 1 }), array); }); QUnit.test('`_.' + methodName + '` should ignore values that are not arrays or `arguments` objects', function(assert) { assert.expect(3); var array = [1, 2]; assert.deepEqual(func(array, 3, { '0': 1 }, null), array); assert.deepEqual(func(null, array, null, [2, 3]), [1, 3]); assert.deepEqual(func(array, null, args, null), [3]); }); QUnit.test('`_.' + methodName + '` should return a wrapped value when chaining', function(assert) { assert.expect(1); if (!isNpm) { var wrapped = _([1, 2, 3])[methodName]([5, 2, 1, 4]); assert.ok(wrapped instanceof _); } else { skipAssert(assert); } }); QUnit.test('`_.' + methodName + '` should work when in a lazy sequence before `head` or `last`', function(assert) { assert.expect(1); if (!isNpm) { var array = lodashStable.range(LARGE_ARRAY_SIZE + 1), wrapped = _(array).slice(1)[methodName]([LARGE_ARRAY_SIZE, LARGE_ARRAY_SIZE + 1]); var actual = lodashStable.map(['head', 'last'], function(methodName) { return wrapped[methodName](); }); assert.deepEqual(actual, [1, LARGE_ARRAY_SIZE + 1]); } else { skipAssert(assert); } }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.xorBy'); (function() { QUnit.test('should accept an `iteratee`', function(assert) { assert.expect(2); var actual = _.xorBy([2.1, 1.2], [2.3, 3.4], Math.floor); assert.deepEqual(actual, [1.2, 3.4]); actual = _.xorBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); assert.deepEqual(actual, [{ 'x': 2 }]); }); QUnit.test('should provide correct `iteratee` arguments', function(assert) { assert.expect(1); var args; _.xorBy([2.1, 1.2], [2.3, 3.4], function() { args || (args = slice.call(arguments)); }); assert.deepEqual(args, [2.3]); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.xorWith'); (function() { QUnit.test('should work with a `comparator`', function(assert) { assert.expect(1); var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }], others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }], actual = _.xorWith(objects, others, lodashStable.isEqual); assert.deepEqual(actual, [objects[1], others[0]]); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('zipObject methods'); lodashStable.each(['zipObject', 'zipObjectDeep'], function(methodName) { var func = _[methodName], object = { 'barney': 36, 'fred': 40 }, isDeep = methodName == 'zipObjectDeep'; QUnit.test('`_.' + methodName + '` should zip together key/value arrays into an object', function(assert) { assert.expect(1); var actual = func(['barney', 'fred'], [36, 40]); assert.deepEqual(actual, object); }); QUnit.test('`_.' + methodName + '` should ignore extra `values`', function(assert) { assert.expect(1); assert.deepEqual(func(['a'], [1, 2]), { 'a': 1 }); }); QUnit.test('`_.' + methodName + '` should assign `undefined` values for extra `keys`', function(assert) { assert.expect(1); assert.deepEqual(func(['a', 'b'], [1]), { 'a': 1, 'b': undefined }); }); QUnit.test('`_.' + methodName + '` should ' + (isDeep ? '' : 'not ') + 'support deep paths', function(assert) { assert.expect(2); lodashStable.each(['a.b.c', ['a', 'b', 'c']], function(path, index) { var expected = isDeep ? ({ 'a': { 'b': { 'c': 1 } } }) : (index ? { 'a,b,c': 1 } : { 'a.b.c': 1 }); assert.deepEqual(func([path], [1]), expected); }); }); QUnit.test('`_.' + methodName + '` should work in a lazy sequence', function(assert) { assert.expect(1); if (!isNpm) { var values = lodashStable.range(LARGE_ARRAY_SIZE), props = lodashStable.map(values, function(value) { return 'key' + value; }), actual = _(props)[methodName](values).map(square).filter(isEven).take().value(); assert.deepEqual(actual, _.take(_.filter(_.map(func(props, values), square), isEven))); } else { skipAssert(assert); } }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.zipWith'); (function() { QUnit.test('should zip arrays combining grouped elements with `iteratee`', function(assert) { assert.expect(2); var array1 = [1, 2, 3], array2 = [4, 5, 6], array3 = [7, 8, 9]; var actual = _.zipWith(array1, array2, array3, function(a, b, c) { return a + b + c; }); assert.deepEqual(actual, [12, 15, 18]); var actual = _.zipWith(array1, [], function(a, b) { return a + (b || 0); }); assert.deepEqual(actual, [1, 2, 3]); }); QUnit.test('should provide correct `iteratee` arguments', function(assert) { assert.expect(1); var args; _.zipWith([1, 2], [3, 4], [5, 6], function() { args || (args = slice.call(arguments)); }); assert.deepEqual(args, [1, 3, 5]); }); QUnit.test('should perform a basic zip when `iteratee` is nullish', function(assert) { assert.expect(1); var array1 = [1, 2], array2 = [3, 4], values = [, null, undefined], expected = lodashStable.map(values, lodashStable.constant(_.zip(array1, array2))); var actual = lodashStable.map(values, function(value, index) { return index ? _.zipWith(array1, array2, value) : _.zipWith(array1, array2); }); assert.deepEqual(actual, expected); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash.unzip and lodash.zip'); lodashStable.each(['unzip', 'zip'], function(methodName, index) { var func = _[methodName]; func = lodashStable.bind(index ? func.apply : func.call, func, null); var object = { 'an empty array': [ [], [] ], '0-tuples': [ [[], []], [] ], '2-tuples': [ [['barney', 'fred'], [36, 40]], [['barney', 36], ['fred', 40]] ], '3-tuples': [ [['barney', 'fred'], [36, 40], [false, true]], [['barney', 36, false], ['fred', 40, true]] ] }; lodashStable.forOwn(object, function(pair, key) { QUnit.test('`_.' + methodName + '` should work with ' + key, function(assert) { assert.expect(2); var actual = func(pair[0]); assert.deepEqual(actual, pair[1]); assert.deepEqual(func(actual), actual.length ? pair[0] : []); }); }); QUnit.test('`_.' + methodName + '` should work with tuples of different lengths', function(assert) { assert.expect(4); var pair = [ [['barney', 36], ['fred', 40, false]], [['barney', 'fred'], [36, 40], [undefined, false]] ]; var actual = func(pair[0]); assert.ok('0' in actual[2]); assert.deepEqual(actual, pair[1]); actual = func(actual); assert.ok('2' in actual[0]); assert.deepEqual(actual, [['barney', 36, undefined], ['fred', 40, false]]); }); QUnit.test('`_.' + methodName + '` should treat falsey values as empty arrays', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, stubArray); var actual = lodashStable.map(falsey, function(value) { return func([value, value, value]); }); assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should ignore values that are not arrays or `arguments` objects', function(assert) { assert.expect(1); var array = [[1, 2], [3, 4], null, undefined, { '0': 1 }]; assert.deepEqual(func(array), [[1, 3], [2, 4]]); }); QUnit.test('`_.' + methodName + '` should support consuming its return value', function(assert) { assert.expect(1); var expected = [['barney', 'fred'], [36, 40]]; assert.deepEqual(func(func(func(func(expected)))), expected); }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash(...).commit'); (function() { QUnit.test('should execute the chained sequence and returns the wrapped result', function(assert) { assert.expect(4); if (!isNpm) { var array = [1], wrapped = _(array).push(2).push(3); assert.deepEqual(array, [1]); var otherWrapper = wrapped.commit(); assert.ok(otherWrapper instanceof _); assert.deepEqual(otherWrapper.value(), [1, 2, 3]); assert.deepEqual(wrapped.value(), [1, 2, 3, 2, 3]); } else { skipAssert(assert, 4); } }); QUnit.test('should track the `__chain__` value of a wrapper', function(assert) { assert.expect(2); if (!isNpm) { var wrapped = _([1]).chain().commit().head(); assert.ok(wrapped instanceof _); assert.strictEqual(wrapped.value(), 1); } else { skipAssert(assert, 2); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash(...).next'); lodashStable.each([false, true], function(implicit) { function chain(value) { return implicit ? _(value) : _.chain(value); } var chainType = 'in an ' + (implicit ? 'implicit' : 'explict') + ' chain'; QUnit.test('should follow the iterator protocol ' + chainType, function(assert) { assert.expect(3); if (!isNpm) { var wrapped = chain([1, 2]); assert.deepEqual(wrapped.next(), { 'done': false, 'value': 1 }); assert.deepEqual(wrapped.next(), { 'done': false, 'value': 2 }); assert.deepEqual(wrapped.next(), { 'done': true, 'value': undefined }); } else { skipAssert(assert, 3); } }); QUnit.test('should act as an iterable ' + chainType, function(assert) { assert.expect(2); if (!isNpm && Symbol && Symbol.iterator) { var array = [1, 2], wrapped = chain(array); assert.strictEqual(wrapped[Symbol.iterator](), wrapped); assert.deepEqual(lodashStable.toArray(wrapped), array); } else { skipAssert(assert, 2); } }); QUnit.test('should use `_.toArray` to generate the iterable result ' + chainType, function(assert) { assert.expect(3); if (!isNpm && Array.from) { var hearts = '\ud83d\udc95', values = [[1], { 'a': 1 }, hearts]; lodashStable.each(values, function(value) { var wrapped = chain(value); assert.deepEqual(Array.from(wrapped), _.toArray(value)); }); } else { skipAssert(assert, 3); } }); QUnit.test('should reset the iterator correctly ' + chainType, function(assert) { assert.expect(4); if (!isNpm && Symbol && Symbol.iterator) { var array = [1, 2], wrapped = chain(array); assert.deepEqual(lodashStable.toArray(wrapped), array); assert.deepEqual(lodashStable.toArray(wrapped), [], 'produces an empty array for exhausted iterator'); var other = wrapped.filter(); assert.deepEqual(lodashStable.toArray(other), array, 'reset for new chain segments'); assert.deepEqual(lodashStable.toArray(wrapped), [], 'iterator is still exhausted'); } else { skipAssert(assert, 4); } }); QUnit.test('should work in a lazy sequence ' + chainType, function(assert) { assert.expect(3); if (!isNpm && Symbol && Symbol.iterator) { var array = lodashStable.range(LARGE_ARRAY_SIZE), predicate = function(value) { values.push(value); return isEven(value); }, values = [], wrapped = chain(array); assert.deepEqual(lodashStable.toArray(wrapped), array); wrapped = wrapped.filter(predicate); assert.deepEqual(lodashStable.toArray(wrapped), _.filter(array, isEven), 'reset for new lazy chain segments'); assert.deepEqual(values, array, 'memoizes iterator values'); } else { skipAssert(assert, 3); } }); }); /*--------------------------------------------------------------------------*/ QUnit.module('lodash(...).plant'); (function() { QUnit.test('should clone the chained sequence planting `value` as the wrapped value', function(assert) { assert.expect(2); if (!isNpm) { var array1 = [5, null, 3, null, 1], array2 = [10, null, 8, null, 6], wrapped1 = _(array1).thru(_.compact).map(square).takeRight(2).sort(), wrapped2 = wrapped1.plant(array2); assert.deepEqual(wrapped2.value(), [36, 64]); assert.deepEqual(wrapped1.value(), [1, 9]); } else { skipAssert(assert, 2); } }); QUnit.test('should clone `chainAll` settings', function(assert) { assert.expect(1); if (!isNpm) { var array1 = [2, 4], array2 = [6, 8], wrapped1 = _(array1).chain().map(square), wrapped2 = wrapped1.plant(array2); assert.deepEqual(wrapped2.head().value(), 36); } else { skipAssert(assert); } }); QUnit.test('should reset iterator data on cloned sequences', function(assert) { assert.expect(3); if (!isNpm && Symbol && Symbol.iterator) { var array1 = [2, 4], array2 = [6, 8], wrapped1 = _(array1).map(square); assert.deepEqual(lodashStable.toArray(wrapped1), [4, 16]); assert.deepEqual(lodashStable.toArray(wrapped1), []); var wrapped2 = wrapped1.plant(array2); assert.deepEqual(lodashStable.toArray(wrapped2), [36, 64]); } else { skipAssert(assert, 3); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash(...).pop'); (function() { QUnit.test('should remove elements from the end of `array`', function(assert) { assert.expect(5); if (!isNpm) { var array = [1, 2], wrapped = _(array); assert.strictEqual(wrapped.pop(), 2); assert.deepEqual(wrapped.value(), [1]); assert.strictEqual(wrapped.pop(), 1); var actual = wrapped.value(); assert.strictEqual(actual, array); assert.deepEqual(actual, []); } else { skipAssert(assert, 5); } }); QUnit.test('should accept falsey arguments', function(assert) { assert.expect(1); if (!isNpm) { var expected = lodashStable.map(falsey, stubTrue); var actual = lodashStable.map(falsey, function(value, index) { try { var result = index ? _(value).pop() : _().pop(); return result === undefined; } catch (e) {} }); assert.deepEqual(actual, expected); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash(...).push'); (function() { QUnit.test('should append elements to `array`', function(assert) { assert.expect(2); if (!isNpm) { var array = [1], wrapped = _(array).push(2, 3), actual = wrapped.value(); assert.strictEqual(actual, array); assert.deepEqual(actual, [1, 2, 3]); } else { skipAssert(assert, 2); } }); QUnit.test('should accept falsey arguments', function(assert) { assert.expect(1); if (!isNpm) { var expected = lodashStable.map(falsey, stubTrue); var actual = lodashStable.map(falsey, function(value, index) { try { var result = index ? _(value).push(1).value() : _().push(1).value(); return lodashStable.eq(result, value); } catch (e) {} }); assert.deepEqual(actual, expected); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash(...).shift'); (function() { QUnit.test('should remove elements from the front of `array`', function(assert) { assert.expect(5); if (!isNpm) { var array = [1, 2], wrapped = _(array); assert.strictEqual(wrapped.shift(), 1); assert.deepEqual(wrapped.value(), [2]); assert.strictEqual(wrapped.shift(), 2); var actual = wrapped.value(); assert.strictEqual(actual, array); assert.deepEqual(actual, []); } else { skipAssert(assert, 5); } }); QUnit.test('should accept falsey arguments', function(assert) { assert.expect(1); if (!isNpm) { var expected = lodashStable.map(falsey, stubTrue); var actual = lodashStable.map(falsey, function(value, index) { try { var result = index ? _(value).shift() : _().shift(); return result === undefined; } catch (e) {} }); assert.deepEqual(actual, expected); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash(...).sort'); (function() { QUnit.test('should return the wrapped sorted `array`', function(assert) { assert.expect(2); if (!isNpm) { var array = [3, 1, 2], wrapped = _(array).sort(), actual = wrapped.value(); assert.strictEqual(actual, array); assert.deepEqual(actual, [1, 2, 3]); } else { skipAssert(assert, 2); } }); QUnit.test('should accept falsey arguments', function(assert) { assert.expect(1); if (!isNpm) { var expected = lodashStable.map(falsey, stubTrue); var actual = lodashStable.map(falsey, function(value, index) { try { var result = index ? _(value).sort().value() : _().sort().value(); return lodashStable.eq(result, value); } catch (e) {} }); assert.deepEqual(actual, expected); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash(...).splice'); (function() { QUnit.test('should support removing and inserting elements', function(assert) { assert.expect(5); if (!isNpm) { var array = [1, 2], wrapped = _(array); assert.deepEqual(wrapped.splice(1, 1, 3).value(), [2]); assert.deepEqual(wrapped.value(), [1, 3]); assert.deepEqual(wrapped.splice(0, 2).value(), [1, 3]); var actual = wrapped.value(); assert.strictEqual(actual, array); assert.deepEqual(actual, []); } else { skipAssert(assert, 5); } }); QUnit.test('should accept falsey arguments', function(assert) { assert.expect(1); if (!isNpm) { var expected = lodashStable.map(falsey, stubTrue); var actual = lodashStable.map(falsey, function(value, index) { try { var result = index ? _(value).splice(0, 1).value() : _().splice(0, 1).value(); return lodashStable.isEqual(result, []); } catch (e) {} }); assert.deepEqual(actual, expected); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash(...).unshift'); (function() { QUnit.test('should prepend elements to `array`', function(assert) { assert.expect(2); if (!isNpm) { var array = [3], wrapped = _(array).unshift(1, 2), actual = wrapped.value(); assert.strictEqual(actual, array); assert.deepEqual(actual, [1, 2, 3]); } else { skipAssert(assert, 2); } }); QUnit.test('should accept falsey arguments', function(assert) { assert.expect(1); if (!isNpm) { var expected = lodashStable.map(falsey, stubTrue); var actual = lodashStable.map(falsey, function(value, index) { try { var result = index ? _(value).unshift(1).value() : _().unshift(1).value(); return lodashStable.eq(result, value); } catch (e) {} }); assert.deepEqual(actual, expected); } else { skipAssert(assert); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash(...).value'); (function() { QUnit.test('should execute the chained sequence and extract the unwrapped value', function(assert) { assert.expect(4); if (!isNpm) { var array = [1], wrapped = _(array).push(2).push(3); assert.deepEqual(array, [1]); assert.deepEqual(wrapped.value(), [1, 2, 3]); assert.deepEqual(wrapped.value(), [1, 2, 3, 2, 3]); assert.deepEqual(array, [1, 2, 3, 2, 3]); } else { skipAssert(assert, 4); } }); QUnit.test('should return the `valueOf` result of the wrapped value', function(assert) { assert.expect(1); if (!isNpm) { var wrapped = _(123); assert.strictEqual(Number(wrapped), 123); } else { skipAssert(assert); } }); QUnit.test('should stringify the wrapped value when used by `JSON.stringify`', function(assert) { assert.expect(1); if (!isNpm && JSON) { var wrapped = _([1, 2, 3]); assert.strictEqual(JSON.stringify(wrapped), '[1,2,3]'); } else { skipAssert(assert); } }); QUnit.test('should be aliased', function(assert) { assert.expect(2); if (!isNpm) { var expected = _.prototype.value; assert.strictEqual(_.prototype.toJSON, expected); assert.strictEqual(_.prototype.valueOf, expected); } else { skipAssert(assert, 2); } }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash(...) methods that return the wrapped modified array'); (function() { var funcs = [ 'push', 'reverse', 'sort', 'unshift' ]; lodashStable.each(funcs, function(methodName) { QUnit.test('`_(...).' + methodName + '` should return a new wrapper', function(assert) { assert.expect(2); if (!isNpm) { var array = [1, 2, 3], wrapped = _(array), actual = wrapped[methodName](); assert.ok(actual instanceof _); assert.notStrictEqual(actual, wrapped); } else { skipAssert(assert, 2); } }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash(...) methods that return new wrapped values'); (function() { var funcs = [ 'castArray', 'concat', 'difference', 'differenceBy', 'differenceWith', 'intersection', 'intersectionBy', 'intersectionWith', 'pull', 'pullAll', 'pullAt', 'sampleSize', 'shuffle', 'slice', 'splice', 'split', 'toArray', 'union', 'unionBy', 'unionWith', 'uniq', 'uniqBy', 'uniqWith', 'words', 'xor', 'xorBy', 'xorWith' ]; lodashStable.each(funcs, function(methodName) { QUnit.test('`_(...).' + methodName + '` should return a new wrapped value', function(assert) { assert.expect(2); if (!isNpm) { var value = methodName == 'split' ? 'abc' : [1, 2, 3], wrapped = _(value), actual = wrapped[methodName](); assert.ok(actual instanceof _); assert.notStrictEqual(actual, wrapped); } else { skipAssert(assert, 2); } }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash(...) methods that return unwrapped values'); (function() { var funcs = [ 'add', 'camelCase', 'capitalize', 'ceil', 'clone', 'deburr', 'defaultTo', 'divide', 'endsWith', 'escape', 'escapeRegExp', 'every', 'find', 'floor', 'has', 'hasIn', 'head', 'includes', 'isArguments', 'isArray', 'isArrayBuffer', 'isArrayLike', 'isBoolean', 'isBuffer', 'isDate', 'isElement', 'isEmpty', 'isEqual', 'isError', 'isFinite', 'isFunction', 'isInteger', 'isMap', 'isNaN', 'isNative', 'isNil', 'isNull', 'isNumber', 'isObject', 'isObjectLike', 'isPlainObject', 'isRegExp', 'isSafeInteger', 'isSet', 'isString', 'isUndefined', 'isWeakMap', 'isWeakSet', 'join', 'kebabCase', 'last', 'lowerCase', 'lowerFirst', 'max', 'maxBy', 'min', 'minBy', 'multiply', 'nth', 'pad', 'padEnd', 'padStart', 'parseInt', 'pop', 'random', 'reduce', 'reduceRight', 'repeat', 'replace', 'round', 'sample', 'shift', 'size', 'snakeCase', 'some', 'startCase', 'startsWith', 'subtract', 'sum', 'toFinite', 'toInteger', 'toLower', 'toNumber', 'toSafeInteger', 'toString', 'toUpper', 'trim', 'trimEnd', 'trimStart', 'truncate', 'unescape', 'upperCase', 'upperFirst' ]; lodashStable.each(funcs, function(methodName) { QUnit.test('`_(...).' + methodName + '` should return an unwrapped value when implicitly chaining', function(assert) { assert.expect(1); if (!isNpm) { var actual = _()[methodName](); assert.notOk(actual instanceof _); } else { skipAssert(assert); } }); QUnit.test('`_(...).' + methodName + '` should return a wrapped value when explicitly chaining', function(assert) { assert.expect(1); if (!isNpm) { var actual = _().chain()[methodName](); assert.ok(actual instanceof _); } else { skipAssert(assert); } }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('"Arrays" category methods'); (function() { var args = toArgs([1, null, [3], null, 5]), sortedArgs = toArgs([1, [3], 5, null, null]), array = [1, 2, 3, 4, 5, 6]; QUnit.test('should work with `arguments` objects', function(assert) { assert.expect(30); function message(methodName) { return '`_.' + methodName + '` should work with `arguments` objects'; } assert.deepEqual(_.difference(args, [null]), [1, [3], 5], message('difference')); assert.deepEqual(_.difference(array, args), [2, 3, 4, 6], '_.difference should work with `arguments` objects as secondary arguments'); assert.deepEqual(_.union(args, [null, 6]), [1, null, [3], 5, 6], message('union')); assert.deepEqual(_.union(array, args), array.concat([null, [3]]), '_.union should work with `arguments` objects as secondary arguments'); assert.deepEqual(_.compact(args), [1, [3], 5], message('compact')); assert.deepEqual(_.drop(args, 3), [null, 5], message('drop')); assert.deepEqual(_.dropRight(args, 3), [1, null], message('dropRight')); assert.deepEqual(_.dropRightWhile(args,identity), [1, null, [3], null], message('dropRightWhile')); assert.deepEqual(_.dropWhile(args,identity), [null, [3], null, 5], message('dropWhile')); assert.deepEqual(_.findIndex(args, identity), 0, message('findIndex')); assert.deepEqual(_.findLastIndex(args, identity), 4, message('findLastIndex')); assert.deepEqual(_.flatten(args), [1, null, 3, null, 5], message('flatten')); assert.deepEqual(_.head(args), 1, message('head')); assert.deepEqual(_.indexOf(args, 5), 4, message('indexOf')); assert.deepEqual(_.initial(args), [1, null, [3], null], message('initial')); assert.deepEqual(_.intersection(args, [1]), [1], message('intersection')); assert.deepEqual(_.last(args), 5, message('last')); assert.deepEqual(_.lastIndexOf(args, 1), 0, message('lastIndexOf')); assert.deepEqual(_.sortedIndex(sortedArgs, 6), 3, message('sortedIndex')); assert.deepEqual(_.sortedIndexOf(sortedArgs, 5), 2, message('sortedIndexOf')); assert.deepEqual(_.sortedLastIndex(sortedArgs, 5), 3, message('sortedLastIndex')); assert.deepEqual(_.sortedLastIndexOf(sortedArgs, 1), 0, message('sortedLastIndexOf')); assert.deepEqual(_.tail(args, 4), [null, [3], null, 5], message('tail')); assert.deepEqual(_.take(args, 2), [1, null], message('take')); assert.deepEqual(_.takeRight(args, 1), [5], message('takeRight')); assert.deepEqual(_.takeRightWhile(args, identity), [5], message('takeRightWhile')); assert.deepEqual(_.takeWhile(args, identity), [1], message('takeWhile')); assert.deepEqual(_.uniq(args), [1, null, [3], 5], message('uniq')); assert.deepEqual(_.without(args, null), [1, [3], 5], message('without')); assert.deepEqual(_.zip(args, args), [[1, 1], [null, null], [[3], [3]], [null, null], [5, 5]], message('zip')); }); QUnit.test('should accept falsey primary arguments', function(assert) { assert.expect(4); function message(methodName) { return '`_.' + methodName + '` should accept falsey primary arguments'; } assert.deepEqual(_.difference(null, array), [], message('difference')); assert.deepEqual(_.intersection(null, array), [], message('intersection')); assert.deepEqual(_.union(null, array), array, message('union')); assert.deepEqual(_.xor(null, array), array, message('xor')); }); QUnit.test('should accept falsey secondary arguments', function(assert) { assert.expect(3); function message(methodName) { return '`_.' + methodName + '` should accept falsey secondary arguments'; } assert.deepEqual(_.difference(array, null), array, message('difference')); assert.deepEqual(_.intersection(array, null), [], message('intersection')); assert.deepEqual(_.union(array, null), array, message('union')); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('"Strings" category methods'); (function() { var stringMethods = [ 'camelCase', 'capitalize', 'escape', 'kebabCase', 'lowerCase', 'lowerFirst', 'pad', 'padEnd', 'padStart', 'repeat', 'snakeCase', 'toLower', 'toUpper', 'trim', 'trimEnd', 'trimStart', 'truncate', 'unescape', 'upperCase', 'upperFirst' ]; lodashStable.each(stringMethods, function(methodName) { var func = _[methodName]; QUnit.test('`_.' + methodName + '` should return an empty string for empty values', function(assert) { assert.expect(1); var values = [, null, undefined, ''], expected = lodashStable.map(values, stubString); var actual = lodashStable.map(values, function(value, index) { return index ? func(value) : func(); }); assert.deepEqual(actual, expected); }); }); }()); /*--------------------------------------------------------------------------*/ QUnit.module('lodash methods'); (function() { var allMethods = lodashStable.reject(_.functions(_).sort(), function(methodName) { return lodashStable.startsWith(methodName, '_'); }); var checkFuncs = [ 'after', 'ary', 'before', 'bind', 'curry', 'curryRight', 'debounce', 'defer', 'delay', 'flip', 'flow', 'flowRight', 'memoize', 'negate', 'once', 'partial', 'partialRight', 'rearg', 'rest', 'spread', 'throttle', 'unary' ]; var noBinding = [ 'flip', 'memoize', 'negate', 'once', 'overArgs', 'partial', 'partialRight', 'rearg', 'rest', 'spread' ]; var rejectFalsey = [ 'tap', 'thru' ].concat(checkFuncs); var returnArrays = [ 'at', 'chunk', 'compact', 'difference', 'drop', 'filter', 'flatten', 'functions', 'initial', 'intersection', 'invokeMap', 'keys', 'map', 'orderBy', 'pull', 'pullAll', 'pullAt', 'range', 'rangeRight', 'reject', 'remove', 'shuffle', 'sortBy', 'tail', 'take', 'times', 'toArray', 'toPairs', 'toPairsIn', 'union', 'uniq', 'values', 'without', 'xor', 'zip' ]; var acceptFalsey = lodashStable.difference(allMethods, rejectFalsey); QUnit.test('should accept falsey arguments', function(assert) { assert.expect(316); var arrays = lodashStable.map(falsey, stubArray); lodashStable.each(acceptFalsey, function(methodName) { var expected = arrays, func = _[methodName]; var actual = lodashStable.map(falsey, function(value, index) { return index ? func(value) : func(); }); if (methodName == 'noConflict') { root._ = oldDash; } else if (methodName == 'pull' || methodName == 'pullAll') { expected = falsey; } if (lodashStable.includes(returnArrays, methodName) && methodName != 'sample') { assert.deepEqual(actual, expected, '_.' + methodName + ' returns an array'); } assert.ok(true, '`_.' + methodName + '` accepts falsey arguments'); }); // Skip tests for missing methods of modularized builds. lodashStable.each(['chain', 'noConflict', 'runInContext'], function(methodName) { if (!_[methodName]) { skipAssert(assert); } }); }); QUnit.test('should return an array', function(assert) { assert.expect(70); var array = [1, 2, 3]; lodashStable.each(returnArrays, function(methodName) { var actual, func = _[methodName]; switch (methodName) { case 'invokeMap': actual = func(array, 'toFixed'); break; case 'sample': actual = func(array, 1); break; default: actual = func(array); } assert.ok(lodashStable.isArray(actual), '_.' + methodName + ' returns an array'); var isPull = methodName == 'pull' || methodName == 'pullAll'; assert.strictEqual(actual === array, isPull, '_.' + methodName + ' should ' + (isPull ? '' : 'not ') + 'return the given array'); }); }); QUnit.test('should throw an error for falsey arguments', function(assert) { assert.expect(24); lodashStable.each(rejectFalsey, function(methodName) { var expected = lodashStable.map(falsey, stubTrue), func = _[methodName]; var actual = lodashStable.map(falsey, function(value, index) { var pass = !index && /^(?:backflow|compose|cond|flow(Right)?|over(?:Every|Some)?)$/.test(methodName); try { index ? func(value) : func(); } catch (e) { pass = !pass && (e instanceof TypeError) && (!lodashStable.includes(checkFuncs, methodName) || (e.message == FUNC_ERROR_TEXT)); } return pass; }); assert.deepEqual(actual, expected, '`_.' + methodName + '` rejects falsey arguments'); }); }); QUnit.test('should use `this` binding of function', function(assert) { assert.expect(30); lodashStable.each(noBinding, function(methodName) { var fn = function() { return this.a; }, func = _[methodName], isNegate = methodName == 'negate', object = { 'a': 1 }, expected = isNegate ? false : 1; var wrapper = func(_.bind(fn, object)); assert.strictEqual(wrapper(), expected, '`_.' + methodName + '` can consume a bound function'); wrapper = _.bind(func(fn), object); assert.strictEqual(wrapper(), expected, '`_.' + methodName + '` can be bound'); object.wrapper = func(fn); assert.strictEqual(object.wrapper(), expected, '`_.' + methodName + '` uses the `this` of its parent object'); }); }); QUnit.test('should not contain minified method names (test production builds)', function(assert) { assert.expect(1); var shortNames = ['_', 'at', 'eq', 'gt', 'lt']; assert.ok(lodashStable.every(_.functions(_), function(methodName) { return methodName.length > 2 || lodashStable.includes(shortNames, methodName); })); }); }()); /*--------------------------------------------------------------------------*/ QUnit.config.asyncRetries = 10; QUnit.config.hidepassed = true; if (!document) { QUnit.config.noglobals = true; QUnit.load(); QUnit.start(); } }.call(this));