~ubuntu-branches/ubuntu/utopic/python-docutils/utopic

« back to all changes in this revision

Viewing changes to .pc/fix_element_test.diff/test/test_nodes.py

  • Committer: Package Import Robot
  • Author(s): Martin Pitt
  • Date: 2013-12-20 10:24:09 UTC
  • Revision ID: package-import@ubuntu.com-20131220102409-ljkm3vtu2qu4kiey
Tags: 0.11-2ubuntu1
Add fix_element_test.diff: Since Python 3.3.3, 2to3 changes our already
existing Python3 specific test for the "dot" (•) symbol to a double-slash
like in the Python 2 version, breaking the test. Use the actual Unicode
symbol to prevent 2to3 from doing that, instead of \u2022.
(Closes: #732679)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#! /usr/bin/env python
 
2
# -*- coding: utf-8 -*-
 
3
 
 
4
# $Id: test_nodes.py 7595 2013-01-21 17:33:56Z milde $
 
5
# Author: David Goodger <goodger@python.org>
 
6
# Copyright: This module has been placed in the public domain.
 
7
 
 
8
"""
 
9
Test module for nodes.py.
 
10
"""
 
11
 
 
12
import sys
 
13
import unittest
 
14
import types
 
15
import DocutilsTestSupport              # must be imported before docutils
 
16
from DocutilsTestSupport import nodes, utils
 
17
from docutils._compat import b
 
18
 
 
19
debug = False
 
20
 
 
21
 
 
22
class TextTests(unittest.TestCase):
 
23
 
 
24
    def setUp(self):
 
25
        self.text = nodes.Text('Line 1.\nLine 2.')
 
26
        self.unicode_text = nodes.Text(u'Möhren')
 
27
        self.longtext = nodes.Text('Mary had a little lamb whose '
 
28
                                   'fleece was white as snow and '
 
29
                                   'everwhere that Mary went the '
 
30
                                   'lamb was sure to go.')
 
31
 
 
32
    def test_repr(self):
 
33
        self.assertEqual(repr(self.text), r"<#text: 'Line 1.\nLine 2.'>")
 
34
        self.assertEqual(self.text.shortrepr(),
 
35
                          r"<#text: 'Line 1.\nLine 2.'>")
 
36
        self.assertEqual(nodes.reprunicode('foo'), u'foo')
 
37
        if sys.version_info < (3,):
 
38
            self.assertEqual(repr(self.unicode_text), r"<#text: 'M\xf6hren'>")
 
39
        else:
 
40
            self.assertEqual(repr(self.unicode_text), u"<#text: 'Möhren'>")
 
41
 
 
42
    def test_str(self):
 
43
        self.assertEqual(str(self.text), 'Line 1.\nLine 2.')
 
44
 
 
45
    def test_unicode(self):
 
46
        self.assertEqual(unicode(self.unicode_text), u'Möhren')
 
47
        self.assertEqual(str(self.unicode_text), 'M\xf6hren')
 
48
 
 
49
    def test_astext(self):
 
50
        self.assertTrue(isinstance(self.text.astext(), unicode))
 
51
        self.assertEqual(self.text.astext(), u'Line 1.\nLine 2.')
 
52
        self.assertEqual(self.unicode_text.astext(), u'Möhren')
 
53
 
 
54
    def test_pformat(self):
 
55
        self.assertTrue(isinstance(self.text.pformat(), unicode))
 
56
        self.assertEqual(self.text.pformat(), u'Line 1.\nLine 2.\n')
 
57
 
 
58
    def test_asciirestriction(self):
 
59
        if sys.version_info < (3,):
 
60
            self.assertRaises(UnicodeDecodeError, nodes.Text,
 
61
                              b('hol%s' % chr(224)))
 
62
        else:
 
63
            # no bytes at all allowed
 
64
            self.assertRaises(TypeError, nodes.Text, b('hol'))
 
65
 
 
66
    def test_longrepr(self):
 
67
        self.assertEqual(repr(self.longtext), r"<#text: 'Mary had a "
 
68
                          r"little lamb whose fleece was white as snow "
 
69
                          r"and everwh ...'>")
 
70
        self.assertEqual(self.longtext.shortrepr(),
 
71
                          r"<#text: 'Mary had a lit ...'>")
 
72
 
 
73
class ElementTests(unittest.TestCase):
 
74
 
 
75
    def test_empty(self):
 
76
        element = nodes.Element()
 
77
        self.assertEqual(repr(element), '<Element: >')
 
78
        self.assertEqual(str(element), '<Element/>')
 
79
        dom = element.asdom()
 
80
        self.assertEqual(dom.toxml(), '<Element/>')
 
81
        dom.unlink()
 
82
        element['attr'] = '1'
 
83
        self.assertEqual(repr(element), '<Element: >')
 
84
        self.assertEqual(str(element), '<Element attr="1"/>')
 
85
        dom = element.asdom()
 
86
        self.assertEqual(dom.toxml(), '<Element attr="1"/>')
 
87
        dom.unlink()
 
88
        self.assertEqual(element.pformat(), '<Element attr="1">\n')
 
89
        del element['attr']
 
90
        element['mark'] = u'\u2022'
 
91
        self.assertEqual(repr(element), '<Element: >')
 
92
        if sys.version_info < (3,):
 
93
            self.assertEqual(str(element), '<Element mark="\\u2022"/>')
 
94
        else:
 
95
            self.assertEqual(str(element), '<Element mark="\u2022"/>')
 
96
        dom = element.asdom()
 
97
        self.assertEqual(dom.toxml(), u'<Element mark="\u2022"/>')
 
98
        dom.unlink()
 
99
        element['names'] = ['nobody', u'имя', u'näs']
 
100
        if sys.version_info < (3,):
 
101
            self.assertEqual(repr(element),
 
102
                '<Element "nobody; \\u0438\\u043c\\u044f; n\\xe4s": >')
 
103
        else:
 
104
            self.assertEqual(repr(element), u'<Element "nobody; имя; näs": >')
 
105
        self.assertTrue(isinstance(repr(element), str))
 
106
 
 
107
    def test_withtext(self):
 
108
        element = nodes.Element('text\nmore', nodes.Text('text\nmore'))
 
109
        uelement = nodes.Element(u'grün', nodes.Text(u'grün'))
 
110
        self.assertEqual(repr(element), r"<Element: <#text: 'text\nmore'>>")
 
111
        if sys.version_info < (3,):
 
112
            self.assertEqual(repr(uelement), "<Element: <#text: 'gr\\xfcn'>>")
 
113
        else:
 
114
            self.assertEqual(repr(uelement), u"<Element: <#text: 'grün'>>")
 
115
        self.assertTrue(isinstance(repr(uelement),str))
 
116
        self.assertEqual(str(element), '<Element>text\nmore</Element>')
 
117
        self.assertEqual(str(uelement), '<Element>gr\xfcn</Element>')
 
118
        dom = element.asdom()
 
119
        self.assertEqual(dom.toxml(), '<Element>text\nmore</Element>')
 
120
        dom.unlink()
 
121
        element['attr'] = '1'
 
122
        self.assertEqual(repr(element), r"<Element: <#text: 'text\nmore'>>")
 
123
        self.assertEqual(str(element),
 
124
                          '<Element attr="1">text\nmore</Element>')
 
125
        dom = element.asdom()
 
126
        self.assertEqual(dom.toxml(),
 
127
                          '<Element attr="1">text\nmore</Element>')
 
128
        dom.unlink()
 
129
        self.assertEqual(element.pformat(),
 
130
                          '<Element attr="1">\n    text\n    more\n')
 
131
 
 
132
    def test_clear(self):
 
133
        element = nodes.Element()
 
134
        element += nodes.Element()
 
135
        self.assertTrue(len(element))
 
136
        element.clear()
 
137
        self.assertTrue(not len(element))
 
138
 
 
139
    def test_normal_attributes(self):
 
140
        element = nodes.Element()
 
141
        self.assertTrue('foo' not in element)
 
142
        self.assertRaises(KeyError, element.__getitem__, 'foo')
 
143
        element['foo'] = 'sometext'
 
144
        self.assertEqual(element['foo'], 'sometext')
 
145
        del element['foo']
 
146
        self.assertRaises(KeyError, element.__getitem__, 'foo')
 
147
 
 
148
    def test_default_attributes(self):
 
149
        element = nodes.Element()
 
150
        self.assertEqual(element['ids'], [])
 
151
        self.assertEqual(element.non_default_attributes(), {})
 
152
        self.assertTrue(not element.is_not_default('ids'))
 
153
        self.assertTrue(element['ids'] is not nodes.Element()['ids'])
 
154
        element['ids'].append('someid')
 
155
        self.assertEqual(element['ids'], ['someid'])
 
156
        self.assertEqual(element.non_default_attributes(),
 
157
                          {'ids': ['someid']})
 
158
        self.assertTrue(element.is_not_default('ids'))
 
159
 
 
160
    def test_update_basic_atts(self):
 
161
        element1 = nodes.Element(ids=['foo', 'bar'], test=['test1'])
 
162
        element2 = nodes.Element(ids=['baz', 'qux'], test=['test2'])
 
163
        element1.update_basic_atts(element2)
 
164
        # 'ids' are appended because 'ids' is a basic attribute.
 
165
        self.assertEqual(element1['ids'], ['foo', 'bar', 'baz', 'qux'])
 
166
        # 'test' is not overwritten because it is not a basic attribute.
 
167
        self.assertEqual(element1['test'], ['test1'])
 
168
 
 
169
    def test_update_all_atts(self):
 
170
        # Note: Also tests is_not_list_attribute and is_not_known_attribute
 
171
        # and various helpers
 
172
        ## Test for full attribute replacement
 
173
        element1 = nodes.Element(ids=['foo', 'bar'], parent_only='parent',
 
174
                                 all_nodes='mom')
 
175
        element2 = nodes.Element(ids=['baz', 'qux'], child_only='child',
 
176
                                 all_nodes='dad', source='source')
 
177
 
 
178
        # Test for when same fields are replaced as well as source...
 
179
        element1.update_all_atts_consistantly(element2, True, True)
 
180
        # 'ids' are appended because 'ids' is a basic attribute.
 
181
        self.assertEquals(element1['ids'], ['foo', 'bar', 'baz', 'qux'])
 
182
        # 'parent_only' should remain unaffected.
 
183
        self.assertEquals(element1['parent_only'], 'parent')
 
184
        # 'all_nodes' is overwritten due to the second parameter == True.
 
185
        self.assertEquals(element1['all_nodes'], 'dad')
 
186
        # 'child_only' should have been added.
 
187
        self.assertEquals(element1['child_only'], 'child')
 
188
        # 'source' is also overwritten due to the third parameter == True.
 
189
        self.assertEquals(element1['source'], 'source')
 
190
 
 
191
        # Test for when same fields are replaced but not source...
 
192
        element1 = nodes.Element(ids=['foo', 'bar'], parent_only='parent',
 
193
                                 all_nodes='mom')
 
194
        element1.update_all_atts_consistantly(element2)
 
195
        # 'ids' are appended because 'ids' is a basic attribute.
 
196
        self.assertEquals(element1['ids'], ['foo', 'bar', 'baz', 'qux'])
 
197
        # 'parent_only' should remain unaffected.
 
198
        self.assertEquals(element1['parent_only'], 'parent')
 
199
        # 'all_nodes' is overwritten due to the second parameter default of True.
 
200
        self.assertEquals(element1['all_nodes'], 'dad')
 
201
        # 'child_only' should have been added.
 
202
        self.assertEquals(element1['child_only'], 'child')
 
203
        # 'source' remains unset due to the third parameter default of False.
 
204
        self.assertEquals(element1.get('source'), None)
 
205
 
 
206
        # Test for when fields are NOT replaced but source is...
 
207
        element1 = nodes.Element(ids=['foo', 'bar'], parent_only='parent',
 
208
                                 all_nodes='mom')
 
209
        element1.update_all_atts_consistantly(element2, False, True)
 
210
        # 'ids' are appended because 'ids' is a basic attribute.
 
211
        self.assertEquals(element1['ids'], ['foo', 'bar', 'baz', 'qux'])
 
212
        # 'parent_only' should remain unaffected.
 
213
        self.assertEquals(element1['parent_only'], 'parent')
 
214
        # 'all_nodes' is preserved due to the second parameter == False.
 
215
        self.assertEquals(element1['all_nodes'], 'mom')
 
216
        # 'child_only' should have been added.
 
217
        self.assertEquals(element1['child_only'], 'child')
 
218
        # 'source' is added due to the third parameter == True.
 
219
        self.assertEquals(element1['source'], 'source')
 
220
        element1 = nodes.Element(source='destination')
 
221
        element1.update_all_atts_consistantly(element2, False, True)
 
222
        # 'source' remains unchanged due to the second parameter == False.
 
223
        self.assertEquals(element1['source'], 'destination')
 
224
 
 
225
        # Test for when same fields are replaced but not source...
 
226
        element1 = nodes.Element(ids=['foo', 'bar'], parent_only='parent',
 
227
                                 all_nodes='mom')
 
228
        element1.update_all_atts_consistantly(element2, False)
 
229
        # 'ids' are appended because 'ids' is a basic attribute.
 
230
        self.assertEquals(element1['ids'], ['foo', 'bar', 'baz', 'qux'])
 
231
        # 'parent_only' should remain unaffected.
 
232
        self.assertEquals(element1['parent_only'], 'parent')
 
233
        # 'all_nodes' is preserved due to the second parameter == False.
 
234
        self.assertEquals(element1['all_nodes'], 'mom')
 
235
        # 'child_only' should have been added.
 
236
        self.assertEquals(element1['child_only'], 'child')
 
237
        # 'source' remains unset due to the third parameter default of False.
 
238
        self.assertEquals(element1.get('source'), None)
 
239
 
 
240
        ## Test for List attribute merging
 
241
        # Attribute Concatination
 
242
        element1 = nodes.Element(ss='a', sl='1', ls=['I'], ll=['A'])
 
243
        element2 = nodes.Element(ss='b', sl=['2'], ls='II', ll=['B'])
 
244
        element1.update_all_atts_concatenating(element2)
 
245
        # 'ss' is replaced because non-list
 
246
        self.assertEquals(element1['ss'], 'b')
 
247
        # 'sl' is replaced because they are both not lists
 
248
        self.assertEquals(element1['sl'], ['2'])
 
249
        # 'ls' is replaced because they are both not lists
 
250
        self.assertEquals(element1['ls'], 'II')
 
251
        # 'll' is extended because they are both lists
 
252
        self.assertEquals(element1['ll'], ['A', 'B'])
 
253
 
 
254
        # Attribute Coercion
 
255
        element1 = nodes.Element(ss='a', sl='1', ls=['I'], ll=['A'])
 
256
        element2 = nodes.Element(ss='b', sl=['2'], ls='II', ll=['B'])
 
257
        element1.update_all_atts_coercion(element2)
 
258
        # 'ss' is replaced because non-list
 
259
        self.assertEquals(element1['ss'], 'b')
 
260
        # 'sl' is converted to a list and appended because element2 has a list
 
261
        self.assertEquals(element1['sl'], ['1', '2'])
 
262
        # 'ls' has element2's value appended to the list
 
263
        self.assertEquals(element1['ls'], ['I', 'II'])
 
264
        # 'll' is extended because they are both lists
 
265
        self.assertEquals(element1['ll'], ['A', 'B'])
 
266
 
 
267
        # Attribute Conversion
 
268
        element1 = nodes.Element(ss='a', sl='1', ls=['I'], ll=['A'])
 
269
        element2 = nodes.Element(ss='b', sl=['2'], ls='II', ll=['B'])
 
270
        element1.update_all_atts_convert(element2)
 
271
        # 'ss' is converted to a list with the values from each element
 
272
        self.assertEquals(element1['ss'], ['a', 'b'])
 
273
        # 'sl' is converted to a list and appended
 
274
        self.assertEquals(element1['sl'], ['1', '2'])
 
275
        # 'ls' has element2's value appended to the list
 
276
        self.assertEquals(element1['ls'], ['I', 'II'])
 
277
        # 'll' is extended
 
278
        self.assertEquals(element1['ll'], ['A', 'B'])
 
279
 
 
280
    def test_replace_self(self):
 
281
        parent = nodes.Element(ids=['parent'])
 
282
        child1 = nodes.Element(ids=['child1'])
 
283
        grandchild = nodes.Element(ids=['grandchild'])
 
284
        child1 += grandchild
 
285
        child2 = nodes.Element(ids=['child2'])
 
286
        twins = [nodes.Element(ids=['twin%s' % i]) for i in (1, 2)]
 
287
        child2 += twins
 
288
        child3 = nodes.Element(ids=['child3'])
 
289
        child4 = nodes.Element(ids=['child4'])
 
290
        parent += [child1, child2, child3, child4]
 
291
        self.assertEqual(parent.pformat(), """\
 
292
<Element ids="parent">
 
293
    <Element ids="child1">
 
294
        <Element ids="grandchild">
 
295
    <Element ids="child2">
 
296
        <Element ids="twin1">
 
297
        <Element ids="twin2">
 
298
    <Element ids="child3">
 
299
    <Element ids="child4">
 
300
""")
 
301
        # Replace child1 with the grandchild.
 
302
        child1.replace_self(child1[0])
 
303
        self.assertEqual(parent[0], grandchild)
 
304
        # Assert that 'ids' have been updated.
 
305
        self.assertEqual(grandchild['ids'], ['grandchild', 'child1'])
 
306
        # Replace child2 with its children.
 
307
        child2.replace_self(child2[:])
 
308
        self.assertEqual(parent[1:3], twins)
 
309
        # Assert that 'ids' have been propagated to first child.
 
310
        self.assertEqual(twins[0]['ids'], ['twin1', 'child2'])
 
311
        self.assertEqual(twins[1]['ids'], ['twin2'])
 
312
        # Replace child3 with new child.
 
313
        newchild = nodes.Element(ids=['newchild'])
 
314
        child3.replace_self(newchild)
 
315
        self.assertEqual(parent[3], newchild)
 
316
        self.assertEqual(newchild['ids'], ['newchild', 'child3'])
 
317
        # Crazy but possible case: Substitute child4 for itself.
 
318
        child4.replace_self(child4)
 
319
        # Make sure the 'child4' ID hasn't been duplicated.
 
320
        self.assertEqual(child4['ids'], ['child4'])
 
321
        self.assertEqual(len(parent), 5)
 
322
 
 
323
    def test_unicode(self):
 
324
        node = nodes.Element(u'Möhren', nodes.Text(u'Möhren', u'Möhren'))
 
325
        self.assertEqual(unicode(node), u'<Element>Möhren</Element>')
 
326
 
 
327
 
 
328
class MiscTests(unittest.TestCase):
 
329
 
 
330
    def test_reprunicode(self):
 
331
        # return `unicode` instance
 
332
        self.assertTrue(isinstance(nodes.reprunicode('foo'), unicode))
 
333
        self.assertEqual(nodes.reprunicode('foo'), u'foo')
 
334
        self.assertEqual(nodes.reprunicode(u'Möhre'), u'Möhre')
 
335
        if sys.version_info < (3,): # strip leading "u" from representation
 
336
            self.assertEqual(repr(nodes.reprunicode(u'Möhre')),
 
337
                             repr(u'Möhre')[1:])
 
338
        else: # no change to `unicode` under Python 3k
 
339
            self.assertEqual(repr(nodes.reprunicode(u'Möhre')), repr(u'Möhre'))
 
340
 
 
341
    def test_ensure_str(self):
 
342
        self.assertTrue(isinstance(nodes.ensure_str(u'über'), str))
 
343
        self.assertEqual(nodes.ensure_str('over'), 'over')
 
344
        if sys.version_info < (3,): # strip leading "u" from representation
 
345
            self.assertEqual(nodes.ensure_str(u'über'), r'\xfcber')
 
346
        else:
 
347
            self.assertEqual(nodes.ensure_str(u'über'), r'über')
 
348
 
 
349
    def test_node_class_names(self):
 
350
        node_class_names = []
 
351
        for x in dir(nodes):
 
352
            c = getattr(nodes, x)
 
353
            if isinstance(c, (type, types.ClassType)) and \
 
354
                   issubclass(c, nodes.Node) and len(c.__bases__) > 1:
 
355
                node_class_names.append(x)
 
356
        node_class_names.sort()
 
357
        nodes.node_class_names.sort()
 
358
        self.assertEqual(node_class_names, nodes.node_class_names)
 
359
 
 
360
    ids = [(u'a', 'a'), ('A', 'a'), ('', ''), ('a b \n c', 'a-b-c'),
 
361
           ('a.b.c', 'a-b-c'), (' - a - b - c - ', 'a-b-c'), (' - ', ''),
 
362
           (u'\u2020\u2066', ''), (u'a \xa7 b \u2020 c', 'a-b-c'),
 
363
           ('1', ''), ('1abc', 'abc'),
 
364
          ]
 
365
    ids_unicode_all = [
 
366
            (u'\u00f8 o with stroke', 'o-o-with-stroke'),
 
367
            (u'\u0111 d with stroke', 'd-d-with-stroke'),
 
368
            (u'\u0127 h with stroke', 'h-h-with-stroke'),
 
369
            (u'\u0131 dotless i', 'i-dotless-i'),
 
370
            (u'\u0142 l with stroke', 'l-l-with-stroke'),
 
371
            (u'\u0167 t with stroke', 't-t-with-stroke'),
 
372
           # From Latin Extended-B
 
373
            (u'\u0180 b with stroke', 'b-b-with-stroke'),
 
374
            (u'\u0183 b with topbar', 'b-b-with-topbar'),
 
375
            (u'\u0188 c with hook', 'c-c-with-hook'),
 
376
            (u'\u018c d with topbar', 'd-d-with-topbar'),
 
377
            (u'\u0192 f with hook', 'f-f-with-hook'),
 
378
            (u'\u0199 k with hook', 'k-k-with-hook'),
 
379
            (u'\u019a l with bar', 'l-l-with-bar'),
 
380
            (u'\u019e n with long right leg', 'n-n-with-long-right-leg'),
 
381
            (u'\u01a5 p with hook', 'p-p-with-hook'),
 
382
            (u'\u01ab t with palatal hook', 't-t-with-palatal-hook'),
 
383
            (u'\u01ad t with hook', 't-t-with-hook'),
 
384
            (u'\u01b4 y with hook', 'y-y-with-hook'),
 
385
            (u'\u01b6 z with stroke', 'z-z-with-stroke'),
 
386
            (u'\u01e5 g with stroke', 'g-g-with-stroke'),
 
387
            (u'\u0225 z with hook', 'z-z-with-hook'),
 
388
            (u'\u0234 l with curl', 'l-l-with-curl'),
 
389
            (u'\u0235 n with curl', 'n-n-with-curl'),
 
390
            (u'\u0236 t with curl', 't-t-with-curl'),
 
391
            (u'\u0237 dotless j', 'j-dotless-j'),
 
392
            (u'\u023c c with stroke', 'c-c-with-stroke'),
 
393
            (u'\u023f s with swash tail', 's-s-with-swash-tail'),
 
394
            (u'\u0240 z with swash tail', 'z-z-with-swash-tail'),
 
395
            (u'\u0247 e with stroke', 'e-e-with-stroke'),
 
396
            (u'\u0249 j with stroke', 'j-j-with-stroke'),
 
397
            (u'\u024b q with hook tail', 'q-q-with-hook-tail'),
 
398
            (u'\u024d r with stroke', 'r-r-with-stroke'),
 
399
            (u'\u024f y with stroke', 'y-y-with-stroke'),
 
400
           # From Latin-1 Supplements
 
401
            (u'\u00e0: a with grave', 'a-a-with-grave'),
 
402
            (u'\u00e1 a with acute', 'a-a-with-acute'),
 
403
            (u'\u00e2 a with circumflex', 'a-a-with-circumflex'),
 
404
            (u'\u00e3 a with tilde', 'a-a-with-tilde'),
 
405
            (u'\u00e4 a with diaeresis', 'a-a-with-diaeresis'),
 
406
            (u'\u00e5 a with ring above', 'a-a-with-ring-above'),
 
407
            (u'\u00e7 c with cedilla', 'c-c-with-cedilla'),
 
408
            (u'\u00e8 e with grave', 'e-e-with-grave'),
 
409
            (u'\u00e9 e with acute', 'e-e-with-acute'),
 
410
            (u'\u00ea e with circumflex', 'e-e-with-circumflex'),
 
411
            (u'\u00eb e with diaeresis', 'e-e-with-diaeresis'),
 
412
            (u'\u00ec i with grave', 'i-i-with-grave'),
 
413
            (u'\u00ed i with acute', 'i-i-with-acute'),
 
414
            (u'\u00ee i with circumflex', 'i-i-with-circumflex'),
 
415
            (u'\u00ef i with diaeresis', 'i-i-with-diaeresis'),
 
416
            (u'\u00f1 n with tilde', 'n-n-with-tilde'),
 
417
            (u'\u00f2 o with grave', 'o-o-with-grave'),
 
418
            (u'\u00f3 o with acute', 'o-o-with-acute'),
 
419
            (u'\u00f4 o with circumflex', 'o-o-with-circumflex'),
 
420
            (u'\u00f5 o with tilde', 'o-o-with-tilde'),
 
421
            (u'\u00f6 o with diaeresis', 'o-o-with-diaeresis'),
 
422
            (u'\u00f9 u with grave', 'u-u-with-grave'),
 
423
            (u'\u00fa u with acute', 'u-u-with-acute'),
 
424
            (u'\u00fb u with circumflex', 'u-u-with-circumflex'),
 
425
            (u'\u00fc u with diaeresis', 'u-u-with-diaeresis'),
 
426
            (u'\u00fd y with acute', 'y-y-with-acute'),
 
427
            (u'\u00ff y with diaeresis', 'y-y-with-diaeresis'),
 
428
           # From Latin Extended-A
 
429
            (u'\u0101 a with macron', 'a-a-with-macron'),
 
430
            (u'\u0103 a with breve', 'a-a-with-breve'),
 
431
            (u'\u0105 a with ogonek', 'a-a-with-ogonek'),
 
432
            (u'\u0107 c with acute', 'c-c-with-acute'),
 
433
            (u'\u0109 c with circumflex', 'c-c-with-circumflex'),
 
434
            (u'\u010b c with dot above', 'c-c-with-dot-above'),
 
435
            (u'\u010d c with caron', 'c-c-with-caron'),
 
436
            (u'\u010f d with caron', 'd-d-with-caron'),
 
437
            (u'\u0113 e with macron', 'e-e-with-macron'),
 
438
            (u'\u0115 e with breve', 'e-e-with-breve'),
 
439
            (u'\u0117 e with dot above', 'e-e-with-dot-above'),
 
440
            (u'\u0119 e with ogonek', 'e-e-with-ogonek'),
 
441
            (u'\u011b e with caron', 'e-e-with-caron'),
 
442
            (u'\u011d g with circumflex', 'g-g-with-circumflex'),
 
443
            (u'\u011f g with breve', 'g-g-with-breve'),
 
444
            (u'\u0121 g with dot above', 'g-g-with-dot-above'),
 
445
            (u'\u0123 g with cedilla', 'g-g-with-cedilla'),
 
446
            (u'\u0125 h with circumflex', 'h-h-with-circumflex'),
 
447
            (u'\u0129 i with tilde', 'i-i-with-tilde'),
 
448
            (u'\u012b i with macron', 'i-i-with-macron'),
 
449
            (u'\u012d i with breve', 'i-i-with-breve'),
 
450
            (u'\u012f i with ogonek', 'i-i-with-ogonek'),
 
451
            (u'\u0133 ligature ij', 'ij-ligature-ij'),
 
452
            (u'\u0135 j with circumflex', 'j-j-with-circumflex'),
 
453
            (u'\u0137 k with cedilla', 'k-k-with-cedilla'),
 
454
            (u'\u013a l with acute', 'l-l-with-acute'),
 
455
            (u'\u013c l with cedilla', 'l-l-with-cedilla'),
 
456
            (u'\u013e l with caron', 'l-l-with-caron'),
 
457
            (u'\u0140 l with middle dot', 'l-l-with-middle-dot'),
 
458
            (u'\u0144 n with acute', 'n-n-with-acute'),
 
459
            (u'\u0146 n with cedilla', 'n-n-with-cedilla'),
 
460
            (u'\u0148 n with caron', 'n-n-with-caron'),
 
461
            (u'\u014d o with macron', 'o-o-with-macron'),
 
462
            (u'\u014f o with breve', 'o-o-with-breve'),
 
463
            (u'\u0151 o with double acute', 'o-o-with-double-acute'),
 
464
            (u'\u0155 r with acute', 'r-r-with-acute'),
 
465
            (u'\u0157 r with cedilla', 'r-r-with-cedilla'),
 
466
            (u'\u0159 r with caron', 'r-r-with-caron'),
 
467
            (u'\u015b s with acute', 's-s-with-acute'),
 
468
            (u'\u015d s with circumflex', 's-s-with-circumflex'),
 
469
            (u'\u015f s with cedilla', 's-s-with-cedilla'),
 
470
            (u'\u0161 s with caron', 's-s-with-caron'),
 
471
            (u'\u0163 t with cedilla', 't-t-with-cedilla'),
 
472
            (u'\u0165 t with caron', 't-t-with-caron'),
 
473
            (u'\u0169 u with tilde', 'u-u-with-tilde'),
 
474
            (u'\u016b u with macron', 'u-u-with-macron'),
 
475
            (u'\u016d u with breve', 'u-u-with-breve'),
 
476
            (u'\u016f u with ring above', 'u-u-with-ring-above'),
 
477
            (u'\u0171 u with double acute', 'u-u-with-double-acute'),
 
478
            (u'\u0173 u with ogonek', 'u-u-with-ogonek'),
 
479
            (u'\u0175 w with circumflex', 'w-w-with-circumflex'),
 
480
            (u'\u0177 y with circumflex', 'y-y-with-circumflex'),
 
481
            (u'\u017a z with acute', 'z-z-with-acute'),
 
482
            (u'\u017c z with dot above', 'z-z-with-dot-above'),
 
483
            (u'\u017e z with caron', 'z-z-with-caron'),
 
484
           # From Latin Extended-B
 
485
            (u'\u01a1 o with horn', 'o-o-with-horn'),
 
486
            (u'\u01b0 u with horn', 'u-u-with-horn'),
 
487
            (u'\u01c6 dz with caron', 'dz-dz-with-caron'),
 
488
            (u'\u01c9 lj', 'lj-lj'),
 
489
            (u'\u01cc nj', 'nj-nj'),
 
490
            (u'\u01ce a with caron', 'a-a-with-caron'),
 
491
            (u'\u01d0 i with caron', 'i-i-with-caron'),
 
492
            (u'\u01d2 o with caron', 'o-o-with-caron'),
 
493
            (u'\u01d4 u with caron', 'u-u-with-caron'),
 
494
            (u'\u01e7 g with caron', 'g-g-with-caron'),
 
495
            (u'\u01e9 k with caron', 'k-k-with-caron'),
 
496
            (u'\u01eb o with ogonek', 'o-o-with-ogonek'),
 
497
            (u'\u01ed o with ogonek and macron', 'o-o-with-ogonek-and-macron'),
 
498
            (u'\u01f0 j with caron', 'j-j-with-caron'),
 
499
            (u'\u01f3 dz', 'dz-dz'),
 
500
            (u'\u01f5 g with acute', 'g-g-with-acute'),
 
501
            (u'\u01f9 n with grave', 'n-n-with-grave'),
 
502
            (u'\u0201 a with double grave', 'a-a-with-double-grave'),
 
503
            (u'\u0203 a with inverted breve', 'a-a-with-inverted-breve'),
 
504
            (u'\u0205 e with double grave', 'e-e-with-double-grave'),
 
505
            (u'\u0207 e with inverted breve', 'e-e-with-inverted-breve'),
 
506
            (u'\u0209 i with double grave', 'i-i-with-double-grave'),
 
507
            (u'\u020b i with inverted breve', 'i-i-with-inverted-breve'),
 
508
            (u'\u020d o with double grave', 'o-o-with-double-grave'),
 
509
            (u'\u020f o with inverted breve', 'o-o-with-inverted-breve'),
 
510
            (u'\u0211 r with double grave', 'r-r-with-double-grave'),
 
511
            (u'\u0213 r with inverted breve', 'r-r-with-inverted-breve'),
 
512
            (u'\u0215 u with double grave', 'u-u-with-double-grave'),
 
513
            (u'\u0217 u with inverted breve', 'u-u-with-inverted-breve'),
 
514
            (u'\u0219 s with comma below', 's-s-with-comma-below'),
 
515
            (u'\u021b t with comma below', 't-t-with-comma-below'),
 
516
            (u'\u021f h with caron', 'h-h-with-caron'),
 
517
            (u'\u0227 a with dot above', 'a-a-with-dot-above'),
 
518
            (u'\u0229 e with cedilla', 'e-e-with-cedilla'),
 
519
            (u'\u022f o with dot above', 'o-o-with-dot-above'),
 
520
            (u'\u0233 y with macron', 'y-y-with-macron'),
 
521
           # digraphs From Latin-1 Supplements
 
522
            (u'\u00df: ligature sz', 'sz-ligature-sz'),
 
523
            (u'\u00e6 ae', 'ae-ae'),
 
524
            (u'\u0153 ligature oe', 'oe-ligature-oe'),
 
525
            (u'\u0238 db digraph', 'db-db-digraph'),
 
526
            (u'\u0239 qp digraph', 'qp-qp-digraph'),
 
527
            ]
 
528
 
 
529
    def test_make_id(self):
 
530
        failures = []
 
531
        tests = self.ids + self.ids_unicode_all
 
532
        for input, expect in tests:
 
533
            output = nodes.make_id(input)
 
534
            if expect != output:
 
535
                failures.append("'%s' != '%s'" % (expect, output))
 
536
        if failures:
 
537
            self.fail("%d failures in %d\n%s" % (len(failures), len(self.ids), "\n".join(failures)))
 
538
 
 
539
    def test_traverse(self):
 
540
        e = nodes.Element()
 
541
        e += nodes.Element()
 
542
        e[0] += nodes.Element()
 
543
        e[0] += nodes.TextElement()
 
544
        e[0][1] += nodes.Text('some text')
 
545
        e += nodes.Element()
 
546
        e += nodes.Element()
 
547
        self.assertEqual(list(e.traverse()),
 
548
                          [e, e[0], e[0][0], e[0][1], e[0][1][0], e[1], e[2]])
 
549
        self.assertEqual(list(e.traverse(include_self=False)),
 
550
                          [e[0], e[0][0], e[0][1], e[0][1][0], e[1], e[2]])
 
551
        self.assertEqual(list(e.traverse(descend=False)),
 
552
                          [e])
 
553
        self.assertEqual(list(e[0].traverse(descend=False, ascend=True)),
 
554
                          [e[0], e[1], e[2]])
 
555
        self.assertEqual(list(e[0][0].traverse(descend=False, ascend=True)),
 
556
                          [e[0][0], e[0][1], e[1], e[2]])
 
557
        self.assertEqual(list(e[0][0].traverse(descend=False, siblings=True)),
 
558
                          [e[0][0], e[0][1]])
 
559
        self.testlist = e[0:2]
 
560
        self.assertEqual(list(e.traverse(condition=self.not_in_testlist)),
 
561
                          [e, e[0][0], e[0][1], e[0][1][0], e[2]])
 
562
        # Return siblings despite siblings=False because ascend is true.
 
563
        self.assertEqual(list(e[1].traverse(ascend=True, siblings=False)),
 
564
                          [e[1], e[2]])
 
565
        self.assertEqual(list(e[0].traverse()),
 
566
                          [e[0], e[0][0], e[0][1], e[0][1][0]])
 
567
        self.testlist = [e[0][0], e[0][1]]
 
568
        self.assertEqual(list(e[0].traverse(condition=self.not_in_testlist)),
 
569
                               [e[0], e[0][1][0]])
 
570
        self.testlist.append(e[0][1][0])
 
571
        self.assertEqual(list(e[0].traverse(condition=self.not_in_testlist)),
 
572
                               [e[0]])
 
573
        self.assertEqual(list(e.traverse(nodes.TextElement)), [e[0][1]])
 
574
 
 
575
    def test_next_node(self):
 
576
        e = nodes.Element()
 
577
        e += nodes.Element()
 
578
        e[0] += nodes.Element()
 
579
        e[0] += nodes.TextElement()
 
580
        e[0][1] += nodes.Text('some text')
 
581
        e += nodes.Element()
 
582
        e += nodes.Element()
 
583
        self.testlist = [e[0], e[0][1], e[1]]
 
584
        compare = [(e, e[0][0]),
 
585
                   (e[0], e[0][0]),
 
586
                   (e[0][0], e[0][1][0]),
 
587
                   (e[0][1], e[0][1][0]),
 
588
                   (e[0][1][0], e[2]),
 
589
                   (e[1], e[2]),
 
590
                   (e[2], None)]
 
591
        for node, next_node in compare:
 
592
            self.assertEqual(node.next_node(self.not_in_testlist, ascend=True),
 
593
                              next_node)
 
594
        self.assertEqual(e[0][0].next_node(ascend=True), e[0][1])
 
595
        self.assertEqual(e[2].next_node(), None)
 
596
 
 
597
    def not_in_testlist(self, x):
 
598
        return x not in self.testlist
 
599
 
 
600
    def test_copy(self):
 
601
        grandchild = nodes.Text('rawsource')
 
602
        child = nodes.emphasis('rawsource', grandchild, att='child')
 
603
        e = nodes.Element('rawsource', child, att='e')
 
604
        # Shallow copy:
 
605
        e_copy = e.copy()
 
606
        self.assertTrue(e is not e_copy)
 
607
        # Internal attributes (like `rawsource`) are also copied.
 
608
        self.assertEqual(e.rawsource, 'rawsource')
 
609
        self.assertEqual(e_copy.rawsource, e.rawsource)
 
610
        self.assertEqual(e_copy['att'], 'e')
 
611
        # Children are not copied.
 
612
        self.assertEqual(len(e_copy), 0)
 
613
        # Deep copy:
 
614
        e_deepcopy = e.deepcopy()
 
615
        self.assertEqual(e_deepcopy.rawsource, e.rawsource)
 
616
        self.assertEqual(e_deepcopy['att'], 'e')
 
617
        # Children are copied recursively.
 
618
        self.assertEqual(e_deepcopy[0][0], grandchild)
 
619
        self.assertTrue(e_deepcopy[0][0] is not grandchild)
 
620
        self.assertEqual(e_deepcopy[0]['att'], 'child')
 
621
 
 
622
 
 
623
class TreeCopyVisitorTests(unittest.TestCase):
 
624
 
 
625
    def setUp(self):
 
626
        document = utils.new_document('test data')
 
627
        document += nodes.paragraph('', 'Paragraph 1.')
 
628
        blist = nodes.bullet_list()
 
629
        for i in range(1, 6):
 
630
            item = nodes.list_item()
 
631
            for j in range(1, 4):
 
632
                item += nodes.paragraph('', 'Item %s, paragraph %s.' % (i, j))
 
633
            blist += item
 
634
        document += blist
 
635
        self.document = document
 
636
 
 
637
    def compare_trees(self, one, two):
 
638
        self.assertEqual(one.__class__, two.__class__)
 
639
        self.assertNotEqual(id(one), id(two))
 
640
        self.assertEqual(len(one.children), len(two.children))
 
641
        for i in range(len(one.children)):
 
642
            self.compare_trees(one.children[i], two.children[i])
 
643
 
 
644
    def test_copy_whole(self):
 
645
        visitor = nodes.TreeCopyVisitor(self.document)
 
646
        self.document.walkabout(visitor)
 
647
        newtree = visitor.get_tree_copy()
 
648
        self.assertEqual(self.document.pformat(), newtree.pformat())
 
649
        self.compare_trees(self.document, newtree)
 
650
 
 
651
 
 
652
class MiscFunctionTests(unittest.TestCase):
 
653
 
 
654
    names = [('a', 'a'), ('A', 'a'), ('A a A', 'a a a'),
 
655
             ('A  a  A  a', 'a a a a'),
 
656
             ('  AaA\n\r\naAa\tAaA\t\t', 'aaa aaa aaa')]
 
657
 
 
658
    def test_normalize_name(self):
 
659
        for input, output in self.names:
 
660
            normed = nodes.fully_normalize_name(input)
 
661
            self.assertEqual(normed, output)
 
662
 
 
663
    def test_set_id_default(self):
 
664
        # Default prefixes.
 
665
        document = utils.new_document('test')
 
666
        # From name.
 
667
        element = nodes.Element(names=['test'])
 
668
        document.set_id(element)
 
669
        self.assertEqual(element['ids'], ['test'])
 
670
        # Auto-generated.
 
671
        element = nodes.Element()
 
672
        document.set_id(element)
 
673
        self.assertEqual(element['ids'], ['id1'])
 
674
 
 
675
    def test_set_id_custom(self):
 
676
        # Custom prefixes.
 
677
        document = utils.new_document('test')
 
678
        # Change settings.
 
679
        document.settings.id_prefix = 'prefix'
 
680
        document.settings.auto_id_prefix = 'auto'
 
681
        # From name.
 
682
        element = nodes.Element(names=['test'])
 
683
        document.set_id(element)
 
684
        self.assertEqual(element['ids'], ['prefixtest'])
 
685
        # Auto-generated.
 
686
        element = nodes.Element()
 
687
        document.set_id(element)
 
688
        self.assertEqual(element['ids'], ['prefixauto1'])
 
689
 
 
690
 
 
691
if __name__ == '__main__':
 
692
    unittest.main()