mirror of
https://github.com/codeflash-ai/codeflash-agent.git
synced 2026-05-04 18:25:19 +00:00
199 lines
5.9 KiB
Python
199 lines
5.9 KiB
Python
"""Tests for GitHub API helpers."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import httpx
|
|
import respx
|
|
|
|
from github_app.github import (
|
|
add_labels,
|
|
build_file_summary,
|
|
create_check_run,
|
|
fetch_commit_diff,
|
|
fetch_pr_details,
|
|
fetch_pr_diff,
|
|
fetch_pr_files,
|
|
fetch_repo_labels,
|
|
post_comment,
|
|
post_review,
|
|
truncate_diff,
|
|
)
|
|
|
|
API = "https://api.github.com"
|
|
|
|
|
|
@respx.mock
|
|
async def test_fetch_pr_diff():
|
|
respx.get(f"{API}/repos/o/r/pulls/1").respond(text="diff content")
|
|
async with httpx.AsyncClient() as client:
|
|
result = await fetch_pr_diff(client, "o", "r", 1, "tok")
|
|
assert result == "diff content"
|
|
|
|
|
|
@respx.mock
|
|
async def test_fetch_pr_files():
|
|
def side_effect(request):
|
|
page = int(request.url.params.get("page", "1"))
|
|
if page == 1:
|
|
return httpx.Response(200, json=[{"filename": "a.py"}])
|
|
return httpx.Response(200, json=[])
|
|
|
|
respx.get(f"{API}/repos/o/r/pulls/1/files").mock(
|
|
side_effect=side_effect,
|
|
)
|
|
async with httpx.AsyncClient() as client:
|
|
result = await fetch_pr_files(client, "o", "r", 1, "tok")
|
|
assert result == [{"filename": "a.py"}]
|
|
|
|
|
|
@respx.mock
|
|
async def test_fetch_pr_files_paginated():
|
|
page1 = [{"filename": f"f{i}.py"} for i in range(100)]
|
|
page2 = [{"filename": "last.py"}]
|
|
|
|
def side_effect(request):
|
|
page = int(request.url.params.get("page", "1"))
|
|
if page == 1:
|
|
return httpx.Response(200, json=page1)
|
|
if page == 2:
|
|
return httpx.Response(200, json=page2)
|
|
return httpx.Response(200, json=[])
|
|
|
|
respx.get(f"{API}/repos/o/r/pulls/1/files").mock(
|
|
side_effect=side_effect,
|
|
)
|
|
async with httpx.AsyncClient() as client:
|
|
result = await fetch_pr_files(client, "o", "r", 1, "tok")
|
|
assert len(result) == 101
|
|
|
|
|
|
@respx.mock
|
|
async def test_fetch_pr_details():
|
|
pr = {"number": 1, "title": "Test"}
|
|
respx.get(f"{API}/repos/o/r/pulls/1").respond(json=pr)
|
|
async with httpx.AsyncClient() as client:
|
|
result = await fetch_pr_details(client, "o", "r", 1, "tok")
|
|
assert result["title"] == "Test"
|
|
|
|
|
|
@respx.mock
|
|
async def test_fetch_commit_diff():
|
|
respx.get(f"{API}/repos/o/r/commits/abc").respond(text="commit diff")
|
|
async with httpx.AsyncClient() as client:
|
|
result = await fetch_commit_diff(client, "o", "r", "abc", "tok")
|
|
assert result == "commit diff"
|
|
|
|
|
|
@respx.mock
|
|
async def test_fetch_repo_labels():
|
|
def side_effect(request):
|
|
page = int(request.url.params.get("page", "1"))
|
|
if page == 1:
|
|
return httpx.Response(
|
|
200,
|
|
json=[{"name": "bug"}, {"name": "enhancement"}],
|
|
)
|
|
return httpx.Response(200, json=[])
|
|
|
|
respx.get(f"{API}/repos/o/r/labels").mock(side_effect=side_effect)
|
|
async with httpx.AsyncClient() as client:
|
|
result = await fetch_repo_labels(client, "o", "r", "tok")
|
|
assert result == ["bug", "enhancement"]
|
|
|
|
|
|
@respx.mock
|
|
async def test_post_review():
|
|
route = respx.post(f"{API}/repos/o/r/pulls/1/reviews").respond(200)
|
|
async with httpx.AsyncClient() as client:
|
|
await post_review(client, "o", "r", 1, "body", "COMMENT", "tok")
|
|
assert route.called
|
|
|
|
|
|
@respx.mock
|
|
async def test_post_comment():
|
|
route = respx.post(f"{API}/repos/o/r/issues/1/comments").respond(200)
|
|
async with httpx.AsyncClient() as client:
|
|
await post_comment(client, "o", "r", 1, "body", "tok")
|
|
assert route.called
|
|
|
|
|
|
@respx.mock
|
|
async def test_add_labels():
|
|
route = respx.post(f"{API}/repos/o/r/issues/1/labels").respond(200)
|
|
async with httpx.AsyncClient() as client:
|
|
await add_labels(client, "o", "r", 1, ["bug"], "tok")
|
|
assert route.called
|
|
|
|
|
|
@respx.mock
|
|
async def test_create_check_run():
|
|
route = respx.post(f"{API}/repos/o/r/check-runs").respond(200)
|
|
async with httpx.AsyncClient() as client:
|
|
await create_check_run(
|
|
client,
|
|
"o",
|
|
"r",
|
|
"sha",
|
|
"name",
|
|
"neutral",
|
|
{"title": "t", "summary": "s"},
|
|
"tok",
|
|
)
|
|
assert route.called
|
|
|
|
|
|
def test_build_file_summary():
|
|
files = [
|
|
{"filename": "a.py", "status": "modified", "additions": 5, "deletions": 2},
|
|
{"filename": "b.py", "status": "added", "additions": 10, "deletions": 0},
|
|
]
|
|
result = build_file_summary(files)
|
|
assert "a.py" in result
|
|
assert "+5/-2" in result
|
|
assert "added" in result
|
|
|
|
|
|
def test_truncate_diff_short():
|
|
diff = "short diff"
|
|
assert truncate_diff(diff) == diff
|
|
|
|
|
|
def test_truncate_diff_long():
|
|
diff = "x" * 70_000
|
|
result = truncate_diff(diff)
|
|
assert len(result) < 70_000
|
|
assert "truncated" in result
|
|
|
|
|
|
@respx.mock
|
|
async def test_fetch_pr_files_pagination_cap():
|
|
"""Pagination stops at MAX_PAGES to prevent infinite loops."""
|
|
from github_app.github import MAX_PAGES
|
|
|
|
def side_effect(request):
|
|
# Always return data, simulating a repo with unlimited pages.
|
|
page = int(request.url.params.get("page", "1"))
|
|
return httpx.Response(200, json=[{"filename": f"f{page}.py"}])
|
|
|
|
respx.get(f"{API}/repos/o/r/pulls/1/files").mock(
|
|
side_effect=side_effect,
|
|
)
|
|
async with httpx.AsyncClient() as client:
|
|
result = await fetch_pr_files(client, "o", "r", 1, "tok")
|
|
# Should stop after MAX_PAGES pages, not loop forever.
|
|
assert len(result) == MAX_PAGES
|
|
|
|
|
|
@respx.mock
|
|
async def test_fetch_repo_labels_pagination_cap():
|
|
"""Label fetching stops at MAX_PAGES to prevent infinite loops."""
|
|
from github_app.github import MAX_PAGES
|
|
|
|
def side_effect(request):
|
|
page = int(request.url.params.get("page", "1"))
|
|
return httpx.Response(200, json=[{"name": f"label-{page}"}])
|
|
|
|
respx.get(f"{API}/repos/o/r/labels").mock(side_effect=side_effect)
|
|
async with httpx.AsyncClient() as client:
|
|
result = await fetch_repo_labels(client, "o", "r", "tok")
|
|
assert len(result) == MAX_PAGES
|