2 # Copyright 2014 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 from ast
import literal_eval
11 from compile import Checker
12 from processor
import FileCache
, Processor
15 _SCRIPT_DIR
= os
.path
.dirname(os
.path
.abspath(__file__
))
16 _SRC_DIR
= os
.path
.join(_SCRIPT_DIR
, os
.pardir
, os
.pardir
)
17 _RESOURCES_DIR
= os
.path
.join(_SRC_DIR
, "ui", "webui", "resources", "js")
18 _ASSERT_JS
= os
.path
.join(_RESOURCES_DIR
, "assert.js")
19 _CR_JS
= os
.path
.join(_RESOURCES_DIR
, "cr.js")
20 _CR_UI_JS
= os
.path
.join(_RESOURCES_DIR
, "cr", "ui.js")
21 _POLYMER_EXTERNS
= os
.path
.join(_SRC_DIR
, "third_party", "polymer", "v1_0",
22 "components-chromium", "polymer-externs",
24 _CHROME_SEND_EXTERNS
= os
.path
.join(_SRC_DIR
, "third_party", "closure_compiler",
25 "externs", "chrome_send.js")
26 _CLOSURE_ARGS_GYPI
= os
.path
.join(_SCRIPT_DIR
, "closure_args.gypi")
27 _GYPI_DICT
= literal_eval(open(_CLOSURE_ARGS_GYPI
).read())
28 _COMMON_CLOSURE_ARGS
= _GYPI_DICT
["closure_args"] + \
29 _GYPI_DICT
["default_disabled_closure_args"]
32 class CompilerTest(unittest
.TestCase
):
33 _ASSERT_DEFINITION
= Processor(_ASSERT_JS
).contents
34 _CR_DEFINE_DEFINITION
= Processor(_CR_JS
).contents
35 _CR_UI_DECORATE_DEFINITION
= Processor(_CR_UI_JS
).contents
38 self
._checker
= Checker()
42 for file in self
._tmp
_files
:
43 if os
.path
.exists(file):
46 def _runChecker(self
, source_code
, closure_args
=None):
47 file_path
= "/script.js"
48 FileCache
._cache
[file_path
] = source_code
49 out_file
, out_map
= self
._createOutFiles
()
50 args
= _COMMON_CLOSURE_ARGS
+ (closure_args
or [])
52 externs
= [_POLYMER_EXTERNS
, _CHROME_SEND_EXTERNS
]
53 found_errors
, stderr
= self
._checker
.check(file_path
,
57 return found_errors
, stderr
, out_file
, out_map
59 def _runCheckerTestExpectError(self
, source_code
, expected_error
):
60 _
, stderr
, out_file
, out_map
= self
._runChecker
(source_code
)
62 self
.assertTrue(expected_error
in stderr
,
63 msg
="Expected chunk: \n%s\n\nOutput:\n%s\n" % (
64 expected_error
, stderr
))
65 self
.assertFalse(os
.path
.exists(out_file
))
66 self
.assertFalse(os
.path
.exists(out_map
))
68 def _runCheckerTestExpectSuccess(self
, source_code
, expected_output
=None,
70 found_errors
, stderr
, out_file
, out_map
= self
._runChecker
(source_code
,
73 self
.assertFalse(found_errors
,
74 msg
="Expected success, but got failure\n\nOutput:\n%s\n" % stderr
)
76 self
.assertTrue(os
.path
.exists(out_map
))
77 self
.assertTrue(os
.path
.exists(out_file
))
79 with
open(out_file
, "r") as file:
80 self
.assertEquals(file.read(), expected_output
)
82 def _createOutFiles(self
):
83 out_file
= tempfile
.NamedTemporaryFile(delete
=False)
84 out_map
= "%s.map" % out_file
.name
86 self
._tmp
_files
.append(out_file
.name
)
87 self
._tmp
_files
.append(out_map
)
88 return out_file
.name
, out_map
90 def testGetInstance(self
):
91 self
._runCheckerTestExpectError
("""
93 /** @param {!Function} ctor */
94 addSingletonGetter: function(ctor) {
95 ctor.getInstance = function() {
96 return ctor.instance_ || (ctor.instance_ = new ctor());
103 /** @param {number} num */
104 this.needsNumber = function(num) {};
107 cr.addSingletonGetter(Class);
108 Class.getInstance().needsNumber("wrong type");
109 """, "ERROR - actual parameter 1 of Class.needsNumber does not match formal "
112 def testCrDefineFunctionDefinition(self
):
113 self
._runCheckerTestExpectError
(self
._CR
_DEFINE
_DEFINITION
+ """
114 cr.define('a.b.c', function() {
115 /** @param {number} num */
116 function internalName(num) {}
119 needsNumber: internalName
123 a.b.c.needsNumber("wrong type");
124 """, "ERROR - actual parameter 1 of a.b.c.needsNumber does not match formal "
127 def testCrDefineFunctionAssignment(self
):
128 self
._runCheckerTestExpectError
(self
._CR
_DEFINE
_DEFINITION
+ """
129 cr.define('a.b.c', function() {
130 /** @param {number} num */
131 var internalName = function(num) {};
134 needsNumber: internalName
138 a.b.c.needsNumber("wrong type");
139 """, "ERROR - actual parameter 1 of a.b.c.needsNumber does not match formal "
142 def testCrDefineConstructorDefinitionPrototypeMethod(self
):
143 self
._runCheckerTestExpectError
(self
._CR
_DEFINE
_DEFINITION
+ """
144 cr.define('a.b.c', function() {
146 function ClassInternalName() {}
148 ClassInternalName.prototype = {
149 /** @param {number} num */
150 method: function(num) {}
154 ClassExternalName: ClassInternalName
158 new a.b.c.ClassExternalName().method("wrong type");
159 """, "ERROR - actual parameter 1 of a.b.c.ClassExternalName.prototype.method "
160 "does not match formal parameter")
162 def testCrDefineConstructorAssignmentPrototypeMethod(self
):
163 self
._runCheckerTestExpectError
(self
._CR
_DEFINE
_DEFINITION
+ """
164 cr.define('a.b.c', function() {
166 var ClassInternalName = function() {};
168 ClassInternalName.prototype = {
169 /** @param {number} num */
170 method: function(num) {}
174 ClassExternalName: ClassInternalName
178 new a.b.c.ClassExternalName().method("wrong type");
179 """, "ERROR - actual parameter 1 of a.b.c.ClassExternalName.prototype.method "
180 "does not match formal parameter")
182 def testCrDefineEnum(self
):
183 self
._runCheckerTestExpectError
(self
._CR
_DEFINE
_DEFINITION
+ """
184 cr.define('a.b.c', function() {
185 /** @enum {string} */
186 var internalNameForEnum = {key: 'wrong_type'};
189 exportedEnum: internalNameForEnum
193 /** @param {number} num */
194 function needsNumber(num) {}
196 needsNumber(a.b.c.exportedEnum.key);
197 """, "ERROR - actual parameter 1 of needsNumber does not match formal "
200 def testObjectDefineProperty(self
):
201 self
._runCheckerTestExpectSuccess
("""
205 Object.defineProperty(Class.prototype, 'myProperty', {});
207 alert(new Class().myProperty);
210 def testCrDefineProperty(self
):
211 self
._runCheckerTestExpectSuccess
(self
._CR
_DEFINE
_DEFINITION
+ """
215 cr.defineProperty(Class.prototype, 'myProperty', cr.PropertyKind.JS);
217 alert(new Class().myProperty);
220 def testCrDefinePropertyTypeChecking(self
):
221 self
._runCheckerTestExpectError
(self
._CR
_DEFINE
_DEFINITION
+ """
225 cr.defineProperty(Class.prototype, 'booleanProp', cr.PropertyKind.BOOL_ATTR);
227 /** @param {number} num */
228 function needsNumber(num) {}
230 needsNumber(new Class().booleanProp);
231 """, "ERROR - actual parameter 1 of needsNumber does not match formal "
234 def testCrDefineOnCrWorks(self
):
235 self
._runCheckerTestExpectSuccess
(self
._CR
_DEFINE
_DEFINITION
+ """
236 cr.define('cr', function() {
241 def testAssertWorks(self
):
242 self
._runCheckerTestExpectSuccess
(self
._ASSERT
_DEFINITION
+ """
243 /** @return {?string} */
248 /** @type {!string} */
252 def testAssertInstanceofWorks(self
):
253 self
._runCheckerTestExpectSuccess
(self
._ASSERT
_DEFINITION
+ """
257 /** @return {Class} */
259 var a = document.createElement('div');
260 return assertInstanceof(a, Class);
264 def testCrUiDecorateWorks(self
):
265 self
._runCheckerTestExpectSuccess
(self
._CR
_DEFINE
_DEFINITION
+
266 self
._CR
_UI
_DECORATE
_DEFINITION
+ """
270 /** @return {Class} */
272 var a = document.createElement('div');
273 cr.ui.decorate(a, Class);
278 def testValidScriptCompilation(self
):
279 self
._runCheckerTestExpectSuccess
("""
280 var testScript = function() {
281 console.log("hello world")
284 """'use strict';var testScript=function(){console.log("hello world")};\n""")
286 def testOutputWrapper(self
):
288 var testScript = function() {
289 console.log("hello world");
292 expected_output
= ("""(function(){'use strict';var testScript=function()"""
293 """{console.log("hello world")};})();\n""")
294 closure_args
=["output_wrapper='(function(){%output%})();'"]
295 self
._runCheckerTestExpectSuccess
(source_code
, expected_output
,
298 def testCheckMultiple(self
):
299 source_file1
= tempfile
.NamedTemporaryFile(delete
=False)
300 with
open(source_file1
.name
, "w") as f
:
302 goog.provide('testScript');
304 var testScript = function() {};
306 self
._tmp
_files
.append(source_file1
.name
)
308 source_file2
= tempfile
.NamedTemporaryFile(delete
=False)
309 with
open(source_file2
.name
, "w") as f
:
311 goog.require('testScript');
315 self
._tmp
_files
.append(source_file2
.name
)
317 out_file
, out_map
= self
._createOutFiles
()
318 sources
= [source_file1
.name
, source_file2
.name
]
319 externs
= [_POLYMER_EXTERNS
]
320 found_errors
, stderr
= self
._checker
.check_multiple(
321 sources
, externs
=externs
, out_file
=out_file
,
322 closure_args
=_COMMON_CLOSURE_ARGS
)
323 self
.assertFalse(found_errors
,
324 msg
="Expected success, but got failure\n\nOutput:\n%s\n" % stderr
)
326 expected_output
= "'use strict';var testScript=function(){};testScript();\n"
327 self
.assertTrue(os
.path
.exists(out_map
))
328 self
.assertTrue(os
.path
.exists(out_file
))
329 with
open(out_file
, "r") as file:
330 self
.assertEquals(file.read(), expected_output
)
332 def testExportPath(self
):
333 self
._runCheckerTestExpectSuccess
(self
._CR
_DEFINE
_DEFINITION
+
334 "cr.exportPath('a.b.c');");
336 def testExportPathWithTargets(self
):
337 self
._runCheckerTestExpectSuccess
(self
._CR
_DEFINE
_DEFINITION
+
338 "var path = 'a.b.c'; cr.exportPath(path, {}, {});")
340 def testExportPathNoPath(self
):
341 self
._runCheckerTestExpectError
(self
._CR
_DEFINE
_DEFINITION
+
343 "ERROR - cr.exportPath() should have at least 1 argument: path name")
346 if __name__
== "__main__":