import base64 import os import tempfile import unittest from unittest.mock import patch import app as rollcalc_app class CalculationApiTests(unittest.TestCase): def setUp(self): self.temp_dir = tempfile.TemporaryDirectory() self.original_log_file = rollcalc_app.LOG_FILE rollcalc_app.LOG_FILE = os.path.join(self.temp_dir.name, "access.json") rollcalc_app.app.config.update(TESTING=True) self.client = rollcalc_app.app.test_client() credentials = base64.b64encode(b"mtazl:rollcalc").decode("ascii") self.headers = {"Authorization": f"Basic {credentials}"} def tearDown(self): rollcalc_app.LOG_FILE = self.original_log_file self.temp_dir.cleanup() def test_calculation_endpoint_returns_machine_readable_authoritative_result(self): response = self.client.post( "/api/calculations/roll", json={ "article_number": "180205", "roll_length_m": 65, "core_diameter_mm": 150, }, headers=self.headers, ) result = response.get_json() self.assertEqual(response.status_code, 200) self.assertEqual(result["status"], "success") self.assertEqual(result["resolved_article"]["number"], "180205") self.assertEqual( result["provenance"]["calculator"], "roll_calculation.calculate_roll", ) def test_modification_endpoint_changes_state_and_recalculates(self): response = self.client.post( "/api/calculations/roll/modify", json={ "state": { "request": { "article_number": "180205", "roll_length_m": 65, "core_diameter_mm": 150, } }, "changes": {"roll_length_m": 80}, }, headers=self.headers, ) result = response.get_json() self.assertEqual(response.status_code, 200) self.assertEqual(result["status"], "success") self.assertEqual(result["state"]["request"]["roll_length_m"], 80.0) self.assertEqual(result["calculation"]["effective_roll_length_m"], 80.0) def test_product_length_endpoint_uses_the_domain_calculation(self): response = self.client.post( "/api/calculations/product-length", json={ "target_roll_diameter_mm": 600, "core_diameter_mm": 140, "thickness_mm": 4.311611, "thickness_stddev_mm": 0.249999, "width_m": 6.0, "area_weight_g_m2": 495.395833, }, headers=self.headers, ) result = response.get_json() self.assertEqual(response.status_code, 200) self.assertEqual(result["status"], "success") self.assertAlmostEqual( result["calculation"]["average_product_length_m"], 62.0068774341 ) def test_transport_endpoint_delegates_to_shared_domain_service(self): payload = { "length_m": 10, "width_m": 5, "height_m": 5, "max_weight_kg": 10000, "roll_diameter_mm": 1000, "core_diameter_mm": 150, "roll_width_m": 1, "roll_weight_kg": 1000, } with patch.object( rollcalc_app, "analyze_transport", return_value={"status": "success", "analysis": {"final_rolls": 10}}, ) as analyze: response = self.client.post( "/api/calculations/transport", json=payload, headers=self.headers, ) self.assertEqual(response.status_code, 200) self.assertEqual(response.get_json()["analysis"]["final_rolls"], 10) analyze.assert_called_once_with(payload) def test_transport_endpoint_returns_structured_domain_validation(self): response = self.client.post( "/api/calculations/transport", json={"length_m": 0}, headers=self.headers, ) self.assertEqual(response.status_code, 200) self.assertEqual(response.get_json()["status"], "invalid_parameter") if __name__ == "__main__": unittest.main()