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:
Qwen Code Assistant
2026-03-28 18:39:19 +00:00
parent fdcaab7fef
commit 4a7fb58b78
3 changed files with 879 additions and 0 deletions

View 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