#!/usr/bin/env python3 """ Автоматические тесты для Домовой Бот Проверка критических функций без запуска бота """ import sys import asyncio from pathlib import Path # Добавляем путь к проекту BASE_DIR = Path(__file__).resolve().parent sys.path.insert(0, str(BASE_DIR)) # Тесты TESTS_PASSED = 0 TESTS_FAILED = 0 def test_result(name: str, passed: bool, details: str = ""): """Вывод результата теста""" global TESTS_PASSED, TESTS_FAILED if passed: print(f"✅ {name}") TESTS_PASSED += 1 else: print(f"❌ {name}: {details}") TESTS_FAILED += 1 def test_syntax(): """Тест 1: Синтаксис Python файлов""" print("\n=== ТЕСТ 1: СИНТАКСИС ===") import py_compile import glob py_files = glob.glob("**/*.py", recursive=True) py_files = [f for f in py_files if 'venv' not in f] for file in py_files: try: py_compile.compile(file, doraise=True) test_result(f"✅ {file}", True) except py_compile.PyCompileError as e: test_result(f"❌ {file}", False, str(e)) def test_imports(): """Тест 2: Импорты модулей""" print("\n=== ТЕСТ 2: ИМПОРТЫ ===") modules = [ 'handlers.admin', 'handlers.users', 'handlers.verification', 'handlers.chat_monitor', 'handlers.security', 'handlers.apartments', 'handlers.antimat', 'handlers.phones', 'handlers.polls', 'handlers.antispam', 'handlers.ratelimit', 'handlers.schedule', 'handlers.ads', 'handlers.payments', 'handlers.multicount', 'handlers.topics', 'handlers.toxicity', 'handlers.profile_history', 'handlers.achievements', 'handlers.thanks', 'handlers.events', 'handlers.initiative_group', 'keyboards.admin_menu', 'keyboards.inline', 'keyboards.reply', 'database.models', 'database.db', 'config', ] for module in modules: try: __import__(module) test_result(f"✅ {module}", True) except ImportError as e: test_result(f"❌ {module}", False, str(e)) def test_callback_data_unique(): """Тест 3: Уникальность callback_data""" print("\n=== ТЕСТ 3: УНИКАЛЬНОСТЬ CALLBACK_DATA ===") import re import glob callbacks = [] files = glob.glob("handlers/*.py") + glob.glob("keyboards/*.py") for file in files: if 'venv' not in file: with open(file, 'r', encoding='utf-8') as f: content = f.read() found = re.findall(r"callback_data=['\"]([^'\"]+)['\"]", content) callbacks.extend(found) # Исключения (шаблоны с переменными) callbacks = [c for c in callbacks if '_' not in c.split('_')[-1] or not c.split('_')[-1].isdigit()] duplicates = [c for c in callbacks if callbacks.count(c) > 1] unique_duplicates = list(set(duplicates)) if unique_duplicates: test_result("Уникальность callback_data", False, f"Дубликаты: {unique_duplicates[:10]}") else: test_result("Уникальность callback_data", True) def test_commands_unique(): """Тест 4: Уникальность Command""" print("\n=== ТЕСТ 4: УНИКАЛЬНОСТЬ COMMAND ===") import re import glob commands = [] files = glob.glob("handlers/*.py") for file in files: if 'venv' not in file: with open(file, 'r', encoding='utf-8') as f: content = f.read() found = re.findall(r"@router\.message\(Command\(['\"]([^'\"]+)['\"]", content) commands.extend(found) # Считаем дубликаты (разрешены алиасы) from collections import Counter cmd_counts = Counter(commands) # Находим реальные дубликаты (не алиасы) duplicates = [cmd for cmd, count in cmd_counts.items() if count > 2] if duplicates: test_result("Уникальность Command", False, f"Дубликаты: {duplicates}") else: test_result("Уникальность Command", True) def test_database_structure(): """Тест 5: Структура БД""" print("\n=== ТЕСТ 5: СТРУКТУРА БД ===") import sqlite3 db_path = "database/domovoy.db" try: conn = sqlite3.connect(db_path) cursor = conn.cursor() # Проверяем таблицы cursor.execute("SELECT name FROM sqlite_master WHERE type='table'") tables = [row[0] for row in cursor.fetchall()] expected_tables = ['user', 'verification_request', 'service', 'announcement'] for table in expected_tables: test_result(f"Таблица '{table}'", table in tables) # Проверяем количество пользователей cursor.execute("SELECT COUNT(*) FROM user") count = cursor.fetchone()[0] test_result(f"Пользователей в БД: {count}", count >= 0) conn.close() except Exception as e: test_result("Проверка БД", False, str(e)) def test_keyboard_functions(): """Тест 6: Функции клавиатур""" print("\n=== ТЕСТ 6: ФУНКЦИИ КЛАВИАТУР ===") from keyboards.admin_menu import ( get_admin_main_menu, get_admin_reply_menu, get_admin_toxicity_menu, get_admin_search_menu, get_admin_antispam_menu, get_user_pagination_keyboard, get_user_action_menu, get_bad_words_list_keyboard, get_yes_no_keyboard, get_back_keyboard, ) from keyboards.inline import ( get_main_menu, get_thank_user_keyboard, get_thank_confirm_keyboard, ) functions = [ ('get_admin_main_menu', get_admin_main_menu), ('get_admin_toxicity_menu', get_admin_toxicity_menu), ('get_admin_search_menu', get_admin_search_menu), ('get_admin_antispam_menu', get_admin_antispam_menu), ('get_user_action_menu', lambda: get_user_action_menu(123, 'Test')), ('get_bad_words_list_keyboard', lambda: get_bad_words_list_keyboard(['test'])), ('get_yes_no_keyboard', lambda: get_yes_no_keyboard('test')), ('get_back_keyboard', get_back_keyboard), ('get_main_menu', get_main_menu), ('get_thank_user_keyboard', lambda: get_thank_user_keyboard([])), ('get_thank_confirm_keyboard', lambda: get_thank_confirm_keyboard(123)), ] for name, func in functions: try: result = func() test_result(f"✅ {name}", result is not None) except Exception as e: test_result(f"❌ {name}", False, str(e)) def test_fsm_states(): """Тест 7: FSM состояния""" print("\n=== ТЕСТ 7: FSM СОСТОЯНИЯ ===") from handlers.admin import SearchState, AddWordState, AddDomainState, AddPatternState states = [ ('SearchState.waiting_for_apt_search', SearchState.waiting_for_apt_search), ('SearchState.waiting_for_user_search', SearchState.waiting_for_user_search), ('AddWordState.waiting_for_word', AddWordState.waiting_for_word), ('AddDomainState.waiting_for_domain', AddDomainState.waiting_for_domain), ('AddPatternState.waiting_for_pattern', AddPatternState.waiting_for_pattern), ] for name, state in states: test_result(f"✅ {name}", state is not None) def test_config(): """Тест 8: Конфигурация""" print("\n=== ТЕСТ 8: КОНФИГУРАЦИЯ ===") from config import BOT_TOKEN, ADMIN_CHAT_ID, ADMIN_USER_ID test_result("BOT_TOKEN настроен", len(BOT_TOKEN) > 10) test_result("ADMIN_CHAT_ID настроен", ADMIN_CHAT_ID != 0) test_result("ADMIN_USER_ID настроен", ADMIN_USER_ID != 0) def run_all_tests(): """Запуск всех тестов""" print("=" * 60) print("🧪 АВТОМАТИЧЕСКИЕ ТЕСТЫ ДОМОВОЙ БОТ") print("=" * 60) test_syntax() test_imports() test_callback_data_unique() test_commands_unique() test_database_structure() test_keyboard_functions() test_fsm_states() test_config() print("\n" + "=" * 60) print(f"✅ ПРОЙДЕНО: {TESTS_PASSED}") print(f"❌ ПРОВАЛЕНО: {TESTS_FAILED}") print("=" * 60) return TESTS_FAILED == 0 if __name__ == '__main__': success = run_all_tests() sys.exit(0 if success else 1)