File size: 4,816 Bytes
27d7338
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
351c200
27d7338
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
351c200
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
"""Advanced adversarial test cases for the code-review environment.

These tests focus on edge conditions, undesirable behaviors, and ensuring the
reward/grader logic produces varied, deterministic outcomes.
"""

from __future__ import annotations

from fastapi.testclient import TestClient

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


def test_add_comment_missing_line_number_returns_negative_reward_and_error() -> None:
    """Missing line_number for add_comment returns -0.05 and error in info."""

    env = CodeReviewEnv()
    env.reset("easy")
    obs, reward, done, info = env.step(CodeReviewAction(operation="add_comment", severity="minor", category="bug", message="x"))
    assert done is False
    assert reward == 0.01
    assert info["error"] is not None
    assert info["false_positives"] >= 1
    assert obs.step_number >= 2


def test_bug_matching_within_plus_minus_five_is_positive() -> None:
    """Comment within +/-5 lines of a real bug yields positive reward."""

    env = CodeReviewEnv()
    env.reset("medium")
    obs, reward, done, info = env.step(
        CodeReviewAction(operation="add_comment", line_number=26, severity="critical", category="security", message="SQLi")
    )
    assert done is False
    assert reward > 0.0
    assert info["bugs_found"] >= 1
    assert len(obs.existing_comments) == 1


def test_comment_outside_plus_minus_five_is_false_positive() -> None:
    """Comment far from any bug yields -0.10 false positive penalty."""

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


def test_red_herring_penalty_is_applied_on_hard_task() -> None:
    """Flagging the hard-task red herring yields -0.20."""

    env = CodeReviewEnv()
    env.reset("hard")
    _, reward, _, info = env.step(
        CodeReviewAction(operation="add_comment", line_number=54, severity="nit", category="style", message="suspicious pass")
    )
    assert reward == 0.01
    assert info["false_positives"] >= 1


def test_approve_bonus_when_no_critical_or_major_remaining() -> None:
    """approve yields +0.10 only after all critical/major are found."""

    env = CodeReviewEnv()
    env.reset("medium")
    env.step(CodeReviewAction(operation="add_comment", line_number=20, severity="major", category="security", message="secret"))
    env.step(CodeReviewAction(operation="add_comment", line_number=21, severity="critical", category="security", message="sqli"))
    env.step(CodeReviewAction(operation="add_comment", line_number=23, severity="major", category="security", message="validation"))
    env.step(CodeReviewAction(operation="add_comment", line_number=24, severity="critical", category="security", message="idor"))
    _, reward, done, _ = env.step(CodeReviewAction(operation="approve", summary="LGTM"))
    assert done is True
    assert reward == 0.10


def test_request_changes_reward_depends_on_evidence() -> None:
    """request_changes yields +0.05 with evidence, -0.05 without."""

    env = CodeReviewEnv()
    env.reset("easy")
    _, r0, done0, _ = env.step(CodeReviewAction(operation="request_changes", summary="needs work"))
    assert done0 is True
    assert r0 == 0.01

    env.reset("easy")
    env.step(CodeReviewAction(operation="add_comment", line_number=18, severity="major", category="bug", message="bug"))
    _, r1, done1, _ = env.step(CodeReviewAction(operation="request_changes", summary="needs work"))
    assert done1 is True
    assert r1 == 0.05


def test_done_score_varies_with_behavior() -> None:
    """done reward should differ for different comment behaviors."""

    env = CodeReviewEnv()
    env.reset("hard")
    _, reward_none, _, _ = env.step(CodeReviewAction(operation="done"))

    env.reset("hard")
    env.step(CodeReviewAction(operation="add_comment", line_number=30, severity="critical", category="security", message="unsafe loader"))
    _, reward_one, _, _ = env.step(CodeReviewAction(operation="done"))

    assert reward_one != reward_none


def test_api_root_route_returns_200() -> None:
    """GET / returns 200 with JSON body for HF Space UI."""

    client = TestClient(app)
    r = client.get("/")
    assert r.status_code == 200
    body = r.json()
    assert body["status"] == "ok"


def test_api_step_rejects_malformed_body_with_422() -> None:
    """POST /step with malformed JSON does not crash and returns 422 or 500."""

    client = TestClient(app)
    client.post("/reset", json={"task_id": "easy"})
    r = client.post("/step", data="{bad", headers={"content-type": "application/json"})
    assert r.status_code in (422, 500)