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 |