Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(63)

Side by Side Diff: third_party/closure_linter/closure_linter/closurizednamespacesinfo_test.py

Issue 2592193002: Remove closure_linter from Chrome (Closed)
Patch Set: Created 3 years, 12 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 #
3 # Copyright 2010 The Closure Linter Authors. All Rights Reserved.
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS-IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 """Unit tests for ClosurizedNamespacesInfo."""
18
19
20
21 import unittest as googletest
22 from closure_linter import aliaspass
23 from closure_linter import closurizednamespacesinfo
24 from closure_linter import ecmametadatapass
25 from closure_linter import javascriptstatetracker
26 from closure_linter import javascripttokens
27 from closure_linter import testutil
28 from closure_linter import tokenutil
29
30 # pylint: disable=g-bad-name
31 TokenType = javascripttokens.JavaScriptTokenType
32
33
34 def _ToLineDict(illegal_alias_stmts):
35 """Replaces tokens with the respective line number."""
36 return {k: v.line_number for k, v in illegal_alias_stmts.iteritems()}
37
38
39 class ClosurizedNamespacesInfoTest(googletest.TestCase):
40 """Tests for ClosurizedNamespacesInfo."""
41
42 _test_cases = {
43 'goog.global.anything': None,
44 'package.CONSTANT': 'package',
45 'package.methodName': 'package',
46 'package.subpackage.methodName': 'package.subpackage',
47 'package.subpackage.methodName.apply': 'package.subpackage',
48 'package.ClassName.something': 'package.ClassName',
49 'package.ClassName.Enum.VALUE.methodName': 'package.ClassName',
50 'package.ClassName.CONSTANT': 'package.ClassName',
51 'package.namespace.CONSTANT.methodName': 'package.namespace',
52 'package.ClassName.inherits': 'package.ClassName',
53 'package.ClassName.apply': 'package.ClassName',
54 'package.ClassName.methodName.apply': 'package.ClassName',
55 'package.ClassName.methodName.call': 'package.ClassName',
56 'package.ClassName.prototype.methodName': 'package.ClassName',
57 'package.ClassName.privateMethod_': 'package.ClassName',
58 'package.className.privateProperty_': 'package.className',
59 'package.className.privateProperty_.methodName': 'package.className',
60 'package.ClassName.PrivateEnum_': 'package.ClassName',
61 'package.ClassName.prototype.methodName.apply': 'package.ClassName',
62 'package.ClassName.property.subProperty': 'package.ClassName',
63 'package.className.prototype.something.somethingElse': 'package.className'
64 }
65
66 def testGetClosurizedNamespace(self):
67 """Tests that the correct namespace is returned for various identifiers."""
68 namespaces_info = closurizednamespacesinfo.ClosurizedNamespacesInfo(
69 closurized_namespaces=['package'], ignored_extra_namespaces=[])
70 for identifier, expected_namespace in self._test_cases.items():
71 actual_namespace = namespaces_info.GetClosurizedNamespace(identifier)
72 self.assertEqual(
73 expected_namespace,
74 actual_namespace,
75 'expected namespace "' + str(expected_namespace) +
76 '" for identifier "' + str(identifier) + '" but was "' +
77 str(actual_namespace) + '"')
78
79 def testIgnoredExtraNamespaces(self):
80 """Tests that ignored_extra_namespaces are ignored."""
81 token = self._GetRequireTokens('package.Something')
82 namespaces_info = closurizednamespacesinfo.ClosurizedNamespacesInfo(
83 closurized_namespaces=['package'],
84 ignored_extra_namespaces=['package.Something'])
85
86 self.assertFalse(namespaces_info.IsExtraRequire(token),
87 'Should be valid since it is in ignored namespaces.')
88
89 namespaces_info = closurizednamespacesinfo.ClosurizedNamespacesInfo(
90 ['package'], [])
91
92 self.assertTrue(namespaces_info.IsExtraRequire(token),
93 'Should be invalid since it is not in ignored namespaces.')
94
95 def testIsExtraProvide_created(self):
96 """Tests that provides for created namespaces are not extra."""
97 input_lines = [
98 'goog.provide(\'package.Foo\');',
99 'package.Foo = function() {};'
100 ]
101
102 token, namespaces_info = self._GetStartTokenAndNamespacesInfoForScript(
103 input_lines, ['package'])
104
105 self.assertFalse(namespaces_info.IsExtraProvide(token),
106 'Should not be extra since it is created.')
107
108 def testIsExtraProvide_createdIdentifier(self):
109 """Tests that provides for created identifiers are not extra."""
110 input_lines = [
111 'goog.provide(\'package.Foo.methodName\');',
112 'package.Foo.methodName = function() {};'
113 ]
114
115 token, namespaces_info = self._GetStartTokenAndNamespacesInfoForScript(
116 input_lines, ['package'])
117
118 self.assertFalse(namespaces_info.IsExtraProvide(token),
119 'Should not be extra since it is created.')
120
121 def testIsExtraProvide_notCreated(self):
122 """Tests that provides for non-created namespaces are extra."""
123 input_lines = ['goog.provide(\'package.Foo\');']
124
125 token, namespaces_info = self._GetStartTokenAndNamespacesInfoForScript(
126 input_lines, ['package'])
127
128 self.assertTrue(namespaces_info.IsExtraProvide(token),
129 'Should be extra since it is not created.')
130
131 def testIsExtraProvide_notCreatedMultipartClosurizedNamespace(self):
132 """Tests that provides for non-created namespaces are extra."""
133 input_lines = ['goog.provide(\'multi.part.namespace.Foo\');']
134
135 token, namespaces_info = self._GetStartTokenAndNamespacesInfoForScript(
136 input_lines, ['multi.part'])
137
138 self.assertTrue(namespaces_info.IsExtraProvide(token),
139 'Should be extra since it is not created.')
140
141 def testIsExtraProvide_duplicate(self):
142 """Tests that providing a namespace twice makes the second one extra."""
143 input_lines = [
144 'goog.provide(\'package.Foo\');',
145 'goog.provide(\'package.Foo\');',
146 'package.Foo = function() {};'
147 ]
148
149 token, namespaces_info = self._GetStartTokenAndNamespacesInfoForScript(
150 input_lines, ['package'])
151
152 # Advance to the second goog.provide token.
153 token = tokenutil.Search(token.next, TokenType.IDENTIFIER)
154
155 self.assertTrue(namespaces_info.IsExtraProvide(token),
156 'Should be extra since it is already provided.')
157
158 def testIsExtraProvide_notClosurized(self):
159 """Tests that provides of non-closurized namespaces are not extra."""
160 input_lines = ['goog.provide(\'notclosurized.Foo\');']
161
162 token, namespaces_info = self._GetStartTokenAndNamespacesInfoForScript(
163 input_lines, ['package'])
164
165 self.assertFalse(namespaces_info.IsExtraProvide(token),
166 'Should not be extra since it is not closurized.')
167
168 def testIsExtraRequire_used(self):
169 """Tests that requires for used namespaces are not extra."""
170 input_lines = [
171 'goog.require(\'package.Foo\');',
172 'var x = package.Foo.methodName();'
173 ]
174
175 token, namespaces_info = self._GetStartTokenAndNamespacesInfoForScript(
176 input_lines, ['package'])
177
178 self.assertFalse(namespaces_info.IsExtraRequire(token),
179 'Should not be extra since it is used.')
180
181 def testIsExtraRequire_usedIdentifier(self):
182 """Tests that requires for used methods on classes are extra."""
183 input_lines = [
184 'goog.require(\'package.Foo.methodName\');',
185 'var x = package.Foo.methodName();'
186 ]
187
188 token, namespaces_info = self._GetStartTokenAndNamespacesInfoForScript(
189 input_lines, ['package'])
190
191 self.assertTrue(namespaces_info.IsExtraRequire(token),
192 'Should require the package, not the method specifically.')
193
194 def testIsExtraRequire_notUsed(self):
195 """Tests that requires for unused namespaces are extra."""
196 input_lines = ['goog.require(\'package.Foo\');']
197
198 token, namespaces_info = self._GetStartTokenAndNamespacesInfoForScript(
199 input_lines, ['package'])
200
201 self.assertTrue(namespaces_info.IsExtraRequire(token),
202 'Should be extra since it is not used.')
203
204 def testIsExtraRequire_notUsedMultiPartClosurizedNamespace(self):
205 """Tests unused require with multi-part closurized namespaces."""
206
207 input_lines = ['goog.require(\'multi.part.namespace.Foo\');']
208
209 token, namespaces_info = self._GetStartTokenAndNamespacesInfoForScript(
210 input_lines, ['multi.part'])
211
212 self.assertTrue(namespaces_info.IsExtraRequire(token),
213 'Should be extra since it is not used.')
214
215 def testIsExtraRequire_notClosurized(self):
216 """Tests that requires of non-closurized namespaces are not extra."""
217 input_lines = ['goog.require(\'notclosurized.Foo\');']
218
219 token, namespaces_info = self._GetStartTokenAndNamespacesInfoForScript(
220 input_lines, ['package'])
221
222 self.assertFalse(namespaces_info.IsExtraRequire(token),
223 'Should not be extra since it is not closurized.')
224
225 def testIsExtraRequire_objectOnClass(self):
226 """Tests that requiring an object on a class is extra."""
227 input_lines = [
228 'goog.require(\'package.Foo.Enum\');',
229 'var x = package.Foo.Enum.VALUE1;',
230 ]
231
232 token, namespaces_info = self._GetStartTokenAndNamespacesInfoForScript(
233 input_lines, ['package'])
234
235 self.assertTrue(namespaces_info.IsExtraRequire(token),
236 'The whole class, not the object, should be required.');
237
238 def testIsExtraRequire_constantOnClass(self):
239 """Tests that requiring a constant on a class is extra."""
240 input_lines = [
241 'goog.require(\'package.Foo.CONSTANT\');',
242 'var x = package.Foo.CONSTANT',
243 ]
244
245 token, namespaces_info = self._GetStartTokenAndNamespacesInfoForScript(
246 input_lines, ['package'])
247
248 self.assertTrue(namespaces_info.IsExtraRequire(token),
249 'The class, not the constant, should be required.');
250
251 def testIsExtraRequire_constantNotOnClass(self):
252 """Tests that requiring a constant not on a class is OK."""
253 input_lines = [
254 'goog.require(\'package.subpackage.CONSTANT\');',
255 'var x = package.subpackage.CONSTANT',
256 ]
257
258 token, namespaces_info = self._GetStartTokenAndNamespacesInfoForScript(
259 input_lines, ['package'])
260
261 self.assertFalse(namespaces_info.IsExtraRequire(token),
262 'Constants can be required except on classes.');
263
264 def testIsExtraRequire_methodNotOnClass(self):
265 """Tests that requiring a method not on a class is OK."""
266 input_lines = [
267 'goog.require(\'package.subpackage.method\');',
268 'var x = package.subpackage.method()',
269 ]
270
271 token, namespaces_info = self._GetStartTokenAndNamespacesInfoForScript(
272 input_lines, ['package'])
273
274 self.assertFalse(namespaces_info.IsExtraRequire(token),
275 'Methods can be required except on classes.');
276
277 def testIsExtraRequire_defaults(self):
278 """Tests that there are no warnings about extra requires for test utils"""
279 input_lines = ['goog.require(\'goog.testing.jsunit\');']
280
281 token, namespaces_info = self._GetStartTokenAndNamespacesInfoForScript(
282 input_lines, ['goog'])
283
284 self.assertFalse(namespaces_info.IsExtraRequire(token),
285 'Should not be extra since it is for testing.')
286
287 def testGetMissingProvides_provided(self):
288 """Tests that provided functions don't cause a missing provide."""
289 input_lines = [
290 'goog.provide(\'package.Foo\');',
291 'package.Foo = function() {};'
292 ]
293
294 namespaces_info = self._GetNamespacesInfoForScript(
295 input_lines, ['package'])
296
297 self.assertEquals(0, len(namespaces_info.GetMissingProvides()))
298
299 def testGetMissingProvides_providedIdentifier(self):
300 """Tests that provided identifiers don't cause a missing provide."""
301 input_lines = [
302 'goog.provide(\'package.Foo.methodName\');',
303 'package.Foo.methodName = function() {};'
304 ]
305
306 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['package'])
307 self.assertEquals(0, len(namespaces_info.GetMissingProvides()))
308
309 def testGetMissingProvides_providedParentIdentifier(self):
310 """Tests that provided identifiers on a class don't cause a missing provide
311 on objects attached to that class."""
312 input_lines = [
313 'goog.provide(\'package.foo.ClassName\');',
314 'package.foo.ClassName.methodName = function() {};',
315 'package.foo.ClassName.ObjectName = 1;',
316 ]
317
318 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['package'])
319 self.assertEquals(0, len(namespaces_info.GetMissingProvides()))
320
321 def testGetMissingProvides_unprovided(self):
322 """Tests that unprovided functions cause a missing provide."""
323 input_lines = ['package.Foo = function() {};']
324
325 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['package'])
326
327 missing_provides = namespaces_info.GetMissingProvides()
328 self.assertEquals(1, len(missing_provides))
329 missing_provide = missing_provides.popitem()
330 self.assertEquals('package.Foo', missing_provide[0])
331 self.assertEquals(1, missing_provide[1])
332
333 def testGetMissingProvides_privatefunction(self):
334 """Tests that unprovided private functions don't cause a missing provide."""
335 input_lines = ['package.Foo_ = function() {};']
336
337 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['package'])
338 self.assertEquals(0, len(namespaces_info.GetMissingProvides()))
339
340 def testGetMissingProvides_required(self):
341 """Tests that required namespaces don't cause a missing provide."""
342 input_lines = [
343 'goog.require(\'package.Foo\');',
344 'package.Foo.methodName = function() {};'
345 ]
346
347 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['package'])
348 self.assertEquals(0, len(namespaces_info.GetMissingProvides()))
349
350 def testGetMissingRequires_required(self):
351 """Tests that required namespaces don't cause a missing require."""
352 input_lines = [
353 'goog.require(\'package.Foo\');',
354 'package.Foo();'
355 ]
356
357 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['package'])
358 missing_requires, _ = namespaces_info.GetMissingRequires()
359 self.assertEquals(0, len(missing_requires))
360
361 def testGetMissingRequires_requiredIdentifier(self):
362 """Tests that required namespaces satisfy identifiers on that namespace."""
363 input_lines = [
364 'goog.require(\'package.Foo\');',
365 'package.Foo.methodName();'
366 ]
367
368 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['package'])
369 missing_requires, _ = namespaces_info.GetMissingRequires()
370 self.assertEquals(0, len(missing_requires))
371
372 def testGetMissingRequires_requiredNamespace(self):
373 """Tests that required namespaces satisfy the namespace."""
374 input_lines = [
375 'goog.require(\'package.soy.fooTemplate\');',
376 'render(package.soy.fooTemplate);'
377 ]
378
379 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['package'])
380 missing_requires, _ = namespaces_info.GetMissingRequires()
381 self.assertEquals(0, len(missing_requires))
382
383 def testGetMissingRequires_requiredParentClass(self):
384 """Tests that requiring a parent class of an object is sufficient to prevent
385 a missing require on that object."""
386 input_lines = [
387 'goog.require(\'package.Foo\');',
388 'package.Foo.methodName();',
389 'package.Foo.methodName(package.Foo.ObjectName);'
390 ]
391
392 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['package'])
393 missing_requires, _ = namespaces_info.GetMissingRequires()
394 self.assertEquals(0, len(missing_requires))
395
396 def testGetMissingRequires_unrequired(self):
397 """Tests that unrequired namespaces cause a missing require."""
398 input_lines = ['package.Foo();']
399
400 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['package'])
401
402 missing_requires, _ = namespaces_info.GetMissingRequires()
403 self.assertEquals(1, len(missing_requires))
404 missing_req = missing_requires.popitem()
405 self.assertEquals('package.Foo', missing_req[0])
406 self.assertEquals(1, missing_req[1])
407
408 def testGetMissingRequires_provided(self):
409 """Tests that provided namespaces satisfy identifiers on that namespace."""
410 input_lines = [
411 'goog.provide(\'package.Foo\');',
412 'package.Foo.methodName();'
413 ]
414
415 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['package'])
416 missing_requires, _ = namespaces_info.GetMissingRequires()
417 self.assertEquals(0, len(missing_requires))
418
419 def testGetMissingRequires_created(self):
420 """Tests that created namespaces do not satisfy usage of an identifier."""
421 input_lines = [
422 'package.Foo = function();',
423 'package.Foo.methodName();',
424 'package.Foo.anotherMethodName1();',
425 'package.Foo.anotherMethodName2();'
426 ]
427
428 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['package'])
429
430 missing_requires, _ = namespaces_info.GetMissingRequires()
431 self.assertEquals(1, len(missing_requires))
432 missing_require = missing_requires.popitem()
433 self.assertEquals('package.Foo', missing_require[0])
434 # Make sure line number of first occurrence is reported
435 self.assertEquals(2, missing_require[1])
436
437 def testGetMissingRequires_createdIdentifier(self):
438 """Tests that created identifiers satisfy usage of the identifier."""
439 input_lines = [
440 'package.Foo.methodName = function();',
441 'package.Foo.methodName();'
442 ]
443
444 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['package'])
445 missing_requires, _ = namespaces_info.GetMissingRequires()
446 self.assertEquals(0, len(missing_requires))
447
448 def testGetMissingRequires_implements(self):
449 """Tests that a parametrized type requires the correct identifier."""
450 input_lines = [
451 '/** @constructor @implements {package.Bar<T>} */',
452 'package.Foo = function();',
453 ]
454
455 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['package'])
456 missing_requires, _ = namespaces_info.GetMissingRequires()
457 self.assertItemsEqual({'package.Bar': 1}, missing_requires)
458
459 def testGetMissingRequires_objectOnClass(self):
460 """Tests that we should require a class, not the object on the class."""
461 input_lines = [
462 'goog.require(\'package.Foo.Enum\');',
463 'var x = package.Foo.Enum.VALUE1;',
464 ]
465
466 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['package'])
467 missing_requires, _ = namespaces_info.GetMissingRequires()
468 self.assertEquals(1, len(missing_requires),
469 'The whole class, not the object, should be required.')
470
471 def testGetMissingRequires_variableWithSameName(self):
472 """Tests that we should not goog.require variables and parameters.
473
474 b/5362203 Variables in scope are not missing namespaces.
475 """
476 input_lines = [
477 'goog.provide(\'Foo\');',
478 'Foo.A = function();',
479 'Foo.A.prototype.method = function(ab) {',
480 ' if (ab) {',
481 ' var docs;',
482 ' var lvalue = new Obj();',
483 ' // Variable in scope hence not goog.require here.',
484 ' docs.foo.abc = 1;',
485 ' lvalue.next();',
486 ' }',
487 ' // Since js is function scope this should also not goog.require.',
488 ' docs.foo.func();',
489 ' // Its not a variable in scope hence goog.require.',
490 ' dummy.xyz.reset();',
491 ' return this.method2();',
492 '};',
493 'Foo.A.prototype.method1 = function(docs, abcd, xyz) {',
494 ' // Parameter hence not goog.require.',
495 ' docs.nodes.length = 2;',
496 ' lvalue.abc.reset();',
497 '};'
498 ]
499
500 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['Foo',
501 'docs',
502 'lvalue',
503 'dummy'])
504 missing_requires, _ = namespaces_info.GetMissingRequires()
505 self.assertEquals(2, len(missing_requires))
506 self.assertItemsEqual(
507 {'dummy.xyz': 14,
508 'lvalue.abc': 20}, missing_requires)
509
510 def testIsFirstProvide(self):
511 """Tests operation of the isFirstProvide method."""
512 input_lines = [
513 'goog.provide(\'package.Foo\');',
514 'package.Foo.methodName();'
515 ]
516
517 token, namespaces_info = self._GetStartTokenAndNamespacesInfoForScript(
518 input_lines, ['package'])
519 self.assertTrue(namespaces_info.IsFirstProvide(token))
520
521 def testGetWholeIdentifierString(self):
522 """Tests that created identifiers satisfy usage of the identifier."""
523 input_lines = [
524 'package.Foo.',
525 ' veryLong.',
526 ' identifier;'
527 ]
528
529 token = testutil.TokenizeSource(input_lines)
530
531 self.assertEquals('package.Foo.veryLong.identifier',
532 tokenutil.GetIdentifierForToken(token))
533
534 self.assertEquals(None,
535 tokenutil.GetIdentifierForToken(token.next))
536
537 def testScopified(self):
538 """Tests that a goog.scope call is noticed."""
539 input_lines = [
540 'goog.scope(function() {',
541 '});'
542 ]
543
544 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['goog'])
545 self.assertTrue(namespaces_info._scopified_file)
546
547 def testScope_unusedAlias(self):
548 """Tests that an unused alias symbol is illegal."""
549 input_lines = [
550 'goog.scope(function() {',
551 'var Event = goog.events.Event;',
552 '});'
553 ]
554
555 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['goog'])
556 missing_requires, illegal_alias_stmts = namespaces_info.GetMissingRequires()
557 self.assertEquals({}, missing_requires)
558 self.assertEquals({'goog.events': 2}, _ToLineDict(illegal_alias_stmts))
559
560 def testScope_usedMultilevelAlias(self):
561 """Tests that an used alias symbol in a deep namespace is ok."""
562 input_lines = [
563 'goog.require(\'goog.Events\');',
564 'goog.scope(function() {',
565 'var Event = goog.Events.DeepNamespace.Event;',
566 'Event();',
567 '});'
568 ]
569
570 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['goog'])
571 missing_requires, illegal_alias_stmts = namespaces_info.GetMissingRequires()
572 self.assertEquals({}, missing_requires)
573 self.assertEquals({}, illegal_alias_stmts)
574
575 def testScope_usedAlias(self):
576 """Tests that aliased symbols result in correct requires."""
577 input_lines = [
578 'goog.scope(function() {',
579 'var Event = goog.events.Event;',
580 'var dom = goog.dom;',
581 'Event(dom.classes.get);',
582 '});'
583 ]
584
585 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['goog'])
586 missing_requires, illegal_alias_stmts = namespaces_info.GetMissingRequires()
587 self.assertEquals({}, illegal_alias_stmts)
588 self.assertEquals({'goog.dom.classes': 4, 'goog.events.Event': 4},
589 missing_requires)
590
591 def testModule_alias(self):
592 """Tests that goog.module style aliases are supported."""
593 input_lines = [
594 'goog.module(\'test.module\');',
595 'var Unused = goog.require(\'goog.Unused\');',
596 'var AliasedClass = goog.require(\'goog.AliasedClass\');',
597 'var x = new AliasedClass();',
598 ]
599
600 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['goog'])
601 namespaceToken = self._GetRequireTokens('goog.AliasedClass')
602 self.assertFalse(namespaces_info.IsExtraRequire(namespaceToken),
603 'AliasedClass should be marked as used')
604 unusedToken = self._GetRequireTokens('goog.Unused')
605 self.assertTrue(namespaces_info.IsExtraRequire(unusedToken),
606 'Unused should be marked as not used')
607
608 def testModule_aliasInScope(self):
609 """Tests that goog.module style aliases are supported."""
610 input_lines = [
611 'goog.module(\'test.module\');',
612 'var AliasedClass = goog.require(\'goog.AliasedClass\');',
613 'goog.scope(function() {',
614 'var x = new AliasedClass();',
615 '});',
616 ]
617
618 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['goog'])
619 namespaceToken = self._GetRequireTokens('goog.AliasedClass')
620 self.assertFalse(namespaces_info.IsExtraRequire(namespaceToken),
621 'AliasedClass should be marked as used')
622
623 def testModule_getAlwaysProvided(self):
624 """Tests that goog.module.get is recognized as a built-in."""
625 input_lines = [
626 'goog.provide(\'test.MyClass\');',
627 'goog.require(\'goog.someModule\');',
628 'goog.scope(function() {',
629 'var someModule = goog.module.get(\'goog.someModule\');',
630 'test.MyClass = function() {};',
631 '});',
632 ]
633
634 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['goog'])
635 self.assertEquals({}, namespaces_info.GetMissingRequires()[0])
636
637 def testModule_requireForGet(self):
638 """Tests that goog.module.get needs a goog.require call."""
639 input_lines = [
640 'goog.provide(\'test.MyClass\');',
641 'function foo() {',
642 ' var someModule = goog.module.get(\'goog.someModule\');',
643 ' someModule.doSth();',
644 '}',
645 ]
646
647 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['goog'])
648 self.assertEquals({'goog.someModule': 3},
649 namespaces_info.GetMissingRequires()[0])
650
651 def testScope_usedTypeAlias(self):
652 """Tests aliased symbols in type annotations."""
653 input_lines = [
654 'goog.scope(function() {',
655 'var Event = goog.events.Event;',
656 '/** @type {Event} */;',
657 '});'
658 ]
659
660 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['goog'])
661 missing_requires, illegal_alias_stmts = namespaces_info.GetMissingRequires()
662 self.assertEquals({}, missing_requires)
663 self.assertEquals({'goog.events': 2}, _ToLineDict(illegal_alias_stmts))
664
665 def testScope_partialAlias_typeOnly(self):
666 """Tests a partial alias only used in type annotations.
667
668 In this example, some goog.events namespace would need to be required
669 so that evaluating goog.events.bar doesn't throw an error.
670 """
671 input_lines = [
672 'goog.scope(function() {',
673 'var bar = goog.events.bar;',
674 '/** @type {bar.Foo} */;',
675 '});'
676 ]
677
678 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['goog'])
679 missing_requires, illegal_alias_stmts = namespaces_info.GetMissingRequires()
680 self.assertEquals({}, missing_requires)
681 self.assertEquals({'goog.events': 2}, _ToLineDict(illegal_alias_stmts))
682
683 def testScope_partialAlias(self):
684 """Tests a partial alias in conjunction with a type annotation.
685
686 In this example, the partial alias is already defined by another type,
687 therefore the doc-only type doesn't need to be required.
688 """
689 input_lines = [
690 'goog.scope(function() {',
691 'var bar = goog.events.bar;',
692 '/** @type {bar.Event} */;',
693 'bar.EventType();'
694 '});'
695 ]
696
697 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['goog'])
698 missing_requires, illegal_alias_stmts = namespaces_info.GetMissingRequires()
699 self.assertEquals({'goog.events.bar.EventType': 4}, missing_requires)
700 self.assertEquals({}, illegal_alias_stmts)
701
702 def testScope_partialAliasRequires(self):
703 """Tests partial aliases with correct requires."""
704 input_lines = [
705 'goog.require(\'goog.events.bar.EventType\');',
706 'goog.scope(function() {',
707 'var bar = goog.events.bar;',
708 '/** @type {bar.Event} */;',
709 'bar.EventType();'
710 '});'
711 ]
712
713 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['goog'])
714 missing_requires, illegal_alias_stmts = namespaces_info.GetMissingRequires()
715 self.assertEquals({}, missing_requires)
716 self.assertEquals({}, illegal_alias_stmts)
717
718 def testScope_partialAliasRequiresBoth(self):
719 """Tests partial aliases with correct requires."""
720 input_lines = [
721 'goog.require(\'goog.events.bar.Event\');',
722 'goog.require(\'goog.events.bar.EventType\');',
723 'goog.scope(function() {',
724 'var bar = goog.events.bar;',
725 '/** @type {bar.Event} */;',
726 'bar.EventType();'
727 '});'
728 ]
729
730 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['goog'])
731 missing_requires, illegal_alias_stmts = namespaces_info.GetMissingRequires()
732 self.assertEquals({}, missing_requires)
733 self.assertEquals({}, illegal_alias_stmts)
734 event_token = self._GetRequireTokens('goog.events.bar.Event')
735 self.assertTrue(namespaces_info.IsExtraRequire(event_token))
736
737 def testScope_partialAliasNoSubtypeRequires(self):
738 """Tests that partial aliases don't yield subtype requires (regression)."""
739 input_lines = [
740 'goog.provide(\'goog.events.Foo\');',
741 'goog.scope(function() {',
742 'goog.events.Foo = {};',
743 'var Foo = goog.events.Foo;'
744 'Foo.CssName_ = {};'
745 'var CssName_ = Foo.CssName_;'
746 '});'
747 ]
748
749 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['goog'])
750 missing_requires, _ = namespaces_info.GetMissingRequires()
751 self.assertEquals({}, missing_requires)
752
753 def testScope_aliasNamespace(self):
754 """Tests that an unused alias namespace is not required when available.
755
756 In the example goog.events.Bar is not required, because the namespace
757 goog.events is already defined because goog.events.Foo is required.
758 """
759 input_lines = [
760 'goog.require(\'goog.events.Foo\');',
761 'goog.scope(function() {',
762 'var Bar = goog.events.Bar;',
763 '/** @type {Bar} */;',
764 'goog.events.Foo;',
765 '});'
766 ]
767
768 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['goog'])
769 missing_requires, illegal_alias_stmts = namespaces_info.GetMissingRequires()
770 self.assertEquals({}, missing_requires)
771 self.assertEquals({}, illegal_alias_stmts)
772
773 def testScope_aliasNamespaceIllegal(self):
774 """Tests that an unused alias namespace is not required when available."""
775 input_lines = [
776 'goog.scope(function() {',
777 'var Bar = goog.events.Bar;',
778 '/** @type {Bar} */;',
779 '});'
780 ]
781
782 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['goog'])
783 missing_requires, illegal_alias_stmts = namespaces_info.GetMissingRequires()
784 self.assertEquals({}, missing_requires)
785 self.assertEquals({'goog.events': 2}, _ToLineDict(illegal_alias_stmts))
786
787 def testScope_provides(self):
788 """Tests that aliased symbols result in correct provides."""
789 input_lines = [
790 'goog.scope(function() {',
791 'goog.bar = {};',
792 'var bar = goog.bar;',
793 'bar.Foo = {};',
794 '});'
795 ]
796
797 namespaces_info = self._GetNamespacesInfoForScript(input_lines, ['goog'])
798 missing_provides = namespaces_info.GetMissingProvides()
799 self.assertEquals({'goog.bar.Foo': 4}, missing_provides)
800 _, illegal_alias_stmts = namespaces_info.GetMissingRequires()
801 self.assertEquals({}, illegal_alias_stmts)
802
803 def testSetTestOnlyNamespaces(self):
804 """Tests that a namespace in setTestOnly makes it a valid provide."""
805 namespaces_info = self._GetNamespacesInfoForScript([
806 'goog.setTestOnly(\'goog.foo.barTest\');'
807 ], ['goog'])
808
809 token = self._GetProvideTokens('goog.foo.barTest')
810 self.assertFalse(namespaces_info.IsExtraProvide(token))
811
812 token = self._GetProvideTokens('goog.foo.bazTest')
813 self.assertTrue(namespaces_info.IsExtraProvide(token))
814
815 def testSetTestOnlyComment(self):
816 """Ensure a comment in setTestOnly does not cause a created namespace."""
817 namespaces_info = self._GetNamespacesInfoForScript([
818 'goog.setTestOnly(\'this is a comment\');'
819 ], ['goog'])
820
821 self.assertEquals(
822 [], namespaces_info._created_namespaces,
823 'A comment in setTestOnly should not modify created namespaces.')
824
825 def _GetNamespacesInfoForScript(self, script, closurized_namespaces=None):
826 _, namespaces_info = self._GetStartTokenAndNamespacesInfoForScript(
827 script, closurized_namespaces)
828
829 return namespaces_info
830
831 def _GetStartTokenAndNamespacesInfoForScript(
832 self, script, closurized_namespaces):
833
834 token = testutil.TokenizeSource(script)
835 return token, self._GetInitializedNamespacesInfo(
836 token, closurized_namespaces, [])
837
838 def _GetInitializedNamespacesInfo(self, token, closurized_namespaces,
839 ignored_extra_namespaces):
840 """Returns a namespaces info initialized with the given token stream."""
841 namespaces_info = closurizednamespacesinfo.ClosurizedNamespacesInfo(
842 closurized_namespaces=closurized_namespaces,
843 ignored_extra_namespaces=ignored_extra_namespaces)
844 state_tracker = javascriptstatetracker.JavaScriptStateTracker()
845
846 ecma_pass = ecmametadatapass.EcmaMetaDataPass()
847 ecma_pass.Process(token)
848
849 state_tracker.DocFlagPass(token, error_handler=None)
850
851 alias_pass = aliaspass.AliasPass(closurized_namespaces)
852 alias_pass.Process(token)
853
854 while token:
855 state_tracker.HandleToken(token, state_tracker.GetLastNonSpaceToken())
856 namespaces_info.ProcessToken(token, state_tracker)
857 state_tracker.HandleAfterToken(token)
858 token = token.next
859
860 return namespaces_info
861
862 def _GetProvideTokens(self, namespace):
863 """Returns a list of tokens for a goog.require of the given namespace."""
864 line_text = 'goog.require(\'' + namespace + '\');\n'
865 return testutil.TokenizeSource([line_text])
866
867 def _GetRequireTokens(self, namespace):
868 """Returns a list of tokens for a goog.require of the given namespace."""
869 line_text = 'goog.require(\'' + namespace + '\');\n'
870 return testutil.TokenizeSource([line_text])
871
872 if __name__ == '__main__':
873 googletest.main()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698