Chromium Code Reviews| Index: chrome/test/data/webui/test_api.js |
| diff --git a/chrome/test/data/webui/test_api.js b/chrome/test/data/webui/test_api.js |
| index 4e554bd8722b8d8d7051966d576dba1cdbb20ed3..37f1f3cb5336d649065ad76c8ea2515ae161128b 100644 |
| --- a/chrome/test/data/webui/test_api.js |
| +++ b/chrome/test/data/webui/test_api.js |
| @@ -4,128 +4,171 @@ |
| /** |
| * @fileoverview Library providing basic test framework functionality. |
| - **/ |
| + */ |
| /** |
| * Namespace for |Test|. |
| * @type {Object} |
| - **/ |
| -var testing = {}; |
| - |
| -/** |
| - * Hold the currentTestCase across between PreLoad and Run. |
| - * @type {TestCase} |
| - **/ |
| -var currentTestCase = null; |
| - |
| -/** |
| - * @type {?string} The string representation of the currently running test |
| - * function. |
| */ |
| -var currentTestFunction = null; |
| +var testing = {}; |
| +(function(window) { |
| + /** |
| + * Hold the currentTestCase across between preLoad and run. |
| + * @type {TestCase} |
| + */ |
| + var currentTestCase = null; |
| -/** |
| - * @type {?Array} The arguments of the currently running test. |
| - */ |
| -var currentTestArguments = null; |
| - |
| -(function() { |
| - // Provide global objects for generation case. |
| - if (this['window'] === undefined) |
| - this['window'] = this; |
| - if (this['chrome'] === undefined) { |
| - this['chrome'] = { |
| - send: function() {}, |
| - }; |
| - } |
| - if (this['console'] === undefined) { |
| - this['console'] = { |
| - log: print, |
| - }; |
| - } |
| + /** |
| + * @type {?string} The string representation of the currently running test |
| + * function. |
| + */ |
| + var currentTestFunction = null; |
| /** |
| + * @type {?Array} The arguments of the currently running test. |
| + */ |
| + var currentTestArguments = null; |
| + |
| + /** |
| * This class will be exported as testing.Test, and is provided to hold the |
| * fixture's configuration and callback methods for the various phases of |
| * invoking a test. It is called "Test" rather than TestFixture to roughly |
| * mimic the gtest's class names. |
| * @constructor |
| - **/ |
| + */ |
| function Test() {} |
| Test.prototype = { |
| /** |
| * The name of the test. |
| - **/ |
| + */ |
| name: null, |
| /** |
| * When set to a string value representing a url, generate BrowsePreload |
| - * call, which will browse to the url and call fixture.PreLoad of the |
| + * call, which will browse to the url and call fixture.preLoad of the |
| * currentTestCase. |
| * @type {string} |
| - **/ |
| + */ |
| browsePreload: null, |
| /** |
| * When set to a string value representing an html page in the test |
| * directory, generate BrowsePrintPreload call, which will browse to a url |
| - * representing the file, cause print, and call fixture.PreLoad of the |
| + * representing the file, cause print, and call fixture.preLoad of the |
| * currentTestCase. |
| * @type {string} |
| - **/ |
| + */ |
| browsePrintPreload: null, |
| /** |
| * When set to a function, will be called in the context of the test |
| * generation inside the function, and before any generated C++. |
| * @type {function(string,string)} |
| - **/ |
| + */ |
| testGenPreamble: null, |
| /** |
| * When set to a function, will be called in the context of the test |
| * generation inside the function, and after any generated C++. |
| * @type {function(string,string)} |
| - **/ |
| + */ |
| testGenPostamble: null, |
| /** |
| * When set to a non-null string, auto-generate typedef before generating |
| * TEST*: {@code typedef typedefCppFixture testFixture}. |
| * @type {string} |
| - **/ |
| + */ |
| typedefCppFixture: 'WebUIBrowserTest', |
| /** |
| * This should be initialized by the test fixture and can be referenced |
| - * during the test run. |
| - * @type {Mock4JS.Mock} |
| - **/ |
| + * during the test run. It holds any mocked handler methods. |
| + * @type {?Mock4JS.Mock} |
| + */ |
| mockHandler: null, |
| /** |
| + * This should be initialized by the test fixture and can be referenced |
| + * during the test run. It holds any mocked global functions. |
| + * @type {?Mock4JS.Mock} |
| + */ |
| + mockGlobals: null, |
| + |
| + /** |
| + * Value is passed through call to C++ RunJavascriptF to invoke this test. |
| + * @type {boolean} |
| + */ |
| + isAsync: false, |
| + |
| + /** |
| * Override this method to perform initialization during preload (such as |
| * creating mocks and registering handlers). |
| * @type {Function} |
| - **/ |
| - PreLoad: function() {}, |
| + */ |
| + preLoad: function() {}, |
| /** |
| * Override this method to perform tasks before running your test. |
| * @type {Function} |
| - **/ |
| - SetUp: function() {}, |
| + */ |
| + setUp: function() {}, |
| /** |
| * Override this method to perform tasks after running your test. If you |
| * create a mock class, you must call Mock4JS.verifyAllMocks() in this |
| * phase. |
| * @type {Function} |
| - **/ |
| - TearDown: function() { |
| + */ |
| + tearDown: function() { |
| Mock4JS.verifyAllMocks(); |
| - } |
| + }, |
| + |
| + /** |
| + * Called to run the body from the perspective of this fixture. |
| + * @type {Function} |
| + */ |
| + runTest: function(testBody) { |
| + testBody.call(this); |
| + }, |
| + |
| + /** |
| + * Create a closure function for continuing the test at a later time. May be |
| + * used as a listener function. |
| + * @param {WhenTestDone} whenTestDone Call testDone() at the appropriate |
| + * time. |
| + * @param {Function} completion The function to call to complete the test. |
| + * @return {function(): void} Return a function, bound to this test fixture, |
| + * which continues the test. |
| + */ |
| + continueTest: function(whenTestDone, completion) { |
| + var completionAction = new CallFunctionAction( |
| + this, null, completion, null); |
| + if (whenTestDone === WhenTestDone.DEFAULT) |
| + whenTestDone = WhenTestDone.ASSERT; |
| + var runAll = new RunAllAction( |
| + true, whenTestDone, [completionAction]); |
| + return function() { |
|
mmenke
2011/08/23 15:26:29
Might be a good idea for this function to pass alo
Sheridan Rawlins
2011/08/24 02:33:53
Done.
|
| + runAll.invoke(); |
| + }; |
| + }, |
| + |
| + /** |
| + * Call this during setUp to defer the call to runTest() until later. The |
| + * caller must call the returned function at some point to run the test. |
| + * @type {Function} |
| + * @param {WhenTestDone} whenTestDone Call testDone() at the appropriate |
| + * time. |
| + * @return {function(): void} A function which will run the current body of |
| + * the currentTestCase. |
| + */ |
| + deferRunTest: function(whenTestDone) { |
| + if (whenTestDone === WhenTestDone.DEFAULT) |
| + whenTestDone = WhenTestDone.ALWAYS; |
| + |
| + return currentTestCase.deferRunTest(whenTestDone); |
| + }, |
| }; |
| /** |
| @@ -135,7 +178,7 @@ var currentTestArguments = null; |
| * @param {Test} fixture The fixture object for this test case. |
| * @param {Function} body The code to run for the test. |
| * @constructor |
| - **/ |
| + */ |
| function TestCase(name, fixture, body) { |
| this.name = name; |
| this.fixture = fixture; |
| @@ -143,17 +186,62 @@ var currentTestArguments = null; |
| } |
| TestCase.prototype = { |
| + /** |
| + * The name of this test. |
| + * @type {string} |
| + */ |
| name: null, |
| + |
| + /** |
| + * The test fixture to set |this| to when running the test |body|. |
| + * @type {testing.Test} |
| + */ |
| fixture: null, |
| + |
| + /** |
| + * The test body to execute in runTest(). |
| + * @type {Function} |
| + */ |
| body: null, |
| /** |
| + * True when the test fixture will run the test later. |
| + * @type {boolean} |
| + * @private |
| + */ |
| + deferred_: false, |
| + |
| + /** |
| * Called at preload time, proxies to the fixture. |
| * @type {Function} |
| - **/ |
| - PreLoad: function(name) { |
| + */ |
| + preLoad: function(name) { |
| + if (this.fixture) |
| + this.fixture.preLoad(); |
| + }, |
| + |
| + /** |
| + * Called before a test runs. |
| + */ |
| + setUp: function() { |
| + if (this.fixture) |
| + this.fixture.setUp(); |
| + }, |
| + |
| + /** |
| + * Called before a test is torn down (by testDone()). |
| + */ |
| + tearDown: function() { |
| if (this.fixture) |
| - this.fixture.PreLoad(); |
| + this.fixture.tearDown(); |
| + }, |
| + |
| + /** |
| + * Called to run this test's body. |
| + */ |
| + runTest: function() { |
| + if (this.body && this.fixture) |
| + this.fixture.runTest(this.body); |
| }, |
| /** |
| @@ -164,30 +252,55 @@ var currentTestArguments = null; |
| * dummy constructor, but tests created with TEST should not rely on |this| |
| * being set. |
| * @type {Function} |
| - **/ |
| - Run: function() { |
| - if (this.fixture) |
| - this.fixture.SetUp(); |
| - if (this.body) |
| - this.body.call(this.fixture); |
| - if (this.fixture) |
| - this.fixture.TearDown(); |
| + */ |
| + run: function() { |
| + try { |
| + this.setUp(); |
| + } catch(e) { |
| + console.error(e.stack); |
| + } |
| + |
| + if (!this.deferred_) |
| + this.runTest(); |
| + |
| + // tearDown called by testDone(). |
| }, |
| + |
| + /** |
| + * Cause this TestCase to be deferred (don't call runTest()) until the |
| + * returned function is called. |
| + * @type {Function} |
| + * @param {WhenTestDone} whenTestDone Call testDone() at the appropriate |
| + * time. |
| + * @return {function(): void} A function thatwill run this TestCase when |
| + * called. |
| + */ |
| + deferRunTest: function(whenTestDone) { |
| + this.deferred_ = true; |
| + var completionAction = new CallFunctionAction( |
| + this, null, this.runTest, null); |
| + var runAll = new RunAllAction( |
| + true, whenTestDone, [completionAction]); |
| + return function() { |
| + runAll.invoke(); |
| + }; |
| + }, |
| + |
| }; |
| /** |
| * Registry of javascript-defined callbacks for {@code chrome.send}. |
| * @type {Object} |
| - **/ |
| + */ |
| var sendCallbacks = {}; |
| /** |
| * Registers the message, object and callback for {@code chrome.send} |
| * @param {string} name The name of the message to route to this |callback|. |
| - * @param {Object} messageHAndler Pass as |this| when calling the |callback|. |
| + * @param {Object} messageHandler Pass as |this| when calling the |callback|. |
| * @param {function(...)} callback Called by {@code chrome.send}. |
| * @see sendCallbacks |
| - **/ |
| + */ |
| function registerMessageCallback(name, messageHandler, callback) { |
| sendCallbacks[name] = [messageHandler, callback]; |
| } |
| @@ -199,14 +312,49 @@ var currentTestArguments = null; |
| * @param {Mock4JS.Mock} mockObject The mock to register callbacks against. |
| * @param {function(new:Object)} mockClAss Constructor for the mocked class. |
| * @see registerMessageCallback |
| - **/ |
| + */ |
| function registerMockMessageCallbacks(mockObject, mockClass) { |
| var mockProxy = mockObject.proxy(); |
| - for (func in mockClass.prototype) { |
| + for (var func in mockClass.prototype) { |
| + if (typeof mockClass.prototype[func] == 'function') { |
| + registerMessageCallback(func, mockProxy, mockProxy[func]); |
| + } |
| + } |
| + } |
| + |
| + /** |
| + * Holds the mapping of name -> global override information. |
| + * @type {Object} |
| + */ |
| + var globalOverrides = {}; |
| + |
| + /** |
| + * Registers the global function name, object and callback. |
| + * @param {string} name The name of the message to route to this |callback|. |
| + * @param {Object} object Pass as |this| when calling the |callback|. |
| + * @param {function(...)} callback Called by {@code chrome.send}. |
| + */ |
| + function registerMockGlobal(name, object, callback) { |
| + assertEquals(undefined, globalOverrides[name]); |
| + globalOverrides[name] = { |
| + object: object, |
| + callback: callback, |
| + }; |
| + } |
| + |
| + /** |
| + * Register all methods of {@code mockClass.prototype} as overrides to global |
| + * functions of the same name as the method, using the proxy of the |
| + * |mockObject| to handle the functions. |
| + * @param {Mock4JS.Mock} mockObject The mock to register callbacks against. |
| + * @param {function(new:Object)} mockClAss Constructor for the mocked class. |
| + * @see registerMessageCallback |
| + */ |
| + function registerMockGlobals(mockObject, mockClass) { |
| + var mockProxy = mockObject.proxy(); |
| + for (var func in mockClass.prototype) { |
| if (typeof(mockClass.prototype[func]) == 'function') { |
| - registerMessageCallback(func, |
| - mockProxy, |
| - mockProxy[func]); |
| + registerMockGlobal(func, mockProxy, mockProxy[func]); |
| } |
| } |
| } |
| @@ -215,7 +363,7 @@ var currentTestArguments = null; |
| * Overrides {@code chrome.send} for routing messages to javascript |
| * functions. Also falls back to sending with the original chrome object. |
| * @param {string} messageName The message to route. |
| - **/ |
| + */ |
| function send(messageName) { |
| var callback = sendCallbacks[messageName]; |
| if (callback != undefined) |
| @@ -229,7 +377,7 @@ var currentTestArguments = null; |
| * of their caller. Assert* methods should |registerCall| and expect* methods |
| * should set |isExpect| and |expectName| properties to indicate that the |
| * interesting caller is one more level up the stack. |
| - **/ |
| + */ |
| function CallHelper() { |
| this.__proto__ = CallHelper.prototype; |
| } |
| @@ -239,7 +387,7 @@ var currentTestArguments = null; |
| * Holds the mapping of (callerCallerString, callerName) -> count of times |
| * called. |
| * @type {Object.<string, Object.<string, number>>} |
| - **/ |
| + */ |
| counts_: {}, |
| /** |
| @@ -248,7 +396,7 @@ var currentTestArguments = null; |
| * @param {Function} caller the caller of the assert* routine. |
| * @return {{callerName: string, callercallerString: string}} stackInfo |
| * @private |
| - **/ |
| + */ |
| getCallerInfo_: function(caller) { |
| var callerName = caller.name; |
| var callerCaller = caller.caller; |
| @@ -265,7 +413,7 @@ var currentTestArguments = null; |
| /** |
| * Register a call to an assertion class. |
| - **/ |
| + */ |
| registerCall: function() { |
| var stackInfo = this.getCallerInfo_(arguments.callee.caller); |
| if (!(stackInfo.callerCallerString in this.counts_)) |
| @@ -281,7 +429,7 @@ var currentTestArguments = null; |
| * @param {Function} caller The caller of the assert* routine. |
| * @return {String} Call signature. |
| * @private |
| - **/ |
| + */ |
| getCall_: function(caller) { |
| var stackInfo = this.getCallerInfo_(caller); |
| var count = |
| @@ -304,7 +452,7 @@ var currentTestArguments = null; |
| /** |
| * Returns the text of the call signature and any |message|. |
| * @param {string=} message Addtional message text from caller. |
| - **/ |
| + */ |
| getCallMessage: function(message) { |
| var callMessage = this.getCall_(arguments.callee.caller); |
| if (message) |
| @@ -316,7 +464,7 @@ var currentTestArguments = null; |
| /** |
| * Help register calls for better error reporting. |
| * @type {CallHelper} |
| - **/ |
| + */ |
| var helper = new CallHelper(); |
| /** |
| @@ -329,12 +477,18 @@ var currentTestArguments = null; |
| * Holds the errors, if any, caught by expects so that the test case can |
| * fail. Cleared when results are reported from runTest() or testDone(). |
| * @type {Array.<Error>} |
| - **/ |
| + */ |
| var errors = []; |
| /** |
| + * URL to dummy WebUI page for testing framework. |
| + * @type {string} |
| + */ |
| + var DUMMY_URL = 'http://DummyURL'; |
| + |
| + /** |
| * Resets test state by clearing |errors| and |testIsDone| flags. |
| - **/ |
| + */ |
| function resetTestState() { |
| errors.splice(0, errors.length); |
| testIsDone = false; |
| @@ -344,10 +498,14 @@ var currentTestArguments = null; |
| * Notifies the running browser test of the test results. Clears |errors|. |
| * @param {Array.<boolean, string>=} result When passed, this is used for the |
| * testResult message. |
| - **/ |
| + */ |
| function testDone(result) { |
| if (!testIsDone) { |
| testIsDone = true; |
| + if (currentTestCase) { |
| + currentTestCase.tearDown(); |
| + currentTestCase = null; |
| + } |
| chrome.send('testResult', result ? result : testResult()); |
| errors.splice(0, errors.length); |
| } else { |
| @@ -358,7 +516,7 @@ var currentTestArguments = null; |
| /** |
| * Returns [success, message] & clears |errors|. |
| * @return {Array.<boolean, string>} |
| - **/ |
| + */ |
| function testResult() { |
| var result = [true, '']; |
| if (errors.length) { |
| @@ -382,7 +540,7 @@ var currentTestArguments = null; |
| * @param {boolean} test The predicate to check against |expected|. |
| * @param {string=} message The message to include in the Error thrown. |
| * @throws {Error} upon failure. |
| - **/ |
| + */ |
| function assertTrue(test, message) { |
| helper.registerCall(); |
| if (test !== true) |
| @@ -395,7 +553,7 @@ var currentTestArguments = null; |
| * @param {boolean} test The predicate to check against |expected|. |
| * @param {string=} message The message to include in the Error thrown. |
| * @throws {Error} upon failure. |
| - **/ |
| + */ |
| function assertFalse(test, message) { |
| helper.registerCall(); |
| if (test !== false) |
| @@ -408,7 +566,7 @@ var currentTestArguments = null; |
| * @param {number} val1 The number expected to be >= |val2|. |
| * @param {number} val2 The number expected to be < |val1|. |
| * @param {string=} message The message to include in the Error thrown. |
| - **/ |
| + */ |
| function assertGE(val1, val2, message) { |
| helper.registerCall(); |
| if (val1 < val2) { |
| @@ -422,7 +580,7 @@ var currentTestArguments = null; |
| * @param {number} val1 The number expected to be > |val2|. |
| * @param {number} val2 The number expected to be <= |val1|. |
| * @param {string=} message The message to include in the Error thrown. |
| - **/ |
| + */ |
| function assertGT(val1, val2, message) { |
| helper.registerCall(); |
| if (val1 <= val2) { |
| @@ -437,7 +595,7 @@ var currentTestArguments = null; |
| * @param {*} actual The predicate to check against |expected|. |
| * @param {string=} message The message to include in the Error thrown. |
| * @throws {Error} upon failure. |
| - **/ |
| + */ |
| function assertEquals(expected, actual, message) { |
| helper.registerCall(); |
| if (expected != actual) { |
| @@ -458,7 +616,7 @@ var currentTestArguments = null; |
| * @param {number} val1 The number expected to be <= |val2|. |
| * @param {number} val2 The number expected to be > |val1|. |
| * @param {string=} message The message to include in the Error thrown. |
| - **/ |
| + */ |
| function assertLE(val1, val2, message) { |
| helper.registerCall(); |
| if (val1 > val2) { |
| @@ -472,7 +630,7 @@ var currentTestArguments = null; |
| * @param {number} val1 The number expected to be < |val2|. |
| * @param {number} val2 The number expected to be >= |val1|. |
| * @param {string=} message The message to include in the Error thrown. |
| - **/ |
| + */ |
| function assertLT(val1, val2, message) { |
| helper.registerCall(); |
| if (val1 >= val2) { |
| @@ -487,7 +645,7 @@ var currentTestArguments = null; |
| * @param {*} actual The predicate to check against |notExpected|. |
| * @param {string=} message The message to include in the Error thrown. |
| * @throws {Error} upon failure. |
| - **/ |
| + */ |
| function assertNotEquals(notExpected, actual, message) { |
| helper.registerCall(); |
| if (notExpected === actual) { |
| @@ -501,7 +659,7 @@ var currentTestArguments = null; |
| * Always aborts the current test. |
| * @param {string=} message The message to include in the Error thrown. |
| * @throws {Error} always. |
| - **/ |
| + */ |
| function assertNotReached(message) { |
| helper.registerCall(); |
| throw new Error(helper.getCallMessage(message)); |
| @@ -516,7 +674,7 @@ var currentTestArguments = null; |
| * @return {Function} A function that applies its arguments to |assertFunc|. |
| * @see errors |
| * @see runTest |
| - **/ |
| + */ |
| function createExpect(assertFunc) { |
| var expectFunc = function() { |
| try { |
| @@ -543,7 +701,7 @@ var currentTestArguments = null; |
| * necessarily successful results) of this test. |
| * @see errors |
| * @see runTestFunction |
| - **/ |
| + */ |
| function runTest(isAsync, testFunction, testArguments) { |
| // Avoid eval() if at all possible, since it will not work on pages |
| // that have enabled content-security-policy. |
| @@ -574,7 +732,7 @@ var currentTestArguments = null; |
| * @return {Array.<boolean, string>} [test-succeeded, message-if-failed] |
| * @see createExpect |
| * @see testDone |
| - **/ |
| + */ |
| function runTestFunction(testFunction, testBody, testArguments) { |
| currentTestFunction = testFunction; |
| currentTestArguments = testArguments; |
| @@ -588,7 +746,7 @@ var currentTestArguments = null; |
| * @param {string} testFixture The fixture for this test case. |
| * @param {string} testName The name for this test case. |
| * @return {TestCase} A newly created TestCase. |
| - **/ |
| + */ |
| function createTestCase(testFixture, testName) { |
| var fixtureConstructor = this[testFixture]; |
| var testBody = fixtureConstructor.testCaseBodies[testName]; |
| @@ -600,7 +758,7 @@ var currentTestArguments = null; |
| /** |
| * Used by WebUIBrowserTest to preload the javascript libraries at the |
| * appropriate time for javascript injection into the current page. This |
| - * creates a test case and calls its PreLoad for any early initialization such |
| + * creates a test case and calls its preLoad for any early initialization such |
| * as registering handlers before the page's javascript runs it's OnLoad |
| * method. This is called before the page is loaded, so the |chrome| object is |
| * not yet bound and this DOMContentLoaded listener will be called first to |
| @@ -608,7 +766,7 @@ var currentTestArguments = null; |
| * @param {string} testFixture The test fixture name. |
| * @param {string} testName The test name. |
| * @see sendCallbacks |
| - **/ |
| + */ |
| function preloadJavascriptLibraries(testFixture, testName) { |
| window.addEventListener('DOMContentLoaded', function() { |
| var oldChrome = chrome; |
| @@ -616,14 +774,24 @@ var currentTestArguments = null; |
| __proto__: oldChrome, |
| send: send, |
| }; |
| + |
| + // Override globals at load time so they will be defined. |
| + for (var func in globalOverrides) { |
| + assertNotEquals(undefined, this[func]); |
| + var globalOverride = globalOverrides[func]; |
| + assertNotEquals(undefined, globalOverride); |
| + assertEquals(undefined, globalOverride.original); |
| + globalOverride.original = this[func]; |
| + this[func] = globalOverride.callback.bind(globalOverride.object); |
| + } |
| }); |
| currentTestCase = createTestCase(testFixture, testName); |
| - currentTestCase.PreLoad(); |
| + currentTestCase.preLoad(); |
| } |
| /** |
| * During generation phase, this outputs; do nothing at runtime. |
| - **/ |
| + */ |
| function GEN() {} |
| /** |
| @@ -633,7 +801,7 @@ var currentTestArguments = null; |
| * @param {string} testCaseName The name of the test case. |
| * @param {string} testName The name of the test function. |
| * @param {Function} testBody The body to execute when running this test. |
| - **/ |
| + */ |
| function TEST(testCaseName, testName, testBody) { |
| var fixtureConstructor = this[testCaseName]; |
| if (fixtureConstructor === undefined) { |
| @@ -655,7 +823,7 @@ var currentTestArguments = null; |
| * @param {string} testFixture The name of the test fixture class. |
| * @param {string} testName The name of the test function. |
| * @param {Function} testBody The body to execute when running this test. |
| - **/ |
| + */ |
| function TEST_F(testFixture, testName, testBody) { |
| var fixtureConstructor = this[testFixture]; |
| if (!fixtureConstructor.prototype.name) |
| @@ -674,94 +842,372 @@ var currentTestArguments = null; |
| * @param {string} testName The name of the test function. |
| * @see preloadJavascriptLibraries |
| * @see runTest |
| - **/ |
| + */ |
| function RUN_TEST_F(testFixture, testName) { |
| - try { |
| - if (!currentTestCase) |
| - currentTestCase = createTestCase(testFixture, testName); |
| - assertEquals(currentTestCase.name, testName); |
| - assertEquals(currentTestCase.fixture.name, testFixture); |
| - console.log('Running TestCase ' + testFixture + '.' + testName); |
| - currentTestCase.Run(); |
| - } finally { |
| - currentTestCase = null; |
| - } |
| + if (!currentTestCase) |
| + currentTestCase = createTestCase(testFixture, testName); |
| + assertEquals(currentTestCase.name, testName); |
| + assertEquals(currentTestCase.fixture.name, testFixture); |
| + console.log('Running TestCase ' + testFixture + '.' + testName); |
| + currentTestCase.run(); |
| + } |
| + |
| + /** |
| + * This Mock4JS matcher object pushes each |actualArgument| parameter to |
| + * match() calls onto |args|. |
| + * @param {Array} args The array to push |actualArgument| onto. |
| + * @param {Object} realMatcher The real matcher check arguments with. |
| + * @constructor |
| + * @extends {realMatcher} |
| + */ |
| + function SaveMockArgumentMatcher(args, realMatcher) { |
| + this.arguments_ = args; |
| + this.realMatcher_ = realMatcher; |
| + } |
| + |
| + SaveMockArgumentMatcher.prototype = { |
| + /** |
| + * Holds the arguments to push each |actualArgument| onto. |
| + * @type {Array} |
| + * @private |
| + */ |
| + arguments_: null, |
| + |
| + /** |
| + * The real Mock4JS matcher object to check arguments with. |
| + * @type {Object} |
| + */ |
| + realMatcher_: null, |
| + |
| + /** |
| + * Pushes |actualArgument| onto |arguments_| and call |realMatcher_|. Clears |
| + * |arguments_| on non-match. |
| + * @param {*} actualArgument The argument to match and save. |
| + * @return {boolean} Result of calling the |realMatcher|. |
| + */ |
| + argumentMatches: function(actualArgument) { |
| + this.arguments_.push(actualArgument); |
| + var match = this.realMatcher_.argumentMatches(actualArgument); |
| + if (!match) |
| + this.arguments_.splice(0, this.arguments_.length); |
| + |
| + return match; |
| + }, |
| + |
| + /** |
| + * Proxy to |realMatcher_| for description. |
| + * @return {string} Description of this Mock4JS matcher. |
| + */ |
| + describe: function() { |
| + return this.realMatcher_.describe(); |
| + }, |
| + }; |
| + |
| + /** |
| + * Actions invoked by Mock4JS's "will()" syntax do not receive arguments from |
| + * the mocked method. This class works with SaveMockArgumentMatcher to save |
| + * arguments so that the invoked Action can pass arguments through to the |
| + * invoked function. |
| + * @param {!Object} realMatcher The real matcher to perform matching with. |
| + * @constructor |
| + */ |
| + function SaveMockArguments() { |
| + this.arguments = []; |
| } |
| + SaveMockArguments.prototype = { |
| + /** |
| + * Wraps the |realMatcher| with an object which will push its argument onto |
| + * |arguments| and call realMatcher. |
| + * @param {Object} realMatcher A Mock4JS matcher object for this argument. |
| + * @return {SaveMockArgumentMatcher} A new matcher which will push its |
| + * argument onto |arguments|. |
| + */ |
| + match: function(realMatcher) { |
| + return new SaveMockArgumentMatcher(this.arguments, realMatcher); |
| + }, |
| + |
| + /** |
| + * Remember the argument passed to this stub invocation. |
| + * @type {Array} |
| + */ |
| + arguments: null, |
| + }; |
| + |
| /** |
| * CallFunctionAction is provided to allow mocks to have side effects. |
| + * @param {Object} obj The object to set |this| to when calling |func_|. |
| + * @param {?SaveMockArguments} savedArgs when non-null, saved arguments are |
| + * passed to |func|. |
| * @param {Function} func The function to call. |
| * @param {Array} args Any arguments to pass to func. |
| * @constructor |
| - **/ |
| - function CallFunctionAction(func, args) { |
| - this._func = func; |
| - this._args = args; |
| + */ |
| + function CallFunctionAction(obj, savedArgs, func, args) { |
| + this.obj_ = obj; |
| + this.savedArgs_ = savedArgs; |
| + this.func_ = func; |
| + this.args_ = args; |
| } |
| CallFunctionAction.prototype = { |
| + /** |
| + * Set |this| to |obj_| when calling |func_|. |
| + * @type {?Object} |
| + */ |
| + obj_: null, |
| + |
| + /** |
| + * The SaveMockArguments to hold arguments when invoking |func_|. |
| + * @type {?SaveMockArguments} |
| + * @private |
| + */ |
| + savedArgs_: null, |
| + |
| + /** |
| + * The function to call when invoked. |
| + * @type {!Function} |
| + * @private |
| + */ |
| + func_: null, |
| + |
| + /** |
| + * Arguments to pass to |func_| when invoked. |
| + * @type {!Array} |
| + */ |
| + args_: null, |
| + |
| + /** |
| + * Accessor for |func_|. |
| + * @return {Function} The function to invoke. |
| + */ |
| + get func() { |
| + return this.func_; |
| + }, |
| + |
| + /** |
| + * Called by Mock4JS when using .will() to specify actions for stubs() or |
| + * expects(). Clears |savedArgs_| so it can be reused. |
| + * @return The results of calling |func_| with the concatenation of |
| + * |savedArgs_| and |args_|. |
| + */ |
| invoke: function() { |
| - return this._func.apply(null, this._args); |
| + var prependArgs = []; |
| + if (this.savedArgs_) { |
| + prependArgs = this.savedArgs_.arguments.splice( |
| + 0, this.savedArgs_.arguments.length); |
| + } |
| + return this.func.apply(this.obj_, prependArgs.concat(this.args_)); |
| }, |
| + |
| + /** |
| + * Describe this action to Mock4JS. |
| + * @return {string} A description of this action. |
| + */ |
| describe: function() { |
| - return 'calls the given function with arguments ' + this._args; |
| + return 'calls the given function with saved arguments and ' + this.args_; |
| } |
| }; |
| /** |
| - * Syntactic sugar for will() on a Mock4JS.Mock. |
| - * @param {Function} func the function to call when the method is invoked. |
| - * @param {...*} var_args arguments to pass when calling func. |
| - **/ |
| + * Syntactic sugar for use with will() on a Mock4JS.Mock. |
| + * @param {Function} func The function to call when the method is invoked. |
| + * @param {...*} var_args Arguments to pass when calling func. |
| + * @return {CallFunctionAction} Action for use in will. |
| + */ |
| function callFunction(func) { |
| - return new CallFunctionAction(func, |
| - Array.prototype.slice.call(arguments, 1)); |
| + return new CallFunctionAction( |
| + null, null, func, Array.prototype.slice.call(arguments, 1)); |
| } |
| /** |
| - * Allow mock stubs() and expects() to know what arguments were passed to the |
| - * |realMatcher|. |
| - * @param {!Object} realMatcher The real matcher to perform matching with. |
| + * Syntactic sugar for use with will() on a Mock4JS.Mock. |
| + * @param {SaveMockArguments} savedArgs Arguments saved with this object |
| + * are passed to |func|. |
| + * @param {Function} func The function to call when the method is invoked. |
| + * @param {...*} var_args Arguments to pass when calling func. |
| + * @return {CallFunctionAction} Action for use in will. |
| + */ |
| + function callFunctionWithSavedArgs(savedArgs, func) { |
| + return new CallFunctionAction( |
| + null, savedArgs, func, Array.prototype.slice.call(arguments, 2)); |
| + } |
| + |
| + /** |
| + * CallGlobalAction as a subclass of CallFunctionAction looks up the original |
| + * global object in |globalOverrides| using |funcName| as the key. This allows |
| + * tests, which need to wait until a global function to be called in order to |
| + * start the test to run the original function. When used with runAllActions |
| + * or runAllActionsAsync, Mock4JS expectations may call start or continue the |
| + * test after calling the original function. |
| + * @param {?SaveMockArguments} savedArgs when non-null, saved arguments are |
| + * passed to the global function |funcName|. |
| + * @param {Function} funcName The name of the global function to call. |
|
mmenke
2011/08/23 15:26:29
nit: Would "string" be more accurate than "Functi
Sheridan Rawlins
2011/08/24 02:33:53
Done.
|
| + * @param {Array} args Any arguments to pass to func. |
| * @constructor |
| - **/ |
| - function SaveArgumentsMatcher(realMatcher) { |
| - this.realMatcher_ = realMatcher; |
| + * @extends {CallFunctionAction} |
| + * @see globalOverrides |
| + */ |
| + function CallGlobalAction(savedArgs, funcName, args) { |
| + CallFunctionAction.call(this, null, savedArgs, funcName, args); |
| } |
| - SaveArgumentsMatcher.prototype = { |
| + CallGlobalAction.prototype = { |
| + __proto__: CallFunctionAction.prototype, |
| + |
| /** |
| - * Remember the argument passed to this stub invocation. |
| - * @type {*} |
| - **/ |
| - argument: undefined, |
| + * Fetch and return the original global function to call. |
| + * @return {Function} The global function to invoke. |
| + * @override |
| + */ |
| + get func() { |
| + var func = globalOverrides[this.func_].original; |
| + assertNotEquals(undefined, func); |
| + return func; |
| + }, |
| + }; |
| + |
| + /** |
| + * Syntactic sugar for use with will() on a Mock4JS.Mock. |
| + * @param {SaveMockArguments} savedArgs Arguments saved with this object |
| + * are passed to the global function |funcName|. |
| + * @param {Function} funcName The name of a registered mock global function to |
| + * call when the method is invoked. |
| + * @param {...*} var_args Arguments to pass when calling func. |
| + * @return {CallGlobalAction} Action for use in Mock4JS will(). |
| + */ |
| + function callGlobalWithSavedArgs(savedArgs, funcName) { |
| + return new CallGlobalAction( |
| + savedArgs, funcName, Array.prototype.slice.call(arguments, 2)); |
| + } |
| + |
| + /** |
| + * When to call testDone(). |
| + * @enum {number} |
| + */ |
| + var WhenTestDone = { |
| + /** |
| + * Default for the method called. |
| + */ |
| + DEFAULT: -1, |
| + |
| + /** |
| + * Never call testDone(). |
| + */ |
| + NEVER: 0, |
| + |
| + /** |
| + * Call testDone() on assert failure. |
| + */ |
| + ASSERT: 1, |
| + |
| + /** |
| + * Call testDone() if there are any assert or expect failures. |
| + */ |
| + EXPECT: 2, |
| /** |
| - * @type {Object} the object performing the real match. |
| + * Always call testDone(). |
| + */ |
| + ALWAYS: 4, |
| + }; |
| + |
| + /** |
| + * Runs all |actions|. |
| + * @param {boolean} isAsync When true, call testDone() on Errors. |
| + * @param {WhenTestDone} whenTestDone Call testDone() at the appropriate |
| + * time. |
| + * @param {Array.<Object>} actions Actions to run. |
| + * @constructor |
| + */ |
| + function RunAllAction(isAsync, whenTestDone, actions) { |
| + this.isAsync_ = isAsync; |
| + this.whenTestDone_ = whenTestDone; |
| + this.actions_ = actions; |
| + } |
| + |
| + RunAllAction.prototype = { |
| + /** |
| + * When true, call testDone() on Errors. |
| + * @type {boolean} |
| * @private |
| */ |
| - realMatcher_: null, |
| + isAsync_: false, |
| /** |
| - * Saves |actualArgument| for later use by the mock stub or expect. |
| - * @param {*} actualArgument The argument to match and save. |
| - * @return {boolean} value of calling the |realMatcher_|. |
| - **/ |
| - argumentMatches: function(actualArgument) { |
| - this.argument = actualArgument; |
| - return this.realMatcher_.argumentMatches.call(this.realMatcher_, |
| - actualArgument); |
| + * Call testDone() at appropriate time. |
| + * @type {WhenTestDone} |
| + * @private |
| + * @see WhenTestDone |
| + */ |
| + whenTestDone_: WhenTestDone.ASSERT, |
| + |
| + /** |
| + * Holds the actions to execute when invoked. |
| + * @type {Array} |
| + * @private |
| + */ |
| + actions_: null, |
| + |
| + /** |
| + * Runs all |actions_|, returning the last one. When running in sync mode, |
| + * throws any exceptions to be caught by runTest() or |
| + * runTestFunction(). Call testDone() according to |whenTestDone_| setting. |
| + */ |
| + invoke: function() { |
| + try { |
| + var result; |
| + for(var i = 0; i < this.actions_.length; ++i) { |
| + result = this.actions_[i].invoke.apply(this.actions_[i], arguments); |
| + if (errors.length && this.whenTestDone_ >= WhenTestDone.EXPECT) { |
|
mmenke
2011/08/23 15:26:29
Should use == here. Otherwise, ALWAYS behaves a l
Sheridan Rawlins
2011/08/24 02:33:53
Done.
|
| + testDone(); |
| + return result; |
|
mmenke
2011/08/23 15:26:29
Returning |result| when it's not the result of the
Sheridan Rawlins
2011/08/24 02:33:53
Done.
|
| + } |
| + } |
| + if (this.whenTestDone_ >= WhenTestDone.ALWAYS) |
| + testDone(); |
| + |
| + return result; |
| + } catch (e) { |
| + if (!this.isAsync_) |
| + throw e; |
| + |
| + errors.push(e); |
| + if (this.whenTestDone_ >= WhenTestDone.ASSERT) |
| + testDone(); |
| + } |
| }, |
| /** |
| - * Generic description for this Matcher object. |
| - * @return {string} description of the matcher for this argument. |
| - **/ |
| + * Describe this action to Mock4JS. |
| + * @return {string} A description of this action. |
| + */ |
| describe: function() { |
| - return 'SaveArguments(' + |
| - this.realMatcher_.describe.call(this.realMatcher_) + ')'; |
| + return 'Calls all actions: ' + this.actions_; |
| }, |
| }; |
| + /** |
| + * Syntactic sugar for use with will() on a Mock4JS.Mock. |
| + * @param {...Object} var_actions Actions to run. |
| + * @return {RunAllAction} Action for use in will. |
| + */ |
| + function runAllActions() { |
| + return new RunAllAction(false, WhenTestDone.NEVER, |
| + Array.prototype.slice.call(arguments)); |
| + } |
| + |
| + /** |
| + * Syntactic sugar for use with will() on a Mock4JS.Mock. |
| + * @param {WhenTestDone} whenTestDone Call testDone() at the appropriate |
| + * time. |
| + * @return {RunAllAction} Action for use in will. |
| + */ |
| + function runAllActionsAsync(whenTestDone) { |
| + return new RunAllAction(true, whenTestDone, |
| + Array.prototype.slice.call(arguments)); |
|
mmenke
2011/08/23 15:26:29
You should remove |whenTestDone| from |arguments|.
Sheridan Rawlins
2011/08/24 02:33:53
Done.
|
| + } |
| + |
| // Exports. |
| testing.Test = Test; |
| window.testDone = testDone; |
| @@ -775,6 +1221,8 @@ var currentTestArguments = null; |
| window.assertNotEquals = assertNotEquals; |
| window.assertNotReached = assertNotReached; |
| window.callFunction = callFunction; |
| + window.callFunctionWithSavedArgs = callFunctionWithSavedArgs; |
| + window.callGlobalWithSavedArgs = callGlobalWithSavedArgs; |
| window.expectTrue = createExpect(assertTrue); |
| window.expectFalse = createExpect(assertFalse); |
| window.expectGE = createExpect(assertGE); |
| @@ -786,15 +1234,20 @@ var currentTestArguments = null; |
| window.expectNotReached = createExpect(assertNotReached); |
| window.preloadJavascriptLibraries = preloadJavascriptLibraries; |
| window.registerMessageCallback = registerMessageCallback; |
| + window.registerMockGlobals = registerMockGlobals; |
| window.registerMockMessageCallbacks = registerMockMessageCallbacks; |
| window.resetTestState = resetTestState; |
| + window.runAllActions = runAllActions; |
| + window.runAllActionsAsync = runAllActionsAsync; |
| window.runTest = runTest; |
| window.runTestFunction = runTestFunction; |
| - window.SaveArgumentsMatcher = SaveArgumentsMatcher; |
| + window.SaveMockArguments = SaveMockArguments; |
| + window.DUMMY_URL = DUMMY_URL; |
| window.TEST = TEST; |
| window.TEST_F = TEST_F; |
| window.GEN = GEN; |
| + window.WhenTestDone = WhenTestDone; |
| // Import the Mock4JS helpers. |
| Mock4JS.addMockSupport(window); |
| -})(); |
| +})(('window' in this) ? window : this); |