Ctrl K
ComunidadGuías…

tests/test_binary_media_words.py

Rama v8 · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
"""Binary media stays discoverable without being decoded or counted as text."""

import builtins
import os
from pathlib import Path
from unittest.mock import Mock

import pytest

from graphify import cache
from graphify import detect as detect_mod


MEDIA_SUFFIXES = [
    ".png", ".jpg", ".jpeg", ".gif", ".webp", ".PNG",
    ".mp4", ".mov", ".webm", ".mkv", ".avi", ".m4v",
    ".mp3", ".wav", ".m4a", ".ogg", ".MP3",
]


@pytest.mark.parametrize("suffix", MEDIA_SUFFIXES)
def test_count_words_does_not_read_binary_media(tmp_path, monkeypatch, suffix):
    media = tmp_path / f"sample{suffix}"
    media.write_bytes(b"\x89\x00\xff imaginary words in binary media")
    reader = Mock(wraps=builtins.open)
    monkeypatch.setattr(detect_mod, "open", reader, raising=False)

    words = detect_mod.count_words(media)

    reader.assert_not_called()
    assert words == 0


@pytest.mark.parametrize("suffix", [".svg", ".SVG", ".txt", ".md", ".py"])
def test_count_words_preserves_text(tmp_path, suffix):
    path = tmp_path / f"sample{suffix}"
    text = "<svg><text>real words</text></svg>" if suffix.lower() == ".svg" else "real words"
    path.write_text(text, encoding="utf-8")

    assert detect_mod.count_words(path) == 2


@pytest.mark.parametrize("suffix,extractor", [
    (".pdf", "extract_pdf_text"),
    (".docx", "docx_to_markdown"),
    (".xlsx", "xlsx_to_markdown"),
])
def test_count_words_preserves_document_extraction(tmp_path, monkeypatch, suffix, extractor):
    path = tmp_path / f"document{suffix}"
    path.write_bytes(b"binary document container")
    convert = Mock(return_value="three extracted words")
    monkeypatch.setattr(detect_mod, extractor, convert)

    assert detect_mod.count_words(path) == 3
    convert.assert_called_once_with(path)


@pytest.mark.parametrize("cached_counts", [False, True], ids=["cold", "legacy-cache"])
def test_detect_keeps_media_without_counting_it(tmp_path, monkeypatch, cached_counts):
    for name, value in (
        ("_stat_index", {}), ("_stat_index_root", None),
        ("_stat_index_anchor", None), ("_stat_index_path", None),
        ("_stat_index_dirty", False),
    ):
        monkeypatch.setattr(cache, name, value)
    monkeypatch.setenv("GRAPHIFY_MTIME_GRANULARITY_MS", "2000")

    media_paths = [tmp_path / f"media_{index}{suffix}"
                   for index, suffix in enumerate(MEDIA_SUFFIXES)]
    for path in media_paths:
        path.write_bytes(b"\x89\x00\xff imaginary words in binary media")
        if cached_counts:
            old = path.stat().st_mtime_ns - 10_000_000_000
            os.utime(path, ns=(old, old))
            assert cache.cached_word_count(path, tmp_path, lambda _: 999) == 999
            recompute = Mock(return_value=0)
            assert cache.cached_word_count(path, tmp_path, recompute) == 999
            recompute.assert_not_called()

    svg = tmp_path / "diagram.SVG"
    svg.write_text("<svg><text>real words</text></svg>", encoding="utf-8")
    (tmp_path / "notes.txt").write_text("three real words", encoding="utf-8")
    word_cache = Mock(wraps=cache.cached_word_count)
    monkeypatch.setattr(cache, "cached_word_count", word_cache)

    result = detect_mod.detect(tmp_path)

    images = {Path(p) for p in result["files"]["image"]}
    videos = {Path(p) for p in result["files"]["video"]}
    assert images == {svg} | {p for p in media_paths if p.suffix.lower() in detect_mod.IMAGE_EXTENSIONS}
    assert videos == {p for p in media_paths if p.suffix.lower() in detect_mod.VIDEO_EXTENSIONS}
    assert result["total_files"] == len(media_paths) + 2
    assert result["total_words"] == 5
    assert {call.args[0] for call in word_cache.call_args_list} == {svg, tmp_path / "notes.txt"}