""" Тесты edge cases со странными названиями инжекторов, типов и зависимостей. Проверяет устойчивость библиотеки к нестандартным именам. """ from dataclasses import dataclass from typing import Any import pytest from breakshaft import ConvRepo from breakshaft.util import hashname, universal_qualname # ============================================================================= # Тесты hashname # ============================================================================= class TestHashnameEdgeCases: """Тесты hashname со странными значениями.""" def test_hashname_with_special_chars(self): """Хэш с специальными символами.""" result = hashname("test-name") assert isinstance(result, str) assert "-" not in result def test_hashname_with_unicode(self): """Хэш с unicode символами.""" result = hashname("тест_привет") assert isinstance(result, str) def test_hashname_with_emoji(self): """Хэш с emoji.""" result = hashname("test_🚀_rocket") assert isinstance(result, str) def test_hashname_with_spaces(self): """Хэш с пробелами.""" result = hashname("test name with spaces") assert isinstance(result, str) def test_hashname_empty_string(self): """Хэш пустой строки.""" result = hashname("") assert isinstance(result, str) assert len(result) > 0 def test_hashname_very_long_string(self): """Хэш очень длинной строки.""" long_name = "a" * 10000 result = hashname(long_name) assert isinstance(result, str) assert len(result) < 100 def test_hashname_consistency(self): """Хэш должен быть консистентным.""" result1 = hashname("test") result2 = hashname("test") assert result1 == result2 # ============================================================================= # Тесты universal_qualname # ============================================================================= class TestUniversalQualnameEdgeCases: """Тесты universal_qualname со странными значениями.""" def test_universal_qualname_with_special_chars(self): """qualname с специальными символами.""" result = universal_qualname("test-name") assert isinstance(result, str) def test_universal_qualname_with_unicode(self): """qualname с unicode.""" result = universal_qualname("тест_привет") assert isinstance(result, str) def test_universal_qualname_with_emoji(self): """qualname с emoji.""" result = universal_qualname("test_🚀") assert isinstance(result, str) def test_universal_qualname_with_brackets(self): """qualname с скобками (Generic types).""" result = universal_qualname("List[int]") assert isinstance(result, str) def test_universal_qualname_with_angle_brackets(self): """qualname с угловыми скобками.""" result = universal_qualname("Dict[str, int]") assert isinstance(result, str) def test_universal_qualname_class(self): """qualname класса.""" class TestClass: pass result = universal_qualname(TestClass) assert isinstance(result, str) assert "TestClass" in result # ============================================================================= # Тесты странных имён типов # ============================================================================= class TestStrangeTypeNames: """Тесты со странными именами типов.""" def test_type_with_special_chars_in_name(self): """Тип с специальными символами в имени.""" StrangeType = type("Type-With-Dash", (), {"value": 42}) repo = ConvRepo() @repo.mark_injector() def int_to_strange(i: int) -> StrangeType: return StrangeType() def consumer(dep: StrangeType) -> int: return dep.value fn = repo.get_conversion((int,), consumer, force_commutative=False) result = fn(42) assert result == 42 def test_type_with_unicode_name(self): """Тип с unicode именем.""" UnicodeType = type("测试类型", (), {"value": 42}) repo = ConvRepo() @repo.mark_injector() def int_to_unicode(i: int) -> UnicodeType: return UnicodeType() def consumer(dep: UnicodeType) -> int: return dep.value fn = repo.get_conversion((int,), consumer, force_commutative=False) result = fn(42) assert result == 42 def test_type_with_very_long_name(self): """Тип с очень длинным именем.""" LongType = type("a" * 500, (), {"value": 42}) repo = ConvRepo() @repo.mark_injector() def int_to_long(i: int) -> LongType: return LongType() def consumer(dep: LongType) -> int: return dep.value fn = repo.get_conversion((int,), consumer, force_commutative=False) result = fn(42) assert result == 42 def test_type_with_spaces_in_name(self): """Тип с пробелами в имени.""" SpaceType = type("Type With Spaces", (), {"value": 42}) repo = ConvRepo() @repo.mark_injector() def int_to_space(i: int) -> SpaceType: return SpaceType() def consumer(dep: SpaceType) -> int: return dep.value fn = repo.get_conversion((int,), consumer, force_commutative=False) result = fn(42) assert result == 42 def test_type_with_reserved_word_name(self): """Тип с именем зарезервированного слова.""" ClassType = type("class", (), {"value": 42}) repo = ConvRepo() @repo.mark_injector() def int_to_class(i: int) -> ClassType: return ClassType() def consumer(dep: ClassType) -> int: return dep.value fn = repo.get_conversion((int,), consumer, force_commutative=False) result = fn(42) assert result == 42 def test_multiple_types_with_same_name(self): """Несколько типов с одинаковым именем (в разных scope).""" Type1 = type("SameType", (), {"value": 1}) Type2 = type("SameType", (), {"value": 2}) repo = ConvRepo() @repo.mark_injector() def int_to_type1(i: int) -> Type1: return Type1() @repo.mark_injector() def int_to_type2(i: int) -> Type2: return Type2() def consumer1(dep: Type1) -> int: return dep.value def consumer2(dep: Type2) -> int: return dep.value fn1 = repo.get_conversion((int,), consumer1, force_commutative=False) result1 = fn1(42) assert result1 == 1 fn2 = repo.get_conversion((int,), consumer2, force_commutative=False) result2 = fn2(42) assert result2 == 2 # ============================================================================= # Тесты странных зависимостей # ============================================================================= class TestStrangeDependencies: """Тесты со странными зависимостями.""" def test_circular_type_dependency(self): """Циклическая зависимость типов.""" repo = ConvRepo() @dataclass class TypeA: value: int @dataclass class TypeB: value: int @repo.mark_injector() def a_to_b(a: TypeA) -> TypeB: return TypeB(a.value) @repo.mark_injector() def b_to_a(b: TypeB) -> TypeA: return TypeA(b.value) def consumer(dep: TypeA) -> int: return dep.value # Должно работать без бесконечной рекурсии fn = repo.get_conversion((TypeA,), consumer, force_commutative=False) result = fn(TypeA(42)) assert result == 42 def test_many_similar_types(self): """Много похожих типов.""" repo = ConvRepo() # Создаём 50 похожих типов types = [] for i in range(50): t = type(f"Type{i}", (), {"value": i}) types.append(t) def make_injector(idx, type_t): def injector(i: int) -> type_t: return type_t() injector.__name__ = f"int_to_type_{idx}" return injector repo.add_injector(make_injector(i, t)) def consumer(dep: types[0]) -> int: return dep.value # Должно работать без коллизий fn = repo.get_conversion((int,), consumer, force_commutative=False) result = fn(42) assert result == 0 # ============================================================================= # Тесты коллизий хэшей # ============================================================================= class TestHashCollisions: """Тесты коллизий хэшей.""" def test_hashname_different_types(self): """Разные типы должны иметь разные хэши (обычно).""" h1 = hashname(int) h2 = hashname(str) assert isinstance(h1, str) assert isinstance(h2, str) def test_universal_qualname_different_types(self): """universal_qualname для разных типов.""" q1 = universal_qualname(int) q2 = universal_qualname(str) assert q1 != q2 # ============================================================================= # Тесты Any аннотаций # ============================================================================= class TestAnyAnnotation: """Тесты с Any аннотациями.""" def test_injector_with_any_annotation(self): """Инжектор с Any аннотацией.""" repo = ConvRepo() @repo.mark_injector() def int_to_any(i: int) -> Any: return i def consumer(dep: Any) -> int: return dep fn = repo.get_conversion((int,), consumer, force_commutative=False) result = fn(42) assert result == 42