"""Юнит-тесты для validator.py.
Покрывают контрактные правила из design.md §5 и явные требования задачи:
- валидный SVG → ok=True
- отсутствует viewBox → ok=False (missing_viewbox)
- есть
"""
ok, reason, _ = validate_svg(bad, mode="icon")
assert ok is False
assert reason == "disallowed_tag"
def test_foreign_object_rejected():
bad = """"""
ok, reason, _ = validate_svg(bad, mode="icon")
assert ok is False
assert reason == "disallowed_tag"
def test_http_ref_rejected():
bad = """"""
ok, reason, _ = validate_svg(bad, mode="icon")
assert ok is False
assert reason == "external_ref"
def test_onclick_attribute_rejected():
bad = """"""
ok, reason, _ = validate_svg(bad, mode="icon")
assert ok is False
assert reason == "event_handler"
def test_url_with_https_rejected():
"""https:// в url(...) тоже блокируется."""
bad = """"""
ok, reason, _ = validate_svg(bad, mode="icon")
assert ok is False
# Сейчас external_ref ловится на `url(` независимо от http(s).
assert reason in ("external_ref", "disallowed_tag", "unknown_tag")
def test_too_large_rejected():
"""SVG > MAX_BYTES[mode] → too_large."""
# Соберём раздутый SVG с большим комментарием.
pad = ""
bad = (
'"
)
ok, reason, _ = validate_svg(bad, mode="icon")
assert ok is False
assert reason == "too_large"
def test_empty_input_rejected():
ok, reason, _ = validate_svg("", mode="icon")
assert ok is False
assert reason == "empty_input"
def test_no_svg_block_rejected():
ok, reason, _ = validate_svg("Sorry, I cannot help with that.", mode="icon")
assert ok is False
assert reason == "not_svg"
# ---------------------------------------------------------------------------
# Прямые проверки API (validate() бросает, extract_svg() утилитарный)
# ---------------------------------------------------------------------------
def test_validate_strict_raises():
with pytest.raises(ValidatorError) as excinfo:
validate("plain text", mode="icon")
assert excinfo.value.code == "not_svg"
def test_extract_svg_finds_block():
text = "noise noise"
found = extract_svg(text)
assert found.startswith("