headroom/tests/test_mixed_content_sections.py
JD Davis 9bacf4810f
refactor(transforms): isolate mixed content parsing (#1939)
## Description

Extracts mixed-content parsing out of the large `ContentRouter` module
into a pure transform-domain module. The router still exports the
existing compatibility names, but section typing, mixed-content
indicators, section splitting, and JSON block extraction now live in a
focused domain object/function layer.

Closes #

## Type of Change

- [ ] Bug fix (non-breaking change that fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update
- [ ] Performance improvement
- [x] Code refactoring (no functional changes)

## Changes Made

- Added `headroom.transforms.mixed_content` with `ContentSection`,
`mixed_content_indicators`, `is_mixed_content`, `split_into_sections`,
and JSON block extraction.
- Updated `ContentRouter` to delegate mixed-content debug indicators and
parsing to the new module while preserving legacy imports from
`content_router.py`.
- Added direct unit coverage for mixed-content detection, section
boundaries, and JSON delimiters inside string literals.
- Included the LiteLLM callback signature compatibility shim needed for
repo-wide mypy while the earlier architecture PRs are still open.

## Testing

- [x] Unit tests pass (`pytest`)
- [x] Linting passes (`ruff check .`)
- [x] Type checking passes (`mypy headroom`)
- [x] New tests added for new functionality
- [ ] Manual testing performed

### Test Output

```text
python -m pytest tests/test_mixed_content_sections.py tests/test_transforms_content_router.py tests/test_litellm_callback.py tests/test_compress_api.py::TestLiteLLMCallback -q
50 passed in 6.82s

python -m ruff check .
All checks passed!

python -m ruff format --check .
1095 files already formatted

python -m mypy headroom --ignore-missing-imports
headroom\proxy\server.py:1457: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
headroom\proxy\server.py:1468: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
Success: no issues found in 409 source files
```

## Real Behavior Proof

- Environment: Windows, Python 3.13.13, clean worktree
`C:\git\headroom-pr-slice6`
- Exact command / steps: ran the pytest, Ruff, format, and mypy commands
listed above.
- Observed result: mixed-content parsing behavior remains covered
through existing router tests and new direct tests; repo-wide lint/type
checks pass.
- Not tested: full pytest suite and Docker/native CI jobs are left to
GitHub Actions.

## Review Readiness

- [x] I have performed a self-review
- [x] This PR is ready for human review

## Checklist

- [x] My code follows the project's style guidelines
- [x] I have performed a self-review of my code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] I have updated the CHANGELOG.md if applicable

## Screenshots (if applicable)

N/A.

## Additional Notes

- Documentation, changelog, and screenshots are N/A for this internal
refactor.
- Manual UI testing is N/A; this is pure transform parsing logic.
- Comment checklist is unchecked because the extracted functions are
small and covered by direct tests.
2026-07-10 19:28:21 -05:00

63 lines
1.8 KiB
Python

from headroom.transforms.content_detector import ContentType
from headroom.transforms.mixed_content import (
_extract_json_block,
is_mixed_content,
split_into_sections,
)
def test_mixed_content_detection_requires_multiple_signals():
prose = "\n".join(
[
"First sentence has enough words to count.",
"Second sentence has enough words to count.",
"Third sentence has enough words to count.",
"Fourth sentence has enough words to count.",
"Fifth sentence has enough words to count.",
"Sixth sentence has enough words to count.",
]
)
assert is_mixed_content(prose) is False
assert is_mixed_content(f"{prose}\n```python\nprint('x')\n```") is True
def test_split_into_sections_preserves_typed_boundaries():
content = "\n".join(
[
"Intro text",
"```python",
"print('x')",
"```",
'[{"id": 1}]',
"src/app.py:10:print('x')",
]
)
sections = split_into_sections(content)
assert [section.content_type for section in sections] == [
ContentType.PLAIN_TEXT,
ContentType.SOURCE_CODE,
ContentType.JSON_ARRAY,
ContentType.SEARCH_RESULTS,
]
assert sections[1].language == "python"
assert sections[1].content == "print('x')"
assert sections[1].is_code_fence is True
assert sections[2].content == '[{"id": 1}]'
assert sections[3].start_line == 5
def test_extract_json_block_ignores_delimiters_inside_strings():
lines = [
"[",
' {"path": "a]b", "message": "keep {literal} braces"},',
' {"path": "c"}',
"]",
]
block, end_line = _extract_json_block(lines, 0)
assert end_line == 3
assert block == "\n".join(lines)