168 lines
5.2 KiB
Python
168 lines
5.2 KiB
Python
from dataclasses import replace
|
|
from pathlib import Path
|
|
|
|
from takopi.config import ProjectConfig, ProjectsConfig
|
|
from takopi.context import RunContext
|
|
from takopi.router import AutoRouter, RunnerEntry
|
|
from takopi.runners.mock import Return, ScriptRunner
|
|
from takopi.telegram import context as tg_context
|
|
from takopi.telegram.topic_state import TopicThreadSnapshot
|
|
from takopi.transport_runtime import TransportRuntime
|
|
from tests.telegram_fakes import DEFAULT_ENGINE_ID, FakeTransport, make_cfg
|
|
|
|
|
|
def _runtime(tmp_path: Path) -> TransportRuntime:
|
|
runner = ScriptRunner([Return(answer="ok")], engine=DEFAULT_ENGINE_ID)
|
|
router = AutoRouter(
|
|
entries=[RunnerEntry(engine=runner.engine, runner=runner)],
|
|
default_engine=runner.engine,
|
|
)
|
|
projects = ProjectsConfig(
|
|
projects={
|
|
"alpha": ProjectConfig(
|
|
alias="Alpha",
|
|
path=tmp_path,
|
|
worktrees_dir=Path(".worktrees"),
|
|
),
|
|
"beta": ProjectConfig(
|
|
alias="Beta",
|
|
path=tmp_path / "beta",
|
|
worktrees_dir=Path(".worktrees"),
|
|
),
|
|
},
|
|
default_project="alpha",
|
|
chat_map={123: "alpha"},
|
|
)
|
|
return TransportRuntime(router=router, projects=projects)
|
|
|
|
|
|
def _cfg(tmp_path: Path):
|
|
transport = FakeTransport()
|
|
return replace(make_cfg(transport), runtime=_runtime(tmp_path))
|
|
|
|
|
|
def test_format_context_variants(tmp_path: Path) -> None:
|
|
runtime = _runtime(tmp_path)
|
|
assert tg_context._format_context(runtime, None) == "none"
|
|
assert tg_context._format_context(runtime, RunContext(project="alpha")) == "Alpha"
|
|
assert (
|
|
tg_context._format_context(runtime, RunContext(project="alpha", branch="dev"))
|
|
== "Alpha @dev"
|
|
)
|
|
|
|
|
|
def test_usage_helpers() -> None:
|
|
assert (
|
|
tg_context._usage_ctx_set(chat_project=None)
|
|
== "usage: `/ctx set <project> [@branch]`"
|
|
)
|
|
assert (
|
|
tg_context._usage_ctx_set(chat_project="alpha") == "usage: `/ctx set [@branch]`"
|
|
)
|
|
assert (
|
|
tg_context._usage_topic(chat_project=None)
|
|
== "usage: `/topic <project> @branch`"
|
|
)
|
|
assert tg_context._usage_topic(chat_project="alpha") == "usage: `/topic @branch`"
|
|
|
|
|
|
def test_parse_project_branch_args_missing_project(tmp_path: Path) -> None:
|
|
runtime = _runtime(tmp_path)
|
|
context, error = tg_context._parse_project_branch_args(
|
|
"",
|
|
runtime=runtime,
|
|
require_branch=False,
|
|
chat_project=None,
|
|
)
|
|
assert context is None
|
|
assert error == "usage: `/ctx set <project> [@branch]`"
|
|
|
|
|
|
def test_parse_project_branch_args_requires_branch(tmp_path: Path) -> None:
|
|
runtime = _runtime(tmp_path)
|
|
context, error = tg_context._parse_project_branch_args(
|
|
"alpha",
|
|
runtime=runtime,
|
|
require_branch=True,
|
|
chat_project=None,
|
|
)
|
|
assert context is None
|
|
assert error == "branch is required"
|
|
|
|
|
|
def test_parse_project_branch_args_chat_project_mismatch(tmp_path: Path) -> None:
|
|
runtime = _runtime(tmp_path)
|
|
context, error = tg_context._parse_project_branch_args(
|
|
"beta @dev",
|
|
runtime=runtime,
|
|
require_branch=True,
|
|
chat_project="alpha",
|
|
)
|
|
assert context is None
|
|
assert error is not None
|
|
assert "project mismatch" in error
|
|
assert "Alpha" in error
|
|
|
|
|
|
def test_parse_project_branch_args_missing_at_prefix(tmp_path: Path) -> None:
|
|
runtime = _runtime(tmp_path)
|
|
context, error = tg_context._parse_project_branch_args(
|
|
"alpha dev",
|
|
runtime=runtime,
|
|
require_branch=False,
|
|
chat_project=None,
|
|
)
|
|
assert context is None
|
|
assert error == "branch must be prefixed with @"
|
|
|
|
|
|
def test_parse_project_branch_args_chat_project_branch_only(tmp_path: Path) -> None:
|
|
runtime = _runtime(tmp_path)
|
|
context, error = tg_context._parse_project_branch_args(
|
|
"@feature",
|
|
runtime=runtime,
|
|
require_branch=True,
|
|
chat_project="alpha",
|
|
)
|
|
assert error is None
|
|
assert context == RunContext(project="alpha", branch="feature")
|
|
|
|
|
|
def test_format_ctx_status_includes_sessions(tmp_path: Path) -> None:
|
|
cfg = _cfg(tmp_path)
|
|
runtime = cfg.runtime
|
|
snapshot = TopicThreadSnapshot(
|
|
chat_id=cfg.chat_id,
|
|
thread_id=1,
|
|
context=None,
|
|
sessions={"b": "token", "a": "token2"},
|
|
topic_title=None,
|
|
default_engine=None,
|
|
)
|
|
text = tg_context._format_ctx_status(
|
|
cfg=cfg,
|
|
runtime=runtime,
|
|
bound=None,
|
|
resolved=RunContext(project="alpha", branch="main"),
|
|
context_source="directives",
|
|
snapshot=snapshot,
|
|
chat_project=None,
|
|
)
|
|
assert "topics: enabled" in text
|
|
assert "bound ctx: none" in text
|
|
assert "resolved ctx: Alpha @main" in text
|
|
assert "note: unbound topic" in text
|
|
assert "sessions: a, b" in text
|
|
|
|
|
|
def test_merge_topic_context() -> None:
|
|
assert tg_context._merge_topic_context(chat_project=None, bound=None) is None
|
|
assert tg_context._merge_topic_context(
|
|
chat_project="alpha",
|
|
bound=None,
|
|
) == RunContext(project="alpha", branch=None)
|
|
assert tg_context._merge_topic_context(
|
|
chat_project="alpha",
|
|
bound=RunContext(project=None, branch="dev"),
|
|
) == RunContext(project="alpha", branch="dev")
|