asserts.js 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353
  1. // Copyright 2010 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. goog.provide('goog.testing.asserts');
  15. goog.setTestOnly();
  16. goog.require('goog.testing.JsUnitException');
  17. // TODO(user): Copied from JsUnit with some small modifications, we should
  18. // reimplement the asserters.
  19. var DOUBLE_EQUALITY_PREDICATE = function(var1, var2) {
  20. return var1 == var2;
  21. };
  22. var JSUNIT_UNDEFINED_VALUE = void 0;
  23. var TO_STRING_EQUALITY_PREDICATE = function(var1, var2) {
  24. return var1.toString() === var2.toString();
  25. };
  26. var OUTPUT_NEW_LINE_THRESHOLD = 40;
  27. /** @typedef {function(?, ?):boolean} */
  28. var PredicateFunctionType;
  29. /**
  30. * @const {{
  31. * String : PredicateFunctionType,
  32. * Number : PredicateFunctionType,
  33. * Boolean : PredicateFunctionType,
  34. * Date : PredicateFunctionType,
  35. * RegExp : PredicateFunctionType,
  36. * Function : PredicateFunctionType
  37. * }}
  38. */
  39. var PRIMITIVE_EQUALITY_PREDICATES = {
  40. 'String': DOUBLE_EQUALITY_PREDICATE,
  41. 'Number': DOUBLE_EQUALITY_PREDICATE,
  42. 'Boolean': DOUBLE_EQUALITY_PREDICATE,
  43. 'Date': function(date1, date2) { return date1.getTime() == date2.getTime(); },
  44. 'RegExp': TO_STRING_EQUALITY_PREDICATE,
  45. 'Function': TO_STRING_EQUALITY_PREDICATE
  46. };
  47. /**
  48. * Compares equality of two numbers, allowing them to differ up to a given
  49. * tolerance.
  50. * @param {number} var1 A number.
  51. * @param {number} var2 A number.
  52. * @param {number} tolerance the maximum allowed difference.
  53. * @return {boolean} Whether the two variables are sufficiently close.
  54. * @private
  55. */
  56. goog.testing.asserts.numberRoughEqualityPredicate_ = function(
  57. var1, var2, tolerance) {
  58. return Math.abs(var1 - var2) <= tolerance;
  59. };
  60. /**
  61. * @type {Object<string, function(*, *, number): boolean>}
  62. * @private
  63. */
  64. goog.testing.asserts.primitiveRoughEqualityPredicates_ = {
  65. 'Number': goog.testing.asserts.numberRoughEqualityPredicate_
  66. };
  67. var _trueTypeOf = function(something) {
  68. var result = typeof something;
  69. try {
  70. switch (result) {
  71. case 'string':
  72. break;
  73. case 'boolean':
  74. break;
  75. case 'number':
  76. break;
  77. case 'object':
  78. if (something == null) {
  79. result = 'null';
  80. break;
  81. }
  82. case 'function':
  83. switch (something.constructor) {
  84. case new String('').constructor:
  85. result = 'String';
  86. break;
  87. case new Boolean(true).constructor:
  88. result = 'Boolean';
  89. break;
  90. case new Number(0).constructor:
  91. result = 'Number';
  92. break;
  93. case new Array().constructor:
  94. result = 'Array';
  95. break;
  96. case new RegExp().constructor:
  97. result = 'RegExp';
  98. break;
  99. case new Date().constructor:
  100. result = 'Date';
  101. break;
  102. case Function:
  103. result = 'Function';
  104. break;
  105. default:
  106. var m =
  107. something.constructor.toString().match(/function\s*([^( ]+)\(/);
  108. if (m) {
  109. result = m[1];
  110. } else {
  111. break;
  112. }
  113. }
  114. break;
  115. }
  116. } catch (e) {
  117. } finally {
  118. result = result.substr(0, 1).toUpperCase() + result.substr(1);
  119. }
  120. return result;
  121. };
  122. var _displayStringForValue = function(aVar) {
  123. var result;
  124. try {
  125. result = '<' + String(aVar) + '>';
  126. } catch (ex) {
  127. result = '<toString failed: ' + ex.message + '>';
  128. // toString does not work on this object :-(
  129. }
  130. if (!(aVar === null || aVar === JSUNIT_UNDEFINED_VALUE)) {
  131. result += ' (' + _trueTypeOf(aVar) + ')';
  132. }
  133. return result;
  134. };
  135. var fail = function(failureMessage) {
  136. goog.testing.asserts.raiseException('Call to fail()', failureMessage);
  137. };
  138. var argumentsIncludeComments = function(expectedNumberOfNonCommentArgs, args) {
  139. return args.length == expectedNumberOfNonCommentArgs + 1;
  140. };
  141. var commentArg = function(expectedNumberOfNonCommentArgs, args) {
  142. if (argumentsIncludeComments(expectedNumberOfNonCommentArgs, args)) {
  143. return args[0];
  144. }
  145. return null;
  146. };
  147. var nonCommentArg = function(
  148. desiredNonCommentArgIndex, expectedNumberOfNonCommentArgs, args) {
  149. return argumentsIncludeComments(expectedNumberOfNonCommentArgs, args) ?
  150. args[desiredNonCommentArgIndex] :
  151. args[desiredNonCommentArgIndex - 1];
  152. };
  153. var _validateArguments = function(expectedNumberOfNonCommentArgs, args) {
  154. var valid = args.length == expectedNumberOfNonCommentArgs ||
  155. args.length == expectedNumberOfNonCommentArgs + 1 &&
  156. goog.isString(args[0]);
  157. _assert(null, valid, 'Incorrect arguments passed to assert function');
  158. };
  159. var _getCurrentTestCase = function() {
  160. // We can't call goog.testing.TestCase.getActiveTestCase because there would
  161. // be a dependency cycle; this effectively does the same thing.
  162. var testRunner = goog.global['G_testRunner'];
  163. return testRunner ? testRunner.testCase : null;
  164. };
  165. var _assert = function(comment, booleanValue, failureMessage) {
  166. if (!booleanValue) {
  167. goog.testing.asserts.raiseException(comment, failureMessage);
  168. }
  169. };
  170. /**
  171. * @param {*} expected The expected value.
  172. * @param {*} actual The actual value.
  173. * @return {string} A failure message of the values don't match.
  174. * @private
  175. */
  176. goog.testing.asserts.getDefaultErrorMsg_ = function(expected, actual) {
  177. var expectedDisplayString = _displayStringForValue(expected);
  178. var actualDisplayString = _displayStringForValue(actual);
  179. var shouldUseNewLines =
  180. expectedDisplayString.length > OUTPUT_NEW_LINE_THRESHOLD ||
  181. actualDisplayString.length > OUTPUT_NEW_LINE_THRESHOLD;
  182. var msg = [
  183. 'Expected', expectedDisplayString, 'but was', actualDisplayString
  184. ].join(shouldUseNewLines ? '\n' : ' ');
  185. if ((typeof expected == 'string') && (typeof actual == 'string')) {
  186. // Try to find a human-readable difference.
  187. var limit = Math.min(expected.length, actual.length);
  188. var commonPrefix = 0;
  189. while (commonPrefix < limit &&
  190. expected.charAt(commonPrefix) == actual.charAt(commonPrefix)) {
  191. commonPrefix++;
  192. }
  193. var commonSuffix = 0;
  194. while (commonSuffix < limit &&
  195. expected.charAt(expected.length - commonSuffix - 1) ==
  196. actual.charAt(actual.length - commonSuffix - 1)) {
  197. commonSuffix++;
  198. }
  199. if (commonPrefix + commonSuffix > limit) {
  200. commonSuffix = 0;
  201. }
  202. if (commonPrefix > 2 || commonSuffix > 2) {
  203. var printString = function(str) {
  204. var startIndex = Math.max(0, commonPrefix - 2);
  205. var endIndex = Math.min(str.length, str.length - (commonSuffix - 2));
  206. return (startIndex > 0 ? '...' : '') +
  207. str.substring(startIndex, endIndex) +
  208. (endIndex < str.length ? '...' : '');
  209. };
  210. var expectedPrinted = printString(expected);
  211. var expectedActual = printString(actual);
  212. var shouldUseNewLinesInDiff =
  213. expectedPrinted.length > OUTPUT_NEW_LINE_THRESHOLD ||
  214. expectedActual.length > OUTPUT_NEW_LINE_THRESHOLD;
  215. msg += '\nDifference was at position ' + commonPrefix + '. ' + [
  216. 'Expected', '[' + expectedPrinted + ']', 'vs. actual',
  217. '[' + expectedActual + ']'
  218. ].join(shouldUseNewLinesInDiff ? '\n' : ' ');
  219. }
  220. }
  221. return msg;
  222. };
  223. /**
  224. * @param {*} a The value to assert (1 arg) or debug message (2 args).
  225. * @param {*=} opt_b The value to assert (2 args only).
  226. */
  227. var assert = function(a, opt_b) {
  228. _validateArguments(1, arguments);
  229. var comment = commentArg(1, arguments);
  230. var booleanValue = nonCommentArg(1, 1, arguments);
  231. _assert(
  232. comment, goog.isBoolean(booleanValue), 'Bad argument to assert(boolean)');
  233. _assert(comment, booleanValue, 'Call to assert(boolean) with false');
  234. };
  235. /**
  236. * Asserts that the function throws an error.
  237. *
  238. * @param {!(string|Function)} a The assertion comment or the function to call.
  239. * @param {!Function=} opt_b The function to call (if the first argument of
  240. * {@code assertThrows} was the comment).
  241. * @return {*} The error thrown by the function.
  242. * @throws {goog.testing.JsUnitException} If the assertion failed.
  243. */
  244. var assertThrows = function(a, opt_b) {
  245. _validateArguments(1, arguments);
  246. var func = nonCommentArg(1, 1, arguments);
  247. var comment = commentArg(1, arguments);
  248. _assert(
  249. comment, typeof func == 'function',
  250. 'Argument passed to assertThrows is not a function');
  251. try {
  252. func();
  253. } catch (e) {
  254. if (e && goog.isString(e['stacktrace']) && goog.isString(e['message'])) {
  255. // Remove the stack trace appended to the error message by Opera 10.0
  256. var startIndex = e['message'].length - e['stacktrace'].length;
  257. if (e['message'].indexOf(e['stacktrace'], startIndex) == startIndex) {
  258. e['message'] = e['message'].substr(0, startIndex - 14);
  259. }
  260. }
  261. var testCase = _getCurrentTestCase();
  262. if (e && e['isJsUnitException'] && testCase &&
  263. testCase.failOnUnreportedAsserts) {
  264. goog.testing.asserts.raiseException(
  265. comment,
  266. 'Function passed to assertThrows caught a JsUnitException (usually ' +
  267. 'from an assert or call to fail()). If this is expected, use ' +
  268. 'assertThrowsJsUnitException instead.');
  269. }
  270. return e;
  271. }
  272. goog.testing.asserts.raiseException(
  273. comment, 'No exception thrown from function passed to assertThrows');
  274. };
  275. /**
  276. * Asserts that the function does not throw an error.
  277. *
  278. * @param {!(string|Function)} a The assertion comment or the function to call.
  279. * @param {!Function=} opt_b The function to call (if the first argument of
  280. * {@code assertNotThrows} was the comment).
  281. * @return {*} The return value of the function.
  282. * @throws {goog.testing.JsUnitException} If the assertion failed.
  283. */
  284. var assertNotThrows = function(a, opt_b) {
  285. _validateArguments(1, arguments);
  286. var comment = commentArg(1, arguments);
  287. var func = nonCommentArg(1, 1, arguments);
  288. _assert(
  289. comment, typeof func == 'function',
  290. 'Argument passed to assertNotThrows is not a function');
  291. try {
  292. return func();
  293. } catch (e) {
  294. comment = comment ? (comment + '\n') : '';
  295. comment += 'A non expected exception was thrown from function passed to ' +
  296. 'assertNotThrows';
  297. // Some browsers don't have a stack trace so at least have the error
  298. // description.
  299. var stackTrace = e['stack'] || e['stacktrace'] || e.toString();
  300. goog.testing.asserts.raiseException(comment, stackTrace);
  301. }
  302. };
  303. /**
  304. * Asserts that the given callback function results in a JsUnitException when
  305. * called, and that the resulting failure message matches the given expected
  306. * message.
  307. * @param {function() : void} callback Function to be run expected to result
  308. * in a JsUnitException (usually contains a call to an assert).
  309. * @param {string=} opt_expectedMessage Failure message expected to be given
  310. * with the exception.
  311. * @return {!goog.testing.JsUnitException} The error thrown by the function.
  312. * @throws {goog.testing.JsUnitException} If the function did not throw a
  313. * JsUnitException.
  314. */
  315. var assertThrowsJsUnitException = function(callback, opt_expectedMessage) {
  316. try {
  317. goog.testing.asserts.callWithoutLogging(callback);
  318. } catch (e) {
  319. var testCase = _getCurrentTestCase();
  320. if (testCase) {
  321. testCase.invalidateAssertionException(e);
  322. } else {
  323. goog.global.console.error(
  324. 'Failed to remove expected exception: no test case is installed.');
  325. }
  326. if (!e.isJsUnitException) {
  327. fail('Expected a JsUnitException');
  328. }
  329. if (typeof opt_expectedMessage != 'undefined' &&
  330. e.message != opt_expectedMessage) {
  331. fail(
  332. 'Expected message [' + opt_expectedMessage + '] but got [' +
  333. e.message + ']');
  334. }
  335. return e;
  336. }
  337. var msg = 'Expected a failure';
  338. if (typeof opt_expectedMessage != 'undefined') {
  339. msg += ': ' + opt_expectedMessage;
  340. }
  341. throw new goog.testing.JsUnitException(msg);
  342. };
  343. /**
  344. * @param {*} a The value to assert (1 arg) or debug message (2 args).
  345. * @param {*=} opt_b The value to assert (2 args only).
  346. */
  347. var assertTrue = function(a, opt_b) {
  348. _validateArguments(1, arguments);
  349. var comment = commentArg(1, arguments);
  350. var booleanValue = nonCommentArg(1, 1, arguments);
  351. _assert(
  352. comment, goog.isBoolean(booleanValue),
  353. 'Bad argument to assertTrue(boolean)');
  354. _assert(comment, booleanValue, 'Call to assertTrue(boolean) with false');
  355. };
  356. /**
  357. * @param {*} a The value to assert (1 arg) or debug message (2 args).
  358. * @param {*=} opt_b The value to assert (2 args only).
  359. */
  360. var assertFalse = function(a, opt_b) {
  361. _validateArguments(1, arguments);
  362. var comment = commentArg(1, arguments);
  363. var booleanValue = nonCommentArg(1, 1, arguments);
  364. _assert(
  365. comment, goog.isBoolean(booleanValue),
  366. 'Bad argument to assertFalse(boolean)');
  367. _assert(comment, !booleanValue, 'Call to assertFalse(boolean) with true');
  368. };
  369. /**
  370. * @param {*} a The expected value (2 args) or the debug message (3 args).
  371. * @param {*} b The actual value (2 args) or the expected value (3 args).
  372. * @param {*=} opt_c The actual value (3 args only).
  373. */
  374. var assertEquals = function(a, b, opt_c) {
  375. _validateArguments(2, arguments);
  376. var var1 = nonCommentArg(1, 2, arguments);
  377. var var2 = nonCommentArg(2, 2, arguments);
  378. _assert(
  379. commentArg(2, arguments), var1 === var2,
  380. goog.testing.asserts.getDefaultErrorMsg_(var1, var2));
  381. };
  382. /**
  383. * @param {*} a The expected value (2 args) or the debug message (3 args).
  384. * @param {*} b The actual value (2 args) or the expected value (3 args).
  385. * @param {*=} opt_c The actual value (3 args only).
  386. */
  387. var assertNotEquals = function(a, b, opt_c) {
  388. _validateArguments(2, arguments);
  389. var var1 = nonCommentArg(1, 2, arguments);
  390. var var2 = nonCommentArg(2, 2, arguments);
  391. _assert(
  392. commentArg(2, arguments), var1 !== var2,
  393. 'Expected not to be ' + _displayStringForValue(var2));
  394. };
  395. /**
  396. * @param {*} a The value to assert (1 arg) or debug message (2 args).
  397. * @param {*=} opt_b The value to assert (2 args only).
  398. */
  399. var assertNull = function(a, opt_b) {
  400. _validateArguments(1, arguments);
  401. var aVar = nonCommentArg(1, 1, arguments);
  402. _assert(
  403. commentArg(1, arguments), aVar === null,
  404. goog.testing.asserts.getDefaultErrorMsg_(null, aVar));
  405. };
  406. /**
  407. * @param {*} a The value to assert (1 arg) or debug message (2 args).
  408. * @param {*=} opt_b The value to assert (2 args only).
  409. */
  410. var assertNotNull = function(a, opt_b) {
  411. _validateArguments(1, arguments);
  412. var aVar = nonCommentArg(1, 1, arguments);
  413. _assert(
  414. commentArg(1, arguments), aVar !== null,
  415. 'Expected not to be ' + _displayStringForValue(null));
  416. };
  417. /**
  418. * @param {*} a The value to assert (1 arg) or debug message (2 args).
  419. * @param {*=} opt_b The value to assert (2 args only).
  420. */
  421. var assertUndefined = function(a, opt_b) {
  422. _validateArguments(1, arguments);
  423. var aVar = nonCommentArg(1, 1, arguments);
  424. _assert(
  425. commentArg(1, arguments), aVar === JSUNIT_UNDEFINED_VALUE,
  426. goog.testing.asserts.getDefaultErrorMsg_(JSUNIT_UNDEFINED_VALUE, aVar));
  427. };
  428. /**
  429. * @param {*} a The value to assert (1 arg) or debug message (2 args).
  430. * @param {*=} opt_b The value to assert (2 args only).
  431. */
  432. var assertNotUndefined = function(a, opt_b) {
  433. _validateArguments(1, arguments);
  434. var aVar = nonCommentArg(1, 1, arguments);
  435. _assert(
  436. commentArg(1, arguments), aVar !== JSUNIT_UNDEFINED_VALUE,
  437. 'Expected not to be ' + _displayStringForValue(JSUNIT_UNDEFINED_VALUE));
  438. };
  439. /**
  440. * @param {*} a The value to assert (1 arg) or debug message (2 args).
  441. * @param {*=} opt_b The value to assert (2 args only).
  442. */
  443. var assertNotNullNorUndefined = function(a, opt_b) {
  444. _validateArguments(1, arguments);
  445. assertNotNull.apply(null, arguments);
  446. assertNotUndefined.apply(null, arguments);
  447. };
  448. /**
  449. * @param {*} a The value to assert (1 arg) or debug message (2 args).
  450. * @param {*=} opt_b The value to assert (2 args only).
  451. */
  452. var assertNonEmptyString = function(a, opt_b) {
  453. _validateArguments(1, arguments);
  454. var aVar = nonCommentArg(1, 1, arguments);
  455. _assert(
  456. commentArg(1, arguments), aVar !== JSUNIT_UNDEFINED_VALUE &&
  457. aVar !== null && typeof aVar == 'string' && aVar !== '',
  458. 'Expected non-empty string but was ' + _displayStringForValue(aVar));
  459. };
  460. /**
  461. * @param {*} a The value to assert (1 arg) or debug message (2 args).
  462. * @param {*=} opt_b The value to assert (2 args only).
  463. */
  464. var assertNaN = function(a, opt_b) {
  465. _validateArguments(1, arguments);
  466. var aVar = nonCommentArg(1, 1, arguments);
  467. _assert(commentArg(1, arguments), isNaN(aVar), 'Expected NaN');
  468. };
  469. /**
  470. * @param {*} a The value to assert (1 arg) or debug message (2 args).
  471. * @param {*=} opt_b The value to assert (2 args only).
  472. */
  473. var assertNotNaN = function(a, opt_b) {
  474. _validateArguments(1, arguments);
  475. var aVar = nonCommentArg(1, 1, arguments);
  476. _assert(commentArg(1, arguments), !isNaN(aVar), 'Expected not NaN');
  477. };
  478. /**
  479. * Runs a function in an environment where test failures are not logged. This is
  480. * useful for testing test code, where failures can be a normal part of a test.
  481. * @param {function() : void} fn Function to run without logging failures.
  482. */
  483. goog.testing.asserts.callWithoutLogging = function(fn) {
  484. var testRunner = goog.global['G_testRunner'];
  485. var oldLogTestFailure = testRunner['logTestFailure'];
  486. try {
  487. // Any failures in the callback shouldn't be recorded.
  488. testRunner['logTestFailure'] = undefined;
  489. fn();
  490. } finally {
  491. testRunner['logTestFailure'] = oldLogTestFailure;
  492. }
  493. };
  494. /**
  495. * The return value of the equality predicate passed to findDifferences below,
  496. * in cases where the predicate can't test the input variables for equality.
  497. * @type {?string}
  498. */
  499. goog.testing.asserts.EQUALITY_PREDICATE_CANT_PROCESS = null;
  500. /**
  501. * The return value of the equality predicate passed to findDifferences below,
  502. * in cases where the input vriables are equal.
  503. * @type {?string}
  504. */
  505. goog.testing.asserts.EQUALITY_PREDICATE_VARS_ARE_EQUAL = '';
  506. /**
  507. * Determines if two items of any type match, and formulates an error message
  508. * if not.
  509. * @param {*} expected Expected argument to match.
  510. * @param {*} actual Argument as a result of performing the test.
  511. * @param {(function(string, *, *): ?string)=} opt_equalityPredicate An optional
  512. * function that can be used to check equality of variables. It accepts 3
  513. * arguments: type-of-variables, var1, var2 (in that order) and returns an
  514. * error message if the variables are not equal,
  515. * goog.testing.asserts.EQUALITY_PREDICATE_VARS_ARE_EQUAL if the variables
  516. * are equal, or
  517. * goog.testing.asserts.EQUALITY_PREDICATE_CANT_PROCESS if the predicate
  518. * couldn't check the input variables. The function will be called only if
  519. * the types of var1 and var2 are identical.
  520. * @return {?string} Null on success, error message on failure.
  521. */
  522. goog.testing.asserts.findDifferences = function(
  523. expected, actual, opt_equalityPredicate) {
  524. var failures = [];
  525. var seen1 = [];
  526. var seen2 = [];
  527. // To avoid infinite recursion when the two parameters are self-referential
  528. // along the same path of properties, keep track of the object pairs already
  529. // seen in this call subtree, and abort when a cycle is detected.
  530. function innerAssertWithCycleCheck(var1, var2, path) {
  531. // This is used for testing, so we can afford to be slow (but more
  532. // accurate). So we just check whether var1 is in seen1. If we
  533. // found var1 in index i, we simply need to check whether var2 is
  534. // in seen2[i]. If it is, we do not recurse to check var1/var2. If
  535. // it isn't, we know that the structures of the two objects must be
  536. // different.
  537. //
  538. // This is based on the fact that values at index i in seen1 and
  539. // seen2 will be checked for equality eventually (when
  540. // innerAssertImplementation(seen1[i], seen2[i], path) finishes).
  541. for (var i = 0; i < seen1.length; ++i) {
  542. var match1 = seen1[i] === var1;
  543. var match2 = seen2[i] === var2;
  544. if (match1 || match2) {
  545. if (!match1 || !match2) {
  546. // Asymmetric cycles, so the objects have different structure.
  547. failures.push('Asymmetric cycle detected at ' + path);
  548. }
  549. return;
  550. }
  551. }
  552. seen1.push(var1);
  553. seen2.push(var2);
  554. innerAssertImplementation(var1, var2, path);
  555. seen1.pop();
  556. seen2.pop();
  557. }
  558. var equalityPredicate = opt_equalityPredicate || function(type, var1, var2) {
  559. var typedPredicate = PRIMITIVE_EQUALITY_PREDICATES[type];
  560. if (!typedPredicate) {
  561. return goog.testing.asserts.EQUALITY_PREDICATE_CANT_PROCESS;
  562. }
  563. var equal = typedPredicate(var1, var2);
  564. return equal ? goog.testing.asserts.EQUALITY_PREDICATE_VARS_ARE_EQUAL :
  565. goog.testing.asserts.getDefaultErrorMsg_(var1, var2);
  566. };
  567. /**
  568. * @param {*} var1 An item in the expected object.
  569. * @param {*} var2 The corresponding item in the actual object.
  570. * @param {string} path Their path in the objects.
  571. * @suppress {missingProperties} The map_ property is unknown to the compiler
  572. * unless goog.structs.Map is loaded.
  573. */
  574. function innerAssertImplementation(var1, var2, path) {
  575. if (var1 === var2) {
  576. return;
  577. }
  578. var typeOfVar1 = _trueTypeOf(var1);
  579. var typeOfVar2 = _trueTypeOf(var2);
  580. if (typeOfVar1 == typeOfVar2) {
  581. var isArray = typeOfVar1 == 'Array';
  582. var errorMessage = equalityPredicate(typeOfVar1, var1, var2);
  583. if (errorMessage !=
  584. goog.testing.asserts.EQUALITY_PREDICATE_CANT_PROCESS) {
  585. if (errorMessage !=
  586. goog.testing.asserts.EQUALITY_PREDICATE_VARS_ARE_EQUAL) {
  587. failures.push(path + ': ' + errorMessage);
  588. }
  589. } else if (isArray && var1.length != var2.length) {
  590. failures.push(
  591. path + ': Expected ' + var1.length + '-element array ' +
  592. 'but got a ' + var2.length + '-element array');
  593. } else if (typeOfVar1 == 'String') {
  594. if (var1 != var2) {
  595. failures.push(
  596. path + ': Expected String "' + var1 + '" ' +
  597. 'but got "' + var2 + '"');
  598. }
  599. } else {
  600. var childPath = path + (isArray ? '[%s]' : (path ? '.%s' : '%s'));
  601. // These type checks do not use _trueTypeOf because that does not work
  602. // for polyfilled Map/Set. Note that these checks may potentially fail
  603. // if var1 comes from a different window.
  604. if ((typeof Map != 'undefined' && var1 instanceof Map) ||
  605. (typeof Set != 'undefined' && var1 instanceof Set)) {
  606. var1.forEach(function(value, key) {
  607. if (var2.has(key)) {
  608. // For a map, the values must be compared, but with Set, checking
  609. // that the second set contains the first set's "keys" is
  610. // sufficient.
  611. if (var2.get) {
  612. innerAssertWithCycleCheck(
  613. value, var2.get(key), childPath.replace('%s', key));
  614. }
  615. } else {
  616. failures.push(
  617. key + ' not present in actual ' + (path || typeOfVar2));
  618. }
  619. });
  620. var2.forEach(function(value, key) {
  621. if (!var1.has(key)) {
  622. failures.push(
  623. key + ' not present in expected ' + (path || typeOfVar1));
  624. }
  625. });
  626. } else if (!var1['__iterator__']) {
  627. // if an object has an __iterator__ property, we have no way of
  628. // actually inspecting its raw properties, and JS 1.7 doesn't
  629. // overload [] to make it possible for someone to generically
  630. // use what the iterator returns to compare the object-managed
  631. // properties. This gets us into deep poo with things like
  632. // goog.structs.Map, at least on systems that support iteration.
  633. for (var prop in var1) {
  634. if (isArray && goog.testing.asserts.isArrayIndexProp_(prop)) {
  635. // Skip array indices for now. We'll handle them later.
  636. continue;
  637. }
  638. if (prop in var2) {
  639. innerAssertWithCycleCheck(
  640. var1[prop], var2[prop], childPath.replace('%s', prop));
  641. } else {
  642. failures.push(
  643. 'property ' + prop + ' not present in actual ' +
  644. (path || typeOfVar2));
  645. }
  646. }
  647. // make sure there aren't properties in var2 that are missing
  648. // from var1. if there are, then by definition they don't
  649. // match.
  650. for (var prop in var2) {
  651. if (isArray && goog.testing.asserts.isArrayIndexProp_(prop)) {
  652. // Skip array indices for now. We'll handle them later.
  653. continue;
  654. }
  655. if (!(prop in var1)) {
  656. failures.push(
  657. 'property ' + prop + ' not present in expected ' +
  658. (path || typeOfVar1));
  659. }
  660. }
  661. // Handle array indices by iterating from 0 to arr.length.
  662. //
  663. // Although all browsers allow holes in arrays, browsers
  664. // are inconsistent in what they consider a hole. For example,
  665. // "[0,undefined,2]" has a hole on IE but not on Firefox.
  666. //
  667. // Because our style guide bans for...in iteration over arrays,
  668. // we assume that most users don't care about holes in arrays,
  669. // and that it is ok to say that a hole is equivalent to a slot
  670. // populated with 'undefined'.
  671. if (isArray) {
  672. for (prop = 0; prop < var1.length; prop++) {
  673. innerAssertWithCycleCheck(
  674. var1[prop], var2[prop],
  675. childPath.replace('%s', String(prop)));
  676. }
  677. }
  678. } else {
  679. // special-case for closure objects that have iterators
  680. if (goog.isFunction(var1.equals)) {
  681. // use the object's own equals function, assuming it accepts an
  682. // object and returns a boolean
  683. if (!var1.equals(var2)) {
  684. failures.push(
  685. 'equals() returned false for ' + (path || typeOfVar1));
  686. }
  687. } else if (var1.map_) {
  688. // assume goog.structs.Map or goog.structs.Set, where comparing
  689. // their private map_ field is sufficient
  690. innerAssertWithCycleCheck(
  691. var1.map_, var2.map_, childPath.replace('%s', 'map_'));
  692. } else {
  693. // else die, so user knows we can't do anything
  694. failures.push(
  695. 'unable to check ' + (path || typeOfVar1) +
  696. ' for equality: it has an iterator we do not ' +
  697. 'know how to handle. please add an equals method');
  698. }
  699. }
  700. }
  701. } else {
  702. failures.push(
  703. path + ' ' + goog.testing.asserts.getDefaultErrorMsg_(var1, var2));
  704. }
  705. }
  706. innerAssertWithCycleCheck(expected, actual, '');
  707. return failures.length == 0 ? null : goog.testing.asserts.getDefaultErrorMsg_(
  708. expected, actual) +
  709. '\n ' + failures.join('\n ');
  710. };
  711. /**
  712. * Notes:
  713. * Object equality has some nasty browser quirks, and this implementation is
  714. * not 100% correct. For example,
  715. *
  716. * <code>
  717. * var a = [0, 1, 2];
  718. * var b = [0, 1, 2];
  719. * delete a[1];
  720. * b[1] = undefined;
  721. * assertObjectEquals(a, b); // should fail, but currently passes
  722. * </code>
  723. *
  724. * See asserts_test.html for more interesting edge cases.
  725. *
  726. * The first comparison object provided is the expected value, the second is
  727. * the actual.
  728. *
  729. * @param {*} a Assertion message or comparison object.
  730. * @param {*} b Comparison object.
  731. * @param {*=} opt_c Comparison object, if an assertion message was provided.
  732. */
  733. var assertObjectEquals = function(a, b, opt_c) {
  734. _validateArguments(2, arguments);
  735. var v1 = nonCommentArg(1, 2, arguments);
  736. var v2 = nonCommentArg(2, 2, arguments);
  737. var failureMessage = commentArg(2, arguments) ? commentArg(2, arguments) : '';
  738. var differences = goog.testing.asserts.findDifferences(v1, v2);
  739. _assert(failureMessage, !differences, differences);
  740. };
  741. /**
  742. * Similar to assertObjectEquals above, but accepts a tolerance margin.
  743. *
  744. * @param {*} a Assertion message or comparison object.
  745. * @param {*} b Comparison object.
  746. * @param {*} c Comparison object or tolerance.
  747. * @param {*=} opt_d Tolerance, if an assertion message was provided.
  748. */
  749. var assertObjectRoughlyEquals = function(a, b, c, opt_d) {
  750. _validateArguments(3, arguments);
  751. var v1 = nonCommentArg(1, 3, arguments);
  752. var v2 = nonCommentArg(2, 3, arguments);
  753. var tolerance = nonCommentArg(3, 3, arguments);
  754. var failureMessage = commentArg(3, arguments) ? commentArg(3, arguments) : '';
  755. var equalityPredicate = function(type, var1, var2) {
  756. var typedPredicate =
  757. goog.testing.asserts.primitiveRoughEqualityPredicates_[type];
  758. if (!typedPredicate) {
  759. return goog.testing.asserts.EQUALITY_PREDICATE_CANT_PROCESS;
  760. }
  761. var equal = typedPredicate(var1, var2, tolerance);
  762. return equal ? goog.testing.asserts.EQUALITY_PREDICATE_VARS_ARE_EQUAL :
  763. goog.testing.asserts.getDefaultErrorMsg_(var1, var2) +
  764. ' which was more than ' + tolerance + ' away';
  765. };
  766. var differences =
  767. goog.testing.asserts.findDifferences(v1, v2, equalityPredicate);
  768. _assert(failureMessage, !differences, differences);
  769. };
  770. /**
  771. * Compares two arbitrary objects for non-equalness.
  772. *
  773. * All the same caveats as for assertObjectEquals apply here:
  774. * Undefined values may be confused for missing values, or vice versa.
  775. *
  776. * @param {*} a Assertion message or comparison object.
  777. * @param {*} b Comparison object.
  778. * @param {*=} opt_c Comparison object, if an assertion message was provided.
  779. */
  780. var assertObjectNotEquals = function(a, b, opt_c) {
  781. _validateArguments(2, arguments);
  782. var v1 = nonCommentArg(1, 2, arguments);
  783. var v2 = nonCommentArg(2, 2, arguments);
  784. var failureMessage = commentArg(2, arguments) ? commentArg(2, arguments) : '';
  785. var differences = goog.testing.asserts.findDifferences(v1, v2);
  786. _assert(failureMessage, differences, 'Objects should not be equal');
  787. };
  788. /**
  789. * Compares two arrays ignoring negative indexes and extra properties on the
  790. * array objects. Use case: Internet Explorer adds the index, lastIndex and
  791. * input enumerable fields to the result of string.match(/regexp/g), which makes
  792. * assertObjectEquals fail.
  793. * @param {*} a The expected array (2 args) or the debug message (3 args).
  794. * @param {*} b The actual array (2 args) or the expected array (3 args).
  795. * @param {*=} opt_c The actual array (3 args only).
  796. */
  797. var assertArrayEquals = function(a, b, opt_c) {
  798. _validateArguments(2, arguments);
  799. var v1 = nonCommentArg(1, 2, arguments);
  800. var v2 = nonCommentArg(2, 2, arguments);
  801. var failureMessage = commentArg(2, arguments) ? commentArg(2, arguments) : '';
  802. var typeOfVar1 = _trueTypeOf(v1);
  803. _assert(
  804. failureMessage, typeOfVar1 == 'Array',
  805. 'Expected an array for assertArrayEquals but found a ' + typeOfVar1);
  806. var typeOfVar2 = _trueTypeOf(v2);
  807. _assert(
  808. failureMessage, typeOfVar2 == 'Array',
  809. 'Expected an array for assertArrayEquals but found a ' + typeOfVar2);
  810. assertObjectEquals(
  811. failureMessage, Array.prototype.concat.call(v1),
  812. Array.prototype.concat.call(v2));
  813. };
  814. /**
  815. * Compares two objects that can be accessed like an array and assert that
  816. * each element is equal.
  817. * @param {string|Object} a Failure message (3 arguments)
  818. * or object #1 (2 arguments).
  819. * @param {Object} b Object #1 (2 arguments) or object #2 (3 arguments).
  820. * @param {Object=} opt_c Object #2 (3 arguments).
  821. */
  822. var assertElementsEquals = function(a, b, opt_c) {
  823. _validateArguments(2, arguments);
  824. var v1 = nonCommentArg(1, 2, arguments);
  825. var v2 = nonCommentArg(2, 2, arguments);
  826. var failureMessage = commentArg(2, arguments) ? commentArg(2, arguments) : '';
  827. if (!v1) {
  828. assert(failureMessage, !v2);
  829. } else {
  830. assertEquals('length mismatch: ' + failureMessage, v1.length, v2.length);
  831. for (var i = 0; i < v1.length; ++i) {
  832. assertEquals(
  833. 'mismatch at index ' + i + ': ' + failureMessage, v1[i], v2[i]);
  834. }
  835. }
  836. };
  837. /**
  838. * Compares two objects that can be accessed like an array and assert that
  839. * each element is roughly equal.
  840. * @param {string|Object} a Failure message (4 arguments)
  841. * or object #1 (3 arguments).
  842. * @param {Object} b Object #1 (4 arguments) or object #2 (3 arguments).
  843. * @param {Object|number} c Object #2 (4 arguments) or tolerance (3 arguments).
  844. * @param {number=} opt_d tolerance (4 arguments).
  845. */
  846. var assertElementsRoughlyEqual = function(a, b, c, opt_d) {
  847. _validateArguments(3, arguments);
  848. var v1 = nonCommentArg(1, 3, arguments);
  849. var v2 = nonCommentArg(2, 3, arguments);
  850. var tolerance = nonCommentArg(3, 3, arguments);
  851. var failureMessage = commentArg(3, arguments) ? commentArg(3, arguments) : '';
  852. if (!v1) {
  853. assert(failureMessage, !v2);
  854. } else {
  855. assertEquals('length mismatch: ' + failureMessage, v1.length, v2.length);
  856. for (var i = 0; i < v1.length; ++i) {
  857. assertRoughlyEquals(failureMessage, v1[i], v2[i], tolerance);
  858. }
  859. }
  860. };
  861. /**
  862. * Compares two array-like objects without taking their order into account.
  863. * @param {string|IArrayLike} a Assertion message or the
  864. * expected elements.
  865. * @param {IArrayLike} b Expected elements or the actual
  866. * elements.
  867. * @param {IArrayLike=} opt_c Actual elements.
  868. */
  869. var assertSameElements = function(a, b, opt_c) {
  870. _validateArguments(2, arguments);
  871. var expected = nonCommentArg(1, 2, arguments);
  872. var actual = nonCommentArg(2, 2, arguments);
  873. var message = commentArg(2, arguments);
  874. assertTrue(
  875. 'Bad arguments to assertSameElements(opt_message, expected: ' +
  876. 'ArrayLike, actual: ArrayLike)',
  877. goog.isArrayLike(expected) && goog.isArrayLike(actual));
  878. // Clones expected and actual and converts them to real arrays.
  879. expected = goog.testing.asserts.toArray_(expected);
  880. actual = goog.testing.asserts.toArray_(actual);
  881. // TODO(user): It would be great to show only the difference
  882. // between the expected and actual elements.
  883. _assert(
  884. message, expected.length == actual.length, 'Expected ' + expected.length +
  885. ' elements: [' + expected + '], ' +
  886. 'got ' + actual.length + ' elements: [' + actual + ']');
  887. var toFind = goog.testing.asserts.toArray_(expected);
  888. for (var i = 0; i < actual.length; i++) {
  889. var index = goog.testing.asserts.indexOf_(toFind, actual[i]);
  890. _assert(
  891. message, index != -1,
  892. 'Expected [' + expected + '], got [' + actual + ']');
  893. toFind.splice(index, 1);
  894. }
  895. };
  896. /**
  897. * @param {*} a The value to assert (1 arg) or debug message (2 args).
  898. * @param {*=} opt_b The value to assert (2 args only).
  899. */
  900. var assertEvaluatesToTrue = function(a, opt_b) {
  901. _validateArguments(1, arguments);
  902. var value = nonCommentArg(1, 1, arguments);
  903. if (!value) {
  904. _assert(commentArg(1, arguments), false, 'Expected to evaluate to true');
  905. }
  906. };
  907. /**
  908. * @param {*} a The value to assert (1 arg) or debug message (2 args).
  909. * @param {*=} opt_b The value to assert (2 args only).
  910. */
  911. var assertEvaluatesToFalse = function(a, opt_b) {
  912. _validateArguments(1, arguments);
  913. var value = nonCommentArg(1, 1, arguments);
  914. if (value) {
  915. _assert(commentArg(1, arguments), false, 'Expected to evaluate to false');
  916. }
  917. };
  918. /**
  919. * Compares two HTML snippets.
  920. *
  921. * Take extra care if attributes are involved. {@code assertHTMLEquals}'s
  922. * implementation isn't prepared for complex cases. For example, the following
  923. * comparisons erroneously fail:
  924. * <pre>
  925. * assertHTMLEquals('<a href="x" target="y">', '<a target="y" href="x">');
  926. * assertHTMLEquals('<div class="a b">', '<div class="b a">');
  927. * assertHTMLEquals('<input disabled>', '<input disabled="disabled">');
  928. * </pre>
  929. *
  930. * When in doubt, use {@code goog.testing.dom.assertHtmlMatches}.
  931. *
  932. * @param {*} a The expected value (2 args) or the debug message (3 args).
  933. * @param {*} b The actual value (2 args) or the expected value (3 args).
  934. * @param {*=} opt_c The actual value (3 args only).
  935. */
  936. var assertHTMLEquals = function(a, b, opt_c) {
  937. _validateArguments(2, arguments);
  938. var var1 = nonCommentArg(1, 2, arguments);
  939. var var2 = nonCommentArg(2, 2, arguments);
  940. var var1Standardized = standardizeHTML(var1);
  941. var var2Standardized = standardizeHTML(var2);
  942. _assert(
  943. commentArg(2, arguments), var1Standardized === var2Standardized,
  944. goog.testing.asserts.getDefaultErrorMsg_(
  945. var1Standardized, var2Standardized));
  946. };
  947. /**
  948. * Compares two CSS property values to make sure that they represent the same
  949. * things. This will normalize values in the browser. For example, in Firefox,
  950. * this assertion will consider "rgb(0, 0, 255)" and "#0000ff" to be identical
  951. * values for the "color" property. This function won't normalize everything --
  952. * for example, in most browsers, "blue" will not match "#0000ff". It is
  953. * intended only to compensate for unexpected normalizations performed by
  954. * the browser that should also affect your expected value.
  955. * @param {string} a Assertion message, or the CSS property name.
  956. * @param {string} b CSS property name, or the expected value.
  957. * @param {string} c The expected value, or the actual value.
  958. * @param {string=} opt_d The actual value.
  959. */
  960. var assertCSSValueEquals = function(a, b, c, opt_d) {
  961. _validateArguments(3, arguments);
  962. var propertyName = nonCommentArg(1, 3, arguments);
  963. var expectedValue = nonCommentArg(2, 3, arguments);
  964. var actualValue = nonCommentArg(3, 3, arguments);
  965. var expectedValueStandardized =
  966. standardizeCSSValue(propertyName, expectedValue);
  967. var actualValueStandardized = standardizeCSSValue(propertyName, actualValue);
  968. _assert(
  969. commentArg(3, arguments),
  970. expectedValueStandardized == actualValueStandardized,
  971. goog.testing.asserts.getDefaultErrorMsg_(
  972. expectedValueStandardized, actualValueStandardized));
  973. };
  974. /**
  975. * @param {*} a The expected value (2 args) or the debug message (3 args).
  976. * @param {*} b The actual value (2 args) or the expected value (3 args).
  977. * @param {*=} opt_c The actual value (3 args only).
  978. */
  979. var assertHashEquals = function(a, b, opt_c) {
  980. _validateArguments(2, arguments);
  981. var var1 = nonCommentArg(1, 2, arguments);
  982. var var2 = nonCommentArg(2, 2, arguments);
  983. var message = commentArg(2, arguments);
  984. for (var key in var1) {
  985. _assert(
  986. message, key in var2,
  987. 'Expected hash had key ' + key + ' that was not found');
  988. _assert(
  989. message, var1[key] == var2[key], 'Value for key ' + key +
  990. ' mismatch - expected = ' + var1[key] + ', actual = ' + var2[key]);
  991. }
  992. for (var key in var2) {
  993. _assert(
  994. message, key in var1,
  995. 'Actual hash had key ' + key + ' that was not expected');
  996. }
  997. };
  998. /**
  999. * @param {*} a The expected value (3 args) or the debug message (4 args).
  1000. * @param {*} b The actual value (3 args) or the expected value (4 args).
  1001. * @param {*} c The tolerance (3 args) or the actual value (4 args).
  1002. * @param {*=} opt_d The tolerance (4 args only).
  1003. */
  1004. var assertRoughlyEquals = function(a, b, c, opt_d) {
  1005. _validateArguments(3, arguments);
  1006. var expected = nonCommentArg(1, 3, arguments);
  1007. var actual = nonCommentArg(2, 3, arguments);
  1008. var tolerance = nonCommentArg(3, 3, arguments);
  1009. _assert(
  1010. commentArg(3, arguments),
  1011. goog.testing.asserts.numberRoughEqualityPredicate_(
  1012. expected, actual, tolerance),
  1013. 'Expected ' + expected + ', but got ' + actual + ' which was more than ' +
  1014. tolerance + ' away');
  1015. };
  1016. /**
  1017. * Checks if the test value is a member of the given container. Uses
  1018. * container.indexOf as the underlying function, so this works for strings
  1019. * and arrays.
  1020. * @param {*} a Failure message (3 arguments) or the test value
  1021. * (2 arguments).
  1022. * @param {*} b The test value (3 arguments) or the container
  1023. * (2 arguments).
  1024. * @param {*=} opt_c The container.
  1025. */
  1026. var assertContains = function(a, b, opt_c) {
  1027. _validateArguments(2, arguments);
  1028. var contained = nonCommentArg(1, 2, arguments);
  1029. var container = nonCommentArg(2, 2, arguments);
  1030. _assert(
  1031. commentArg(2, arguments),
  1032. goog.testing.asserts.contains_(container, contained),
  1033. 'Expected \'' + container + '\' to contain \'' + contained + '\'');
  1034. };
  1035. /**
  1036. * Checks if the given element is not the member of the given container.
  1037. * @param {*} a Failure message (3 arguments) or the contained element
  1038. * (2 arguments).
  1039. * @param {*} b The contained element (3 arguments) or the container
  1040. * (2 arguments).
  1041. * @param {*=} opt_c The container.
  1042. */
  1043. var assertNotContains = function(a, b, opt_c) {
  1044. _validateArguments(2, arguments);
  1045. var contained = nonCommentArg(1, 2, arguments);
  1046. var container = nonCommentArg(2, 2, arguments);
  1047. _assert(
  1048. commentArg(2, arguments),
  1049. !goog.testing.asserts.contains_(container, contained),
  1050. 'Expected \'' + container + '\' not to contain \'' + contained + '\'');
  1051. };
  1052. /**
  1053. * Checks if the given string matches the given regular expression.
  1054. * @param {*} a Failure message (3 arguments) or the expected regular
  1055. * expression as a string or RegExp (2 arguments).
  1056. * @param {*} b The regular expression (3 arguments) or the string to test
  1057. * (2 arguments).
  1058. * @param {*=} opt_c The string to test.
  1059. */
  1060. var assertRegExp = function(a, b, opt_c) {
  1061. _validateArguments(2, arguments);
  1062. var regexp = nonCommentArg(1, 2, arguments);
  1063. var string = nonCommentArg(2, 2, arguments);
  1064. if (typeof(regexp) == 'string') {
  1065. regexp = new RegExp(regexp);
  1066. }
  1067. _assert(
  1068. commentArg(2, arguments), regexp.test(string),
  1069. 'Expected \'' + string + '\' to match RegExp ' + regexp.toString());
  1070. };
  1071. /**
  1072. * Converts an array like object to array or clones it if it's already array.
  1073. * @param {IArrayLike} arrayLike The collection.
  1074. * @return {!Array<?>} Copy of the collection as array.
  1075. * @private
  1076. */
  1077. goog.testing.asserts.toArray_ = function(arrayLike) {
  1078. var ret = [];
  1079. for (var i = 0; i < arrayLike.length; i++) {
  1080. ret[i] = arrayLike[i];
  1081. }
  1082. return ret;
  1083. };
  1084. /**
  1085. * Finds the position of the first occurrence of an element in a container.
  1086. * @param {IArrayLike} container
  1087. * The array to find the element in.
  1088. * @param {*} contained Element to find.
  1089. * @return {number} Index of the first occurrence or -1 if not found.
  1090. * @private
  1091. */
  1092. goog.testing.asserts.indexOf_ = function(container, contained) {
  1093. if (container.indexOf) {
  1094. return container.indexOf(contained);
  1095. } else {
  1096. // IE6/7 do not have indexOf so do a search.
  1097. for (var i = 0; i < container.length; i++) {
  1098. if (container[i] === contained) {
  1099. return i;
  1100. }
  1101. }
  1102. return -1;
  1103. }
  1104. };
  1105. /**
  1106. * Tells whether the array contains the given element.
  1107. * @param {IArrayLike} container The array to
  1108. * find the element in.
  1109. * @param {*} contained Element to find.
  1110. * @return {boolean} Whether the element is in the array.
  1111. * @private
  1112. */
  1113. goog.testing.asserts.contains_ = function(container, contained) {
  1114. // TODO(user): Can we check for container.contains as well?
  1115. // That would give us support for most goog.structs (though weird results
  1116. // with anything else with a contains method, like goog.math.Range). Falling
  1117. // back with container.some would catch all iterables, too.
  1118. return goog.testing.asserts.indexOf_(container, contained) != -1;
  1119. };
  1120. var standardizeHTML = function(html) {
  1121. var translator = document.createElement('DIV');
  1122. translator.innerHTML = html;
  1123. // Trim whitespace from result (without relying on goog.string)
  1124. return translator.innerHTML.replace(/^\s+|\s+$/g, '');
  1125. };
  1126. /**
  1127. * Standardizes a CSS value for a given property by applying it to an element
  1128. * and then reading it back.
  1129. * @param {string} propertyName CSS property name.
  1130. * @param {string} value CSS value.
  1131. * @return {string} Normalized CSS value.
  1132. */
  1133. var standardizeCSSValue = function(propertyName, value) {
  1134. var styleDeclaration = document.createElement('DIV').style;
  1135. styleDeclaration[propertyName] = value;
  1136. return styleDeclaration[propertyName];
  1137. };
  1138. /**
  1139. * Raises a JsUnit exception with the given comment. If the exception is
  1140. * unexpectedly caught during a unit test, it will be rethrown so that it is
  1141. * seen by the test framework.
  1142. * @param {string} comment A summary for the exception.
  1143. * @param {string=} opt_message A description of the exception.
  1144. */
  1145. goog.testing.asserts.raiseException = function(comment, opt_message) {
  1146. var e = new goog.testing.JsUnitException(comment, opt_message);
  1147. var testCase = _getCurrentTestCase();
  1148. if (testCase) {
  1149. testCase.raiseAssertionException(e);
  1150. } else {
  1151. goog.global.console.error(
  1152. 'Failed to save thrown exception: no test case is installed.');
  1153. throw e;
  1154. }
  1155. };
  1156. /**
  1157. * Helper function for assertObjectEquals.
  1158. * @param {string} prop A property name.
  1159. * @return {boolean} If the property name is an array index.
  1160. * @private
  1161. */
  1162. goog.testing.asserts.isArrayIndexProp_ = function(prop) {
  1163. return (prop | 0) == prop;
  1164. };
  1165. goog.exportSymbol('fail', fail);
  1166. goog.exportSymbol('assert', assert);
  1167. goog.exportSymbol('assertThrows', assertThrows);
  1168. goog.exportSymbol('assertNotThrows', assertNotThrows);
  1169. goog.exportSymbol('assertThrowsJsUnitException', assertThrowsJsUnitException);
  1170. goog.exportSymbol('assertTrue', assertTrue);
  1171. goog.exportSymbol('assertFalse', assertFalse);
  1172. goog.exportSymbol('assertEquals', assertEquals);
  1173. goog.exportSymbol('assertNotEquals', assertNotEquals);
  1174. goog.exportSymbol('assertNull', assertNull);
  1175. goog.exportSymbol('assertNotNull', assertNotNull);
  1176. goog.exportSymbol('assertUndefined', assertUndefined);
  1177. goog.exportSymbol('assertNotUndefined', assertNotUndefined);
  1178. goog.exportSymbol('assertNotNullNorUndefined', assertNotNullNorUndefined);
  1179. goog.exportSymbol('assertNonEmptyString', assertNonEmptyString);
  1180. goog.exportSymbol('assertNaN', assertNaN);
  1181. goog.exportSymbol('assertNotNaN', assertNotNaN);
  1182. goog.exportSymbol('assertObjectEquals', assertObjectEquals);
  1183. goog.exportSymbol('assertObjectRoughlyEquals', assertObjectRoughlyEquals);
  1184. goog.exportSymbol('assertObjectNotEquals', assertObjectNotEquals);
  1185. goog.exportSymbol('assertArrayEquals', assertArrayEquals);
  1186. goog.exportSymbol('assertElementsEquals', assertElementsEquals);
  1187. goog.exportSymbol('assertElementsRoughlyEqual', assertElementsRoughlyEqual);
  1188. goog.exportSymbol('assertSameElements', assertSameElements);
  1189. goog.exportSymbol('assertEvaluatesToTrue', assertEvaluatesToTrue);
  1190. goog.exportSymbol('assertEvaluatesToFalse', assertEvaluatesToFalse);
  1191. goog.exportSymbol('assertHTMLEquals', assertHTMLEquals);
  1192. goog.exportSymbol('assertHashEquals', assertHashEquals);
  1193. goog.exportSymbol('assertRoughlyEquals', assertRoughlyEquals);
  1194. goog.exportSymbol('assertContains', assertContains);
  1195. goog.exportSymbol('assertNotContains', assertNotContains);
  1196. goog.exportSymbol('assertRegExp', assertRegExp);