Files
PythonInUnreal/tests/test_automatic_catalog.py
T
2026-10-31 23:11:57 +01:00

78 lines
3.6 KiB
Python

"""Automatic catalogs preserve other models, partial selections and offline imports."""
from pathlib import Path
import sys
import tempfile
from types import ModuleType
import unittest
from unittest.mock import patch
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "Content/Python"))
from ue_workshop import animation_catalog
from ue_workshop.animation_clip import AnimationClip
class AutomaticCatalogTests(unittest.TestCase):
def setUp(self):
self.folder = tempfile.TemporaryDirectory()
self.addCleanup(self.folder.cleanup)
self.output = Path(self.folder.name) / "animations.py"
def load(self):
namespace = {"__name__": "ue_workshop._catalog_test", "__package__": "ue_workshop"}
exec(compile(self.output.read_text(encoding="utf-8"), str(self.output), "exec"), namespace)
return namespace
def update(self, name, clips, **options):
return animation_catalog.update_catalog(name, clips, output=self.output, **options)
def test_new_model_produces_enum_with_durations_without_unreal(self):
self.assertEqual(self.update("StudentHero", {"walking": 2.0}), "StudentHeroAnimations")
clip = self.load()["StudentHeroAnimations"].WALKING
self.assertEqual(clip.key, "walking")
self.assertEqual(clip.seconds, 2)
self.assertEqual(clip.frames(24), 48)
self.assertNotIn("unreal", sys.modules)
def test_full_update_preserves_other_models_and_removes_deleted_clips(self):
self.update("Fighter", {"walk": 1.0, "attack": 2.0})
self.update("StudentHero", {"jump": 3.0})
self.update("Fighter", {"walk": 1.5})
namespace = self.load()
self.assertEqual([clip.key for clip in namespace["FighterAnimations"]], ["walk"])
self.assertEqual(namespace["StudentHeroAnimations"].JUMP.seconds, 3.0)
def test_partial_selection_updates_duration_without_erasing_other_clips(self):
self.update("Hero", {"walk": 1.0, "attack": 2.0})
self.update("Hero", {"walk": 1.5}, replace=False)
catalog = self.load()["HeroAnimations"]
self.assertEqual(catalog.WALK.seconds, 1.5)
self.assertEqual(catalog.ATTACK.seconds, 2.0)
def test_unchanged_metadata_does_not_rewrite_file(self):
self.update("Hero", {"walk": 1.0})
with patch.object(animation_catalog.tempfile, "NamedTemporaryFile", side_effect=AssertionError("rewritten")):
self.update("Hero", {"walk": 1.0})
def test_empty_model_is_valid(self):
self.update("Hero", {})
self.assertEqual(list(self.load()["HeroAnimations"]), [])
def test_invalid_metadata_does_not_damage_existing_catalog(self):
self.update("Hero", {"walk": 1.0})
before = self.output.read_bytes()
for data in ({"walk": 0}, {"walk": float("nan")}, {"walk": 1.0, "WALK": 2.0}):
with self.subTest(data=data), self.assertRaises(ValueError):
self.update("Hero", data)
self.assertEqual(self.output.read_bytes(), before)
def test_publish_adds_class_to_loaded_module_without_replacing_other_enums(self):
module = ModuleType("ue_workshop.animations")
module.AnimationClip = AnimationClip
module.ExistingAnimations = object()
original = module.ExistingAnimations
source = animation_catalog._class_source("StudentHeroAnimations", {"walk": 2.0})
with patch.dict(sys.modules, {"ue_workshop.animations": module}):
animation_catalog._publish_class(source, self.output)
self.assertEqual(module.StudentHeroAnimations.WALK.frames(24), 48)
self.assertIs(module.ExistingAnimations, original)