From ed235136ad61f27ba327301416cc10900c8ecda2 Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Thu, 3 Jul 2025 15:16:27 -0400 Subject: [PATCH] Add search_entries method and tests --- src/password_manager/entry_management.py | 43 ++++++++++++++++++++++++ src/tests/test_search_entries.py | 42 +++++++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 src/tests/test_search_entries.py diff --git a/src/password_manager/entry_management.py b/src/password_manager/entry_management.py index e526b44..713d3e3 100644 --- a/src/password_manager/entry_management.py +++ b/src/password_manager/entry_management.py @@ -449,6 +449,49 @@ class EntryManager: print(colored(f"Error: Failed to list entries: {e}", "red")) return [] + def search_entries( + self, query: str + ) -> List[Tuple[int, str, Optional[str], Optional[str], bool]]: + """Return entries matching the query across common fields.""" + data = self.vault.load_index() + entries_data = data.get("entries", {}) + + if not entries_data: + return [] + + query_lower = query.lower() + results: List[Tuple[int, str, Optional[str], Optional[str], bool]] = [] + + for idx, entry in sorted(entries_data.items(), key=lambda x: int(x[0])): + etype = entry.get("type", EntryType.PASSWORD.value) + if etype == EntryType.TOTP.value: + label = entry.get("label", "") + notes = entry.get("notes", "") + if query_lower in label.lower() or query_lower in notes.lower(): + results.append((int(idx), label, None, None, False)) + else: + website = entry.get("website", "") + username = entry.get("username", "") + url = entry.get("url", "") + notes = entry.get("notes", "") + if ( + query_lower in website.lower() + or query_lower in username.lower() + or query_lower in url.lower() + or query_lower in notes.lower() + ): + results.append( + ( + int(idx), + website, + username, + url, + entry.get("blacklisted", False), + ) + ) + + return results + def delete_entry(self, index: int) -> None: """ Deletes an entry based on the provided index. diff --git a/src/tests/test_search_entries.py b/src/tests/test_search_entries.py new file mode 100644 index 0000000..9daa228 --- /dev/null +++ b/src/tests/test_search_entries.py @@ -0,0 +1,42 @@ +import sys +from pathlib import Path +from tempfile import TemporaryDirectory + +from helpers import create_vault, TEST_SEED, TEST_PASSWORD + +sys.path.append(str(Path(__file__).resolve().parents[1])) + +from password_manager.entry_management import EntryManager +from password_manager.backup import BackupManager +from password_manager.config_manager import ConfigManager + + +def setup_entry_manager(tmp_path: Path) -> EntryManager: + vault, _ = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + cfg_mgr = ConfigManager(vault, tmp_path) + backup_mgr = BackupManager(tmp_path, cfg_mgr) + return EntryManager(vault, backup_mgr) + + +def test_search_by_website(): + with TemporaryDirectory() as tmpdir: + tmp_path = Path(tmpdir) + entry_mgr = setup_entry_manager(tmp_path) + + idx0 = entry_mgr.add_entry("Example.com", 12, "alice") + entry_mgr.add_entry("Other.com", 8, "bob") + + result = entry_mgr.search_entries("example") + assert result == [(idx0, "Example.com", "alice", "", False)] + + +def test_search_by_username(): + with TemporaryDirectory() as tmpdir: + tmp_path = Path(tmpdir) + entry_mgr = setup_entry_manager(tmp_path) + + entry_mgr.add_entry("Example.com", 12, "alice") + idx1 = entry_mgr.add_entry("Test.com", 8, "Bob") + + result = entry_mgr.search_entries("bob") + assert result == [(idx1, "Test.com", "Bob", "", False)]