1 # -*- coding: utf-8 -*- 
   3 from __future__ 
import with_statement
 
  10     import simplejson 
as json
 
  11 from mock 
import Mock
, patch
 
  13 from txclib
.project 
import Project
 
  14 from txclib
.config 
import Flipdict
 
  17 class TestProject(unittest
.TestCase
): 
  19     def test_extract_fields(self
): 
  20         """Test the functions that extract a field from a stats object.""" 
  23             'last_update': '00:00', 
  27             stats
['completed'], '%s%%' % Project
._extract_completed(stats
) 
  29         self
.assertEqual(stats
['last_update'], Project
._extract_updated(stats
)) 
  31     def test_specifying_resources(self
): 
  32         """Test the various ways to specify resources in a project.""" 
  33         p 
= Project(init
=False) 
  40         with patch
.object(p
, 'get_resource_list') as mock
: 
  41             mock
.return_value 
= resources
 
  43                 'proj1.res1', '*1*', 'transifex*', '*r*', 
  44                 '*o', 'transifex.tx?', 'transifex.txn', 
  49                 ['transifex.txn', 'transifex.txo', ], 
  50                 ['proj1.res1', 'proj2.res2', 'transifex.txn', 'transifex.txo', ], 
  52                 ['transifex.txn', 'transifex.txo', ], 
  57             for i
, arg 
in enumerate(cmd_args
): 
  59                 self
.assertEqual(p
.get_chosen_resources(resources
), results
[i
]) 
  62             resources 
= ['*trasnifex*', ] 
  63             self
.assertRaises(Exception, p
.get_chosen_resources
, resources
) 
  66 class TestProjectMinimumPercent(unittest
.TestCase
): 
  67     """Test the minimum-perc option.""" 
  70         super(TestProjectMinimumPercent
, self
).setUp() 
  71         self
.p 
= Project(init
=False) 
  72         self
.p
.minimum_perc 
= None 
  73         self
.p
.resource 
= "resource" 
  75     def test_cmd_option(self
): 
  76         """Test command-line option.""" 
  77         self
.p
.minimum_perc 
= 20 
  78         results 
= itertools
.cycle([80, 90 ]) 
  79         def side_effect(*args
): 
  82         with patch
.object(self
.p
, "get_resource_option") as mock
: 
  83             mock
.side_effect 
= side_effect
 
  84             self
.assertFalse(self
.p
._satisfies_min_translated({'completed': '12%'})) 
  85             self
.assertTrue(self
.p
._satisfies_min_translated({'completed': '20%'})) 
  86             self
.assertTrue(self
.p
._satisfies_min_translated({'completed': '30%'})) 
  88     def test_global_only(self
): 
  89         """Test only global option.""" 
  90         results 
= itertools
.cycle([80, None ]) 
  91         def side_effect(*args
): 
  94         with patch
.object(self
.p
, "get_resource_option") as mock
: 
  95             mock
.side_effect 
= side_effect
 
  96             self
.assertFalse(self
.p
._satisfies_min_translated({'completed': '70%'})) 
  97             self
.assertTrue(self
.p
._satisfies_min_translated({'completed': '80%'})) 
  98             self
.assertTrue(self
.p
._satisfies_min_translated({'completed': '90%'})) 
 100     def test_local_lower_than_global(self
): 
 101         """Test the case where the local option is lower than the global.""" 
 102         results 
= itertools
.cycle([80, 70 ]) 
 103         def side_effect(*args
): 
 104             return results
.next() 
 106         with patch
.object(self
.p
, "get_resource_option") as mock
: 
 107             mock
.side_effect 
= side_effect
 
 108             self
.assertFalse(self
.p
._satisfies_min_translated({'completed': '60%'})) 
 109             self
.assertTrue(self
.p
._satisfies_min_translated({'completed': '70%'})) 
 110             self
.assertTrue(self
.p
._satisfies_min_translated({'completed': '80%'})) 
 111             self
.assertTrue(self
.p
._satisfies_min_translated({'completed': '90%'})) 
 113     def test_local_higher_than_global(self
): 
 114         """Test the case where the local option is lower than the global.""" 
 115         results 
= itertools
.cycle([60, 70 ]) 
 116         def side_effect(*args
): 
 117             return results
.next() 
 119         with patch
.object(self
.p
, "get_resource_option") as mock
: 
 120             mock
.side_effect 
= side_effect
 
 121             self
.assertFalse(self
.p
._satisfies_min_translated({'completed': '60%'})) 
 122             self
.assertTrue(self
.p
._satisfies_min_translated({'completed': '70%'})) 
 123             self
.assertTrue(self
.p
._satisfies_min_translated({'completed': '80%'})) 
 124             self
.assertTrue(self
.p
._satisfies_min_translated({'completed': '90%'})) 
 126     def test_local_only(self
): 
 127         """Test the case where the local option is lower than the global.""" 
 128         results 
= itertools
.cycle([None, 70 ]) 
 129         def side_effect(*args
): 
 130             return results
.next() 
 132         with patch
.object(self
.p
, "get_resource_option") as mock
: 
 133             mock
.side_effect 
= side_effect
 
 134             self
.assertFalse(self
.p
._satisfies_min_translated({'completed': '60%'})) 
 135             self
.assertTrue(self
.p
._satisfies_min_translated({'completed': '70%'})) 
 136             self
.assertTrue(self
.p
._satisfies_min_translated({'completed': '80%'})) 
 137             self
.assertTrue(self
.p
._satisfies_min_translated({'completed': '90%'})) 
 139     def test_no_option(self
): 
 140         """"Test the case there is nothing defined.""" 
 141         results 
= itertools
.cycle([None, None ]) 
 142         def side_effect(*args
): 
 143             return results
.next() 
 145         with patch
.object(self
.p
, "get_resource_option") as mock
: 
 146             mock
.side_effect 
= side_effect
 
 147             self
.assertTrue(self
.p
._satisfies_min_translated({'completed': '0%'})) 
 148             self
.assertTrue(self
.p
._satisfies_min_translated({'completed': '10%'})) 
 149             self
.assertTrue(self
.p
._satisfies_min_translated({'completed': '90%'})) 
 152 class TestProjectFilters(unittest
.TestCase
): 
 153     """Test filters used to decide whether to push/pull a translation or not.""" 
 156         super(TestProjectFilters
, self
).setUp() 
 157         self
.p 
= Project(init
=False) 
 158         self
.p
.minimum_perc 
= None 
 159         self
.p
.resource 
= "resource" 
 162                 'completed': '100%', 'last_update': '2011-11-01 15:00:00', 
 164                 'completed': '60%', 'last_update': '2011-11-01 15:00:00', 
 166                 'completed': '70%', 'last_update': '2011-11-01 15:00:00', 
 169         self
.langs 
= self
.stats
.keys() 
 171     def test_add_translation(self
): 
 172         """Test filters for adding translations. 
 174         We do not test here for minimum percentages. 
 176         with patch
.object(self
.p
, "get_resource_option") as mock
: 
 177             mock
.return_value 
= None 
 178             should_add 
= self
.p
._should_add_translation
 
 179             for force 
in [True, False]: 
 180                 for lang 
in self
.langs
: 
 181                     self
.assertTrue(should_add(lang
, self
.stats
, force
)) 
 184             self
.assertFalse(should_add('es', self
.stats
)) 
 186     def test_update_translation(self
): 
 187         """Test filters for updating a translation. 
 189         We do not test here for minimum percentages. 
 191         with patch
.object(self
.p
, "get_resource_option") as mock
: 
 192             mock
.return_value 
= None 
 194             should_update 
= self
.p
._should_update_translation
 
 196             for lang 
in self
.langs
: 
 197                 self
.assertTrue(should_update(lang
, self
.stats
, 'foo', force
)) 
 199             force 
= False       # reminder 
 203             self
.assertFalse(should_update('es', self
.stats
, local_file
)) 
 206             with patch
.object(self
.p
, "_get_time_of_local_file") as time_mock
: 
 207                 time_mock
.return_value 
= None 
 208                 with patch
.object(self
.p
, "get_full_path") as path_mock
: 
 209                     path_mock
.return_value 
= "foo" 
 210                     for lang 
in self
.langs
: 
 212                             should_update(lang
, self
.stats
, local_file
) 
 216             local_times 
= [self
.p
._generate_timestamp('2011-11-01 14:00:59')] 
 217             results 
= itertools
.cycle(local_times
) 
 218             def side_effect(*args
): 
 219                 return results
.next() 
 221             with patch
.object(self
.p
, "_get_time_of_local_file") as time_mock
: 
 222                 time_mock
.side_effect 
= side_effect
 
 223                 with patch
.object(self
.p
, "get_full_path") as path_mock
: 
 224                     path_mock
.return_value 
= "foo" 
 225                     for lang 
in self
.langs
: 
 227                             should_update(lang
, self
.stats
, local_file
) 
 231             local_times 
= [self
.p
._generate_timestamp('2011-11-01 15:01:59')] 
 232             results 
= itertools
.cycle(local_times
) 
 233             def side_effect(*args
): 
 234                 return results
.next() 
 236             with patch
.object(self
.p
, "_get_time_of_local_file") as time_mock
: 
 237                 time_mock
.side_effect 
= side_effect
 
 238                 with patch
.object(self
.p
, "get_full_path") as path_mock
: 
 239                     path_mock
.return_value 
= "foo" 
 240                     for lang 
in self
.langs
: 
 242                             should_update(lang
, self
.stats
, local_file
) 
 245     def test_push_translation(self
): 
 246         """Test filters for pushing a translation file.""" 
 247         with patch
.object(self
.p
, "get_resource_option") as mock
: 
 248             mock
.return_value 
= None 
 251             should_push 
= self
.p
._should_push_translation
 
 253             for lang 
in self
.langs
: 
 254                 self
.assertTrue(should_push(lang
, self
.stats
, local_file
, force
)) 
 256             force 
= False       # reminder 
 259             self
.assertTrue(should_push('es', self
.stats
, local_file
)) 
 262             local_times 
= [self
.p
._generate_timestamp('2011-11-01 14:00:59')] 
 263             results 
= itertools
.cycle(local_times
) 
 264             def side_effect(*args
): 
 265                 return results
.next() 
 267             with patch
.object(self
.p
, "_get_time_of_local_file") as time_mock
: 
 268                 time_mock
.side_effect 
= side_effect
 
 269                 with patch
.object(self
.p
, "get_full_path") as path_mock
: 
 270                     path_mock
.return_value 
= "foo" 
 271                     for lang 
in self
.langs
: 
 273                             should_push(lang
, self
.stats
, local_file
) 
 277             local_times 
= [self
.p
._generate_timestamp('2011-11-01 15:01:59')] 
 278             results 
= itertools
.cycle(local_times
) 
 279             def side_effect(*args
): 
 280                 return results
.next() 
 282             with patch
.object(self
.p
, "_get_time_of_local_file") as time_mock
: 
 283                 time_mock
.side_effect 
= side_effect
 
 284                 with patch
.object(self
.p
, "get_full_path") as path_mock
: 
 285                     path_mock
.return_value 
= "foo" 
 286                     for lang 
in self
.langs
: 
 288                             should_push(lang
, self
.stats
, local_file
) 
 292 class TestProjectPull(unittest
.TestCase
): 
 293     """Test bits & pieces of the pull method.""" 
 296         super(TestProjectPull
, self
).setUp() 
 297         self
.p 
= Project(init
=False) 
 298         self
.p
.minimum_perc 
= None 
 299         self
.p
.resource 
= "resource" 
 301         self
.p
.project_slug 
= 'foo' 
 302         self
.p
.resource_slug 
= 'foo' 
 305                 'completed': '100%', 'last_update': '2011-11-01 15:00:00', 
 307                 'completed': '60%', 'last_update': '2011-11-01 15:00:00', 
 309                 'completed': '70%', 'last_update': '2011-11-01 15:00:00', 
 312         self
.langs 
= self
.stats
.keys() 
 313         self
.files 
= dict(zip(self
.langs
, itertools
.repeat(None))) 
 314         self
.details 
= {'available_languages': []} 
 315         for lang 
in self
.langs
: 
 316             self
.details
['available_languages'].append({'code': lang
}) 
 318         self
.lang_map 
= Flipdict() 
 320     def test_new_translations(self
): 
 321         """Test finding new transaltions to add.""" 
 322         with patch
.object(self
.p
, 'do_url_request') as resource_mock
: 
 323             resource_mock
.return_value 
= json
.dumps(self
.details
) 
 324             files_keys 
= self
.langs
 
 325             new_trans 
= self
.p
._new_translations_to_add
 
 326             for force 
in [True, False]: 
 328                     self
.files
, self
.slang
, self
.lang_map
, self
.stats
, force
 
 330                 self
.assertEquals(res
, set([])) 
 332             with patch
.object(self
.p
, '_should_add_translation') as filter_mock
: 
 333                 filter_mock
.return_value 
= True 
 334                 for force 
in [True, False]: 
 336                         {'el': None}, self
.slang
, self
.lang_map
, self
.stats
, force
 
 338                     self
.assertEquals(res
, set(['pt'])) 
 339                 for force 
in [True, False]: 
 341                         {}, self
.slang
, self
.lang_map
, self
.stats
, force
 
 343                     self
.assertEquals(res
, set(['el', 'pt'])) 
 346                 files
['pt_PT'] = None 
 347                 lang_map 
= {'pt': 'pt_PT'} 
 348                 for force 
in [True, False]: 
 350                         files
, self
.slang
, lang_map
, self
.stats
, force
 
 352                     self
.assertEquals(res
, set(['el'])) 
 354     def test_languages_to_pull_empty_initial_list(self
): 
 355         """Test determining the languages to pull, when the initial 
 361         res 
= self
.p
._languages_to_pull( 
 362             languages
, self
.files
, self
.lang_map
, self
.stats
, force
 
 366         self
.assertEquals(existing
, set(['el', 'en', 'pt'])) 
 367         self
.assertFalse(new
) 
 370         self
.files
['el-gr'] = None 
 371         self
.lang_map
['el'] = 'el-gr' 
 372         res 
= self
.p
._languages_to_pull( 
 373             languages
, self
.files
, self
.lang_map
, self
.stats
, force
 
 377         self
.assertEquals(existing
, set(['el', 'en', 'pt'])) 
 378         self
.assertFalse(new
) 
 380     def test_languages_to_pull_with_initial_list(self
): 
 381         """Test determining the languages to pull, then there is a 
 382         language selection from the user. 
 384         languages 
= ['el', 'en'] 
 385         self
.lang_map
['el'] = 'el-gr' 
 387         self
.files
['el-gr'] = None 
 390         with patch
.object(self
.p
, '_should_add_translation') as mock
: 
 391             mock
.return_value 
= True 
 392             res 
= self
.p
._languages_to_pull( 
 393                 languages
, self
.files
, self
.lang_map
, self
.stats
, force
 
 397             self
.assertEquals(existing
, set(['en', 'el-gr', ])) 
 398             self
.assertFalse(new
) 
 400             mock
.return_value 
= False 
 401             res 
= self
.p
._languages_to_pull( 
 402                 languages
, self
.files
, self
.lang_map
, self
.stats
, force
 
 406             self
.assertEquals(existing
, set(['en', 'el-gr', ])) 
 407             self
.assertFalse(new
) 
 409             del self
.files
['el-gr'] 
 410             mock
.return_value 
= True 
 411             res 
= self
.p
._languages_to_pull( 
 412                 languages
, self
.files
, self
.lang_map
, self
.stats
, force
 
 416             self
.assertEquals(existing
, set(['en', ])) 
 417             self
.assertEquals(new
, set(['el', ])) 
 419             mock
.return_value 
= False 
 420             res 
= self
.p
._languages_to_pull( 
 421                 languages
, self
.files
, self
.lang_map
, self
.stats
, force
 
 425             self
.assertEquals(existing
, set(['en', ])) 
 426             self
.assertEquals(new
, set([])) 
 428     def test_in_combination_with_force_option(self
): 
 429         """Test the minumum-perc option along with -f.""" 
 430         with patch
.object(self
.p
, 'get_resource_option') as mock
: 
 431             mock
.return_value 
= 70 
 433             res 
= self
.p
._should_download('de', self
.stats
, None, False) 
 434             self
.assertEquals(res
, False) 
 435             res 
= self
.p
._should_download('el', self
.stats
, None, False) 
 436             self
.assertEquals(res
, False) 
 437             res 
= self
.p
._should_download('el', self
.stats
, None, True) 
 438             self
.assertEquals(res
, False) 
 439             res 
= self
.p
._should_download('en', self
.stats
, None, False) 
 440             self
.assertEquals(res
, True) 
 441             res 
= self
.p
._should_download('en', self
.stats
, None, True) 
 442             self
.assertEquals(res
, True) 
 444             with patch
.object(self
.p
, '_remote_is_newer') as local_file_mock
: 
 445                 local_file_mock 
= False 
 446                 res 
= self
.p
._should_download('pt', self
.stats
, None, False) 
 447                 self
.assertEquals(res
, True) 
 448                 res 
= self
.p
._should_download('pt', self
.stats
, None, True) 
 449                 self
.assertEquals(res
, True) 
 452 class TestFormats(unittest
.TestCase
): 
 453     """Tests for the supported formats.""" 
 456         self
.p 
= Project(init
=False) 
 458     def test_extensions(self
): 
 459         """Test returning the correct extension for a format.""" 
 461             'PO': {'file-extensions': '.po, .pot'}, 
 462             'QT': {'file-extensions': '.ts'}, 
 464         extensions 
= ['.po', '.ts', '', ] 
 465         with patch
.object(self
.p
, "do_url_request") as mock
: 
 466             mock
.return_value 
= json
.dumps(sample_formats
) 
 467             for (type_
, ext
) in zip(['PO', 'QT', 'NONE', ], extensions
): 
 468                 extension 
= self
.p
._extension_for(type_
) 
 469                 self
.assertEquals(extension
, ext
) 
 472 class TestOptions(unittest
.TestCase
): 
 473     """Test the methods related to parsing the configuration file.""" 
 476         self
.p 
= Project(init
=False) 
 478     def test_get_option(self
): 
 479         """Test _get_option method.""" 
 480         with contextlib
.nested( 
 481             patch
.object(self
.p
, 'get_resource_option'), 
 482             patch
.object(self
.p
, 'config', create
=True) 
 484             rmock
.return_value 
= 'resource' 
 485             cmock
.has_option
.return_value 
= 'main' 
 486             cmock
.get
.return_value 
= 'main' 
 487             self
.assertEqual(self
.p
._get_option(None, None), 'resource') 
 488             rmock
.return_value 
= None 
 489             cmock
.has_option
.return_value 
= 'main' 
 490             cmock
.get
.return_value 
= 'main' 
 491             self
.assertEqual(self
.p
._get_option(None, None), 'main') 
 492             cmock
.has_option
.return_value 
= None 
 493             self
.assertIs(self
.p
._get_option(None, None), None) 
 496 class TestConfigurationOptions(unittest
.TestCase
): 
 497     """Test the various configuration options.""" 
 499     def test_i18n_type(self
): 
 500         p 
= Project(init
=False) 
 503         with patch
.object(p
, 'config', create
=True) as config_mock
: 
 504             p
.set_i18n_type([], i18n_type
) 
 505             calls 
= config_mock
.method_calls
 
 506             self
.assertEquals('set', calls
[0][0]) 
 507             self
.assertEquals('main', calls
[0][1][0]) 
 508             p
.set_i18n_type(['transifex.txo'], 'PO') 
 509             calls 
= config_mock
.method_calls
 
 510             self
.assertEquals('set', calls
[0][0]) 
 511             p
.set_i18n_type(['transifex.txo', 'transifex.txn'], 'PO') 
 512             calls 
= config_mock
.method_calls
 
 513             self
.assertEquals('set', calls
[0][0]) 
 514             self
.assertEquals('set', calls
[1][0]) 
 517 class TestStats(unittest
.TestCase
): 
 518     """Test the access to the stats objects.""" 
 522         self
.stats
.__getitem__ 
= Mock() 
 523         self
.stats
.__getitem__
.return_value 
= '12%' 
 525     def test_field_used_per_mode(self
): 
 526         """Test the fields used for each mode.""" 
 527         Project
._extract_completed(self
.stats
, 'translate') 
 528         self
.stats
.__getitem__
.assert_called_with('completed') 
 529         Project
._extract_completed(self
.stats
, 'reviewed') 
 530         self
.stats
.__getitem__
.assert_called_with('reviewed_percentage')