mirror of
https://github.com/aclist/dztui.git
synced 2026-11-12 13:00:37 +01:00
chore: typehint tests
This commit is contained in:
1 parent
a5374d1f1a
commit
e29433b388
23 files changed
+170
-93
No files matched your search
Vendored
+4
-2
@@ -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)
|
||||||
@@ -43,23 +43,25 @@ def patch_api() -> None:
|
|||||||
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)
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ gi.require_version("Gtk", "3.0")
|
|||||||
from gi.repository import Gtk, Gio, GLib # noqa
|
from gi.repository import Gtk, Gio, GLib # noqa
|
||||||
|
|
||||||
|
|
||||||
class DummyWidget(ColorAwareApp, Gtk.Button):
|
class DummyWidget(ColorAwareApp, Gtk.Button): # type: ignore
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
@@ -27,7 +27,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
@@ -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
@@ -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()
|
||||||
@@ -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,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
|
||||||
|
|
||||||
|
|||||||
@@ -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 ValueError()
|
||||||
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)
|
||||||
|
|||||||
@@ -1,26 +1,30 @@
|
|||||||
|
import gi
|
||||||
import pytest
|
import pytest
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
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.base import OuterWindow
|
||||||
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
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
@@ -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"
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
@@ -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,7 +20,9 @@ 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(
|
||||||
|
monkeypatch: "MonkeyPatch", file_list: list[str], expect: bool
|
||||||
|
) -> None:
|
||||||
def mock_get_pending_downloads(steam_path: Path, appid: int) -> None:
|
def mock_get_pending_downloads(steam_path: Path, appid: int) -> None:
|
||||||
files = [Path(file) for file in file_list]
|
files = [Path(file) for file in file_list]
|
||||||
return files
|
return files
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from dzgui.api.steam import (
|
|||||||
VDFLoadError,
|
VDFLoadError,
|
||||||
AppNotInstalledError,
|
AppNotInstalledError,
|
||||||
AppMovedError,
|
AppMovedError,
|
||||||
get_app_path
|
get_app_path,
|
||||||
)
|
)
|
||||||
|
|
||||||
from dzgui.config.query import get_config
|
from dzgui.config.query import get_config
|
||||||
@@ -20,16 +20,14 @@ 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: split into separate test file
|
def test_pefile_length(default_steam_path: str) -> None:
|
||||||
# FIXME: use fixtures
|
|
||||||
def test_pefile_length(default_steam_path):
|
|
||||||
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)
|
||||||
@@ -39,7 +37,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)
|
||||||
@@ -57,6 +55,7 @@ def test_invalid_pefile_path():
|
|||||||
)
|
)
|
||||||
def test_not_in_library(monkeypatch, fixture, exception):
|
def test_not_in_library(monkeypatch, fixture, exception):
|
||||||
import dzgui.api.steam as steam
|
import dzgui.api.steam as steam
|
||||||
|
|
||||||
monkeypatch.setattr(steam, "LIBRARYFOLDERS_PATH", fixture)
|
monkeypatch.setattr(steam, "LIBRARYFOLDERS_PATH", fixture)
|
||||||
|
|
||||||
folder_path = Path(fixture_path("api"))
|
folder_path = Path(fixture_path("api"))
|
||||||
@@ -68,12 +67,13 @@ 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, 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)
|
||||||
folder_path = Path(fixture_path("api"))
|
folder_path = Path(fixture_path("api"))
|
||||||
path = get_app_path(folder_path, APPID_DAYZ)
|
path = get_app_path(folder_path, APPID_DAYZ)
|
||||||
|
|||||||
@@ -14,9 +14,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, *, 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 +29,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 +38,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 +46,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 +73,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")
|
||||||
@@ -1,23 +1,28 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
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
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
pytestmark = pytest.mark.webtest
|
pytestmark = pytest.mark.webtest
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def config():
|
def config() -> dict[str, "Path"]:
|
||||||
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: dict[str, "Path"]) -> None:
|
||||||
key = config["steam_api"]
|
key = config["steam_api"]
|
||||||
assert probe.test_steam_api(key)
|
assert probe.test_steam_api(key)
|
||||||
@@ -23,7 +23,7 @@ def test_time_accel(details, key, expect) -> 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]$)"
|
||||||
match = re.match(time_reg, details.gametime)
|
match = re.match(time_reg, details.gametime)
|
||||||
assert match is not None
|
assert match is not None
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
import pytest
|
import pytest
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from _pytest.monkeypatch import MonkeyPatch
|
from _pytest.monkeypatch import MonkeyPatch
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
@@ -22,13 +27,13 @@ def patch_api() -> None:
|
|||||||
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, str]:
|
||||||
d = {
|
d = {
|
||||||
"AppName": "TEST APP",
|
"AppName": "TEST APP",
|
||||||
"StartDir": "TEST_DIR",
|
"StartDir": "TEST_DIR",
|
||||||
|
|||||||
Reference in new issue
Block a user