Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions Libraries/PyKotor/tests/cli/test_json_commands.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
from __future__ import annotations

import base64
import io
import json
import logging

from argparse import Namespace
from pathlib import Path
from unittest.mock import patch

import pytest
from loggerplus import RobustLogger
Expand All @@ -28,6 +30,7 @@
from pykotor.resource.type import ResourceType
from pykotor.tools.resource_json import (
_serialize_mdl_face,
_supports_live_progress,
export_installation_to_json_tree,
iter_installation_resource_documents,
serialize_file_resource_document,
Expand Down Expand Up @@ -922,3 +925,27 @@ def fake_main(argv: list[str]) -> int:
assert "--merge-module" in captured_argv
assert captured_argv.count("--merge-path") == 2
assert "--merge-conflict-policy" in captured_argv


@pytest.mark.parametrize("env_name", ["CI", "GITHUB_ACTIONS"])
@pytest.mark.parametrize("env_value", ["true", "1", "yes", "TRUE"])
def test_supports_live_progress_disabled_in_ci_env(
env_name: str, env_value: str, monkeypatch: pytest.MonkeyPatch
) -> None:
tty_stream = io.StringIO()
monkeypatch.setenv(env_name, env_value)
with patch.object(tty_stream, "isatty", return_value=True):
assert _supports_live_progress(tty_stream) is False


def test_supports_live_progress_follows_tty_when_not_in_ci(
monkeypatch: pytest.MonkeyPatch,
) -> None:
tty_stream = io.StringIO()
non_tty_stream = io.StringIO()
monkeypatch.delenv("CI", raising=False)
monkeypatch.delenv("GITHUB_ACTIONS", raising=False)
with patch.object(tty_stream, "isatty", return_value=True):
assert _supports_live_progress(tty_stream) is True
with patch.object(non_tty_stream, "isatty", return_value=False):
assert _supports_live_progress(non_tty_stream) is False
96 changes: 96 additions & 0 deletions Libraries/PyKotor/tests/common/test_is_kotor_install_dir.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
from __future__ import annotations

import pathlib
import sys
import tempfile
import unittest

THIS_SCRIPT_PATH = pathlib.Path(__file__).resolve()
PYKOTOR_PATH = THIS_SCRIPT_PATH.parents[3].joinpath("src")
UTILITY_PATH = THIS_SCRIPT_PATH.parents[5].joinpath("Libraries", "Utility", "src")


def add_sys_path(p: pathlib.Path) -> None:
working_dir = str(p)
if working_dir not in sys.path:
sys.path.append(working_dir)


if PYKOTOR_PATH.joinpath("pykotor").exists():
add_sys_path(PYKOTOR_PATH)
if UTILITY_PATH.joinpath("utility").exists():
add_sys_path(UTILITY_PATH)

from pykotor.diff_tool.cli_utils import is_kotor_install_dir as cli_is_kotor_install_dir
from pykotor.tools.patching import is_kotor_install_dir as patching_is_kotor_install_dir
from pykotor.tslpatcher.diff.engine import is_kotor_install_dir as engine_is_kotor_install_dir


class TestIsKotorInstallDir(unittest.TestCase):
_IMPLEMENTATIONS = (
("cli_utils", cli_is_kotor_install_dir),
("patching", patching_is_kotor_install_dir),
("diff_engine", engine_is_kotor_install_dir),
)

def test_detects_install_with_exact_case(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
root = pathlib.Path(tmp) / "KotorInstall"
root.mkdir()
(root / "chitin.key").write_bytes(b"key")

for name, is_install in self._IMPLEMENTATIONS:
with self.subTest(implementation=name):
self.assertTrue(is_install(root))

def test_rejects_directory_without_chitin_key(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
root = pathlib.Path(tmp) / "NotInstall"
root.mkdir()

for name, is_install in self._IMPLEMENTATIONS:
with self.subTest(implementation=name):
self.assertFalse(is_install(root))

def test_rejects_file_path(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
file_path = pathlib.Path(tmp) / "not_a_dir"
file_path.write_bytes(b"x")

for name, is_install in self._IMPLEMENTATIONS:
with self.subTest(implementation=name):
self.assertFalse(is_install(file_path))

@unittest.skipIf(
sys.platform == "win32",
"Case mismatch semantics differ on Windows filesystems.",
)
def test_detects_install_with_case_mismatched_chitin_key(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
root = pathlib.Path(tmp) / "KotorInstall"
root.mkdir()
(root / "CHITIN.KEY").write_bytes(b"key")

for name, is_install in self._IMPLEMENTATIONS:
with self.subTest(implementation=name):
self.assertTrue(is_install(root))

@unittest.skipIf(
sys.platform == "win32",
"Case mismatch semantics differ on Windows filesystems.",
)
def test_detects_install_with_case_mismatched_root_path(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
root = pathlib.Path(tmp) / "KotorInstall"
root.mkdir()
(root / "chitin.key").write_bytes(b"key")

mismatched_root = root.parent / "kotorinstall"

for name, is_install in self._IMPLEMENTATIONS:
with self.subTest(implementation=name):
self.assertTrue(is_install(mismatched_root))


if __name__ == "__main__":
unittest.main()
9 changes: 9 additions & 0 deletions Libraries/PyKotor/tests/extract/test_installation.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ def add_sys_path(p: pathlib.Path):


class TestInstallation(TestCase):
def test_create_installation_uses_modules_directory_casing(self):
with tempfile.TemporaryDirectory() as tmp:
install_path = Path(tmp) / "k1_install"
create_installation(install_path, Game.K1)

self.assertTrue((install_path / "Modules").is_dir())
if sys.platform != "win32":
self.assertFalse((install_path / "modules").exists())

@classmethod
def setUpClass(cls):
# Create temporary directory for installation
Expand Down
20 changes: 20 additions & 0 deletions Libraries/PyKotor/tests/tslpatcher/test_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -1850,5 +1850,25 @@ def _setupIniAndConfig(self, ini_text: str) -> PatcherConfig:
# endregion


class TestConfigReaderFromFilepath(unittest.TestCase):
@unittest.skipIf(
sys.platform == "win32",
"Case mismatch semantics differ on Windows filesystems.",
)
def test_from_filepath_resolves_case_mismatched_mod_directory(self):
with tempfile.TemporaryDirectory() as tmp:
mod_root = Path(tmp) / "MyMod"
mod_root.mkdir()
ini_path = mod_root / "changes.ini"
ini_path.write_text(
"[Settings]\nLookupGameFolder=0\nLookupGameNumber=1\n",
encoding="utf-8",
)

reader = ConfigReader.from_filepath(mod_root.parent / "mymod" / "CHANGES.INI")
self.assertTrue(reader.mod_path.is_dir())
self.assertEqual(reader.mod_path.name, "MyMod")


if __name__ == "__main__":
unittest.main()
Loading