Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 #!/usr/bin/env python | |
| 2 # Copyright (c) 2012 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 | |
| 7 """Unit tests for Web Development Style Guide checker.""" | |
| 8 | |
| 9 | |
| 10 import re | |
| 11 import unittest | |
| 12 from testing_support.super_mox import SuperMoxTestBase | |
|
M-A Ruel
2012/02/09 22:14:14
ROOT = os.path.dirname(os.path.abspath(__file__))
Dan Beam
2012/02/14 17:02:01
This doesn't work so far as SuperMoxTestBase is in
M-A Ruel
2012/02/14 17:15:19
I often use an adhoc script to do it automatically
Dan Beam
2012/02/14 17:48:46
But this is script is also in depot_tools. You're
Dan Beam
2012/02/15 01:07:44
Done. (this script is in in tools/, I was on crack
| |
| 13 from web_dev_style import css_checker | |
| 14 | |
| 15 | |
| 16 class WebDevStyleGuideTest(SuperMoxTestBase): | |
| 17 @staticmethod | |
| 18 def RunAllTests(): | |
| 19 tests = unittest.TestLoader().loadTestsFromTestCase(WebDevStyleGuideTest) | |
| 20 unittest.TextTestRunner().run(tests) | |
| 21 | |
| 22 def setUp(self): | |
| 23 SuperMoxTestBase.setUp(self) | |
| 24 | |
| 25 self.fake_file_name = 'fake.css' | |
| 26 | |
| 27 self.fake_file = self.mox.CreateMockAnything() | |
| 28 self.mox.StubOutWithMock(self.fake_file, 'LocalPath') | |
| 29 self.fake_file.LocalPath().AndReturn(self.fake_file_name) | |
| 30 # Actual calls to NewContents() are defined in each test. | |
| 31 self.mox.StubOutWithMock(self.fake_file, 'NewContents') | |
| 32 | |
| 33 self.input_api = self.mox.CreateMockAnything() | |
| 34 self.input_api.re = re | |
| 35 self.mox.StubOutWithMock(self.input_api, 'AffectedSourceFiles') | |
| 36 self.input_api.AffectedFiles( | |
| 37 include_deletes=False, file_filter=None).AndReturn([self.fake_file]) | |
| 38 | |
| 39 # Actual creations of PresubmitNotifyResult are defined in each test. | |
| 40 self.output_api = self.mox.CreateMockAnything() | |
| 41 self.mox.StubOutWithMock(self.output_api, 'PresubmitNotifyResult', | |
| 42 use_mock_anything=True) | |
| 43 | |
| 44 def VerifyContentsProducesOutput(self, contents, output): | |
| 45 self.fake_file.NewContents().AndReturn(contents.splitlines()) | |
| 46 self.output_api.PresubmitNotifyResult( | |
| 47 self.fake_file_name + ':\n' + output.strip()).AndReturn(None) | |
| 48 self.mox.ReplayAll() | |
| 49 css_checker.CSSChecker(self.input_api, self.output_api).RunChecks() | |
| 50 | |
| 51 def testCssAlphaWithAtBlock(self): | |
| 52 self.VerifyContentsProducesOutput(""" | |
| 53 /* A hopefully safely ignored comment and @media statement. /**/ | |
| 54 @media print { | |
| 55 div { | |
| 56 display: block; | |
| 57 color: red; | |
| 58 } | |
| 59 }""", """ | |
| 60 - Alphabetize properties and list vendor specific (i.e. -webkit) above standard. | |
| 61 display: block; | |
| 62 color: red;""") | |
| 63 | |
| 64 def testCssAlphaWithNonStandard(self): | |
| 65 self.VerifyContentsProducesOutput(""" | |
| 66 div { | |
| 67 /* A hopefully safely ignored comment and @media statement. /**/ | |
| 68 color: red; | |
| 69 -webkit-margin-start: 5px; | |
| 70 }""", """ | |
| 71 - Alphabetize properties and list vendor specific (i.e. -webkit) above standard. | |
| 72 color: red; | |
| 73 -webkit-margin-start: 5px;""") | |
| 74 | |
| 75 def testCssAlphaWithLongerDashedProps(self): | |
| 76 self.VerifyContentsProducesOutput(""" | |
| 77 div { | |
| 78 border-left: 5px; /* A hopefully removed comment. */ | |
| 79 border: 5px solid red; | |
| 80 }""", """ | |
| 81 - Alphabetize properties and list vendor specific (i.e. -webkit) above standard. | |
| 82 border-left: 5px; | |
| 83 border: 5px solid red;""") | |
| 84 | |
| 85 def testCssBracesHaveSpaceBeforeAndNothingAfter(self): | |
| 86 self.VerifyContentsProducesOutput(""" | |
| 87 /* Hello! */div/* Comment here*/{ | |
| 88 display: block; | |
| 89 } | |
| 90 | |
| 91 blah /* hey! */ | |
| 92 { | |
| 93 rule: value; | |
| 94 } | |
| 95 | |
| 96 .this.is { /* allowed */ | |
| 97 rule: value; | |
| 98 }""", """ | |
| 99 - Start braces ({) end a selector, have a space before them and no rules after. | |
| 100 div{ | |
| 101 {""") | |
| 102 | |
| 103 def testCssClassesUseDashes(self): | |
| 104 self.VerifyContentsProducesOutput(""" | |
| 105 .className, | |
| 106 .ClassName, | |
| 107 .class-name /* We should not catch this. */, | |
| 108 .class_name { | |
| 109 display: block; | |
| 110 }""", """ | |
| 111 - Classes use .dash-form. | |
| 112 .className, | |
| 113 .ClassName, | |
| 114 .class_name {""") | |
| 115 | |
| 116 def testCssCloseBraceOnNewLine(self): | |
| 117 self.VerifyContentsProducesOutput(""" | |
| 118 @media { /* TODO(dbeam) Fix this case. | |
| 119 .rule { | |
| 120 display: block; | |
| 121 }} | |
| 122 | |
| 123 #rule { | |
| 124 rule: value; }""", """ | |
| 125 - Always put a rule closing brace (}) on a new line. | |
| 126 rule: value; }""") | |
| 127 | |
| 128 def testCssColonsHaveSpaceAfter(self): | |
| 129 self.VerifyContentsProducesOutput(""" | |
| 130 div:not(.class):not([attr]) /* We should not catch this. */ { | |
| 131 display:block; | |
| 132 }""", """ | |
| 133 - Colons (:) should have a space after them. | |
| 134 display:block;""") | |
| 135 | |
| 136 def testCssFavorSingleQuotes(self): | |
| 137 self.VerifyContentsProducesOutput(""" | |
| 138 html[dir="rtl"] body, | |
| 139 html[dir=ltr] body /* TODO(dbeam): Require '' around rtl in future? */ { | |
| 140 background: url("chrome://resources/BLAH"); | |
| 141 font-family: "Open Sans"; | |
| 142 }""", """ | |
| 143 - Use single quotes (') instead of double quotes (") in strings. | |
| 144 html[dir="rtl"] body, | |
| 145 background: url("chrome://resources/BLAH"); | |
| 146 font-family: "Open Sans";""") | |
| 147 | |
| 148 def testCssHexCouldBeShorter(self): | |
| 149 self.VerifyContentsProducesOutput(""" | |
| 150 #abc, | |
| 151 #abc-, | |
| 152 #abc-ghij, | |
| 153 #abcdef-, | |
| 154 #abcdef-ghij, | |
| 155 #aaaaaa, | |
| 156 #bbaacc { | |
| 157 color: #999999; | |
| 158 color: #666; | |
| 159 }""", """ | |
| 160 - Use abbreviated hex (#rgb) when in form #rrggbb. | |
| 161 color: #999999; (replace with #99)""") | |
| 162 | |
| 163 def testCssUseMillisecondsForSmallTimes(self): | |
| 164 self.VerifyContentsProducesOutput(""" | |
| 165 .transition-0s /* This is gross but may happen. */ { | |
| 166 transform: one 0.2s; | |
| 167 transform: two .1s; | |
| 168 transform: tree 1s; | |
| 169 transform: four 300ms; | |
| 170 }""", """ | |
| 171 - Use milliseconds for time measurements under 1 second. | |
| 172 transform: one 0.2s; (replace with 200ms) | |
| 173 transform: two .1s; (replace with 100ms)""") | |
| 174 | |
| 175 def testCssOneRulePerLine(self): | |
| 176 self.VerifyContentsProducesOutput(""" | |
| 177 div { | |
| 178 rule: value; /* rule: value; */ | |
| 179 rule: value; rule: value; | |
| 180 }""", """ | |
| 181 - One rule per line (what not to do: color: red; margin: 0;). | |
| 182 rule: value; rule: value;""") | |
| 183 | |
| 184 def testCssOneSelectorPerLine(self): | |
| 185 self.VerifyContentsProducesOutput(""" | |
| 186 a, | |
| 187 div,a, | |
| 188 div,/* Hello! */ span, | |
| 189 #id.class([dir=rtl):not(.class):any(a, b, d) { | |
| 190 rule: value; | |
| 191 }""", """ | |
| 192 - One selector per line (what not to do: a, b {}). | |
| 193 div,a, | |
| 194 div, span,""") | |
| 195 | |
| 196 | |
| 197 def testCssRgbIfNotGray(self): | |
| 198 self.VerifyContentsProducesOutput(""" | |
| 199 #abc, | |
| 200 #aaa, | |
| 201 #aabbcc { | |
| 202 background: -webkit-linear-gradient(left, from(#abc), to(#def)); | |
| 203 color: #bad; | |
| 204 color: #bada55; | |
| 205 }""", """ | |
| 206 - Use rgb() over #hex when not a shade of gray (like #333). | |
| 207 background: -webkit-linear-gradient(left, from(#abc), to(#def)); """ | |
| 208 """(replace with rgb(170, 187, 204), rgb(221, 238, 255)) | |
| 209 color: #bad; (replace with rgb(187, 170, 221)) | |
| 210 color: #bada55; (replace with rgb(186, 218, 85))""") | |
| 211 | |
| 212 def testCssZeroLengthTerms(self): | |
| 213 self.VerifyContentsProducesOutput(""" | |
| 214 @-webkit-keyframe anim { | |
| 215 0% { /* Ignore key frames */ | |
| 216 width: 0px; | |
| 217 } | |
| 218 10% { | |
| 219 width: 10px; | |
| 220 } | |
| 221 100% { | |
| 222 width: 100px; | |
| 223 } | |
| 224 } | |
| 225 .animating { | |
| 226 -webkit-animation: anim 0s; | |
| 227 -webkit-animation-duration: anim 0ms; | |
| 228 -webkit-transform: scale(0%), | |
| 229 translateX(0deg), | |
| 230 translateY(0rad), | |
| 231 translateZ(0grad); | |
| 232 background-position-x: 0em; | |
| 233 background-position-y: 0ex; | |
| 234 border-width: 0em; | |
| 235 color: hsl(0, 0%, 85%); /* Shouldn't trigger error. */ | |
| 236 } | |
| 237 | |
| 238 @page { | |
| 239 border-width: 0mm; | |
| 240 height: 0cm; | |
| 241 width: 0in; | |
| 242 }""",""" | |
| 243 - Make all zero length terms (i.e. 0px) 0 unless inside of hsl() or part of""" | |
| 244 """ @keyframe. | |
| 245 width: 0px; | |
| 246 -webkit-animation: anim 0s; | |
| 247 -webkit-animation-duration: anim 0ms; | |
| 248 -webkit-transform: scale(0%), | |
| 249 translateX(0deg), | |
| 250 translateY(0rad), | |
| 251 translateZ(0grad); | |
| 252 background-position-x: 0em; | |
| 253 background-position-y: 0ex; | |
| 254 border-width: 0em; | |
| 255 border-width: 0mm; | |
| 256 height: 0cm; | |
| 257 width: 0in; | |
| 258 """) | |
| 259 | |
| 260 if __name__ == '__main__': | |
| 261 WebDevStyleGuideTest.RunAllTests() | |
| OLD | NEW |