Home | History | Annotate | Download | only in closure_compiler
      1 #!/usr/bin/env python
      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.
      5 
      6 import os
      7 import unittest
      8 
      9 from checker import Checker
     10 from processor import FileCache, Processor
     11 
     12 
     13 ASSERT_FILE = os.path.join("..", "..", "ui", "webui", "resources", "js",
     14     "assert.js")
     15 CR_FILE = os.path.join("..", "..", "ui", "webui", "resources", "js", "cr.js")
     16 UI_FILE = os.path.join("..", "..", "ui", "webui", "resources", "js", "cr",
     17     "ui.js")
     18 
     19 
     20 def rel_to_abs(rel_path):
     21   script_path = os.path.dirname(os.path.abspath(__file__))
     22   return os.path.join(script_path, rel_path)
     23 
     24 
     25 class CompilerCustomizationTest(unittest.TestCase):
     26   _ASSERT_DEFINITION = Processor(rel_to_abs(ASSERT_FILE)).contents
     27   _CR_DEFINE_DEFINITION = Processor(rel_to_abs(CR_FILE)).contents
     28   _CR_UI_DECORATE_DEFINITION = Processor(rel_to_abs(UI_FILE)).contents
     29 
     30   def setUp(self):
     31     self._checker = Checker()
     32 
     33   def _runChecker(self, source_code):
     34     file_path = "/script.js"
     35     FileCache._cache[file_path] = source_code
     36     return self._checker.check(file_path)
     37 
     38   def _runCheckerTestExpectError(self, source_code, expected_error):
     39     _, output = self._runChecker(source_code)
     40 
     41     self.assertTrue(expected_error in output,
     42         msg="Expected chunk: \n%s\n\nOutput:\n%s\n" % (
     43             expected_error, output))
     44 
     45   def _runCheckerTestExpectSuccess(self, source_code):
     46     return_code, output = self._runChecker(source_code)
     47 
     48     self.assertTrue(return_code == 0,
     49         msg="Expected success, got return code %d\n\nOutput:\n%s\n" % (
     50             return_code, output))
     51 
     52   def testGetInstance(self):
     53     self._runCheckerTestExpectError("""
     54 var cr = {
     55   /** @param {!Function} ctor */
     56   addSingletonGetter: function(ctor) {
     57     ctor.getInstance = function() {
     58       return ctor.instance_ || (ctor.instance_ = new ctor());
     59     };
     60   }
     61 };
     62 
     63 /** @constructor */
     64 function Class() {
     65   /** @param {number} num */
     66   this.needsNumber = function(num) {};
     67 }
     68 
     69 cr.addSingletonGetter(Class);
     70 Class.getInstance().needsNumber("wrong type");
     71 """, "ERROR - actual parameter 1 of Class.needsNumber does not match formal "
     72         "parameter")
     73 
     74   def testCrDefineFunctionDefinition(self):
     75     self._runCheckerTestExpectError(self._CR_DEFINE_DEFINITION + """
     76 cr.define('a.b.c', function() {
     77   /** @param {number} num */
     78   function internalName(num) {}
     79 
     80   return {
     81     needsNumber: internalName
     82   };
     83 });
     84 
     85 a.b.c.needsNumber("wrong type");
     86 """, "ERROR - actual parameter 1 of a.b.c.needsNumber does not match formal "
     87         "parameter")
     88 
     89   def testCrDefineFunctionAssignment(self):
     90     self._runCheckerTestExpectError(self._CR_DEFINE_DEFINITION + """
     91 cr.define('a.b.c', function() {
     92   /** @param {number} num */
     93   var internalName = function(num) {};
     94 
     95   return {
     96     needsNumber: internalName
     97   };
     98 });
     99 
    100 a.b.c.needsNumber("wrong type");
    101 """, "ERROR - actual parameter 1 of a.b.c.needsNumber does not match formal "
    102         "parameter")
    103 
    104   def testCrDefineConstructorDefinitionPrototypeMethod(self):
    105     self._runCheckerTestExpectError(self._CR_DEFINE_DEFINITION + """
    106 cr.define('a.b.c', function() {
    107   /** @constructor */
    108   function ClassInternalName() {}
    109 
    110   ClassInternalName.prototype = {
    111     /** @param {number} num */
    112     method: function(num) {}
    113   };
    114 
    115   return {
    116     ClassExternalName: ClassInternalName
    117   };
    118 });
    119 
    120 new a.b.c.ClassExternalName().method("wrong type");
    121 """, "ERROR - actual parameter 1 of a.b.c.ClassExternalName.prototype.method "
    122         "does not match formal parameter")
    123 
    124   def testCrDefineConstructorAssignmentPrototypeMethod(self):
    125     self._runCheckerTestExpectError(self._CR_DEFINE_DEFINITION + """
    126 cr.define('a.b.c', function() {
    127   /** @constructor */
    128   var ClassInternalName = function() {};
    129 
    130   ClassInternalName.prototype = {
    131     /** @param {number} num */
    132     method: function(num) {}
    133   };
    134 
    135   return {
    136     ClassExternalName: ClassInternalName
    137   };
    138 });
    139 
    140 new a.b.c.ClassExternalName().method("wrong type");
    141 """, "ERROR - actual parameter 1 of a.b.c.ClassExternalName.prototype.method "
    142         "does not match formal parameter")
    143 
    144   def testCrDefineEnum(self):
    145     self._runCheckerTestExpectError(self._CR_DEFINE_DEFINITION + """
    146 cr.define('a.b.c', function() {
    147   /** @enum {string} */
    148   var internalNameForEnum = {key: 'wrong_type'};
    149 
    150   return {
    151     exportedEnum: internalNameForEnum
    152   };
    153 });
    154 
    155 /** @param {number} num */
    156 function needsNumber(num) {}
    157 
    158 needsNumber(a.b.c.exportedEnum.key);
    159 """, "ERROR - actual parameter 1 of needsNumber does not match formal "
    160         "parameter")
    161 
    162   def testObjectDefineProperty(self):
    163     self._runCheckerTestExpectSuccess("""
    164 /** @constructor */
    165 function Class() {}
    166 
    167 Object.defineProperty(Class.prototype, 'myProperty', {});
    168 
    169 alert(new Class().myProperty);
    170 """)
    171 
    172   def testCrDefineProperty(self):
    173     self._runCheckerTestExpectSuccess(self._CR_DEFINE_DEFINITION + """
    174 /** @constructor */
    175 function Class() {}
    176 
    177 cr.defineProperty(Class.prototype, 'myProperty', cr.PropertyKind.JS);
    178 
    179 alert(new Class().myProperty);
    180 """)
    181 
    182   def testCrDefinePropertyTypeChecking(self):
    183     self._runCheckerTestExpectError(self._CR_DEFINE_DEFINITION + """
    184 /** @constructor */
    185 function Class() {}
    186 
    187 cr.defineProperty(Class.prototype, 'booleanProp', cr.PropertyKind.BOOL_ATTR);
    188 
    189 /** @param {number} num */
    190 function needsNumber(num) {}
    191 
    192 needsNumber(new Class().booleanProp);
    193 """, "ERROR - actual parameter 1 of needsNumber does not match formal "
    194         "parameter")
    195 
    196   def testCrDefineOnCrWorks(self):
    197     self._runCheckerTestExpectSuccess(self._CR_DEFINE_DEFINITION + """
    198 cr.define('cr', function() {
    199   return {};
    200 });
    201 """)
    202 
    203   def testAssertWorks(self):
    204     self._runCheckerTestExpectSuccess(self._ASSERT_DEFINITION + """
    205 /** @return {?string} */
    206 function f() {
    207   return "string";
    208 }
    209 
    210 /** @type {!string} */
    211 var a = assert(f());
    212 """)
    213 
    214   def testAssertInstanceofWorks(self):
    215     self._runCheckerTestExpectSuccess(self._ASSERT_DEFINITION + """
    216 /** @constructor */
    217 function Class() {}
    218 
    219 /** @return {Class} */
    220 function f() {
    221   var a = document.createElement('div');
    222   return assertInstanceof(a, Class);
    223 }
    224 """)
    225 
    226   def testCrUiDecorateWorks(self):
    227     self._runCheckerTestExpectSuccess(self._CR_DEFINE_DEFINITION +
    228         self._CR_UI_DECORATE_DEFINITION + """
    229 /** @constructor */
    230 function Class() {}
    231 
    232 /** @return {Class} */
    233 function f() {
    234   var a = document.createElement('div');
    235   cr.ui.decorate(a, Class);
    236   return a;
    237 }
    238 """)
    239 
    240 
    241 if __name__ == "__main__":
    242   unittest.main()
    243