"""Tests for navigation helper functions.""" import argparse from pathlib import Path import pytest import main @pytest.fixture def seeded_indexers(sample_files: dict[str, Path], tmp_path: Path) -> None: """Initialize with a fixed salt so hashes are predictable.""" args = argparse.Namespace( source=str(tmp_path), host="127.0.0.1", port=0, salt="nav-test-salt", password=None, ) main.initialize_server(args) class TestGetNavigationData: """Tests for _get_navigation_data.""" def test_returns_all_keys(self, seeded_indexers: None) -> None: """Navigation data contains all required keys.""" file_hash = list(main.file_mapping.keys())[0] data = main._get_navigation_data(file_hash, order=None) assert "file_hash" in data assert "next_hash" in data assert "prev_hash" in data assert "filename" in data def test_file_hash_matches_input(self, seeded_indexers: None) -> None: """Returned file_hash matches the input.""" file_hash = list(main.file_mapping.keys())[0] data = main._get_navigation_data(file_hash, order=None) assert data["file_hash"] == file_hash def test_sequential_next_and_prev(self, seeded_indexers: None) -> None: """In sequential mode, next and prev are adjacent in the list.""" keys = list(main.file_mapping.keys()) if len(keys) < 2: pytest.skip("Need at least 2 files for sequential navigation") file_hash = keys[0] data = main._get_navigation_data(file_hash, order=None) assert data["next_hash"] == keys[1] # First item's prev wraps to last assert data["prev_hash"] == keys[-1] def test_middle_item_navigation(self, seeded_indexers: None) -> None: """Middle item has correct prev and next.""" keys = list(main.file_mapping.keys()) if len(keys) < 3: pytest.skip("Need at least 3 files for middle-item test") mid_idx = len(keys) // 2 file_hash = keys[mid_idx] data = main._get_navigation_data(file_hash, order=None) assert data["next_hash"] == keys[mid_idx + 1] assert data["prev_hash"] == keys[mid_idx - 1] def test_last_item_wraps_next(self, seeded_indexers: None) -> None: """Last item's next wraps to the first item.""" keys = list(main.file_mapping.keys()) if len(keys) < 2: pytest.skip("Need at least 2 files for wrap test") file_hash = keys[-1] data = main._get_navigation_data(file_hash, order=None) assert data["next_hash"] == keys[0] def test_random_order_returns_different_hashes(self, seeded_indexers: None) -> None: """Random order returns hashes that may differ from current.""" keys = list(main.file_mapping.keys()) if len(keys) < 3: pytest.skip("Need at least 3 files for random test") file_hash = keys[0] data = main._get_navigation_data(file_hash, order="random") # next and prev should be random (not necessarily adjacent) assert data["next_hash"] in keys assert data["prev_hash"] in keys def test_filename_is_returned(self, seeded_indexers: None) -> None: """Filename is populated from the indexer.""" file_hash = list(main.file_mapping.keys())[0] data = main._get_navigation_data(file_hash, order=None) assert data["filename"] is not None assert isinstance(data["filename"], str) class TestGetRandomHash: """Tests for _get_random_hash.""" def test_returns_valid_hash(self, seeded_indexers: None) -> None: """Returns a hash that exists in the mapping.""" random_hash = main._get_random_hash() assert random_hash in main.file_mapping def test_raises_when_empty(self) -> None: """Raises HTTPException when no files are indexed.""" main.file_mapping.clear() with pytest.raises(main.HTTPException) as exc_info: main._get_random_hash() assert exc_info.value.status_code == 404 class TestFindIndexerForHash: """Tests for _find_indexer_for_hash.""" def test_finds_correct_indexer(self, seeded_indexers: None) -> None: """Returns the indexer containing the given hash.""" file_hash = list(main.file_mapping.keys())[0] indexer = main._find_indexer_for_hash(file_hash) assert indexer is not None assert file_hash in indexer._file_mapping def test_returns_none_for_unknown_hash(self, seeded_indexers: None) -> None: """Returns None for a hash not in any indexer.""" assert main._find_indexer_for_hash("nonexistent") is None def test_returns_none_when_no_indexers(self) -> None: """Returns None when no indexers are registered.""" main.indexers.clear() assert main._find_indexer_for_hash("any-hash") is None