Files
tgit/tests/repo/test_validate.py
T
ElebobaandClaude Opus 5.5 614f8eafd5 feat(bot): Коммит — создание, замена и удаление файлов, черновик
- новый файл: имя → содержимое текстом (```-обёртка снимается) или документом
- новая папка (виртуальная, пока в ней нет файлов), замена с diff +N/−M, удаление
- валидация: имя, ≤ 100 КБ, UTF-8, без NUL; .py — ast.parse с выбором «исправить / всё равно»;
  .sourcecraft/, .tgit/, ruff.toml из бота не меняются
- DraftService: черновик в БД, 24 ч, ≤ 50 изменений; удаление нового файла убирает его из черновика
- дерево показывает черновик поверх репозитория: 🆕 / ✏️ / 🗑, размер — как будет после пуша
- экран черновика (A/M/D) с «↩️ убрать»

Refs #26

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 19:18:49 +03:00

75 lines
2.0 KiB
Python

import pytest
from app.repo.validate import (
ValidationError,
check_content,
check_name,
diff_stat,
is_protected,
join,
python_syntax,
strip_fence,
)
@pytest.mark.parametrize("name", ["main.py", "a-b_c.1", ".gitignore", "X" * 100])
def test_good_names(name: str) -> None:
assert check_name(f" {name} ") == name
@pytest.mark.parametrize("name", ["", ".", "..", "a/b", "привет.py", "a b", "X" * 101, "a;rm"])
def test_bad_names(name: str) -> None:
with pytest.raises(ValidationError):
check_name(name)
@pytest.mark.parametrize(
("path", "protected"),
[
(".sourcecraft/ci.yaml", True),
(".tgit/x.py", True),
("ruff.toml", True),
(".sourcecraft", True),
("services/a/ruff.toml", False),
("README.md", False),
("services/a/main.py", False),
],
)
def test_protected_paths(path: str, protected: bool) -> None:
assert is_protected(path) is protected
def test_join() -> None:
assert join("", "a.py") == "a.py" and join("s/x", "a.py") == "s/x/a.py"
@pytest.mark.parametrize(
("text", "expected"),
[
("```python\nprint(1)\n```", "print(1)"),
("```\na\nb\n```", "a\nb"),
("print(1)", "print(1)"),
("x ``` y", "x ``` y"),
],
)
def test_strip_fence(text: str, expected: str) -> None:
assert strip_fence(text) == expected
def test_content_checks() -> None:
assert check_content("привет".encode()) == "привет"
for data, reason in [(b"a\0b", "binary"), (b"\xff\xfe", "encoding"), (b"x" * (100 * 1024 + 1), "too_big")]:
with pytest.raises(ValidationError, match=reason):
check_content(data)
def test_python_syntax_only_for_py() -> None:
issue = python_syntax("a.py", "def f(:\n pass\n")
assert issue is not None and issue.line == 1
assert python_syntax("a.py", "x = 1\n") is None
assert python_syntax("a.txt", "def f(:") is None
def test_diff_stat() -> None:
assert diff_stat("a\nb\nc", "a\nB\nc\nd") == (2, 1)