Split up monolithic test file
Split the tests up into multiple files for easier maintenance. Update the import order of modules used by the tests. bp graduate-oslo-i18n Change-Id: If225bfa0a4d319ebc530c6497f74a20d0f25835b
This commit is contained in:
parent
73d16d8134
commit
d601e1c55b
60
tests/test_factory.py
Normal file
60
tests/test_factory.py
Normal file
@ -0,0 +1,60 @@
|
||||
# Copyright 2012 Red Hat, Inc.
|
||||
# Copyright 2013 IBM Corp.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import mock
|
||||
import six
|
||||
|
||||
from oslotest import base as test_base
|
||||
|
||||
from oslo.i18n import gettextutils
|
||||
|
||||
|
||||
class TranslatorFactoryTest(test_base.BaseTestCase):
|
||||
|
||||
def test_lazy(self):
|
||||
with mock.patch.object(gettextutils, 'Message') as msg:
|
||||
tf = gettextutils.TranslatorFactory('domain', lazy=True)
|
||||
tf.primary('some text')
|
||||
msg.assert_called_with('some text', domain='domain')
|
||||
|
||||
def test_py2(self):
|
||||
with mock.patch.object(six, 'PY3', False):
|
||||
with mock.patch('gettext.translation') as translation:
|
||||
trans = mock.Mock()
|
||||
translation.return_value = trans
|
||||
trans.gettext.side_effect = AssertionError(
|
||||
'should have called ugettext')
|
||||
tf = gettextutils.TranslatorFactory('domain', lazy=False)
|
||||
tf.primary('some text')
|
||||
trans.ugettext.assert_called_with('some text')
|
||||
|
||||
def test_py3(self):
|
||||
with mock.patch.object(six, 'PY3', True):
|
||||
with mock.patch('gettext.translation') as translation:
|
||||
trans = mock.Mock()
|
||||
translation.return_value = trans
|
||||
trans.ugettext.side_effect = AssertionError(
|
||||
'should have called gettext')
|
||||
tf = gettextutils.TranslatorFactory('domain', lazy=False)
|
||||
tf.primary('some text')
|
||||
trans.gettext.assert_called_with('some text')
|
||||
|
||||
def test_log_level_domain_name(self):
|
||||
with mock.patch.object(gettextutils.TranslatorFactory,
|
||||
'_make_translation_func') as mtf:
|
||||
tf = gettextutils.TranslatorFactory('domain', lazy=False)
|
||||
tf._make_log_translation_func('mylevel')
|
||||
mtf.assert_called_with('domain-log-mylevel')
|
@ -17,16 +17,18 @@
|
||||
import gettext
|
||||
import logging
|
||||
|
||||
from oslo.i18n import gettextutils
|
||||
|
||||
from babel import localedata
|
||||
import mock
|
||||
import six
|
||||
import testtools
|
||||
|
||||
from oslotest import base as test_base
|
||||
from oslotest import moxstubout
|
||||
|
||||
from tests import fakes
|
||||
from tests import utils
|
||||
|
||||
from oslo.i18n import gettextutils
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -141,664 +143,6 @@ class GettextTest(test_base.BaseTestCase):
|
||||
mock_translation.side_effect = translator
|
||||
|
||||
# translate() works on msgs and on objects whose unicode reps are msgs
|
||||
obj = SomeObject(message)
|
||||
obj = utils.SomeObject(message)
|
||||
self.assertEqual(es_translation, gettextutils.translate(message, 'es'))
|
||||
self.assertEqual(es_translation, gettextutils.translate(obj, 'es'))
|
||||
|
||||
|
||||
class MessageTestCase(test_base.BaseTestCase):
|
||||
"""Unit tests for locale Message class."""
|
||||
|
||||
@staticmethod
|
||||
def message(msg):
|
||||
return gettextutils.Message(msg)
|
||||
|
||||
def test_message_id_and_message_text(self):
|
||||
message = gettextutils.Message('1')
|
||||
self.assertEqual('1', message.msgid)
|
||||
self.assertEqual('1', message)
|
||||
message = gettextutils.Message('1', msgtext='A')
|
||||
self.assertEqual('1', message.msgid)
|
||||
self.assertEqual('A', message)
|
||||
|
||||
def test_message_is_unicode(self):
|
||||
message = self.message('some %s') % 'message'
|
||||
self.assertIsInstance(message, six.text_type)
|
||||
|
||||
@mock.patch('locale.getdefaultlocale')
|
||||
@mock.patch('gettext.translation')
|
||||
def test_create_message_non_english_default_locale(self,
|
||||
mock_translation,
|
||||
mock_getdefaultlocale):
|
||||
msgid = 'A message in English'
|
||||
es_translation = 'A message in Spanish'
|
||||
|
||||
es_translations = {msgid: es_translation}
|
||||
translations_map = {'es': es_translations}
|
||||
translator = fakes.FakeTranslations.translator(translations_map)
|
||||
mock_translation.side_effect = translator
|
||||
mock_getdefaultlocale.return_value = ('es',)
|
||||
|
||||
message = gettextutils.Message(msgid)
|
||||
|
||||
# The base representation of the message is in Spanish, as well as
|
||||
# the default translation, since the default locale was Spanish.
|
||||
self.assertEqual(es_translation, message)
|
||||
self.assertEqual(es_translation, message.translate())
|
||||
|
||||
def test_translate_returns_unicode(self):
|
||||
message = self.message('some %s') % 'message'
|
||||
self.assertIsInstance(message.translate(), six.text_type)
|
||||
|
||||
def test_mod_with_named_parameters(self):
|
||||
msgid = ("%(description)s\nCommand: %(cmd)s\n"
|
||||
"Exit code: %(exit_code)s\nStdout: %(stdout)r\n"
|
||||
"Stderr: %(stderr)r %%(something)s")
|
||||
params = {'description': 'test1',
|
||||
'cmd': 'test2',
|
||||
'exit_code': 'test3',
|
||||
'stdout': 'test4',
|
||||
'stderr': 'test5',
|
||||
'something': 'trimmed'}
|
||||
|
||||
result = self.message(msgid) % params
|
||||
|
||||
expected = msgid % params
|
||||
self.assertEqual(result, expected)
|
||||
self.assertEqual(result.translate(), expected)
|
||||
|
||||
def test_multiple_mod_with_named_parameter(self):
|
||||
msgid = ("%(description)s\nCommand: %(cmd)s\n"
|
||||
"Exit code: %(exit_code)s\nStdout: %(stdout)r\n"
|
||||
"Stderr: %(stderr)r")
|
||||
params = {'description': 'test1',
|
||||
'cmd': 'test2',
|
||||
'exit_code': 'test3',
|
||||
'stdout': 'test4',
|
||||
'stderr': 'test5'}
|
||||
|
||||
# Run string interpolation the first time to make a new Message
|
||||
first = self.message(msgid) % params
|
||||
|
||||
# Run string interpolation on the new Message, to replicate
|
||||
# one of the error paths with some Exception classes we've
|
||||
# implemented in OpenStack. We should receive a second Message
|
||||
# object, but the translation results should be the same.
|
||||
#
|
||||
# The production code that triggers this problem does something
|
||||
# like:
|
||||
#
|
||||
# msg = _('there was a problem %(name)s') % {'name': 'some value'}
|
||||
# LOG.error(msg)
|
||||
# raise BadExceptionClass(msg)
|
||||
#
|
||||
# where BadExceptionClass does something like:
|
||||
#
|
||||
# class BadExceptionClass(Exception):
|
||||
# def __init__(self, msg, **kwds):
|
||||
# super(BadExceptionClass, self).__init__(msg % kwds)
|
||||
#
|
||||
expected = first % {}
|
||||
|
||||
# Base message id should be the same
|
||||
self.assertEqual(first.msgid, expected.msgid)
|
||||
|
||||
# Preserved arguments should be the same
|
||||
self.assertEqual(first.params, expected.params)
|
||||
|
||||
# Should have different objects
|
||||
self.assertIsNot(expected, first)
|
||||
|
||||
# Final translations should be the same
|
||||
self.assertEqual(expected.translate(), first.translate())
|
||||
|
||||
def test_mod_with_named_parameters_no_space(self):
|
||||
msgid = ("Request: %(method)s http://%(server)s:"
|
||||
"%(port)s%(url)s with headers %(headers)s")
|
||||
params = {'method': 'POST',
|
||||
'server': 'test1',
|
||||
'port': 1234,
|
||||
'url': 'test2',
|
||||
'headers': {'h1': 'val1'}}
|
||||
|
||||
result = self.message(msgid) % params
|
||||
|
||||
expected = msgid % params
|
||||
self.assertEqual(result, expected)
|
||||
self.assertEqual(result.translate(), expected)
|
||||
|
||||
def test_mod_with_dict_parameter(self):
|
||||
msgid = "Test that we can inject a dictionary %s"
|
||||
params = {'description': 'test1'}
|
||||
|
||||
result = self.message(msgid) % params
|
||||
|
||||
expected = msgid % params
|
||||
self.assertEqual(result, expected)
|
||||
self.assertEqual(result.translate(), expected)
|
||||
|
||||
def test_mod_with_integer_parameters(self):
|
||||
msgid = "Some string with params: %d"
|
||||
params = [0, 1, 10, 24124]
|
||||
|
||||
messages = []
|
||||
results = []
|
||||
for param in params:
|
||||
messages.append(msgid % param)
|
||||
results.append(self.message(msgid) % param)
|
||||
|
||||
for message, result in zip(messages, results):
|
||||
self.assertEqual(type(result), gettextutils.Message)
|
||||
self.assertEqual(result.translate(), message)
|
||||
|
||||
# simulate writing out as string
|
||||
result_str = '%s' % result.translate()
|
||||
self.assertEqual(result_str, message)
|
||||
self.assertEqual(result, message)
|
||||
|
||||
def test_mod_copies_parameters(self):
|
||||
msgid = "Found object: %(current_value)s"
|
||||
changing_dict = {'current_value': 1}
|
||||
# A message created with some params
|
||||
result = self.message(msgid) % changing_dict
|
||||
# The parameters may change
|
||||
changing_dict['current_value'] = 2
|
||||
# Even if the param changes when the message is
|
||||
# translated it should use the original param
|
||||
self.assertEqual(result.translate(), 'Found object: 1')
|
||||
|
||||
def test_mod_deep_copies_parameters(self):
|
||||
msgid = "Found list: %(current_list)s"
|
||||
changing_list = list([1, 2, 3])
|
||||
params = {'current_list': changing_list}
|
||||
# Apply the params
|
||||
result = self.message(msgid) % params
|
||||
# Change the list
|
||||
changing_list.append(4)
|
||||
# Even though the list changed the message
|
||||
# translation should use the original list
|
||||
self.assertEqual(result.translate(), "Found list: [1, 2, 3]")
|
||||
|
||||
def test_mod_deep_copies_param_nodeep_param(self):
|
||||
msgid = "Value: %s"
|
||||
params = NoDeepCopyObject(5)
|
||||
# Apply the params
|
||||
result = self.message(msgid) % params
|
||||
self.assertEqual(result.translate(), "Value: 5")
|
||||
|
||||
def test_mod_deep_copies_param_nodeep_dict(self):
|
||||
msgid = "Values: %(val1)s %(val2)s"
|
||||
params = {'val1': 1, 'val2': NoDeepCopyObject(2)}
|
||||
# Apply the params
|
||||
result = self.message(msgid) % params
|
||||
self.assertEqual(result.translate(), "Values: 1 2")
|
||||
|
||||
# Apply again to make sure other path works as well
|
||||
params = {'val1': 3, 'val2': NoDeepCopyObject(4)}
|
||||
result = self.message(msgid) % params
|
||||
self.assertEqual(result.translate(), "Values: 3 4")
|
||||
|
||||
def test_mod_returns_a_copy(self):
|
||||
msgid = "Some msgid string: %(test1)s %(test2)s"
|
||||
message = self.message(msgid)
|
||||
m1 = message % {'test1': 'foo', 'test2': 'bar'}
|
||||
m2 = message % {'test1': 'foo2', 'test2': 'bar2'}
|
||||
|
||||
self.assertIsNot(message, m1)
|
||||
self.assertIsNot(message, m2)
|
||||
self.assertEqual(m1.translate(),
|
||||
msgid % {'test1': 'foo', 'test2': 'bar'})
|
||||
self.assertEqual(m2.translate(),
|
||||
msgid % {'test1': 'foo2', 'test2': 'bar2'})
|
||||
|
||||
def test_mod_with_none_parameter(self):
|
||||
msgid = "Some string with params: %s"
|
||||
message = self.message(msgid) % None
|
||||
self.assertEqual(msgid % None, message)
|
||||
self.assertEqual(msgid % None, message.translate())
|
||||
|
||||
def test_mod_with_missing_parameters(self):
|
||||
msgid = "Some string with params: %s %s"
|
||||
test_me = lambda: self.message(msgid) % 'just one'
|
||||
# Just like with strings missing parameters raise TypeError
|
||||
self.assertRaises(TypeError, test_me)
|
||||
|
||||
def test_mod_with_extra_parameters(self):
|
||||
msgid = "Some string with params: %(param1)s %(param2)s"
|
||||
params = {'param1': 'test',
|
||||
'param2': 'test2',
|
||||
'param3': 'notinstring'}
|
||||
|
||||
result = self.message(msgid) % params
|
||||
|
||||
expected = msgid % params
|
||||
self.assertEqual(result, expected)
|
||||
self.assertEqual(result.translate(), expected)
|
||||
|
||||
# Make sure unused params still there
|
||||
self.assertEqual(result.params.keys(), params.keys())
|
||||
|
||||
def test_mod_with_missing_named_parameters(self):
|
||||
msgid = ("Some string with params: %(param1)s %(param2)s"
|
||||
" and a missing one %(missing)s")
|
||||
params = {'param1': 'test',
|
||||
'param2': 'test2'}
|
||||
|
||||
test_me = lambda: self.message(msgid) % params
|
||||
# Just like with strings missing named parameters raise KeyError
|
||||
self.assertRaises(KeyError, test_me)
|
||||
|
||||
def test_add_disabled(self):
|
||||
msgid = "A message"
|
||||
test_me = lambda: self.message(msgid) + ' some string'
|
||||
self.assertRaises(TypeError, test_me)
|
||||
|
||||
def test_radd_disabled(self):
|
||||
msgid = "A message"
|
||||
test_me = lambda: SomeObject('test') + self.message(msgid)
|
||||
self.assertRaises(TypeError, test_me)
|
||||
|
||||
@testtools.skipIf(six.PY3, 'test specific to Python 2')
|
||||
def test_str_disabled(self):
|
||||
msgid = "A message"
|
||||
test_me = lambda: str(self.message(msgid))
|
||||
self.assertRaises(UnicodeError, test_me)
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_translate(self, mock_translation):
|
||||
en_message = 'A message in the default locale'
|
||||
es_translation = 'A message in Spanish'
|
||||
message = gettextutils.Message(en_message)
|
||||
|
||||
es_translations = {en_message: es_translation}
|
||||
translations_map = {'es': es_translations}
|
||||
translator = fakes.FakeTranslations.translator(translations_map)
|
||||
mock_translation.side_effect = translator
|
||||
|
||||
self.assertEqual(es_translation, message.translate('es'))
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_translate_message_from_unicoded_object(self, mock_translation):
|
||||
en_message = 'A message in the default locale'
|
||||
es_translation = 'A message in Spanish'
|
||||
message = gettextutils.Message(en_message)
|
||||
es_translations = {en_message: es_translation}
|
||||
translations_map = {'es': es_translations}
|
||||
translator = fakes.FakeTranslations.translator(translations_map)
|
||||
mock_translation.side_effect = translator
|
||||
|
||||
# Here we are not testing the Message object directly but the result
|
||||
# of unicoding() an object whose unicode representation is a Message
|
||||
obj = SomeObject(message)
|
||||
unicoded_obj = six.text_type(obj)
|
||||
|
||||
self.assertEqual(es_translation, unicoded_obj.translate('es'))
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_translate_multiple_languages(self, mock_translation):
|
||||
en_message = 'A message in the default locale'
|
||||
es_translation = 'A message in Spanish'
|
||||
zh_translation = 'A message in Chinese'
|
||||
message = gettextutils.Message(en_message)
|
||||
|
||||
es_translations = {en_message: es_translation}
|
||||
zh_translations = {en_message: zh_translation}
|
||||
translations_map = {'es': es_translations,
|
||||
'zh': zh_translations}
|
||||
translator = fakes.FakeTranslations.translator(translations_map)
|
||||
mock_translation.side_effect = translator
|
||||
|
||||
self.assertEqual(es_translation, message.translate('es'))
|
||||
self.assertEqual(zh_translation, message.translate('zh'))
|
||||
self.assertEqual(en_message, message.translate(None))
|
||||
self.assertEqual(en_message, message.translate('en'))
|
||||
self.assertEqual(en_message, message.translate('XX'))
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_translate_message_with_param(self, mock_translation):
|
||||
message_with_params = 'A message: %s'
|
||||
es_translation = 'A message in Spanish: %s'
|
||||
param = 'A Message param'
|
||||
|
||||
translations = {message_with_params: es_translation}
|
||||
translator = fakes.FakeTranslations.translator({'es': translations})
|
||||
mock_translation.side_effect = translator
|
||||
|
||||
msg = gettextutils.Message(message_with_params)
|
||||
msg = msg % param
|
||||
|
||||
default_translation = message_with_params % param
|
||||
expected_translation = es_translation % param
|
||||
self.assertEqual(expected_translation, msg.translate('es'))
|
||||
self.assertEqual(default_translation, msg.translate('XX'))
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_translate_message_with_object_param(self, mock_translation):
|
||||
message_with_params = 'A message: %s'
|
||||
es_translation = 'A message in Spanish: %s'
|
||||
param = 'A Message param'
|
||||
param_translation = 'A Message param in Spanish'
|
||||
|
||||
translations = {message_with_params: es_translation,
|
||||
param: param_translation}
|
||||
translator = fakes.FakeTranslations.translator({'es': translations})
|
||||
mock_translation.side_effect = translator
|
||||
|
||||
msg = gettextutils.Message(message_with_params)
|
||||
param_msg = gettextutils.Message(param)
|
||||
|
||||
# Here we are testing translation of a Message with another object
|
||||
# that can be translated via its unicode() representation, this is
|
||||
# very common for instance when modding an Exception with a Message
|
||||
obj = SomeObject(param_msg)
|
||||
msg = msg % obj
|
||||
|
||||
default_translation = message_with_params % param
|
||||
expected_translation = es_translation % param_translation
|
||||
|
||||
self.assertEqual(expected_translation, msg.translate('es'))
|
||||
self.assertEqual(default_translation, msg.translate('XX'))
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_translate_message_with_param_from_unicoded_obj(self,
|
||||
mock_translation):
|
||||
message_with_params = 'A message: %s'
|
||||
es_translation = 'A message in Spanish: %s'
|
||||
param = 'A Message param'
|
||||
|
||||
translations = {message_with_params: es_translation}
|
||||
translator = fakes.FakeTranslations.translator({'es': translations})
|
||||
mock_translation.side_effect = translator
|
||||
|
||||
msg = gettextutils.Message(message_with_params)
|
||||
msg = msg % param
|
||||
|
||||
default_translation = message_with_params % param
|
||||
expected_translation = es_translation % param
|
||||
|
||||
obj = SomeObject(msg)
|
||||
unicoded_obj = six.text_type(obj)
|
||||
|
||||
self.assertEqual(expected_translation, unicoded_obj.translate('es'))
|
||||
self.assertEqual(default_translation, unicoded_obj.translate('XX'))
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_translate_message_with_message_parameter(self, mock_translation):
|
||||
message_with_params = 'A message with param: %s'
|
||||
es_translation = 'A message with param in Spanish: %s'
|
||||
message_param = 'A message param'
|
||||
es_param_translation = 'A message param in Spanish'
|
||||
|
||||
translations = {message_with_params: es_translation,
|
||||
message_param: es_param_translation}
|
||||
translator = fakes.FakeTranslations.translator({'es': translations})
|
||||
mock_translation.side_effect = translator
|
||||
|
||||
msg = gettextutils.Message(message_with_params)
|
||||
msg_param = gettextutils.Message(message_param)
|
||||
msg = msg % msg_param
|
||||
|
||||
default_translation = message_with_params % message_param
|
||||
expected_translation = es_translation % es_param_translation
|
||||
self.assertEqual(expected_translation, msg.translate('es'))
|
||||
self.assertEqual(default_translation, msg.translate('XX'))
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_translate_message_with_message_parameters(self, mock_translation):
|
||||
message_with_params = 'A message with params: %s %s'
|
||||
es_translation = 'A message with params in Spanish: %s %s'
|
||||
message_param = 'A message param'
|
||||
es_param_translation = 'A message param in Spanish'
|
||||
another_message_param = 'Another message param'
|
||||
another_es_param_translation = 'Another message param in Spanish'
|
||||
|
||||
translations = {message_with_params: es_translation,
|
||||
message_param: es_param_translation,
|
||||
another_message_param: another_es_param_translation}
|
||||
translator = fakes.FakeTranslations.translator({'es': translations})
|
||||
mock_translation.side_effect = translator
|
||||
|
||||
msg = gettextutils.Message(message_with_params)
|
||||
param_1 = gettextutils.Message(message_param)
|
||||
param_2 = gettextutils.Message(another_message_param)
|
||||
msg = msg % (param_1, param_2)
|
||||
|
||||
default_translation = message_with_params % (message_param,
|
||||
another_message_param)
|
||||
expected_translation = es_translation % (es_param_translation,
|
||||
another_es_param_translation)
|
||||
self.assertEqual(expected_translation, msg.translate('es'))
|
||||
self.assertEqual(default_translation, msg.translate('XX'))
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_translate_message_with_named_parameters(self, mock_translation):
|
||||
message_with_params = 'A message with params: %(param)s'
|
||||
es_translation = 'A message with params in Spanish: %(param)s'
|
||||
message_param = 'A Message param'
|
||||
es_param_translation = 'A message param in Spanish'
|
||||
|
||||
translations = {message_with_params: es_translation,
|
||||
message_param: es_param_translation}
|
||||
translator = fakes.FakeTranslations.translator({'es': translations})
|
||||
mock_translation.side_effect = translator
|
||||
|
||||
msg = gettextutils.Message(message_with_params)
|
||||
msg_param = gettextutils.Message(message_param)
|
||||
msg = msg % {'param': msg_param}
|
||||
|
||||
default_translation = message_with_params % {'param': message_param}
|
||||
expected_translation = es_translation % {'param': es_param_translation}
|
||||
self.assertEqual(expected_translation, msg.translate('es'))
|
||||
self.assertEqual(default_translation, msg.translate('XX'))
|
||||
|
||||
@mock.patch('locale.getdefaultlocale')
|
||||
@mock.patch('gettext.translation')
|
||||
def test_translate_message_non_default_locale(self,
|
||||
mock_translation,
|
||||
mock_getdefaultlocale):
|
||||
message_with_params = 'A message with params: %(param)s'
|
||||
es_translation = 'A message with params in Spanish: %(param)s'
|
||||
zh_translation = 'A message with params in Chinese: %(param)s'
|
||||
fr_translation = 'A message with params in French: %(param)s'
|
||||
|
||||
message_param = 'A Message param'
|
||||
es_param_translation = 'A message param in Spanish'
|
||||
zh_param_translation = 'A message param in Chinese'
|
||||
fr_param_translation = 'A message param in French'
|
||||
|
||||
es_translations = {message_with_params: es_translation,
|
||||
message_param: es_param_translation}
|
||||
zh_translations = {message_with_params: zh_translation,
|
||||
message_param: zh_param_translation}
|
||||
fr_translations = {message_with_params: fr_translation,
|
||||
message_param: fr_param_translation}
|
||||
|
||||
translator = fakes.FakeTranslations.translator({'es': es_translations,
|
||||
'zh': zh_translations,
|
||||
'fr': fr_translations})
|
||||
mock_translation.side_effect = translator
|
||||
mock_getdefaultlocale.return_value = ('es',)
|
||||
|
||||
msg = gettextutils.Message(message_with_params)
|
||||
msg_param = gettextutils.Message(message_param)
|
||||
msg = msg % {'param': msg_param}
|
||||
|
||||
es_translation = es_translation % {'param': es_param_translation}
|
||||
zh_translation = zh_translation % {'param': zh_param_translation}
|
||||
fr_translation = fr_translation % {'param': fr_param_translation}
|
||||
|
||||
# Because sys.getdefaultlocale() was Spanish,
|
||||
# the default translation will be to Spanish
|
||||
self.assertEqual(es_translation, msg)
|
||||
self.assertEqual(es_translation, msg.translate())
|
||||
self.assertEqual(es_translation, msg.translate('es'))
|
||||
|
||||
# Translation into other locales still works
|
||||
self.assertEqual(zh_translation, msg.translate('zh'))
|
||||
self.assertEqual(fr_translation, msg.translate('fr'))
|
||||
|
||||
|
||||
class TranslationHandlerTestCase(test_base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TranslationHandlerTestCase, self).setUp()
|
||||
|
||||
self.stream = six.StringIO()
|
||||
self.destination_handler = logging.StreamHandler(self.stream)
|
||||
self.translation_handler = gettextutils.TranslationHandler('zh_CN')
|
||||
self.translation_handler.setTarget(self.destination_handler)
|
||||
|
||||
self.logger = logging.getLogger('localehander_logger')
|
||||
self.logger.setLevel(logging.DEBUG)
|
||||
self.logger.addHandler(self.translation_handler)
|
||||
|
||||
def test_set_formatter(self):
|
||||
formatter = 'some formatter'
|
||||
self.translation_handler.setFormatter(formatter)
|
||||
self.assertEqual(formatter, self.translation_handler.target.formatter)
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_emit_translated_message(self, mock_translation):
|
||||
log_message = 'A message to be logged'
|
||||
log_message_translation = 'A message to be logged in Chinese'
|
||||
translations = {log_message: log_message_translation}
|
||||
translations_map = {'zh_CN': translations}
|
||||
translator = fakes.FakeTranslations.translator(translations_map)
|
||||
mock_translation.side_effect = translator
|
||||
|
||||
msg = gettextutils.Message(log_message)
|
||||
|
||||
self.logger.info(msg)
|
||||
self.assertIn(log_message_translation, self.stream.getvalue())
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_emit_translated_message_with_args(self, mock_translation):
|
||||
log_message = 'A message to be logged %s'
|
||||
log_message_translation = 'A message to be logged in Chinese %s'
|
||||
log_arg = 'Arg to be logged'
|
||||
log_arg_translation = 'An arg to be logged in Chinese'
|
||||
|
||||
translations = {log_message: log_message_translation,
|
||||
log_arg: log_arg_translation}
|
||||
translations_map = {'zh_CN': translations}
|
||||
translator = fakes.FakeTranslations.translator(translations_map)
|
||||
mock_translation.side_effect = translator
|
||||
|
||||
msg = gettextutils.Message(log_message)
|
||||
arg = gettextutils.Message(log_arg)
|
||||
|
||||
self.logger.info(msg, arg)
|
||||
self.assertIn(log_message_translation % log_arg_translation,
|
||||
self.stream.getvalue())
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_emit_translated_message_with_named_args(self, mock_translation):
|
||||
log_message = 'A message to be logged %(arg1)s $(arg2)s'
|
||||
log_message_translation = 'Chinese msg to be logged %(arg1)s $(arg2)s'
|
||||
log_arg_1 = 'Arg1 to be logged'
|
||||
log_arg_1_translation = 'Arg1 to be logged in Chinese'
|
||||
log_arg_2 = 'Arg2 to be logged'
|
||||
log_arg_2_translation = 'Arg2 to be logged in Chinese'
|
||||
|
||||
translations = {log_message: log_message_translation,
|
||||
log_arg_1: log_arg_1_translation,
|
||||
log_arg_2: log_arg_2_translation}
|
||||
translations_map = {'zh_CN': translations}
|
||||
translator = fakes.FakeTranslations.translator(translations_map)
|
||||
mock_translation.side_effect = translator
|
||||
|
||||
msg = gettextutils.Message(log_message)
|
||||
arg_1 = gettextutils.Message(log_arg_1)
|
||||
arg_2 = gettextutils.Message(log_arg_2)
|
||||
|
||||
self.logger.info(msg, {'arg1': arg_1, 'arg2': arg_2})
|
||||
translation = log_message_translation % {'arg1': log_arg_1_translation,
|
||||
'arg2': log_arg_2_translation}
|
||||
self.assertIn(translation, self.stream.getvalue())
|
||||
|
||||
|
||||
class TranslatorFactoryTest(test_base.BaseTestCase):
|
||||
|
||||
def test_lazy(self):
|
||||
with mock.patch.object(gettextutils, 'Message') as msg:
|
||||
tf = gettextutils.TranslatorFactory('domain', lazy=True)
|
||||
tf.primary('some text')
|
||||
msg.assert_called_with('some text', domain='domain')
|
||||
|
||||
def test_py2(self):
|
||||
with mock.patch.object(six, 'PY3', False):
|
||||
with mock.patch('gettext.translation') as translation:
|
||||
trans = mock.Mock()
|
||||
translation.return_value = trans
|
||||
trans.gettext.side_effect = AssertionError(
|
||||
'should have called ugettext')
|
||||
tf = gettextutils.TranslatorFactory('domain', lazy=False)
|
||||
tf.primary('some text')
|
||||
trans.ugettext.assert_called_with('some text')
|
||||
|
||||
def test_py3(self):
|
||||
with mock.patch.object(six, 'PY3', True):
|
||||
with mock.patch('gettext.translation') as translation:
|
||||
trans = mock.Mock()
|
||||
translation.return_value = trans
|
||||
trans.ugettext.side_effect = AssertionError(
|
||||
'should have called gettext')
|
||||
tf = gettextutils.TranslatorFactory('domain', lazy=False)
|
||||
tf.primary('some text')
|
||||
trans.gettext.assert_called_with('some text')
|
||||
|
||||
def test_log_level_domain_name(self):
|
||||
with mock.patch.object(gettextutils.TranslatorFactory,
|
||||
'_make_translation_func') as mtf:
|
||||
tf = gettextutils.TranslatorFactory('domain', lazy=False)
|
||||
tf._make_log_translation_func('mylevel')
|
||||
mtf.assert_called_with('domain-log-mylevel')
|
||||
|
||||
|
||||
class LogLevelTranslationsTest(test_base.BaseTestCase):
|
||||
|
||||
def test_info(self):
|
||||
self._test('info')
|
||||
|
||||
def test_warning(self):
|
||||
self._test('warning')
|
||||
|
||||
def test_error(self):
|
||||
self._test('error')
|
||||
|
||||
def test_critical(self):
|
||||
self._test('critical')
|
||||
|
||||
def _test(self, level):
|
||||
with mock.patch.object(gettextutils.TranslatorFactory,
|
||||
'_make_translation_func') as mtf:
|
||||
tf = gettextutils.TranslatorFactory('domain', lazy=False)
|
||||
getattr(tf, 'log_%s' % level)
|
||||
mtf.assert_called_with('domain-log-%s' % level)
|
||||
|
||||
|
||||
class SomeObject(object):
|
||||
|
||||
def __init__(self, message):
|
||||
self.message = message
|
||||
|
||||
def __unicode__(self):
|
||||
return self.message
|
||||
# alias for Python 3
|
||||
__str__ = __unicode__
|
||||
|
||||
|
||||
class NoDeepCopyObject(object):
|
||||
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
if six.PY3:
|
||||
def __str__(self):
|
||||
return str(self.value)
|
||||
else:
|
||||
def __unicode__(self):
|
||||
return unicode(self.value)
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
raise TypeError('Deep Copy not supported')
|
||||
|
107
tests/test_handler.py
Normal file
107
tests/test_handler.py
Normal file
@ -0,0 +1,107 @@
|
||||
# Copyright 2012 Red Hat, Inc.
|
||||
# Copyright 2013 IBM Corp.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import logging
|
||||
|
||||
import mock
|
||||
import six
|
||||
|
||||
from oslotest import base as test_base
|
||||
|
||||
from tests import fakes
|
||||
|
||||
from oslo.i18n import gettextutils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TranslationHandlerTestCase(test_base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TranslationHandlerTestCase, self).setUp()
|
||||
|
||||
self.stream = six.StringIO()
|
||||
self.destination_handler = logging.StreamHandler(self.stream)
|
||||
self.translation_handler = gettextutils.TranslationHandler('zh_CN')
|
||||
self.translation_handler.setTarget(self.destination_handler)
|
||||
|
||||
self.logger = logging.getLogger('localehander_logger')
|
||||
self.logger.setLevel(logging.DEBUG)
|
||||
self.logger.addHandler(self.translation_handler)
|
||||
|
||||
def test_set_formatter(self):
|
||||
formatter = 'some formatter'
|
||||
self.translation_handler.setFormatter(formatter)
|
||||
self.assertEqual(formatter, self.translation_handler.target.formatter)
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_emit_translated_message(self, mock_translation):
|
||||
log_message = 'A message to be logged'
|
||||
log_message_translation = 'A message to be logged in Chinese'
|
||||
translations = {log_message: log_message_translation}
|
||||
translations_map = {'zh_CN': translations}
|
||||
translator = fakes.FakeTranslations.translator(translations_map)
|
||||
mock_translation.side_effect = translator
|
||||
|
||||
msg = gettextutils.Message(log_message)
|
||||
|
||||
self.logger.info(msg)
|
||||
self.assertIn(log_message_translation, self.stream.getvalue())
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_emit_translated_message_with_args(self, mock_translation):
|
||||
log_message = 'A message to be logged %s'
|
||||
log_message_translation = 'A message to be logged in Chinese %s'
|
||||
log_arg = 'Arg to be logged'
|
||||
log_arg_translation = 'An arg to be logged in Chinese'
|
||||
|
||||
translations = {log_message: log_message_translation,
|
||||
log_arg: log_arg_translation}
|
||||
translations_map = {'zh_CN': translations}
|
||||
translator = fakes.FakeTranslations.translator(translations_map)
|
||||
mock_translation.side_effect = translator
|
||||
|
||||
msg = gettextutils.Message(log_message)
|
||||
arg = gettextutils.Message(log_arg)
|
||||
|
||||
self.logger.info(msg, arg)
|
||||
self.assertIn(log_message_translation % log_arg_translation,
|
||||
self.stream.getvalue())
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_emit_translated_message_with_named_args(self, mock_translation):
|
||||
log_message = 'A message to be logged %(arg1)s $(arg2)s'
|
||||
log_message_translation = 'Chinese msg to be logged %(arg1)s $(arg2)s'
|
||||
log_arg_1 = 'Arg1 to be logged'
|
||||
log_arg_1_translation = 'Arg1 to be logged in Chinese'
|
||||
log_arg_2 = 'Arg2 to be logged'
|
||||
log_arg_2_translation = 'Arg2 to be logged in Chinese'
|
||||
|
||||
translations = {log_message: log_message_translation,
|
||||
log_arg_1: log_arg_1_translation,
|
||||
log_arg_2: log_arg_2_translation}
|
||||
translations_map = {'zh_CN': translations}
|
||||
translator = fakes.FakeTranslations.translator(translations_map)
|
||||
mock_translation.side_effect = translator
|
||||
|
||||
msg = gettextutils.Message(log_message)
|
||||
arg_1 = gettextutils.Message(log_arg_1)
|
||||
arg_2 = gettextutils.Message(log_arg_2)
|
||||
|
||||
self.logger.info(msg, {'arg1': arg_1, 'arg2': arg_2})
|
||||
translation = log_message_translation % {'arg1': log_arg_1_translation,
|
||||
'arg2': log_arg_2_translation}
|
||||
self.assertIn(translation, self.stream.getvalue())
|
42
tests/test_logging.py
Normal file
42
tests/test_logging.py
Normal file
@ -0,0 +1,42 @@
|
||||
# Copyright 2012 Red Hat, Inc.
|
||||
# Copyright 2013 IBM Corp.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import mock
|
||||
from oslotest import base as test_base
|
||||
|
||||
from oslo.i18n import gettextutils
|
||||
|
||||
|
||||
class LogLevelTranslationsTest(test_base.BaseTestCase):
|
||||
|
||||
def test_info(self):
|
||||
self._test('info')
|
||||
|
||||
def test_warning(self):
|
||||
self._test('warning')
|
||||
|
||||
def test_error(self):
|
||||
self._test('error')
|
||||
|
||||
def test_critical(self):
|
||||
self._test('critical')
|
||||
|
||||
def _test(self, level):
|
||||
with mock.patch.object(gettextutils.TranslatorFactory,
|
||||
'_make_translation_func') as mtf:
|
||||
tf = gettextutils.TranslatorFactory('domain', lazy=False)
|
||||
getattr(tf, 'log_%s' % level)
|
||||
mtf.assert_called_with('domain-log-%s' % level)
|
522
tests/test_message.py
Normal file
522
tests/test_message.py
Normal file
@ -0,0 +1,522 @@
|
||||
# Copyright 2012 Red Hat, Inc.
|
||||
# Copyright 2013 IBM Corp.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import logging
|
||||
|
||||
import mock
|
||||
import six
|
||||
import testtools
|
||||
|
||||
from oslotest import base as test_base
|
||||
|
||||
from tests import fakes
|
||||
from tests import utils
|
||||
|
||||
from oslo.i18n import gettextutils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MessageTestCase(test_base.BaseTestCase):
|
||||
"""Unit tests for locale Message class."""
|
||||
|
||||
@staticmethod
|
||||
def message(msg):
|
||||
return gettextutils.Message(msg)
|
||||
|
||||
def test_message_id_and_message_text(self):
|
||||
message = gettextutils.Message('1')
|
||||
self.assertEqual('1', message.msgid)
|
||||
self.assertEqual('1', message)
|
||||
message = gettextutils.Message('1', msgtext='A')
|
||||
self.assertEqual('1', message.msgid)
|
||||
self.assertEqual('A', message)
|
||||
|
||||
def test_message_is_unicode(self):
|
||||
message = self.message('some %s') % 'message'
|
||||
self.assertIsInstance(message, six.text_type)
|
||||
|
||||
@mock.patch('locale.getdefaultlocale')
|
||||
@mock.patch('gettext.translation')
|
||||
def test_create_message_non_english_default_locale(self,
|
||||
mock_translation,
|
||||
mock_getdefaultlocale):
|
||||
msgid = 'A message in English'
|
||||
es_translation = 'A message in Spanish'
|
||||
|
||||
es_translations = {msgid: es_translation}
|
||||
translations_map = {'es': es_translations}
|
||||
translator = fakes.FakeTranslations.translator(translations_map)
|
||||
mock_translation.side_effect = translator
|
||||
mock_getdefaultlocale.return_value = ('es',)
|
||||
|
||||
message = gettextutils.Message(msgid)
|
||||
|
||||
# The base representation of the message is in Spanish, as well as
|
||||
# the default translation, since the default locale was Spanish.
|
||||
self.assertEqual(es_translation, message)
|
||||
self.assertEqual(es_translation, message.translate())
|
||||
|
||||
def test_translate_returns_unicode(self):
|
||||
message = self.message('some %s') % 'message'
|
||||
self.assertIsInstance(message.translate(), six.text_type)
|
||||
|
||||
def test_mod_with_named_parameters(self):
|
||||
msgid = ("%(description)s\nCommand: %(cmd)s\n"
|
||||
"Exit code: %(exit_code)s\nStdout: %(stdout)r\n"
|
||||
"Stderr: %(stderr)r %%(something)s")
|
||||
params = {'description': 'test1',
|
||||
'cmd': 'test2',
|
||||
'exit_code': 'test3',
|
||||
'stdout': 'test4',
|
||||
'stderr': 'test5',
|
||||
'something': 'trimmed'}
|
||||
|
||||
result = self.message(msgid) % params
|
||||
|
||||
expected = msgid % params
|
||||
self.assertEqual(result, expected)
|
||||
self.assertEqual(result.translate(), expected)
|
||||
|
||||
def test_multiple_mod_with_named_parameter(self):
|
||||
msgid = ("%(description)s\nCommand: %(cmd)s\n"
|
||||
"Exit code: %(exit_code)s\nStdout: %(stdout)r\n"
|
||||
"Stderr: %(stderr)r")
|
||||
params = {'description': 'test1',
|
||||
'cmd': 'test2',
|
||||
'exit_code': 'test3',
|
||||
'stdout': 'test4',
|
||||
'stderr': 'test5'}
|
||||
|
||||
# Run string interpolation the first time to make a new Message
|
||||
first = self.message(msgid) % params
|
||||
|
||||
# Run string interpolation on the new Message, to replicate
|
||||
# one of the error paths with some Exception classes we've
|
||||
# implemented in OpenStack. We should receive a second Message
|
||||
# object, but the translation results should be the same.
|
||||
#
|
||||
# The production code that triggers this problem does something
|
||||
# like:
|
||||
#
|
||||
# msg = _('there was a problem %(name)s') % {'name': 'some value'}
|
||||
# LOG.error(msg)
|
||||
# raise BadExceptionClass(msg)
|
||||
#
|
||||
# where BadExceptionClass does something like:
|
||||
#
|
||||
# class BadExceptionClass(Exception):
|
||||
# def __init__(self, msg, **kwds):
|
||||
# super(BadExceptionClass, self).__init__(msg % kwds)
|
||||
#
|
||||
expected = first % {}
|
||||
|
||||
# Base message id should be the same
|
||||
self.assertEqual(first.msgid, expected.msgid)
|
||||
|
||||
# Preserved arguments should be the same
|
||||
self.assertEqual(first.params, expected.params)
|
||||
|
||||
# Should have different objects
|
||||
self.assertIsNot(expected, first)
|
||||
|
||||
# Final translations should be the same
|
||||
self.assertEqual(expected.translate(), first.translate())
|
||||
|
||||
def test_mod_with_named_parameters_no_space(self):
|
||||
msgid = ("Request: %(method)s http://%(server)s:"
|
||||
"%(port)s%(url)s with headers %(headers)s")
|
||||
params = {'method': 'POST',
|
||||
'server': 'test1',
|
||||
'port': 1234,
|
||||
'url': 'test2',
|
||||
'headers': {'h1': 'val1'}}
|
||||
|
||||
result = self.message(msgid) % params
|
||||
|
||||
expected = msgid % params
|
||||
self.assertEqual(result, expected)
|
||||
self.assertEqual(result.translate(), expected)
|
||||
|
||||
def test_mod_with_dict_parameter(self):
|
||||
msgid = "Test that we can inject a dictionary %s"
|
||||
params = {'description': 'test1'}
|
||||
|
||||
result = self.message(msgid) % params
|
||||
|
||||
expected = msgid % params
|
||||
self.assertEqual(result, expected)
|
||||
self.assertEqual(result.translate(), expected)
|
||||
|
||||
def test_mod_with_integer_parameters(self):
|
||||
msgid = "Some string with params: %d"
|
||||
params = [0, 1, 10, 24124]
|
||||
|
||||
messages = []
|
||||
results = []
|
||||
for param in params:
|
||||
messages.append(msgid % param)
|
||||
results.append(self.message(msgid) % param)
|
||||
|
||||
for message, result in zip(messages, results):
|
||||
self.assertEqual(type(result), gettextutils.Message)
|
||||
self.assertEqual(result.translate(), message)
|
||||
|
||||
# simulate writing out as string
|
||||
result_str = '%s' % result.translate()
|
||||
self.assertEqual(result_str, message)
|
||||
self.assertEqual(result, message)
|
||||
|
||||
def test_mod_copies_parameters(self):
|
||||
msgid = "Found object: %(current_value)s"
|
||||
changing_dict = {'current_value': 1}
|
||||
# A message created with some params
|
||||
result = self.message(msgid) % changing_dict
|
||||
# The parameters may change
|
||||
changing_dict['current_value'] = 2
|
||||
# Even if the param changes when the message is
|
||||
# translated it should use the original param
|
||||
self.assertEqual(result.translate(), 'Found object: 1')
|
||||
|
||||
def test_mod_deep_copies_parameters(self):
|
||||
msgid = "Found list: %(current_list)s"
|
||||
changing_list = list([1, 2, 3])
|
||||
params = {'current_list': changing_list}
|
||||
# Apply the params
|
||||
result = self.message(msgid) % params
|
||||
# Change the list
|
||||
changing_list.append(4)
|
||||
# Even though the list changed the message
|
||||
# translation should use the original list
|
||||
self.assertEqual(result.translate(), "Found list: [1, 2, 3]")
|
||||
|
||||
def test_mod_deep_copies_param_nodeep_param(self):
|
||||
msgid = "Value: %s"
|
||||
params = utils.NoDeepCopyObject(5)
|
||||
# Apply the params
|
||||
result = self.message(msgid) % params
|
||||
self.assertEqual(result.translate(), "Value: 5")
|
||||
|
||||
def test_mod_deep_copies_param_nodeep_dict(self):
|
||||
msgid = "Values: %(val1)s %(val2)s"
|
||||
params = {'val1': 1, 'val2': utils.NoDeepCopyObject(2)}
|
||||
# Apply the params
|
||||
result = self.message(msgid) % params
|
||||
self.assertEqual(result.translate(), "Values: 1 2")
|
||||
|
||||
# Apply again to make sure other path works as well
|
||||
params = {'val1': 3, 'val2': utils.NoDeepCopyObject(4)}
|
||||
result = self.message(msgid) % params
|
||||
self.assertEqual(result.translate(), "Values: 3 4")
|
||||
|
||||
def test_mod_returns_a_copy(self):
|
||||
msgid = "Some msgid string: %(test1)s %(test2)s"
|
||||
message = self.message(msgid)
|
||||
m1 = message % {'test1': 'foo', 'test2': 'bar'}
|
||||
m2 = message % {'test1': 'foo2', 'test2': 'bar2'}
|
||||
|
||||
self.assertIsNot(message, m1)
|
||||
self.assertIsNot(message, m2)
|
||||
self.assertEqual(m1.translate(),
|
||||
msgid % {'test1': 'foo', 'test2': 'bar'})
|
||||
self.assertEqual(m2.translate(),
|
||||
msgid % {'test1': 'foo2', 'test2': 'bar2'})
|
||||
|
||||
def test_mod_with_none_parameter(self):
|
||||
msgid = "Some string with params: %s"
|
||||
message = self.message(msgid) % None
|
||||
self.assertEqual(msgid % None, message)
|
||||
self.assertEqual(msgid % None, message.translate())
|
||||
|
||||
def test_mod_with_missing_parameters(self):
|
||||
msgid = "Some string with params: %s %s"
|
||||
test_me = lambda: self.message(msgid) % 'just one'
|
||||
# Just like with strings missing parameters raise TypeError
|
||||
self.assertRaises(TypeError, test_me)
|
||||
|
||||
def test_mod_with_extra_parameters(self):
|
||||
msgid = "Some string with params: %(param1)s %(param2)s"
|
||||
params = {'param1': 'test',
|
||||
'param2': 'test2',
|
||||
'param3': 'notinstring'}
|
||||
|
||||
result = self.message(msgid) % params
|
||||
|
||||
expected = msgid % params
|
||||
self.assertEqual(result, expected)
|
||||
self.assertEqual(result.translate(), expected)
|
||||
|
||||
# Make sure unused params still there
|
||||
self.assertEqual(result.params.keys(), params.keys())
|
||||
|
||||
def test_mod_with_missing_named_parameters(self):
|
||||
msgid = ("Some string with params: %(param1)s %(param2)s"
|
||||
" and a missing one %(missing)s")
|
||||
params = {'param1': 'test',
|
||||
'param2': 'test2'}
|
||||
|
||||
test_me = lambda: self.message(msgid) % params
|
||||
# Just like with strings missing named parameters raise KeyError
|
||||
self.assertRaises(KeyError, test_me)
|
||||
|
||||
def test_add_disabled(self):
|
||||
msgid = "A message"
|
||||
test_me = lambda: self.message(msgid) + ' some string'
|
||||
self.assertRaises(TypeError, test_me)
|
||||
|
||||
def test_radd_disabled(self):
|
||||
msgid = "A message"
|
||||
test_me = lambda: utils.SomeObject('test') + self.message(msgid)
|
||||
self.assertRaises(TypeError, test_me)
|
||||
|
||||
@testtools.skipIf(six.PY3, 'test specific to Python 2')
|
||||
def test_str_disabled(self):
|
||||
msgid = "A message"
|
||||
test_me = lambda: str(self.message(msgid))
|
||||
self.assertRaises(UnicodeError, test_me)
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_translate(self, mock_translation):
|
||||
en_message = 'A message in the default locale'
|
||||
es_translation = 'A message in Spanish'
|
||||
message = gettextutils.Message(en_message)
|
||||
|
||||
es_translations = {en_message: es_translation}
|
||||
translations_map = {'es': es_translations}
|
||||
translator = fakes.FakeTranslations.translator(translations_map)
|
||||
mock_translation.side_effect = translator
|
||||
|
||||
self.assertEqual(es_translation, message.translate('es'))
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_translate_message_from_unicoded_object(self, mock_translation):
|
||||
en_message = 'A message in the default locale'
|
||||
es_translation = 'A message in Spanish'
|
||||
message = gettextutils.Message(en_message)
|
||||
es_translations = {en_message: es_translation}
|
||||
translations_map = {'es': es_translations}
|
||||
translator = fakes.FakeTranslations.translator(translations_map)
|
||||
mock_translation.side_effect = translator
|
||||
|
||||
# Here we are not testing the Message object directly but the result
|
||||
# of unicoding() an object whose unicode representation is a Message
|
||||
obj = utils.SomeObject(message)
|
||||
unicoded_obj = six.text_type(obj)
|
||||
|
||||
self.assertEqual(es_translation, unicoded_obj.translate('es'))
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_translate_multiple_languages(self, mock_translation):
|
||||
en_message = 'A message in the default locale'
|
||||
es_translation = 'A message in Spanish'
|
||||
zh_translation = 'A message in Chinese'
|
||||
message = gettextutils.Message(en_message)
|
||||
|
||||
es_translations = {en_message: es_translation}
|
||||
zh_translations = {en_message: zh_translation}
|
||||
translations_map = {'es': es_translations,
|
||||
'zh': zh_translations}
|
||||
translator = fakes.FakeTranslations.translator(translations_map)
|
||||
mock_translation.side_effect = translator
|
||||
|
||||
self.assertEqual(es_translation, message.translate('es'))
|
||||
self.assertEqual(zh_translation, message.translate('zh'))
|
||||
self.assertEqual(en_message, message.translate(None))
|
||||
self.assertEqual(en_message, message.translate('en'))
|
||||
self.assertEqual(en_message, message.translate('XX'))
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_translate_message_with_param(self, mock_translation):
|
||||
message_with_params = 'A message: %s'
|
||||
es_translation = 'A message in Spanish: %s'
|
||||
param = 'A Message param'
|
||||
|
||||
translations = {message_with_params: es_translation}
|
||||
translator = fakes.FakeTranslations.translator({'es': translations})
|
||||
mock_translation.side_effect = translator
|
||||
|
||||
msg = gettextutils.Message(message_with_params)
|
||||
msg = msg % param
|
||||
|
||||
default_translation = message_with_params % param
|
||||
expected_translation = es_translation % param
|
||||
self.assertEqual(expected_translation, msg.translate('es'))
|
||||
self.assertEqual(default_translation, msg.translate('XX'))
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_translate_message_with_object_param(self, mock_translation):
|
||||
message_with_params = 'A message: %s'
|
||||
es_translation = 'A message in Spanish: %s'
|
||||
param = 'A Message param'
|
||||
param_translation = 'A Message param in Spanish'
|
||||
|
||||
translations = {message_with_params: es_translation,
|
||||
param: param_translation}
|
||||
translator = fakes.FakeTranslations.translator({'es': translations})
|
||||
mock_translation.side_effect = translator
|
||||
|
||||
msg = gettextutils.Message(message_with_params)
|
||||
param_msg = gettextutils.Message(param)
|
||||
|
||||
# Here we are testing translation of a Message with another object
|
||||
# that can be translated via its unicode() representation, this is
|
||||
# very common for instance when modding an Exception with a Message
|
||||
obj = utils.SomeObject(param_msg)
|
||||
msg = msg % obj
|
||||
|
||||
default_translation = message_with_params % param
|
||||
expected_translation = es_translation % param_translation
|
||||
|
||||
self.assertEqual(expected_translation, msg.translate('es'))
|
||||
self.assertEqual(default_translation, msg.translate('XX'))
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_translate_message_with_param_from_unicoded_obj(self,
|
||||
mock_translation):
|
||||
message_with_params = 'A message: %s'
|
||||
es_translation = 'A message in Spanish: %s'
|
||||
param = 'A Message param'
|
||||
|
||||
translations = {message_with_params: es_translation}
|
||||
translator = fakes.FakeTranslations.translator({'es': translations})
|
||||
mock_translation.side_effect = translator
|
||||
|
||||
msg = gettextutils.Message(message_with_params)
|
||||
msg = msg % param
|
||||
|
||||
default_translation = message_with_params % param
|
||||
expected_translation = es_translation % param
|
||||
|
||||
obj = utils.SomeObject(msg)
|
||||
unicoded_obj = six.text_type(obj)
|
||||
|
||||
self.assertEqual(expected_translation, unicoded_obj.translate('es'))
|
||||
self.assertEqual(default_translation, unicoded_obj.translate('XX'))
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_translate_message_with_message_parameter(self, mock_translation):
|
||||
message_with_params = 'A message with param: %s'
|
||||
es_translation = 'A message with param in Spanish: %s'
|
||||
message_param = 'A message param'
|
||||
es_param_translation = 'A message param in Spanish'
|
||||
|
||||
translations = {message_with_params: es_translation,
|
||||
message_param: es_param_translation}
|
||||
translator = fakes.FakeTranslations.translator({'es': translations})
|
||||
mock_translation.side_effect = translator
|
||||
|
||||
msg = gettextutils.Message(message_with_params)
|
||||
msg_param = gettextutils.Message(message_param)
|
||||
msg = msg % msg_param
|
||||
|
||||
default_translation = message_with_params % message_param
|
||||
expected_translation = es_translation % es_param_translation
|
||||
self.assertEqual(expected_translation, msg.translate('es'))
|
||||
self.assertEqual(default_translation, msg.translate('XX'))
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_translate_message_with_message_parameters(self, mock_translation):
|
||||
message_with_params = 'A message with params: %s %s'
|
||||
es_translation = 'A message with params in Spanish: %s %s'
|
||||
message_param = 'A message param'
|
||||
es_param_translation = 'A message param in Spanish'
|
||||
another_message_param = 'Another message param'
|
||||
another_es_param_translation = 'Another message param in Spanish'
|
||||
|
||||
translations = {message_with_params: es_translation,
|
||||
message_param: es_param_translation,
|
||||
another_message_param: another_es_param_translation}
|
||||
translator = fakes.FakeTranslations.translator({'es': translations})
|
||||
mock_translation.side_effect = translator
|
||||
|
||||
msg = gettextutils.Message(message_with_params)
|
||||
param_1 = gettextutils.Message(message_param)
|
||||
param_2 = gettextutils.Message(another_message_param)
|
||||
msg = msg % (param_1, param_2)
|
||||
|
||||
default_translation = message_with_params % (message_param,
|
||||
another_message_param)
|
||||
expected_translation = es_translation % (es_param_translation,
|
||||
another_es_param_translation)
|
||||
self.assertEqual(expected_translation, msg.translate('es'))
|
||||
self.assertEqual(default_translation, msg.translate('XX'))
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_translate_message_with_named_parameters(self, mock_translation):
|
||||
message_with_params = 'A message with params: %(param)s'
|
||||
es_translation = 'A message with params in Spanish: %(param)s'
|
||||
message_param = 'A Message param'
|
||||
es_param_translation = 'A message param in Spanish'
|
||||
|
||||
translations = {message_with_params: es_translation,
|
||||
message_param: es_param_translation}
|
||||
translator = fakes.FakeTranslations.translator({'es': translations})
|
||||
mock_translation.side_effect = translator
|
||||
|
||||
msg = gettextutils.Message(message_with_params)
|
||||
msg_param = gettextutils.Message(message_param)
|
||||
msg = msg % {'param': msg_param}
|
||||
|
||||
default_translation = message_with_params % {'param': message_param}
|
||||
expected_translation = es_translation % {'param': es_param_translation}
|
||||
self.assertEqual(expected_translation, msg.translate('es'))
|
||||
self.assertEqual(default_translation, msg.translate('XX'))
|
||||
|
||||
@mock.patch('locale.getdefaultlocale')
|
||||
@mock.patch('gettext.translation')
|
||||
def test_translate_message_non_default_locale(self,
|
||||
mock_translation,
|
||||
mock_getdefaultlocale):
|
||||
message_with_params = 'A message with params: %(param)s'
|
||||
es_translation = 'A message with params in Spanish: %(param)s'
|
||||
zh_translation = 'A message with params in Chinese: %(param)s'
|
||||
fr_translation = 'A message with params in French: %(param)s'
|
||||
|
||||
message_param = 'A Message param'
|
||||
es_param_translation = 'A message param in Spanish'
|
||||
zh_param_translation = 'A message param in Chinese'
|
||||
fr_param_translation = 'A message param in French'
|
||||
|
||||
es_translations = {message_with_params: es_translation,
|
||||
message_param: es_param_translation}
|
||||
zh_translations = {message_with_params: zh_translation,
|
||||
message_param: zh_param_translation}
|
||||
fr_translations = {message_with_params: fr_translation,
|
||||
message_param: fr_param_translation}
|
||||
|
||||
translator = fakes.FakeTranslations.translator({'es': es_translations,
|
||||
'zh': zh_translations,
|
||||
'fr': fr_translations})
|
||||
mock_translation.side_effect = translator
|
||||
mock_getdefaultlocale.return_value = ('es',)
|
||||
|
||||
msg = gettextutils.Message(message_with_params)
|
||||
msg_param = gettextutils.Message(message_param)
|
||||
msg = msg % {'param': msg_param}
|
||||
|
||||
es_translation = es_translation % {'param': es_param_translation}
|
||||
zh_translation = zh_translation % {'param': zh_param_translation}
|
||||
fr_translation = fr_translation % {'param': fr_param_translation}
|
||||
|
||||
# Because sys.getdefaultlocale() was Spanish,
|
||||
# the default translation will be to Spanish
|
||||
self.assertEqual(es_translation, msg)
|
||||
self.assertEqual(es_translation, msg.translate())
|
||||
self.assertEqual(es_translation, msg.translate('es'))
|
||||
|
||||
# Translation into other locales still works
|
||||
self.assertEqual(zh_translation, msg.translate('zh'))
|
||||
self.assertEqual(fr_translation, msg.translate('fr'))
|
42
tests/utils.py
Normal file
42
tests/utils.py
Normal file
@ -0,0 +1,42 @@
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import six
|
||||
|
||||
|
||||
class SomeObject(object):
|
||||
|
||||
def __init__(self, message):
|
||||
self.message = message
|
||||
|
||||
def __unicode__(self):
|
||||
return self.message
|
||||
# alias for Python 3
|
||||
__str__ = __unicode__
|
||||
|
||||
|
||||
class NoDeepCopyObject(object):
|
||||
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
if six.PY3:
|
||||
def __str__(self):
|
||||
return str(self.value)
|
||||
else:
|
||||
def __unicode__(self):
|
||||
return unicode(self.value)
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
raise TypeError('Deep Copy not supported')
|
Loading…
x
Reference in New Issue
Block a user