""" Unit tests for tab completion system. """ import pytest from unittest.mock import MagicMock, patch from terminal_client.completions import CompletionHelper, GameREPLCompletions class TestCompletionHelper: """Tests for CompletionHelper utility class.""" def test_filter_completions_exact_match(self): """Test filtering with exact match.""" options = ['apple', 'apricot', 'banana'] result = CompletionHelper.filter_completions('appl', options) assert result == ['apple'] def test_filter_completions_no_match(self): """Test filtering with no matches.""" options = ['apple', 'apricot', 'banana'] result = CompletionHelper.filter_completions('cherry', options) assert result == [] def test_filter_completions_empty_text(self): """Test filtering with empty text returns all.""" options = ['apple', 'apricot', 'banana'] result = CompletionHelper.filter_completions('', options) assert result == options def test_complete_option_with_prefix(self): """Test completing option with -- prefix.""" available = ['league', 'home-team', 'away-team'] result = CompletionHelper.complete_option('--le', 'cmd --le', available) assert result == ['--league'] def test_complete_option_partial_match(self): """Test completing option with partial match.""" available = ['league', 'home-team', 'away-team'] result = CompletionHelper.complete_option('--ho', 'cmd --ho', available) assert result == ['--home-team'] def test_complete_option_show_all(self): """Test showing all options when text is empty.""" available = ['league', 'home-team'] result = CompletionHelper.complete_option('', 'cmd ', available) assert set(result) == {'--league', '--home-team'} def test_complete_option_no_match(self): """Test completing option with no match.""" available = ['league', 'home-team'] result = CompletionHelper.complete_option('--invalid', 'cmd --invalid', available) assert result == [] def test_get_current_option_simple(self): """Test getting current option from simple line.""" line = 'defensive --alignment ' result = CompletionHelper.get_current_option(line, len(line)) assert result == 'alignment' def test_get_current_option_multiple(self): """Test getting current option with multiple options.""" line = 'defensive --infield normal --alignment ' result = CompletionHelper.get_current_option(line, len(line)) assert result == 'alignment' def test_get_current_option_none(self): """Test getting current option when none present.""" line = 'defensive ' result = CompletionHelper.get_current_option(line, len(line)) assert result is None def test_get_current_option_hyphen_to_underscore(self): """Test option name converts hyphens to underscores.""" line = 'new_game --home-team ' result = CompletionHelper.get_current_option(line, len(line)) assert result == 'home_team' def test_get_current_option_mid_line(self): """Test getting current option when cursor is mid-line.""" line = 'defensive --alignment normal --hold ' result = CompletionHelper.get_current_option(line, len('defensive --alignment ')) assert result == 'alignment' class TestGameREPLCompletions: """Tests for GameREPLCompletions mixin.""" @pytest.fixture def repl_completions(self): """Create GameREPLCompletions instance.""" return GameREPLCompletions() def test_complete_new_game_options(self, repl_completions): """Test completing new_game options.""" result = repl_completions.complete_new_game( '--', 'new_game --', 9, 11 ) assert '--league' in result assert '--home-team' in result assert '--away-team' in result def test_complete_new_game_option_partial(self, repl_completions): """Test completing new_game option with partial match.""" result = repl_completions.complete_new_game( '--ho', 'new_game --ho', 9, 13 ) assert '--home-team' in result assert '--away-team' not in result def test_complete_new_game_league_value(self, repl_completions): """Test completing league value.""" result = repl_completions.complete_new_game( 's', 'new_game --league s', 9, 20 ) assert 'sba' in result assert 'pd' not in result def test_complete_new_game_league_all_values(self, repl_completions): """Test showing all league values.""" result = repl_completions.complete_new_game( '', 'new_game --league ', 0, 19 ) assert 'sba' in result assert 'pd' in result def test_complete_defensive_options(self, repl_completions): """Test completing defensive options.""" result = repl_completions.complete_defensive( '--', 'defensive --', 10, 12 ) assert '--alignment' in result assert '--infield' in result assert '--outfield' in result assert '--hold' in result def test_complete_defensive_alignment(self, repl_completions): """Test completing defensive alignment values.""" result = repl_completions.complete_defensive( 'shift', 'defensive --alignment shift', 10, 30 ) assert 'shifted_left' in result assert 'shifted_right' in result assert 'normal' not in result def test_complete_defensive_alignment_all(self, repl_completions): """Test showing all defensive alignment values.""" result = repl_completions.complete_defensive( '', 'defensive --alignment ', 0, 24 ) assert 'normal' in result assert 'shifted_left' in result assert 'shifted_right' in result assert 'extreme_shift' in result def test_complete_defensive_infield(self, repl_completions): """Test completing defensive infield values.""" result = repl_completions.complete_defensive( 'dou', 'defensive --infield dou', 10, 25 ) assert 'double_play' in result assert 'normal' not in result def test_complete_defensive_hold_bases(self, repl_completions): """Test completing hold bases.""" result = repl_completions.complete_defensive( '1,', 'defensive --hold 1,', 10, 19 ) assert '1,2' in result assert '1,3' in result def test_complete_defensive_hold_first_base(self, repl_completions): """Test completing first hold base.""" result = repl_completions.complete_defensive( '', 'defensive --hold ', 0, 17 ) assert '1' in result assert '2' in result assert '3' in result def test_complete_offensive_options(self, repl_completions): """Test completing offensive options.""" result = repl_completions.complete_offensive( '--', 'offensive --', 10, 12 ) assert '--approach' in result assert '--steal' in result assert '--hit-run' in result assert '--bunt' in result def test_complete_offensive_approach(self, repl_completions): """Test completing offensive approach values.""" result = repl_completions.complete_offensive( 'p', 'offensive --approach p', 10, 22 ) assert 'power' in result assert 'patient' in result assert 'normal' not in result def test_complete_offensive_approach_all(self, repl_completions): """Test showing all offensive approach values.""" result = repl_completions.complete_offensive( '', 'offensive --approach ', 0, 21 ) assert 'normal' in result assert 'contact' in result assert 'power' in result assert 'patient' in result def test_complete_offensive_steal_bases(self, repl_completions): """Test completing steal bases.""" result = repl_completions.complete_offensive( '', 'offensive --steal ', 0, 18 ) assert '2' in result assert '3' in result assert '1' not in result # Can't steal first def test_complete_offensive_steal_multiple(self, repl_completions): """Test completing multiple steal bases.""" result = repl_completions.complete_offensive( '2,', 'offensive --steal 2,', 10, 20 ) assert '2,3' in result def test_complete_quick_play_counts(self, repl_completions): """Test completing quick_play with common counts.""" result = repl_completions.complete_quick_play( '1', 'quick_play 1', 11, 12 ) assert '1' in result assert '10' in result assert '100' in result def test_complete_quick_play_all_counts(self, repl_completions): """Test showing all quick_play counts.""" result = repl_completions.complete_quick_play( '', 'quick_play ', 11, 11 ) assert '1' in result assert '5' in result assert '10' in result assert '27' in result assert '50' in result assert '100' in result @patch('app.core.state_manager.state_manager') def test_complete_use_game_with_games(self, mock_sm, repl_completions): """Test completing use_game with active games.""" from uuid import uuid4 game_id1 = uuid4() game_id2 = uuid4() mock_sm.list_games.return_value = [game_id1, game_id2] result = repl_completions.complete_use_game( str(game_id1)[:8], f'use_game {str(game_id1)[:8]}', 9, 17 ) # Should return the matching game ID assert any(str(game_id1) in r for r in result) @patch('app.core.state_manager.state_manager') def test_complete_use_game_no_games(self, mock_sm, repl_completions): """Test completing use_game with no active games.""" mock_sm.list_games.return_value = [] result = repl_completions.complete_use_game( '', 'use_game ', 9, 9 ) assert result == [] def test_completedefault_with_option(self, repl_completions): """Test default completion with option prefix.""" result = repl_completions.completedefault( '--', 'some_cmd --', 9, 11 ) assert '--help' in result assert '--verbose' in result assert '--debug' in result def test_completedefault_without_option(self, repl_completions): """Test default completion without option prefix.""" result = repl_completions.completedefault( 'text', 'some_cmd text', 9, 13 ) assert result == [] def test_completenames_partial_command(self, repl_completions): """Test completing command name with partial text.""" # Mock get_names to return command list repl_completions.get_names = lambda: ['do_new_game', 'do_defensive', 'do_offensive'] result = repl_completions.completenames('new', None) assert 'new_game' in result def test_completenames_with_aliases(self, repl_completions): """Test completing command name includes aliases.""" repl_completions.get_names = lambda: ['do_quit'] result = repl_completions.completenames('q', None) assert 'quit' in result def test_completenames_exit_alias(self, repl_completions): """Test completing command name includes exit alias.""" repl_completions.get_names = lambda: ['do_exit'] result = repl_completions.completenames('ex', None) assert 'exit' in result