dcs_liberation/tests/persistence/test_savemanager.py
Dan Albert bc0dacf974 Fix saving of saves from other machines.
Need to reset the persisted save paths on load, since the file that was
loaded may have been moved since it was saved and the original location
may no longer be accessible.

Fixes https://github.com/dcs-liberation/dcs_liberation/issues/2756.
2023-03-13 19:41:28 -07:00

180 lines
6.3 KiB
Python

import datetime
from pathlib import Path
from unittest.mock import Mock
import pytest
from pytest_mock import MockerFixture
from game import Game
from game.persistence import SaveManager, set_dcs_save_game_directory
@pytest.fixture(autouse=True)
def mock_setup_last_save_file(mocker: MockerFixture) -> Mock:
return mocker.patch("qt_ui.liberation_install.setup_last_save_file")
@pytest.fixture(autouse=True)
def mock_save_config(mocker: MockerFixture) -> Mock:
return mocker.patch("qt_ui.liberation_install.save_config")
@pytest.fixture(autouse=True)
def setup_persistence_paths(tmp_path: Path) -> None:
set_dcs_save_game_directory(tmp_path)
@pytest.fixture
def save_manager(game: Game) -> SaveManager:
return game.save_manager
def test_new_savemanager_saves_to_autosave(save_manager: SaveManager) -> None:
assert save_manager.default_save_location == save_manager.autosave_path
def test_savemanager_saves_to_last_save_location(save_manager: SaveManager) -> None:
save_manager.player_save_location = Path("Saves/foo.liberation.zip")
assert save_manager.default_save_location == save_manager.player_save_location
def test_saving_without_name_saves_to_autosave_path(save_manager: SaveManager) -> None:
assert not save_manager.autosave_path.exists()
save_manager.save_player()
assert save_manager.autosave_path.exists()
def test_saving_with_name_updates_last_save_location(
save_manager: SaveManager, tmp_path: Path
) -> None:
save_path = tmp_path / "foo.liberation.zip"
assert not save_path.exists()
save_manager.save_player(override_destination=save_path)
assert save_path.exists()
assert save_manager.last_saved_bundle is not None
assert save_manager.last_saved_bundle.bundle_path == save_path
def test_player_save_location(save_manager: SaveManager, tmp_path: Path) -> None:
assert save_manager.player_save_location is None
save_manager.save_last_turn()
assert save_manager.player_save_location is None
save_manager.save_start_of_turn()
assert save_manager.player_save_location is None
expect_location = tmp_path / "player.liberation.zip"
save_manager.save_player(override_destination=expect_location)
assert save_manager.player_save_location == expect_location
def test_saving_updates_preferences_with_save_location(
save_manager: SaveManager, mock_setup_last_save_file: Mock, mock_save_config: Mock
) -> None:
save_manager.save_player()
mock_setup_last_save_file.assert_called_once_with(
str(save_manager.default_save_location)
)
mock_save_config.assert_called_once()
def test_non_player_saves_do_not_update_preferences(
save_manager: SaveManager, mock_setup_last_save_file: Mock
) -> None:
save_manager.save_last_turn()
mock_setup_last_save_file.assert_not_called()
save_manager.save_start_of_turn()
mock_setup_last_save_file.assert_not_called()
def test_load_game_loads_correct_data(save_manager: SaveManager) -> None:
test_date = datetime.date.today()
assert save_manager.game.date != test_date
save_manager.game.date = test_date
save_manager.save_player()
game = SaveManager.load_player_save(save_manager.default_save_location)
assert game.date == test_date
def test_loading_missing_save_raises() -> None:
with pytest.raises(FileNotFoundError):
SaveManager.load_player_save(Path("does not exist"))
def test_saving_after_autosave_copies_autosave_members(
save_manager: SaveManager, tmp_path: Path
) -> None:
save_manager.save_start_of_turn()
save_path = tmp_path / "foo.liberation.zip"
save_manager.save_player(override_destination=save_path)
SaveManager.load_start_of_turn(save_path)
def test_failed_save_does_not_update_last_saved_path(
save_manager: SaveManager, tmp_path: Path
) -> None:
expect_date = datetime.date.today()
save_manager.game.date = expect_date
save_manager.save_player()
assert save_manager.last_saved_bundle is not None
expect_path = save_manager.last_saved_bundle.bundle_path
# Add some non-pickleable member to the game to cause an error on save.
def local_f() -> None:
pass
save_manager.game.garbage = local_f # type: ignore
with pytest.raises(AttributeError):
save_manager.save_player(
override_destination=tmp_path / "badsave.liberation.zip"
)
assert save_manager.last_saved_bundle.bundle_path == expect_path
def test_load_reads_correct_data(save_manager: SaveManager) -> None:
last_turn_date = datetime.date.today() - datetime.timedelta(days=2)
save_manager.game.date = last_turn_date
save_manager.save_last_turn()
start_of_turn_date = datetime.date.today() - datetime.timedelta(days=1)
save_manager.game.date = start_of_turn_date
save_manager.save_start_of_turn()
player_date = datetime.date.today()
save_manager.game.date = player_date
save_manager.save_player()
assert save_manager.last_saved_bundle is not None
bundle_path = save_manager.last_saved_bundle.bundle_path
assert SaveManager.load_last_turn(bundle_path).date == last_turn_date
assert SaveManager.load_start_of_turn(bundle_path).date == start_of_turn_date
assert SaveManager.load_player_save(bundle_path).date == player_date
def test_save_after_loading_foreign_save(
save_manager: SaveManager, tmp_path: Path
) -> None:
"""Tests that we can save games that were copied from another machine.
Regression test for https://github.com/dcs-liberation/dcs_liberation/issues/2756.
"""
# To simulate the situation from the bug, we save a game to a directory, move it out
# of that directory, delete the directory, then attempt to load and save the game.
# It should save to the new location. If it tries to save to the old location, it
# will fail because the directory does not exist.
# Create the save on "the other machine"...
bad_directory = tmp_path / "other-machine"
bad_directory.mkdir()
bad_save_path = bad_directory / "foo.liberation.zip"
save_manager.save_player(override_destination=bad_save_path)
good_save_path = tmp_path / "foo.liberation.zip"
bad_save_path.rename(good_save_path)
bad_directory.rmdir()
game = SaveManager.load_player_save(good_save_path)
assert game.save_manager.player_save_location == good_save_path
game.save_manager.save_player()