File size: 3,548 Bytes
27d7338
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
"""Tests for CodeReviewEnv reset/step behavior."""

from __future__ import annotations

from env.environment import CodeReviewEnv
from env.models import CodeReviewAction


def test_reset_returns_observation() -> None:
    """reset() returns a valid observation with empty comments."""

    env = CodeReviewEnv()
    obs = env.reset("easy")
    assert obs.task_id == "easy"
    assert obs.language == "python"
    assert obs.step_number == 1
    assert obs.max_steps == 8
    assert obs.existing_comments == []


def test_reset_twice_clears_state() -> None:
    """reset() called twice returns clean state with zero comments."""

    env = CodeReviewEnv()
    env.reset("easy")
    obs2 = env.reset("easy")
    assert obs2.existing_comments == []
    assert obs2.step_number == 1


def test_step_add_comment_near_bug_positive_reward() -> None:
    """Valid add_comment near real bug yields positive reward."""

    env = CodeReviewEnv()
    env.reset("easy")
    action = CodeReviewAction(operation="add_comment", line_number=18, severity="major", category="bug", message="Index error risk")
    obs, reward, done, info = env.step(action)
    assert reward > 0.0
    assert done is False
    assert info["bugs_found"] >= 1
    assert len(obs.existing_comments) == 1


def test_step_add_comment_false_positive_negative_reward() -> None:
    """add_comment on a non-bug line yields negative reward."""

    env = CodeReviewEnv()
    env.reset("easy")
    action = CodeReviewAction(operation="add_comment", line_number=2, severity="minor", category="style", message="Nit")
    _, reward, _, info = env.step(action)
    assert reward == 0.01
    assert info["false_positives"] >= 1


def test_step_duplicate_comment_negative_reward() -> None:
    """Duplicate comment on same bug yields negative reward."""

    env = CodeReviewEnv()
    env.reset("easy")
    a1 = CodeReviewAction(operation="add_comment", line_number=18, severity="major", category="bug", message="Bug")
    _, r1, _, _ = env.step(a1)
    assert r1 > 0.0
    a2 = CodeReviewAction(operation="add_comment", line_number=19, severity="major", category="bug", message="Duplicate")
    _, r2, _, _ = env.step(a2)
    assert r2 == 0.01


def test_approve_with_unfound_critical_or_major_penalty() -> None:
    """approve() when major bugs exist yields large negative reward."""

    env = CodeReviewEnv()
    env.reset("medium")
    obs, reward, done, info = env.step(CodeReviewAction(operation="approve", summary="LGTM"))
    assert done is True
    assert reward == 0.01
    assert info["current_score"] == 0.001


def test_done_returns_final_grader_score() -> None:
    """done triggers grader and returns final score reward."""

    env = CodeReviewEnv()
    env.reset("easy")
    env.step(CodeReviewAction(operation="add_comment", line_number=18, severity="major", category="bug", message="Bug 1"))
    obs, reward, done, info = env.step(CodeReviewAction(operation="done"))
    assert done is True
    assert reward >= 0.0
    assert isinstance(info["current_score"], float)
    assert obs.review_status == "submitted"


def test_step_number_increments_and_episode_ends_at_max_steps() -> None:
    """step_number increments and episode ends at max steps."""

    env = CodeReviewEnv()
    obs = env.reset("easy")
    assert obs.step_number == 1
    done = False
    for _ in range(8):
        obs, _, done, _ = env.step(CodeReviewAction(operation="add_comment", line_number=2, severity="minor", category="style", message="x"))
        if done:
            break
    assert done is True