def test_manage_project_strings_existing_resource(client_superuser, locale_a): project = ProjectFactory.create( data_source='database', repositories=[], locales=[locale_a], ) ResourceFactory.create( path='not_database', project=project, ) url = reverse('pontoon.admin.project.strings', args=(project.slug,)) # Test sending a well-formatted batch of strings. new_strings = """Hey, I just met you And this is crazy But here's my number So call me maybe? """ response = client_superuser.post(url, {'new_strings': new_strings}) assert response.status_code == 200 # Verify no new resources have been created. resources = list(Resource.objects.filter(project=project)) assert len(resources) == 1 # The preexisting resource has been sucessfully used. assert resources[0].path == 'not_database' assert resources[0].total_strings == 4
def test_manage_project_strings_existing_resource(client_superuser, locale_a): project = ProjectFactory.create( data_source='database', repositories=[], locales=[locale_a], ) ResourceFactory.create( path='not_database', project=project, ) url = reverse('pontoon.admin.project.strings', args=(project.slug, )) # Test sending a well-formatted batch of strings. new_strings = """Hey, I just met you And this is crazy But here's my number So call me maybe? """ response = client_superuser.post(url, {'new_strings': new_strings}) assert response.status_code == 200 # Verify no new resources have been created. resources = list(Resource.objects.filter(project=project)) assert len(resources) == 1 # The preexisting resource has been sucessfully used. assert resources[0].path == 'not_database' assert resources[0].total_strings == 4
def setUp(self): """ We don't call project synchronization during the tests, so we have to create dummy resource project to avoid recurse redirect at /. """ ResourceFactory.create(project=Project.objects.get(pk=1)) self.factory = RequestFactory()
def test_locale_parts_stats_pages_tied_to_resources(locale_parts): """ Return subpage name and stats for locales resources are available for. """ locale_a, locale_b, entity_a = locale_parts project = entity_a.resource.project resourceX = ResourceFactory.create(project=project, path="/other/path.po",) EntityFactory.create(resource=resourceX, string="Entity X") TranslatedResourceFactory.create( resource=resourceX, locale=locale_a, ) TranslatedResourceFactory.create( resource=resourceX, locale=locale_b, ) sub1 = SubpageFactory.create(project=project, name="Subpage",) sub1.resources.add(resourceX) sub2 = SubpageFactory.create(project=project, name="Other Subpage",) sub2.resources.add(resourceX) details0 = locale_a.parts_stats(project) detailsX = locale_b.parts_stats(project) assert details0[0]["title"] == "Other Subpage" assert details0[0]["unreviewed_strings"] == 0 assert details0[1]["title"] == "Subpage" assert details0[1]["unreviewed_strings"] == 0 assert detailsX[0]["title"] == "Other Subpage" assert detailsX[0]["unreviewed_strings"] == 0
def test_locale_parts_stats_no_page_multiple_resources(locale_parts): """ Return resource paths and stats for locales resources are available for. """ locale_c, locale_b, entityX = locale_parts project = entityX.resource.project resourceY = ResourceFactory.create( total_strings=1, project=project, path='/other/path.po', ) EntityFactory.create(resource=resourceY, string="Entity Y") TranslatedResourceFactory.create( resource=resourceY, locale=locale_c, ) TranslatedResourceFactory.create( resource=resourceY, locale=locale_b, ) # results are sorted by title detailsX = locale_c.parts_stats(project) assert ( [detail["title"] for detail in detailsX][:2] == sorted([entityX.resource.path, '/other/path.po']) ) assert detailsX[0]['unreviewed_strings'] == 0 assert detailsX[1]['unreviewed_strings'] == 0 detailsY = locale_b.parts_stats(project) assert len(detailsY) == 2 assert detailsY[0]['title'] == '/other/path.po' assert detailsY[0]['unreviewed_strings'] == 0
def test_translation_save_latest_missing_project_locale(locale_a, project_a): """ If a translation is saved for a locale that isn't active on the project, do not fail due to a missing ProjectLocale. """ resource = ResourceFactory.create( project=project_a, path="resource.po", format="po", ) tr = TranslatedResourceFactory.create(locale=locale_a, resource=resource) entity = EntityFactory.create(resource=resource, string="Entity X") # This calls .save, this should fail if we're not properly # handling the missing ProjectLocale. translation = TranslationFactory.create( locale=locale_a, entity=entity, date=aware_datetime(1970, 1, 1), ) locale_a.refresh_from_db() project_a.refresh_from_db() tr.refresh_from_db() assert locale_a.latest_translation == translation assert project_a.latest_translation == translation assert tr.latest_translation == translation
def test_locale_parts_stats_pages_tied_to_resources(locale_parts): """ Return subpage name and stats for locales resources are available for. """ locale_a, locale_b, entity_a = locale_parts project = entity_a.resource.project resourceX = ResourceFactory.create( project=project, path='/other/path.po', ) EntityFactory.create(resource=resourceX, string="Entity X") TranslatedResourceFactory.create( resource=resourceX, locale=locale_a, ) TranslatedResourceFactory.create( resource=resourceX, locale=locale_b, ) sub1 = SubpageFactory.create( project=project, name='Subpage', ) sub1.resources.add(resourceX) sub2 = SubpageFactory.create( project=project, name='Other Subpage', ) sub2.resources.add(resourceX) details0 = locale_a.parts_stats(project) detailsX = locale_b.parts_stats(project) assert details0[0]['title'] == 'Other Subpage' assert details0[0]['unreviewed_strings'] == 0 assert details0[1]['title'] == 'Subpage' assert details0[1]['unreviewed_strings'] == 0 assert detailsX[0]['title'] == 'Other Subpage' assert detailsX[0]['unreviewed_strings'] == 0
def test_view_translate_not_authed_public_project( client, locale_a, settings_debug, ): """ If the user is not authenticated and we're translating project ID 1, return a 200. """ project = ProjectFactory.create(slug='valid-project') ProjectLocaleFactory.create( project=project, locale=locale_a, ) resource = ResourceFactory.create( project=project, path='foo.lang', total_strings=1, ) TranslatedResourceFactory.create( resource=resource, locale=locale_a, ) response = client.get('/%s/%s/%s/' % (locale_a.code, project.slug, resource.path)) assert response.status_code == 200
def test_translation_save_latest_update_for_system_project(locale_a, system_project_a): """ When a translation is saved for a system project, update the latest_translation attribute on the project, translatedresource and project_locale objects, but not on the locale object. """ project_locale = ProjectLocaleFactory.create( project=system_project_a, locale=locale_a, ) resource = ResourceFactory.create( project=system_project_a, path="resource.po", format="po", ) tr = TranslatedResourceFactory.create(locale=locale_a, resource=resource) entity = EntityFactory.create(resource=resource, string="Entity X") assert locale_a.latest_translation is None assert system_project_a.latest_translation is None assert tr.latest_translation is None assert project_locale.latest_translation is None translation = TranslationFactory.create( locale=locale_a, entity=entity, date=aware_datetime(1970, 1, 1), ) for i in [locale_a, system_project_a, project_locale, tr]: i.refresh_from_db() assert locale_a.latest_translation is None assert system_project_a.latest_translation == translation assert tr.latest_translation == translation assert project_locale.latest_translation == translation
def test_locale_parts_stats_no_page_multiple_resources(locale_parts): """ Return resource paths and stats for locales resources are available for. """ locale_c, locale_b, entityX = locale_parts project = entityX.resource.project resourceY = ResourceFactory.create( total_strings=1, project=project, path="/other/path.po", ) EntityFactory.create(resource=resourceY, string="Entity Y") TranslatedResourceFactory.create( resource=resourceY, locale=locale_c, ) TranslatedResourceFactory.create( resource=resourceY, locale=locale_b, ) # results are sorted by title detailsX = locale_c.parts_stats(project) assert [detail["title"] for detail in detailsX][:2] == sorted( [entityX.resource.path, "/other/path.po"] ) assert detailsX[0]["unreviewed_strings"] == 0 assert detailsX[1]["unreviewed_strings"] == 0 detailsY = locale_b.parts_stats(project) assert len(detailsY) == 2 assert detailsY[0]["title"] == "/other/path.po" assert detailsY[0]["unreviewed_strings"] == 0
def test_view_translate_not_authed_public_project( client, locale_a, settings_debug, ): """ If the user is not authenticated and we're translating project ID 1, return a 200. """ project = ProjectFactory.create(slug='valid-project') ProjectLocaleFactory.create( project=project, locale=locale_a, ) resource = ResourceFactory.create( project=project, path='foo.lang', total_strings=1, ) TranslatedResourceFactory.create( resource=resource, locale=locale_a, ) response = client.get( '/%s/%s/%s/' % (locale_a.code, project.slug, resource.path) ) assert response.status_code == 200
def locale_parts(project_b, locale_c, locale_b): ProjectLocaleFactory.create(project=project_b, locale=locale_c) ProjectLocaleFactory.create(project=project_b, locale=locale_b) resourceX = ResourceFactory.create( project=project_b, path="resourceX.po", format="po", ) entityX = EntityFactory.create(resource=resourceX, string="entityX") resourceX.total_strings = 1 resourceX.save() TranslatedResourceFactory.create(locale=locale_c, resource=resourceX) return locale_c, locale_b, entityX
def entity_test_models(translation_a, locale_b): """This fixture provides: - 2 translations of a plural entity - 1 translation of a non-plural entity - A subpage that contains the plural entity """ entity_a = translation_a.entity locale_a = translation_a.locale project_a = entity_a.resource.project locale_a.cldr_plurals = "0,1" locale_a.save() translation_a.plural_form = 0 translation_a.active = True translation_a.save() resourceX = ResourceFactory( project=project_a, path="resourceX.po", ) entity_a.string = "Entity zero" entity_a.key = entity_a.string entity_a.string_plural = "Plural %s" % entity_a.string entity_a.order = 0 entity_a.save() entity_b = EntityFactory( resource=resourceX, string="entity_b", key="Key%sentity_b" % KEY_SEPARATOR, order=0, ) translation_a_pl = TranslationFactory( entity=entity_a, locale=locale_a, plural_form=1, active=True, string="Plural %s" % translation_a.string, ) translationX = TranslationFactory( entity=entity_b, locale=locale_a, active=True, string="Translation %s" % entity_b.string, ) subpageX = SubpageFactory( project=project_a, name="Subpage", ) subpageX.resources.add(entity_a.resource) return translation_a, translation_a_pl, translationX, subpageX
def test_pretranslate(gt_mock, project_a, locale_a, resource_a, locale_b): project_a.pretranslation_enabled = True project_a.save() resources = [ ResourceFactory(project=project_a, path=x, format="po") for x in ["resource_x.po", "resource_y.po"] ] for i, x in enumerate(["abaa", "abac"]): EntityFactory.create(resource=resources[0], string=x, order=i) for i, x in enumerate(["aaab", "abab"]): EntityFactory.create(resource=resources[1], string=x, order=i) TranslatedResourceFactory.create(resource=resources[0], locale=locale_a) TranslatedResourceFactory.create(resource=resources[0], locale=locale_b) TranslatedResourceFactory.create(resource=resources[1], locale=locale_a) ProjectLocaleFactory.create( project=project_a, locale=locale_a, pretranslation_enabled=True, ) ProjectLocaleFactory.create( project=project_a, locale=locale_b, pretranslation_enabled=True, ) tm_user = User.objects.get(email="*****@*****.**") gt_mock.return_value = [("pretranslation", None, tm_user)] pretranslate(project_a.pk) project_a.refresh_from_db() translations = Translation.objects.filter(user=tm_user) # Total pretranslations = 2(tr_ax) + 2(tr_bx) + 2(tr_ay) assert len(translations) == 6 # pretranslated count == total pretranslations. assert project_a.pretranslated_strings == 6 # latest_translation belongs to pretranslations. assert project_a.latest_translation in translations
def test_project_needs_sync(project_a, project_b, locale_a): """ Project.needs_sync should be True if ChangedEntityLocale objects exist for its entities or if Project has unsynced locales. """ resource = ResourceFactory.create(project=project_a, path="resourceX.po") entity = EntityFactory.create(resource=resource, string="entityX") assert not project_a.needs_sync ChangedEntityLocaleFactory.create(entity=entity, locale=locale_a) assert project_a.needs_sync assert not project_b.needs_sync assert project_b.unsynced_locales == [] del project_b.unsynced_locales ProjectLocaleFactory.create( project=project_b, locale=locale_a, ) assert project_b.needs_sync == [locale_a]
def test_translation_unapproved_not_in_tm(locale_a, project_a): """ Unapproved translation shouldn't be in the translation memory. """ resource = ResourceFactory.create( project=project_a, path="resource.po", format="po", ) entity = EntityFactory.create(resource=resource, string="Entity X") translation = TranslationFactory.create( locale=locale_a, entity=entity, ) with pytest.raises(TranslationMemoryEntry.DoesNotExist): TranslationMemoryEntry.objects.get( source=translation.entity.string, target=translation.string, locale=translation.locale, )
def test_translation_approved_in_tm(locale_a, project_a): """ Every save of approved translation should generate a new entry in the translation memory. """ resource = ResourceFactory.create( project=project_a, path="resource.po", format="po", ) entity = EntityFactory.create(resource=resource, string="Entity X") translation = TranslationFactory.create( locale=locale_a, entity=entity, approved=True, ) assert TranslationMemoryEntry.objects.get( source=translation.entity.string, target=translation.string, locale=translation.locale, )
def test_translation_rejected_not_in_tm(locale_a, project_a): """ When translation is deleted, its corresponding TranslationMemoryEntry needs to be deleted, too. """ resource = ResourceFactory.create( project=project_a, path="resource.po", format="po", ) entity = EntityFactory.create(resource=resource, string="Entity X") translation = TranslationFactory.create( locale=locale_a, entity=entity, rejected=True, ) with pytest.raises(TranslationMemoryEntry.DoesNotExist): TranslationMemoryEntry.objects.get( source=translation.entity.string, target=translation.string, locale=translation.locale, )
def test_translation_save_latest_update(locale_a, project_a): """ When a translation is saved, update the latest_translation attribute on the related project, locale, translatedresource, and project_locale objects. """ project_locale = ProjectLocaleFactory.create( project=project_a, locale=locale_a, ) resource = ResourceFactory.create( project=project_a, path="resource.po", format="po", ) tr = TranslatedResourceFactory.create(locale=locale_a, resource=resource) entity = EntityFactory.create(resource=resource, string="Entity X") assert locale_a.latest_translation is None assert project_a.latest_translation is None assert tr.latest_translation is None assert project_locale.latest_translation is None translation = TranslationFactory.create( locale=locale_a, entity=entity, date=aware_datetime(1970, 1, 1), ) locale_a.refresh_from_db() project_a.refresh_from_db() tr.refresh_from_db() project_locale.refresh_from_db() assert locale_a.latest_translation == translation assert project_a.latest_translation == translation assert tr.latest_translation == translation assert project_locale.latest_translation == translation # Ensure translation is replaced for newer translations newer_translation = TranslationFactory.create( locale=locale_a, entity=entity, date=aware_datetime(1970, 2, 1), ) locale_a.refresh_from_db() project_a.refresh_from_db() tr.refresh_from_db() project_locale.refresh_from_db() assert locale_a.latest_translation == newer_translation assert project_a.latest_translation == newer_translation assert tr.latest_translation == newer_translation assert project_locale.latest_translation == newer_translation # Ensure translation isn't replaced for older translations. TranslationFactory.create( locale=locale_a, entity=entity, date=aware_datetime(1970, 1, 5), ) locale_a.refresh_from_db() project_a.refresh_from_db() tr.refresh_from_db() project_locale.refresh_from_db() assert locale_a.latest_translation == newer_translation assert project_a.latest_translation == newer_translation assert tr.latest_translation == newer_translation assert project_locale.latest_translation == newer_translation # Ensure approved_date is taken into consideration as well. newer_approved_translation = TranslationFactory.create( locale=locale_a, entity=entity, approved_date=aware_datetime(1970, 3, 1), ) locale_a.refresh_from_db() project_a.refresh_from_db() tr.refresh_from_db() project_locale.refresh_from_db() assert locale_a.latest_translation == newer_approved_translation assert project_a.latest_translation == newer_approved_translation assert tr.latest_translation == newer_approved_translation assert project_locale.latest_translation == newer_approved_translation
def resource_c(project_a): return ResourceFactory.create( project=project_a, path="resource_c.po", format="po" )
def test_manage_project_strings_list(client_superuser): project = ProjectFactory.create(data_source='database', repositories=[]) resource = ResourceFactory.create(project=project) nb_entities = 2 entities = EntityFactory.create_batch(nb_entities, resource=resource) url = reverse('pontoon.admin.project.strings', args=(project.slug,)) response = client_superuser.get(url) assert response.status_code == 200 for i in range(nb_entities): assert 'string %s' % i in response.content # Test editing strings and comments. form_data = { 'form-TOTAL_FORMS': nb_entities, 'form-INITIAL_FORMS': nb_entities, 'form-MIN_NUM_FORMS': 0, 'form-MAX_NUM_FORMS': 1000, 'form-0-id': entities[0].id, 'form-0-string': 'changed 0', 'form-0-comment': 'Wubba lubba dub dub', 'form-1-id': entities[1].id, 'form-1-string': 'string 1', 'form-1-obsolete': 'on', # Remove this one. } response = client_superuser.post(url, form_data) assert response.status_code == 200 assert 'changed 0' in response.content assert 'Wubba lubba dub dub' in response.content assert 'string 0' not in response.content assert 'string 1' not in response.content # It's been removed. total = Entity.objects.filter( resource=resource, obsolete=False, ).count() assert total == nb_entities - 1 # Test adding a new string. form_data = { 'form-TOTAL_FORMS': nb_entities, 'form-INITIAL_FORMS': nb_entities - 1, 'form-MIN_NUM_FORMS': 0, 'form-MAX_NUM_FORMS': 1000, 'form-0-id': entities[0].id, 'form-0-string': 'changed 0', 'form-0-comment': 'Wubba lubba dub dub', 'form-1-id': '', 'form-1-string': 'new string', 'form-1-comment': 'adding this entity now', } response = client_superuser.post(url, form_data) assert response.status_code == 200 assert 'changed 0' in response.content assert 'new string' in response.content assert 'adding this entity now' in response.content total = Entity.objects.filter( resource=resource, obsolete=False, ).count() assert total == nb_entities # Verify the new string has the correct order. new_string = Entity.objects.filter( resource=resource, obsolete=False, string='new string', ).first() # The highest order before adding new string was 0, # so the order of that new one should be 1. assert new_string.order == 1
def resource_c(project_a): return ResourceFactory.create(project=project_a, path="resource_c.po", format="po")
def test_manage_project_strings_list(client_superuser): project = ProjectFactory.create(data_source='database', repositories=[]) resource = ResourceFactory.create(project=project) nb_entities = 2 entities = EntityFactory.create_batch(nb_entities, resource=resource) url = reverse('pontoon.admin.project.strings', args=(project.slug, )) response = client_superuser.get(url) assert response.status_code == 200 for i in range(nb_entities): assert ('string %s' % i).encode('utf-8') in response.content # Test editing strings and comments. form_data = { 'form-TOTAL_FORMS': nb_entities, 'form-INITIAL_FORMS': nb_entities, 'form-MIN_NUM_FORMS': 0, 'form-MAX_NUM_FORMS': 1000, 'form-0-id': entities[0].id, 'form-0-string': 'changed 0', 'form-0-comment': 'Wubba lubba dub dub', 'form-1-id': entities[1].id, 'form-1-string': 'string 1', 'form-1-obsolete': 'on', # Remove this one. } response = client_superuser.post(url, form_data) assert response.status_code == 200 assert b'changed 0' in response.content assert b'Wubba lubba dub dub' in response.content assert b'string 0' not in response.content assert b'string 1' not in response.content # It's been removed. total = Entity.objects.filter( resource=resource, obsolete=False, ).count() assert total == nb_entities - 1 # Test adding a new string. form_data = { 'form-TOTAL_FORMS': nb_entities, 'form-INITIAL_FORMS': nb_entities - 1, 'form-MIN_NUM_FORMS': 0, 'form-MAX_NUM_FORMS': 1000, 'form-0-id': entities[0].id, 'form-0-string': 'changed 0', 'form-0-comment': 'Wubba lubba dub dub', 'form-1-id': '', 'form-1-string': 'new string', 'form-1-comment': 'adding this entity now', } response = client_superuser.post(url, form_data) assert response.status_code == 200 assert b'changed 0' in response.content assert b'new string' in response.content assert b'adding this entity now' in response.content total = Entity.objects.filter( resource=resource, obsolete=False, ).count() assert total == nb_entities # Verify the new string has the correct order. new_string = Entity.objects.filter( resource=resource, obsolete=False, string='new string', ).first() # The highest order before adding new string was 0, # so the order of that new one should be 1. assert new_string.order == 1
def test_manage_project_strings_list(client_superuser): project = ProjectFactory.create(data_source="database", repositories=[]) resource = ResourceFactory.create(project=project) nb_entities = 2 entities = EntityFactory.create_batch(nb_entities, resource=resource) url = reverse("pontoon.admin.project.strings", args=(project.slug, )) response = client_superuser.get(url) assert response.status_code == 200 for i in range(nb_entities): assert (entities[i].string).encode("utf-8") in response.content # Test editing strings and comments. form_data = { "form-TOTAL_FORMS": nb_entities, "form-INITIAL_FORMS": nb_entities, "form-MIN_NUM_FORMS": 0, "form-MAX_NUM_FORMS": 1000, "form-0-id": entities[0].id, "form-0-string": "changed 0", "form-0-comment": "Wubba lubba dub dub", "form-1-id": entities[1].id, "form-1-string": "string 1", "form-1-obsolete": "on", # Remove this one. } response = client_superuser.post(url, form_data) assert response.status_code == 200 assert b"changed 0" in response.content assert b"Wubba lubba dub dub" in response.content assert b"string 0" not in response.content assert b"string 1" not in response.content # It's been removed. total = Entity.objects.filter( resource=resource, obsolete=False, ).count() assert total == nb_entities - 1 # Test adding a new string. form_data = { "form-TOTAL_FORMS": nb_entities, "form-INITIAL_FORMS": nb_entities - 1, "form-MIN_NUM_FORMS": 0, "form-MAX_NUM_FORMS": 1000, "form-0-id": entities[0].id, "form-0-string": "changed 0", "form-0-comment": "Wubba lubba dub dub", "form-1-id": "", "form-1-string": "new string", "form-1-comment": "adding this entity now", } response = client_superuser.post(url, form_data) assert response.status_code == 200 assert b"changed 0" in response.content assert b"new string" in response.content assert b"adding this entity now" in response.content total = Entity.objects.filter( resource=resource, obsolete=False, ).count() assert total == nb_entities # Verify the new string has the correct order. new_string = Entity.objects.filter( resource=resource, obsolete=False, string="new string", ).first() # The order of the new string should be that of the highest existing order # plus one. In our case, we know the highest was simply the other string. assert new_string.order == entities[0].order + 1