Path: blob/trunk/third_party/closure/goog/testing/asserts.js
4500 views
/**1* @license2* Copyright The Closure Library Authors.3* SPDX-License-Identifier: Apache-2.04*/56goog.provide('goog.testing.asserts');7goog.setTestOnly();89goog.require('goog.dom.safe');10goog.require('goog.html.uncheckedconversions');11goog.require('goog.string');12goog.require('goog.string.Const');13goog.require('goog.testing.JsUnitException');1415var DOUBLE_EQUALITY_PREDICATE = function(var1, var2) {16'use strict';17return var1 == var2;18};19var JSUNIT_UNDEFINED_VALUE = void 0;20var TO_STRING_EQUALITY_PREDICATE = function(var1, var2) {21'use strict';22return var1.toString() === var2.toString();23};24var OUTPUT_NEW_LINE_THRESHOLD = 40;252627/** @typedef {function(?, ?):boolean} */28var PredicateFunctionType;293031/**32* An associative array of constructors corresponding to primitive and33* well-known JS types.34* @const {!Array<string>}35*/36const PRIMITIVE_TRUE_TYPES =37['String', 'Boolean', 'Number', 'Array', 'RegExp', 'Date', 'Function'];3839if (typeof ArrayBuffer === 'function') {40PRIMITIVE_TRUE_TYPES.push('ArrayBuffer');41}424344/**45* @const {{46* String : !PredicateFunctionType,47* Number : !PredicateFunctionType,48* Boolean : !PredicateFunctionType,49* Date : !PredicateFunctionType,50* RegExp : !PredicateFunctionType,51* Function : !PredicateFunctionType,52* TrustedHTML : !PredicateFunctionType,53* TrustedScript : !PredicateFunctionType,54* TrustedScriptURL : !PredicateFunctionType55* }}56*/57const EQUALITY_PREDICATES = {58'String': DOUBLE_EQUALITY_PREDICATE,59'Number': DOUBLE_EQUALITY_PREDICATE,60'Bigint': DOUBLE_EQUALITY_PREDICATE,61'Boolean': DOUBLE_EQUALITY_PREDICATE,62'Date': function(date1, date2) {63'use strict';64return date1.getTime() == date2.getTime();65},66'RegExp': TO_STRING_EQUALITY_PREDICATE,67'Function': TO_STRING_EQUALITY_PREDICATE,68'TrustedHTML': TO_STRING_EQUALITY_PREDICATE,69'TrustedScript': TO_STRING_EQUALITY_PREDICATE,70'TrustedScriptURL': TO_STRING_EQUALITY_PREDICATE71};727374/**75* Compares equality of two numbers, allowing them to differ up to a given76* tolerance.77* @param {number} var1 A number.78* @param {number} var2 A number.79* @param {number} tolerance the maximum allowed difference.80* @return {boolean} Whether the two variables are sufficiently close.81* @private82*/83goog.testing.asserts.numberRoughEqualityPredicate_ = function(84var1, var2, tolerance) {85'use strict';86return Math.abs(var1 - var2) <= tolerance;87};888990/**91* @type {!Object<string, function(?, ?, number): boolean>}92* @private93*/94goog.testing.asserts.primitiveRoughEqualityPredicates_ = {95'Number': goog.testing.asserts.numberRoughEqualityPredicate_96};979899var _trueTypeOf = function(something) {100'use strict';101let result = typeof something;102try {103switch (result) {104case 'string':105break;106case 'boolean':107break;108case 'number':109break;110case 'object':111if (something == null) {112result = 'null';113break;114}115case 'function':116let foundConstructor = false;117for (let i = 0; i < PRIMITIVE_TRUE_TYPES.length; i++) {118// NOTE: this cannot be a for-of loop because it's used from Rhino119// without the necessary Array.prototype[Symbol.iterator] polyfill.120const trueType = PRIMITIVE_TRUE_TYPES[i];121if (something.constructor === goog.global[trueType]) {122result = trueType;123foundConstructor = true;124break;125}126}127// Constructor doesn't match any of the known "primitive" constructors.128if (!foundConstructor) {129const m =130something.constructor.toString().match(/function\s*([^( ]+)\(/);131if (m) {132result = m[1];133}134}135break;136}137} catch (e) {138} finally {139result = result.slice(0, 1).toUpperCase() + result.slice(1);140}141return result;142};143144var _displayStringForValue = function(aVar) {145'use strict';146var result;147try {148result = '<' + String(aVar) + '>';149} catch (ex) {150result = '<toString failed: ' + ex.message + '>';151// toString does not work on this object :-(152}153if (!(aVar === null || aVar === JSUNIT_UNDEFINED_VALUE)) {154result += ' (' + _trueTypeOf(aVar) + ')';155}156return result;157};158159/** @param {?} failureMessage */160goog.testing.asserts.fail = function(failureMessage) {161'use strict';162_assert('Call to fail()', false, failureMessage);163};164/**165* @const166* @suppress {duplicate,checkTypes} Test frameworks like Jasmine may also167* define global fail functions.168*/169var fail = goog.testing.asserts.fail;170171var argumentsIncludeComments = function(expectedNumberOfNonCommentArgs, args) {172'use strict';173return args.length == expectedNumberOfNonCommentArgs + 1;174};175176var commentArg = function(expectedNumberOfNonCommentArgs, args) {177'use strict';178if (argumentsIncludeComments(expectedNumberOfNonCommentArgs, args)) {179return args[0];180}181182return null;183};184185var nonCommentArg = function(186desiredNonCommentArgIndex, expectedNumberOfNonCommentArgs, args) {187'use strict';188return argumentsIncludeComments(expectedNumberOfNonCommentArgs, args) ?189args[desiredNonCommentArgIndex] :190args[desiredNonCommentArgIndex - 1];191};192193var _validateArguments = function(expectedNumberOfNonCommentArgs, args) {194'use strict';195var valid = args.length == expectedNumberOfNonCommentArgs ||196args.length == expectedNumberOfNonCommentArgs + 1 &&197typeof args[0] === 'string';198if (!valid) {199goog.testing.asserts.raiseException(200'Incorrect arguments passed to assert function.\n' +201'Expected ' + expectedNumberOfNonCommentArgs + ' argument(s) plus ' +202'optional comment; got ' + args.length + '.');203}204};205206/**207* @return {?} goog.testing.TestCase or null208* We suppress the lint error and we explicitly do not goog.require()209* goog.testing.TestCase to avoid a build time dependency cycle.210* @suppress {missingRequire|undefinedVars|missingProperties}211* @private212*/213var _getCurrentTestCase = function() {214'use strict';215// Some users of goog.testing.asserts do not use goog.testing.TestRunner and216// they do not include goog.testing.TestCase. Exceptions will not be217// completely correct for these users.218if (!goog.testing.TestCase) {219if (goog.global.console) {220goog.global.console.error(221'Missing goog.testing.TestCase, ' +222'add /* @suppress {extraRequire} */' +223'goog.require(\'goog.testing.TestCase\')');224}225return null;226}227return goog.testing.TestCase.getActiveTestCase();228};229230var _assert = function(comment, booleanValue, failureMessage) {231'use strict';232// If another framework has installed an adapter, tell it about the assertion.233var adapter =234typeof window !== 'undefined' && window['Closure assert adapter'];235if (adapter) {236adapter['assertWithMessage'](237booleanValue,238goog.testing.JsUnitException.generateMessage(comment, failureMessage));239// Also throw an error, for callers that assume that asserts throw. We don't240// include error details to avoid duplicate failure messages.241if (!booleanValue) throw new Error('goog.testing assertion failed');242}243if (!booleanValue) {244goog.testing.asserts.raiseException(comment, failureMessage);245}246};247248249/**250* @param {*} expected The expected value.251* @param {*} actual The actual value.252* @return {string} A failure message of the values don't match.253* @private254*/255goog.testing.asserts.getDefaultErrorMsg_ = function(expected, actual) {256'use strict';257var expectedDisplayString = _displayStringForValue(expected);258var actualDisplayString = _displayStringForValue(actual);259var shouldUseNewLines =260expectedDisplayString.length > OUTPUT_NEW_LINE_THRESHOLD ||261actualDisplayString.length > OUTPUT_NEW_LINE_THRESHOLD;262var msg = [263'Expected', expectedDisplayString, 'but was', actualDisplayString264].join(shouldUseNewLines ? '\n' : ' ');265266if ((typeof expected == 'string') && (typeof actual == 'string')) {267// Try to find a human-readable difference.268var limit = Math.min(expected.length, actual.length);269var commonPrefix = 0;270while (commonPrefix < limit &&271expected.charAt(commonPrefix) == actual.charAt(commonPrefix)) {272commonPrefix++;273}274275var commonSuffix = 0;276while (commonSuffix < limit &&277expected.charAt(expected.length - commonSuffix - 1) ==278actual.charAt(actual.length - commonSuffix - 1)) {279commonSuffix++;280}281282if (commonPrefix + commonSuffix > limit) {283commonSuffix = 0;284}285286if (commonPrefix > 2 || commonSuffix > 2) {287var printString = function(str) {288'use strict';289var startIndex = Math.max(0, commonPrefix - 2);290var endIndex = Math.min(str.length, str.length - (commonSuffix - 2));291return (startIndex > 0 ? '...' : '') +292str.substring(startIndex, endIndex) +293(endIndex < str.length ? '...' : '');294};295296var expectedPrinted = printString(expected);297var expectedActual = printString(actual);298var shouldUseNewLinesInDiff =299expectedPrinted.length > OUTPUT_NEW_LINE_THRESHOLD ||300expectedActual.length > OUTPUT_NEW_LINE_THRESHOLD;301msg += '\nDifference was at position ' + commonPrefix + '. ' + [302'Expected', '[' + expectedPrinted + ']', 'vs. actual',303'[' + expectedActual + ']'304].join(shouldUseNewLinesInDiff ? '\n' : ' ');305}306}307return msg;308};309310311/**312* @param {*} a The value to assert (1 arg) or debug message (2 args).313* @param {*=} opt_b The value to assert (2 args only).314*/315goog.testing.asserts.assert = function(a, opt_b) {316'use strict';317_validateArguments(1, arguments);318var comment = commentArg(1, arguments);319var booleanValue = nonCommentArg(1, 1, arguments);320321_assert(322comment, typeof booleanValue === 'boolean',323'Bad argument to assert(boolean): ' +324_displayStringForValue(booleanValue));325_assert(comment, booleanValue, 'Call to assert(boolean) with false');326};327/** @const */328var assert = goog.testing.asserts.assert;329330331/**332* Asserts that the function throws an error.333*334* @param {!(string|Function)} a The assertion comment or the function to call.335* @param {!Function=} opt_b The function to call (if the first argument of336* `assertThrows` was the comment).337* @return {!Error} The error thrown by the function. Beware that code may throw338* other types in strange scenarios.339* @throws {goog.testing.JsUnitException} If the assertion failed.340*/341goog.testing.asserts.assertThrows = function(a, opt_b) {342'use strict';343_validateArguments(1, arguments);344var func = nonCommentArg(1, 1, arguments);345var comment = commentArg(1, arguments);346_assert(347comment, typeof func == 'function',348'Argument passed to assertThrows is not a function');349350try {351func();352} catch (e) {353goog.testing.asserts.removeOperaStacktrace_(e);354355var testCase = _getCurrentTestCase();356if (e && e['isJsUnitException'] && testCase) {357goog.testing.asserts.raiseException(358comment,359'Function passed to assertThrows caught a JsUnitException (usually ' +360'from an assert or call to fail()). If this is expected, use ' +361'assertThrowsJsUnitException instead.');362}363364return e;365}366goog.testing.asserts.raiseException(367comment, 'No exception thrown from function passed to assertThrows');368throw new Error('Should have thrown an error.'); // Make the compiler happy.369};370/** @const */371var assertThrows = goog.testing.asserts.assertThrows;372373374/**375* Removes a stacktrace from an Error object for Opera 10.0.376* @param {*} e377* @private378*/379goog.testing.asserts.removeOperaStacktrace_ = function(e) {380'use strict';381if (!goog.isObject(e)) return;382const stack = e['stacktrace'];383const errorMsg = e['message'];384if (typeof stack !== 'string' || typeof errorMsg !== 'string') {385return;386}387const stackStartIndex = errorMsg.length - stack.length;388if (errorMsg.indexOf(stack, stackStartIndex) == stackStartIndex) {389e['message'] = errorMsg.slice(0, stackStartIndex - 14);390}391};392393394/**395* Asserts that the function does not throw an error.396*397* @param {!(string|Function)} a The assertion comment or the function to call.398* @param {!Function=} opt_b The function to call (if the first argument of399* `assertNotThrows` was the comment).400* @return {*} The return value of the function.401* @throws {goog.testing.JsUnitException} If the assertion failed.402*/403goog.testing.asserts.assertNotThrows = function(a, opt_b) {404'use strict';405_validateArguments(1, arguments);406var comment = commentArg(1, arguments);407var func = nonCommentArg(1, 1, arguments);408_assert(409comment, typeof func == 'function',410'Argument passed to assertNotThrows is not a function');411412try {413return func();414} catch (e) {415comment = comment ? (comment + '\n') : '';416comment += 'A non expected exception was thrown from function passed to ' +417'assertNotThrows';418// Some browsers don't have a stack trace so at least have the error419// description.420var stackTrace = e['stack'] || e['stacktrace'] || e.toString();421goog.testing.asserts.raiseException(comment, stackTrace);422}423};424/** @const */425var assertNotThrows = goog.testing.asserts.assertNotThrows;426427428/**429* Asserts that the given callback function results in a JsUnitException when430* called, and that the resulting failure message matches the given expected431* message.432* @param {function() : void} callback Function to be run expected to result433* in a JsUnitException (usually contains a call to an assert).434* @param {string=} opt_expectedMessage Failure message expected to be given435* with the exception.436* @return {!goog.testing.JsUnitException} The error thrown by the function.437* @throws {goog.testing.JsUnitException} If the function did not throw a438* JsUnitException.439*/440goog.testing.asserts.assertThrowsJsUnitException = function(441callback, opt_expectedMessage) {442'use strict';443try {444callback();445} catch (e) {446var testCase = _getCurrentTestCase();447if (testCase) {448testCase.invalidateAssertionException(e);449} else {450goog.global.console.error(451'Failed to remove expected exception: no test case is installed.');452}453454if (!e.isJsUnitException) {455goog.testing.asserts.fail(456'Expected a JsUnitException, got \'' + e + '\' instead');457}458459if (typeof opt_expectedMessage != 'undefined' &&460e.message != opt_expectedMessage) {461goog.testing.asserts.fail(462'Expected message [' + opt_expectedMessage + '] but got [' +463e.message + ']');464}465466return e;467}468469var msg = 'Expected a failure';470if (typeof opt_expectedMessage != 'undefined') {471msg += ': ' + opt_expectedMessage;472}473throw new goog.testing.JsUnitException(msg);474};475/** @const */476var assertThrowsJsUnitException =477goog.testing.asserts.assertThrowsJsUnitException;478479480/**481* Asserts that the IThenable rejects.482*483* This is useful for asserting that async functions throw, like an asynchronous484* assertThrows. Example:485*486* ```487* async function shouldThrow() { throw new Error('error!'); }488* async function testShouldThrow() {489* const error = await assertRejects(shouldThrow());490* assertEquals('error!', error.message);491* }492* ```493*494* @param {!(string|IThenable)} a The assertion comment or the IThenable.495* @param {!IThenable=} opt_b The IThenable (if the first argument of496* `assertRejects` was the comment).497* @return {!IThenable<*>} A child IThenable which resolves with the error that498* the passed in IThenable rejects with. This IThenable will reject if the499* passed in IThenable does not reject.500*/501goog.testing.asserts.assertRejects = function(a, opt_b) {502'use strict';503_validateArguments(1, arguments);504var thenable = /** @type {!IThenable<*>} */ (nonCommentArg(1, 1, arguments));505var comment = commentArg(1, arguments);506_assert(507comment, goog.isObject(thenable) && typeof thenable.then === 'function',508'Argument passed to assertRejects is not an IThenable');509510return thenable.then(511function() {512'use strict';513goog.testing.asserts.raiseException(514comment, 'IThenable passed into assertRejects did not reject');515},516function(e) {517'use strict';518goog.testing.asserts.removeOperaStacktrace_(e);519return e;520});521};522/** @const */523var assertRejects = goog.testing.asserts.assertRejects;524525526/**527* @param {*} a The value to assert (1 arg) or debug message (2 args).528* @param {*=} opt_b The value to assert (2 args only).529*/530goog.testing.asserts.assertTrue = function(a, opt_b) {531'use strict';532_validateArguments(1, arguments);533var comment = commentArg(1, arguments);534var booleanValue = nonCommentArg(1, 1, arguments);535536_assert(537comment, typeof booleanValue === 'boolean',538'Bad argument to assertTrue(boolean): ' +539_displayStringForValue(booleanValue));540_assert(comment, booleanValue, 'Call to assertTrue(boolean) with false');541};542/** @const */543var assertTrue = goog.testing.asserts.assertTrue;544545546/**547* @param {*} a The value to assert (1 arg) or debug message (2 args).548* @param {*=} opt_b The value to assert (2 args only).549*/550goog.testing.asserts.assertFalse = function(a, opt_b) {551'use strict';552_validateArguments(1, arguments);553var comment = commentArg(1, arguments);554var booleanValue = nonCommentArg(1, 1, arguments);555556_assert(557comment, typeof booleanValue === 'boolean',558'Bad argument to assertFalse(boolean): ' +559_displayStringForValue(booleanValue));560_assert(comment, !booleanValue, 'Call to assertFalse(boolean) with true');561};562/** @const */563var assertFalse = goog.testing.asserts.assertFalse;564565566/**567* @param {*} a The expected value (2 args) or the debug message (3 args).568* @param {*} b The actual value (2 args) or the expected value (3 args).569* @param {*=} opt_c The actual value (3 args only).570*/571goog.testing.asserts.assertEquals = function(a, b, opt_c) {572'use strict';573_validateArguments(2, arguments);574var var1 = nonCommentArg(1, 2, arguments);575var var2 = nonCommentArg(2, 2, arguments);576_assert(577commentArg(2, arguments), var1 === var2,578goog.testing.asserts.getDefaultErrorMsg_(var1, var2));579};580/** @const */581var assertEquals = goog.testing.asserts.assertEquals;582583584/**585* @param {*} a The expected value (2 args) or the debug message (3 args).586* @param {*} b The actual value (2 args) or the expected value (3 args).587* @param {*=} opt_c The actual value (3 args only).588*/589goog.testing.asserts.assertNotEquals = function(a, b, opt_c) {590'use strict';591_validateArguments(2, arguments);592var var1 = nonCommentArg(1, 2, arguments);593var var2 = nonCommentArg(2, 2, arguments);594_assert(595commentArg(2, arguments), var1 !== var2,596'Expected not to be ' + _displayStringForValue(var2));597};598/** @const */599var assertNotEquals = goog.testing.asserts.assertNotEquals;600601/**602* @param {*} a The value to assert (1 arg) or debug message (2 args).603* @param {*=} opt_b The value to assert (2 args only).604*/605goog.testing.asserts.assertNull = function(a, opt_b) {606'use strict';607_validateArguments(1, arguments);608var aVar = nonCommentArg(1, 1, arguments);609_assert(610commentArg(1, arguments), aVar === null,611goog.testing.asserts.getDefaultErrorMsg_(null, aVar));612};613/** @const */614var assertNull = goog.testing.asserts.assertNull;615616617/**618* @param {*} a The value to assert (1 arg) or debug message (2 args).619* @param {*=} opt_b The value to assert (2 args only).620*/621goog.testing.asserts.assertNotNull = function(a, opt_b) {622'use strict';623_validateArguments(1, arguments);624var aVar = nonCommentArg(1, 1, arguments);625_assert(626commentArg(1, arguments), aVar !== null,627'Expected not to be ' + _displayStringForValue(null));628};629/** @const */630var assertNotNull = goog.testing.asserts.assertNotNull;631632633/**634* @param {*} a The value to assert (1 arg) or debug message (2 args).635* @param {*=} opt_b The value to assert (2 args only).636*/637goog.testing.asserts.assertUndefined = function(a, opt_b) {638'use strict';639_validateArguments(1, arguments);640var aVar = nonCommentArg(1, 1, arguments);641_assert(642commentArg(1, arguments), aVar === JSUNIT_UNDEFINED_VALUE,643goog.testing.asserts.getDefaultErrorMsg_(JSUNIT_UNDEFINED_VALUE, aVar));644};645/** @const */646var assertUndefined = goog.testing.asserts.assertUndefined;647648649/**650* @param {*} a The value to assert (1 arg) or debug message (2 args).651* @param {*=} opt_b The value to assert (2 args only).652*/653goog.testing.asserts.assertNotUndefined = function(a, opt_b) {654'use strict';655_validateArguments(1, arguments);656var aVar = nonCommentArg(1, 1, arguments);657_assert(658commentArg(1, arguments), aVar !== JSUNIT_UNDEFINED_VALUE,659'Expected not to be ' + _displayStringForValue(JSUNIT_UNDEFINED_VALUE));660};661/** @const */662var assertNotUndefined = goog.testing.asserts.assertNotUndefined;663664/**665* @param {*} a The value to assert (1 arg) or debug message (2 args).666* @param {*=} opt_b The value to assert (2 args only).667*/668goog.testing.asserts.assertNullOrUndefined = function(a, opt_b) {669'use strict';670_validateArguments(1, arguments);671var aVar = nonCommentArg(1, 1, arguments);672_assert(673commentArg(1, arguments), aVar == null,674'Expected ' + _displayStringForValue(null) + ' or ' +675_displayStringForValue(JSUNIT_UNDEFINED_VALUE) + ' but was ' +676_displayStringForValue(aVar));677};678/** @const */679var assertNullOrUndefined = goog.testing.asserts.assertNullOrUndefined;680681/**682* @param {*} a The value to assert (1 arg) or debug message (2 args).683* @param {*=} opt_b The value to assert (2 args only).684*/685goog.testing.asserts.assertNotNullNorUndefined = function(a, opt_b) {686'use strict';687_validateArguments(1, arguments);688goog.testing.asserts.assertNotNull.apply(null, arguments);689goog.testing.asserts.assertNotUndefined.apply(null, arguments);690};691/** @const */692var assertNotNullNorUndefined = goog.testing.asserts.assertNotNullNorUndefined;693694695/**696* @param {*} a The value to assert (1 arg) or debug message (2 args).697* @param {*=} opt_b The value to assert (2 args only).698*/699goog.testing.asserts.assertNonEmptyString = function(a, opt_b) {700'use strict';701_validateArguments(1, arguments);702var aVar = nonCommentArg(1, 1, arguments);703_assert(704commentArg(1, arguments), aVar !== JSUNIT_UNDEFINED_VALUE &&705aVar !== null && typeof aVar == 'string' && aVar !== '',706'Expected non-empty string but was ' + _displayStringForValue(aVar));707};708/** @const */709var assertNonEmptyString = goog.testing.asserts.assertNonEmptyString;710711712/**713* @param {*} a The value to assert (1 arg) or debug message (2 args).714* @param {*=} opt_b The value to assert (2 args only).715*/716goog.testing.asserts.assertNaN = function(a, opt_b) {717'use strict';718_validateArguments(1, arguments);719var aVar = nonCommentArg(1, 1, arguments);720_assert(721commentArg(1, arguments), aVar !== aVar,722'Expected NaN but was ' + _displayStringForValue(aVar));723};724/** @const */725var assertNaN = goog.testing.asserts.assertNaN;726727728/**729* @param {*} a The value to assert (1 arg) or debug message (2 args).730* @param {*=} opt_b The value to assert (2 args only).731*/732goog.testing.asserts.assertNotNaN = function(a, opt_b) {733'use strict';734_validateArguments(1, arguments);735var aVar = nonCommentArg(1, 1, arguments);736_assert(commentArg(1, arguments), !isNaN(aVar), 'Expected not NaN');737};738/** @const */739var assertNotNaN = goog.testing.asserts.assertNotNaN;740741742/**743* The return value of the equality predicate passed to findDifferences below,744* in cases where the predicate can't test the input variables for equality.745* @type {?string}746*/747goog.testing.asserts.EQUALITY_PREDICATE_CANT_PROCESS = null;748749750/**751* The return value of the equality predicate passed to findDifferences below,752* in cases where the input vriables are equal.753* @type {?string}754*/755goog.testing.asserts.EQUALITY_PREDICATE_VARS_ARE_EQUAL = '';756757758/**759* @const {!Object<string, boolean>}760*/761goog.testing.asserts.ARRAY_TYPES = {762'Array': true,763'Float32Array': true,764'Float64Array': true,765'Int8Array': true,766'Int16Array': true,767'Int32Array': true,768'Uint8Array': true,769'Uint8ClampedArray': true,770'Uint16Array': true,771'Uint32Array': true,772'BigInt64Array': true,773'BigUint64Array': true774};775776/**777* The result of a comparison performed by an EqualityFunction: if undefined,778* the inputs are equal; otherwise, a human-readable description of their779* inequality.780*781* @typedef {string|undefined}782*/783goog.testing.asserts.ComparisonResult;784785/**786* A equality predicate.787*788* The first two arguments are the values to be compared. The third is an789* equality function which can be used to recursively apply findDifferences.790*791* An example comparison implementation for Array could be:792*793* function arrayEq(a, b, eq) {794* if (a.length !== b.length) {795* return "lengths unequal";796* }797*798* const differences = [];799* for (let i = 0; i < a.length; i++) {800* // Use the findDifferences implementation to perform recursive801* // comparisons.802* const diff = eq(a[i], b[i], eq);803* if (diff) {804* differences[i] = diff;805* }806* }807*808* if (differences) {809* return `found array differences: ${differences}`;810* }811*812* // Otherwise return undefined, indicating no differences.813* return undefined;814* }815*816* @typedef {function(?, ?, !goog.testing.asserts.EqualityFunction):817* ?goog.testing.asserts.ComparisonResult}818*/819goog.testing.asserts.EqualityFunction;820821/**822* A map from prototype to custom equality matcher.823*824* @type {!Map<!Object, !goog.testing.asserts.EqualityFunction>}825* @private826*/827goog.testing.asserts.CUSTOM_EQUALITY_MATCHERS = new Map();828829/**830* Returns the custom equality predicate for a given prototype, or else831* undefined.832*833* @param {?Object} prototype834* @return {!goog.testing.asserts.EqualityFunction|undefined}835* @private836*/837goog.testing.asserts.getCustomEquality = function(prototype) {838for (; (prototype != null) && (typeof prototype === 'object') &&839(prototype !== Object.prototype);840prototype = Object.getPrototypeOf(prototype)) {841const matcher = goog.testing.asserts.CUSTOM_EQUALITY_MATCHERS.get(842/** @type {!Object} */ (prototype));843if (matcher) {844return matcher;845}846}847return undefined;848};849850/**851* Returns the most specific custom equality predicate which can be applied to852* both arguments, or else undefined.853*854* @param {!Object} obj1855* @param {!Object} obj2856* @return {!goog.testing.asserts.EqualityFunction|undefined}857* @private858*/859goog.testing.asserts.getMostSpecificCustomEquality = function(obj1, obj2) {860for (let prototype = Object.getPrototypeOf(obj1); (prototype != null) &&861(typeof prototype === 'object') && (prototype !== Object.prototype);862prototype = Object.getPrototypeOf(prototype)) {863if (prototype.isPrototypeOf(obj2)) {864return goog.testing.asserts.getCustomEquality(prototype);865}866}867868// Otherwise, obj1 and obj2 did not share a common ancestor other than869// Object.prototype so we cannot have a comparator.870return undefined;871};872873/**874* Executes a custom equality function875*876* @param {!goog.testing.asserts.EqualityFunction} comparator877* @param {!Object} obj1878* @param {!Object} obj2879* @param {string} path of the current field being checked.880* @return {?goog.testing.asserts.ComparisonResult}881* @private882*/883goog.testing.asserts.applyCustomEqualityFunction = function(884comparator, obj1, obj2, path) {885const /* !goog.testing.asserts.EqualityFunction */ callback =886(left, right, unusedEq) => {887const result = goog.testing.asserts.findDifferences(left, right);888return result ? (path ? path + ': ' : '') + result : undefined;889};890return comparator(obj1, obj2, callback);891};892893/**894* Marks the given prototype as having equality semantics provided by the given895* custom equality function.896*897* This will cause findDifferences and assertObjectEquals to use the given898* function when comparing objects with this prototype. When comparing two899* objects with different prototypes, the equality (if any) attached to their900* lowest common ancestor in the prototype hierarchy will be used.901*902* @param {!Object} prototype903* @param {!goog.testing.asserts.EqualityFunction} fn904*/905goog.testing.asserts.registerComparator = function(prototype, fn) {906// First check that there is no comparator currently defined for this907// prototype.908if (goog.testing.asserts.CUSTOM_EQUALITY_MATCHERS.has(prototype)) {909throw new Error('duplicate comparator installation for ' + prototype);910}911912// We cannot install custom equality matchers on Object.prototype, as it913// would replace all other comparisons.914if (prototype === Object.prototype) {915throw new Error('cannot customize root object comparator');916}917918goog.testing.asserts.CUSTOM_EQUALITY_MATCHERS.set(prototype, fn);919};920921/**922* Clears the custom equality function currently applied to the given prototype.923* Returns true if a function was removed.924*925* @param {!Object} prototype926* @return {boolean} whether a comparator was removed.927*/928goog.testing.asserts.clearCustomComparator = function(prototype) {929return goog.testing.asserts.CUSTOM_EQUALITY_MATCHERS.delete(prototype);930};931932/**933* Determines if two items of any type match, and formulates an error message934* if not.935* @param {*} expected Expected argument to match.936* @param {*} actual Argument as a result of performing the test.937* @param {(function(string, *, *): ?string)=} opt_equalityPredicate An optional938* function that can be used to check equality of variables. It accepts 3939* arguments: type-of-variables, var1, var2 (in that order) and returns an940* error message if the variables are not equal,941* goog.testing.asserts.EQUALITY_PREDICATE_VARS_ARE_EQUAL if the variables942* are equal, or943* goog.testing.asserts.EQUALITY_PREDICATE_CANT_PROCESS if the predicate944* couldn't check the input variables. The function will be called only if945* the types of var1 and var2 are identical.946* @return {?string} Null on success, error message on failure.947*/948goog.testing.asserts.findDifferences = function(949expected, actual, opt_equalityPredicate) {950'use strict';951var failures = [];952// Non-null if there an error at the root (with no path). If so, we should953// fail, but not add to the failures array (because it will be included at the954// top anyway).955let /** ?string*/ rootFailure = null;956var seen1 = [];957var seen2 = [];958959// To avoid infinite recursion when the two parameters are self-referential960// along the same path of properties, keep track of the object pairs already961// seen in this call subtree, and abort when a cycle is detected.962function innerAssertWithCycleCheck(var1, var2, path) {963// This is used for testing, so we can afford to be slow (but more964// accurate). So we just check whether var1 is in seen1. If we965// found var1 in index i, we simply need to check whether var2 is966// in seen2[i]. If it is, we do not recurse to check var1/var2. If967// it isn't, we know that the structures of the two objects must be968// different.969//970// This is based on the fact that values at index i in seen1 and971// seen2 will be checked for equality eventually (when972// innerAssertImplementation(seen1[i], seen2[i], path) finishes).973for (var i = 0; i < seen1.length; ++i) {974var match1 = seen1[i] === var1;975var match2 = seen2[i] === var2;976if (match1 || match2) {977if (!match1 || !match2) {978// Asymmetric cycles, so the objects have different structure.979failures.push('Asymmetric cycle detected at ' + path);980}981return;982}983}984985seen1.push(var1);986seen2.push(var2);987innerAssertImplementation(var1, var2, path);988seen1.pop();989seen2.pop();990}991992const equalityPredicate = function(type, var1, var2) {993'use strict';994// use the custom predicate if supplied.995const customPredicateResult = opt_equalityPredicate ?996opt_equalityPredicate(type, var1, var2) :997goog.testing.asserts.EQUALITY_PREDICATE_CANT_PROCESS;998if (customPredicateResult !==999goog.testing.asserts.EQUALITY_PREDICATE_CANT_PROCESS) {1000return customPredicateResult;1001}1002// otherwise use the default behavior.1003const typedPredicate = EQUALITY_PREDICATES[type];1004if (!typedPredicate) {1005return goog.testing.asserts.EQUALITY_PREDICATE_CANT_PROCESS;1006}1007const equal = typedPredicate(var1, var2);1008return equal ? goog.testing.asserts.EQUALITY_PREDICATE_VARS_ARE_EQUAL :1009goog.testing.asserts.getDefaultErrorMsg_(var1, var2);1010};10111012/**1013* @param {*} var1 An item in the expected object.1014* @param {*} var2 The corresponding item in the actual object.1015* @param {string} path Their path in the objects.1016* @suppress {missingProperties} The map_ property is unknown to the compiler1017* unless goog.structs.Map is loaded.1018*/1019function innerAssertImplementation(var1, var2, path) {1020if (var1 === var2) {1021return;1022}10231024var typeOfVar1 = _trueTypeOf(var1);1025var typeOfVar2 = _trueTypeOf(var2);10261027if (typeOfVar1 === typeOfVar2) {1028// For two objects of the same type, if one is a prototype of another, use1029// the custom equality function for the more generic of the two1030// prototypes, if available.1031if (var1 && typeof var1 === 'object') {1032try {1033const o1 = /** @type {!Object} */ (var1);1034const o2 = /** @type {!Object} */ (var2);1035const comparator =1036goog.testing.asserts.getMostSpecificCustomEquality(o1, o2);1037if (comparator) {1038const result = goog.testing.asserts.applyCustomEqualityFunction(1039comparator, o1, o2, path);1040if (result != null) {1041if (path) {1042failures.push(path + ': ' + result);1043} else {1044rootFailure = result;1045}1046}1047return;1048}1049} catch (e) {1050// Catch and log errors from custom comparators but fall back onto1051// ordinary comparisons. Such errors can occur, e.g. with proxies or1052// when the prototypes of a polyfill are not traversable.1053//1054// If you see a failure due to this line, please do not use1055// findDifferences or assertObjectEquals on these argument types.1056goog.global.console.error('Error in custom comparator: ' + e);1057}1058}10591060const isArrayBuffer = typeOfVar1 === 'ArrayBuffer';1061if (isArrayBuffer) {1062// Since ArrayBuffer instances can't themselves be iterated through,1063// compare 1-byte-per-element views of them.1064var1 = new Uint8Array(/** @type {!ArrayBuffer} */ (var1));1065var2 = new Uint8Array(/** @type {!ArrayBuffer} */ (var2));1066}1067const isArray =1068isArrayBuffer || goog.testing.asserts.ARRAY_TYPES[typeOfVar1];1069var errorMessage = equalityPredicate(typeOfVar1, var1, var2);1070if (errorMessage !=1071goog.testing.asserts.EQUALITY_PREDICATE_CANT_PROCESS) {1072if (errorMessage !=1073goog.testing.asserts.EQUALITY_PREDICATE_VARS_ARE_EQUAL) {1074if (path) {1075failures.push(path + ': ' + errorMessage);1076} else {1077rootFailure = errorMessage;1078}1079}1080} else if (isArray && var1.length != var2.length) {1081failures.push(1082(path ? path + ': ' : '') + 'Expected ' + var1.length +1083'-element array ' +1084'but got a ' + var2.length + '-element array');1085} else if (typeOfVar1 == 'String') {1086// If the comparer cannot process strings (eg, roughlyEquals).1087if (var1 != var2) {1088const error = goog.testing.asserts.getDefaultErrorMsg_(var1, var2);1089if (path) {1090failures.push(path + ': ' + error);1091} else {1092rootFailure = error;1093}1094}1095} else {1096var childPath = path + (isArray ? '[%s]' : (path ? '.%s' : '%s'));1097// These type checks do not use _trueTypeOf because that does not work1098// for polyfilled Map/Set. Note that these checks may potentially fail1099// if var1 comes from a different window.1100if ((typeof Map != 'undefined' && var1 instanceof Map) ||1101(typeof Set != 'undefined' && var1 instanceof Set)) {1102var1.forEach(function(value, key) {1103'use strict';1104if (var2.has(key)) {1105// For a map, the values must be compared, but with Set, checking1106// that the second set contains the first set's "keys" is1107// sufficient.1108if (var2.get) {1109innerAssertWithCycleCheck(1110// NOTE: replace will call functions, so stringify eagerly.1111value, var2.get(key), childPath.replace('%s', String(key)));1112}1113} else {1114failures.push(1115key + ' not present in actual ' + (path || typeOfVar2));1116}1117});11181119var2.forEach(function(value, key) {1120'use strict';1121if (!var1.has(key)) {1122failures.push(1123key + ' not present in expected ' + (path || typeOfVar1));1124}1125});1126} else if (!var1['__iterator__']) {1127// if an object has an __iterator__ property, we have no way of1128// actually inspecting its raw properties, and JS 1.7 doesn't1129// overload [] to make it possible for someone to generically1130// use what the iterator returns to compare the object-managed1131// properties. This gets us into deep poo with things like1132// goog.structs.Map, at least on systems that support iteration.1133for (var prop in var1) {1134if (isArray && goog.testing.asserts.isArrayIndexProp_(prop)) {1135// Skip array indices for now. We'll handle them later.1136continue;1137}11381139if (prop in var2) {1140innerAssertWithCycleCheck(1141var1[prop], var2[prop], childPath.replace('%s', prop));1142} else {1143failures.push(1144'property ' + prop + ' not present in actual ' +1145(path || typeOfVar2));1146}1147}1148// make sure there aren't properties in var2 that are missing1149// from var1. if there are, then by definition they don't1150// match.1151for (var prop in var2) {1152if (isArray && goog.testing.asserts.isArrayIndexProp_(prop)) {1153// Skip array indices for now. We'll handle them later.1154continue;1155}11561157if (!(prop in var1)) {1158failures.push(1159'property ' + prop + ' not present in expected ' +1160(path || typeOfVar1));1161}1162}11631164// Handle array indices by iterating from 0 to arr.length.1165//1166// Although all browsers allow holes in arrays, browsers1167// are inconsistent in what they consider a hole. For example,1168// "[0,undefined,2]" has a hole on IE but not on Firefox.1169//1170// Because our style guide bans for...in iteration over arrays,1171// we assume that most users don't care about holes in arrays,1172// and that it is ok to say that a hole is equivalent to a slot1173// populated with 'undefined'.1174if (isArray) {1175for (prop = 0; prop < var1.length; prop++) {1176innerAssertWithCycleCheck(1177var1[prop], var2[prop],1178childPath.replace('%s', String(prop)));1179}1180}1181} else {1182// special-case for closure objects that have iterators1183if (typeof var1.equals === 'function') {1184// use the object's own equals function, assuming it accepts an1185// object and returns a boolean1186if (!var1.equals(var2)) {1187failures.push(1188'equals() returned false for ' + (path || typeOfVar1));1189}1190} else if (var1.map_) {1191// assume goog.structs.Map or goog.structs.Set, where comparing1192// their private map_ field is sufficient1193innerAssertWithCycleCheck(1194var1.map_, var2.map_, childPath.replace('%s', 'map_'));1195} else {1196// else die, so user knows we can't do anything1197failures.push(1198'unable to check ' + (path || typeOfVar1) +1199' for equality: it has an iterator we do not ' +1200'know how to handle. please add an equals method');1201}1202}1203}1204} else if (path) {1205failures.push(1206path + ': ' + goog.testing.asserts.getDefaultErrorMsg_(var1, var2));1207} else {1208rootFailure = goog.testing.asserts.getDefaultErrorMsg_(var1, var2);1209}1210}12111212innerAssertWithCycleCheck(expected, actual, '');12131214if (rootFailure) {1215return rootFailure;1216}1217return failures.length == 0 ? null : goog.testing.asserts.getDefaultErrorMsg_(1218expected, actual) +1219'\n ' + failures.join('\n ');1220};122112221223/**1224* Notes:1225* Object equality has some nasty browser quirks, and this implementation is1226* not 100% correct. For example,1227*1228* <code>1229* var a = [0, 1, 2];1230* var b = [0, 1, 2];1231* delete a[1];1232* b[1] = undefined;1233* assertObjectEquals(a, b); // should fail, but currently passes1234* </code>1235*1236* See asserts_test.html for more interesting edge cases.1237*1238* The first comparison object provided is the expected value, the second is1239* the actual.1240*1241* @param {*} a Assertion message or comparison object.1242* @param {*} b Comparison object.1243* @param {*=} opt_c Comparison object, if an assertion message was provided.1244*/1245goog.testing.asserts.assertObjectEquals = function(a, b, opt_c) {1246'use strict';1247_validateArguments(2, arguments);1248var v1 = nonCommentArg(1, 2, arguments);1249var v2 = nonCommentArg(2, 2, arguments);1250var failureMessage = commentArg(2, arguments) ? commentArg(2, arguments) : '';1251var differences = goog.testing.asserts.findDifferences(v1, v2);12521253_assert(failureMessage, !differences, differences);1254};1255/** @const */1256var assertObjectEquals = goog.testing.asserts.assertObjectEquals;125712581259/**1260* Similar to assertObjectEquals above, but accepts a tolerance margin.1261*1262* @param {*} a Assertion message or comparison object.1263* @param {*} b Comparison object.1264* @param {*} c Comparison object or tolerance.1265* @param {*=} opt_d Tolerance, if an assertion message was provided.1266*/1267goog.testing.asserts.assertObjectRoughlyEquals = function(a, b, c, opt_d) {1268'use strict';1269_validateArguments(3, arguments);1270var v1 = nonCommentArg(1, 3, arguments);1271var v2 = nonCommentArg(2, 3, arguments);1272var tolerance = nonCommentArg(3, 3, arguments);1273var failureMessage = commentArg(3, arguments) ? commentArg(3, arguments) : '';1274var equalityPredicate = function(type, var1, var2) {1275'use strict';1276var typedPredicate =1277goog.testing.asserts.primitiveRoughEqualityPredicates_[type];1278if (!typedPredicate) {1279return goog.testing.asserts.EQUALITY_PREDICATE_CANT_PROCESS;1280}1281var equal = typedPredicate(var1, var2, tolerance);1282return equal ? goog.testing.asserts.EQUALITY_PREDICATE_VARS_ARE_EQUAL :1283goog.testing.asserts.getDefaultErrorMsg_(var1, var2) +1284' which was more than ' + tolerance + ' away';1285};1286var differences =1287goog.testing.asserts.findDifferences(v1, v2, equalityPredicate);12881289_assert(failureMessage, !differences, differences);1290};1291/** @const */1292var assertObjectRoughlyEquals = goog.testing.asserts.assertObjectRoughlyEquals;12931294/**1295* Compares two arbitrary objects for non-equalness.1296*1297* All the same caveats as for assertObjectEquals apply here:1298* Undefined values may be confused for missing values, or vice versa.1299*1300* @param {*} a Assertion message or comparison object.1301* @param {*} b Comparison object.1302* @param {*=} opt_c Comparison object, if an assertion message was provided.1303*/1304goog.testing.asserts.assertObjectNotEquals = function(a, b, opt_c) {1305'use strict';1306_validateArguments(2, arguments);1307var v1 = nonCommentArg(1, 2, arguments);1308var v2 = nonCommentArg(2, 2, arguments);1309var failureMessage = commentArg(2, arguments) ? commentArg(2, arguments) : '';1310var differences = goog.testing.asserts.findDifferences(v1, v2);13111312_assert(failureMessage, differences, 'Objects should not be equal');1313};1314/** @const */1315var assertObjectNotEquals = goog.testing.asserts.assertObjectNotEquals;131613171318/**1319* Compares two arrays ignoring negative indexes and extra properties on the1320* array objects. Use case: Internet Explorer adds the index, lastIndex and1321* input enumerable fields to the result of string.match(/regexp/g), which makes1322* assertObjectEquals fail.1323* @param {*} a The expected array (2 args) or the debug message (3 args).1324* @param {*} b The actual array (2 args) or the expected array (3 args).1325* @param {*=} opt_c The actual array (3 args only).1326*/1327goog.testing.asserts.assertArrayEquals = function(a, b, opt_c) {1328'use strict';1329_validateArguments(2, arguments);1330var v1 = nonCommentArg(1, 2, arguments);1331var v2 = nonCommentArg(2, 2, arguments);1332var failureMessage = commentArg(2, arguments) ? commentArg(2, arguments) : '';13331334var typeOfVar1 = _trueTypeOf(v1);1335_assert(1336failureMessage, typeOfVar1 == 'Array',1337'Expected an array for assertArrayEquals but found a ' + typeOfVar1);13381339var typeOfVar2 = _trueTypeOf(v2);1340_assert(1341failureMessage, typeOfVar2 == 'Array',1342'Expected an array for assertArrayEquals but found a ' + typeOfVar2);13431344goog.testing.asserts.assertObjectEquals(1345failureMessage, Array.prototype.concat.call(v1),1346Array.prototype.concat.call(v2));1347};1348/** @const */1349var assertArrayEquals = goog.testing.asserts.assertArrayEquals;135013511352/**1353* Compares two objects that can be accessed like an array and assert that1354* each element is equal.1355* @param {string|Object} a Failure message (3 arguments)1356* or object #1 (2 arguments).1357* @param {Object} b Object #2 (2 arguments) or object #1 (3 arguments).1358* @param {Object=} opt_c Object #2 (3 arguments).1359*/1360goog.testing.asserts.assertElementsEquals = function(a, b, opt_c) {1361'use strict';1362_validateArguments(2, arguments);13631364var v1 = nonCommentArg(1, 2, arguments);1365var v2 = nonCommentArg(2, 2, arguments);1366var failureMessage = commentArg(2, arguments) ? commentArg(2, arguments) : '';13671368if (!v1) {1369goog.testing.asserts.assert(failureMessage, !v2);1370} else {1371goog.testing.asserts.assertEquals(1372'length mismatch: ' + failureMessage, v1.length, v2.length);1373for (var i = 0; i < v1.length; ++i) {1374goog.testing.asserts.assertEquals(1375'mismatch at index ' + i + ': ' + failureMessage, v1[i], v2[i]);1376}1377}1378};1379/** @const */1380var assertElementsEquals = goog.testing.asserts.assertElementsEquals;138113821383/**1384* Compares two objects that can be accessed like an array and assert that1385* each element is roughly equal.1386* @param {string|Object} a Failure message (4 arguments)1387* or object #1 (3 arguments).1388* @param {Object} b Object #1 (4 arguments) or object #2 (3 arguments).1389* @param {Object|number} c Object #2 (4 arguments) or tolerance (3 arguments).1390* @param {number=} opt_d tolerance (4 arguments).1391*/1392goog.testing.asserts.assertElementsRoughlyEqual = function(a, b, c, opt_d) {1393'use strict';1394_validateArguments(3, arguments);13951396var v1 = nonCommentArg(1, 3, arguments);1397var v2 = nonCommentArg(2, 3, arguments);1398var tolerance = nonCommentArg(3, 3, arguments);1399var failureMessage = commentArg(3, arguments) ? commentArg(3, arguments) : '';14001401if (!v1) {1402goog.testing.asserts.assert(failureMessage, !v2);1403} else {1404goog.testing.asserts.assertEquals(1405'length mismatch: ' + failureMessage, v1.length, v2.length);1406for (var i = 0; i < v1.length; ++i) {1407goog.testing.asserts.assertRoughlyEquals(1408failureMessage, v1[i], v2[i], tolerance);1409}1410}1411};1412/** @const */1413var assertElementsRoughlyEqual =1414goog.testing.asserts.assertElementsRoughlyEqual;14151416/**1417* Compares elements of two array-like or iterable objects using strict equality1418* without taking their order into account.1419* @param {string|!IArrayLike|!Iterable} a Assertion message or the1420* expected elements.1421* @param {!IArrayLike|!Iterable} b Expected elements or the actual1422* elements.1423* @param {!IArrayLike|!Iterable=} opt_c Actual elements.1424*/1425goog.testing.asserts.assertSameElements = function(a, b, opt_c) {1426'use strict';1427_validateArguments(2, arguments);1428var expected = nonCommentArg(1, 2, arguments);1429var actual = nonCommentArg(2, 2, arguments);1430var message = commentArg(2, arguments);14311432goog.testing.asserts.assertTrue(1433'Value of \'expected\' should be array-like or iterable',1434goog.testing.asserts.isArrayLikeOrIterable_(expected));14351436goog.testing.asserts.assertTrue(1437'Value of \'actual\' should be array-like or iterable',1438goog.testing.asserts.isArrayLikeOrIterable_(actual));14391440// Clones expected and actual and converts them to real arrays.1441expected = goog.testing.asserts.toArray_(expected);1442actual = goog.testing.asserts.toArray_(actual);1443// TODO(user): It would be great to show only the difference1444// between the expected and actual elements.1445_assert(1446message, expected.length == actual.length, 'Expected ' + expected.length +1447' elements: [' + expected + '], ' +1448'got ' + actual.length + ' elements: [' + actual + ']');14491450var toFind = goog.testing.asserts.toArray_(expected);1451for (var i = 0; i < actual.length; i++) {1452var index = goog.testing.asserts.indexOf_(toFind, actual[i]);1453_assert(1454message, index != -1,1455'Expected [' + expected + '], got [' + actual + ']');1456toFind.splice(index, 1);1457}1458};1459/** @const */1460var assertSameElements = goog.testing.asserts.assertSameElements;14611462/**1463* @param {*} obj Object to test.1464* @return {boolean} Whether given object is array-like or iterable.1465* @private1466*/1467goog.testing.asserts.isArrayLikeOrIterable_ = function(obj) {1468'use strict';1469return goog.isArrayLike(obj) || goog.testing.asserts.isIterable_(obj);1470};14711472/**1473* @param {*} a The value to assert (1 arg) or debug message (2 args).1474* @param {*=} opt_b The value to assert (2 args only).1475*/1476goog.testing.asserts.assertEvaluatesToTrue = function(a, opt_b) {1477'use strict';1478_validateArguments(1, arguments);1479var value = nonCommentArg(1, 1, arguments);1480if (!value) {1481_assert(commentArg(1, arguments), false, 'Expected to evaluate to true');1482}1483};1484/** @const */1485var assertEvaluatesToTrue = goog.testing.asserts.assertEvaluatesToTrue;14861487/**1488* @param {*} a The value to assert (1 arg) or debug message (2 args).1489* @param {*=} opt_b The value to assert (2 args only).1490*/1491goog.testing.asserts.assertEvaluatesToFalse = function(a, opt_b) {1492'use strict';1493_validateArguments(1, arguments);1494var value = nonCommentArg(1, 1, arguments);1495if (value) {1496_assert(commentArg(1, arguments), false, 'Expected to evaluate to false');1497}1498};1499/** @const */1500var assertEvaluatesToFalse = goog.testing.asserts.assertEvaluatesToFalse;15011502/**1503* Compares two HTML snippets.1504*1505* Take extra care if attributes are involved. `assertHTMLEquals`'s1506* implementation isn't prepared for complex cases. For example, the following1507* comparisons erroneously fail:1508* <pre>1509* assertHTMLEquals('<a href="x" target="y">', '<a target="y" href="x">');1510* assertHTMLEquals('<div class="a b">', '<div class="b a">');1511* assertHTMLEquals('<input disabled>', '<input disabled="disabled">');1512* </pre>1513*1514* When in doubt, use `goog.testing.dom.assertHtmlMatches`.1515*1516* @param {*} a The expected value (2 args) or the debug message (3 args).1517* @param {*} b The actual value (2 args) or the expected value (3 args).1518* @param {*=} opt_c The actual value (3 args only).1519*/1520goog.testing.asserts.assertHTMLEquals = function(a, b, opt_c) {1521'use strict';1522_validateArguments(2, arguments);1523var var1 = nonCommentArg(1, 2, arguments);1524var var2 = nonCommentArg(2, 2, arguments);1525var var1Standardized = standardizeHTML(var1);1526var var2Standardized = standardizeHTML(var2);15271528_assert(1529commentArg(2, arguments), var1Standardized === var2Standardized,1530goog.testing.asserts.getDefaultErrorMsg_(1531var1Standardized, var2Standardized));1532};1533/** @const */1534var assertHTMLEquals = goog.testing.asserts.assertHTMLEquals;153515361537/**1538* Compares two CSS property values to make sure that they represent the same1539* things. This will normalize values in the browser. For example, in Firefox,1540* this assertion will consider "rgb(0, 0, 255)" and "#0000ff" to be identical1541* values for the "color" property. This function won't normalize everything --1542* for example, in most browsers, "blue" will not match "#0000ff". It is1543* intended only to compensate for unexpected normalizations performed by1544* the browser that should also affect your expected value.1545* @param {string} a Assertion message, or the CSS property name.1546* @param {string} b CSS property name, or the expected value.1547* @param {string} c The expected value, or the actual value.1548* @param {string=} opt_d The actual value.1549*/1550goog.testing.asserts.assertCSSValueEquals = function(a, b, c, opt_d) {1551'use strict';1552_validateArguments(3, arguments);1553var propertyName = nonCommentArg(1, 3, arguments);1554var expectedValue = nonCommentArg(2, 3, arguments);1555var actualValue = nonCommentArg(3, 3, arguments);1556var expectedValueStandardized =1557standardizeCSSValue(propertyName, expectedValue);1558var actualValueStandardized = standardizeCSSValue(propertyName, actualValue);15591560_assert(1561commentArg(3, arguments),1562expectedValueStandardized == actualValueStandardized,1563goog.testing.asserts.getDefaultErrorMsg_(1564expectedValueStandardized, actualValueStandardized));1565};1566/** @const */1567var assertCSSValueEquals = goog.testing.asserts.assertCSSValueEquals;156815691570/**1571* @param {*} a The expected value (2 args) or the debug message (3 args).1572* @param {*} b The actual value (2 args) or the expected value (3 args).1573* @param {*=} opt_c The actual value (3 args only).1574*/1575goog.testing.asserts.assertHashEquals = function(a, b, opt_c) {1576'use strict';1577_validateArguments(2, arguments);1578var var1 = nonCommentArg(1, 2, arguments);1579var var2 = nonCommentArg(2, 2, arguments);1580var message = commentArg(2, arguments);1581for (var key in var1) {1582_assert(1583message, key in var2,1584'Expected hash had key ' + key + ' that was not found');1585_assert(1586message, var1[key] == var2[key], 'Value for key ' + key +1587' mismatch - expected = ' + var1[key] + ', actual = ' + var2[key]);1588}15891590for (var key in var2) {1591_assert(1592message, key in var1,1593'Actual hash had key ' + key + ' that was not expected');1594}1595};1596/** @const */1597var assertHashEquals = goog.testing.asserts.assertHashEquals;159815991600/**1601* @param {*} a The expected value (3 args) or the debug message (4 args).1602* @param {*} b The actual value (3 args) or the expected value (4 args).1603* @param {*} c The tolerance (3 args) or the actual value (4 args).1604* @param {*=} opt_d The tolerance (4 args only).1605*/1606goog.testing.asserts.assertRoughlyEquals = function(a, b, c, opt_d) {1607'use strict';1608_validateArguments(3, arguments);1609var expected = nonCommentArg(1, 3, arguments);1610var actual = nonCommentArg(2, 3, arguments);1611var tolerance = nonCommentArg(3, 3, arguments);1612_assert(1613commentArg(3, arguments),1614goog.testing.asserts.numberRoughEqualityPredicate_(1615expected, actual, tolerance),1616'Expected ' + expected + ', but got ' + actual + ' which was more than ' +1617tolerance + ' away');1618};1619/** @const */1620var assertRoughlyEquals = goog.testing.asserts.assertRoughlyEquals;162116221623/**1624* Checks if the test value is included in the given container. The container1625* can be a string (where "included" means a substring), an array or any1626* `IArrayLike` (where "included" means a member), or any type implementing1627* `indexOf` with similar semantics (returning -1 for not included).1628*1629* @param {*} a Failure message (3 arguments) or the test value1630* (2 arguments).1631* @param {*} b The test value (3 arguments) or the container1632* (2 arguments).1633* @param {*=} opt_c The container.1634*/1635goog.testing.asserts.assertContains = function(a, b, opt_c) {1636'use strict';1637_validateArguments(2, arguments);1638var contained = nonCommentArg(1, 2, arguments);1639var container = nonCommentArg(2, 2, arguments);1640_assert(1641commentArg(2, arguments),1642goog.testing.asserts.contains_(container, contained),1643'Expected \'' + container + '\' to contain \'' + contained + '\'');1644};1645/** @const */1646var assertContains = goog.testing.asserts.assertContains;16471648/**1649* Checks if the test value is not included in the given container. The1650* container can be a string (where "included" means a substring), an array or1651* any `IArrayLike` (where "included" means a member), or any type implementing1652* `indexOf` with similar semantics (returning -1 for not included).1653* @param {*} a Failure message (3 arguments) or the contained element1654* (2 arguments).1655* @param {*} b The contained element (3 arguments) or the container1656* (2 arguments).1657* @param {*=} opt_c The container.1658*/1659goog.testing.asserts.assertNotContains = function(a, b, opt_c) {1660'use strict';1661_validateArguments(2, arguments);1662var contained = nonCommentArg(1, 2, arguments);1663var container = nonCommentArg(2, 2, arguments);1664_assert(1665commentArg(2, arguments),1666!goog.testing.asserts.contains_(container, contained),1667'Expected \'' + container + '\' not to contain \'' + contained + '\'');1668};1669/** @const */1670var assertNotContains = goog.testing.asserts.assertNotContains;167116721673/**1674* Checks if the given string matches the given regular expression.1675* @param {*} a Failure message (3 arguments) or the expected regular1676* expression as a string or RegExp (2 arguments).1677* @param {*} b The regular expression (3 arguments) or the string to test1678* (2 arguments).1679* @param {*=} opt_c The string to test.1680*/1681goog.testing.asserts.assertRegExp = function(a, b, opt_c) {1682'use strict';1683_validateArguments(2, arguments);1684var regexp = nonCommentArg(1, 2, arguments);1685var string = nonCommentArg(2, 2, arguments);1686if (typeof(regexp) == 'string') {1687regexp = new RegExp(regexp);1688}1689_assert(1690commentArg(2, arguments), regexp.test(string),1691'Expected \'' + string + '\' to match RegExp ' + regexp.toString());1692};1693/** @const */1694var assertRegExp = goog.testing.asserts.assertRegExp;169516961697/**1698* Converts an array-like or iterable object to an array (clones it if it's1699* already an array).1700* @param {!Iterable|!IArrayLike} obj The collection object.1701* @return {!Array<?>} Copy of the collection as array.1702* @private1703*/1704goog.testing.asserts.toArray_ = function(obj) {1705'use strict';1706var ret = [];1707if (goog.testing.asserts.isIterable_(obj)) {1708var iterator =1709goog.testing.asserts.getIterator_(/** @type {!Iterable} */ (obj));17101711// Cannot use for..of syntax here as ES6 syntax is not available in Closure.1712// See b/1172310921713while (true) {1714var result = iterator.next();1715if (result.done) {1716return ret;1717}1718ret.push(result.value);1719}1720}17211722for (var i = 0; i < /** @type {!IArrayLike} */ (obj).length; i++) {1723ret[i] = obj[i];1724}1725return ret;1726};17271728// TODO(nnaze): Consider moving isIterable_ and getIterator_ functionality1729// into goog.iter.es6. See discussion in cl/217356297.17301731/**1732* @param {*} obj1733* @return {boolean} Whether the object is iterable (JS iterator protocol).1734* @private1735*/1736goog.testing.asserts.isIterable_ = function(obj) {1737'use strict';1738return !!(1739typeof Symbol !== 'undefined' && Symbol.iterator && obj[Symbol.iterator]);1740};17411742/**1743* @param {!Iterable} iterable1744* @return {!Iterator} An iterator for obj.1745* @throws {!goog.testing.JsUnitException} If the given object is not iterable.1746* @private1747*/1748goog.testing.asserts.getIterator_ = function(iterable) {1749'use strict';1750if (!goog.testing.asserts.isIterable_(iterable)) {1751goog.testing.asserts.raiseException('parameter iterable is not iterable');1752}17531754return iterable[Symbol.iterator]();1755};175617571758/**1759* Finds the position of the first occurrence of an element in a container.1760* @param {IArrayLike<?>|{indexOf: function(*): number}} container1761* The array to find the element in.1762* @param {*} contained Element to find.1763* @return {number} Index of the first occurrence or -1 if not found.1764* @private1765*/1766goog.testing.asserts.indexOf_ = function(container, contained) {1767'use strict';1768if (typeof container.indexOf == 'function') {1769return /** @type {{indexOf: function(*): number}} */ (container).indexOf(1770contained);1771} else {1772// IE6/7 do not have indexOf so do a search.1773for (var i = 0; i < /** @type {!IArrayLike<?>} */ (container).length; i++) {1774if (container[i] === contained) {1775return i;1776}1777}1778return -1;1779}1780};178117821783/**1784* Tells whether the array contains the given element.1785* @param {IArrayLike<?>|{indexOf: function(*): number}} container The array to1786* find the element in.1787* @param {*} contained Element to find.1788* @return {boolean} Whether the element is in the array.1789* @private1790*/1791goog.testing.asserts.contains_ = function(container, contained) {1792'use strict';1793// TODO(user): Can we check for container.contains as well?1794// That would give us support for most goog.structs (though weird results1795// with anything else with a contains method, like goog.math.Range). Falling1796// back with container.some would catch all iterables, too.1797return goog.testing.asserts.indexOf_(container, contained) != -1;1798};17991800var standardizeHTML = function(html) {1801'use strict';1802var translator = document.createElement('div');18031804goog.dom.safe.setInnerHtml(1805translator,1806goog.html.uncheckedconversions1807.safeHtmlFromStringKnownToSatisfyTypeContract(1808goog.string.Const.from('HTML is never attached to DOM'), html));18091810// Trim whitespace from result (without relying on goog.string)1811return translator.innerHTML.replace(/^\s+|\s+$/g, '');1812};181318141815/**1816* Standardizes a CSS value for a given property by applying it to an element1817* and then reading it back.1818* @param {string} propertyName CSS property name.1819* @param {string} value CSS value.1820* @return {string} Normalized CSS value.1821*/1822var standardizeCSSValue = function(propertyName, value) {1823'use strict';1824var styleDeclaration = document.createElement('div').style;1825styleDeclaration[propertyName] = value;1826return styleDeclaration[propertyName];1827};182818291830/**1831* Raises a JsUnit exception with the given comment. If the exception is1832* unexpectedly caught during a unit test, it will be rethrown so that it is1833* seen by the test framework.1834* @param {string} comment A summary for the exception.1835* @param {string=} opt_message A description of the exception.1836*/1837goog.testing.asserts.raiseException = function(comment, opt_message) {1838'use strict';1839var e = new goog.testing.JsUnitException(comment, opt_message);18401841var testCase = _getCurrentTestCase();1842if (testCase) {1843testCase.raiseAssertionException(e);1844} else {1845goog.global.console.error(1846'Failed to save thrown exception: no test case is installed.');1847throw e;1848}1849};185018511852/**1853* Helper function for assertObjectEquals.1854* @param {string} prop A property name.1855* @return {boolean} If the property name is an array index.1856* @private1857*/1858goog.testing.asserts.isArrayIndexProp_ = function(prop) {1859'use strict';1860return prop === '0' || /^[1-9][0-9]*$/.test(prop);1861};18621863/** @define {boolean} */1864goog.EXPORT_ASSERTIONS = goog.define('goog.EXPORT_ASSERTIONS', true);1865/*1866* These symbols are both exported in the global namespace (for legacy1867* reasons) and as part of the goog.testing.asserts namespace. Although they1868* can be used globally in tests, these symbols are allowed to be imported for1869* cleaner typing.1870*/1871if (goog.EXPORT_ASSERTIONS) {1872goog.exportSymbol('fail', fail);1873goog.exportSymbol('assert', assert);1874goog.exportSymbol('assertThrows', assertThrows);1875goog.exportSymbol('assertNotThrows', assertNotThrows);1876goog.exportSymbol('assertThrowsJsUnitException', assertThrowsJsUnitException);1877goog.exportSymbol('assertRejects', assertRejects);1878goog.exportSymbol('assertTrue', assertTrue);1879goog.exportSymbol('assertFalse', assertFalse);1880goog.exportSymbol('assertEquals', assertEquals);1881goog.exportSymbol('assertNotEquals', assertNotEquals);1882goog.exportSymbol('assertNull', assertNull);1883goog.exportSymbol('assertNotNull', assertNotNull);1884goog.exportSymbol('assertUndefined', assertUndefined);1885goog.exportSymbol('assertNotUndefined', assertNotUndefined);1886goog.exportSymbol('assertNullOrUndefined', assertNullOrUndefined);1887goog.exportSymbol('assertNotNullNorUndefined', assertNotNullNorUndefined);1888goog.exportSymbol('assertNonEmptyString', assertNonEmptyString);1889goog.exportSymbol('assertNaN', assertNaN);1890goog.exportSymbol('assertNotNaN', assertNotNaN);1891goog.exportSymbol('assertObjectEquals', assertObjectEquals);1892goog.exportSymbol('assertObjectRoughlyEquals', assertObjectRoughlyEquals);1893goog.exportSymbol('assertObjectNotEquals', assertObjectNotEquals);1894goog.exportSymbol('assertArrayEquals', assertArrayEquals);1895goog.exportSymbol('assertElementsEquals', assertElementsEquals);1896goog.exportSymbol('assertElementsRoughlyEqual', assertElementsRoughlyEqual);1897goog.exportSymbol('assertSameElements', assertSameElements);1898goog.exportSymbol('assertEvaluatesToTrue', assertEvaluatesToTrue);1899goog.exportSymbol('assertEvaluatesToFalse', assertEvaluatesToFalse);1900goog.exportSymbol('assertHTMLEquals', assertHTMLEquals);1901goog.exportSymbol('assertHashEquals', assertHashEquals);1902goog.exportSymbol('assertRoughlyEquals', assertRoughlyEquals);1903goog.exportSymbol('assertContains', assertContains);1904goog.exportSymbol('assertNotContains', assertNotContains);1905goog.exportSymbol('assertRegExp', assertRegExp);1906}190719081909