""" Tests for DSL autocompletion utilities. Tests for line extraction, word boundaries, comment/string detection, and indentation functions. """ import pytest from myfasthtml.core.dsl.types import Position, WordRange from myfasthtml.core.dsl.utils import ( get_line_at, get_line_up_to_cursor, get_lines_up_to, find_word_boundaries, get_prefix, is_in_comment, is_in_string, get_indentation, is_indented, strip_quotes, ) # ============================================================================= # Line Extraction Tests # ============================================================================= def test_i_can_get_line_at_valid_index(): """Test that get_line_at returns the correct line.""" text = "line0\nline1\nline2" assert get_line_at(text, 0) == "line0" assert get_line_at(text, 1) == "line1" assert get_line_at(text, 2) == "line2" def test_i_can_get_line_at_invalid_index(): """Test that get_line_at returns empty string for invalid index.""" text = "line0\nline1" assert get_line_at(text, -1) == "" assert get_line_at(text, 5) == "" def test_i_can_get_line_up_to_cursor(): """Test that get_line_up_to_cursor truncates at cursor position.""" text = "hello world\nfoo bar" cursor = Position(line=0, ch=5) assert get_line_up_to_cursor(text, cursor) == "hello" cursor = Position(line=1, ch=3) assert get_line_up_to_cursor(text, cursor) == "foo" def test_i_can_get_lines_up_to(): """Test that get_lines_up_to returns lines 0..N.""" text = "line0\nline1\nline2\nline3" assert get_lines_up_to(text, 0) == ["line0"] assert get_lines_up_to(text, 2) == ["line0", "line1", "line2"] # ============================================================================= # Word Boundaries Tests # ============================================================================= def test_i_can_find_word_boundaries_in_middle(): """Test word boundaries when cursor is in middle of word.""" line = "hello world" result = find_word_boundaries(line, 3) # hel|lo assert result.start == 0 assert result.end == 5 assert result.text == "hello" def test_i_can_find_word_boundaries_at_start(): """Test word boundaries when cursor is at start of word.""" line = "hello world" result = find_word_boundaries(line, 0) # |hello assert result.start == 0 assert result.end == 5 assert result.text == "hello" def test_i_can_find_word_boundaries_at_end(): """Test word boundaries when cursor is at end of word.""" line = "hello world" result = find_word_boundaries(line, 5) # hello| assert result.start == 0 assert result.end == 5 assert result.text == "hello" def test_i_can_find_word_boundaries_with_delimiters(): """Test word boundaries with delimiter characters like parentheses and quotes.""" line = 'style("error")' result = find_word_boundaries(line, 10) # style("err|or") assert result.start == 7 assert result.end == 12 assert result.text == "error" def test_i_can_find_word_boundaries_empty_line(): """Test word boundaries on empty line.""" line = "" result = find_word_boundaries(line, 0) assert result.start == 0 assert result.end == 0 assert result.text == "" def test_i_can_get_prefix(): """Test that get_prefix returns text from word start to cursor.""" line = "style" prefix = get_prefix(line, 3) # sty|le assert prefix == "sty" def test_i_can_get_prefix_at_word_start(): """Test that get_prefix returns empty at word start.""" line = "style" prefix = get_prefix(line, 0) # |style assert prefix == "" # ============================================================================= # Comment Detection Tests # ============================================================================= def test_i_can_detect_comment(): """Test that cursor after # is detected as in comment.""" line = "text # comment" assert is_in_comment(line, 12) is True # In "comment" assert is_in_comment(line, 7) is True # Right after # def test_i_cannot_detect_comment_before_hash(): """Test that cursor before # is not detected as in comment.""" line = "text # comment" assert is_in_comment(line, 4) is False # Before # assert is_in_comment(line, 0) is False # At start def test_i_cannot_detect_comment_hash_in_string(): """Test that # inside a string is not detected as comment start.""" line = '"#hash" text' assert is_in_comment(line, 9) is False # After the string def test_i_can_detect_comment_hash_after_string(): """Test that # after a string is detected as comment.""" line = '"text" # comment' assert is_in_comment(line, 10) is True # ============================================================================= # String Detection Tests # ============================================================================= def test_i_can_detect_string_double_quote(): """Test detection of cursor inside double-quoted string.""" line = 'style("error")' in_string, quote_char = is_in_string(line, 10) # Inside "error" assert in_string is True assert quote_char == '"' def test_i_can_detect_string_single_quote(): """Test detection of cursor inside single-quoted string.""" line = "style('error')" in_string, quote_char = is_in_string(line, 10) # Inside 'error' assert in_string is True assert quote_char == "'" def test_i_cannot_detect_string_outside_quotes(): """Test that cursor outside quotes is not detected as in string.""" line = 'style("error")' in_string, quote_char = is_in_string(line, 3) # In "style" assert in_string is False assert quote_char is None def test_i_cannot_detect_string_after_closing_quote(): """Test that cursor after closing quote is not in string.""" line = '"text" other' in_string, quote_char = is_in_string(line, 8) assert in_string is False assert quote_char is None # ============================================================================= # Indentation Tests # ============================================================================= def test_i_can_get_indentation_spaces(): """Test that spaces are counted correctly.""" line = " text" assert get_indentation(line) == 4 def test_i_can_get_indentation_tabs(): """Test that tabs are converted to 4 spaces.""" line = "\ttext" assert get_indentation(line) == 4 def test_i_can_get_indentation_mixed(): """Test mixed spaces and tabs.""" line = " \t text" # 2 spaces + tab (4) + 2 spaces = 8 assert get_indentation(line) == 8 def test_i_can_detect_indented_line(): """Test that indented line is detected.""" assert is_indented(" text") is True assert is_indented("\ttext") is True def test_i_cannot_detect_indented_for_non_indented(): """Test that non-indented line is not detected as indented.""" assert is_indented("text") is False def test_i_cannot_detect_indented_for_empty_line(): """Test that empty line is not detected as indented.""" assert is_indented("") is False # ============================================================================= # Quote Stripping Tests # ============================================================================= def test_i_can_strip_quotes_double(): """Test stripping double quotes.""" assert strip_quotes('"text"') == "text" def test_i_can_strip_quotes_single(): """Test stripping single quotes.""" assert strip_quotes("'text'") == "text" def test_i_cannot_strip_quotes_unquoted(): """Test that unquoted text is returned unchanged.""" assert strip_quotes("text") == "text" def test_i_cannot_strip_quotes_mismatched(): """Test that mismatched quotes are not stripped.""" assert strip_quotes('"text\'') == '"text\'' assert strip_quotes("'text\"") == "'text\"" def test_i_cannot_strip_quotes_too_short(): """Test that text shorter than 2 chars is returned unchanged.""" assert strip_quotes('"') == '"' assert strip_quotes("") == ""