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

Side by Side Diff: chrome/browser/test_presubmit.py

Issue 1242383003: Split web_dev_style tests into separate files. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: merge Created 5 years, 5 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
« no previous file with comments | « chrome/browser/PRESUBMIT.py ('k') | chrome/browser/web_dev_style/closure_lint_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Unit tests for Web Development Style Guide checker.""" 6 """Unit test runner for Web Development Style Guide checks."""
7 7
8 import os 8 from web_dev_style import closure_lint_test, \
9 import re 9 css_checker_test, \
10 import sys 10 html_checker_test, \
11 import unittest 11 js_checker_test, \
12 resource_checker_test
12 13
13 test_dir = os.path.dirname(os.path.abspath(__file__)) 14 _TEST_MODULES = [
14 sys.path.extend([ 15 closure_lint_test,
15 os.path.normpath(os.path.join(test_dir, '..', '..', 'tools')), 16 css_checker_test,
16 os.path.join(test_dir), 17 html_checker_test,
17 ]) 18 js_checker_test,
19 resource_checker_test
20 ]
18 21
19 import find_depot_tools # pylint: disable=W0611 22 for test_module in _TEST_MODULES:
20 from testing_support.super_mox import SuperMoxTestBase 23 test_module.unittest.main(test_module)
21 from web_dev_style import css_checker, html_checker, js_checker, \
22 resource_checker # pylint: disable=F0401
23
24
25 def GetHighlight(line, error):
26 """Returns the substring of |line| that is highlighted in |error|."""
27 error_lines = error.split('\n')
28 highlight = error_lines[error_lines.index(line) + 1]
29 return ''.join(ch1 for (ch1, ch2) in zip(line, highlight) if ch2 == '^')
30
31
32 class HtmlStyleTest(SuperMoxTestBase):
33 def setUp(self):
34 SuperMoxTestBase.setUp(self)
35
36 input_api = self.mox.CreateMockAnything()
37 input_api.re = re
38 output_api = self.mox.CreateMockAnything()
39 self.checker = html_checker.HtmlChecker(input_api, output_api)
40
41 def ShouldFailCheck(self, line, checker):
42 """Checks that the |checker| flags |line| as a style error."""
43 error = checker(1, line)
44 self.assertNotEqual('', error, 'Should be flagged as style error: ' + line)
45 highlight = GetHighlight(line, error).strip()
46
47 def ShouldPassCheck(self, line, checker):
48 """Checks that the |checker| doesn't flag |line| as a style error."""
49 error = checker(1, line)
50 self.assertEqual('', error, 'Should not be flagged as style error: ' + line)
51
52 def testClassesUseDashFormCheckFails(self):
53 lines = [
54 ' <a class="Foo-bar" href="classBar"> ',
55 '<b class="foo-Bar"> ',
56 '<i class="foo_bar" >',
57 ' <hr class="fooBar"> ',
58 ]
59 for line in lines:
60 self.ShouldFailCheck(line, self.checker.ClassesUseDashFormCheck)
61
62 def testClassesUseDashFormCheckPasses(self):
63 lines = [
64 ' class="abc" ',
65 'class="foo-bar"',
66 '<div class="foo-bar" id="classBar"',
67 ]
68 for line in lines:
69 self.ShouldPassCheck(line, self.checker.ClassesUseDashFormCheck)
70
71 def testDoNotCloseSingleTagsCheckFails(self):
72 lines = [
73 "<input/>",
74 ' <input id="a" /> ',
75 "<div/>",
76 "<br/>",
77 "<br />",
78 ]
79 for line in lines:
80 self.ShouldFailCheck(line, self.checker.DoNotCloseSingleTagsCheck)
81
82 def testDoNotCloseSingleTagsCheckPasses(self):
83 lines = [
84 "<input>",
85 "<link>",
86 "<div></div>",
87 '<input text="/">',
88 ]
89 for line in lines:
90 self.ShouldPassCheck(line, self.checker.DoNotCloseSingleTagsCheck)
91
92 def testDoNotUseBrElementCheckFails(self):
93 lines = [
94 " <br>",
95 "<br > ",
96 "<br\>",
97 '<br name="a">',
98 ]
99 for line in lines:
100 self.ShouldFailCheck(
101 line, self.checker.DoNotUseBrElementCheck)
102
103 def testDoNotUseBrElementCheckPasses(self):
104 lines = [
105 "br",
106 "br>",
107 "give me a break"
108 ]
109 for line in lines:
110 self.ShouldPassCheck(
111 line, self.checker.DoNotUseBrElementCheck)
112
113 def testDoNotUseInputTypeButtonCheckFails(self):
114 lines = [
115 '<input type="button">',
116 ' <input id="a" type="button" >',
117 '<input type="button" id="a"> ',
118 ]
119 for line in lines:
120 self.ShouldFailCheck(line, self.checker.DoNotUseInputTypeButtonCheck)
121
122 def testDoNotUseInputTypeButtonCheckPasses(self):
123 lines = [
124 "<input>",
125 '<input type="text">',
126 '<input type="result">',
127 '<input type="submit">',
128 "<button>",
129 '<button type="button">',
130 '<button type="reset">',
131 '<button type="submit">',
132
133 ]
134 for line in lines:
135 self.ShouldPassCheck(line, self.checker.DoNotUseInputTypeButtonCheck)
136
137 def testI18nContentJavaScriptCaseCheckFails(self):
138 lines = [
139 ' i18n-content="foo-bar" ',
140 'i18n-content="foo_bar"',
141 'i18n-content="FooBar"',
142 'i18n-content="_foo"',
143 'i18n-content="foo_"',
144 'i18n-content="-foo"',
145 'i18n-content="foo-"',
146 'i18n-content="Foo"',
147 ]
148 for line in lines:
149 self.ShouldFailCheck(line, self.checker.I18nContentJavaScriptCaseCheck)
150
151 def testI18nContentJavaScriptCaseCheckPasses(self):
152 lines = [
153 ' i18n-content="abc" ',
154 'i18n-content="fooBar"',
155 '<div i18n-content="exampleTitle"',
156 ]
157 for line in lines:
158 self.ShouldPassCheck(line, self.checker.I18nContentJavaScriptCaseCheck)
159
160 def testLabelCheckFails(self):
161 lines = [
162 ' for="abc"',
163 "for= ",
164 " \tfor= ",
165 " for="
166 ]
167 for line in lines:
168 self.ShouldFailCheck(line, self.checker.LabelCheck)
169
170 def testLabelCheckPass(self):
171 lines = [
172 ' my-for="abc" ',
173 ' myfor="abc" ',
174 " <for",
175 ]
176 for line in lines:
177 self.ShouldPassCheck(line, self.checker.LabelCheck)
178
179
180 class ResourceStyleGuideTest(SuperMoxTestBase):
181 def setUp(self):
182 SuperMoxTestBase.setUp(self)
183
184 input_api = self.mox.CreateMockAnything()
185 input_api.re = re
186 output_api = self.mox.CreateMockAnything()
187 self.checker = resource_checker.ResourceChecker(input_api, output_api)
188
189 def ShouldFailIncludeCheck(self, line):
190 """Checks that the '</include>' checker flags |line| as a style error."""
191 error = self.checker.IncludeCheck(1, line)
192 self.assertNotEqual('', error,
193 'Should be flagged as style error: ' + line)
194 highlight = GetHighlight(line, error).strip()
195 self.assertTrue('include' in highlight and highlight[0] == '<')
196
197 def ShouldPassIncludeCheck(self, line):
198 """Checks that the '</include>' checker doesn't flag |line| as an error."""
199 self.assertEqual('', self.checker.IncludeCheck(1, line),
200 'Should not be flagged as style error: ' + line)
201
202 def testIncludeFails(self):
203 lines = [
204 "</include> ",
205 " </include>",
206 " </include> ",
207 ' <include src="blah.js" /> ',
208 '<include src="blee.js"/>',
209 ]
210 for line in lines:
211 self.ShouldFailIncludeCheck(line)
212
213 def testIncludePasses(self):
214 lines = [
215 '<include src="assert.js">',
216 "<include src='../../assert.js'>",
217 "<i>include src='blah'</i>",
218 "</i>nclude",
219 "</i>include",
220 ]
221 for line in lines:
222 self.ShouldPassIncludeCheck(line)
223
224
225 class JsStyleGuideTest(SuperMoxTestBase):
226 def setUp(self):
227 SuperMoxTestBase.setUp(self)
228
229 input_api = self.mox.CreateMockAnything()
230 input_api.re = re
231 output_api = self.mox.CreateMockAnything()
232 self.checker = js_checker.JSChecker(input_api, output_api)
233
234 def ShouldFailConstCheck(self, line):
235 """Checks that the 'const' checker flags |line| as a style error."""
236 error = self.checker.ConstCheck(1, line)
237 self.assertNotEqual('', error,
238 'Should be flagged as style error: ' + line)
239 self.assertEqual(GetHighlight(line, error), 'const')
240
241 def ShouldPassConstCheck(self, line):
242 """Checks that the 'const' checker doesn't flag |line| as a style error."""
243 self.assertEqual('', self.checker.ConstCheck(1, line),
244 'Should not be flagged as style error: ' + line)
245
246 def testConstFails(self):
247 lines = [
248 "const foo = 'bar';",
249 " const bar = 'foo';",
250
251 # Trying to use |const| as a variable name
252 "var const = 0;",
253
254 "var x = 5; const y = 6;",
255 "for (var i=0, const e=10; i<e; i++) {",
256 "for (const x=0; x<foo; i++) {",
257 "while (const x = 7) {",
258 ]
259 for line in lines:
260 self.ShouldFailConstCheck(line)
261
262 def testConstPasses(self):
263 lines = [
264 # sanity check
265 "var foo = 'bar'",
266
267 # @const JsDoc tag
268 "/** @const */ var SEVEN = 7;",
269
270 # @const tag in multi-line comment
271 " * @const",
272 " * @const",
273
274 # @constructor tag in multi-line comment
275 " * @constructor",
276 " * @constructor",
277
278 # words containing 'const'
279 "if (foo.constructor) {",
280 "var deconstruction = 'something';",
281 "var madeUpWordconst = 10;",
282
283 # Strings containing the word |const|
284 "var str = 'const at the beginning';",
285 "var str = 'At the end: const';",
286
287 # doing this one with regex is probably not practical
288 #"var str = 'a const in the middle';",
289 ]
290 for line in lines:
291 self.ShouldPassConstCheck(line)
292
293 def ShouldFailChromeSendCheck(self, line):
294 """Checks that the 'chrome.send' checker flags |line| as a style error."""
295 error = self.checker.ChromeSendCheck(1, line)
296 self.assertNotEqual('', error,
297 'Should be flagged as style error: ' + line)
298 self.assertEqual(GetHighlight(line, error), ', []')
299
300 def ShouldPassChromeSendCheck(self, line):
301 """Checks that the 'chrome.send' checker doesn't flag |line| as a style
302 error.
303 """
304 self.assertEqual('', self.checker.ChromeSendCheck(1, line),
305 'Should not be flagged as style error: ' + line)
306
307 def testChromeSendFails(self):
308 lines = [
309 "chrome.send('message', []);",
310 " chrome.send('message', []);",
311 ]
312 for line in lines:
313 self.ShouldFailChromeSendCheck(line)
314
315 def testChromeSendPasses(self):
316 lines = [
317 "chrome.send('message', constructArgs('foo', []));",
318 " chrome.send('message', constructArgs('foo', []));",
319 "chrome.send('message', constructArgs([]));",
320 " chrome.send('message', constructArgs([]));",
321 ]
322 for line in lines:
323 self.ShouldPassChromeSendCheck(line)
324
325 def ShouldFailEndJsDocCommentCheck(self, line):
326 """Checks that the **/ checker flags |line| as a style error."""
327 error = self.checker.EndJsDocCommentCheck(1, line)
328 self.assertNotEqual('', error,
329 'Should be flagged as style error: ' + line)
330 self.assertEqual(GetHighlight(line, error), '**/')
331
332 def ShouldPassEndJsDocCommentCheck(self, line):
333 """Checks that the **/ checker doesn't flag |line| as a style error."""
334 self.assertEqual('', self.checker.EndJsDocCommentCheck(1, line),
335 'Should not be flagged as style error: ' + line)
336
337 def testEndJsDocCommentFails(self):
338 lines = [
339 "/** @override **/",
340 "/** @type {number} @const **/",
341 " **/",
342 "**/ ",
343 ]
344 for line in lines:
345 self.ShouldFailEndJsDocCommentCheck(line)
346
347 def testEndJsDocCommentPasses(self):
348 lines = [
349 "/***************/", # visual separators
350 " */", # valid JSDoc comment ends
351 "*/ ",
352 "/**/", # funky multi-line comment enders
353 "/** @override */", # legit JSDoc one-liners
354 ]
355 for line in lines:
356 self.ShouldPassEndJsDocCommentCheck(line)
357
358 def ShouldFailExtraDotInGenericCheck(self, line):
359 """Checks that Array.< or Object.< is flagged as a style nit."""
360 error = self.checker.ExtraDotInGenericCheck(1, line)
361 self.assertNotEqual('', error)
362 self.assertTrue(GetHighlight(line, error).endswith(".<"))
363
364 def testExtraDotInGenericFails(self):
365 lines = [
366 "/** @private {!Array.<!Frobber>} */",
367 "var a = /** @type {Object.<number>} */({});",
368 "* @return {!Promise.<Change>}"
369 ]
370 for line in lines:
371 self.ShouldFailExtraDotInGenericCheck(line)
372
373 def ShouldFailGetElementByIdCheck(self, line):
374 """Checks that the 'getElementById' checker flags |line| as a style
375 error.
376 """
377 error = self.checker.GetElementByIdCheck(1, line)
378 self.assertNotEqual('', error,
379 'Should be flagged as style error: ' + line)
380 self.assertEqual(GetHighlight(line, error), 'document.getElementById')
381
382 def ShouldPassGetElementByIdCheck(self, line):
383 """Checks that the 'getElementById' checker doesn't flag |line| as a style
384 error.
385 """
386 self.assertEqual('', self.checker.GetElementByIdCheck(1, line),
387 'Should not be flagged as style error: ' + line)
388
389 def testGetElementByIdFails(self):
390 lines = [
391 "document.getElementById('foo');",
392 " document.getElementById('foo');",
393 "var x = document.getElementById('foo');",
394 "if (document.getElementById('foo').hidden) {",
395 ]
396 for line in lines:
397 self.ShouldFailGetElementByIdCheck(line)
398
399 def testGetElementByIdPasses(self):
400 lines = [
401 "elem.ownerDocument.getElementById('foo');",
402 " elem.ownerDocument.getElementById('foo');",
403 "var x = elem.ownerDocument.getElementById('foo');",
404 "if (elem.ownerDocument.getElementById('foo').hidden) {",
405 "doc.getElementById('foo');",
406 " doc.getElementById('foo');",
407 "cr.doc.getElementById('foo');",
408 " cr.doc.getElementById('foo');",
409 "var x = doc.getElementById('foo');",
410 "if (doc.getElementById('foo').hidden) {",
411 ]
412 for line in lines:
413 self.ShouldPassGetElementByIdCheck(line)
414
415 def ShouldFailInheritDocCheck(self, line):
416 """Checks that the '@inheritDoc' checker flags |line| as a style error."""
417 error = self.checker.InheritDocCheck(1, line)
418 self.assertNotEqual('', error,
419 msg='Should be flagged as style error: ' + line)
420 self.assertEqual(GetHighlight(line, error), '@inheritDoc')
421
422 def ShouldPassInheritDocCheck(self, line):
423 """Checks that the '@inheritDoc' checker doesn't flag |line| as a style
424 error.
425 """
426 self.assertEqual('', self.checker.InheritDocCheck(1, line),
427 msg='Should not be flagged as style error: ' + line)
428
429 def testInheritDocFails(self):
430 lines = [
431 " /** @inheritDoc */",
432 " * @inheritDoc",
433 ]
434 for line in lines:
435 self.ShouldFailInheritDocCheck(line)
436
437 def testInheritDocPasses(self):
438 lines = [
439 "And then I said, but I won't @inheritDoc! Hahaha!",
440 " If your dad's a doctor, do you inheritDoc?",
441 " What's up, inherit doc?",
442 " this.inheritDoc(someDoc)",
443 ]
444 for line in lines:
445 self.ShouldPassInheritDocCheck(line)
446
447 def ShouldFailWrapperTypeCheck(self, line):
448 """Checks that the use of wrapper types (i.e. new Number(), @type {Number})
449 is a style error.
450 """
451 error = self.checker.WrapperTypeCheck(1, line)
452 self.assertNotEqual('', error,
453 msg='Should be flagged as style error: ' + line)
454 highlight = GetHighlight(line, error)
455 self.assertTrue(highlight in ('Boolean', 'Number', 'String'))
456
457 def ShouldPassWrapperTypeCheck(self, line):
458 """Checks that the wrapper type checker doesn't flag |line| as a style
459 error.
460 """
461 self.assertEqual('', self.checker.WrapperTypeCheck(1, line),
462 msg='Should not be flagged as style error: ' + line)
463
464 def testWrapperTypePasses(self):
465 lines = [
466 "/** @param {!ComplexType} */",
467 " * @type {Object}",
468 " * @param {Function=} opt_callback",
469 " * @param {} num Number of things to add to {blah}.",
470 " * @return {!print_preview.PageNumberSet}",
471 " /* @returns {Number} */", # Should be /** @return {Number} */
472 "* @param {!LocalStrings}"
473 " Your type of Boolean is false!",
474 " Then I parameterized her Number from her friend!",
475 " A String of Pearls",
476 " types.params.aBoolean.typeString(someNumber)",
477 ]
478 for line in lines:
479 self.ShouldPassWrapperTypeCheck(line)
480
481 def testWrapperTypeFails(self):
482 lines = [
483 " /**@type {String}*/(string)",
484 " * @param{Number=} opt_blah A number",
485 "/** @private @return {!Boolean} */",
486 " * @param {number|String}",
487 ]
488 for line in lines:
489 self.ShouldFailWrapperTypeCheck(line)
490
491 def ShouldFailVarNameCheck(self, line):
492 """Checks that var unix_hacker, $dollar are style errors."""
493 error = self.checker.VarNameCheck(1, line)
494 self.assertNotEqual('', error,
495 msg='Should be flagged as style error: ' + line)
496 highlight = GetHighlight(line, error)
497 self.assertFalse('var ' in highlight);
498
499 def ShouldPassVarNameCheck(self, line):
500 """Checks that variableNamesLikeThis aren't style errors."""
501 self.assertEqual('', self.checker.VarNameCheck(1, line),
502 msg='Should not be flagged as style error: ' + line)
503
504 def testVarNameFails(self):
505 lines = [
506 "var private_;",
507 " var _super_private",
508 " var unix_hacker = someFunc();",
509 ]
510 for line in lines:
511 self.ShouldFailVarNameCheck(line)
512
513 def testVarNamePasses(self):
514 lines = [
515 " var namesLikeThis = [];",
516 " for (var i = 0; i < 10; ++i) { ",
517 "for (var i in obj) {",
518 " var one, two, three;",
519 " var magnumPI = {};",
520 " var g_browser = 'da browzer';",
521 "/** @const */ var Bla = options.Bla;", # goog.scope() replacement.
522 " var $ = function() {", # For legacy reasons.
523 " var StudlyCaps = cr.define('bla')", # Classes.
524 " var SCARE_SMALL_CHILDREN = [", # TODO(dbeam): add @const in
525 # front of all these vars like
526 "/** @const */ CONST_VAR = 1;", # this line has (<--).
527 ]
528 for line in lines:
529 self.ShouldPassVarNameCheck(line)
530
531
532 class ClosureLintTest(SuperMoxTestBase):
533 def setUp(self):
534 SuperMoxTestBase.setUp(self)
535
536 input_api = self.mox.CreateMockAnything()
537 input_api.os_path = os.path
538 input_api.re = re
539
540 input_api.change = self.mox.CreateMockAnything()
541 self.mox.StubOutWithMock(input_api.change, 'RepositoryRoot')
542 src_root = os.path.join(os.path.dirname(__file__), '..', '..')
543 input_api.change.RepositoryRoot().MultipleTimes().AndReturn(src_root)
544
545 output_api = self.mox.CreateMockAnything()
546
547 self.mox.ReplayAll()
548
549 self.checker = js_checker.JSChecker(input_api, output_api)
550
551 def ShouldPassClosureLint(self, source):
552 errors = self.checker.ClosureLint('', source=source)
553
554 for error in errors:
555 print 'Error: ' + error.message
556
557 self.assertListEqual([], errors)
558
559 def testBindFalsePositives(self):
560 sources = [
561 [
562 'var addOne = function(prop) {\n',
563 ' this[prop] += 1;\n',
564 '}.bind(counter, timer);\n',
565 '\n',
566 'setInterval(addOne, 1000);\n',
567 '\n',
568 ],
569 [
570 '/** Da clickz. */\n',
571 'button.onclick = function() { this.add_(this.total_); }.bind(this);\n',
572 ],
573 ]
574 for source in sources:
575 self.ShouldPassClosureLint(source)
576
577 def testPromiseFalsePositives(self):
578 sources = [
579 [
580 'Promise.reject(1).catch(function(error) {\n',
581 ' alert(error);\n',
582 '});\n',
583 ],
584 [
585 'var loaded = new Promise();\n',
586 'loaded.then(runAwesomeApp);\n',
587 'loaded.catch(showSadFace);\n',
588 '\n',
589 '/** Da loadz. */\n',
590 'document.onload = function() { loaded.resolve(); };\n',
591 '\n',
592 '/** Da errorz. */\n',
593 'document.onerror = function() { loaded.reject(); };\n',
594 '\n',
595 "if (document.readystate == 'complete') loaded.resolve();\n",
596 ],
597 ]
598 for source in sources:
599 self.ShouldPassClosureLint(source)
600
601
602 class CssStyleGuideTest(SuperMoxTestBase):
603 def setUp(self):
604 SuperMoxTestBase.setUp(self)
605
606 self.fake_file_name = 'fake.css'
607
608 self.fake_file = self.mox.CreateMockAnything()
609 self.mox.StubOutWithMock(self.fake_file, 'LocalPath')
610 self.fake_file.LocalPath().AndReturn(self.fake_file_name)
611 # Actual calls to NewContents() are defined in each test.
612 self.mox.StubOutWithMock(self.fake_file, 'NewContents')
613
614 self.input_api = self.mox.CreateMockAnything()
615 self.input_api.re = re
616 self.mox.StubOutWithMock(self.input_api, 'AffectedSourceFiles')
617 self.input_api.AffectedFiles(
618 include_deletes=False, file_filter=None).AndReturn([self.fake_file])
619
620 # Actual creations of PresubmitPromptWarning are defined in each test.
621 self.output_api = self.mox.CreateMockAnything()
622 self.mox.StubOutWithMock(self.output_api, 'PresubmitPromptWarning',
623 use_mock_anything=True)
624
625 self.output_api = self.mox.CreateMockAnything()
626 self.mox.StubOutWithMock(self.output_api, 'PresubmitNotifyResult',
627 use_mock_anything=True)
628
629 def VerifyContentsIsValid(self, contents):
630 self.fake_file.NewContents().AndReturn(contents.splitlines())
631 self.mox.ReplayAll()
632 css_checker.CSSChecker(self.input_api, self.output_api).RunChecks()
633
634 def VerifyContentsProducesOutput(self, contents, output):
635 self.fake_file.NewContents().AndReturn(contents.splitlines())
636 author_msg = ('Was the CSS checker useful? '
637 'Send feedback or hate mail to dbeam@chromium.org.')
638 self.output_api.PresubmitNotifyResult(author_msg).AndReturn(None)
639 self.output_api.PresubmitPromptWarning(
640 self.fake_file_name + ':\n' + output.strip()).AndReturn(None)
641 self.mox.ReplayAll()
642 css_checker.CSSChecker(self.input_api, self.output_api).RunChecks()
643
644 def testCssAlphaWithAtBlock(self):
645 self.VerifyContentsProducesOutput("""
646 <include src="../shared/css/cr/ui/overlay.css">
647 <include src="chrome://resources/totally-cool.css" />
648
649 /* A hopefully safely ignored comment and @media statement. /**/
650 @media print {
651 div {
652 display: block;
653 color: red;
654 }
655 }
656
657 .rule {
658 z-index: 5;
659 <if expr="not is macosx">
660 background-image: url(chrome://resources/BLAH); /* TODO(dbeam): Fix this. */
661 background-color: rgb(235, 239, 249);
662 </if>
663 <if expr="is_macosx">
664 background-color: white;
665 background-image: url(chrome://resources/BLAH2);
666 </if>
667 color: black;
668 }
669
670 <if expr="is_macosx">
671 .language-options-right {
672 visibility: hidden;
673 opacity: 1; /* TODO(dbeam): Fix this. */
674 }
675 </if>""", """
676 - Alphabetize properties and list vendor specific (i.e. -webkit) above standard.
677 display: block;
678 color: red;
679
680 z-index: 5;
681 color: black;""")
682
683 def testCssStringWithAt(self):
684 self.VerifyContentsIsValid("""
685 #logo {
686 background-image: url(images/google_logo.png@2x);
687 }
688
689 body.alternate-logo #logo {
690 -webkit-mask-image: url(images/google_logo.png@2x);
691 background: none;
692 }
693
694 .stuff1 {
695 }
696
697 .stuff2 {
698 }
699 """)
700
701 def testCssAlphaWithNonStandard(self):
702 self.VerifyContentsProducesOutput("""
703 div {
704 /* A hopefully safely ignored comment and @media statement. /**/
705 color: red;
706 -webkit-margin-start: 5px;
707 }""", """
708 - Alphabetize properties and list vendor specific (i.e. -webkit) above standard.
709 color: red;
710 -webkit-margin-start: 5px;""")
711
712 def testCssAlphaWithLongerDashedProps(self):
713 self.VerifyContentsProducesOutput("""
714 div {
715 border-left: 5px; /* A hopefully removed comment. */
716 border: 5px solid red;
717 }""", """
718 - Alphabetize properties and list vendor specific (i.e. -webkit) above standard.
719 border-left: 5px;
720 border: 5px solid red;""")
721
722 def testCssBracesHaveSpaceBeforeAndNothingAfter(self):
723 self.VerifyContentsProducesOutput("""
724 /* Hello! */div/* Comment here*/{
725 display: block;
726 }
727
728 blah /* hey! */
729 {
730 rule: value;
731 }
732
733 .this.is { /* allowed */
734 rule: value;
735 }""", """
736 - Start braces ({) end a selector, have a space before them and no rules after.
737 div{
738 {""")
739
740 def testCssClassesUseDashes(self):
741 self.VerifyContentsProducesOutput("""
742 .className,
743 .ClassName,
744 .class-name /* We should not catch this. */,
745 .class_name {
746 display: block;
747 }""", """
748 - Classes use .dash-form.
749 .className,
750 .ClassName,
751 .class_name {""")
752
753 def testCssCloseBraceOnNewLine(self):
754 self.VerifyContentsProducesOutput("""
755 @media { /* TODO(dbeam) Fix this case. */
756 .rule {
757 display: block;
758 }}
759
760 @-webkit-keyframe blah {
761 from { height: rotate(-10turn); }
762 100% { height: 500px; }
763 }
764
765 #id { /* ${TemplateExpressions} should be ignored. */
766 rule: ${someValue};
767 --css-mixin: {
768 color: red;
769 };
770 }
771
772 #rule {
773 rule: value; }""", """
774 - Always put a rule closing brace (}) on a new line.
775 rule: value; }""")
776
777 def testCssColonsHaveSpaceAfter(self):
778 self.VerifyContentsProducesOutput("""
779 div:not(.class):not([attr=5]), /* We should not catch this. */
780 div:not(.class):not([attr]) /* Nor this. */ {
781 background: url(data:image/jpeg,asdfasdfsadf); /* Ignore this. */
782 background: -webkit-linear-gradient(left, red,
783 80% blah blee blar);
784 color: red;
785 display:block;
786 }""", """
787 - Colons (:) should have a space after them.
788 display:block;
789
790 - Don't use data URIs in source files. Use grit instead.
791 background: url(data:image/jpeg,asdfasdfsadf);""")
792
793 def testCssFavorSingleQuotes(self):
794 self.VerifyContentsProducesOutput("""
795 html[dir="rtl"] body,
796 html[dir=ltr] body /* TODO(dbeam): Require '' around rtl in future? */ {
797 font-family: "Open Sans";
798 <if expr="is_macosx">
799 blah: blee;
800 </if>
801 }""", """
802 - Use single quotes (') instead of double quotes (") in strings.
803 html[dir="rtl"] body,
804 font-family: "Open Sans";""")
805
806 def testCssHexCouldBeShorter(self):
807 self.VerifyContentsProducesOutput("""
808 #abc,
809 #abc-,
810 #abc-ghij,
811 #abcdef-,
812 #abcdef-ghij,
813 #aaaaaa,
814 #bbaacc {
815 background-color: #336699; /* Ignore short hex rule if not gray. */
816 color: #999999;
817 color: #666;
818 }""", """
819 - Use abbreviated hex (#rgb) when in form #rrggbb.
820 color: #999999; (replace with #999)
821
822 - Use rgb() over #hex when not a shade of gray (like #333).
823 background-color: #336699; (replace with rgb(51, 102, 153))""")
824
825 def testCssUseMillisecondsForSmallTimes(self):
826 self.VerifyContentsProducesOutput("""
827 .transition-0s /* This is gross but may happen. */ {
828 transform: one 0.2s;
829 transform: two .1s;
830 transform: tree 1s;
831 transform: four 300ms;
832 }""", """
833 - Use milliseconds for time measurements under 1 second.
834 transform: one 0.2s; (replace with 200ms)
835 transform: two .1s; (replace with 100ms)""")
836
837 def testCssNoDataUrisInSourceFiles(self):
838 self.VerifyContentsProducesOutput("""
839 img {
840 background: url( data:image/jpeg,4\/\/350|\/|3|2 );
841 }""", """
842 - Don't use data URIs in source files. Use grit instead.
843 background: url( data:image/jpeg,4\/\/350|\/|3|2 );""")
844
845 def testCssNoQuotesInUrl(self):
846 self.VerifyContentsProducesOutput("""
847 img {
848 background: url('chrome://resources/images/blah.jpg');
849 background: url("../../folder/hello.png");
850 }""", """
851 - Use single quotes (') instead of double quotes (") in strings.
852 background: url("../../folder/hello.png");
853
854 - Don't use quotes in url().
855 background: url('chrome://resources/images/blah.jpg');
856 background: url("../../folder/hello.png");""")
857
858 def testCssOneRulePerLine(self):
859 self.VerifyContentsProducesOutput("""
860 a:not([hidden]):not(.custom-appearance):not([version=1]):first-of-type,
861 a:not([hidden]):not(.custom-appearance):not([version=1]):first-of-type ~
862 input[type='checkbox']:not([hidden]),
863 div {
864 background: url(chrome://resources/BLAH);
865 rule: value; /* rule: value; */
866 rule: value; rule: value;
867 }""", """
868 - One rule per line (what not to do: color: red; margin: 0;).
869 rule: value; rule: value;""")
870
871 def testCssOneSelectorPerLine(self):
872 self.VerifyContentsProducesOutput("""
873 a,
874 div,a,
875 div,/* Hello! */ span,
876 #id.class([dir=rtl):not(.class):any(a, b, d) {
877 rule: value;
878 }
879
880 a,
881 div,a {
882 some-other: rule here;
883 }""", """
884 - One selector per line (what not to do: a, b {}).
885 div,a,
886 div, span,
887 div,a {""")
888
889 def testCssPseudoElementDoubleColon(self):
890 self.VerifyContentsProducesOutput("""
891 a:href,
892 br::after,
893 ::-webkit-scrollbar-thumb,
894 a:not([empty]):hover:focus:active, /* shouldn't catch here and above */
895 abbr:after,
896 .tree-label:empty:after,
897 b:before,
898 :-WebKit-ScrollBar {
899 rule: value;
900 }""", """
901 - Pseudo-elements should use double colon (i.e. ::after).
902 :after (should be ::after)
903 :after (should be ::after)
904 :before (should be ::before)
905 :-WebKit-ScrollBar (should be ::-WebKit-ScrollBar)
906 """)
907
908 def testCssRgbIfNotGray(self):
909 self.VerifyContentsProducesOutput("""
910 #abc,
911 #aaa,
912 #aabbcc {
913 background: -webkit-linear-gradient(left, from(#abc), to(#def));
914 color: #bad;
915 color: #bada55;
916 }""", """
917 - Use rgb() over #hex when not a shade of gray (like #333).
918 background: -webkit-linear-gradient(left, from(#abc), to(#def)); """
919 """(replace with rgb(170, 187, 204), rgb(221, 238, 255))
920 color: #bad; (replace with rgb(187, 170, 221))
921 color: #bada55; (replace with rgb(186, 218, 85))""")
922
923 def testWebkitBeforeOrAfter(self):
924 self.VerifyContentsProducesOutput("""
925 .test {
926 -webkit-margin-before: 10px;
927 -webkit-margin-start: 20px;
928 -webkit-padding-after: 3px;
929 -webkit-padding-end: 5px;
930 }
931 """, """
932 - Use *-top/bottom instead of -webkit-*-before/after.
933 -webkit-margin-before: 10px; (replace with margin-top)
934 -webkit-padding-after: 3px; (replace with padding-bottom)""")
935
936 def testCssZeroWidthLengths(self):
937 self.VerifyContentsProducesOutput("""
938 @-webkit-keyframe anim {
939 0% { /* Ignore key frames */
940 width: 0px;
941 }
942 10% {
943 width: 10px;
944 }
945 100% {
946 width: 100px;
947 }
948 }
949
950 #logo {
951 background-image: url(images/google_logo.png@2x);
952 }
953
954 body.alternate-logo #logo {
955 -webkit-mask-image: url(images/google_logo.png@2x);
956 }
957
958 /* http://crbug.com/359682 */
959 #spinner-container #spinner {
960 -webkit-animation-duration: 1.0s;
961 }
962
963 .media-button.play > .state0.active,
964 .media-button[state='0'] > .state0.normal /* blah */, /* blee */
965 .media-button[state='0']:not(.disabled):hover > .state0.hover {
966 -webkit-animation: anim 0s;
967 -webkit-animation-duration: anim 0ms;
968 -webkit-transform: scale(0%);
969 background-position-x: 0em;
970 background-position-y: 0ex;
971 border-width: 0em;
972 color: hsl(0, 0%, 85%); /* Shouldn't trigger error. */
973 opacity: .0;
974 opacity: 0.0;
975 opacity: 0.;
976 }
977
978 @page {
979 border-width: 0mm;
980 height: 0cm;
981 width: 0in;
982 }""", """
983 - Use "0" for zero-width lengths (i.e. 0px -> 0)
984 width: 0px;
985 -webkit-transform: scale(0%);
986 background-position-x: 0em;
987 background-position-y: 0ex;
988 border-width: 0em;
989 opacity: .0;
990 opacity: 0.0;
991 opacity: 0.;
992 border-width: 0mm;
993 height: 0cm;
994 width: 0in;
995 """)
996
997 if __name__ == '__main__':
998 unittest.main()
OLDNEW
« no previous file with comments | « chrome/browser/PRESUBMIT.py ('k') | chrome/browser/web_dev_style/closure_lint_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698