2026-09-21 12:19:20 -04:00
|
|
|
from pathlib import Path
|
|
|
|
|
import importlib.util
|
2026-09-21 14:25:16 -04:00
|
|
|
import math
|
2026-09-21 12:19:20 -04:00
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
HERE = Path(__file__).resolve().parent
|
|
|
|
|
|
|
|
|
|
spec = importlib.util.spec_from_file_location("concrete_beam_calc", HERE / "calc.py")
|
|
|
|
|
assert spec is not None and spec.loader is not None
|
|
|
|
|
calc_module = importlib.util.module_from_spec(spec)
|
|
|
|
|
spec.loader.exec_module(calc_module)
|
|
|
|
|
compute = calc_module.compute
|
|
|
|
|
|
|
|
|
|
|
2026-09-21 14:25:16 -04:00
|
|
|
def _load(name: str, filename: str):
|
|
|
|
|
spec = importlib.util.spec_from_file_location(name, HERE / filename)
|
|
|
|
|
assert spec is not None and spec.loader is not None
|
|
|
|
|
module = importlib.util.module_from_spec(spec)
|
|
|
|
|
spec.loader.exec_module(module)
|
|
|
|
|
return module
|
|
|
|
|
|
|
|
|
|
|
2026-09-21 12:19:20 -04:00
|
|
|
@pytest.fixture
|
|
|
|
|
def result():
|
|
|
|
|
import yaml
|
|
|
|
|
|
|
|
|
|
with (HERE / "input.yaml").open(encoding="utf-8") as handle:
|
|
|
|
|
return compute(yaml.safe_load(handle))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_example_demands(result):
|
|
|
|
|
v = result["values"]
|
2026-09-21 12:44:28 -04:00
|
|
|
assert v["self_weight"] == pytest.approx(0.1)
|
|
|
|
|
assert v["wu"] == pytest.approx(0.7325)
|
|
|
|
|
assert v["Mu"] == pytest.approx(23.44)
|
|
|
|
|
assert v["Vu"] == pytest.approx(5.86)
|
2026-09-21 12:19:20 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_example_flexure(result):
|
|
|
|
|
v = result["values"]
|
2026-09-21 19:16:57 -04:00
|
|
|
assert v["a"] == pytest.approx(1.804683, rel=1e-5)
|
|
|
|
|
assert v["et"] == pytest.approx(0.010423, rel=1e-3)
|
2026-09-21 12:19:20 -04:00
|
|
|
assert v["phi"] == pytest.approx(0.9)
|
2026-09-21 19:16:57 -04:00
|
|
|
assert v["phiMn"] == pytest.approx(23.739557, rel=1e-5)
|
2026-09-21 12:19:20 -04:00
|
|
|
assert result["checks"]["flexure"]["ok"] is True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_example_min_steel_and_shear(result):
|
|
|
|
|
v = result["values"]
|
2026-09-21 12:44:28 -04:00
|
|
|
assert v["As_min"] == pytest.approx(0.253333, rel=1e-4)
|
|
|
|
|
assert v["phiVc"] == pytest.approx(6.244016, rel=1e-4)
|
2026-09-21 12:19:20 -04:00
|
|
|
assert result["checks"]["minimum_steel"]["ok"] is True
|
|
|
|
|
assert result["checks"]["shear"]["ok"] is True
|
2026-09-21 14:25:16 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_reinforcement_geometry(result):
|
|
|
|
|
v = result["values"]
|
|
|
|
|
assert v["cover"] == pytest.approx(1.5)
|
|
|
|
|
assert v["stirrup_size"] == 3
|
|
|
|
|
assert v["stirrup_db"] == pytest.approx(0.375)
|
|
|
|
|
assert v["stirrup_spacing"] == pytest.approx(6.0)
|
|
|
|
|
assert v["bar_size"] == 5
|
|
|
|
|
assert v["n_bars"] == 2
|
|
|
|
|
assert v["bar_db"] == pytest.approx(0.625)
|
|
|
|
|
assert v["top_bar_size"] == 4
|
|
|
|
|
assert v["n_top_bars"] == 2
|
|
|
|
|
assert v["top_bar_db"] == pytest.approx(0.5)
|
2026-09-21 19:16:57 -04:00
|
|
|
assert v["As"] == pytest.approx(2 * math.pi * 0.625**2 / 4.0, rel=1e-6)
|
2026-09-21 14:25:16 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_rejects_depth_without_room_for_bars():
|
|
|
|
|
import yaml
|
|
|
|
|
|
|
|
|
|
with (HERE / "input.yaml").open(encoding="utf-8") as handle:
|
|
|
|
|
inp = yaml.safe_load(handle)
|
|
|
|
|
inp["d"] = "11.9 in"
|
|
|
|
|
with pytest.raises(ValueError):
|
|
|
|
|
compute(inp)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_section_fragment_is_current(result):
|
|
|
|
|
module = _load("beam_section", "beam_section.py")
|
|
|
|
|
expected = module.render(result["values"])
|
|
|
|
|
actual = (HERE / "assets" / "beam-section.typ").read_text(encoding="utf-8")
|
|
|
|
|
assert actual == expected
|