Spaces:
Sleeping
Sleeping
| """ | |
| Tests for the Reward Engine — 100% coverage of all reward signals. | |
| """ | |
| import pytest | |
| from rewards.engine import RewardEngine | |
| from executor.docker_executor import ExecutionResult | |
| from scenarios.registry import Scenario | |
| def _make_scenario(**kwargs): | |
| """Create a test scenario with sensible defaults.""" | |
| defaults = dict( | |
| id="test_scenario", | |
| level=1, | |
| description="Test scenario", | |
| initial_state={}, | |
| success_condition=lambda output: "success" in output.lower(), | |
| hint_commands=["pip install flask"], | |
| error_fingerprint=r"ModuleNotFoundError", | |
| ) | |
| defaults.update(kwargs) | |
| return Scenario(**defaults) | |
| def _make_result(**kwargs): | |
| """Create a test ExecutionResult with sensible defaults.""" | |
| defaults = dict(stdout="", stderr="", exit_code=0, timed_out=False, blocked=False, block_reason="") | |
| defaults.update(kwargs) | |
| return ExecutionResult(**defaults) | |
| class TestRewardSuccess: | |
| """Test the success reward signal.""" | |
| def test_success_gives_positive_reward(self): | |
| engine = RewardEngine() | |
| scenario = _make_scenario() | |
| result = _make_result(stdout="Successfully installed flask\nSuccess") | |
| total, breakdown = engine.compute_reward( | |
| action="pip install flask", | |
| result=result, | |
| scenario=scenario, | |
| step_count=1, | |
| command_history=["pip install flask"], | |
| prev_error_log="ModuleNotFoundError", | |
| curr_error_log="Successfully installed flask", | |
| ) | |
| assert breakdown.get("success", 0) == 10.0 | |
| assert total > 0 | |
| def test_no_success_gives_no_success_reward(self): | |
| engine = RewardEngine() | |
| scenario = _make_scenario() | |
| result = _make_result(stdout="some output", stderr="still broken") | |
| total, breakdown = engine.compute_reward( | |
| action="ls", | |
| result=result, | |
| scenario=scenario, | |
| step_count=1, | |
| command_history=["ls"], | |
| prev_error_log="error", | |
| curr_error_log="still broken", | |
| ) | |
| assert "success" not in breakdown | |
| class TestRewardCorrectCommand: | |
| """Test the correct_command reward signal.""" | |
| def test_hint_command_gets_bonus(self): | |
| engine = RewardEngine() | |
| scenario = _make_scenario(hint_commands=["pip install flask"]) | |
| result = _make_result(stdout="installed") | |
| total, breakdown = engine.compute_reward( | |
| action="pip install flask", | |
| result=result, | |
| scenario=scenario, | |
| step_count=1, | |
| command_history=["pip install flask"], | |
| prev_error_log="error", | |
| curr_error_log="installed", | |
| ) | |
| assert breakdown.get("correct_command", 0) == 1.5 | |
| def test_wrong_command_no_bonus(self): | |
| engine = RewardEngine() | |
| scenario = _make_scenario(hint_commands=["pip install flask"]) | |
| result = _make_result(stdout="output") | |
| total, breakdown = engine.compute_reward( | |
| action="apt-get install python", | |
| result=result, | |
| scenario=scenario, | |
| step_count=1, | |
| command_history=["apt-get install python"], | |
| prev_error_log="error", | |
| curr_error_log="output", | |
| ) | |
| assert "correct_command" not in breakdown | |
| class TestRewardProgress: | |
| """Test the progress and no_progress signals.""" | |
| def test_progress_when_error_changes(self): | |
| engine = RewardEngine() | |
| scenario = _make_scenario() | |
| result = _make_result(stdout="new output") | |
| total, breakdown = engine.compute_reward( | |
| action="pip install flask", | |
| result=result, | |
| scenario=scenario, | |
| step_count=1, | |
| command_history=["pip install flask"], | |
| prev_error_log="ModuleNotFoundError: No module named 'flask'", | |
| curr_error_log="installed successfully", | |
| ) | |
| assert breakdown.get("progress", 0) == 1.0 | |
| def test_no_progress_when_identical_logs(self): | |
| engine = RewardEngine() | |
| scenario = _make_scenario() | |
| result = _make_result(stdout="same error") | |
| same_log = "ModuleNotFoundError: No module named 'flask'" | |
| total, breakdown = engine.compute_reward( | |
| action="echo hello", | |
| result=result, | |
| scenario=scenario, | |
| step_count=2, | |
| command_history=["echo hello"], | |
| prev_error_log=same_log, | |
| curr_error_log=same_log, | |
| ) | |
| assert breakdown.get("no_progress", 0) == -1.0 | |
| class TestRewardEfficiency: | |
| """Test the efficiency_bonus signal.""" | |
| def test_efficiency_bonus_when_solved_fast(self): | |
| engine = RewardEngine() | |
| scenario = _make_scenario(hint_commands=["pip install flask"]) | |
| result = _make_result(stdout="Success") | |
| total, breakdown = engine.compute_reward( | |
| action="pip install flask", | |
| result=result, | |
| scenario=scenario, | |
| step_count=1, | |
| command_history=["pip install flask"], | |
| prev_error_log="error", | |
| curr_error_log="Success", | |
| ) | |
| assert breakdown.get("efficiency_bonus", 0) == 2.0 | |
| def test_no_efficiency_bonus_when_too_many_steps(self): | |
| engine = RewardEngine() | |
| scenario = _make_scenario(hint_commands=["pip install flask"]) | |
| result = _make_result(stdout="Success") | |
| total, breakdown = engine.compute_reward( | |
| action="pip install flask", | |
| result=result, | |
| scenario=scenario, | |
| step_count=5, | |
| command_history=["a", "b", "c", "d", "pip install flask"], | |
| prev_error_log="error", | |
| curr_error_log="Success", | |
| ) | |
| assert "efficiency_bonus" not in breakdown | |
| class TestRewardPenalties: | |
| """Test penalty signals.""" | |
| def test_blocked_command_penalty(self): | |
| engine = RewardEngine() | |
| scenario = _make_scenario() | |
| result = _make_result(blocked=True, block_reason="Command 'foo' is not in the whitelist") | |
| total, breakdown = engine.compute_reward( | |
| action="foo", | |
| result=result, | |
| scenario=scenario, | |
| step_count=1, | |
| command_history=["foo"], | |
| prev_error_log="error", | |
| curr_error_log="blocked", | |
| ) | |
| assert breakdown.get("invalid_command", 0) == -2.0 | |
| def test_dangerous_command_penalty(self): | |
| engine = RewardEngine() | |
| scenario = _make_scenario() | |
| result = _make_result(blocked=True, block_reason="Dangerous blocklist pattern matched") | |
| total, breakdown = engine.compute_reward( | |
| action="rm -rf /", | |
| result=result, | |
| scenario=scenario, | |
| step_count=1, | |
| command_history=["rm -rf /"], | |
| prev_error_log="error", | |
| curr_error_log="blocked", | |
| ) | |
| assert breakdown.get("dangerous_command", 0) == -10.0 | |
| def test_timeout_penalty(self): | |
| engine = RewardEngine() | |
| scenario = _make_scenario() | |
| result = _make_result(timed_out=True) | |
| total, breakdown = engine.compute_reward( | |
| action="sleep 100", | |
| result=result, | |
| scenario=scenario, | |
| step_count=1, | |
| command_history=["sleep 100"], | |
| prev_error_log="error", | |
| curr_error_log="timeout", | |
| ) | |
| assert breakdown.get("timeout", 0) == -5.0 | |
| def test_repeated_command_penalty(self): | |
| engine = RewardEngine() | |
| scenario = _make_scenario() | |
| result = _make_result(stdout="output") | |
| total, breakdown = engine.compute_reward( | |
| action="pip install flask", | |
| result=result, | |
| scenario=scenario, | |
| step_count=2, | |
| command_history=["pip install flask", "pip install flask"], | |
| prev_error_log="error", | |
| curr_error_log="output", | |
| ) | |
| assert breakdown.get("repeated_command", 0) == -1.5 | |
| def test_step_cost_always_applied(self): | |
| engine = RewardEngine() | |
| scenario = _make_scenario() | |
| result = _make_result(stdout="output") | |
| total, breakdown = engine.compute_reward( | |
| action="ls", | |
| result=result, | |
| scenario=scenario, | |
| step_count=1, | |
| command_history=["ls"], | |
| prev_error_log="error", | |
| curr_error_log="output", | |
| ) | |
| assert breakdown.get("step_cost", 0) == -0.2 | |
| class TestRewardCombinations: | |
| """Test reward signal combinations.""" | |
| def test_perfect_solve_gives_max_reward(self): | |
| engine = RewardEngine() | |
| scenario = _make_scenario(hint_commands=["pip install flask"]) | |
| result = _make_result(stdout="Successfully installed flask. Success") | |
| total, breakdown = engine.compute_reward( | |
| action="pip install flask", | |
| result=result, | |
| scenario=scenario, | |
| step_count=1, | |
| command_history=["pip install flask"], | |
| prev_error_log="ModuleNotFoundError", | |
| curr_error_log="installed", | |
| ) | |
| # Should get: success(10) + correct_command(1.5) + progress(1) + efficiency(2) + step_cost(-0.2) = 14.3 | |
| assert total > 14.0 | |
| assert "success" in breakdown | |
| assert "correct_command" in breakdown | |
| assert "efficiency_bonus" in breakdown | |
| def test_blocked_command_short_circuits(self): | |
| """Blocked commands should only get step_cost + the block penalty.""" | |
| engine = RewardEngine() | |
| scenario = _make_scenario() | |
| result = _make_result(blocked=True, block_reason="not in whitelist") | |
| total, breakdown = engine.compute_reward( | |
| action="foo", | |
| result=result, | |
| scenario=scenario, | |
| step_count=1, | |
| command_history=["foo"], | |
| prev_error_log="error", | |
| curr_error_log="blocked", | |
| ) | |
| assert len(breakdown) == 2 # step_cost + invalid_command | |
| assert "success" not in breakdown | |
| assert "progress" not in breakdown | |
| def test_timed_out_short_circuits(self): | |
| """Timed out commands should only get step_cost + timeout penalty.""" | |
| engine = RewardEngine() | |
| scenario = _make_scenario() | |
| result = _make_result(timed_out=True) | |
| total, breakdown = engine.compute_reward( | |
| action="sleep 999", | |
| result=result, | |
| scenario=scenario, | |
| step_count=1, | |
| command_history=["sleep 999"], | |
| prev_error_log="error", | |
| curr_error_log="timeout", | |
| ) | |
| assert len(breakdown) == 2 # step_cost + timeout | |
| assert total == -5.2 | |