from selectui import SelectItem, SelectUI class TestSelectUIInitialization: """Test SelectUI initialization.""" def test_init_with_dict_items(self, sample_items): """Test initialization with dictionary items.""" app = SelectUI(items=sample_items) assert len(app.items) == 4 assert app.items[0]["title"] == "Python" assert app.oneshot is False assert app.fuzzy_search is False assert app.case_sensitive is False def test_init_with_pydantic_items(self): """Test initialization with SelectItem instances.""" items = [ SelectItem(title="Python", subtitle="Language"), SelectItem(title="Rust", subtitle="Systems"), ] app = SelectUI(items=items) assert len(app.items) == 2 assert app.items[0]["title"] == "Python" def test_init_empty(self): """Test initialization with no items.""" app = SelectUI() assert app.items == [] assert app.filtered_items == [] def test_init_with_oneshot(self, sample_items): """Test initialization with oneshot mode.""" app = SelectUI(items=sample_items, oneshot=True) assert app.oneshot is True def test_init_with_custom_keys(self, sample_items): """Test initialization with custom key configuration.""" app = SelectUI( items=sample_items, title_key="name", subtitle_key="desc", info_key="year" ) assert app.title_key == "name" assert app.subtitle_key == "desc" assert app.info_key == "year" def test_init_with_events_mode(self, sample_items): """Test initialization with events mode.""" app = SelectUI(items=sample_items, events_mode=True) assert app.events_mode is True def test_init_with_command_template(self): """Test initialization with command template.""" app = SelectUI(command_template="echo {}") assert app.command_template == "echo {}" assert app.input_mode is True class TestSelectUIFiltering: """Test SelectUI filtering functionality.""" def test_filter_items_exact_match(self, sample_items): """Test exact string filtering.""" app = SelectUI(items=sample_items) app.fuzzy_search = False app.case_sensitive = False # Simulate filtering for "python" filtered = [] query = "python" for item in app.items: title = str(item.get("title", "")).lower() subtitle = str(item.get("subtitle", "")).lower() if query in title or query in subtitle: filtered.append(item) assert len(filtered) == 1 assert filtered[0]["title"] == "Python" def test_filter_items_case_sensitive(self, sample_items): """Test case-sensitive filtering.""" app = SelectUI(items=sample_items) # Lowercase query should not match "Python" in case-sensitive mode filtered = [] query = "python" for item in app.items: title = str(item.get("title", "")) subtitle = str(item.get("subtitle", "")) if query in title or query in subtitle: filtered.append(item) assert len(filtered) == 0 # Correct case should match filtered = [] query = "Python" for item in app.items: title = str(item.get("title", "")) subtitle = str(item.get("subtitle", "")) if query in title or query in subtitle: filtered.append(item) assert len(filtered) == 1 def test_filter_by_subtitle(self, sample_items): """Test filtering by subtitle.""" app = SelectUI(items=sample_items) filtered = [] query = "language" for item in app.items: title = str(item.get("title", "")).lower() subtitle = str(item.get("subtitle", "")).lower() if query in title or query in subtitle: filtered.append(item) assert len(filtered) == 4 # All items have "language" in subtitle class TestSelectUINormalization: """Test item normalization in SelectUI.""" def test_normalize_dict_items(self, sample_items): """Test that dict items are normalized correctly.""" app = SelectUI(items=sample_items) assert isinstance(app.items, list) assert all(isinstance(item, dict) for item in app.items) def test_normalize_pydantic_items(self): """Test that Pydantic items are converted to dicts.""" items = [ SelectItem(title="Python", subtitle="Language", info="1991"), SelectItem(title="Rust", subtitle="Systems", info="2010"), ] app = SelectUI(items=items) assert isinstance(app.items, list) assert all(isinstance(item, dict) for item in app.items) assert app.items[0]["title"] == "Python" assert app.items[1]["title"] == "Rust" def test_normalize_with_custom_keys(self): """Test normalization preserves custom key mappings.""" items = [ SelectItem(title="Alice", subtitle="Engineer", info="Backend"), ] app = SelectUI( items=items, title_key="name", subtitle_key="role", info_key="team" ) # Should have both standard and custom keys assert app.items[0]["title"] == "Alice" assert app.items[0]["name"] == "Alice" assert app.items[0]["subtitle"] == "Engineer" assert app.items[0]["role"] == "Engineer" class TestSelectUIState: """Test SelectUI state management.""" def test_initial_state(self, sample_items): """Test initial state after initialization.""" app = SelectUI(items=sample_items) assert app.selected_item is None assert app.fuzzy_search is False assert app.case_sensitive is False assert app._stream_complete is False assert app._refresh_timer_running is False def test_filtered_items_initial(self, sample_items): """Test that filtered_items initially equals items.""" app = SelectUI(items=sample_items) assert app.filtered_items == app.items def test_command_mode_state(self): """Test state in command mode.""" app = SelectUI(command_template="echo {}") assert app.input_mode is True assert app.command_template == "echo {}" assert app._command_running is False def test_stdin_mode_state(self): """Test state when stdin_fd is not provided.""" app = SelectUI() assert app.stdin_fd is None assert app._stream_complete is False class TestSelectUIEdgeCases: """Test edge cases and error handling.""" def test_empty_items_list(self): """Test with empty items list.""" app = SelectUI(items=[]) assert app.items == [] assert app.filtered_items == [] def test_none_items(self): """Test with None items.""" app = SelectUI(items=None) assert app.items == [] assert app.filtered_items == [] def test_items_without_required_keys(self): """Test items missing title key.""" items = [{"name": "Test"}] # Missing 'title' key app = SelectUI(items=items, title_key="name") assert len(app.items) == 1 def test_mixed_item_types(self): """Test that dict items work after Pydantic items.""" pydantic_items = [SelectItem(title="A")] dict_items = [{"title": "B"}] app1 = SelectUI(items=pydantic_items) app2 = SelectUI(items=dict_items) assert app1.items[0]["title"] == "A" assert app2.items[0]["title"] == "B" class TestSelectUICustomKeys: """Test custom key configuration.""" def test_custom_title_key(self, custom_key_items): """Test using custom title key.""" app = SelectUI(items=custom_key_items, title_key="name") assert app.title_key == "name" def test_custom_subtitle_key(self, custom_key_items): """Test using custom subtitle key.""" app = SelectUI(items=custom_key_items, subtitle_key="role") assert app.subtitle_key == "role" def test_custom_info_key(self, custom_key_items): """Test using custom info key.""" app = SelectUI(items=custom_key_items, info_key="team") assert app.info_key == "team" def test_no_subtitle_key(self, single_line_items): """Test with subtitle_key=None for single-line display.""" app = SelectUI(items=single_line_items, subtitle_key=None) assert app.subtitle_key is None