"""Tests for RunnerUpVerificationMixin in _runnerup_verification.py.""" from __future__ import annotations import os from pathlib import Path import shutil from unittest.mock import MagicMock from screen_locker.tests.conftest import create_locker # Minimal valid TCX XML for a 40-minute, 6-km run. _TCX_RUNNING = """\ 2400.0 6000.0 """ # TCX with a non-running sport tag (Gym). _TCX_GYM = """\ 3600.0 0.0 """ # Two laps that together make a valid run. _TCX_MULTI_LAP = """\ 1200.0 3000.0 1200.0 3000.0 """ # --------------------------------------------------------------------------- # Helpers # --------------------------------------------------------------------------- def _write_tcx(tmp_path: Path, content: str, name: str = "activity.tcx") -> str: """Write TCX content to a temp file and return the path string.""" p = tmp_path / name p.write_text(content) return str(p) # --------------------------------------------------------------------------- # _validate_runnerup_data # --------------------------------------------------------------------------- class TestFindRunnerupPackage: """Tests for _find_runnerup_package (lines 256-260).""" def test_returns_none_when_no_package_found( self, mock_tk: MagicMock, mock_sys_exit: MagicMock, tmp_path: Path, ) -> None: """No package installed → None.""" locker = create_locker(mock_tk, tmp_path) object.__setattr__(locker, "_adb_shell", MagicMock(return_value=(True, ""))) assert locker._find_runnerup_package() is None def test_returns_first_installed_package( self, mock_tk: MagicMock, mock_sys_exit: MagicMock, tmp_path: Path, ) -> None: """First package found → returned.""" locker = create_locker(mock_tk, tmp_path) object.__setattr__( locker, "_adb_shell", MagicMock(return_value=(True, "package:org.runnerup")), ) result = locker._find_runnerup_package() assert result == "org.runnerup" # --------------------------------------------------------------------------- # _cleanup_runnerup_sdcard # --------------------------------------------------------------------------- class TestCleanupRunnerupSdcard: """Tests for _cleanup_runnerup_sdcard (lines 315-316).""" def test_calls_adb_shell_for_each_suffix( self, mock_tk: MagicMock, mock_sys_exit: MagicMock, tmp_path: Path, ) -> None: """Cleanup invokes _adb_shell for '', '-wal', '-shm'.""" locker = create_locker(mock_tk, tmp_path) mock_shell = MagicMock(return_value=(True, "")) object.__setattr__(locker, "_adb_shell", mock_shell) locker._cleanup_runnerup_sdcard() assert mock_shell.call_count == 3 # --------------------------------------------------------------------------- # _pull_runnerup_db # --------------------------------------------------------------------------- class TestPullRunnerupDb: """Tests for _pull_runnerup_db (lines 272-311).""" def test_returns_none_when_package_not_found( self, mock_tk: MagicMock, mock_sys_exit: MagicMock, tmp_path: Path, ) -> None: """No RunnerUp package installed → None.""" locker = create_locker(mock_tk, tmp_path) object.__setattr__( locker, "_find_runnerup_package", MagicMock(return_value=None) ) assert locker._pull_runnerup_db() is None def test_returns_none_when_cp_fails( self, mock_tk: MagicMock, mock_sys_exit: MagicMock, tmp_path: Path, ) -> None: """Root cp fails → None (cleanup still called).""" locker = create_locker(mock_tk, tmp_path) object.__setattr__( locker, "_find_runnerup_package", MagicMock(return_value="org.runnerup"), ) object.__setattr__( locker, "_adb_shell", MagicMock(return_value=(False, "permission denied")) ) assert locker._pull_runnerup_db() is None def test_returns_none_when_pull_fails( self, mock_tk: MagicMock, mock_sys_exit: MagicMock, tmp_path: Path, ) -> None: """cp succeeds but adb pull fails → None, cleanup called.""" locker = create_locker(mock_tk, tmp_path) object.__setattr__( locker, "_find_runnerup_package", MagicMock(return_value="org.runnerup"), ) object.__setattr__(locker, "_adb_shell", MagicMock(return_value=(True, ""))) object.__setattr__(locker, "_run_adb", MagicMock(return_value=(False, ""))) mock_cleanup = MagicMock() object.__setattr__(locker, "_cleanup_runnerup_sdcard", mock_cleanup) assert locker._pull_runnerup_db() is None mock_cleanup.assert_called() def test_returns_local_path_on_success( self, mock_tk: MagicMock, mock_sys_exit: MagicMock, tmp_path: Path, ) -> None: """Successful cp + pull + sidecar pulls → returns local db path string.""" locker = create_locker(mock_tk, tmp_path) # Create a placeholder db so _pull returns a real path. def _fake_run_adb(args: list[str]) -> tuple[bool, str]: if args[0] == "pull" and args[2].endswith(".db"): # Create the local file so the caller finds it. Path(args[2]).touch() return True, "" object.__setattr__( locker, "_find_runnerup_package", MagicMock(return_value="org.runnerup"), ) object.__setattr__(locker, "_adb_shell", MagicMock(return_value=(True, ""))) object.__setattr__(locker, "_run_adb", MagicMock(side_effect=_fake_run_adb)) object.__setattr__(locker, "_cleanup_runnerup_sdcard", MagicMock()) result = locker._pull_runnerup_db() assert result is not None assert result.endswith(".db") # Cleanup temp dir. if result and os.path.exists(result): shutil.rmtree(os.path.dirname(result), ignore_errors=True) # --------------------------------------------------------------------------- # _query_todays_run # ---------------------------------------------------------------------------