Chromium Code Reviews| 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 before any generated C++. |
|
David Tseng
2011/07/18 18:31:59
nit: after?
Sheridan Rawlins
2011/07/19 01:19:25
Done.
| |
| 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 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 146 }, | 146 }, |
| 147 | 147 |
| 148 /** | 148 /** |
| 149 * Runs this test case. | 149 * Runs this test case. |
| 150 * @type {Function} | 150 * @type {Function} |
| 151 **/ | 151 **/ |
| 152 Run: function() { | 152 Run: function() { |
| 153 if (this.fixture) | 153 if (this.fixture) |
| 154 this.fixture.SetUp(); | 154 this.fixture.SetUp(); |
| 155 if (this.body) | 155 if (this.body) |
| 156 this.body.call(this.fixture); | 156 this.body.call(this.fixture); |
|
David Tseng
2011/07/18 18:31:59
Dnit: Does the |body| expect |fixture| to be non-n
Sheridan Rawlins
2011/07/19 01:19:25
It doesn't need to, but it may, if you are writing
| |
| 157 if (this.fixture) | 157 if (this.fixture) |
| 158 this.fixture.TearDown(); | 158 this.fixture.TearDown(); |
| 159 }, | 159 }, |
| 160 }; | 160 }; |
| 161 | 161 |
| 162 /** | 162 /** |
| 163 * Registry of javascript-defined callbacks for {@code chrome.send}. | 163 * Registry of javascript-defined callbacks for {@code chrome.send}. |
| 164 * @type {Object} | 164 * @type {Object} |
| 165 **/ | 165 **/ |
| 166 var sendCallbacks = {}; | 166 var sendCallbacks = {}; |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 210 **/ | 210 **/ |
| 211 function send(messageName) { | 211 function send(messageName) { |
| 212 var callback = sendCallbacks[messageName]; | 212 var callback = sendCallbacks[messageName]; |
| 213 var args = Array.prototype.slice.call(arguments, 1); | 213 var args = Array.prototype.slice.call(arguments, 1); |
| 214 if (callback != undefined) | 214 if (callback != undefined) |
| 215 callback[1].apply(callback[0], args); | 215 callback[1].apply(callback[0], args); |
| 216 else | 216 else |
| 217 oldChrome.send.apply(oldChrome, args); | 217 oldChrome.send.apply(oldChrome, args); |
| 218 } | 218 } |
| 219 | 219 |
| 220 function CallHelper() { | |
|
David Tseng
2011/07/18 18:31:59
Document.
Sheridan Rawlins
2011/07/19 01:19:25
Done.
| |
| 221 this.__proto__ = CallHelper.prototype; | |
| 222 } | |
| 223 | |
| 224 CallHelper.prototype = { | |
| 225 'counts_': {}, | |
|
David Tseng
2011/07/18 18:31:59
nit: should document this since it's not obvious y
Sheridan Rawlins
2011/07/19 01:19:25
Done.
| |
| 226 'getStackInfo': function(caller) { | |
|
David Tseng
2011/07/18 18:31:59
nit: clearer to call this 'getCallerInfo", or 'get
Sheridan Rawlins
2011/07/19 01:19:25
used getCallerInfo. Done.
On 2011/07/18 18:31:59
| |
| 227 var callerName = caller.name; | |
| 228 var callerCaller = caller.caller; | |
| 229 if (callerCaller['isExpect']) { | |
| 230 callerName = callerCaller.expectName; | |
| 231 callerCaller = callerCaller.caller; | |
| 232 } | |
| 233 var callerCallerString = callerCaller.toString(); | |
| 234 return { | |
| 235 callerName: callerName, | |
| 236 callerCallerString: callerCallerString, | |
| 237 }; | |
| 238 }, | |
| 239 'registerCall': function() { | |
| 240 var stackInfo = this.getStackInfo(arguments.callee.caller); | |
| 241 if (!(stackInfo.callerCallerString in this.counts_)) | |
| 242 this.counts_[stackInfo.callerCallerString] = {}; | |
| 243 if (!(stackInfo.callerName in this.counts_[stackInfo.callerCallerString])) | |
| 244 this.counts_[stackInfo.callerCallerString][stackInfo.callerName] = 0; | |
|
David Tseng
2011/07/18 18:31:59
could we just combine the two strings
stackInfo.ca
Sheridan Rawlins
2011/07/19 01:19:25
I could, but then we'd need to use a separator cha
| |
| 245 ++this.counts_[stackInfo.callerCallerString][stackInfo.callerName]; | |
| 246 }, | |
| 247 'matchedParamsIndex': function(string, index) { | |
|
David Tseng
2011/07/18 18:31:59
nit: up to you, but it seems like we can do this m
Sheridan Rawlins
2011/07/19 01:19:25
Hah, that's what you'd think. Unfortunately, it's
David Tseng
2011/07/19 16:53:03
True, but are we not just looking for strings of t
Sheridan Rawlins
2011/07/19 16:57:40
What about
assertTrue(expected, function(foo, ba
David Tseng
2011/07/19 16:58:13
I don't think the code as is handles this case.
David Tseng
2011/07/19 17:46:50
You can make reg ex's lazy by using "?". Also not
Sheridan Rawlins
2011/07/21 02:05:27
Mea Culpa; good catch, David.
Yeah, short of bein
| |
| 248 var args = []; | |
| 249 var parenCount = 1; | |
| 250 var argStart = index + 1; | |
| 251 for(index = argStart; | |
| 252 parenCount && index < string.length; | |
| 253 ++index) { | |
| 254 if (string[index] == '(') { | |
| 255 ++parenCount; | |
| 256 } else if (string[index] == ')') { | |
| 257 if (--parenCount == 0) | |
| 258 args.push(string.substring(argStart, index)); | |
| 259 } else if (string[index] == ',' && parenCount == 1) { | |
| 260 args.push(string.substring(argStart, index)); | |
| 261 argStart = index + 1; | |
| 262 } | |
| 263 } | |
| 264 return [index, args]; | |
| 265 }, | |
| 266 'getParams': function(caller_, count_) { | |
| 267 var caller = (caller_ == undefined) ? | |
| 268 arguments.callee.caller : caller_; | |
| 269 var stackInfo = this.getStackInfo(caller); | |
| 270 var count = (count_ == undefined) ? | |
| 271 this.counts_[stackInfo.callerCallerString][stackInfo.callerName] : | |
| 272 count_; | |
| 273 var searchStart = 0; | |
| 274 var args; | |
| 275 for(var i = 0; | |
| 276 i < count && searchStart < stackInfo.callerCallerString.length; | |
| 277 ++i) { | |
| 278 searchStart = stackInfo.callerCallerString.indexOf( | |
| 279 stackInfo.callerName, searchStart); | |
| 280 if (searchStart == -1) { | |
| 281 if (i && count_ == undefined) { | |
| 282 return this.getParams(caller, ((count - 1) % i) + 1); | |
| 283 } else { | |
| 284 console.error('bad count ' + count); | |
| 285 return undefined; | |
| 286 } | |
| 287 } | |
| 288 searchStart += stackInfo.callerName.length; | |
| 289 var matched = this.matchedParamsIndex(stackInfo.callerCallerString, | |
| 290 searchStart); | |
| 291 args = matched[1]; | |
| 292 searchStart = matched[0]; | |
| 293 } | |
| 294 return args; | |
| 295 }, | |
| 296 'getCall': function() { | |
| 297 var caller = arguments.callee.caller; | |
| 298 var stackInfo = this.getStackInfo(caller); | |
| 299 return stackInfo.callerName + '(' + this.getParams(caller) + ')'; | |
| 300 }, | |
| 301 }; | |
| 302 | |
| 303 var helper = new CallHelper(); | |
| 304 | |
| 220 // Asserts. | 305 // Asserts. |
| 221 // Use the following assertions to verify a condition within a test. | 306 // Use the following assertions to verify a condition within a test. |
| 222 // If assertion fails, the C++ backend will be immediately notified. | 307 // If assertion fails, the C++ backend will be immediately notified. |
| 223 // If assertion passes, no notification will be sent to the C++ backend. | 308 // If assertion passes, no notification will be sent to the C++ backend. |
| 224 | 309 |
| 225 /** | 310 /** |
| 226 * When |test| !== |expected|, aborts the current test. | 311 * When |test| !== |expected|, aborts the current test. |
| 227 * @param {Boolean} test The predicate to check against |expected|. | 312 * @param {Boolean} test The predicate to check against |expected|. |
| 228 * @param {Boolean} expected The expected value of |test|. | 313 * @param {Boolean} expected The expected value of |test|. |
| 229 * @param {String=} message The message to include in the Error thrown. | 314 * @param {String=} message The message to include in the Error thrown. |
| 230 * @throws {Error} upon failure. | 315 * @throws {Error} upon failure. |
| 231 **/ | 316 **/ |
| 232 function assertBool(test, expected, message) { | 317 function assertBool(test, expected, message) { |
| 233 if (test !== expected) { | 318 helper.registerCall(); |
| 234 if (message) | 319 if (test !== expected) |
| 235 message = test + '\n' + message; | 320 throw new Error('Test Error ' + helper.getCall() + ': ' + test); |
| 236 else | |
| 237 message = test; | |
| 238 throw new Error(message); | |
| 239 } | |
| 240 } | 321 } |
| 241 | 322 |
| 242 /** | 323 /** |
| 243 * When |test| !== true, aborts the current test. | 324 * When |test| !== true, aborts the current test. |
| 244 * @param {Boolean} test The predicate to check against |expected|. | 325 * @param {Boolean} test The predicate to check against |expected|. |
| 245 * @param {String=} message The message to include in the Error thrown. | 326 * @param {String=} message The message to include in the Error thrown. |
| 246 * @throws {Error} upon failure. | 327 * @throws {Error} upon failure. |
| 247 **/ | 328 **/ |
| 248 function assertTrue(test, message) { | 329 function assertTrue(test, message) { |
| 249 assertBool(test, true, message); | 330 helper.registerCall(); |
| 331 if (test !== true) | |
| 332 throw new Error('Test Error ' + helper.getCall() + ': ' + test); | |
| 250 } | 333 } |
| 251 | 334 |
| 252 /** | 335 /** |
| 253 * When |test| !== false, aborts the current test. | 336 * When |test| !== false, aborts the current test. |
| 254 * @param {Boolean} test The predicate to check against |expected|. | 337 * @param {Boolean} test The predicate to check against |expected|. |
| 255 * @param {String=} message The message to include in the Error thrown. | 338 * @param {String=} message The message to include in the Error thrown. |
| 256 * @throws {Error} upon failure. | 339 * @throws {Error} upon failure. |
| 257 **/ | 340 **/ |
| 258 function assertFalse(test, message) { | 341 function assertFalse(test, message) { |
| 259 assertBool(test, false, message); | 342 helper.registerCall(); |
| 343 if (test !== false) | |
| 344 throw new Error('Test Error ' + helper.getCall() + ': ' + test); | |
| 260 } | 345 } |
| 261 | 346 |
| 262 /** | 347 /** |
| 263 * When |expected| !== |actual|, aborts the current test. | 348 * When |expected| !== |actual|, aborts the current test. |
| 264 * @param {*} expected The predicate to check against |expected|. | 349 * @param {*} expected The predicate to check against |expected|. |
| 265 * @param {*} actual The expected value of |test|. | 350 * @param {*} actual The expected value of |test|. |
| 266 * @param {String=} message The message to include in the Error thrown. | 351 * @param {String=} message The message to include in the Error thrown. |
| 267 * @throws {Error} upon failure. | 352 * @throws {Error} upon failure. |
| 268 **/ | 353 **/ |
| 269 function assertEquals(expected, actual, message) { | 354 function assertEquals(expected, actual, message) { |
| 355 helper.registerCall(); | |
| 270 if (expected != actual) { | 356 if (expected != actual) { |
| 271 throw new Error('Test Error. Actual: ' + actual + '\nExpected: ' + | 357 throw new Error('Test Error ' + helper.getCall() + '\nActual: ' + actual + |
| 272 expected + '\n' + message); | 358 '\nExpected: ' + expected); |
| 273 } | 359 } |
| 274 if (typeof expected != typeof actual) { | 360 if (typeof expected != typeof actual) { |
| 275 throw new Error('Test Error' + | 361 throw new Error('Test Error (type mismatch) ' + helper.getCall() + |
| 276 ' (type mismatch)\nActual Type: ' + typeof actual + | 362 '\nActual Type: ' + typeof actual + |
| 277 '\nExpected Type:' + typeof expected + '\n' + message); | 363 '\nExpected Type:' + typeof expected); |
| 278 } | 364 } |
| 279 } | 365 } |
| 280 | 366 |
| 281 /** | 367 /** |
| 282 * Always aborts the current test. | 368 * Always aborts the current test. |
| 283 * @param {String=} message The message to include in the Error thrown. | 369 * @param {String=} message The message to include in the Error thrown. |
| 284 * @throws {Error} always. | 370 * @throws {Error} always. |
| 285 **/ | 371 **/ |
| 286 function assertNotReached(message) { | 372 function assertNotReached(message) { |
| 287 throw new Error(message); | 373 helper.registerCall(); |
| 374 throw new Error(helper.getCall()); | |
| 288 } | 375 } |
| 289 | 376 |
| 290 /** | 377 /** |
| 291 * Holds the errors, if any, caught by expects so that the test case can fail. | 378 * Holds the errors, if any, caught by expects so that the test case can fail. |
| 292 * @type {Array.<Error>} | 379 * @type {Array.<Error>} |
| 293 **/ | 380 **/ |
| 294 var errors = []; | 381 var errors = []; |
| 295 | 382 |
| 296 /** | 383 /** |
| 297 * Creates a function based upon a function that thows an exception on | 384 * 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 | 385 * failure. The new function stuffs any errors into the |errors| array for |
| 299 * checking by runTest. This allows tests to continue running other checks, | 386 * checking by runTest. This allows tests to continue running other checks, |
| 300 * while failing the overal test if any errors occurrred. | 387 * while failing the overal test if any errors occurrred. |
| 301 * @param {Function} assertFunc The function which may throw an Error. | 388 * @param {Function} assertFunc The function which may throw an Error. |
| 302 * @return {Function} A function that applies its arguments to |assertFunc|. | 389 * @return {Function} A function that applies its arguments to |assertFunc|. |
| 303 * @see errors | 390 * @see errors |
| 304 * @see runTest | 391 * @see runTest |
| 305 **/ | 392 **/ |
| 306 function createExpect(assertFunc) { | 393 function createExpect(assertFunc) { |
| 307 return function() { | 394 var expectFunc = function() { |
| 308 try { | 395 try { |
| 309 assertFunc.apply(null, arguments); | 396 assertFunc.apply(null, arguments); |
| 310 } catch (e) { | 397 } catch (e) { |
| 311 errors.push(e); | 398 errors.push(e); |
| 312 } | 399 } |
| 313 }; | 400 }; |
| 401 expectFunc.isExpect = true; | |
| 402 expectFunc.expectName = assertFunc.name.replace(/^assert/, 'expect'); | |
| 403 return expectFunc; | |
| 314 } | 404 } |
| 315 | 405 |
| 316 /** | 406 /** |
| 317 * This is the starting point for tests run by WebUIBrowserTest. It clears | 407 * 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 | 408 * |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 | 409 * |errors| is non-empty, it reports a failure and a message by joining |
| 320 * |errors|. | 410 * |errors|. |
| 321 * @param {String} testFunction The function name to call. | 411 * @param {String} testFunction The function name to call. |
| 322 * @param {Array} testArguments The arguments to call |testFunction| with. | 412 * @param {Array} testArguments The arguments to call |testFunction| with. |
| 323 * @return {Array.<Boolean, String>} [test-succeeded, message-if-failed] | 413 * @return {Array.<Boolean, String>} [test-succeeded, message-if-failed] |
| 324 * @see errors | 414 * @see errors |
| 325 * @see createExpect | 415 * @see createExpect |
| 326 **/ | 416 **/ |
| 327 function runTest(testFunction, testArguments) { | 417 function runTest(testFunction, testArguments) { |
| 328 errors = []; | 418 errors.splice(0, errors.length); |
| 329 // Avoid eval() if at all possible, since it will not work on pages | 419 // Avoid eval() if at all possible, since it will not work on pages |
| 330 // that have enabled content-security-policy. | 420 // that have enabled content-security-policy. |
| 331 var testBody = this[testFunction]; // global object -- not a method. | 421 var testBody = this[testFunction]; // global object -- not a method. |
| 332 if (typeof testBody === "undefined") | 422 if (typeof testBody === "undefined") |
| 333 testBody = eval(testFunction); | 423 testBody = eval(testFunction); |
| 334 if (testBody != RUN_TEST_F) | 424 if (testBody != RUN_TEST_F) { |
| 335 console.log('Running test ' + testBody.name); | 425 var testName = |
| 426 testFunction.name ? testFunction.name : testBody.toString(); | |
| 427 console.log('Running test ' + testName); | |
| 428 } | |
| 336 createExpect(testBody).apply(null, testArguments); | 429 createExpect(testBody).apply(null, testArguments); |
| 337 | 430 |
| 431 var result = [true]; | |
| 338 if (errors.length) { | 432 if (errors.length) { |
| 433 var message = ''; | |
| 339 for (var i = 0; i < errors.length; ++i) { | 434 for (var i = 0; i < errors.length; ++i) { |
| 340 console.log('Failed: ' + testFunction + '(' + | 435 message += 'Failed: ' + testFunction + '(' + |
| 341 testArguments.toString() + ')\n' + errors[i].stack); | 436 testArguments.map(JSON.stringify) + |
| 437 ')\n' + errors[i].stack; | |
| 342 } | 438 } |
| 343 return [false, errors.join('\n')]; | 439 errors.splice(0, errors.length); |
| 344 } else { | 440 result = [false, message]; |
| 345 return [true]; | |
| 346 } | 441 } |
| 442 return result; | |
| 347 } | 443 } |
| 348 | 444 |
| 349 /** | 445 /** |
| 350 * Creates a new test case for the given |testFixture| and |testName|. Assumes | 446 * Creates a new test case for the given |testFixture| and |testName|. Assumes |
| 351 * |testFixture| describes a globally available subclass of type Test. | 447 * |testFixture| describes a globally available subclass of type Test. |
| 352 * @param {String} testFixture The fixture for this test case. | 448 * @param {String} testFixture The fixture for this test case. |
| 353 * @param {String} testName The name for this test case. | 449 * @param {String} testName The name for this test case. |
| 354 * @return {TestCase} A newly created TestCase. | 450 * @return {TestCase} A newly created TestCase. |
| 355 **/ | 451 **/ |
| 356 function createTestCase(testFixture, testName) { | 452 function createTestCase(testFixture, testName) { |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 491 window.registerMockMessageCallbacks = registerMockMessageCallbacks; | 587 window.registerMockMessageCallbacks = registerMockMessageCallbacks; |
| 492 window.runTest = runTest; | 588 window.runTest = runTest; |
| 493 window.preloadJavascriptLibraries = preloadJavascriptLibraries; | 589 window.preloadJavascriptLibraries = preloadJavascriptLibraries; |
| 494 window.TEST = TEST; | 590 window.TEST = TEST; |
| 495 window.TEST_F = TEST_F; | 591 window.TEST_F = TEST_F; |
| 496 window.GEN = GEN; | 592 window.GEN = GEN; |
| 497 | 593 |
| 498 // Import the Mock4JS helpers. | 594 // Import the Mock4JS helpers. |
| 499 Mock4JS.addMockSupport(window); | 595 Mock4JS.addMockSupport(window); |
| 500 })(); | 596 })(); |
| OLD | NEW |