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.
5 package com.google.javascript.jscomp;
8 * Tests {@link ChromePass}.
10 public class ChromePassTest extends CompilerTestCase {
13 protected CompilerPass getProcessor(Compiler compiler) {
14 return new ChromePass(compiler);
18 protected int getNumRepetitions() {
19 // This pass isn't idempotent and only runs once.
23 public void testCrDefineCreatesObjectsForQualifiedName() throws Exception {
25 "cr.define('my.namespace.name', function() {\n" +
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" +
36 public void testCrDefineAssignsExportedFunctionByQualifiedName() throws Exception {
38 "cr.define('namespace', function() {\n" +
39 " function internalStaticMethod() {\n" +
43 " externalStaticMethod: internalStaticMethod\n" +
46 "var namespace = namespace || {};\n" +
47 "cr.define('namespace', function() {\n" +
48 " namespace.externalStaticMethod = function internalStaticMethod() {\n" +
52 " externalStaticMethod: namespace.externalStaticMethod\n" +
57 public void testCrDefineCopiesJSDocForExportedFunction() throws Exception {
58 test("cr.define('namespace', function() {\n" +
59 " /** I'm function's JSDoc */\n" +
60 " function internalStaticMethod() {\n" +
64 " externalStaticMethod: internalStaticMethod\n" +
67 "var namespace = namespace || {};\n" +
68 "cr.define('namespace', function() {\n" +
69 " /** I'm function's JSDoc */\n" +
70 " namespace.externalStaticMethod = function internalStaticMethod() {\n" +
74 " externalStaticMethod: namespace.externalStaticMethod\n" +
79 public void testCrDefineReassignsExportedVarByQualifiedName() throws Exception {
81 "cr.define('namespace', function() {\n" +
82 " var internalStaticMethod = function() {\n" +
86 " externalStaticMethod: internalStaticMethod\n" +
89 "var namespace = namespace || {};\n" +
90 "cr.define('namespace', function() {\n" +
91 " namespace.externalStaticMethod = function() {\n" +
95 " externalStaticMethod: namespace.externalStaticMethod\n" +
100 public void testCrDefineExportsVarsWithoutAssignment() throws Exception {
102 "cr.define('namespace', function() {\n" +
108 "var namespace = namespace || {};\n" +
109 "cr.define('namespace', function() {\n" +
112 " a: namespace.a\n" +
117 public void testCrDefineExportsVarsWithoutAssignmentWithJSDoc() throws Exception {
119 "cr.define('namespace', function() {\n" +
120 " /** @type {number} */\n" +
126 "var namespace = namespace || {};\n" +
127 "cr.define('namespace', function() {\n" +
128 " /** @type {number} */\n" +
131 " a: namespace.a\n" +
136 public void testCrDefineCopiesJSDocForExportedVariable() throws Exception {
138 "cr.define('namespace', function() {\n" +
139 " /** I'm function's JSDoc */\n" +
140 " var internalStaticMethod = function() {\n" +
144 " externalStaticMethod: internalStaticMethod\n" +
147 "var namespace = namespace || {};\n" +
148 "cr.define('namespace', function() {\n" +
149 " /** I'm function's JSDoc */\n" +
150 " namespace.externalStaticMethod = function() {\n" +
154 " externalStaticMethod: namespace.externalStaticMethod\n" +
159 public void testCrDefineDoesNothingWithNonExportedFunction() throws Exception {
161 "cr.define('namespace', function() {\n" +
162 " function internalStaticMethod() {\n" +
167 "var namespace = namespace || {};\n" +
168 "cr.define('namespace', function() {\n" +
169 " function internalStaticMethod() {\n" +
176 public void testCrDefineDoesNothingWithNonExportedVar() throws Exception {
178 "cr.define('namespace', function() {\n" +
185 "var namespace = namespace || {};\n" +
186 "cr.define('namespace', function() {\n" +
190 " a: namespace.a\n" +
195 public void testCrDefineChangesReferenceToExportedFunction() throws Exception {
197 "cr.define('namespace', function() {\n" +
198 " function internalStaticMethod() {\n" +
201 " function letsUseIt() {\n" +
202 " internalStaticMethod();\n" +
205 " externalStaticMethod: internalStaticMethod\n" +
208 "var namespace = namespace || {};\n" +
209 "cr.define('namespace', function() {\n" +
210 " namespace.externalStaticMethod = function internalStaticMethod() {\n" +
213 " function letsUseIt() {\n" +
214 " namespace.externalStaticMethod();\n" +
217 " externalStaticMethod: namespace.externalStaticMethod\n" +
222 public void testCrDefineWrongNumberOfArguments() throws Exception {
223 test("cr.define('namespace', function() { return {}; }, 'invalid argument')\n",
224 null, ChromePass.CR_DEFINE_WRONG_NUMBER_OF_ARGUMENTS);
227 public void testCrDefineInvalidFirstArgument() throws Exception {
228 test("cr.define(42, function() { return {}; })\n",
229 null, ChromePass.CR_DEFINE_INVALID_FIRST_ARGUMENT);
232 public void testCrDefineInvalidSecondArgument() throws Exception {
233 test("cr.define('namespace', 42)\n",
234 null, ChromePass.CR_DEFINE_INVALID_SECOND_ARGUMENT);
237 public void testCrDefineInvalidReturnInFunction() throws Exception {
238 test("cr.define('namespace', function() {})\n",
239 null, ChromePass.CR_DEFINE_INVALID_RETURN_IN_FUNCTION);
242 public void testObjectDefinePropertyDefinesUnquotedProperty() throws Exception {
244 "Object.defineProperty(a.b, 'c', {});",
245 "Object.defineProperty(a.b, 'c', {});\n" +
246 "/** @type {?} */\n" +
250 public void testCrDefinePropertyDefinesUnquotedPropertyWithStringTypeForPropertyKindAttr()
253 "cr.defineProperty(a.prototype, 'c', cr.PropertyKind.ATTR);",
254 "cr.defineProperty(a.prototype, 'c', cr.PropertyKind.ATTR);\n" +
255 "/** @type {string} */\n" +
259 public void testCrDefinePropertyDefinesUnquotedPropertyWithBooleanTypeForPropertyKindBoolAttr()
262 "cr.defineProperty(a.prototype, 'c', cr.PropertyKind.BOOL_ATTR);",
263 "cr.defineProperty(a.prototype, 'c', cr.PropertyKind.BOOL_ATTR);\n" +
264 "/** @type {boolean} */\n" +
268 public void testCrDefinePropertyDefinesUnquotedPropertyWithAnyTypeForPropertyKindJs()
271 "cr.defineProperty(a.prototype, 'c', cr.PropertyKind.JS);",
272 "cr.defineProperty(a.prototype, 'c', cr.PropertyKind.JS);\n" +
273 "/** @type {?} */\n" +
277 public void testCrDefinePropertyCalledWithouthThirdArgumentMeansCrPropertyKindJs()
280 "cr.defineProperty(a.prototype, 'c');",
281 "cr.defineProperty(a.prototype, 'c');\n" +
282 "/** @type {?} */\n" +
286 public void testCrDefinePropertyDefinesUnquotedPropertyOnPrototypeWhenFunctionIsPassed()
289 "cr.defineProperty(a, 'c', cr.PropertyKind.JS);",
290 "cr.defineProperty(a, 'c', cr.PropertyKind.JS);\n" +
291 "/** @type {?} */\n" +
295 public void testCrDefinePropertyInvalidPropertyKind()
298 "cr.defineProperty(a.b, 'c', cr.PropertyKind.INEXISTENT_KIND);",
299 null, ChromePass.CR_DEFINE_PROPERTY_INVALID_PROPERTY_KIND);
302 public void testCrExportPath() throws Exception {
304 "cr.exportPath('a.b.c');",
305 "var a = a || {};\n" +
306 "a.b = a.b || {};\n" +
307 "a.b.c = a.b.c || {};\n" +
308 "cr.exportPath('a.b.c');");
311 public void testCrDefineCreatesEveryObjectOnlyOnce() throws Exception {
313 "cr.define('a.b.c.d', function() {\n" +
316 "cr.define('a.b.e.f', function() {\n" +
319 "var a = a || {};\n" +
320 "a.b = a.b || {};\n" +
321 "a.b.c = a.b.c || {};\n" +
322 "a.b.c.d = a.b.c.d || {};\n" +
323 "cr.define('a.b.c.d', function() {\n" +
326 "a.b.e = a.b.e || {};\n" +
327 "a.b.e.f = a.b.e.f || {};\n" +
328 "cr.define('a.b.e.f', function() {\n" +
333 public void testCrDefineAndCrExportPathCreateEveryObjectOnlyOnce() throws Exception {
335 "cr.exportPath('a.b.c.d');\n" +
336 "cr.define('a.b.e.f', function() {\n" +
339 "var a = a || {};\n" +
340 "a.b = a.b || {};\n" +
341 "a.b.c = a.b.c || {};\n" +
342 "a.b.c.d = a.b.c.d || {};\n" +
343 "cr.exportPath('a.b.c.d');\n" +
344 "a.b.e = a.b.e || {};\n" +
345 "a.b.e.f = a.b.e.f || {};\n" +
346 "cr.define('a.b.e.f', function() {\n" +
351 public void testCrDefineDoesntRedefineCrVar() throws Exception {
353 "cr.define('cr.ui', function() {\n" +
356 "cr.ui = cr.ui || {};\n" +
357 "cr.define('cr.ui', function() {\n" +
362 public void testCrExportPathInvalidNumberOfArguments() throws Exception {
363 test("cr.exportPath();", null, ChromePass.CR_EXPORT_PATH_WRONG_NUMBER_OF_ARGUMENTS);
366 public void testCrMakePublicWorksOnOneMethodDefinedInPrototypeObject() throws Exception {
368 "/** @constructor */\n" +
369 "function Class() {};\n" +
371 "Class.prototype = {\n" +
372 " /** @return {number} */\n" +
373 " method_: function() { return 42; }\n" +
376 "cr.makePublic(Class, ['method']);",
377 "/** @constructor */\n" +
378 "function Class() {};\n" +
380 "Class.prototype = {\n" +
381 " /** @return {number} */\n" +
382 " method_: function() { return 42; }\n" +
385 "/** @return {number} */\n" +
388 "cr.makePublic(Class, ['method']);");
391 public void testCrMakePublicWorksOnTwoMethods() throws Exception {
393 "/** @constructor */\n" +
394 "function Class() {}\n" +
396 "Class.prototype = {\n" +
397 " /** @return {number} */\n" +
398 " m1_: function() { return 42; },\n" +
400 " /** @return {string} */\n" +
401 " m2_: function() { return ''; }\n" +
404 "cr.makePublic(Class, ['m1', 'm2']);",
405 "/** @constructor */\n" +
406 "function Class() {}\n" +
408 "Class.prototype = {\n" +
409 " /** @return {number} */\n" +
410 " m1_: function() { return 42; },\n" +
412 " /** @return {string} */\n" +
413 " m2_: function() { return ''; }\n" +
416 "/** @return {number} */\n" +
419 "/** @return {string} */\n" +
422 "cr.makePublic(Class, ['m1', 'm2']);");
425 public void testCrMakePublicRequiresMethodsToHaveJSDoc() throws Exception {
426 test("/** @constructor */\n" +
427 "function Class() {}\n" +
429 "Class.prototype = {\n" +
430 " method_: function() {}\n" +
433 "cr.makePublic(Class, ['method']);", null, ChromePass.CR_MAKE_PUBLIC_HAS_NO_JSDOC);
436 public void testCrMakePublicDoesNothingWithMethodsNotInAPI() throws Exception {
438 "/** @constructor */\n" +
439 "function Class() {}\n" +
441 "Class.prototype = {\n" +
442 " method_: function() {}\n" +
445 "cr.makePublic(Class, []);",
446 "/** @constructor */\n" +
447 "function Class() {}\n" +
449 "Class.prototype = {\n" +
450 " method_: function() {}\n" +
453 "cr.makePublic(Class, []);");
456 public void testCrMakePublicRequiresExportedMethodToBeDeclared() throws Exception {
458 "/** @constructor */\n" +
459 "function Class() {}\n" +
461 "Class.prototype = {\n" +
464 "cr.makePublic(Class, ['method']);", null,
465 ChromePass.CR_MAKE_PUBLIC_MISSED_DECLARATION);
468 public void testCrMakePublicWorksOnOneMethodDefinedDirectlyOnPrototype() throws Exception {
470 "/** @constructor */\n" +
471 "function Class() {}\n" +
473 "/** @return {number} */\n" +
474 "Class.prototype.method_ = function() {};\n" +
476 "cr.makePublic(Class, ['method']);",
477 "/** @constructor */\n" +
478 "function Class() {}\n" +
480 "/** @return {number} */\n" +
481 "Class.prototype.method_ = function() {};\n" +
483 "/** @return {number} */\n" +
486 "cr.makePublic(Class, ['method']);");
489 public void testCrMakePublicWorksOnDummyDeclaration() throws Exception {
491 "/** @constructor */\n" +
492 "function Class() {}\n" +
494 "/** @return {number} */\n" +
495 "Class.prototype.method_;\n" +
497 "cr.makePublic(Class, ['method']);",
498 "/** @constructor */\n" +
499 "function Class() {}\n" +
501 "/** @return {number} */\n" +
502 "Class.prototype.method_;\n" +
504 "/** @return {number} */\n" +
507 "cr.makePublic(Class, ['method']);");
510 public void testCrMakePublicReportsInvalidSecondArgumentMissing() throws Exception {
512 "cr.makePublic(Class);", null,
513 ChromePass.CR_MAKE_PUBLIC_INVALID_SECOND_ARGUMENT);
516 public void testCrMakePublicReportsInvalidSecondArgumentNotAnArray() throws Exception {
518 "cr.makePublic(Class, 42);", null,
519 ChromePass.CR_MAKE_PUBLIC_INVALID_SECOND_ARGUMENT);
522 public void testCrMakePublicReportsInvalidSecondArgumentArrayWithNotAString() throws Exception {
524 "cr.makePublic(Class, [42]);", null,
525 ChromePass.CR_MAKE_PUBLIC_INVALID_SECOND_ARGUMENT);