mirror of
https://github.com/divkit/divkit.git
synced 2026-05-07 20:02:32 +00:00
2987d93ba7
commit_hash:cf5070a543788fa57136adb1a4a7ea42f4490329
259 lines
9.0 KiB
Python
259 lines
9.0 KiB
Python
"""Tests for pydivkit.core.schema module.
|
|
|
|
Covers _field_to_schema and its helper functions directly.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import enum
|
|
from typing import Any, Mapping, Optional, Sequence, Union
|
|
|
|
import pytest
|
|
|
|
from pydivkit.core import BaseEntity, Expr, Field
|
|
from pydivkit.core.fields import _Field
|
|
from pydivkit.core.schema import (
|
|
BUILTIN_TYPES_TO_SCHEMA,
|
|
SchemaType,
|
|
_add_field_extra_to_schema,
|
|
_dict_to_schema,
|
|
_enum_to_schema,
|
|
_field_to_schema,
|
|
_list_to_schema,
|
|
_type_field_to_schema,
|
|
_union_to_schema,
|
|
)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# _type_field_to_schema
|
|
# ---------------------------------------------------------------------------
|
|
class TestTypeFieldToSchema:
|
|
def test_produces_enum_schema(self) -> None:
|
|
field = _Field(name="type", default="my_component")
|
|
result = _type_field_to_schema(field)
|
|
assert result == {
|
|
"type": "string",
|
|
"enum": ["my_component"],
|
|
}
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# _enum_to_schema
|
|
# ---------------------------------------------------------------------------
|
|
class TestEnumToSchema:
|
|
def test_multiple_values(self) -> None:
|
|
class Direction(enum.Enum):
|
|
LEFT = "left"
|
|
RIGHT = "right"
|
|
UP = "up"
|
|
|
|
result = _enum_to_schema(Direction)
|
|
assert result["type"] == "string"
|
|
assert set(result["enum"]) == {"left", "right", "up"}
|
|
|
|
def test_single_value(self) -> None:
|
|
class Single(enum.Enum):
|
|
ONLY = "only"
|
|
|
|
result = _enum_to_schema(Single)
|
|
assert result == {"type": "string", "enum": ["only"]}
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# _list_to_schema
|
|
# ---------------------------------------------------------------------------
|
|
class TestListToSchema:
|
|
def test_sequence_of_int(self) -> None:
|
|
defs: dict[str, SchemaType] = {}
|
|
result = _list_to_schema(Sequence[int], defs, {})
|
|
assert result == {
|
|
"type": "array",
|
|
"items": {"type": "integer"},
|
|
}
|
|
|
|
def test_sequence_of_str(self) -> None:
|
|
defs: dict[str, SchemaType] = {}
|
|
result = _list_to_schema(Sequence[str], defs, {})
|
|
assert result == {
|
|
"type": "array",
|
|
"items": {"type": "string"},
|
|
}
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# _dict_to_schema
|
|
# ---------------------------------------------------------------------------
|
|
class TestDictToSchema:
|
|
def test_returns_object_schema(self) -> None:
|
|
result = _dict_to_schema()
|
|
assert result == {
|
|
"type": "object",
|
|
"additionalProperties": True,
|
|
}
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# _union_to_schema
|
|
# ---------------------------------------------------------------------------
|
|
class TestUnionToSchema:
|
|
def test_anyof_generation(self) -> None:
|
|
defs: dict[str, SchemaType] = {}
|
|
result = _union_to_schema(None, Union[int, str], {}, defs)
|
|
assert "anyOf" in result
|
|
type_values = [a["type"] for a in result["anyOf"]]
|
|
assert "integer" in type_values
|
|
assert "string" in type_values
|
|
|
|
def test_multi_type_union(self) -> None:
|
|
"""Union[int, str, float] produces anyOf with all arms."""
|
|
defs: dict[str, SchemaType] = {}
|
|
result = _union_to_schema(None, Union[int, str, float], {}, defs)
|
|
assert "anyOf" in result
|
|
assert len(result["anyOf"]) == 3
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# _add_field_extra_to_schema
|
|
# ---------------------------------------------------------------------------
|
|
class TestAddFieldExtraToSchema:
|
|
def test_description_added(self) -> None:
|
|
field = _Field(description="A field")
|
|
schema: SchemaType = {"type": "string"}
|
|
_add_field_extra_to_schema(field, schema)
|
|
assert schema["description"] == "A field"
|
|
|
|
def test_default_added(self) -> None:
|
|
field = _Field(default="val")
|
|
schema: SchemaType = {"type": "string"}
|
|
_add_field_extra_to_schema(field, schema)
|
|
assert schema["default"] == "val"
|
|
|
|
def test_constraints_added(self) -> None:
|
|
field = _Field(constraints={"minimum": 0, "maximum": 100})
|
|
schema: SchemaType = {"type": "integer"}
|
|
_add_field_extra_to_schema(field, schema)
|
|
assert schema["minimum"] == 0
|
|
assert schema["maximum"] == 100
|
|
|
|
def test_empty_field_no_extras(self) -> None:
|
|
field = _Field()
|
|
schema: SchemaType = {"type": "integer"}
|
|
_add_field_extra_to_schema(field, schema)
|
|
assert schema == {"type": "integer"}
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# _field_to_schema (main dispatcher)
|
|
# ---------------------------------------------------------------------------
|
|
class TestFieldToSchema:
|
|
def test_type_field_dispatch(self) -> None:
|
|
field = _Field(name="type", default="comp")
|
|
defs: dict[str, SchemaType] = {}
|
|
result = _field_to_schema(field, str, {}, defs)
|
|
assert result["type"] == "string"
|
|
assert result["enum"] == ["comp"]
|
|
|
|
def test_builtin_int(self) -> None:
|
|
defs: dict[str, SchemaType] = {}
|
|
result = _field_to_schema(None, int, {}, defs)
|
|
assert result == {"type": "integer"}
|
|
|
|
def test_builtin_str(self) -> None:
|
|
defs: dict[str, SchemaType] = {}
|
|
result = _field_to_schema(None, str, {}, defs)
|
|
assert result == {"type": "string"}
|
|
|
|
def test_builtin_float(self) -> None:
|
|
defs: dict[str, SchemaType] = {}
|
|
result = _field_to_schema(None, float, {}, defs)
|
|
assert result == {"type": "number"}
|
|
|
|
def test_builtin_bool(self) -> None:
|
|
defs: dict[str, SchemaType] = {}
|
|
result = _field_to_schema(None, bool, {}, defs)
|
|
assert result["type"] == "integer"
|
|
assert result["format"] == "boolean"
|
|
|
|
def test_expr_type(self) -> None:
|
|
defs: dict[str, SchemaType] = {}
|
|
result = _field_to_schema(None, Expr, {}, defs)
|
|
assert result["type"] == "string"
|
|
assert "pattern" in result
|
|
|
|
def test_any_type(self) -> None:
|
|
defs: dict[str, SchemaType] = {}
|
|
result = _field_to_schema(None, Any, {}, defs)
|
|
assert result == {}
|
|
|
|
def test_sequence_type(self) -> None:
|
|
defs: dict[str, SchemaType] = {}
|
|
result = _field_to_schema(None, Sequence[int], {}, defs)
|
|
assert result["type"] == "array"
|
|
assert result["items"]["type"] == "integer"
|
|
|
|
def test_mapping_type(self) -> None:
|
|
defs: dict[str, SchemaType] = {}
|
|
result = _field_to_schema(None, Mapping[str, Any], {}, defs)
|
|
assert result["type"] == "object"
|
|
|
|
def test_union_type(self) -> None:
|
|
defs: dict[str, SchemaType] = {}
|
|
result = _field_to_schema(None, Union[int, str], {}, defs)
|
|
assert "anyOf" in result
|
|
|
|
def test_entity_type(self) -> None:
|
|
class Nested(BaseEntity):
|
|
x: int = Field(default=0)
|
|
|
|
defs: dict[str, SchemaType] = {}
|
|
result = _field_to_schema(None, Nested, {}, defs)
|
|
assert "$ref" in result
|
|
assert "Nested" in result["$ref"]
|
|
|
|
def test_enum_type(self) -> None:
|
|
class Color(enum.Enum):
|
|
RED = "red"
|
|
GREEN = "green"
|
|
|
|
defs: dict[str, SchemaType] = {}
|
|
result = _field_to_schema(None, Color, {}, defs)
|
|
assert result["type"] == "string"
|
|
assert set(result["enum"]) == {"red", "green"}
|
|
|
|
def test_unknown_type_raises(self) -> None:
|
|
defs: dict[str, SchemaType] = {}
|
|
with pytest.raises(TypeError, match="unknown type"):
|
|
_field_to_schema(None, object, {}, defs)
|
|
|
|
def test_optional_unwraps(self) -> None:
|
|
"""Optional[int] unwraps to int schema."""
|
|
defs: dict[str, SchemaType] = {}
|
|
result = _field_to_schema(None, Optional[int], {}, defs)
|
|
assert result == {"type": "integer"}
|
|
|
|
def test_field_extras_applied(self) -> None:
|
|
field = _Field(
|
|
description="count",
|
|
constraints={"minimum": 0},
|
|
)
|
|
defs: dict[str, SchemaType] = {}
|
|
result = _field_to_schema(field, int, {}, defs)
|
|
assert result["type"] == "integer"
|
|
assert result["description"] == "count"
|
|
assert result["minimum"] == 0
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# BUILTIN_TYPES_TO_SCHEMA coverage
|
|
# ---------------------------------------------------------------------------
|
|
class TestBuiltinTypesToSchema:
|
|
def test_all_expected_types_present(self) -> None:
|
|
expected = {int, float, bool, str, bytes, Expr, Any}
|
|
assert set(BUILTIN_TYPES_TO_SCHEMA.keys()) == expected
|
|
|
|
def test_immutable(self) -> None:
|
|
"""BUILTIN_TYPES_TO_SCHEMA should be immutable."""
|
|
with pytest.raises(TypeError):
|
|
BUILTIN_TYPES_TO_SCHEMA[int] = {} # type: ignore[index]
|