Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2145)

Side by Side Diff: chrome/test/data/webui/test_api.js

Issue 7250009: Added guts to pull call signatures when assertions & expectations fail. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Changes from review. Created 9 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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 })();
OLDNEW
« chrome/test/data/webui/assertions.js ('K') | « chrome/test/data/webui/assertions.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698