"""Проверка нормализатора. Запуск: python bench/test_normalize.py Отдельный файл без pytest намеренно: нормализатор публикуется вместе с цифрами, и проверять его должен уметь любой, кто скачал репозиторий, одной командой и без установки чего-либо. Ошибка здесь искажает все результаты сразу, поэтому набор проверок покрывает и обычные случаи, и те, на которых нормализатор уже ломался. """ from __future__ import annotations import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).parent)) from normalize import has_digits, int_to_words, normalize, plural, words_with_punct # noqa: E402 CASES: list[tuple[str, str]] = [ # регистр, ё, пунктуация ('Привет, Мир!', 'привет мир'), ('Ёлки-палки', 'елки палки'), ('Он сказал: «да».', 'он сказал да'), # дефис — не ошибка распознавания ('по-русски', 'по русски'), # числа ('5 домов', 'пять домов'), ('в 2026 году', 'в две тысячи двадцать шесть году'), ('1990', 'тысяча девятьсот девяносто'), ('0', 'ноль'), ('101', 'сто один'), ('1000000', 'миллион'), ('12 000 ₽', 'двенадцать тысяч рублей'), ('3,5', 'три целых пять десятых'), ('0,125', 'ноль целых сто двадцать пять тысячных'), ('-5', 'минус пять'), # знак единицы не должен склеиваться с предыдущим словом ('рост 5% за год', 'рост пять процентов за год'), ('1 %', 'один процент'), ('2 %', 'два процента'), ('11 %', 'одиннадцать процентов'), # обе формы чтения тысяч сводятся к одной ('тысяча девятьсот', 'тысяча девятьсот'), ('одна тысяча девятьсот', 'тысяча девятьсот'), # пробелы (' два пробела ', 'два пробела'), ('', ''), ] INT_CASES: list[tuple[int, str]] = [ (1, 'один'), (2, 'два'), (11, 'одиннадцать'), (21, 'двадцать один'), (40, 'сорок'), (90, 'девяносто'), (100, 'сто'), (999, 'девятьсот девяносто девять'), (1001, 'одна тысяча один'), (2000, 'две тысячи'), (5000, 'пять тысяч'), (21000, 'двадцать одна тысяча'), (1000000, 'один миллион'), (2000000000, 'два миллиарда'), ] PLURAL_CASES: list[tuple[int, str]] = [ (1, 'дом'), (2, 'дома'), (4, 'дома'), (5, 'домов'), (11, 'домов'), (12, 'домов'), (14, 'домов'), (21, 'дом'), (22, 'дома'), (100, 'домов'), ] def main() -> int: failed = 0 for src, want in CASES: got = normalize(src) if got != want: print(f'FAIL normalize({src!r})\n ждал: {want!r}\n вышло: {got!r}') failed += 1 for n, want in INT_CASES: got = int_to_words(n) if got != want: print(f'FAIL int_to_words({n})\n ждал: {want!r}\n вышло: {got!r}') failed += 1 for n, want in PLURAL_CASES: got = plural(n, ('дом', 'дома', 'домов')) if got != want: print(f'FAIL plural({n})\n ждал: {want!r}\n вышло: {got!r}') failed += 1 # симметрия: нормализованный текст не меняется от повторного прогона. # Если меняется — на одной стороне сравнения окажется другой результат for src, _ in CASES: once = normalize(src) if normalize(once) != once: print(f'FAIL идемпотентность на {src!r}: {once!r} → {normalize(once)!r}') failed += 1 # правило отбора: цифры в эталоне if has_digits('пять') or not has_digits('в 1990'): print('FAIL has_digits') failed += 1 # пунктуация: знак вешается на последнее слово развёрнутого числа got_pairs = words_with_punct('Было 21, потом всё.') want_pairs = [('было', None), ('двадцать', None), ('один', ','), ('потом', None), ('все', '.')] if got_pairs != want_pairs: print(f'FAIL words_with_punct\n ждал: {want_pairs}\n вышло: {got_pairs}') failed += 1 # восклицание и многоточие сводятся к точке, двоеточие — к запятой if [m for _, m in words_with_punct('Да! Нет… Так: вот;')] != ['.', '.', ',', ',']: print(f'FAIL классы знаков: {words_with_punct("Да! Нет… Так: вот;")}') failed += 1 total = len(CASES) + len(INT_CASES) + len(PLURAL_CASES) + len(CASES) + 3 print(f'{"ПРОВАЛ" if failed else "ok"}: проверок {total}, ошибок {failed}') return 1 if failed else 0 if __name__ == '__main__': raise SystemExit(main())