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
56 changes: 56 additions & 0 deletions Libraries/PyKotor/tests/cli/test_json_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from argparse import Namespace
from pathlib import Path
from typing import TextIO, cast

import pytest
from loggerplus import RobustLogger
Expand All @@ -27,7 +28,9 @@
from pykotor.resource.formats.tpc import TPC, TPCTextureFormat, bytes_tpc, read_tpc
from pykotor.resource.type import ResourceType
from pykotor.tools.resource_json import (
_ExportProgressReporter,
_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,56 @@ 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


def test_supports_live_progress_false_when_ci_set(monkeypatch: pytest.MonkeyPatch) -> None:
"""Regression: CI must disable carriage-return progress even if stderr is a TTY."""
monkeypatch.setenv("CI", "true")

class TtyStream:
def isatty(self) -> bool:
return True

assert _supports_live_progress(TtyStream()) is False


def test_supports_live_progress_false_when_github_actions_set(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.delenv("CI", raising=False)
monkeypatch.setenv("GITHUB_ACTIONS", "yes")

class TtyStream:
def isatty(self) -> bool:
return True

assert _supports_live_progress(TtyStream()) is False


def test_export_progress_reporter_uses_logger_not_stream_when_ci_forces_non_tty(
monkeypatch: pytest.MonkeyPatch,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Regression: percentage milestones must reach logging (caplog/aggregators) in automation."""
monkeypatch.setenv("CI", "true")

class StrictTTY:
def isatty(self) -> bool:
return True

def write(self, *_args: object, **_kwargs: object) -> None:
msg = "stream write must not be used when CI disables live progress"
raise AssertionError(msg)

def flush(self) -> None:
msg = "stream flush must not be used when CI disables live progress"
raise AssertionError(msg)

with caplog.at_level(logging.INFO):
progress = _ExportProgressReporter(RobustLogger(), 2, stream=cast(TextIO, StrictTTY()))
assert progress.live_updates is False
progress.update(1, "sample.txt")
progress.finish()

combined = caplog.text
assert "50.00%" in combined and "sample.txt" in combined
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ def test_resource_bytes_to_plaintext_gff_from_raw_bytes() -> None:
assert payload["fields"]["SomeField"]["value"] == 42


def test_resource_bytes_to_plaintext_returns_none_when_only_base64_embedding() -> None:
"""When embedded mode cannot produce a structured/plain payload, helper returns None."""
raw = bytes(range(256))
assert _resource_bytes_to_plaintext(raw, ResourceType.WAV) is None


def test_gff_json_writer_binary_field_is_base64_ascii() -> None:
"""Binary GFF fields must serialize to JSON-safe base64 strings."""
payload = b"\x00\xff\x01"
Expand Down
Loading