Add comprehensive tests for edge depth extension, empty image edits, and material view adaptation

- Introduced `test_edge_depth.py` to validate the functionality of edge depth extension, ensuring core alpha preservation, proper depth handling, and edge padding behavior.
- Created `test_empty_image_edits.py` to verify the behavior of image edits in Blender, focusing on shared edits, preservation of image properties, and handling of failed operations.
- Developed `test_material_view_adaptation.py` to test material adaptation preferences, ensuring color space and alpha settings are correctly applied and preserved across various scenarios.
This commit is contained in:
2026-09-06 21:43:47 +08:00
parent 1994d38ccd
commit 7e55af6722
58 changed files with 3607 additions and 200 deletions

View File

@@ -71,6 +71,7 @@ class ExtensionPackagingTest(unittest.TestCase):
"operators/cutout_tool/main.py",
"operators/cutout_tool/interaction.py",
"operators/cutout_tool/geometry.py",
"operators/cutout_tool/fine_mesh.py",
"operators/cutout_tool/object.py",
"operators/cutout_tool/shape.py",
"operators/convert_to_plane/__init__.py",
@@ -104,6 +105,7 @@ class ExtensionPackagingTest(unittest.TestCase):
self.assertIn("server/jobs/depth_plane.py", names)
self.assertIn("server/geometry/depth_texture.py", names)
self.assertIn("server/geometry/prediction_artifacts.py", names)
self.assertIn("server/geometry/edge_depth.py", names)
self.assertIn("server/geometry/normal_texture.py", names)
self.assertNotIn(
"server/geometry/generate_geometry_and_normal.py", names
@@ -125,6 +127,8 @@ class ExtensionPackagingTest(unittest.TestCase):
self.assertIn("server/models/onnx_upscale.py", names)
self.assertIn("server/models/upscale.py", names)
self.assertIn("server/__init__.py", names)
self.assertIn("operators/cutout_tool/polygon.py", names)
self.assertIn("licenses/scikit-image.txt", names)
self.assertIn(
"wheels/blendjob-0.1.16-py3-none-any.whl",
names,
@@ -141,30 +145,105 @@ class ExtensionPackagingTest(unittest.TestCase):
def test_reads_extension_dependencies_from_pyproject(self):
pack = load_pack()
self.assertEqual(pack.project_dependencies(), ["blendjob==0.1.16"])
self.assertEqual(
pack.project_dependencies(),
[
"blendjob==0.1.16",
"numpy>=1.26,<2.0",
"scipy==1.15.3",
],
)
def test_downloads_declared_wheels_for_target_platform(self):
def test_manifest_includes_all_resolved_numerical_wheels(self):
pack = load_pack()
wheels = [
Path(name)
for name in (
"blendjob-0.1.16-py3-none-any.whl",
"numpy-1.26.4-cp311-cp311-win_amd64.whl",
"scipy-1.15.3-cp311-cp311-win_amd64.whl",
)
]
manifest = tomllib.loads(pack.manifest_for_platform("windows-x64", wheels))
self.assertEqual(
set(manifest["wheels"]),
{
f"./wheels/{wheel.name}"
for wheel in wheels
if not wheel.name.startswith("numpy-")
},
)
def test_downloads_both_python_versions_for_each_platform(self):
pack = load_pack()
for platform, config in pack.PLATFORM_CONFIGS.items():
with self.subTest(platform=platform), tempfile.TemporaryDirectory() as directory:
destination = Path(directory)
def fake_run(command, check):
self.assertTrue(check)
target = Path(command[command.index("--dest") + 1])
tag = "cp" + target.name.replace(".", "")
if target.name == "3.13":
constraints = Path(command[command.index("--constraint") + 1])
self.assertEqual(
constraints.read_text(), "blendjob==0.1.16"
)
else:
self.assertNotIn("--constraint", command)
for name in (
"blendjob-0.1.16-py3-none-any.whl",
f"scipy-1.15.3-{tag}-{tag}-{config.pip_platform}.whl",
f"numpy-2.1.0-{tag}-{tag}-{config.pip_platform}.whl",
):
(target / name).write_bytes(b"wheel")
with patch.object(pack.subprocess, "run", side_effect=fake_run) as run:
wheels = pack.download_wheels(platform, destination)
self.assertEqual(run.call_count, 2)
for call, version, numpy_requirement in zip(
run.call_args_list,
("3.11", "3.13"),
("numpy>=1.26,<2.0", "numpy>=2.1,<3.0"),
):
command = call.args[0]
self.assertIn("blendjob==0.1.16", command)
self.assertIn(str(pack.SOURCE_DIR / "wheels"), command)
self.assertIn(f"--python-version={version}", command)
self.assertIn("--implementation=cp", command)
self.assertIn(f"--platform={config.pip_platform}", command)
self.assertEqual(
[value for value in command if value.startswith("numpy")],
[numpy_requirement],
)
self.assertEqual(len(wheels), 3)
self.assertEqual(
[wheel.name for wheel in wheels], sorted({wheel.name for wheel in wheels})
)
self.assertFalse(any(wheel.name.startswith("numpy-") for wheel in wheels))
with patch.object(pack, "DIST_DIR", destination / "dist"):
output = pack._build_extension(platform, wheels)
with ZipFile(output) as archive:
manifest = tomllib.loads(archive.read("blender_manifest.toml").decode())
expected = {f"wheels/{wheel.name}" for wheel in wheels}
self.assertEqual({name[2:] for name in manifest["wheels"]}, expected)
self.assertEqual(
{name for name in archive.namelist() if name.startswith("wheels/")},
expected,
)
def test_empty_second_python_download_is_rejected(self):
pack = load_pack()
with tempfile.TemporaryDirectory() as directory:
destination = Path(directory)
def fake_run(command, check):
self.assertTrue(check)
(destination / "blendjob-0.1.16-py3-none-any.whl").write_bytes(b"wheel")
target = Path(command[command.index("--dest") + 1])
if target.name == "3.11":
(target / "blendjob-0.1.16-py3-none-any.whl").write_bytes(b"wheel")
with patch.object(pack.subprocess, "run", side_effect=fake_run) as run:
wheels = pack.download_wheels("linux-x64", destination)
command = run.call_args.args[0]
self.assertIn("blendjob==0.1.16", command)
self.assertIn("--find-links", command)
self.assertIn(str(pack.SOURCE_DIR / "wheels"), command)
self.assertIn("--python-version=3.11", command)
self.assertIn("--platform=manylinux2014_x86_64", command)
self.assertEqual(
[wheel.name for wheel in wheels],
["blendjob-0.1.16-py3-none-any.whl"],
)
with patch.object(pack.subprocess, "run", side_effect=fake_run):
with self.assertRaisesRegex(RuntimeError, "Python 3.13"):
pack.download_wheels("windows-x64", Path(directory))
def test_rejects_unknown_platform(self):
pack = load_pack()
@@ -176,12 +255,113 @@ class ExtensionPackagingTest(unittest.TestCase):
manifest = tomllib.loads(
(pack.SOURCE_DIR / "blender_manifest.toml").read_text(encoding="utf-8")
)
self.assertEqual(set(pack.PLATFORMS), set(manifest["platforms"]))
self.assertTrue(set(manifest["platforms"]) <= set(pack.PLATFORMS))
self.assertEqual(
set(pack.PLATFORMS),
{"windows-x64", "macos-arm64", "linux-x64"},
)
def test_prepares_local_wheels_and_removes_stale_versions(self):
pack = load_pack()
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
source = root / "source"
source.mkdir()
manifest_path = source / "blender_manifest.toml"
manifest_path.write_text(
(pack.SOURCE_DIR / "blender_manifest.toml").read_text(encoding="utf-8"),
encoding="utf-8",
)
destination = source / "wheels"
destination.mkdir()
(destination / "numpy-1.26.4-cp311-cp311-win_amd64.whl").write_bytes(
b"numpy"
)
(destination / "scipy-1.14.0-cp311-cp311-win_amd64.whl").write_bytes(b"old")
(destination / "notes.txt").write_text("keep", encoding="utf-8")
wheel = root / "scipy-1.15.3-cp311-cp311-win_amd64.whl"
wheel.write_bytes(b"new")
with (
patch.object(pack, "SOURCE_DIR", source),
patch.object(pack, "download_wheels", return_value=[wheel]),
):
result = pack.prepare_local_dependencies("windows-x64")
self.assertEqual(result, [destination / wheel.name])
self.assertEqual(result[0].read_bytes(), b"new")
self.assertTrue((destination / "notes.txt").exists())
manifest = tomllib.loads(manifest_path.read_text(encoding="utf-8"))
self.assertEqual(manifest["wheels"], [f"./wheels/{wheel.name}"])
self.assertEqual(manifest["platforms"], ["windows-x64"])
self.assertIn("permissions", manifest)
def test_failed_download_keeps_local_dependencies_and_manifest(self):
pack = load_pack()
with tempfile.TemporaryDirectory() as directory:
source = Path(directory)
manifest = source / "blender_manifest.toml"
manifest.write_bytes(b"original manifest")
wheels = source / "wheels"
wheels.mkdir()
old = wheels / "old.whl"
old.write_bytes(b"original wheel")
def fake_run(command, check):
target = Path(command[command.index("--dest") + 1])
if target.name == "3.13":
raise RuntimeError("download failed")
(target / "blendjob-0.1.16-py3-none-any.whl").write_bytes(b"wheel")
with (
patch.object(pack, "SOURCE_DIR", source),
patch.object(pack.subprocess, "run", side_effect=fake_run),
):
with self.assertRaisesRegex(RuntimeError, "download failed"):
pack.prepare_local_dependencies("windows-x64")
self.assertEqual(manifest.read_bytes(), b"original manifest")
self.assertEqual(old.read_bytes(), b"original wheel")
def test_archive_excludes_blender_numpy(self):
pack = load_pack()
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
wheel = root / "numpy-1.26.4-cp311-cp311-win_amd64.whl"
wheel.write_bytes(b"numpy")
with patch.object(pack, "DIST_DIR", root / "dist"):
output = pack._build_extension("windows-x64", [wheel])
with ZipFile(output) as archive:
self.assertFalse(any("numpy-" in name for name in archive.namelist()))
self.assertEqual(
tomllib.loads(archive.read("blender_manifest.toml").decode())[
"wheels"
],
[],
)
def test_prepare_command_defaults_to_host_and_does_not_build(self):
pack = load_pack()
with (
patch.object(pack, "current_platform", return_value="windows-x64"),
patch.object(
pack, "prepare_local_dependencies", return_value=[]
) as prepare,
patch.object(pack, "build_all") as build,
):
pack.main(["--prepare"])
prepare.assert_called_once_with("windows-x64")
build.assert_not_called()
def test_detects_supported_hosts(self):
pack = load_pack()
for system, machine, expected in (
("Windows", "AMD64", "windows-x64"),
("Darwin", "arm64", "macos-arm64"),
("Linux", "x86_64", "linux-x64"),
):
with (
patch.object(pack.host_platform, "system", return_value=system),
patch.object(pack.host_platform, "machine", return_value=machine),
):
self.assertEqual(pack.current_platform(), expected)
if __name__ == "__main__":
unittest.main()