Final acceptance: Консольная утилита поиска и скачивания изображений для вызова ИИ-агентом (#18)
Repository Validate / repository-checks (push) Successful in 21s
Repository Validate / repository-checks (push) Successful in 21s
Co-authored-by: AI Tester <ai-tester@git.p2prod.ru>
This commit was merged in pull request #18.
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
"""End-to-end tests for the example image-search CLI and its request document."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from tools import envelope, example
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[1]
|
||||
EXAMPLE_REQUEST = REPO_ROOT / "examples" / "input.json"
|
||||
|
||||
|
||||
def run_cli(*args: str) -> subprocess.CompletedProcess[str]:
|
||||
"""Run the CLI in a subprocess so stdout/exit codes are asserted end to end."""
|
||||
return subprocess.run(
|
||||
[sys.executable, "-m", "tools.example", *args],
|
||||
cwd=REPO_ROOT,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
)
|
||||
|
||||
|
||||
def single_document(stdout: str) -> dict:
|
||||
lines = [line for line in stdout.splitlines() if line.strip()]
|
||||
assert len(lines) == 1, stdout
|
||||
document = json.loads(lines[0])
|
||||
assert isinstance(document, dict)
|
||||
return document
|
||||
|
||||
|
||||
def test_example_request_document_is_canonical_dry_run_request() -> None:
|
||||
document = json.loads(EXAMPLE_REQUEST.read_text(encoding="utf-8"))
|
||||
|
||||
assert isinstance(document, dict)
|
||||
assert set(example.REQUEST_FIELDS) <= set(document)
|
||||
assert document["dry_run"] is True
|
||||
assert document["format"] in example.ACCEPTED_FORMATS
|
||||
assert isinstance(document["topic"], str) and document["topic"].strip()
|
||||
assert document["source"] in example.default_registry().available_sources()
|
||||
|
||||
|
||||
def test_example_request_document_passes_normalization() -> None:
|
||||
document = json.loads(EXAMPLE_REQUEST.read_text(encoding="utf-8"))
|
||||
|
||||
request = example.normalize_request(document)
|
||||
|
||||
assert request["dry_run"] is True
|
||||
assert request["format"] == "png"
|
||||
assert request["source"] == "wikimedia_commons"
|
||||
assert request["count"] == document["count"]
|
||||
|
||||
|
||||
def test_cli_prints_single_json_envelope_and_exits_zero() -> None:
|
||||
result = run_cli("examples/input.json")
|
||||
|
||||
assert result.returncode == envelope.EXIT_OK, result.stderr
|
||||
assert result.stderr == ""
|
||||
response = single_document(result.stdout)
|
||||
assert response["status"] == envelope.STATUS_DRY_RUN
|
||||
assert response["source"] == "wikimedia_commons"
|
||||
assert response["items"] == []
|
||||
assert response["request"]["dry_run"] is True
|
||||
assert response["error"] is None
|
||||
|
||||
|
||||
def test_cli_envelope_is_deterministic() -> None:
|
||||
first = run_cli("examples/input.json")
|
||||
second = run_cli("examples/input.json")
|
||||
|
||||
assert first.returncode == second.returncode == envelope.EXIT_OK
|
||||
assert first.stdout == second.stdout
|
||||
|
||||
|
||||
def test_cli_help_exits_zero_and_documents_parameters() -> None:
|
||||
result = run_cli("--help")
|
||||
|
||||
assert result.returncode == 0
|
||||
assert "REQUEST" in result.stdout
|
||||
|
||||
|
||||
def test_cli_reports_missing_request_document(tmp_path: Path) -> None:
|
||||
missing = tmp_path / "missing.json"
|
||||
|
||||
result = run_cli(str(missing))
|
||||
|
||||
assert result.returncode == envelope.EXIT_INVALID_REQUEST
|
||||
response = single_document(result.stdout)
|
||||
assert response["status"] == envelope.STATUS_INVALID_REQUEST
|
||||
assert response["error"]["code"] == "request_document"
|
||||
|
||||
|
||||
def test_cli_reports_malformed_json(tmp_path: Path) -> None:
|
||||
malformed = tmp_path / "malformed.json"
|
||||
malformed.write_text("{not json", encoding="utf-8")
|
||||
|
||||
result = run_cli(str(malformed))
|
||||
|
||||
assert result.returncode == envelope.EXIT_INVALID_REQUEST
|
||||
response = single_document(result.stdout)
|
||||
assert response["status"] == envelope.STATUS_INVALID_REQUEST
|
||||
assert response["error"]["code"] == "request_document"
|
||||
|
||||
|
||||
def test_cli_reports_non_object_document(tmp_path: Path) -> None:
|
||||
payload = tmp_path / "list.json"
|
||||
payload.write_text("[]", encoding="utf-8")
|
||||
|
||||
result = run_cli(str(payload))
|
||||
|
||||
assert result.returncode == envelope.EXIT_INVALID_REQUEST
|
||||
assert single_document(result.stdout)["status"] == envelope.STATUS_INVALID_REQUEST
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"document",
|
||||
[
|
||||
{},
|
||||
{"topic": "red fox"},
|
||||
{"topic": "", "format": "png"},
|
||||
{"topic": "red fox", "format": "gif"},
|
||||
{"topic": "red fox", "format": "png", "count": 0},
|
||||
],
|
||||
)
|
||||
def test_normalize_request_rejects_invalid_documents(document: object) -> None:
|
||||
with pytest.raises(example.RequestError):
|
||||
example.normalize_request(document) # type: ignore[arg-type]
|
||||
Reference in New Issue
Block a user