Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * @fileoverview Library providing basic test framework functionality. | 6 * @fileoverview Library providing basic test framework functionality. |
| 7 **/ | 7 **/ |
|
arv (Not doing code reviews)
2011/08/22 20:57:18
Close these JSDoc comments with */ instead of **/
Sheridan Rawlins
2011/08/23 01:06:15
Done.
| |
| 8 | 8 |
| 9 /** | 9 /** |
| 10 * Namespace for |Test|. | 10 * Namespace for |Test|. |
| 11 * @type {Object} | 11 * @type {Object} |
| 12 **/ | 12 **/ |
| 13 var testing = {}; | 13 var testing = {}; |
| 14 | 14 |
| 15 /** | 15 /** |
| 16 * Hold the currentTestCase across between PreLoad and Run. | 16 * Hold the currentTestCase across between PreLoad and Run. |
| 17 * @type {TestCase} | 17 * @type {TestCase} |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 33 // Provide global objects for generation case. | 33 // Provide global objects for generation case. |
| 34 if (this['window'] === undefined) | 34 if (this['window'] === undefined) |
| 35 this['window'] = this; | 35 this['window'] = this; |
| 36 if (this['chrome'] === undefined) { | 36 if (this['chrome'] === undefined) { |
| 37 this['chrome'] = { | 37 this['chrome'] = { |
| 38 send: function() {}, | 38 send: function() {}, |
| 39 }; | 39 }; |
| 40 } | 40 } |
| 41 if (this['console'] === undefined) { | 41 if (this['console'] === undefined) { |
| 42 this['console'] = { | 42 this['console'] = { |
| 43 log: print, | 43 log: print, |
|
arv (Not doing code reviews)
2011/08/22 20:57:18
what about error and info?
Sheridan Rawlins
2011/08/23 01:06:15
Only the window is needed, actually. I nuked thes
| |
| 44 }; | 44 }; |
| 45 } | 45 } |
| 46 | 46 |
| 47 /** | 47 /** |
| 48 * This class will be exported as testing.Test, and is provided to hold the | 48 * This class will be exported as testing.Test, and is provided to hold the |
| 49 * fixture's configuration and callback methods for the various phases of | 49 * fixture's configuration and callback methods for the various phases of |
| 50 * invoking a test. It is called "Test" rather than TestFixture to roughly | 50 * invoking a test. It is called "Test" rather than TestFixture to roughly |
| 51 * mimic the gtest's class names. | 51 * mimic the gtest's class names. |
| 52 * @constructor | 52 * @constructor |
| 53 **/ | 53 **/ |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 92 | 92 |
| 93 /** | 93 /** |
| 94 * When set to a non-null string, auto-generate typedef before generating | 94 * When set to a non-null string, auto-generate typedef before generating |
| 95 * TEST*: {@code typedef typedefCppFixture testFixture}. | 95 * TEST*: {@code typedef typedefCppFixture testFixture}. |
| 96 * @type {string} | 96 * @type {string} |
| 97 **/ | 97 **/ |
| 98 typedefCppFixture: 'WebUIBrowserTest', | 98 typedefCppFixture: 'WebUIBrowserTest', |
| 99 | 99 |
| 100 /** | 100 /** |
| 101 * This should be initialized by the test fixture and can be referenced | 101 * This should be initialized by the test fixture and can be referenced |
| 102 * during the test run. | 102 * during the test run. It holds any mocked handler methods. |
| 103 * @type {Mock4JS.Mock} | 103 * @type {?Mock4JS.Mock} |
| 104 **/ | 104 **/ |
| 105 mockHandler: null, | 105 mockHandler: null, |
| 106 | 106 |
| 107 /** | 107 /** |
| 108 * This should be initialized by the test fixture and can be referenced | |
| 109 * during the test run. It holds any mocked global functions. | |
| 110 * @type {?Mock4JS.Mock} | |
| 111 **/ | |
| 112 mockGlobals: null, | |
| 113 | |
| 114 /** | |
| 115 * Value is passed through call to C++ RunJavascriptF to invoke this test. | |
| 116 * @type {boolean} | |
| 117 **/ | |
| 118 isAsync: false, | |
| 119 | |
| 120 /** | |
| 108 * Override this method to perform initialization during preload (such as | 121 * Override this method to perform initialization during preload (such as |
| 109 * creating mocks and registering handlers). | 122 * creating mocks and registering handlers). |
| 110 * @type {Function} | 123 * @type {Function} |
| 111 **/ | 124 **/ |
| 112 PreLoad: function() {}, | 125 PreLoad: function() {}, |
|
arv (Not doing code reviews)
2011/08/22 20:57:18
Can the names of these be fixed?
Sheridan Rawlins
2011/08/23 01:06:15
Done.
| |
| 113 | 126 |
| 114 /** | 127 /** |
| 115 * Override this method to perform tasks before running your test. | 128 * Override this method to perform tasks before running your test. |
| 116 * @type {Function} | 129 * @type {Function} |
| 117 **/ | 130 **/ |
| 118 SetUp: function() {}, | 131 SetUp: function() {}, |
| 119 | 132 |
| 120 /** | 133 /** |
| 121 * Override this method to perform tasks after running your test. If you | 134 * Override this method to perform tasks after running your test. If you |
| 122 * create a mock class, you must call Mock4JS.verifyAllMocks() in this | 135 * create a mock class, you must call Mock4JS.verifyAllMocks() in this |
| 123 * phase. | 136 * phase. |
| 124 * @type {Function} | 137 * @type {Function} |
| 125 **/ | 138 **/ |
| 126 TearDown: function() { | 139 TearDown: function() { |
| 127 Mock4JS.verifyAllMocks(); | 140 Mock4JS.verifyAllMocks(); |
| 128 } | 141 }, |
| 142 | |
| 143 /** | |
| 144 * Called to run the body from the perspective of this fixture. | |
| 145 * @type {Function} | |
| 146 */ | |
| 147 RunTest: function(testBody) { | |
| 148 testBody.call(this); | |
| 149 }, | |
| 150 | |
| 151 /** | |
| 152 * @param {boolean} alwaysDone When true, always call testDone(). | |
| 153 * @param {Function} completion The function to call to complete the test. | |
| 154 * @return {function(): void} Return a function, bound to this test fixture, | |
| 155 * which continues the test. | |
| 156 **/ | |
| 157 continueTest: function(alwaysDone, completion) { | |
| 158 var completionAction = new CallFunctionAction( | |
| 159 this, null, completion, null); | |
| 160 var runAll = new RunAllAction( | |
| 161 true, alwaysDone, [completionAction]); | |
| 162 return function() { | |
| 163 runAll.invoke(); | |
| 164 }; | |
| 165 }, | |
| 166 | |
| 167 /** | |
| 168 * Call this during SetUp to defer the call to RunTest() until later. The | |
| 169 * caller must call the returned function at some point to run the test. | |
| 170 * @type {Function} | |
| 171 * @return {function(): void} A function which will run the current body of | |
| 172 * the currentTestCase. | |
| 173 */ | |
| 174 deferRunTest: function() { | |
| 175 return currentTestCase.deferRunTest(); | |
| 176 }, | |
| 129 }; | 177 }; |
| 130 | 178 |
| 131 /** | 179 /** |
| 132 * This class is not exported and is available to hold the state of the | 180 * This class is not exported and is available to hold the state of the |
| 133 * |currentTestCase| throughout preload and test run. | 181 * |currentTestCase| throughout preload and test run. |
| 134 * @param {string} name The name of the test case. | 182 * @param {string} name The name of the test case. |
| 135 * @param {Test} fixture The fixture object for this test case. | 183 * @param {Test} fixture The fixture object for this test case. |
| 136 * @param {Function} body The code to run for the test. | 184 * @param {Function} body The code to run for the test. |
| 137 * @constructor | 185 * @constructor |
| 138 **/ | 186 **/ |
| 139 function TestCase(name, fixture, body) { | 187 function TestCase(name, fixture, body) { |
| 140 this.name = name; | 188 this.name = name; |
| 141 this.fixture = fixture; | 189 this.fixture = fixture; |
| 142 this.body = body; | 190 this.body = body; |
| 143 } | 191 } |
| 144 | 192 |
| 145 TestCase.prototype = { | 193 TestCase.prototype = { |
| 194 /** | |
| 195 * The name of this test. | |
| 196 * @type {string} | |
| 197 */ | |
| 146 name: null, | 198 name: null, |
| 199 | |
| 200 /** | |
| 201 * The test fixture to set |this| to when running the test |body|. | |
| 202 * @type {testing.Test} | |
| 203 */ | |
| 147 fixture: null, | 204 fixture: null, |
| 205 | |
| 206 /** | |
| 207 * The test body to execute in RunTest(). | |
| 208 * @type {Function} | |
| 209 **/ | |
| 148 body: null, | 210 body: null, |
| 149 | 211 |
| 150 /** | 212 /** |
| 213 * True when the test fixture will run the test later. | |
| 214 * @type {boolean} | |
| 215 * @private | |
| 216 */ | |
| 217 deferred_: false, | |
| 218 | |
| 219 /** | |
| 151 * Called at preload time, proxies to the fixture. | 220 * Called at preload time, proxies to the fixture. |
| 152 * @type {Function} | 221 * @type {Function} |
| 153 **/ | 222 **/ |
| 154 PreLoad: function(name) { | 223 PreLoad: function(name) { |
| 155 if (this.fixture) | 224 if (this.fixture) |
| 156 this.fixture.PreLoad(); | 225 this.fixture.PreLoad(); |
| 157 }, | 226 }, |
| 158 | 227 |
| 159 /** | 228 /** |
| 229 * Called before a test runs. | |
| 230 **/ | |
| 231 SetUp: function() { | |
| 232 if (this.fixture) | |
| 233 this.fixture.SetUp(); | |
| 234 }, | |
| 235 | |
| 236 /** | |
| 237 * Called before a test is torn down (by testDone()). | |
| 238 **/ | |
| 239 TearDown: function() { | |
| 240 if (this.fixture) | |
| 241 this.fixture.TearDown(); | |
| 242 }, | |
| 243 | |
| 244 /** | |
| 245 * Called to run this test's body. | |
| 246 **/ | |
| 247 RunTest: function() { | |
| 248 if (this.body && this.fixture) | |
| 249 this.fixture.RunTest(this.body); | |
| 250 }, | |
| 251 | |
| 252 /** | |
| 160 * Runs this test case with |this| set to the |fixture|. | 253 * Runs this test case with |this| set to the |fixture|. |
| 161 * | 254 * |
| 162 * Note: Tests created with TEST_F may depend upon |this| being set to an | 255 * Note: Tests created with TEST_F may depend upon |this| being set to an |
| 163 * instance of this.fixture. The current implementation of TEST creates a | 256 * instance of this.fixture. The current implementation of TEST creates a |
| 164 * dummy constructor, but tests created with TEST should not rely on |this| | 257 * dummy constructor, but tests created with TEST should not rely on |this| |
| 165 * being set. | 258 * being set. |
| 166 * @type {Function} | 259 * @type {Function} |
| 167 **/ | 260 **/ |
| 168 Run: function() { | 261 Run: function() { |
| 169 if (this.fixture) | 262 try { |
| 170 this.fixture.SetUp(); | 263 this.SetUp(); |
| 171 if (this.body) | 264 } catch(e) { |
| 172 this.body.call(this.fixture); | 265 console.error(e.stack); |
| 173 if (this.fixture) | 266 } |
| 174 this.fixture.TearDown(); | 267 |
| 268 if (!this.deferred_) | |
| 269 this.RunTest(); | |
| 270 | |
| 271 // TearDown called by testDone(). | |
| 175 }, | 272 }, |
| 273 | |
| 274 /** | |
| 275 * Cause this TestCase to be deferred (don't call RunTest()) until the | |
| 276 * returned function is called. | |
| 277 * @type {Function} | |
| 278 * @return {function(): void} A function thatwill run this TestCase when | |
| 279 * called. | |
| 280 */ | |
| 281 deferRunTest: function() { | |
| 282 this.deferred_ = true; | |
| 283 var completionAction = new CallFunctionAction( | |
| 284 this, null, this.RunTest, null); | |
| 285 var runAll = new RunAllAction( | |
| 286 true, true, [completionAction]); | |
| 287 return function() { | |
| 288 runAll.invoke(); | |
| 289 }; | |
| 290 }, | |
| 291 | |
| 176 }; | 292 }; |
| 177 | 293 |
| 178 /** | 294 /** |
| 179 * Registry of javascript-defined callbacks for {@code chrome.send}. | 295 * Registry of javascript-defined callbacks for {@code chrome.send}. |
| 180 * @type {Object} | 296 * @type {Object} |
| 181 **/ | 297 **/ |
| 182 var sendCallbacks = {}; | 298 var sendCallbacks = {}; |
| 183 | 299 |
| 184 /** | 300 /** |
| 185 * Registers the message, object and callback for {@code chrome.send} | 301 * Registers the message, object and callback for {@code chrome.send} |
| 186 * @param {string} name The name of the message to route to this |callback|. | 302 * @param {string} name The name of the message to route to this |callback|. |
| 187 * @param {Object} messageHAndler Pass as |this| when calling the |callback|. | 303 * @param {Object} messageHandler Pass as |this| when calling the |callback|. |
| 188 * @param {function(...)} callback Called by {@code chrome.send}. | 304 * @param {function(...)} callback Called by {@code chrome.send}. |
| 189 * @see sendCallbacks | 305 * @see sendCallbacks |
| 190 **/ | 306 **/ |
| 191 function registerMessageCallback(name, messageHandler, callback) { | 307 function registerMessageCallback(name, messageHandler, callback) { |
| 192 sendCallbacks[name] = [messageHandler, callback]; | 308 sendCallbacks[name] = [messageHandler, callback]; |
| 193 } | 309 } |
| 194 | 310 |
| 195 /** | 311 /** |
| 196 * Register all methods of {@code mockClass.prototype} with messages of the | 312 * Register all methods of {@code mockClass.prototype} with messages of the |
| 197 * same name as the method, using the proxy of the |mockObject| as the | 313 * same name as the method, using the proxy of the |mockObject| as the |
| 198 * |messageHandler| when registering. | 314 * |messageHandler| when registering. |
| 199 * @param {Mock4JS.Mock} mockObject The mock to register callbacks against. | 315 * @param {Mock4JS.Mock} mockObject The mock to register callbacks against. |
| 200 * @param {function(new:Object)} mockClAss Constructor for the mocked class. | 316 * @param {function(new:Object)} mockClAss Constructor for the mocked class. |
| 201 * @see registerMessageCallback | 317 * @see registerMessageCallback |
| 202 **/ | 318 **/ |
| 203 function registerMockMessageCallbacks(mockObject, mockClass) { | 319 function registerMockMessageCallbacks(mockObject, mockClass) { |
| 204 var mockProxy = mockObject.proxy(); | 320 var mockProxy = mockObject.proxy(); |
| 205 for (func in mockClass.prototype) { | 321 for (var func in mockClass.prototype) { |
| 206 if (typeof(mockClass.prototype[func]) == 'function') { | 322 if (typeof(mockClass.prototype[func]) == 'function') { |
| 207 registerMessageCallback(func, | 323 registerMessageCallback(func, mockProxy, mockProxy[func]); |
| 208 mockProxy, | |
| 209 mockProxy[func]); | |
| 210 } | 324 } |
| 211 } | 325 } |
| 212 } | 326 } |
| 327 | |
| 328 /** | |
| 329 * Holds the mapping of name -> global override information. | |
| 330 * @type {Object} | |
| 331 **/ | |
| 332 var globalOverrides = {}; | |
| 333 | |
| 334 /** | |
| 335 * Registers the global function name, object and callback. | |
| 336 * @param {string} name The name of the message to route to this |callback|. | |
| 337 * @param {Object} object Pass as |this| when calling the |callback|. | |
| 338 * @param {function(...)} callback Called by {@code chrome.send}. | |
| 339 **/ | |
| 340 function registerMockGlobal(name, object, callback) { | |
| 341 assertEquals(undefined, globalOverrides[name]); | |
| 342 globalOverrides[name] = { | |
| 343 object: object, | |
| 344 callback: callback, | |
| 345 }; | |
| 346 } | |
| 347 | |
| 348 /** | |
| 349 * Register all methods of {@code mockClass.prototype} as overrides to global | |
| 350 * functions of the same name as the method, using the proxy of the | |
| 351 * |mockObject| to handle the functions. | |
| 352 * @param {Mock4JS.Mock} mockObject The mock to register callbacks against. | |
| 353 * @param {function(new:Object)} mockClAss Constructor for the mocked class. | |
| 354 * @see registerMessageCallback | |
| 355 **/ | |
| 356 function registerMockGlobals(mockObject, mockClass) { | |
| 357 var mockProxy = mockObject.proxy(); | |
| 358 for (var func in mockClass.prototype) { | |
| 359 if (typeof(mockClass.prototype[func]) == 'function') { | |
|
arv (Not doing code reviews)
2011/08/22 20:57:18
typeof should not have parentheses
Sheridan Rawlins
2011/08/23 01:06:15
Done.
| |
| 360 registerMockGlobal(func, mockProxy, mockProxy[func]); | |
| 361 } | |
| 362 } | |
| 363 } | |
| 213 | 364 |
| 214 /** | 365 /** |
| 215 * Overrides {@code chrome.send} for routing messages to javascript | 366 * Overrides {@code chrome.send} for routing messages to javascript |
| 216 * functions. Also falls back to sending with the original chrome object. | 367 * functions. Also falls back to sending with the original chrome object. |
| 217 * @param {string} messageName The message to route. | 368 * @param {string} messageName The message to route. |
| 218 **/ | 369 **/ |
| 219 function send(messageName) { | 370 function send(messageName) { |
| 220 var callback = sendCallbacks[messageName]; | 371 var callback = sendCallbacks[messageName]; |
| 221 if (callback != undefined) | 372 if (callback != undefined) |
| 222 callback[1].apply(callback[0], Array.prototype.slice.call(arguments, 1)); | 373 callback[1].apply(callback[0], Array.prototype.slice.call(arguments, 1)); |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 341 } | 492 } |
| 342 | 493 |
| 343 /** | 494 /** |
| 344 * Notifies the running browser test of the test results. Clears |errors|. | 495 * Notifies the running browser test of the test results. Clears |errors|. |
| 345 * @param {Array.<boolean, string>=} result When passed, this is used for the | 496 * @param {Array.<boolean, string>=} result When passed, this is used for the |
| 346 * testResult message. | 497 * testResult message. |
| 347 **/ | 498 **/ |
| 348 function testDone(result) { | 499 function testDone(result) { |
| 349 if (!testIsDone) { | 500 if (!testIsDone) { |
| 350 testIsDone = true; | 501 testIsDone = true; |
| 502 if (currentTestCase) { | |
| 503 currentTestCase.TearDown(); | |
| 504 currentTestCase = null; | |
| 505 } | |
| 351 chrome.send('testResult', result ? result : testResult()); | 506 chrome.send('testResult', result ? result : testResult()); |
| 352 errors.splice(0, errors.length); | 507 errors.splice(0, errors.length); |
| 353 } else { | 508 } else { |
| 354 console.warn('testIsDone already'); | 509 console.warn('testIsDone already'); |
| 355 } | 510 } |
| 356 } | 511 } |
| 357 | 512 |
| 358 /** | 513 /** |
| 359 * Returns [success, message] & clears |errors|. | 514 * Returns [success, message] & clears |errors|. |
| 360 * @return {Array.<boolean, string>} | 515 * @return {Array.<boolean, string>} |
| (...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 609 * @param {string} testName The test name. | 764 * @param {string} testName The test name. |
| 610 * @see sendCallbacks | 765 * @see sendCallbacks |
| 611 **/ | 766 **/ |
| 612 function preloadJavascriptLibraries(testFixture, testName) { | 767 function preloadJavascriptLibraries(testFixture, testName) { |
| 613 window.addEventListener('DOMContentLoaded', function() { | 768 window.addEventListener('DOMContentLoaded', function() { |
| 614 var oldChrome = chrome; | 769 var oldChrome = chrome; |
| 615 chrome = { | 770 chrome = { |
| 616 __proto__: oldChrome, | 771 __proto__: oldChrome, |
| 617 send: send, | 772 send: send, |
| 618 }; | 773 }; |
| 774 | |
| 775 // Override globals at load time so they will be defined. | |
| 776 for (var func in globalOverrides) { | |
| 777 assertNotEquals(undefined, this[func]); | |
| 778 var globalOverride = globalOverrides[func]; | |
| 779 assertNotEquals(undefined, globalOverride); | |
| 780 assertEquals(undefined, globalOverride.original); | |
| 781 globalOverride.original = this[func]; | |
| 782 this[func] = globalOverride.callback.bind(globalOverride.object); | |
| 783 } | |
| 619 }); | 784 }); |
| 620 currentTestCase = createTestCase(testFixture, testName); | 785 currentTestCase = createTestCase(testFixture, testName); |
| 621 currentTestCase.PreLoad(); | 786 currentTestCase.PreLoad(); |
| 622 } | 787 } |
| 623 | 788 |
| 624 /** | 789 /** |
| 625 * During generation phase, this outputs; do nothing at runtime. | 790 * During generation phase, this outputs; do nothing at runtime. |
| 626 **/ | 791 **/ |
| 627 function GEN() {} | 792 function GEN() {} |
| 628 | 793 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 669 * RunJavascriptTestF uses this as the |testFunction| when invoking | 834 * RunJavascriptTestF uses this as the |testFunction| when invoking |
| 670 * runTest. If |currentTestCase| is non-null at this point, verify that | 835 * runTest. If |currentTestCase| is non-null at this point, verify that |
| 671 * |testFixture| and |testName| agree with the preloaded values. Create | 836 * |testFixture| and |testName| agree with the preloaded values. Create |
| 672 * |currentTestCase|, if needed, run it, and clear the |currentTestCase|. | 837 * |currentTestCase|, if needed, run it, and clear the |currentTestCase|. |
| 673 * @param {string} testFixture The name of the test fixture class. | 838 * @param {string} testFixture The name of the test fixture class. |
| 674 * @param {string} testName The name of the test function. | 839 * @param {string} testName The name of the test function. |
| 675 * @see preloadJavascriptLibraries | 840 * @see preloadJavascriptLibraries |
| 676 * @see runTest | 841 * @see runTest |
| 677 **/ | 842 **/ |
| 678 function RUN_TEST_F(testFixture, testName) { | 843 function RUN_TEST_F(testFixture, testName) { |
| 679 try { | 844 if (!currentTestCase) |
| 680 if (!currentTestCase) | 845 currentTestCase = createTestCase(testFixture, testName); |
| 681 currentTestCase = createTestCase(testFixture, testName); | 846 assertEquals(currentTestCase.name, testName); |
| 682 assertEquals(currentTestCase.name, testName); | 847 assertEquals(currentTestCase.fixture.name, testFixture); |
| 683 assertEquals(currentTestCase.fixture.name, testFixture); | 848 console.log('Running TestCase ' + testFixture + '.' + testName); |
| 684 console.log('Running TestCase ' + testFixture + '.' + testName); | 849 currentTestCase.Run(); |
| 685 currentTestCase.Run(); | 850 } |
| 686 } finally { | 851 |
| 687 currentTestCase = null; | 852 /** |
| 688 } | 853 * Matcher which pushes the |actualArgument| of argumentMatches() onto |
| 689 } | 854 * |arguments|, then proxies the return result to the |realMatcher|. Because |
| 690 | 855 * |realMatcher| can be any type, this constructor overrides argumentMatches, |
| 691 /** | 856 * then forces |this| to be an instance of |realMatcher|. |
|
mmenke
2011/08/22 16:26:44
You're defining a class in terms of one of its met
Sheridan Rawlins
2011/08/23 01:06:15
I rewrote this with composition instead of hacky i
| |
| 692 * CallFunctionAction is provided to allow mocks to have side effects. | 857 * @param {Array} arguments The arguments to push |actualArgument| onto. |
| 693 * @param {Function} func The function to call. | 858 * @param {Object} realMatcher The real matcher check arguments with. |
| 694 * @param {Array} args Any arguments to pass to func. | 859 * @constructor |
| 695 * @constructor | 860 * @extends {realMatcher} |
|
arv (Not doing code reviews)
2011/08/22 20:57:18
This annotation is a bit strange
Sheridan Rawlins
2011/08/23 01:06:15
See new version.
On 2011/08/22 20:57:18, arv wrot
| |
| 696 **/ | 861 **/ |
| 697 function CallFunctionAction(func, args) { | 862 function SaveArgumentMatcher(arguments, realMatcher) { |
| 698 this._func = func; | 863 this.arguments_ = arguments; |
| 699 this._args = args; | 864 this.argumentMatches = this.argumentMatches; |
|
mmenke
2011/08/22 16:26:44
?
Sheridan Rawlins
2011/08/23 01:06:15
Yeah, this was weird - it could have been this.arg
| |
| 700 } | 865 this.__proto__ = realMatcher; |
|
arv (Not doing code reviews)
2011/08/22 20:57:18
This seems a bit hacky. How about?
var obj = Obje
Sheridan Rawlins
2011/08/23 01:06:15
See new version with composition instead of the ha
| |
| 701 | 866 } |
| 702 CallFunctionAction.prototype = { | 867 |
| 703 invoke: function() { | 868 SaveArgumentMatcher.prototype = { |
| 704 return this._func.apply(null, this._args); | 869 /** |
| 705 }, | 870 * Holds the arguments to push each |actualArgument| onto. |
| 706 describe: function() { | 871 * @type {Array} |
| 707 return 'calls the given function with arguments ' + this._args; | 872 * @private |
| 708 } | 873 **/ |
| 709 }; | 874 arguments_: null, |
| 710 | 875 |
| 711 /** | 876 /** |
| 712 * Syntactic sugar for will() on a Mock4JS.Mock. | 877 * Pushes |actualArgument| onto |arguments_| for later use. Clears |
| 713 * @param {Function} func the function to call when the method is invoked. | 878 * |arguments_| on non-match. |
| 714 * @param {...*} var_args arguments to pass when calling func. | 879 * @param {*} actualArgument The argument to match and save. |
| 715 **/ | 880 * @return {boolean} value of calling the |realMatcher|. |
| 716 function callFunction(func) { | 881 * @override |
| 717 return new CallFunctionAction(func, | 882 **/ |
| 718 Array.prototype.slice.call(arguments, 1)); | 883 argumentMatches: function(actualArgument) { |
| 719 } | 884 this.arguments_.push(actualArgument); |
| 885 var match = this.__proto__.argumentMatches(actualArgument); | |
| 886 if (!match) | |
| 887 this.arguments_.splice(0, this.arguments_.length); | |
| 888 | |
| 889 return match; | |
| 890 }, | |
| 891 }; | |
| 720 | 892 |
| 721 /** | 893 /** |
| 722 * Allow mock stubs() and expects() to know what arguments were passed to the | 894 * Allow mock stubs() and expects() to know what arguments were passed to the |
| 723 * |realMatcher|. | 895 * |realMatcher|. |
|
mmenke
2011/08/22 16:26:44
This isn't terribly illuminating for someone tryin
Sheridan Rawlins
2011/08/23 01:06:15
OK. Added more context to comments.
On 2011/08/2
| |
| 724 * @param {!Object} realMatcher The real matcher to perform matching with. | 896 * @param {!Object} realMatcher The real matcher to perform matching with. |
| 725 * @constructor | 897 * @constructor |
| 726 **/ | 898 **/ |
| 727 function SaveArgumentsMatcher(realMatcher) { | 899 function SaveMockArguments() { |
| 728 this.realMatcher_ = realMatcher; | 900 this.arguments = []; |
| 729 } | 901 } |
| 730 | 902 |
| 731 SaveArgumentsMatcher.prototype = { | 903 SaveMockArguments.prototype = { |
| 904 /** | |
| 905 * Wraps the |realMatcher| with an object which will push its argument onto | |
| 906 * |arguments| and call realMatcher. | |
| 907 * @param {Object} realMatcher A Mock4JS matcher object for this argument. | |
| 908 * @return {SaveArgumentMatcher} A new matcher which will push its argument | |
| 909 * onto |arguments|. | |
| 910 **/ | |
| 911 match: function(realMatcher) { | |
| 912 return new SaveArgumentMatcher(this.arguments, realMatcher); | |
| 913 }, | |
| 914 | |
| 732 /** | 915 /** |
| 733 * Remember the argument passed to this stub invocation. | 916 * Remember the argument passed to this stub invocation. |
| 734 * @type {*} | 917 * @type {Array} |
| 735 **/ | 918 **/ |
| 736 argument: undefined, | 919 arguments: null, |
| 737 | 920 }; |
| 738 /** | 921 |
| 739 * @type {Object} the object performing the real match. | 922 /** |
| 740 * @private | 923 * CallFunctionAction is provided to allow mocks to have side effects. |
| 741 */ | 924 * @param {Object} obj The object to set |this| to when calling |func_|. |
| 742 realMatcher_: null, | 925 * @param {?SaveMockArguments} savedArgs when non-null, saved arguments are |
| 743 | 926 * passed to |func|. |
| 744 /** | 927 * @param {Function} func The function to call. |
| 745 * Saves |actualArgument| for later use by the mock stub or expect. | 928 * @param {Array} args Any arguments to pass to func. |
| 746 * @param {*} actualArgument The argument to match and save. | 929 * @constructor |
| 747 * @return {boolean} value of calling the |realMatcher_|. | 930 **/ |
| 748 **/ | 931 function CallFunctionAction(obj, savedArgs, func, args) { |
| 749 argumentMatches: function(actualArgument) { | 932 this.obj_ = obj; |
| 750 this.argument = actualArgument; | 933 this.savedArgs_ = savedArgs; |
| 751 return this.realMatcher_.argumentMatches.call(this.realMatcher_, | 934 this.func_ = func; |
| 752 actualArgument); | 935 this.args_ = args; |
| 753 }, | 936 } |
| 754 | 937 |
| 755 /** | 938 CallFunctionAction.prototype = { |
| 756 * Generic description for this Matcher object. | 939 /** |
| 757 * @return {string} description of the matcher for this argument. | 940 * Set |this| to |obj_| when calling |func_|. |
| 941 * @type {?Object} | |
| 942 **/ | |
| 943 obj_: null, | |
| 944 | |
| 945 /** | |
| 946 * The SaveMockArguments to hold arguments when invoking |func_|. | |
| 947 * @type {?SaveMockArguments} | |
| 948 * @private | |
| 949 **/ | |
| 950 savedArgs_: null, | |
| 951 | |
| 952 /** | |
| 953 * The function to call when invoked. | |
| 954 * @type {!Function} | |
| 955 * @private | |
| 956 **/ | |
| 957 func_: null, | |
| 958 | |
| 959 /** | |
| 960 * Arguments to pass to |func_| when invoked. | |
| 961 * @type {!Array} | |
| 962 **/ | |
| 963 args_: null, | |
| 964 | |
| 965 /** | |
| 966 * Accessor for |func_|. | |
| 967 * @return {Function} The function to invoke. | |
| 968 **/ | |
| 969 get func() { | |
| 970 return this.func_; | |
| 971 }, | |
| 972 | |
| 973 /** | |
| 974 * Called by Mock4JS when using .will() to specify actions for stubs() or | |
| 975 * expects(). Clears |savedArgs_| so it can be reused. | |
| 976 * @return The results of calling |func_| with the concatenation of | |
| 977 * |savedArgs_| and |args_|. | |
| 978 **/ | |
| 979 invoke: function() { | |
| 980 var prependArgs = []; | |
| 981 if (this.savedArgs_) { | |
| 982 prependArgs = this.savedArgs_.arguments.splice( | |
| 983 0, this.savedArgs_.arguments.length); | |
| 984 } | |
| 985 return this.func.apply(this.obj_, prependArgs.concat(this.args_)); | |
| 986 }, | |
| 987 | |
| 988 /** | |
| 989 * Describe this action to Mock4JS. | |
| 990 * @return {string} A description of this action. | |
| 758 **/ | 991 **/ |
| 759 describe: function() { | 992 describe: function() { |
| 760 return 'SaveArguments(' + | 993 return 'calls the given function with saved arguments and ' + this.args_; |
| 761 this.realMatcher_.describe.call(this.realMatcher_) + ')'; | 994 } |
| 762 }, | 995 }; |
| 763 }; | 996 |
| 997 /** | |
| 998 * Syntactic sugar for will() on a Mock4JS.Mock. | |
|
mmenke
2011/08/22 16:26:44
nit: "for use with" make it clearer that this sho
Sheridan Rawlins
2011/08/23 01:06:15
Done.
| |
| 999 * @param {Function} func The function to call when the method is invoked. | |
| 1000 * @param {...*} var_args Arguments to pass when calling func. | |
| 1001 * @return {CallFunctionAction} Action for use in will. | |
| 1002 **/ | |
| 1003 function callFunction(func) { | |
| 1004 return new CallFunctionAction( | |
| 1005 null, null, func, Array.prototype.slice.call(arguments, 1)); | |
| 1006 } | |
| 1007 | |
| 1008 /** | |
| 1009 * Syntactic sugar for will() on a Mock4JS.Mock. | |
|
mmenke
2011/08/22 16:26:44
nit: "for use with"
Sheridan Rawlins
2011/08/23 01:06:15
Done.
| |
| 1010 * @param {SaveMockArguments} savedArgs Arguments saved with this object | |
| 1011 * are passed to |func|. | |
| 1012 * @param {Function} func The function to call when the method is invoked. | |
| 1013 * @param {...*} var_args Arguments to pass when calling func. | |
| 1014 * @return {CallFunctionAction} Action for use in will. | |
| 1015 **/ | |
| 1016 function callFunctionWithSavedArgs(savedArgs, func) { | |
| 1017 return new CallFunctionAction( | |
| 1018 null, savedArgs, func, Array.prototype.slice.call(arguments, 2)); | |
| 1019 } | |
| 1020 | |
| 1021 /** | |
| 1022 * CallGlobalAction is provided to help override global function with mocking | |
| 1023 * expectations and still call the global function. | |
|
mmenke
2011/08/22 16:26:44
nit: Say what it does, not just why it exists.
Sheridan Rawlins
2011/08/23 01:06:15
Done.
| |
| 1024 * @param {?SaveMockArguments} savedArgs when non-null, saved arguments are | |
| 1025 * passed to the global function |funcName|. | |
| 1026 * @param {Function} funcName The name of the global function to call. | |
| 1027 * @param {Array} args Any arguments to pass to func. | |
| 1028 * @constructor | |
| 1029 * @extends {CallFunctionAction} | |
| 1030 * @see globalOverrides | |
| 1031 **/ | |
| 1032 function CallGlobalAction(savedArgs, funcName, args) { | |
| 1033 CallFunctionAction.call(this, null, savedArgs, funcName, args); | |
| 1034 } | |
| 1035 | |
| 1036 CallGlobalAction.prototype = { | |
| 1037 __proto__: CallFunctionAction.prototype, | |
| 1038 | |
| 1039 /** | |
| 1040 * Fetch and return the original global function to call. | |
| 1041 * @return {Function} The global function to invoke. | |
| 1042 * @override | |
| 1043 **/ | |
| 1044 get func() { | |
| 1045 var func = globalOverrides[this.func_].original; | |
| 1046 assertNotEquals(undefined, func); | |
| 1047 return func; | |
| 1048 }, | |
| 1049 }; | |
| 1050 | |
| 1051 /** | |
| 1052 * Syntactic sugar for will() on a Mock4JS.Mock. | |
|
mmenke
2011/08/22 16:26:44
nit: For use with.
Sheridan Rawlins
2011/08/23 01:06:15
Done.
| |
| 1053 * @param {SaveMockArguments} savedArgs Arguments saved with this object | |
| 1054 * are passed to the global function |funcName|. | |
| 1055 * @param {Function} funcName The name of the global function to call when the | |
| 1056 * method is invoked. | |
|
mmenke
2011/08/22 16:26:44
nit: Name of a registered mock global function.
Sheridan Rawlins
2011/08/23 01:06:15
Done.
| |
| 1057 * @param {...*} var_args Arguments to pass when calling func. | |
| 1058 * @return {CallGlobalAction} Action for use in will. | |
| 1059 **/ | |
| 1060 function callGlobalWithSavedArgs(savedArgs, funcName) { | |
| 1061 return new CallGlobalAction( | |
| 1062 savedArgs, funcName, Array.prototype.slice.call(arguments, 2)); | |
| 1063 } | |
| 1064 | |
| 1065 /** | |
| 1066 * Runs all |actions|. | |
| 1067 * @param {boolean} isAsync When true, call testDone() on Errors. | |
| 1068 * @param {boolean} alwaysDone When true, always call testDone(). | |
| 1069 * @param {Array.<Object>} actions Actions to run. | |
| 1070 * @constructor | |
| 1071 **/ | |
| 1072 function RunAllAction(isAsync, alwaysDone, actions) { | |
| 1073 this.isAsync_ = isAsync; | |
| 1074 this.alwaysDone_ = alwaysDone; | |
| 1075 this.actions_ = actions; | |
| 1076 } | |
| 1077 | |
| 1078 RunAllAction.prototype = { | |
| 1079 /** | |
| 1080 * When true, call testDone() on Errors. | |
| 1081 * @type {boolean} | |
| 1082 * @private | |
| 1083 **/ | |
| 1084 isAsync_: false, | |
| 1085 | |
| 1086 /** | |
| 1087 * When true, always call testDone(). | |
| 1088 * @type {boolean} | |
| 1089 * @private | |
| 1090 **/ | |
| 1091 alwaysDone_: false, | |
| 1092 | |
| 1093 /** | |
| 1094 * Holds the actions to execute when invoked. | |
| 1095 * @type {Array} | |
| 1096 * @private | |
| 1097 **/ | |
| 1098 actions_: null, | |
| 1099 | |
| 1100 /** | |
| 1101 * Runs all |actions_|, returning the last one. | |
| 1102 **/ | |
| 1103 invoke: function() { | |
| 1104 try { | |
| 1105 var result; | |
| 1106 for(var i = 0; i < this.actions_.length; ++i) { | |
| 1107 result = this.actions_[i].invoke.apply( | |
| 1108 this.actions_[i], Array.prototype.slice.call(arguments)); | |
| 1109 } | |
| 1110 if (this.alwaysDone_) | |
| 1111 testDone(); | |
| 1112 | |
| 1113 return result; | |
| 1114 } catch (e) { | |
| 1115 if (!this.isAsync_) | |
| 1116 throw e; | |
| 1117 | |
| 1118 errors.push(e); | |
| 1119 testDone(); | |
|
mmenke
2011/08/22 16:26:44
You should also call testDone on expect failures,
Sheridan Rawlins
2011/08/23 01:06:15
I don't think so. There should be a distinction be
mmenke
2011/08/23 01:36:09
Then should probably add a way to tell if there's
Sheridan Rawlins
2011/08/23 05:52:18
Ok. I added a whenTestDone enum to describe when
mmenke
2011/08/23 15:26:29
Seems reasonable to me.
| |
| 1120 } | |
| 1121 }, | |
| 1122 | |
| 1123 /** | |
| 1124 * Describe this action to Mock4JS. | |
| 1125 * @return {string} A description of this action. | |
| 1126 **/ | |
| 1127 describe: function() { | |
| 1128 return 'Calls all actions: ' + this.actions_; | |
| 1129 }, | |
| 1130 }; | |
| 1131 | |
| 1132 /** | |
| 1133 * Syntactic sugar for will() on a Mock4JS.Mock. | |
| 1134 * @param {...Object} var_actions Actions to run. | |
| 1135 * @return {RunAllAction} Action for use in will. | |
| 1136 **/ | |
| 1137 function runAllActions() { | |
| 1138 return new RunAllAction(false, false, | |
| 1139 Array.prototype.slice.call(arguments)); | |
| 1140 } | |
| 1141 | |
| 1142 /** | |
| 1143 * Syntactic sugar for will() on a Mock4JS.Mock. | |
| 1144 * @param {boolean} alwaysDone When true, always call testDone() otherwise, | |
| 1145 * call it only when Errors are thrown (from asserts). | |
| 1146 * @return {RunAllAction} Action for use in will. | |
| 1147 **/ | |
| 1148 function runAllActionsAsync(alwaysDone) { | |
| 1149 return new RunAllAction(true, alwaysDone, | |
| 1150 Array.prototype.slice.call(arguments)); | |
| 1151 } | |
| 764 | 1152 |
| 765 // Exports. | 1153 // Exports. |
| 766 testing.Test = Test; | 1154 testing.Test = Test; |
| 767 window.testDone = testDone; | 1155 window.testDone = testDone; |
| 768 window.assertTrue = assertTrue; | 1156 window.assertTrue = assertTrue; |
| 769 window.assertFalse = assertFalse; | 1157 window.assertFalse = assertFalse; |
| 770 window.assertGE = assertGE; | 1158 window.assertGE = assertGE; |
| 771 window.assertGT = assertGT; | 1159 window.assertGT = assertGT; |
| 772 window.assertEquals = assertEquals; | 1160 window.assertEquals = assertEquals; |
| 773 window.assertLE = assertLE; | 1161 window.assertLE = assertLE; |
| 774 window.assertLT = assertLT; | 1162 window.assertLT = assertLT; |
| 775 window.assertNotEquals = assertNotEquals; | 1163 window.assertNotEquals = assertNotEquals; |
| 776 window.assertNotReached = assertNotReached; | 1164 window.assertNotReached = assertNotReached; |
| 777 window.callFunction = callFunction; | 1165 window.callFunction = callFunction; |
| 1166 window.callFunctionWithSavedArgs = callFunctionWithSavedArgs; | |
| 1167 window.callGlobalWithSavedArgs = callGlobalWithSavedArgs; | |
| 778 window.expectTrue = createExpect(assertTrue); | 1168 window.expectTrue = createExpect(assertTrue); |
| 779 window.expectFalse = createExpect(assertFalse); | 1169 window.expectFalse = createExpect(assertFalse); |
| 780 window.expectGE = createExpect(assertGE); | 1170 window.expectGE = createExpect(assertGE); |
| 781 window.expectGT = createExpect(assertGT); | 1171 window.expectGT = createExpect(assertGT); |
| 782 window.expectEquals = createExpect(assertEquals); | 1172 window.expectEquals = createExpect(assertEquals); |
| 783 window.expectLE = createExpect(assertLE); | 1173 window.expectLE = createExpect(assertLE); |
| 784 window.expectLT = createExpect(assertLT); | 1174 window.expectLT = createExpect(assertLT); |
| 785 window.expectNotEquals = createExpect(assertNotEquals); | 1175 window.expectNotEquals = createExpect(assertNotEquals); |
| 786 window.expectNotReached = createExpect(assertNotReached); | 1176 window.expectNotReached = createExpect(assertNotReached); |
| 787 window.preloadJavascriptLibraries = preloadJavascriptLibraries; | 1177 window.preloadJavascriptLibraries = preloadJavascriptLibraries; |
| 788 window.registerMessageCallback = registerMessageCallback; | 1178 window.registerMessageCallback = registerMessageCallback; |
| 1179 window.registerMockGlobals = registerMockGlobals; | |
| 789 window.registerMockMessageCallbacks = registerMockMessageCallbacks; | 1180 window.registerMockMessageCallbacks = registerMockMessageCallbacks; |
| 790 window.resetTestState = resetTestState; | 1181 window.resetTestState = resetTestState; |
| 1182 window.runAllActions = runAllActions; | |
| 1183 window.runAllActionsAsync = runAllActionsAsync; | |
| 791 window.runTest = runTest; | 1184 window.runTest = runTest; |
| 792 window.runTestFunction = runTestFunction; | 1185 window.runTestFunction = runTestFunction; |
| 793 window.SaveArgumentsMatcher = SaveArgumentsMatcher; | 1186 window.SaveMockArguments = SaveMockArguments; |
| 794 window.TEST = TEST; | 1187 window.TEST = TEST; |
| 795 window.TEST_F = TEST_F; | 1188 window.TEST_F = TEST_F; |
| 796 window.GEN = GEN; | 1189 window.GEN = GEN; |
| 797 | 1190 |
| 798 // Import the Mock4JS helpers. | 1191 // Import the Mock4JS helpers. |
| 799 Mock4JS.addMockSupport(window); | 1192 Mock4JS.addMockSupport(window); |
| 800 })(); | 1193 })(); |
| OLD | NEW |