OLD | NEW |
| (Empty) |
1 #!/usr/bin/env python | |
2 # Copyright 2015 The Chromium Authors. All rights reserved. | |
3 # Use of this source code is governed by a BSD-style license that can be | |
4 # found in the LICENSE file. | |
5 | |
6 import js_checker | |
7 from os import path as os_path | |
8 import re | |
9 from sys import path as sys_path | |
10 import test_util | |
11 import unittest | |
12 | |
13 _HERE = os_path.dirname(os_path.abspath(__file__)) | |
14 sys_path.append(os_path.join(_HERE, '..', '..', '..', 'build')) | |
15 | |
16 import find_depot_tools # pylint: disable=W0611 | |
17 from testing_support.super_mox import SuperMoxTestBase | |
18 | |
19 | |
20 class JsCheckerTest(SuperMoxTestBase): | |
21 def setUp(self): | |
22 SuperMoxTestBase.setUp(self) | |
23 | |
24 input_api = self.mox.CreateMockAnything() | |
25 input_api.re = re | |
26 output_api = self.mox.CreateMockAnything() | |
27 self.checker = js_checker.JSChecker(input_api, output_api) | |
28 | |
29 def ShouldFailCommentCheck(self, line): | |
30 """Checks that uncommented '<if>' and '<include>' are a style error.""" | |
31 error = self.checker.CommentIfAndIncludeCheck(1, line) | |
32 self.assertNotEqual('', error, 'Should be flagged as style error: ' + line) | |
33 highlight = test_util.GetHighlight(line, error).strip() | |
34 self.assertTrue(highlight.startswith(('<if', '<include'))) | |
35 | |
36 def ShouldPassCommentCheck(self, line): | |
37 """Checks that commented '<if>' and '<include>' are allowed.""" | |
38 self.assertEqual('', self.checker.CommentIfAndIncludeCheck(1, line), | |
39 'Should not be flagged as style error: ' + line) | |
40 | |
41 def testCommentFails(self): | |
42 lines = [ | |
43 '<include src="blah.js">', | |
44 # Currently, only "// " is accepted (not just "//" or "//\s+") as Python | |
45 # can't do variable-length lookbehind. | |
46 '//<include src="blah.js">', | |
47 '// <include src="blah.js">', | |
48 ' <include src="blee.js">', | |
49 ' <if expr="chromeos">', | |
50 '<if expr="lang == \'de\'">', | |
51 '//<if expr="bitness == 64">', | |
52 ] | |
53 for line in lines: | |
54 self.ShouldFailCommentCheck(line) | |
55 | |
56 def testCommentPasses(self): | |
57 lines = [ | |
58 '// <include src="assert.js">', | |
59 ' // <include src="util.js"/>', | |
60 '// <if expr="chromeos">', | |
61 ' // <if expr="not chromeos">', | |
62 " '<iframe src=blah.html>';", | |
63 ] | |
64 for line in lines: | |
65 self.ShouldPassCommentCheck(line) | |
66 | |
67 def ShouldFailConstCheck(self, line): | |
68 """Checks that the 'const' checker flags |line| as a style error.""" | |
69 error = self.checker.ConstCheck(1, line) | |
70 self.assertNotEqual('', error, | |
71 'Should be flagged as style error: ' + line) | |
72 self.assertEqual(test_util.GetHighlight(line, error), 'const') | |
73 | |
74 def ShouldPassConstCheck(self, line): | |
75 """Checks that the 'const' checker doesn't flag |line| as a style error.""" | |
76 self.assertEqual('', self.checker.ConstCheck(1, line), | |
77 'Should not be flagged as style error: ' + line) | |
78 | |
79 def testConstFails(self): | |
80 lines = [ | |
81 "const foo = 'bar';", | |
82 " const bar = 'foo';", | |
83 | |
84 # Trying to use |const| as a variable name | |
85 "var const = 0;", | |
86 | |
87 "var x = 5; const y = 6;", | |
88 "for (var i=0, const e=10; i<e; i++) {", | |
89 "for (const x=0; x<foo; i++) {", | |
90 "while (const x = 7) {", | |
91 ] | |
92 for line in lines: | |
93 self.ShouldFailConstCheck(line) | |
94 | |
95 def testConstPasses(self): | |
96 lines = [ | |
97 # sanity check | |
98 "var foo = 'bar'", | |
99 | |
100 # @const JsDoc tag | |
101 "/** @const */ var SEVEN = 7;", | |
102 | |
103 # @const tag in multi-line comment | |
104 " * @const", | |
105 " * @const", | |
106 | |
107 # @constructor tag in multi-line comment | |
108 " * @constructor", | |
109 " * @constructor", | |
110 | |
111 # words containing 'const' | |
112 "if (foo.constructor) {", | |
113 "var deconstruction = 'something';", | |
114 "var madeUpWordconst = 10;", | |
115 | |
116 # Strings containing the word |const| | |
117 "var str = 'const at the beginning';", | |
118 "var str = 'At the end: const';", | |
119 | |
120 # doing this one with regex is probably not practical | |
121 #"var str = 'a const in the middle';", | |
122 ] | |
123 for line in lines: | |
124 self.ShouldPassConstCheck(line) | |
125 | |
126 def ShouldFailChromeSendCheck(self, line): | |
127 """Checks that the 'chrome.send' checker flags |line| as a style error.""" | |
128 error = self.checker.ChromeSendCheck(1, line) | |
129 self.assertNotEqual('', error, | |
130 'Should be flagged as style error: ' + line) | |
131 self.assertEqual(test_util.GetHighlight(line, error), ', []') | |
132 | |
133 def ShouldPassChromeSendCheck(self, line): | |
134 """Checks that the 'chrome.send' checker doesn't flag |line| as a style | |
135 error. | |
136 """ | |
137 self.assertEqual('', self.checker.ChromeSendCheck(1, line), | |
138 'Should not be flagged as style error: ' + line) | |
139 | |
140 def testChromeSendFails(self): | |
141 lines = [ | |
142 "chrome.send('message', []);", | |
143 " chrome.send('message', []);", | |
144 ] | |
145 for line in lines: | |
146 self.ShouldFailChromeSendCheck(line) | |
147 | |
148 def testChromeSendPasses(self): | |
149 lines = [ | |
150 "chrome.send('message', constructArgs('foo', []));", | |
151 " chrome.send('message', constructArgs('foo', []));", | |
152 "chrome.send('message', constructArgs([]));", | |
153 " chrome.send('message', constructArgs([]));", | |
154 ] | |
155 for line in lines: | |
156 self.ShouldPassChromeSendCheck(line) | |
157 | |
158 def ShouldFailEndJsDocCommentCheck(self, line): | |
159 """Checks that the **/ checker flags |line| as a style error.""" | |
160 error = self.checker.EndJsDocCommentCheck(1, line) | |
161 self.assertNotEqual('', error, | |
162 'Should be flagged as style error: ' + line) | |
163 self.assertEqual(test_util.GetHighlight(line, error), '**/') | |
164 | |
165 def ShouldPassEndJsDocCommentCheck(self, line): | |
166 """Checks that the **/ checker doesn't flag |line| as a style error.""" | |
167 self.assertEqual('', self.checker.EndJsDocCommentCheck(1, line), | |
168 'Should not be flagged as style error: ' + line) | |
169 | |
170 def testEndJsDocCommentFails(self): | |
171 lines = [ | |
172 "/** @override **/", | |
173 "/** @type {number} @const **/", | |
174 " **/", | |
175 "**/ ", | |
176 ] | |
177 for line in lines: | |
178 self.ShouldFailEndJsDocCommentCheck(line) | |
179 | |
180 def testEndJsDocCommentPasses(self): | |
181 lines = [ | |
182 "/***************/", # visual separators | |
183 " */", # valid JSDoc comment ends | |
184 "*/ ", | |
185 "/**/", # funky multi-line comment enders | |
186 "/** @override */", # legit JSDoc one-liners | |
187 ] | |
188 for line in lines: | |
189 self.ShouldPassEndJsDocCommentCheck(line) | |
190 | |
191 def ShouldFailExtraDotInGenericCheck(self, line): | |
192 """Checks that Array.< or Object.< is flagged as a style nit.""" | |
193 error = self.checker.ExtraDotInGenericCheck(1, line) | |
194 self.assertNotEqual('', error) | |
195 self.assertTrue(test_util.GetHighlight(line, error).endswith(".<")) | |
196 | |
197 def testExtraDotInGenericFails(self): | |
198 lines = [ | |
199 "/** @private {!Array.<!Frobber>} */", | |
200 "var a = /** @type {Object.<number>} */({});", | |
201 "* @return {!Promise.<Change>}" | |
202 ] | |
203 for line in lines: | |
204 self.ShouldFailExtraDotInGenericCheck(line) | |
205 | |
206 def ShouldFailGetElementByIdCheck(self, line): | |
207 """Checks that the 'getElementById' checker flags |line| as a style | |
208 error. | |
209 """ | |
210 error = self.checker.GetElementByIdCheck(1, line) | |
211 self.assertNotEqual('', error, | |
212 'Should be flagged as style error: ' + line) | |
213 self.assertEqual(test_util.GetHighlight(line, error), | |
214 'document.getElementById') | |
215 | |
216 def ShouldPassGetElementByIdCheck(self, line): | |
217 """Checks that the 'getElementById' checker doesn't flag |line| as a style | |
218 error. | |
219 """ | |
220 self.assertEqual('', self.checker.GetElementByIdCheck(1, line), | |
221 'Should not be flagged as style error: ' + line) | |
222 | |
223 def testGetElementByIdFails(self): | |
224 lines = [ | |
225 "document.getElementById('foo');", | |
226 " document.getElementById('foo');", | |
227 "var x = document.getElementById('foo');", | |
228 "if (document.getElementById('foo').hidden) {", | |
229 ] | |
230 for line in lines: | |
231 self.ShouldFailGetElementByIdCheck(line) | |
232 | |
233 def testGetElementByIdPasses(self): | |
234 lines = [ | |
235 "elem.ownerDocument.getElementById('foo');", | |
236 " elem.ownerDocument.getElementById('foo');", | |
237 "var x = elem.ownerDocument.getElementById('foo');", | |
238 "if (elem.ownerDocument.getElementById('foo').hidden) {", | |
239 "doc.getElementById('foo');", | |
240 " doc.getElementById('foo');", | |
241 "cr.doc.getElementById('foo');", | |
242 " cr.doc.getElementById('foo');", | |
243 "var x = doc.getElementById('foo');", | |
244 "if (doc.getElementById('foo').hidden) {", | |
245 ] | |
246 for line in lines: | |
247 self.ShouldPassGetElementByIdCheck(line) | |
248 | |
249 def ShouldFailInheritDocCheck(self, line): | |
250 """Checks that the '@inheritDoc' checker flags |line| as a style error.""" | |
251 error = self.checker.InheritDocCheck(1, line) | |
252 self.assertNotEqual('', error, | |
253 msg='Should be flagged as style error: ' + line) | |
254 self.assertEqual(test_util.GetHighlight(line, error), '@inheritDoc') | |
255 | |
256 def ShouldPassInheritDocCheck(self, line): | |
257 """Checks that the '@inheritDoc' checker doesn't flag |line| as a style | |
258 error. | |
259 """ | |
260 self.assertEqual('', self.checker.InheritDocCheck(1, line), | |
261 msg='Should not be flagged as style error: ' + line) | |
262 | |
263 def testInheritDocFails(self): | |
264 lines = [ | |
265 " /** @inheritDoc */", | |
266 " * @inheritDoc", | |
267 ] | |
268 for line in lines: | |
269 self.ShouldFailInheritDocCheck(line) | |
270 | |
271 def testInheritDocPasses(self): | |
272 lines = [ | |
273 "And then I said, but I won't @inheritDoc! Hahaha!", | |
274 " If your dad's a doctor, do you inheritDoc?", | |
275 " What's up, inherit doc?", | |
276 " this.inheritDoc(someDoc)", | |
277 ] | |
278 for line in lines: | |
279 self.ShouldPassInheritDocCheck(line) | |
280 | |
281 def ShouldFailPolymerLocalIdCheck(self, line): | |
282 """Checks that element.$.localId check marks |line| as a style error.""" | |
283 error = self.checker.PolymerLocalIdCheck(1, line) | |
284 self.assertNotEqual('', error, | |
285 msg='Should be flagged as a style error: ' + line) | |
286 self.assertTrue('.$' in test_util.GetHighlight(line, error)) | |
287 | |
288 def ShouldPassPolymerLocalIdCheck(self, line): | |
289 """Checks that element.$.localId check doesn't mark |line| as a style | |
290 error.""" | |
291 self.assertEqual('', self.checker.PolymerLocalIdCheck(1, line), | |
292 msg='Should not be flagged as a style error: ' + line) | |
293 | |
294 def testPolymerLocalIdFails(self): | |
295 lines = [ | |
296 "cat.$.dog", | |
297 "thing1.$.thing2", | |
298 "element.$.localId", | |
299 "element.$['fancy-hyphenated-id']", | |
300 ] | |
301 for line in lines: | |
302 self.ShouldFailPolymerLocalIdCheck(line) | |
303 | |
304 def testPolymerLocalIdPasses(self): | |
305 lines = [ | |
306 "this.$.id", | |
307 "this.$.localId", | |
308 "this.$['fancy-id']", | |
309 ] | |
310 for line in lines: | |
311 self.ShouldPassPolymerLocalIdCheck(line) | |
312 | |
313 def ShouldFailWrapperTypeCheck(self, line): | |
314 """Checks that the use of wrapper types (i.e. new Number(), @type {Number}) | |
315 is a style error. | |
316 """ | |
317 error = self.checker.WrapperTypeCheck(1, line) | |
318 self.assertNotEqual('', error, | |
319 msg='Should be flagged as style error: ' + line) | |
320 highlight = test_util.GetHighlight(line, error) | |
321 self.assertTrue(highlight in ('Boolean', 'Number', 'String')) | |
322 | |
323 def ShouldPassWrapperTypeCheck(self, line): | |
324 """Checks that the wrapper type checker doesn't flag |line| as a style | |
325 error. | |
326 """ | |
327 self.assertEqual('', self.checker.WrapperTypeCheck(1, line), | |
328 msg='Should not be flagged as style error: ' + line) | |
329 | |
330 def testWrapperTypePasses(self): | |
331 lines = [ | |
332 "/** @param {!ComplexType} */", | |
333 " * @type {Object}", | |
334 " * @param {Function=} opt_callback", | |
335 " * @param {} num Number of things to add to {blah}.", | |
336 " * @return {!print_preview.PageNumberSet}", | |
337 " /* @returns {Number} */", # Should be /** @return {Number} */ | |
338 "* @param {!LocalStrings}" | |
339 " Your type of Boolean is false!", | |
340 " Then I parameterized a Number from my friend!", | |
341 " A String of Pearls", | |
342 " types.params.aBoolean.typeString(someNumber)", | |
343 ] | |
344 for line in lines: | |
345 self.ShouldPassWrapperTypeCheck(line) | |
346 | |
347 def testWrapperTypeFails(self): | |
348 lines = [ | |
349 " /**@type {String}*/(string)", | |
350 " * @param{Number=} opt_blah A number", | |
351 "/** @private @return {!Boolean} */", | |
352 " * @param {number|String}", | |
353 ] | |
354 for line in lines: | |
355 self.ShouldFailWrapperTypeCheck(line) | |
356 | |
357 def ShouldFailVarNameCheck(self, line): | |
358 """Checks that var unix_hacker, $dollar are style errors.""" | |
359 error = self.checker.VarNameCheck(1, line) | |
360 self.assertNotEqual('', error, | |
361 msg='Should be flagged as style error: ' + line) | |
362 highlight = test_util.GetHighlight(line, error) | |
363 self.assertFalse('var ' in highlight); | |
364 | |
365 def ShouldPassVarNameCheck(self, line): | |
366 """Checks that variableNamesLikeThis aren't style errors.""" | |
367 self.assertEqual('', self.checker.VarNameCheck(1, line), | |
368 msg='Should not be flagged as style error: ' + line) | |
369 | |
370 def testVarNameFails(self): | |
371 lines = [ | |
372 "var private_;", | |
373 "var hostName_ = 'https://google.com';", | |
374 " var _super_private", | |
375 " var unix_hacker = someFunc();", | |
376 ] | |
377 for line in lines: | |
378 self.ShouldFailVarNameCheck(line) | |
379 | |
380 def testVarNamePasses(self): | |
381 lines = [ | |
382 " var namesLikeThis = [];", | |
383 " for (var i = 0; i < 10; ++i) { ", | |
384 "for (var i in obj) {", | |
385 " var one, two, three;", | |
386 " var magnumPI = {};", | |
387 " var g_browser = 'da browzer';", | |
388 "/** @const */ var Bla = options.Bla;", # goog.scope() replacement. | |
389 " var $ = function() {", # For legacy reasons. | |
390 " var StudlyCaps = cr.define('bla')", # Classes. | |
391 " var SCARE_SMALL_CHILDREN = [", # TODO(dbeam): add @const in | |
392 # front of all these vars like | |
393 "/** @const */ CONST_VAR = 1;", # this line has (<--). | |
394 ] | |
395 for line in lines: | |
396 self.ShouldPassVarNameCheck(line) | |
397 | |
398 | |
399 if __name__ == '__main__': | |
400 unittest.main() | |
OLD | NEW |