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
16
19
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
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'),
58 'x::first-line': (None, 'x'),
59 'x:not(href)': (None, 'x'),
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
71 "Selector.namespaces"
72 namespaces = [
73 {'p': 'other'},
74 {'': 'default', 'p': 'other'},
75 {'': 'default', 'p': 'default' }
76 ]
77 tests = {
78
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
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
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
112
113
114
115
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
126 sheet.namespaces['p'] = 'default'
127 self.assertEqual(sheet.cssText,
128 u'@namespace p "default";\np|a[att] {\n color: green\n }')
129
143
145 "Selector.selectorText"
146 tests = {
147
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
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
187 u'.a a': None,
188 u'a1': None,
189 u'a1-1': None,
190 u'.a1-1': None,
191
192
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
206 u'''#a''': None,
207 u'''#a1''': None,
208 u'''#1a''': None,
209 u'''#1''': None,
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
218 u'ab': 'ab',
219 u'a.b': None,
220 u'a.b.c': None,
221 u'.a1._1': None,
222
223
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,
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]',
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
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
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
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
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
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
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
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
336 u'elemenT.clasS#iD[atT="valuE"]:noT(x)::firsT-linE':
337 u'elemenT.clasS#iD[atT="valuE"]:not(x)::first-line'
338 }
339
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,
362 u'::a()': xml.dom.SyntaxErr,
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
386 u'*:lang(': xml.dom.SyntaxErr,
387 u'*:lang()': xml.dom.SyntaxErr,
388
389
390 u'not(x)': xml.dom.SyntaxErr,
391 u':not()': xml.dom.SyntaxErr,
392 u':not(x': xml.dom.SyntaxErr,
393 u':not(-': xml.dom.SyntaxErr,
394 u':not(+': xml.dom.SyntaxErr,
395
396
397 u',': xml.dom.InvalidModificationErr,
398 u',a': xml.dom.InvalidModificationErr,
399 u'a,': xml.dom.InvalidModificationErr,
400 }
401
402 self.do_raise_r(tests, att='_setSelectorText')
403
405 "Selector.specificity"
406 selector = cssutils.css.Selector()
407
408
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
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
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),
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
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),
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
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