diff options
| author | xXJSONDeruloXx <danielhimebauch@gmail.com> | 2025-07-22 11:11:44 -0400 |
|---|---|---|
| committer | xXJSONDeruloXx <danielhimebauch@gmail.com> | 2025-07-22 11:11:44 -0400 |
| commit | c02343e68874efd57c2e312cb6b7e4f02222e43a (patch) | |
| tree | 31e7a46aca624de9eeb778f2337b2c0d9906b628 | |
| parent | 97bb41947bd44a712ad26905771a9d2cc4692878 (diff) | |
| download | decky-lsfg-vk-c02343e68874efd57c2e312cb6b7e4f02222e43a.tar.gz decky-lsfg-vk-c02343e68874efd57c2e312cb6b7e4f02222e43a.zip | |
add workaround env vars, rm old tests
| -rw-r--r-- | package.json | 2 | ||||
| -rw-r--r-- | py_modules/lsfg_vk/config_schema.py | 28 | ||||
| -rw-r--r-- | py_modules/lsfg_vk/configuration.py | 19 | ||||
| -rw-r--r-- | py_modules/lsfg_vk/plugin.py | 9 | ||||
| -rw-r--r-- | shared_config.py | 14 | ||||
| -rw-r--r-- | src/api/lsfgApi.ts | 4 | ||||
| -rw-r--r-- | src/components/ConfigurationSection.tsx | 18 | ||||
| -rw-r--r-- | src/config/configSchema.ts | 6 | ||||
| -rw-r--r-- | src/config/generatedConfigSchema.ts | 18 | ||||
| -rw-r--r-- | tests/conftest.py | 31 | ||||
| -rw-r--r-- | tests/test_configuration.py | 190 | ||||
| -rw-r--r-- | tests/test_dll_detection.py | 129 | ||||
| -rw-r--r-- | tests/test_installation.py | 150 |
13 files changed, 106 insertions, 512 deletions
diff --git a/package.json b/package.json index 9fcf10d..ee18530 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "decky-lossless-scaling-vk", - "version": "0.6.9", + "version": "0.6.10", "description": "Use Lossless Scaling on the Steam Deck using the lsfg-vk vulkan layer", "type": "module", "scripts": { diff --git a/py_modules/lsfg_vk/config_schema.py b/py_modules/lsfg_vk/config_schema.py index c82d1d3..6a68db1 100644 --- a/py_modules/lsfg_vk/config_schema.py +++ b/py_modules/lsfg_vk/config_schema.py @@ -73,6 +73,20 @@ SCRIPT_ONLY_FIELDS = { field_type=ConfigFieldType.BOOLEAN, default=False, description="disable Steam Deck mode (unlocks hidden settings in some games)" + ), + + "mangohud_workaround": ConfigField( + name="mangohud_workaround", + field_type=ConfigFieldType.BOOLEAN, + default=False, + description="Enables a transparent mangohud overlay, sometimes fixes issues with 2X multiplier in game mode" + ), + + "disable_vkbasalt": ConfigField( + name="disable_vkbasalt", + field_type=ConfigFieldType.BOOLEAN, + default=False, + description="Disables vkBasalt layer which can conflict with LSFG (Reshade, some Decky plugins)" ) } @@ -91,6 +105,8 @@ class ConfigurationData(TypedDict): dxvk_frame_rate: int enable_wow64: bool disable_steamdeck_mode: bool + mangohud_workaround: bool + disable_vkbasalt: bool class ConfigurationManager: @@ -335,6 +351,10 @@ class ConfigurationManager: script_values["enable_wow64"] = value == "1" elif key == "SteamDeck": script_values["disable_steamdeck_mode"] = value == "0" + elif key == "MANGOHUD": + script_values["mangohud_workaround"] = value == "1" + elif key == "DISABLE_VKBASALT": + script_values["disable_vkbasalt"] = value == "1" except (ValueError, KeyError, IndexError) as e: # If parsing fails, log the error and return empty dict (will use defaults) @@ -368,7 +388,9 @@ class ConfigurationManager: experimental_present_mode: str = "fifo", dxvk_frame_rate: int = 0, enable_wow64: bool = False, - disable_steamdeck_mode: bool = False) -> ConfigurationData: + disable_steamdeck_mode: bool = False, + mangohud_workaround: bool = False, + disable_vkbasalt: bool = False) -> ConfigurationData: """Create configuration from individual arguments""" return cast(ConfigurationData, { "dll": dll, @@ -379,5 +401,7 @@ class ConfigurationManager: "experimental_present_mode": experimental_present_mode, "dxvk_frame_rate": dxvk_frame_rate, "enable_wow64": enable_wow64, - "disable_steamdeck_mode": disable_steamdeck_mode + "disable_steamdeck_mode": disable_steamdeck_mode, + "mangohud_workaround": mangohud_workaround, + "disable_vkbasalt": disable_vkbasalt }) diff --git a/py_modules/lsfg_vk/configuration.py b/py_modules/lsfg_vk/configuration.py index 47d0ebc..82982e5 100644 --- a/py_modules/lsfg_vk/configuration.py +++ b/py_modules/lsfg_vk/configuration.py @@ -65,7 +65,9 @@ class ConfigurationService(BaseService): experimental_present_mode: str = "fifo", dxvk_frame_rate: int = 0, enable_wow64: bool = False, - disable_steamdeck_mode: bool = False) -> ConfigurationResponse: + disable_steamdeck_mode: bool = False, + mangohud_workaround: bool = False, + disable_vkbasalt: bool = False) -> ConfigurationResponse: """Update TOML configuration Args: @@ -78,6 +80,8 @@ class ConfigurationService(BaseService): dxvk_frame_rate: Frame rate cap for DirectX games, before frame multiplier (0 = disabled) enable_wow64: Whether to enable PROTON_USE_WOW64=1 for 32-bit games disable_steamdeck_mode: Whether to disable Steam Deck mode + mangohud_workaround: Whether to enable MangoHud workaround with transparent overlay + disable_vkbasalt: Whether to disable vkBasalt layer Returns: ConfigurationResponse with success status @@ -86,7 +90,8 @@ class ConfigurationService(BaseService): # Create configuration from individual arguments config = ConfigurationManager.create_config_from_args( dll, multiplier, flow_scale, performance_mode, hdr_mode, - experimental_present_mode, dxvk_frame_rate, enable_wow64, disable_steamdeck_mode + experimental_present_mode, dxvk_frame_rate, enable_wow64, disable_steamdeck_mode, + mangohud_workaround, disable_vkbasalt ) # Generate TOML content using centralized manager @@ -108,7 +113,8 @@ class ConfigurationService(BaseService): f"performance_mode={performance_mode}, hdr_mode={hdr_mode}, " f"experimental_present_mode='{experimental_present_mode}', " f"dxvk_frame_rate={dxvk_frame_rate}, " - f"enable_wow64={enable_wow64}, disable_steamdeck_mode={disable_steamdeck_mode}") + f"enable_wow64={enable_wow64}, disable_steamdeck_mode={disable_steamdeck_mode}, " + f"mangohud_workaround={mangohud_workaround}, disable_vkbasalt={disable_vkbasalt}") return self._success_response(ConfigurationResponse, "lsfg configuration updated successfully", @@ -214,6 +220,13 @@ class ConfigurationService(BaseService): if config.get("disable_steamdeck_mode", False): lines.append("export SteamDeck=0") + if config.get("mangohud_workaround", False): + lines.append("export MANGOHUD=1") + lines.append("export MANGOHUD_CONFIG=alpha=0.01,background_alpha=0.01") + + if config.get("disable_vkbasalt", False): + lines.append("export DISABLE_VKBASALT=1") + # Add DXVK_FRAME_RATE if dxvk_frame_rate is set dxvk_frame_rate = config.get("dxvk_frame_rate", 0) if dxvk_frame_rate > 0: diff --git a/py_modules/lsfg_vk/plugin.py b/py_modules/lsfg_vk/plugin.py index 425d7e7..7deed71 100644 --- a/py_modules/lsfg_vk/plugin.py +++ b/py_modules/lsfg_vk/plugin.py @@ -189,7 +189,9 @@ class Plugin: experimental_present_mode: str = "fifo", dxvk_frame_rate: int = 0, enable_wow64: bool = False, - disable_steamdeck_mode: bool = False) -> Dict[str, Any]: + disable_steamdeck_mode: bool = False, + mangohud_workaround: bool = False, + disable_vkbasalt: bool = False) -> Dict[str, Any]: """Update lsfg TOML configuration Args: @@ -202,13 +204,16 @@ class Plugin: dxvk_frame_rate: Frame rate cap for DirectX games, before frame multiplier (0 = disabled) enable_wow64: Whether to enable PROTON_USE_WOW64=1 for 32-bit games disable_steamdeck_mode: Whether to disable Steam Deck mode + mangohud_workaround: Whether to enable MangoHud workaround with transparent overlay + disable_vkbasalt: Whether to disable vkBasalt layer Returns: ConfigurationResponse dict with success status """ return self.configuration_service.update_config( dll, multiplier, flow_scale, performance_mode, hdr_mode, - experimental_present_mode, dxvk_frame_rate, enable_wow64, disable_steamdeck_mode + experimental_present_mode, dxvk_frame_rate, enable_wow64, disable_steamdeck_mode, + mangohud_workaround, disable_vkbasalt ) async def update_dll_path(self, dll_path: str) -> Dict[str, Any]: diff --git a/shared_config.py b/shared_config.py index 46bfc84..518294d 100644 --- a/shared_config.py +++ b/shared_config.py @@ -81,6 +81,20 @@ CONFIG_SCHEMA_DEF = { "fieldType": ConfigFieldType.BOOLEAN, "default": False, "description": "disable Steam Deck mode (unlocks hidden settings in some games)" + }, + + "mangohud_workaround": { + "name": "mangohud_workaround", + "fieldType": ConfigFieldType.BOOLEAN, + "default": False, + "description": "Enables a transparent mangohud overlay, sometimes fixes issues with 2X multiplier in game mode" + }, + + "disable_vkbasalt": { + "name": "disable_vkbasalt", + "fieldType": ConfigFieldType.BOOLEAN, + "default": False, + "description": "Disables vkBasalt layer which can conflict with LSFG (Reshade, some Decky plugins)" } } diff --git a/src/api/lsfgApi.ts b/src/api/lsfgApi.ts index 74caa57..0b221e9 100644 --- a/src/api/lsfgApi.ts +++ b/src/api/lsfgApi.ts @@ -101,14 +101,14 @@ export const getLaunchScriptContent = callable<[], FileContentResult>("get_launc // Updated config function using centralized configuration export const updateLsfgConfig = callable< - [string, number, number, boolean, boolean, string, number, boolean, boolean], + [string, number, number, boolean, boolean, string, number, boolean, boolean, boolean, boolean], ConfigUpdateResult >("update_lsfg_config"); // Helper function to create config update from configuration object export const updateLsfgConfigFromObject = async (config: ConfigurationData): Promise<ConfigUpdateResult> => { const args = ConfigurationManager.createArgsFromConfig(config); - return updateLsfgConfig(...args as [string, number, number, boolean, boolean, string, number, boolean, boolean]); + return updateLsfgConfig(...args as [string, number, number, boolean, boolean, string, number, boolean, boolean, boolean, boolean]); }; // Self-updater API functions diff --git a/src/components/ConfigurationSection.tsx b/src/components/ConfigurationSection.tsx index 59ad880..26099e7 100644 --- a/src/components/ConfigurationSection.tsx +++ b/src/components/ConfigurationSection.tsx @@ -154,6 +154,24 @@ export function ConfigurationSection({ onChange={(value) => onConfigChange('disable_steamdeck_mode', value)} /> </PanelSectionRow> + + <PanelSectionRow> + <ToggleField + label="MangoHud Workaround" + description="Enables a transparent mangohud overlay, sometimes fixes issues with 2X multiplier in game mode" + checked={config.mangohud_workaround} + onChange={(value) => onConfigChange('mangohud_workaround', value)} + /> + </PanelSectionRow> + + <PanelSectionRow> + <ToggleField + label="Disable vkBasalt" + description="Disables vkBasalt layer which can conflict with LSFG (Reshade, some Decky plugins)" + checked={config.disable_vkbasalt} + onChange={(value) => onConfigChange('disable_vkbasalt', value)} + /> + </PanelSectionRow> </> ); } diff --git a/src/config/configSchema.ts b/src/config/configSchema.ts index 4ab0d25..979d3c9 100644 --- a/src/config/configSchema.ts +++ b/src/config/configSchema.ts @@ -52,7 +52,7 @@ export class ConfigurationManager { /** * Create args array from config object for lsfg API calls */ - static createArgsFromConfig(config: ConfigurationData): [string, number, number, boolean, boolean, string, number, boolean, boolean] { + static createArgsFromConfig(config: ConfigurationData): [string, number, number, boolean, boolean, string, number, boolean, boolean, boolean, boolean] { return [ config.dll, config.multiplier, @@ -62,7 +62,9 @@ export class ConfigurationManager { config.experimental_present_mode, config.dxvk_frame_rate, config.enable_wow64, - config.disable_steamdeck_mode + config.disable_steamdeck_mode, + config.mangohud_workaround, + config.disable_vkbasalt ]; } diff --git a/src/config/generatedConfigSchema.ts b/src/config/generatedConfigSchema.ts index 5f0e368..cb08252 100644 --- a/src/config/generatedConfigSchema.ts +++ b/src/config/generatedConfigSchema.ts @@ -71,6 +71,18 @@ export const CONFIG_SCHEMA: Record<string, ConfigField> = { default: false, description: "disable Steam Deck mode (unlocks hidden settings in some games)" }, + mangohud_workaround: { + name: "mangohud_workaround", + fieldType: ConfigFieldType.BOOLEAN, + default: false, + description: "Enables a transparent mangohud overlay, sometimes fixes issues with 2X multiplier in game mode" + }, + disable_vkbasalt: { + name: "disable_vkbasalt", + fieldType: ConfigFieldType.BOOLEAN, + default: false, + description: "Disables vkBasalt layer which can conflict with LSFG (Reshade, some Decky plugins)" + }, }; // Type-safe configuration data structure @@ -84,6 +96,8 @@ export interface ConfigurationData { dxvk_frame_rate: number; enable_wow64: boolean; disable_steamdeck_mode: boolean; + mangohud_workaround: boolean; + disable_vkbasalt: boolean; } // Helper functions @@ -102,6 +116,8 @@ export function getDefaults(): ConfigurationData { dxvk_frame_rate: 0, enable_wow64: false, disable_steamdeck_mode: false, + mangohud_workaround: false, + disable_vkbasalt: false, }; } @@ -116,6 +132,8 @@ export function getFieldTypes(): Record<string, ConfigFieldType> { dxvk_frame_rate: ConfigFieldType.INTEGER, enable_wow64: ConfigFieldType.BOOLEAN, disable_steamdeck_mode: ConfigFieldType.BOOLEAN, + mangohud_workaround: ConfigFieldType.BOOLEAN, + disable_vkbasalt: ConfigFieldType.BOOLEAN, }; } diff --git a/tests/conftest.py b/tests/conftest.py deleted file mode 100644 index 9ac31a0..0000000 --- a/tests/conftest.py +++ /dev/null @@ -1,31 +0,0 @@ -""" -Test configuration for the lsfg-vk plugin tests. -""" - -import pytest -from unittest.mock import Mock - - -@pytest.fixture -def mock_logger(): - """Provide a mock logger for testing""" - return Mock() - - -@pytest.fixture -def mock_decky_logger(monkeypatch): - """Mock decky.logger for tests that import decky""" - mock_logger = Mock() - - # Create a mock decky module - mock_decky = Mock() - mock_decky.logger = mock_logger - - # Monkeypatch the import - monkeypatch.setattr('lsfg_vk.base_service.decky', mock_decky) - monkeypatch.setattr('lsfg_vk.installation.decky', mock_decky) - monkeypatch.setattr('lsfg_vk.dll_detection.decky', mock_decky) - monkeypatch.setattr('lsfg_vk.configuration.decky', mock_decky) - monkeypatch.setattr('lsfg_vk.plugin.decky', mock_decky) - - return mock_logger diff --git a/tests/test_configuration.py b/tests/test_configuration.py deleted file mode 100644 index 3e0ad79..0000000 --- a/tests/test_configuration.py +++ /dev/null @@ -1,190 +0,0 @@ -""" -Tests for the configuration service. -""" - -import tempfile -from pathlib import Path -from unittest.mock import Mock - -from lsfg_vk.configuration import ConfigurationService -from lsfg_vk.config_schema import ConfigurationManager - - -def test_parse_script_content(): - """Test parsing of script content with current environment variable format""" - - # Test script content matching current format - script_content = """#!/bin/bash -# lsfg-vk launch script generated by decky-lossless-scaling-vk plugin -# This script sets up the environment for lsfg-vk to work with the plugin configuration -export PROTON_USE_WOW64=1 -export SteamDeck=0 -export DXVK_FRAME_RATE=18 -export LSFG_PROCESS=decky-lsfg-vk -exec "$@" -""" - - script_values = ConfigurationManager.parse_script_content(script_content) - - assert script_values["enable_wow64"] is True - assert script_values["disable_steamdeck_mode"] is True # SteamDeck=0 means disable - assert script_values["dxvk_frame_rate"] == 18 - - -def test_parse_script_content_minimal(): - """Test parsing when only required exports are present""" - - script_content = """#!/bin/bash -# lsfg-vk launch script generated by decky-lossless-scaling-vk plugin -export LSFG_PROCESS=decky-lsfg-vk -exec "$@" -""" - - script_values = ConfigurationManager.parse_script_content(script_content) - - # Should be empty dict since no tracked env vars are present - assert script_values == {} - - -def test_merge_config_with_script(): - """Test merging TOML config with script environment variables""" - - # Get defaults - toml_config = ConfigurationManager.get_defaults() - - # Script values from parsing - script_values = { - "enable_wow64": True, - "disable_steamdeck_mode": True, - "dxvk_frame_rate": 30 - } - - merged = ConfigurationManager.merge_config_with_script(toml_config, script_values) - - # TOML fields should be preserved - assert merged["multiplier"] == 1 # default from TOML - assert merged["flow_scale"] == 0.8 # default from TOML - assert merged["performance_mode"] is True # default from TOML - - # Script fields should be overlaid - assert merged["enable_wow64"] is True - assert merged["disable_steamdeck_mode"] is True - assert merged["dxvk_frame_rate"] == 30 - - with tempfile.TemporaryDirectory() as temp_dir: - temp_home = Path(temp_dir) - - service = ConfigurationService(logger=mock_logger) - service.user_home = temp_home - service.lsfg_script_path = temp_home / "lsfg" - - script_content = """#!/bin/bash - -# export ENABLE_LSFG=1 -export LSFG_MULTIPLIER=2 -export LSFG_FLOW_SCALE=1.0 -# export LSFG_HDR=1 -# export LSFG_PERF_MODE=1 -# export MESA_VK_WSI_PRESENT_MODE=immediate # - disable vsync - -exec "$@" -""" - - config = service._parse_script_content(script_content) - - assert config["enable_lsfg"] is False - assert config["multiplier"] == 2 - assert config["flow_scale"] == 1.0 - assert config["hdr"] is False - assert config["perf_mode"] is False - assert config["immediate_mode"] is False - - -def test_generate_script_content(): - """Test script content generation""" - mock_logger = Mock() - - with tempfile.TemporaryDirectory() as temp_dir: - temp_home = Path(temp_dir) - - service = ConfigurationService(logger=mock_logger) - service.user_home = temp_home - service.lsfg_script_path = temp_home / "lsfg" - - # Test with no toggles enabled - config = { - "enable_wow64": False, - "disable_steamdeck_mode": False - } - content = service._generate_script_content(config) - - assert "#!/bin/bash" in content - assert "export LSFG_PROCESS=decky-lsfg-vk" in content - assert "export PROTON_USE_WOW64=1" not in content - assert "export SteamDeck=0" not in content - assert 'exec "$@"' in content - - # Test with both toggles enabled - config = { - "enable_wow64": True, - "disable_steamdeck_mode": True - } - content = service._generate_script_content(config) - - assert "#!/bin/bash" in content - assert "export PROTON_USE_WOW64=1" in content - assert "export SteamDeck=0" in content - assert "export LSFG_PROCESS=decky-lsfg-vk" in content - assert 'exec "$@"' in content - - -def test_config_roundtrip(): - """Test that we can write config and read it back correctly""" - mock_logger = Mock() - - with tempfile.TemporaryDirectory() as temp_dir: - temp_home = Path(temp_dir) - - service = ConfigurationService(logger=mock_logger) - service.user_home = temp_home - service.lsfg_script_path = temp_home / "lsfg" - - # Update config - result = service.update_config( - dll="/path/to/dll", - multiplier=3, - flow_scale=1.5, - performance_mode=False, - hdr_mode=True, - experimental_present_mode="immediate", - dxvk_frame_rate=30, - enable_wow64=True, - disable_steamdeck_mode=False - ) - - assert result["success"] is True - - # Read it back - read_result = service.get_config() - - assert read_result["success"] is True - config = read_result["config"] - assert config["dll"] == "/path/to/dll" - assert config["multiplier"] == 3 - assert config["flow_scale"] == 1.5 - assert config["performance_mode"] is False - assert config["hdr_mode"] is True - assert config["experimental_present_mode"] == "immediate" - assert config["dxvk_frame_rate"] == 30 - assert config["enable_wow64"] is True - assert config["disable_steamdeck_mode"] is False - - assert read_result["success"] is True - config = read_result["config"] - - assert config["enable_lsfg"] is True - assert config["multiplier"] == 3 - assert config["flow_scale"] == 1.5 - assert config["hdr"] is True - assert config["perf_mode"] is False - assert config["immediate_mode"] is True diff --git a/tests/test_dll_detection.py b/tests/test_dll_detection.py deleted file mode 100644 index e50d733..0000000 --- a/tests/test_dll_detection.py +++ /dev/null @@ -1,129 +0,0 @@ -""" -Tests for the DLL detection service. -""" - -import os -import tempfile -from pathlib import Path -from unittest.mock import Mock, patch - -from lsfg_vk.dll_detection import DllDetectionService -from lsfg_vk.constants import LOSSLESS_DLL_NAME - - -def test_dll_detection_via_env_variable(): - """Test DLL detection via LSFG_DLL_PATH environment variable""" - mock_logger = Mock() - - with tempfile.TemporaryDirectory() as temp_dir: - # Create a fake DLL file - dll_path = Path(temp_dir) / LOSSLESS_DLL_NAME - dll_path.write_text("fake dll content") - - service = DllDetectionService(logger=mock_logger) - - # Test with environment variable set - with patch.dict(os.environ, {"LSFG_DLL_PATH": str(dll_path)}): - result = service.check_lossless_scaling_dll() - - assert result["detected"] is True - assert result["path"] == str(dll_path) - assert "LSFG_DLL_PATH" in result["source"] - assert result["error"] is None - - -def test_dll_detection_via_xdg_data_home(): - """Test DLL detection via XDG_DATA_HOME""" - mock_logger = Mock() - - with tempfile.TemporaryDirectory() as temp_dir: - # Create the expected directory structure - steam_dir = Path(temp_dir) / "Steam" / "steamapps" / "common" / "Lossless Scaling" - steam_dir.mkdir(parents=True) - - dll_path = steam_dir / LOSSLESS_DLL_NAME - dll_path.write_text("fake dll content") - - service = DllDetectionService(logger=mock_logger) - - # Test with XDG_DATA_HOME set, no LSFG_DLL_PATH - with patch.dict(os.environ, {"XDG_DATA_HOME": temp_dir}, clear=True): - result = service.check_lossless_scaling_dll() - - assert result["detected"] is True - assert result["path"] == str(dll_path) - assert "XDG_DATA_HOME" in result["source"] - assert result["error"] is None - - -def test_dll_detection_via_home_local_share(): - """Test DLL detection via HOME/.local/share""" - mock_logger = Mock() - - with tempfile.TemporaryDirectory() as temp_dir: - # Create the expected directory structure - steam_dir = Path(temp_dir) / ".local" / "share" / "Steam" / "steamapps" / "common" / "Lossless Scaling" - steam_dir.mkdir(parents=True) - - dll_path = steam_dir / LOSSLESS_DLL_NAME - dll_path.write_text("fake dll content") - - service = DllDetectionService(logger=mock_logger) - - # Test with HOME set, no other env vars - env = {"HOME": temp_dir} - with patch.dict(os.environ, env, clear=True): - result = service.check_lossless_scaling_dll() - - assert result["detected"] is True - assert result["path"] == str(dll_path) - assert "HOME/.local/share" in result["source"] - assert result["error"] is None - - -def test_dll_detection_not_found(): - """Test DLL detection when DLL is not found""" - mock_logger = Mock() - - service = DllDetectionService(logger=mock_logger) - - # Test with no environment variables set - with patch.dict(os.environ, {}, clear=True): - result = service.check_lossless_scaling_dll() - - assert result["detected"] is False - assert result["path"] is None - assert result["source"] is None - assert "not found" in result["message"] - assert result["error"] is None - - -def test_dll_detection_priority(): - """Test that LSFG_DLL_PATH takes priority over other locations""" - mock_logger = Mock() - - with tempfile.TemporaryDirectory() as temp_dir1, tempfile.TemporaryDirectory() as temp_dir2: - # Create DLL in both locations - dll_path1 = Path(temp_dir1) / LOSSLESS_DLL_NAME - dll_path1.write_text("fake dll content 1") - - steam_dir = Path(temp_dir2) / "Steam" / "steamapps" / "common" / "Lossless Scaling" - steam_dir.mkdir(parents=True) - dll_path2 = steam_dir / LOSSLESS_DLL_NAME - dll_path2.write_text("fake dll content 2") - - service = DllDetectionService(logger=mock_logger) - - # Set both environment variables - env = { - "LSFG_DLL_PATH": str(dll_path1), - "XDG_DATA_HOME": temp_dir2 - } - - with patch.dict(os.environ, env, clear=True): - result = service.check_lossless_scaling_dll() - - # Should prefer LSFG_DLL_PATH - assert result["detected"] is True - assert result["path"] == str(dll_path1) - assert "LSFG_DLL_PATH" in result["source"] diff --git a/tests/test_installation.py b/tests/test_installation.py deleted file mode 100644 index 2b3690e..0000000 --- a/tests/test_installation.py +++ /dev/null @@ -1,150 +0,0 @@ -""" -Tests for the installation service. -""" - -import os -import tempfile -import zipfile -from pathlib import Path -from unittest.mock import Mock, patch - -import pytest -from pyfakefs.fake_filesystem_unittest import TestCase - -from lsfg_vk.installation import InstallationService -from lsfg_vk.constants import LIB_FILENAME, JSON_FILENAME, ZIP_FILENAME - - -class TestInstallationService(TestCase): - """Test cases for InstallationService using pyfakefs""" - - def setUp(self): - """Set up fake filesystem""" - self.setUpPyfakefs() - self.mock_logger = Mock() - - # Create a test home directory - self.test_home = Path("/home/testuser") - self.fs.create_dir(self.test_home) - - # Patch Path.home() to return our test home - with patch('lsfg_vk.base_service.Path.home', return_value=self.test_home): - self.service = InstallationService(logger=self.mock_logger) - - def test_check_installation_no_files(self): - """Test installation check when no files are installed""" - result = self.service.check_installation() - - assert result["installed"] is False - assert result["lib_exists"] is False - assert result["json_exists"] is False - assert result["script_exists"] is False - assert result["error"] is None - - def test_check_installation_all_files_exist(self): - """Test installation check when all files exist""" - # Create the files - self.service.lib_file.parent.mkdir(parents=True, exist_ok=True) - self.service.lib_file.touch() - - self.service.json_file.parent.mkdir(parents=True, exist_ok=True) - self.service.json_file.touch() - - self.service.lsfg_script_path.touch() - - result = self.service.check_installation() - - assert result["installed"] is True - assert result["lib_exists"] is True - assert result["json_exists"] is True - assert result["script_exists"] is True - assert result["error"] is None - - def test_create_zip_for_testing(self): - """Helper to create a test zip file""" - # Create temp directory for zip contents - zip_content_dir = Path("/tmp/zip_content") - self.fs.create_dir(zip_content_dir) - - # Create test files - lib_file = zip_content_dir / LIB_FILENAME - json_file = zip_content_dir / JSON_FILENAME - - lib_file.write_text("fake library content") - json_file.write_text('{"layer": {"name": "VK_LAYER_LS_frame_generation"}}') - - # Create zip file - zip_path = Path("/tmp/test.zip") - with zipfile.ZipFile(zip_path, 'w') as zip_file: - zip_file.write(lib_file, LIB_FILENAME) - zip_file.write(json_file, JSON_FILENAME) - - return zip_path - - @patch('lsfg_vk.installation.Path.home') - def test_install_success(self, mock_home): - """Test successful installation""" - mock_home.return_value = self.test_home - - # Create the plugin directory and zip file - plugin_dir = Path("/plugin") - bin_dir = plugin_dir / "bin" - self.fs.create_dir(bin_dir) - - # Create a test zip file - zip_path = self.test_create_zip_for_testing() - zip_dest = bin_dir / ZIP_FILENAME - - # Copy our test zip to the expected location - with open(zip_path, 'rb') as src, open(zip_dest, 'wb') as dst: - dst.write(src.read()) - - # Mock the plugin directory detection - with patch('lsfg_vk.installation.Path.__file__', f"{plugin_dir}/lsfg_vk/installation.py"): - result = self.service.install() - - assert result["success"] is True - assert "successfully" in result["message"] - assert result["error"] is None - - # Check that files were created - assert self.service.lib_file.exists() - assert self.service.json_file.exists() - assert self.service.lsfg_script_path.exists() - - def test_uninstall_no_files(self): - """Test uninstall when no files exist""" - result = self.service.uninstall() - - assert result["success"] is True - assert "No lsfg-vk files found" in result["message"] - assert result["removed_files"] is None - - def test_uninstall_with_files(self): - """Test uninstall when files exist""" - # Create the files - self.service.lib_file.parent.mkdir(parents=True, exist_ok=True) - self.service.lib_file.touch() - - self.service.json_file.parent.mkdir(parents=True, exist_ok=True) - self.service.json_file.touch() - - self.service.lsfg_script_path.touch() - - result = self.service.uninstall() - - assert result["success"] is True - assert "uninstalled successfully" in result["message"] - assert len(result["removed_files"]) == 3 - - # Check that files were removed - assert not self.service.lib_file.exists() - assert not self.service.json_file.exists() - assert not self.service.lsfg_script_path.exists() - - -def test_installation_service_with_mock_logger(): - """Test that InstallationService accepts a mock logger""" - mock_logger = Mock() - service = InstallationService(logger=mock_logger) - assert service.log == mock_logger |
