Spaces:
Build error
Build error
Download tests/test_transforms/test_content_router.py from minhtudragon/headroom_3: direct link, hf CLI and curl.
- Browser
- Download file 18 kB
-
https://huggingface.co/spaces/minhtudragon/headroom_3/resolve/7de545c00eea8cbb7d30e142ef021991eac75391/tests/test_transforms/test_content_router.py
- Command line
-
hf download hf://spaces/minhtudragon/headroom_3@7de545c00eea8cbb7d30e142ef021991eac75391/tests/test_transforms/test_content_router.py
-
curl -L -o test_content_router.py https://huggingface.co/spaces/minhtudragon/headroom_3/resolve/7de545c00eea8cbb7d30e142ef021991eac75391/tests/test_transforms/test_content_router.py
18 kB
| """Tests for ContentRouter - intelligent content-based compression routing. | |
| Comprehensive tests covering: | |
| - ContentRouterConfig: Configuration validation and defaults | |
| - ContentRouter: Core routing functionality | |
| - Strategy detection: Code, JSON, search, logs, text | |
| - Mixed content handling: Split, route, reassemble | |
| - Transform interface: apply(), should_apply() methods | |
| """ | |
| import pytest | |
| from headroom.transforms.content_detector import ContentType | |
| from headroom.transforms.content_router import ( | |
| CompressionStrategy, | |
| ContentRouter, | |
| ContentRouterConfig, | |
| RouterCompressionResult, | |
| RoutingDecision, | |
| ) | |
| # ============================================================================= | |
| # Test Fixtures | |
| # ============================================================================= | |
| def default_config(): | |
| """Default ContentRouterConfig for testing.""" | |
| return ContentRouterConfig( | |
| min_section_tokens=10, # Low threshold for tests | |
| ) | |
| def router(default_config): | |
| """ContentRouter instance with default config.""" | |
| return ContentRouter(default_config) | |
| def tokenizer(): | |
| """Get a tokenizer for Transform interface tests.""" | |
| from headroom.providers import OpenAIProvider | |
| from headroom.tokenizer import Tokenizer | |
| provider = OpenAIProvider() | |
| token_counter = provider.get_token_counter("gpt-4o") | |
| return Tokenizer(token_counter, "gpt-4o") | |
| # ============================================================================= | |
| # Test Data Generators | |
| # ============================================================================= | |
| def generate_python_code(n_functions: int = 5) -> str: | |
| """Generate Python code for testing.""" | |
| lines = [ | |
| '"""Module with functions."""', | |
| "import os", | |
| "from typing import Any", | |
| "", | |
| ] | |
| for i in range(n_functions): | |
| lines.extend( | |
| [ | |
| f"def function_{i}(arg: Any) -> str:", | |
| f' """Process argument {i}."""', | |
| " return str(arg)", | |
| "", | |
| ] | |
| ) | |
| return "\n".join(lines) | |
| def generate_json_data(n_items: int = 20) -> str: | |
| """Generate JSON content for testing.""" | |
| import json | |
| items = [ | |
| {"id": i, "name": f"Item {i}", "value": i * 10, "active": i % 2 == 0} | |
| for i in range(n_items) | |
| ] | |
| return json.dumps(items, indent=2) | |
| def generate_search_results(n_results: int = 10) -> str: | |
| """Generate grep/search-like results for testing.""" | |
| lines = [] | |
| for i in range(n_results): | |
| lines.append(f"src/module{i}.py:42: def process_data(input: str) -> str:") | |
| lines.append(f"src/module{i}.py:43: return transform(input)") | |
| return "\n".join(lines) | |
| def generate_log_output(n_lines: int = 30) -> str: | |
| """Generate build/test log output for testing.""" | |
| lines = [ | |
| "Running tests...", | |
| "=== Test Suite: Unit Tests ===", | |
| ] | |
| for i in range(n_lines): | |
| if i % 10 == 0: | |
| lines.append(f"PASS tests/test_module{i}.py::test_function") | |
| elif i % 15 == 0: | |
| lines.append(f"FAIL tests/test_module{i}.py::test_failing") | |
| else: | |
| lines.append(f" Running test_{i}... ok") | |
| lines.append("=== Summary ===") | |
| lines.append(f"Tests: {n_lines}, Passed: {n_lines - 2}, Failed: 2") | |
| return "\n".join(lines) | |
| def generate_mixed_content() -> str: | |
| """Generate content with mixed types (markdown with code).""" | |
| return """# Documentation | |
| This is a README file with code examples. | |
| ## Python Example | |
| ```python | |
| def example(): | |
| return "hello" | |
| ``` | |
| ## JSON Configuration | |
| ```json | |
| {"key": "value", "number": 42} | |
| ``` | |
| ## Usage | |
| Run the following command: | |
| ```bash | |
| python main.py --verbose | |
| ``` | |
| That's all! | |
| """ | |
| # ============================================================================= | |
| # TestContentRouterConfig | |
| # ============================================================================= | |
| class TestContentRouterConfig: | |
| """Tests for ContentRouterConfig dataclass.""" | |
| def test_default_values(self): | |
| """Default config values are sensible.""" | |
| config = ContentRouterConfig() | |
| assert config.enable_code_aware is True | |
| assert config.enable_llmlingua is True | |
| assert config.enable_smart_crusher is True | |
| assert config.enable_search_compressor is True | |
| assert config.enable_log_compressor is True | |
| assert config.min_section_tokens == 20 | |
| assert config.fallback_strategy == CompressionStrategy.PASSTHROUGH | |
| def test_custom_values(self): | |
| """Custom config values are applied.""" | |
| config = ContentRouterConfig( | |
| min_section_tokens=50, | |
| enable_code_aware=False, | |
| enable_llmlingua=False, | |
| fallback_strategy=CompressionStrategy.TEXT, | |
| ) | |
| assert config.min_section_tokens == 50 | |
| assert config.enable_code_aware is False | |
| assert config.enable_llmlingua is False | |
| assert config.fallback_strategy == CompressionStrategy.TEXT | |
| def test_all_strategies_in_enum(self): | |
| """All expected strategies are in the enum.""" | |
| expected = [ | |
| "CODE_AWARE", | |
| "SMART_CRUSHER", | |
| "SEARCH", | |
| "LOG", | |
| "LLMLINGUA", | |
| "TEXT", | |
| "MIXED", | |
| "PASSTHROUGH", | |
| ] | |
| actual = [s.name for s in CompressionStrategy] | |
| for strategy in expected: | |
| assert strategy in actual, f"Missing strategy: {strategy}" | |
| # ============================================================================= | |
| # TestRouterCompressionResult | |
| # ============================================================================= | |
| class TestRouterCompressionResult: | |
| """Tests for RouterCompressionResult dataclass.""" | |
| def test_tokens_saved_from_routing_log(self): | |
| """tokens_saved property calculates correctly from routing log.""" | |
| result = RouterCompressionResult( | |
| compressed="short", | |
| original="long content here", | |
| strategy_used=CompressionStrategy.CODE_AWARE, | |
| routing_log=[ | |
| RoutingDecision( | |
| content_type=ContentType.SOURCE_CODE, | |
| strategy=CompressionStrategy.CODE_AWARE, | |
| confidence=0.9, | |
| original_tokens=100, | |
| compressed_tokens=30, | |
| ) | |
| ], | |
| sections_processed=1, | |
| ) | |
| assert result.tokens_saved == 70 | |
| def test_tokens_saved_no_negative(self): | |
| """tokens_saved never returns negative.""" | |
| result = RouterCompressionResult( | |
| compressed="expanded", | |
| original="short", | |
| strategy_used=CompressionStrategy.PASSTHROUGH, | |
| routing_log=[ | |
| RoutingDecision( | |
| content_type=ContentType.PLAIN_TEXT, | |
| strategy=CompressionStrategy.PASSTHROUGH, | |
| confidence=1.0, | |
| original_tokens=10, | |
| compressed_tokens=20, # Expanded | |
| ) | |
| ], | |
| sections_processed=1, | |
| ) | |
| # Should be 0 not negative | |
| assert result.tokens_saved == 0 | |
| def test_savings_percentage(self): | |
| """savings_percentage property calculates correctly.""" | |
| result = RouterCompressionResult( | |
| compressed="short", | |
| original="long content", | |
| strategy_used=CompressionStrategy.TEXT, | |
| routing_log=[ | |
| RoutingDecision( | |
| content_type=ContentType.PLAIN_TEXT, | |
| strategy=CompressionStrategy.TEXT, | |
| confidence=0.8, | |
| original_tokens=100, | |
| compressed_tokens=25, | |
| ) | |
| ], | |
| sections_processed=1, | |
| ) | |
| assert result.savings_percentage == 75.0 | |
| def test_empty_routing_log(self): | |
| """Handles empty routing log gracefully.""" | |
| result = RouterCompressionResult( | |
| compressed="content", | |
| original="content", | |
| strategy_used=CompressionStrategy.PASSTHROUGH, | |
| routing_log=[], | |
| sections_processed=0, | |
| ) | |
| assert result.total_original_tokens == 0 | |
| assert result.total_compressed_tokens == 0 | |
| assert result.savings_percentage == 0.0 | |
| # ============================================================================= | |
| # TestStrategyDetection | |
| # ============================================================================= | |
| class TestStrategyDetection: | |
| """Tests for content type and strategy detection.""" | |
| def test_detect_python_code(self, router): | |
| """Python code is detected.""" | |
| code = generate_python_code(5) | |
| strategy = router._determine_strategy(code) | |
| # Should be either CODE_AWARE or fallback | |
| assert strategy in CompressionStrategy | |
| def test_detect_json_content(self, router): | |
| """JSON content is detected.""" | |
| json_data = generate_json_data(20) | |
| strategy = router._determine_strategy(json_data) | |
| assert strategy in CompressionStrategy | |
| def test_detect_search_results(self, router): | |
| """Search/grep results are detected.""" | |
| search_results = generate_search_results(10) | |
| strategy = router._determine_strategy(search_results) | |
| assert strategy in CompressionStrategy | |
| def test_detect_log_output(self, router): | |
| """Build/test logs are detected.""" | |
| logs = generate_log_output(30) | |
| strategy = router._determine_strategy(logs) | |
| assert strategy in CompressionStrategy | |
| def test_detect_plain_text(self, router): | |
| """Plain text detection.""" | |
| text = "This is just plain text without any special formatting." | |
| strategy = router._determine_strategy(text) | |
| assert strategy in CompressionStrategy | |
| # ============================================================================= | |
| # TestContentRouter | |
| # ============================================================================= | |
| class TestContentRouter: | |
| """Tests for ContentRouter core functionality.""" | |
| def test_init_with_default_config(self): | |
| """Router initializes with default config.""" | |
| router = ContentRouter() | |
| assert router.config is not None | |
| assert router.config.enable_code_aware is True | |
| def test_init_with_custom_config(self, default_config): | |
| """Router initializes with custom config.""" | |
| router = ContentRouter(default_config) | |
| assert router.config == default_config | |
| def test_compress_empty_content(self, router): | |
| """Empty content returns passthrough.""" | |
| result = router.compress("") | |
| assert result.compressed == "" | |
| assert result.strategy_used == CompressionStrategy.PASSTHROUGH | |
| def test_compress_small_content(self, router): | |
| """Small content returns same content.""" | |
| result = router.compress("small") | |
| assert result.compressed == "small" | |
| # Small content might use TEXT or PASSTHROUGH strategy | |
| assert result.strategy_used in ( | |
| CompressionStrategy.PASSTHROUGH, | |
| CompressionStrategy.TEXT, | |
| ) | |
| def test_compress_returns_result(self, router): | |
| """compress() returns RouterCompressionResult.""" | |
| content = generate_python_code(10) | |
| result = router.compress(content) | |
| assert isinstance(result, RouterCompressionResult) | |
| assert result.original == content | |
| assert result.strategy_used is not None | |
| def test_name_property(self, router): | |
| """Router has correct name.""" | |
| assert router.name == "content_router" | |
| # ============================================================================= | |
| # TestTransformInterface | |
| # ============================================================================= | |
| class TestTransformInterface: | |
| """Tests for Transform interface (apply, should_apply).""" | |
| def test_should_apply_returns_bool(self, default_config, tokenizer): | |
| """should_apply returns a boolean.""" | |
| router = ContentRouter(default_config) | |
| messages = [{"role": "user", "content": "small"}] | |
| result = router.should_apply(messages, tokenizer) | |
| assert isinstance(result, bool) | |
| def test_should_apply_returns_true_for_large_content(self, default_config, tokenizer): | |
| """should_apply returns True for large content.""" | |
| router = ContentRouter(default_config) | |
| content = generate_python_code(20) | |
| messages = [{"role": "tool", "tool_call_id": "call_1", "content": content}] | |
| assert router.should_apply(messages, tokenizer) | |
| def test_apply_returns_transform_result(self, default_config, tokenizer): | |
| """apply() returns proper TransformResult.""" | |
| router = ContentRouter(default_config) | |
| content = generate_python_code(10) | |
| messages = [{"role": "tool", "tool_call_id": "call_1", "content": content}] | |
| result = router.apply(messages, tokenizer) | |
| assert result is not None | |
| assert result.tokens_before > 0 | |
| assert len(result.messages) == 1 | |
| def test_apply_passes_through_non_tool_messages(self, default_config, tokenizer): | |
| """apply() passes through non-tool messages unchanged.""" | |
| router = ContentRouter(default_config) | |
| messages = [ | |
| {"role": "user", "content": "Hello"}, | |
| {"role": "assistant", "content": "Hi there!"}, | |
| ] | |
| result = router.apply(messages, tokenizer) | |
| assert result.messages[0]["content"] == "Hello" | |
| assert result.messages[1]["content"] == "Hi there!" | |
| # ============================================================================= | |
| # TestCompressorDisabling | |
| # ============================================================================= | |
| class TestCompressorDisabling: | |
| """Tests for disabling specific compressors. | |
| Note: These tests verify the config is accepted, not that the router | |
| actually respects the disable flags (which may not be fully implemented). | |
| """ | |
| def test_config_accepts_disable_code_compression(self): | |
| """Config accepts enable_code_aware=False.""" | |
| config = ContentRouterConfig( | |
| enable_code_aware=False, | |
| min_section_tokens=10, | |
| ) | |
| router = ContentRouter(config) | |
| code = generate_python_code(10) | |
| # Should not crash | |
| result = router.compress(code) | |
| assert result is not None | |
| def test_config_accepts_disable_search_compression(self): | |
| """Config accepts enable_search_compressor=False.""" | |
| config = ContentRouterConfig( | |
| enable_search_compressor=False, | |
| min_section_tokens=10, | |
| ) | |
| router = ContentRouter(config) | |
| search_results = generate_search_results(10) | |
| # Should not crash | |
| result = router.compress(search_results) | |
| assert result is not None | |
| def test_config_accepts_disable_log_compression(self): | |
| """Config accepts enable_log_compressor=False.""" | |
| config = ContentRouterConfig( | |
| enable_log_compressor=False, | |
| min_section_tokens=10, | |
| ) | |
| router = ContentRouter(config) | |
| logs = generate_log_output(30) | |
| # Should not crash | |
| result = router.compress(logs) | |
| assert result is not None | |
| # ============================================================================= | |
| # TestEdgeCases | |
| # ============================================================================= | |
| class TestEdgeCases: | |
| """Edge case tests for ContentRouter.""" | |
| def test_whitespace_only_content(self, router): | |
| """Whitespace-only content is handled gracefully.""" | |
| result = router.compress(" \n\t\n ") | |
| assert result.strategy_used == CompressionStrategy.PASSTHROUGH | |
| def test_unicode_content(self, router): | |
| """Unicode content is handled correctly.""" | |
| content = "This has unicode: \u4e2d\u6587 \u65e5\u672c\u8a9e " * 50 | |
| result = router.compress(content) | |
| assert result is not None | |
| def test_very_long_content(self, router): | |
| """Very long content is handled.""" | |
| content = generate_python_code(100) | |
| result = router.compress(content) | |
| assert result is not None | |
| # ============================================================================= | |
| # TestRoutingLog | |
| # ============================================================================= | |
| class TestRoutingLog: | |
| """Tests for routing log functionality.""" | |
| def test_routing_log_populated(self, router): | |
| """Routing log is populated with decisions.""" | |
| content = generate_python_code(10) | |
| result = router.compress(content) | |
| # Routing log should be a list | |
| assert isinstance(result.routing_log, list) | |
| def test_routing_log_entries_have_strategy(self, router): | |
| """Routing log entries contain strategy.""" | |
| content = generate_python_code(10) | |
| result = router.compress(content) | |
| for entry in result.routing_log: | |
| assert hasattr(entry, "strategy") | |
| assert entry.strategy in CompressionStrategy | |
| # ============================================================================= | |
| # TestSummary | |
| # ============================================================================= | |
| class TestSummary: | |
| """Tests for result summary generation.""" | |
| def test_summary_property(self, router): | |
| """Summary property exists and is callable or returns string.""" | |
| content = generate_python_code(10) | |
| result = router.compress(content) | |
| # Check summary property exists | |
| assert hasattr(result, "summary") | |
| # Get summary (call if callable) | |
| summary = result.summary | |
| if callable(summary): | |
| summary = summary() | |
| # Should be a string | |
| assert summary is not None | |