Chromium Code Reviews| 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 |