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 **/ |
| 249 'getCallerInfo': function(caller) { |
| 250 var callerName = caller.name; |
| 251 var callerCaller = caller.caller; |
| 252 if (callerCaller['isExpect']) { |
| 253 callerName = callerCaller.expectName; |
| 254 callerCaller = callerCaller.caller; |
| 255 } |
| 256 var callerCallerString = callerCaller.toString(); |
| 257 return { |
| 258 callerName: callerName, |
| 259 callerCallerString: callerCallerString, |
| 260 }; |
| 261 }, |
| 262 |
| 263 /** |
| 264 * Register a call to an assertion class. |
| 265 **/ |
| 266 'registerCall': function() { |
| 267 var stackInfo = this.getCallerInfo(arguments.callee.caller); |
| 268 if (!(stackInfo.callerCallerString in this.counts_)) |
| 269 this.counts_[stackInfo.callerCallerString] = {}; |
| 270 if (!(stackInfo.callerName in this.counts_[stackInfo.callerCallerString])) |
| 271 this.counts_[stackInfo.callerCallerString][stackInfo.callerName] = 0; |
| 272 ++this.counts_[stackInfo.callerCallerString][stackInfo.callerName]; |
| 273 }, |
| 274 |
| 275 /** |
| 276 * @param {String} string the string to match parentheses. |
| 277 * @param {number} index offset to the opening parenthesis. |
| 278 * @return {[number, Array]} the index after matching paren and the args. |
| 279 **/ |
| 280 'matchedParamsIndex': function(string, index) { |
| 281 var args = []; |
| 282 var parenCount = 1; |
| 283 var argStart = index + 1; |
| 284 for(index = argStart; |
| 285 parenCount && index < string.length; |
| 286 ++index) { |
| 287 if (string[index] == '(') { |
| 288 ++parenCount; |
| 289 } else if (string[index] == ')') { |
| 290 if (--parenCount == 0) |
| 291 args.push(string.substring(argStart, index)); |
| 292 } else if (string[index] == ',' && parenCount == 1) { |
| 293 args.push(string.substring(argStart, index)); |
| 294 argStart = index + 1; |
| 295 } |
| 296 } |
| 297 return [index, args]; |
| 298 }, |
| 299 |
| 300 /** |
| 301 * Get the parameters of this instance of caller's call to this function. |
| 302 * @param {Function} caller_ a particular caller or |undefined|. |
| 303 * @param {number} count_ the number of times this instance was called. |
| 304 * @return {Array.<string>} parameters of caller's call to this function. |
| 305 **/ |
| 306 'getParams': function(caller_, count_) { |
| 307 var caller = (caller_ == undefined) ? |
| 308 arguments.callee.caller : caller_; |
| 309 var stackInfo = this.getCallerInfo(caller); |
| 310 var count = (count_ == undefined) ? |
| 311 this.counts_[stackInfo.callerCallerString][stackInfo.callerName] : |
| 312 count_; |
| 313 var searchStart = 0; |
| 314 var args; |
| 315 for(var i = 0; |
| 316 i < count && searchStart < stackInfo.callerCallerString.length; |
| 317 ++i) { |
| 318 searchStart = stackInfo.callerCallerString.indexOf( |
| 319 stackInfo.callerName, searchStart); |
| 320 if (searchStart == -1) { |
| 321 if (i && count_ == undefined) { |
| 322 return this.getParams(caller, ((count - 1) % i) + 1); |
| 323 } else { |
| 324 console.error('bad count ' + count); |
| 325 return undefined; |
| 326 } |
| 327 } |
| 328 searchStart += stackInfo.callerName.length; |
| 329 var matched = this.matchedParamsIndex(stackInfo.callerCallerString, |
| 330 searchStart); |
| 331 args = matched[1]; |
| 332 searchStart = matched[0]; |
| 333 } |
| 334 return args; |
| 335 }, |
| 336 |
| 337 /** |
| 338 * Get the call signature of this instance of the caller's call to this |
| 339 * function. |
| 340 * @return {String} call signature. |
| 341 **/ |
| 342 'getCall': function() { |
| 343 var caller = arguments.callee.caller; |
| 344 var stackInfo = this.getCallerInfo(caller); |
| 345 return stackInfo.callerName + '(' + this.getParams(caller) + ')'; |
| 346 }, |
| 347 }; |
| 348 |
| 349 /** |
| 350 * Help register calls for better error reporting. |
| 351 * @type {CallHelper} |
| 352 **/ |
| 353 var helper = new CallHelper(); |
| 354 |
220 // Asserts. | 355 // Asserts. |
221 // Use the following assertions to verify a condition within a test. | 356 // Use the following assertions to verify a condition within a test. |
222 // If assertion fails, the C++ backend will be immediately notified. | 357 // If assertion fails, the C++ backend will be immediately notified. |
223 // If assertion passes, no notification will be sent to the C++ backend. | 358 // If assertion passes, no notification will be sent to the C++ backend. |
224 | 359 |
225 /** | 360 /** |
226 * When |test| !== |expected|, aborts the current test. | 361 * When |test| !== |expected|, aborts the current test. |
227 * @param {Boolean} test The predicate to check against |expected|. | 362 * @param {Boolean} test The predicate to check against |expected|. |
228 * @param {Boolean} expected The expected value of |test|. | 363 * @param {Boolean} expected The expected value of |test|. |
229 * @param {String=} message The message to include in the Error thrown. | 364 * @param {String=} message The message to include in the Error thrown. |
230 * @throws {Error} upon failure. | 365 * @throws {Error} upon failure. |
231 **/ | 366 **/ |
232 function assertBool(test, expected, message) { | 367 function assertBool(test, expected, message) { |
233 if (test !== expected) { | 368 helper.registerCall(); |
234 if (message) | 369 if (test !== expected) |
235 message = test + '\n' + message; | 370 throw new Error('Test Error ' + helper.getCall() + ': ' + test); |
236 else | |
237 message = test; | |
238 throw new Error(message); | |
239 } | |
240 } | 371 } |
241 | 372 |
242 /** | 373 /** |
243 * When |test| !== true, aborts the current test. | 374 * When |test| !== true, aborts the current test. |
244 * @param {Boolean} test The predicate to check against |expected|. | 375 * @param {Boolean} test The predicate to check against |expected|. |
245 * @param {String=} message The message to include in the Error thrown. | 376 * @param {String=} message The message to include in the Error thrown. |
246 * @throws {Error} upon failure. | 377 * @throws {Error} upon failure. |
247 **/ | 378 **/ |
248 function assertTrue(test, message) { | 379 function assertTrue(test, message) { |
249 assertBool(test, true, message); | 380 helper.registerCall(); |
| 381 if (test !== true) |
| 382 throw new Error('Test Error ' + helper.getCall() + ': ' + test); |
250 } | 383 } |
251 | 384 |
252 /** | 385 /** |
253 * When |test| !== false, aborts the current test. | 386 * When |test| !== false, aborts the current test. |
254 * @param {Boolean} test The predicate to check against |expected|. | 387 * @param {Boolean} test The predicate to check against |expected|. |
255 * @param {String=} message The message to include in the Error thrown. | 388 * @param {String=} message The message to include in the Error thrown. |
256 * @throws {Error} upon failure. | 389 * @throws {Error} upon failure. |
257 **/ | 390 **/ |
258 function assertFalse(test, message) { | 391 function assertFalse(test, message) { |
259 assertBool(test, false, message); | 392 helper.registerCall(); |
| 393 if (test !== false) |
| 394 throw new Error('Test Error ' + helper.getCall() + ': ' + test); |
260 } | 395 } |
261 | 396 |
262 /** | 397 /** |
263 * When |expected| !== |actual|, aborts the current test. | 398 * When |expected| !== |actual|, aborts the current test. |
264 * @param {*} expected The predicate to check against |expected|. | 399 * @param {*} expected The predicate to check against |expected|. |
265 * @param {*} actual The expected value of |test|. | 400 * @param {*} actual The expected value of |test|. |
266 * @param {String=} message The message to include in the Error thrown. | 401 * @param {String=} message The message to include in the Error thrown. |
267 * @throws {Error} upon failure. | 402 * @throws {Error} upon failure. |
268 **/ | 403 **/ |
269 function assertEquals(expected, actual, message) { | 404 function assertEquals(expected, actual, message) { |
| 405 helper.registerCall(); |
270 if (expected != actual) { | 406 if (expected != actual) { |
271 throw new Error('Test Error. Actual: ' + actual + '\nExpected: ' + | 407 throw new Error('Test Error ' + helper.getCall() + '\nActual: ' + actual + |
272 expected + '\n' + message); | 408 '\nExpected: ' + expected); |
273 } | 409 } |
274 if (typeof expected != typeof actual) { | 410 if (typeof expected != typeof actual) { |
275 throw new Error('Test Error' + | 411 throw new Error('Test Error (type mismatch) ' + helper.getCall() + |
276 ' (type mismatch)\nActual Type: ' + typeof actual + | 412 '\nActual Type: ' + typeof actual + |
277 '\nExpected Type:' + typeof expected + '\n' + message); | 413 '\nExpected Type:' + typeof expected); |
278 } | 414 } |
279 } | 415 } |
280 | 416 |
281 /** | 417 /** |
282 * Always aborts the current test. | 418 * Always aborts the current test. |
283 * @param {String=} message The message to include in the Error thrown. | 419 * @param {String=} message The message to include in the Error thrown. |
284 * @throws {Error} always. | 420 * @throws {Error} always. |
285 **/ | 421 **/ |
286 function assertNotReached(message) { | 422 function assertNotReached(message) { |
287 throw new Error(message); | 423 helper.registerCall(); |
| 424 throw new Error(helper.getCall()); |
288 } | 425 } |
289 | 426 |
290 /** | 427 /** |
291 * Holds the errors, if any, caught by expects so that the test case can fail. | 428 * Holds the errors, if any, caught by expects so that the test case can fail. |
292 * @type {Array.<Error>} | 429 * @type {Array.<Error>} |
293 **/ | 430 **/ |
294 var errors = []; | 431 var errors = []; |
295 | 432 |
296 /** | 433 /** |
297 * Creates a function based upon a function that thows an exception on | 434 * 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 | 435 * failure. The new function stuffs any errors into the |errors| array for |
299 * checking by runTest. This allows tests to continue running other checks, | 436 * checking by runTest. This allows tests to continue running other checks, |
300 * while failing the overal test if any errors occurrred. | 437 * while failing the overal test if any errors occurrred. |
301 * @param {Function} assertFunc The function which may throw an Error. | 438 * @param {Function} assertFunc The function which may throw an Error. |
302 * @return {Function} A function that applies its arguments to |assertFunc|. | 439 * @return {Function} A function that applies its arguments to |assertFunc|. |
303 * @see errors | 440 * @see errors |
304 * @see runTest | 441 * @see runTest |
305 **/ | 442 **/ |
306 function createExpect(assertFunc) { | 443 function createExpect(assertFunc) { |
307 return function() { | 444 var expectFunc = function() { |
308 try { | 445 try { |
309 assertFunc.apply(null, arguments); | 446 assertFunc.apply(null, arguments); |
310 } catch (e) { | 447 } catch (e) { |
311 errors.push(e); | 448 errors.push(e); |
312 } | 449 } |
313 }; | 450 }; |
| 451 expectFunc.isExpect = true; |
| 452 expectFunc.expectName = assertFunc.name.replace(/^assert/, 'expect'); |
| 453 return expectFunc; |
314 } | 454 } |
315 | 455 |
316 /** | 456 /** |
317 * This is the starting point for tests run by WebUIBrowserTest. It clears | 457 * 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 | 458 * |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 | 459 * |errors| is non-empty, it reports a failure and a message by joining |
320 * |errors|. | 460 * |errors|. |
321 * @param {String} testFunction The function name to call. | 461 * @param {String} testFunction The function name to call. |
322 * @param {Array} testArguments The arguments to call |testFunction| with. | 462 * @param {Array} testArguments The arguments to call |testFunction| with. |
323 * @return {Array.<Boolean, String>} [test-succeeded, message-if-failed] | 463 * @return {Array.<Boolean, String>} [test-succeeded, message-if-failed] |
324 * @see errors | 464 * @see errors |
325 * @see createExpect | 465 * @see createExpect |
326 **/ | 466 **/ |
327 function runTest(testFunction, testArguments) { | 467 function runTest(testFunction, testArguments) { |
328 errors = []; | 468 errors.splice(0, errors.length); |
329 // Avoid eval() if at all possible, since it will not work on pages | 469 // Avoid eval() if at all possible, since it will not work on pages |
330 // that have enabled content-security-policy. | 470 // that have enabled content-security-policy. |
331 var testBody = this[testFunction]; // global object -- not a method. | 471 var testBody = this[testFunction]; // global object -- not a method. |
332 if (typeof testBody === "undefined") | 472 if (typeof testBody === "undefined") |
333 testBody = eval(testFunction); | 473 testBody = eval(testFunction); |
334 if (testBody != RUN_TEST_F) | 474 if (testBody != RUN_TEST_F) { |
335 console.log('Running test ' + testBody.name); | 475 var testName = |
| 476 testFunction.name ? testFunction.name : testBody.toString(); |
| 477 console.log('Running test ' + testName); |
| 478 } |
336 createExpect(testBody).apply(null, testArguments); | 479 createExpect(testBody).apply(null, testArguments); |
337 | 480 |
| 481 var result = [true]; |
338 if (errors.length) { | 482 if (errors.length) { |
| 483 var message = ''; |
339 for (var i = 0; i < errors.length; ++i) { | 484 for (var i = 0; i < errors.length; ++i) { |
340 console.log('Failed: ' + testFunction + '(' + | 485 message += 'Failed: ' + testFunction + '(' + |
341 testArguments.toString() + ')\n' + errors[i].stack); | 486 testArguments.map(JSON.stringify) + |
| 487 ')\n' + errors[i].stack; |
342 } | 488 } |
343 return [false, errors.join('\n')]; | 489 errors.splice(0, errors.length); |
344 } else { | 490 result = [false, message]; |
345 return [true]; | |
346 } | 491 } |
| 492 return result; |
347 } | 493 } |
348 | 494 |
349 /** | 495 /** |
350 * Creates a new test case for the given |testFixture| and |testName|. Assumes | 496 * Creates a new test case for the given |testFixture| and |testName|. Assumes |
351 * |testFixture| describes a globally available subclass of type Test. | 497 * |testFixture| describes a globally available subclass of type Test. |
352 * @param {String} testFixture The fixture for this test case. | 498 * @param {String} testFixture The fixture for this test case. |
353 * @param {String} testName The name for this test case. | 499 * @param {String} testName The name for this test case. |
354 * @return {TestCase} A newly created TestCase. | 500 * @return {TestCase} A newly created TestCase. |
355 **/ | 501 **/ |
356 function createTestCase(testFixture, testName) { | 502 function createTestCase(testFixture, testName) { |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
491 window.registerMockMessageCallbacks = registerMockMessageCallbacks; | 637 window.registerMockMessageCallbacks = registerMockMessageCallbacks; |
492 window.runTest = runTest; | 638 window.runTest = runTest; |
493 window.preloadJavascriptLibraries = preloadJavascriptLibraries; | 639 window.preloadJavascriptLibraries = preloadJavascriptLibraries; |
494 window.TEST = TEST; | 640 window.TEST = TEST; |
495 window.TEST_F = TEST_F; | 641 window.TEST_F = TEST_F; |
496 window.GEN = GEN; | 642 window.GEN = GEN; |
497 | 643 |
498 // Import the Mock4JS helpers. | 644 // Import the Mock4JS helpers. |
499 Mock4JS.addMockSupport(window); | 645 Mock4JS.addMockSupport(window); |
500 })(); | 646 })(); |
OLD | NEW |