normalize_language_tag() now returns `BCP 47`_ conformant tags
[docutils.git] / test / test_utils.py
blobdec123ee415515a340b6dc4f6d45da35b64814f3
1 # -*- coding: utf-8 -*-
2 #! /usr/bin/env python
4 # $Id$
5 # Author: David Goodger <goodger@python.org>
6 # Copyright: This module has been placed in the public domain.
8 """
9 Test module for utils/__init__.py.
10 """
12 import unittest
13 import sys
14 import os
15 from DocutilsTestSupport import utils, nodes
16 try:
17 from io import StringIO
18 except ImportError: # io is new in Python 2.6
19 from StringIO import StringIO
22 class ReporterTests(unittest.TestCase):
24 stream = StringIO()
25 reporter = utils.Reporter('test data', 2, 4, stream, 1)
27 def setUp(self):
28 self.stream.seek(0)
29 self.stream.truncate()
31 def test_level0(self):
32 sw = self.reporter.system_message(0, 'debug output')
33 self.assertEqual(sw.pformat(), """\
34 <system_message level="0" source="test data" type="DEBUG">
35 <paragraph>
36 debug output
37 """)
38 self.assertEqual(self.stream.getvalue(),
39 'test data:: (DEBUG/0) debug output\n')
41 def test_level1(self):
42 sw = self.reporter.system_message(1, 'a little reminder')
43 self.assertEqual(sw.pformat(), """\
44 <system_message level="1" source="test data" type="INFO">
45 <paragraph>
46 a little reminder
47 """)
48 self.assertEqual(self.stream.getvalue(), '')
50 def test_level2(self):
51 sw = self.reporter.system_message(2, 'a warning')
52 self.assertEqual(sw.pformat(), """\
53 <system_message level="2" source="test data" type="WARNING">
54 <paragraph>
55 a warning
56 """)
57 self.assertEqual(self.stream.getvalue(),
58 'test data:: (WARNING/2) a warning\n')
60 def test_level3(self):
61 sw = self.reporter.system_message(3, 'an error')
62 self.assertEqual(sw.pformat(), """\
63 <system_message level="3" source="test data" type="ERROR">
64 <paragraph>
65 an error
66 """)
67 self.assertEqual(self.stream.getvalue(),
68 'test data:: (ERROR/3) an error\n')
70 def test_level4(self):
71 self.assertRaises(utils.SystemMessage, self.reporter.system_message, 4,
72 'a severe error, raises an exception')
73 self.assertEqual(self.stream.getvalue(), 'test data:: (SEVERE/4) '
74 'a severe error, raises an exception\n')
77 def test_unicode_message(self):
78 sw = self.reporter.system_message(0, u'mesidʒ')
79 self.assertEqual(sw.pformat(), u"""\
80 <system_message level="0" source="test data" type="DEBUG">
81 <paragraph>
82 mesidʒ
83 """)
85 def test_unicode_message_from_exception(self):
86 """Workaround for Python < 2.6 bug:
87 unicode(<exception instance>) uses __str__
88 and hence fails with unicode message"""
89 try:
90 raise Exception(u'mesidʒ')
91 except Exception, err:
92 sw = self.reporter.system_message(0, err)
93 self.assertEqual(sw.pformat(), u"""\
94 <system_message level="0" source="test data" type="DEBUG">
95 <paragraph>
96 mesidʒ
97 """)
99 class QuietReporterTests(unittest.TestCase):
101 stream = StringIO()
102 reporter = utils.Reporter('test data', 5, 5, stream, 0)
104 def setUp(self):
105 self.stream.seek(0)
106 self.stream.truncate()
108 def test_debug(self):
109 sw = self.reporter.debug('a debug message')
110 # None because debug is disabled.
111 self.assertEqual(sw, None)
112 self.assertEqual(self.stream.getvalue(), '')
114 def test_info(self):
115 sw = self.reporter.info('an informational message')
116 self.assertEqual(sw.pformat(), """\
117 <system_message level="1" source="test data" type="INFO">
118 <paragraph>
119 an informational message
120 """)
121 self.assertEqual(self.stream.getvalue(), '')
123 def test_warning(self):
124 sw = self.reporter.warning('a warning')
125 self.assertEqual(sw.pformat(), """\
126 <system_message level="2" source="test data" type="WARNING">
127 <paragraph>
128 a warning
129 """)
130 self.assertEqual(self.stream.getvalue(), '')
132 def test_error(self):
133 sw = self.reporter.error('an error')
134 self.assertEqual(sw.pformat(), """\
135 <system_message level="3" source="test data" type="ERROR">
136 <paragraph>
137 an error
138 """)
139 self.assertEqual(self.stream.getvalue(), '')
141 def test_severe(self):
142 sw = self.reporter.severe('a severe error')
143 self.assertEqual(sw.pformat(), """\
144 <system_message level="4" source="test data" type="SEVERE">
145 <paragraph>
146 a severe error
147 """)
148 self.assertEqual(self.stream.getvalue(), '')
151 class NameValueTests(unittest.TestCase):
153 def test_extract_name_value(self):
154 self.assertRaises(utils.NameValueError, utils.extract_name_value,
155 'hello')
156 self.assertRaises(utils.NameValueError, utils.extract_name_value,
157 'hello')
158 self.assertRaises(utils.NameValueError, utils.extract_name_value,
159 '=hello')
160 self.assertRaises(utils.NameValueError, utils.extract_name_value,
161 'hello=')
162 self.assertRaises(utils.NameValueError, utils.extract_name_value,
163 'hello="')
164 self.assertRaises(utils.NameValueError, utils.extract_name_value,
165 'hello="something')
166 self.assertRaises(utils.NameValueError, utils.extract_name_value,
167 'hello="something"else')
168 output = utils.extract_name_value(
169 """att1=val1 att2=val2 att3="value number '3'" att4=val4""")
170 self.assertEqual(output, [('att1', 'val1'), ('att2', 'val2'),
171 ('att3', "value number '3'"),
172 ('att4', 'val4')])
175 class ExtensionOptionTests(unittest.TestCase):
177 optionspec = {'a': int, 'bbb': float, 'cdef': (lambda x: x),
178 'empty': (lambda x: x)}
180 def test_assemble_option_dict(self):
181 input = utils.extract_name_value('a=1 bbb=2.0 cdef=hol%s' % chr(224))
182 self.assertEqual(
183 utils.assemble_option_dict(input, self.optionspec),
184 {'a': 1, 'bbb': 2.0, 'cdef': ('hol%s' % chr(224))})
185 input = utils.extract_name_value('a=1 b=2.0 c=hol%s' % chr(224))
186 self.assertRaises(KeyError, utils.assemble_option_dict,
187 input, self.optionspec)
188 input = utils.extract_name_value('a=1 bbb=two cdef=hol%s' % chr(224))
189 self.assertRaises(ValueError, utils.assemble_option_dict,
190 input, self.optionspec)
192 def test_extract_extension_options(self):
193 field_list = nodes.field_list()
194 field_list += nodes.field(
195 '', nodes.field_name('', 'a'),
196 nodes.field_body('', nodes.paragraph('', '1')))
197 field_list += nodes.field(
198 '', nodes.field_name('', 'bbb'),
199 nodes.field_body('', nodes.paragraph('', '2.0')))
200 field_list += nodes.field(
201 '', nodes.field_name('', 'cdef'),
202 nodes.field_body('', nodes.paragraph('', u'hol\u00e0')))
203 field_list += nodes.field(
204 '', nodes.field_name('', 'empty'), nodes.field_body())
205 self.assertEqual(
206 utils.extract_extension_options(field_list, self.optionspec),
207 {'a': 1, 'bbb': 2.0,
208 'cdef': u'hol\u00e0',
209 'empty': None})
210 self.assertRaises(KeyError, utils.extract_extension_options,
211 field_list, {})
212 field_list += nodes.field(
213 '', nodes.field_name('', 'cdef'),
214 nodes.field_body('', nodes.paragraph('', 'one'),
215 nodes.paragraph('', 'two')))
216 self.assertRaises(utils.BadOptionDataError,
217 utils.extract_extension_options,
218 field_list, self.optionspec)
219 field_list[-1] = nodes.field(
220 '', nodes.field_name('', 'cdef bad'),
221 nodes.field_body('', nodes.paragraph('', 'no arguments')))
222 self.assertRaises(utils.BadOptionError,
223 utils.extract_extension_options,
224 field_list, self.optionspec)
225 field_list[-1] = nodes.field(
226 '', nodes.field_name('', 'cdef'),
227 nodes.field_body('', nodes.paragraph('', 'duplicate')))
228 self.assertRaises(utils.DuplicateOptionError,
229 utils.extract_extension_options,
230 field_list, self.optionspec)
231 field_list[-2] = nodes.field(
232 '', nodes.field_name('', 'unkown'),
233 nodes.field_body('', nodes.paragraph('', 'unknown')))
234 self.assertRaises(KeyError, utils.extract_extension_options,
235 field_list, self.optionspec)
238 class HelperFunctionsTests(unittest.TestCase):
240 def test_normalize_language_tag(self):
241 self.assertEqual(utils.normalize_language_tag('de'), ['de'])
242 self.assertEqual(utils.normalize_language_tag('de-AT'),
243 ['de-at', 'de'])
244 self.assertEqual(utils.normalize_language_tag('de-AT-1901'),
245 ['de-at-1901', 'de-at', 'de-1901', 'de'])
246 self.assertEqual(utils.normalize_language_tag('de-AT-1901-frak'),
247 ['de-at-1901-frak', 'de-at-1901', 'de-at-frak',
248 'de-1901-frak', 'de-at', 'de-1901', 'de-frak', 'de'])
249 self.assertEqual(utils.normalize_language_tag('grc-ibycus-x-altquot'),
250 ['grc-ibycus-x-altquot', 'grc-ibycus',
251 'grc-x-altquot', 'grc'])
253 def test_column_width(self):
254 self.assertEqual(utils.column_width(u'de'), 2)
255 self.assertEqual(utils.column_width(u'dâ'), 2) # pre-composed
256 self.assertEqual(utils.column_width(u'dâ'), 2) # combining
259 def test_relative_path(self):
260 # Build and return a path to `target`, relative to `source`:
261 # Use '/' as path sep in result.
262 self.assertEqual(utils.relative_path('spam', 'spam'), '')
263 source = os.path.join('h\xE4m', 'spam', 'fileA')
264 target = os.path.join('h\xE4m', 'spam', 'fileB')
265 self.assertEqual(utils.relative_path(source, target), 'fileB')
266 source = os.path.join('h\xE4m', 'spam', 'fileA')
267 target = os.path.join('h\xE4m', 'fileB')
268 self.assertEqual(utils.relative_path(source, target), '../fileB')
269 # if source is None, default to the cwd:
270 target = os.path.join('eggs', 'fileB')
271 self.assertEqual(utils.relative_path(None, target), 'eggs/fileB')
272 # If there is no common prefix, return the absolute path to `target`:
273 # source = '/foo/bar/fileA' # POSIX
274 # TODO: how to specify an absolute path independent of the OS?
275 # target = os.path.join('eggs', 'fileB')
276 # self.assertEqual(utils.relative_path(source, target),
277 # os.path.abspath('fileB'))
278 # Correctly process unicode instances:
279 self.assertEqual(utils.relative_path(u'spam', u'spam'), u'')
280 source = os.path.join(u'h\xE4m', u'spam', u'fileA')
281 target = os.path.join(u'h\xE4m', u'spam', u'fileB')
282 self.assertEqual(utils.relative_path(source, target), u'fileB')
283 source = os.path.join(u'h\xE4m', u'spam', u'fileA')
284 target = os.path.join(u'h\xE4m', u'fileB')
285 self.assertEqual(utils.relative_path(source, target), u'../fileB')
286 # if source is None, default to the cwd:
287 target = os.path.join(u'eggs', u'fileB')
288 self.assertEqual(utils.relative_path(None, target), u'eggs/fileB')
291 if __name__ == '__main__':
292 unittest.main()