docs: добавить TESTING_REPORT.md и бенчмарки
- TESTING_REPORT.md: полный отчёт по тестированию - benchmarks_production.py: production бенчмарки - test_edge_cases_names.py: тесты edge cases (unicode, emoji, длинные имена) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
332
tests/test_edge_cases_names.py
Normal file
332
tests/test_edge_cases_names.py
Normal file
@@ -0,0 +1,332 @@
|
||||
"""
|
||||
Тесты 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
|
||||
Reference in New Issue
Block a user