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