Update policies on branches and versioning.
[docutils.git] / docutils / test / test_language.py
blob0410a07779abf29472f564a1b9712670c02f368c
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'
30 class LanguageTestSuite(DocutilsTestSupport.CustomTestSuite):
32 language_module_pattern = re.compile('^([a-z]{2,3}(_[a-z]{2,8})*)\.py$')
34 def __init__(self, languages=None):
35 DocutilsTestSupport.CustomTestSuite.__init__(self)
36 if languages:
37 self.languages = languages
38 else:
39 self.get_languages()
41 def get_languages(self):
42 """
43 Get installed language translations from docutils.languages and from
44 docutils.parsers.rst.languages.
45 """
46 languages = {}
47 for mod in (os.listdir(docutils.languages.__path__[0])
48 + os.listdir(docutils.parsers.rst.languages.__path__[0])):
49 match = self.language_module_pattern.match(mod)
50 if match:
51 languages[match.group(1)] = 1
52 self.languages = languages.keys()
53 # test language tag normalization:
54 self.languages += ['en_gb', 'en_US', 'en-CA', 'de-DE', 'de-AT-1901',
55 'pt-BR', 'pt-foo-BR']
56 # test that locally created language files are also loaded.
57 # requires local_dummy_lang.py in test directory (testroot)
58 # The local_dummy_lang.py contains all the fields from both
59 # the docutils language tags and the parser.rst language tags
60 self.languages += ['local_dummy_lang']
62 def generateTests(self):
63 for language in self.languages:
64 for method in LanguageTestCase.test_methods:
65 self.addTestCase(LanguageTestCase, method, None, None,
66 id=language+'.py', language=language)
69 class LanguageTestCase(DocutilsTestSupport.CustomTestCase):
71 test_methods = ['test_labels', 'test_bibliographic_fields',
72 'test_directives', 'test_roles']
73 """Names of methods used to test each language."""
75 def __init__(self, *args, **kwargs):
76 self.ref = docutils.languages.get_language(reference_language,
77 _reporter)
78 self.language = kwargs['language']
79 del kwargs['language'] # only wanted here
80 DocutilsTestSupport.CustomTestCase.__init__(self, *args, **kwargs)
82 def _xor(self, ref_dict, l_dict):
83 """
84 Returns entries that are only in one dictionary.
85 (missing_in_lang, more_than_in_ref).
86 """
87 missing = [] # in ref but not in l.
88 too_much = [] # in l but not in ref.
89 for label in ref_dict.keys():
90 if label not in l_dict:
91 missing.append(label)
92 for label in l_dict.keys():
93 if label not in ref_dict:
94 too_much.append(label)
95 return (missing, too_much)
97 def _invert(self, adict):
98 """Return an inverted (keys & values swapped) dictionary."""
99 inverted = {}
100 for key, value in adict.items():
101 inverted[value] = key
102 return inverted
104 def test_labels(self):
105 try:
106 module = docutils.languages.get_language(self.language, _reporter)
107 if not module:
108 raise ImportError
109 except ImportError:
110 self.fail('No docutils.languages.%s module.' % self.language)
111 missed, unknown = self._xor(self.ref.labels, module.labels)
112 if missed or unknown:
113 self.fail('Module docutils.languages.%s.labels:\n'
114 ' Missed: %s; Unknown: %s'
115 % (self.language, str(missed), str(unknown)))
117 def test_bibliographic_fields(self):
118 try:
119 module = docutils.languages.get_language(self.language, _reporter)
120 if not module:
121 raise ImportError
122 except ImportError:
123 self.fail('No docutils.languages.%s module.' % self.language)
124 missed, unknown = self._xor(
125 self._invert(self.ref.bibliographic_fields),
126 self._invert(module.bibliographic_fields))
127 if missed or unknown:
128 self.fail('Module docutils.languages.%s.bibliographic_fields:\n'
129 ' Missed: %s; Unknown: %s'
130 % (self.language, str(missed), str(unknown)))
132 def test_directives(self):
133 try:
134 module = docutils.parsers.rst.languages.get_language(
135 self.language)
136 if not module:
137 raise ImportError
138 except ImportError:
139 self.fail('No docutils.parsers.rst.languages.%s module.'
140 % self.language)
141 failures = []
142 for d in module.directives.keys():
143 try:
144 func, msg = directives.directive(d, module, None)
145 if not func:
146 failures.append('"%s": unknown directive' % d)
147 except Exception, error:
148 failures.append('"%s": %s' % (d, error))
149 inverted = self._invert(module.directives)
150 canonical = directives._directive_registry.keys()
151 canonical.sort()
152 canonical.remove('restructuredtext-test-directive')
153 for name in canonical:
154 if name not in inverted:
155 failures.append('"%s": translation missing' % name)
156 if failures:
157 text = ('Module docutils.parsers.rst.languages.%s:\n %s'
158 % (self.language, '\n '.join(failures)))
159 if type(text) is unicode:
160 text = text.encode('raw_unicode_escape')
161 self.fail(text)
163 def test_roles(self):
164 try:
165 module = docutils.parsers.rst.languages.get_language(
166 self.language)
167 if not module:
168 raise ImportError
169 module.roles
170 except ImportError:
171 self.fail('No docutils.parsers.rst.languages.%s module.'
172 % self.language)
173 except AttributeError:
174 self.fail('No "roles" mapping in docutils.parsers.rst.languages.'
175 '%s module.' % self.language)
176 failures = []
177 for d in module.roles.values():
178 try:
179 method = roles._role_registry[d]
180 #if not method:
181 # failures.append('"%s": unknown role' % d)
182 except KeyError, error:
183 failures.append('"%s": %s' % (d, error))
184 inverted = self._invert(module.roles)
185 canonical = roles._role_registry.keys()
186 canonical.sort()
187 canonical.remove('restructuredtext-unimplemented-role')
188 for name in canonical:
189 if name not in inverted:
190 failures.append('"%s": translation missing' % name)
191 if failures:
192 text = ('Module docutils.parsers.rst.languages.%s:\n %s'
193 % (self.language, '\n '.join(failures)))
194 if type(text) is unicode:
195 text = text.encode('raw_unicode_escape')
196 self.fail(text)
198 languages_to_test = []
200 def suite():
201 s = LanguageTestSuite(languages_to_test)
202 s.generateTests()
203 return s
205 def get_language_arguments():
206 while len(sys.argv) > 1:
207 last = sys.argv[-1]
208 if last.startswith('-'):
209 break
210 languages_to_test.append(last)
211 sys.argv.pop()
212 languages_to_test.reverse()
215 if __name__ == '__main__':
216 get_language_arguments()
217 import unittest
218 unittest.main(defaultTest='suite')
220 # vim: set et ts=4 ai :