from pathlib import Path from types import SimpleNamespace import numpy as np import pytest import orisys from orisys.finger import ( TactileProcessor, load_finger_export_bundle, resolve_export_paths, ) from orisys.finger.exports import DEFAULT_FINGER_MAP_CACHE from orisys.finger.runtime import resolve_finger_geometry def _touch_bundle(root: Path): for name in ("mesh.npz", "camera_intrinsics.npz", "world_to_cam.npy"): (root / name).write_bytes(b"") def test_resolve_export_paths_returns_expected_bundle(tmp_path): _touch_bundle(tmp_path) bundle = resolve_export_paths(tmp_path) assert bundle.export_dir == tmp_path.resolve() assert bundle.mesh.name == "mesh.npz" assert bundle.intrinsics.name == "camera_intrinsics.npz" assert bundle.pose.name == "world_to_cam.npy" def test_load_finger_export_bundle_rehomes_default_map_cache(tmp_path, monkeypatch): _touch_bundle(tmp_path) import orisys.finger.exports as exports_mod monkeypatch.setattr( exports_mod, "load_exported_data", lambda *args: {"K": np.eye(3), "width": 1280, "height": 720}, ) monkeypatch.setattr(exports_mod, "compute_uv_distortion_metrics", lambda data: {"ok": True}) monkeypatch.setattr(exports_mod, "recommend_edge_expand", lambda _: 1.2) bundle = load_finger_export_bundle( tmp_path, map_cache=DEFAULT_FINGER_MAP_CACHE, source_scale=1.0, ) assert Path(bundle.map_cache) == (tmp_path / "unroll_map_uv.npz").resolve() assert bundle.edge_expand == 1.2 def test_resolve_finger_geometry_uses_config_defaults(tmp_path, monkeypatch): _touch_bundle(tmp_path) import orisys.finger.exports as exports_mod import orisys.finger.runtime as runtime_mod monkeypatch.setattr( runtime_mod, "load_config", lambda _: {"camera": {"resolution_stitch": [280, 300], "source_scale": 0.4}}, ) monkeypatch.setattr( exports_mod, "load_exported_data", lambda *args: {"K": np.eye(3), "width": 1280, "height": 720}, ) monkeypatch.setattr(exports_mod, "compute_uv_distortion_metrics", lambda data: {"ok": True}) monkeypatch.setattr(exports_mod, "recommend_edge_expand", lambda _: 1.2) geometry = resolve_finger_geometry( export_dir=tmp_path, config="dd02-ov", ) assert geometry.out_width == 280 assert geometry.out_height == 300 assert geometry.source_scale == 0.4 assert geometry.source_width == 512 assert geometry.source_height == 288 assert Path(geometry.map_cache) == (tmp_path / "unroll_map_uv_s0.4.npz").resolve() def test_default_map_cache_rehomes_to_resolved_export_dir(tmp_path, monkeypatch): _touch_bundle(tmp_path) import orisys.finger.exports as exports_mod import orisys.finger.runtime as runtime_mod monkeypatch.setattr( runtime_mod, "load_config", lambda _: {"camera": {"resolution_stitch": [280, 300], "source_scale": 1.0}}, ) monkeypatch.setattr( exports_mod, "load_exported_data", lambda *args: {"K": np.eye(3), "width": 1280, "height": 720}, ) monkeypatch.setattr(exports_mod, "compute_uv_distortion_metrics", lambda data: {"ok": True}) monkeypatch.setattr(exports_mod, "recommend_edge_expand", lambda _: 1.2) geometry = resolve_finger_geometry( export_dir=tmp_path, config="dd02-ov", map_cache=DEFAULT_FINGER_MAP_CACHE, ) assert Path(geometry.map_cache) == (tmp_path / "unroll_map_uv.npz").resolve() def test_orisys_root_exports_finger_module(): assert hasattr(orisys, "finger") def test_tactile_processor_push_frame_uses_default_valid_mask(): class DummySensor: info = object() def __init__(self): self.calls = [] self.frame = None self.img = None self.flow = None self.vnormal = None self.vshear = None self.depth_map = None self.mask_stats = {} self.valid_mask = None def get_img(self, **kwargs): self.calls.append(kwargs) self.frame = kwargs["frame"] self.valid_mask = kwargs["valid_mask"] return "ok" sensor = DummySensor() default_mask = np.array([[True, False], [False, True]]) tactile = TactileProcessor(sensor, default_valid_mask=default_mask) frame = np.zeros((2, 2), dtype=np.uint8) result = tactile.push_frame(frame, already_gray=True) assert result == "ok" assert sensor.calls[0]["frame"] is frame assert sensor.calls[0]["already_processed"] is True assert sensor.calls[0]["already_gray"] is True assert sensor.calls[0]["valid_mask"] is default_mask def test_finger_runtime_get_img_returns_none_on_capture_failure(): from orisys.finger.runtime import FingerRuntime runtime = object.__new__(FingerRuntime) runtime.grab_and_process = lambda *, color=False: (False, None) assert runtime.get_img() is None def test_finger_open_selects_device_calibration_before_capture(monkeypatch, tmp_path): import orisys.finger.runtime as runtime_mod selected = {} geometry = SimpleNamespace( export_paths=SimpleNamespace(as_tuple=lambda: ("mesh", "intrinsics", "pose")), map_cache="cache", source_K=np.eye(3), source_width=2, source_height=2, out_width=2, out_height=2, edge_expand=1.0, source_scale=1.0, config={"camera": {}}, ) monkeypatch.setattr(runtime_mod, "resolve_finger_geometry", lambda **_: geometry) monkeypatch.setattr( runtime_mod, "build_or_load_domain", lambda *args, **kwargs: SimpleNamespace( remap=SimpleNamespace(ensure_fast_maps=lambda: None) ), ) monkeypatch.setattr(runtime_mod, "Sensor", lambda *args, **kwargs: selected.update(kwargs)) monkeypatch.setattr(runtime_mod.CaptureConfig, "from_camera_dict", lambda *args, **kwargs: None) def stop_before_capture(*args, **kwargs): assert selected["calibration_dir"] == tmp_path assert selected["device_id"] == "FINGER-001" raise RuntimeError("capture reached") monkeypatch.setattr(runtime_mod, "open_capture", stop_before_capture) with pytest.raises(RuntimeError, match="capture reached"): runtime_mod.FingerRuntime.open(calibration_dir=tmp_path, device_id="FINGER-001") def test_finger_runtime_get_img_returns_unrolled_frame_on_success(): from orisys.finger.runtime import FingerRuntime frame = np.zeros((2, 2), dtype=np.uint8) runtime = object.__new__(FingerRuntime) runtime.grab_and_process = lambda *, color=False: (True, frame) assert runtime.get_img(color=True) is frame @pytest.mark.parametrize( "video,expected", [ ("0", 0), (" 1 ", 1), (r".\data\dd02\0607_1.mp4" + "\\", r".\data\dd02\0607_1.mp4"), (0, 0), ("./clip.mp4", "./clip.mp4"), ], ) def test_normalize_video_source(video, expected): from orisys.finger.runtime import normalize_video_source assert normalize_video_source(video) == expected