|
| 1 | +"""Native sessions of one project must share a vertical axis: one water column serves them all.""" |
| 2 | + |
| 3 | +from __future__ import annotations |
| 4 | + |
| 5 | +from pathlib import Path |
| 6 | + |
| 7 | +import pytest |
| 8 | + |
| 9 | +from track2data.api import Engine |
| 10 | +from track2data.core.errors import ImportError_ |
| 11 | +from track2data.core.models import SessionRef |
| 12 | + |
| 13 | +from .test_project_rules import _manifest, _native |
| 14 | + |
| 15 | + |
| 16 | +def _ref(session_id: str, axis: str | None = None, **extra) -> SessionRef: |
| 17 | + options: dict = {"fps": 25.0, "unit": "mm", **extra} |
| 18 | + if axis is not None: |
| 19 | + options["vertical_axis"] = axis |
| 20 | + return SessionRef( |
| 21 | + session_id=session_id, |
| 22 | + folder=Path("/tmp") / session_id, |
| 23 | + sha256="", |
| 24 | + reader="anipose", |
| 25 | + reader_options=options, |
| 26 | + ) |
| 27 | + |
| 28 | + |
| 29 | +def _with_axis(session, axis: str): |
| 30 | + attrs = {"native_3d": {"vertical_axis": axis, "flip": False}} |
| 31 | + return session.model_copy(update={"raw_attrs": attrs}) |
| 32 | + |
| 33 | + |
| 34 | +def test_a_batch_with_two_vertical_axes_is_refused_naming_both() -> None: |
| 35 | + engine = Engine(_manifest([])) |
| 36 | + with pytest.raises(ImportError_) as caught: |
| 37 | + engine.check_native_refs([_ref("a", "z"), _ref("b", "y")]) |
| 38 | + assert caught.value.code == "NATIVE_3D_AXIS_MISMATCH" |
| 39 | + message = str(caught.value) |
| 40 | + assert "'a'" in message and "'b'" in message and "'z'" in message and "'y'" in message |
| 41 | + |
| 42 | + |
| 43 | +def test_a_file_on_another_axis_than_the_projects_is_refused() -> None: |
| 44 | + engine = Engine(_manifest([_ref("a", "z")])) |
| 45 | + with pytest.raises(ImportError_) as caught: |
| 46 | + engine.check_native_refs([_ref("b", "x")]) |
| 47 | + assert caught.value.code == "NATIVE_3D_AXIS_MISMATCH" |
| 48 | + assert "'a'" in str(caught.value) and "'b'" in str(caught.value) |
| 49 | + |
| 50 | + |
| 51 | +def test_the_default_axis_is_z_when_the_option_is_not_saved() -> None: |
| 52 | + engine = Engine(_manifest([_ref("a")])) # no vertical_axis saved: z |
| 53 | + engine.check_native_refs([_ref("b", "z")]) # does not raise |
| 54 | + with pytest.raises(ImportError_): |
| 55 | + engine.check_native_refs([_ref("c", "y")]) |
| 56 | + |
| 57 | + |
| 58 | +def test_the_same_axis_with_a_different_flip_is_accepted() -> None: |
| 59 | + engine = Engine(_manifest([_ref("a", "z", flip=False)])) |
| 60 | + engine.check_native_refs([_ref("b", "z", flip=True)]) |
| 61 | + |
| 62 | + |
| 63 | +def test_a_read_session_on_another_axis_is_refused() -> None: |
| 64 | + engine = Engine(_manifest([_ref("a", "z")])) |
| 65 | + with pytest.raises(ImportError_) as caught: |
| 66 | + engine.check_native_import(_with_axis(_native("b"), "y")) |
| 67 | + assert caught.value.code == "NATIVE_3D_AXIS_MISMATCH" |
| 68 | + |
| 69 | + |
| 70 | +def test_a_read_session_on_the_projects_axis_is_accepted() -> None: |
| 71 | + engine = Engine(_manifest([_ref("a", "y")])) |
| 72 | + engine.check_native_import(_with_axis(_native("b"), "y")) |
| 73 | + |
| 74 | + |
| 75 | +def test_a_session_without_axis_attributes_counts_as_z() -> None: |
| 76 | + engine = Engine(_manifest([_ref("a", "z")])) |
| 77 | + engine.check_native_import(_native("b")) # raw_attrs carries nothing: z |
| 78 | + |
| 79 | + |
| 80 | +def test_the_refusal_says_how_to_fix_it() -> None: |
| 81 | + engine = Engine(_manifest([_ref("a", "z")])) |
| 82 | + with pytest.raises(ImportError_) as caught: |
| 83 | + engine.check_native_refs([_ref("b", "y")]) |
| 84 | + assert "vertical_axis" in (caught.value.remediation or "") |
| 85 | + |
| 86 | + |
| 87 | +def test_a_project_whose_files_already_disagree_is_refused_when_one_is_read() -> None: |
| 88 | + """The rule runs on every import, as the unit rule does, so an existing mixed project says |
| 89 | + why instead of computing a water column that means two things.""" |
| 90 | + engine = Engine(_manifest([_ref("a", "z"), _ref("b", "y")])) |
| 91 | + with pytest.raises(ImportError_) as caught: |
| 92 | + engine.check_native_import(_native("a")) |
| 93 | + assert caught.value.code == "NATIVE_3D_AXIS_MISMATCH" |
0 commit comments