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 // Library providing basic test framework functionality. | 5 // Library providing basic test framework functionality. |
6 | 6 |
| 7 var testing = {}; |
| 8 var currentTest = null; |
| 9 var currentTestCase = null; |
| 10 |
7 (function() { | 11 (function() { |
| 12 // Provide global objects for generation case. |
| 13 if (!('window' in this)) |
| 14 this['window'] = this; |
| 15 if (!('chrome' in this)) { |
| 16 this['chrome'] = { |
| 17 'send': function() {}, |
| 18 }; |
| 19 } |
| 20 if (!('console' in this)) { |
| 21 this['console'] = { |
| 22 'log': print, |
| 23 }; |
| 24 } |
| 25 |
| 26 /** |
| 27 * This class will be exported as testing.Test, and is provided to hold the |
| 28 * fixture's configuration and callback methods for the various phases of |
| 29 * invoking a test. It is called "Test" rather than TestFixture to roughly |
| 30 * mimic the gtest's class names. |
| 31 * @constructor |
| 32 **/ |
| 33 function Test() {} |
| 34 |
| 35 Test.prototype = { |
| 36 /** |
| 37 * The name of the test. |
| 38 **/ |
| 39 'name': null, |
| 40 |
| 41 /** |
| 42 * When set to a string value representing a url, generate BrowsePreload |
| 43 * call, which will browse to the url and call fixture.PreLoad of the |
| 44 * currentTestCase. |
| 45 * @type {String} |
| 46 **/ |
| 47 'browsePreload': null, |
| 48 |
| 49 /** |
| 50 * When set to a string value representing an html page in the test |
| 51 * directory, generate BrowsePrintPreload call, which will browse to a url |
| 52 * representing the file, cause print, and call fixture.PreLoad of the |
| 53 * currentTestCase. |
| 54 * @type {String} |
| 55 **/ |
| 56 'browsePrintPreload': null, |
| 57 |
| 58 /** |
| 59 * This should be initialized by the test fixture and can be referenced |
| 60 * during the test run. |
| 61 * @type {Mock4JS.Mock} |
| 62 **/ |
| 63 'mockHandler': null, |
| 64 |
| 65 /** |
| 66 * Override this method to perform initialization during preload (such as |
| 67 * creating mocks and registering handlers). |
| 68 * @type {Function} |
| 69 **/ |
| 70 'PreLoad': function() {}, |
| 71 |
| 72 /** |
| 73 * Override this method to perform tasks before running your test. |
| 74 * @type {Function} |
| 75 **/ |
| 76 'SetUp': function() {}, |
| 77 |
| 78 /** |
| 79 * Override this method to perform tasks after running your test. If you |
| 80 * create a mock class, you must call Mock4JS.verifyAllMocks() in this |
| 81 * phase. |
| 82 * @type {Function} |
| 83 **/ |
| 84 'TearDown': function() { |
| 85 Mock4JS.verifyAllMocks(); |
| 86 } |
| 87 }; |
| 88 |
| 89 /** |
| 90 * This class is not exported and is available to hold the state of the |
| 91 * |currentTestCase| throughout preload and test run. |
| 92 * @param {String} name the name of the test case. |
| 93 * @param {Test} fixture the fixture object for this test case. |
| 94 * @param {Function} body the code to run for the test. |
| 95 * @constructor |
| 96 **/ |
| 97 function TestCase(name, fixture, body) { |
| 98 this.name = name; |
| 99 this.fixture = fixture; |
| 100 this.body = body; |
| 101 } |
| 102 |
| 103 TestCase.prototype = { |
| 104 /** |
| 105 * The name of this test case. |
| 106 * @type {String} |
| 107 **/ |
| 108 'name': null, |
| 109 |
| 110 /** |
| 111 * The fixture of this test case. |
| 112 * @type {Test} |
| 113 **/ |
| 114 'fixture': null, |
| 115 |
| 116 /** |
| 117 * The code to call when running this test case. |
| 118 * @type {Function} |
| 119 **/ |
| 120 'body': null, |
| 121 |
| 122 /** |
| 123 * Called at preload time, proxies to the fixture. |
| 124 * @type {Function} |
| 125 **/ |
| 126 'PreLoad': function(name) { |
| 127 if (this.fixture) |
| 128 this.fixture.PreLoad(); |
| 129 }, |
| 130 |
| 131 /** |
| 132 * Runs this test case. |
| 133 * @type {Function} |
| 134 **/ |
| 135 'Run': function() { |
| 136 if (this.fixture) |
| 137 this.fixture.SetUp(); |
| 138 if (this.body) |
| 139 this.body.call(this.fixture); |
| 140 if (this.fixture) |
| 141 this.fixture.TearDown(); |
| 142 }, |
| 143 }; |
| 144 |
8 // Asserts. | 145 // Asserts. |
9 // Use the following assertions to verify a condition within a test. | 146 // Use the following assertions to verify a condition within a test. |
10 // If assertion fails, the C++ backend will be immediately notified. | 147 // If assertion fails, the C++ backend will be immediately notified. |
11 // If assertion passes, no notification will be sent to the C++ backend. | 148 // If assertion passes, no notification will be sent to the C++ backend. |
12 function assertBool(test, expected, message) { | 149 function assertBool(test, expected, message) { |
13 if (test !== expected) { | 150 if (test !== expected) { |
14 if (message) | 151 if (message) |
15 message = test + '\n' + message; | 152 message = test + '\n' + message; |
16 else | 153 else |
17 message = test; | 154 message = test; |
18 throw new Error(message); | 155 throw new Error(message); |
19 } | 156 } |
20 } | 157 } |
21 | 158 |
22 var old_chrome = chrome; | 159 var oldChrome = chrome; |
23 var send_callbacks = {}; | 160 var sendCallbacks = {}; |
24 | 161 |
25 function registerMessageCallback(name, object, callback) { | 162 function registerMessageCallback(name, object, callback) { |
26 send_callbacks[name] = [object, callback]; | 163 sendCallbacks[name] = [object, callback]; |
27 } | 164 } |
28 | 165 |
| 166 function registerMockMessageCallbacks(mockObject, mockClass) { |
| 167 var mockProxy = mockObject.proxy(); |
| 168 for (func in mockClass.prototype) { |
| 169 if (typeof(mockClass.prototype[func]) == 'function') { |
| 170 registerMessageCallback(func, |
| 171 mockProxy, |
| 172 mockProxy[func]); |
| 173 } |
| 174 } |
| 175 } |
| 176 |
| 177 |
29 function send(messageName) { | 178 function send(messageName) { |
30 var callback = send_callbacks[messageName]; | 179 var callback = sendCallbacks[messageName]; |
31 var args = Array.prototype.slice.call(arguments, 1); | 180 var args = Array.prototype.slice.call(arguments, 1); |
32 if (callback != undefined) | 181 if (callback != undefined) |
33 callback[1].apply(callback[0], args); | 182 callback[1].apply(callback[0], args); |
34 else | 183 else |
35 old_chrome.send.apply(old_chrome, args); | 184 oldChrome.send.apply(oldChrome, args); |
36 } | 185 } |
37 | 186 |
38 function assertTrue(test, message) { | 187 function assertTrue(test, message) { |
39 assertBool(test, true, message); | 188 assertBool(test, true, message); |
40 } | 189 } |
41 | 190 |
42 function assertFalse(test, message) { | 191 function assertFalse(test, message) { |
43 assertBool(test, false, message); | 192 assertBool(test, false, message); |
44 } | 193 } |
45 | 194 |
(...skipping 24 matching lines...) Expand all Loading... |
70 errors.push(e); | 219 errors.push(e); |
71 } | 220 } |
72 }; | 221 }; |
73 } | 222 } |
74 | 223 |
75 function runTest(testFunction, testArguments) { | 224 function runTest(testFunction, testArguments) { |
76 errors = []; | 225 errors = []; |
77 // Avoid eval() if at all possible, since it will not work on pages | 226 // Avoid eval() if at all possible, since it will not work on pages |
78 // that have enabled content-security-policy. | 227 // that have enabled content-security-policy. |
79 currentTest = this[testFunction]; // global object -- not a method. | 228 currentTest = this[testFunction]; // global object -- not a method. |
80 if (typeof currentTest === "undefined") { | 229 if (typeof currentTest === "undefined") |
81 currentTest = eval(testFunction); | 230 currentTest = eval(testFunction); |
82 } | 231 if (currentTest != RUN_TEST_F) |
83 console.log('Running test ' + currentTest.name); | 232 console.log('Running test ' + currentTest.name); |
84 createExpect(currentTest).apply(null, testArguments); | 233 createExpect(currentTest).apply(null, testArguments); |
| 234 currentTest = null; |
85 | 235 |
86 if (errors.length) { | 236 if (errors.length) { |
87 return [false, errors.join('\n')]; | 237 return [false, errors.join('\n')]; |
88 } | 238 } |
89 | 239 |
90 return [true]; | 240 return [true]; |
91 } | 241 } |
92 | 242 |
93 function preloadJavascriptLibraries(overload_chrome_send) { | 243 function preloadJavascriptLibraries(testFixtureName, testName) { |
94 if (overload_chrome_send) | 244 chrome = { |
95 chrome = { 'send': send }; | 245 '__proto__': oldChrome, |
| 246 'send': send, |
| 247 }; |
| 248 var testFixture = new this[testFixtureName](); |
| 249 testFixture.name = testFixtureName; |
| 250 var testBody = this[testName]; |
| 251 currentTestCase = new TestCase(testName, testFixture, testBody); |
| 252 currentTestCase.PreLoad(); |
| 253 } |
| 254 |
| 255 /** |
| 256 * During generation phase, this outputs; do nothing at runtime. |
| 257 **/ |
| 258 function GEN() { |
| 259 } |
| 260 |
| 261 /** |
| 262 * At runtime, register the testFunction as a global object. |
| 263 * @param {String} testFixture the name of the test fixture class. |
| 264 * @param {String} testFunction the name of the test function. |
| 265 * @param {Function} the body to execute when running this test. |
| 266 **/ |
| 267 function TEST(testFixture, testFunction, testBody) { |
| 268 testBody.testFunction = testFunction; |
| 269 window[testFunction] = testBody; |
| 270 } |
| 271 |
| 272 /** |
| 273 * At runtime, register the testFunction as a global object. |
| 274 * @param {String} testFixture the name of the test fixture class. |
| 275 * @param {String} testFunction the name of the test function. |
| 276 * @param {Function} the body to execute when running this test. |
| 277 **/ |
| 278 function TEST_F(testFixture, testFunction, testBody) { |
| 279 testBody.testFunction = testFunction; |
| 280 testBody.testFixture = testFixture; |
| 281 window[testFunction] = testBody; |
| 282 } |
| 283 |
| 284 /** |
| 285 * Called by RunJavascriptTestF to invoke the named testFixture & |
| 286 * testFunction. |
| 287 * @param {String} testFixture the name of the test fixture class. |
| 288 * @param {String} testFunction the name of the test function. |
| 289 **/ |
| 290 function RUN_TEST_F(testFixture, testFunction) { |
| 291 assertTrue(!!currentTestCase, 'currentTestCase'); |
| 292 assertEquals(currentTestCase.name, testFunction); |
| 293 assertEquals(currentTestCase.fixture.name, testFixture); |
| 294 console.log('Running Test fixture ' + testFixture + '.' + testFunction); |
| 295 currentTestCase.Run(); |
| 296 } |
| 297 |
| 298 /** |
| 299 * CallFunctionAction is provided to allow mocks to have side effects. |
| 300 * @param {Function} func the function to call. |
| 301 * @param {Array} args any arguments to pass to func. |
| 302 * @constructor |
| 303 **/ |
| 304 function CallFunctionAction(func, args) { |
| 305 this._func = func; |
| 306 this._args = args; |
| 307 } |
| 308 |
| 309 CallFunctionAction.prototype = { |
| 310 invoke: function() { |
| 311 return this._func.apply(null, this._args); |
| 312 }, |
| 313 describe: function() { |
| 314 return 'calls the given function with arguments ' + this._args; |
| 315 } |
| 316 }; |
| 317 |
| 318 /** |
| 319 * Syntactic sugar for will() on a Mock4JS.Mock. |
| 320 * @param {Function} func the function to call when the method is invoked. |
| 321 * @param {*} ... arguments to pass when calling func. |
| 322 **/ |
| 323 function callFunction(func) { |
| 324 return new CallFunctionAction(func, |
| 325 Array.prototype.slice.call(arguments, 1)); |
96 } | 326 } |
97 | 327 |
98 // Exports. | 328 // Exports. |
| 329 testing.Test = Test; |
99 window.assertTrue = assertTrue; | 330 window.assertTrue = assertTrue; |
100 window.assertFalse = assertFalse; | 331 window.assertFalse = assertFalse; |
101 window.assertEquals = assertEquals; | 332 window.assertEquals = assertEquals; |
102 window.assertNotReached = assertNotReached; | 333 window.assertNotReached = assertNotReached; |
| 334 window.callFunction = callFunction; |
103 window.expectTrue = createExpect(assertTrue); | 335 window.expectTrue = createExpect(assertTrue); |
104 window.expectFalse = createExpect(assertFalse); | 336 window.expectFalse = createExpect(assertFalse); |
105 window.expectEquals = createExpect(assertEquals); | 337 window.expectEquals = createExpect(assertEquals); |
106 window.expectNotReached = createExpect(assertNotReached); | 338 window.expectNotReached = createExpect(assertNotReached); |
107 window.registerMessageCallback = registerMessageCallback; | 339 window.registerMessageCallback = registerMessageCallback; |
| 340 window.registerMockMessageCallbacks = registerMockMessageCallbacks; |
108 window.runTest = runTest; | 341 window.runTest = runTest; |
109 window.preloadJavascriptLibraries = preloadJavascriptLibraries; | 342 window.preloadJavascriptLibraries = preloadJavascriptLibraries; |
| 343 window.TEST = TEST; |
| 344 window.TEST_F = TEST_F; |
| 345 window.GEN = GEN; |
| 346 |
| 347 // Import the Mock4JS helpers. |
| 348 Mock4JS.addMockSupport(window); |
110 })(); | 349 })(); |
OLD | NEW |