Files
AnyImage/tests/anyimage/test_job_operator.py
nan 591e62085a feat(cutout): implement boundary padding for cutout textures
- Introduced a new `Boundary Padding` preference in the Cutout Tool with a default of 2 px and a configurable range of 1-4 px.
- Updated the Cutout client to establish inward mapping from the final Mask, sampling in a fixed direction and processing independent material RGBA and Depth.
- Enhanced the handling of RGBA and Depth during cutout operations, ensuring proper mapping and preservation of source data.
- Added tests to validate the new boundary padding functionality and its integration with existing cutout processes.

feat(geometry): remove overall mesh smoothing from geometry nodes

- Removed the `Smooth` input from several geometry node groups to eliminate unnecessary overall mesh smoothing.
- Retained `Smooth Weight` for depth nodes while removing it from Cutout and Relief Plane nodes.
- Ensured that boundary, normal, and fill smoothing behaviors remain intact and consistent.
- Updated tests and documentation to reflect the changes in node interfaces and behaviors.

feat(normals): scale tangent normals with depth

- Reused the existing `o_normal_reduction` attribute to adjust Tangent Normal strength based on the geometry's `Depth Scale`.
- Ensured that Tangent Normal strength is consistent with the geometry depth, preserving full strength for materials that do not provide the attribute.
- Updated tests to verify the correct behavior of normal strength adjustments in both Tangent and Object Space.
2026-09-15 00:40:24 +08:00

137 lines
4.7 KiB
Python

import importlib
import json
import sys
import tempfile
import threading
from pathlib import Path
from types import SimpleNamespace
from unittest.mock import patch
from tests.support.blender import BlenderTestCase
class JobOperatorTest(BlenderTestCase):
def test_runtime_submits_job_type_and_plain_dict(self):
calls = []
submitted = threading.Event()
class Controller:
def submit(self, job_type, parameters):
calls.append((job_type, parameters))
submitted.set()
return {"job_id": "job", "directory": "."}
def cancel(self, _job_id):
pass
def mark_job_complete(self, _job_id):
pass
class Example(self.runtime.JobOperatorBase):
job_type = "example"
value: object()
def controller(self, _runtime):
return Controller()
timers = []
window_manager = SimpleNamespace(
progress_begin=lambda *_args: None,
progress_update=lambda _value: None,
event_timer_add=lambda *_args, **_kwargs: (
timers.append(object()) or timers[-1]
),
event_timer_remove=lambda _timer: None,
modal_handler_add=lambda _operator: None,
)
context = SimpleNamespace(
window_manager=window_manager,
window=object(),
)
operator = Example()
operator.value = 9
self.assertEqual(operator.execute(context), {"RUNNING_MODAL"})
self.assertTrue(submitted.wait(1.0))
self.assertEqual(calls, [("example", {"value": 9})])
def test_runtime_owns_environment_and_storage_paths(self):
runtime = self.anyimage.runtime
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
with patch.object(runtime, "storage_root_factory", root):
self.assertEqual(runtime.storage_root(), root.resolve())
self.assertEqual(runtime.environment_directory(), root / ".venv")
self.assertEqual(
runtime.install_status_path(), root / "install-status.json"
)
self.assertEqual(runtime.install_log_path(), root / "install.log")
self.assertEqual(runtime.server_log_path(), root / "server.log")
def test_runtime_checks_its_environment_dictionary_hash(self):
runtime = self.anyimage.runtime
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
python = (
root
/ ".venv"
/ ("Scripts/python.exe" if sys.platform == "win32" else "bin/python")
)
python.parent.mkdir(parents=True)
python.touch()
(root / "manifest.json").write_text(
json.dumps({"environment_hash": runtime.environment_hash}),
encoding="utf-8",
)
with patch.object(runtime, "storage_root_factory", root):
self.assertTrue(runtime.environment_ready())
def test_runtime_builds_the_standard_installer_command(self):
runtime = self.anyimage.runtime
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
with patch.object(runtime, "storage_root_factory", root):
command = runtime.install_command()
self.assertEqual(command[0], sys.executable)
self.assertEqual(Path(command[1]).name, "environment.py")
self.assertEqual(Path(command[1]).parent.name, "installer")
self.assertIn("--storage-root", command)
self.assertIn("--config", command)
def test_server_request_returns_job_result_and_calls_response(self):
controller_type = importlib.import_module(
"blendjob.controller"
).ServerController
controller = controller_type.__new__(controller_type)
statuses = iter(
(
{"state": "running", "progress": 0.5},
{
"state": "succeeded",
"progress": 1.0,
"result": {"value": 7},
},
)
)
controller.submit = lambda _job_type, _parameters: {
"job_id": "job",
"directory": ".",
}
controller.status = lambda _job_id: next(statuses)
controller.mark_job_complete = lambda _job_id: None
responses = []
result = controller.request(
"example",
{"input": 3},
response=responses.append,
poll_interval=0.01,
)
self.assertEqual(result.value, {"value": 7})
self.assertEqual(responses, [result])