forked from darkskyapp/translations
-
Notifications
You must be signed in to change notification settings - Fork 1
/
test.py
164 lines (117 loc) · 5.37 KB
/
test.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
import pytest
import os
import re
import importlib.util
from lib.translation import Translation
@pytest.fixture
def test_translation():
return Translation(
{
"foo": "bar",
"bar": "meeple $2",
"baz": lambda a, b, c: f"meeple {c}",
"quux": lambda a: "glorple",
}
)
def test_return_number_in_string_form(test_translation):
assert test_translation.translate(42) == "42"
def test_throw_error_for_unrecognized_string(test_translation):
with pytest.raises(ValueError):
test_translation.translate("42")
def test_apply_value_conversion(test_translation):
assert test_translation.translate("foo") == "bar"
def test_throw_error_for_expected_string(test_translation):
with pytest.raises(ValueError):
test_translation.translate("bar")
def test_throw_error_for_expected_function(test_translation):
with pytest.raises(ValueError):
test_translation.translate("baz")
def test_throw_error_for_empty_array(test_translation):
with pytest.raises(ValueError):
test_translation.translate([])
def test_apply_string_template(test_translation):
assert test_translation.translate(["bar", 10, 20]) == "meeple 20"
def test_fail_to_apply_function_with_wrong_arity(test_translation):
with pytest.raises(ValueError):
test_translation.translate(["baz", 10, 20, 30])
def test_apply_function_template(test_translation):
assert test_translation.translate(["baz", 10, 20]) == "meeple 20"
def test_recursively_apply_function_templates(test_translation):
assert (
test_translation.translate(["bar", 10, ["baz", 20, "foo"]])
== "meeple meeple bar"
)
def test_throw_error_for_undefined(test_translation):
with pytest.raises(ValueError):
test_translation.translate(None)
def test_throw_error_for_null(test_translation):
with pytest.raises(ValueError):
test_translation.translate(None)
def test_throw_error_for_object(test_translation):
with pytest.raises(ValueError):
test_translation.translate({})
def test_apply_zero_argument_function(test_translation):
assert test_translation.translate("quux") == "glorple"
def test_fail_to_apply_zero_argument_function_given_arguments(test_translation):
with pytest.raises(ValueError):
test_translation.translate(["quux"])
def test_fail_to_apply_function_template_given_value(test_translation):
with pytest.raises(ValueError):
test_translation.translate("baz")
def test_provide_context_to_functions():
test = Translation(
{
"foo": lambda a, b, c, d: f"Moop. {b} {c} {d}",
"bar": "Boop.",
"baz": lambda a, b: f"Soup. {b}",
"quux": lambda a: "Floop.",
"neem": lambda a, b: f"Bloop. {b}",
"glorp": lambda a, b: "Rope?",
}
)
# Call the translation with nested structure to validate context
assert (
test.translate(["foo", "bar", ["baz", "quux"], ["neem", ["glorp", 42]]])
== "Moop. Boop. Soup. Floop. Bloop. Rope?"
)
def test_languages(subtests):
test_dir = os.path.join(os.path.dirname(__file__), "test_cases")
# Iterate over files in lang directory
for filename in os.listdir(test_dir):
with subtests.test(msg="custom message", filename=filename):
if filename.endswith(".py"):
match = re.match(r"^([^.].*)\.py$", filename)
# Extract the language name (e.g. 'en', 'fr', etc.)
lang_name = match.group(1)
# Construct the corresponding Python module path.
# Here we assume each .js has been replaced by a .py file with the same base name.
py_module_path = os.path.join(test_dir, lang_name + ".py")
# Dynamically load the Python module
spec = importlib.util.spec_from_file_location(lang_name, py_module_path)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
# `template` must be defined inside the Python module
if not hasattr(mod, "cases"): # pragma: no cover
raise Exception(f"No 'cases' found in {lang_name}.py")
template = mod.cases
lang_dir = os.path.join(os.path.dirname(__file__), "lib", "lang")
# Construct the corresponding Python module path.
# Here we assume each .js has been replaced by a .py file with the same base name.
py_module_path = os.path.join(lang_dir, lang_name + ".py")
# Dynamically load the Python module
l_spec = importlib.util.spec_from_file_location(
lang_name, py_module_path
)
l_mod = importlib.util.module_from_spec(l_spec)
l_spec.loader.exec_module(l_mod)
l_template = l_mod.template
# There's no direct equivalent to Object.freeze() in Python,
# but we trust that we won't modify 'template'.
for source, expected in template.items():
with subtests.test(
msg="custom message",
l_template=l_template,
expected=expected,
source=source,
):
assert Translation(l_template).translate(expected) == source