167 lines
6.5 KiB
Python
167 lines
6.5 KiB
Python
import importlib
|
||
import io
|
||
import json
|
||
import os
|
||
import shutil
|
||
import tempfile
|
||
import unittest
|
||
from unittest.mock import patch
|
||
|
||
from babel.messages import Catalog, mofile
|
||
import natcap.invest
|
||
from natcap.invest import validation
|
||
from osgeo import gdal
|
||
|
||
gdal.UseExceptions()
|
||
TEST_LANG = 'll'
|
||
|
||
# assign to local variable so that it won't be changed by translation
|
||
missing_key_msg = validation.MESSAGES['MISSING_KEY']
|
||
not_a_number_msg = validation.MESSAGES['NOT_A_NUMBER']
|
||
|
||
# Fake translations for testing
|
||
TEST_MESSAGES = {
|
||
"InVEST Carbon Model": "ιиνєѕт ςαявσи мσ∂єℓ",
|
||
"Available models:": "αναιℓαвℓє мσ∂єℓѕ:",
|
||
"Carbon Storage and Sequestration": "ςαявσи ѕтσяαgє αи∂ ѕєףυєѕтяαтισи",
|
||
"current LULC": "ςυяяєит ℓυℓς",
|
||
missing_key_msg: "кєу ιѕ мιѕѕιиg fяσм тнє αяgѕ ∂ιςт",
|
||
not_a_number_msg: 'ναℓυє "{value}" ςσυℓ∂ иσт вє ιитєяρяєтє∂ αѕ α иυмвєя'
|
||
}
|
||
|
||
TEST_CATALOG = Catalog(locale=TEST_LANG)
|
||
for key, value in TEST_MESSAGES.items():
|
||
TEST_CATALOG.add(key, value)
|
||
|
||
|
||
def reset_locale():
|
||
"""Reset affected parts of the global context."""
|
||
from natcap.invest import carbon, cli, ui_server, set_locale
|
||
set_locale('en')
|
||
|
||
# "unimport" the modules being translated
|
||
# NOTE: it would be better to run each test in a new process,
|
||
# but that's difficult on windows: https://stackoverflow.com/a/48310939
|
||
importlib.reload(natcap.invest)
|
||
importlib.reload(validation)
|
||
importlib.reload(cli)
|
||
importlib.reload(carbon)
|
||
importlib.reload(ui_server)
|
||
|
||
class TranslationTests(unittest.TestCase):
|
||
"""Tests for translation."""
|
||
|
||
def setUp(self):
|
||
self.workspace_dir = tempfile.mkdtemp()
|
||
test_locale_dir = os.path.join(self.workspace_dir, 'locales')
|
||
mo_path = os.path.join(
|
||
test_locale_dir, TEST_LANG, 'LC_MESSAGES', 'messages.mo')
|
||
os.makedirs(os.path.dirname(mo_path))
|
||
# format the test catalog object into MO file format
|
||
with open(mo_path, 'wb') as mo_file:
|
||
mofile.write_mo(mo_file, TEST_CATALOG)
|
||
|
||
# patch the LOCALE_DIR variable in natcap/invest/__init__.py
|
||
# this is where gettext will look for translations
|
||
self.locale_dir_patcher = patch(
|
||
'natcap.invest.LOCALE_DIR', test_locale_dir)
|
||
# patch the LOCALES variable to allow a fake test locale
|
||
self.locales_patcher = patch('natcap.invest.LOCALES', [TEST_LANG, 'en'])
|
||
self.locale_dir_patcher.start()
|
||
self.locales_patcher.start()
|
||
|
||
def tearDown(self):
|
||
reset_locale() # reset after each test case
|
||
self.locale_dir_patcher.stop()
|
||
self.locales_patcher.stop()
|
||
shutil.rmtree(self.workspace_dir)
|
||
|
||
def test_invest_list(self):
|
||
"""Translation: test that CLI list output is translated."""
|
||
from natcap.invest import cli
|
||
with patch('sys.stdout', new=io.StringIO()) as out:
|
||
with self.assertRaises(SystemExit):
|
||
cli.main(['--language', TEST_LANG, 'list'])
|
||
result = out.getvalue()
|
||
self.assertIn(TEST_MESSAGES['Available models:'], result)
|
||
self.assertIn(
|
||
TEST_MESSAGES['Carbon Storage and Sequestration'], result)
|
||
|
||
def test_invest_getspec(self):
|
||
"""Translation: test that CLI getspec output is translated."""
|
||
from natcap.invest import cli
|
||
with patch('sys.stdout', new=io.StringIO()) as out:
|
||
with self.assertRaises(SystemExit):
|
||
cli.main(['--language', TEST_LANG, 'getspec', 'carbon'])
|
||
result = out.getvalue()
|
||
self.assertIn(TEST_MESSAGES['current LULC'], result)
|
||
|
||
def test_invest_validate(self):
|
||
"""Translation: test that CLI validate output is translated."""
|
||
datastack = { # write datastack to a JSON file
|
||
'model_name': 'natcap.invest.carbon',
|
||
'invest_version': '0.0',
|
||
'args': {}
|
||
}
|
||
datastack_path = os.path.join(self.workspace_dir, 'datastack.json')
|
||
with open(datastack_path, 'w') as file:
|
||
json.dump(datastack, file)
|
||
|
||
from natcap.invest import cli
|
||
with patch('sys.stdout', new=io.StringIO()) as out:
|
||
with self.assertRaises(SystemExit):
|
||
cli.main(
|
||
['--language', TEST_LANG, 'validate', datastack_path])
|
||
|
||
result = out.getvalue()
|
||
self.assertIn(TEST_MESSAGES[missing_key_msg], result)
|
||
|
||
def test_server_get_invest_models(self):
|
||
"""Translation: test that /models endpoint is translated."""
|
||
from natcap.invest import ui_server
|
||
test_client = ui_server.app.test_client()
|
||
response = test_client.get(
|
||
'api/models', query_string={'language': TEST_LANG})
|
||
result = json.loads(response.get_data(as_text=True))
|
||
self.assertIn(
|
||
TEST_MESSAGES['Carbon Storage and Sequestration'], result)
|
||
|
||
def test_server_get_invest_getspec(self):
|
||
"""Translation: test that /getspec endpoint is translated."""
|
||
from natcap.invest import ui_server
|
||
test_client = ui_server.app.test_client()
|
||
response = test_client.post(
|
||
'api/getspec', json='carbon', query_string={'language': TEST_LANG})
|
||
spec = json.loads(response.get_data(as_text=True))
|
||
self.assertEqual(
|
||
spec['args']['lulc_cur_path']['name'],
|
||
TEST_MESSAGES['current LULC'])
|
||
|
||
def test_server_get_invest_validate(self):
|
||
"""Translation: test that /validate endpoint is translated."""
|
||
from natcap.invest import ui_server
|
||
from natcap.invest import carbon
|
||
test_client = ui_server.app.test_client()
|
||
payload = {
|
||
'model_module': carbon.MODEL_SPEC['pyname'],
|
||
'args': json.dumps({})
|
||
}
|
||
response = test_client.post(
|
||
'api/validate', json=payload,
|
||
query_string={'language': TEST_LANG})
|
||
results = json.loads(response.get_data(as_text=True))
|
||
messages = [item[1] for item in results]
|
||
self.assertIn(TEST_MESSAGES[missing_key_msg], messages)
|
||
|
||
def test_translate_formatted_string(self):
|
||
"""Translation: test that f-string can be translated."""
|
||
from natcap.invest import carbon, validation, set_locale
|
||
set_locale(TEST_LANG)
|
||
importlib.reload(validation)
|
||
importlib.reload(carbon)
|
||
args = {'n_workers': 'not a number'}
|
||
validation_messages = carbon.validate(args)
|
||
self.assertIn(
|
||
TEST_MESSAGES[not_a_number_msg].format(value=args['n_workers']),
|
||
str(validation_messages))
|