|
| 1 | +""" |
| 2 | +Tests for locale directory lookup and language resource resolution. |
| 3 | +
|
| 4 | +Covers: |
| 5 | +- _get_word() resolves word_connectors.json via get_language_dir() |
| 6 | +- join_word_list() produces correct output for all supported language |
| 7 | + variants, including case-insensitive and short-code inputs |
| 8 | +- All locale folders present in ovos_workshop/locale/ have valid |
| 9 | + word_connectors.json with "and"/"or" keys |
| 10 | +""" |
| 11 | +import json |
| 12 | +import os |
| 13 | +import unittest |
| 14 | +from os.path import dirname, join |
| 15 | + |
| 16 | +from ovos_workshop.skills.ovos import _get_word, join_word_list |
| 17 | + |
| 18 | +LOCALE_DIR = join(dirname(dirname(dirname(__file__))), |
| 19 | + "ovos_workshop", "locale") |
| 20 | + |
| 21 | + |
| 22 | +class TestGetWord(unittest.TestCase): |
| 23 | + """_get_word() must resolve connectors for all supported langs.""" |
| 24 | + |
| 25 | + def test_canonical_tag(self): |
| 26 | + self.assertEqual(_get_word("en-US", "and"), "and") |
| 27 | + self.assertEqual(_get_word("en-US", "or"), "or") |
| 28 | + |
| 29 | + def test_short_code_resolves(self): |
| 30 | + """Plain 'en' should match en-US folder.""" |
| 31 | + self.assertEqual(_get_word("en", "and"), "and") |
| 32 | + |
| 33 | + def test_lowercase_tag_resolves(self): |
| 34 | + """en-us (all-lowercase) must still resolve.""" |
| 35 | + self.assertEqual(_get_word("en-us", "and"), "and") |
| 36 | + |
| 37 | + def test_italian_canonical(self): |
| 38 | + self.assertEqual(_get_word("it-IT", "and"), "e") |
| 39 | + self.assertEqual(_get_word("it-IT", "or"), "o") |
| 40 | + |
| 41 | + def test_italian_short_code(self): |
| 42 | + """'it' must resolve to it-IT folder.""" |
| 43 | + self.assertEqual(_get_word("it", "and"), "e") |
| 44 | + self.assertEqual(_get_word("it", "or"), "o") |
| 45 | + |
| 46 | + def test_spanish_canonical(self): |
| 47 | + self.assertEqual(_get_word("es-ES", "and"), "y") |
| 48 | + self.assertEqual(_get_word("es-ES", "or"), "o") |
| 49 | + |
| 50 | + def test_spanish_short_code(self): |
| 51 | + self.assertEqual(_get_word("es", "and"), "y") |
| 52 | + self.assertEqual(_get_word("es", "or"), "o") |
| 53 | + |
| 54 | + def test_german(self): |
| 55 | + self.assertEqual(_get_word("de-DE", "and"), "und") |
| 56 | + |
| 57 | + def test_french(self): |
| 58 | + self.assertEqual(_get_word("fr-FR", "and"), "et") |
| 59 | + |
| 60 | + def test_missing_lang_returns_fallback(self): |
| 61 | + """Unknown language must return ', ' not raise.""" |
| 62 | + result = _get_word("xx-XX", "and") |
| 63 | + self.assertEqual(result, ", ") |
| 64 | + |
| 65 | + def test_all_locale_folders_have_connectors(self): |
| 66 | + """Every locale folder must contain a parseable word_connectors.json |
| 67 | + with both 'and' and 'or' keys.""" |
| 68 | + for folder in os.listdir(LOCALE_DIR): |
| 69 | + path = join(LOCALE_DIR, folder, "word_connectors.json") |
| 70 | + if not os.path.isfile(path): |
| 71 | + continue # not every locale needs connectors |
| 72 | + with open(path) as f: |
| 73 | + data = json.load(f) |
| 74 | + self.assertIn("and", data, |
| 75 | + f"{folder}/word_connectors.json missing 'and'") |
| 76 | + self.assertIn("or", data, |
| 77 | + f"{folder}/word_connectors.json missing 'or'") |
| 78 | + |
| 79 | + |
| 80 | +class TestJoinWordList(unittest.TestCase): |
| 81 | + """join_word_list() end-to-end for several languages and input shapes.""" |
| 82 | + |
| 83 | + # --- English --- |
| 84 | + def test_en_two_items_and(self): |
| 85 | + self.assertEqual(join_word_list(["a", "b"], "and", ",", "en-US"), |
| 86 | + "a and b") |
| 87 | + |
| 88 | + def test_en_three_items_and(self): |
| 89 | + self.assertEqual(join_word_list(["a", "b", "c"], "and", ",", "en-US"), |
| 90 | + "a, b and c") |
| 91 | + |
| 92 | + def test_en_two_items_or(self): |
| 93 | + self.assertEqual(join_word_list(["x", "y"], "or", ",", "en-US"), |
| 94 | + "x or y") |
| 95 | + |
| 96 | + def test_en_single_item(self): |
| 97 | + self.assertEqual(join_word_list(["only"], "and", ",", "en-US"), "only") |
| 98 | + |
| 99 | + def test_en_empty(self): |
| 100 | + self.assertEqual(join_word_list([], "and", ",", "en-US"), "") |
| 101 | + |
| 102 | + # --- Italian (euphony) --- |
| 103 | + def test_it_and_basic(self): |
| 104 | + self.assertEqual( |
| 105 | + join_word_list(["mare", "montagna"], "and", ",", "it-IT"), |
| 106 | + "mare e montagna") |
| 107 | + |
| 108 | + def test_it_and_euphonic(self): |
| 109 | + """'e' + vowel 'e' → 'ed'""" |
| 110 | + self.assertEqual( |
| 111 | + join_word_list(["inverno", "estate"], "and", ",", "it-IT"), |
| 112 | + "inverno ed estate") |
| 113 | + |
| 114 | + def test_it_or_euphonic(self): |
| 115 | + """'o' + vowel 'o' → 'od'""" |
| 116 | + self.assertEqual( |
| 117 | + join_word_list(["mare", "oceano"], "or", ",", "it-IT"), |
| 118 | + "mare od oceano") |
| 119 | + |
| 120 | + def test_it_short_code(self): |
| 121 | + """Short code 'it' must produce the same result as 'it-IT'.""" |
| 122 | + self.assertEqual( |
| 123 | + join_word_list(["mare", "montagna"], "and", ",", "it"), |
| 124 | + join_word_list(["mare", "montagna"], "and", ",", "it-IT")) |
| 125 | + |
| 126 | + # --- Spanish (euphony) --- |
| 127 | + def test_es_and_euphonic(self): |
| 128 | + """'y' before 'i' → 'e'""" |
| 129 | + self.assertEqual( |
| 130 | + join_word_list(["Juan", "Irene"], "and", ",", "es-ES"), |
| 131 | + "Juan e Irene") |
| 132 | + |
| 133 | + def test_es_or_euphonic(self): |
| 134 | + """'o' before 'o' → 'u'""" |
| 135 | + self.assertEqual( |
| 136 | + join_word_list(["uno", "otro"], "or", ",", "es-ES"), |
| 137 | + "uno u otro") |
| 138 | + |
| 139 | + def test_es_and_no_euphony(self): |
| 140 | + self.assertEqual( |
| 141 | + join_word_list(["tierra", "agua"], "and", ",", "es-ES"), |
| 142 | + "tierra y agua") |
| 143 | + |
| 144 | + def test_es_short_code(self): |
| 145 | + self.assertEqual( |
| 146 | + join_word_list(["tierra", "agua"], "and", ",", "es"), |
| 147 | + join_word_list(["tierra", "agua"], "and", ",", "es-ES")) |
| 148 | + |
| 149 | + # --- German --- |
| 150 | + def test_de_and(self): |
| 151 | + self.assertEqual( |
| 152 | + join_word_list(["Hund", "Katze"], "and", ",", "de-DE"), |
| 153 | + "Hund und Katze") |
| 154 | + |
| 155 | + # --- French --- |
| 156 | + def test_fr_and(self): |
| 157 | + self.assertEqual( |
| 158 | + join_word_list(["chien", "chat"], "and", ",", "fr-FR"), |
| 159 | + "chien et chat") |
| 160 | + |
| 161 | + |
| 162 | +if __name__ == "__main__": |
| 163 | + unittest.main() |
0 commit comments