Package cssutils :: Package tests :: Module test_selector
[hide private]
[frames] | no frames]

Source Code for Module cssutils.tests.test_selector

  1  """Testcases for cssutils.css.selector.Selector. 
  2   
  3  what should happen here? 
  4      - star 7 hack:: 
  5          x* 
  6          does not validate but works in IE>5 and FF, does it??? 
  7   
  8  """ 
  9  __version__ = '$Id: test_selector.py 1116 2008-03-05 13:52:23Z cthedot $' 
 10   
 11  import xml.dom 
 12  import basetest 
 13  import cssutils 
 14   
15 -class SelectorTestCase(basetest.BaseTestCase):
16
17 - def setUp(self):
18 self.r = cssutils.css.Selector('*')
19
20 - def test_init(self):
21 "Selector.__init__()" 22 s = cssutils.css.Selector('*') 23 self.assertEqual((None, '*'), s.element) 24 self.assertEqual({}, s._namespaces.namespaces) 25 self.assertEqual(None, s.parentList) 26 self.assertEqual('*', s.selectorText) 27 self.assertEqual((0,0,0,0), s.specificity) 28 self.assertEqual(True, s.wellformed) 29 30 s = cssutils.css.Selector(('p|b', {'p': 'URI'}) ) 31 self.assertEqual(('URI', 'b'), s.element) 32 self.assertEqual({'p': 'URI'}, s._namespaces.namespaces) 33 self.assertEqual(None, s.parentList) 34 self.assertEqual('p|b', s.selectorText) 35 self.assertEqual((0,0,0,1), s.specificity) 36 self.assertEqual(True, s.wellformed) 37 38 self.assertRaisesEx(xml.dom.NamespaceErr, cssutils.css.Selector, 'p|b')
39
40 - def test_element(self):
41 "Selector.element (TODO: RESOLVE)" 42 tests = { 43 '*': (None, '*'), 44 'x': (None, 'x'), 45 '\\x': (None, '\\x'), 46 '|x': (u'', 'x'), 47 '*|x': (cssutils._ANYNS, 'x'), 48 'ex|x': (u'example', 'x'), 49 'a x': (None, 'x'), 50 'a+x': (None, 'x'), 51 'a>x': (None, 'x'), 52 'a~x': (None, 'x'), 53 'a+b~c x': (None, 'x'), 54 'x[href]': (None, 'x'), 55 'x[href="123"]': (None, 'x'), 56 'x:hover': (None, 'x'), 57 'x:first-letter': (None, 'x'), # TODO: Really? 58 'x::first-line': (None, 'x'), # TODO: Really? 59 'x:not(href)': (None, 'x'), # TODO: Really? 60 61 '#id': None, 62 '.c': None, 63 'x#id': (None, 'x'), 64 'x.c': (None, 'x') 65 } 66 for test, ele in tests.items(): 67 s = cssutils.css.Selector((test,{'ex': 'example'})) 68 self.assertEqual(ele, s.element)
69
70 - def test_namespaces(self):
71 "Selector.namespaces" 72 namespaces = [ 73 {'p': 'other'}, # no default 74 {'': 'default', 'p': 'other'}, # with default 75 {'': 'default', 'p': 'default' } # same default 76 ] 77 tests = { 78 # selector: with default, no default, same default 79 '*': ('*', '*', '*'), 80 'x': ('x', 'x', 'x'), 81 '|*': ('|*', '|*', '|*'), 82 '|x': ('|x', '|x', '|x'), 83 '*|*': ('*|*', '*|*', '*|*'), 84 '*|x': ('*|x', '*|x', '*|x'), 85 'p|*': ('p|*', 'p|*', '*'), 86 'p|x': ('p|x', 'p|x', 'x'), 87 'x[a][|a][*|a][p|a]': ('x[a][a][*|a][p|a]', 88 'x[a][a][*|a][p|a]', 89 'x[a][a][*|a][a]') 90 } 91 for sel, exp in tests.items(): 92 for i, result in enumerate(exp): 93 s = cssutils.css.Selector((sel, namespaces[i])) 94 self.assertEqual(result, s.selectorText) 95 96 # add to CSSStyleSheet 97 sheet = cssutils.css.CSSStyleSheet() 98 sheet.cssText = '@namespace p "u"; a { color: green }' 99 100 r = sheet.cssRules[1] 101 102 self.assertEqual(r.selectorText, u'a') 103 104 # add default namespace 105 sheet.namespaces[''] = 'a'; 106 self.assertEqual(r.selectorText, u'|a') 107 108 del sheet.namespaces['']; 109 self.assertEqual(r.selectorText, u'a')
110 111 # r.selectorList.append('a') 112 # self.assertEqual(r.selectorText, u'|a, a') 113 # r.selectorList.append('*|a') 114 # self.assertEqual(r.selectorText, u'|a, a, *|a') 115
116 - def test_default_namespace(self):
117 "Selector.namespaces default" 118 css = '''@namespace "default"; 119 a[att] { color:green; } 120 ''' 121 sheet = cssutils.css.CSSStyleSheet() 122 sheet.cssText = css 123 self.assertEqual(sheet.cssText, 124 u'@namespace "default";\na[att] {\n color: green\n }') 125 # use a prefix for default namespace, does not goes for atts! 126 sheet.namespaces['p'] = 'default' 127 self.assertEqual(sheet.cssText, 128 u'@namespace p "default";\np|a[att] {\n color: green\n }')
129
130 - def test_parentList(self):
131 "Selector.parentList" 132 sl = cssutils.css.SelectorList('a, b') 133 for sel in sl: 134 self.assertEqual(sl, sel.parentList) 135 136 newsel = cssutils.css.Selector('x') 137 sl.append(newsel) 138 self.assertEqual(sl, newsel.parentList) 139 140 newsel = cssutils.css.Selector('y') 141 sl.appendSelector(newsel) 142 self.assertEqual(sl, newsel.parentList)
143
144 - def test_selectorText(self):
145 "Selector.selectorText" 146 tests = { 147 # combinators 148 u'a+b>c~e f': u'a + b > c ~ e f', 149 u'a + b > c ~ e f': u'a + b > c ~ e f', 150 u'a+b': u'a + b', 151 u'a + b': 'a + b', 152 u'a\n +\t b': 'a + b', 153 u'a~b': u'a ~ b', 154 u'a b': None, 155 u'a b': 'a b', 156 u'a\nb': 'a b', 157 u'a\tb': 'a b', 158 u'a #b': 'a #b', 159 u'a .b': 'a .b', 160 u'a * b': None, 161 # > 162 u'a>b': u'a > b', 163 u'a> b': 'a > b', 164 u'a >b': 'a > b', 165 u'a > b': 'a > b', 166 # + 167 u'a+b': u'a + b', 168 u'a+ b': 'a + b', 169 u'a +b': 'a + b', 170 u'a + b': 'a + b', 171 # ~ 172 u'a~b': u'a ~ b', 173 u'a~ b': 'a ~ b', 174 u'a ~b': 'a ~ b', 175 u'a ~ b': 'a ~ b', 176 177 # type selector 178 u'a': None, 179 u'h1-a_x__--': None, 180 u'a-a': None, 181 u'a_a': None, 182 u'-a': None, 183 u'_': None, 184 u'-_': None, 185 ur'-\72': u'-r', 186 #ur'\25': u'%', # TODO: should be escaped! 187 u'.a a': None, 188 u'a1': None, 189 u'a1-1': None, 190 u'.a1-1': None, 191 192 # universal 193 u'*': None, 194 u'*/*x*/': None, 195 u'* /*x*/': None, 196 u'*:hover': None, 197 u'* :hover': None, 198 u'*:lang(fr)': None, 199 u'* :lang(fr)': None, 200 u'*::first-line': None, 201 u'* ::first-line': None, 202 u'*[lang=fr]': None, 203 u'[lang=fr]': None, 204 205 # HASH 206 u'''#a''': None, 207 u'''#a1''': None, 208 u'''#1a''': None, # valid to grammar but not for HTML 209 u'''#1''': None, # valid to grammar but not for HTML 210 u'''a#b''': None, 211 u'''a #b''': None, 212 u'''a#b.c''': None, 213 u'''a.c#b''': None, 214 u'''a #b.c''': None, 215 u'''a .c#b''': None, 216 217 # class 218 u'ab': 'ab', 219 u'a.b': None, 220 u'a.b.c': None, 221 u'.a1._1': None, 222 223 # attrib 224 u'''[x]''': None, 225 u'''*[x]''': None, 226 u'''a[x]''': None, 227 u'''a[ x]''': 'a[x]', 228 u'''a[x ]''': 'a[x]', 229 u'''a [x]''': 'a [x]', 230 u'''* [x]''': None, # is really * *[x] 231 232 u'''a[x="1"]''': None, 233 u'''a[x ="1"]''': 'a[x="1"]', 234 u'''a[x= "1"]''': 'a[x="1"]', 235 u'''a[x = "1"]''': 'a[x="1"]', 236 u'''a[ x = "1"]''': 'a[x="1"]', 237 u'''a[x = "1" ]''': 'a[x="1"]', 238 u'''a[ x = "1" ]''': 'a[x="1"]', 239 u'''a [ x = "1" ]''': 'a [x="1"]', 240 241 u'''a[x~=a1]''': None, 242 u'''a[x ~=a1]''': 'a[x~=a1]', 243 u'''a[x~= a1]''': 'a[x~=a1]', 244 u'''a[x ~= a1]''': 'a[x~=a1]', 245 u'''a[ x ~= a1]''': 'a[x~=a1]', 246 u'''a[x ~= a1 ]''': 'a[x~=a1]', 247 u'''a[ x ~= a1 ]''': 'a[x~=a1]', 248 u'''a [ x ~= a1 ]''': 'a [x~=a1]', # same as next! 249 u'''a *[ x ~= a1 ]''': 'a *[x~=a1]', 250 251 u'''a[x|=en]''': None, 252 u'''a[x|= en]''': 'a[x|=en]', 253 u'''a[x |=en]''': 'a[x|=en]', 254 u'''a[x |= en]''': 'a[x|=en]', 255 u'''a[ x |= en]''': 'a[x|=en]', 256 u'''a[x |= en ]''': 'a[x|=en]', 257 u'''a[ x |= en]''': 'a[x|=en]', 258 u'''a [ x |= en]''': 'a [x|=en]', 259 # CSS3 260 u'''a[x^=en]''': None, 261 u'''a[x$=en]''': None, 262 u'''a[x*=en]''': None, 263 264 u'''a[/*1*/x/*2*/]''': None, 265 u'''a[/*1*/x/*2*/=/*3*/a/*4*/]''': None, 266 u'''a[/*1*/x/*2*/~=/*3*/a/*4*/]''': None, 267 u'''a[/*1*/x/*2*/|=/*3*/a/*4*/]''': None, 268 269 # pseudo-elements 270 u'a x:first-line': None, 271 u'a x:first-letter': None, 272 u'a x:before': None, 273 u'a x:after': None, 274 u'a x::selection': None, 275 u'a:hover+b:hover>c:hover~e:hover f:hover': 276 u'a:hover + b:hover > c:hover ~ e:hover f:hover', 277 u'a:hover + b:hover > c:hover ~ e:hover f:hover': 278 u'a:hover + b:hover > c:hover ~ e:hover f:hover', 279 u'a::selection+b::selection>c::selection~e::selection f::selection': 280 u'a::selection + b::selection > c::selection ~ e::selection f::selection', 281 u'a::selection + b::selection > c::selection ~ e::selection f::selection': 282 u'a::selection + b::selection > c::selection ~ e::selection f::selection', 283 284 u'x:lang(de) y': None, 285 u'x:nth-child(odd) y': None, 286 # functional pseudo 287 u'x:func(a + b-2px22.3"s"i)': None, 288 u'x:func(1 + 1)': None, 289 u'x:func(1+1)': u'x:func(1 + 1)', 290 u'x:func(1 + 1)': u'x:func(1 + 1)', 291 u'x:func(1-1)': u'x:func(1-1)', 292 u'x:func(1 - 1)': u'x:func(1 -1)', 293 u'x:func(a-1)': u'x:func(a-1)', 294 u'x:func(a -1px)': u'x:func(a -1px)', 295 u'x:func(1px)': None, 296 u'x:func(23.4)': None, 297 u'x:func("s")': None, 298 u'x:func(i)': None, 299 300 # negation 301 u':not(y)': None, 302 u':not( y \t\n)': u':not(y)', 303 u'*:not(y)': None, 304 u'x:not(y)': None, 305 u'.x:not(y)': None, 306 u':not(*)': None, 307 u':not(#a)': None, 308 u':not(.a)': None, 309 u':not([a])': None, 310 u':not(:first-letter)': None, 311 u':not(::first-letter)': None, 312 313 # escapes 314 ur'\74\72 td': 'trtd', 315 ur'\74\72 td': 'tr td', 316 ur'\74\000072 td': 'trtd', 317 ur'\74\000072 td': 'tr td', 318 319 # comments 320 u'a/**/ b': None, 321 u'a /**/b': None, 322 u'a /**/ b': None, 323 u'a /**/ b': u'a /**/ b', 324 u'a /**/ b': u'a /**/ b', 325 326 # namespaces 327 u'|e': None, 328 u'*|e': None, 329 u'*|*': None, 330 (u'p|*', (('p', 'uri'),)): u'p|*', 331 (u'p|e', (('p', 'uri'),)): u'p|e', 332 (u'-a_x12|e', (('-a_x12', 'uri'),)): u'-a_x12|e', 333 (u'*|b[p|a]', (('p', 'uri'),)): '*|b[p|a]', 334 335 # case 336 u'elemenT.clasS#iD[atT="valuE"]:noT(x)::firsT-linE': 337 u'elemenT.clasS#iD[atT="valuE"]:not(x)::first-line' 338 } 339 # do not parse as not complete 340 self.do_equal_r(tests, att='selectorText') 341 342 tests = { 343 u'x|a': xml.dom.NamespaceErr, 344 (u'p|*', (('x', 'uri'),)): xml.dom.NamespaceErr, 345 346 u'': xml.dom.SyntaxErr, 347 u'1': xml.dom.SyntaxErr, 348 u'-1': xml.dom.SyntaxErr, 349 u'a*b': xml.dom.SyntaxErr, 350 u'a *b': xml.dom.SyntaxErr, 351 u'a* b': xml.dom.SyntaxErr, 352 u'a/**/b': xml.dom.SyntaxErr, 353 354 u'#': xml.dom.SyntaxErr, 355 u'|': xml.dom.SyntaxErr, 356 357 u':': xml.dom.SyntaxErr, 358 u'::': xml.dom.SyntaxErr, 359 u': a': xml.dom.SyntaxErr, 360 u':: a': xml.dom.SyntaxErr, 361 u':a()': xml.dom.SyntaxErr, # no value 362 u'::a()': xml.dom.SyntaxErr, # no value 363 u':::a': xml.dom.SyntaxErr, 364 u':1': xml.dom.SyntaxErr, 365 366 u'#.x': xml.dom.SyntaxErr, 367 u'.': xml.dom.SyntaxErr, 368 u'.1': xml.dom.SyntaxErr, 369 u'.a.1': xml.dom.SyntaxErr, 370 371 u'[a': xml.dom.SyntaxErr, 372 u'a]': xml.dom.SyntaxErr, 373 u'[a b]': xml.dom.SyntaxErr, 374 u'[=b]': xml.dom.SyntaxErr, 375 u'[a=]': xml.dom.SyntaxErr, 376 u'[a|=]': xml.dom.SyntaxErr, 377 u'[a~=]': xml.dom.SyntaxErr, 378 u'[a=1]': xml.dom.SyntaxErr, 379 380 u'a +': xml.dom.SyntaxErr, 381 u'a >': xml.dom.SyntaxErr, 382 u'a ++ b': xml.dom.SyntaxErr, 383 u'a + > b': xml.dom.SyntaxErr, 384 385 # functional pseudo 386 u'*:lang(': xml.dom.SyntaxErr, 387 u'*:lang()': xml.dom.SyntaxErr, # no arg 388 389 # negation 390 u'not(x)': xml.dom.SyntaxErr, # no valid function 391 u':not()': xml.dom.SyntaxErr, # no arg 392 u':not(x': xml.dom.SyntaxErr, # no ) 393 u':not(-': xml.dom.SyntaxErr, # not allowed 394 u':not(+': xml.dom.SyntaxErr, # not allowed 395 396 # only one selector! 397 u',': xml.dom.InvalidModificationErr, 398 u',a': xml.dom.InvalidModificationErr, 399 u'a,': xml.dom.InvalidModificationErr, 400 } 401 # only set as not complete 402 self.do_raise_r(tests, att='_setSelectorText')
403
404 - def test_specificity(self):
405 "Selector.specificity" 406 selector = cssutils.css.Selector() 407 408 # readonly 409 def _set(): selector.specificity = 1 410 self.assertRaisesMsg(AttributeError, "can't set attribute", _set) 411 412 tests = { 413 u'*': (0,0,0,0), 414 u'li': (0,0,0,1), 415 u'li:first-line': (0,0,0,2), 416 u'ul li': (0,0,0,2), 417 u'ul ol+li': (0,0,0,3), 418 u'h1 + *[rel=up]': (0,0,1,1), 419 u'ul ol li.red': (0,0,1,3), 420 u'li.red.level': (0,0,2,1), 421 u'#x34y': (0,1,0,0), 422 423 u'UL OL LI.red': (0,0,1,3), 424 u'LI.red.level': (0,0,2,1), 425 u'#s12:not(FOO)': (0,1,0,1), 426 u'button:not([DISABLED])': (0,0,1,1), #? 427 u'*:not(FOO)': (0,0,0,1), 428 429 # elements 430 u'a+b': (0,0,0,2), 431 u'a>b': (0,0,0,2), 432 u'a b': (0,0,0,2), 433 u'* a': (0,0,0,1), 434 u'a *': (0,0,0,1), 435 u'a * b': (0,0,0,2), 436 437 u'a:hover': (0,0,0,1), 438 439 u'a:first-line': (0,0,0,2), 440 u'a:first-letter': (0,0,0,2), 441 u'a:before': (0,0,0,2), 442 u'a:after': (0,0,0,2), 443 444 # classes and attributes 445 u'.a': (0,0,1,0), 446 u'*.a': (0,0,1,0), 447 u'a.a': (0,0,1,1), 448 u'.a.a': (0,0,2,0), # IE<7 False (0,0,1,0) 449 u'a.a.a': (0,0,2,1), 450 u'.a.b': (0,0,2,0), 451 u'a.a.b': (0,0,2,1), 452 u'.a .a': (0,0,2,0), 453 u'*[x]': (0,0,1,0), 454 u'*[x]': (0,0,1,0), 455 u'*[x]': (0,0,1,0), 456 u'*[x=a]': (0,0,1,0), 457 u'*[x~=a]': (0,0,1,0), 458 u'*[x|=a]': (0,0,1,0), 459 u'*[x^=a]': (0,0,1,0), 460 u'*[x*=a]': (0,0,1,0), 461 u'*[x$=a]': (0,0,1,0), 462 u'*[x][y]': (0,0,2,0), 463 464 # ids 465 u'#a': (0,1,0,0), 466 u'*#a': (0,1,0,0), 467 u'x#a': (0,1,0,1), 468 u'.x#a': (0,1,1,0), 469 u'a.x#a': (0,1,1,1), 470 u'#a#a': (0,2,0,0), # e.g. html:id + xml:id 471 u'#a#b': (0,2,0,0), 472 u'#a #b': (0,2,0,0), 473 } 474 for text in tests: 475 selector.selectorText = text 476 self.assertEqual(tests[text], selector.specificity)
477
478 - def test_reprANDstr(self):
479 "Selector.__repr__(), .__str__()" 480 sel=u'a + b' 481 482 s = cssutils.css.Selector(selectorText=sel) 483 484 self.assert_(sel in str(s)) 485 486 s2 = eval(repr(s)) 487 self.assert_(isinstance(s2, s.__class__)) 488 self.assert_(sel == s2.selectorText)
489 490 491 if __name__ == '__main__': 492 import unittest 493 unittest.main() 494