from thefuzz import fuzz class TestExactFiltering: """Test exact string matching.""" def test_filter_by_title_case_insensitive(self, sample_items): """Test filtering by title (case insensitive).""" query = "python" filtered = [] for item in sample_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_by_subtitle(self, sample_items): """Test filtering by subtitle.""" query = "web" filtered = [] for item in sample_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"] == "JavaScript" def test_filter_no_matches(self, sample_items): """Test filtering with no matches.""" query = "nonexistent" filtered = [] for item in sample_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) == 0 def test_filter_all_match(self, sample_items): """Test filtering that matches all items.""" query = "language" filtered = [] for item in sample_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 def test_filter_partial_match(self, sample_items): """Test partial string matching.""" query = "rust" filtered = [] for item in sample_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"] == "Rust" class TestCaseSensitiveFiltering: """Test case-sensitive filtering.""" def test_case_sensitive_title_match(self, sample_items): """Test case-sensitive title matching.""" query = "Python" filtered = [] for item in sample_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 assert filtered[0]["title"] == "Python" def test_case_sensitive_no_match(self, sample_items): """Test case-sensitive no match.""" query = "python" # lowercase filtered = [] for item in sample_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 def test_case_sensitive_subtitle_match(self, sample_items): """Test case-sensitive subtitle matching.""" query = "Programming" filtered = [] for item in sample_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 class TestFuzzyFiltering: """Test fuzzy search functionality.""" def test_fuzzy_match_with_typo(self, sample_items): """Test fuzzy matching with a typo.""" query = "Pythn" # Missing 'o' filtered = [] for item in sample_items: title = str(item.get("title", "")) subtitle = str(item.get("subtitle", "")) title_score = fuzz.partial_ratio(query, title) subtitle_score = fuzz.partial_ratio(query, subtitle) if title_score > 60 or subtitle_score > 60: filtered.append(item) assert len(filtered) >= 1 assert any(item["title"] == "Python" for item in filtered) def test_fuzzy_match_partial(self, sample_items): """Test fuzzy partial matching.""" query = "Jav" filtered = [] for item in sample_items: title = str(item.get("title", "")) subtitle = str(item.get("subtitle", "")) title_score = fuzz.partial_ratio(query, title) subtitle_score = fuzz.partial_ratio(query, subtitle) if title_score > 60 or subtitle_score > 60: filtered.append(item) assert len(filtered) >= 1 assert any(item["title"] == "JavaScript" for item in filtered) def test_fuzzy_match_transposition(self, sample_items): """Test fuzzy match with character transposition.""" query = "Rsut" # Characters swapped filtered = [] for item in sample_items: title = str(item.get("title", "")) subtitle = str(item.get("subtitle", "")) title_score = fuzz.partial_ratio(query, title) subtitle_score = fuzz.partial_ratio(query, subtitle) if title_score > 60 or subtitle_score > 60: filtered.append(item) assert len(filtered) >= 1 assert any(item["title"] == "Rust" for item in filtered) def test_fuzzy_no_match(self, sample_items): """Test fuzzy search with no close matches.""" query = "xyz123" filtered = [] for item in sample_items: title = str(item.get("title", "")) subtitle = str(item.get("subtitle", "")) title_score = fuzz.partial_ratio(query, title) subtitle_score = fuzz.partial_ratio(query, subtitle) if title_score > 60 or subtitle_score > 60: filtered.append(item) assert len(filtered) == 0 class TestFilteringWithCustomKeys: """Test filtering with custom key configurations.""" def test_filter_custom_title_key(self, custom_key_items): """Test filtering with custom title key.""" query = "alice" filtered = [] title_key = "name" subtitle_key = "role" for item in custom_key_items: title = str(item.get(title_key, "")).lower() subtitle = str(item.get(subtitle_key, "")).lower() if query in title or query in subtitle: filtered.append(item) assert len(filtered) == 1 assert filtered[0]["name"] == "Alice" def test_filter_custom_subtitle_key(self, custom_key_items): """Test filtering with custom subtitle key.""" query = "engineer" filtered = [] title_key = "name" subtitle_key = "role" for item in custom_key_items: title = str(item.get(title_key, "")).lower() subtitle = str(item.get(subtitle_key, "")).lower() if query in title or query in subtitle: filtered.append(item) assert len(filtered) == 1 assert filtered[0]["role"] == "Engineer" def test_filter_no_subtitle_key(self, single_line_items): """Test filtering when subtitle_key is None.""" query = "config" filtered = [] title_key = "filename" for item in single_line_items: title = str(item.get(title_key, "")).lower() if query in title: filtered.append(item) assert len(filtered) == 1 assert filtered[0]["filename"] == "config.json" class TestEmptyQueryFiltering: """Test filtering with empty query.""" def test_empty_query_returns_all(self, sample_items): """Test that empty query returns all items.""" query = "" filtered = sample_items.copy() if not query else [] assert len(filtered) == len(sample_items) def test_whitespace_query(self, sample_items): """Test filtering with whitespace-only query.""" query = " " filtered = [] # Whitespace query should not match anything for item in sample_items: title = str(item.get("title", "")).lower() subtitle = str(item.get("subtitle", "")).lower() if query.strip() and (query.strip() in title or query.strip() in subtitle): filtered.append(item) assert len(filtered) == 0 class TestFilteringEdgeCases: """Test edge cases in filtering.""" def test_filter_with_missing_fields(self): """Test filtering when items are missing title/subtitle.""" items = [ {"other_field": "value"}, {"title": "Has Title"}, ] query = "title" filtered = [] for item in 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 def test_filter_with_numeric_values(self): """Test filtering with numeric values in fields.""" items = [ {"title": "Item 123", "subtitle": "Test"}, {"title": "Item 456", "subtitle": "Test"}, ] query = "123" filtered = [] for item in 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 def test_filter_special_characters(self): """Test filtering with special characters.""" items = [ {"title": "test@example.com", "subtitle": "Email"}, {"title": "user-name", "subtitle": "Username"}, ] query = "@" filtered = [] for item in 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 "@" in filtered[0]["title"]