- Add core VRM addon infrastructure with manifest and registration - Add common utilities module with file system, logging, and conversion helpers - Add human bone mapper with support for multiple rigging standards (Mixamo, MMD, Unreal, Rigify, etc.) - Add VRM 0.x and 1.x format support with property groups and handlers - Add editor UI panels for VRM metadata, spring bones, and MToon materials - Add exporter with glTF2 extension support for VRM format serialization - Add importer with scene reconstruction and armature generation - Add MToon shader support with auto-setup and material migration - Add spring bone physics simulation with constraint handling - Add node constraint editor for advanced rigging control - Add comprehensive validation and error handling with user dialogs - Add scene watcher for real-time property synchronization - Add workspace management and preference system - Include Python cache files and Blender manifest configuration - This is the initial commit establishing the complete VRM addon ecosystem for Blender
60 lines
1.8 KiB
Python
60 lines
1.8 KiB
Python
# SPDX-License-Identifier: MIT OR GPL-3.0-or-later
|
|
from typing import Optional
|
|
from unittest import TestCase
|
|
|
|
import bpy
|
|
|
|
from .blender_manifest import BlenderManifest
|
|
|
|
DEVELOPMENT_MODULE = ".".join(__name__.split(".")[:-2])
|
|
MANIFEST_ID = BlenderManifest.read().id
|
|
|
|
|
|
def make_test_method_name(text: str) -> str:
|
|
replaced_chars: list[str] = []
|
|
for char in text:
|
|
if char == "«":
|
|
replaced_chars.append("««")
|
|
elif char == "»":
|
|
replaced_chars.append("»»")
|
|
elif ("_" + char).isidentifier():
|
|
replaced_chars.append(char)
|
|
else:
|
|
replaced_chars.append(f"«{ord(char):x}»")
|
|
return "test_" + ("".join(replaced_chars))
|
|
|
|
|
|
class AddonTestCase(TestCase):
|
|
disabled_installed_module: Optional[str]
|
|
|
|
@classmethod
|
|
def setUpClass(cls) -> None:
|
|
super().setUpClass()
|
|
|
|
cls.disabled_installed_module = None
|
|
for addon in bpy.context.preferences.addons:
|
|
module = addon.module
|
|
if not module.endswith("." + MANIFEST_ID):
|
|
continue
|
|
bpy.ops.preferences.addon_disable(module=module)
|
|
cls.disabled_installed_module = module
|
|
|
|
def setUp(self) -> None:
|
|
super().setUp()
|
|
bpy.ops.preferences.addon_enable(module=DEVELOPMENT_MODULE)
|
|
bpy.ops.wm.read_homefile(use_empty=True)
|
|
|
|
def tearDown(self) -> None:
|
|
super().tearDown()
|
|
bpy.ops.preferences.addon_disable(module=DEVELOPMENT_MODULE)
|
|
|
|
@classmethod
|
|
def tearDownClass(cls) -> None:
|
|
super().tearDownClass()
|
|
|
|
disabled_installed_module = cls.disabled_installed_module
|
|
if disabled_installed_module is not None:
|
|
bpy.ops.preferences.addon_enable(module=disabled_installed_module)
|
|
|
|
cls.disabled_installed_module = None
|