Merge pull request #542 from aclist/chore/test-typehints
Mirror to Codeberg / mirror-to-codeberg (push) Canceled after 0s

chore: typehint tests
This commit is contained in:
aclist authored and GitHub committed 2026-11-12 07:47:03 +09:00
commit e935276e32
29 files changed
+268 -160

No files matched your search

+4 -2
View File
@@ -1,5 +1,7 @@
from pathlib import Path from pathlib import Path
CWD = Path(__file__).parent 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)
+9 -6
View File
@@ -1,6 +1,7 @@
import pytest import pytest
from _pytest.monkeypatch import MonkeyPatch from _pytest.monkeypatch import MonkeyPatch
from collections.abc import Iterator
from pathlib import Path from pathlib import Path
from dzgui.api.steam import get_app_allows_downloads, get_last_updated from dzgui.api.steam import get_app_allows_downloads, get_last_updated
@@ -36,30 +37,32 @@ def steam_path() -> Path:
@pytest.fixture(scope="module", autouse=True) @pytest.fixture(scope="module", autouse=True)
def patch_api() -> None: def patch_api() -> Iterator[None]:
mp = MonkeyPatch() mp = MonkeyPatch()
mp.setattr("dzgui.api.steam.get_app_path", mock_path) mp.setattr("dzgui.api.steam.get_app_path", mock_path)
yield yield
mp.undo() 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 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" 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 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 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) monkeypatch.setattr("dzgui.api.steam.get_config", mock_config_disallows)
assert get_app_allows_downloads(steam_path, 333) is False assert get_app_allows_downloads(steam_path, 333) is False
monkeypatch.setattr("dzgui.api.steam.get_config", mock_config_allows) monkeypatch.setattr("dzgui.api.steam.get_config", mock_config_allows)
+10 -4
View File
@@ -1,6 +1,8 @@
import pytest import pytest
import tempfile import tempfile
from typing import TYPE_CHECKING
from dzgui.app_init import copy_bare_configs from dzgui.app_init import copy_bare_configs
from dzgui.config.xdg import get_xdg_paths, parse_filepaths 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" CONF_STRING = "DZGUI_CONF\n"
STATE_STRING = "DZGUI_STATE\n" STATE_STRING = "DZGUI_STATE\n"
if TYPE_CHECKING:
from _pytest.monkeypatch import MonkeyPatch
from dzgui.config.xdg import Xdg
@pytest.fixture @pytest.fixture
def state_files(): def state_files() -> list[str]:
state = [ state = [
"dzg.history", "dzg.history",
"dzg.versions", "dzg.versions",
@@ -25,7 +31,7 @@ def state_files():
@pytest.fixture @pytest.fixture
def xdg_paths(monkeypatch): def xdg_paths(monkeypatch: "MonkeyPatch") -> "Xdg":
routes = { routes = {
"XDG_CONFIG_HOME": "", "XDG_CONFIG_HOME": "",
"XDG_STATE_HOME": "", "XDG_STATE_HOME": "",
@@ -42,7 +48,7 @@ def xdg_paths(monkeypatch):
@pytest.mark.mods @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 # NOTE: write bare files in root
tmp_conf = xdg_paths.config.parent.parent tmp_conf = xdg_paths.config.parent.parent
@@ -67,7 +73,7 @@ def test_config_file_import(xdg_paths, state_files):
@pytest.mark.mods @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: for subdir in xdg_paths.config.parent, xdg_paths.resolution.parent:
subdir.mkdir() subdir.mkdir()
+2 -2
View File
@@ -5,7 +5,7 @@ from pathlib import Path
@pytest.fixture @pytest.fixture
def changelog(request) -> None: def changelog(request: pytest.FixtureRequest) -> str:
root = request.config.rootpath root = request.config.rootpath
changelog = Path(root).joinpath("CHANGELOG.md").read_text() changelog = Path(root).joinpath("CHANGELOG.md").read_text()
return changelog return changelog
@@ -19,7 +19,7 @@ def count_hash(line: str) -> int:
return cnt return cnt
def test_changelog_prefix(changelog) -> None: def test_changelog_prefix(changelog: str) -> None:
r = r".*(\[.*\]).*" r = r".*(\[.*\]).*"
lines = changelog.splitlines() lines = changelog.splitlines()
sort = sorted(lines) sort = sorted(lines)
+7 -2
View File
@@ -1,14 +1,19 @@
import pytest import pytest
from typing import Any, TYPE_CHECKING
from dzgui.const.constants import FLATPAK_RUN_CMD, STEAM_CMD from dzgui.const.constants import FLATPAK_RUN_CMD, STEAM_CMD
from dzgui.controllers.mc import Controller from dzgui.controllers.mc import Controller
if TYPE_CHECKING:
from _pytest.monkeypatch import MonkeyPatch
@pytest.mark.parametrize( @pytest.mark.parametrize(
"value, expected", [(FLATPAK_RUN_CMD, "Flatpak"), (STEAM_CMD, "Steam")] "value, expected", [(FLATPAK_RUN_CMD, "Flatpak"), (STEAM_CMD, "Steam")]
) )
def test_human_name(monkeypatch, value, expected) -> None: def test_human_name(monkeypatch: "MonkeyPatch", value: str, expected: str) -> None:
def mock_query_config(*args) -> str: def mock_query_config(*args: Any) -> str:
return value return value
monkeypatch.setattr( monkeypatch.setattr(
+2 -2
View File
@@ -9,7 +9,7 @@ gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib from gi.repository import Gtk, GLib
class DummyWidget(ColorAwareApp, Gtk.Button): class DummyWidget(ColorAwareApp, Gtk.Button): # type: ignore
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
@@ -26,7 +26,7 @@ def widget() -> DummyWidget:
@pytest.mark.parametrize("key, expect", [("default", False), ("prefer-dark", True)]) @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( local_pref = subprocess.run(
["gsettings", "get", "org.gnome.desktop.interface", "color-scheme"], ["gsettings", "get", "org.gnome.desktop.interface", "color-scheme"],
capture_output=True, capture_output=True,
+21 -6
View File
@@ -1,33 +1,48 @@
import pytest import pytest
from typing import TYPE_CHECKING
from dzgui.init.migrate import convert_cols_file from dzgui.init.migrate import convert_cols_file
from tests.fixtures import fixture_path from tests.fixtures import fixture_path
if TYPE_CHECKING:
from pathlib import Path
@pytest.fixture @pytest.fixture
def columns_with_perspective(): def columns_with_perspective() -> "Path":
return fixture_path("columns_1") return fixture_path("columns_1")
@pytest.fixture @pytest.fixture
def columns_without_perspective(): def columns_without_perspective() -> "Path":
return fixture_path("columns_2") return fixture_path("columns_2")
@pytest.fixture @pytest.fixture
def columns_with_view(): def columns_with_view() -> "Path":
return fixture_path("columns_3") return fixture_path("columns_3")
@pytest.mark.config @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) j = convert_cols_file(columns_with_perspective)
if j is None:
return
assert "View" in j["cols"] assert "View" in j["cols"]
assert "Max" in j["cols"] assert "Max" in j["cols"]
@pytest.mark.config @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) j = convert_cols_file(columns_without_perspective)
if j is None:
return
assert "View" not in j["cols"] assert "View" not in j["cols"]
assert "Max" not in j["cols"] assert "Max" not in j["cols"]
@pytest.mark.config @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) j = convert_cols_file(columns_with_view)
assert j is None assert j is None
+17 -12
View File
@@ -1,25 +1,30 @@
import json import json
import pytest import pytest
from typing import Any, TYPE_CHECKING
from dzgui.const.boilerplate import config_boilerplate from dzgui.const.boilerplate import config_boilerplate
from dzgui.config.query import get_config from dzgui.config.query import get_config
from dzgui.config.xdg import get_xdg_paths, parse_filepaths from dzgui.config.xdg import get_xdg_paths, parse_filepaths
from dzgui.config import convert from dzgui.config import convert
from tests.fixtures import fixture_path from tests.fixtures import fixture_path
if TYPE_CHECKING:
from pathlib import Path
@pytest.fixture @pytest.fixture
def legacy_config(): def legacy_config() -> "Path":
return fixture_path("dztuirc_1") return fixture_path("dztuirc_1")
@pytest.fixture @pytest.fixture
def unset_values(): def unset_values() -> "Path":
return fixture_path("dztuirc_3") return fixture_path("dztuirc_3")
@pytest.fixture @pytest.fixture
def keys(): def keys() -> list[str]:
return [ return [
"fav_server", "fav_server",
"fav_label", "fav_label",
@@ -36,7 +41,7 @@ def keys():
# TODO: use a static fixture instead of system config # TODO: use a static fixture instead of system config
@pytest.fixture @pytest.fixture
def config(): def config() -> Any:
paths = get_xdg_paths() paths = get_xdg_paths()
xdg = parse_filepaths(paths) xdg = parse_filepaths(paths)
return get_config(xdg.config) return get_config(xdg.config)
@@ -44,21 +49,21 @@ def config():
@pytest.mark.post_install @pytest.mark.post_install
@pytest.mark.realconfig @pytest.mark.realconfig
def test_invalid_config_value(config): def test_invalid_config_value(config: Any) -> None:
with pytest.raises(Exception): with pytest.raises(Exception):
assert config["foo"] is None assert config["foo"] is None
@pytest.mark.post_install @pytest.mark.post_install
@pytest.mark.realconfig @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: for key in keys:
assert config[key] is not None assert config[key] is not None
@pytest.mark.post_install @pytest.mark.post_install
@pytest.mark.realconfig @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: for key in config:
assert key in keys assert key in keys
@@ -70,15 +75,15 @@ def test_contains_invalid_values(keys, config):
("dztuirc_2", (False, False, False)), ("dztuirc_2", (False, False, False)),
], ],
) )
def test_bool_conversion(fixture, expect): def test_bool_conversion(fixture: str, expect: tuple[bool, bool, bool]) -> None:
fixture = fixture_path(fixture) fixture_p = fixture_path(fixture)
j = convert.rc2json(fixture) j = convert.rc2json(fixture_p)
j = json.loads(j) j = json.loads(j)
assert j["fullscreen"] == expect[0] assert j["fullscreen"] == expect[0]
assert not j["use_miles"] 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 = convert.rc2json(legacy_config)
j = json.loads(j) j = json.loads(j)
keys = [ keys = [
@@ -92,7 +97,7 @@ def test_key_conversion(legacy_config):
assert key not in j 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 = convert.rc2json(unset_values)
j = json.loads(j) j = json.loads(j)
assert j.keys() == config_boilerplate.keys() assert j.keys() == config_boilerplate.keys()
+11 -7
View File
@@ -1,6 +1,8 @@
import configparser import configparser
import pytest import pytest
from pathlib import Path
from dzgui.const.constants import FLATPAK_APPID, GTK_APP_ID, TMP_PATH from dzgui.const.constants import FLATPAK_APPID, GTK_APP_ID, TMP_PATH
from dzgui.config.xdg import get_xdg_paths from dzgui.config.xdg import get_xdg_paths
from dzgui.util.flatpak import apply_overrides from dzgui.util.flatpak import apply_overrides
@@ -13,17 +15,17 @@ pytestmark = pytest.mark.flatpak
@pytest.fixture @pytest.fixture
def xdg_paths() -> dict[str, str]: def xdg_paths() -> dict[str, Path]:
return get_xdg_paths() return get_xdg_paths()
@pytest.fixture @pytest.fixture
def override(xdg_paths) -> None: def override(xdg_paths: dict[str, Path]) -> None:
apply_overrides(xdg_paths) apply_overrides(xdg_paths)
@pytest.fixture @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( conf_path = xdg_paths["XDG_DATA_HOME"].parent.joinpath(
f"flatpak/overrides/{FLATPAK_APPID}" f"flatpak/overrides/{FLATPAK_APPID}"
) )
@@ -32,14 +34,16 @@ def config(xdg_paths) -> configparser.ConfigParser:
return config 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] bus = config[BUS_KEY][GTK_APP_ID]
assert bus == "own" assert bus == "own"
def test_paths(override, xdg_paths, config) -> None: def test_paths(
expect: list[str] = [] override: None, xdg_paths: dict[str, Path], config: configparser.ConfigParser
expect.append(TMP_PATH) ) -> None:
expect: list[Path] = []
expect.append(Path(TMP_PATH))
expect.extend([*xdg_paths.values()]) expect.extend([*xdg_paths.values()])
paths = config[PATHS_KEY][PATHS_SUBKEY].split(";") paths = config[PATHS_KEY][PATHS_SUBKEY].split(";")
assert all(str(path) in paths for path in expect) 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.constants import FLATPAK_RUN_CMD, FLATPAK_SANDBOX
from dzgui.const.enum import Preferences from dzgui.const.enum import Preferences
from dzgui.controllers.mc import Controller
from dzgui.views.pages.options import FlatpakToggleField from dzgui.views.pages.options import FlatpakToggleField
class MockController: class MockController(Controller):
def __init__(self) -> None: def __init__(self) -> None:
self.command: str self.command: str
+6 -3
View File
@@ -20,20 +20,23 @@ def get_db_len(path: Path) -> int:
c = conn.cursor() c = conn.cursor()
c.execute("SELECT COUNT(*) from ips") c.execute("SELECT COUNT(*) from ips")
db_len = c.fetchone()[0] db_len = c.fetchone()[0]
return db_len return int(db_len)
@pytest.fixture @pytest.fixture
def csv() -> Path: def csv() -> Path:
csv = Path(tempfile.NamedTemporaryFile().name) csv = Path(tempfile.NamedTemporaryFile().name)
url = find_download_url(DB_IP) url = find_download_url(DB_IP)
if url is None:
raise TypeError
tmp = serialize(url) tmp = serialize(url)
unzip(tmp, csv) unzip(tmp, csv)
strip_ipv6(csv) strip_ipv6(csv)
return csv return csv
@pytest.mark.slow @pytest.mark.slow
def test_stripping(csv): def test_stripping(csv: Path) -> None:
with open(csv, "rb") as f: with open(csv, "rb") as f:
first = f.readline().decode().rstrip() first = f.readline().decode().rstrip()
try: try:
@@ -52,7 +55,7 @@ def test_stripping(csv):
@pytest.mark.slow @pytest.mark.slow
def test_row_parity(csv) -> None: def test_row_parity(csv: Path) -> None:
rows = csv.read_text().splitlines() rows = csv.read_text().splitlines()
db = Path(tempfile.NamedTemporaryFile().name) db = Path(tempfile.NamedTemporaryFile().name)
+9 -7
View File
@@ -1,26 +1,28 @@
import gi
import pytest import pytest
from dzgui.api.servers import Details from dzgui.api.servers import Details
from dzgui.controllers.mc import Controller
from dzgui.controllers.emitter import Emitter
from dzgui.views.dialogs.servers import ServerDetailsDialog from dzgui.views.dialogs.servers import ServerDetailsDialog
import gi
gi.require_version("Gtk", "3.0") gi.require_version("Gtk", "3.0")
from gi.repository import Gtk from gi.repository import Gtk
class MockController: class MockController(Controller):
def __init__(self) -> None: def __init__(self) -> None:
self.window = Gtk.Window() pass
def get_window(self) -> Gtk.Window: def get_window(self) -> None: # type: ignore[override]
return self.window return None
def get_server_name(self) -> str: def get_server_name(self) -> str:
return "My server" return "My server"
def get_emitter(self) -> None: def get_emitter(self) -> Emitter:
return None return Emitter()
@pytest.mark.filterwarnings("ignore::DeprecationWarning") @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), ("192.168.1.101:27016", True),
], ],
) )
def test_ip_entry(ip) -> None: def test_ip_entry(ip: tuple[str, bool]) -> None:
string, state = ip string, state = ip
assert validate_ip_truthy(string) is state assert validate_ip_truthy(string) is state
+11 -7
View File
@@ -1,27 +1,29 @@
import pytest import pytest
from typing import Any
from dzgui.model.model_factory import FastInsertListStore from dzgui.model.model_factory import FastInsertListStore
@pytest.fixture @pytest.fixture
def heterogeneous_list() -> None: def heterogeneous_list() -> list[list[Any]]:
return [["a", 0, True], ["b", 1, False]] return [["a", 0, True], ["b", 1, False]]
@pytest.fixture @pytest.fixture
def mismatched_length_list() -> None: def mismatched_length_list() -> list[list[Any]]:
return [["a", 0, True], ["b", 1, False, 0]] return [["a", 0, True], ["b", 1, False, 0]]
@pytest.fixture @pytest.fixture
def extended_list(heterogeneous_list) -> None: def extended_list(heterogeneous_list: list[list[Any]]) -> FastInsertListStore:
fs = FastInsertListStore(str, int, bool) fs = FastInsertListStore(str, int, bool)
fs.extend(heterogeneous_list) fs.extend(heterogeneous_list)
return fs return fs
@pytest.fixture @pytest.fixture
def appended_list(heterogeneous_list) -> None: def appended_list(heterogeneous_list: list[list[Any]]) -> FastInsertListStore:
fs = FastInsertListStore(str, int, bool) fs = FastInsertListStore(str, int, bool)
for row in heterogeneous_list: for row in heterogeneous_list:
fs.append(row) fs.append(row)
@@ -29,19 +31,21 @@ def appended_list(heterogeneous_list) -> None:
@pytest.mark.parametrize("target", ["extended_list", "appended_list"]) @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) target = request.getfixturevalue(target)
extracted = [[el for el in row] for row in target] extracted = [[el for el in row] for row in target]
assert heterogeneous_list == extracted 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): with pytest.raises(TypeError):
fs = FastInsertListStore(str, bool, bool) fs = FastInsertListStore(str, bool, bool)
fs.extend(heterogeneous_list) 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): with pytest.raises(ValueError):
fs = FastInsertListStore(str, int, bool) fs = FastInsertListStore(str, int, bool)
fs.extend(mismatched_length_list) fs.extend(mismatched_length_list)
+9 -4
View File
@@ -1,27 +1,32 @@
from typing import TYPE_CHECKING
from dzgui.util import localize 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") monkeypatch.setenv("LC_ALL", "de_DE.UTF-8")
localize.set_locale() localize.set_locale()
assert localize.number(9900) == "9.900" assert localize.number(9900) == "9.900"
assert localize.number(99.88) == "99,88" 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") monkeypatch.setenv("LC_ALL", "en_US.UTF-8")
localize.set_locale() localize.set_locale()
assert localize.number(9900) == "9,900" assert localize.number(9900) == "9,900"
assert localize.number(99.88) == "99.88" assert localize.number(99.88) == "99.88"
def test_none(monkeypatch): def test_none(monkeypatch: "MonkeyPatch") -> None:
localize.set_locale() localize.set_locale()
assert localize.number(9900) == "9,900" assert localize.number(9900) == "9,900"
assert localize.number(99.88) == "99.88" assert localize.number(99.88) == "99.88"
def test_empty(monkeypatch): def test_empty(monkeypatch: "MonkeyPatch") -> None:
monkeypatch.setenv("LC_ALL", "") monkeypatch.setenv("LC_ALL", "")
localize.set_locale() localize.set_locale()
assert localize.number(9900) == "9,900" 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): class RecordsListHandler(logging.Handler):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
self.records_list = [] self.records_list: list[logging.LogRecord] = []
def emit(self, record: logging.LogRecord) -> None: def emit(self, record: logging.LogRecord) -> None:
self.records_list.append(record) self.records_list.append(record)
def pop(self) -> None: def pop(self) -> str:
return self.records_list[-1].msg return str(self.records_list[-1].msg)
@pytest.mark.redact @pytest.mark.redact
+7 -1
View File
@@ -1,6 +1,7 @@
import pytest import pytest
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING
from dzgui.api.steam import find_user_id from dzgui.api.steam import find_user_id
from dzgui.const.constants import DEFAULT_STEAM_PATH from dzgui.const.constants import DEFAULT_STEAM_PATH
@@ -8,6 +9,9 @@ from tests.fixtures import fixture_path
pytestmark = pytest.mark.apitest pytestmark = pytest.mark.apitest
if TYPE_CHECKING:
from _pytest.monkeypatch import MonkeyPatch
@pytest.mark.parametrize( @pytest.mark.parametrize(
"fixture, expect", "fixture, expect",
@@ -19,12 +23,14 @@ pytestmark = pytest.mark.apitest
("api/loginusers_beta_client_multiple_2.vdf", 0), ("api/loginusers_beta_client_multiple_2.vdf", 0),
], ],
) )
def test_loginusers(monkeypatch, fixture: str, expect: int) -> None: def test_loginusers(monkeypatch: "MonkeyPatch", fixture: str, expect: int) -> None:
def mock_loginusers(path: Path) -> Path: def mock_loginusers(path: Path) -> Path:
return fixture_path(fixture) return fixture_path(fixture)
monkeypatch.setattr("dzgui.api.steam.find_loginusers", mock_loginusers) monkeypatch.setattr("dzgui.api.steam.find_loginusers", mock_loginusers)
uid = find_user_id(Path("")) uid = find_user_id(Path(""))
if uid is None:
raise TypeError
assert int(uid) == expect assert int(uid) == expect
+16 -6
View File
@@ -11,37 +11,47 @@ import dzgui.config.query
from tests.fixtures import fixture_path from tests.fixtures import fixture_path
if TYPE_CHECKING: if TYPE_CHECKING:
from dzgui.const.enums import Preferences from _pytest.monkeypatch import MonkeyPatch
from dzgui.const.enum import Preferences
pytestmark = pytest.mark.mods pytestmark = pytest.mark.mods
@pytest.fixture @pytest.fixture
def versions() -> str: def versions() -> "Path":
return fixture_path("dzg.versions") return fixture_path("dzg.versions")
@pytest.fixture @pytest.fixture
def tmp() -> str: def tmp() -> str:
with tempfile.NamedTemporaryFile(delete=False) as f: with tempfile.NamedTemporaryFile(delete=False) as f:
tmp = f.name tmp = f.name
return tmp return tmp
def mock_local_ids(path: Path) -> list[int]: def mock_local_ids(path: Path) -> list[int]:
return [3410710885, 3739934289] return [3410710885, 3739934289]
def mock_lookup(path: Path, prefs: "Preferences") -> str: def mock_lookup(path: Path, prefs: "Preferences") -> str:
return "" return ""
def test_signatures(monkeypatch, tmp: str, versions: str) -> None:
def test_signatures(monkeypatch: "MonkeyPatch", tmp: str, versions: str) -> None:
ids = [1559212036, 1654462998] ids = [1559212036, 1654462998]
shutil.copyfile(versions, tmp) shutil.copyfile(versions, tmp)
path = Path(tmp) path = Path(tmp)
monkeypatch.setattr("dzgui.api.mods.lookup", mock_lookup) monkeypatch.setattr("dzgui.api.mods.lookup", mock_lookup)
dzgui.api.mods.remove_stale_signatures(path, path, ids) dzgui.api.mods.remove_stale_signatures(path, path, ids)
with open(tmp, "r") as f: with open(tmp, "r") as f:
lines = f.readlines() lines = [line.rstrip() for line in f.readlines()]
assert ids not in lines concat = ",".join(map(str, ids))
assert concat not in lines
def test_signatures_with_no_ids(monkeypatch, tmp: str, versions: str) -> None:
def test_signatures_with_no_ids(
monkeypatch: "MonkeyPatch", tmp: str, versions: str
) -> None:
shutil.copyfile(versions, tmp) shutil.copyfile(versions, tmp)
path = Path(tmp) path = Path(tmp)
monkeypatch.setattr("dzgui.api.mods.get_local_mod_ids", mock_local_ids) monkeypatch.setattr("dzgui.api.mods.get_local_mod_ids", mock_local_ids)
+3
View File
@@ -4,10 +4,13 @@ from pathlib import Path
from dzgui.api.mods import tokenize from dzgui.api.mods import tokenize
from tests.fixtures import fixture_path from tests.fixtures import fixture_path
@pytest.mark.mods @pytest.mark.mods
@pytest.mark.parametrize("i", range(1, 7)) @pytest.mark.parametrize("i", range(1, 7))
def test_modmeta(i: int) -> None: def test_modmeta(i: int) -> None:
fixture = fixture_path(f"cpp/mod{i}") fixture = fixture_path(f"cpp/mod{i}")
path = Path(fixture) path = Path(fixture)
meta = tokenize(path) meta = tokenize(path)
if meta is None:
raise TypeError
assert meta["name"] == "ModName" assert meta["name"] == "ModName"
+6 -1
View File
@@ -1,8 +1,13 @@
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING
from dzgui.config.xdg import get_xdg_paths 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"] envs = ["XDG_DATA_HOME", "XDG_STATE_HOME", "XDG_CONFIG_HOME", "XDG_CACHE_HOME"]
for env in envs: for env in envs:
monkeypatch.setenv(env, "/etc/dzgui") monkeypatch.setenv(env, "/etc/dzgui")
+9 -3
View File
@@ -1,8 +1,12 @@
import pytest import pytest
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING
from dzgui.api.steam import is_dayz_downloading from dzgui.api.steam import is_dayz_downloading
if TYPE_CHECKING:
from _pytest.monkeypatch import MonkeyPatch
@pytest.mark.parametrize( @pytest.mark.parametrize(
"file_list, expect", "file_list, expect",
@@ -16,12 +20,14 @@ from dzgui.api.steam import is_dayz_downloading
(["state_221100_1111"], False), (["state_221100_1111"], False),
], ],
) )
def test_dayz_patch_pending(monkeypatch, file_list: list[str], expect: bool) -> None: def test_dayz_patch_pending(
def mock_get_pending_downloads(steam_path: Path, appid: int) -> None: monkeypatch: "MonkeyPatch", file_list: list[str], expect: bool
) -> None:
def mock_get_pending_downloads(steam_path: Path, appid: int) -> list[Path]:
files = [Path(file) for file in file_list] files = [Path(file) for file in file_list]
return files return files
monkeypatch.setattr( monkeypatch.setattr(
"dzgui.api.steam.get_pending_downloads", mock_get_pending_downloads "dzgui.api.steam.get_pending_downloads", mock_get_pending_downloads
) )
assert is_dayz_downloading(Path("/tmp"), Path("/tmp")) == expect assert is_dayz_downloading(Path("/tmp"), 221100) == expect
+14 -8
View File
@@ -1,6 +1,7 @@
import pytest import pytest
from pathlib import Path
from pathlib import Path
from typing import TYPE_CHECKING
import dzgui.api.pefile as PeFile import dzgui.api.pefile as PeFile
from dzgui.api.steam import ( from dzgui.api.steam import (
@@ -16,19 +17,22 @@ from dzgui.const.constants import APPID_DAYZ
from tests.fixtures import fixture_path from tests.fixtures import fixture_path
if TYPE_CHECKING:
from _pytest.monkeypatch import MonkeyPatch
pytestmark = pytest.mark.apitest pytestmark = pytest.mark.apitest
@pytest.fixture @pytest.fixture
def default_steam_path(): def default_steam_path() -> str:
paths = get_xdg_paths() paths = get_xdg_paths()
xdg = parse_filepaths(paths) xdg = parse_filepaths(paths)
conf = get_config(xdg.config) conf = get_config(xdg.config)
return conf["default_steam_path"] return str(conf["default_steam_path"])
# TODO: additional parsing tests # TODO: additional parsing tests
def test_pefile_length(default_steam_path): def test_pefile_length(default_steam_path: str) -> None:
try: try:
pe_file_path = PeFile.get_pefile_path(Path(default_steam_path), APPID_DAYZ) pe_file_path = PeFile.get_pefile_path(Path(default_steam_path), APPID_DAYZ)
vers = PeFile.get_dayz_version(pe_file_path) vers = PeFile.get_dayz_version(pe_file_path)
@@ -38,7 +42,7 @@ def test_pefile_length(default_steam_path):
assert len(st) == 3 assert len(st) == 3
def test_invalid_pefile_path(): def test_invalid_pefile_path() -> None:
with pytest.raises(VDFLoadError): with pytest.raises(VDFLoadError):
try: try:
PeFile.get_pefile_path(Path("/not/a/path"), APPID_DAYZ) PeFile.get_pefile_path(Path("/not/a/path"), APPID_DAYZ)
@@ -55,7 +59,9 @@ def test_invalid_pefile_path():
("malformed.vdf", VDFLoadError), ("malformed.vdf", VDFLoadError),
], ],
) )
def test_not_in_library(monkeypatch, fixture, exception): def test_not_in_library(
monkeypatch: "MonkeyPatch", fixture: str, exception: type[Exception]
) -> None:
import dzgui.api.steam as steam import dzgui.api.steam as steam
monkeypatch.setattr(steam, "LIBRARYFOLDERS_PATH", fixture) monkeypatch.setattr(steam, "LIBRARYFOLDERS_PATH", fixture)
@@ -69,11 +75,11 @@ def test_not_in_library(monkeypatch, fixture, exception):
@pytest.fixture @pytest.fixture
def second_drive(): def second_drive() -> str:
return "in_library_on_second_drive.vdf" return "in_library_on_second_drive.vdf"
def test_on_second_drive(monkeypatch, second_drive): def test_on_second_drive(monkeypatch: "MonkeyPatch", second_drive: str) -> None:
import dzgui.api.steam as steam import dzgui.api.steam as steam
monkeypatch.setattr(steam, "LIBRARYFOLDERS_PATH", second_drive) monkeypatch.setattr(steam, "LIBRARYFOLDERS_PATH", second_drive)
+9 -7
View File
@@ -1,6 +1,8 @@
import pytest import pytest
import unittest import unittest
from unittest.mock import patch from unittest.mock import patch
from typing import Any
from dzgui.const.constants import ( from dzgui.const.constants import (
FLATPAK_APPID, FLATPAK_APPID,
@@ -14,9 +16,9 @@ pytestmark = pytest.mark.flatpak
class TestSteamDetection(unittest.TestCase): class TestSteamDetection(unittest.TestCase):
def test_flatpak_detection_with_multiple_running_apps(self): def test_flatpak_detection_with_multiple_running_apps(self) -> None:
def flatpak_output(args, *, text): def flatpak_output(args: Any, *, text: str) -> str:
# Default `flatpak ps` includes instance, PID, app and runtime columns. # Default 'flatpak ps' includes instance, PID, app and runtime columns.
if args == ["flatpak", "ps", "--columns=application"]: if args == ["flatpak", "ps", "--columns=application"]:
return f"com.spotify.Client\n{FLATPAK_APPID}\n{FLATPAK_APPID}\n" return f"com.spotify.Client\n{FLATPAK_APPID}\n{FLATPAK_APPID}\n"
return f"3904921611\t1257689\t{FLATPAK_APPID}\torg.freedesktop.Platform\n" return f"3904921611\t1257689\t{FLATPAK_APPID}\torg.freedesktop.Platform\n"
@@ -29,7 +31,7 @@ class TestSteamDetection(unittest.TestCase):
with self.subTest(client=client): with self.subTest(client=client):
self.assertTrue(proc.is_steam_running(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): with patch.object(proc, "has_cmd", return_value=True):
for output in ("", "com.spotify.Client\n", f"{FLATPAK_APPID}Helper\n"): for output in ("", "com.spotify.Client\n", f"{FLATPAK_APPID}Helper\n"):
with ( with (
@@ -38,7 +40,7 @@ class TestSteamDetection(unittest.TestCase):
): ):
self.assertFalse(proc.is_flatpak_steam_running()) self.assertFalse(proc.is_flatpak_steam_running())
def test_flatpak_not_installed(self): def test_flatpak_not_installed(self) -> None:
with ( with (
patch.object(proc, "has_cmd", return_value=False), patch.object(proc, "has_cmd", return_value=False),
patch.object(proc.subprocess, "check_output") as check_output, patch.object(proc.subprocess, "check_output") as check_output,
@@ -46,7 +48,7 @@ class TestSteamDetection(unittest.TestCase):
self.assertFalse(proc.is_flatpak_steam_running()) self.assertFalse(proc.is_flatpak_steam_running())
check_output.assert_not_called() 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): with patch.object(proc, "has_cmd", return_value=True):
for output, expected in ( for output, expected in (
( (
@@ -73,6 +75,6 @@ class TestSteamDetection(unittest.TestCase):
): ):
self.assertEqual(proc.is_native_steam_running(), expected) self.assertEqual(proc.is_native_steam_running(), expected)
def test_invalid_client(self): def test_invalid_client(self) -> None:
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
proc.is_steam_running("invalid-client") proc.is_steam_running("invalid-client")
+6 -4
View File
@@ -1,23 +1,25 @@
import pytest import pytest
from typing import Any
from dzgui.api import probe
from dzgui.config.query import get_config from dzgui.config.query import get_config
from dzgui.config.xdg import get_xdg_paths, parse_filepaths from dzgui.config.xdg import get_xdg_paths, parse_filepaths
from dzgui.api import probe
pytestmark = pytest.mark.webtest pytestmark = pytest.mark.webtest
@pytest.fixture @pytest.fixture
def config(): def config() -> Any:
paths = get_xdg_paths() paths = get_xdg_paths()
xdg = parse_filepaths(paths) xdg = parse_filepaths(paths)
return get_config(xdg.config) return get_config(xdg.config)
def test_ipdb(): def test_ipdb() -> None:
assert probe.test_ipdb() assert probe.test_ipdb()
def test_steam(config): def test_steam(config: Any) -> None:
key = config["steam_api"] key = config["steam_api"]
assert probe.test_steam_api(key) assert probe.test_steam_api(key)
+3 -2
View File
@@ -18,9 +18,10 @@ def test_row_conversion() -> None:
"Unofficial", "Unofficial",
False, False,
] ]
rows = [ServerRow(*data)] rows = [ServerRow(*data)] # type: ignore
marshalled = ServerRow.marshal_rows(rows) marshalled = ServerRow.marshal_rows(rows)
store = ModelFactory().make_server_store() store = ModelFactory().make_server_store()
store.extend(marshalled) store.extend(marshalled)
converted = [[el for el in row] for row in store] cols = store.get_n_columns()
converted = [[row[i] for i in range(cols)] for row in store]
assert data == converted[0] assert data == converted[0]
+10 -4
View File
@@ -3,9 +3,11 @@ import re
from dzgui.api.servers import Details, Record, get_details from dzgui.api.servers import Details, Record, get_details
pytestmark = pytest.mark.slow
@pytest.fixture @pytest.fixture
def details() -> Details: def details() -> Details | None:
""" """
Static official server, metadata is expected to be invariate Static official server, metadata is expected to be invariate
""" """
@@ -19,17 +21,21 @@ def test_invalid_server() -> None:
@pytest.mark.parametrize("key, expect", [("day_accel", 2.3), ("night_accel", 6.8)]) @pytest.mark.parametrize("key, expect", [("day_accel", 2.3), ("night_accel", 6.8)])
def test_time_accel(details, key, expect) -> None: def test_time_accel(details: Details | None, key: str, expect: float) -> None:
assert getattr(details, key) == expect 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]$)" time_reg = r"^(0[0-9]|1[0-9]|2[0-3]):([0-5][0-9]$)"
if details is None:
raise TypeError
match = re.match(time_reg, details.gametime) match = re.match(time_reg, details.gametime)
assert match is not None assert match is not None
def test_metadata(details) -> None: def test_metadata(details: Details | None) -> None:
if details is None:
raise TypeError
for row in details.data: for row in details.data:
label, value = row label, value = row
match label: match label:
+18 -17
View File
@@ -1,9 +1,9 @@
import pytest import pytest
from hypothesis import given, strategies as st
from datetime import datetime, timedelta from datetime import datetime, timedelta
from hypothesis import given, strategies as st
from dzgui.views.dialogs.calc import ( from dzgui.views.dialogs.calc import (
Emitter,
LocalClock, LocalClock,
ServerClock, ServerClock,
Time, Time,
@@ -13,31 +13,28 @@ from dzgui.views.dialogs.calc import (
) )
class DummyEmitter:
def __init__(self) -> None:
pass
def connect(self, _, __) -> None:
pass
@pytest.fixture(params=[("05:00", 10.0), ("15:30", 5.0)]) @pytest.fixture(params=[("05:00", 10.0), ("15:30", 5.0)])
def accel_server_clock(request) -> None: def accel_server_clock(request: pytest.FixtureRequest) -> tuple[str, ServerClock]:
clock_time, expect = request.param clock_time, expect = request.param
cur_time = Time(clock_time, 5.0, 2.0) cur_time = Time(clock_time, 5.0, 2.0)
emitter = DummyEmitter() emitter = Emitter()
local_clock = LocalClock(emitter) local_clock = LocalClock(emitter)
server_clock = ServerClock(cur_time, emitter, local_clock) server_clock = ServerClock(cur_time, emitter, local_clock)
return expect, server_clock return expect, server_clock
def test_accel_factor(accel_server_clock) -> None: def test_accel_factor(accel_server_clock: tuple[float, ServerClock]) -> None:
"""Static test checking times at known boundaries""" """Static test checking times at known boundaries"""
expect, clock = accel_server_clock expect, clock = accel_server_clock
assert clock.get_accel_factor(clock.cur_time) == expect assert clock.get_accel_factor(clock.cur_time) == expect
def reference_calc(start, end, day_factor, night_factor): def reference_calc(
start: datetime,
end: datetime,
day_factor: float,
night_factor: float,
) -> timedelta:
""" """
Reference implementation to test validity of UI-side calculator Reference implementation to test validity of UI-side calculator
Aggregates total seconds and applies accel factors after Aggregates total seconds and applies accel factors after
@@ -80,7 +77,7 @@ night_accel = st.floats(
@st.composite @st.composite
def time_ranges(draw): def time_ranges(draw: st.DrawFn) -> tuple[datetime, datetime]:
start_time = draw(st.times()) start_time = draw(st.times())
deltas = st.timedeltas(min_value=timedelta(0), max_value=timedelta(days=1)) deltas = st.timedeltas(min_value=timedelta(0), max_value=timedelta(days=1))
duration = draw(deltas) duration = draw(deltas)
@@ -91,12 +88,16 @@ def time_ranges(draw):
@given(span=time_ranges(), day_factor=day_accel, night_factor=night_accel) @given(span=time_ranges(), day_factor=day_accel, night_factor=night_accel)
def test_time_aggregation(span, day_factor, night_factor) -> None: def test_time_aggregation(
span: tuple[datetime, datetime],
day_factor: float,
night_factor: float,
) -> None:
start, end = span start, end = span
strtime = start.strftime("%H:%M") strtime = start.strftime("%H:%M")
t = Time(strtime, day_factor, night_factor) t = Time(strtime, day_factor, night_factor)
emitter = DummyEmitter() emitter = Emitter()
local_clock = LocalClock(emitter) local_clock = LocalClock(emitter)
server_clock = ServerClock(t, emitter, local_clock) server_clock = ServerClock(t, emitter, local_clock)
h = end.time().hour h = end.time().hour
+41 -37
View File
@@ -1,91 +1,95 @@
import pytest import pytest
import tempfile import tempfile
from pathlib import Path
from _pytest.monkeypatch import MonkeyPatch from _pytest.monkeypatch import MonkeyPatch
from collections.abc import Iterator
from pathlib import Path
from typing import Any, cast, TYPE_CHECKING
from dzgui.api.shortcuts import Shortcuts from dzgui.api.shortcuts import Shortcuts
from tests.fixtures import fixture_path from tests.fixtures import fixture_path
if TYPE_CHECKING:
from _pytest.monkeypatch import MonkeyPatch
pytestmark = pytest.mark.apitest pytestmark = pytest.mark.apitest
def mock_find_shortcuts(self, steam_path: Path) -> Path: def mock_find_shortcuts(self: Shortcuts, steam_path: Path) -> Path:
return Path(fixture_path("api/no_shortcuts.vdf")) return Path(fixture_path("api/no_shortcuts.vdf"))
@pytest.fixture(scope="module", autouse=True) @pytest.fixture(scope="module", autouse=True)
def patch_api() -> None: def patch_api() -> Iterator[None]:
mp = MonkeyPatch() mp = MonkeyPatch()
mp.setattr("dzgui.api.shortcuts.Shortcuts.find_shortcuts_path", mock_find_shortcuts) mp.setattr("dzgui.api.shortcuts.Shortcuts.find_shortcuts_path", mock_find_shortcuts)
yield yield
mp.undo() mp.undo()
def test_no_shortcuts(monkeypatch) -> None: def test_no_shortcuts(monkeypatch: "MonkeyPatch") -> None:
s = Shortcuts(Path("")) s = Shortcuts(Path(""))
assert len(s.shortcuts["shortcuts"]) == 0 assert len(s.shortcuts["shortcuts"]) == 0
@pytest.fixture @pytest.fixture
def dummy_app() -> None: def dummy_app() -> dict[str, Any]:
d = { d = {
"AppName": "TEST APP", "AppName": "TEST APP",
"StartDir": "TEST_DIR", "StartDir": Path("TEST_DIR"),
"Exe": "TEST_DIR/TEST_EXE.EXE", "Exe": Path("TEST_DIR/TEST_EXE.EXE"),
"icon": "IMAGES_DIR/TEST_IMAGE.PNG", "icon": Path("IMAGES_DIR/TEST_IMAGE.PNG"),
} }
return d return d
def test_wrap_exe(dummy_app: dict[str, str]) -> None: @pytest.fixture
def shortcuts(dummy_app: dict[str, Any]) -> Shortcuts:
s = Shortcuts(Path("")) s = Shortcuts(Path(""))
s.add_shortcut(*dummy_app.values()) args = cast(tuple[str, Path, Path, Path], dummy_app.values())
assert s.shortcuts["shortcuts"]["0"]["Exe"][0] == '"' s.add_shortcut(*args)
assert s.shortcuts["shortcuts"]["0"]["Exe"][-1] == '"' return s
def test_add_shortcut(dummy_app: dict[str, str]) -> None: def test_wrap_exe(shortcuts: Shortcuts) -> None:
s = Shortcuts(Path("")) assert shortcuts.shortcuts["shortcuts"]["0"]["Exe"][0] == '"'
s.add_shortcut(*dummy_app.values()) assert shortcuts.shortcuts["shortcuts"]["0"]["Exe"][-1] == '"'
new = s.shortcuts["shortcuts"]
def test_add_shortcut(shortcuts: Shortcuts, dummy_app: dict[str, Any]) -> None:
new = shortcuts.shortcuts["shortcuts"]
ind = str(len(new) - 1) ind = str(len(new) - 1)
for k, v in dummy_app.items(): for k, v in dummy_app.items():
if k == "Exe": if k == "Exe":
v = f'"{v}"' v = f'"{v}"'
assert new[ind][k] == v assert new[ind][k] == str(v)
def test_save_shortcut(dummy_app: dict[str, str]) -> None: def test_save_shortcut(shortcuts: Shortcuts) -> None:
s = Shortcuts(Path(""))
s.add_shortcut(*dummy_app.values())
with tempfile.NamedTemporaryFile() as f: with tempfile.NamedTemporaryFile() as f:
tmp = Path(f.name) tmp = Path(f.name)
s.shortcuts_path = tmp shortcuts.shortcuts_path = tmp
s.save_shortcuts() shortcuts.save_shortcuts()
s._load_shortcuts(tmp) shortcuts._load_shortcuts(tmp)
assert len(s.shortcuts["shortcuts"]) == 1 assert len(shortcuts.shortcuts["shortcuts"]) == 1
def test_shortcut_crc(dummy_app: dict[str, str]) -> None: def test_shortcut_crc(shortcuts: Shortcuts) -> None:
s = Shortcuts(Path("")) for key in shortcuts.shortcuts["shortcuts"].keys():
s.add_shortcut(*dummy_app.values()) entry = shortcuts.shortcuts["shortcuts"][key]
for key in s.shortcuts["shortcuts"].keys():
entry = s.shortcuts["shortcuts"][key]
name = entry["AppName"] name = entry["AppName"]
exe = entry["Exe"] exe = entry["Exe"]
uid = name + exe uid = name + exe
bpid = s.gen_bpid(uid) bpid = shortcuts.gen_bpid(uid)
assert entry["appid"] & 0xFFFFFFFF == bpid assert entry["appid"] & 0xFFFFFFFF == bpid
def test_reverse_crc(dummy_app: dict[str, str]) -> None: def test_reverse_crc(shortcuts: Shortcuts) -> None:
s = Shortcuts(Path("")) for key in shortcuts.shortcuts["shortcuts"].keys():
s.add_shortcut(*dummy_app.values()) entry = shortcuts.shortcuts["shortcuts"][key]
for key in s.shortcuts["shortcuts"].keys():
entry = s.shortcuts["shortcuts"][key]
name = entry["AppName"] name = entry["AppName"]
exe = entry["Exe"] exe = entry["Exe"]
uid = name + exe uid = name + exe
bpid = s.gen_bpid(uid) bpid = shortcuts.gen_bpid(uid)
assert s.find_appname_by_unsigned_id(bpid) == name assert shortcuts.find_appname_by_unsigned_id(bpid) == name
+2 -1
View File
@@ -2,7 +2,8 @@ import re
from dzgui.model.proxy_model import DAY_REG, NIGHT_REG from dzgui.model.proxy_model import DAY_REG, NIGHT_REG
def iterate(h: str, r: str) -> None:
def iterate(h: int, r: str) -> None:
for m in range(60): for m in range(60):
time = f"{h:02}:{m:02}" time = f"{h:02}:{m:02}"
assert re.match(r, time) is not None assert re.match(r, time) is not None