From ba9685b965c64a170ff5ca566f750d3ae4225769 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 12 Aug 2026 02:33:08 +0900 Subject: [PATCH] test(ata): require Rust-owned fixed-form assembly --- tests/test_test_form_rust_ownership.py | 42 ++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 tests/test_test_form_rust_ownership.py diff --git a/tests/test_test_form_rust_ownership.py b/tests/test_test_form_rust_ownership.py new file mode 100644 index 000000000..c63dace80 --- /dev/null +++ b/tests/test_test_form_rust_ownership.py @@ -0,0 +1,42 @@ +"""Fail-first ownership contracts for fixed-form maximum-information assembly.""" + +from __future__ import annotations + +import numpy as np + +import fast_mlsirm._core as core +from fast_mlsirm.test_design import assemble_test_form + + +def test_public_test_form_assembly_delegates_selection_to_rust(monkeypatch) -> None: + """Ordering, exclusion, and content-feasibility decisions come from Rust.""" + information = np.array([1.0, 4.0, 3.0, 2.0], dtype=np.float64) + content = np.array(["A", "A", "B", "B"], dtype=object) + exclude = np.array([3], dtype=np.int64) + information_before = information.copy() + content_before = content.copy() + exclude_before = exclude.copy() + calls: list[tuple[tuple[object, ...], dict[str, object]]] = [] + + def fake_assemble(*args: object, **kwargs: object) -> list[int]: + calls.append((args, kwargs)) + # A deliberately different valid form from the current Python greedy + # result proves public result ownership rather than mere helper reuse. + return [2, 0] + + monkeypatch.setattr(core, "assemble_test_form_greedy", fake_assemble, raising=False) + + selected = assemble_test_form( + information, + length=2, + content=content, + min_per_content={"B": 1}, + max_per_content={"A": 1}, + exclude=exclude, + ) + + assert len(calls) == 1 + assert np.array_equal(selected, np.array([2, 0], dtype=np.int64)) + assert np.array_equal(information, information_before) + assert np.array_equal(content, content_before) + assert np.array_equal(exclude, exclude_before)