""" Tests for BaseCompletionEngine. Uses a mock implementation to test the abstract base class functionality. """ import pytest from typing import Any from myfasthtml.core.dsl.types import Position, Suggestion, CompletionResult from myfasthtml.core.dsl.base_completion import BaseCompletionEngine from myfasthtml.core.dsl.base_provider import BaseMetadataProvider class MockProvider: """Mock metadata provider for testing.""" def get_style_presets(self) -> list[str]: return ["custom_highlight"] def get_format_presets(self) -> list[str]: return ["CHF"] class MockCompletionEngine(BaseCompletionEngine): """Mock completion engine for testing base class functionality.""" def __init__(self, provider: BaseMetadataProvider, suggestions: list[Suggestion] = None): super().__init__(provider) self._suggestions = suggestions or [] self._scope = None self._context = "test_context" def detect_scope(self, text: str, current_line: int) -> Any: return self._scope def detect_context(self, text: str, cursor: Position, scope: Any) -> Any: return self._context def get_suggestions(self, context: Any, scope: Any, prefix: str) -> list[Suggestion]: return self._suggestions # ============================================================================= # Filter Suggestions Tests # ============================================================================= def test_i_can_filter_suggestions_by_prefix(): """Test that _filter_suggestions filters case-insensitively.""" provider = MockProvider() engine = MockCompletionEngine(provider) suggestions = [ Suggestion("primary", "Primary color", "preset"), Suggestion("error", "Error color", "preset"), Suggestion("warning", "Warning color", "preset"), Suggestion("Error", "Title case error", "preset"), ] # Filter by "err" - should match "error" and "Error" (case-insensitive) filtered = engine._filter_suggestions(suggestions, "err") labels = [s.label for s in filtered] assert "error" in labels assert "Error" in labels assert "primary" not in labels assert "warning" not in labels def test_i_can_filter_suggestions_empty_prefix(): """Test that empty prefix returns all suggestions.""" provider = MockProvider() engine = MockCompletionEngine(provider) suggestions = [ Suggestion("a"), Suggestion("b"), Suggestion("c"), ] filtered = engine._filter_suggestions(suggestions, "") assert len(filtered) == 3 # ============================================================================= # Empty Result Tests # ============================================================================= def test_i_can_get_empty_result(): """Test that _empty_result returns a CompletionResult with no suggestions.""" provider = MockProvider() engine = MockCompletionEngine(provider) cursor = Position(line=5, ch=10) result = engine._empty_result(cursor) assert result.from_pos == cursor assert result.to_pos == cursor assert result.suggestions == [] assert result.is_empty is True # ============================================================================= # Comment Skipping Tests # ============================================================================= def test_i_can_skip_completion_in_comment(): """Test that get_completions returns empty when cursor is in a comment.""" provider = MockProvider() suggestions = [Suggestion("should_not_appear")] engine = MockCompletionEngine(provider, suggestions) text = "# This is a comment" cursor = Position(line=0, ch=15) # Inside the comment result = engine.get_completions(text, cursor) assert result.is_empty is True assert len(result.suggestions) == 0 def test_i_can_get_completions_outside_comment(): """Test that get_completions works when cursor is not in a comment.""" provider = MockProvider() suggestions = [Suggestion("style"), Suggestion("format")] engine = MockCompletionEngine(provider, suggestions) # Cursor at space (ch=5) so prefix is empty and all suggestions are returned text = "text # comment" cursor = Position(line=0, ch=5) # At empty space, before comment result = engine.get_completions(text, cursor) assert result.is_empty is False assert len(result.suggestions) == 2