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_util.py @ 475

History | View | Annotate | Download (17.6 KB)

1
# -*- coding: utf-8 -*-
2
"""Testcases for cssutils.util"""
3
from __future__ import with_statement
4

    
5
import cgi
6
from email import message_from_string, message_from_file
7
import StringIO
8
import sys
9
import urllib2
10
import xml.dom
11

    
12
try:
13
    import mock
14
except ImportError:
15
    mock = None
16
    print "install mock library to run all tests"
17

    
18
import basetest
19
import encutils
20

    
21
from cssutils.util import Base, ListSeq, _readUrl, _defaultFetcher
22

    
23
class ListSeqTestCase(basetest.BaseTestCase):
24

    
25
    def test_all(self):
26
        "util.ListSeq"
27
        ls = ListSeq()
28
        self.assertEqual(0, len(ls))
29
        # append()
30
        self.assertRaises(NotImplementedError, ls.append, 1)
31
        # set
32
        self.assertRaises(NotImplementedError, ls.__setitem__, 0, 1)
33

    
34
        # hack:
35
        ls.seq.append(1)
36
        ls.seq.append(2)
37

    
38
        # len
39
        self.assertEqual(2, len(ls))
40
        # __contains__
41
        self.assertEqual(True, 1 in ls)
42
        # get
43
        self.assertEqual(1, ls[0])
44
        self.assertEqual(2, ls[1])
45
        # del
46
        del ls[0]
47
        self.assertEqual(1, len(ls))
48
        self.assertEqual(False, 1 in ls)
49
        # for in
50
        for x in ls:
51
            self.assertEqual(2, x)
52

    
53

    
54
class BaseTestCase(basetest.BaseTestCase):
55

    
56
    def test_normalize(self):
57
        "Base._normalize()"
58
        b = Base()
59
        tests = {u'abcdefg ABCDEFG äöü߀ AÖÜ': u'abcdefg abcdefg äöü߀ aöü',
60
                 ur'\ga\Ga\\\ ': ur'gaga\ ',
61
                 ur'0123456789': u'0123456789',
62
                 # unicode escape seqs should have been done by
63
                 # the tokenizer...
64
                 }
65
        for test, exp in tests.items():
66
            self.assertEqual(b._normalize(test), exp)
67
            # static too
68
            self.assertEqual(Base._normalize(test), exp)
69

    
70
    def test_tokenupto(self):
71
        "Base._tokensupto2()"
72

    
73
        # tests nested blocks of {} [] or ()
74
        b = Base()
75

    
76
        tests = [
77
            ('default', u'a[{1}]({2}) { } NOT', u'a[{1}]({2}) { }', False),
78
            ('default', u'a[{1}]({2}) { } NOT', u'a[{1}]func({2}) { }', True),
79
            ('blockstartonly', u'a[{1}]({2}) { NOT', u'a[{1}]({2}) {', False),
80
            ('blockstartonly', u'a[{1}]({2}) { NOT', u'a[{1}]func({2}) {', True),
81
            ('propertynameendonly', u'a[(2)1] { }2 : a;', u'a[(2)1] { }2 :', False),
82
            ('propertynameendonly', u'a[(2)1] { }2 : a;', u'a[func(2)1] { }2 :', True),
83
            ('propertyvalueendonly', u'a{;{;}[;](;)}[;{;}[;](;)](;{;}[;](;)) 1; NOT',
84
                u'a{;{;}[;](;)}[;{;}[;](;)](;{;}[;](;)) 1;', False),
85
            ('propertyvalueendonly', u'a{;{;}[;](;)}[;{;}[;](;)](;{;}[;](;)) 1; NOT',
86
                u'a{;{;}[;]func(;)}[;{;}[;]func(;)]func(;{;}[;]func(;)) 1;', True),
87
            ('funcendonly', u'a{[1]}([3])[{[1]}[2]([3])]) NOT',
88
                u'a{[1]}([3])[{[1]}[2]([3])])', False),
89
            ('funcendonly', u'a{[1]}([3])[{[1]}[2]([3])]) NOT',
90
                u'a{[1]}func([3])[{[1]}[2]func([3])])', True),
91
            ('selectorattendonly', u'[a[()]{()}([()]{()}())] NOT',
92
                u'[a[()]{()}([()]{()}())]', False),
93
            ('selectorattendonly', u'[a[()]{()}([()]{()}())] NOT',
94
                u'[a[func()]{func()}func([func()]{func()}func())]', True),
95
            # issue 50
96
            ('withstarttoken [', u'a];x', u'[a];', False)
97
            ]
98

    
99
        for typ, values, exp, paransasfunc in tests:
100

    
101
            def maketokens(valuelist):
102
                # returns list of tuples
103
                return [('TYPE', v, 0, 0) for v in valuelist]
104

    
105
            tokens = maketokens(list(values))
106
            if paransasfunc:
107
                for i, t in enumerate(tokens):
108
                    if u'(' == t[1]:
109
                        tokens[i] = ('FUNCTION', u'func(', t[2], t[3])
110

    
111
            if 'default' == typ:
112
                restokens = b._tokensupto2(tokens)
113
            elif 'blockstartonly' == typ:
114
                restokens = b._tokensupto2(
115
                    tokens, blockstartonly=True)
116
            elif 'propertynameendonly' == typ:
117
                restokens = b._tokensupto2(
118
                    tokens, propertynameendonly=True)
119
            elif 'propertyvalueendonly' == typ:
120
                restokens = b._tokensupto2(
121
                    tokens, propertyvalueendonly=True)
122
            elif 'funcendonly' == typ:
123
                restokens = b._tokensupto2(
124
                    tokens, funcendonly=True)
125
            elif 'selectorattendonly' == typ:
126
                restokens = b._tokensupto2(
127
                    tokens, selectorattendonly=True)
128
            elif 'withstarttoken [' == typ:
129
                restokens = b._tokensupto2(tokens, ('CHAR', '[', 0, 0))
130

    
131
            res = u''.join([t[1] for t in restokens])
132
            self.assertEqual(exp, res)
133

    
134

    
135
class _readUrl_TestCase(basetest.BaseTestCase):
136
    """needs mock"""
137

    
138
    def test_readUrl(self):
139
        """util._readUrl()"""
140
        # for additional tests see test_parse.py
141
        url = 'http://example.com/test.css'
142

    
143
        def make_fetcher(r):
144
            # normally r == encoding, content
145
            def fetcher(url):
146
                return r
147
            return fetcher
148

    
149
        tests = {
150
            # defaultFetcher returns: readUrl returns
151
            None: (None, None, None),
152
            (None, ''): ('utf-8', 5, u''),
153
            (None, u''.encode('utf-8')): ('utf-8', 5, u''),
154
            ('utf-8', u''.encode('utf-8')): ('utf-8', 1, u''),
155
            ('ISO-8859-1', u'ä'.encode('iso-8859-1')): ('ISO-8859-1', 1, u'ä'),
156
            ('ASCII', u'a'.encode('ascii')): ('ASCII', 1, u'a')
157
        }
158

    
159
        for r, exp in tests.items():
160
            self.assertEqual(_readUrl(url, fetcher=make_fetcher(r)), exp)
161

    
162
        tests = {
163
            # (overrideEncoding, parentEncoding, (httpencoding, content)):
164
            #                        readUrl returns
165

    
166
            # ===== 0. OVERRIDE WINS =====
167
            # override + parent + http
168
            ('latin1', 'ascii', ('utf-16', u''.encode())): ('latin1', 0, u''),
169
            ('latin1', 'ascii', ('utf-16', u'123'.encode())): ('latin1', 0, u'123'),
170
            ('latin1', 'ascii', ('utf-16', u'ä'.encode('iso-8859-1'))):
171
                ('latin1', 0, u'ä'),
172
            ('latin1', 'ascii', ('utf-16', u'a'.encode('ascii'))):
173
                ('latin1',0,  u'a'),
174
            # + @charset
175
            ('latin1', 'ascii', ('utf-16', u'@charset "ascii";'.encode())):
176
                ('latin1', 0, u'@charset "latin1";'),
177
            ('latin1', 'ascii', ('utf-16', u'@charset "utf-8";ä'.encode('latin1'))):
178
                ('latin1', 0, u'@charset "latin1";ä'),
179
            ('latin1', 'ascii', ('utf-16', u'@charset "utf-8";ä'.encode('utf-8'))):
180
                ('latin1', 0, u'@charset "latin1";\xc3\xa4'), # read as latin1!
181

    
182
            # override only
183
            ('latin1', None, None): (None, None, None),
184
            ('latin1', None, (None, u''.encode())): ('latin1', 0, u''),
185
            ('latin1', None, (None, u'123'.encode())): ('latin1', 0, u'123'),
186
            ('latin1', None, (None, u'ä'.encode('iso-8859-1'))):
187
                ('latin1', 0, u'ä'),
188
            ('latin1', None, (None, u'a'.encode('ascii'))):
189
                ('latin1', 0, u'a'),
190
            # + @charset
191
            ('latin1', None, (None, u'@charset "ascii";'.encode())):
192
                ('latin1', 0, u'@charset "latin1";'),
193
            ('latin1', None, (None, u'@charset "utf-8";ä'.encode('latin1'))):
194
                ('latin1', 0, u'@charset "latin1";ä'),
195
            ('latin1', None, (None, u'@charset "utf-8";ä'.encode('utf-8'))):
196
                ('latin1', 0, u'@charset "latin1";\xc3\xa4'), # read as latin1!
197

    
198
            # override + parent
199
            ('latin1', 'ascii', None): (None, None, None),
200
            ('latin1', 'ascii', (None, u''.encode())): ('latin1', 0, u''),
201
            ('latin1', 'ascii', (None, u'123'.encode())): ('latin1', 0, u'123'),
202
            ('latin1', 'ascii', (None, u'ä'.encode('iso-8859-1'))):
203
                ('latin1', 0, u'ä'),
204
            ('latin1', 'ascii', (None, u'a'.encode('ascii'))):
205
                ('latin1', 0, u'a'),
206
            # + @charset
207
            ('latin1', 'ascii', (None, u'@charset "ascii";'.encode())):
208
                ('latin1', 0, u'@charset "latin1";'),
209
            ('latin1', 'ascii', (None, u'@charset "utf-8";ä'.encode('latin1'))):
210
                ('latin1', 0, u'@charset "latin1";ä'),
211
            ('latin1', 'ascii', (None, u'@charset "utf-8";ä'.encode('utf-8'))):
212
                ('latin1', 0, u'@charset "latin1";\xc3\xa4'), # read as latin1!
213

    
214
            # override + http
215
            ('latin1', None, ('utf-16', u''.encode())): ('latin1', 0, u''),
216
            ('latin1', None, ('utf-16', u'123'.encode())): ('latin1', 0, u'123'),
217
            ('latin1', None, ('utf-16', u'ä'.encode('iso-8859-1'))):
218
                ('latin1', 0, u'ä'),
219
            ('latin1', None, ('utf-16', u'a'.encode('ascii'))):
220
                ('latin1', 0, u'a'),
221
            # + @charset
222
            ('latin1', None, ('utf-16', u'@charset "ascii";'.encode())):
223
                ('latin1', 0, u'@charset "latin1";'),
224
            ('latin1', None, ('utf-16', u'@charset "utf-8";ä'.encode('latin1'))):
225
                ('latin1', 0, u'@charset "latin1";ä'),
226
            ('latin1', None, ('utf-16', u'@charset "utf-8";ä'.encode('utf-8'))):
227
                ('latin1', 0, u'@charset "latin1";\xc3\xa4'), # read as latin1!
228

    
229
            # override ü @charset
230
            ('latin1', None, (None, u'@charset "ascii";'.encode())):
231
                ('latin1', 0, u'@charset "latin1";'),
232
            ('latin1', None, (None, u'@charset "utf-8";ä'.encode('latin1'))):
233
                ('latin1', 0, u'@charset "latin1";ä'),
234
            ('latin1', None, (None, u'@charset "utf-8";ä'.encode('utf-8'))):
235
                ('latin1', 0, u'@charset "latin1";\xc3\xa4'), # read as latin1!
236

    
237

    
238
            # ===== 1. HTTP WINS =====
239
            (None, 'ascii', ('latin1', u''.encode())): ('latin1', 1, u''),
240
            (None, 'ascii', ('latin1', u'123'.encode())): ('latin1', 1, u'123'),
241
            (None, 'ascii', ('latin1', u'ä'.encode('iso-8859-1'))):
242
                ('latin1', 1, u'ä'),
243
            (None, 'ascii', ('latin1', u'a'.encode('ascii'))):
244
                ('latin1', 1, u'a'),
245
            # + @charset
246
            (None, 'ascii', ('latin1', u'@charset "ascii";'.encode())):
247
                ('latin1', 1, u'@charset "latin1";'),
248
            (None, 'ascii', ('latin1', u'@charset "utf-8";ä'.encode('latin1'))):
249
                ('latin1', 1, u'@charset "latin1";ä'),
250
            (None, 'ascii', ('latin1', u'@charset "utf-8";ä'.encode('utf-8'))):
251
                ('latin1', 1, u'@charset "latin1";\xc3\xa4'), # read as latin1!
252

    
253

    
254
            # ===== 2. @charset WINS =====
255
            (None, 'ascii', (None, u'@charset "latin1";'.encode())):
256
                ('latin1', 2, u'@charset "latin1";'),
257
            (None, 'ascii', (None, u'@charset "latin1";ä'.encode('latin1'))):
258
                ('latin1', 2, u'@charset "latin1";ä'),
259
            (None, 'ascii', (None, u'@charset "latin1";ä'.encode('utf-8'))):
260
                ('latin1', 2, u'@charset "latin1";\xc3\xa4'), # read as latin1!
261

    
262
            # ===== 2. BOM WINS =====
263
            (None, 'ascii', (None, u'ä'.encode('utf-8-sig'))):
264
                ('utf-8-sig', 2, u'\xe4'), # read as latin1!
265
            (None, 'ascii', (None, u'@charset "utf-8";ä'.encode('utf-8-sig'))):
266
                ('utf-8-sig', 2, u'@charset "utf-8";\xe4'), # read as latin1!
267
            (None, 'ascii', (None, u'@charset "latin1";ä'.encode('utf-8-sig'))):
268
                ('utf-8-sig', 2, u'@charset "utf-8";\xe4'), # read as latin1!
269

    
270

    
271
            # ===== 4. parentEncoding WINS =====
272
            (None, 'latin1', (None, u''.encode())): ('latin1', 4, u''),
273
            (None, 'latin1', (None, u'123'.encode())): ('latin1', 4, u'123'),
274
            (None, 'latin1', (None, u'ä'.encode('iso-8859-1'))):
275
                ('latin1', 4, u'ä'),
276
            (None, 'latin1', (None, u'a'.encode('ascii'))):
277
                ('latin1', 4, u'a'),
278
            (None, 'latin1', (None, u'ä'.encode('utf-8'))):
279
                ('latin1', 4, u'\xc3\xa4'), # read as latin1!
280

    
281
            # ===== 5. default WINS which in this case is None! =====
282
            (None, None, (None, u''.encode())): ('utf-8', 5, u''),
283
            (None, None, (None, u'123'.encode())): ('utf-8', 5, u'123'),
284
            (None, None, (None, u'a'.encode('ascii'))):
285
                ('utf-8', 5, u'a'),
286
            (None, None, (None, u'ä'.encode('utf-8'))):
287
                ('utf-8', 5, u'ä'), # read as utf-8
288
            (None, None, (None, u'ä'.encode('iso-8859-1'))): # trigger UnicodeDecodeError!
289
                ('utf-8', 5, None),
290

    
291

    
292
        }
293
        for (override, parent, r), exp in tests.items():
294
            self.assertEqual(_readUrl(url,
295
                                       overrideEncoding=override,
296
                                       parentEncoding=parent,
297
                                       fetcher=make_fetcher(r)),
298
                              exp)
299

    
300
    def test_defaultFetcher(self):
301
        """util._defaultFetcher"""
302
        if mock:
303

    
304
            class Response(object):
305
                """urllib2.Reponse mock"""
306
                def __init__(self, url,
307
                             contenttype, content,
308
                             exception=None, args=None):
309
                    self.url = url
310

    
311
                    mt, params = cgi.parse_header(contenttype)
312
                    self.mimetype = mt
313
                    self.charset = params.get('charset', None)
314

    
315
                    self.text = content
316

    
317
                    self.exception = exception
318
                    self.args = args
319

    
320
                def geturl(self):
321
                    return self.url
322

    
323
                def info(self):
324
                    mimetype, charset = self.mimetype, self.charset
325
                    class Info(object):
326
                        
327
                        # py2x
328
                        def gettype(self):
329
                            return mimetype
330
                        def getparam(self, name=None):
331
                            return charset
332
                        
333
                        # py 3x
334
                        get_content_type = gettype
335
                        get_content_charset = getparam # here always charset!  
336
                        
337
                    return Info()
338

    
339
                def read(self):
340
                    # returns fake text or raises fake exception
341
                    if not self.exception:
342
                        return self.text
343
                    else:
344
                        raise self.exception(*self.args)
345

    
346
            def urlopen(url,
347
                        contenttype=None, content=None,
348
                        exception=None, args=None):
349
                # return an mock which returns parameterized Response
350
                def x(*ignored):
351
                    if exception:
352
                        raise exception(*args)
353
                    else:
354
                        return Response(url,
355
                                        contenttype, content,
356
                                        exception=exception, args=args)
357
                return x
358

    
359
            urlopenpatch = 'urllib2.urlopen' if basetest.PY2x else 'urllib.request.urlopen' 
360

    
361
            # positive tests
362
            tests = {
363
                # content-type, contentstr: encoding, contentstr
364
                ('text/css', u''.encode('utf-8')):
365
                        (None, u''.encode('utf-8')),
366
                ('text/css;charset=utf-8', u''.encode('utf-8')):
367
                        ('utf-8', u''.encode('utf-8')),
368
                ('text/css;charset=ascii', 'a'):
369
                        ('ascii', 'a')
370
            }
371
            url = 'http://example.com/test.css'
372
            for (contenttype, content), exp in tests.items():
373
                @mock.patch(urlopenpatch, new=urlopen(url, contenttype, content))
374
                def do(url):
375
                    return _defaultFetcher(url)
376
                
377
                self.assertEqual(exp, do(url))
378

    
379
            # wrong mimetype
380
            @mock.patch(urlopenpatch, new=urlopen(url, 'text/html', 'a'))
381
            def do(url):
382
                return _defaultFetcher(url)
383
            
384
            self.assertRaises(ValueError, do, url)
385
            
386
            # calling url results in fake exception
387
                            
388
            # py2 ~= py3 raises error earlier than urlopen!
389
            tests = {
390
                '1': (ValueError, ['invalid value for url']),
391
                #_readUrl('mailto:a.css')
392
                'mailto:e4': (urllib2.URLError, ['urlerror']),
393
                # cannot resolve x, IOError
394
                'http://x': (urllib2.URLError, ['ioerror']),
395
            }
396
            for url, (exception, args) in tests.items():
397
                @mock.patch(urlopenpatch, new=urlopen(url, exception=exception, args=args))
398
                def do(url):
399
                    return _defaultFetcher(url)
400
                
401
                self.assertRaises(exception, do, url)
402

    
403
            # py2 != py3 raises error earlier than urlopen!
404
            urlrequestpatch = 'urllib2.urlopen' if basetest.PY2x else 'urllib.request.Request' 
405
            tests = {
406
                #_readUrl('http://cthedot.de/__UNKNOWN__.css')
407
                'e2': (urllib2.HTTPError, ['u', 500, 'server error', {}, None]),
408
                'e3': (urllib2.HTTPError, ['u', 404, 'not found', {}, None]),
409
            }
410
            for url, (exception, args) in tests.items():
411
                @mock.patch(urlrequestpatch, new=urlopen(url, exception=exception, args=args))
412
                def do(url):
413
                    return _defaultFetcher(url)
414
                
415
                self.assertRaises(exception, do, url)
416

    
417
        else:
418
            self.assertEqual(False, u'Mock needed for this test')
419

    
420
if __name__ == '__main__':
421
    import unittest
422
    unittest.main()