70 lines
3.6 KiB
Python
70 lines
3.6 KiB
Python
import contextlib
|
|
import dataclasses
|
|
import io
|
|
import json
|
|
import os
|
|
import tempfile
|
|
import unittest
|
|
|
|
from tests.fakes import HEAD, ROOT, FakeGitea, FakeModel, config, deps, diff_for, gitea_file, pr_ref
|
|
from werkrevisor.cli import execute, main
|
|
from werkrevisor.redact import Redactor
|
|
from werkrevisor.verdict import Verdict
|
|
|
|
|
|
def prompt_run(gitea, model, cfg):
|
|
path = os.path.join(tempfile.mkdtemp(prefix="werkrevisor-test-"), "prompt.json")
|
|
d = dataclasses.replace(deps(gitea, model), prompt_out=path)
|
|
outcome = execute(cfg, pr_ref(), d, Redactor(), publish=False)
|
|
with open(path, encoding="utf-8") as f:
|
|
return outcome, json.load(f), path
|
|
|
|
|
|
class PromptOutTest(unittest.TestCase):
|
|
def test_the_prompt_goes_to_the_file_instead_of_the_model(self):
|
|
"""Scenario#65.01"""
|
|
gitea = FakeGitea(files=[gitea_file("src/a.py")], diff=diff_for("src/a.py", added=["x"]))
|
|
model = FakeModel(prompt_files=["src/a.py"])
|
|
outcome, written, path = prompt_run(gitea, model, config(gate={"yellow_gate": "block"}))
|
|
self.assertEqual(model.calls, [])
|
|
self.assertEqual((written["system"], written["user"]), model.prompts[-1])
|
|
self.assertEqual(outcome.result.llm_status, "skipped (prompt written)")
|
|
reason = next(r for r in outcome.result.reasons if r.code == "prompt_out")
|
|
self.assertEqual((reason.text, reason.verdict), (f"model not called: the prompt is in {path}", Verdict.GREEN))
|
|
|
|
def test_the_file_holds_the_prompt_after_the_size_checks(self):
|
|
"""Scenario#65.02"""
|
|
text = "".join(f"line number {i} of the large file\n" for i in range(1, 701)).encode()
|
|
diff = diff_for("src/a.py", added=["x"]).replace("@@ -1,0 +1,1 @@", "@@ -350,0 +350,1 @@")
|
|
gitea = FakeGitea(files=[gitea_file("src/a.py")], diff=diff)
|
|
gitea.raw_files["src/a.py"] = text
|
|
model = FakeModel(prompt_files=["src/a.py"], prompt_words=50)
|
|
cfg = config(gate={"yellow_gate": "block"}, model={"max_context_tokens": 3000},
|
|
review={"full_files": True, "max_full_file_chars": 100000, "max_full_files_chars": 200000,
|
|
"excerpt_context_lines": 400})
|
|
outcome, written, _ = prompt_run(gitea, model, cfg)
|
|
self.assertGreater(len(model.prompts), 1)
|
|
self.assertIn("### Full file: 'src/a.py'", model.prompts[0][1])
|
|
self.assertEqual(written["user"], model.prompts[-1][1])
|
|
self.assertNotIn("line number 1 of the large file", written["user"])
|
|
self.assertIn("context_reduced", [r.code for r in outcome.result.reasons])
|
|
|
|
def test_only_a_dry_run_writes_the_prompt(self):
|
|
"""Scenario#65.03, Scenario#65.04"""
|
|
with open(os.path.join(ROOT, "config", "werkprobe.toml"), encoding="utf-8") as f:
|
|
toml = f.read()
|
|
environ = {"WERKREVISOR_CONFIG_TOML": toml, "GITEA_BOT_TOKEN": "gitea-token-123",
|
|
"OPENROUTER_API_KEY": "sk-or-v1-test", "TYPESAFE_API_KEY": "ts-test",
|
|
"WERKATOR_GITEA_BASE_URL": "https://git.example.org", "WERKATOR_GITEA_OWNER": "o",
|
|
"WERKATOR_GITEA_REPO": "r", "WERKATOR_PR_NUMBER": "1", "WERKATOR_PR_HEAD_SHA": HEAD}
|
|
for argv in (["--prompt-out", "p.json"], ["--prompt-out", "p.json", "--no-publish", "--no-llm"]):
|
|
with self.subTest(argv=argv):
|
|
err = io.StringIO()
|
|
with contextlib.redirect_stderr(err):
|
|
self.assertEqual(main(argv, environ), 30)
|
|
self.assertIn("--prompt-out needs --no-publish and no --no-llm", err.getvalue())
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|