Skip to content

Commit 48b0d57

Browse files
cursoragentBoden
andcommitted
test(cli): cover to-json --all-detected validation and exit codes
Co-authored-by: Boden <th3w1zard1@users.noreply.github.com>
1 parent fdd5c7c commit 48b0d57

1 file changed

Lines changed: 173 additions & 0 deletions

File tree

Libraries/PyKotor/tests/cli/test_json_commands.py

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import base64
44
import json
5+
import logging
56

67
from argparse import Namespace
78
from pathlib import Path
@@ -12,6 +13,7 @@
1213
from pykotor.cli.argparser import create_parser
1314
from pykotor.cli.commands.find_cmd import cmd_find
1415
from pykotor.cli.commands.get_cmd import cmd_get
16+
from pykotor.cli.commands.installation_to_json import cmd_installation_to_json
1517
from pykotor.cli.commands.diff_installation import cmd_diff_installation
1618
from pykotor.cli.dispatch import cli_main
1719
from pykotor.common.language import Language
@@ -418,6 +420,177 @@ def create_install(install_path: Path, dialog_text: str, executable_name: str) -
418420
)
419421

420422

423+
def test_to_json_all_detected_rejects_positional_input_with_install_path(
424+
tmp_path: Path, capsys: pytest.CaptureFixture[str]
425+
) -> None:
426+
"""Regression: --all-detected must not run batch export when a path was given (ambiguous)."""
427+
install = tmp_path / "K1"
428+
install.mkdir()
429+
(install / "chitin.key").write_bytes(b"")
430+
(install / "swkotor.exe").write_bytes(b"")
431+
432+
out = tmp_path / "out"
433+
assert (
434+
cli_main(["to-json", str(install), "--all-detected", "--output", str(out)])
435+
== 1
436+
)
437+
captured = capsys.readouterr()
438+
combined = captured.out + captured.err
439+
assert "cannot be combined" in combined
440+
441+
442+
def test_cmd_installation_to_json_all_detected_rejects_path_flag(
443+
tmp_path: Path, caplog: pytest.LogCaptureFixture
444+
) -> None:
445+
logger = RobustLogger()
446+
args = Namespace(
447+
all_detected=True,
448+
path=str(tmp_path),
449+
game=None,
450+
clean=False,
451+
output=str(tmp_path / "out"),
452+
)
453+
with caplog.at_level(logging.ERROR):
454+
assert cmd_installation_to_json(args, logger) == 1
455+
assert "cannot be combined" in caplog.text
456+
457+
458+
def test_cmd_installation_to_json_all_detected_unknown_game_errors(
459+
tmp_path: Path, caplog: pytest.LogCaptureFixture
460+
) -> None:
461+
logger = RobustLogger()
462+
args = Namespace(
463+
all_detected=True,
464+
path=None,
465+
game="not-a-game",
466+
clean=False,
467+
output=str(tmp_path / "out"),
468+
)
469+
with caplog.at_level(logging.ERROR):
470+
assert cmd_installation_to_json(args, logger) == 1
471+
assert "Unknown game" in caplog.text
472+
473+
474+
def test_cmd_installation_to_json_all_detected_no_installs_errors(
475+
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, caplog: pytest.LogCaptureFixture
476+
) -> None:
477+
monkeypatch.setattr(
478+
"pykotor.cli.commands.installation_to_json.get_kotor_paths_from_default",
479+
lambda: {Game.K1: [], Game.K2: []},
480+
)
481+
logger = RobustLogger()
482+
args = Namespace(
483+
all_detected=True,
484+
path=None,
485+
game=None,
486+
clean=False,
487+
output=str(tmp_path / "out"),
488+
)
489+
with caplog.at_level(logging.ERROR):
490+
assert cmd_installation_to_json(args, logger) == 1
491+
assert "No default installations were found" in caplog.text
492+
493+
494+
def test_to_json_all_detected_filters_by_game_k1_only(
495+
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
496+
) -> None:
497+
def create_install(install_path: Path, dialog_text: str, executable_name: str) -> None:
498+
install_path.mkdir()
499+
(install_path / "Override").mkdir()
500+
(install_path / "Modules").mkdir()
501+
(install_path / "chitin.key").write_bytes(b"")
502+
(install_path / executable_name).write_bytes(b"")
503+
504+
tlk = TLK(Language.ENGLISH)
505+
tlk.add(dialog_text, "voice")
506+
write_tlk(tlk, install_path / "dialog.tlk", ResourceType.TLK)
507+
508+
k1_install = tmp_path / "K1only"
509+
k2_install = tmp_path / "K2only"
510+
create_install(k1_install, "k1 dialog", "swkotor.exe")
511+
create_install(k2_install, "k2 dialog", "swkotor2.exe")
512+
513+
monkeypatch.setattr(
514+
"pykotor.cli.commands.installation_to_json.get_kotor_paths_from_default",
515+
lambda: {Game.K1: [k1_install], Game.K2: [k2_install]},
516+
)
517+
518+
output_path = tmp_path / "json-export-k1-filter"
519+
assert (
520+
cli_main(
521+
[
522+
"to-json",
523+
"--all-detected",
524+
"--game",
525+
"k1",
526+
"--output",
527+
str(output_path),
528+
]
529+
)
530+
== 0
531+
)
532+
533+
assert (output_path / "k1" / "0" / "dialog.tlk.json").is_file()
534+
assert not (output_path / "k2").exists()
535+
payload = json.loads(
536+
(output_path / "k1" / "0" / "dialog.tlk.json").read_text(encoding="utf-8")
537+
)
538+
assert payload["data"]["strings"][0]["text"] == "k1 dialog"
539+
540+
541+
def test_cmd_installation_to_json_all_detected_returns_2_when_any_export_has_errors(
542+
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
543+
) -> None:
544+
"""Batch export propagates code 2 when any installation hit non-fatal serialize errors."""
545+
546+
def create_install(install_path: Path, label: str) -> None:
547+
install_path.mkdir()
548+
(install_path / "Override").mkdir()
549+
(install_path / "Modules").mkdir()
550+
(install_path / "chitin.key").write_bytes(b"")
551+
(install_path / "swkotor.exe").write_bytes(b"")
552+
553+
tlk = TLK(Language.ENGLISH)
554+
tlk.add(label, "voice")
555+
write_tlk(tlk, install_path / "dialog.tlk", ResourceType.TLK)
556+
557+
first = tmp_path / "K1A"
558+
second = tmp_path / "K1B"
559+
create_install(first, "ok")
560+
create_install(second, "ok")
561+
562+
monkeypatch.setattr(
563+
"pykotor.cli.commands.installation_to_json.get_kotor_paths_from_default",
564+
lambda: {Game.K1: [first, second], Game.K2: []},
565+
)
566+
567+
calls: list[Path] = []
568+
569+
def fake_export(
570+
installation_path: Path, install_output_root: Path, logger: RobustLogger
571+
) -> int:
572+
calls.append(installation_path)
573+
if installation_path == first:
574+
return 0
575+
return 2
576+
577+
monkeypatch.setattr(
578+
"pykotor.cli.commands.installation_to_json.export_installation_to_json_tree",
579+
fake_export,
580+
)
581+
582+
logger = _CaptureLogger()
583+
args = Namespace(
584+
all_detected=True,
585+
path=None,
586+
game=None,
587+
clean=False,
588+
output=str(tmp_path / "batch-out"),
589+
)
590+
assert cmd_installation_to_json(args, logger) == 2
591+
assert calls == [first, second]
592+
593+
421594
def test_to_json_roundtrips_tpc_without_base64_payload(tmp_path: Path) -> None:
422595
input_path = tmp_path / "sample.tpc"
423596
json_path = tmp_path / "sample.tpc.json"

0 commit comments

Comments
 (0)