Refs #26677 -- Simplified i18n test cleanups.

The fact that we aren't dealing with the Django source tree anymore
allows us to drop several tearDown()/addCleanup() calls that were
concerned with removing apiece files/dirs/symlinks created by test
cases, as we are covered by the removal of the parent temporary tree
anyways.

Thanks Tim Graham for advice and review.
This commit is contained in:
Ramiro Morales 2016-06-09 10:08:31 -03:00
parent 0451dcc2eb
commit bb7bb379e8
4 changed files with 77 additions and 161 deletions

View File

@ -3,9 +3,7 @@ from __future__ import unicode_literals
import gettext as gettext_module import gettext as gettext_module
import os import os
import shutil
import stat import stat
import tempfile
import unittest import unittest
from subprocess import Popen from subprocess import Popen
@ -18,43 +16,20 @@ from django.core.management.utils import find_command
from django.test import SimpleTestCase, mock, override_settings from django.test import SimpleTestCase, mock, override_settings
from django.test.utils import captured_stderr, captured_stdout from django.test.utils import captured_stderr, captured_stdout
from django.utils import six, translation from django.utils import six, translation
from django.utils._os import upath
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.six import StringIO from django.utils.six import StringIO
from django.utils.translation import ugettext from django.utils.translation import ugettext
from .utils import RunInTmpDirMixin, copytree
has_msgfmt = find_command('msgfmt') has_msgfmt = find_command('msgfmt')
source_code_dir = os.path.dirname(upath(__file__))
@unittest.skipUnless(has_msgfmt, 'msgfmt is mandatory for compilation tests') @unittest.skipUnless(has_msgfmt, 'msgfmt is mandatory for compilation tests')
class MessageCompilationTests(SimpleTestCase): class MessageCompilationTests(RunInTmpDirMixin, SimpleTestCase):
work_subdir = 'commands' work_subdir = 'commands'
def setUp(self):
self._cwd = os.getcwd()
self.work_dir = tempfile.mkdtemp(prefix='i18n_')
self.test_dir = os.path.abspath(os.path.join(self.work_dir, self.work_subdir))
shutil.copytree(os.path.join(source_code_dir, self.work_subdir), self.test_dir)
# Make sure we step out of the temporary working tree before we
# remove it as we might be pulling the rug from under our own feet
# othewise. Rhis is especially true on Windows.
# Remember cleanup actions registered with addCleanup() are called in
# reverse so this ordering is important:
self.addCleanup(self._rmrf, self.test_dir)
self.addCleanup(os.chdir, self._cwd)
os.chdir(self.test_dir)
def _rmrf(self, dname):
if os.path.commonprefix([self.test_dir, os.path.abspath(dname)]) != self.test_dir:
return
shutil.rmtree(dname)
def rmfile(self, filepath):
if os.path.exists(filepath):
os.remove(filepath)
class PoFileTests(MessageCompilationTests): class PoFileTests(MessageCompilationTests):
@ -87,10 +62,6 @@ class PoFileContentsTests(MessageCompilationTests):
LOCALE = 'fr' LOCALE = 'fr'
MO_FILE = 'locale/%s/LC_MESSAGES/django.mo' % LOCALE MO_FILE = 'locale/%s/LC_MESSAGES/django.mo' % LOCALE
def setUp(self):
super(PoFileContentsTests, self).setUp()
self.addCleanup(os.unlink, os.path.join(self.test_dir, self.MO_FILE))
def test_percent_symbol_in_po_file(self): def test_percent_symbol_in_po_file(self):
call_command('compilemessages', locale=[self.LOCALE], stdout=StringIO()) call_command('compilemessages', locale=[self.LOCALE], stdout=StringIO())
self.assertTrue(os.path.exists(self.MO_FILE)) self.assertTrue(os.path.exists(self.MO_FILE))
@ -106,8 +77,6 @@ class MultipleLocaleCompilationTests(MessageCompilationTests):
localedir = os.path.join(self.test_dir, 'locale') localedir = os.path.join(self.test_dir, 'locale')
self.MO_FILE_HR = os.path.join(localedir, 'hr/LC_MESSAGES/django.mo') self.MO_FILE_HR = os.path.join(localedir, 'hr/LC_MESSAGES/django.mo')
self.MO_FILE_FR = os.path.join(localedir, 'fr/LC_MESSAGES/django.mo') self.MO_FILE_FR = os.path.join(localedir, 'fr/LC_MESSAGES/django.mo')
self.addCleanup(self.rmfile, os.path.join(localedir, self.MO_FILE_HR))
self.addCleanup(self.rmfile, os.path.join(localedir, self.MO_FILE_FR))
def test_one_locale(self): def test_one_locale(self):
with override_settings(LOCALE_PATHS=[os.path.join(self.test_dir, 'locale')]): with override_settings(LOCALE_PATHS=[os.path.join(self.test_dir, 'locale')]):
@ -131,8 +100,7 @@ class ExcludedLocaleCompilationTests(MessageCompilationTests):
def setUp(self): def setUp(self):
super(ExcludedLocaleCompilationTests, self).setUp() super(ExcludedLocaleCompilationTests, self).setUp()
shutil.copytree('canned_locale', 'locale') copytree('canned_locale', 'locale')
self.addCleanup(self._rmrf, os.path.join(self.test_dir, 'locale'))
def test_command_help(self): def test_command_help(self):
with captured_stdout(), captured_stderr(): with captured_stdout(), captured_stderr():
@ -170,15 +138,11 @@ class ExcludedLocaleCompilationTests(MessageCompilationTests):
class CompilationErrorHandling(MessageCompilationTests): class CompilationErrorHandling(MessageCompilationTests):
def test_error_reported_by_msgfmt(self): def test_error_reported_by_msgfmt(self):
# po file contains wrong po formatting. # po file contains wrong po formatting.
mo_file = 'locale/ja/LC_MESSAGES/django.mo'
self.addCleanup(self.rmfile, os.path.join(self.test_dir, mo_file))
with self.assertRaises(CommandError): with self.assertRaises(CommandError):
call_command('compilemessages', locale=['ja'], verbosity=0) call_command('compilemessages', locale=['ja'], verbosity=0)
def test_msgfmt_error_including_non_ascii(self): def test_msgfmt_error_including_non_ascii(self):
# po file contains invalid msgstr content (triggers non-ascii error content). # po file contains invalid msgstr content (triggers non-ascii error content).
mo_file = 'locale/ko/LC_MESSAGES/django.mo'
self.addCleanup(self.rmfile, os.path.join(self.test_dir, mo_file))
# Make sure the output of msgfmt is unaffected by the current locale. # Make sure the output of msgfmt is unaffected by the current locale.
env = os.environ.copy() env = os.environ.copy()
env.update({str('LANG'): str('C')}) env.update({str('LANG'): str('C')})
@ -202,11 +166,6 @@ class ProjectAndAppTests(MessageCompilationTests):
PROJECT_MO_FILE = 'locale/%s/LC_MESSAGES/django.mo' % LOCALE PROJECT_MO_FILE = 'locale/%s/LC_MESSAGES/django.mo' % LOCALE
APP_MO_FILE = 'app_with_locale/locale/%s/LC_MESSAGES/django.mo' % LOCALE APP_MO_FILE = 'app_with_locale/locale/%s/LC_MESSAGES/django.mo' % LOCALE
def setUp(self):
super(ProjectAndAppTests, self).setUp()
self.addCleanup(self.rmfile, os.path.join(self.test_dir, self.PROJECT_MO_FILE))
self.addCleanup(self.rmfile, os.path.join(self.test_dir, self.APP_MO_FILE))
class FuzzyTranslationTest(ProjectAndAppTests): class FuzzyTranslationTest(ProjectAndAppTests):

View File

@ -5,12 +5,10 @@ import io
import os import os
import re import re
import shutil import shutil
import tempfile
import time import time
import warnings import warnings
from unittest import SkipTest, skipUnless from unittest import SkipTest, skipUnless
from django.conf import settings
from django.core import management from django.core import management
from django.core.management import execute_from_command_line from django.core.management import execute_from_command_line
from django.core.management.base import CommandError from django.core.management.base import CommandError
@ -20,62 +18,23 @@ from django.core.management.utils import find_command
from django.test import SimpleTestCase, mock, override_settings from django.test import SimpleTestCase, mock, override_settings
from django.test.utils import captured_stderr, captured_stdout from django.test.utils import captured_stderr, captured_stdout
from django.utils import six from django.utils import six
from django.utils._os import upath
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.six import StringIO from django.utils.six import StringIO
from django.utils.translation import TranslatorCommentWarning from django.utils.translation import TranslatorCommentWarning
from .utils import POFileAssertionMixin, RunInTmpDirMixin, copytree
LOCALE = 'de' LOCALE = 'de'
has_xgettext = find_command('xgettext') has_xgettext = find_command('xgettext')
source_code_dir = os.path.dirname(upath(__file__))
class POFileAssertionMixin(object):
def _assertPoKeyword(self, keyword, expected_value, haystack, use_quotes=True):
q = '"'
if use_quotes:
expected_value = '"%s"' % expected_value
q = "'"
needle = '%s %s' % (keyword, expected_value)
expected_value = re.escape(expected_value)
return self.assertTrue(re.search('^%s %s' % (keyword, expected_value), haystack, re.MULTILINE),
'Could not find %(q)s%(n)s%(q)s in generated PO file' % {'n': needle, 'q': q})
def assertMsgId(self, msgid, haystack, use_quotes=True):
return self._assertPoKeyword('msgid', msgid, haystack, use_quotes=use_quotes)
@skipUnless(has_xgettext, 'xgettext is mandatory for extraction tests') @skipUnless(has_xgettext, 'xgettext is mandatory for extraction tests')
class ExtractorTests(POFileAssertionMixin, SimpleTestCase): class ExtractorTests(POFileAssertionMixin, RunInTmpDirMixin, SimpleTestCase):
work_subdir = 'commands' work_subdir = 'commands'
PO_FILE = 'locale/%s/LC_MESSAGES/django.po' % LOCALE PO_FILE = 'locale/%s/LC_MESSAGES/django.po' % LOCALE
def setUp(self):
self.work_dir = tempfile.mkdtemp(prefix='i18n_')
self.test_dir = os.path.abspath(os.path.join(self.work_dir, self.work_subdir))
shutil.copytree(os.path.join(source_code_dir, self.work_subdir), self.test_dir)
self._cwd = os.getcwd()
def _rmrf(self, dname):
if os.path.commonprefix([self.test_dir, os.path.abspath(dname)]) != self.test_dir:
return
shutil.rmtree(dname)
def rmfile(self, filepath):
if os.path.exists(filepath):
os.remove(filepath)
def tearDown(self):
os.chdir(self.test_dir)
try:
self._rmrf('locale/%s' % LOCALE)
except OSError:
pass
os.chdir(self._cwd)
def _run_makemessages(self, **options): def _run_makemessages(self, **options):
os.chdir(self.test_dir) os.chdir(self.test_dir)
out = StringIO() out = StringIO()
@ -177,7 +136,6 @@ class ExtractorTests(POFileAssertionMixin, SimpleTestCase):
class BasicExtractorTests(ExtractorTests): class BasicExtractorTests(ExtractorTests):
def test_comments_extractor(self): def test_comments_extractor(self):
os.chdir(self.test_dir)
management.call_command('makemessages', locale=[LOCALE], verbosity=0) management.call_command('makemessages', locale=[LOCALE], verbosity=0)
self.assertTrue(os.path.exists(self.PO_FILE)) self.assertTrue(os.path.exists(self.PO_FILE))
with io.open(self.PO_FILE, 'r', encoding='utf-8') as fp: with io.open(self.PO_FILE, 'r', encoding='utf-8') as fp:
@ -211,7 +169,6 @@ class BasicExtractorTests(ExtractorTests):
) )
def test_special_char_extracted(self): def test_special_char_extracted(self):
os.chdir(self.test_dir)
management.call_command('makemessages', locale=[LOCALE], verbosity=0) management.call_command('makemessages', locale=[LOCALE], verbosity=0)
self.assertTrue(os.path.exists(self.PO_FILE)) self.assertTrue(os.path.exists(self.PO_FILE))
with io.open(self.PO_FILE, 'r', encoding='utf-8') as fp: with io.open(self.PO_FILE, 'r', encoding='utf-8') as fp:
@ -219,7 +176,6 @@ class BasicExtractorTests(ExtractorTests):
self.assertMsgId("Non-breaking space\u00a0:", po_contents) self.assertMsgId("Non-breaking space\u00a0:", po_contents)
def test_blocktrans_trimmed(self): def test_blocktrans_trimmed(self):
os.chdir(self.test_dir)
management.call_command('makemessages', locale=[LOCALE], verbosity=0) management.call_command('makemessages', locale=[LOCALE], verbosity=0)
self.assertTrue(os.path.exists(self.PO_FILE)) self.assertTrue(os.path.exists(self.PO_FILE))
with open(self.PO_FILE, 'r') as fp: with open(self.PO_FILE, 'r') as fp:
@ -237,7 +193,6 @@ class BasicExtractorTests(ExtractorTests):
self.assertTrue(MakeMessagesCommand.leave_locale_alone) self.assertTrue(MakeMessagesCommand.leave_locale_alone)
def test_extraction_error(self): def test_extraction_error(self):
os.chdir(self.test_dir)
msg = ( msg = (
'Translation blocks must not include other block tags: blocktrans ' 'Translation blocks must not include other block tags: blocktrans '
'(file %s, line 3)' % os.path.join('templates', 'template_with_error.tpl') '(file %s, line 3)' % os.path.join('templates', 'template_with_error.tpl')
@ -248,9 +203,7 @@ class BasicExtractorTests(ExtractorTests):
self.assertFalse(os.path.exists('./templates/template_with_error.tpl.py')) self.assertFalse(os.path.exists('./templates/template_with_error.tpl.py'))
def test_unicode_decode_error(self): def test_unicode_decode_error(self):
os.chdir(self.test_dir)
shutil.copyfile('./not_utf8.sample', './not_utf8.txt') shutil.copyfile('./not_utf8.sample', './not_utf8.txt')
self.addCleanup(self.rmfile, os.path.join(self.test_dir, 'not_utf8.txt'))
out = StringIO() out = StringIO()
management.call_command('makemessages', locale=[LOCALE], stdout=out) management.call_command('makemessages', locale=[LOCALE], stdout=out)
self.assertIn("UnicodeDecodeError: skipped file not_utf8.txt in .", self.assertIn("UnicodeDecodeError: skipped file not_utf8.txt in .",
@ -258,9 +211,7 @@ class BasicExtractorTests(ExtractorTests):
def test_extraction_warning(self): def test_extraction_warning(self):
"""test xgettext warning about multiple bare interpolation placeholders""" """test xgettext warning about multiple bare interpolation placeholders"""
os.chdir(self.test_dir)
shutil.copyfile('./code.sample', './code_sample.py') shutil.copyfile('./code.sample', './code_sample.py')
self.addCleanup(self.rmfile, os.path.join(self.test_dir, 'code_sample.py'))
out = StringIO() out = StringIO()
management.call_command('makemessages', locale=[LOCALE], stdout=out) management.call_command('makemessages', locale=[LOCALE], stdout=out)
self.assertIn("code_sample.py:4", force_text(out.getvalue())) self.assertIn("code_sample.py:4", force_text(out.getvalue()))
@ -271,7 +222,6 @@ class BasicExtractorTests(ExtractorTests):
{% trans %} and {% blocktrans %} template tags. {% trans %} and {% blocktrans %} template tags.
Refs #14806. Refs #14806.
""" """
os.chdir(self.test_dir)
management.call_command('makemessages', locale=[LOCALE], verbosity=0) management.call_command('makemessages', locale=[LOCALE], verbosity=0)
self.assertTrue(os.path.exists(self.PO_FILE)) self.assertTrue(os.path.exists(self.PO_FILE))
with open(self.PO_FILE, 'r') as fp: with open(self.PO_FILE, 'r') as fp:
@ -302,7 +252,6 @@ class BasicExtractorTests(ExtractorTests):
self.assertMsgId("Translatable literal #8d %(a)s", po_contents) self.assertMsgId("Translatable literal #8d %(a)s", po_contents)
def test_context_in_single_quotes(self): def test_context_in_single_quotes(self):
os.chdir(self.test_dir)
management.call_command('makemessages', locale=[LOCALE], verbosity=0) management.call_command('makemessages', locale=[LOCALE], verbosity=0)
self.assertTrue(os.path.exists(self.PO_FILE)) self.assertTrue(os.path.exists(self.PO_FILE))
with open(self.PO_FILE, 'r') as fp: with open(self.PO_FILE, 'r') as fp:
@ -317,7 +266,6 @@ class BasicExtractorTests(ExtractorTests):
def test_template_comments(self): def test_template_comments(self):
"""Template comment tags on the same line of other constructs (#19552)""" """Template comment tags on the same line of other constructs (#19552)"""
os.chdir(self.test_dir)
# Test detection/end user reporting of old, incorrect templates # Test detection/end user reporting of old, incorrect templates
# translator comments syntax # translator comments syntax
with warnings.catch_warnings(record=True) as ws: with warnings.catch_warnings(record=True) as ws:
@ -432,9 +380,7 @@ class BasicExtractorTests(ExtractorTests):
def test_po_file_encoding_when_updating(self): def test_po_file_encoding_when_updating(self):
"""Update of PO file doesn't corrupt it with non-UTF-8 encoding on Python3+Windows (#23271)""" """Update of PO file doesn't corrupt it with non-UTF-8 encoding on Python3+Windows (#23271)"""
BR_PO_BASE = 'locale/pt_BR/LC_MESSAGES/django' BR_PO_BASE = 'locale/pt_BR/LC_MESSAGES/django'
os.chdir(self.test_dir)
shutil.copyfile(BR_PO_BASE + '.pristine', BR_PO_BASE + '.po') shutil.copyfile(BR_PO_BASE + '.pristine', BR_PO_BASE + '.po')
self.addCleanup(self.rmfile, os.path.join(self.test_dir, 'locale', 'pt_BR', 'LC_MESSAGES', 'django.po'))
management.call_command('makemessages', locale=['pt_BR'], verbosity=0) management.call_command('makemessages', locale=['pt_BR'], verbosity=0)
self.assertTrue(os.path.exists(BR_PO_BASE + '.po')) self.assertTrue(os.path.exists(BR_PO_BASE + '.po'))
with io.open(BR_PO_BASE + '.po', 'r', encoding='utf-8') as fp: with io.open(BR_PO_BASE + '.po', 'r', encoding='utf-8') as fp:
@ -447,7 +393,6 @@ class JavascriptExtractorTests(ExtractorTests):
PO_FILE = 'locale/%s/LC_MESSAGES/djangojs.po' % LOCALE PO_FILE = 'locale/%s/LC_MESSAGES/djangojs.po' % LOCALE
def test_javascript_literals(self): def test_javascript_literals(self):
os.chdir(self.test_dir)
_, po_contents = self._run_makemessages(domain='djangojs') _, po_contents = self._run_makemessages(domain='djangojs')
self.assertMsgId('This literal should be included.', po_contents) self.assertMsgId('This literal should be included.', po_contents)
self.assertMsgId('gettext_noop should, too.', po_contents) self.assertMsgId('gettext_noop should, too.', po_contents)
@ -522,15 +467,6 @@ class SymlinkExtractorTests(ExtractorTests):
super(SymlinkExtractorTests, self).setUp() super(SymlinkExtractorTests, self).setUp()
self.symlinked_dir = os.path.join(self.test_dir, 'templates_symlinked') self.symlinked_dir = os.path.join(self.test_dir, 'templates_symlinked')
def tearDown(self):
super(SymlinkExtractorTests, self).tearDown()
os.chdir(self.test_dir)
try:
os.remove(self.symlinked_dir)
except OSError:
pass
os.chdir(self._cwd)
def test_symlink(self): def test_symlink(self):
# On Python < 3.2 os.symlink() exists only on Unix # On Python < 3.2 os.symlink() exists only on Unix
if hasattr(os, 'symlink'): if hasattr(os, 'symlink'):
@ -561,17 +497,7 @@ class CopyPluralFormsExtractorTests(ExtractorTests):
PO_FILE_ES = 'locale/es/LC_MESSAGES/django.po' PO_FILE_ES = 'locale/es/LC_MESSAGES/django.po'
def tearDown(self):
super(CopyPluralFormsExtractorTests, self).tearDown()
os.chdir(self.test_dir)
try:
self._rmrf('locale/es')
except OSError:
pass
os.chdir(self._cwd)
def test_copy_plural_forms(self): def test_copy_plural_forms(self):
os.chdir(self.test_dir)
management.call_command('makemessages', locale=[LOCALE], verbosity=0) management.call_command('makemessages', locale=[LOCALE], verbosity=0)
self.assertTrue(os.path.exists(self.PO_FILE)) self.assertTrue(os.path.exists(self.PO_FILE))
with open(self.PO_FILE, 'r') as fp: with open(self.PO_FILE, 'r') as fp:
@ -580,7 +506,6 @@ class CopyPluralFormsExtractorTests(ExtractorTests):
def test_override_plural_forms(self): def test_override_plural_forms(self):
"""Ticket #20311.""" """Ticket #20311."""
os.chdir(self.test_dir)
management.call_command('makemessages', locale=['es'], extensions=['djtpl'], verbosity=0) management.call_command('makemessages', locale=['es'], extensions=['djtpl'], verbosity=0)
self.assertTrue(os.path.exists(self.PO_FILE_ES)) self.assertTrue(os.path.exists(self.PO_FILE_ES))
with io.open(self.PO_FILE_ES, 'r', encoding='utf-8') as fp: with io.open(self.PO_FILE_ES, 'r', encoding='utf-8') as fp:
@ -594,7 +519,6 @@ class CopyPluralFormsExtractorTests(ExtractorTests):
found inside a {% trans %} tag and also in another file inside a found inside a {% trans %} tag and also in another file inside a
{% blocktrans %} with a plural (#17375). {% blocktrans %} with a plural (#17375).
""" """
os.chdir(self.test_dir)
management.call_command('makemessages', locale=[LOCALE], extensions=['html', 'djtpl'], verbosity=0) management.call_command('makemessages', locale=[LOCALE], extensions=['html', 'djtpl'], verbosity=0)
self.assertTrue(os.path.exists(self.PO_FILE)) self.assertTrue(os.path.exists(self.PO_FILE))
with open(self.PO_FILE, 'r') as fp: with open(self.PO_FILE, 'r') as fp:
@ -607,7 +531,6 @@ class CopyPluralFormsExtractorTests(ExtractorTests):
class NoWrapExtractorTests(ExtractorTests): class NoWrapExtractorTests(ExtractorTests):
def test_no_wrap_enabled(self): def test_no_wrap_enabled(self):
os.chdir(self.test_dir)
management.call_command('makemessages', locale=[LOCALE], verbosity=0, no_wrap=True) management.call_command('makemessages', locale=[LOCALE], verbosity=0, no_wrap=True)
self.assertTrue(os.path.exists(self.PO_FILE)) self.assertTrue(os.path.exists(self.PO_FILE))
with open(self.PO_FILE, 'r') as fp: with open(self.PO_FILE, 'r') as fp:
@ -619,7 +542,6 @@ class NoWrapExtractorTests(ExtractorTests):
) )
def test_no_wrap_disabled(self): def test_no_wrap_disabled(self):
os.chdir(self.test_dir)
management.call_command('makemessages', locale=[LOCALE], verbosity=0, no_wrap=False) management.call_command('makemessages', locale=[LOCALE], verbosity=0, no_wrap=False)
self.assertTrue(os.path.exists(self.PO_FILE)) self.assertTrue(os.path.exists(self.PO_FILE))
with open(self.PO_FILE, 'r') as fp: with open(self.PO_FILE, 'r') as fp:
@ -636,14 +558,12 @@ class LocationCommentsTests(ExtractorTests):
def test_no_location_enabled(self): def test_no_location_enabled(self):
"""Behavior is correct if --no-location switch is specified. See #16903.""" """Behavior is correct if --no-location switch is specified. See #16903."""
os.chdir(self.test_dir)
management.call_command('makemessages', locale=[LOCALE], verbosity=0, no_location=True) management.call_command('makemessages', locale=[LOCALE], verbosity=0, no_location=True)
self.assertTrue(os.path.exists(self.PO_FILE)) self.assertTrue(os.path.exists(self.PO_FILE))
self.assertLocationCommentNotPresent(self.PO_FILE, None, 'test.html') self.assertLocationCommentNotPresent(self.PO_FILE, None, 'test.html')
def test_no_location_disabled(self): def test_no_location_disabled(self):
"""Behavior is correct if --no-location switch isn't specified.""" """Behavior is correct if --no-location switch isn't specified."""
os.chdir(self.test_dir)
management.call_command('makemessages', locale=[LOCALE], verbosity=0, no_location=False) management.call_command('makemessages', locale=[LOCALE], verbosity=0, no_location=False)
self.assertTrue(os.path.exists(self.PO_FILE)) self.assertTrue(os.path.exists(self.PO_FILE))
# #16903 -- Standard comment with source file relative path should be present # #16903 -- Standard comment with source file relative path should be present
@ -654,7 +574,6 @@ class LocationCommentsTests(ExtractorTests):
Ensure no leaky paths in comments, e.g. #: path\to\file.html.py:123 Ensure no leaky paths in comments, e.g. #: path\to\file.html.py:123
Refs #21209/#26341. Refs #21209/#26341.
""" """
os.chdir(self.test_dir)
management.call_command('makemessages', locale=[LOCALE], verbosity=0) management.call_command('makemessages', locale=[LOCALE], verbosity=0)
self.assertTrue(os.path.exists(self.PO_FILE)) self.assertTrue(os.path.exists(self.PO_FILE))
with open(self.PO_FILE, 'r') as fp: with open(self.PO_FILE, 'r') as fp:
@ -668,28 +587,16 @@ class KeepPotFileExtractorTests(ExtractorTests):
POT_FILE = 'locale/django.pot' POT_FILE = 'locale/django.pot'
def tearDown(self):
super(KeepPotFileExtractorTests, self).tearDown()
os.chdir(self.test_dir)
try:
os.unlink(self.POT_FILE)
except OSError:
pass
os.chdir(self._cwd)
def test_keep_pot_disabled_by_default(self): def test_keep_pot_disabled_by_default(self):
os.chdir(self.test_dir)
management.call_command('makemessages', locale=[LOCALE], verbosity=0) management.call_command('makemessages', locale=[LOCALE], verbosity=0)
self.assertFalse(os.path.exists(self.POT_FILE)) self.assertFalse(os.path.exists(self.POT_FILE))
def test_keep_pot_explicitly_disabled(self): def test_keep_pot_explicitly_disabled(self):
os.chdir(self.test_dir)
management.call_command('makemessages', locale=[LOCALE], verbosity=0, management.call_command('makemessages', locale=[LOCALE], verbosity=0,
keep_pot=False) keep_pot=False)
self.assertFalse(os.path.exists(self.POT_FILE)) self.assertFalse(os.path.exists(self.POT_FILE))
def test_keep_pot_enabled(self): def test_keep_pot_enabled(self):
os.chdir(self.test_dir)
management.call_command('makemessages', locale=[LOCALE], verbosity=0, management.call_command('makemessages', locale=[LOCALE], verbosity=0,
keep_pot=True) keep_pot=True)
self.assertTrue(os.path.exists(self.POT_FILE)) self.assertTrue(os.path.exists(self.POT_FILE))
@ -700,18 +607,7 @@ class MultipleLocaleExtractionTests(ExtractorTests):
PO_FILE_DE = 'locale/de/LC_MESSAGES/django.po' PO_FILE_DE = 'locale/de/LC_MESSAGES/django.po'
LOCALES = ['pt', 'de', 'ch'] LOCALES = ['pt', 'de', 'ch']
def tearDown(self):
super(MultipleLocaleExtractionTests, self).tearDown()
os.chdir(self.test_dir)
for locale in self.LOCALES:
try:
self._rmrf('locale/%s' % locale)
except OSError:
pass
os.chdir(self._cwd)
def test_multiple_locales(self): def test_multiple_locales(self):
os.chdir(self.test_dir)
management.call_command('makemessages', locale=['pt', 'de'], verbosity=0) management.call_command('makemessages', locale=['pt', 'de'], verbosity=0)
self.assertTrue(os.path.exists(self.PO_FILE_PT)) self.assertTrue(os.path.exists(self.PO_FILE_PT))
self.assertTrue(os.path.exists(self.PO_FILE_DE)) self.assertTrue(os.path.exists(self.PO_FILE_DE))
@ -733,10 +629,8 @@ class ExcludedLocaleExtractionTests(ExtractorTests):
def setUp(self): def setUp(self):
super(ExcludedLocaleExtractionTests, self).setUp() super(ExcludedLocaleExtractionTests, self).setUp()
os.chdir(self.test_dir) # ExtractorTests.tearDown() takes care of restoring. copytree('canned_locale', 'locale')
shutil.copytree('canned_locale', 'locale')
self._set_times_for_all_po_files() self._set_times_for_all_po_files()
self.addCleanup(self._rmrf, os.path.join(self.test_dir, 'locale'))
def test_command_help(self): def test_command_help(self):
with captured_stdout(), captured_stderr(): with captured_stdout(), captured_stderr():
@ -776,7 +670,6 @@ class CustomLayoutExtractionTests(ExtractorTests):
work_subdir = 'project_dir' work_subdir = 'project_dir'
def test_no_locale_raises(self): def test_no_locale_raises(self):
os.chdir(self.test_dir)
msg = "Unable to find a locale path to store translations for file" msg = "Unable to find a locale path to store translations for file"
with self.assertRaisesMessage(management.CommandError, msg): with self.assertRaisesMessage(management.CommandError, msg):
management.call_command('makemessages', locale=LOCALE, verbosity=0) management.call_command('makemessages', locale=LOCALE, verbosity=0)
@ -788,10 +681,6 @@ class CustomLayoutExtractionTests(ExtractorTests):
* translations outside of that app are in LOCALE_PATHS[0] * translations outside of that app are in LOCALE_PATHS[0]
""" """
with override_settings(LOCALE_PATHS=[os.path.join(self.test_dir, 'project_locale')]): with override_settings(LOCALE_PATHS=[os.path.join(self.test_dir, 'project_locale')]):
os.chdir(self.test_dir)
self.addCleanup(shutil.rmtree, os.path.join(settings.LOCALE_PATHS[0], LOCALE), True)
self.addCleanup(shutil.rmtree, os.path.join(self.test_dir, 'app_with_locale', 'locale', LOCALE), True)
management.call_command('makemessages', locale=[LOCALE], verbosity=0) management.call_command('makemessages', locale=[LOCALE], verbosity=0)
project_de_locale = os.path.join( project_de_locale = os.path.join(
self.test_dir, 'project_locale', 'de', 'LC_MESSAGES', 'django.po') self.test_dir, 'project_locale', 'de', 'LC_MESSAGES', 'django.po')

View File

@ -9,7 +9,8 @@ from django.utils._os import upath
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.translation import activate, get_language, trans_real from django.utils.translation import activate, get_language, trans_real
from .test_extraction import POFileAssertionMixin from .utils import POFileAssertionMixin
SAMPLEPROJECT_DIR = os.path.join(os.path.dirname(os.path.abspath(upath(__file__))), 'sampleproject') SAMPLEPROJECT_DIR = os.path.join(os.path.dirname(os.path.abspath(upath(__file__))), 'sampleproject')
SAMPLEPROJECT_LOCALE = os.path.join(SAMPLEPROJECT_DIR, 'locale') SAMPLEPROJECT_LOCALE = os.path.join(SAMPLEPROJECT_DIR, 'locale')

67
tests/i18n/utils.py Normal file
View File

@ -0,0 +1,67 @@
import os
import re
import shutil
import tempfile
from django.utils._os import upath
source_code_dir = os.path.dirname(upath(__file__))
def copytree(src, dst):
shutil.copytree(src, dst, ignore=shutil.ignore_patterns('*.pyc', '__pycache__'))
class POFileAssertionMixin(object):
def _assertPoKeyword(self, keyword, expected_value, haystack, use_quotes=True):
q = '"'
if use_quotes:
expected_value = '"%s"' % expected_value
q = "'"
needle = '%s %s' % (keyword, expected_value)
expected_value = re.escape(expected_value)
return self.assertTrue(
re.search('^%s %s' % (keyword, expected_value), haystack, re.MULTILINE),
'Could not find %(q)s%(n)s%(q)s in generated PO file' % {'n': needle, 'q': q}
)
def assertMsgId(self, msgid, haystack, use_quotes=True):
return self._assertPoKeyword('msgid', msgid, haystack, use_quotes=use_quotes)
class RunInTmpDirMixin(object):
"""
Allow i18n tests that need to generate .po/.mo files to run in an isolated
temporary filesystem tree created by tempfile.mkdtemp() that contains a
clean copy of the relevant test code.
Test classes using this mixin need to define a `work_subdir` attribute
which designates the subdir under `tests/i18n/` that will be copied to the
temporary tree from which its test cases will run.
The setUp() method sets the current working dir to the temporary tree.
It'll be removed when cleaning up.
"""
def setUp(self):
self._cwd = os.getcwd()
self.work_dir = tempfile.mkdtemp(prefix='i18n_')
self.test_dir = os.path.abspath(os.path.join(self.work_dir, self.work_subdir))
copytree(os.path.join(source_code_dir, self.work_subdir), self.test_dir)
# Step out of the temporary working tree before removing it to avoid
# deletion problems on Windows. Cleanup actions registered with
# addCleanup() are called in reverse so preserve this ordering.
self.addCleanup(self._rmrf, self.test_dir)
self.addCleanup(os.chdir, self._cwd)
os.chdir(self.test_dir)
def _rmrf(self, dname):
if os.path.commonprefix([self.test_dir, os.path.abspath(dname)]) != self.test_dir:
return
shutil.rmtree(dname)
def rmfile(self, filepath):
if os.path.exists(filepath):
os.remove(filepath)