- add sources.
[platform/framework/web/crosswalk.git] / src / third_party / closure_linter / closure_linter / closurizednamespacesinfo_test.py
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 closurizednamespacesinfo
23 from closure_linter import javascriptstatetracker
24 from closure_linter import javascripttokenizer
25 from closure_linter import javascripttokens
26 from closure_linter import tokenutil
27
28 # pylint: disable-msg=C6409
29 TokenType = javascripttokens.JavaScriptTokenType
30
31
32 class ClosurizedNamespacesInfoTest(googletest.TestCase):
33   """Tests for ClosurizedNamespacesInfo."""
34
35   _test_cases = {
36       'goog.global.anything': None,
37       'package.CONSTANT': 'package',
38       'package.methodName': 'package',
39       'package.subpackage.methodName': 'package.subpackage',
40       'package.subpackage.methodName.apply': 'package.subpackage',
41       'package.ClassName.something': 'package.ClassName',
42       'package.ClassName.Enum.VALUE.methodName': 'package.ClassName',
43       'package.ClassName.CONSTANT': 'package.ClassName',
44       'package.namespace.CONSTANT.methodName': 'package.namespace',
45       'package.ClassName.inherits': 'package.ClassName',
46       'package.ClassName.apply': 'package.ClassName',
47       'package.ClassName.methodName.apply': 'package.ClassName',
48       'package.ClassName.methodName.call': 'package.ClassName',
49       'package.ClassName.prototype.methodName': 'package.ClassName',
50       'package.ClassName.privateMethod_': 'package.ClassName',
51       'package.className.privateProperty_': 'package.className',
52       'package.className.privateProperty_.methodName': 'package.className',
53       'package.ClassName.PrivateEnum_': 'package.ClassName',
54       'package.ClassName.prototype.methodName.apply': 'package.ClassName',
55       'package.ClassName.property.subProperty': 'package.ClassName',
56       'package.className.prototype.something.somethingElse': 'package.className'
57   }
58
59   _tokenizer = javascripttokenizer.JavaScriptTokenizer()
60
61   def testGetClosurizedNamespace(self):
62     """Tests that the correct namespace is returned for various identifiers."""
63     namespaces_info = closurizednamespacesinfo.ClosurizedNamespacesInfo(
64         closurized_namespaces=['package'], ignored_extra_namespaces=[])
65     for identifier, expected_namespace in self._test_cases.items():
66       actual_namespace = namespaces_info.GetClosurizedNamespace(identifier)
67       self.assertEqual(
68           expected_namespace,
69           actual_namespace,
70           'expected namespace "' + str(expected_namespace) +
71           '" for identifier "' + str(identifier) + '" but was "' +
72           str(actual_namespace) + '"')
73
74   def testIgnoredExtraNamespaces(self):
75     """Tests that ignored_extra_namespaces are ignored."""
76     token = self._GetRequireTokens('package.Something')
77     namespaces_info = closurizednamespacesinfo.ClosurizedNamespacesInfo(
78         closurized_namespaces=['package'],
79         ignored_extra_namespaces=['package.Something'])
80
81     self.assertFalse(namespaces_info.IsExtraRequire(token),
82                      'Should be valid since it is in ignored namespaces.')
83
84     namespaces_info = closurizednamespacesinfo.ClosurizedNamespacesInfo(
85         ['package'], [])
86
87     self.assertTrue(namespaces_info.IsExtraRequire(token),
88                     'Should be invalid since it is not in ignored namespaces.')
89
90   def testIsExtraProvide_created(self):
91     """Tests that provides for created namespaces are not extra."""
92     input_lines = [
93         'goog.provide(\'package.Foo\');',
94         'package.Foo = function() {};'
95     ]
96     token = self._tokenizer.TokenizeFile(input_lines)
97     namespaces_info = self._GetInitializedNamespacesInfo(token, ['package'], [])
98
99     self.assertFalse(namespaces_info.IsExtraProvide(token),
100                      'Should not be extra since it is created.')
101
102   def testIsExtraProvide_createdIdentifier(self):
103     """Tests that provides for created identifiers are not extra."""
104     input_lines = [
105         'goog.provide(\'package.Foo.methodName\');',
106         'package.Foo.methodName = function() {};'
107     ]
108     token = self._tokenizer.TokenizeFile(input_lines)
109     namespaces_info = self._GetInitializedNamespacesInfo(token, ['package'], [])
110
111     self.assertFalse(namespaces_info.IsExtraProvide(token),
112                      'Should not be extra since it is created.')
113
114   def testIsExtraProvide_notCreated(self):
115     """Tests that provides for non-created namespaces are extra."""
116     input_lines = ['goog.provide(\'package.Foo\');']
117     token = self._tokenizer.TokenizeFile(input_lines)
118     namespaces_info = self._GetInitializedNamespacesInfo(token, ['package'], [])
119
120     self.assertTrue(namespaces_info.IsExtraProvide(token),
121                     'Should be extra since it is not created.')
122
123   def testIsExtraProvide_duplicate(self):
124     """Tests that providing a namespace twice makes the second one extra."""
125     input_lines = [
126         'goog.provide(\'package.Foo\');',
127         'goog.provide(\'package.Foo\');',
128         'package.Foo = function() {};'
129     ]
130     token = self._tokenizer.TokenizeFile(input_lines)
131     namespaces_info = self._GetInitializedNamespacesInfo(token, ['package'], [])
132
133     # Advance to the second goog.provide token.
134     token = tokenutil.Search(token.next, TokenType.IDENTIFIER)
135
136     self.assertTrue(namespaces_info.IsExtraProvide(token),
137                     'Should be extra since it is already provided.')
138
139   def testIsExtraProvide_notClosurized(self):
140     """Tests that provides of non-closurized namespaces are not extra."""
141     input_lines = ['goog.provide(\'notclosurized.Foo\');']
142     token = self._tokenizer.TokenizeFile(input_lines)
143     namespaces_info = self._GetInitializedNamespacesInfo(token, ['package'], [])
144
145     self.assertFalse(namespaces_info.IsExtraProvide(token),
146                      'Should not be extra since it is not closurized.')
147
148   def testIsExtraRequire_used(self):
149     """Tests that requires for used namespaces are not extra."""
150     input_lines = [
151         'goog.require(\'package.Foo\');',
152         'var x = package.Foo.methodName();'
153     ]
154     token = self._tokenizer.TokenizeFile(input_lines)
155     namespaces_info = self._GetInitializedNamespacesInfo(token, ['package'], [])
156
157     self.assertFalse(namespaces_info.IsExtraRequire(token),
158                      'Should not be extra since it is used.')
159
160   def testIsExtraRequire_usedIdentifier(self):
161     """Tests that requires for used methods on classes are extra."""
162     input_lines = [
163         'goog.require(\'package.Foo.methodName\');',
164         'var x = package.Foo.methodName();'
165     ]
166     token = self._tokenizer.TokenizeFile(input_lines)
167     namespaces_info = self._GetInitializedNamespacesInfo(token, ['package'], [])
168
169     self.assertTrue(namespaces_info.IsExtraRequire(token),
170                     'Should require the package, not the method specifically.')
171
172   def testIsExtraRequire_notUsed(self):
173     """Tests that requires for unused namespaces are extra."""
174     input_lines = ['goog.require(\'package.Foo\');']
175     token = self._tokenizer.TokenizeFile(input_lines)
176     namespaces_info = self._GetInitializedNamespacesInfo(token, ['package'], [])
177
178     self.assertTrue(namespaces_info.IsExtraRequire(token),
179                     'Should be extra since it is not used.')
180
181   def testIsExtraRequire_notClosurized(self):
182     """Tests that requires of non-closurized namespaces are not extra."""
183     input_lines = ['goog.require(\'notclosurized.Foo\');']
184     token = self._tokenizer.TokenizeFile(input_lines)
185     namespaces_info = self._GetInitializedNamespacesInfo(token, ['package'], [])
186
187     self.assertFalse(namespaces_info.IsExtraRequire(token),
188                      'Should not be extra since it is not closurized.')
189
190   def testIsExtraRequire_objectOnClass(self):
191     """Tests that requiring an object on a class is extra."""
192     input_lines = [
193         'goog.require(\'package.Foo.Enum\');',
194         'var x = package.Foo.Enum.VALUE1;',
195     ]
196     token = self._tokenizer.TokenizeFile(input_lines)
197     namespaces_info = self._GetInitializedNamespacesInfo(token, ['package'], [])
198
199     self.assertTrue(namespaces_info.IsExtraRequire(token),
200                     'The whole class, not the object, should be required.');
201
202   def testIsExtraRequire_constantOnClass(self):
203     """Tests that requiring a constant on a class is extra."""
204     input_lines = [
205         'goog.require(\'package.Foo.CONSTANT\');',
206         'var x = package.Foo.CONSTANT',
207     ]
208     token = self._tokenizer.TokenizeFile(input_lines)
209     namespaces_info = self._GetInitializedNamespacesInfo(token, ['package'], [])
210
211     self.assertTrue(namespaces_info.IsExtraRequire(token),
212                     'The class, not the constant, should be required.');
213
214   def testIsExtraRequire_constantNotOnClass(self):
215     """Tests that requiring a constant not on a class is OK."""
216     input_lines = [
217         'goog.require(\'package.subpackage.CONSTANT\');',
218         'var x = package.subpackage.CONSTANT',
219     ]
220     token = self._tokenizer.TokenizeFile(input_lines)
221     namespaces_info = self._GetInitializedNamespacesInfo(token, ['package'], [])
222
223     self.assertFalse(namespaces_info.IsExtraRequire(token),
224                     'Constants can be required except on classes.');
225
226   def testIsExtraRequire_methodNotOnClass(self):
227     """Tests that requiring a method not on a class is OK."""
228     input_lines = [
229         'goog.require(\'package.subpackage.method\');',
230         'var x = package.subpackage.method()',
231     ]
232     token = self._tokenizer.TokenizeFile(input_lines)
233     namespaces_info = self._GetInitializedNamespacesInfo(token, ['package'], [])
234
235     self.assertFalse(namespaces_info.IsExtraRequire(token),
236                     'Methods can be required except on classes.');
237
238   def testIsExtraRequire_defaults(self):
239     """Tests that there are no warnings about extra requires for test utils"""
240     input_lines = ['goog.require(\'goog.testing.jsunit\');']
241     token = self._tokenizer.TokenizeFile(input_lines)
242     namespaces_info = self._GetInitializedNamespacesInfo(token, ['goog'], [])
243
244     self.assertFalse(namespaces_info.IsExtraRequire(token),
245                      'Should not be extra since it is for testing.')
246
247   def testGetMissingProvides_provided(self):
248     """Tests that provided functions don't cause a missing provide."""
249     input_lines = [
250         'goog.provide(\'package.Foo\');',
251         'package.Foo = function() {};'
252     ]
253     token = self._tokenizer.TokenizeFile(input_lines)
254     namespaces_info = self._GetInitializedNamespacesInfo(token, ['package'], [])
255
256     self.assertEquals(0, len(namespaces_info.GetMissingProvides()))
257
258   def testGetMissingProvides_providedIdentifier(self):
259     """Tests that provided identifiers don't cause a missing provide."""
260     input_lines = [
261         'goog.provide(\'package.Foo.methodName\');',
262         'package.Foo.methodName = function() {};'
263     ]
264     token = self._tokenizer.TokenizeFile(input_lines)
265     namespaces_info = self._GetInitializedNamespacesInfo(token, ['package'], [])
266
267     self.assertEquals(0, len(namespaces_info.GetMissingProvides()))
268
269   def testGetMissingProvides_providedParentIdentifier(self):
270     """Tests that provided identifiers on a class don't cause a missing provide
271     on objects attached to that class."""
272     input_lines = [
273         'goog.provide(\'package.foo.ClassName\');',
274         'package.foo.ClassName.methodName = function() {};',
275         'package.foo.ClassName.ObjectName = 1;',
276     ]
277     token = self._tokenizer.TokenizeFile(input_lines)
278     namespaces_info = self._GetInitializedNamespacesInfo(token, ['package'], [])
279
280     self.assertEquals(0, len(namespaces_info.GetMissingProvides()))
281
282   def testGetMissingProvides_unprovided(self):
283     """Tests that unprovided functions cause a missing provide."""
284     input_lines = ['package.Foo = function() {};']
285     token = self._tokenizer.TokenizeFile(input_lines)
286     namespaces_info = self._GetInitializedNamespacesInfo(token, ['package'], [])
287
288     self.assertEquals(1, len(namespaces_info.GetMissingProvides()))
289     self.assertTrue('package.Foo' in namespaces_info.GetMissingProvides())
290
291   def testGetMissingProvides_privatefunction(self):
292     """Tests that unprovided private functions don't cause a missing provide."""
293     input_lines = ['package.Foo_ = function() {};']
294     token = self._tokenizer.TokenizeFile(input_lines)
295     namespaces_info = self._GetInitializedNamespacesInfo(token, ['package'], [])
296
297     self.assertEquals(0, len(namespaces_info.GetMissingProvides()))
298
299   def testGetMissingProvides_required(self):
300     """Tests that required namespaces don't cause a missing provide."""
301     input_lines = [
302         'goog.require(\'package.Foo\');',
303         'package.Foo.methodName = function() {};'
304     ]
305     token = self._tokenizer.TokenizeFile(input_lines)
306     namespaces_info = self._GetInitializedNamespacesInfo(token, ['package'], [])
307
308     self.assertEquals(0, len(namespaces_info.GetMissingProvides()))
309
310   def testGetMissingRequires_required(self):
311     """Tests that required namespaces don't cause a missing require."""
312     input_lines = [
313         'goog.require(\'package.Foo\');',
314         'package.Foo();'
315     ]
316     token = self._tokenizer.TokenizeFile(input_lines)
317     namespaces_info = self._GetInitializedNamespacesInfo(token, ['package'], [])
318
319     self.assertEquals(0, len(namespaces_info.GetMissingProvides()))
320
321   def testGetMissingRequires_requiredIdentifier(self):
322     """Tests that required namespaces satisfy identifiers on that namespace."""
323     input_lines = [
324         'goog.require(\'package.Foo\');',
325         'package.Foo.methodName();'
326     ]
327     token = self._tokenizer.TokenizeFile(input_lines)
328     namespaces_info = self._GetInitializedNamespacesInfo(token, ['package'], [])
329
330     self.assertEquals(0, len(namespaces_info.GetMissingProvides()))
331
332   def testGetMissingRequires_requiredParentClass(self):
333     """Tests that requiring a parent class of an object is sufficient to prevent
334     a missing require on that object."""
335     input_lines = [
336         'goog.require(\'package.Foo\');',
337         'package.Foo.methodName();',
338         'package.Foo.methodName(package.Foo.ObjectName);'
339     ]
340     token = self._tokenizer.TokenizeFile(input_lines)
341     namespaces_info = self._GetInitializedNamespacesInfo(token, ['package'], [])
342
343     self.assertEquals(0, len(namespaces_info.GetMissingRequires()))
344
345   def testGetMissingRequires_unrequired(self):
346     """Tests that unrequired namespaces cause a missing require."""
347     input_lines = ['package.Foo();']
348     token = self._tokenizer.TokenizeFile(input_lines)
349     namespaces_info = self._GetInitializedNamespacesInfo(token, ['package'], [])
350
351     self.assertEquals(1, len(namespaces_info.GetMissingRequires()))
352     self.assertTrue('package.Foo' in namespaces_info.GetMissingRequires())
353
354   def testGetMissingRequires_provided(self):
355     """Tests that provided namespaces satisfy identifiers on that namespace."""
356     input_lines = [
357         'goog.provide(\'package.Foo\');',
358         'package.Foo.methodName();'
359     ]
360     token = self._tokenizer.TokenizeFile(input_lines)
361     namespaces_info = self._GetInitializedNamespacesInfo(token, ['package'], [])
362
363     self.assertEquals(0, len(namespaces_info.GetMissingRequires()))
364
365   def testGetMissingRequires_created(self):
366     """Tests that created namespaces do not satisfy usage of an identifier."""
367     input_lines = [
368         'package.Foo = function();',
369         'package.Foo.methodName();'
370     ]
371     token = self._tokenizer.TokenizeFile(input_lines)
372     namespaces_info = self._GetInitializedNamespacesInfo(token, ['package'], [])
373
374     self.assertEquals(1, len(namespaces_info.GetMissingRequires()))
375     self.assertTrue('package.Foo' in namespaces_info.GetMissingRequires())
376
377   def testGetMissingRequires_createdIdentifier(self):
378     """Tests that created identifiers satisfy usage of the identifier."""
379     input_lines = [
380         'package.Foo.methodName = function();',
381         'package.Foo.methodName();'
382     ]
383     token = self._tokenizer.TokenizeFile(input_lines)
384     namespaces_info = self._GetInitializedNamespacesInfo(token, ['package'], [])
385
386     self.assertEquals(0, len(namespaces_info.GetMissingRequires()))
387
388   def testGetMissingRequires_objectOnClass(self):
389     """Tests that we should require a class, not the object on the class."""
390     input_lines = [
391         'goog.require(\'package.Foo.Enum\');',
392         'var x = package.Foo.Enum.VALUE1;',
393     ]
394     token = self._tokenizer.TokenizeFile(input_lines)
395     namespaces_info = self._GetInitializedNamespacesInfo(token, ['package'], [])
396
397     self.assertEquals(1, len(namespaces_info.GetMissingRequires()),
398                     'The whole class, not the object, should be required.');
399
400   def testIsFirstProvide(self):
401     """Tests operation of the isFirstProvide method."""
402     input_lines = [
403         'goog.provide(\'package.Foo\');',
404         'package.Foo.methodName();'
405     ]
406     token = self._tokenizer.TokenizeFile(input_lines)
407     namespaces_info = self._GetInitializedNamespacesInfo(token, ['package'], [])
408
409     self.assertTrue(namespaces_info.IsFirstProvide(token))
410
411   def testGetWholeIdentifierString(self):
412     """Tests that created identifiers satisfy usage of the identifier."""
413     input_lines = [
414         'package.Foo.',
415         '    veryLong.',
416         '    identifier;'
417     ]
418     token = self._tokenizer.TokenizeFile(input_lines)
419     namespaces_info = closurizednamespacesinfo.ClosurizedNamespacesInfo([], [])
420
421     self.assertEquals('package.Foo.veryLong.identifier',
422                       namespaces_info._GetWholeIdentifierString(token))
423     self.assertEquals(None,
424                       namespaces_info._GetWholeIdentifierString(token.next))
425
426   def _GetInitializedNamespacesInfo(self, token, closurized_namespaces,
427                                     ignored_extra_namespaces):
428     """Returns a namespaces info initialized with the given token stream."""
429     namespaces_info = closurizednamespacesinfo.ClosurizedNamespacesInfo(
430         closurized_namespaces=closurized_namespaces,
431         ignored_extra_namespaces=ignored_extra_namespaces)
432     state_tracker = javascriptstatetracker.JavaScriptStateTracker()
433
434     while token:
435       namespaces_info.ProcessToken(token, state_tracker)
436       token = token.next
437
438     return namespaces_info
439
440   def _GetProvideTokens(self, namespace):
441     """Returns a list of tokens for a goog.require of the given namespace."""
442     line_text = 'goog.require(\'' + namespace + '\');\n'
443     return javascripttokenizer.JavaScriptTokenizer().TokenizeFile([line_text])
444
445   def _GetRequireTokens(self, namespace):
446     """Returns a list of tokens for a goog.require of the given namespace."""
447     line_text = 'goog.require(\'' + namespace + '\');\n'
448     return javascripttokenizer.JavaScriptTokenizer().TokenizeFile([line_text])
449
450 if __name__ == '__main__':
451   googletest.main()