""" Тесты extractor.py — извлечение текста, ZIP-распаковка. Запуск: python3 tests/test_extractor.py """ import io import zipfile import sys import os sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from drhider.extractor import extract_text, expand_zips, docx_to_markdown, pdf_to_markdown passed = 0 failed = 0 def check(name, condition): global passed, failed if condition: passed += 1 print(f" ✅ {name}") else: failed += 1 print(f" ❌ {name}") # ═══════════════════════════════════════════════════════════════ # extract_text # ═══════════════════════════════════════════════════════════════ print("\n=== extract_text ===") # 1. .txt text = extract_text("test.txt", "Просто текст".encode("utf-8")) check(".txt — текст извлечён", text == "Просто текст") # 2. .txt с кириллицей text = extract_text("документ.txt", "Привет мир".encode("utf-8")) check(".txt — кириллица", "Привет" in text) # 3. .doc (бинарный — пропускается) text = extract_text("старый.doc", b"\xD0\xCF\x11\xE0\x00" * 10) check(".doc — заглушка", "not supported" in text.lower() or "binary" in text.lower()) # 4. Неизвестное расширение → UTF-8 text = extract_text("file.xyz", "hello".encode("utf-8")) check(".xyz — как текст", text == "hello") # ═══════════════════════════════════════════════════════════════ # expand_zips # ═══════════════════════════════════════════════════════════════ print("\n=== expand_zips ===") # 1. Не-ZIP файлы проходят без изменений files = [("test.txt", b"content", "text/plain")] result = expand_zips(files) check("не-ZIP — без изменений", len(result) == 1 and result[0][0] == "test.txt") # 2. ZIP распаковывается buf = io.BytesIO() with zipfile.ZipFile(buf, 'w') as zf: zf.writestr("inner.txt", b"hello") result = expand_zips([("archive.zip", buf.getvalue(), "application/zip")]) check("ZIP — распакован", len(result) == 1 and result[0][0] == "inner.txt") check("ZIP — контент верный", result[0][1] == b"hello") # 3. ZIP с несколькими файлами buf = io.BytesIO() with zipfile.ZipFile(buf, 'w') as zf: zf.writestr("a.txt", b"aaa") zf.writestr("b.txt", b"bbb") result = expand_zips([("multi.zip", buf.getvalue(), "")]) check("ZIP — два файла", len(result) == 2) # 4. Path traversal защита buf = io.BytesIO() with zipfile.ZipFile(buf, 'w') as zf: zf.writestr("../../etc/passwd", b"bad") result = expand_zips([("evil.zip", buf.getvalue(), "")]) check("path traversal — заблокирован", all("/" not in r[0] and ".." not in r[0] for r in result)) # 5. Директории пропускаются buf = io.BytesIO() with zipfile.ZipFile(buf, 'w') as zf: zf.writestr("dir/", b"") zf.writestr("dir/file.txt", b"ok") result = expand_zips([("dirs.zip", buf.getvalue(), "")]) check("директории — пропущены", len(result) == 1) # ═══════════════════════════════════════════════════════════════ # docx_to_markdown # ═══════════════════════════════════════════════════════════════ print("\n=== docx_to_markdown ===") try: from docx import Document # Создаём тестовый DOCX doc = Document() doc.add_heading("Заголовок", level=1) p = doc.add_paragraph("Обычный текст") p.add_run(" жирный").bold = True doc.add_paragraph("") # Таблица table = doc.add_table(rows=2, cols=2) table.rows[0].cells[0].text = "A" table.rows[0].cells[1].text = "B" table.rows[1].cells[0].text = "1" table.rows[1].cells[1].text = "2" buf = io.BytesIO() doc.save(buf) md = docx_to_markdown(buf.getvalue()) check("DOCX — заголовок #", "# Заголовок" in md) check("DOCX — жирный **", "жирный**" in md and "**" in md) check("DOCX — таблица", "| A | B |" in md) check("DOCX — разделитель таблицы", "---|---|" in md) check("DOCX — данные таблицы", "| 1 | 2 |" in md) except ImportError: print(" ⚠️ python-docx не установлен — тесты DOCX пропущены") # ═══════════════════════════════════════════════════════════════ # Итог # ═══════════════════════════════════════════════════════════════ print(f"\n{'='*50}") print(f"Результат: {passed} OK, {failed} FAIL из {passed + failed}") if failed > 0: print("❌ ТЕСТЫ ПРОВАЛЕНЫ") sys.exit(1) else: print("✅ ВСЕ ТЕСТЫ ПРОЙДЕНЫ")