"""Tests for bot version management.""" from pathlib import Path from typing import BinaryIO, TextIO from unittest.mock import patch import pytest from python_pkg.lichess_bot.utils import _version_file_path, get_and_increment_version def test_version_file_increments_and_persists( tmp_path: Path, monkeypatch: pytest.MonkeyPatch ) -> None: """Test that version increments and persists to file.""" version_file = tmp_path / "version.txt" monkeypatch.setenv("LICHESS_BOT_VERSION_FILE", str(version_file)) v1 = get_and_increment_version() v2 = get_and_increment_version() assert v1 == 1 assert v2 == 2 # Ensure it persisted with version_file.open() as f: assert f.read().strip() == "2" def test_version_file_path_uses_env_override( tmp_path: Path, monkeypatch: pytest.MonkeyPatch ) -> None: """Test _version_file_path uses environment variable when set.""" custom_path = str(tmp_path / "custom_version.txt") monkeypatch.setenv("LICHESS_BOT_VERSION_FILE", custom_path) result = _version_file_path() assert result == custom_path def test_version_file_path_default(monkeypatch: pytest.MonkeyPatch) -> None: """Test _version_file_path returns default when no env var.""" monkeypatch.delenv("LICHESS_BOT_VERSION_FILE", raising=False) result = _version_file_path() assert ".bot_version" in result def test_get_version_handles_missing_file( tmp_path: Path, monkeypatch: pytest.MonkeyPatch ) -> None: """Test get_and_increment_version handles missing file gracefully.""" version_file = tmp_path / "nonexistent" / "version.txt" monkeypatch.setenv("LICHESS_BOT_VERSION_FILE", str(version_file)) # The directory doesn't exist, but it should handle gracefully # First call should fail to read, start from 0, and return 1 v1 = get_and_increment_version() assert v1 == 1 def test_get_version_handles_invalid_content( tmp_path: Path, monkeypatch: pytest.MonkeyPatch ) -> None: """Test get_and_increment_version handles invalid file content.""" version_file = tmp_path / "version.txt" version_file.write_text("not_a_number") monkeypatch.setenv("LICHESS_BOT_VERSION_FILE", str(version_file)) # Should handle ValueError and treat as version 0 v1 = get_and_increment_version() assert v1 == 1 def test_get_version_handles_empty_file( tmp_path: Path, monkeypatch: pytest.MonkeyPatch ) -> None: """Test get_and_increment_version handles empty file.""" version_file = tmp_path / "version.txt" version_file.write_text("") monkeypatch.setenv("LICHESS_BOT_VERSION_FILE", str(version_file)) # Empty file should be treated as version 0 v1 = get_and_increment_version() assert v1 == 1 def test_get_version_handles_write_failure( tmp_path: Path, monkeypatch: pytest.MonkeyPatch ) -> None: """Test get_and_increment_version handles write failures.""" version_file = tmp_path / "version.txt" monkeypatch.setenv("LICHESS_BOT_VERSION_FILE", str(version_file)) # Make the parent directory read-only after first call v1 = get_and_increment_version() assert v1 == 1 # Mock to simulate write failure original_open = Path.open write_error_msg = "Simulated write failure" def failing_open( self: Path, mode: str = "r", *args: object, **kwargs: object ) -> TextIO | BinaryIO: if "w" in mode and str(self).endswith((".tmp", "version.txt")): raise OSError(write_error_msg) return original_open(self, mode, *args, **kwargs) with patch.object(Path, "open", failing_open): # Should still return incremented version even if write fails v2 = get_and_increment_version() assert v2 == 2 def test_get_version_fallback_direct_write( tmp_path: Path, monkeypatch: pytest.MonkeyPatch ) -> None: """Test fallback direct write when replace fails.""" version_file = tmp_path / "version.txt" monkeypatch.setenv("LICHESS_BOT_VERSION_FILE", str(version_file)) # Create initial version v1 = get_and_increment_version() assert v1 == 1 # Mock to make .replace() fail but direct write succeed original_replace = Path.replace replace_error_msg = "Simulated replace failure" def failing_replace(self: Path, target: Path) -> Path: if str(self).endswith(".tmp"): raise OSError(replace_error_msg) return original_replace(self, target) with patch.object(Path, "replace", failing_replace): v2 = get_and_increment_version() assert v2 == 2 # Version should still be written via fallback with version_file.open() as f: content = f.read().strip() assert content == "2"