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 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 namespace/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 * For each path included in the |depsFile|, if any, contains | |
134 * the list of object/namespace names required by the file. | |
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 can contain paths relative to the test script and, | |
163 * if a deps file was provided, namespace/object names provided by the | |
164 * deps file. For the latter case, dependencies will be resolved and | |
165 * included in the correct order, meaning that the returned array may contain | |
166 * more entries than the input. | |
167 * @param {Array.<string>} libraries List of libraries, either paths or | |
168 * namespace/object names if a deps file was provided. | |
169 * @return {Array.<string>} List of paths to load. | |
170 */ | |
171 function resolveLibraries(libraries) { | |
172 var resultPaths = []; | |
173 var addedPaths = {}; | |
174 | |
175 function addPath(path) { | |
176 addedPaths[path] = true; | |
177 resultPaths.push(path); | |
178 } | |
179 | |
180 function resolveAndAppend(path) { | |
181 if (addedPaths[path]) { | |
182 return; | |
183 } | |
184 // Set before recursing to catch cycles. | |
185 addedPaths[path] = true; | |
186 dependencyPathsToRequires[path].forEach(function(require) { | |
187 var providingPath = dependencyProvidesToPaths[require]; | |
188 if (!providingPath) { | |
189 print('Unknown object', require, 'required by', path); | |
190 quit(-1); | |
191 } | |
192 resolveAndAppend(providingPath); | |
193 }); | |
194 resultPaths.push(path); | |
195 } | |
196 | |
197 // Always add closure libaries base.js if provided by deps. | |
David Tseng
2014/05/30 17:08:46
libraries
| |
198 var basePath = dependencyProvidesToPaths['goog']; | |
199 if (basePath) { | |
200 addPath(basePath); | |
201 } | |
202 | |
203 libraries.forEach(function(library) { | |
204 var providingPath = dependencyProvidesToPaths[library]; | |
205 if (providingPath) { | |
206 resolveAndAppend(providingPath); | |
207 } else { | |
208 var basePath = includeFileToPaths(library).base; | |
209 if (!addedPaths[basePath]) { | |
210 addPath(basePath); | |
211 } | |
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 21 matching lines...) Expand all Loading... | |
148 var browsePreload = this[testFixture].prototype.browsePreload; | 249 var browsePreload = this[testFixture].prototype.browsePreload; |
149 var browsePrintPreload = this[testFixture].prototype.browsePrintPreload; | 250 var browsePrintPreload = this[testFixture].prototype.browsePrintPreload; |
150 var testGenPreamble = this[testFixture].prototype.testGenPreamble; | 251 var testGenPreamble = this[testFixture].prototype.testGenPreamble; |
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 resolveLibraries(this[testFixture].prototype.extraLibraries)); |
David Tseng
2014/05/30 17:08:46
Nice.
| |
159 function(includeFile) { | |
160 return includeFileToPaths(includeFile).base; | |
161 })); | |
162 | 260 |
163 if (typedefCppFixture && !(testFixture in typedeffedCppFixtures)) { | 261 if (typedefCppFixture && !(testFixture in typedeffedCppFixtures)) { |
164 print('typedef ' + typedefCppFixture + ' ' + testFixture + ';'); | 262 print('typedef ' + typedefCppFixture + ' ' + testFixture + ';'); |
165 typedeffedCppFixtures[testFixture] = typedefCppFixture; | 263 typedeffedCppFixtures[testFixture] = typedefCppFixture; |
166 } | 264 } |
167 | 265 |
168 print(testF + '(' + testFixture + ', ' + testFunction + ') {'); | 266 print(testF + '(' + testFixture + ', ' + testFunction + ') {'); |
169 for (var i = 0; i < extraLibraries.length; i++) { | 267 for (var i = 0; i < extraLibraries.length; i++) { |
170 print(' AddLibrary(base::FilePath(FILE_PATH_LITERAL("' + | 268 print(' AddLibrary(base::FilePath(FILE_PATH_LITERAL("' + |
171 extraLibraries[i].replace(/\\/g, '/') + '")));'); | 269 extraLibraries[i].replace(/\\/g, '/') + '")));'); |
(...skipping 17 matching lines...) Expand all Loading... | |
189 '"' + testFunction + '"));'); | 287 '"' + testFunction + '"));'); |
190 if (testGenPostamble) | 288 if (testGenPostamble) |
191 testGenPostamble(testFixture, testFunction); | 289 testGenPostamble(testFixture, testFunction); |
192 print('}'); | 290 print('}'); |
193 print(); | 291 print(); |
194 } | 292 } |
195 | 293 |
196 // Now that generation functions are defined, load in |jsFile|. | 294 // Now that generation functions are defined, load in |jsFile|. |
197 var js = read(jsFile); | 295 var js = read(jsFile); |
198 eval(js); | 296 eval(js); |
OLD | NEW |