js_checker_test.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. #!/usr/bin/env python3
  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. from . import js_checker
  6. from os import path as os_path
  7. import re
  8. from sys import path as sys_path
  9. from . import test_util
  10. import unittest
  11. _HERE = os_path.dirname(os_path.abspath(__file__))
  12. sys_path.append(os_path.join(_HERE, "..", ".."))
  13. from PRESUBMIT_test_mocks import MockInputApi, MockOutputApi
  14. _DECLARATION_METHODS = "const", "let", "var"
  15. class JsCheckerTest(unittest.TestCase):
  16. def setUp(self):
  17. super(JsCheckerTest, self).setUp()
  18. self.checker = js_checker.JSChecker(MockInputApi(), MockOutputApi())
  19. def ShouldFailDebuggerCheck(self, line):
  20. error = self.checker.DebuggerCheck(1, line)
  21. self.assertNotEqual("", error, "Should be flagged as style error: " + line)
  22. highlight = test_util.GetHighlight(line, error).strip()
  23. self.assertTrue(highlight.startswith("debugger"))
  24. def ShouldPassDebuggerCheck(self, line):
  25. self.assertEqual("", self.checker.DebuggerCheck(1, line),
  26. "Should not be flagged as style error: " + line)
  27. def testDebuggerFails(self):
  28. lines = [
  29. "debugger;",
  30. " debugger;",
  31. ]
  32. for line in lines:
  33. self.ShouldFailDebuggerCheck(line)
  34. def testDebuggerPasses(self):
  35. lines = [
  36. "// Test that it works in the debugger",
  37. " // Test that it works in the debugger",
  38. "debugger.debug(func);",
  39. " debugger.debug(func);",
  40. "console.log('debugger enabled');",
  41. " console.log('debugger enabled');",
  42. ]
  43. for line in lines:
  44. self.ShouldPassDebuggerCheck(line)
  45. def ShouldFailBindThisCheck(self, line):
  46. error = self.checker.BindThisCheck(1, line)
  47. self.assertNotEqual("", error, "Should be flagged as style error: " + line)
  48. highlight = test_util.GetHighlight(line, error).strip()
  49. self.assertTrue(highlight.startswith(".bind(this"))
  50. def ShouldPassBindThisCheck(self, line):
  51. self.assertEqual("", self.checker.BindThisCheck(1, line),
  52. "Should not be flagged as style error: " + line)
  53. def testBindThisFails(self):
  54. lines = [
  55. 'this.api_.getThinger((function() {console.log(\'foo\');}).bind(this));',
  56. 'this.api_.getThinger((function foo() {console.log(\'foo\');}).bind(this));',
  57. ]
  58. for line in lines:
  59. self.ShouldFailBindThisCheck(line)
  60. def testBindThisPasses(self):
  61. lines = [
  62. 'let bound = this.method_.bind(this);',
  63. "document.addEventListener('click', this.onClick_.bind(this));",
  64. 'this.api_.onEvent = this.onClick_.bind(this);',
  65. 'this.api_.getThinger(this.gotThinger_.bind(this));',
  66. 'this.api_.getThinger(this.gotThinger_.bind(this, param1, param2));',
  67. '// And in the darkness bind them.',
  68. 'this.methodName_.bind(scope, param)',
  69. ]
  70. for line in lines:
  71. self.ShouldPassBindThisCheck(line)
  72. def ShouldFailCommentCheck(self, line):
  73. """Checks that uncommented "<if>" and "<include>" are a style error."""
  74. error = self.checker.CommentIfAndIncludeCheck(1, line)
  75. self.assertNotEqual("", error, "Should be flagged as style error: " + line)
  76. highlight = test_util.GetHighlight(line, error).strip()
  77. self.assertTrue(highlight.startswith(("<if", "<include")))
  78. def ShouldPassCommentCheck(self, line):
  79. """Checks that commented "<if>" and "<include>" are allowed."""
  80. self.assertEqual("", self.checker.CommentIfAndIncludeCheck(1, line),
  81. "Should not be flagged as style error: " + line)
  82. def testCommentFails(self):
  83. lines = [
  84. '<include src="blah.js">',
  85. # Currently, only "// " is accepted (not just "//" or "//\s+") as Python
  86. # can't do variable-length lookbehind.
  87. '//<include src="blah.js">',
  88. '// <include src="blah.js">',
  89. ' <include src="blee.js">',
  90. ' <if expr="chromeos">',
  91. '<if expr="lang == \'de\'">',
  92. '//<if expr="bitness == 64">',
  93. ]
  94. for line in lines:
  95. self.ShouldFailCommentCheck(line)
  96. def testCommentPasses(self):
  97. lines = [
  98. '// <include src="assert.js">',
  99. ' // <include src="util.js"/>',
  100. '// <if expr="chromeos">',
  101. ' // <if expr="not chromeos">',
  102. " '<iframe src=blah.html>';",
  103. ]
  104. for line in lines:
  105. self.ShouldPassCommentCheck(line)
  106. def ShouldFailChromeSendCheck(self, line):
  107. """Checks that the "chrome.send" checker flags |line| as a style error."""
  108. error = self.checker.ChromeSendCheck(1, line)
  109. self.assertNotEqual("", error, "Should be flagged as style error: " + line)
  110. self.assertEqual(test_util.GetHighlight(line, error), ", []")
  111. def ShouldPassChromeSendCheck(self, line):
  112. """Checks that the "chrome.send" checker doesn"t flag |line| as a style
  113. error.
  114. """
  115. self.assertEqual("", self.checker.ChromeSendCheck(1, line),
  116. "Should not be flagged as style error: " + line)
  117. def testChromeSendFails(self):
  118. lines = [
  119. "chrome.send('message', []);",
  120. " chrome.send('message', []);",
  121. ]
  122. for line in lines:
  123. self.ShouldFailChromeSendCheck(line)
  124. def testChromeSendPasses(self):
  125. lines = [
  126. 'chrome.send("message", constructArgs("foo", []));',
  127. ' chrome.send("message", constructArgs("foo", []));',
  128. 'chrome.send("message", constructArgs([]));',
  129. ' chrome.send("message", constructArgs([]));',
  130. ]
  131. for line in lines:
  132. self.ShouldPassChromeSendCheck(line)
  133. def ShouldFailEndJsDocCommentCheck(self, line):
  134. """Checks that the **/ checker flags |line| as a style error."""
  135. error = self.checker.EndJsDocCommentCheck(1, line)
  136. self.assertNotEqual("", error, "Should be flagged as style error: " + line)
  137. self.assertEqual(test_util.GetHighlight(line, error), "**/")
  138. def ShouldPassEndJsDocCommentCheck(self, line):
  139. """Checks that the **/ checker doesn"t flag |line| as a style error."""
  140. self.assertEqual("", self.checker.EndJsDocCommentCheck(1, line),
  141. "Should not be flagged as style error: " + line)
  142. def testEndJsDocCommentFails(self):
  143. lines = [
  144. "/** @override **/",
  145. "/** @type {number} @const **/",
  146. " **/",
  147. "**/ ",
  148. ]
  149. for line in lines:
  150. self.ShouldFailEndJsDocCommentCheck(line)
  151. def testEndJsDocCommentPasses(self):
  152. lines = [
  153. "/***************/", # visual separators
  154. " */", # valid JSDoc comment ends
  155. "*/ ",
  156. "/**/", # funky multi-line comment enders
  157. "/** @override */", # legit JSDoc one-liners
  158. ]
  159. for line in lines:
  160. self.ShouldPassEndJsDocCommentCheck(line)
  161. def ShouldFailExtraDotInGenericCheck(self, line):
  162. """Checks that Array.< or Object.< is flagged as a style nit."""
  163. error = self.checker.ExtraDotInGenericCheck(1, line)
  164. self.assertNotEqual("", error)
  165. self.assertTrue(test_util.GetHighlight(line, error).endswith(".<"))
  166. def testExtraDotInGenericFails(self):
  167. lines = [
  168. "/** @private {!Array.<!Frobber>} */",
  169. "var a = /** @type {Object.<number>} */({});",
  170. "* @return {!Promise.<Change>}"
  171. ]
  172. for line in lines:
  173. self.ShouldFailExtraDotInGenericCheck(line)
  174. def ShouldFailInheritDocCheck(self, line):
  175. """Checks that the "@inheritDoc" checker flags |line| as a style error."""
  176. error = self.checker.InheritDocCheck(1, line)
  177. self.assertNotEqual("", error, "Should be flagged as style error: " + line)
  178. self.assertEqual(test_util.GetHighlight(line, error), "@inheritDoc")
  179. def ShouldPassInheritDocCheck(self, line):
  180. """Checks that the "@inheritDoc" checker doesn"t flag |line| as a style
  181. error.
  182. """
  183. self.assertEqual("", self.checker.InheritDocCheck(1, line),
  184. msg="Should not be flagged as style error: " + line)
  185. def testInheritDocFails(self):
  186. lines = [
  187. " /** @inheritDoc */",
  188. " * @inheritDoc",
  189. ]
  190. for line in lines:
  191. self.ShouldFailInheritDocCheck(line)
  192. def testInheritDocPasses(self):
  193. lines = [
  194. "And then I said, but I won't @inheritDoc! Hahaha!",
  195. " If your dad's a doctor, do you inheritDoc?",
  196. " What's up, inherit doc?",
  197. " this.inheritDoc(someDoc)",
  198. ]
  199. for line in lines:
  200. self.ShouldPassInheritDocCheck(line)
  201. def ShouldFailPolymerLocalIdCheck(self, line):
  202. """Checks that element.$.localId check marks |line| as a style error."""
  203. error = self.checker.PolymerLocalIdCheck(1, line)
  204. self.assertNotEqual("", error, "Should be flagged as style error: " + line)
  205. self.assertTrue(".$" in test_util.GetHighlight(line, error))
  206. def ShouldPassPolymerLocalIdCheck(self, line):
  207. """Checks that element.$.localId check doesn't mark |line| as a style
  208. error."""
  209. self.assertEqual("", self.checker.PolymerLocalIdCheck(1, line),
  210. msg="Should not be flagged as a style error: " + line)
  211. def testPolymerLocalIdFails(self):
  212. lines = [
  213. "cat.$.dog",
  214. "thing1.$.thing2",
  215. "element.$.localId",
  216. 'element.$["fancy-hyphenated-id"]',
  217. ]
  218. for line in lines:
  219. self.ShouldFailPolymerLocalIdCheck(line)
  220. def testPolymerLocalIdPasses(self):
  221. lines = [
  222. "this.$.id",
  223. "this.$.localId",
  224. 'this.$["fancy-id"]',
  225. "this.page.$.flushForTesting()",
  226. ]
  227. for line in lines:
  228. self.ShouldPassPolymerLocalIdCheck(line)
  229. def ShouldFailVariableNameCheck(self, line):
  230. """Checks that var unix_hacker, $dollar are style errors."""
  231. error = self.checker.VariableNameCheck(1, line)
  232. self.assertNotEqual("", error, "Should be flagged as style error: " + line)
  233. highlight = test_util.GetHighlight(line, error)
  234. self.assertFalse(any(dm in highlight for dm in _DECLARATION_METHODS))
  235. def ShouldPassVariableNameCheck(self, line):
  236. """Checks that variableNamesLikeThis aren"t style errors."""
  237. self.assertEqual("", self.checker.VariableNameCheck(1, line),
  238. msg="Should not be flagged as style error: " + line)
  239. def testVariableNameFails(self):
  240. lines = [
  241. "%s private_;",
  242. "%s hostName_ = 'https://google.com';",
  243. " %s _super_private",
  244. " %s unix_hacker = someFunc();",
  245. ]
  246. for line in lines:
  247. for declaration_method in _DECLARATION_METHODS:
  248. self.ShouldFailVariableNameCheck(line % declaration_method)
  249. def testVariableNamePasses(self):
  250. lines = [
  251. " %s namesLikeThis = [];",
  252. " for (%s i = 0; i < 10; ++i) { ",
  253. "for (%s i in obj) {",
  254. " %s one, two, three;",
  255. " %s magnumPI = {};",
  256. " %s g_browser = 'da browzer';",
  257. "/** @const */ %s Bla = options.Bla;", # goog.scope() replacement.
  258. " %s $ = function() {", # For legacy reasons.
  259. " %s StudlyCaps = cr.define('bla')", # Classes.
  260. " %s SCARE_SMALL_CHILDREN = [", # TODO(dbeam): add @const in
  261. # front of all these vars like
  262. # "/** @const */ %s CONST_VAR = 1;", # this line has (<--).
  263. ]
  264. for line in lines:
  265. for declaration_method in _DECLARATION_METHODS:
  266. self.ShouldPassVariableNameCheck(line % declaration_method)
  267. if __name__ == "__main__":
  268. unittest.main()