Files

188 lines
6.0 KiB
Python

import pytest
from pathlib import Path
from navaltoolbox import (
Hull,
Vessel,
StabilityCalculator,
CriteriaContext,
ScriptEngine,
)
class TestRhaiScripting:
"""Tests for Rhai scripting integration."""
@pytest.fixture
def dtmb5415_vessel(self):
"""Load DTMB5415 hull and create vessel."""
stl_path = (
Path(__file__).parent.parent.parent
/ "rust"
/ "tests"
/ "data"
/ "dtmb5415.stl"
)
if not stl_path.exists():
pytest.skip("DTMB5415 STL file not found")
hull = Hull(str(stl_path))
return Vessel(hull)
def test_reproduce_is_code_2008_error(self, dtmb5415_vessel):
"""
Reproduce the 'Function not found' error for IS Code 2008 script.
Specifically checking:
- find_max_gz
- area_under_curve
"""
# 1. Setup stability result
displacement = 8635000.0 # kg
lcg = 71.670
tcg = 0.0
vcg = 7.555
cog = (lcg, tcg, vcg)
calc = StabilityCalculator(dtmb5415_vessel, 1025.0)
# Calculate full curve 0-180
heels = list(range(0, 70, 5))
result = calc.complete_stability(displacement, cog, heels)
# 2. Create Context
ctx = CriteriaContext.from_result(
result,
vessel_name="DTMB 5415",
loading_condition="Design Load"
)
# 3. Initialize Engine
engine = ScriptEngine()
# 4. Load and run IS Code 2008 script
script_path = (
Path(__file__).parent.parent.parent
/ "rules"
/ "is_code_2008_general.rhai"
)
if not script_path.exists():
pytest.skip(f"Script not found at {script_path}")
print(f"Running script: {script_path}")
# This is expected to fail currently
try:
result = engine.run_script_file(str(script_path), ctx)
print("Script execution successful!")
print(f"Overall Pass: {result.overall_pass}")
for crit in result.criteria:
print(
f" - {crit.name}: "
f"{crit.status} ({crit.actual_value:.3f} {crit.unit})"
)
except ValueError as e:
pytest.fail(f"Script execution failed: {e}")
def test_minimal_reproduction(self, dtmb5415_vessel):
"""Minimal reproduction of specific function calls."""
displacement = 8635000.0
cog = (71.670, 0.0, 7.555)
calc = StabilityCalculator(dtmb5415_vessel, 1025.0)
heels = [0, 10, 20, 30, 40, 50, 60]
result = calc.complete_stability(displacement, cog, heels)
ctx = CriteriaContext.from_result(result, "Test", "Test")
engine = ScriptEngine()
# Test find_max_gz
script_max_gz = """
fn check(ctx) {
let max = ctx.find_max_gz();
print("Max GZ: " + max);
return #{ name: "Test", status: "PASS" };
}
"""
engine.run_script(script_max_gz, ctx)
# Test area_under_curve
script_area = """
fn check(ctx) {
let area = ctx.area_under_curve(0.0, 30.0);
print("Area: " + area);
return #{ name: "Test", status: "PASS" };
}
"""
engine.run_script(script_area, ctx)
def test_is_code_2008_values_dtmb5415(self, dtmb5415_vessel):
"""Verify numerical values of IS Code 2008 criteria on DTMB5415."""
displacement = 8635000.0
cog = (71.670, 0.0, 7.555)
calc = StabilityCalculator(dtmb5415_vessel, 1025.0)
heels = list(range(0, 70, 5))
result = calc.complete_stability(displacement, cog, heels)
ctx = CriteriaContext.from_result(result, "DTMB 5415", "Test")
engine = ScriptEngine()
script_path = (
Path(__file__).parent.parent.parent
/ "rules"
/ "is_code_2008_general.rhai"
)
if not script_path.exists():
pytest.skip("IS Code script not found")
res = engine.run_script_file(str(script_path), ctx)
assert res.overall_pass is True, (
"DTMB5415 should pass all general criteria"
)
assert len(res.criteria) == 6
crit_names = [c.name for c in res.criteria]
assert any("Area 0-30°" in n for n in crit_names)
assert any("GZ at 30°+" in n for n in crit_names)
assert any("Initial GM₀" in n for n in crit_names)
for crit in res.criteria:
assert crit.status == "PASS"
if "GM₀" in crit.name:
assert abs(crit.actual_value - result.hydrostatics.gmt) < 0.01
def test_run_all_rules(self, dtmb5415_vessel):
"""Verify that all scripts in rules/ directory can be executed."""
displacement = 8635000.0
cog = (71.670, 0.0, 7.555)
calc = StabilityCalculator(dtmb5415_vessel, 1025.0)
heels = list(range(0, 70, 5))
result = calc.complete_stability(displacement, cog, heels)
ctx = CriteriaContext.from_result(result, "Test", "Test")
engine = ScriptEngine()
rules_dir = Path(__file__).parent.parent.parent / "rules"
scripts = list(rules_dir.glob("*.rhai"))
assert len(scripts) > 0, "No rule scripts found"
for script in scripts:
print(f"Testing script: {script.name}")
try:
res = engine.run_script_file(str(script), ctx)
# Basic check that we got a result
assert res.overall_pass is not None
except Exception as e:
# template.rhai might fail if it expects parameters
# we didn't set, but we should check if it's a
# syntax error vs runtime error
print(f"Script {script.name} failed: {e}")
# We expect success for IMO scripts. Template might fail logic
# but should run.
if "im" in script.name:
pytest.fail(f"IMO script {script.name} failed: {e}")