chore: typehint tests

This commit is contained in:
aclist committed 2026-11-12 05:10:02 +09:00
1 parent a5374d1f1a
commit e29433b388
23 files changed
+170 -93

No files matched your search

+4 -2
View File
@@ -1,5 +1,7 @@
from pathlib import Path
CWD = Path(__file__).parent
def fixture_path(fixture: str) -> str:
return str(CWD / fixture)
def fixture_path(fixture: str) -> Path:
return Path(CWD).joinpath(fixture)
+7 -5
View File
@@ -43,23 +43,25 @@ def patch_api() -> None:
mp.undo()
def test_no_last_update(steam_path) -> None:
def test_no_last_update(steam_path: Path) -> None:
assert get_last_updated(steam_path, 555) is None
def test_last_update(steam_path) -> None:
def test_last_update(steam_path: Path) -> None:
assert get_last_updated(steam_path, 444) == "2026-10-22 00:09:33"
def test_app_allows_downloads(steam_path) -> None:
def test_app_allows_downloads(steam_path: Path) -> None:
assert get_app_allows_downloads(steam_path, 111) is True
def test_app_disallows_downloads(steam_path):
def test_app_disallows_downloads(steam_path: Path) -> None:
assert get_app_allows_downloads(steam_path, 222) is False
def test_app_delegates_downloads(monkeypatch, steam_path, client_allows):
def test_app_delegates_downloads(
monkeypatch: MonkeyPatch, steam_path: Path, client_allows: Path
) -> None:
monkeypatch.setattr("dzgui.api.steam.get_config", mock_config_disallows)
assert get_app_allows_downloads(steam_path, 333) is False
monkeypatch.setattr("dzgui.api.steam.get_config", mock_config_allows)
+10 -4
View File
@@ -1,6 +1,8 @@
import pytest
import tempfile
from typing import TYPE_CHECKING
from dzgui.app_init import copy_bare_configs
from dzgui.config.xdg import get_xdg_paths, parse_filepaths
@@ -8,9 +10,13 @@ from dzgui.config.xdg import get_xdg_paths, parse_filepaths
CONF_STRING = "DZGUI_CONF\n"
STATE_STRING = "DZGUI_STATE\n"
if TYPE_CHECKING:
from _pytest.monkeypatch import MonkeyPatch
from dzgui.config.xdg import Xdg
@pytest.fixture
def state_files():
def state_files() -> list[str]:
state = [
"dzg.history",
"dzg.versions",
@@ -25,7 +31,7 @@ def state_files():
@pytest.fixture
def xdg_paths(monkeypatch):
def xdg_paths(monkeypatch: "MonkeyPatch") -> "Xdg":
routes = {
"XDG_CONFIG_HOME": "",
"XDG_STATE_HOME": "",
@@ -42,7 +48,7 @@ def xdg_paths(monkeypatch):
@pytest.mark.mods
def test_config_file_import(xdg_paths, state_files):
def test_config_file_import(xdg_paths: "Xdg", state_files: list[str]) -> None:
# NOTE: write bare files in root
tmp_conf = xdg_paths.config.parent.parent
@@ -67,7 +73,7 @@ def test_config_file_import(xdg_paths, state_files):
@pytest.mark.mods
def test_config_file_no_import(xdg_paths, state_files):
def test_config_file_no_import(xdg_paths: "Xdg", state_files: list[str]) -> None:
for subdir in xdg_paths.config.parent, xdg_paths.resolution.parent:
subdir.mkdir()
+2 -2
View File
@@ -5,7 +5,7 @@ from pathlib import Path
@pytest.fixture
def changelog(request) -> None:
def changelog(request: pytest.FixtureRequest) -> str:
root = request.config.rootpath
changelog = Path(root).joinpath("CHANGELOG.md").read_text()
return changelog
@@ -19,7 +19,7 @@ def count_hash(line: str) -> int:
return cnt
def test_changelog_prefix(changelog) -> None:
def test_changelog_prefix(changelog: str) -> None:
r = r".*(\[.*\]).*"
lines = changelog.splitlines()
sort = sorted(lines)
+7 -2
View File
@@ -1,14 +1,19 @@
import pytest
from typing import Any, TYPE_CHECKING
from dzgui.const.constants import FLATPAK_RUN_CMD, STEAM_CMD
from dzgui.controllers.mc import Controller
if TYPE_CHECKING:
from _pytest.monkeypatch import MonkeyPatch
@pytest.mark.parametrize(
"value, expected", [(FLATPAK_RUN_CMD, "Flatpak"), (STEAM_CMD, "Steam")]
)
def test_human_name(monkeypatch, value, expected) -> None:
def mock_query_config(*args) -> str:
def test_human_name(monkeypatch: "MonkeyPatch", value: str, expected: str) -> None:
def mock_query_config(*args: Any) -> str:
return value
monkeypatch.setattr(
+2 -2
View File
@@ -10,7 +10,7 @@ gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gio, GLib # noqa
class DummyWidget(ColorAwareApp, Gtk.Button):
class DummyWidget(ColorAwareApp, Gtk.Button): # type: ignore
def __init__(self) -> None:
super().__init__()
@@ -27,7 +27,7 @@ def widget() -> DummyWidget:
@pytest.mark.parametrize("key, expect", [("default", False), ("prefer-dark", True)])
def test_light_mode(widget, key: str, expect: bool) -> None:
def test_light_mode(widget: DummyWidget, key: str, expect: bool) -> None:
local_pref = subprocess.run(
["gsettings", "get", "org.gnome.desktop.interface", "color-scheme"],
capture_output=True,
+21 -6
View File
@@ -1,33 +1,48 @@
import pytest
from typing import TYPE_CHECKING
from dzgui.init.migrate import convert_cols_file
from tests.fixtures import fixture_path
if TYPE_CHECKING:
from pathlib import Path
@pytest.fixture
def columns_with_perspective():
def columns_with_perspective() -> "Path":
return fixture_path("columns_1")
@pytest.fixture
def columns_without_perspective():
def columns_without_perspective() -> "Path":
return fixture_path("columns_2")
@pytest.fixture
def columns_with_view():
def columns_with_view() -> "Path":
return fixture_path("columns_3")
@pytest.mark.config
def test_columns_with_perspective(columns_with_perspective):
def test_columns_with_perspective(columns_with_perspective: "Path") -> None:
j = convert_cols_file(columns_with_perspective)
if j is None:
return
assert "View" in j["cols"]
assert "Max" in j["cols"]
@pytest.mark.config
def test_columns_without_perspective(columns_without_perspective):
def test_columns_without_perspective(columns_without_perspective: "Path") -> None:
j = convert_cols_file(columns_without_perspective)
if j is None:
return
assert "View" not in j["cols"]
assert "Max" not in j["cols"]
@pytest.mark.config
def test_columns_with_view(columns_with_view):
def test_columns_with_view(columns_with_view: "Path") -> None:
j = convert_cols_file(columns_with_view)
assert j is None
+17 -12
View File
@@ -1,25 +1,30 @@
import json
import pytest
from typing import Any, TYPE_CHECKING
from dzgui.const.boilerplate import config_boilerplate
from dzgui.config.query import get_config
from dzgui.config.xdg import get_xdg_paths, parse_filepaths
from dzgui.config import convert
from tests.fixtures import fixture_path
if TYPE_CHECKING:
from pathlib import Path
@pytest.fixture
def legacy_config():
def legacy_config() -> "Path":
return fixture_path("dztuirc_1")
@pytest.fixture
def unset_values():
def unset_values() -> "Path":
return fixture_path("dztuirc_3")
@pytest.fixture
def keys():
def keys() -> list[str]:
return [
"fav_server",
"fav_label",
@@ -36,7 +41,7 @@ def keys():
# TODO: use a static fixture instead of system config
@pytest.fixture
def config():
def config() -> Any:
paths = get_xdg_paths()
xdg = parse_filepaths(paths)
return get_config(xdg.config)
@@ -44,21 +49,21 @@ def config():
@pytest.mark.post_install
@pytest.mark.realconfig
def test_invalid_config_value(config):
def test_invalid_config_value(config: Any) -> None:
with pytest.raises(Exception):
assert config["foo"] is None
@pytest.mark.post_install
@pytest.mark.realconfig
def test_default_config_values(keys, config):
def test_default_config_values(keys: list[str], config: Any) -> None:
for key in keys:
assert config[key] is not None
@pytest.mark.post_install
@pytest.mark.realconfig
def test_contains_invalid_values(keys, config):
def test_contains_invalid_values(keys: list[str], config: Any) -> None:
for key in config:
assert key in keys
@@ -70,15 +75,15 @@ def test_contains_invalid_values(keys, config):
("dztuirc_2", (False, False, False)),
],
)
def test_bool_conversion(fixture, expect):
fixture = fixture_path(fixture)
j = convert.rc2json(fixture)
def test_bool_conversion(fixture: str, expect: tuple[bool, bool, bool]) -> None:
fixture_p = fixture_path(fixture)
j = convert.rc2json(fixture_p)
j = json.loads(j)
assert j["fullscreen"] == expect[0]
assert not j["use_miles"]
def test_key_conversion(legacy_config):
def test_key_conversion(legacy_config: "Path") -> None:
j = convert.rc2json(legacy_config)
j = json.loads(j)
keys = [
@@ -92,7 +97,7 @@ def test_key_conversion(legacy_config):
assert key not in j
def test_missing_values(unset_values):
def test_missing_values(unset_values: "Path") -> None:
j = convert.rc2json(unset_values)
j = json.loads(j)
assert j.keys() == config_boilerplate.keys()
+11 -7
View File
@@ -1,6 +1,8 @@
import configparser
import pytest
from pathlib import Path
from dzgui.const.constants import FLATPAK_APPID, GTK_APP_ID, TMP_PATH
from dzgui.config.xdg import get_xdg_paths
from dzgui.util.flatpak import apply_overrides
@@ -13,17 +15,17 @@ pytestmark = pytest.mark.flatpak
@pytest.fixture
def xdg_paths() -> dict[str, str]:
def xdg_paths() -> dict[str, Path]:
return get_xdg_paths()
@pytest.fixture
def override(xdg_paths) -> None:
def override(xdg_paths: dict[str, Path]) -> None:
apply_overrides(xdg_paths)
@pytest.fixture
def config(xdg_paths) -> configparser.ConfigParser:
def config(xdg_paths: dict[str, Path]) -> configparser.ConfigParser:
conf_path = xdg_paths["XDG_DATA_HOME"].parent.joinpath(
f"flatpak/overrides/{FLATPAK_APPID}"
)
@@ -32,14 +34,16 @@ def config(xdg_paths) -> configparser.ConfigParser:
return config
def test_session_bus(override, config) -> None:
def test_session_bus(override: None, config: configparser.ConfigParser) -> None:
bus = config[BUS_KEY][GTK_APP_ID]
assert bus == "own"
def test_paths(override, xdg_paths, config) -> None:
expect: list[str] = []
expect.append(TMP_PATH)
def test_paths(
override: None, xdg_paths: dict[str, Path], config: configparser.ConfigParser
) -> None:
expect: list[Path] = []
expect.append(Path(TMP_PATH))
expect.extend([*xdg_paths.values()])
paths = config[PATHS_KEY][PATHS_SUBKEY].split(";")
assert all(str(path) in paths for path in expect)
+2 -1
View File
@@ -2,10 +2,11 @@ import pytest
from dzgui.const.constants import FLATPAK_RUN_CMD, FLATPAK_SANDBOX
from dzgui.const.enum import Preferences
from dzgui.controllers.mc import Controller
from dzgui.views.pages.options import FlatpakToggleField
class MockController:
class MockController(Controller):
def __init__(self) -> None:
self.command: str
+6 -3
View File
@@ -20,20 +20,23 @@ def get_db_len(path: Path) -> int:
c = conn.cursor()
c.execute("SELECT COUNT(*) from ips")
db_len = c.fetchone()[0]
return db_len
return int(db_len)
@pytest.fixture
def csv() -> Path:
csv = Path(tempfile.NamedTemporaryFile().name)
url = find_download_url(DB_IP)
if url is None:
raise ValueError()
tmp = serialize(url)
unzip(tmp, csv)
strip_ipv6(csv)
return csv
@pytest.mark.slow
def test_stripping(csv):
def test_stripping(csv: Path) -> None:
with open(csv, "rb") as f:
first = f.readline().decode().rstrip()
try:
@@ -52,7 +55,7 @@ def test_stripping(csv):
@pytest.mark.slow
def test_row_parity(csv) -> None:
def test_row_parity(csv: Path) -> None:
rows = csv.read_text().splitlines()
db = Path(tempfile.NamedTemporaryFile().name)
+11 -7
View File
@@ -1,26 +1,30 @@
import gi
import pytest
from typing import Any
from dzgui.api.servers import Details
from dzgui.controllers.mc import Controller
from dzgui.controllers.emitter import Emitter
from dzgui.views.base import OuterWindow
from dzgui.views.dialogs.servers import ServerDetailsDialog
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class MockController:
class MockController(Controller):
def __init__(self) -> None:
self.window = Gtk.Window()
pass
def get_window(self) -> Gtk.Window:
return self.window
def get_window(self) -> None: # type: ignore[override]
return None
def get_server_name(self) -> str:
return "My server"
def get_emitter(self) -> None:
return None
def get_emitter(self) -> Emitter:
return Emitter()
@pytest.mark.filterwarnings("ignore::DeprecationWarning")
+1 -1
View File
@@ -15,7 +15,7 @@ from dzgui.views.components.entry import validate_ip_truthy
("192.168.1.101:27016", True),
],
)
def test_ip_entry(ip) -> None:
def test_ip_entry(ip: tuple[str, bool]) -> None:
string, state = ip
assert validate_ip_truthy(string) is state
+11 -7
View File
@@ -1,27 +1,29 @@
import pytest
from typing import Any
from dzgui.model.model_factory import FastInsertListStore
@pytest.fixture
def heterogeneous_list() -> None:
def heterogeneous_list() -> list[list[Any]]:
return [["a", 0, True], ["b", 1, False]]
@pytest.fixture
def mismatched_length_list() -> None:
def mismatched_length_list() -> list[list[Any]]:
return [["a", 0, True], ["b", 1, False, 0]]
@pytest.fixture
def extended_list(heterogeneous_list) -> None:
def extended_list(heterogeneous_list: list[list[Any]]) -> FastInsertListStore:
fs = FastInsertListStore(str, int, bool)
fs.extend(heterogeneous_list)
return fs
@pytest.fixture
def appended_list(heterogeneous_list) -> None:
def appended_list(heterogeneous_list: list[list[Any]]) -> FastInsertListStore:
fs = FastInsertListStore(str, int, bool)
for row in heterogeneous_list:
fs.append(row)
@@ -29,19 +31,21 @@ def appended_list(heterogeneous_list) -> None:
@pytest.mark.parametrize("target", ["extended_list", "appended_list"])
def test_list_parity(heterogeneous_list, request, target) -> None:
def test_list_parity(
heterogeneous_list: list[list[Any]], request: pytest.FixtureRequest, target: str
) -> None:
target = request.getfixturevalue(target)
extracted = [[el for el in row] for row in target]
assert heterogeneous_list == extracted
def test_type_disparity(heterogeneous_list) -> None:
def test_type_disparity(heterogeneous_list: list[list[Any]]) -> None:
with pytest.raises(TypeError):
fs = FastInsertListStore(str, bool, bool)
fs.extend(heterogeneous_list)
def test_length_disparity(mismatched_length_list) -> None:
def test_length_disparity(mismatched_length_list: list[list[Any]]) -> None:
with pytest.raises(ValueError):
fs = FastInsertListStore(str, int, bool)
fs.extend(mismatched_length_list)
+9 -4
View File
@@ -1,27 +1,32 @@
from typing import TYPE_CHECKING
from dzgui.util import localize
if TYPE_CHECKING:
from _pytest.monkeypatch import MonkeyPatch
def test_de(monkeypatch):
def test_de(monkeypatch: "MonkeyPatch") -> None:
monkeypatch.setenv("LC_ALL", "de_DE.UTF-8")
localize.set_locale()
assert localize.number(9900) == "9.900"
assert localize.number(99.88) == "99,88"
def test_en(monkeypatch):
def test_en(monkeypatch: "MonkeyPatch") -> None:
monkeypatch.setenv("LC_ALL", "en_US.UTF-8")
localize.set_locale()
assert localize.number(9900) == "9,900"
assert localize.number(99.88) == "99.88"
def test_none(monkeypatch):
def test_none(monkeypatch: "MonkeyPatch") -> None:
localize.set_locale()
assert localize.number(9900) == "9,900"
assert localize.number(99.88) == "99.88"
def test_empty(monkeypatch):
def test_empty(monkeypatch: "MonkeyPatch") -> None:
monkeypatch.setenv("LC_ALL", "")
localize.set_locale()
assert localize.number(9900) == "9,900"
+3 -3
View File
@@ -7,13 +7,13 @@ from dzgui.util.redact import RedactionFilter, REDACTION_PATTERNS
class RecordsListHandler(logging.Handler):
def __init__(self) -> None:
super().__init__()
self.records_list = []
self.records_list: list[logging.LogRecord] = []
def emit(self, record: logging.LogRecord) -> None:
self.records_list.append(record)
def pop(self) -> None:
return self.records_list[-1].msg
def pop(self) -> str:
return str(self.records_list[-1].msg)
@pytest.mark.redact
+6 -1
View File
@@ -1,8 +1,13 @@
from pathlib import Path
from typing import TYPE_CHECKING
from dzgui.config.xdg import get_xdg_paths
if TYPE_CHECKING:
from _pytest.monkeypatch import MonkeyPatch
def test_path_fallback(monkeypatch) -> None:
def test_path_fallback(monkeypatch: "MonkeyPatch") -> None:
envs = ["XDG_DATA_HOME", "XDG_STATE_HOME", "XDG_CONFIG_HOME", "XDG_CACHE_HOME"]
for env in envs:
monkeypatch.setenv(env, "/etc/dzgui")
+7 -1
View File
@@ -1,8 +1,12 @@
import pytest
from pathlib import Path
from typing import TYPE_CHECKING
from dzgui.api.steam import is_dayz_downloading
if TYPE_CHECKING:
from _pytest.monkeypatch import MonkeyPatch
@pytest.mark.parametrize(
"file_list, expect",
@@ -16,7 +20,9 @@ from dzgui.api.steam import is_dayz_downloading
(["state_221100_1111"], False),
],
)
def test_dayz_patch_pending(monkeypatch, file_list: list[str], expect: bool) -> None:
def test_dayz_patch_pending(
monkeypatch: "MonkeyPatch", file_list: list[str], expect: bool
) -> None:
def mock_get_pending_downloads(steam_path: Path, appid: int) -> None:
files = [Path(file) for file in file_list]
return files
+9 -9
View File
@@ -7,7 +7,7 @@ from dzgui.api.steam import (
VDFLoadError,
AppNotInstalledError,
AppMovedError,
get_app_path
get_app_path,
)
from dzgui.config.query import get_config
@@ -20,16 +20,14 @@ pytestmark = pytest.mark.apitest
@pytest.fixture
def default_steam_path():
def default_steam_path() -> str:
paths = get_xdg_paths()
xdg = parse_filepaths(paths)
conf = get_config(xdg.config)
return conf["default_steam_path"]
return str(conf["default_steam_path"])
# TODO: split into separate test file
# FIXME: use fixtures
def test_pefile_length(default_steam_path):
def test_pefile_length(default_steam_path: str) -> None:
try:
pe_file_path = PeFile.get_pefile_path(Path(default_steam_path), APPID_DAYZ)
vers = PeFile.get_dayz_version(pe_file_path)
@@ -39,7 +37,7 @@ def test_pefile_length(default_steam_path):
assert len(st) == 3
def test_invalid_pefile_path():
def test_invalid_pefile_path() -> None:
with pytest.raises(VDFLoadError):
try:
PeFile.get_pefile_path(Path("/not/a/path"), APPID_DAYZ)
@@ -57,6 +55,7 @@ def test_invalid_pefile_path():
)
def test_not_in_library(monkeypatch, fixture, exception):
import dzgui.api.steam as steam
monkeypatch.setattr(steam, "LIBRARYFOLDERS_PATH", fixture)
folder_path = Path(fixture_path("api"))
@@ -68,12 +67,13 @@ def test_not_in_library(monkeypatch, fixture, exception):
@pytest.fixture
def second_drive():
def second_drive() -> str:
return "in_library_on_second_drive.vdf"
def test_on_second_drive(monkeypatch, second_drive):
def test_on_second_drive(monkeypatch, second_drive: str) -> None:
import dzgui.api.steam as steam
monkeypatch.setattr(steam, "LIBRARYFOLDERS_PATH", second_drive)
folder_path = Path(fixture_path("api"))
path = get_app_path(folder_path, APPID_DAYZ)
+7 -7
View File
@@ -14,9 +14,9 @@ pytestmark = pytest.mark.flatpak
class TestSteamDetection(unittest.TestCase):
def test_flatpak_detection_with_multiple_running_apps(self):
def flatpak_output(args, *, text):
# Default `flatpak ps` includes instance, PID, app and runtime columns.
def test_flatpak_detection_with_multiple_running_apps(self) -> None:
def flatpak_output(args, *, text: str) -> str:
# Default 'flatpak ps' includes instance, PID, app and runtime columns.
if args == ["flatpak", "ps", "--columns=application"]:
return f"com.spotify.Client\n{FLATPAK_APPID}\n{FLATPAK_APPID}\n"
return f"3904921611\t1257689\t{FLATPAK_APPID}\torg.freedesktop.Platform\n"
@@ -29,7 +29,7 @@ class TestSteamDetection(unittest.TestCase):
with self.subTest(client=client):
self.assertTrue(proc.is_steam_running(client))
def test_flatpak_not_running(self):
def test_flatpak_not_running(self) -> None:
with patch.object(proc, "has_cmd", return_value=True):
for output in ("", "com.spotify.Client\n", f"{FLATPAK_APPID}Helper\n"):
with (
@@ -38,7 +38,7 @@ class TestSteamDetection(unittest.TestCase):
):
self.assertFalse(proc.is_flatpak_steam_running())
def test_flatpak_not_installed(self):
def test_flatpak_not_installed(self) -> None:
with (
patch.object(proc, "has_cmd", return_value=False),
patch.object(proc.subprocess, "check_output") as check_output,
@@ -46,7 +46,7 @@ class TestSteamDetection(unittest.TestCase):
self.assertFalse(proc.is_flatpak_steam_running())
check_output.assert_not_called()
def test_native_steam(self):
def test_native_steam(self) -> None:
with patch.object(proc, "has_cmd", return_value=True):
for output, expected in (
(
@@ -73,6 +73,6 @@ class TestSteamDetection(unittest.TestCase):
):
self.assertEqual(proc.is_native_steam_running(), expected)
def test_invalid_client(self):
def test_invalid_client(self) -> None:
with self.assertRaises(TypeError):
proc.is_steam_running("invalid-client")
+9 -4
View File
@@ -1,23 +1,28 @@
import pytest
from typing import TYPE_CHECKING
from dzgui.api import probe
from dzgui.config.query import get_config
from dzgui.config.xdg import get_xdg_paths, parse_filepaths
from dzgui.api import probe
if TYPE_CHECKING:
from pathlib import Path
pytestmark = pytest.mark.webtest
@pytest.fixture
def config():
def config() -> dict[str, "Path"]:
paths = get_xdg_paths()
xdg = parse_filepaths(paths)
return get_config(xdg.config)
def test_ipdb():
def test_ipdb() -> None:
assert probe.test_ipdb()
def test_steam(config):
def test_steam(config: dict[str, "Path"]) -> None:
key = config["steam_api"]
assert probe.test_steam_api(key)
+1 -1
View File
@@ -23,7 +23,7 @@ def test_time_accel(details, key, expect) -> None:
assert getattr(details, key) == expect
def test_gametime(details) -> None:
def test_gametime(details: Details | None) -> None:
time_reg = r"^(0[0-9]|1[0-9]|2[0-3]):([0-5][0-9]$)"
match = re.match(time_reg, details.gametime)
assert match is not None
+7 -2
View File
@@ -1,12 +1,17 @@
import pytest
import tempfile
from typing import TYPE_CHECKING
from pathlib import Path
from _pytest.monkeypatch import MonkeyPatch
from dzgui.api.shortcuts import Shortcuts
from tests.fixtures import fixture_path
if TYPE_CHECKING:
from _pytest.monkeypatch import MonkeyPatch
pytestmark = pytest.mark.apitest
@@ -22,13 +27,13 @@ def patch_api() -> None:
mp.undo()
def test_no_shortcuts(monkeypatch) -> None:
def test_no_shortcuts(monkeypatch: "MonkeyPatch") -> None:
s = Shortcuts(Path(""))
assert len(s.shortcuts["shortcuts"]) == 0
@pytest.fixture
def dummy_app() -> None:
def dummy_app() -> dict[str, str]:
d = {
"AppName": "TEST APP",
"StartDir": "TEST_DIR",