# lib/goog/testing/asserts.js

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