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