Revert "Reland c91b178b07b0d - Delete dead signin code (SigninGlobalError)"
[chromium-blink-merge.git] / chrome / browser / web_dev_style / css_checker_test.py
blob1866614ab61ee9e25d523e79e8c58f6bc85303c0
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.
6 import css_checker
7 from os import path as os_path
8 import re
9 from sys import path as sys_path
10 import unittest
12 _HERE = os_path.dirname(os_path.abspath(__file__))
13 sys_path.append(os_path.join(_HERE, '..', '..', '..', 'tools'))
15 import find_depot_tools # pylint: disable=W0611
16 from testing_support.super_mox import SuperMoxTestBase
19 class CssCheckerTest(SuperMoxTestBase):
20 def setUp(self):
21 SuperMoxTestBase.setUp(self)
23 self.fake_file_name = 'fake.css'
25 self.fake_file = self.mox.CreateMockAnything()
26 self.mox.StubOutWithMock(self.fake_file, 'LocalPath')
27 self.fake_file.LocalPath().AndReturn(self.fake_file_name)
28 # Actual calls to NewContents() are defined in each test.
29 self.mox.StubOutWithMock(self.fake_file, 'NewContents')
31 self.input_api = self.mox.CreateMockAnything()
32 self.input_api.re = re
33 self.mox.StubOutWithMock(self.input_api, 'AffectedSourceFiles')
34 self.input_api.AffectedFiles(
35 include_deletes=False, file_filter=None).AndReturn([self.fake_file])
37 # Actual creations of PresubmitPromptWarning are defined in each test.
38 self.output_api = self.mox.CreateMockAnything()
39 self.mox.StubOutWithMock(self.output_api, 'PresubmitPromptWarning',
40 use_mock_anything=True)
42 self.output_api = self.mox.CreateMockAnything()
43 self.mox.StubOutWithMock(self.output_api, 'PresubmitNotifyResult',
44 use_mock_anything=True)
46 def VerifyContentsIsValid(self, contents):
47 self.fake_file.NewContents().AndReturn(contents.splitlines())
48 self.mox.ReplayAll()
49 css_checker.CSSChecker(self.input_api, self.output_api).RunChecks()
51 def VerifyContentsProducesOutput(self, contents, output):
52 self.fake_file.NewContents().AndReturn(contents.splitlines())
53 self.output_api.PresubmitPromptWarning(
54 self.fake_file_name + ':\n' + output.strip()).AndReturn(None)
55 self.mox.ReplayAll()
56 css_checker.CSSChecker(self.input_api, self.output_api).RunChecks()
58 def testCssAlphaWithAtBlock(self):
59 self.VerifyContentsProducesOutput("""
60 <include src="../shared/css/cr/ui/overlay.css">
61 <include src="chrome://resources/totally-cool.css" />
63 /* A hopefully safely ignored comment and @media statement. /**/
64 @media print {
65 div {
66 display: block;
67 color: red;
71 .rule {
72 z-index: 5;
73 <if expr="not is macosx">
74 background-image: url(chrome://resources/BLAH); /* TODO(dbeam): Fix this. */
75 background-color: rgb(235, 239, 249);
76 </if>
77 <if expr="is_macosx">
78 background-color: white;
79 background-image: url(chrome://resources/BLAH2);
80 </if>
81 color: black;
84 <if expr="is_macosx">
85 .language-options-right {
86 visibility: hidden;
87 opacity: 1; /* TODO(dbeam): Fix this. */
89 </if>""", """
90 - Alphabetize properties and list vendor specific (i.e. -webkit) above standard.
91 display: block;
92 color: red;
94 z-index: 5;
95 color: black;""")
97 def testCssStringWithAt(self):
98 self.VerifyContentsIsValid("""
99 #logo {
100 background-image: url(images/google_logo.png@2x);
103 body.alternate-logo #logo {
104 -webkit-mask-image: url(images/google_logo.png@2x);
105 background: none;
108 .stuff1 {
111 .stuff2 {
113 """)
115 def testCssAlphaWithNonStandard(self):
116 self.VerifyContentsProducesOutput("""
117 div {
118 /* A hopefully safely ignored comment and @media statement. /**/
119 color: red;
120 -webkit-margin-start: 5px;
121 }""", """
122 - Alphabetize properties and list vendor specific (i.e. -webkit) above standard.
123 color: red;
124 -webkit-margin-start: 5px;""")
126 def testCssAlphaWithLongerDashedProps(self):
127 self.VerifyContentsProducesOutput("""
128 div {
129 border-left: 5px; /* A hopefully removed comment. */
130 border: 5px solid red;
131 }""", """
132 - Alphabetize properties and list vendor specific (i.e. -webkit) above standard.
133 border-left: 5px;
134 border: 5px solid red;""")
136 def testCssBracesHaveSpaceBeforeAndNothingAfter(self):
137 self.VerifyContentsProducesOutput("""
138 /* Hello! */div/* Comment here*/{
139 display: block;
142 blah /* hey! */
144 rule: value;
147 .mixed-in {
148 display: none;
149 --css-mixin: {
150 color: red;
151 }; /* This should be ignored. */
154 .this.is { /* allowed */
155 rule: value;
156 }""", """
157 - Start braces ({) end a selector, have a space before them and no rules after.
158 div{
159 {""")
161 def testCssClassesUseDashes(self):
162 self.VerifyContentsProducesOutput("""
163 .className,
164 .ClassName,
165 .class-name /* We should not catch this. */,
166 .class_name {
167 display: block;
168 }""", """
169 - Classes use .dash-form.
170 .className,
171 .ClassName,
172 .class_name {""")
174 def testCssCloseBraceOnNewLine(self):
175 self.VerifyContentsProducesOutput("""
176 @media { /* TODO(dbeam) Fix this case. */
177 .rule {
178 display: block;
181 @-webkit-keyframe blah {
182 from { height: rotate(-10turn); }
183 100% { height: 500px; }
186 #id { /* ${TemplateExpressions} should be ignored. */
187 rule: ${someValue};
188 --css-mixin: {
189 color: red;
193 .paper-wrapper {
194 --paper-thinger: {
195 background: blue;
199 #rule {
200 rule: value; }""", """
201 - Always put a rule closing brace (}) on a new line.
202 rule: value; }""")
204 def testCssColonsHaveSpaceAfter(self):
205 self.VerifyContentsProducesOutput("""
206 div:not(.class):not([attr=5]), /* We should not catch this. */
207 div:not(.class):not([attr]) /* Nor this. */ {
208 background: url(data:image/jpeg,asdfasdfsadf); /* Ignore this. */
209 background: -webkit-linear-gradient(left, red,
210 80% blah blee blar);
211 color: red;
212 display:block;
213 }""", """
214 - Colons (:) should have a space after them.
215 display:block;
217 - Don't use data URIs in source files. Use grit instead.
218 background: url(data:image/jpeg,asdfasdfsadf);""")
220 def testCssFavorSingleQuotes(self):
221 self.VerifyContentsProducesOutput("""
222 html[dir="rtl"] body,
223 html[dir=ltr] body /* TODO(dbeam): Require '' around rtl in future? */ {
224 font-family: "Open Sans";
225 <if expr="is_macosx">
226 blah: blee;
227 </if>
228 }""", """
229 - Use single quotes (') instead of double quotes (") in strings.
230 html[dir="rtl"] body,
231 font-family: "Open Sans";""")
233 def testCssHexCouldBeShorter(self):
234 self.VerifyContentsProducesOutput("""
235 #abc,
236 #abc-,
237 #abc-ghij,
238 #abcdef-,
239 #abcdef-ghij,
240 #aaaaaa,
241 #bbaacc {
242 background-color: #336699; /* Ignore short hex rule if not gray. */
243 color: #999999;
244 color: #666;
245 }""", """
246 - Use abbreviated hex (#rgb) when in form #rrggbb.
247 color: #999999; (replace with #999)
249 - Use rgb() over #hex when not a shade of gray (like #333).
250 background-color: #336699; (replace with rgb(51, 102, 153))""")
252 def testCssUseMillisecondsForSmallTimes(self):
253 self.VerifyContentsProducesOutput("""
254 .transition-0s /* This is gross but may happen. */ {
255 transform: one 0.2s;
256 transform: two .1s;
257 transform: tree 1s;
258 transform: four 300ms;
259 }""", """
260 - Use milliseconds for time measurements under 1 second.
261 transform: one 0.2s; (replace with 200ms)
262 transform: two .1s; (replace with 100ms)""")
264 def testCssNoDataUrisInSourceFiles(self):
265 self.VerifyContentsProducesOutput("""
266 img {
267 background: url( data:image/jpeg,4\/\/350|\/|3|2 );
268 }""", """
269 - Don't use data URIs in source files. Use grit instead.
270 background: url( data:image/jpeg,4\/\/350|\/|3|2 );""")
272 def testCssNoQuotesInUrl(self):
273 self.VerifyContentsProducesOutput("""
274 img {
275 background: url('chrome://resources/images/blah.jpg');
276 background: url("../../folder/hello.png");
277 }""", """
278 - Use single quotes (') instead of double quotes (") in strings.
279 background: url("../../folder/hello.png");
281 - Don't use quotes in url().
282 background: url('chrome://resources/images/blah.jpg');
283 background: url("../../folder/hello.png");""")
285 def testCssOneRulePerLine(self):
286 self.VerifyContentsProducesOutput("""
287 a:not([hidden]):not(.custom-appearance):not([version=1]):first-of-type,
288 a:not([hidden]):not(.custom-appearance):not([version=1]):first-of-type ~
289 input[type='checkbox']:not([hidden]),
290 div {
291 background: url(chrome://resources/BLAH);
292 rule: value; /* rule: value; */
293 rule: value; rule: value;
296 .remix {
297 --dj: {
298 spin: that;
301 """, """
302 - One rule per line (what not to do: color: red; margin: 0;).
303 rule: value; rule: value;""")
305 def testCssOneSelectorPerLine(self):
306 self.VerifyContentsProducesOutput("""
308 div,a,
309 div,/* Hello! */ span,
310 #id.class([dir=rtl):not(.class):any(a, b, d) {
311 rule: value;
315 div,a {
316 some-other: rule here;
317 }""", """
318 - One selector per line (what not to do: a, b {}).
319 div,a,
320 div, span,
321 div,a {""")
323 def testCssPseudoElementDoubleColon(self):
324 self.VerifyContentsProducesOutput("""
325 a:href,
326 br::after,
327 ::-webkit-scrollbar-thumb,
328 a:not([empty]):hover:focus:active, /* shouldn't catch here and above */
329 abbr:after,
330 .tree-label:empty:after,
331 b:before,
332 :-WebKit-ScrollBar {
333 rule: value;
334 }""", """
335 - Pseudo-elements should use double colon (i.e. ::after).
336 :after (should be ::after)
337 :after (should be ::after)
338 :before (should be ::before)
339 :-WebKit-ScrollBar (should be ::-WebKit-ScrollBar)
340 """)
342 def testCssRgbIfNotGray(self):
343 self.VerifyContentsProducesOutput("""
344 #abc,
345 #aaa,
346 #aabbcc {
347 background: -webkit-linear-gradient(left, from(#abc), to(#def));
348 color: #bad;
349 color: #bada55;
350 }""", """
351 - Use rgb() over #hex when not a shade of gray (like #333).
352 background: -webkit-linear-gradient(left, from(#abc), to(#def)); """
353 """(replace with rgb(170, 187, 204), rgb(221, 238, 255))
354 color: #bad; (replace with rgb(187, 170, 221))
355 color: #bada55; (replace with rgb(186, 218, 85))""")
357 def testWebkitBeforeOrAfter(self):
358 self.VerifyContentsProducesOutput("""
359 .test {
360 -webkit-margin-before: 10px;
361 -webkit-margin-start: 20px;
362 -webkit-padding-after: 3px;
363 -webkit-padding-end: 5px;
365 """, """
366 - Use *-top/bottom instead of -webkit-*-before/after.
367 -webkit-margin-before: 10px; (replace with margin-top)
368 -webkit-padding-after: 3px; (replace with padding-bottom)""")
370 def testCssZeroWidthLengths(self):
371 self.VerifyContentsProducesOutput("""
372 @-webkit-keyframe anim {
373 0% { /* Ignore key frames */
374 width: 0px;
376 10% {
377 width: 10px;
379 100% {
380 width: 100px;
384 #logo {
385 background-image: url(images/google_logo.png@2x);
388 body.alternate-logo #logo {
389 -webkit-mask-image: url(images/google_logo.png@2x);
392 /* http://crbug.com/359682 */
393 #spinner-container #spinner {
394 -webkit-animation-duration: 1.0s;
397 .media-button.play > .state0.active,
398 .media-button[state='0'] > .state0.normal /* blah */, /* blee */
399 .media-button[state='0']:not(.disabled):hover > .state0.hover {
400 -webkit-animation: anim 0s;
401 -webkit-animation-duration: anim 0ms;
402 -webkit-transform: scale(0%);
403 background-position-x: 0em;
404 background-position-y: 0ex;
405 border-width: 0em;
406 color: hsl(0, 0%, 85%); /* Shouldn't trigger error. */
407 opacity: .0;
408 opacity: 0.0;
409 opacity: 0.;
412 @page {
413 border-width: 0mm;
414 height: 0cm;
415 width: 0in;
416 }""", """
417 - Use "0" for zero-width lengths (i.e. 0px -> 0)
418 width: 0px;
419 -webkit-transform: scale(0%);
420 background-position-x: 0em;
421 background-position-y: 0ex;
422 border-width: 0em;
423 opacity: .0;
424 opacity: 0.0;
425 opacity: 0.;
426 border-width: 0mm;
427 height: 0cm;
428 width: 0in;
429 """)
432 if __name__ == '__main__':
433 unittest.main()