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