"""Acceptance for the calibration service's rules about *whose* a file is. The window used to own these: reading a coefficient file's claimed identity and deciding whether it obviously belongs to the device on the bench. They are pure rules about files, so they now live with the rest of the calibration file work — and can be tested without building a window. The end-to-end apply path is still covered by ``test_ui_smoke``. """ from __future__ import annotations import json from pathlib import Path from orisys_app_shared.force.calibration_io import ( CalSample, CalSessionStore, build_export_model, ) from orisys_studio.calibration_service import CalibrationService def _calibration_file(directory: Path, *, sensor_type: str, config_ref: str) -> Path: """A coefficient document that names the device it was measured on.""" store = CalSessionStore() store.aggregate("fn", CalSample(weight_n=0.0, raw_mean=0.0, n=10)) store.aggregate("fn", CalSample(weight_n=5.0, raw_mean=500.0, n=10)) model = build_export_model({key: store.channel(key) for key in ("fn", "fx", "fy")}) document = model.to_dict() document["identity"] = {"sensor_type": sensor_type, "sn": "SN-A"} document["pipeline"] = {"config_ref": config_ref} path = directory / f"{sensor_type}_calibration.json" path.write_text(json.dumps(document), encoding="utf-8") return path def test_the_identity_names_the_sensor_and_the_configuration(tmp_path): path = _calibration_file(tmp_path, sensor_type="box", config_ref="D:/lab/a/sensor.json") identity = CalibrationService.identity_of(path) assert identity["sensor_type"] == "box" assert identity["sn"] == "SN-A" assert identity["config_ref"] == "D:/lab/a/sensor.json" def test_a_file_that_cannot_be_read_claims_nothing(tmp_path): """No identity must mean "no mismatch claim", not "mismatch".""" broken = tmp_path / "not-a-calibration.json" broken.write_text("this is not a coefficient document\n", encoding="utf-8") assert CalibrationService.identity_of(broken) == {} assert CalibrationService.target_mismatch( broken, sensor_type="finger", config_ref="D:/lab/b/sensor.json" ) == [] def test_another_devices_calibration_is_reported_with_its_reasons(tmp_path): path = _calibration_file(tmp_path, sensor_type="box", config_ref="D:/lab/a/sensor.json") reasons = CalibrationService.target_mismatch( path, sensor_type="finger", config_ref="D:/lab/b/sensor.json" ) assert any("sensor_type" in reason for reason in reasons), reasons assert any("config_ref" in reason for reason in reasons), reasons # The same device and configuration is not a mismatch. assert ( CalibrationService.target_mismatch( path, sensor_type="box", config_ref="D:/lab/a/sensor.json" ) == [] ) def test_the_same_configuration_named_differently_is_not_a_mismatch(tmp_path): """A path is compared as a path: the apply path must not cry wolf over spelling.""" assert CalibrationService.same_path("", "D:/lab/a/sensor.json") is True assert CalibrationService.same_path("D:/lab/a/sensor.json", "") is True assert CalibrationService.same_path("D:/lab/a/sensor.json", "D:/lab/./a/sensor.json") # ...but it does have to be a path: a non-path value simply differs. assert CalibrationService.same_path("D:/lab/a/sensor.json", "not a path\x00") is False # --------------------------------------------------- one parse, both answers def test_read_identity_returns_the_identity_and_no_error(tmp_path): """The strict parse answers with the identity *and* says it succeeded.""" path = _calibration_file(tmp_path, sensor_type="box", config_ref="D:/lab/a/sensor.json") identity, error = CalibrationService.read_identity(path) assert error == "" assert identity == { "sensor_type": "box", "sn": "SN-A", "config_ref": "D:/lab/a/sensor.json", } # The old name keeps its behaviour and is a thin wrapper over the one parse. assert CalibrationService.identity_of(path) == identity def test_read_identity_keeps_the_parsers_reason_when_the_file_cannot_be_read(tmp_path): broken = tmp_path / "broken.json" broken.write_text( json.dumps({"schema_version": 2, "unit": "N", "channels": {"fn": "bogus"}}), encoding="utf-8", ) identity, error = CalibrationService.read_identity(broken) assert identity == {} assert error assert "\n" not in error, "the reason must stay one line for the status bar" assert CalibrationService.identity_of(broken) == {} def test_read_identity_distinguishes_a_parsed_document_without_an_sn(tmp_path): """A readable document that simply names no device is not a parse failure.""" path = _calibration_file(tmp_path, sensor_type="box", config_ref="D:/lab/a/sensor.json") document = json.loads(path.read_text(encoding="utf-8")) document.pop("identity") document.pop("pipeline") path.write_text(json.dumps(document), encoding="utf-8") identity, error = CalibrationService.read_identity(path) assert error == "" assert identity["sn"] == "" assert identity["sensor_type"] == ""