Spaces:
Sleeping
Sleeping
""" | |
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 # Используем существующий кастомный класс | |
# Фикстуры | |
def base_entity() -> LinkerEntity: | |
"""Фикстура для базовой сущности.""" | |
return LinkerEntity(id=uuid4(), name="Base Name", text="Base Text") | |
def link_entity() -> LinkerEntity: | |
"""Фикстура для сущности-связи.""" | |
return LinkerEntity( | |
id=uuid4(), | |
name="Link Name", | |
source_id=uuid4(), | |
target_id=uuid4(), | |
number_in_relation=1, | |
) | |
def custom_entity_instance() -> CustomEntity: | |
"""Фикстура для кастомной сущности.""" | |
return CustomEntity( | |
id=uuid4(), | |
name="Custom Name", | |
text="Custom Text", | |
custom_field="custom_value", | |
metadata={"existing_meta": "meta_value"}, | |
) | |
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.""" | |
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 |