1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3# 4# Copyright (c) 2013 the BabelFish authors. All rights reserved. 5# Use of this source code is governed by the 3-clause BSD license 6# that can be found in the LICENSE file. 7# 8from __future__ import unicode_literals 9import re 10import sys 11import pickle 12from unittest import TestCase, TestSuite, TestLoader, TextTestRunner 13from pkg_resources import resource_stream # @UnresolvedImport 14from babelfish import (LANGUAGES, Language, Country, Script, language_converters, country_converters, 15 LanguageReverseConverter, LanguageConvertError, LanguageReverseError, CountryReverseError) 16 17 18if sys.version_info[:2] <= (2, 6): 19 _MAX_LENGTH = 80 20 21 def safe_repr(obj, short=False): 22 try: 23 result = repr(obj) 24 except Exception: 25 result = object.__repr__(obj) 26 if not short or len(result) < _MAX_LENGTH: 27 return result 28 return result[:_MAX_LENGTH] + ' [truncated]...' 29 30 class _AssertRaisesContext(object): 31 """A context manager used to implement TestCase.assertRaises* methods.""" 32 33 def __init__(self, expected, test_case, expected_regexp=None): 34 self.expected = expected 35 self.failureException = test_case.failureException 36 self.expected_regexp = expected_regexp 37 38 def __enter__(self): 39 return self 40 41 def __exit__(self, exc_type, exc_value, tb): 42 if exc_type is None: 43 try: 44 exc_name = self.expected.__name__ 45 except AttributeError: 46 exc_name = str(self.expected) 47 raise self.failureException( 48 "{0} not raised".format(exc_name)) 49 if not issubclass(exc_type, self.expected): 50 # let unexpected exceptions pass through 51 return False 52 self.exception = exc_value # store for later retrieval 53 if self.expected_regexp is None: 54 return True 55 56 expected_regexp = self.expected_regexp 57 if isinstance(expected_regexp, basestring): 58 expected_regexp = re.compile(expected_regexp) 59 if not expected_regexp.search(str(exc_value)): 60 raise self.failureException('"%s" does not match "%s"' % 61 (expected_regexp.pattern, str(exc_value))) 62 return True 63 64 class _Py26FixTestCase(object): 65 def assertIsNone(self, obj, msg=None): 66 """Same as self.assertTrue(obj is None), with a nicer default message.""" 67 if obj is not None: 68 standardMsg = '%s is not None' % (safe_repr(obj),) 69 self.fail(self._formatMessage(msg, standardMsg)) 70 71 def assertIsNotNone(self, obj, msg=None): 72 """Included for symmetry with assertIsNone.""" 73 if obj is None: 74 standardMsg = 'unexpectedly None' 75 self.fail(self._formatMessage(msg, standardMsg)) 76 77 def assertIn(self, member, container, msg=None): 78 """Just like self.assertTrue(a in b), but with a nicer default message.""" 79 if member not in container: 80 standardMsg = '%s not found in %s' % (safe_repr(member), 81 safe_repr(container)) 82 self.fail(self._formatMessage(msg, standardMsg)) 83 84 def assertNotIn(self, member, container, msg=None): 85 """Just like self.assertTrue(a not in b), but with a nicer default message.""" 86 if member in container: 87 standardMsg = '%s unexpectedly found in %s' % (safe_repr(member), 88 safe_repr(container)) 89 self.fail(self._formatMessage(msg, standardMsg)) 90 91 def assertIs(self, expr1, expr2, msg=None): 92 """Just like self.assertTrue(a is b), but with a nicer default message.""" 93 if expr1 is not expr2: 94 standardMsg = '%s is not %s' % (safe_repr(expr1), 95 safe_repr(expr2)) 96 self.fail(self._formatMessage(msg, standardMsg)) 97 98 def assertIsNot(self, expr1, expr2, msg=None): 99 """Just like self.assertTrue(a is not b), but with a nicer default message.""" 100 if expr1 is expr2: 101 standardMsg = 'unexpectedly identical: %s' % (safe_repr(expr1),) 102 self.fail(self._formatMessage(msg, standardMsg)) 103 104else: 105 class _Py26FixTestCase(object): 106 pass 107 108 109class TestScript(TestCase, _Py26FixTestCase): 110 def test_wrong_script(self): 111 self.assertRaises(ValueError, lambda: Script('Azer')) 112 113 def test_eq(self): 114 self.assertEqual(Script('Latn'), Script('Latn')) 115 116 def test_ne(self): 117 self.assertNotEqual(Script('Cyrl'), Script('Latn')) 118 119 def test_hash(self): 120 self.assertEqual(hash(Script('Hira')), hash('Hira')) 121 122 def test_pickle(self): 123 self.assertEqual(pickle.loads(pickle.dumps(Script('Latn'))), Script('Latn')) 124 125 126class TestCountry(TestCase, _Py26FixTestCase): 127 def test_wrong_country(self): 128 self.assertRaises(ValueError, lambda: Country('ZZ')) 129 130 def test_eq(self): 131 self.assertEqual(Country('US'), Country('US')) 132 133 def test_ne(self): 134 self.assertNotEqual(Country('GB'), Country('US')) 135 self.assertIsNotNone(Country('US')) 136 137 def test_hash(self): 138 self.assertEqual(hash(Country('US')), hash('US')) 139 140 def test_pickle(self): 141 for country in [Country('GB'), Country('US')]: 142 self.assertEqual(pickle.loads(pickle.dumps(country)), country) 143 144 def test_converter_name(self): 145 self.assertEqual(Country('US').name, 'UNITED STATES') 146 self.assertEqual(Country.fromname('UNITED STATES'), Country('US')) 147 self.assertEqual(Country.fromcode('UNITED STATES', 'name'), Country('US')) 148 self.assertRaises(CountryReverseError, lambda: Country.fromname('ZZZZZ')) 149 self.assertEqual(len(country_converters['name'].codes), 249) 150 151 152class TestLanguage(TestCase, _Py26FixTestCase): 153 def test_languages(self): 154 self.assertEqual(len(LANGUAGES), 7874) 155 156 def test_wrong_language(self): 157 self.assertRaises(ValueError, lambda: Language('zzz')) 158 159 def test_unknown_language(self): 160 self.assertEqual(Language('zzzz', unknown='und'), Language('und')) 161 162 def test_converter_alpha2(self): 163 self.assertEqual(Language('eng').alpha2, 'en') 164 self.assertEqual(Language.fromalpha2('en'), Language('eng')) 165 self.assertEqual(Language.fromcode('en', 'alpha2'), Language('eng')) 166 self.assertRaises(LanguageReverseError, lambda: Language.fromalpha2('zz')) 167 self.assertRaises(LanguageConvertError, lambda: Language('aaa').alpha2) 168 self.assertEqual(len(language_converters['alpha2'].codes), 184) 169 170 def test_converter_alpha3b(self): 171 self.assertEqual(Language('fra').alpha3b, 'fre') 172 self.assertEqual(Language.fromalpha3b('fre'), Language('fra')) 173 self.assertEqual(Language.fromcode('fre', 'alpha3b'), Language('fra')) 174 self.assertRaises(LanguageReverseError, lambda: Language.fromalpha3b('zzz')) 175 self.assertRaises(LanguageConvertError, lambda: Language('aaa').alpha3b) 176 self.assertEqual(len(language_converters['alpha3b'].codes), 418) 177 178 def test_converter_alpha3t(self): 179 self.assertEqual(Language('fra').alpha3t, 'fra') 180 self.assertEqual(Language.fromalpha3t('fra'), Language('fra')) 181 self.assertEqual(Language.fromcode('fra', 'alpha3t'), Language('fra')) 182 self.assertRaises(LanguageReverseError, lambda: Language.fromalpha3t('zzz')) 183 self.assertRaises(LanguageConvertError, lambda: Language('aaa').alpha3t) 184 self.assertEqual(len(language_converters['alpha3t'].codes), 418) 185 186 def test_converter_name(self): 187 self.assertEqual(Language('eng').name, 'English') 188 self.assertEqual(Language.fromname('English'), Language('eng')) 189 self.assertEqual(Language.fromcode('English', 'name'), Language('eng')) 190 self.assertRaises(LanguageReverseError, lambda: Language.fromname('Zzzzzzzzz')) 191 self.assertEqual(len(language_converters['name'].codes), 7874) 192 193 def test_converter_scope(self): 194 self.assertEqual(language_converters['scope'].codes, set(['I', 'S', 'M'])) 195 self.assertEqual(Language('eng').scope, 'individual') 196 self.assertEqual(Language('und').scope, 'special') 197 198 def test_converter_type(self): 199 self.assertEqual(language_converters['type'].codes, set(['A', 'C', 'E', 'H', 'L', 'S'])) 200 self.assertEqual(Language('eng').type, 'living') 201 self.assertEqual(Language('und').type, 'special') 202 203 def test_converter_opensubtitles(self): 204 self.assertEqual(Language('fra').opensubtitles, Language('fra').alpha3b) 205 self.assertEqual(Language('por', 'BR').opensubtitles, 'pob') 206 self.assertEqual(Language.fromopensubtitles('fre'), Language('fra')) 207 self.assertEqual(Language.fromopensubtitles('pob'), Language('por', 'BR')) 208 self.assertEqual(Language.fromopensubtitles('pb'), Language('por', 'BR')) 209 # Montenegrin is not recognized as an ISO language (yet?) but for now it is 210 # unofficially accepted as Serbian from Montenegro 211 self.assertEqual(Language.fromopensubtitles('mne'), Language('srp', 'ME')) 212 self.assertEqual(Language.fromcode('pob', 'opensubtitles'), Language('por', 'BR')) 213 self.assertRaises(LanguageReverseError, lambda: Language.fromopensubtitles('zzz')) 214 self.assertRaises(LanguageConvertError, lambda: Language('aaa').opensubtitles) 215 self.assertEqual(len(language_converters['opensubtitles'].codes), 606) 216 217 # test with all the LANGUAGES from the opensubtitles api 218 # downloaded from: http://www.opensubtitles.org/addons/export_languages.php 219 f = resource_stream('babelfish', 'data/opensubtitles_languages.txt') 220 f.readline() 221 for l in f: 222 idlang, alpha2, _, upload_enabled, web_enabled = l.decode('utf-8').strip().split('\t') 223 if not int(upload_enabled) and not int(web_enabled): 224 # do not test LANGUAGES that are too esoteric / not widely available 225 continue 226 self.assertEqual(Language.fromopensubtitles(idlang).opensubtitles, idlang) 227 if alpha2: 228 self.assertEqual(Language.fromopensubtitles(idlang), Language.fromopensubtitles(alpha2)) 229 f.close() 230 231 def test_fromietf_country_script(self): 232 language = Language.fromietf('fra-FR-Latn') 233 self.assertEqual(language.alpha3, 'fra') 234 self.assertEqual(language.country, Country('FR')) 235 self.assertEqual(language.script, Script('Latn')) 236 237 def test_fromietf_country_no_script(self): 238 language = Language.fromietf('fra-FR') 239 self.assertEqual(language.alpha3, 'fra') 240 self.assertEqual(language.country, Country('FR')) 241 self.assertIsNone(language.script) 242 243 def test_fromietf_no_country_no_script(self): 244 language = Language.fromietf('fra-FR') 245 self.assertEqual(language.alpha3, 'fra') 246 self.assertEqual(language.country, Country('FR')) 247 self.assertIsNone(language.script) 248 249 def test_fromietf_no_country_script(self): 250 language = Language.fromietf('fra-Latn') 251 self.assertEqual(language.alpha3, 'fra') 252 self.assertIsNone(language.country) 253 self.assertEqual(language.script, Script('Latn')) 254 255 def test_fromietf_alpha2_language(self): 256 language = Language.fromietf('fr-Latn') 257 self.assertEqual(language.alpha3, 'fra') 258 self.assertIsNone(language.country) 259 self.assertEqual(language.script, Script('Latn')) 260 261 def test_fromietf_wrong_language(self): 262 self.assertRaises(ValueError, lambda: Language.fromietf('xyz-FR')) 263 264 def test_fromietf_wrong_country(self): 265 self.assertRaises(ValueError, lambda: Language.fromietf('fra-YZ')) 266 267 def test_fromietf_wrong_script(self): 268 self.assertRaises(ValueError, lambda: Language.fromietf('fra-FR-Wxyz')) 269 270 def test_eq(self): 271 self.assertEqual(Language('eng'), Language('eng')) 272 273 def test_ne(self): 274 self.assertNotEqual(Language('fra'), Language('eng')) 275 self.assertIsNotNone(Language('fra')) 276 277 def test_nonzero(self): 278 self.assertFalse(bool(Language('und'))) 279 self.assertTrue(bool(Language('eng'))) 280 281 def test_language_hasattr(self): 282 self.assertTrue(hasattr(Language('fra'), 'alpha3')) 283 self.assertTrue(hasattr(Language('fra'), 'alpha2')) 284 self.assertFalse(hasattr(Language('bej'), 'alpha2')) 285 286 def test_country_hasattr(self): 287 self.assertTrue(hasattr(Country('US'), 'name')) 288 self.assertTrue(hasattr(Country('FR'), 'alpha2')) 289 self.assertFalse(hasattr(Country('BE'), 'none')) 290 291 def test_country(self): 292 self.assertEqual(Language('por', 'BR').country, Country('BR')) 293 self.assertEqual(Language('eng', Country('US')).country, Country('US')) 294 295 def test_eq_with_country(self): 296 self.assertEqual(Language('eng', 'US'), Language('eng', Country('US'))) 297 298 def test_ne_with_country(self): 299 self.assertNotEqual(Language('eng', 'US'), Language('eng', Country('GB'))) 300 301 def test_script(self): 302 self.assertEqual(Language('srp', script='Latn').script, Script('Latn')) 303 self.assertEqual(Language('srp', script=Script('Cyrl')).script, Script('Cyrl')) 304 305 def test_eq_with_script(self): 306 self.assertEqual(Language('srp', script='Latn'), Language('srp', script=Script('Latn'))) 307 308 def test_ne_with_script(self): 309 self.assertNotEqual(Language('srp', script='Latn'), Language('srp', script=Script('Cyrl'))) 310 311 def test_eq_with_country_and_script(self): 312 self.assertEqual(Language('srp', 'SR', 'Latn'), Language('srp', Country('SR'), Script('Latn'))) 313 314 def test_ne_with_country_and_script(self): 315 self.assertNotEqual(Language('srp', 'SR', 'Latn'), Language('srp', Country('SR'), Script('Cyrl'))) 316 317 def test_hash(self): 318 self.assertEqual(hash(Language('fra')), hash('fr')) 319 self.assertEqual(hash(Language('ace')), hash('ace')) 320 self.assertEqual(hash(Language('por', 'BR')), hash('pt-BR')) 321 self.assertEqual(hash(Language('srp', script='Cyrl')), hash('sr-Cyrl')) 322 self.assertEqual(hash(Language('eng', 'US', 'Latn')), hash('en-US-Latn')) 323 324 def test_pickle(self): 325 for lang in [Language('fra'), 326 Language('eng', 'US'), 327 Language('srp', script='Latn'), 328 Language('eng', 'US', 'Latn')]: 329 self.assertEqual(pickle.loads(pickle.dumps(lang)), lang) 330 331 def test_str(self): 332 self.assertEqual(Language.fromietf(str(Language('eng', 'US', 'Latn'))), Language('eng', 'US', 'Latn')) 333 self.assertEqual(Language.fromietf(str(Language('fra', 'FR'))), Language('fra', 'FR')) 334 self.assertEqual(Language.fromietf(str(Language('bel'))), Language('bel')) 335 336 def test_register_converter(self): 337 class TestConverter(LanguageReverseConverter): 338 def __init__(self): 339 self.to_test = {'fra': 'test1', 'eng': 'test2'} 340 self.from_test = {'test1': 'fra', 'test2': 'eng'} 341 342 def convert(self, alpha3, country=None, script=None): 343 if alpha3 not in self.to_test: 344 raise LanguageConvertError(alpha3, country, script) 345 return self.to_test[alpha3] 346 347 def reverse(self, test): 348 if test not in self.from_test: 349 raise LanguageReverseError(test) 350 return (self.from_test[test], None) 351 language = Language('fra') 352 self.assertFalse(hasattr(language, 'test')) 353 language_converters['test'] = TestConverter() 354 self.assertTrue(hasattr(language, 'test')) 355 self.assertIn('test', language_converters) 356 self.assertEqual(Language('fra').test, 'test1') 357 self.assertEqual(Language.fromtest('test2').alpha3, 'eng') 358 del language_converters['test'] 359 self.assertNotIn('test', language_converters) 360 self.assertRaises(KeyError, lambda: Language.fromtest('test1')) 361 self.assertRaises(AttributeError, lambda: Language('fra').test) 362 363 364def suite(): 365 suite = TestSuite() 366 suite.addTest(TestLoader().loadTestsFromTestCase(TestScript)) 367 suite.addTest(TestLoader().loadTestsFromTestCase(TestCountry)) 368 suite.addTest(TestLoader().loadTestsFromTestCase(TestLanguage)) 369 return suite 370 371 372if __name__ == '__main__': 373 TextTestRunner().run(suite()) 374