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

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: Rebase, fix and fix nits. 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
« no previous file with comments | « chrome/test/data/webui/assertions.js ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 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
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
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
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 })();
OLDNEW
« no previous file with comments | « chrome/test/data/webui/assertions.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698