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 testCrDefineDoesNothingWithExportedNotAName() throws Exception {
197 "cr.define('namespace', function() {\n" +
202 "var namespace = namespace || {};\n" +
203 "cr.define('namespace', function() {\n" +
210 public void testCrDefineChangesReferenceToExportedFunction() throws Exception {
212 "cr.define('namespace', function() {\n" +
213 " function internalStaticMethod() {\n" +
216 " function letsUseIt() {\n" +
217 " internalStaticMethod();\n" +
220 " externalStaticMethod: internalStaticMethod\n" +
223 "var namespace = namespace || {};\n" +
224 "cr.define('namespace', function() {\n" +
225 " namespace.externalStaticMethod = function internalStaticMethod() {\n" +
228 " function letsUseIt() {\n" +
229 " namespace.externalStaticMethod();\n" +
232 " externalStaticMethod: namespace.externalStaticMethod\n" +
237 public void testCrDefineWrongNumberOfArguments() throws Exception {
238 test("cr.define('namespace', function() { return {}; }, 'invalid argument')\n",
239 null, ChromePass.CR_DEFINE_WRONG_NUMBER_OF_ARGUMENTS);
242 public void testCrDefineInvalidFirstArgument() throws Exception {
243 test("cr.define(42, function() { return {}; })\n",
244 null, ChromePass.CR_DEFINE_INVALID_FIRST_ARGUMENT);
247 public void testCrDefineInvalidSecondArgument() throws Exception {
248 test("cr.define('namespace', 42)\n",
249 null, ChromePass.CR_DEFINE_INVALID_SECOND_ARGUMENT);
252 public void testCrDefineInvalidReturnInFunction() throws Exception {
253 test("cr.define('namespace', function() {})\n",
254 null, ChromePass.CR_DEFINE_INVALID_RETURN_IN_FUNCTION);
257 public void testObjectDefinePropertyDefinesUnquotedProperty() throws Exception {
259 "Object.defineProperty(a.b, 'c', {});",
260 "Object.defineProperty(a.b, 'c', {});\n" +
261 "/** @type {?} */\n" +
265 public void testCrDefinePropertyDefinesUnquotedPropertyWithStringTypeForPropertyKindAttr()
268 "cr.defineProperty(a.prototype, 'c', cr.PropertyKind.ATTR);",
269 "cr.defineProperty(a.prototype, 'c', cr.PropertyKind.ATTR);\n" +
270 "/** @type {string} */\n" +
274 public void testCrDefinePropertyDefinesUnquotedPropertyWithBooleanTypeForPropertyKindBoolAttr()
277 "cr.defineProperty(a.prototype, 'c', cr.PropertyKind.BOOL_ATTR);",
278 "cr.defineProperty(a.prototype, 'c', cr.PropertyKind.BOOL_ATTR);\n" +
279 "/** @type {boolean} */\n" +
283 public void testCrDefinePropertyDefinesUnquotedPropertyWithAnyTypeForPropertyKindJs()
286 "cr.defineProperty(a.prototype, 'c', cr.PropertyKind.JS);",
287 "cr.defineProperty(a.prototype, 'c', cr.PropertyKind.JS);\n" +
288 "/** @type {?} */\n" +
292 public void testCrDefinePropertyCalledWithouthThirdArgumentMeansCrPropertyKindJs()
295 "cr.defineProperty(a.prototype, 'c');",
296 "cr.defineProperty(a.prototype, 'c');\n" +
297 "/** @type {?} */\n" +
301 public void testCrDefinePropertyDefinesUnquotedPropertyOnPrototypeWhenFunctionIsPassed()
304 "cr.defineProperty(a, 'c', cr.PropertyKind.JS);",
305 "cr.defineProperty(a, 'c', cr.PropertyKind.JS);\n" +
306 "/** @type {?} */\n" +
310 public void testCrDefinePropertyInvalidPropertyKind()
313 "cr.defineProperty(a.b, 'c', cr.PropertyKind.INEXISTENT_KIND);",
314 null, ChromePass.CR_DEFINE_PROPERTY_INVALID_PROPERTY_KIND);
317 public void testCrExportPath() throws Exception {
319 "cr.exportPath('a.b.c');",
320 "var a = a || {};\n" +
321 "a.b = a.b || {};\n" +
322 "a.b.c = a.b.c || {};\n" +
323 "cr.exportPath('a.b.c');");
326 public void testCrDefineCreatesEveryObjectOnlyOnce() throws Exception {
328 "cr.define('a.b.c.d', function() {\n" +
331 "cr.define('a.b.e.f', function() {\n" +
334 "var a = a || {};\n" +
335 "a.b = a.b || {};\n" +
336 "a.b.c = a.b.c || {};\n" +
337 "a.b.c.d = a.b.c.d || {};\n" +
338 "cr.define('a.b.c.d', function() {\n" +
341 "a.b.e = a.b.e || {};\n" +
342 "a.b.e.f = a.b.e.f || {};\n" +
343 "cr.define('a.b.e.f', function() {\n" +
348 public void testCrDefineAndCrExportPathCreateEveryObjectOnlyOnce() throws Exception {
350 "cr.exportPath('a.b.c.d');\n" +
351 "cr.define('a.b.e.f', function() {\n" +
354 "var a = a || {};\n" +
355 "a.b = a.b || {};\n" +
356 "a.b.c = a.b.c || {};\n" +
357 "a.b.c.d = a.b.c.d || {};\n" +
358 "cr.exportPath('a.b.c.d');\n" +
359 "a.b.e = a.b.e || {};\n" +
360 "a.b.e.f = a.b.e.f || {};\n" +
361 "cr.define('a.b.e.f', function() {\n" +
366 public void testCrDefineDoesntRedefineCrVar() throws Exception {
368 "cr.define('cr.ui', function() {\n" +
371 "cr.ui = cr.ui || {};\n" +
372 "cr.define('cr.ui', function() {\n" +
377 public void testCrExportPathInvalidNumberOfArguments() throws Exception {
378 test("cr.exportPath();", null, ChromePass.CR_EXPORT_PATH_WRONG_NUMBER_OF_ARGUMENTS);
381 public void testCrMakePublicWorksOnOneMethodDefinedInPrototypeObject() throws Exception {
383 "/** @constructor */\n" +
384 "function Class() {};\n" +
386 "Class.prototype = {\n" +
387 " /** @return {number} */\n" +
388 " method_: function() { return 42; }\n" +
391 "cr.makePublic(Class, ['method']);",
392 "/** @constructor */\n" +
393 "function Class() {};\n" +
395 "Class.prototype = {\n" +
396 " /** @return {number} */\n" +
397 " method_: function() { return 42; }\n" +
400 "/** @return {number} */\n" +
403 "cr.makePublic(Class, ['method']);");
406 public void testCrMakePublicWorksOnTwoMethods() throws Exception {
408 "/** @constructor */\n" +
409 "function Class() {}\n" +
411 "Class.prototype = {\n" +
412 " /** @return {number} */\n" +
413 " m1_: function() { return 42; },\n" +
415 " /** @return {string} */\n" +
416 " m2_: function() { return ''; }\n" +
419 "cr.makePublic(Class, ['m1', 'm2']);",
420 "/** @constructor */\n" +
421 "function Class() {}\n" +
423 "Class.prototype = {\n" +
424 " /** @return {number} */\n" +
425 " m1_: function() { return 42; },\n" +
427 " /** @return {string} */\n" +
428 " m2_: function() { return ''; }\n" +
431 "/** @return {number} */\n" +
434 "/** @return {string} */\n" +
437 "cr.makePublic(Class, ['m1', 'm2']);");
440 public void testCrMakePublicRequiresMethodsToHaveJSDoc() throws Exception {
441 test("/** @constructor */\n" +
442 "function Class() {}\n" +
444 "Class.prototype = {\n" +
445 " method_: function() {}\n" +
448 "cr.makePublic(Class, ['method']);", null, ChromePass.CR_MAKE_PUBLIC_HAS_NO_JSDOC);
451 public void testCrMakePublicDoesNothingWithMethodsNotInAPI() throws Exception {
453 "/** @constructor */\n" +
454 "function Class() {}\n" +
456 "Class.prototype = {\n" +
457 " method_: function() {}\n" +
460 "cr.makePublic(Class, []);",
461 "/** @constructor */\n" +
462 "function Class() {}\n" +
464 "Class.prototype = {\n" +
465 " method_: function() {}\n" +
468 "cr.makePublic(Class, []);");
471 public void testCrMakePublicRequiresExportedMethodToBeDeclared() throws Exception {
473 "/** @constructor */\n" +
474 "function Class() {}\n" +
476 "Class.prototype = {\n" +
479 "cr.makePublic(Class, ['method']);", null,
480 ChromePass.CR_MAKE_PUBLIC_MISSED_DECLARATION);
483 public void testCrMakePublicWorksOnOneMethodDefinedDirectlyOnPrototype() throws Exception {
485 "/** @constructor */\n" +
486 "function Class() {}\n" +
488 "/** @return {number} */\n" +
489 "Class.prototype.method_ = function() {};\n" +
491 "cr.makePublic(Class, ['method']);",
492 "/** @constructor */\n" +
493 "function Class() {}\n" +
495 "/** @return {number} */\n" +
496 "Class.prototype.method_ = function() {};\n" +
498 "/** @return {number} */\n" +
501 "cr.makePublic(Class, ['method']);");
504 public void testCrMakePublicWorksOnDummyDeclaration() throws Exception {
506 "/** @constructor */\n" +
507 "function Class() {}\n" +
509 "/** @return {number} */\n" +
510 "Class.prototype.method_;\n" +
512 "cr.makePublic(Class, ['method']);",
513 "/** @constructor */\n" +
514 "function Class() {}\n" +
516 "/** @return {number} */\n" +
517 "Class.prototype.method_;\n" +
519 "/** @return {number} */\n" +
522 "cr.makePublic(Class, ['method']);");
525 public void testCrMakePublicReportsInvalidSecondArgumentMissing() throws Exception {
527 "cr.makePublic(Class);", null,
528 ChromePass.CR_MAKE_PUBLIC_INVALID_SECOND_ARGUMENT);
531 public void testCrMakePublicReportsInvalidSecondArgumentNotAnArray() throws Exception {
533 "cr.makePublic(Class, 42);", null,
534 ChromePass.CR_MAKE_PUBLIC_INVALID_SECOND_ARGUMENT);
537 public void testCrMakePublicReportsInvalidSecondArgumentArrayWithNotAString() throws Exception {
539 "cr.makePublic(Class, [42]);", null,
540 ChromePass.CR_MAKE_PUBLIC_INVALID_SECOND_ARGUMENT);