zapretgui/tests/test_runtime_layout.py
loop-uh 8d4a04f27c
Some checks failed
Zapret source guards / validate (push) Successful in 4s
Windows-сборка / Stable Stable 21.1.1.6 опубликован
Windows-сборка / Dev Ошибка: Сборка Nuitka (21.1.5.67)
Хранить запасной кэш обновления в user
2026-08-16 18:40:19 +03:00

209 lines
8.6 KiB
Python

from __future__ import annotations
from pathlib import Path
import sys
import unittest
PUBLIC_ROOT = Path(__file__).resolve().parents[1]
SRC_ROOT = PUBLIC_ROOT / "src"
if str(SRC_ROOT) not in sys.path:
sys.path.insert(0, str(SRC_ROOT))
from config.runtime_layout import ( # noqa: E402
ApplicationPaths,
RUNTIME_DIR_NAME,
SourceApplicationLaunchForbidden,
require_packaged_application,
resolve_application_root,
resolve_runtime_root,
)
from config import runtime_layout # noqa: E402
from core.paths import AppPaths # noqa: E402
class RuntimeLayoutTests(unittest.TestCase):
def test_all_application_folders_follow_a_changed_install_root(self) -> None:
root = Path("D:/Программы/ZapretCustom").resolve()
paths = ApplicationPaths.from_root(root)
expected = {
"runtime_dir": root / "_internal",
"executable": root / "_internal" / "Zapret.exe",
"bin_dir": root / "bin",
"exe_dir": root / "exe",
"ico_dir": root / "system" / "ico",
"system_dir": root / "system",
"user_dir": root / "user",
"user_lua_dir": root / "user" / "lua",
"hosts_catalog_database": root / "system" / "hosts_catalog.sqlite3",
"strategy_catalogs_dir": root / "system" / "strategy_catalogs",
"profile_templates_dir": root / "system" / "templates",
"lists_dir": root / "lists",
"lists_base_dir": root / "lists" / "base",
"lists_user_dir": root / "lists" / "user",
"lua_dir": root / "lua",
"presets_dir": root / "presets",
"settings_database": root / "user" / "settings.sqlite3",
"premium_database": root / "user" / "premium.sqlite3",
"logs_dir": root / "user" / "logs",
"crash_logs_dir": root / "user" / "logs" / "crashes",
"tmp_dir": root / "user" / "tmp",
"themes_dir": root / "system" / "themes",
"windivert_filter_dir": root / "windivert.filter",
"update_cache_dir": root / "user" / "update_cache",
"stable_icon": root / "system" / "ico" / "Zapret2.ico",
"dev_icon": root / "system" / "ico" / "ZapretDevLogo4.ico",
"sidebar_icons_dir": root / "system" / "ico" / "windows11_fluent" / "sidebar",
}
for attribute, expected_path in expected.items():
with self.subTest(attribute=attribute):
self.assertEqual(getattr(paths, attribute), expected_path)
def test_runtime_path_consumers_do_not_restore_separate_folder_constants(self) -> None:
config_source = (SRC_ROOT / "config" / "config.py").read_text(encoding="utf-8")
forbidden_names = (
"BIN_FOLDER",
"INDEXJSON_FOLDER",
"EXE_FOLDER",
"LUA_FOLDER",
"ICO_FOLDER",
"THEME_FOLDER",
"WINDIVERT_FILTER",
"ICON_PATH",
"ICON_DEV_PATH",
)
for name in forbidden_names:
with self.subTest(name=name):
self.assertNotIn(name, config_source)
critical_sources = (
SRC_ROOT / "main" / "early_startup_crash.py",
SRC_ROOT / "main" / "prelaunch.py",
SRC_ROOT / "autostart" / "nssm_service.py",
SRC_ROOT / "app" / "navigation_icon_resources.py",
)
for path in critical_sources:
source = path.read_text(encoding="utf-8")
with self.subTest(path=path.name):
self.assertTrue(
"APPLICATION_PATHS" in source or "APPLICATION_RESOURCE_PATHS" in source
)
self.assertNotIn("Path.cwd()", source)
self.assertNotIn("abspath(__file__)", source)
def test_source_tree_has_no_hard_coded_install_root(self) -> None:
for path in SRC_ROOT.rglob("*.py"):
source = path.read_text(encoding="utf-8", errors="replace")
with self.subTest(path=path.relative_to(SRC_ROOT)):
self.assertNotIn(r"C:\Zapret", source)
self.assertNotIn("C:/Zapret", source)
def test_packaged_detection_supports_nuitka_and_pyinstaller(self) -> None:
previous_frozen = getattr(sys, "frozen", None)
had_frozen = hasattr(sys, "frozen")
try:
sys.frozen = True
self.assertTrue(runtime_layout.is_packaged_runtime())
finally:
if had_frozen:
sys.frozen = previous_frozen
else:
delattr(sys, "frozen")
runtime_layout.__dict__["__compiled__"] = object()
try:
self.assertTrue(runtime_layout.is_packaged_runtime())
finally:
runtime_layout.__dict__.pop("__compiled__", None)
def test_packaged_runtime_uses_parent_of_internal(self) -> None:
executable = Path("C:/Zapret/Dev") / RUNTIME_DIR_NAME / "Zapret.exe"
root = resolve_application_root(
executable=executable,
module_file=SRC_ROOT / "config" / "runtime_layout.py",
packaged=True,
)
self.assertEqual(root, Path("C:/Zapret/Dev").resolve())
self.assertEqual(
resolve_runtime_root(executable=executable, packaged=True),
(Path("C:/Zapret/Dev") / RUNTIME_DIR_NAME).resolve(),
)
def test_packaged_preset_paths_stay_inside_channel_install_root(self) -> None:
executable = Path("C:/Zapret/Dev") / RUNTIME_DIR_NAME / "Zapret.exe"
app_root = resolve_application_root(
executable=executable,
module_file=SRC_ROOT / "config" / "runtime_layout.py",
packaged=True,
)
engine_paths = AppPaths(user_root=app_root, local_root=app_root).engine_paths("winws2")
self.assertEqual(engine_paths.presets_root_dir, Path("C:/Zapret/Dev/presets").resolve())
self.assertEqual(engine_paths.user_presets_dir, Path("C:/Zapret/Dev/presets/winws2").resolve())
self.assertEqual(
engine_paths.builtin_presets_dir,
Path("C:/Zapret/Dev/presets/winws2_builtin").resolve(),
)
self.assertNotEqual(engine_paths.presets_root_dir, Path("C:/Zapret/presets").resolve())
def test_flat_packaged_runtime_is_rejected(self) -> None:
with self.assertRaisesRegex(RuntimeError, "Некорректная структура"):
resolve_application_root(
executable=Path("C:/Zapret/Dev/Zapret.exe"),
module_file=SRC_ROOT / "config" / "runtime_layout.py",
packaged=True,
)
def test_build_tool_import_uses_public_repository_root(self) -> None:
module_file = PUBLIC_ROOT / "src" / "config" / "runtime_layout.py"
root = resolve_application_root(
executable=sys.executable,
module_file=module_file,
packaged=False,
)
self.assertEqual(root, PUBLIC_ROOT.resolve())
self.assertIsNone(resolve_runtime_root(executable=sys.executable, packaged=False))
def test_source_application_entrypoint_is_forbidden(self) -> None:
with self.assertRaisesRegex(SourceApplicationLaunchForbidden, "запрещён"):
require_packaged_application()
def test_main_checks_packaged_runtime_before_application_imports(self) -> None:
main_source = (SRC_ROOT / "main.py").read_text(encoding="utf-8")
gate = main_source.index("require_packaged_application()")
process_start = main_source.index("import main.process_start_time")
crash_handler = main_source.index("from main.early_startup_crash")
self.assertLess(gate, process_start)
self.assertLess(gate, crash_handler)
def test_internal_application_entrypoint_repeats_packaged_runtime_gate(self) -> None:
entry_source = (SRC_ROOT / "main" / "entry.py").read_text(encoding="utf-8")
main_body = entry_source.split("def main() -> None:", 1)[1]
self.assertIn("require_packaged_application()", main_body)
self.assertLess(
main_body.index("require_packaged_application()"),
main_body.index('log("=== ЗАПУСК ПРИЛОЖЕНИЯ ==="'),
)
def test_runtime_helpers_do_not_fall_back_to_source_launch(self) -> None:
admin_source = (SRC_ROOT / "startup" / "admin_check.py").read_text(encoding="utf-8")
kaspersky_source = (SRC_ROOT / "startup" / "kaspersky.py").read_text(encoding="utf-8")
self.assertNotIn("sys.argv[0]", admin_source)
self.assertNotIn("zapret.pyw", kaspersky_source)
self.assertNotIn("getattr(sys, \"frozen\"", kaspersky_source)
if __name__ == "__main__":
unittest.main()