| 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 |