82 lines
3.6 KiB
Python
82 lines
3.6 KiB
Python
"""Automatic folder discovery, explicit selection and the manual reimport switch."""
|
|
import importlib.util
|
|
from pathlib import Path
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "Content/Python"))
|
|
from ue_workshop.characters import _clips
|
|
|
|
|
|
class Mesh:
|
|
def get_editor_property(self, name):
|
|
return "Skeleton"
|
|
|
|
|
|
class Clip:
|
|
def get_name(self):
|
|
return "EmbeddedTake"
|
|
|
|
|
|
class DiscoveryTests(unittest.TestCase):
|
|
def setUp(self):
|
|
self.folder = tempfile.TemporaryDirectory()
|
|
self.addCleanup(self.folder.cleanup)
|
|
self.model = Path(self.folder.name) / "Hero.fbx"
|
|
self.walk = self.model.with_name("great sword walk.fbx")
|
|
self.attack = self.model.with_name("great sword attack (2).fbx")
|
|
for path in (self.model, self.walk, self.attack):
|
|
path.touch()
|
|
unreal = MagicMock()
|
|
unreal.SkeletalMesh, unreal.AnimSequence = Mesh, Clip
|
|
name = "ue_workshop._skeletal_discovery_test"
|
|
path = Path(__file__).resolve().parents[1] / "Content/Python/ue_workshop/skeletal.py"
|
|
spec = importlib.util.spec_from_file_location(name, path)
|
|
self.module = importlib.util.module_from_spec(spec)
|
|
with patch.dict(sys.modules, {"unreal": unreal, name: self.module}):
|
|
spec.loader.exec_module(self.module)
|
|
self.cache = patch.object(self.module, "_cached", return_value=[Mesh()]).start()
|
|
self.importer = patch.object(self.module, "_import", return_value=[Mesh()]).start()
|
|
self.animation = patch.object(self.module, "import_animation", side_effect=lambda *a, **kw: Clip()).start()
|
|
self.addCleanup(patch.stopall)
|
|
|
|
def test_discovery_excludes_model_and_derives_names_without_aliases(self):
|
|
self.assertEqual(_clips(self.model), {
|
|
"great_sword_attack_2": self.attack,
|
|
"great_sword_walk": self.walk,
|
|
})
|
|
|
|
def test_omitted_animations_loads_every_neighbor_and_reuses_model(self):
|
|
result = self.module.import_model(self.model, name="Hero")
|
|
self.assertEqual(set(result.animations), {"great_sword_attack_2", "great_sword_walk"})
|
|
self.importer.assert_not_called()
|
|
self.assertEqual(self.animation.call_count, 2)
|
|
for call in self.animation.call_args_list:
|
|
self.assertFalse(call.kwargs["reimport"])
|
|
|
|
def test_empty_dictionary_disables_discovery_and_keeps_embedded_name(self):
|
|
self.cache.return_value = [Mesh(), Clip()]
|
|
result = self.module.import_model(self.model, name="Hero", animations={})
|
|
self.assertEqual(set(result.animations), {"EmbeddedTake"})
|
|
self.animation.assert_not_called()
|
|
|
|
def test_explicit_selection_ignores_other_files(self):
|
|
result = self.module.import_model(self.model, name="Hero", animations={"selected": self.walk})
|
|
self.assertEqual(set(result.animations), {"selected"})
|
|
self.animation.assert_called_once()
|
|
self.assertEqual(self.animation.call_args.args[0], self.walk)
|
|
|
|
def test_reimport_true_reimports_model_and_discovered_clips(self):
|
|
self.module.import_model(self.model, name="Hero", reimport=True)
|
|
self.cache.assert_not_called()
|
|
self.importer.assert_called_once()
|
|
self.assertTrue(self.importer.call_args.kwargs["reimport"])
|
|
self.assertTrue(all(call.kwargs["reimport"] for call in self.animation.call_args_list))
|
|
|
|
def test_colliding_normalized_names_are_rejected(self):
|
|
self.model.with_name("great-sword-walk.fbx").touch()
|
|
with self.assertRaises(ValueError):
|
|
_clips(self.model)
|