Report table parsing errors with correct line number.
[docutils.git] / test / test_language.py
bloba7c0d566650ed835924c9ae12c6f00b275607dc1
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']
57 def generateTests(self):
58 for language in self.languages:
59 for method in LanguageTestCase.test_methods:
60 self.addTestCase(LanguageTestCase, method, None, None,
61 id=language+'.py', language=language)
64 class LanguageTestCase(DocutilsTestSupport.CustomTestCase):
66 test_methods = ['test_labels', 'test_bibliographic_fields',
67 'test_directives', 'test_roles']
68 """Names of methods used to test each language."""
70 def __init__(self, *args, **kwargs):
71 self.ref = docutils.languages.get_language(reference_language,
72 _reporter)
73 self.language = kwargs['language']
74 del kwargs['language'] # only wanted here
75 DocutilsTestSupport.CustomTestCase.__init__(self, *args, **kwargs)
77 def _xor(self, ref_dict, l_dict):
78 """
79 Returns entries that are only in one dictionary.
80 (missing_in_lang, more_than_in_ref).
81 """
82 missing = [] # in ref but not in l.
83 too_much = [] # in l but not in ref.
84 for label in ref_dict.keys():
85 if label not in l_dict:
86 missing.append(label)
87 for label in l_dict.keys():
88 if label not in ref_dict:
89 too_much.append(label)
90 return (missing, too_much)
92 def _invert(self, adict):
93 """Return an inverted (keys & values swapped) dictionary."""
94 inverted = {}
95 for key, value in adict.items():
96 inverted[value] = key
97 return inverted
99 def test_labels(self):
100 try:
101 module = docutils.languages.get_language(self.language, _reporter)
102 if not module:
103 raise ImportError
104 except ImportError:
105 self.fail('No docutils.languages.%s module.' % self.language)
106 missed, unknown = self._xor(self.ref.labels, module.labels)
107 if missed or unknown:
108 self.fail('Module docutils.languages.%s.labels:\n'
109 ' Missed: %s; Unknown: %s'
110 % (self.language, str(missed), str(unknown)))
112 def test_bibliographic_fields(self):
113 try:
114 module = docutils.languages.get_language(self.language, _reporter)
115 if not module:
116 raise ImportError
117 except ImportError:
118 self.fail('No docutils.languages.%s module.' % self.language)
119 missed, unknown = self._xor(
120 self._invert(self.ref.bibliographic_fields),
121 self._invert(module.bibliographic_fields))
122 if missed or unknown:
123 self.fail('Module docutils.languages.%s.bibliographic_fields:\n'
124 ' Missed: %s; Unknown: %s'
125 % (self.language, str(missed), str(unknown)))
127 def test_directives(self):
128 try:
129 module = docutils.parsers.rst.languages.get_language(
130 self.language)
131 if not module:
132 raise ImportError
133 except ImportError:
134 self.fail('No docutils.parsers.rst.languages.%s module.'
135 % self.language)
136 failures = []
137 for d in module.directives.keys():
138 try:
139 func, msg = directives.directive(d, module, None)
140 if not func:
141 failures.append('"%s": unknown directive' % d)
142 except Exception, error:
143 failures.append('"%s": %s' % (d, error))
144 inverted = self._invert(module.directives)
145 canonical = directives._directive_registry.keys()
146 canonical.sort()
147 canonical.remove('restructuredtext-test-directive')
148 for name in canonical:
149 if name not in inverted:
150 failures.append('"%s": translation missing' % name)
151 if failures:
152 text = ('Module docutils.parsers.rst.languages.%s:\n %s'
153 % (self.language, '\n '.join(failures)))
154 if type(text) is unicode:
155 text = text.encode('raw_unicode_escape')
156 self.fail(text)
158 def test_roles(self):
159 try:
160 module = docutils.parsers.rst.languages.get_language(
161 self.language)
162 if not module:
163 raise ImportError
164 module.roles
165 except ImportError:
166 self.fail('No docutils.parsers.rst.languages.%s module.'
167 % self.language)
168 except AttributeError:
169 self.fail('No "roles" mapping in docutils.parsers.rst.languages.'
170 '%s module.' % self.language)
171 failures = []
172 for d in module.roles.values():
173 try:
174 method = roles._role_registry[d]
175 #if not method:
176 # failures.append('"%s": unknown role' % d)
177 except KeyError, error:
178 failures.append('"%s": %s' % (d, error))
179 inverted = self._invert(module.roles)
180 canonical = roles._role_registry.keys()
181 canonical.sort()
182 canonical.remove('restructuredtext-unimplemented-role')
183 for name in canonical:
184 if name not in inverted:
185 failures.append('"%s": translation missing' % name)
186 if failures:
187 text = ('Module docutils.parsers.rst.languages.%s:\n %s'
188 % (self.language, '\n '.join(failures)))
189 if type(text) is unicode:
190 text = text.encode('raw_unicode_escape')
191 self.fail(text)
193 languages_to_test = []
195 def suite():
196 s = LanguageTestSuite(languages_to_test)
197 s.generateTests()
198 return s
200 def get_language_arguments():
201 while len(sys.argv) > 1:
202 last = sys.argv[-1]
203 if last.startswith('-'):
204 break
205 languages_to_test.append(last)
206 sys.argv.pop()
207 languages_to_test.reverse()
210 if __name__ == '__main__':
211 get_language_arguments()
212 import unittest
213 unittest.main(defaultTest='suite')
215 # vim: set et ts=4 ai :