1
2 """Tests for css.CSSStyleSheet"""
3 __version__ = '$Id: test_cssstylesheet.py 1172 2008-03-20 17:42:34Z cthedot $'
4
5 import xml.dom
6 import basetest
7 import cssutils.css
8
10
16
18 "CSSStyleSheet.__init__()"
19 self.assertEqual('text/css', self.s.type)
20 self.assertEqual(False, self.s._readonly)
21 self.assertEqual([], self.s.cssRules)
22 self.assertEqual(False, self.s.disabled)
23 self.assertEqual(None, self.s.href)
24 self.assertEqual(None, self.s.media)
25 self.assertEqual(None, self.s.ownerNode)
26 self.assertEqual(None, self.s.parentStyleSheet)
27 self.assertEqual(u'', self.s.title)
28
29
30 self.assertRaises(AttributeError, self.r.__setattr__, 'href', 'x')
31 self.assertRaises(AttributeError, self.r.__setattr__, 'parentStyleSheet', 'x')
32 self.assertRaises(AttributeError, self.r.__setattr__, 'ownerNode', 'x')
33 self.assertRaises(AttributeError, self.r.__setattr__, 'type', 'x')
34
45
46 - def test_cssText(self):
47 "CSSStyleSheet.cssText"
48 tests = {
49 u'': None,
50
51 u'@charset "ascii";\n@import "x";': None,
52 u'@charset "ascii";\n@media all {}': u'@charset "ascii";',
53 u'@charset "ascii";\n@x;': None,
54 u'@charset "ascii";\na {\n x: 1\n }': None,
55
56 u'@x;\n@import "x";': None,
57 u'@import "x";\n@import "y";': None,
58 u'@import "x";\n@media all {}': u'@import "x";',
59 u'@import "x";\n@x;': None,
60 u'@import "x";\na {\n x: 1\n }': None,
61
62 u'@x;\n@namespace a "x";': None,
63 u'@namespace a "x";\n@namespace b "y";': None,
64 u'@import "x";\n@namespace a "x";\n@media all {}':
65 u'@import "x";\n@namespace a "x";',
66 u'@namespace a "x";\n@x;': None,
67 u'@namespace a "x";\na {\n x: 1\n }': None,
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84 }
85 self.do_equal_r(tests)
86 self.do_equal_p(tests)
87
88 s = cssutils.css.CSSStyleSheet()
89 s.cssText = u'''@charset "ascii";@import "x";@namespace a "x";
90 @media all {/*1*/}@page {margin: 0}a {\n x: 1\n }@unknown;/*comment*/'''
91 for r in s.cssRules:
92 self.assertEqual(s, r.parentStyleSheet)
93
95 "CSSStyleSheet.cssText HierarchyRequestErr"
96 tests = {
97
98 u' @charset "utf-8";': xml.dom.HierarchyRequestErr,
99 u'@charset "ascii";@charset "ascii";': xml.dom.HierarchyRequestErr, u'/*c*/@charset "ascii";': xml.dom.HierarchyRequestErr,
100 u'@import "x"; @charset "ascii";': xml.dom.HierarchyRequestErr,
101 u'@namespace a "x"; @charset "ascii";': xml.dom.HierarchyRequestErr,
102 u'@media all {} @charset "ascii";': xml.dom.HierarchyRequestErr,
103 u'@page {} @charset "ascii";': xml.dom.HierarchyRequestErr,
104 u'a {} @charset "ascii";': xml.dom.HierarchyRequestErr,
105
106
107 u'@namespace a "x"; @import "x";': xml.dom.HierarchyRequestErr,
108 u'@media all {} @import "x";': xml.dom.HierarchyRequestErr,
109 u'@page {} @import "x";': xml.dom.HierarchyRequestErr,
110 u'a {} @import "x";': xml.dom.HierarchyRequestErr,
111
112
113 u'@media all {} @namespace a "x";': xml.dom.HierarchyRequestErr,
114 u'@page {} @namespace a "x";': xml.dom.HierarchyRequestErr,
115 u'a {} @namespace a "x";': xml.dom.HierarchyRequestErr,
116 }
117 self.do_raise_r(tests)
118 self.do_raise_p(tests)
119
121 """CSSStyleSheet.cssText SyntaxErr
122
123 for single {, } or ;
124 """
125 tests = {
126 u'{': xml.dom.SyntaxErr,
127 u'}': xml.dom.SyntaxErr,
128 u';': xml.dom.SyntaxErr,
129 u'@charset "ascii";{': xml.dom.SyntaxErr,
130 u'@charset "ascii";}': xml.dom.SyntaxErr,
131 u'@charset "ascii";;': xml.dom.SyntaxErr,
132 }
133 self.do_raise_r(tests)
134 self.do_raise_p(tests)
135
137 "CSSStyleSheet.encoding"
138 self.s.cssText=''
139 self.assertEqual('utf-8', self.s.encoding)
140
141 self.s.encoding = 'ascii'
142 self.assertEqual('ascii', self.s.encoding)
143 self.assertEqual(1, self.s.cssRules.length)
144 self.assertEqual('ascii', self.s.cssRules[0].encoding)
145
146 self.s.encoding = None
147 self.assertEqual('utf-8', self.s.encoding)
148 self.assertEqual(0, self.s.cssRules.length)
149
150 self.s.encoding = 'UTF-8'
151 self.assertEqual('utf-8', self.s.encoding)
152 self.assertEqual(1, self.s.cssRules.length)
153
154 self.assertRaises(xml.dom.SyntaxErr, self.s._setEncoding,
155 'INVALID ENCODING')
156 self.assertEqual('utf-8', self.s.encoding)
157 self.assertEqual(1, self.s.cssRules.length)
158
160 "CSSStyleSheet.namespaces.namespaces"
161
162 s = cssutils.css.CSSStyleSheet()
163 self.assertEqual(0, len(s.namespaces))
164
165 css = u'''@namespace "default";
166 @namespace ex "example";
167 @namespace ex2 "example";
168 ex2|x { top: 0 }'''
169 expcss = u'''@namespace "default";
170 @namespace ex2 "example";
171 ex2|x {
172 top: 0
173 }'''
174 s.cssText = css
175 self.assertEqual(s.cssText, expcss)
176 self.assertEqual(s.namespaces.namespaces,
177 { u'': u'default', u'ex2': u'example'})
178
179
180 self.assertTrue('' in s.namespaces)
181 self.assertTrue('ex2' in s.namespaces)
182 self.assertFalse('NOTSET' in s.namespaces)
183
184 self.assertRaises(xml.dom.NoModificationAllowedErr,
185 s.namespaces.__delitem__, 'ex2')
186 s.namespaces['del'] = 'del'
187 del s.namespaces['del']
188 self.assertRaises(xml.dom.NamespaceErr, s.namespaces.__getitem__, 'del')
189
190 self.assertEquals('default', s.namespaces[''])
191 self.assertEquals('example', s.namespaces['ex2'])
192 self.assertRaises(xml.dom.NamespaceErr, s.namespaces.__getitem__, 'UNSET')
193
194 self.assertEquals(['', 'ex2'], [n for n in s.namespaces])
195
196 self.assertEqual(2, len(s.namespaces))
197
198 self.assertRaises(xml.dom.NoModificationAllowedErr,
199 s.namespaces.__setitem__, 'ex2', 'NEWURI')
200 s.namespaces['n1'] = 'new'
201 self.assertEqual(s.namespaces.namespaces,
202 { u'': u'default', u'ex2': u'example', u'n1': 'new'})
203 s.namespaces['n'] = 'new'
204 self.assertEqual(s.namespaces.namespaces,
205 { u'': u'default', u'ex2': u'example', u'n': 'new'})
206
207 self.assertEquals('', s.namespaces.prefixForNamespaceURI('default'))
208 self.assertEquals('ex2', s.namespaces.prefixForNamespaceURI('example'))
209 self.assertRaises(IndexError,
210 s.namespaces.prefixForNamespaceURI, 'UNSET')
211
212 self.assertEqual(set(s.namespaces.keys()), set(['', 'ex2', 'n']))
213
214 self.assertEqual('x', s.namespaces.get('UNKNOWN', 'x'))
215 self.assertEqual('example', s.namespaces.get('ex2', 'not used defa'))
216
218 "CSSStyleSheet.namespaces"
219
220
221 s = cssutils.css.CSSStyleSheet()
222 css = '@namespace n "new";'
223
224 s.insertRule(css + css)
225 self.assertEqual(css, s.cssText)
226 r = cssutils.css.CSSNamespaceRule(prefix='ex2', namespaceURI='example')
227 s.insertRule(r)
228 r = cssutils.css.CSSNamespaceRule(namespaceURI='default')
229 s.insertRule(r)
230
231 expcss = '''@namespace n "new";
232 @namespace ex2 "example";
233 @namespace "default";'''
234 self.assertEqual(s.cssText, expcss)
235 r.prefix = 'DEFAULT'
236 expcss = '''@namespace n "new";
237 @namespace ex2 "example";
238 @namespace DEFAULT "default";'''
239 self.assertEqual(s.cssText, expcss)
240
241
242 self.assertRaises(xml.dom.NamespaceErr, s.add, '@media all {x|a {left: 0}}')
243 mcss = '@media all {\n ex2|SEL1 {\n left: 0\n }\n }'
244 s.add(mcss)
245 expcss += '\n' + mcss
246 self.assertEqual(s.cssText, expcss)
247
248
249 self.assertRaises(xml.dom.NamespaceErr, s.add, 'x|a {top: 0}')
250 scss = 'n|SEL2 {\n top: 0\n }'
251 s.add(scss)
252 expcss += '\n' + scss
253 self.assertEqual(s.cssText, expcss)
254
255 mr = s.cssRules[3]
256 sr = s.cssRules[4]
257
258
259 self.assertRaises(xml.dom.NamespaceErr,
260 mr.cssRules[0]._setSelectorText, 'x|b')
261 oldsel, newsel = mr.cssRules[0].selectorText, 'n|SEL3, a'
262 mr.cssRules[0].selectorText = newsel
263 expcss = expcss.replace(oldsel, newsel)
264 self.assertEqual(s.cssText, expcss)
265
266 self.assertRaises(xml.dom.NamespaceErr,
267 sr._setSelectorText, 'x|b')
268 oldsel, newsel = sr.selectorText, 'ex2|SEL4, a'
269 sr.selectorText = newsel
270 expcss = expcss.replace(oldsel, newsel)
271 self.assertEqual(s.cssText, expcss)
272
273
274 self.assertRaises(xml.dom.NamespaceErr,
275 mr.cssRules[0].selectorList.append, 'x|b')
276 oldsel, newsel = mr.cssRules[0].selectorText, 'ex2|SELMR'
277 mr.cssRules[0].selectorList.append(newsel)
278 expcss = expcss.replace(oldsel, oldsel + ', ' + newsel)
279 self.assertEqual(s.cssText, expcss)
280
281 self.assertRaises(xml.dom.NamespaceErr,
282 sr.selectorList.append, 'x|b')
283 oldsel, newsel = sr.selectorText, 'ex2|SELSR'
284 sr.selectorList.append(newsel)
285 expcss = expcss.replace(oldsel, oldsel + ', ' + newsel)
286 self.assertEqual(s.cssText, expcss)
287
288 self.assertEqual(s.cssText, u'''@namespace n "new";
289 @namespace ex2 "example";
290 @namespace DEFAULT "default";
291 @media all {
292 n|SEL3, a, ex2|SELMR {
293 left: 0
294 }
295 }
296 ex2|SEL4, a, ex2|SELSR {
297 top: 0
298 }''')
299
301 "CSSStyleSheet.namespaces 3"
302
303 s = cssutils.css.CSSStyleSheet()
304 css = u'h|a { top: 0 }'
305 self.assertRaises(xml.dom.NamespaceErr, s.add, css)
306
307 s.add('@namespace x "html";')
308 self.assert_(s.namespaces['x'] == 'html')
309
310 r = cssutils.css.CSSStyleRule()
311 r.cssText = ((css, {'h': 'html'}))
312 s.add(r)
313 self.assertEqual(s.cssText, '@namespace x "html";\nx|a {\n top: 0\n }')
314
315
316 self.assertRaises(xml.dom.NamespaceErr, r.selectorList.append, 'h|b')
317 self.assertRaises(xml.dom.NamespaceErr, r.selectorList.append, 'y|b')
318 s.namespaces['y'] = 'html'
319 r.selectorList.append('y|b')
320 self.assertEqual(s.cssText,
321 u'@namespace y "html";\ny|a, y|b {\n top: 0\n }')
322
323 self.assertRaises(xml.dom.NoModificationAllowedErr,
324 s.namespaces.__delitem__, 'y')
325 self.assertEqual(s.cssText,
326 u'@namespace y "html";\ny|a, y|b {\n top: 0\n }')
327
328 s.cssRules[0].prefix = ''
329 self.assertEqual(s.cssText,
330 u'@namespace "html";\na, b {\n top: 0\n }')
331
332
333 s.cssRules[0].prefix = 'x'
334 s.cssRules[1].selectorText = 'a, b'
335 self.assertEqual(s.cssText,
336 u'@namespace x "html";\na, b {\n top: 0\n }')
337
338
364
366 "CSSStyleSheet.deleteRule()"
367 self.s.cssText = u'@charset "ascii"; @import "x"; @x; a {\n x: 1\n }@y;'
368 self.assertEqual(5, self.s.cssRules.length)
369
370 self.assertRaises(xml.dom.IndexSizeErr, self.s.deleteRule, 5)
371
372
373
374 r = self.s.cssRules[-1]
375 self.assertEqual(self.s, r.parentStyleSheet)
376 self.s.deleteRule(-1)
377 self.assertEqual(None, r.parentStyleSheet)
378
379 self.assertEqual(4, self.s.cssRules.length)
380 self.assertEqual(
381 u'@charset "ascii";\n@import "x";\n@x;\na {\n x: 1\n }', self.s.cssText)
382
383 self.s.deleteRule(0)
384 self.assertEqual(3, self.s.cssRules.length)
385 self.assertEqual(u'@import "x";\n@x;\na {\n x: 1\n }', self.s.cssText)
386
387 self.s.deleteRule(1)
388 self.assertEqual(2, self.s.cssRules.length)
389 self.assertEqual(u'@import "x";\na {\n x: 1\n }', self.s.cssText)
390
391 self.s.deleteRule(1)
392 self.assertEqual(1, self.s.cssRules.length)
393 self.assertEqual(u'@import "x";', self.s.cssText)
394
420
422 "CSSStyleSheet.add()"
423 full = cssutils.css.CSSStyleSheet()
424 sheet = cssutils.css.CSSStyleSheet()
425 css = ['@charset "ascii";',
426 '@import "x";',
427 '@namespace p "u";',
428 '@page {\n left: 0\n }',
429 '@font-face {\n color: red\n }',
430 '@media all {\n a {\n color: red\n }\n }',
431 'a {\n color: green\n }',
432 '/*comment*/',
433 '@x;'
434 ]
435 fullcss = u'\n'.join(css)
436 full.cssText = fullcss
437 self.assertEqual(full.cssText, fullcss)
438 for i, line in enumerate(css):
439
440 before = css[:i]
441 after = css[i+1:]
442 sheet.cssText = u''.join(before + after)
443 index = sheet.add(line)
444 if i < 3:
445 self.assertEqual(fullcss, sheet.cssText)
446 self.assertEqual(i, index)
447 else:
448 expected = before
449 expected.extend(after)
450 expected.append(line)
451 self.assertEqual(u'\n'.join(expected), sheet.cssText)
452 self.assertEqual(8, index)
453
454
455 if i == 1: line = '@import "x2";'
456 if i == 2: line = '@namespace p2 "u2";'
457 full.cssText = fullcss
458 index = full.add(line)
459 if i < 1:
460 self.assertEqual(fullcss, sheet.cssText)
461 self.assertEqual(i, index)
462 else:
463 expected = css[:i+1]
464 expected.append(line)
465 expected.extend(css[i+1:])
466 self.assertEqual(u'\n'.join(expected), full.cssText)
467 self.assertEqual(i+1, index)
468
470 "CSSStyleSheet.insertRule()"
471 s, L = self._gets()
472
473
474 self.assertRaises(xml.dom.IndexSizeErr,
475 s.insertRule, self.sr, -1)
476 self.assertRaises(xml.dom.IndexSizeErr,
477 s.insertRule, self.sr, s.cssRules.length + 1)
478
479 self.assertEqual(L, s.cssRules.length)
480
481
482 s.insertRule('a {}')
483 self.assertEqual(L+1, s.cssRules.length)
484
485 s.insertRule(self.sr)
486 self.assertEqual(L+2, s.cssRules.length)
487
488 s2, L2 = self._gets()
489 rulelist = s2.cssRules
490 del rulelist[:-2]
491 s.insertRule(rulelist)
492 self.assertEqual(L+2 + 2, s.cssRules.length)
493
494 - def _insertRule(self, rules, notbefore, notafter, anywhere,
495 checkdoubles=True):
496 """
497 helper
498 test if any rule in rules cannot be inserted before rules in before
499 or after rules in after but before and after rules in anywhere
500 """
501 for rule in rules:
502 for r in notbefore:
503 s = cssutils.css.CSSStyleSheet()
504 s.insertRule(r)
505 self.assertRaises(xml.dom.HierarchyRequestErr,
506 s.insertRule, rule, 0)
507 s = cssutils.css.CSSStyleSheet()
508 s.add(r)
509 self.assertRaises(xml.dom.HierarchyRequestErr,
510 s.insertRule, rule, 0)
511 for r in notafter:
512 s = cssutils.css.CSSStyleSheet()
513 s.insertRule(r)
514 self.assertRaises(xml.dom.HierarchyRequestErr,
515 s.insertRule, rule, 1)
516 s = cssutils.css.CSSStyleSheet()
517 s.add(r)
518 s.add(rule)
519
520 for r in anywhere:
521 s = cssutils.css.CSSStyleSheet()
522 s.insertRule(r)
523 s.insertRule(rule, 0)
524 s.insertRule(rule)
525 if checkdoubles:
526 self.assertEqual(s.cssRules.length, 3)
527 self.assertEqual(s, r.parentStyleSheet)
528
530 "CSSStyleSheet.insertRule(@charset)"
531 s, L = self._gets()
532 notbefore = (self.cr,)
533 notafter = (self.cr, self.ir, self.nr, self.mr, self.pr, self.sr,
534 self.c, self.ur)
535 anywhere = ()
536 self._insertRule((self.cr,),
537 notbefore, notafter, anywhere)
538
540 "CSSStyleSheet.insertRule(@import)"
541 s, L = self._gets()
542 notbefore = (self.cr,)
543 notafter = (self.nr, self.pr, self.mr, self.sr)
544 anywhere = (self.c, self.ur, self.ir)
545 self._insertRule((self.ir,),
546 notbefore, notafter, anywhere)
547
549 "CSSStyleSheet.insertRule(@namespace)"
550 s, L = self._gets()
551 notbefore = (self.cr, self.ir)
552 notafter = (self.pr, self.mr, self.sr)
553 anywhere = (self.c, self.ur, self.nr)
554 self._insertRule((self.nr,), notbefore, notafter, anywhere,
555 checkdoubles=False)
556
558 "CSSStyleSheet.insertRule(@media, @page, stylerule)"
559 s, L = self._gets()
560 notbefore = (self.cr, self.ir, self.nr)
561 notafter = ()
562 anywhere = (self.c, self.ur, self.mr, self.pr, self.sr)
563 self._insertRule((self.pr, self.mr, self.sr),
564 notbefore, notafter, anywhere)
565
575
593
595 "CSSStyleRule (incomplete)"
596 tests = {
597 u'@import "a': u'@import "a";',
598 u'a { x: 1': u'a {\n x: 1\n }',
599 u'a { font-family: "arial sans':
600 u'a {\n font-family: "arial sans"\n }',
601 }
602 self.do_equal_p(tests)
603
605 "CSSStyleSheet NoModificationAllowedErr"
606 css = cssutils.css.CSSStyleSheet(readonly=True)
607
608 self.assertEqual(True, css._readonly)
609
610 self.assertRaises(xml.dom.NoModificationAllowedErr,
611 css._setCssText, u'@x;')
612 self.assertRaises(xml.dom.NoModificationAllowedErr,
613 css.insertRule, self.rule)
614 self.assertRaises(xml.dom.NoModificationAllowedErr,
615 css.insertRule, self.rule, 0)
616 self.assertRaises(xml.dom.NoModificationAllowedErr,
617 css.deleteRule, 0)
618
620 "CSSStyleSheet.__repr__(), .__str__()"
621 href = 'file:foo.css'
622 title = 'title-of-css'
623
624 s = cssutils.css.CSSStyleSheet(href=href, title=title)
625
626 self.assert_(href in str(s))
627 self.assert_(title in str(s))
628
629 s2 = eval(repr(s))
630 self.assert_(isinstance(s2, s.__class__))
631 self.assert_(href == s2.href)
632 self.assert_(title == s2.title)
633
634
636 "cssutils.replaceUrls() DEPRECATED"
637 cssutils.ser.prefs.keepAllProperties = True
638
639 css='''
640 @import "im1";
641 @import url(im2);
642 a {
643 background-image: url(c) !important;
644 background-\image: url(b);
645 background: url(a) no-repeat !important;
646 }'''
647 s = cssutils.parseString(css)
648 s.replaceUrls(lambda old: "NEW" + old)
649 self.assertEqual(u'@import "NEWim1";', s.cssRules[0].cssText)
650 self.assertEqual(u'NEWim2', s.cssRules[1].href)
651 self.assertEqual(u'''background-image: url(NEWc) !important;
652 background-\\image: url(NEWb);
653 background: url(NEWa) no-repeat !important''', s.cssRules[2].style.cssText)
654
655 cssutils.ser.prefs.keepAllProperties = False
656
657
658 if __name__ == '__main__':
659 import unittest
660 unittest.main()
661