"""Tests for aztext. Runs under pytest OR as a plain script (python test_aztext.py). python -m pytest aztext/tests -q # if pytest is available python aztext/tests/test_aztext.py # dependency-free fallback """ import os import sys sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) import aztext from aztext import alphabet import aztext.deasciify # ensure submodule is imported (name is shadowed by the func export) deasc = sys.modules["aztext.deasciify"] # the MODULE, not the re-exported function # --- Turkic i-family case mapping (the thing Python gets wrong) -------------- def test_az_upper_i_family(): assert alphabet.az_upper("i") == "İ" assert alphabet.az_upper("ı") == "I" assert alphabet.az_upper("işıq") == "İŞIQ" def test_az_lower_i_family(): assert alphabet.az_lower("İ") == "i" assert alphabet.az_lower("I") == "ı" assert alphabet.az_lower("İŞIQ") == "işıq" def test_i_distinction_never_collapses(): # the four characters must stay pairwise distinct through case round-trips assert alphabet.az_lower(alphabet.az_upper("i")) == "i" assert alphabet.az_lower(alphabet.az_upper("ı")) == "ı" # --- number to words -------------------------------------------------------- def test_num_to_words(): cases = { 0: "sıfır", 1: "bir", 7: "yeddi", 10: "on", 11: "on bir", 20: "iyirmi", 25: "iyirmi beş", 100: "yüz", 101: "yüz bir", 200: "iki yüz", 1000: "min", 2000: "iki min", 1234: "min iki yüz otuz dörd", 1_000_000: "bir milyon", } for n, expected in cases.items(): assert aztext.num_to_words(n) == expected, (n, aztext.num_to_words(n)) def test_num_to_words_negative(): assert aztext.num_to_words(-5) == "mənfi beş" # --- language id ------------------------------------------------------------ def test_langid_az_vs_tr(): assert aztext.is_azerbaijani("Mən Azərbaycan dilini öyrənirəm.") # Turkish sentence (no ə, Turkish function words) must NOT be Azerbaijani lang, _ = aztext.detect_language("Ben Türkçe öğreniyorum ve kitap okuyorum.") assert lang == "tr", lang def test_langid_rejects_cyrillic(): lang, _ = aztext.detect_language("Привет как дела") assert lang == "other", lang # --- normalize -------------------------------------------------------------- def test_normalize_idempotent_and_preserves_az(): s = "Gözəl şəhər — “Bakı”." once = aztext.normalize(s) assert aztext.normalize(once) == once # idempotent for ch in "əöşıü": pass assert "ə" in once and "ş" in once and "ı" in once # az letters preserved assert '"' in once and "'" not in once # curly quotes -> ascii # --- deasciify -------------------------------------------------------------- def test_deasciify_known_words(): assert deasc.deasciify("ucun") == "üçün" assert deasc.deasciify("cixis") == "çıxış" assert deasc.deasciify("mekteb") == "məktəb" assert deasc.deasciify("usaq") == "uşaq" # casing preserved assert deasc.deasciify("Mekteb") == "Məktəb" # already-diacritic words pass through untouched assert deasc.deasciify("gözəl") == "gözəl" # unknown words untouched assert deasc.deasciify("xyzzy") == "xyzzy" def test_ascii_fold(): assert deasc.ascii_fold("gözəl çıxış") == "gozel cixis" assert deasc.ascii_fold("işıq") == "isiq" # --- tokenize / script ------------------------------------------------------ def test_tokenize(): assert aztext.word_tokenize("Bakı, Azərbaycanın paytaxtıdır.") == \ ["Bakı", "Azərbaycanın", "paytaxtıdır"] assert len(aztext.sent_tokenize("Bir. İki! Üç?")) == 3 def test_is_latin_azerbaijani(): assert aztext.is_latin_azerbaijani("Azərbaycan dili") assert not aztext.is_latin_azerbaijani("Азәрбајҹан дили") # --- dictionary integrity: no homoglyph / non-Azerbaijani letters ----------- def test_dictionary_is_clean_azerbaijani(): bad = [] for w in deasc._CORRECT_WORDS: for ch in w: if ch.isalpha() and ch not in alphabet.AZ_LETTERS: bad.append((w, ch, hex(ord(ch)))) assert not bad, f"non-Azerbaijani letters in deasciify dict: {bad}" def _run_all(): fns = [v for k, v in sorted(globals().items()) if k.startswith("test_") and callable(v)] failed = 0 for fn in fns: try: fn() print(f"PASS {fn.__name__}") except AssertionError as e: failed += 1 print(f"FAIL {fn.__name__}: {e}") except Exception as e: # noqa: BLE001 failed += 1 print(f"ERROR {fn.__name__}: {type(e).__name__}: {e}") print(f"\n{len(fns) - failed}/{len(fns)} passed") return failed if __name__ == "__main__": sys.exit(1 if _run_all() else 0)