summaryrefslogtreecommitdiff
path: root/tests/test_backend.py
blob: fafee68e8628912399818da463723cffe89fa365 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import sys
import tempfile
import unittest
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "py_modules"))

from services import config
from services.bundle import BundleManager
from services.patcher import PatchManager
from services.steam import SteamLibrary


class BackendSafetyTests(unittest.TestCase):
    def setUp(self):
        self.temp_dir = tempfile.TemporaryDirectory()
        root = Path(self.temp_dir.name)
        self.home = root / "home"
        self.plugin_dir = root / "plugin"
        self.home.mkdir()
        self.plugin_dir.mkdir()

        bundle_path = self.home / "fgmod"
        (bundle_path / "renames").mkdir(parents=True)
        (bundle_path / "plugins").mkdir()
        (bundle_path / "fsr4-rdna2-3").mkdir()
        (bundle_path / "OptiScaler.dll").write_bytes(b"optiscaler")
        (bundle_path / "renames" / "dxgi.dll").write_bytes(b"managed-proxy")
        (bundle_path / "OptiScaler.ini").write_text("FGInput=auto\nFGOutput=auto\n", encoding="utf-8")
        (bundle_path / "plugins" / "OptiPatcher.asi").write_bytes(b"plugin")
        (bundle_path / "fsr4-rdna2-3" / "amd_fidelityfx_upscaler_dx12.dll").write_bytes(b"upscaler")

        logger = lambda _message: None
        bundle = BundleManager(self.home, self.plugin_dir, logger)
        self.manager = PatchManager(self.home, bundle, SteamLibrary(self.home, logger), logger)
        self.target = root / "game"
        (self.target / "plugins").mkdir(parents=True)
        (self.target / "plugins" / "keep.txt").write_text("user-owned", encoding="utf-8")
        (self.target / "dxgi.dll").write_bytes(b"original-game-proxy")
        (self.target / "OptiScaler.ini").write_text("FGInput=auto\nFGOutput=auto\nUserSetting=true\n", encoding="utf-8")

    def tearDown(self):
        self.temp_dir.cleanup()

    def test_patch_and_unpatch_preserve_unowned_files(self):
        result = self.manager.manual_patch_directory(str(self.target), "dxgi.dll", "rdna23-int8", "auto")
        self.assertEqual(result["status"], "success")
        self.assertTrue((self.target / "FRAMEGEN_PATCH").exists())
        self.assertTrue((self.target / "dxgi.dll.b").exists())
        self.assertTrue((self.target / "plugins" / "keep.txt").exists())

        cleanup = self.manager.manual_unpatch_directory(str(self.target))
        self.assertEqual(cleanup["status"], "success")
        self.assertFalse((self.target / "FRAMEGEN_PATCH").exists())
        self.assertEqual((self.target / "dxgi.dll").read_bytes(), b"original-game-proxy")
        self.assertEqual((self.target / "plugins" / "keep.txt").read_text(encoding="utf-8"), "user-owned")
        self.assertEqual(
            (self.target / "OptiScaler.ini").read_text(encoding="utf-8"),
            "FGInput=auto\nFGOutput=auto\nUserSetting=true\n",
        )
        self.assertFalse((self.target / "plugins" / "OptiPatcher.asi").exists())

    def test_unpatch_refuses_modified_managed_file_and_keeps_marker(self):
        result = self.manager.manual_patch_directory(str(self.target), "dxgi.dll", "rdna23-int8", "nukems")
        self.assertEqual(result["status"], "success")
        (self.target / "dxgi.dll").write_bytes(b"user-modified")

        cleanup = self.manager.manual_unpatch_directory(str(self.target))
        self.assertEqual(cleanup["status"], "error")
        self.assertTrue((self.target / "FRAMEGEN_PATCH").exists())
        self.assertEqual((self.target / "dxgi.dll").read_bytes(), b"user-modified")
        self.assertTrue((self.target / "plugins" / "keep.txt").exists())

    def test_appid_unpatch_propagates_cleanup_failure(self):
        class FakeSteam:
            def game_record(self, appid):
                return {"appid": appid, "name": "Test Game", "install_path": str(self_target)}

            def is_game_running(self, _game_info):
                return False

            def guess_patch_target(self, _game_info):
                return self_target, None

        self_target = self.target
        self.manager.steam = FakeSteam()
        result = self.manager.patch_game("123", "dxgi.dll", "", "rdna23-int8", "auto")
        self.assertEqual(result["status"], "success")
        (self.target / "dxgi.dll").write_bytes(b"modified after patch")

        cleanup = self.manager.unpatch_game("123")
        self.assertEqual(cleanup["status"], "error")
        self.assertTrue((self.target / "FRAMEGEN_PATCH").exists())

    def test_backend_configuration_is_explicit(self):
        ini_file = self.target / "backend.ini"
        ini_file.write_text("FGInput=auto\nFGOutput=auto\n", encoding="utf-8")
        self.assertTrue(config.configure(ini_file, "nukems"))
        self.assertIn("FGInput=nukems", ini_file.read_text(encoding="utf-8"))
        self.assertIn("FGOutput=nukems", ini_file.read_text(encoding="utf-8"))
        self.assertTrue(config.configure(ini_file, "auto"))
        self.assertIn("FGInput=auto", ini_file.read_text(encoding="utf-8"))
        self.assertIn("FGOutput=auto", ini_file.read_text(encoding="utf-8"))


if __name__ == "__main__":
    unittest.main()