build(python): simplify rpycdec vendor layout
This commit was merged in pull request #17.
This commit is contained in:
8
third_party/python/rpycdec/tests/.gitignore
vendored
Normal file
8
third_party/python/rpycdec/tests/.gitignore
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
*.swp
|
||||
*.pyc
|
||||
*.rpyc
|
||||
__pycache__
|
||||
saves
|
||||
cache
|
||||
*_decompiled
|
||||
log.txt
|
||||
109
third_party/python/rpycdec/tests/test_ast.py
vendored
Normal file
109
third_party/python/rpycdec/tests/test_ast.py
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
"""Tests for renpy.ast node code generation"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src"))
|
||||
|
||||
import renpy.ast as ast
|
||||
|
||||
|
||||
def make_pycode(code_str):
|
||||
"""Create a PyCode object with the given source string."""
|
||||
pycode = ast.PyCode()
|
||||
pycode.state = (None, code_str, None, None, None)
|
||||
return pycode
|
||||
|
||||
|
||||
class TestPythonGetCode(unittest.TestCase):
|
||||
"""Tests for Python.get_code() keyword order and correctness."""
|
||||
|
||||
def _make_node(self, code_str, store=None, hide=None):
|
||||
node = ast.Python(loc=("script.rpyc", 1))
|
||||
node.code = make_pycode(code_str)
|
||||
if store is not None:
|
||||
node.store = store
|
||||
if hide is not None:
|
||||
node.hide = hide
|
||||
return node
|
||||
|
||||
def test_single_line_shorthand(self):
|
||||
"""Single-line Python without store/hide uses $ shorthand."""
|
||||
node = self._make_node("flag = True")
|
||||
self.assertEqual(node.get_code(), "$ flag = True")
|
||||
|
||||
def test_hide_before_store(self):
|
||||
"""'hide' must appear before 'in <store>' per Ren'Py grammar."""
|
||||
node = self._make_node("flag = True", hide=True, store="store.mystore")
|
||||
result = node.get_code()
|
||||
self.assertIn("python hide in mystore:", result)
|
||||
|
||||
def test_hide_only(self):
|
||||
"""python hide: block without store."""
|
||||
node = self._make_node("flag = True", hide=True)
|
||||
result = node.get_code()
|
||||
self.assertTrue(result.startswith("python hide:"))
|
||||
|
||||
def test_store_only(self):
|
||||
"""python in <store>: block without hide."""
|
||||
node = self._make_node("flag = True", store="store.mystore")
|
||||
result = node.get_code()
|
||||
self.assertTrue(result.startswith("python in mystore:"))
|
||||
|
||||
def test_multiline(self):
|
||||
"""Multiline code produces a python: block."""
|
||||
node = self._make_node("flag = True\nother = False")
|
||||
result = node.get_code()
|
||||
self.assertIn("python:", result)
|
||||
|
||||
|
||||
class TestEarlyPythonGetCode(unittest.TestCase):
|
||||
"""Tests for EarlyPython.get_code() — keyword order and missing-attribute safety."""
|
||||
|
||||
def _make_node(self, code_str, store=None, hide=None):
|
||||
node = ast.EarlyPython(loc=("script.rpyc", 1))
|
||||
node.code = make_pycode(code_str)
|
||||
if store is not None:
|
||||
node.store = store
|
||||
if hide is not None:
|
||||
node.hide = hide
|
||||
return node
|
||||
|
||||
def test_single_line_no_hide_attr(self):
|
||||
"""EarlyPython without 'hide' attribute should not raise AttributeError."""
|
||||
node = self._make_node("flag = True")
|
||||
self.assertEqual(node.get_code(), "$ flag = True")
|
||||
|
||||
def test_single_line_hide_false(self):
|
||||
"""EarlyPython with hide=False should use $ shorthand."""
|
||||
node = self._make_node("flag = True", hide=False)
|
||||
self.assertEqual(node.get_code(), "$ flag = True")
|
||||
|
||||
def test_hide_before_store(self):
|
||||
"""'hide' must appear before 'in <store>' per Ren'Py grammar."""
|
||||
node = self._make_node("flag = True", hide=True, store="store.mystore")
|
||||
result = node.get_code()
|
||||
self.assertIn("python early hide in mystore:", result)
|
||||
|
||||
def test_hide_only(self):
|
||||
"""python early hide: block without store."""
|
||||
node = self._make_node("flag = True", hide=True)
|
||||
result = node.get_code()
|
||||
self.assertTrue(result.startswith("python early hide:"))
|
||||
|
||||
def test_store_only(self):
|
||||
"""python early in <store>: block without hide."""
|
||||
node = self._make_node("flag = True", store="store.mystore")
|
||||
result = node.get_code()
|
||||
self.assertTrue(result.startswith("python early in mystore:"))
|
||||
|
||||
def test_multiline(self):
|
||||
"""Multiline code should emit 'python early:' block."""
|
||||
node = self._make_node("flag = True\nother = False")
|
||||
result = node.get_code()
|
||||
self.assertIn("python early:", result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
187
third_party/python/rpycdec/tests/test_rpa.py
vendored
Normal file
187
third_party/python/rpycdec/tests/test_rpa.py
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from subprocess import run
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||||
|
||||
from rpycdec.rpa import create_rpa, extract_rpa
|
||||
|
||||
SRC_DIR = str(Path(__file__).resolve().parents[1] / "src")
|
||||
|
||||
|
||||
class RPATests(unittest.TestCase):
|
||||
def create_filter_fixture(self, root: Path) -> Path:
|
||||
source = root / "game"
|
||||
(source / "images").mkdir(parents=True)
|
||||
(source / "scripts").mkdir()
|
||||
(source / "script.rpy").write_text('label start:\n "Hello"\n')
|
||||
(source / "scripts" / "chapter.RPYC").write_bytes(b"compiled")
|
||||
(source / "images" / "bg.png").write_bytes(b"image")
|
||||
(source / "notes.txt").write_text("notes")
|
||||
|
||||
archive = root / "archive.rpa"
|
||||
create_rpa(str(archive), [str(source)])
|
||||
return archive
|
||||
|
||||
def test_create_rpa_round_trips_directory(self):
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
root = Path(td)
|
||||
source = root / "game"
|
||||
(source / "images").mkdir(parents=True)
|
||||
(source / "script.rpy").write_text('label start:\n "Hello"\n')
|
||||
(source / "images" / "bg.png").write_bytes(b"\x89PNG\r\n\x1a\n")
|
||||
|
||||
archive = root / "archive.rpa"
|
||||
create_rpa(str(archive), [str(source)])
|
||||
|
||||
output = root / "out"
|
||||
with archive.open("rb") as f:
|
||||
extract_rpa(f, str(output))
|
||||
|
||||
self.assertEqual(
|
||||
(output / "script.rpy").read_text(), 'label start:\n "Hello"\n'
|
||||
)
|
||||
self.assertEqual(
|
||||
(output / "images" / "bg.png").read_bytes(), b"\x89PNG\r\n\x1a\n"
|
||||
)
|
||||
|
||||
def test_rpa_cli_creates_archive_from_file(self):
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
root = Path(td)
|
||||
source = root / "00unlock.rpy"
|
||||
source.write_text("define unlock = True\n")
|
||||
archive = root / "unlock.rpa"
|
||||
env = os.environ.copy()
|
||||
env["PYTHONPATH"] = SRC_DIR + os.pathsep + env.get("PYTHONPATH", "")
|
||||
|
||||
result = run(
|
||||
[
|
||||
sys.executable,
|
||||
"-m",
|
||||
"rpycdec",
|
||||
"rpa",
|
||||
"-o",
|
||||
str(archive),
|
||||
str(source),
|
||||
],
|
||||
text=True,
|
||||
capture_output=True,
|
||||
env=env,
|
||||
)
|
||||
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
|
||||
output = root / "out"
|
||||
with archive.open("rb") as f:
|
||||
extract_rpa(f, str(output))
|
||||
|
||||
self.assertEqual(
|
||||
(output / "00unlock.rpy").read_text(), "define unlock = True\n"
|
||||
)
|
||||
|
||||
def test_extract_rpa_filters_by_multiple_suffixes_case_insensitively(self):
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
root = Path(td)
|
||||
archive = self.create_filter_fixture(root)
|
||||
output = root / "out"
|
||||
|
||||
with archive.open("rb") as f:
|
||||
extract_rpa(f, str(output), suffixes=[".rpy", ".rpyc"])
|
||||
|
||||
self.assertTrue((output / "script.rpy").is_file())
|
||||
self.assertTrue((output / "scripts" / "chapter.RPYC").is_file())
|
||||
self.assertFalse((output / "images" / "bg.png").exists())
|
||||
self.assertFalse((output / "notes.txt").exists())
|
||||
|
||||
def test_extract_rpa_accepts_a_single_filter_string(self):
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
root = Path(td)
|
||||
archive = self.create_filter_fixture(root)
|
||||
output = root / "out"
|
||||
|
||||
with archive.open("rb") as f:
|
||||
extract_rpa(f, str(output), suffixes=".rpy")
|
||||
|
||||
self.assertTrue((output / "script.rpy").is_file())
|
||||
self.assertFalse((output / "scripts" / "chapter.RPYC").exists())
|
||||
|
||||
def test_extract_rpa_combines_expressions_and_suffixes_with_or(self):
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
root = Path(td)
|
||||
archive = self.create_filter_fixture(root)
|
||||
output = root / "out"
|
||||
|
||||
with archive.open("rb") as f:
|
||||
extract_rpa(
|
||||
f,
|
||||
str(output),
|
||||
expressions=[r"^images/.*\.png$"],
|
||||
suffixes=[".rpy"],
|
||||
)
|
||||
|
||||
self.assertTrue((output / "script.rpy").is_file())
|
||||
self.assertTrue((output / "images" / "bg.png").is_file())
|
||||
self.assertFalse((output / "scripts" / "chapter.RPYC").exists())
|
||||
self.assertFalse((output / "notes.txt").exists())
|
||||
|
||||
def test_unrpa_cli_supports_expression_and_multiple_suffixes(self):
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
root = Path(td)
|
||||
archive = self.create_filter_fixture(root)
|
||||
output = root / "out"
|
||||
env = os.environ.copy()
|
||||
env["PYTHONPATH"] = SRC_DIR + os.pathsep + env.get("PYTHONPATH", "")
|
||||
|
||||
result = run(
|
||||
[
|
||||
sys.executable,
|
||||
"-m",
|
||||
"rpycdec",
|
||||
"unrpa",
|
||||
str(archive),
|
||||
"-o",
|
||||
str(output),
|
||||
"-e",
|
||||
r"^images/",
|
||||
"-s",
|
||||
".rpy",
|
||||
".rpyc",
|
||||
],
|
||||
text=True,
|
||||
capture_output=True,
|
||||
env=env,
|
||||
)
|
||||
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
self.assertTrue((output / "script.rpy").is_file())
|
||||
self.assertTrue((output / "scripts" / "chapter.RPYC").is_file())
|
||||
self.assertTrue((output / "images" / "bg.png").is_file())
|
||||
self.assertFalse((output / "notes.txt").exists())
|
||||
|
||||
def test_unrpa_cli_rejects_invalid_expression(self):
|
||||
env = os.environ.copy()
|
||||
env["PYTHONPATH"] = SRC_DIR + os.pathsep + env.get("PYTHONPATH", "")
|
||||
result = run(
|
||||
[
|
||||
sys.executable,
|
||||
"-m",
|
||||
"rpycdec",
|
||||
"unrpa",
|
||||
"archive.rpa",
|
||||
"-e",
|
||||
"[",
|
||||
],
|
||||
text=True,
|
||||
capture_output=True,
|
||||
env=env,
|
||||
)
|
||||
|
||||
self.assertEqual(result.returncode, 2)
|
||||
self.assertIn("invalid regular expression", result.stderr)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
296
third_party/python/rpycdec/tests/test_translate.py
vendored
Normal file
296
third_party/python/rpycdec/tests/test_translate.py
vendored
Normal file
@@ -0,0 +1,296 @@
|
||||
"""Tests for rpycdec.translate module"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src"))
|
||||
|
||||
import renpy.ast
|
||||
from rpycdec.translate import (
|
||||
DialogueTranslation,
|
||||
StringTranslation,
|
||||
TranslationExtractor,
|
||||
elide_filename,
|
||||
get_translation_filename,
|
||||
quote_unicode,
|
||||
unique_identifier,
|
||||
write_dialogue_translations,
|
||||
write_string_translations,
|
||||
)
|
||||
|
||||
|
||||
class TestGetTranslationFilename(unittest.TestCase):
|
||||
"""Tests for get_translation_filename()"""
|
||||
|
||||
def test_rpyc_to_rpy(self):
|
||||
self.assertEqual(get_translation_filename("script.rpyc"), "script.rpy")
|
||||
|
||||
def test_rpymc_to_rpym(self):
|
||||
self.assertEqual(get_translation_filename("script.rpymc"), "script.rpym")
|
||||
|
||||
def test_subdirectory_preserved(self):
|
||||
"""Directory structure should be preserved (was a bug: basename stripped dirs)"""
|
||||
self.assertEqual(get_translation_filename("sub/intro.rpyc"), "sub/intro.rpy")
|
||||
|
||||
def test_nested_subdirectory_preserved(self):
|
||||
self.assertEqual(
|
||||
get_translation_filename("a/b/c/script.rpyc"), "a/b/c/script.rpy"
|
||||
)
|
||||
|
||||
def test_rpym_unchanged(self):
|
||||
self.assertEqual(get_translation_filename("script.rpym"), "script.rpym")
|
||||
|
||||
def test_rpy_unchanged(self):
|
||||
self.assertEqual(get_translation_filename("script.rpy"), "script.rpy")
|
||||
|
||||
|
||||
class TestElideFilename(unittest.TestCase):
|
||||
def test_strips_game_dir(self):
|
||||
result = elide_filename("/game/script.rpyc", "/game")
|
||||
self.assertEqual(result, "script.rpy")
|
||||
|
||||
def test_rpymc_to_rpym(self):
|
||||
result = elide_filename("/game/script.rpymc", "/game")
|
||||
self.assertEqual(result, "script.rpym")
|
||||
|
||||
def test_no_game_dir(self):
|
||||
result = elide_filename("script.rpyc")
|
||||
self.assertEqual(result, "script.rpy")
|
||||
|
||||
|
||||
class TestQuoteUnicode(unittest.TestCase):
|
||||
def test_backslash(self):
|
||||
self.assertEqual(quote_unicode("a\\b"), "a\\\\b")
|
||||
|
||||
def test_double_quote(self):
|
||||
self.assertEqual(quote_unicode('say "hi"'), 'say \\"hi\\"')
|
||||
|
||||
def test_newline(self):
|
||||
self.assertEqual(quote_unicode("line1\nline2"), "line1\\nline2")
|
||||
|
||||
def test_plain_string(self):
|
||||
self.assertEqual(quote_unicode("hello"), "hello")
|
||||
|
||||
|
||||
class TestUniqueIdentifier(unittest.TestCase):
|
||||
def test_no_label(self):
|
||||
result = unique_identifier(None, "abcd1234")
|
||||
self.assertEqual(result, "abcd1234")
|
||||
|
||||
def test_with_label(self):
|
||||
result = unique_identifier("start", "abcd1234")
|
||||
self.assertEqual(result, "start_abcd1234")
|
||||
|
||||
def test_label_dot_replaced(self):
|
||||
result = unique_identifier("chapter.one", "abcd1234")
|
||||
self.assertEqual(result, "chapter_one_abcd1234")
|
||||
|
||||
def test_collision_appends_index(self):
|
||||
existing = {"start_abcd1234"}
|
||||
result = unique_identifier("start", "abcd1234", existing)
|
||||
self.assertEqual(result, "start_abcd1234_1")
|
||||
|
||||
def test_multiple_collisions(self):
|
||||
existing = {"start_abcd1234", "start_abcd1234_1"}
|
||||
result = unique_identifier("start", "abcd1234", existing)
|
||||
self.assertEqual(result, "start_abcd1234_2")
|
||||
|
||||
|
||||
class TestTranslationExtractor(unittest.TestCase):
|
||||
def _make_say_node(self, who, what, filename="script.rpyc", linenumber=1):
|
||||
node = renpy.ast.Say(loc=(filename, linenumber))
|
||||
node.who = who
|
||||
node.what = what
|
||||
node.interact = True
|
||||
node.identifier = None
|
||||
node.explicit_identifier = False
|
||||
node.attributes = None
|
||||
node.temporary_attributes = None
|
||||
node.arguments = None
|
||||
node.with_ = None
|
||||
return node
|
||||
|
||||
def test_extract_say_dialogue(self):
|
||||
extractor = TranslationExtractor()
|
||||
node = self._make_say_node("e", "Hello world.")
|
||||
extractor.extract_file("script.rpyc", [node])
|
||||
self.assertEqual(len(extractor.dialogues), 1)
|
||||
d = extractor.dialogues[0]
|
||||
self.assertEqual(d.who, "e")
|
||||
self.assertEqual(d.what, "Hello world.")
|
||||
self.assertEqual(d.filename, "script.rpyc")
|
||||
|
||||
def test_extract_say_no_speaker(self):
|
||||
extractor = TranslationExtractor()
|
||||
node = self._make_say_node(None, "A narrator line.")
|
||||
extractor.extract_file("script.rpyc", [node])
|
||||
self.assertEqual(len(extractor.dialogues), 1)
|
||||
self.assertIsNone(extractor.dialogues[0].who)
|
||||
|
||||
def test_no_say_no_dialogue(self):
|
||||
extractor = TranslationExtractor()
|
||||
extractor.extract_file("script.rpyc", [])
|
||||
self.assertEqual(len(extractor.dialogues), 0)
|
||||
self.assertEqual(len(extractor.strings), 0)
|
||||
|
||||
def test_identifier_generated(self):
|
||||
extractor = TranslationExtractor()
|
||||
node = self._make_say_node("e", "Hello.")
|
||||
extractor.extract_file("script.rpyc", [node])
|
||||
self.assertIsNotNone(extractor.dialogues[0].identifier)
|
||||
self.assertIsInstance(extractor.dialogues[0].identifier, str)
|
||||
|
||||
|
||||
class TestWriteDialogueTranslations(unittest.TestCase):
|
||||
def test_writes_dialogue_file(self):
|
||||
dialogues = [
|
||||
DialogueTranslation(
|
||||
identifier="start_abcd1234",
|
||||
filename="script.rpyc",
|
||||
linenumber=5,
|
||||
who="e",
|
||||
what="Hello.",
|
||||
code='e "Hello."',
|
||||
)
|
||||
]
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
write_dialogue_translations(
|
||||
dialogues, tmpdir, "chinese", empty_translation=False
|
||||
)
|
||||
tl_file = os.path.join(tmpdir, "script.rpy")
|
||||
self.assertTrue(os.path.exists(tl_file))
|
||||
with open(tl_file) as f:
|
||||
content = f.read()
|
||||
self.assertIn("translate chinese start_abcd1234:", content)
|
||||
self.assertIn('e "Hello."', content)
|
||||
|
||||
def test_preserves_subdirectory_structure(self):
|
||||
"""Translation files should mirror the source directory structure"""
|
||||
dialogues = [
|
||||
DialogueTranslation(
|
||||
identifier="intro_abcd1234",
|
||||
filename="sub/intro.rpyc",
|
||||
linenumber=3,
|
||||
who=None,
|
||||
what="Welcome.",
|
||||
code='"Welcome."',
|
||||
)
|
||||
]
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
write_dialogue_translations(
|
||||
dialogues, tmpdir, "chinese", empty_translation=False
|
||||
)
|
||||
tl_file = os.path.join(tmpdir, "sub", "intro.rpy")
|
||||
self.assertTrue(
|
||||
os.path.exists(tl_file),
|
||||
f"Expected {tl_file} to exist (subdirectory structure not preserved)",
|
||||
)
|
||||
|
||||
def test_empty_translation(self):
|
||||
dialogues = [
|
||||
DialogueTranslation(
|
||||
identifier="start_abcd1234",
|
||||
filename="script.rpyc",
|
||||
linenumber=1,
|
||||
who="e",
|
||||
what="Hello.",
|
||||
code='e "Hello."',
|
||||
)
|
||||
]
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
write_dialogue_translations(
|
||||
dialogues, tmpdir, "chinese", empty_translation=True
|
||||
)
|
||||
with open(os.path.join(tmpdir, "script.rpy")) as f:
|
||||
content = f.read()
|
||||
self.assertIn('e ""', content)
|
||||
|
||||
|
||||
class TestWriteStringTranslations(unittest.TestCase):
|
||||
def test_writes_strings_file(self):
|
||||
strings = [StringTranslation(filename="script.rpyc", linenumber=2, text="Play")]
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
count = write_string_translations(
|
||||
strings, tmpdir, "chinese", empty_translation=False
|
||||
)
|
||||
self.assertEqual(count, 1)
|
||||
tl_file = os.path.join(tmpdir, "strings.rpy")
|
||||
self.assertTrue(os.path.exists(tl_file))
|
||||
with open(tl_file) as f:
|
||||
content = f.read()
|
||||
self.assertIn("translate chinese strings:", content)
|
||||
self.assertIn('old "Play"', content)
|
||||
self.assertIn('new "Play"', content)
|
||||
|
||||
def test_empty_strings_not_written(self):
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
count = write_string_translations([], tmpdir, "chinese")
|
||||
self.assertEqual(count, 0)
|
||||
self.assertFalse(os.path.exists(os.path.join(tmpdir, "strings.rpy")))
|
||||
|
||||
|
||||
class TestCLIExtractTranslate(unittest.TestCase):
|
||||
"""Integration tests for the extract-translate CLI command"""
|
||||
|
||||
def test_language_argument_recognized(self):
|
||||
"""The --language argument must be recognized by the CLI parser"""
|
||||
from rpycdec.cli import main
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
sys.argv = [
|
||||
"rpycdec",
|
||||
"extract-translate",
|
||||
tmpdir,
|
||||
"--language",
|
||||
"chinese",
|
||||
]
|
||||
# Should not raise SystemExit with non-zero code (unrecognized arguments)
|
||||
try:
|
||||
main()
|
||||
except SystemExit as e:
|
||||
if e.code != 0:
|
||||
self.fail(
|
||||
f"CLI raised SystemExit({e.code}) - --language may not be recognized"
|
||||
)
|
||||
|
||||
def test_language_short_flag(self):
|
||||
"""The -l short flag must also work"""
|
||||
from rpycdec.cli import main
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
sys.argv = ["rpycdec", "extract-translate", tmpdir, "-l", "japanese"]
|
||||
try:
|
||||
main()
|
||||
except SystemExit as e:
|
||||
if e.code != 0:
|
||||
self.fail(
|
||||
f"CLI raised SystemExit({e.code}) - -l flag may not be recognized"
|
||||
)
|
||||
|
||||
def test_creates_tl_directory(self):
|
||||
"""extract-translate must create tl/<language>/ directory in output"""
|
||||
from rpycdec.cli import main
|
||||
|
||||
with tempfile.TemporaryDirectory() as game_dir:
|
||||
with tempfile.TemporaryDirectory() as out_dir:
|
||||
sys.argv = [
|
||||
"rpycdec",
|
||||
"extract-translate",
|
||||
game_dir,
|
||||
"--language",
|
||||
"chinese",
|
||||
"--output",
|
||||
out_dir,
|
||||
]
|
||||
main()
|
||||
tl_dir = os.path.join(out_dir, "tl", "chinese")
|
||||
self.assertTrue(
|
||||
os.path.isdir(tl_dir),
|
||||
f"Expected tl/chinese/ directory at {tl_dir}",
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user