| """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 |
|
|
|
|
| |
| |
| |
|
|
| 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 |
|
|
|
|
| |
| |
| |
|
|
| 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", |
| ) |
| |
| 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", |
| ) |
| |
| 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 |
|
|