# -*- coding: utf-8 -*- import filecmp import hashlib import os import shutil import vcr try: # Python 3 from urllib.parse import urlencode except ImportError: # Python 2 from urllib import urlencode from django.conf import settings from django.dispatch import receiver from django.core.exceptions import ImproperlyConfigured from django.http import Http404 from django.test import TestCase, RequestFactory, override_settings from django.test.client import Client from django import VERSION from django.urls import reverse, resolve from django.utils.encoding import force_bytes import six from rosetta.signals import entry_changed, post_save from rosetta.storage import get_storage from rosetta import views class RosettaTestCase(TestCase): def __init__(self, *args, **kwargs): super(RosettaTestCase, self).__init__(*args, **kwargs) self.curdir = os.path.dirname(__file__) self.dest_file = os.path.normpath( os.path.join(self.curdir, '../locale/xx/LC_MESSAGES/django.po') ) def setUp(self): from django.contrib.auth.models import User user = User.objects.create_superuser('test_admin', 'test@test.com', 'test_password') user2 = User.objects.create_superuser('test_admin2', 'test@test2.com', 'test_password') user3 = User.objects.create_superuser('test_admin3', 'test@test2.com', 'test_password') user3.is_staff = False user3.save() self.user = user self.client2 = Client() self.client.login(username=user.username, password='test_password') self.client2.login(username=user2.username, password='test_password') shutil.copy(self.dest_file, self.dest_file + '.orig') def tearDown(self): shutil.move(self.dest_file + '.orig', self.dest_file) def copy_po_file_from_template(self, template_path): """Utility method to handle swapping a template po file in place for testing. """ src_path = os.path.normpath(os.path.join(self.curdir, template_path)) shutil.copy(src_path, self.dest_file) @property def xx_form_url(self): kwargs = {'po_filter': 'third-party', 'lang_id': 'xx', 'idx': 0} return reverse('rosetta-form', kwargs=kwargs) @property def all_file_list_url(self): return reverse('rosetta-file-list', kwargs={'po_filter': 'all'}) @property def project_file_list_url(self): return reverse('rosetta-file-list', kwargs={'po_filter': 'project'}) @property def third_party_file_list_url(self): return reverse('rosetta-file-list', kwargs={'po_filter': 'third-party'}) def test_1_ListLoading(self): r = self.client.get(self.third_party_file_list_url) self.assertTrue( os.path.normpath('rosetta/locale/xx/LC_MESSAGES/django.po') in str(r.content) ) @override_settings(ROSETTA_LANGUAGES=( ('xx', 'dummy language'), )) def test_2_PickFile(self): r = self.client.get(self.xx_form_url) self.assertTrue('dummy language' in str(r.content)) def test_3_DownloadZIP(self): kwargs = {'po_filter': 'third-party', 'lang_id': 'xx', 'idx': 0} url = reverse('rosetta-download-file', kwargs=kwargs) r = self.client.get(url) self.assertTrue('content-type' in r._headers.keys()) self.assertTrue('application/x-zip' in r._headers.get('content-type')) @override_settings(ROSETTA_LANGUAGES=( ('xx', 'dummy language'), )) def test_4_DoChanges(self): self.copy_po_file_from_template('./django.po.template') untranslated_url = self.xx_form_url + '?msg_filter=untranslated' translated_url = self.xx_form_url + '?msg_filter=translated' # Load the template file r = self.client.get(untranslated_url) # make sure both strings are untranslated self.assertTrue('dummy language' in str(r.content)) self.assertTrue('String 1' in str(r.content)) self.assertTrue('String 2' in str(r.content)) self.assertTrue('m_e48f149a8b2e8baa81b816c0edf93890' in str(r.content)) # post a translation data = {'m_e48f149a8b2e8baa81b816c0edf93890': 'Hello, world'} r = self.client.post(untranslated_url, data, follow=True) # reload all untranslated strings r = self.client.get(untranslated_url) # the translated string no longer is up for translation self.assertTrue('String 1' in str(r.content)) self.assertTrue('String 2' not in str(r.content)) # display only translated strings r = self.client.get(translated_url) # The translation was persisted self.assertTrue('String 1' not in str(r.content)) self.assertTrue('String 2' in str(r.content)) self.assertTrue('Hello, world' in str(r.content)) @override_settings(ROSETTA_LANGUAGES=( ('xx', 'dummy language'), )) def test_5_TestIssue67(self): # issue 67: http://code.google.com/p/django-rosetta/issues/detail?id=67 self.copy_po_file_from_template('./django.po.issue67.template') # Make sure the plurals string is valid with open(self.dest_file, 'rb') as f_: content = f_.read() self.assertTrue('Hello, world' not in six.text_type(content)) self.assertTrue('|| n%100>=20) ? 1 : 2)' in six.text_type(content)) del(content) r = self.client.get(self.xx_form_url + '?msg_filter=untranslated') # make sure all strings are untranslated self.assertTrue('dummy language' in str(r.content)) self.assertTrue('String 1' in str(r.content)) self.assertTrue('String 2' in str(r.content)) self.assertTrue('m_e48f149a8b2e8baa81b816c0edf93890' in str(r.content)) # post a translation data = {'m_e48f149a8b2e8baa81b816c0edf93890': 'Hello, world'} self.client.post(self.xx_form_url + '?msg_filter=untranslated', data) # Make sure the plurals string is still valid with open(self.dest_file, 'rb') as f_: content = f_.read() self.assertTrue('Hello, world' in str(content)) self.assertTrue('|| n%100>=20) ? 1 : 2)' in str(content)) self.assertTrue('or n%100>=20) ? 1 : 2)' not in str(content)) del(content) @override_settings(ROSETTA_LANGUAGES=( ('xx', 'dummy language'), )) def test_6_ExcludedApps(self): with self.settings(ROSETTA_EXCLUDED_APPLICATIONS=('rosetta', )): r = self.client.get(self.third_party_file_list_url) self.assertNotContains(r, 'rosetta/locale/xx/LC_MESSAGES/django.po') with self.settings(ROSETTA_EXCLUDED_APPLICATIONS=()): r = self.client.get(self.third_party_file_list_url) self.assertContains(r, 'rosetta/locale/xx/LC_MESSAGES/django.po') def test_7_selfInApplist(self): r = self.client.get(self.third_party_file_list_url) self.assertContains(r, 'rosetta/locale/xx/LC_MESSAGES/django.po') r = self.client.get(self.project_file_list_url) self.assertNotContains(r, 'rosetta/locale/xx/LC_MESSAGES/django.po') @override_settings(ROSETTA_LANGUAGES=( ('xx', 'dummy language'), )) def test_8_hideObsoletes(self): r = self.client.get(self.xx_form_url) # not in listing for p in range(1, 5): r = self.client.get(self.xx_form_url + '?page=%d' % p) self.assertTrue('dummy language' in str(r.content)) self.assertTrue('Les deux' not in str(r.content)) r = self.client.get(self.xx_form_url + '?query=Les%20Deux') self.assertContains(r, 'dummy language') self.assertNotContains(r, 'Les deux') def test_9_concurrency(self): self.copy_po_file_from_template('./django.po.template') translated_url = self.xx_form_url + '?msg_filter=translated' untranslated_url = self.xx_form_url + '?msg_filter=untranslated' # Load the template file r = self.client.get(untranslated_url) r2 = self.client2.get(untranslated_url) self.assertContains(r, 'String 1') self.assertContains(r2, 'String 1') self.assertContains(r, 'm_08e4e11e2243d764fc45a5a4fba5d0f2') data = {'m_08e4e11e2243d764fc45a5a4fba5d0f2': 'Hello, world'} r = self.client.post(untranslated_url, data, follow=True) # Client 2 reloads, forces a reload of the catalog; untranslated # string1 is now translated r2 = self.client2.get(untranslated_url, follow=True) self.assertNotContains(r, 'String 1') self.assertContains(r, 'String 2') self.assertNotContains(r2, 'String 1') self.assertContains(r2, 'String 2') r = self.client.get(untranslated_url) r2 = self.client2.get(untranslated_url) self.assertContains(r2, 'String 2') self.assertContains(r2, 'm_e48f149a8b2e8baa81b816c0edf93890') self.assertContains(r, 'String 2') self.assertContains(r, 'm_e48f149a8b2e8baa81b816c0edf93890') # client 2 posts! data = {'m_e48f149a8b2e8baa81b816c0edf93890': 'Hello, world, from client two!'} r2 = self.client2.post(untranslated_url, data, follow=True) self.assertNotContains(r2, 'save-conflict') # uh-oh here comes client 1 data = {'m_e48f149a8b2e8baa81b816c0edf93890': 'Hello, world, from client one!'} r = self.client.post(untranslated_url, data, follow=True) # An error message is displayed self.assertContains(r, 'save-conflict') # client 2 won with open(self.dest_file, 'r') as po_file: pofile_content = po_file.read() self.assertTrue('Hello, world, from client two!' in pofile_content) # Both clients show all strings, error messages are gone r = self.client.get(translated_url) self.assertNotContains(r, 'save-conflict') r2 = self.client2.get(translated_url) self.assertNotContains(r2, 'save-conflict') r = self.client.get(self.xx_form_url) self.assertNotContains(r, 'save-conflict') r2 = self.client2.get(self.xx_form_url) self.assertNotContains(r2, 'save-conflict') # Both have client's two version self.assertContains(r, 'Hello, world, from client two!') self.assertContains(r2, 'Hello, world, from client two!') def test_10_issue_79_num_entries(self): self.copy_po_file_from_template('./django.po.issue79.template') r = self.client.get(self.third_party_file_list_url) self.assertContains(r, '1') self.assertContains(r, '0%') self.assertContains(r, '1') def test_11_issue_80_tab_indexes(self): r = self.client.get(self.xx_form_url) self.assertTrue('tabindex="3"' in str(r.content)) def test_12_issue_82_staff_user(self): self.client3 = Client() self.client3.login(username='test_admin3', password='test_password') # When auth is required, we get an empty response (and a redirect) with # this user. with self.settings(ROSETTA_REQUIRES_AUTH=True): r = self.client3.get(self.xx_form_url) self.assertFalse(r.content) self.assertEqual(r.status_code, 302) # When it's not required, we sail through. with self.settings(ROSETTA_REQUIRES_AUTH=False): r = self.client3.get(self.xx_form_url) self.assertTrue(r.content) self.assertEqual(r.status_code, 200) @override_settings(ROSETTA_LANGUAGES=(('fr', 'French'), ('xx', 'Dummy Language'),)) def test_13_catalog_filters(self): r = self.client.get(self.third_party_file_list_url) self.assertTrue( os.path.normpath('rosetta/locale/xx/LC_MESSAGES/django.po') in str(r.content) ) self.assertTrue(('contrib') not in str(r.content)) url = reverse('rosetta-file-list', kwargs={'po_filter': 'django'}) r = self.client.get(url) self.assertTrue( os.path.normpath('rosetta/locale/xx/LC_MESSAGES/django.po') not in str(r.content) ) self.assertTrue(('contrib') in str(r.content)) r = self.client.get(self.all_file_list_url) self.assertTrue( os.path.normpath('rosetta/locale/xx/LC_MESSAGES/django.po') in str(r.content) ) self.assertTrue(('contrib') in str(r.content)) r = self.client.get(self.project_file_list_url) self.assertTrue( os.path.normpath('rosetta/locale/xx/LC_MESSAGES/django.po') not in str(r.content) ) self.assertTrue(('contrib') not in str(r.content)) def test_14_issue_99_context_and_comments(self): r = self.client.get(self.xx_form_url) self.assertTrue('This is a text of the base template' in str(r.content)) self.assertTrue('Context hint' in str(r.content)) def test_15_issue_87_entry_changed_signal(self): self.copy_po_file_from_template('./django.po.template') r = self.client.get(self.xx_form_url) @receiver(entry_changed) def test_receiver(sender, **kwargs): self.test_old_msgstr = kwargs.get('old_msgstr') self.test_new_msgstr = sender.msgstr self.test_msg_id = sender.msgid self.assertTrue('m_e48f149a8b2e8baa81b816c0edf93890' in str(r.content)) # post a translation data = {'m_e48f149a8b2e8baa81b816c0edf93890': 'Hello, world'} self.client.post(self.xx_form_url, data) self.assertTrue(self.test_old_msgstr == '') self.assertTrue(self.test_new_msgstr == 'Hello, world') self.assertTrue(self.test_msg_id == 'String 2') del(self.test_old_msgstr, self.test_new_msgstr, self.test_msg_id) def test_16_issue_101_post_save_signal(self): self.copy_po_file_from_template('./django.po.template') r = self.client.get(self.xx_form_url) @receiver(post_save) def test_receiver(sender, **kwargs): self.test_sig_lang = kwargs.get('language_code') self.assertTrue('m_e48f149a8b2e8baa81b816c0edf93890' in str(r.content)) # post a translation data = {'m_e48f149a8b2e8baa81b816c0edf93890': 'Hello, world'} self.client.post(self.xx_form_url, data) self.assertTrue(self.test_sig_lang == 'xx') del(self.test_sig_lang) def test_17_issue_103_post_save_signal_has_request(self): self.copy_po_file_from_template('./django.po.template') r = self.client.get(self.xx_form_url) @receiver(post_save) def test_receiver(sender, **kwargs): self.test_16_has_request = 'request' in kwargs self.assertTrue('m_e48f149a8b2e8baa81b816c0edf93890' in str(r.content)) # post a translation data = {'m_e48f149a8b2e8baa81b816c0edf93890': 'Hello, world'} r = self.client.post(self.xx_form_url, data) self.assertTrue(self.test_16_has_request) del(self.test_16_has_request) def test_18_Test_Issue_gh24(self): self.copy_po_file_from_template('./django.po.issue24gh.template') r = self.client.get(self.xx_form_url) self.assertTrue('m_bb9d8fe6159187b9ea494c1b313d23d4' in str(r.content)) # Post a translation, it should have properly wrapped lines data = {'m_bb9d8fe6159187b9ea494c1b313d23d4': 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean ' 'commodo ligula eget dolor. Aenean massa. Cum sociis natoque ' 'penatibus et magnis dis parturient montes, nascetur ridiculus ' 'mus. Donec quam felis, ultricies nec, pellentesque eu, pretium ' 'quis, sem. Nulla consequat massa quis enim. Donec pede justo, ' 'fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, ' 'rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum ' 'felis eu pede mollis pretium.'} r = self.client.post(self.xx_form_url, data) with open(self.dest_file, 'r') as po_file: pofile_content = po_file.read() self.assertTrue('"pede mollis pretium."' in pofile_content) # Again, with unwrapped lines self.copy_po_file_from_template('./django.po.issue24gh.template') with self.settings(ROSETTA_POFILE_WRAP_WIDTH=0): r = self.client.get(self.xx_form_url) self.assertTrue('m_bb9d8fe6159187b9ea494c1b313d23d4' in str(r.content)) r = self.client.post(self.xx_form_url, data) with open(self.dest_file, 'r') as po_file: pofile_content = po_file.read() self.assertTrue('felis eu pede mollis pretium."' in pofile_content) def test_19_Test_Issue_gh34(self): self.copy_po_file_from_template('./django.po.issue34gh.template') r = self.client.get(self.xx_form_url) self.assertTrue('m_ff7060c1a9aae9c42af4d54ac8551f67_1' in str(r.content)) self.assertTrue('m_ff7060c1a9aae9c42af4d54ac8551f67_0' in str(r.content)) self.assertTrue('m_09f7e02f1290be211da707a266f153b3' in str(r.content)) # post a translation, it should have properly wrapped lines data = { 'm_ff7060c1a9aae9c42af4d54ac8551f67_0': 'Foo %s', 'm_ff7060c1a9aae9c42af4d54ac8551f67_1': 'Bar %s', 'm_09f7e02f1290be211da707a266f153b3': 'Salut', } r = self.client.post(self.xx_form_url, data) with open(self.dest_file, 'r') as po_file: pofile_content = po_file.read() self.assertTrue('msgstr "Salut\\n"' in pofile_content) self.assertTrue('msgstr[0] ""\n"\\n"\n"Foo %s\\n"' in pofile_content) self.assertTrue('msgstr[1] ""\n"\\n"\n"Bar %s\\n"' in pofile_content) @override_settings( SESSION_ENGINE='django.contrib.sessions.backends.signed_cookies', ROSETTA_STORAGE_CLASS='rosetta.storage.CacheRosettaStorage', ) def test_20_Test_Issue_gh38(self): # (Have to log in again, since our session engine changed) self.client.login(username='test_admin', password='test_password') self.assertTrue('django.contrib.sessions.middleware.SessionMiddleware' in settings.MIDDLEWARE) # Only one backend to test: cache backend self.copy_po_file_from_template('./django.po.issue38gh.template') r = self.client.get(self.xx_form_url) self.assertFalse(len(str(self.client.cookies.get('sessionid'))) > 4096) self.assertTrue('m_9efd113f7919952523f06e0d88da9c54' in str(r.content)) data = {'m_9efd113f7919952523f06e0d88da9c54': 'Testing cookie length'} r = self.client.post(self.xx_form_url, data) with open(self.dest_file, 'r') as po_file: pofile_content = po_file.read() self.assertTrue('Testing cookie length' in pofile_content) r = self.client.get(self.xx_form_url + '?filter=translated') self.assertTrue('Testing cookie length' in str(r.content)) self.assertTrue('m_9f6c442c6d579707440ba9dada0fb373' in str(r.content)) @override_settings(ROSETTA_STORAGE_CLASS='rosetta.storage.CacheRosettaStorage') def test_21_concurrency_of_cache_backend(self): self.copy_po_file_from_template('./django.po.issue38gh.template') # Force caching into play by making .po file read-only os.chmod(self.dest_file, 292) # 0444 self.client.get(self.xx_form_url) self.client2.get(self.xx_form_url) self.assertNotEqual( self.client.session.get('rosetta_cache_storage_key_prefix'), self.client2.session.get('rosetta_cache_storage_key_prefix') ) # Clean up (restore perms) os.chmod(self.dest_file, 420) # 0644 def test_22_Test_Issue_gh39(self): self.copy_po_file_from_template('./django.po.issue39gh.template') r = self.client.get(self.xx_form_url) # We have distinct hashes, even though the msgid and msgstr are identical self.assertTrue('m_4765f7de94996d3de5975fa797c3451f' in str(r.content)) self.assertTrue('m_08e4e11e2243d764fc45a5a4fba5d0f2' in str(r.content)) @override_settings(ROSETTA_LANGUAGES=( ('xx', 'dummy language'), )) def test_23_save_header_data(self): from django.contrib.auth.models import User self.copy_po_file_from_template('./django.po.template') unicode_user = User.objects.create_user( 'test_unicode', 'save_header_data@test.com', 'test_unicode' ) unicode_user.first_name = "aéaéaé aàaàaàa" unicode_user.last_name = "aâââ üüüü" unicode_user.is_superuser, unicode_user.is_staff = True, True unicode_user.save() self.client.login(username='test_unicode', password='test_unicode') # Load the template file r = self.client.get(self.xx_form_url + '?filter=untranslated') # make sure both strings are untranslated self.assertTrue('dummy language' in str(r.content)) self.assertTrue('String 1' in str(r.content)) self.assertTrue('String 2' in str(r.content)) self.assertTrue('m_e48f149a8b2e8baa81b816c0edf93890' in str(r.content)) # post a translation data = {'m_e48f149a8b2e8baa81b816c0edf93890': 'Hello, world'} r = self.client.post(self.xx_form_url + '?filter=untranslated', data) # read the result with open(self.dest_file, 'rb') as f_: content = six.text_type(f_.read()) # make sure unicode data was properly converted to ascii self.assertTrue('Hello, world' in content) self.assertTrue('save_header_data@test.com' in content) self.assertTrue('aeaeae aaaaaaa aaaa uuuu' in content) def test_24_percent_translation(self): self.copy_po_file_from_template('./django.po.template') # Load the template file r = self.client.get(self.xx_form_url) self.assertTrue('Progress: 0%' in str(r.content)) data = {'m_e48f149a8b2e8baa81b816c0edf93890': 'Hello, world'} r = self.client.post(self.xx_form_url, data, follow=True) self.assertTrue('Progress: 25%' in str(r.content)) def test_25_replace_access_control(self): # Test default access control allows access response = self.client.get(self.project_file_list_url) self.assertEqual(200, response.status_code) # Now replace access control, and check we get redirected with self.settings(ROSETTA_ACCESS_CONTROL_FUNCTION='rosetta.tests.no_access'): response = self.client.get(self.project_file_list_url) self.assertEqual(302, response.status_code) def test_26_urlconf_accept_dots_and_underscores(self): resolver_match = resolve('/rosetta/files/all/fr_FR.utf8/0/') self.assertEqual(resolver_match.url_name, 'rosetta-form') self.assertEqual(resolver_match.kwargs['lang_id'], 'fr_FR.utf8') def test_27_extended_urlconf_language_code_loads_file(self): url = reverse( 'rosetta-form', kwargs={'po_filter': 'all', 'lang_id': 'fr_FR.utf8', 'idx': 0} ) r = self.client.get(url) self.assertTrue('French (France), UTF8' in str(r.content)) self.assertTrue('m_03a603523bd75b00414a413657acdeb2' in str(r.content)) def test_28_issue_gh87(self): """Make sure that rosetta_i18n_catalog_filter is passed into the context.""" r = self.client.get(self.third_party_file_list_url) self.assertContains(r, '
  • ') @override_settings( SESSION_ENGINE='django.contrib.sessions.backends.signed_cookies', ROSETTA_STORAGE_CLASS='rosetta.storage.SessionRosettaStorage', ) def test_29_unsupported_p3_django_16_storage(self): if VERSION[0:2] < (2, 0): self.assertTrue('django.contrib.sessions.middleware.SessionMiddleware' in settings.MIDDLEWARE) # Force caching to be used by making the pofile read-only os.chmod(self.dest_file, 292) # 0444 # (Have to log in again, since our session engine changed) self.client.login(username='test_admin', password='test_password') with self.assertRaises(ImproperlyConfigured): self.client.get(self.xx_form_url) # Cleanup os.chmod(self.dest_file, 420) # 0644 @override_settings( ROSETTA_POFILENAMES=('pr44.po', ), ROSETTA_LANGUAGES=(('xx', 'dummy language'),) ) def test_30_pofile_names(self): os.unlink(self.dest_file) destfile = os.path.normpath( os.path.join(self.curdir, '../locale/xx/LC_MESSAGES/pr44.po') ) shutil.copy( os.path.normpath(os.path.join(self.curdir, './pr44.po.template')), destfile ) r = self.client.get(self.third_party_file_list_url) self.assertTrue('xx/LC_MESSAGES/pr44.po' in str(r.content)) r = self.client.get(self.xx_form_url) self.assertTrue('dummy language' in str(r.content)) # (Clean up) os.unlink(destfile) def test_31_pr_102__exclude_paths(self): r = self.client.get(self.third_party_file_list_url) self.assertContains(r, 'rosetta/locale/xx/LC_MESSAGES/django.po') exclude_path = os.path.normpath(os.path.join(self.curdir, '../locale')) with self.settings(ROSETTA_EXCLUDED_PATHS=exclude_path): r = self.client.get(self.third_party_file_list_url) self.assertNotContains(r, 'rosetta/locale/xx/LC_MESSAGES/django.po') def test_32_pr_103__language_groups(self): from django.contrib.auth.models import User, Group # Default behavior: non-admins need to be in a translators group; they # see all catalogs translators = Group.objects.create(name='translators') translators_xx = Group.objects.create(name='translators-xx') user4 = User.objects.create_user('test_admin4', 'test@test3.com', 'test_password') user4.groups.add(translators) user4.is_superuser = False user4.is_staff = True user4.save() with self.settings(ROSETTA_LANGUAGE_GROUPS=False): self.client.login(username='test_admin4', password='test_password') r = self.client.get(self.third_party_file_list_url) self.assertContains(r, 'rosetta/locale/xx/LC_MESSAGES/django.po') with self.settings(ROSETTA_LANGUAGE_GROUPS=True): r = self.client.get(self.third_party_file_list_url) self.assertNotContains(r, 'rosetta/locale/xx/LC_MESSAGES/django.po') # Now add them to the custom group user4.groups.add(translators_xx) r = self.client.get(self.third_party_file_list_url) self.assertContains(r, 'rosetta/locale/xx/LC_MESSAGES/django.po') @override_settings( ROSETTA_ENABLE_REFLANG=True, ROSETTA_LANGUAGES=(('xx', 'dummy language'),) ) def test_33_reflang(self): self.copy_po_file_from_template('./django.po.issue60.template') r = self.client.get(self.xx_form_url) # Verify that there's an option to select a reflang self.assertTrue('' in str(r.content)) r = self.client.get(self.xx_form_url + '?ref_lang=xx') # The translated string in the test PO file ends up in the "Reference" column self.assertTrue('translated-string1' in str(r.content)) def test_show_occurrences(self): r = self.client.get(self.xx_form_url) # Verify that occurrences in view self.assertTrue('' in str(r.content)) with self.settings(ROSETTA_SHOW_OCCURRENCES=False): r = self.client.get(self.xx_form_url) # Verify that occurrences not in view self.assertFalse('' in str(r.content)) def test_34_issue_113_app_configs(self): r = self.client.get(self.all_file_list_url) self.assertTrue('rosetta/files/all/xx/1/">Test_App' in str(r.content)) @override_settings(ROSETTA_STORAGE_CLASS='rosetta.storage.CacheRosettaStorage') def test_35_issue_135_display_exception_messages(self): # Note: the old version of this test looked for a 'Permission denied' # message reflected in the response. That behavior has now changed so # that changes that can't be persisted through the filesystem .po file # are saved to the cached version of the .po file. self.copy_po_file_from_template('./django.po.template') r = self.client.get(self.xx_form_url + '?msg_filter=untranslated') self.assertContains(r, 'm_e48f149a8b2e8baa81b816c0edf93890') # make the pofile read-only os.chmod(self.dest_file, 292) # 0444 # post a translation data = {'m_e48f149a8b2e8baa81b816c0edf93890': 'Hello, world'} self.client.post(self.xx_form_url, data, follow=True) # Confirm that the filesystem file hasn't changed tmpl_path = os.path.normpath(os.path.join(self.curdir, 'django.po.template')) self.assertTrue(filecmp.cmp(tmpl_path, self.dest_file)) # Confirm that the cached version has been updated cache_key = 'po-file-%s' % self.dest_file request = RequestFactory().get(self.xx_form_url) request.user = self.user request.session = self.client.session storage = get_storage(request) po_file = storage.get(cache_key) entry = po_file.find('String 2') self.assertEqual(entry.msgstr, 'Hello, world') # cleanup os.chmod(self.dest_file, 420) # 0644 def test_36_issue_142_complex_locales(self): r = self.client.get(self.all_file_list_url) self.assertContains(r, 'locale/bs-Cyrl-BA/LC_MESSAGES/django.po') @override_settings(ROSETTA_LANGUAGES=(('yy-Anot', u'Yet Another dummy language'),)) def test_37_issue_133_complex_locales(self): r = self.client.get(self.all_file_list_url) self.assertContains(r, 'locale/yy-Anot/LC_MESSAGES/django.po') def test_38_issue_161_more_weird_locales(self): r = self.client.get(self.all_file_list_url) self.assertTrue(r, 'locale/zh_Hans/LC_MESSAGES/django.po') def test_39_invalid_get_page(self): url = self.xx_form_url + '?filter=untranslated' r = self.client.get(url) # Page not specified self.assertEqual(r.context['page'], 1) r = self.client.get(url + '&page=') # No number given self.assertEqual(r.context['page'], 1) r = self.client.get(url + '&page=9999') # Too-high number given self.assertEqual(r.context['page'], 1) r = self.client.get(url + '&page=x') # Non-number given self.assertEqual(r.context['page'], 1) def test_40_issue_155_auto_compile(self): def file_hash(file_string): if six.PY3: with open(file_string, encoding="latin-1") as file: file_content = file.read().encode('utf-8') else: with open(file_string) as file: file_content = file.read() return hashlib.md5(file_content).hexdigest() def message_hashes(): r = self.client.get(self.xx_form_url) return {m.msgid: 'm_' + m.md5hash for m in r.context['rosetta_messages']} po_file = self.dest_file mo_file = self.dest_file[:-3] + '.mo' # MO file will be compiled by default. # Get PO and MO files into an initial reference state (MO will be # created or updated) msg_hashes = message_hashes() data = {msg_hashes['String 1']: 'Translation 1'} self.client.post(self.xx_form_url, data) po_file_hash_before, mo_file_hash_before = file_hash(po_file), file_hash(mo_file) # Make a change to the translations msg_hashes = message_hashes() data = {msg_hashes['String 1']: 'Translation 2'} self.client.post(self.xx_form_url, data) # Get the new hashes of the PO and MO file contents po_file_hash_after, mo_file_hash_after = file_hash(po_file), file_hash(mo_file) # Both the PO and MO should have changed self.assertNotEqual(po_file_hash_before, po_file_hash_after) self.assertNotEqual(mo_file_hash_before, mo_file_hash_after) # Disable auto-compilation of the MO when the PO is saved with self.settings(ROSETTA_AUTO_COMPILE=False): # Make a change to the translations po_file_hash_before, mo_file_hash_before = po_file_hash_after, mo_file_hash_after msg_hashes = message_hashes() data = {msg_hashes['String 1']: "Translation 3"} self.client.post(self.xx_form_url, data) po_file_hash_after, mo_file_hash_after = file_hash(po_file), file_hash(mo_file) # Only the PO should have changed, the MO should be unchanged self.assertNotEqual(po_file_hash_before, po_file_hash_after) self.assertEqual(mo_file_hash_before, mo_file_hash_after) # Verify that translating another string also leaves the MO unchanged po_file_hash_before, mo_file_hash_before = po_file_hash_after, mo_file_hash_after msg_hashes = message_hashes() data = {msg_hashes['String 2']: "Translation 4"} self.client.post(self.xx_form_url, data) po_file_hash_after, mo_file_hash_after = file_hash(po_file), file_hash(mo_file) self.assertNotEqual(po_file_hash_before, po_file_hash_after) self.assertEqual(mo_file_hash_before, mo_file_hash_after) with self.settings(ROSETTA_AUTO_COMPILE=True): po_file_hash_before, mo_file_hash_before = po_file_hash_after, mo_file_hash_after msg_hashes = message_hashes() data = {msg_hashes['String 2']: "Translation 5"} self.client.post(self.xx_form_url, data) po_file_hash_after, mo_file_hash_after = file_hash(po_file), file_hash(mo_file) self.assertNotEqual(po_file_hash_before, po_file_hash_after) self.assertNotEqual(mo_file_hash_before, mo_file_hash_after) def test_41_pr_176_embed_in_admin(self): resp = self.client.get(reverse('admin:index')) self.assertContains(resp, 'app-rosetta module') def _setup_view(self, view, request, *args, **kwargs): """Mimic as_view() returned callable, but returns view instance. args and kwargs are the same you would pass to ``reverse()`` (From http://tech.novapost.fr/django-unit-test-your-views-en.html.) """ view.request = request view.args = args view.kwargs = kwargs return view def test_42_view_property_po_file_is_writable(self): """Confirm that we're accurately determining the filesystem write-perms on our .po file. """ self.copy_po_file_from_template('./django.po.template') # By default, we're writable request = RequestFactory().get(self.xx_form_url) request.user = self.user kwargs = {'po_filter': 'third-party', 'lang_id': 'xx', 'idx': 0} view = self._setup_view( view=views.TranslationFormView(), request=request, **kwargs ) self.assertTrue(view.po_file_is_writable) # Now try again with the file not writable. (Regenerate the view, since # this po_file_is_writable is cached for the life of the request.) # make the pofile read-only os.chmod(self.dest_file, 292) # 0444 view = self._setup_view( view=views.TranslationFormView(), request=request, **kwargs ) self.assertFalse(view.po_file_is_writable) # Cleanup os.chmod(self.dest_file, 420) # 0644 def test_43_view_property_po_file_path(self): """Confirm our class-based views properly parse/validate the path of the .po file in question derived from the url kwargs. """ self.copy_po_file_from_template('./django.po.template') # By default, when all goes well, we get our existing .po file path request = RequestFactory().get(self.xx_form_url) request.user = self.user kwargs = {'po_filter': 'third-party', 'lang_id': 'xx', 'idx': 0} view = self._setup_view( view=views.TranslationFormView(), request=request, **kwargs ) self.assertEqual(view.po_file_path, self.dest_file) # But if the language isn't an option, we get a 404 with self.settings(ROSETTA_LANGUAGES=[l for l in settings.LANGUAGES if l[0] != 'xx']): view = self._setup_view( view=views.TranslationFormView(), request=request, **kwargs ) with self.assertRaises(Http404): view.po_file_path # And if the index doesn't correspond with a file, we get a 404 new_kwargs = {'po_filter': 'third-party', 'lang_id': 'xx', 'idx': 9} view = self._setup_view( view=views.TranslationFormView(), # Recycle request, even though url kwargs conflict with ones below. request=request, **new_kwargs ) with self.assertRaises(Http404): view.po_file_path def test_44_message_search_function(self): """Confirm that search of the .po file works across the various message fields. """ self.copy_po_file_from_template('./django.po.test44.template') url = self.xx_form_url + '?query=%s' # Here's the message entry we're considering: # #. Translators: consectetur adipisicing # #: templates/eiusmod/tempor.html:43 # msgid "Lorem ipsum" # msgstr "dolor sit amet" # It is buried at the end of the file, so without searching for it, it # shouldn't be on the page r = self.client.get(url % '') self.assertNotContains(r, 'Lorem') # Search msgid r = self.client.get(url % 'ipsum') self.assertContains(r, 'Lorem') # Search msgstr r = self.client.get(url % 'dolor') self.assertContains(r, 'Lorem') # Search occurences r = self.client.get(url % 'tempor') self.assertContains(r, 'Lorem') # Search comments r = self.client.get(url % 'adipisicing') self.assertContains(r, 'Lorem') # Search context r = self.client.get(url % 'pellentesque') self.assertContains(r, 'Lorem') def test_45_issue186_plural_msg_search(self): """Confirm that search of the .po file works for plurals. """ self.copy_po_file_from_template('./django.po.issue186.template') url = self.xx_form_url + '?query=%s' # Here's the message entry we're considering: # msgstr "%d Child" # msgid_plural "%d Childrenen" # msgstr[0] "%d Tchilt" # msgstr[1] "%d Tchildren" # First, confirm that we don't ALWAYS see this particular message on the # page. r = self.client.get(url % 'kids') self.assertNotContains(r, 'Child') # Search msgid_plural r = self.client.get(url % 'childrenen') self.assertContains(r, 'Child') # Search msgstr[0] r = self.client.get(url % 'tchilt') self.assertContains(r, 'Child') # Search msgstr[1] r = self.client.get(url % 'tchildren') self.assertContains(r, 'Child') def test_46_search_string_with_unicode_symbols(self): """Confirm that search works with unicode symbols """ url = self.xx_form_url + '?' + urlencode({'query': force_bytes(u'Лорем')}) # It shouldn't raise r = self.client.get(url) self.assertEqual(r.status_code, 200) @vcr.use_cassette('fixtures/vcr_cassettes/test_47_azure_ajax_translation.yaml', match_on=['method', 'scheme', 'host', 'port', 'path', 'query', 'raw_body'], record_mode='new_episodes') def test_47_azure_ajax_translation(self): r = self.client.get(reverse('rosetta.translate_text') + '?from=en&to=fr&text=hello%20world') self.assertContains(r, '"Salut tout le monde"') @override_settings(ROSETTA_REQUIRES_AUTH=True) def test_48_requires_auth_not_respected_issue_203(self): self.client.logout() r = self.client.get(self.all_file_list_url) self.assertRedirects(r, '{}?next=/rosetta/files/all/'.format(settings.LOGIN_URL), fetch_redirect_response=False) self.assertEqual(302, r.status_code) @override_settings(ROSETTA_REQUIRES_AUTH=False) def test_49_requires_auth_not_respected_issue_203(self): r = self.client.get(self.all_file_list_url) self.assertEqual(200, r.status_code) @override_settings(ROSETTA_REQUIRES_AUTH=True, ROSETTA_LOGIN_URL='/custom-url/') def test_50_custom_login_url(self): self.client.logout() r = self.client.get(self.all_file_list_url) self.assertRedirects(r, '/custom-url/?next=/rosetta/files/all/', fetch_redirect_response=False) self.assertEqual(302, r.status_code) def test_51_rosetta_languages(self): self.assertTrue('xx' in dict(settings.LANGUAGES)) self.assertFalse('yy' in dict(settings.LANGUAGES)) with self.settings(ROSETTA_LANGUAGES=(('xx', 'foo language'), )): r = self.client.get(self.project_file_list_url) self.assertTrue('foo language' in str(r.content)) self.assertFalse('bar language' in str(r.content)) with self.settings(ROSETTA_LANGUAGES=(('xx', 'foo language'), ('yy', 'bar language'), )): r = self.client.get(self.project_file_list_url) self.assertTrue('foo language' in str(r.content)) self.assertTrue('bar language' in str(r.content)) # Stubbed access control function def no_access(user): return False