Files
openapi-first/tests/test_codegen_routes.py
Vishesh 'ironeagle' Bangotra 51ffb4aae9 feat: codegen routes — sanitize resource names, --inject-request/--package, expand form bodies
codegen_routes.generate_routes now sanitizes resource identifiers (fetch-requests -> fetch_requests), optionally prepends 'request: Request' (inject_request) and emits <resource>/routes.py packages with __init__.py (package). multipart/form-data and x-www-form-urlencoded bodies expand to per-property UploadFile/File/Form params instead of an opaque dict; spec paths are normalized to forward slashes to avoid Windows escape issues. Adds CLI flags --inject-request/--package, 7 focused tests, and refreshes lib/wiki/MCP docs to the real CLI.
2026-10-13 03:26:31 +05:30

200 lines
6.4 KiB
Python

"""Smoke tests for openapi_first.codegen_routes."""
import json
import pytest
from openapi_first.codegen_routes import generate_routes
def _write_spec(tmp_path, spec: dict):
path = tmp_path / "openapi.json"
path.write_text(json.dumps(spec), encoding="utf-8")
return path
def _spec(paths: dict, schemas: dict | None = None) -> dict:
spec = {
"openapi": "3.0.3",
"info": {"title": "Codegen Test API", "version": "1.0.0"},
"paths": paths,
}
if schemas is not None:
spec["components"] = {"schemas": schemas}
return spec
def test_flat_output_names_files_by_resource(tmp_path):
spec = _write_spec(
tmp_path,
_spec(
{
"/items": {
"get": {
"operationId": "list_items",
"responses": {"200": {"description": "OK"}},
}
}
}
),
)
files = generate_routes(spec, tmp_path / "routes")
assert [f.name for f in files] == ["items.py"]
def test_resource_name_is_sanitized_to_identifier(tmp_path):
spec = _write_spec(
tmp_path,
_spec(
{
"/fetch-requests": {
"get": {
"operationId": "list_fetch_requests",
"responses": {"200": {"description": "OK"}},
}
}
}
),
)
files = generate_routes(spec, tmp_path / "routes")
assert [f.name for f in files] == ["fetch_requests.py"]
source = files[0].read_text(encoding="utf-8")
compile(source, str(files[0]), "exec")
def test_inject_request_prepends_request_param(tmp_path):
spec = _write_spec(
tmp_path,
_spec(
{
"/items": {
"get": {
"operationId": "list_items",
"responses": {"200": {"description": "OK"}},
}
}
}
),
)
files = generate_routes(spec, tmp_path / "routes", inject_request=True)
source = files[0].read_text(encoding="utf-8")
assert "from fastapi import Request" in source or "Request" in source
assert "def list_items(request: Request):" in source
def test_package_layout_emits_routes_package(tmp_path):
spec = _write_spec(
tmp_path,
_spec(
{
"/items/{id}": {
"get": {
"operationId": "get_item",
"parameters": [
{
"name": "id",
"in": "path",
"required": True,
"schema": {"type": "string"},
}
],
"responses": {"200": {"description": "OK"}},
}
}
}
),
)
out = tmp_path / "interfaces"
files = generate_routes(spec, out, package=True)
assert files[0] == out / "items" / "routes.py"
assert (out / "items" / "__init__.py").exists()
assert (out / "__init__.py").exists()
assert "def get_item(id: str):" in files[0].read_text(encoding="utf-8")
def test_multipart_body_expands_to_uploadfile(tmp_path):
spec = _write_spec(
tmp_path,
_spec(
{
"/pets/{id}/photo": {
"post": {
"operationId": "upload_pet_photo",
"parameters": [
{
"name": "id",
"in": "path",
"required": True,
"schema": {"type": "string"},
}
],
"requestBody": {
"required": True,
"content": {
"multipart/form-data": {
"schema": {
"type": "object",
"required": ["file"],
"properties": {
"file": {
"type": "string",
"format": "binary",
},
"caption": {"type": "string"},
},
}
}
},
},
"responses": {"200": {"description": "OK"}},
}
}
}
),
)
files = generate_routes(spec, tmp_path / "routes")
source = files[0].read_text(encoding="utf-8")
assert "UploadFile" in source
assert "file: UploadFile = File(...)" in source
assert "caption: str = Form(None)" in source
assert "payload: dict" not in source
compile(source, str(files[0]), "exec")
def test_json_body_unchanged_by_default(tmp_path):
spec = _write_spec(
tmp_path,
_spec(
{
"/items": {
"post": {
"operationId": "create_item",
"requestBody": {
"required": True,
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/ItemInput"}
}
},
},
"responses": {"201": {"description": "Created"}},
}
}
},
{"ItemInput": {"type": "object", "properties": {"name": {"type": "string"}}}},
),
)
files = generate_routes(spec, tmp_path / "routes")
source = files[0].read_text(encoding="utf-8")
assert "payload: dict" in source
assert "response: Response" in source
def test_missing_operation_id_raises(tmp_path):
spec = _write_spec(
tmp_path,
_spec({"/items": {"get": {"responses": {"200": {"description": "OK"}}}}}),
)
with pytest.raises(ValueError):
generate_routes(spec, tmp_path / "routes")