def setUp(self): self.locale = LocaleFactory.create(cldr_plurals="0,1") self.project = ProjectFactory.create(locales=[self.locale]) self.main_resource = ResourceFactory.create(project=self.project, path="main.lang") self.other_resource = ResourceFactory.create(project=self.project, path="other.lang") self.main_entity = EntityFactory.create( resource=self.main_resource, string="Source String", string_plural="Plural Source String", key="Source String", ) self.other_entity = EntityFactory.create( resource=self.other_resource, string="Other Source String", key="Key" + KEY_SEPARATOR + "Other Source String", ) self.main_translation = TranslationFactory.create( entity=self.main_entity, locale=self.locale, plural_form=0, string="Translated String" ) self.main_translation_plural = TranslationFactory.create( entity=self.main_entity, locale=self.locale, plural_form=1, string="Translated Plural String" ) self.other_translation = TranslationFactory.create( entity=self.other_entity, locale=self.locale, string="Other Translated String" ) self.subpage = SubpageFactory.create(project=self.project, name="Subpage", resources=[self.main_resource])
def test_multiple_translations(self): """ If there are multiple translations to the same locale, only authors of the final approved version should be returned. """ first_author, second_author = UserFactory.create_batch(2) TranslationFactory.create( locale=self.translated_locale, entity=self.main_db_entity, user=first_author, approved=True ) TranslationFactory.create( locale=self.translated_locale, entity=self.main_db_entity, user=second_author, approved=False ) self.changeset.update_vcs_entity(self.translated_locale, self.main_db_entity, MagicMock()) self.changeset.execute_update_vcs() assert_equal( self.changeset.commit_authors_per_locale[self.translated_locale.code], [first_author] )
def test_unchanged_resources_sync(self): """ Synchronization shouldn't modify resources if their entities weren't changed. """ TranslationFactory.create( locale=self.translated_locale, entity=self.main_db_entity, approved=True, date=aware_datetime(2015, 1, 1) ) resource_file = MagicMock() self.changeset.vcs_project.resources = { self.main_db_entity.resource.path: resource_file } with patch.object( self.main_db_entity, 'has_changed', return_value=False ) as mock_has_changed: self.changeset.update_vcs_entity( self.translated_locale, self.main_db_entity, MagicMock() ) self.changeset.execute_update_vcs() assert mock_has_changed.called assert len(resource_file.save.mock_calls) == 0
def test_no_new_translations(self): """ Don't change any resource if there aren't any new translations. """ TranslationFactory.create( locale=self.translated_locale, entity=self.main_db_entity, approved=True, date=aware_datetime(2015, 1, 1) ) with patch.object( self.main_db_entity, 'has_changed', return_value=False ) as mock_has_changed: resource_file = MagicMock() self.changeset.update_vcs_entity( self.translated_locale, self.main_db_entity, MagicMock() ) self.changeset.vcs_project.resources = { self.main_db_entity.resource.path: resource_file } self.changeset.execute_update_vcs() assert mock_has_changed.called assert not resource_file.save.called
def test_obsolete_entities_asymmetric_resources_sync(self): """ Synchronization should modify asymmetric resources files if their entities were made obsolete, even if their entities weren't changed. """ TranslationFactory.create(locale=self.translated_locale, entity=self.main_db_entity, approved=True, date=aware_datetime(2015, 1, 1)) resource_file = MagicMock() self.changeset.vcs_project.resources = { self.main_db_entity.resource.path: resource_file } # Entity must be made obsolete self.changeset.changes['obsolete_vcs'] = [self.main_db_entity.pk] # Resource file format must be asymmetric self.main_db_entity.resource.format = 'dtd' self.main_db_entity.resource.save() with patch.object(self.main_db_entity, 'has_changed', return_value=False) as mock_has_changed: self.changeset.update_vcs_entity(self.translated_locale, self.main_db_entity, MagicMock()) self.changeset.execute_update_vcs() assert mock_has_changed.called assert resource_file.save.called
def test_save_latest_translation_update(self): """ When a translation is saved, update the latest_translation attribute on the related project, locale, stats, and project_locale objects. """ locale = LocaleFactory.create(latest_translation=None) project = ProjectFactory.create(locales=[locale], latest_translation=None) resource = ResourceFactory.create(project=project) stats = StatsFactory.create(locale=locale, resource=resource, latest_translation=None) project_locale = ProjectLocale.objects.get(locale=locale, project=project) assert_is_none(locale.latest_translation) assert_is_none(project.latest_translation) assert_is_none(stats.latest_translation) assert_is_none(project_locale.latest_translation) translation = TranslationFactory.create( locale=locale, entity__resource=resource, date=aware_datetime(1970, 1, 1) ) self.assert_latest_translation(locale, translation) self.assert_latest_translation(project, translation) self.assert_latest_translation(stats, translation) self.assert_latest_translation(project_locale, translation) # Ensure translation is replaced for newer translations newer_translation = TranslationFactory.create( locale=locale, entity__resource=resource, date=aware_datetime(1970, 2, 1) ) self.assert_latest_translation(locale, newer_translation) self.assert_latest_translation(project, newer_translation) self.assert_latest_translation(stats, newer_translation) self.assert_latest_translation(project_locale, newer_translation) # Ensure translation isn't replaced for older translations. TranslationFactory.create( locale=locale, entity__resource=resource, date=aware_datetime(1970, 1, 5) ) self.assert_latest_translation(locale, newer_translation) self.assert_latest_translation(project, newer_translation) self.assert_latest_translation(stats, newer_translation) self.assert_latest_translation(project_locale, newer_translation) # Ensure approved_date is taken into consideration as well. newer_approved_translation = TranslationFactory.create( locale=locale, entity__resource=resource, approved_date=aware_datetime(1970, 3, 1) ) self.assert_latest_translation(locale, newer_approved_translation) self.assert_latest_translation(project, newer_approved_translation) self.assert_latest_translation(stats, newer_approved_translation) self.assert_latest_translation(project_locale, newer_approved_translation)
def test_contributors_limit(self): """ Checks if proper count of user is returned. """ TranslationFactory.create_batch(110) top_contributors = User.translators.with_translation_counts() assert_equal(top_contributors.count(), 100)
def test_no_translations(self): """ We don't attribute anyone if there aren't any new translations. """ TranslationFactory.create(locale=self.translated_locale, entity=self.main_db_entity, approved=True, date=aware_datetime(2015, 1, 1)) with patch.object(self.main_db_entity, 'has_changed', return_value=False): self.changeset.update_vcs_entity(self.translated_locale, self.main_db_entity, MagicMock()) self.changeset.execute_update_vcs() assert_equal(self.changeset.commit_authors_per_locale[self.translated_locale.code], [])
def test_excluded_contributors(self): """ Checks if contributors with mails in settings.EXCLUDE are excluded from top contributors list. """ included_contributor = TranslationFactory.create(user__email="*****@*****.**").user excluded_contributor = TranslationFactory.create(user__email="*****@*****.**").user top_contributors = User.translators.with_translation_counts() assert_true(included_contributor in top_contributors) assert_true(excluded_contributor not in top_contributors)
def setUp(self): self.locale = LocaleFactory.create( cldr_plurals="0,1" ) self.project = ProjectFactory.create( locales=[self.locale] ) self.main_resource = ResourceFactory.create( project=self.project, path='main.lang' ) self.other_resource = ResourceFactory.create( project=self.project, path='other.lang' ) self.main_entity = EntityFactory.create( resource=self.main_resource, string='Source String', string_plural='Plural Source String', key='Source String' ) self.other_entity = EntityFactory.create( resource=self.other_resource, string='Other Source String', key='Key' + KEY_SEPARATOR + 'Other Source String' ) self.main_translation = TranslationFactory.create( entity=self.main_entity, locale=self.locale, plural_form=0, string='Translated String' ) self.main_translation_plural = TranslationFactory.create( entity=self.main_entity, locale=self.locale, plural_form=1, string='Translated Plural String' ) self.other_translation = TranslationFactory.create( entity=self.other_entity, locale=self.locale, string='Other Translated String' ) self.subpage = SubpageFactory.create( project=self.project, name='Subpage', resources=[self.main_resource] )
def create_db_entities_translations(self): """ Create entities and translations in the database for strings from the fake checkout. """ self.main_db_entity = EntityFactory.create( resource=self.main_db_resource, string='Source String', key='Source String', obsolete=False ) self.other_db_entity = EntityFactory.create( resource=self.other_db_resource, string='Other Source String', key='Other Source String', obsolete=False ) self.main_db_translation = TranslationFactory.create( entity=self.main_db_entity, plural_form=None, locale=self.translated_locale, string='Translated String', date=aware_datetime(1970, 1, 1), approved=True, extra={'tags': []} )
def test_remove_duplicate_approvals(self): """ Ensure that duplicate approvals are removed. """ # Trigger creation of new approved translation. self.main_vcs_translation.strings[None] = 'New Translated String' self.main_vcs_translation.fuzzy = False # Translation approved after the sync started simulates the race # where duplicate translations occur. duplicate_translation = TranslationFactory.create( entity=self.main_db_entity, locale=self.translated_locale, string='Other New Translated String', approved=True, approved_date=aware_datetime(1970, 1, 3) ) ChangedEntityLocale.objects.filter(entity=self.main_db_entity).delete() with patch('pontoon.sync.tasks.VCSProject', return_value=self.vcs_project): sync_project_repo(self.db_project.pk, self.repository.pk, self.project_sync_log.pk, self.now) # Only one translation should be approved: the duplicate_translation. assert_equal(self.main_db_entity.translation_set.filter(approved=True).count(), 1) new_translation = self.main_db_entity.translation_set.get( string='New Translated String' ) assert_false(new_translation.approved) assert_true(new_translation.approved_date is None) duplicate_translation.refresh_from_db() assert_true(duplicate_translation.approved) assert_equal(duplicate_translation.approved_date, aware_datetime(1970, 1, 3))
def setUp(self): """ We setup a sample contributor with random set of translations. """ super(ContributorTimelineViewTests, self).setUp() self.project = ProjectFactory.create() self.translations = OrderedDict() for i in range(26): date = make_aware(datetime(2016, 12, 1) - timedelta(days=i)) translations_count = randint(1, 3) self.translations.setdefault((date, translations_count), []).append( sorted( TranslationFactory.create_batch( translations_count, date=date, user=self.user, entity__resource__project=self.project, ), key=lambda t: t.pk, reverse=True, ) ) mock_render = patch('pontoon.contributors.views.render', return_value=HttpResponse('')) self.mock_render = mock_render.start() self.addCleanup(mock_render.stop)
def test_removed_translation(self): """ Suggestions should be available even after an Entity or Translation has been removed. """ translation = TranslationFactory.create(approved=True) assert TranslationMemoryEntry.objects.get( source=translation.entity.string, target=translation.string, locale=translation.locale ) entity = translation.entity translation.delete() assert TranslationMemoryEntry.objects.get( source=translation.entity.string, target=translation.string, locale=translation.locale ) entity.delete() assert TranslationMemoryEntry.objects.get( source=translation.entity.string, target=translation.string, locale=translation.locale )
def test_update_db_unapprove_existing(self): """ Any existing translations that don't match anything in VCS get unapproved, unless they were created after self.now. """ self.main_db_translation.approved = True self.main_db_translation.approved_date = aware_datetime(1970, 1, 1) self.main_db_translation.approved_user = UserFactory.create() self.main_db_translation.save() self.main_vcs_translation.strings[None] = 'New Translated String' created_after_translation = TranslationFactory.create( entity=self.main_db_entity, approved=True, approved_date=aware_datetime(1970, 1, 3) ) self.update_main_db_entity() self.main_db_translation.refresh_from_db() assert_attributes_equal( self.main_db_translation, approved=False, approved_user=None, approved_date=None ) created_after_translation.refresh_from_db() assert_attributes_equal( created_after_translation, approved=True, approved_date=aware_datetime(1970, 1, 3) )
def _translation(self, user, submitted, approved): return TranslationFactory.create( date=aware_datetime(*submitted), user=user, approved_date=aware_datetime(*approved) if approved else None, approved_user=user )
def test_get_latest_activity_with_latest(self): """ If the locale has a latest_translation and no project is given, return it. """ translation = TranslationFactory.create() locale = LocaleFactory.create(latest_translation=translation) assert_equal(locale.get_latest_activity(), translation.latest_activity)
def test_get_latest_activity_success(self): """ If the matching ProjectLocale has a latest_translation, return it's latest_activity. """ translation = TranslationFactory.create(locale=self.locale, entity__resource__project=self.project) ProjectLocaleFactory.create(project=self.project, locale=self.locale, latest_translation=translation) assert_equal(ProjectLocale.get_latest_activity(self.project, self.locale), translation.latest_activity)
def test_approved_translation_in_memory(self): """ Every save of approved translation should generate a new entry in the translation memory. """ translation = TranslationFactory.create(approved=True) assert TranslationMemoryEntry.objects.get( source=translation.entity.string, target=translation.string, locale=translation.locale )
def test_unapproved_translation_in_memory(self): """ Unapproved translation shouldn't be in the translation memory. """ translation = TranslationFactory.create(approved=False) with assert_raises(TranslationMemoryEntry.DoesNotExist): TranslationMemoryEntry.objects.get( source=translation.entity.string, target=translation.string, locale=translation.locale )
def test_users_without_translations(self): """ Checks if user contributors without translations aren't returned. """ active_contributor = TranslationFactory.create(user__email="*****@*****.**").user inactive_contributor = UserFactory.create(email="*****@*****.**") top_contributors = User.translators.with_translation_counts() assert_true(active_contributor in top_contributors) assert_true(inactive_contributor not in top_contributors)
def test_no_translations(self): """ We don't attribute anyone if there aren't any new translations. """ TranslationFactory.create( locale=self.translated_locale, entity=self.main_db_entity, approved=True, date=aware_datetime(2015, 1, 1), ) with patch.object(self.main_db_entity, "has_changed", return_value=False): self.changeset.update_vcs_entity( self.translated_locale, self.main_db_entity, MagicMock() ) self.changeset.execute_update_vcs() assert ( self.changeset.commit_authors_per_locale[self.translated_locale.code] == [] )
def test_unique_translations(self): """ Checks if contributors with identical translations are returned. """ unique_translator = TranslationFactory.create().user identical_translator = IdenticalTranslationFactory.create().user top_contributors = User.translators.with_translation_counts() assert_true(unique_translator in top_contributors) assert_true(identical_translator not in top_contributors)
def test_locale_top_contributors(self): """ Tests if view returns top contributors specific for given locale. """ first_locale = LocaleFactory.create() first_locale_contributor = TranslationFactory.create(locale=first_locale, entity__resource__project__locales=[first_locale]).user second_locale = LocaleFactory.create() second_locale_contributor = TranslationFactory.create(locale=second_locale, entity__resource__project__locales=[second_locale]).user with patch.object(views.LocaleContributorsView, 'render_to_response', return_value=HttpResponse('')) as mock_render: self.client.get('/{}/contributors/'.format(first_locale.code)) assert_equal(mock_render.call_args[0][0]['locale'], first_locale) assert_equal(list(mock_render.call_args[0][0]['contributors']), [first_locale_contributor]) self.client.get('/{}/contributors/'.format(second_locale.code)) assert_equal(mock_render.call_args[0][0]['locale'], second_locale) assert_equal(list(mock_render.call_args[0][0]['contributors']), [second_locale_contributor])
def test_get_latest_activity_with_latest(self): """ If the project has a latest_translation and no locale is given, return it. """ project = ProjectFactory.create() translation = TranslationFactory.create(entity__resource__project=project) project.latest_translation = translation project.save() assert_equal(project.get_latest_activity(), translation.latest_activity)
def test_users_without_translations(self): """ Checks if user contributors without translations aren't returned. """ active_contributor = TranslationFactory.create( user__email='*****@*****.**').user inactive_contributor = UserFactory.create(email='*****@*****.**') top_contributors = User.translators.with_translation_counts() assert_true(active_contributor in top_contributors) assert_true(inactive_contributor not in top_contributors)
def test_period_filters(self): """ Total counts should be filtered by given date. Test creates 2 contributors with different activity periods and checks if they are filtered properly. """ first_contributor = self.create_contributor_with_translation_counts(approved=12, unapproved=1, needs_work=2, date=aware_datetime(2015, 3, 2)) # Second contributor self.create_contributor_with_translation_counts(approved=2, unapproved=11, needs_work=2, date=aware_datetime(2015, 6, 1)) TranslationFactory.create_batch(5, approved=True, user=first_contributor, date=aware_datetime(2015, 7, 2)) top_contributors = User.translators.with_translation_counts(aware_datetime(2015, 6, 10)) assert_equal(top_contributors.count(), 1) assert_attributes_equal(top_contributors[0], translations_count=5, translations_approved_count=5, translations_unapproved_count=0, translations_needs_work_count=0) top_contributors = User.translators.with_translation_counts(aware_datetime(2015, 5, 10)) assert_equal(top_contributors.count(), 2) assert_attributes_equal(top_contributors[0], translations_count=15, translations_approved_count=2, translations_unapproved_count=11, translations_needs_work_count=2) assert_attributes_equal(top_contributors[1], translations_count=5, translations_approved_count=5, translations_unapproved_count=0, translations_needs_work_count=0) top_contributors = User.translators.with_translation_counts(aware_datetime(2015, 1, 10)) assert_equal(top_contributors.count(), 2) assert_attributes_equal(top_contributors[0], translations_count=20, translations_approved_count=17, translations_unapproved_count=1, translations_needs_work_count=2) assert_attributes_equal(top_contributors[1], translations_count=15, translations_approved_count=2, translations_unapproved_count=11, translations_needs_work_count=2)
def setUp(self): super(TranslationActionsTests, self).setUp() project = ProjectFactory.create() locale = LocaleFactory.create() ProjectLocale.objects.create(project=project, locale=locale) translation = TranslationFactory.create(locale=locale, entity__resource__project=project) translation.approved = True translation.save() self.translation = translation
def test_project_top_contributors(self): """ Tests if view returns top contributors specific for given project. """ first_project = ProjectFactory.create() ResourceFactory.create(project=first_project) first_project_contributor = TranslationFactory.create(entity__resource__project=first_project).user second_project = ProjectFactory.create() ResourceFactory.create(project=second_project) second_project_contributor = TranslationFactory.create(entity__resource__project=second_project).user with patch.object(views.ProjectContributorsView, 'render_to_response', return_value=HttpResponse('')) as mock_render: self.client.get('/projects/{}/contributors/'.format(first_project.slug)) assert_equal(mock_render.call_args[0][0]['project'], first_project) assert_equal(list(mock_render.call_args[0][0]['contributors']), [first_project_contributor]) self.client.get('/projects/{}/contributors/'.format(second_project.slug)) assert_equal(mock_render.call_args[0][0]['project'], second_project) assert_equal(list(mock_render.call_args[0][0]['contributors']), [second_project_contributor])
def test_plural_translations(self): """ If entity has some plural translations and approved translations their authors should be included in commit message. """ first_author, second_author, third_author = UserFactory.create_batch(3) TranslationFactory.create( locale=self.translated_locale, entity=self.main_db_entity, user=first_author, approved=True ) TranslationFactory.create( locale=self.translated_locale, entity=self.main_db_entity, user=third_author, approved=True, plural_form=1 ) TranslationFactory.create( locale=self.translated_locale, entity=self.main_db_entity, user=second_author, approved=False ) self.changeset.update_vcs_entity(self.translated_locale, self.main_db_entity, MagicMock()) self.changeset.execute_update_vcs() assert_equal( set(self.changeset.commit_authors_per_locale[self.translated_locale.code]), {first_author, third_author} )
def test_project_top_contributors(self): """ Tests if view returns top contributors specific for given project. """ first_project = ProjectFactory.create() ResourceFactory.create(project=first_project) first_project_contributor = TranslationFactory.create( entity__resource__project=first_project).user second_project = ProjectFactory.create() ResourceFactory.create(project=second_project) second_project_contributor = TranslationFactory.create( entity__resource__project=second_project).user with patch.object( views.ProjectContributorsView, "render_to_response", return_value=HttpResponse(""), ) as mock_render: self.client.get( "/projects/{}/ajax/contributors/".format(first_project.slug), HTTP_X_REQUESTED_WITH="XMLHttpRequest", ) assert_equal(mock_render.call_args[0][0]["project"], first_project) assert_equal( list(mock_render.call_args[0][0]["contributors"]), [first_project_contributor], ) self.client.get( "/projects/{}/ajax/contributors/".format(second_project.slug), HTTP_X_REQUESTED_WITH="XMLHttpRequest", ) assert_equal(mock_render.call_args[0][0]["project"], second_project) assert_equal( list(mock_render.call_args[0][0]["contributors"]), [second_project_contributor], )
def test_get_latest_activity_with_latest(self): """ If the project has a latest_translation and no locale is given, return it. """ project = ProjectFactory.create() translation = TranslationFactory.create( entity__resource__project=project) project.latest_translation = translation project.save() assert_equal(project.get_latest_activity(), translation.latest_activity)
def setUp(self): super(TranslationUpdateTestCase, self).setUp() locale = LocaleFactory.create() project = ProjectFactory.create() ProjectLocale.objects.create( project=project, locale=locale, ) resource = ResourceFactory.create(project=project) entity = EntityFactory.create(resource=resource) self.translation = TranslationFactory.create(entity=entity, locale=locale) self.translation.locale.translators_group.user_set.add(self.user)
def test_get_latest_activity_success(self): """ If the matching ProjectLocale has a latest_translation, return it's latest_activity. """ translation = TranslationFactory.create( locale=self.locale, entity__resource__project=self.project) ProjectLocaleFactory.create(project=self.project, locale=self.locale, latest_translation=translation) assert_equal( ProjectLocale.get_latest_activity(self.project, self.locale), translation.latest_activity)
def test_no_new_translations(self): """ Don't change any resource if there aren't any new translations. """ TranslationFactory.create(locale=self.translated_locale, entity=self.main_db_entity, approved=True, date=aware_datetime(2015, 1, 1)) with patch.object(self.main_db_entity, 'has_changed', return_value=False) as mock_has_changed: resource_file = MagicMock() self.changeset.update_vcs_entity(self.translated_locale, self.main_db_entity, MagicMock()) self.changeset.vcs_project.resources = { self.main_db_entity.resource.path: resource_file } self.changeset.execute_update_vcs() assert mock_has_changed.called assert not resource_file.save.called
def test_unchanged_resources_sync(self): """ Synchronization shouldn't modify resources if their entities weren't changed. """ TranslationFactory.create(locale=self.translated_locale, entity=self.main_db_entity, approved=True, date=aware_datetime(2015, 1, 1)) resource_file = MagicMock() self.changeset.vcs_project.resources = { self.main_db_entity.resource.path: resource_file } with patch.object(self.main_db_entity, 'has_changed', return_value=False) as mock_has_changed: self.changeset.update_vcs_entity(self.translated_locale, self.main_db_entity, MagicMock()) self.changeset.execute_update_vcs() assert mock_has_changed.called assert len(resource_file.save.mock_calls) == 0
def test_project_top_contributors(client): """ Tests if view returns top contributors specific for given project. """ first_project = ProjectFactory.create(visibility=Project.Visibility.PUBLIC) ResourceFactory.create(project=first_project) first_project_contributor = TranslationFactory.create( entity__resource__project=first_project ).user second_project = ProjectFactory.create(visibility=Project.Visibility.PUBLIC) ResourceFactory.create(project=second_project) second_project_contributor = TranslationFactory.create( entity__resource__project=second_project ).user with patch( "pontoon.projects.views.ProjectContributorsView.render_to_response", return_value=HttpResponse(""), ) as mock_render: client.get( "/projects/{}/ajax/contributors/".format(first_project.slug), HTTP_X_REQUESTED_WITH="XMLHttpRequest", ) assert mock_render.call_args[0][0]["project"] == first_project assert list(mock_render.call_args[0][0]["contributors"]) == [ first_project_contributor ] client.get( "/projects/{}/ajax/contributors/".format(second_project.slug), HTTP_X_REQUESTED_WITH="XMLHttpRequest", ) assert mock_render.call_args[0][0]["project"] == second_project assert list(mock_render.call_args[0][0]["contributors"]) == [ second_project_contributor ]
def create_contributor_with_translation_counts(self, approved=0, unapproved=0, needs_work=0, **kwargs): """ Helper method, creates contributor with given translations counts. """ contributor = UserFactory.create() TranslationFactory.create_batch(approved, user=contributor, approved=True, **kwargs) TranslationFactory.create_batch(unapproved, user=contributor, approved=False, fuzzy=False, **kwargs) TranslationFactory.create_batch(needs_work, user=contributor, fuzzy=True, **kwargs) return contributor
def test_unapprove_translation(self): """Check if unapprove view works properly.""" translation = TranslationFactory.create() translation.approved = True translation.save() response = self.client.ajax_post('/unapprove-translation/', { 'translation': translation.pk, 'paths': [], }) assert_code(response, 200) translation.refresh_from_db() assert_equal(translation.approved, False) assert_equal(translation.unapproved_user, self.user)
def test_multiple_translations(self): """ If there are multiple translations to the same locale, only authors of the final approved version should be returned. """ first_author, second_author = UserFactory.create_batch(2) TranslationFactory.create(locale=self.translated_locale, entity=self.main_db_entity, user=first_author, approved=True) TranslationFactory.create(locale=self.translated_locale, entity=self.main_db_entity, user=second_author, approved=False) self.changeset.update_vcs_entity(self.translated_locale, self.main_db_entity, MagicMock()) self.changeset.execute_update_vcs() assert_equal( self.changeset.commit_authors_per_locale[ self.translated_locale.code], [first_author])
def test_bulk_check_valid_translations(self): translation1, translation2 = TranslationFactory.create_batch( 2, locale=self.translated_locale, entity=self.main_db_entity, approved=True, date=aware_datetime(2015, 1, 1)) self.mock_changed_translations.return_value = [ translation1, translation2, ] assert_equal(self.changeset.bulk_check_translations(), { translation1.pk, translation2.pk, }) assert_equal(Error.objects.count(), 0) assert_equal(Warning.objects.count(), 0)
def test_remove_duplicate_approvals(self): """ Ensure that duplicate approvals are removed. """ # Trigger creation of new approved translation. self.main_vcs_translation.strings[None] = "New Translated String" self.main_vcs_translation.fuzzy = False self.mock_pull_changes.return_value = [ True, { self.repository.pk: Locale.objects.filter(pk=self.translated_locale.pk) }, ] # Translation approved after the sync started simulates the race # where duplicate translations occur. duplicate_translation = TranslationFactory.create( entity=self.main_db_entity, locale=self.translated_locale, string="Other New Translated String", approved=True, approved_date=aware_datetime(1970, 1, 3), ) ChangedEntityLocale.objects.filter(entity=self.main_db_entity).delete() with patch("pontoon.sync.tasks.VCSProject", return_value=self.vcs_project): sync_translations(self.db_project.pk, self.project_sync_log.pk, self.now) # Only one translation should be approved: the duplicate_translation. assert_equal( self.main_db_entity.translation_set.filter(approved=True).count(), 1) new_translation = self.main_db_entity.translation_set.get( string="New Translated String") assert_false(new_translation.approved) assert_true(new_translation.approved_date is None) duplicate_translation.refresh_from_db() assert_true(duplicate_translation.approved) assert_equal(duplicate_translation.approved_date, aware_datetime(1970, 1, 3))
def test_bulk_check_invalid_translations(self): """ Test scenario: * check if errors are detected * check if only valid translation will land in the Translate Memory """ invalid_translation, valid_translation = TranslationFactory.create_batch( 2, locale=self.translated_locale, entity=self.main_db_entity, approved=True, date=aware_datetime(2015, 1, 1), ) invalid_translation.string = "a\nb" invalid_translation.save() # Clear TM entries for those translations invalid_translation.memory_entries.all().delete() valid_translation.memory_entries.all().delete() self.mock_changed_translations.return_value = [ invalid_translation, valid_translation, ] valid_translations = self.changeset.bulk_check_translations() assert valid_translations == {valid_translation.pk} (error, ) = Error.objects.all() assert error.library == FailedCheck.Library.PONTOON assert error.message == "Newline characters are not allowed" assert error.translation == invalid_translation self.changeset.translations_to_update = { valid_translation.pk: valid_translation } self.changeset.bulk_create_translation_memory_entries( valid_translations) assert not invalid_translation.memory_entries.exists() assert valid_translation.memory_entries.count() == 1
def test_bulk_check_invalid_translations(self): """ Test scenario: * check if errors are detected * check if only valid translation will land in the Translate Memory """ invalid_translation, valid_translation = TranslationFactory.create_batch( 2, locale=self.translated_locale, entity=self.main_db_entity, approved=True, date=aware_datetime(2015, 1, 1) ) invalid_translation.string = 'a\nb' invalid_translation.save() # Clear TM entries for those translations invalid_translation.memory_entries.all().delete() valid_translation.memory_entries.all().delete() self.mock_changed_translations.return_value = [ invalid_translation, valid_translation, ] valid_translations = self.changeset.bulk_check_translations() assert_equal(valid_translations, {valid_translation.pk}) error, = Error.objects.all() assert_equal(error.library, 'p') assert_equal(error.message, 'Newline characters are not allowed') assert_equal(error.translation, invalid_translation) self.changeset.translations_to_update = { valid_translation.pk: valid_translation } self.changeset.bulk_create_translation_memory_entries(valid_translations) assert_equal(invalid_translation.memory_entries.count(), 0) assert_equal(valid_translation.memory_entries.count(), 1)
def test_project_locale_modified(self): """ If ProjectLocale is modified (like setting the latest_translation), has_changed should not be modified. """ locale = LocaleFactory.create() project = ProjectFactory.create(locales=[locale]) project.has_changed = False project.save() project.refresh_from_db() assert_false(project.has_changed) project_locale = ProjectLocale.objects.get(project=project, locale=locale) project_locale.latest_translation = TranslationFactory.create( entity__resource__project=project, locale=locale) project_locale.save() project.refresh_from_db() assert_false(project.has_changed)
def test_multiple_authors(self): """ Commit message should include authors from translations of separate entities. """ first_author, second_author = UserFactory.create_batch(2) TranslationFactory.create( locale=self.translated_locale, entity=self.main_db_entity, user=first_author, approved=True ) TranslationFactory.create( locale=self.translated_locale, entity=self.main_db_entity, approved=False ) TranslationFactory.create( locale=self.translated_locale, entity=self.other_db_entity, user=second_author, approved=True ) TranslationFactory.create( locale=self.translated_locale, entity=self.other_db_entity, approved=False ) self.changeset.update_vcs_entity(self.translated_locale, self.main_db_entity, MagicMock()) self.changeset.update_vcs_entity(self.translated_locale, self.other_db_entity, MagicMock()) self.changeset.execute_update_vcs() assert_equal( self.changeset.commit_authors_per_locale[self.translated_locale.code], [first_author, second_author] )
def test_save_latest_translation_missing_project_locale(self): """ If a translation is saved for a locale that isn't active on the project, do not fail due to a missing ProjectLocale. """ locale = LocaleFactory.create(latest_translation=None) project = ProjectFactory.create(latest_translation=None) resource = ResourceFactory.create(project=project) translatedresource = TranslatedResourceFactory.create( locale=locale, resource=resource, latest_translation=None) # This calls .save, this should fail if we're not properly # handling the missing ProjectLocale. translation = TranslationFactory.create(locale=locale, entity__resource=resource, date=aware_datetime( 1970, 1, 1)) self.assert_latest_translation(locale, translation) self.assert_latest_translation(project, translation) self.assert_latest_translation(translatedresource, translation)
def contributor_translations(settings, user_a, project_a): """ Setup a sample contributor with random set of translations. """ translations = OrderedDict() for i in range(6): date = make_aware(datetime(2016, 12, 1) - timedelta(days=i)) translations_count = 2 translations.setdefault((date, translations_count), []).append( sorted( TranslationFactory.create_batch( translations_count, date=date, user=user_a, entity__resource__project=project_a, ), key=lambda t: t.pk, reverse=True, )) settings.CONTRIBUTORS_TIMELINE_EVENTS_PER_PAGE = 2 yield translations
def test_removed_translation(self): """ Suggestions should be available even after an Entity or Translation has been removed. """ translation = TranslationFactory.create(approved=True) assert TranslationMemoryEntry.objects.get( source=translation.entity.string, target=translation.string, locale=translation.locale) entity = translation.entity translation.delete() assert TranslationMemoryEntry.objects.get( source=translation.entity.string, target=translation.string, locale=translation.locale) entity.delete() assert TranslationMemoryEntry.objects.get( source=translation.entity.string, target=translation.string, locale=translation.locale)
def test_update_db_unapprove_existing(self): """ Any existing translations that don't match anything in VCS get unapproved, unless they were created after self.now. """ self.main_db_translation.approved = True self.main_db_translation.approved_date = aware_datetime(1970, 1, 1) self.main_db_translation.approved_user = UserFactory.create() self.main_db_translation.save() self.main_vcs_translation.strings[None] = "New Translated String" created_after_translation = TranslationFactory.create( entity=self.main_db_entity, approved=True, approved_date=aware_datetime(1970, 1, 3), ) self.update_main_db_entity() self.main_db_translation.refresh_from_db() assert_attributes_equal( self.main_db_translation, approved=False, approved_user=None, approved_date=None, ) assert ActionLog.objects.filter( action_type="translation:rejected", translation=self.main_db_translation.pk, ).exists() created_after_translation.refresh_from_db() assert_attributes_equal( created_after_translation, approved=True, approved_date=aware_datetime(1970, 1, 3), )
def setUp(self): """ We setup a sample contributor with random set of translations. """ super(ContributorTimelineViewTests, self).setUp() self.project = ProjectFactory.create() self.translations = OrderedDict() for i in xrange(26): date = make_aware(datetime(2016, 12, 1) - timedelta(days=i)) translations_count = randint(1, 3) self.translations.setdefault( (date, translations_count), []).append( TranslationFactory.create_batch( translations_count, date=date, user=self.user, entity__resource__project=self.project, )) mock_render = patch('pontoon.base.views.render', return_value=HttpResponse('')) self.mock_render = mock_render.start() self.addCleanup(mock_render.stop)
def setUp(self): self.now = aware_datetime(1970, 1, 1) timezone_patch = patch("pontoon.sync.tasks.timezone") self.mock_timezone = timezone_patch.start() self.addCleanup(timezone_patch.stop) self.mock_timezone.now.return_value = self.now self.translated_locale = LocaleFactory.create(code="translated-locale") self.inactive_locale = LocaleFactory.create(code="inactive-locale") self.repository = RepositoryFactory() self.db_project = ProjectFactory.create( name="db-project", locales=[self.translated_locale], repositories=[self.repository], ) self.main_db_resource = ResourceFactory.create(project=self.db_project, path="main.lang", format="lang") self.other_db_resource = ResourceFactory.create( project=self.db_project, path="other.lang", format="lang") self.missing_db_resource = ResourceFactory.create( project=self.db_project, path="missing.lang", format="lang") self.main_db_entity = EntityFactory.create( resource=self.main_db_resource, string="Source String", key="Source String", obsolete=False, ) self.other_db_entity = EntityFactory.create( resource=self.other_db_resource, string="Other Source String", key="Other Source String", obsolete=False, ) self.main_db_translation = TranslationFactory.create( entity=self.main_db_entity, plural_form=None, locale=self.translated_locale, string="Translated String", date=aware_datetime(1970, 1, 1), approved=True, extra={"tags": []}, ) # Load paths from the fake locale directory. checkout_path_patch = patch.object( Project, "checkout_path", new_callable=PropertyMock, return_value=FAKE_CHECKOUT_PATH, ) checkout_path_patch.start() self.addCleanup(checkout_path_patch.stop) vcs_changed_files = { self.main_db_resource.path: [self.translated_locale], self.other_db_resource.path: [self.translated_locale], self.missing_db_resource.path: [self.translated_locale], } changed_files_patch = patch.object( VCSProject, "changed_files", new_callable=PropertyMock, return_value=vcs_changed_files, ) changed_files_patch.start() self.addCleanup(changed_files_patch.stop) source_repository = patch.object( Project, "source_repository", new_callable=PropertyMock, return_value=self.db_project.repositories.all()[0], ) source_repository.start() self.addCleanup(source_repository.stop) self.vcs_project = VCSProject(self.db_project) self.main_vcs_resource = self.vcs_project.resources[ self.main_db_resource.path] self.other_vcs_resource = self.vcs_project.resources[ self.other_db_resource.path] self.missing_vcs_resource = self.vcs_project.resources[ self.missing_db_resource.path] self.main_vcs_entity = self.main_vcs_resource.entities["Source String"] self.main_vcs_translation = self.main_vcs_entity.translations[ "translated-locale"] # Mock VCSResource.save() for each resource to avoid altering # the filesystem. resource_save_patch = patch.object(VCSResource, "save") resource_save_patch.start() self.addCleanup(resource_save_patch.stop) self.changeset = ChangeSet( self.db_project, self.vcs_project, aware_datetime(1970, 1, 1), self.translated_locale, )
def test_period_filters(self): """ Total counts should be filtered by given date. Test creates 2 contributors with different activity periods and checks if they are filtered properly. """ first_contributor = self.create_contributor_with_translation_counts( approved=12, unapproved=1, needs_work=2, date=aware_datetime(2015, 3, 2)) # Second contributor self.create_contributor_with_translation_counts(approved=2, unapproved=11, needs_work=2, date=aware_datetime( 2015, 6, 1)) TranslationFactory.create_batch(5, approved=True, user=first_contributor, date=aware_datetime(2015, 7, 2)) top_contributors = User.translators.with_translation_counts( aware_datetime(2015, 6, 10)) assert_equal(top_contributors.count(), 1) assert_attributes_equal(top_contributors[0], translations_count=5, translations_approved_count=5, translations_unapproved_count=0, translations_needs_work_count=0) top_contributors = User.translators.with_translation_counts( aware_datetime(2015, 5, 10)) assert_equal(top_contributors.count(), 2) assert_attributes_equal(top_contributors[0], translations_count=15, translations_approved_count=2, translations_unapproved_count=11, translations_needs_work_count=2) assert_attributes_equal(top_contributors[1], translations_count=5, translations_approved_count=5, translations_unapproved_count=0, translations_needs_work_count=0) top_contributors = User.translators.with_translation_counts( aware_datetime(2015, 1, 10)) assert_equal(top_contributors.count(), 2) assert_attributes_equal(top_contributors[0], translations_count=20, translations_approved_count=17, translations_unapproved_count=1, translations_needs_work_count=2) assert_attributes_equal(top_contributors[1], translations_count=15, translations_approved_count=2, translations_unapproved_count=11, translations_needs_work_count=2)