Spaces:
Sleeping
Sleeping
File size: 11,422 Bytes
744a170 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 |
"""
Unit-тесты для базового класса LinkerEntity и его механизма сериализации/десериализации.
"""
import uuid
from dataclasses import dataclass, field
from uuid import UUID, uuid4
import pytest
from ntr_text_fragmentation.models import LinkerEntity, register_entity
from tests.custom_entity import \
CustomEntity # Используем существующий кастомный класс
# Фикстуры
@pytest.fixture
def base_entity() -> LinkerEntity:
"""Фикстура для базовой сущности."""
return LinkerEntity(id=uuid4(), name="Base Name", text="Base Text")
@pytest.fixture
def link_entity() -> LinkerEntity:
"""Фикстура для сущности-связи."""
return LinkerEntity(
id=uuid4(),
name="Link Name",
source_id=uuid4(),
target_id=uuid4(),
number_in_relation=1,
)
@pytest.fixture
def custom_entity_instance() -> CustomEntity:
"""Фикстура для кастомной сущности."""
return CustomEntity(
id=uuid4(),
name="Custom Name",
text="Custom Text",
custom_field="custom_value",
metadata={"existing_meta": "meta_value"},
)
@pytest.fixture
def serialized_custom_entity(
custom_entity_instance: CustomEntity,
) -> LinkerEntity:
"""Фикстура для сериализованной кастомной сущности."""
return custom_entity_instance.serialize()
# Тесты
class TestLinkerEntity:
"""Тесты для класса LinkerEntity."""
def test_initialization_defaults(self):
"""Тест инициализации с значениями по умолчанию."""
entity = LinkerEntity()
assert isinstance(entity.id, UUID)
assert entity.name == ""
assert entity.text == ""
assert entity.metadata == {}
assert entity.in_search_text is None
assert entity.source_id is None
assert entity.target_id is None
assert entity.number_in_relation is None
assert entity.groupper is None
assert entity.type == "LinkerEntity" # Имя класса по умолчанию
def test_initialization_with_values(self, base_entity: LinkerEntity):
"""Тест инициализации с заданными значениями."""
entity_id = base_entity.id
assert base_entity.name == "Base Name"
assert base_entity.text == "Base Text"
assert base_entity.id == entity_id
def test_is_link(self, base_entity: LinkerEntity, link_entity: LinkerEntity):
"""Тест метода is_link()."""
assert not base_entity.is_link()
assert link_entity.is_link()
def test_owner_id_property(self, base_entity: LinkerEntity, link_entity: LinkerEntity):
"""Тест свойства owner_id."""
# У обычной сущности owner_id это target_id
owner_uuid = uuid4()
base_entity.target_id = owner_uuid
assert base_entity.owner_id == owner_uuid
# У связи нет owner_id
assert link_entity.owner_id is None
# Попытка установить owner_id для связи должна вызвать ошибку
with pytest.raises(ValueError, match="Связь не может иметь владельца"):
link_entity.owner_id = uuid4()
# Установка owner_id для обычной сущности
new_owner_id = uuid4()
base_entity.owner_id = new_owner_id
assert base_entity.target_id == new_owner_id
def test_str_representation(self, base_entity: LinkerEntity):
"""Тест строкового представления __str__."""
assert str(base_entity) == "Base Name: Base Text"
base_entity.in_search_text = "Search text representation"
assert str(base_entity) == "Search text representation"
def test_equality(self, base_entity: LinkerEntity):
"""Тест сравнения __eq__."""
entity_copy = LinkerEntity(
id=base_entity.id, name="Base Name", text="Base Text"
)
different_entity = LinkerEntity(name="Different Name")
assert base_entity == entity_copy
assert base_entity != different_entity
assert base_entity != "not an entity"
def test_equality_links(self, link_entity: LinkerEntity):
"""Тест сравнения связей."""
link_copy = LinkerEntity(
id=link_entity.id,
name="Link Name",
source_id=link_entity.source_id,
target_id=link_entity.target_id,
number_in_relation=1,
)
different_link = LinkerEntity(
id=link_entity.id,
name="Link Name",
source_id=uuid4(), # Другой source_id
target_id=link_entity.target_id,
number_in_relation=1,
)
non_link = LinkerEntity(id=link_entity.id)
assert link_entity == link_copy
assert link_entity != different_link
assert link_entity != non_link
# --- Тесты сериализации/десериализации ---
def test_serialize_base_entity(self, base_entity: LinkerEntity):
"""Тест сериализации базовой сущности."""
serialized = base_entity.serialize()
assert isinstance(serialized, LinkerEntity)
# Проверяем, что это не тот же самый объект, а копия базового типа
assert serialized is not base_entity
assert type(serialized) is LinkerEntity
assert serialized.id == base_entity.id
assert serialized.name == base_entity.name
assert serialized.text == base_entity.text
assert serialized.metadata == {} # Нет доп. полей
assert serialized.type == "LinkerEntity" # Сохраняем тип
def test_serialize_custom_entity(
self,
custom_entity_instance: CustomEntity,
serialized_custom_entity: LinkerEntity,
):
"""Тест сериализации кастомной сущности."""
serialized = serialized_custom_entity # Используем фикстуру
assert isinstance(serialized, LinkerEntity)
assert type(serialized) is LinkerEntity
assert serialized.id == custom_entity_instance.id
assert serialized.name == custom_entity_instance.name
assert serialized.text == custom_entity_instance.text
# Проверяем, что кастомное поле и исходные метаданные попали в metadata
assert "_custom_field" in serialized.metadata
assert serialized.metadata["_custom_field"] == "custom_value"
assert "existing_meta" in serialized.metadata
assert serialized.metadata["existing_meta"] == "meta_value"
# Тип должен быть именем кастомного класса
assert serialized.type == "CustomEntity"
def test_deserialize_custom_entity(
self, serialized_custom_entity: LinkerEntity
):
"""Тест десериализации в кастомный тип."""
# Используем класс CustomEntity для десериализации, так как он зарегистрирован
deserialized = LinkerEntity._deserialize(serialized_custom_entity)
assert isinstance(deserialized, CustomEntity)
assert deserialized.id == serialized_custom_entity.id
assert deserialized.name == serialized_custom_entity.name
assert deserialized.text == serialized_custom_entity.text
# Проверяем восстановление кастомного поля
assert deserialized.custom_field == "custom_value"
# Проверяем восстановление исходных метаданных
assert "existing_meta" in deserialized.metadata
assert deserialized.metadata["existing_meta"] == "meta_value"
assert deserialized.type == "CustomEntity" # Тип сохраняется
def test_deserialize_base_entity(self, base_entity: LinkerEntity):
"""Тест десериализации базовой сущности (должна вернуться сама)."""
serialized = base_entity.serialize() # Сериализуем базовую
deserialized = LinkerEntity._deserialize(serialized)
assert deserialized is serialized # Возвращается исходный объект LinkerEntity
assert type(deserialized) is LinkerEntity
def test_deserialize_unregistered_type(self):
"""Тест десериализации незарегистрированного типа (должен вернуться исходный объект)."""
unregistered_entity = LinkerEntity(id=uuid4(), type="UnregisteredType")
deserialized = LinkerEntity._deserialize(unregistered_entity)
assert deserialized is unregistered_entity
assert deserialized.type == "UnregisteredType"
def test_deserialize_to_me_on_custom_class(
self, serialized_custom_entity: LinkerEntity
):
"""Тест прямого вызова _deserialize_to_me на кастомном классе."""
# Вызываем метод десериализации непосредственно у CustomEntity
deserialized = CustomEntity._deserialize_to_me(serialized_custom_entity)
assert isinstance(deserialized, CustomEntity)
assert deserialized.id == serialized_custom_entity.id
assert deserialized.custom_field == "custom_value"
assert deserialized.metadata["existing_meta"] == "meta_value"
def test_deserialize_to_me_type_error(self):
"""Тест ошибки TypeError в _deserialize_to_me при неверном типе данных."""
with pytest.raises(TypeError):
# Пытаемся десериализовать не LinkerEntity
CustomEntity._deserialize_to_me("not_an_entity") # type: ignore
def test_register_entity_decorator(self):
"""Тест работы декоратора @register_entity."""
@register_entity
@dataclass
class TempEntity(LinkerEntity):
temp_field: str = "temp"
type: str = "Temporary" # Явно указываем тип для регистрации
assert "Temporary" in LinkerEntity._entity_classes
assert LinkerEntity._entity_classes["Temporary"] is TempEntity
# Проверяем, что он десериализуется
instance = TempEntity(id=uuid4(), name="Temp instance", temp_field="value")
serialized = instance.serialize()
assert serialized.type == "Temporary"
deserialized = LinkerEntity._deserialize(serialized)
assert isinstance(deserialized, TempEntity)
assert deserialized.temp_field == "value"
# Удаляем временный класс из реестра, чтобы не влиять на другие тесты
del LinkerEntity._entity_classes["Temporary"]
assert "Temporary" not in LinkerEntity._entity_classes |