ChromePassTest.java revision 6e8cce623b6e4fe0c9e4af605d675dd9d0338c38
1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5package com.google.javascript.jscomp; 6 7/** 8 * Tests {@link ChromePass}. 9 */ 10public class ChromePassTest extends CompilerTestCase { 11 12 @Override 13 protected CompilerPass getProcessor(Compiler compiler) { 14 return new ChromePass(compiler); 15 } 16 17 @Override 18 protected int getNumRepetitions() { 19 // This pass isn't idempotent and only runs once. 20 return 1; 21 } 22 23 public void testCrDefineCreatesObjectsForQualifiedName() throws Exception { 24 test( 25 "cr.define('my.namespace.name', function() {\n" + 26 " return {};\n" + 27 "});", 28 "var my = my || {};\n" + 29 "my.namespace = my.namespace || {};\n" + 30 "my.namespace.name = my.namespace.name || {};\n" + 31 "cr.define('my.namespace.name', function() {\n" + 32 " return {};\n" + 33 "});"); 34 } 35 36 public void testCrDefineAssignsExportedFunctionByQualifiedName() throws Exception { 37 test( 38 "cr.define('namespace', function() {\n" + 39 " function internalStaticMethod() {\n" + 40 " alert(42);\n" + 41 " }\n" + 42 " return {\n" + 43 " externalStaticMethod: internalStaticMethod\n" + 44 " };\n" + 45 "});", 46 "var namespace = namespace || {};\n" + 47 "cr.define('namespace', function() {\n" + 48 " namespace.externalStaticMethod = function internalStaticMethod() {\n" + 49 " alert(42);\n" + 50 " }\n" + 51 " return {\n" + 52 " externalStaticMethod: namespace.externalStaticMethod\n" + 53 " };\n" + 54 "});"); 55 } 56 57 public void testCrDefineCopiesJSDocForExportedFunction() throws Exception { 58 test("cr.define('namespace', function() {\n" + 59 " /** I'm function's JSDoc */\n" + 60 " function internalStaticMethod() {\n" + 61 " alert(42);\n" + 62 " }\n" + 63 " return {\n" + 64 " externalStaticMethod: internalStaticMethod\n" + 65 " };\n" + 66 "});", 67 "var namespace = namespace || {};\n" + 68 "cr.define('namespace', function() {\n" + 69 " /** I'm function's JSDoc */\n" + 70 " namespace.externalStaticMethod = function internalStaticMethod() {\n" + 71 " alert(42);\n" + 72 " }\n" + 73 " return {\n" + 74 " externalStaticMethod: namespace.externalStaticMethod\n" + 75 " };\n" + 76 "});"); 77 } 78 79 public void testCrDefineReassignsExportedFunctionByQualifiedName() throws Exception { 80 test( 81 "cr.define('namespace', function() {\n" + 82 " var internalStaticMethod = function() {\n" + 83 " alert(42);\n" + 84 " }\n" + 85 " return {\n" + 86 " externalStaticMethod: internalStaticMethod\n" + 87 " };\n" + 88 "});", 89 "var namespace = namespace || {};\n" + 90 "cr.define('namespace', function() {\n" + 91 " namespace.externalStaticMethod = function() {\n" + 92 " alert(42);\n" + 93 " }\n" + 94 " return {\n" + 95 " externalStaticMethod: namespace.externalStaticMethod\n" + 96 " };\n" + 97 "});"); 98 } 99 100 public void testCrDefineCopiesJSDocForExportedVariable() throws Exception { 101 test( 102 "cr.define('namespace', function() {\n" + 103 " /** I'm function's JSDoc */\n" + 104 " var internalStaticMethod = function() {\n" + 105 " alert(42);\n" + 106 " }\n" + 107 " return {\n" + 108 " externalStaticMethod: internalStaticMethod\n" + 109 " };\n" + 110 "});", 111 "var namespace = namespace || {};\n" + 112 "cr.define('namespace', function() {\n" + 113 " /** I'm function's JSDoc */\n" + 114 " namespace.externalStaticMethod = function() {\n" + 115 " alert(42);\n" + 116 " }\n" + 117 " return {\n" + 118 " externalStaticMethod: namespace.externalStaticMethod\n" + 119 " };\n" + 120 "});"); 121 } 122 123 public void testCrDefineDoesNothingWithNonExportedFunction() throws Exception { 124 test( 125 "cr.define('namespace', function() {\n" + 126 " function internalStaticMethod() {\n" + 127 " alert(42);\n" + 128 " }\n" + 129 " return {};\n" + 130 "});", 131 "var namespace = namespace || {};\n" + 132 "cr.define('namespace', function() {\n" + 133 " function internalStaticMethod() {\n" + 134 " alert(42);\n" + 135 " }\n" + 136 " return {};\n" + 137 "});"); 138 } 139 140 public void testCrDefineChangesReferenceToExportedFunction() throws Exception { 141 test( 142 "cr.define('namespace', function() {\n" + 143 " function internalStaticMethod() {\n" + 144 " alert(42);\n" + 145 " }\n" + 146 " function letsUseIt() {\n" + 147 " internalStaticMethod();\n" + 148 " }\n" + 149 " return {\n" + 150 " externalStaticMethod: internalStaticMethod\n" + 151 " };\n" + 152 "});", 153 "var namespace = namespace || {};\n" + 154 "cr.define('namespace', function() {\n" + 155 " namespace.externalStaticMethod = function internalStaticMethod() {\n" + 156 " alert(42);\n" + 157 " }\n" + 158 " function letsUseIt() {\n" + 159 " namespace.externalStaticMethod();\n" + 160 " }\n" + 161 " return {\n" + 162 " externalStaticMethod: namespace.externalStaticMethod\n" + 163 " };\n" + 164 "});"); 165 } 166 167 public void testCrDefineWrongNumberOfArguments() throws Exception { 168 test("cr.define('namespace', function() { return {}; }, 'invalid argument')\n", 169 null, ChromePass.CR_DEFINE_WRONG_NUMBER_OF_ARGUMENTS); 170 } 171 172 public void testCrDefineInvalidFirstArgument() throws Exception { 173 test("cr.define(42, function() { return {}; })\n", 174 null, ChromePass.CR_DEFINE_INVALID_FIRST_ARGUMENT); 175 } 176 177 public void testCrDefineInvalidSecondArgument() throws Exception { 178 test("cr.define('namespace', 42)\n", 179 null, ChromePass.CR_DEFINE_INVALID_SECOND_ARGUMENT); 180 } 181 182 public void testCrDefineInvalidReturnInFunction() throws Exception { 183 test("cr.define('namespace', function() {})\n", 184 null, ChromePass.CR_DEFINE_INVALID_RETURN_IN_FUNCTION); 185 } 186 187 public void testObjectDefinePropertyDefinesUnquotedProperty() throws Exception { 188 test( 189 "Object.defineProperty(a.b, 'c', {});", 190 "Object.defineProperty(a.b, 'c', {});\n" + 191 "/** @type {?} */\n" + 192 "a.b.c;"); 193 } 194 195 public void testCrDefinePropertyDefinesUnquotedPropertyWithStringTypeForPropertyKindAttr() 196 throws Exception { 197 test( 198 "cr.defineProperty(a.prototype, 'c', cr.PropertyKind.ATTR);", 199 "cr.defineProperty(a.prototype, 'c', cr.PropertyKind.ATTR);\n" + 200 "/** @type {string} */\n" + 201 "a.prototype.c;"); 202 } 203 204 public void testCrDefinePropertyDefinesUnquotedPropertyWithBooleanTypeForPropertyKindBoolAttr() 205 throws Exception { 206 test( 207 "cr.defineProperty(a.prototype, 'c', cr.PropertyKind.BOOL_ATTR);", 208 "cr.defineProperty(a.prototype, 'c', cr.PropertyKind.BOOL_ATTR);\n" + 209 "/** @type {boolean} */\n" + 210 "a.prototype.c;"); 211 } 212 213 public void testCrDefinePropertyDefinesUnquotedPropertyWithAnyTypeForPropertyKindJs() 214 throws Exception { 215 test( 216 "cr.defineProperty(a.prototype, 'c', cr.PropertyKind.JS);", 217 "cr.defineProperty(a.prototype, 'c', cr.PropertyKind.JS);\n" + 218 "/** @type {?} */\n" + 219 "a.prototype.c;"); 220 } 221 222 public void testCrDefinePropertyCalledWithouthThirdArgumentMeansCrPropertyKindJs() 223 throws Exception { 224 test( 225 "cr.defineProperty(a.prototype, 'c');", 226 "cr.defineProperty(a.prototype, 'c');\n" + 227 "/** @type {?} */\n" + 228 "a.prototype.c;"); 229 } 230 231 public void testCrDefinePropertyDefinesUnquotedPropertyOnPrototypeWhenFunctionIsPassed() 232 throws Exception { 233 test( 234 "cr.defineProperty(a, 'c', cr.PropertyKind.JS);", 235 "cr.defineProperty(a, 'c', cr.PropertyKind.JS);\n" + 236 "/** @type {?} */\n" + 237 "a.prototype.c;"); 238 } 239 240 public void testCrDefinePropertyInvalidPropertyKind() 241 throws Exception { 242 test( 243 "cr.defineProperty(a.b, 'c', cr.PropertyKind.INEXISTENT_KIND);", 244 null, ChromePass.CR_DEFINE_PROPERTY_INVALID_PROPERTY_KIND); 245 } 246 247 public void testCrExportPath() throws Exception { 248 test( 249 "cr.exportPath('a.b.c');", 250 "var a = a || {};\n" + 251 "a.b = a.b || {};\n" + 252 "a.b.c = a.b.c || {};\n" + 253 "cr.exportPath('a.b.c');"); 254 } 255 256 public void testCrDefineCreatesEveryObjectOnlyOnce() throws Exception { 257 test( 258 "cr.define('a.b.c.d', function() {\n" + 259 " return {};\n" + 260 "});" + 261 "cr.define('a.b.e.f', function() {\n" + 262 " return {};\n" + 263 "});", 264 "var a = a || {};\n" + 265 "a.b = a.b || {};\n" + 266 "a.b.c = a.b.c || {};\n" + 267 "a.b.c.d = a.b.c.d || {};\n" + 268 "cr.define('a.b.c.d', function() {\n" + 269 " return {};\n" + 270 "});" + 271 "a.b.e = a.b.e || {};\n" + 272 "a.b.e.f = a.b.e.f || {};\n" + 273 "cr.define('a.b.e.f', function() {\n" + 274 " return {};\n" + 275 "});"); 276 } 277 278 public void testCrDefineAndCrExportPathCreateEveryObjectOnlyOnce() throws Exception { 279 test( 280 "cr.exportPath('a.b.c.d');\n" + 281 "cr.define('a.b.e.f', function() {\n" + 282 " return {};\n" + 283 "});", 284 "var a = a || {};\n" + 285 "a.b = a.b || {};\n" + 286 "a.b.c = a.b.c || {};\n" + 287 "a.b.c.d = a.b.c.d || {};\n" + 288 "cr.exportPath('a.b.c.d');\n" + 289 "a.b.e = a.b.e || {};\n" + 290 "a.b.e.f = a.b.e.f || {};\n" + 291 "cr.define('a.b.e.f', function() {\n" + 292 " return {};\n" + 293 "});"); 294 } 295 296 public void testCrDefineDoesntRedefineCrVar() throws Exception { 297 test( 298 "cr.define('cr.ui', function() {\n" + 299 " return {};\n" + 300 "});", 301 "cr.ui = cr.ui || {};\n" + 302 "cr.define('cr.ui', function() {\n" + 303 " return {};\n" + 304 "});"); 305 } 306 307 public void testCrExportPathInvalidNumberOfArguments() throws Exception { 308 test("cr.exportPath();", null, ChromePass.CR_EXPORT_PATH_WRONG_NUMBER_OF_ARGUMENTS); 309 } 310 311} 312