308 lines
9.1 KiB
Python
308 lines
9.1 KiB
Python
"""Integration tests for the complete workflow."""
|
|
import pytest
|
|
import json
|
|
import yaml
|
|
from click.testing import CliRunner
|
|
from pathlib import Path
|
|
from json_to_openapi.cli import main
|
|
from json_to_openapi.schema_generator import OpenAPIGenerator
|
|
|
|
|
|
class TestIntegration:
|
|
"""Integration test cases."""
|
|
|
|
@pytest.fixture
|
|
def runner(self):
|
|
return CliRunner()
|
|
|
|
@pytest.fixture
|
|
def user_schema_file(self, tmp_path):
|
|
data = {
|
|
"users": [
|
|
{
|
|
"id": 1,
|
|
"name": "Alice",
|
|
"email": "alice@example.com",
|
|
"age": 30,
|
|
"active": True,
|
|
"created_at": "2024-01-15T10:30:00Z",
|
|
"tags": ["admin", "user"],
|
|
"metadata": {
|
|
"department": "Engineering",
|
|
"level": 5
|
|
}
|
|
},
|
|
{
|
|
"id": 2,
|
|
"name": "Bob",
|
|
"email": "bob@example.com",
|
|
"age": 25,
|
|
"active": False,
|
|
"created_at": "2024-02-20T14:00:00Z",
|
|
"tags": ["user"],
|
|
"metadata": {
|
|
"department": "Sales",
|
|
"level": 3
|
|
}
|
|
}
|
|
],
|
|
"total": 2
|
|
}
|
|
file_path = tmp_path / "users.json"
|
|
file_path.write_text(json.dumps(data))
|
|
return file_path
|
|
|
|
@pytest.fixture
|
|
def product_schema_file(self, tmp_path):
|
|
data = {
|
|
"products": [
|
|
{
|
|
"id": 101,
|
|
"name": "Laptop",
|
|
"price": 999.99,
|
|
"in_stock": True,
|
|
"category": "Electronics",
|
|
"variants": [
|
|
{"color": "black", "sku": "LAP-BLK-001"},
|
|
{"color": "silver", "sku": "LAP-SLV-001"}
|
|
]
|
|
},
|
|
{
|
|
"id": 102,
|
|
"name": "Mouse",
|
|
"price": 29.99,
|
|
"in_stock": True,
|
|
"category": "Electronics",
|
|
"variants": [
|
|
{"color": "white", "sku": "MSE-WHT-001"}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
file_path = tmp_path / "products.json"
|
|
file_path.write_text(json.dumps(data))
|
|
return file_path
|
|
|
|
def test_end_to_end_user_schema(self, runner, user_schema_file, tmp_path):
|
|
"""Test end-to-end conversion of user schema."""
|
|
output_file = tmp_path / "users_openapi.yaml"
|
|
|
|
result = runner.invoke(main, [
|
|
"convert",
|
|
str(user_schema_file),
|
|
"-o", str(output_file),
|
|
"-t", "Users API",
|
|
"-v", "1.0.0",
|
|
"-d", "API for managing users"
|
|
])
|
|
|
|
assert result.exit_code == 0
|
|
assert output_file.exists()
|
|
|
|
content = output_file.read_text()
|
|
spec = yaml.safe_load(content)
|
|
|
|
assert spec["openapi"] == "3.0.3"
|
|
assert spec["info"]["title"] == "Users API"
|
|
assert spec["info"]["version"] == "1.0.0"
|
|
assert spec["info"]["description"] == "API for managing users"
|
|
|
|
def test_end_to_end_product_schema(self, runner, product_schema_file, tmp_path):
|
|
"""Test end-to-end conversion of product schema."""
|
|
output_file = tmp_path / "products_openapi.yaml"
|
|
|
|
result = runner.invoke(main, [
|
|
"convert",
|
|
str(product_schema_file),
|
|
"-o", str(output_file),
|
|
"-t", "Products API"
|
|
])
|
|
|
|
assert result.exit_code == 0
|
|
assert output_file.exists()
|
|
|
|
content = output_file.read_text()
|
|
spec = yaml.safe_load(content)
|
|
|
|
assert spec["openapi"] == "3.0.3"
|
|
assert spec["info"]["title"] == "Products API"
|
|
|
|
def test_batch_processing(self, runner, user_schema_file, product_schema_file, tmp_path):
|
|
"""Test batch processing of multiple JSON files."""
|
|
output_dir = tmp_path / "output"
|
|
output_dir.mkdir()
|
|
|
|
result = runner.invoke(main, [
|
|
"batch",
|
|
str(tmp_path / "*.json"),
|
|
"-o", str(output_dir),
|
|
"-f", "yaml"
|
|
])
|
|
|
|
assert result.exit_code == 0
|
|
assert "Successfully processed 2 files" in result.output
|
|
|
|
assert (output_dir / "users.yaml").exists()
|
|
assert (output_dir / "products.yaml").exists()
|
|
|
|
def test_combined_batch_processing(self, runner, user_schema_file, product_schema_file, tmp_path):
|
|
"""Test combined batch processing."""
|
|
output_dir = tmp_path / "combined_output"
|
|
output_dir.mkdir()
|
|
|
|
result = runner.invoke(main, [
|
|
"batch",
|
|
str(tmp_path / "*.json"),
|
|
"-o", str(output_dir),
|
|
"-c",
|
|
"-f", "yaml"
|
|
])
|
|
|
|
assert result.exit_code == 0
|
|
|
|
def test_spec_validity(self, runner, user_schema_file, tmp_path):
|
|
"""Test that generated spec is valid OpenAPI 3.0.3."""
|
|
output_file = tmp_path / "valid_spec.yaml"
|
|
|
|
runner.invoke(main, [
|
|
"convert",
|
|
str(user_schema_file),
|
|
"-o", str(output_file)
|
|
])
|
|
|
|
result = runner.invoke(main, ["validate", str(output_file)])
|
|
assert result.exit_code == 0
|
|
assert "Validation passed" in result.output
|
|
|
|
def test_json_output_format(self, runner, user_schema_file, tmp_path):
|
|
"""Test JSON output format."""
|
|
output_file = tmp_path / "spec.json"
|
|
|
|
result = runner.invoke(main, [
|
|
"convert",
|
|
str(user_schema_file),
|
|
"-o", str(output_file),
|
|
"-f", "json"
|
|
])
|
|
|
|
assert result.exit_code == 0
|
|
content = output_file.read_text()
|
|
spec = json.loads(content)
|
|
|
|
assert spec["openapi"] == "3.0.3"
|
|
assert "info" in spec
|
|
assert "paths" in spec
|
|
|
|
def test_custom_endpoint_path(self, runner, user_schema_file, tmp_path):
|
|
"""Test custom endpoint path."""
|
|
output_file = tmp_path / "custom_path.yaml"
|
|
|
|
result = runner.invoke(main, [
|
|
"convert",
|
|
str(user_schema_file),
|
|
"-o", str(output_file)
|
|
])
|
|
|
|
assert result.exit_code == 0
|
|
content = output_file.read_text()
|
|
spec = yaml.safe_load(content)
|
|
|
|
assert "/" in spec["paths"] or "/users" in spec["paths"]
|
|
|
|
|
|
class TestEdgeCases:
|
|
"""Test edge cases and error handling."""
|
|
|
|
@pytest.fixture
|
|
def runner(self):
|
|
return CliRunner()
|
|
|
|
def test_empty_object(self, runner, tmp_path):
|
|
"""Test handling of empty object."""
|
|
data = {}
|
|
file_path = tmp_path / "empty.json"
|
|
file_path.write_text(json.dumps(data))
|
|
|
|
output_file = tmp_path / "output.yaml"
|
|
|
|
result = runner.invoke(main, [
|
|
"convert",
|
|
str(file_path),
|
|
"-o", str(output_file)
|
|
])
|
|
|
|
assert result.exit_code == 0
|
|
assert output_file.exists()
|
|
|
|
def test_empty_array(self, runner, tmp_path):
|
|
"""Test handling of empty array."""
|
|
data = []
|
|
file_path = tmp_path / "empty_array.json"
|
|
file_path.write_text(json.dumps(data))
|
|
|
|
output_file = tmp_path / "output.yaml"
|
|
|
|
result = runner.invoke(main, [
|
|
"convert",
|
|
str(file_path),
|
|
"-o", str(output_file)
|
|
])
|
|
|
|
assert result.exit_code == 0
|
|
|
|
def test_nested_deep_structure(self, runner, tmp_path):
|
|
"""Test handling of deeply nested structures."""
|
|
data = {"level1": {"level2": {"level3": {"level4": {"level5": "deep"}}}}}
|
|
file_path = tmp_path / "deep.json"
|
|
file_path.write_text(json.dumps(data))
|
|
|
|
output_file = tmp_path / "output.yaml"
|
|
|
|
result = runner.invoke(main, [
|
|
"convert",
|
|
str(file_path),
|
|
"-o", str(output_file)
|
|
])
|
|
|
|
assert result.exit_code == 0
|
|
|
|
def test_special_characters_in_strings(self, runner, tmp_path):
|
|
"""Test handling of special characters."""
|
|
data = {
|
|
"message": "Hello \"World\"!",
|
|
"path": "/api/v1/users",
|
|
"email": "user@example.com"
|
|
}
|
|
file_path = tmp_path / "special.json"
|
|
file_path.write_text(json.dumps(data))
|
|
|
|
output_file = tmp_path / "output.yaml"
|
|
|
|
result = runner.invoke(main, [
|
|
"convert",
|
|
str(file_path),
|
|
"-o", str(output_file)
|
|
])
|
|
|
|
assert result.exit_code == 0
|
|
|
|
def test_unicode_characters(self, runner, tmp_path):
|
|
"""Test handling of unicode characters."""
|
|
data = {
|
|
"name": "日本語 Test",
|
|
"emoji": "🚀",
|
|
"chinese": "你好"
|
|
}
|
|
file_path = tmp_path / "unicode.json"
|
|
file_path.write_text(json.dumps(data))
|
|
|
|
output_file = tmp_path / "output.yaml"
|
|
|
|
result = runner.invoke(main, [
|
|
"convert",
|
|
str(file_path),
|
|
"-o", str(output_file)
|
|
])
|
|
|
|
assert result.exit_code == 0
|