Fixed #26677 -- Converted some i18n tests to use disposable FS tree.
This allows makemessages/compilemessages tests in `test_extraction.py` and `test_compilation.py` to actually run isolated from each other (unaffected by stray FS objects left by cleanup actions failures, debug sessions, etc.) and to take advantage of the parallel tests execution feature like most of the Django test suite. `test_percents.py` gets slightly refactored to not inherit from the new machinery which sets up every test case to copy and run under a temporary tree.
This commit is contained in:
parent
83120af2c1
commit
faeeb84edf
|
@ -5,6 +5,7 @@ import gettext as gettext_module
|
|||
import os
|
||||
import shutil
|
||||
import stat
|
||||
import tempfile
|
||||
import unittest
|
||||
from subprocess import Popen
|
||||
|
||||
|
@ -23,15 +24,25 @@ from django.utils.six import StringIO
|
|||
from django.utils.translation import ugettext
|
||||
|
||||
has_msgfmt = find_command('msgfmt')
|
||||
source_code_dir = os.path.dirname(upath(__file__))
|
||||
|
||||
|
||||
@unittest.skipUnless(has_msgfmt, 'msgfmt is mandatory for compilation tests')
|
||||
class MessageCompilationTests(SimpleTestCase):
|
||||
|
||||
test_dir = os.path.abspath(os.path.join(os.path.dirname(upath(__file__)), '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)
|
||||
|
||||
|
@ -114,13 +125,12 @@ class MultipleLocaleCompilationTests(MessageCompilationTests):
|
|||
|
||||
class ExcludedLocaleCompilationTests(MessageCompilationTests):
|
||||
|
||||
test_dir = os.path.abspath(os.path.join(os.path.dirname(upath(__file__)), 'exclude'))
|
||||
work_subdir = 'exclude'
|
||||
|
||||
MO_FILE = 'locale/%s/LC_MESSAGES/django.mo'
|
||||
|
||||
def setUp(self):
|
||||
super(ExcludedLocaleCompilationTests, self).setUp()
|
||||
|
||||
shutil.copytree('canned_locale', 'locale')
|
||||
self.addCleanup(self._rmrf, os.path.join(self.test_dir, 'locale'))
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import io
|
|||
import os
|
||||
import re
|
||||
import shutil
|
||||
import tempfile
|
||||
import time
|
||||
import warnings
|
||||
from unittest import SkipTest, skipUnless
|
||||
|
@ -17,7 +18,6 @@ from django.core.management.commands.makemessages import \
|
|||
Command as MakeMessagesCommand
|
||||
from django.core.management.utils import find_command
|
||||
from django.test import SimpleTestCase, mock, override_settings
|
||||
from django.test.testcases import SerializeMixin
|
||||
from django.test.utils import captured_stderr, captured_stdout
|
||||
from django.utils import six
|
||||
from django.utils._os import upath
|
||||
|
@ -27,23 +27,36 @@ from django.utils.translation import TranslatorCommentWarning
|
|||
|
||||
LOCALE = 'de'
|
||||
has_xgettext = find_command('xgettext')
|
||||
this_directory = os.path.dirname(upath(__file__))
|
||||
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')
|
||||
class ExtractorTests(SerializeMixin, SimpleTestCase):
|
||||
class ExtractorTests(POFileAssertionMixin, SimpleTestCase):
|
||||
|
||||
# makemessages scans the current working directory and writes in the
|
||||
# locale subdirectory. There aren't any options to control this. As a
|
||||
# consequence tests can't run in parallel. Since i18n tests run in less
|
||||
# than 4 seconds, serializing them with SerializeMixin is acceptable.
|
||||
lockfile = __file__
|
||||
|
||||
test_dir = os.path.abspath(os.path.join(this_directory, 'commands'))
|
||||
work_subdir = 'commands'
|
||||
|
||||
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):
|
||||
|
@ -73,19 +86,6 @@ class ExtractorTests(SerializeMixin, SimpleTestCase):
|
|||
po_contents = fp.read()
|
||||
return output, po_contents
|
||||
|
||||
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)
|
||||
|
||||
def assertMsgIdPlural(self, msgid, haystack, use_quotes=True):
|
||||
return self._assertPoKeyword('msgid_plural', msgid, haystack, use_quotes=use_quotes)
|
||||
|
||||
|
@ -464,16 +464,15 @@ class JavascriptExtractorTests(ExtractorTests):
|
|||
self.assertMsgId("quz", po_contents)
|
||||
self.assertMsgId("foobar", po_contents)
|
||||
|
||||
@override_settings(
|
||||
STATIC_ROOT=os.path.join(this_directory, 'commands', 'static/'),
|
||||
MEDIA_ROOT=os.path.join(this_directory, 'commands', 'media_root/'))
|
||||
def test_media_static_dirs_ignored(self):
|
||||
"""
|
||||
Regression test for #23583.
|
||||
"""
|
||||
_, po_contents = self._run_makemessages(domain='djangojs')
|
||||
self.assertMsgId("Static content inside app should be included.", po_contents)
|
||||
self.assertNotMsgId("Content from STATIC_ROOT should not be included", po_contents)
|
||||
with override_settings(STATIC_ROOT=os.path.join(self.test_dir, 'static/'),
|
||||
MEDIA_ROOT=os.path.join(self.test_dir, 'media_root/')):
|
||||
_, po_contents = self._run_makemessages(domain='djangojs')
|
||||
self.assertMsgId("Static content inside app should be included.", po_contents)
|
||||
self.assertNotMsgId("Content from STATIC_ROOT should not be included", po_contents)
|
||||
|
||||
@override_settings(STATIC_ROOT=None, MEDIA_ROOT='')
|
||||
def test_default_root_settings(self):
|
||||
|
@ -509,13 +508,12 @@ class IgnoredExtractorTests(ExtractorTests):
|
|||
self.assertIn("ignoring file xxx_ignored.html", out)
|
||||
self.assertNotMsgId('This should be ignored too.', po_contents)
|
||||
|
||||
@override_settings(
|
||||
STATIC_ROOT=os.path.join(this_directory, 'commands', 'static/'),
|
||||
MEDIA_ROOT=os.path.join(this_directory, 'commands', 'media_root/'))
|
||||
def test_media_static_dirs_ignored(self):
|
||||
out, _ = self._run_makemessages()
|
||||
self.assertIn("ignoring directory static", out)
|
||||
self.assertIn("ignoring directory media_root", out)
|
||||
with override_settings(STATIC_ROOT=os.path.join(self.test_dir, 'static/'),
|
||||
MEDIA_ROOT=os.path.join(self.test_dir, 'media_root/')):
|
||||
out, _ = self._run_makemessages()
|
||||
self.assertIn("ignoring directory static", out)
|
||||
self.assertIn("ignoring directory media_root", out)
|
||||
|
||||
|
||||
class SymlinkExtractorTests(ExtractorTests):
|
||||
|
@ -721,11 +719,11 @@ class MultipleLocaleExtractionTests(ExtractorTests):
|
|||
|
||||
class ExcludedLocaleExtractionTests(ExtractorTests):
|
||||
|
||||
work_subdir = 'exclude'
|
||||
|
||||
LOCALES = ['en', 'fr', 'it']
|
||||
PO_FILE = 'locale/%s/LC_MESSAGES/django.po'
|
||||
|
||||
test_dir = os.path.abspath(os.path.join(this_directory, 'exclude'))
|
||||
|
||||
def _set_times_for_all_po_files(self):
|
||||
"""
|
||||
Set access and modification times to the Unix epoch time for all the .po files.
|
||||
|
@ -775,9 +773,7 @@ class ExcludedLocaleExtractionTests(ExtractorTests):
|
|||
|
||||
class CustomLayoutExtractionTests(ExtractorTests):
|
||||
|
||||
def setUp(self):
|
||||
super(CustomLayoutExtractionTests, self).setUp()
|
||||
self.test_dir = os.path.join(this_directory, 'project_dir')
|
||||
work_subdir = 'project_dir'
|
||||
|
||||
def test_no_locale_raises(self):
|
||||
os.chdir(self.test_dir)
|
||||
|
@ -785,31 +781,29 @@ class CustomLayoutExtractionTests(ExtractorTests):
|
|||
with self.assertRaisesMessage(management.CommandError, msg):
|
||||
management.call_command('makemessages', locale=LOCALE, verbosity=0)
|
||||
|
||||
@override_settings(
|
||||
LOCALE_PATHS=[os.path.join(this_directory, 'project_dir', 'project_locale')],
|
||||
)
|
||||
def test_project_locale_paths(self):
|
||||
"""
|
||||
Test that:
|
||||
* translations for an app containing a locale folder are stored in that folder
|
||||
* translations outside of that app are in LOCALE_PATHS[0]
|
||||
"""
|
||||
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)
|
||||
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)
|
||||
project_de_locale = os.path.join(
|
||||
self.test_dir, 'project_locale', 'de', 'LC_MESSAGES', 'django.po')
|
||||
app_de_locale = os.path.join(
|
||||
self.test_dir, 'app_with_locale', 'locale', 'de', 'LC_MESSAGES', 'django.po')
|
||||
self.assertTrue(os.path.exists(project_de_locale))
|
||||
self.assertTrue(os.path.exists(app_de_locale))
|
||||
management.call_command('makemessages', locale=[LOCALE], verbosity=0)
|
||||
project_de_locale = os.path.join(
|
||||
self.test_dir, 'project_locale', 'de', 'LC_MESSAGES', 'django.po')
|
||||
app_de_locale = os.path.join(
|
||||
self.test_dir, 'app_with_locale', 'locale', 'de', 'LC_MESSAGES', 'django.po')
|
||||
self.assertTrue(os.path.exists(project_de_locale))
|
||||
self.assertTrue(os.path.exists(app_de_locale))
|
||||
|
||||
with open(project_de_locale, 'r') as fp:
|
||||
po_contents = force_text(fp.read())
|
||||
self.assertMsgId('This app has no locale directory', po_contents)
|
||||
self.assertMsgId('This is a project-level string', po_contents)
|
||||
with open(app_de_locale, 'r') as fp:
|
||||
po_contents = force_text(fp.read())
|
||||
self.assertMsgId('This app has a locale directory', po_contents)
|
||||
with open(project_de_locale, 'r') as fp:
|
||||
po_contents = force_text(fp.read())
|
||||
self.assertMsgId('This app has no locale directory', po_contents)
|
||||
self.assertMsgId('This is a project-level string', po_contents)
|
||||
with open(app_de_locale, 'r') as fp:
|
||||
po_contents = force_text(fp.read())
|
||||
self.assertMsgId('This app has a locale directory', po_contents)
|
||||
|
|
|
@ -9,7 +9,7 @@ from django.utils._os import upath
|
|||
from django.utils.encoding import force_text
|
||||
from django.utils.translation import activate, get_language, trans_real
|
||||
|
||||
from .test_extraction import ExtractorTests
|
||||
from .test_extraction import POFileAssertionMixin
|
||||
|
||||
SAMPLEPROJECT_DIR = os.path.join(os.path.dirname(os.path.abspath(upath(__file__))), 'sampleproject')
|
||||
SAMPLEPROJECT_LOCALE = os.path.join(SAMPLEPROJECT_DIR, 'locale')
|
||||
|
@ -31,7 +31,7 @@ class FrenchTestCase(SimpleTestCase):
|
|||
activate(self._language)
|
||||
|
||||
|
||||
class ExtractingStringsWithPercentSigns(FrenchTestCase, ExtractorTests):
|
||||
class ExtractingStringsWithPercentSigns(POFileAssertionMixin, FrenchTestCase):
|
||||
"""
|
||||
Tests the extracted string found in the gettext catalog.
|
||||
|
||||
|
|
Loading…
Reference in New Issue