Statistics
| Revision:

gvsig-scripting / org.gvsig.scripting / trunk / org.gvsig.scripting / org.gvsig.scripting.app / org.gvsig.scripting.app.mainplugin / src / main / resources-plugin / scripting / lib / cssutils / tests / test_cssstylesheet.py @ 475

History | View | Annotate | Download (32.7 KB)

1
# -*- coding: utf-8 -*-
2
"""Tests for css.CSSStyleSheet"""
3

    
4
import xml.dom
5
import basetest
6
import cssutils.css
7

    
8
class CSSStyleSheetTestCase(basetest.BaseTestCase):
9

    
10
    def setUp(self):
11
        super(CSSStyleSheetTestCase, self).setUp()
12
        self.r = cssutils.css.CSSStyleSheet() # used by basetest
13
        self.s = self.r # used here
14
        self.rule = cssutils.css.CSSStyleRule()
15

    
16
    def tearDown(self):
17
        cssutils.ser.prefs.useDefaults()
18

    
19
    def test_init(self):
20
        "CSSStyleSheet.__init__()"
21
        self.assertEqual('text/css', self.s.type)
22
        self.assertEqual(False, self.s._readonly)
23
        self.assertEqual([], self.s.cssRules)
24
        self.assertEqual(False, self.s.disabled)
25
        self.assertEqual(None, self.s.href)
26
        self.assertEqual(None, self.s.media)
27
        self.assertEqual(None, self.s.ownerNode)
28
        self.assertEqual(None, self.s.parentStyleSheet)
29
        self.assertEqual(u'', self.s.title)
30

    
31
        # check that type is readonly
32
        self.assertRaises(AttributeError, self.r.__setattr__, 'href', 'x')
33
        self.assertRaises(AttributeError, self.r.__setattr__, 'parentStyleSheet', 'x')
34
        self.assertRaises(AttributeError, self.r.__setattr__, 'ownerNode', 'x')
35
        self.assertRaises(AttributeError, self.r.__setattr__, 'type', 'x')
36

    
37
    def test_iter(self):
38
        "CSSStyleSheet.__iter__()"
39
        s = cssutils.css.CSSStyleSheet()
40
        s.cssText = '''@import "x";@import "y";@namespace "u";'''
41
        types = [cssutils.css.CSSRule.IMPORT_RULE,
42
                 cssutils.css.CSSRule.IMPORT_RULE,
43
                 cssutils.css.CSSRule.NAMESPACE_RULE]
44
        for i, rule in enumerate(s):
45
            self.assertEqual(rule, s.cssRules[i])
46
            self.assertEqual(rule.type, types[i])
47

    
48
    def test_refs(self):
49
        """CSSStylesheet references"""
50
        s = cssutils.parseString('a {}')
51
        rules = s.cssRules
52
        self.assertEqual(s.cssRules[0].parentStyleSheet, s)
53
        self.assertEqual(rules[0].parentStyleSheet, s)
54

    
55
        # set cssText
56
        s.cssText = 'b{}'
57

    
58
        # from 0.9.7b1
59
        self.assertNotEqual(rules, s.cssRules)
60

    
61
        # set cssRules
62
        s.cssRules = cssutils.parseString('''
63
            @charset "ascii";
64
            /**/
65
            @import "x";
66
            @namespace "http://example.com/ns0";
67
            @media all {
68
                a { color: green; }
69
                }
70
            @font-face {
71
                font-family: x;
72
                }
73
            @page {
74
                font-family: Arial;
75
                }
76
            @x;
77
            b {}').cssRules''').cssRules
78
        # new object
79
        self.assertNotEqual(rules, s.cssRules)
80
        for i, r in enumerate(s.cssRules):
81
            self.assertEqual(r.parentStyleSheet, s)
82

    
83
        # namespaces
84
        s = cssutils.parseString('@namespace "http://example.com/ns1"; a {}')
85
        namespaces = s.namespaces
86
        self.assertEqual(s.namespaces.items(), [(u'', 'http://example.com/ns1')])
87
        s.cssText = '@namespace x "http://example.com/ns2"; x|a {}'
88
        # not anymore!
89
        self.assertNotEqual(namespaces, s.namespaces)
90
        self.assertEqual(s.namespaces.items(), [(u'x', 'http://example.com/ns2')])
91

    
92
        # variables
93
        s = cssutils.parseString(u'@variables { a:1}')
94
        vars1 = s.variables
95
        self.assertEqual(vars1[u'a'], u'1')
96

    
97
        s = cssutils.parseString(u'@variables { a:2}')
98
        vars2 = s.variables
99
        self.assertNotEqual(vars1, vars2)
100
        self.assertEqual(vars1[u'a'], u'1')
101
        self.assertEqual(vars2[u'a'], u'2')
102

    
103
    def test_cssRules(self):
104
        "CSSStyleSheet.cssRules"
105
        s = cssutils.parseString('/*1*/a {x:1}')
106
        self.assertEqual(2, s.cssRules.length)
107
        del s.cssRules[0]
108
        self.assertEqual(1, s.cssRules.length)
109
        s.cssRules.append('/*2*/')
110
        self.assertEqual(2, s.cssRules.length)
111
        s.cssRules.extend(cssutils.parseString('/*3*/x {y:2}').cssRules)
112
        self.assertEqual(4, s.cssRules.length)
113
        self.assertEqual(u'a {\n    x: 1\n    }\n/*2*/\n/*3*/\nx {\n    y: 2\n    }'.encode(),
114
                         s.cssText)
115

    
116
        for r in s.cssRules:
117
            self.assertEqual(r.parentStyleSheet, s)
118

    
119
    def test_cssText(self):
120
        "CSSStyleSheet.cssText"
121
        tests = {
122
            '': ''.encode(),
123
            # @charset
124
            '@charset "ascii";\n@import "x";':
125
                '@charset "ascii";\n@import "x";'.encode(),
126
            '@charset "ascii";\n@media all {}': '@charset "ascii";'.encode(),
127
            '@charset "ascii";\n@x;': '@charset "ascii";\n@x;'.encode(),
128
            '@charset "ascii";\na {\n    x: 1\n    }':
129
                '@charset "ascii";\na {\n    x: 1\n    }'.encode(),
130
            # @import
131
            '@x;\n@import "x";': '@x;\n@import "x";'.encode(),
132
            '@import "x";\n@import "y";': '@import "x";\n@import "y";'.encode(),
133
            '@import "x";\n@media all {}': '@import "x";'.encode(),
134
            '@import "x";\n@x;': '@import "x";\n@x;'.encode(),
135
            '@import "x";\na {\n    x: 1\n    }':
136
                '@import "x";\na {\n    x: 1\n    }'.encode(),
137
            # @namespace
138
            '@x;\n@namespace a "x";': '@x;\n@namespace a "x";'.encode(),
139
            '@namespace a "x";\n@namespace b "y";':
140
                '@namespace a "x";\n@namespace b "y";'.encode(),
141
            '@import "x";\n@namespace a "x";\n@media all {}':
142
                '@import "x";\n@namespace a "x";'.encode(),
143
            '@namespace a "x";\n@x;': '@namespace a "x";\n@x;'.encode(),
144
            '@namespace a "x";\na {\n    x: 1\n    }':
145
                '@namespace a "x";\na {\n    x: 1\n    }'.encode(),
146
            """@namespace url("e1");
147
                @namespace url("e2");
148
                @namespace x url("x1");
149
                @namespace x url("x2");
150
                test{color: green}
151
                x|test {color: green}""": """@namespace "e2";
152
@namespace x "x2";
153
test {
154
    color: green
155
    }
156
x|test {
157
    color: green
158
    }""".encode()
159
#            ur'\1 { \2: \3 }': ur'''\x01 {
160
#    \x02: \x03
161
#    }''',
162
#            ur'''
163
#            \@ { \@: \@ }
164
#            \1 { \2: \3 }
165
#            \{{\::\;;}
166
#            ''': ur'''\@ {
167
#    \@: \@
168
#    }
169
#\1 {
170
#    \2: \3
171
#    }
172
#\{
173
#    {\:: \;
174
#    }'''
175
            }
176
        self.do_equal_r(tests)
177

    
178
        tests = {
179
            '': None,
180
            # @charset
181
            '@charset "ascii";\n@import "x";': None,
182
            '@charset "ascii";\n@media all {}': '@charset "ascii";',
183
            '@charset "ascii";\n@x;': None,
184
            '@charset "ascii";\na {\n    x: 1\n    }': None,
185
            # @import
186
            '@x;\n@import "x";': None,
187
            '@import "x";\n@import "y";': None,
188
            '@import "x";\n@media all {}': '@import "x";',
189
            '@import "x";\n@x;': None,
190
            '@import "x";\na {\n    x: 1\n    }': None,
191
            # @namespace
192
            '@x;\n@namespace a "x";': None,
193
            '@namespace a "x";\n@namespace b "y";': None,
194
            '@import "x";\n@namespace a "x";\n@media all {}':
195
                '@import "x";\n@namespace a "x";',
196
            '@namespace a "x";\n@x;': None,
197
            '@namespace a "x";\na {\n    x: 1\n    }': None,
198
            """@namespace url("e1");
199
                @namespace url("e2");
200
                @namespace x url("x1");
201
                @namespace x url("x2");
202
                test{color: green}
203
                x|test {color: green}""": """@namespace "e2";
204
@namespace x "x2";
205
test {
206
    color: green
207
    }
208
x|test {
209
    color: green
210
    }"""
211
#            ur'\1 { \2: \3 }': ur'''\x01 {
212
#    \x02: \x03
213
#    }''',
214
#            ur'''
215
#            \@ { \@: \@ }
216
#            \1 { \2: \3 }
217
#            \{{\::\;;}
218
#            ''': ur'''\@ {
219
#    \@: \@
220
#    }
221
#\1 {
222
#    \2: \3
223
#    }
224
#\{
225
#    {\:: \;
226
#    }'''
227
            }
228
        self.do_equal_p(tests)
229

    
230
        s = cssutils.css.CSSStyleSheet()
231
        s.cssText = u'''@charset "ascii";@import "x";@namespace a "x";
232
        @media all {/*1*/}@page {margin: 0}a {\n    x: 1\n    }@unknown;/*comment*/'''
233
        for r in s.cssRules:
234
            self.assertEqual(s, r.parentStyleSheet)
235

    
236
    def test_cssText_HierarchyRequestErr(self):
237
        "CSSStyleSheet.cssText HierarchyRequestErr"
238
        tests = {
239
            # @charset: only one and always 1st
240
            u' @charset "utf-8";': xml.dom.HierarchyRequestErr,
241
            u'@charset "ascii";@charset "ascii";': xml.dom.HierarchyRequestErr,            u'/*c*/@charset "ascii";': xml.dom.HierarchyRequestErr,
242
            u'@import "x"; @charset "ascii";': xml.dom.HierarchyRequestErr,
243
            u'@namespace a "x"; @charset "ascii";': xml.dom.HierarchyRequestErr,
244
            u'@media all {} @charset "ascii";': xml.dom.HierarchyRequestErr,
245
            u'@page {} @charset "ascii";': xml.dom.HierarchyRequestErr,
246
            u'a {} @charset "ascii";': xml.dom.HierarchyRequestErr,
247

    
248
            # @import: before @namespace, @media, @page, sr
249
            u'@namespace a "x"; @import "x";': xml.dom.HierarchyRequestErr,
250
            u'@media all {} @import "x";': xml.dom.HierarchyRequestErr,
251
            u'@page {} @import "x";': xml.dom.HierarchyRequestErr,
252
            u'a {} @import "x";': xml.dom.HierarchyRequestErr,
253

    
254
            # @namespace: before @media, @page, sr
255
            u'@media all {} @namespace a "x";': xml.dom.HierarchyRequestErr,
256
            u'@page {} @namespace a "x";': xml.dom.HierarchyRequestErr,
257
            u'a {} @namespace a "x";': xml.dom.HierarchyRequestErr,
258
            }
259
        self.do_raise_r(tests)
260
        self.do_raise_p(tests)
261

    
262
    def test_cssText_SyntaxErr(self):
263
        """CSSStyleSheet.cssText SyntaxErr
264

265
        for single {, } or ;
266
        """
267
        tests = {
268
            u'{': xml.dom.SyntaxErr,
269
            u'}': xml.dom.SyntaxErr,
270
            u';': xml.dom.SyntaxErr,
271
            u'@charset "ascii";{': xml.dom.SyntaxErr,
272
            u'@charset "ascii";}': xml.dom.SyntaxErr,
273
            u'@charset "ascii";;': xml.dom.SyntaxErr,
274
            }
275
        self.do_raise_r(tests)
276
        self.do_raise_p(tests)
277

    
278
    def test_encoding(self):
279
        "CSSStyleSheet.encoding"
280
        self.s.cssText=''
281
        self.assertEqual('utf-8', self.s.encoding)
282

    
283
        self.s.encoding = 'ascii'
284
        self.assertEqual('ascii', self.s.encoding)
285
        self.assertEqual(1, self.s.cssRules.length)
286
        self.assertEqual('ascii', self.s.cssRules[0].encoding)
287

    
288
        self.s.encoding = None
289
        self.assertEqual('utf-8', self.s.encoding)
290
        self.assertEqual(0, self.s.cssRules.length)
291

    
292
        self.s.encoding = 'UTF-8'
293
        self.assertEqual('utf-8', self.s.encoding)
294
        self.assertEqual(1, self.s.cssRules.length)
295

    
296
        self.assertRaises(xml.dom.SyntaxErr, self.s._setEncoding,
297
                          'INVALID ENCODING')
298
        self.assertEqual('utf-8', self.s.encoding)
299
        self.assertEqual(1, self.s.cssRules.length)
300

    
301
    def test_namespaces1(self):
302
        "CSSStyleSheet.namespaces.namespaces"
303
        # tests for namespaces internal methods
304
        s = cssutils.css.CSSStyleSheet()
305
        self.assertEqual(0, len(s.namespaces))
306

    
307
        css = u'''@namespace "default";
308
@namespace ex "example";
309
@namespace ex2 "example";
310
ex2|x { top: 0 }'''
311
        expcss = u'''@namespace "default";
312
@namespace ex2 "example";
313
ex2|x {
314
    top: 0
315
    }'''
316
        s.cssText = css
317
        self.assertEqual(s.cssText, expcss.encode())
318
        self.assertEqual(s.namespaces.namespaces,
319
                         { u'': u'default', u'ex2': u'example'})
320

    
321
        # __contains__
322
        self.assertTrue('' in s.namespaces)
323
        self.assertTrue('ex2' in s.namespaces)
324
        self.assertFalse('NOTSET' in s.namespaces)
325
        # __delitem__
326
        self.assertRaises(xml.dom.NoModificationAllowedErr,
327
                          s.namespaces.__delitem__, 'ex2')
328
        s.namespaces['del'] = 'del'
329
        del s.namespaces['del']
330
        self.assertRaises(xml.dom.NamespaceErr, s.namespaces.__getitem__, 'del')
331
        # __getitem__
332
        self.assertEqual('default', s.namespaces[''])
333
        self.assertEqual('example', s.namespaces['ex2'])
334
        self.assertRaises(xml.dom.NamespaceErr, s.namespaces.__getitem__, 'UNSET')
335
        # __iter__
336
        self.assertEqual(['', 'ex2'], sorted(list(s.namespaces)))
337
        # __len__
338
        self.assertEqual(2, len(s.namespaces))
339
        # __setitem__
340
        self.assertRaises(xml.dom.NoModificationAllowedErr,
341
                          s.namespaces.__setitem__, 'ex2', 'NEWURI')
342
        s.namespaces['n1'] = 'new'
343
        self.assertEqual(s.namespaces.namespaces,
344
                         { u'': u'default', u'ex2': u'example', u'n1': 'new'})
345
        s.namespaces['n'] = 'new' # replaces prefix!
346
        self.assertEqual(s.namespaces.namespaces,
347
                         { u'': u'default', u'ex2': u'example', u'n': 'new'})
348
        # prefixForNamespaceURI
349
        self.assertEqual('', s.namespaces.prefixForNamespaceURI('default'))
350
        self.assertEqual('ex2', s.namespaces.prefixForNamespaceURI('example'))
351
        self.assertRaises(IndexError,
352
                          s.namespaces.prefixForNamespaceURI, 'UNSET')
353
        # .keys
354
        self.assertEqual(set(s.namespaces.keys()), set(['', 'ex2', 'n']))
355
        # .get
356
        self.assertEqual('x', s.namespaces.get('UNKNOWN', 'x'))
357
        self.assertEqual('example', s.namespaces.get('ex2', 'not used defa'))
358

    
359
    def test_namespaces2(self):
360
        "CSSStyleSheet.namespaces"
361
        # tests using CSSStyleSheet.namespaces
362

    
363
        s = cssutils.css.CSSStyleSheet()
364
        css = '@namespace n "new";'
365
        # doubles will be removed
366
        s.insertRule(css + css)
367
        self.assertEqual(s.cssText, css.encode())
368
        r = cssutils.css.CSSNamespaceRule(prefix='ex2', namespaceURI='example')
369
        s.insertRule(r)
370
        r = cssutils.css.CSSNamespaceRule(namespaceURI='default')
371
        s.insertRule(r)
372

    
373
        expcss = '''@namespace n "new";
374
@namespace ex2 "example";
375
@namespace "default";'''
376
        self.assertEqual(s.cssText, expcss.encode())
377
        r.prefix = 'DEFAULT'
378
        expcss = '''@namespace n "new";
379
@namespace ex2 "example";
380
@namespace DEFAULT "default";'''
381
        self.assertEqual(s.cssText, expcss.encode())
382

    
383
        # CSSMediaRule
384
        self.assertRaises(xml.dom.NamespaceErr, s.add, '@media all {x|a {left: 0}}')
385
        mcss = '@media all {\n    ex2|SEL1 {\n        left: 0\n        }\n    }'
386
        s.add(mcss)
387
        expcss += '\n' + mcss
388
        self.assertEqual(s.cssText, expcss.encode())
389

    
390
        # CSSStyleRule
391
        self.assertRaises(xml.dom.NamespaceErr, s.add, 'x|a {top: 0}')
392
        scss = 'n|SEL2 {\n    top: 0\n    }'
393
        s.add(scss)
394
        expcss += '\n' + scss
395
        self.assertEqual(s.cssText, expcss.encode())
396

    
397
        mr = s.cssRules[3]
398
        sr = s.cssRules[4]
399

    
400
        # SelectorList @media
401
        self.assertRaises(xml.dom.NamespaceErr,
402
                          mr.cssRules[0]._setSelectorText, 'x|b')
403
        oldsel, newsel = mr.cssRules[0].selectorText, 'n|SEL3, a'
404
        mr.cssRules[0].selectorText = newsel
405
        expcss = expcss.replace(oldsel, newsel)
406
        self.assertEqual(s.cssText, expcss.encode())
407
        # SelectorList stylerule
408
        self.assertRaises(xml.dom.NamespaceErr,
409
                          sr._setSelectorText, 'x|b')
410
        oldsel, newsel = sr.selectorText, 'ex2|SEL4, a'
411
        sr.selectorText = newsel
412
        expcss = expcss.replace(oldsel, newsel)
413
        self.assertEqual(s.cssText, expcss.encode())
414

    
415
        # Selector @media
416
        self.assertRaises(xml.dom.NamespaceErr,
417
                          mr.cssRules[0].selectorList.append, 'x|b')
418
        oldsel, newsel = mr.cssRules[0].selectorText, 'ex2|SELMR'
419
        mr.cssRules[0].selectorList.append(newsel)
420
        expcss = expcss.replace(oldsel, oldsel + ', ' + newsel)
421
        self.assertEqual(s.cssText, expcss.encode())
422
        # Selector stylerule
423
        self.assertRaises(xml.dom.NamespaceErr,
424
                          sr.selectorList.append, 'x|b')
425
        oldsel, newsel = sr.selectorText, 'ex2|SELSR'
426
        sr.selectorList.append(newsel)
427
        expcss = expcss.replace(oldsel, oldsel + ', ' + newsel)
428
        self.assertEqual(s.cssText, expcss.encode())
429

    
430
        self.assertEqual(s.cssText, u'''@namespace n "new";
431
@namespace ex2 "example";
432
@namespace DEFAULT "default";
433
@media all {
434
    n|SEL3, a, ex2|SELMR {
435
        left: 0
436
        }
437
    }
438
ex2|SEL4, a, ex2|SELSR {
439
    top: 0
440
    }'''.encode())
441

    
442
    def test_namespaces3(self):
443
        "CSSStyleSheet.namespaces 3"
444
        # tests setting namespaces with new {}
445
        s = cssutils.css.CSSStyleSheet()
446
        css = u'h|a { top: 0 }'
447
        self.assertRaises(xml.dom.NamespaceErr, s.add, css)
448

    
449
        s.add('@namespace x "html";')
450
        self.assertTrue(s.namespaces['x'] == 'html')
451

    
452
        r = cssutils.css.CSSStyleRule()
453
        r.cssText = ((css, {'h': 'html'}))
454
        s.add(r) # uses x as set before! h is temporary only
455
        self.assertEqual(s.cssText, '@namespace x "html";\nx|a {\n    top: 0\n    }'.encode())
456

    
457
        # prefix is now "x"!
458
        self.assertRaises(xml.dom.NamespaceErr, r.selectorList.append, 'h|b')
459
        self.assertRaises(xml.dom.NamespaceErr, r.selectorList.append, 'y|b')
460
        s.namespaces['y'] = 'html'
461
        r.selectorList.append('y|b')
462
        self.assertEqual(s.cssText,
463
            u'@namespace y "html";\ny|a, y|b {\n    top: 0\n    }'.encode())
464

    
465
        self.assertRaises(xml.dom.NoModificationAllowedErr,
466
                          s.namespaces.__delitem__, 'y')
467
        self.assertEqual(s.cssText,
468
            u'@namespace y "html";\ny|a, y|b {\n    top: 0\n    }'.encode())
469

    
470
        s.cssRules[0].prefix = ''
471
        self.assertEqual(s.cssText,
472
            u'@namespace "html";\na, b {\n    top: 0\n    }'.encode())
473

    
474
        # remove need of namespace
475
        s.cssRules[0].prefix = 'x'
476
        s.cssRules[1].selectorText = 'a, b'
477
        self.assertEqual(s.cssText,
478
            u'@namespace x "html";\na, b {\n    top: 0\n    }'.encode())
479

    
480

    
481
    def test_namespaces4(self):
482
        "CSSStyleSheet.namespaces 4"
483
        # tests setting namespaces with new {}
484
        s = cssutils.css.CSSStyleSheet()
485
        self.assertEqual({}, s.namespaces.namespaces)
486

    
487
        s.namespaces.namespaces['a'] = 'no setting possible'
488
        self.assertEqual({}, s.namespaces.namespaces)
489

    
490
        s.namespaces[None] = 'default'
491
        self.assertEqual({u'': 'default'}, s.namespaces.namespaces)
492

    
493
        del s.namespaces['']
494
        self.assertEqual({}, s.namespaces.namespaces)
495

    
496
        s.namespaces[''] = 'default'
497
        self.assertEqual({u'': 'default'}, s.namespaces.namespaces)
498

    
499
        del s.namespaces[None]
500
        self.assertEqual({}, s.namespaces.namespaces)
501

    
502
        s.namespaces['p'] = 'uri'
503
        # cannot use namespaces.namespaces
504
        del s.namespaces.namespaces['p']
505
        self.assertEqual({u'p': 'uri'}, s.namespaces.namespaces)
506

    
507
        self.assertRaisesMsg(xml.dom.NamespaceErr, u"Prefix undefined not found.",
508
                             s.namespaces.__delitem__, 'undefined')
509

    
510
    def test_namespaces5(self):
511
        "CSSStyleSheet.namespaces 5"
512
        # unknown namespace
513
        s = cssutils.parseString('a|a { color: red }')
514
        self.assertEqual(s.cssText, ''.encode())
515

    
516
        s = cssutils.css.CSSStyleSheet()
517
        self.assertRaisesMsg(xml.dom.NamespaceErr, "Prefix a not found.",
518
                             s._setCssText, 'a|a { color: red }')
519

    
520
    def test_deleteRuleIndex(self):
521
        "CSSStyleSheet.deleteRule(index)"
522
        self.s.cssText = u'@charset "ascii"; @import "x"; @x; a {\n    x: 1\n    }@y;'
523
        self.assertEqual(5, self.s.cssRules.length)
524

    
525
        self.assertRaises(xml.dom.IndexSizeErr, self.s.deleteRule, 5)
526

    
527
        # end -1
528
        # check parentStyleSheet
529
        r = self.s.cssRules[-1]
530
        self.assertEqual(self.s, r.parentStyleSheet)
531
        self.s.deleteRule(-1)
532
        self.assertEqual(None, r.parentStyleSheet)
533

    
534
        self.assertEqual(4, self.s.cssRules.length)
535
        self.assertEqual(
536
            u'@charset "ascii";\n@import "x";\n@x;\na {\n    x: 1\n    }'.encode(), self.s.cssText)
537
        # beginning
538
        self.s.deleteRule(0)
539
        self.assertEqual(3, self.s.cssRules.length)
540
        self.assertEqual(u'@import "x";\n@x;\na {\n    x: 1\n    }'.encode(), self.s.cssText)
541
        # middle
542
        self.s.deleteRule(1)
543
        self.assertEqual(2, self.s.cssRules.length)
544
        self.assertEqual(u'@import "x";\na {\n    x: 1\n    }'.encode(), self.s.cssText)
545
        # end
546
        self.s.deleteRule(1)
547
        self.assertEqual(1, self.s.cssRules.length)
548
        self.assertEqual(u'@import "x";'.encode(), self.s.cssText)
549

    
550
    def test_deleteRule(self):
551
        "CSSStyleSheet.deleteRule(rule)"
552
        s = cssutils.css.CSSStyleSheet()
553
        s.cssText='''
554
        @namespace x "http://example.com";
555
        a { color: red; }
556
        b { color: blue; }
557
        c { color: green; }
558
        '''
559
        n, s1, s2, s3 = s.cssRules
560

    
561
        r = cssutils.css.CSSStyleRule()
562
        self.assertRaises(xml.dom.IndexSizeErr, s.deleteRule, r)
563

    
564
        self.assertEqual(4, s.cssRules.length)
565
        s.deleteRule(n)
566
        self.assertEqual(3, s.cssRules.length)
567
        self.assertEqual(s.cssText, 'a {\n    color: red\n    }\nb {\n    color: blue\n    }\nc {\n    color: green\n    }'.encode())
568
        self.assertRaises(xml.dom.IndexSizeErr, s.deleteRule, n)
569
        s.deleteRule(s2)
570
        self.assertEqual(2, s.cssRules.length)
571
        self.assertEqual(s.cssText, 'a {\n    color: red\n    }\nc {\n    color: green\n    }'.encode())
572
        self.assertRaises(xml.dom.IndexSizeErr, s.deleteRule, s2)
573

    
574
    def _gets(self):
575
        # complete
576
        self.cr = cssutils.css.CSSCharsetRule('ascii')
577
        self.c = cssutils.css.CSSComment(u'/*c*/')
578
        self.ur = cssutils.css.CSSUnknownRule('@x;')
579
        self.ir = cssutils.css.CSSImportRule('x')
580
        self.nr = cssutils.css.CSSNamespaceRule('uri', 'p')
581
        self.mr = cssutils.css.CSSMediaRule()
582
        self.mr.cssText = u'@media all { @m; }'
583
        self.pr = cssutils.css.CSSPageRule()
584
        self.pr.style = u'margin: 0;'
585
        self.sr = cssutils.css.CSSStyleRule()
586
        self.sr.cssText = 'a {\n    x: 1\n    }'
587

    
588
        s = cssutils.css.CSSStyleSheet()
589
        s.insertRule(self.cr) # 0
590
        s.insertRule(self.ir) # 1
591
        s.insertRule(self.nr) # 2
592
        s.insertRule(self.mr) # 3
593
        s.insertRule(self.sr) # 4
594
        s.insertRule(self.mr) # 5
595
        s.insertRule(self.pr) # 6
596
        s.insertRule(self.sr) # 7
597
        self.assertEqual(u'@charset "ascii";\n@import url(x);\n@namespace p "uri";\n@media all {\n    @m;\n    }\na {\n    x: 1\n    }\n@media all {\n    @m;\n    }\n@page {\n    margin: 0\n    }\na {\n    x: 1\n    }'.encode(), s.cssText)
598
        return s, s.cssRules.length
599

    
600
    def test_add(self):
601
        "CSSStyleSheet.add()"
602
        full = cssutils.css.CSSStyleSheet()
603
        sheet = cssutils.css.CSSStyleSheet()
604
        css = ['@charset "ascii";',
605
               '@import "x";',
606
               '@namespace p "u";',
607
               '@page {\n    left: 0\n    }',
608
               '@font-face {\n    src: local(x)\n    }',
609
               '@media all {\n    a {\n        color: red\n        }\n    }',
610
               'a {\n    color: green\n    }',
611
               '/*comment*/',
612
               '@x;'
613
               ]
614

    
615
        fullcss = u'\n'.join(css)
616
        full.cssText = fullcss
617
        self.assertEqual(full.cssText, fullcss.encode())
618
        for i, line in enumerate(css):
619
            # sheet without same ruletype
620
            before = css[:i]
621
            after = css[i+1:]
622
            sheet.cssText = u''.join(before + after)
623

    
624
            index = sheet.add(line)
625
            if i < 3:
626
                # specific insertion point
627
                self.assertEqual(fullcss.encode(), sheet.cssText)
628
                self.assertEqual(i, index)
629
            else:
630
                # end of sheet
631
                expected = before
632
                expected.extend(after)
633
                expected.append(line)
634
                self.assertEqual(u'\n'.join(expected).encode(), sheet.cssText)
635
                self.assertEqual(len(expected)-1, index) # no same rule present
636

    
637
            # sheet with the same ruletype
638
            if i == 1: line = '@import "x2";'
639
            if i == 2: line = '@namespace p2 "u2";'
640

    
641
            full.cssText = fullcss
642
            index = full.add(line)
643
            if i < 1:
644
                self.assertEqual(fullcss.encode(), sheet.cssText)
645
                self.assertEqual(i, index) # no same rule present
646
            else:
647
                if i < 3:
648
                    # in order
649
                    expected = css[:i+1] # including same rule
650
                    expected.append(line)
651
                    expected.extend(css[i+1:])
652
                    expectedindex = i+1
653
                else:
654
                    # just appended as no order needed
655
                    expected = css[:]
656
                    expected.append(line)
657
                    expectedindex = len(expected) - 1
658

    
659
                self.assertEqual(u'\n'.join(expected).encode(), full.cssText)
660
                self.assertEqual(expectedindex, index) # no same rule present
661

    
662
    def test_addimport(self):
663
        p = cssutils.CSSParser(fetcher=lambda url: (None, '/**/'))
664

    
665
        cssrulessheet = p.parseString('@import "example.css";')
666
        imports = (
667
            '@import "example.css";', # string
668
            cssutils.css.CSSImportRule(href="example.css"), # CSSRule
669
            cssrulessheet.cssRules # CSSRuleList
670
            )
671
        for imp in imports:
672
            sheet = p.parseString('', href='http://example.com')
673
            sheet.add(imp)
674
            added = sheet.cssRules[0]
675
            self.assertEqual(sheet, added.parentStyleSheet)
676
            self.assertEqual(u'example.css', added.href)
677
            self.assertEqual(u'utf-8', added.styleSheet.encoding)
678
            self.assertEqual(u'/**/'.encode(), added.styleSheet.cssText)
679

    
680
        cssrulessheet = p.parseString('@import "example.css";')
681
        imports = (
682
            ('@import "example.css";', 'ascii'), # string
683
            (cssutils.css.CSSImportRule(href="example.css"), 'ascii'), # CSSRule
684
            # got encoding from old parent already
685
            (cssrulessheet.cssRules, 'utf-8') # CSSRuleList
686
            )
687
        for imp, enc in imports:
688
            sheet = p.parseString('', href='http://example.com', encoding='ascii')
689
            sheet.add(imp)
690
            added = sheet.cssRules[1]
691
            self.assertEqual(sheet, added.parentStyleSheet)
692
            self.assertEqual(u'example.css', added.href)
693
            self.assertEqual(enc, added.styleSheet.encoding)
694
            if enc == 'ascii':
695
                self.assertEqual(u'@charset "ascii";\n/**/'.encode(), added.styleSheet.cssText)
696
            else:
697
                self.assertEqual(u'/**/'.encode(), added.styleSheet.cssText)
698

    
699
        # if styleSheet is already there encoding is not set new
700
        impsheet = p.parseString('@import "example.css";')
701
        imp = impsheet.cssRules[0]
702
        sheet = p.parseString('', href='http://example.com', encoding='ascii')
703
        sheet.add(imp)
704
        added = sheet.cssRules[1]
705
        self.assertEqual(sheet, added.parentStyleSheet)
706
        self.assertEqual(u'example.css', added.href)
707
        self.assertEqual(u'utf-8', added.styleSheet.encoding)
708
        self.assertEqual(u'/**/'.encode(), added.styleSheet.cssText)
709

    
710
    def test_insertRule(self):
711
        "CSSStyleSheet.insertRule()"
712
        s, L = self._gets()
713

    
714
        # INVALID index
715
        self.assertRaises(xml.dom.IndexSizeErr,
716
                  s.insertRule, self.sr, -1)
717
        self.assertRaises(xml.dom.IndexSizeErr,
718
                  s.insertRule, self.sr, s.cssRules.length + 1)
719
        #   check if rule is really not in
720
        self.assertEqual(L, s.cssRules.length)
721

    
722
        # insert string
723
        s.insertRule('a {}')
724
        self.assertEqual(L+1, s.cssRules.length)
725
        # insert rule
726
        s.insertRule(self.sr)
727
        self.assertEqual(L+2, s.cssRules.length)
728
        # insert rulelist
729
        s2, L2 = self._gets()
730
        rulelist = s2.cssRules
731
        del rulelist[:-2]
732
        s.insertRule(rulelist)
733
        self.assertEqual(L+2 + 2, s.cssRules.length)
734

    
735
    def _insertRule(self, rules, notbefore, notafter, anywhere,
736
                    checkdoubles=True):
737
        """
738
        helper
739
        test if any rule in rules cannot be inserted before rules in before
740
        or after rules in after but before and after rules in anywhere
741
        """
742
        for rule in rules:
743
            for r in notbefore:
744
                s = cssutils.css.CSSStyleSheet()
745
                s.insertRule(r)
746
                self.assertRaises(xml.dom.HierarchyRequestErr,
747
                                  s.insertRule, rule, 0)
748
                s = cssutils.css.CSSStyleSheet()
749
                s.add(r)
750
                self.assertRaises(xml.dom.HierarchyRequestErr,
751
                                  s.insertRule, rule, 0)
752
            for r in notafter:
753
                s = cssutils.css.CSSStyleSheet()
754
                s.insertRule(r)
755
                self.assertRaises(xml.dom.HierarchyRequestErr,
756
                                  s.insertRule, rule, 1)
757
                s = cssutils.css.CSSStyleSheet()
758
                s.add(r)
759
                s.add(rule) # never raises
760
                self.assertEqual(s, r.parentStyleSheet)
761

    
762
            for r in anywhere:
763
                s = cssutils.css.CSSStyleSheet()
764
                s.insertRule(r)
765
                s.insertRule(rule, 0) # before
766
                s.insertRule(rule) # after
767
                if checkdoubles:
768
                    self.assertEqual(s.cssRules.length, 3)
769
                self.assertEqual(s, r.parentStyleSheet)
770

    
771
    def test_insertRule_charset(self):
772
        "CSSStyleSheet.insertRule(@charset)"
773
        s, L = self._gets()
774
        notbefore = (self.cr,)
775
        notafter = (self.cr, self.ir, self.nr, self.mr, self.pr, self.sr,
776
                    self.c, self.ur)
777
        anywhere = ()
778
        self._insertRule((self.cr,),
779
                         notbefore, notafter, anywhere)
780

    
781
    def test_insertRule_import(self):
782
        "CSSStyleSheet.insertRule(@import)"
783
        s, L = self._gets()
784
        notbefore = (self.cr,)
785
        notafter = (self.nr, self.pr, self.mr, self.sr)
786
        anywhere = (self.c, self.ur, self.ir)
787
        self._insertRule((self.ir,),
788
                         notbefore, notafter, anywhere)
789

    
790
    def test_insertRule_namespace(self):
791
        "CSSStyleSheet.insertRule(@namespace)"
792
        s, L = self._gets()
793
        notbefore = (self.cr, self.ir)
794
        notafter = (self.pr, self.mr, self.sr)
795
        anywhere = (self.c, self.ur, self.nr)
796
        self._insertRule((self.nr,), notbefore, notafter, anywhere,
797
                         checkdoubles=False)
798

    
799
    def test_insertRule_media_page_style(self):
800
        "CSSStyleSheet.insertRule(@media, @page, stylerule)"
801
        s, L = self._gets()
802
        notbefore = (self.cr, self.ir, self.nr)
803
        notafter = ()
804
        anywhere = (self.c, self.ur, self.mr, self.pr, self.sr)
805
        self._insertRule((self.pr, self.mr, self.sr),
806
                         notbefore, notafter, anywhere)
807

    
808
    def test_insertRule_unknownandcomment(self):
809
        "CSSStyleSheet.insertRule(@ unknown, comment)"
810
        s, L = self._gets()
811
        notbefore = (self.cr,)
812
        notafter = ()
813
        anywhere = (self.c, self.ur, self.ir, self.nr, self.mr, self.pr,
814
                    self.sr)
815
        self._insertRule((self.ur,),
816
                         notbefore, notafter, anywhere)
817

    
818
    def test_HTMLComments(self):
819
        "CSSStyleSheet CDO CDC"
820
        css = u'''body { color: red }
821
<!-- comment -->
822
body { color: blue }
823
body { color: pink }
824
<!-- comment -->
825
body { color: green }
826
'''
827
        exp = u'''body {
828
    color: red
829
    }
830
body {
831
    color: pink
832
    }'''
833
        sheet = cssutils.parseString(css)
834
        self.assertEqual(sheet.cssText, exp.encode())
835

    
836
    def test_incomplete(self):
837
        "CSSStyleRule (incomplete)"
838
        tests = {
839
            u'@import "a': u'@import "a";', # no }
840
            u'a { x: 1': u'a {\n    x: 1\n    }', # no }
841
            u'a { font-family: "arial sans': # no "
842
                u'a {\n    font-family: "arial sans"\n    }',
843
        }
844
        self.do_equal_p(tests) # parse
845

    
846
    def test_NoModificationAllowedErr(self):
847
        "CSSStyleSheet NoModificationAllowedErr"
848
        css = cssutils.css.CSSStyleSheet(readonly=True)
849

    
850
        self.assertEqual(True, css._readonly) # internal...
851

    
852
        self.assertRaises(xml.dom.NoModificationAllowedErr,
853
                          css._setCssText, u'@x;')
854
        self.assertRaises(xml.dom.NoModificationAllowedErr,
855
                          css.insertRule, self.rule)
856
        self.assertRaises(xml.dom.NoModificationAllowedErr,
857
                          css.insertRule, self.rule, 0)
858
        self.assertRaises(xml.dom.NoModificationAllowedErr,
859
                          css.deleteRule, 0)
860

    
861
    def test_reprANDstr(self):
862
        "CSSStyleSheet.__repr__(), .__str__()"
863
        href = 'file:foo.css'
864
        title = 'title-of-css'
865

    
866
        s = cssutils.css.CSSStyleSheet(href=href, title=title)
867

    
868
        self.assertTrue(href in str(s))
869
        self.assertTrue(title in str(s))
870

    
871
        s2 = eval(repr(s))
872
        self.assertTrue(isinstance(s2, s.__class__))
873
        self.assertTrue(href == s2.href)
874
        self.assertTrue(title == s2.title)
875

    
876

    
877
if __name__ == '__main__':
878
    import unittest
879
    unittest.main()