openenv-secaudit / tests /test_reward.py
dexter-2k's picture
Upload folder using huggingface_hub
ee929ba verified
Raw
History Blame Contribute Delete
3.97 kB
"""Tests for the efficiency bonus reward function."""
from __future__ import annotations
import sys, os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
from graders.reward import compute_efficiency_bonus, RewardBreakdown, STEP_BUDGETS
from graders.health import HealthReport
from graders.security import SecurityReport
# ---------------------------------------------------------------------------
# compute_efficiency_bonus unit tests
# ---------------------------------------------------------------------------
class TestEfficiencyBonus:
def test_full_bonus_at_zero_steps(self):
bonus = compute_efficiency_bonus(steps_taken=0, difficulty="easy")
assert bonus == 0.15
def test_zero_bonus_at_budget(self):
bonus = compute_efficiency_bonus(steps_taken=10, difficulty="easy")
assert bonus == 0.0
def test_half_bonus_at_half_budget(self):
bonus = compute_efficiency_bonus(steps_taken=5, difficulty="easy")
assert abs(bonus - 0.075) < 0.001
def test_over_budget_clamps_to_zero(self):
bonus = compute_efficiency_bonus(steps_taken=50, difficulty="easy")
assert bonus == 0.0
def test_all_difficulty_budgets_exist(self):
for diff in ("easy", "medium", "hard"):
assert diff in STEP_BUDGETS
bonus = compute_efficiency_bonus(steps_taken=0, difficulty=diff)
assert bonus == 0.15
def test_unknown_difficulty_falls_back(self):
bonus = compute_efficiency_bonus(steps_taken=0, difficulty="unknown")
assert bonus == 0.15 # falls back to medium budget
# ---------------------------------------------------------------------------
# RewardBreakdown integration
# ---------------------------------------------------------------------------
def _make_security(finding_count: int) -> SecurityReport:
return SecurityReport(finding_count=finding_count, findings=[])
def _make_health(score: float) -> HealthReport:
return HealthReport(
score=score, passed=1, failures=0, errors=0, total=1,
exit_code=0, stdout="", stderr=""
)
class TestRewardBreakdown:
def test_perfect_score_with_efficiency(self):
reward = RewardBreakdown.from_reports(
security=_make_security(0),
health=_make_health(1.0),
initial_leaks=5,
steps_taken=0,
difficulty="easy",
)
# base = 1.0 * 1.0 = 1.0, efficiency = 0.15 → clamped to 1.0
assert reward.total_reward == 1.0
assert reward.efficiency_bonus == 0.15
def test_zero_security_gets_zero_reward(self):
reward = RewardBreakdown.from_reports(
security=_make_security(5),
health=_make_health(1.0),
initial_leaks=5,
steps_taken=0,
difficulty="easy",
)
# No secrets fixed = base is 0 = no reward (efficiency can't give free points)
assert reward.total_reward == 0.0
def test_reward_clamped_to_1(self):
reward = RewardBreakdown.from_reports(
security=_make_security(0),
health=_make_health(1.0),
initial_leaks=2,
steps_taken=0,
difficulty="hard",
)
assert reward.total_reward <= 1.0
def test_reward_stays_positive(self):
reward = RewardBreakdown.from_reports(
security=_make_security(10),
health=_make_health(0.0),
initial_leaks=10,
steps_taken=30,
difficulty="hard",
)
assert reward.total_reward >= 0.0
def test_efficiency_bonus_field_exposed(self):
reward = RewardBreakdown.from_reports(
security=_make_security(3),
health=_make_health(0.8),
initial_leaks=5,
steps_taken=5,
difficulty="medium",
)
assert hasattr(reward, "efficiency_bonus")
assert 0.0 <= reward.efficiency_bonus <= 0.15