"""Validation tests for the study JSON protocol (v1).""" import json import pytest from fem_solver.errors import FemSolverError from fem_solver.study import parse_study def valid_study() -> dict: return { "version": 1, "material": {"name": "Steel", "youngModulus": 210000, "poissonRatio": 0.3, "density": 7.85e-9}, "mesh": {"targetSize": 2.5}, "fixtures": [{"type": "fixed", "patch": {"vertices": [[0, 0, 0], [0, 10, 10]]}}], "loads": [ {"type": "force", "value": [0, -1000, 0], "patch": {"vertices": [[100, 0, 0], [100, 10, 10]]}} ], } def test_valid_study_is_normalized(): parsed = parse_study(__import__("json").dumps(valid_study())) assert parsed["material"]["youngModulus"] == 210000 assert parsed["mesh"]["targetSize"] == 2.5 assert parsed["fixtures"][0]["type"] == "fixed" assert parsed["loads"][0]["type"] == "force" def test_defaults_are_applied(): study = valid_study() del study["mesh"] study["material"].pop("density") parsed = parse_study(__import__("json").dumps(study)) assert parsed["mesh"]["targetSize"] == 2.5 assert parsed["material"]["density"] == 7.85e-9 @pytest.mark.parametrize( "mutation,stage", [ (lambda s: s.update(material=None), "study"), (lambda s: s["material"].update(youngModulus=-1), "study"), (lambda s: s["material"].update(poissonRatio=0.5), "study"), (lambda s: s.update(fixtures=[]), "study"), (lambda s: s.update(loads=[]), "study"), (lambda s: s["loads"][0].update(value=[0, None, 0]), "study"), (lambda s: s["fixtures"][0].update(patch={"vertices": []}), "study"), (lambda s: s.update(version=99), "study"), ], ) def test_invalid_studies_are_rejected(mutation, stage): study = valid_study() mutation(study) with pytest.raises(FemSolverError) as excinfo: parse_study(__import__("json").dumps(study)) assert excinfo.value.stage == stage def test_pressure_load_requires_area_and_normal(): study = valid_study() study["loads"] = [{"type": "pressure", "value": 0.1, "patch": {"vertices": [[0, 0, 0]]}}] with pytest.raises(FemSolverError): parse_study(__import__("json").dumps(study)) study["loads"][0]["patch"].update(area=120.0, normal=[0, 1, 0]) parsed = parse_study(__import__("json").dumps(study)) assert parsed["loads"][0]["patch"]["area"] == 120.0 def test_malformed_json_is_rejected(): with pytest.raises(FemSolverError) as excinfo: parse_study("{not json") assert excinfo.value.stage == "study"