OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * @fileoverview Library providing basic test framework functionality. | 6 * @fileoverview Library providing basic test framework functionality. |
7 **/ | 7 **/ |
8 | 8 |
9 /** | 9 /** |
10 * Namespace for |Test|. | 10 * Namespace for |Test|. |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
67 | 67 |
68 /** | 68 /** |
69 * When set to a function, will be called in the context of the test | 69 * When set to a function, will be called in the context of the test |
70 * generation inside the function, and before any generated C++. | 70 * generation inside the function, and before any generated C++. |
71 * @type {function(string,string)} | 71 * @type {function(string,string)} |
72 **/ | 72 **/ |
73 testGenPreamble: null, | 73 testGenPreamble: null, |
74 | 74 |
75 /** | 75 /** |
76 * When set to a function, will be called in the context of the test | 76 * When set to a function, will be called in the context of the test |
77 * generation inside the function, and before any generated C++. | 77 * generation inside the function, and after any generated C++. |
78 * @type {function(string,string)} | 78 * @type {function(string,string)} |
79 **/ | 79 **/ |
80 testGenPostamble: null, | 80 testGenPostamble: null, |
81 | 81 |
82 /** | 82 /** |
83 * When set to a non-null String, auto-generate typedef before generating | 83 * When set to a non-null String, auto-generate typedef before generating |
84 * TEST*: {@code typedef typedefCppFixture testFixture}. | 84 * TEST*: {@code typedef typedefCppFixture testFixture}. |
85 * @type {String} | 85 * @type {String} |
86 **/ | 86 **/ |
87 typedefCppFixture: 'WebUIBrowserTest', | 87 typedefCppFixture: 'WebUIBrowserTest', |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
139 /** | 139 /** |
140 * Called at preload time, proxies to the fixture. | 140 * Called at preload time, proxies to the fixture. |
141 * @type {Function} | 141 * @type {Function} |
142 **/ | 142 **/ |
143 PreLoad: function(name) { | 143 PreLoad: function(name) { |
144 if (this.fixture) | 144 if (this.fixture) |
145 this.fixture.PreLoad(); | 145 this.fixture.PreLoad(); |
146 }, | 146 }, |
147 | 147 |
148 /** | 148 /** |
149 * Runs this test case. | 149 * Runs this test case with |this| set to the |fixture|. |
| 150 * |
| 151 * Note: Tests created with TEST_F may depend upon |this| being set to an |
| 152 * instance of this.fixture. The current implementation of TEST creates a |
| 153 * dummy constructor, but tests created with TEST should not rely on |this| |
| 154 * being set. |
150 * @type {Function} | 155 * @type {Function} |
151 **/ | 156 **/ |
152 Run: function() { | 157 Run: function() { |
153 if (this.fixture) | 158 if (this.fixture) |
154 this.fixture.SetUp(); | 159 this.fixture.SetUp(); |
155 if (this.body) | 160 if (this.body) |
156 this.body.call(this.fixture); | 161 this.body.call(this.fixture); |
157 if (this.fixture) | 162 if (this.fixture) |
158 this.fixture.TearDown(); | 163 this.fixture.TearDown(); |
159 }, | 164 }, |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
210 **/ | 215 **/ |
211 function send(messageName) { | 216 function send(messageName) { |
212 var callback = sendCallbacks[messageName]; | 217 var callback = sendCallbacks[messageName]; |
213 var args = Array.prototype.slice.call(arguments, 1); | 218 var args = Array.prototype.slice.call(arguments, 1); |
214 if (callback != undefined) | 219 if (callback != undefined) |
215 callback[1].apply(callback[0], args); | 220 callback[1].apply(callback[0], args); |
216 else | 221 else |
217 oldChrome.send.apply(oldChrome, args); | 222 oldChrome.send.apply(oldChrome, args); |
218 } | 223 } |
219 | 224 |
| 225 /** |
| 226 * Provides a mechanism for assert* and expect* methods to fetch the signature |
| 227 * of their caller. Assert* methods should |registerCall| and expect* methods |
| 228 * should set |isExpect| and |expectName| properties to indicate that the |
| 229 * interesting caller is one more level up the stack. |
| 230 **/ |
| 231 function CallHelper() { |
| 232 this.__proto__ = CallHelper.prototype; |
| 233 } |
| 234 |
| 235 CallHelper.prototype = { |
| 236 /** |
| 237 * Holds the mapping of (callerCallerString, callerName) -> count of times |
| 238 * called. |
| 239 * @type {Object.<string, Object.<string, number>>} |
| 240 **/ |
| 241 counts_: {}, |
| 242 |
| 243 /** |
| 244 * This information about the caller is needed from most of the following |
| 245 * routines. |
| 246 * @param {Function} caller the caller of the assert* routine. |
| 247 * @return {{callerName: string, callercallerString: string}} stackInfo |
| 248 * @private |
| 249 **/ |
| 250 getCallerInfo_: function(caller) { |
| 251 var callerName = caller.name; |
| 252 var callerCaller = caller.caller; |
| 253 if (callerCaller['isExpect']) { |
| 254 callerName = callerCaller.expectName; |
| 255 callerCaller = callerCaller.caller; |
| 256 } |
| 257 var callerCallerString = callerCaller.toString(); |
| 258 return { |
| 259 callerName: callerName, |
| 260 callerCallerString: callerCallerString, |
| 261 }; |
| 262 }, |
| 263 |
| 264 /** |
| 265 * Register a call to an assertion class. |
| 266 **/ |
| 267 registerCall: function() { |
| 268 var stackInfo = this.getCallerInfo_(arguments.callee.caller); |
| 269 if (!(stackInfo.callerCallerString in this.counts_)) |
| 270 this.counts_[stackInfo.callerCallerString] = {}; |
| 271 if (!(stackInfo.callerName in this.counts_[stackInfo.callerCallerString])) |
| 272 this.counts_[stackInfo.callerCallerString][stackInfo.callerName] = 0; |
| 273 ++this.counts_[stackInfo.callerCallerString][stackInfo.callerName]; |
| 274 }, |
| 275 |
| 276 /** |
| 277 * Get the call signature of this instance of the caller's call to this |
| 278 * function. |
| 279 * @param {Function} caller The caller of the assert* routine. |
| 280 * @return {String} Call signature. |
| 281 * @private |
| 282 **/ |
| 283 getCall_: function(caller) { |
| 284 var stackInfo = this.getCallerInfo_(caller); |
| 285 var count = |
| 286 this.counts_[stackInfo.callerCallerString][stackInfo.callerName]; |
| 287 |
| 288 // Allow pattern to match multiple lines for text wrapping. |
| 289 var callerRegExp = |
| 290 new RegExp(stackInfo.callerName + '\\((.|\\n)*?\\);', 'g'); |
| 291 |
| 292 // Find all matches allowing wrap around such as when a helper function |
| 293 // calls assert/expect calls and that helper function is called multiple |
| 294 // times. |
| 295 var matches = stackInfo.callerCallerString.match(callerRegExp); |
| 296 var match = matches[(count - 1) % matches.length]; |
| 297 |
| 298 // Chop off the trailing ';'. |
| 299 return match.substring(0, match.length-1); |
| 300 }, |
| 301 |
| 302 /** |
| 303 * Returns the text of the call signature and any |message|. |
| 304 * @param {string=} message Addtional message text from caller. |
| 305 **/ |
| 306 getCallMessage: function(message) { |
| 307 var callMessage = this.getCall_(arguments.callee.caller); |
| 308 if (message) |
| 309 callMessage += ': ' + message; |
| 310 return callMessage; |
| 311 }, |
| 312 }; |
| 313 |
| 314 /** |
| 315 * Help register calls for better error reporting. |
| 316 * @type {CallHelper} |
| 317 **/ |
| 318 var helper = new CallHelper(); |
| 319 |
220 // Asserts. | 320 // Asserts. |
221 // Use the following assertions to verify a condition within a test. | 321 // Use the following assertions to verify a condition within a test. |
222 // If assertion fails, the C++ backend will be immediately notified. | 322 // If assertion fails, the C++ backend will be immediately notified. |
223 // If assertion passes, no notification will be sent to the C++ backend. | 323 // If assertion passes, no notification will be sent to the C++ backend. |
224 | 324 |
225 /** | 325 /** |
226 * When |test| !== |expected|, aborts the current test. | 326 * When |test| !== |expected|, aborts the current test. |
227 * @param {Boolean} test The predicate to check against |expected|. | 327 * @param {Boolean} test The predicate to check against |expected|. |
228 * @param {Boolean} expected The expected value of |test|. | 328 * @param {Boolean} expected The expected value of |test|. |
229 * @param {String=} message The message to include in the Error thrown. | 329 * @param {String=} message The message to include in the Error thrown. |
230 * @throws {Error} upon failure. | 330 * @throws {Error} upon failure. |
231 **/ | 331 **/ |
232 function assertBool(test, expected, message) { | 332 function assertBool(test, expected, message) { |
233 if (test !== expected) { | 333 helper.registerCall(); |
234 if (message) | 334 if (test !== expected) |
235 message = test + '\n' + message; | 335 throw new Error('Test Error ' + helper.getCallMessage(message) + |
236 else | 336 ': ' + test); |
237 message = test; | |
238 throw new Error(message); | |
239 } | |
240 } | 337 } |
241 | 338 |
242 /** | 339 /** |
243 * When |test| !== true, aborts the current test. | 340 * When |test| !== true, aborts the current test. |
244 * @param {Boolean} test The predicate to check against |expected|. | 341 * @param {Boolean} test The predicate to check against |expected|. |
245 * @param {String=} message The message to include in the Error thrown. | 342 * @param {String=} message The message to include in the Error thrown. |
246 * @throws {Error} upon failure. | 343 * @throws {Error} upon failure. |
247 **/ | 344 **/ |
248 function assertTrue(test, message) { | 345 function assertTrue(test, message) { |
249 assertBool(test, true, message); | 346 helper.registerCall(); |
| 347 if (test !== true) |
| 348 throw new Error('Test Error ' + helper.getCallMessage(message) + |
| 349 ': ' + test); |
250 } | 350 } |
251 | 351 |
252 /** | 352 /** |
253 * When |test| !== false, aborts the current test. | 353 * When |test| !== false, aborts the current test. |
254 * @param {Boolean} test The predicate to check against |expected|. | 354 * @param {Boolean} test The predicate to check against |expected|. |
255 * @param {String=} message The message to include in the Error thrown. | 355 * @param {String=} message The message to include in the Error thrown. |
256 * @throws {Error} upon failure. | 356 * @throws {Error} upon failure. |
257 **/ | 357 **/ |
258 function assertFalse(test, message) { | 358 function assertFalse(test, message) { |
259 assertBool(test, false, message); | 359 helper.registerCall(); |
| 360 if (test !== false) |
| 361 throw new Error('Test Error ' + helper.getCallMessage(message) + |
| 362 ': ' + test); |
260 } | 363 } |
261 | 364 |
262 /** | 365 /** |
263 * When |expected| !== |actual|, aborts the current test. | 366 * When |expected| !== |actual|, aborts the current test. |
264 * @param {*} expected The predicate to check against |expected|. | 367 * @param {*} expected The predicate to check against |expected|. |
265 * @param {*} actual The expected value of |test|. | 368 * @param {*} actual The expected value of |test|. |
266 * @param {String=} message The message to include in the Error thrown. | 369 * @param {String=} message The message to include in the Error thrown. |
267 * @throws {Error} upon failure. | 370 * @throws {Error} upon failure. |
268 **/ | 371 **/ |
269 function assertEquals(expected, actual, message) { | 372 function assertEquals(expected, actual, message) { |
| 373 helper.registerCall(); |
270 if (expected != actual) { | 374 if (expected != actual) { |
271 throw new Error('Test Error. Actual: ' + actual + '\nExpected: ' + | 375 throw new Error('Test Error ' + helper.getCallMessage(message) + |
272 expected + '\n' + message); | 376 '\nActual: ' + actual + '\nExpected: ' + expected); |
273 } | 377 } |
274 if (typeof expected != typeof actual) { | 378 if (typeof expected != typeof actual) { |
275 throw new Error('Test Error' + | 379 throw new Error('Test Error (type mismatch) ' + |
276 ' (type mismatch)\nActual Type: ' + typeof actual + | 380 helper.getCallMessage(message) + |
277 '\nExpected Type:' + typeof expected + '\n' + message); | 381 '\nActual Type: ' + typeof actual + |
| 382 '\nExpected Type:' + typeof expected); |
278 } | 383 } |
279 } | 384 } |
280 | 385 |
281 /** | 386 /** |
282 * Always aborts the current test. | 387 * Always aborts the current test. |
283 * @param {String=} message The message to include in the Error thrown. | 388 * @param {String=} message The message to include in the Error thrown. |
284 * @throws {Error} always. | 389 * @throws {Error} always. |
285 **/ | 390 **/ |
286 function assertNotReached(message) { | 391 function assertNotReached(message) { |
287 throw new Error(message); | 392 helper.registerCall(); |
| 393 throw new Error(helper.getCallMessage(message)); |
288 } | 394 } |
289 | 395 |
290 /** | 396 /** |
291 * Holds the errors, if any, caught by expects so that the test case can fail. | 397 * Holds the errors, if any, caught by expects so that the test case can fail. |
292 * @type {Array.<Error>} | 398 * @type {Array.<Error>} |
293 **/ | 399 **/ |
294 var errors = []; | 400 var errors = []; |
295 | 401 |
296 /** | 402 /** |
297 * Creates a function based upon a function that thows an exception on | 403 * Creates a function based upon a function that thows an exception on |
298 * failure. The new function stuffs any errors into the |errors| array for | 404 * failure. The new function stuffs any errors into the |errors| array for |
299 * checking by runTest. This allows tests to continue running other checks, | 405 * checking by runTest. This allows tests to continue running other checks, |
300 * while failing the overal test if any errors occurrred. | 406 * while failing the overal test if any errors occurrred. |
301 * @param {Function} assertFunc The function which may throw an Error. | 407 * @param {Function} assertFunc The function which may throw an Error. |
302 * @return {Function} A function that applies its arguments to |assertFunc|. | 408 * @return {Function} A function that applies its arguments to |assertFunc|. |
303 * @see errors | 409 * @see errors |
304 * @see runTest | 410 * @see runTest |
305 **/ | 411 **/ |
306 function createExpect(assertFunc) { | 412 function createExpect(assertFunc) { |
307 return function() { | 413 var expectFunc = function() { |
308 try { | 414 try { |
309 assertFunc.apply(null, arguments); | 415 assertFunc.apply(null, arguments); |
310 } catch (e) { | 416 } catch (e) { |
311 errors.push(e); | 417 errors.push(e); |
312 } | 418 } |
313 }; | 419 }; |
| 420 expectFunc.isExpect = true; |
| 421 expectFunc.expectName = assertFunc.name.replace(/^assert/, 'expect'); |
| 422 return expectFunc; |
314 } | 423 } |
315 | 424 |
316 /** | 425 /** |
317 * This is the starting point for tests run by WebUIBrowserTest. It clears | 426 * This is the starting point for tests run by WebUIBrowserTest. It clears |
318 * |errors|, runs the test surrounded by an expect to catch Errors. If | 427 * |errors|, runs the test surrounded by an expect to catch Errors. If |
319 * |errors| is non-empty, it reports a failure and a message by joining | 428 * |errors| is non-empty, it reports a failure and a message by joining |
320 * |errors|. | 429 * |errors|. |
321 * @param {String} testFunction The function name to call. | 430 * @param {String} testFunction The function name to call. |
322 * @param {Array} testArguments The arguments to call |testFunction| with. | 431 * @param {Array} testArguments The arguments to call |testFunction| with. |
323 * @return {Array.<Boolean, String>} [test-succeeded, message-if-failed] | 432 * @return {Array.<Boolean, String>} [test-succeeded, message-if-failed] |
324 * @see errors | 433 * @see errors |
325 * @see createExpect | 434 * @see createExpect |
326 **/ | 435 **/ |
327 function runTest(testFunction, testArguments) { | 436 function runTest(testFunction, testArguments) { |
328 errors = []; | 437 errors.splice(0, errors.length); |
329 // Avoid eval() if at all possible, since it will not work on pages | 438 // Avoid eval() if at all possible, since it will not work on pages |
330 // that have enabled content-security-policy. | 439 // that have enabled content-security-policy. |
331 var testBody = this[testFunction]; // global object -- not a method. | 440 var testBody = this[testFunction]; // global object -- not a method. |
332 if (typeof testBody === "undefined") | 441 if (typeof testBody === "undefined") |
333 testBody = eval(testFunction); | 442 testBody = eval(testFunction); |
334 if (testBody != RUN_TEST_F) | 443 if (testBody != RUN_TEST_F) { |
335 console.log('Running test ' + testBody.name); | 444 var testName = |
| 445 testFunction.name ? testFunction.name : testBody.toString(); |
| 446 console.log('Running test ' + testName); |
| 447 } |
336 createExpect(testBody).apply(null, testArguments); | 448 createExpect(testBody).apply(null, testArguments); |
337 | 449 |
| 450 var result = [true]; |
338 if (errors.length) { | 451 if (errors.length) { |
| 452 var message = ''; |
339 for (var i = 0; i < errors.length; ++i) { | 453 for (var i = 0; i < errors.length; ++i) { |
340 console.log('Failed: ' + testFunction + '(' + | 454 message += 'Failed: ' + testFunction + '(' + |
341 testArguments.toString() + ')\n' + errors[i].stack); | 455 testArguments.map(JSON.stringify) + |
| 456 ')\n' + errors[i].stack; |
342 } | 457 } |
343 return [false, errors.join('\n')]; | 458 errors.splice(0, errors.length); |
344 } else { | 459 result = [false, message]; |
345 return [true]; | |
346 } | 460 } |
| 461 return result; |
347 } | 462 } |
348 | 463 |
349 /** | 464 /** |
350 * Creates a new test case for the given |testFixture| and |testName|. Assumes | 465 * Creates a new test case for the given |testFixture| and |testName|. Assumes |
351 * |testFixture| describes a globally available subclass of type Test. | 466 * |testFixture| describes a globally available subclass of type Test. |
352 * @param {String} testFixture The fixture for this test case. | 467 * @param {String} testFixture The fixture for this test case. |
353 * @param {String} testName The name for this test case. | 468 * @param {String} testName The name for this test case. |
354 * @return {TestCase} A newly created TestCase. | 469 * @return {TestCase} A newly created TestCase. |
355 **/ | 470 **/ |
356 function createTestCase(testFixture, testName) { | 471 function createTestCase(testFixture, testName) { |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
491 window.registerMockMessageCallbacks = registerMockMessageCallbacks; | 606 window.registerMockMessageCallbacks = registerMockMessageCallbacks; |
492 window.runTest = runTest; | 607 window.runTest = runTest; |
493 window.preloadJavascriptLibraries = preloadJavascriptLibraries; | 608 window.preloadJavascriptLibraries = preloadJavascriptLibraries; |
494 window.TEST = TEST; | 609 window.TEST = TEST; |
495 window.TEST_F = TEST_F; | 610 window.TEST_F = TEST_F; |
496 window.GEN = GEN; | 611 window.GEN = GEN; |
497 | 612 |
498 // Import the Mock4JS helpers. | 613 // Import the Mock4JS helpers. |
499 Mock4JS.addMockSupport(window); | 614 Mock4JS.addMockSupport(window); |
500 })(); | 615 })(); |
OLD | NEW |