X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/blobdiff_plain/d2f2500bddb2a3809cd8e96a64c091f331b8f274..adf87805bb2ffb1f297867dcee8dc21264209496:/third_party/transifex-client/tests/test_project.py diff --git a/third_party/transifex-client/tests/test_project.py b/third_party/transifex-client/tests/test_project.py new file mode 100644 index 00000000..3b421214 --- /dev/null +++ b/third_party/transifex-client/tests/test_project.py @@ -0,0 +1,531 @@ +# -*- coding: utf-8 -*- + +from __future__ import with_statement +import unittest +import contextlib +import itertools +try: + import json +except ImportError: + import simplejson as json +from mock import Mock, patch + +from txclib.project import Project +from txclib.config import Flipdict + + +class TestProject(unittest.TestCase): + + def test_extract_fields(self): + """Test the functions that extract a field from a stats object.""" + stats = { + 'completed': '80%', + 'last_update': '00:00', + 'foo': 'bar', + } + self.assertEqual( + stats['completed'], '%s%%' % Project._extract_completed(stats) + ) + self.assertEqual(stats['last_update'], Project._extract_updated(stats)) + + def test_specifying_resources(self): + """Test the various ways to specify resources in a project.""" + p = Project(init=False) + resources = [ + 'proj1.res1', + 'proj2.res2', + 'transifex.txn', + 'transifex.txo', + ] + with patch.object(p, 'get_resource_list') as mock: + mock.return_value = resources + cmd_args = [ + 'proj1.res1', '*1*', 'transifex*', '*r*', + '*o', 'transifex.tx?', 'transifex.txn', + ] + results = [ + ['proj1.res1', ], + ['proj1.res1', ], + ['transifex.txn', 'transifex.txo', ], + ['proj1.res1', 'proj2.res2', 'transifex.txn', 'transifex.txo', ], + ['transifex.txo', ], + ['transifex.txn', 'transifex.txo', ], + ['transifex.txn', ], + [], + ] + + for i, arg in enumerate(cmd_args): + resources = [arg] + self.assertEqual(p.get_chosen_resources(resources), results[i]) + + # wrong argument + resources = ['*trasnifex*', ] + self.assertRaises(Exception, p.get_chosen_resources, resources) + + +class TestProjectMinimumPercent(unittest.TestCase): + """Test the minimum-perc option.""" + + def setUp(self): + super(TestProjectMinimumPercent, self).setUp() + self.p = Project(init=False) + self.p.minimum_perc = None + self.p.resource = "resource" + + def test_cmd_option(self): + """Test command-line option.""" + self.p.minimum_perc = 20 + results = itertools.cycle([80, 90 ]) + def side_effect(*args): + return results.next() + + with patch.object(self.p, "get_resource_option") as mock: + mock.side_effect = side_effect + self.assertFalse(self.p._satisfies_min_translated({'completed': '12%'})) + self.assertTrue(self.p._satisfies_min_translated({'completed': '20%'})) + self.assertTrue(self.p._satisfies_min_translated({'completed': '30%'})) + + def test_global_only(self): + """Test only global option.""" + results = itertools.cycle([80, None ]) + def side_effect(*args): + return results.next() + + with patch.object(self.p, "get_resource_option") as mock: + mock.side_effect = side_effect + self.assertFalse(self.p._satisfies_min_translated({'completed': '70%'})) + self.assertTrue(self.p._satisfies_min_translated({'completed': '80%'})) + self.assertTrue(self.p._satisfies_min_translated({'completed': '90%'})) + + def test_local_lower_than_global(self): + """Test the case where the local option is lower than the global.""" + results = itertools.cycle([80, 70 ]) + def side_effect(*args): + return results.next() + + with patch.object(self.p, "get_resource_option") as mock: + mock.side_effect = side_effect + self.assertFalse(self.p._satisfies_min_translated({'completed': '60%'})) + self.assertTrue(self.p._satisfies_min_translated({'completed': '70%'})) + self.assertTrue(self.p._satisfies_min_translated({'completed': '80%'})) + self.assertTrue(self.p._satisfies_min_translated({'completed': '90%'})) + + def test_local_higher_than_global(self): + """Test the case where the local option is lower than the global.""" + results = itertools.cycle([60, 70 ]) + def side_effect(*args): + return results.next() + + with patch.object(self.p, "get_resource_option") as mock: + mock.side_effect = side_effect + self.assertFalse(self.p._satisfies_min_translated({'completed': '60%'})) + self.assertTrue(self.p._satisfies_min_translated({'completed': '70%'})) + self.assertTrue(self.p._satisfies_min_translated({'completed': '80%'})) + self.assertTrue(self.p._satisfies_min_translated({'completed': '90%'})) + + def test_local_only(self): + """Test the case where the local option is lower than the global.""" + results = itertools.cycle([None, 70 ]) + def side_effect(*args): + return results.next() + + with patch.object(self.p, "get_resource_option") as mock: + mock.side_effect = side_effect + self.assertFalse(self.p._satisfies_min_translated({'completed': '60%'})) + self.assertTrue(self.p._satisfies_min_translated({'completed': '70%'})) + self.assertTrue(self.p._satisfies_min_translated({'completed': '80%'})) + self.assertTrue(self.p._satisfies_min_translated({'completed': '90%'})) + + def test_no_option(self): + """"Test the case there is nothing defined.""" + results = itertools.cycle([None, None ]) + def side_effect(*args): + return results.next() + + with patch.object(self.p, "get_resource_option") as mock: + mock.side_effect = side_effect + self.assertTrue(self.p._satisfies_min_translated({'completed': '0%'})) + self.assertTrue(self.p._satisfies_min_translated({'completed': '10%'})) + self.assertTrue(self.p._satisfies_min_translated({'completed': '90%'})) + + +class TestProjectFilters(unittest.TestCase): + """Test filters used to decide whether to push/pull a translation or not.""" + + def setUp(self): + super(TestProjectFilters, self).setUp() + self.p = Project(init=False) + self.p.minimum_perc = None + self.p.resource = "resource" + self.stats = { + 'en': { + 'completed': '100%', 'last_update': '2011-11-01 15:00:00', + }, 'el': { + 'completed': '60%', 'last_update': '2011-11-01 15:00:00', + }, 'pt': { + 'completed': '70%', 'last_update': '2011-11-01 15:00:00', + }, + } + self.langs = self.stats.keys() + + def test_add_translation(self): + """Test filters for adding translations. + + We do not test here for minimum percentages. + """ + with patch.object(self.p, "get_resource_option") as mock: + mock.return_value = None + should_add = self.p._should_add_translation + for force in [True, False]: + for lang in self.langs: + self.assertTrue(should_add(lang, self.stats, force)) + + # unknown language + self.assertFalse(should_add('es', self.stats)) + + def test_update_translation(self): + """Test filters for updating a translation. + + We do not test here for minimum percentages. + """ + with patch.object(self.p, "get_resource_option") as mock: + mock.return_value = None + + should_update = self.p._should_update_translation + force = True + for lang in self.langs: + self.assertTrue(should_update(lang, self.stats, 'foo', force)) + + force = False # reminder + local_file = 'foo' + + # unknown language + self.assertFalse(should_update('es', self.stats, local_file)) + + # no local file + with patch.object(self.p, "_get_time_of_local_file") as time_mock: + time_mock.return_value = None + with patch.object(self.p, "get_full_path") as path_mock: + path_mock.return_value = "foo" + for lang in self.langs: + self.assertTrue( + should_update(lang, self.stats, local_file) + ) + + # older local files + local_times = [self.p._generate_timestamp('2011-11-01 14:00:59')] + results = itertools.cycle(local_times) + def side_effect(*args): + return results.next() + + with patch.object(self.p, "_get_time_of_local_file") as time_mock: + time_mock.side_effect = side_effect + with patch.object(self.p, "get_full_path") as path_mock: + path_mock.return_value = "foo" + for lang in self.langs: + self.assertTrue( + should_update(lang, self.stats, local_file) + ) + + # newer local files + local_times = [self.p._generate_timestamp('2011-11-01 15:01:59')] + results = itertools.cycle(local_times) + def side_effect(*args): + return results.next() + + with patch.object(self.p, "_get_time_of_local_file") as time_mock: + time_mock.side_effect = side_effect + with patch.object(self.p, "get_full_path") as path_mock: + path_mock.return_value = "foo" + for lang in self.langs: + self.assertFalse( + should_update(lang, self.stats, local_file) + ) + + def test_push_translation(self): + """Test filters for pushing a translation file.""" + with patch.object(self.p, "get_resource_option") as mock: + mock.return_value = None + + local_file = 'foo' + should_push = self.p._should_push_translation + force = True + for lang in self.langs: + self.assertTrue(should_push(lang, self.stats, local_file, force)) + + force = False # reminder + + # unknown language + self.assertTrue(should_push('es', self.stats, local_file)) + + # older local files + local_times = [self.p._generate_timestamp('2011-11-01 14:00:59')] + results = itertools.cycle(local_times) + def side_effect(*args): + return results.next() + + with patch.object(self.p, "_get_time_of_local_file") as time_mock: + time_mock.side_effect = side_effect + with patch.object(self.p, "get_full_path") as path_mock: + path_mock.return_value = "foo" + for lang in self.langs: + self.assertFalse( + should_push(lang, self.stats, local_file) + ) + + # newer local files + local_times = [self.p._generate_timestamp('2011-11-01 15:01:59')] + results = itertools.cycle(local_times) + def side_effect(*args): + return results.next() + + with patch.object(self.p, "_get_time_of_local_file") as time_mock: + time_mock.side_effect = side_effect + with patch.object(self.p, "get_full_path") as path_mock: + path_mock.return_value = "foo" + for lang in self.langs: + self.assertTrue( + should_push(lang, self.stats, local_file) + ) + + +class TestProjectPull(unittest.TestCase): + """Test bits & pieces of the pull method.""" + + def setUp(self): + super(TestProjectPull, self).setUp() + self.p = Project(init=False) + self.p.minimum_perc = None + self.p.resource = "resource" + self.p.host = 'foo' + self.p.project_slug = 'foo' + self.p.resource_slug = 'foo' + self.stats = { + 'en': { + 'completed': '100%', 'last_update': '2011-11-01 15:00:00', + }, 'el': { + 'completed': '60%', 'last_update': '2011-11-01 15:00:00', + }, 'pt': { + 'completed': '70%', 'last_update': '2011-11-01 15:00:00', + }, + } + self.langs = self.stats.keys() + self.files = dict(zip(self.langs, itertools.repeat(None))) + self.details = {'available_languages': []} + for lang in self.langs: + self.details['available_languages'].append({'code': lang}) + self.slang = 'en' + self.lang_map = Flipdict() + + def test_new_translations(self): + """Test finding new transaltions to add.""" + with patch.object(self.p, 'do_url_request') as resource_mock: + resource_mock.return_value = json.dumps(self.details) + files_keys = self.langs + new_trans = self.p._new_translations_to_add + for force in [True, False]: + res = new_trans( + self.files, self.slang, self.lang_map, self.stats, force + ) + self.assertEquals(res, set([])) + + with patch.object(self.p, '_should_add_translation') as filter_mock: + filter_mock.return_value = True + for force in [True, False]: + res = new_trans( + {'el': None}, self.slang, self.lang_map, self.stats, force + ) + self.assertEquals(res, set(['pt'])) + for force in [True, False]: + res = new_trans( + {}, self.slang, self.lang_map, self.stats, force + ) + self.assertEquals(res, set(['el', 'pt'])) + + files = {} + files['pt_PT'] = None + lang_map = {'pt': 'pt_PT'} + for force in [True, False]: + res = new_trans( + files, self.slang, lang_map, self.stats, force + ) + self.assertEquals(res, set(['el'])) + + def test_languages_to_pull_empty_initial_list(self): + """Test determining the languages to pull, when the initial + list is empty. + """ + languages = [] + force = False + + res = self.p._languages_to_pull( + languages, self.files, self.lang_map, self.stats, force + ) + existing = res[0] + new = res[1] + self.assertEquals(existing, set(['el', 'en', 'pt'])) + self.assertFalse(new) + + del self.files['el'] + self.files['el-gr'] = None + self.lang_map['el'] = 'el-gr' + res = self.p._languages_to_pull( + languages, self.files, self.lang_map, self.stats, force + ) + existing = res[0] + new = res[1] + self.assertEquals(existing, set(['el', 'en', 'pt'])) + self.assertFalse(new) + + def test_languages_to_pull_with_initial_list(self): + """Test determining the languages to pull, then there is a + language selection from the user. + """ + languages = ['el', 'en'] + self.lang_map['el'] = 'el-gr' + del self.files['el'] + self.files['el-gr'] = None + force = False + + with patch.object(self.p, '_should_add_translation') as mock: + mock.return_value = True + res = self.p._languages_to_pull( + languages, self.files, self.lang_map, self.stats, force + ) + existing = res[0] + new = res[1] + self.assertEquals(existing, set(['en', 'el-gr', ])) + self.assertFalse(new) + + mock.return_value = False + res = self.p._languages_to_pull( + languages, self.files, self.lang_map, self.stats, force + ) + existing = res[0] + new = res[1] + self.assertEquals(existing, set(['en', 'el-gr', ])) + self.assertFalse(new) + + del self.files['el-gr'] + mock.return_value = True + res = self.p._languages_to_pull( + languages, self.files, self.lang_map, self.stats, force + ) + existing = res[0] + new = res[1] + self.assertEquals(existing, set(['en', ])) + self.assertEquals(new, set(['el', ])) + + mock.return_value = False + res = self.p._languages_to_pull( + languages, self.files, self.lang_map, self.stats, force + ) + existing = res[0] + new = res[1] + self.assertEquals(existing, set(['en', ])) + self.assertEquals(new, set([])) + + def test_in_combination_with_force_option(self): + """Test the minumum-perc option along with -f.""" + with patch.object(self.p, 'get_resource_option') as mock: + mock.return_value = 70 + + res = self.p._should_download('de', self.stats, None, False) + self.assertEquals(res, False) + res = self.p._should_download('el', self.stats, None, False) + self.assertEquals(res, False) + res = self.p._should_download('el', self.stats, None, True) + self.assertEquals(res, False) + res = self.p._should_download('en', self.stats, None, False) + self.assertEquals(res, True) + res = self.p._should_download('en', self.stats, None, True) + self.assertEquals(res, True) + + with patch.object(self.p, '_remote_is_newer') as local_file_mock: + local_file_mock = False + res = self.p._should_download('pt', self.stats, None, False) + self.assertEquals(res, True) + res = self.p._should_download('pt', self.stats, None, True) + self.assertEquals(res, True) + + +class TestFormats(unittest.TestCase): + """Tests for the supported formats.""" + + def setUp(self): + self.p = Project(init=False) + + def test_extensions(self): + """Test returning the correct extension for a format.""" + sample_formats = { + 'PO': {'file-extensions': '.po, .pot'}, + 'QT': {'file-extensions': '.ts'}, + } + extensions = ['.po', '.ts', '', ] + with patch.object(self.p, "do_url_request") as mock: + mock.return_value = json.dumps(sample_formats) + for (type_, ext) in zip(['PO', 'QT', 'NONE', ], extensions): + extension = self.p._extension_for(type_) + self.assertEquals(extension, ext) + + +class TestOptions(unittest.TestCase): + """Test the methods related to parsing the configuration file.""" + + def setUp(self): + self.p = Project(init=False) + + def test_get_option(self): + """Test _get_option method.""" + with contextlib.nested( + patch.object(self.p, 'get_resource_option'), + patch.object(self.p, 'config', create=True) + ) as (rmock, cmock): + rmock.return_value = 'resource' + cmock.has_option.return_value = 'main' + cmock.get.return_value = 'main' + self.assertEqual(self.p._get_option(None, None), 'resource') + rmock.return_value = None + cmock.has_option.return_value = 'main' + cmock.get.return_value = 'main' + self.assertEqual(self.p._get_option(None, None), 'main') + cmock.has_option.return_value = None + self.assertIs(self.p._get_option(None, None), None) + + +class TestConfigurationOptions(unittest.TestCase): + """Test the various configuration options.""" + + def test_i18n_type(self): + p = Project(init=False) + type_string = 'type' + i18n_type = 'PO' + with patch.object(p, 'config', create=True) as config_mock: + p.set_i18n_type([], i18n_type) + calls = config_mock.method_calls + self.assertEquals('set', calls[0][0]) + self.assertEquals('main', calls[0][1][0]) + p.set_i18n_type(['transifex.txo'], 'PO') + calls = config_mock.method_calls + self.assertEquals('set', calls[0][0]) + p.set_i18n_type(['transifex.txo', 'transifex.txn'], 'PO') + calls = config_mock.method_calls + self.assertEquals('set', calls[0][0]) + self.assertEquals('set', calls[1][0]) + + +class TestStats(unittest.TestCase): + """Test the access to the stats objects.""" + + def setUp(self): + self.stats = Mock() + self.stats.__getitem__ = Mock() + self.stats.__getitem__.return_value = '12%' + + def test_field_used_per_mode(self): + """Test the fields used for each mode.""" + Project._extract_completed(self.stats, 'translate') + self.stats.__getitem__.assert_called_with('completed') + Project._extract_completed(self.stats, 'reviewed') + self.stats.__getitem__.assert_called_with('reviewed_percentage') +