1
2 """
3 tests for css.CSSStyleSheet
4 """
5 __author__ = '$LastChangedBy: cthedot $'
6 __date__ = '$LastChangedDate: 2008-02-03 15:10:34 +0100 (So, 03 Feb 2008) $'
7 __version__ = '$LastChangedRevision: 980 $'
8
9 import xml.dom
10 import basetest
11 import cssutils.css
12
14
20
22 "CSSStyleSheet.__init__()"
23 self.assertEqual('text/css', self.s.type)
24 self.assertEqual(False, self.s._readonly)
25 self.assertEqual([], self.s.cssRules)
26 self.assertEqual(False, self.s.disabled)
27 self.assertEqual(None, self.s.href)
28 self.assertEqual(None, self.s.media)
29 self.assertEqual(None, self.s.ownerNode)
30 self.assertEqual(None, self.s.parentStyleSheet)
31 self.assertEqual(u'', self.s.title)
32
43
44 - def test_cssText(self):
45 "CSSStyleSheet.cssText"
46 tests = {
47 u'': None,
48
49 u'@charset "ascii";\n@import "x";': None,
50 u'@charset "ascii";\n@media all {}': u'@charset "ascii";',
51 u'@charset "ascii";\n@x;': None,
52 u'@charset "ascii";\na {\n x: 1\n }': None,
53
54 u'@x;\n@import "x";': None,
55 u'@import "x";\n@import "y";': None,
56 u'@import "x";\n@media all {}': u'@import "x";',
57 u'@import "x";\n@x;': None,
58 u'@import "x";\na {\n x: 1\n }': None,
59
60 u'@x;\n@namespace a "x";': None,
61 u'@namespace a "x";\n@namespace b "y";': None,
62 u'@import "x";\n@namespace a "x";\n@media all {}':
63 u'@import "x";\n@namespace a "x";',
64 u'@namespace a "x";\n@x;': None,
65 u'@namespace a "x";\na {\n x: 1\n }': None,
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82 }
83 self.do_equal_r(tests)
84 self.do_equal_p(tests)
85
86 s = cssutils.css.CSSStyleSheet()
87 s.cssText = u'''@charset "ascii";@import "x";@namespace a "x";
88 @media all {/*1*/}@page {margin: 0}a {\n x: 1\n }@unknown;/*comment*/'''
89 for r in s.cssRules:
90 self.assertEqual(s, r.parentStyleSheet)
91
93 "CSSStyleSheet.cssText HierarchyRequestErr"
94 tests = {
95
96 u' @charset "utf-8";': xml.dom.HierarchyRequestErr,
97 u'@charset "ascii";@charset "ascii";': xml.dom.HierarchyRequestErr, u'/*c*/@charset "ascii";': xml.dom.HierarchyRequestErr,
98 u'@import "x"; @charset "ascii";': xml.dom.HierarchyRequestErr,
99 u'@namespace a "x"; @charset "ascii";': xml.dom.HierarchyRequestErr,
100 u'@media all {} @charset "ascii";': xml.dom.HierarchyRequestErr,
101 u'@page {} @charset "ascii";': xml.dom.HierarchyRequestErr,
102 u'a {} @charset "ascii";': xml.dom.HierarchyRequestErr,
103
104
105 u'@namespace a "x"; @import "x";': xml.dom.HierarchyRequestErr,
106 u'@media all {} @import "x";': xml.dom.HierarchyRequestErr,
107 u'@page {} @import "x";': xml.dom.HierarchyRequestErr,
108 u'a {} @import "x";': xml.dom.HierarchyRequestErr,
109
110
111 u'@media all {} @namespace a "x";': xml.dom.HierarchyRequestErr,
112 u'@page {} @namespace a "x";': xml.dom.HierarchyRequestErr,
113 u'a {} @namespace a "x";': xml.dom.HierarchyRequestErr,
114 }
115 self.do_raise_r(tests)
116 self.do_raise_p(tests)
117
119 """CSSStyleSheet.cssText SyntaxErr
120
121 for single {, } or ;
122 """
123 tests = {
124 u'{': xml.dom.SyntaxErr,
125 u'}': xml.dom.SyntaxErr,
126 u';': xml.dom.SyntaxErr,
127 u'@charset "ascii";{': xml.dom.SyntaxErr,
128 u'@charset "ascii";}': xml.dom.SyntaxErr,
129 u'@charset "ascii";;': xml.dom.SyntaxErr,
130 }
131 self.do_raise_r(tests)
132 self.do_raise_p(tests)
133
135 "CSSStyleSheet.encoding"
136 self.s.cssText=''
137 self.assertEqual('utf-8', self.s.encoding)
138
139 self.s.encoding = 'ascii'
140 self.assertEqual('ascii', self.s.encoding)
141 self.assertEqual(1, self.s.cssRules.length)
142 self.assertEqual('ascii', self.s.cssRules[0].encoding)
143
144 self.s.encoding = None
145 self.assertEqual('utf-8', self.s.encoding)
146 self.assertEqual(0, self.s.cssRules.length)
147
148 self.s.encoding = 'UTF-8'
149 self.assertEqual('utf-8', self.s.encoding)
150 self.assertEqual(1, self.s.cssRules.length)
151
152 self.assertRaises(xml.dom.SyntaxErr, self.s._setEncoding,
153 'INVALID ENCODING')
154 self.assertEqual('utf-8', self.s.encoding)
155 self.assertEqual(1, self.s.cssRules.length)
156
158 "CSSStyleSheet.namespaces.namespaces"
159
160 s = cssutils.css.CSSStyleSheet()
161 self.assertEqual(0, len(s.namespaces))
162
163 css = u'''@namespace "default";
164 @namespace ex "example";
165 @namespace ex2 "example";
166 ex2|x { top: 0 }'''
167 expcss = u'''@namespace "default";
168 @namespace ex2 "example";
169 ex2|x {
170 top: 0
171 }'''
172 s.cssText = css
173 self.assertEqual(s.cssText, expcss)
174 self.assertEqual(s.namespaces.namespaces,
175 { u'': u'default', u'ex2': u'example'})
176
177
178 self.assertTrue('' in s.namespaces)
179 self.assertTrue('ex2' in s.namespaces)
180 self.assertFalse('NOTSET' in s.namespaces)
181
182 self.assertRaises(xml.dom.NoModificationAllowedErr,
183 s.namespaces.__delitem__, 'ex2')
184 s.namespaces['del'] = 'del'
185 del s.namespaces['del']
186 self.assertRaises(xml.dom.NamespaceErr, s.namespaces.__getitem__, 'del')
187
188 self.assertEquals('default', s.namespaces[''])
189 self.assertEquals('example', s.namespaces['ex2'])
190 self.assertRaises(xml.dom.NamespaceErr, s.namespaces.__getitem__, 'UNSET')
191
192 self.assertEquals(['', 'ex2'], [n for n in s.namespaces])
193
194 self.assertEqual(2, len(s.namespaces))
195
196 self.assertRaises(xml.dom.NoModificationAllowedErr,
197 s.namespaces.__setitem__, 'ex2', 'NEWURI')
198 s.namespaces['n1'] = 'new'
199 self.assertEqual(s.namespaces.namespaces,
200 { u'': u'default', u'ex2': u'example', u'n1': 'new'})
201 s.namespaces['n'] = 'new'
202 self.assertEqual(s.namespaces.namespaces,
203 { u'': u'default', u'ex2': u'example', u'n': 'new'})
204
205 self.assertEquals('', s.namespaces.prefixForNamespaceURI('default'))
206 self.assertEquals('ex2', s.namespaces.prefixForNamespaceURI('example'))
207 self.assertRaises(IndexError,
208 s.namespaces.prefixForNamespaceURI, 'UNSET')
209
210 self.assertEqual(set(s.namespaces.keys()), set(['', 'ex2', 'n']))
211
212 self.assertEqual('x', s.namespaces.get('UNKNOWN', 'x'))
213 self.assertEqual('example', s.namespaces.get('ex2', 'not used defa'))
214
216 "CSSStyleSheet.namespaces"
217
218
219 s = cssutils.css.CSSStyleSheet()
220 css = '@namespace n "new";'
221
222 s.insertRule(css + css)
223 self.assertEqual(css, s.cssText)
224 r = cssutils.css.CSSNamespaceRule(prefix='ex2', namespaceURI='example')
225 s.insertRule(r)
226 r = cssutils.css.CSSNamespaceRule(namespaceURI='default')
227 s.insertRule(r)
228
229 expcss = '''@namespace n "new";
230 @namespace ex2 "example";
231 @namespace "default";'''
232 self.assertEqual(s.cssText, expcss)
233 r.prefix = 'DEFAULT'
234 expcss = '''@namespace n "new";
235 @namespace ex2 "example";
236 @namespace DEFAULT "default";'''
237 self.assertEqual(s.cssText, expcss)
238
239
240 self.assertRaises(xml.dom.NamespaceErr, s.add, '@media all {x|a {left: 0}}')
241 mcss = '@media all {\n ex2|SEL1 {\n left: 0\n }\n }'
242 s.add(mcss)
243 expcss += '\n' + mcss
244 self.assertEqual(s.cssText, expcss)
245
246
247 self.assertRaises(xml.dom.NamespaceErr, s.add, 'x|a {top: 0}')
248 scss = 'n|SEL2 {\n top: 0\n }'
249 s.add(scss)
250 expcss += '\n' + scss
251 self.assertEqual(s.cssText, expcss)
252
253 mr = s.cssRules[3]
254 sr = s.cssRules[4]
255
256
257 self.assertRaises(xml.dom.NamespaceErr,
258 mr.cssRules[0]._setSelectorText, 'x|b')
259 oldsel, newsel = mr.cssRules[0].selectorText, 'n|SEL3, a'
260 mr.cssRules[0].selectorText = newsel
261 expcss = expcss.replace(oldsel, newsel)
262 self.assertEqual(s.cssText, expcss)
263
264 self.assertRaises(xml.dom.NamespaceErr,
265 sr._setSelectorText, 'x|b')
266 oldsel, newsel = sr.selectorText, 'ex2|SEL4, a'
267 sr.selectorText = newsel
268 expcss = expcss.replace(oldsel, newsel)
269 self.assertEqual(s.cssText, expcss)
270
271
272 self.assertRaises(xml.dom.NamespaceErr,
273 mr.cssRules[0].selectorList.append, 'x|b')
274 oldsel, newsel = mr.cssRules[0].selectorText, 'ex2|SELMR'
275 mr.cssRules[0].selectorList.append(newsel)
276 expcss = expcss.replace(oldsel, oldsel + ', ' + newsel)
277 self.assertEqual(s.cssText, expcss)
278
279 self.assertRaises(xml.dom.NamespaceErr,
280 sr.selectorList.append, 'x|b')
281 oldsel, newsel = sr.selectorText, 'ex2|SELSR'
282 sr.selectorList.append(newsel)
283 expcss = expcss.replace(oldsel, oldsel + ', ' + newsel)
284 self.assertEqual(s.cssText, expcss)
285
286 self.assertEqual(s.cssText, u'''@namespace n "new";
287 @namespace ex2 "example";
288 @namespace DEFAULT "default";
289 @media all {
290 n|SEL3, a, ex2|SELMR {
291 left: 0
292 }
293 }
294 ex2|SEL4, a, ex2|SELSR {
295 top: 0
296 }''')
297
299 "CSSStyleSheet.namespaces 3"
300
301 s = cssutils.css.CSSStyleSheet()
302 css = u'h|a { top: 0 }'
303 self.assertRaises(xml.dom.NamespaceErr, s.add, css)
304
305 s.add('@namespace x "html";')
306 self.assert_(s.namespaces['x'] == 'html')
307
308 r = cssutils.css.CSSStyleRule()
309 r.cssText = ((css, {'h': 'html'}))
310 s.add(r)
311 self.assertEqual(s.cssText, '@namespace x "html";\nx|a {\n top: 0\n }')
312
313
314 self.assertRaises(xml.dom.NamespaceErr, r.selectorList.append, 'h|b')
315 self.assertRaises(xml.dom.NamespaceErr, r.selectorList.append, 'y|b')
316 s.namespaces['y'] = 'html'
317 r.selectorList.append('y|b')
318 self.assertEqual(s.cssText,
319 u'@namespace y "html";\ny|a, y|b {\n top: 0\n }')
320
321 self.assertRaises(xml.dom.NoModificationAllowedErr,
322 s.namespaces.__delitem__, 'y')
323 self.assertEqual(s.cssText,
324 u'@namespace y "html";\ny|a, y|b {\n top: 0\n }')
325
326 s.cssRules[0].prefix = ''
327 self.assertEqual(s.cssText,
328 u'@namespace "html";\n|a, |b {\n top: 0\n }')
329
330
331 s.cssRules[0].prefix = 'x'
332 s.cssRules[1].selectorText = 'a, b'
333 self.assertEqual(s.cssText,
334 u'@namespace x "html";\na, b {\n top: 0\n }')
335
337 "CSSStyleSheet.deleteRule()"
338 self.s.cssText = u'@charset "ascii"; @import "x"; @x; a {\n x: 1\n }@y;'
339 self.assertEqual(5, self.s.cssRules.length)
340
341 self.assertRaises(xml.dom.IndexSizeErr, self.s.deleteRule, 5)
342
343
344
345 r = self.s.cssRules[-1]
346 self.assertEqual(self.s, r.parentStyleSheet)
347 self.s.deleteRule(-1)
348 self.assertEqual(None, r.parentStyleSheet)
349
350 self.assertEqual(4, self.s.cssRules.length)
351 self.assertEqual(
352 u'@charset "ascii";\n@import "x";\n@x;\na {\n x: 1\n }', self.s.cssText)
353
354 self.s.deleteRule(0)
355 self.assertEqual(3, self.s.cssRules.length)
356 self.assertEqual(u'@import "x";\n@x;\na {\n x: 1\n }', self.s.cssText)
357
358 self.s.deleteRule(1)
359 self.assertEqual(2, self.s.cssRules.length)
360 self.assertEqual(u'@import "x";\na {\n x: 1\n }', self.s.cssText)
361
362 self.s.deleteRule(1)
363 self.assertEqual(1, self.s.cssRules.length)
364 self.assertEqual(u'@import "x";', self.s.cssText)
365
391
393 "CSSStyleSheet.add()"
394 full = cssutils.css.CSSStyleSheet()
395 sheet = cssutils.css.CSSStyleSheet()
396 css = ['@charset "ascii";',
397 '@import "x";',
398 '@namespace p "u";',
399 '@page {\n left: 0\n }',
400 '@font-face {\n color: red\n }',
401 '@media all {\n a {\n color: red\n }\n }',
402 'a {\n color: green\n }',
403 '/*comment*/',
404 '@x;'
405 ]
406 fullcss = u'\n'.join(css)
407 full.cssText = fullcss
408 self.assertEqual(full.cssText, fullcss)
409 for i, line in enumerate(css):
410
411 before = css[:i]
412 after = css[i+1:]
413 sheet.cssText = u''.join(before + after)
414 index = sheet.add(line)
415 if i < 3:
416 self.assertEqual(fullcss, sheet.cssText)
417 self.assertEqual(i, index)
418 else:
419 expected = before
420 expected.extend(after)
421 expected.append(line)
422 self.assertEqual(u'\n'.join(expected), sheet.cssText)
423 self.assertEqual(8, index)
424
425
426 if i == 1: line = '@import "x2";'
427 if i == 2: line = '@namespace p2 "u2";'
428 full.cssText = fullcss
429 index = full.add(line)
430 if i < 1:
431 self.assertEqual(fullcss, sheet.cssText)
432 self.assertEqual(i, index)
433 else:
434 expected = css[:i+1]
435 expected.append(line)
436 expected.extend(css[i+1:])
437 self.assertEqual(u'\n'.join(expected), full.cssText)
438 self.assertEqual(i+1, index)
439
441 "CSSStyleSheet.insertRule()"
442 s, L = self._gets()
443
444
445 self.assertRaises(xml.dom.IndexSizeErr,
446 s.insertRule, self.sr, -1)
447 self.assertRaises(xml.dom.IndexSizeErr,
448 s.insertRule, self.sr, s.cssRules.length + 1)
449
450 self.assertEqual(L, s.cssRules.length)
451
452
453 s.insertRule('a {}')
454 self.assertEqual(L+1, s.cssRules.length)
455
456 s.insertRule(self.sr)
457 self.assertEqual(L+2, s.cssRules.length)
458
459 s2, L2 = self._gets()
460 rulelist = s2.cssRules
461 del rulelist[:-2]
462 s.insertRule(rulelist)
463 self.assertEqual(L+2 + 2, s.cssRules.length)
464
465 - def _insertRule(self, rules, notbefore, notafter, anywhere,
466 checkdoubles=True):
467 """
468 helper
469 test if any rule in rules cannot be inserted before rules in before
470 or after rules in after but before and after rules in anywhere
471 """
472 for rule in rules:
473 for r in notbefore:
474 s = cssutils.css.CSSStyleSheet()
475 s.insertRule(r)
476 self.assertRaises(xml.dom.HierarchyRequestErr,
477 s.insertRule, rule, 0)
478 s = cssutils.css.CSSStyleSheet()
479 s.add(r)
480 self.assertRaises(xml.dom.HierarchyRequestErr,
481 s.insertRule, rule, 0)
482 for r in notafter:
483 s = cssutils.css.CSSStyleSheet()
484 s.insertRule(r)
485 self.assertRaises(xml.dom.HierarchyRequestErr,
486 s.insertRule, rule, 1)
487 s = cssutils.css.CSSStyleSheet()
488 s.add(r)
489 s.add(rule)
490
491 for r in anywhere:
492 s = cssutils.css.CSSStyleSheet()
493 s.insertRule(r)
494 s.insertRule(rule, 0)
495 s.insertRule(rule)
496 if checkdoubles:
497 self.assertEqual(s.cssRules.length, 3)
498 self.assertEqual(s, r.parentStyleSheet)
499
501 "CSSStyleSheet.insertRule(@charset)"
502 s, L = self._gets()
503 notbefore = (self.cr,)
504 notafter = (self.cr, self.ir, self.nr, self.mr, self.pr, self.sr,
505 self.c, self.ur)
506 anywhere = ()
507 self._insertRule((self.cr,),
508 notbefore, notafter, anywhere)
509
511 "CSSStyleSheet.insertRule(@import)"
512 s, L = self._gets()
513 notbefore = (self.cr,)
514 notafter = (self.nr, self.pr, self.mr, self.sr)
515 anywhere = (self.c, self.ur, self.ir)
516 self._insertRule((self.ir,),
517 notbefore, notafter, anywhere)
518
520 "CSSStyleSheet.insertRule(@namespace)"
521 s, L = self._gets()
522 notbefore = (self.cr, self.ir)
523 notafter = (self.pr, self.mr, self.sr)
524 anywhere = (self.c, self.ur, self.nr)
525 self._insertRule((self.nr,), notbefore, notafter, anywhere,
526 checkdoubles=False)
527
529 "CSSStyleSheet.insertRule(@media, @page, stylerule)"
530 s, L = self._gets()
531 notbefore = (self.cr, self.ir, self.nr)
532 notafter = ()
533 anywhere = (self.c, self.ur, self.mr, self.pr, self.sr)
534 self._insertRule((self.pr, self.mr, self.sr),
535 notbefore, notafter, anywhere)
536
546
548 "CSSStyleSheet.replaceUrls()"
549 cssutils.ser.prefs.keepAllProperties = True
550
551 css='''
552 @import "im1";
553 @import url(im2);
554 a {
555 background-image: url(c) !important;
556 background-\image: url(b);
557 background: url(a) no-repeat !important;
558 }'''
559 s = cssutils.parseString(css)
560 s.replaceUrls(lambda old: "NEW" + old)
561 self.assertEqual(u'@import "NEWim1";', s.cssRules[0].cssText)
562 self.assertEqual(u'NEWim2', s.cssRules[1].href)
563 self.assertEqual(u'''background-image: url(NEWc) !important;
564 background-\\image: url(NEWb);
565 background: url(NEWa) no-repeat !important''', s.cssRules[2].style.cssText)
566
567 cssutils.ser.prefs.keepAllProperties = False
568
586
588 "CSSStyleRule (incomplete)"
589 tests = {
590 u'@import "a': u'@import "a";',
591 u'a { x: 1': u'a {\n x: 1\n }',
592 u'a { font-family: "arial sans':
593 u'a {\n font-family: "arial sans"\n }',
594 }
595 self.do_equal_p(tests)
596
598 "CSSStyleSheet NoModificationAllowedErr"
599 css = cssutils.css.CSSStyleSheet(readonly=True)
600
601 self.assertEqual(True, css._readonly)
602
603 self.assertRaises(xml.dom.NoModificationAllowedErr,
604 css._setCssText, u'@x;')
605 self.assertRaises(xml.dom.NoModificationAllowedErr,
606 css.insertRule, self.rule)
607 self.assertRaises(xml.dom.NoModificationAllowedErr,
608 css.insertRule, self.rule, 0)
609 self.assertRaises(xml.dom.NoModificationAllowedErr,
610 css.deleteRule, 0)
611
613 "CSSStyleSheet.__repr__(), .__str__()"
614 href = 'file:foo.css'
615 title = 'title-of-css'
616
617 s = cssutils.css.CSSStyleSheet(href=href, title=title)
618
619 self.assert_(href in str(s))
620 self.assert_(title in str(s))
621
622 s2 = eval(repr(s))
623 self.assert_(isinstance(s2, s.__class__))
624 self.assert_(href == s2.href)
625 self.assert_(title == s2.title)
626
627
628 if __name__ == '__main__':
629 import unittest
630 unittest.main()
631