Formatting changes to facilitate integration of "py3" patchset.
[docutils.git] / docutils / test / test_language.py
blob29de60c2a8a59691dcd6050a65c2a264ba4916eb
1 #!/usr/bin/env python
3 # $Id$
4 # Authors: Engelbert Gruber <grubert@users.sourceforge.net>;
5 # David Goodger <goodger@python.org>
6 # Copyright: This module has been placed in the public domain.
8 """
9 Tests for language module completeness.
11 Specify a language code (e.g. "de") as a command-line parameter to test only
12 that language.
13 """
15 import sys
16 import os
17 import re
18 import DocutilsTestSupport # must be imported before docutils
19 import docutils.languages
20 import docutils.parsers.rst.languages
21 from docutils.parsers.rst import states, directives, roles
22 import docutils.utils, docutils.frontend
24 _settings = docutils.frontend.OptionParser().get_default_values()
25 _reporter = docutils.utils.new_reporter('', _settings)
27 reference_language = 'en'
29 if sys.version_info >= (3, 0):
30 unicode = str # noqa
33 class LanguageTestSuite(DocutilsTestSupport.CustomTestSuite):
35 language_module_pattern = re.compile(r'^([a-z]{2,3}(_[a-z]{2,8})*)\.py$')
37 def __init__(self, languages=None):
38 DocutilsTestSupport.CustomTestSuite.__init__(self)
39 if languages:
40 self.languages = languages
41 else:
42 self.get_languages()
44 def get_languages(self):
45 """
46 Get installed language translations from docutils.languages and from
47 docutils.parsers.rst.languages.
48 """
49 languages = {}
50 for mod in (os.listdir(docutils.languages.__path__[0])
51 + os.listdir(docutils.parsers.rst.languages.__path__[0])):
52 match = self.language_module_pattern.match(mod)
53 if match:
54 languages[match.group(1)] = 1
55 self.languages = languages.keys()
56 # test language tag normalization:
57 self.languages += ['en_gb', 'en_US', 'en-CA', 'de-DE', 'de-AT-1901',
58 'pt-BR', 'pt-foo-BR']
59 # test that locally created language files are also loaded.
60 # requires local_dummy_lang.py in test directory (testroot)
61 # The local_dummy_lang.py contains all the fields from both
62 # the docutils language tags and the parser.rst language tags
63 self.languages += ['local_dummy_lang']
65 def generateTests(self):
66 for language in self.languages:
67 for method in LanguageTestCase.test_methods:
68 self.addTestCase(LanguageTestCase, method, None, None,
69 id=language+'.py', language=language)
72 class LanguageTestCase(DocutilsTestSupport.CustomTestCase):
74 test_methods = ['test_labels', 'test_bibliographic_fields',
75 'test_directives', 'test_roles']
76 """Names of methods used to test each language."""
78 def __init__(self, *args, **kwargs):
79 self.ref = docutils.languages.get_language(reference_language,
80 _reporter)
81 self.language = kwargs['language']
82 del kwargs['language'] # only wanted here
83 DocutilsTestSupport.CustomTestCase.__init__(self, *args, **kwargs)
85 def _xor(self, ref_dict, l_dict):
86 """
87 Returns entries that are only in one dictionary.
88 (missing_in_lang, more_than_in_ref).
89 """
90 missing = [] # in ref but not in l.
91 too_much = [] # in l but not in ref.
92 for label in ref_dict.keys():
93 if label not in l_dict:
94 missing.append(label)
95 for label in l_dict.keys():
96 if label not in ref_dict:
97 too_much.append(label)
98 return (missing, too_much)
100 def _invert(self, adict):
101 """Return an inverted (keys & values swapped) dictionary."""
102 inverted = {}
103 for key, value in adict.items():
104 inverted[value] = key
105 return inverted
107 def test_labels(self):
108 try:
109 module = docutils.languages.get_language(self.language, _reporter)
110 if not module:
111 raise ImportError
112 except ImportError:
113 self.fail('No docutils.languages.%s module.' % self.language)
114 missed, unknown = self._xor(self.ref.labels, module.labels)
115 if missed or unknown:
116 self.fail('Module docutils.languages.%s.labels:\n'
117 ' Missed: %s; Unknown: %s'
118 % (self.language, str(missed), str(unknown)))
120 def test_bibliographic_fields(self):
121 try:
122 module = docutils.languages.get_language(self.language, _reporter)
123 if not module:
124 raise ImportError
125 except ImportError:
126 self.fail('No docutils.languages.%s module.' % self.language)
127 missed, unknown = self._xor(
128 self._invert(self.ref.bibliographic_fields),
129 self._invert(module.bibliographic_fields))
130 if missed or unknown:
131 self.fail('Module docutils.languages.%s.bibliographic_fields:\n'
132 ' Missed: %s; Unknown: %s'
133 % (self.language, str(missed), str(unknown)))
135 def test_directives(self):
136 try:
137 module = docutils.parsers.rst.languages.get_language(
138 self.language)
139 if not module:
140 raise ImportError
141 except ImportError:
142 self.fail('No docutils.parsers.rst.languages.%s module.'
143 % self.language)
144 failures = []
145 for d in module.directives.keys():
146 try:
147 func, msg = directives.directive(d, module, None)
148 if not func:
149 failures.append('"%s": unknown directive' % d)
150 except Exception as error:
151 failures.append('"%s": %s' % (d, error))
152 inverted = self._invert(module.directives)
153 canonical = sorted(directives._directive_registry.keys())
154 canonical.remove('restructuredtext-test-directive')
155 for name in canonical:
156 if name not in inverted:
157 failures.append('"%s": translation missing' % name)
158 if failures:
159 text = ('Module docutils.parsers.rst.languages.%s:\n %s'
160 % (self.language, '\n '.join(failures)))
161 if isinstance(text, unicode):
162 text = text.encode('raw_unicode_escape')
163 self.fail(text)
165 def test_roles(self):
166 try:
167 module = docutils.parsers.rst.languages.get_language(
168 self.language)
169 if not module:
170 raise ImportError
171 module.roles
172 except ImportError:
173 self.fail('No docutils.parsers.rst.languages.%s module.'
174 % self.language)
175 except AttributeError:
176 self.fail('No "roles" mapping in docutils.parsers.rst.languages.'
177 '%s module.' % self.language)
178 failures = []
179 for d in module.roles.values():
180 try:
181 method = roles._role_registry[d]
182 #if not method:
183 # failures.append('"%s": unknown role' % d)
184 except KeyError as error:
185 failures.append('"%s": %s' % (d, error))
186 inverted = self._invert(module.roles)
187 canonical = sorted(roles._role_registry.keys())
188 canonical.remove('restructuredtext-unimplemented-role')
189 for name in canonical:
190 if name not in inverted:
191 failures.append('"%s": translation missing' % name)
192 if failures:
193 text = ('Module docutils.parsers.rst.languages.%s:\n %s'
194 % (self.language, '\n '.join(failures)))
195 if isinstance(text, unicode):
196 text = text.encode('raw_unicode_escape')
197 self.fail(text)
199 languages_to_test = []
201 def suite():
202 s = LanguageTestSuite(languages_to_test)
203 s.generateTests()
204 return s
206 def get_language_arguments():
207 while len(sys.argv) > 1:
208 last = sys.argv[-1]
209 if last.startswith('-'):
210 break
211 languages_to_test.append(last)
212 sys.argv.pop()
213 languages_to_test.reverse()
216 if __name__ == '__main__':
217 get_language_arguments()
218 import unittest
219 unittest.main(defaultTest='suite')
221 # vim: set et ts=4 ai :