175 lines
6.0 KiB
Python
175 lines
6.0 KiB
Python
"""Tests for the OpenAPI spec parser module."""
|
|
|
|
import tempfile
|
|
import yaml
|
|
import pytest
|
|
|
|
from openapi_mock.core.spec_parser import (
|
|
load_spec,
|
|
extract_paths,
|
|
extract_schemas,
|
|
extract_path_params,
|
|
get_operation_id,
|
|
extract_security_schemes,
|
|
get_response_schema,
|
|
get_spec_version,
|
|
is_openapi_3,
|
|
SpecNotFoundError,
|
|
SpecValidationError,
|
|
)
|
|
|
|
|
|
class TestLoadSpec:
|
|
"""Tests for load_spec function."""
|
|
|
|
def test_load_valid_spec(self, temp_spec_file, sample_openapi_spec):
|
|
"""Test loading a valid OpenAPI specification."""
|
|
spec = load_spec(temp_spec_file)
|
|
assert spec["info"]["title"] == "Test API"
|
|
assert spec["info"]["version"] == "1.0.0"
|
|
assert spec["openapi"] == "3.0.0"
|
|
|
|
def test_load_nonexistent_file(self):
|
|
"""Test loading a non-existent file raises error."""
|
|
with pytest.raises(SpecNotFoundError):
|
|
load_spec("/nonexistent/path/spec.yaml")
|
|
|
|
def test_load_invalid_yaml(self, invalid_yaml_file):
|
|
"""Test loading invalid YAML raises error."""
|
|
with pytest.raises(Exception): # Could be various YAML errors
|
|
load_spec(invalid_yaml_file)
|
|
|
|
def test_load_swagger_2_spec(self, tmp_path):
|
|
"""Test loading a Swagger 2.0 specification."""
|
|
swagger_spec = {
|
|
"swagger": "2.0",
|
|
"info": {"title": "Test", "version": "1.0"},
|
|
"paths": {}
|
|
}
|
|
spec_path = tmp_path / "swagger.yaml"
|
|
with open(spec_path, "w") as f:
|
|
yaml.dump(swagger_spec, f)
|
|
|
|
spec = load_spec(str(spec_path))
|
|
assert spec["swagger"] == "2.0"
|
|
|
|
|
|
class TestExtractPaths:
|
|
"""Tests for extract_paths function."""
|
|
|
|
def test_extract_paths(self, sample_openapi_spec):
|
|
"""Test extracting paths from spec."""
|
|
paths = extract_paths(sample_openapi_spec)
|
|
assert "/users" in paths
|
|
assert "/users/{userId}" in paths
|
|
|
|
def test_extract_paths_empty(self):
|
|
"""Test extracting paths from spec with no paths."""
|
|
spec = {"openapi": "3.0.0", "info": {"title": "Test", "version": "1.0"}, "paths": {}}
|
|
paths = extract_paths(spec)
|
|
assert paths == {}
|
|
|
|
def test_extract_paths_missing(self):
|
|
"""Test extracting paths when paths key is missing."""
|
|
spec = {"openapi": "3.0.0", "info": {"title": "Test", "version": "1.0"}}
|
|
paths = extract_paths(spec)
|
|
assert paths == {}
|
|
|
|
|
|
class TestExtractSchemas:
|
|
"""Tests for extract_schemas function."""
|
|
|
|
def test_extract_schemas(self, sample_openapi_spec):
|
|
"""Test extracting schemas from spec."""
|
|
schemas = extract_schemas(sample_openapi_spec)
|
|
assert "User" in schemas
|
|
assert schemas["User"]["type"] == "object"
|
|
|
|
def test_extract_schemas_swagger(self, swagger_2_spec):
|
|
"""Test extracting schemas from Swagger 2.0 spec."""
|
|
schemas = extract_schemas(swagger_2_spec)
|
|
assert "Pet" in schemas
|
|
|
|
def test_extract_schemas_missing(self):
|
|
"""Test extracting schemas when components are missing."""
|
|
spec = {"openapi": "3.0.0", "info": {"title": "Test", "version": "1.0"}, "paths": {}}
|
|
schemas = extract_schemas(spec)
|
|
assert schemas == {}
|
|
|
|
|
|
class TestExtractPathParams:
|
|
"""Tests for extract_path_params function."""
|
|
|
|
def test_extract_single_param(self):
|
|
"""Test extracting a single path parameter."""
|
|
params = extract_path_params("/users/{id}")
|
|
assert params == ["id"]
|
|
|
|
def test_extract_multiple_params(self):
|
|
"""Test extracting multiple path parameters."""
|
|
params = extract_path_params("/users/{userId}/posts/{postId}")
|
|
assert params == ["userId", "postId"]
|
|
|
|
def test_extract_no_params(self):
|
|
"""Test extracting parameters from path with none."""
|
|
params = extract_path_params("/users")
|
|
assert params == []
|
|
|
|
def test_extract_nested_brace_in_pattern(self):
|
|
"""Test extracting parameters handles edge cases."""
|
|
params = extract_path_params("/api/{version}/users/{id}")
|
|
assert params == ["version", "id"]
|
|
|
|
|
|
class TestGetOperationId:
|
|
"""Tests for get_operation_id function."""
|
|
|
|
def test_get_operation_id_simple(self):
|
|
"""Test generating operation ID for simple path."""
|
|
op_id = get_operation_id("/users", "get")
|
|
assert op_id == "get_users"
|
|
|
|
def test_get_operation_id_with_params(self):
|
|
"""Test generating operation ID for path with parameters."""
|
|
op_id = get_operation_id("/users/{id}", "get")
|
|
assert op_id == "get_users__id_"
|
|
|
|
def test_get_operation_id_nested(self):
|
|
"""Test generating operation ID for nested path."""
|
|
op_id = get_operation_id("/api/v1/users", "post")
|
|
assert op_id == "post_api_v1_users"
|
|
|
|
|
|
class TestGetResponseSchema:
|
|
"""Tests for get_response_schema function."""
|
|
|
|
def test_get_response_schema(self, sample_openapi_spec):
|
|
"""Test getting response schema for an operation."""
|
|
schema = get_response_schema(sample_openapi_spec, "/users", "get")
|
|
assert schema is not None
|
|
assert schema["type"] == "array"
|
|
assert schema["items"]["$ref"] == "#/components/schemas/User"
|
|
|
|
def test_get_response_schema_missing(self):
|
|
"""Test getting response schema for non-existent operation."""
|
|
spec = {"openapi": "3.0.0", "info": {"title": "Test", "version": "1.0"}, "paths": {}}
|
|
schema = get_response_schema(spec, "/nonexistent", "get")
|
|
assert schema is None
|
|
|
|
|
|
class TestSpecVersion:
|
|
"""Tests for version detection functions."""
|
|
|
|
def test_get_spec_version(self, sample_openapi_spec):
|
|
"""Test getting OpenAPI version."""
|
|
version = get_spec_version(sample_openapi_spec)
|
|
assert version == "3.0.0"
|
|
|
|
def test_is_openapi_3_true(self, sample_openapi_spec):
|
|
"""Test OpenAPI 3.x detection."""
|
|
assert is_openapi_3(sample_openapi_spec) is True
|
|
|
|
def test_is_openapi_3_false(self, swagger_2_spec):
|
|
"""Test Swagger 2.0 detection."""
|
|
assert is_openapi_3(swagger_2_spec) is False
|