OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 Generator script for creating gtest-style JavaScript | 6 * @fileoverview Generator script for creating gtest-style JavaScript |
7 * tests for WebUI and unit tests. Generates C++ gtest wrappers | 7 * tests for WebUI and unit tests. Generates C++ gtest wrappers |
8 * which will invoke the appropriate JavaScript for each test. | 8 * which will invoke the appropriate JavaScript for each test. |
9 * @author scr@chromium.org (Sheridan Rawlins) | 9 * @author scr@chromium.org (Sheridan Rawlins) |
10 * @see WebUI testing: http://goo.gl/ZWFXF | 10 * @see WebUI testing: http://goo.gl/ZWFXF |
11 * @see gtest documentation: http://goo.gl/Ujj3H | 11 * @see gtest documentation: http://goo.gl/Ujj3H |
12 * @see chrome/chrome_tests.gypi | 12 * @see chrome/chrome_tests.gypi |
13 * @see tools/gypv8sh.py | 13 * @see tools/gypv8sh.py |
14 */ | 14 */ |
15 | 15 |
16 // Arguments from rules in chrome_tests.gypi are passed in through | 16 // Arguments from rules in chrome_tests.gypi are passed in through |
17 // python script gypv8sh.py. | 17 // python script gypv8sh.py. |
18 if (arguments.length < 4) { | 18 if (arguments.length != 6) { |
19 print('usage: ' + | 19 print('usage: ' + |
20 arguments[0] + ' path-to-testfile.js testfile.js output.cc test-type'); | 20 arguments[0] + |
| 21 ' path-to-testfile.js testfile.js path_to_deps.js output.cc test-type'); |
21 quit(-1); | 22 quit(-1); |
22 } | 23 } |
23 | 24 |
24 /** | 25 /** |
25 * Full path to the test input file. | 26 * Full path to the test input file. |
26 * @type {string} | 27 * @type {string} |
27 */ | 28 */ |
28 var jsFile = arguments[1]; | 29 var jsFile = arguments[1]; |
29 | 30 |
30 /** | 31 /** |
31 * Relative path to the test input file appropriate for use in the | 32 * Relative path to the test input file appropriate for use in the |
32 * C++ TestFixture's addLibrary method. | 33 * C++ TestFixture's addLibrary method. |
33 * @type {string} | 34 * @type {string} |
34 */ | 35 */ |
35 var jsFileBase = arguments[2]; | 36 var jsFileBase = arguments[2]; |
36 | 37 |
37 /** | 38 /** |
| 39 * Path to Closure library style deps.js file. |
| 40 * @type {string?} |
| 41 */ |
| 42 var depsFile = arguments[3]; |
| 43 |
| 44 /** |
38 * Path to C++ file generation is outputting to. | 45 * Path to C++ file generation is outputting to. |
39 * @type {string} | 46 * @type {string} |
40 */ | 47 */ |
41 var outputFile = arguments[3]; | 48 var outputFile = arguments[4]; |
42 | 49 |
43 /** | 50 /** |
44 * Type of this test. | 51 * Type of this test. |
45 * @type {string} ('unit'| 'webui') | 52 * @type {string} ('unit'| 'webui') |
46 */ | 53 */ |
47 var testType = arguments[4]; | 54 var testType = arguments[5]; |
48 | 55 |
49 /** | 56 /** |
50 * C++ gtest macro to use for TEST_F depending on |testType|. | 57 * C++ gtest macro to use for TEST_F depending on |testType|. |
51 * @type {string} ('TEST_F'|'IN_PROC_BROWSER_TEST_F') | 58 * @type {string} ('TEST_F'|'IN_PROC_BROWSER_TEST_F') |
52 */ | 59 */ |
53 var testF; | 60 var testF; |
54 | 61 |
55 /** | 62 /** |
56 * Keeps track of whether a typedef has been generated for each test | 63 * Keeps track of whether a typedef has been generated for each test |
57 * fixture. | 64 * fixture. |
(...skipping 26 matching lines...) Expand all Loading... |
84 // | 91 // |
85 // Currently supports: | 92 // Currently supports: |
86 // 'unit' - unit_tests harness, js2unit rule, V8UnitTest superclass. | 93 // 'unit' - unit_tests harness, js2unit rule, V8UnitTest superclass. |
87 // 'webui' - browser_tests harness, js2webui rule, WebUIBrowserTest superclass. | 94 // 'webui' - browser_tests harness, js2webui rule, WebUIBrowserTest superclass. |
88 if (testType === 'unit') { | 95 if (testType === 'unit') { |
89 print('#include "chrome/test/base/v8_unit_test.h"'); | 96 print('#include "chrome/test/base/v8_unit_test.h"'); |
90 testing.Test.prototype.typedefCppFixture = 'V8UnitTest'; | 97 testing.Test.prototype.typedefCppFixture = 'V8UnitTest'; |
91 testF = 'TEST_F'; | 98 testF = 'TEST_F'; |
92 addSetPreloadInfo = false; | 99 addSetPreloadInfo = false; |
93 } else { | 100 } else { |
94 print('#include "chrome/test/base/web_ui_browsertest.h"'); | 101 print('#include "chrome/test/base/web_ui_browser_test.h"'); |
95 testing.Test.prototype.typedefCppFixture = 'WebUIBrowserTest'; | 102 testing.Test.prototype.typedefCppFixture = 'WebUIBrowserTest'; |
96 testF = 'IN_PROC_BROWSER_TEST_F'; | 103 testF = 'IN_PROC_BROWSER_TEST_F'; |
97 addSetPreloadInfo = true; | 104 addSetPreloadInfo = true; |
98 } | 105 } |
99 print('#include "url/gurl.h"'); | 106 print('#include "url/gurl.h"'); |
100 print('#include "testing/gtest/include/gtest/gtest.h"'); | 107 print('#include "testing/gtest/include/gtest/gtest.h"'); |
101 print(); | 108 print(); |
102 | 109 |
103 /** | 110 /** |
104 * Convert the |includeFile| to paths appropriate for immediate | 111 * Convert the |includeFile| to paths appropriate for immediate |
105 * inclusion (path) and runtime inclusion (base). | 112 * inclusion (path) and runtime inclusion (base). |
106 * @param {string} includeFile The file to include. | 113 * @param {string} includeFile The file to include. |
107 * @return {{path: string, base: string}} Object describing the paths | 114 * @return {{path: string, base: string}} Object describing the paths |
108 * for |includeFile|. | 115 * for |includeFile|. |
109 */ | 116 */ |
110 function includeFileToPaths(includeFile) { | 117 function includeFileToPaths(includeFile) { |
111 return { | 118 return { |
112 path: jsFile.replace(/[^\/\\]+$/, includeFile), | 119 path: jsFile.replace(/[^\/\\]+$/, includeFile), |
113 base: jsFileBase.replace(/[^\/\\]+$/, includeFile), | 120 base: jsFileBase.replace(/[^\/\\]+$/, includeFile), |
114 }; | 121 }; |
115 } | 122 } |
116 | 123 |
| 124 |
| 125 /** |
| 126 * Maps object names to the path to the file that provides them. |
| 127 * Populated from the |depsFile| if any. |
| 128 * @type {Object.<string, string>} |
| 129 */ |
| 130 var dependencyProvidesToPaths = {}; |
| 131 |
| 132 /** |
| 133 * Maps dependency path names to object names required by the file. |
| 134 * Populated from the |depsFile| if any. |
| 135 * @type {Object.<string, Array.<string>>} |
| 136 */ |
| 137 var dependencyPathsToRequires = {}; |
| 138 |
| 139 if (depsFile) { |
| 140 var goog = goog || {}; |
| 141 /** |
| 142 * Called by the javascript in the deps file to add modules and their |
| 143 * dependencies. |
| 144 * @param {string} path Relative path to the file. |
| 145 * @param Array.<string> provides Objects provided by this file. |
| 146 * @param Array.<string> requires Objects required by this file. |
| 147 */ |
| 148 goog.addDependency = function(path, provides, requires) { |
| 149 provides.forEach(function(provide) { |
| 150 dependencyProvidesToPaths[provide] = path; |
| 151 }); |
| 152 dependencyPathsToRequires[path] = requires; |
| 153 }; |
| 154 |
| 155 // Read and eval the deps file. It should only contain goog.addDependency |
| 156 // calls. |
| 157 eval(read(depsFile)); |
| 158 } |
| 159 |
| 160 /** |
| 161 * Resolves a list of libraries to an ordered list of paths to load by the |
| 162 * generated C++. The input should contain object names provided |
| 163 * by the deps file. Dependencies will be resolved and included in the |
| 164 * correct order, meaning that the returned array may contain more entries |
| 165 * than the input. |
| 166 * @param {Array.<string>} deps List of dependencies. |
| 167 * @return {Array.<string>} List of paths to load. |
| 168 */ |
| 169 function resolveClosureModuleDeps(deps) { |
| 170 if (!depsFile && deps.length > 0) { |
| 171 print('Can\'t have closure dependencies without a deps file.'); |
| 172 quit(-1); |
| 173 } |
| 174 var resultPaths = []; |
| 175 var addedPaths = {}; |
| 176 |
| 177 function addPath(path) { |
| 178 addedPaths[path] = true; |
| 179 resultPaths.push(path); |
| 180 } |
| 181 |
| 182 function resolveAndAppend(path) { |
| 183 if (addedPaths[path]) { |
| 184 return; |
| 185 } |
| 186 // Set before recursing to catch cycles. |
| 187 addedPaths[path] = true; |
| 188 dependencyPathsToRequires[path].forEach(function(require) { |
| 189 var providingPath = dependencyProvidesToPaths[require]; |
| 190 if (!providingPath) { |
| 191 print('Unknown object', require, 'required by', path); |
| 192 quit(-1); |
| 193 } |
| 194 resolveAndAppend(providingPath); |
| 195 }); |
| 196 resultPaths.push(path); |
| 197 } |
| 198 |
| 199 // Always add closure library's base.js if provided by deps. |
| 200 var basePath = dependencyProvidesToPaths['goog']; |
| 201 if (basePath) { |
| 202 addPath(basePath); |
| 203 } |
| 204 |
| 205 deps.forEach(function(dep) { |
| 206 var providingPath = dependencyProvidesToPaths[dep]; |
| 207 if (providingPath) { |
| 208 resolveAndAppend(providingPath); |
| 209 } else { |
| 210 print('Unknown dependency:', dep); |
| 211 quit(-1); |
| 212 } |
| 213 }); |
| 214 |
| 215 return resultPaths; |
| 216 } |
| 217 |
117 /** | 218 /** |
118 * Output |code| verbatim. | 219 * Output |code| verbatim. |
119 * @param {string} code The code to output. | 220 * @param {string} code The code to output. |
120 */ | 221 */ |
121 function GEN(code) { | 222 function GEN(code) { |
122 print(code); | 223 print(code); |
123 } | 224 } |
124 | 225 |
125 /** | 226 /** |
126 * Generate includes for the current |jsFile| by including them | 227 * Generate includes for the current |jsFile| by including them |
(...skipping 24 matching lines...) Expand all Loading... |
151 var testGenPostamble = this[testFixture].prototype.testGenPostamble; | 252 var testGenPostamble = this[testFixture].prototype.testGenPostamble; |
152 var typedefCppFixture = this[testFixture].prototype.typedefCppFixture; | 253 var typedefCppFixture = this[testFixture].prototype.typedefCppFixture; |
153 var isAsyncParam = testType === 'unit' ? '' : | 254 var isAsyncParam = testType === 'unit' ? '' : |
154 this[testFixture].prototype.isAsync + ', '; | 255 this[testFixture].prototype.isAsync + ', '; |
155 var testShouldFail = this[testFixture].prototype.testShouldFail; | 256 var testShouldFail = this[testFixture].prototype.testShouldFail; |
156 var testPredicate = testShouldFail ? 'ASSERT_FALSE' : 'ASSERT_TRUE'; | 257 var testPredicate = testShouldFail ? 'ASSERT_FALSE' : 'ASSERT_TRUE'; |
157 var extraLibraries = genIncludes.concat( | 258 var extraLibraries = genIncludes.concat( |
158 this[testFixture].prototype.extraLibraries.map( | 259 this[testFixture].prototype.extraLibraries.map( |
159 function(includeFile) { | 260 function(includeFile) { |
160 return includeFileToPaths(includeFile).base; | 261 return includeFileToPaths(includeFile).base; |
161 })); | 262 }), |
| 263 resolveClosureModuleDeps(this[testFixture].prototype.closureModuleDeps)); |
162 | 264 |
163 if (typedefCppFixture && !(testFixture in typedeffedCppFixtures)) { | 265 if (typedefCppFixture && !(testFixture in typedeffedCppFixtures)) { |
164 print('typedef ' + typedefCppFixture + ' ' + testFixture + ';'); | 266 print('typedef ' + typedefCppFixture + ' ' + testFixture + ';'); |
165 typedeffedCppFixtures[testFixture] = typedefCppFixture; | 267 typedeffedCppFixtures[testFixture] = typedefCppFixture; |
166 } | 268 } |
167 | 269 |
168 print(testF + '(' + testFixture + ', ' + testFunction + ') {'); | 270 print(testF + '(' + testFixture + ', ' + testFunction + ') {'); |
169 for (var i = 0; i < extraLibraries.length; i++) { | 271 for (var i = 0; i < extraLibraries.length; i++) { |
170 print(' AddLibrary(base::FilePath(FILE_PATH_LITERAL("' + | 272 print(' AddLibrary(base::FilePath(FILE_PATH_LITERAL("' + |
171 extraLibraries[i].replace(/\\/g, '/') + '")));'); | 273 extraLibraries[i].replace(/\\/g, '/') + '")));'); |
(...skipping 17 matching lines...) Expand all Loading... |
189 '"' + testFunction + '"));'); | 291 '"' + testFunction + '"));'); |
190 if (testGenPostamble) | 292 if (testGenPostamble) |
191 testGenPostamble(testFixture, testFunction); | 293 testGenPostamble(testFixture, testFunction); |
192 print('}'); | 294 print('}'); |
193 print(); | 295 print(); |
194 } | 296 } |
195 | 297 |
196 // Now that generation functions are defined, load in |jsFile|. | 298 // Now that generation functions are defined, load in |jsFile|. |
197 var js = read(jsFile); | 299 var js = read(jsFile); |
198 eval(js); | 300 eval(js); |
OLD | NEW |