Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(64)

Side by Side Diff: chrome/test/base/js2gtest.js

Issue 304793002: Support automatically resolving dependencies in javascript tests. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@lkgr
Patch Set: Various fixes. Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698