blob: ee1056d6d25249d0b4d588367cc64cb83c9e99a5 [file] [log] [blame]
#!/usr/bin/env python
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import os
import tempfile
import unittest
from compile import Checker
from processor import FileCache, Processor
_SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
_SRC_DIR = os.path.join(_SCRIPT_DIR, os.pardir, os.pardir)
_RESOURCES_DIR = os.path.join(_SRC_DIR, "ui", "webui", "resources", "js")
_ASSERT_JS = os.path.join(_RESOURCES_DIR, "assert.js")
_CR_JS = os.path.join(_RESOURCES_DIR, "cr.js")
_CR_UI_JS = os.path.join(_RESOURCES_DIR, "cr", "ui.js")
_POLYMER_EXTERNS = os.path.join(_SRC_DIR, "third_party", "polymer", "v0_8",
"components-chromium", "polymer-externs",
"polymer.externs.js")
class CompilerTest(unittest.TestCase):
_ASSERT_DEFINITION = Processor(_ASSERT_JS).contents
_CR_DEFINE_DEFINITION = Processor(_CR_JS).contents
_CR_UI_DECORATE_DEFINITION = Processor(_CR_UI_JS).contents
def setUp(self):
self._checker = Checker()
self._tmp_files = []
def tearDown(self):
for file in self._tmp_files:
if os.path.exists(file):
os.remove(file)
def _runChecker(self, source_code, output_wrapper=None):
file_path = "/script.js"
FileCache._cache[file_path] = source_code
out_file, out_map = self._createOutFiles()
found_errors, stderr = self._checker.check(file_path,
externs=[_POLYMER_EXTERNS],
out_file=out_file,
output_wrapper=output_wrapper)
return found_errors, stderr, out_file, out_map
def _runCheckerTestExpectError(self, source_code, expected_error):
_, stderr, out_file, out_map = self._runChecker(source_code)
self.assertTrue(expected_error in stderr,
msg="Expected chunk: \n%s\n\nOutput:\n%s\n" % (
expected_error, stderr))
self.assertFalse(os.path.exists(out_file))
self.assertFalse(os.path.exists(out_map))
def _runCheckerTestExpectSuccess(self, source_code, expected_output=None,
output_wrapper=None):
found_errors, stderr, out_file, out_map = self._runChecker(source_code,
output_wrapper)
self.assertFalse(found_errors,
msg="Expected success, but got failure\n\nOutput:\n%s\n" % stderr)
self.assertTrue(os.path.exists(out_map))
self.assertTrue(os.path.exists(out_file))
if expected_output:
with open(out_file, "r") as file:
self.assertEquals(file.read(), expected_output)
def _createOutFiles(self):
out_file = tempfile.NamedTemporaryFile(delete=False)
out_map = "%s.map" % out_file.name
self._tmp_files.append(out_file.name)
self._tmp_files.append(out_map)
return out_file.name, out_map
def testGetInstance(self):
self._runCheckerTestExpectError("""
var cr = {
/** @param {!Function} ctor */
addSingletonGetter: function(ctor) {
ctor.getInstance = function() {
return ctor.instance_ || (ctor.instance_ = new ctor());
};
}
};
/** @constructor */
function Class() {
/** @param {number} num */
this.needsNumber = function(num) {};
}
cr.addSingletonGetter(Class);
Class.getInstance().needsNumber("wrong type");
""", "ERROR - actual parameter 1 of Class.needsNumber does not match formal "
"parameter")
def testCrDefineFunctionDefinition(self):
self._runCheckerTestExpectError(self._CR_DEFINE_DEFINITION + """
cr.define('a.b.c', function() {
/** @param {number} num */
function internalName(num) {}
return {
needsNumber: internalName
};
});
a.b.c.needsNumber("wrong type");
""", "ERROR - actual parameter 1 of a.b.c.needsNumber does not match formal "
"parameter")
def testCrDefineFunctionAssignment(self):
self._runCheckerTestExpectError(self._CR_DEFINE_DEFINITION + """
cr.define('a.b.c', function() {
/** @param {number} num */
var internalName = function(num) {};
return {
needsNumber: internalName
};
});
a.b.c.needsNumber("wrong type");
""", "ERROR - actual parameter 1 of a.b.c.needsNumber does not match formal "
"parameter")
def testCrDefineConstructorDefinitionPrototypeMethod(self):
self._runCheckerTestExpectError(self._CR_DEFINE_DEFINITION + """
cr.define('a.b.c', function() {
/** @constructor */
function ClassInternalName() {}
ClassInternalName.prototype = {
/** @param {number} num */
method: function(num) {}
};
return {
ClassExternalName: ClassInternalName
};
});
new a.b.c.ClassExternalName().method("wrong type");
""", "ERROR - actual parameter 1 of a.b.c.ClassExternalName.prototype.method "
"does not match formal parameter")
def testCrDefineConstructorAssignmentPrototypeMethod(self):
self._runCheckerTestExpectError(self._CR_DEFINE_DEFINITION + """
cr.define('a.b.c', function() {
/** @constructor */
var ClassInternalName = function() {};
ClassInternalName.prototype = {
/** @param {number} num */
method: function(num) {}
};
return {
ClassExternalName: ClassInternalName
};
});
new a.b.c.ClassExternalName().method("wrong type");
""", "ERROR - actual parameter 1 of a.b.c.ClassExternalName.prototype.method "
"does not match formal parameter")
def testCrDefineEnum(self):
self._runCheckerTestExpectError(self._CR_DEFINE_DEFINITION + """
cr.define('a.b.c', function() {
/** @enum {string} */
var internalNameForEnum = {key: 'wrong_type'};
return {
exportedEnum: internalNameForEnum
};
});
/** @param {number} num */
function needsNumber(num) {}
needsNumber(a.b.c.exportedEnum.key);
""", "ERROR - actual parameter 1 of needsNumber does not match formal "
"parameter")
def testObjectDefineProperty(self):
self._runCheckerTestExpectSuccess("""
/** @constructor */
function Class() {}
Object.defineProperty(Class.prototype, 'myProperty', {});
alert(new Class().myProperty);
""")
def testCrDefineProperty(self):
self._runCheckerTestExpectSuccess(self._CR_DEFINE_DEFINITION + """
/** @constructor */
function Class() {}
cr.defineProperty(Class.prototype, 'myProperty', cr.PropertyKind.JS);
alert(new Class().myProperty);
""")
def testCrDefinePropertyTypeChecking(self):
self._runCheckerTestExpectError(self._CR_DEFINE_DEFINITION + """
/** @constructor */
function Class() {}
cr.defineProperty(Class.prototype, 'booleanProp', cr.PropertyKind.BOOL_ATTR);
/** @param {number} num */
function needsNumber(num) {}
needsNumber(new Class().booleanProp);
""", "ERROR - actual parameter 1 of needsNumber does not match formal "
"parameter")
def testCrDefineOnCrWorks(self):
self._runCheckerTestExpectSuccess(self._CR_DEFINE_DEFINITION + """
cr.define('cr', function() {
return {};
});
""")
def testAssertWorks(self):
self._runCheckerTestExpectSuccess(self._ASSERT_DEFINITION + """
/** @return {?string} */
function f() {
return "string";
}
/** @type {!string} */
var a = assert(f());
""")
def testAssertInstanceofWorks(self):
self._runCheckerTestExpectSuccess(self._ASSERT_DEFINITION + """
/** @constructor */
function Class() {}
/** @return {Class} */
function f() {
var a = document.createElement('div');
return assertInstanceof(a, Class);
}
""")
def testCrUiDecorateWorks(self):
self._runCheckerTestExpectSuccess(self._CR_DEFINE_DEFINITION +
self._CR_UI_DECORATE_DEFINITION + """
/** @constructor */
function Class() {}
/** @return {Class} */
function f() {
var a = document.createElement('div');
cr.ui.decorate(a, Class);
return a;
}
""")
def testValidScriptCompilation(self):
self._runCheckerTestExpectSuccess("""
var testScript = function() {
console.log("hello world")
};
""",
"""'use strict';var testScript=function(){console.log("hello world")};\n""")
def testOutputWrapper(self):
source_code = """
var testScript = function() {
console.log("hello world");
};
"""
expected_output = ("""(function(){'use strict';var testScript=function()"""
"""{console.log("hello world")};})();\n""")
output_wrapper="(function(){%output%})();"
self._runCheckerTestExpectSuccess(source_code, expected_output,
output_wrapper=output_wrapper)
def testCheckMultiple(self):
source_file1 = tempfile.NamedTemporaryFile(delete=False)
with open(source_file1.name, "w") as f:
f.write("""
goog.provide('testScript');
var testScript = function() {};
""")
self._tmp_files.append(source_file1.name)
source_file2 = tempfile.NamedTemporaryFile(delete=False)
with open(source_file2.name, "w") as f:
f.write("""
goog.require('testScript');
testScript();
""")
self._tmp_files.append(source_file2.name)
out_file, out_map = self._createOutFiles()
sources = [source_file1.name, source_file2.name]
externs = [_POLYMER_EXTERNS]
found_errors, stderr = self._checker.check_multiple(sources,
externs=externs,
out_file=out_file)
self.assertFalse(found_errors,
msg="Expected success, but got failure\n\nOutput:\n%s\n" % stderr)
expected_output = "'use strict';var testScript=function(){};testScript();\n"
self.assertTrue(os.path.exists(out_map))
self.assertTrue(os.path.exists(out_file))
with open(out_file, "r") as file:
self.assertEquals(file.read(), expected_output)
if __name__ == "__main__":
unittest.main()