135 lines
4.0 KiB
Python
135 lines
4.0 KiB
Python
"""Tests for automaton.dashboard.core.task."""
|
|||
|
|
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
from automaton.dashboard.core.task import (
|
||
|
|
determine_task_state,
|
||
|
|
discover_tasks,
|
||
|
|
parse_sub_tasks,
|
||
|
|
TaskState,
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
def _make_task(tmp_path: Path, name: str, artifacts: dict[str, str]) -> Path:
|
||
|
|
"""Create a task folder with the given artifact contents."""
|
||
|
|
task_dir = tmp_path / name
|
||
|
|
task_dir.mkdir(parents=True)
|
||
|
|
for filename, content in artifacts.items():
|
||
|
|
(task_dir / filename).write_text(content)
|
||
|
|
return task_dir
|
||
|
|
|
||
|
|
|
||
|
|
def test_backlog_state(tmp_path: Path) -> None:
|
||
|
|
task_dir = _make_task(tmp_path, "backlog-task", {})
|
||
|
|
state, artifacts = determine_task_state(task_dir)
|
||
|
|
assert state == TaskState.BACKLOG
|
||
|
|
assert not artifacts
|
||
|
|
|
||
|
|
|
||
|
|
def test_research_state(tmp_path: Path) -> None:
|
||
|
|
task_dir = _make_task(tmp_path, "research-task", {"SPEC.md": "# Spec"})
|
||
|
|
state, artifacts = determine_task_state(task_dir)
|
||
|
|
assert state == TaskState.RESEARCH
|
||
|
|
assert "SPEC.md" in artifacts
|
||
|
|
|
||
|
|
|
||
|
|
def test_implementation_state(tmp_path: Path) -> None:
|
||
|
|
task_dir = _make_task(
|
||
|
|
tmp_path,
|
||
|
|
"impl-task",
|
||
|
|
{"SPEC.md": "# Spec", "IMPLEMENTATION.md": "# Impl"},
|
||
|
|
)
|
||
|
|
state, _ = determine_task_state(task_dir)
|
||
|
|
assert state == TaskState.IMPLEMENT
|
||
|
|
|
||
|
|
|
||
|
|
def test_bug_find_state(tmp_path: Path) -> None:
|
||
|
|
task_dir = _make_task(
|
||
|
|
tmp_path,
|
||
|
|
"bug-task",
|
||
|
|
{"SPEC.md": "# Spec", "IMPLEMENTATION.md": "# Impl", "BUG_REPORT.md": "# Bugs"},
|
||
|
|
)
|
||
|
|
state, _ = determine_task_state(task_dir)
|
||
|
|
assert state == TaskState.BUG_FIND
|
||
|
|
|
||
|
|
|
||
|
|
def test_adv_bug_find_state(tmp_path: Path) -> None:
|
||
|
|
task_dir = _make_task(
|
||
|
|
tmp_path,
|
||
|
|
"adv-task",
|
||
|
|
{
|
||
|
|
"SPEC.md": "# Spec",
|
||
|
|
"IMPLEMENTATION.md": "# Impl",
|
||
|
|
"BUG_REPORT.md": "# Bugs",
|
||
|
|
"ADVERSARIAL_BUG_REPORT.md": "# Adv",
|
||
|
|
},
|
||
|
|
)
|
||
|
|
state, _ = determine_task_state(task_dir)
|
||
|
|
assert state == TaskState.ADV_BUG_FIND
|
||
|
|
|
||
|
|
|
||
|
|
def test_done_state(tmp_path: Path) -> None:
|
||
|
|
task_dir = _make_task(
|
||
|
|
tmp_path,
|
||
|
|
"done-task",
|
||
|
|
{"SPEC.md": "# Spec", "VERDICT.md": "## Status: PASS"},
|
||
|
|
)
|
||
|
|
state, _ = determine_task_state(task_dir)
|
||
|
|
assert state == TaskState.DONE
|
||
|
|
|
||
|
|
|
||
|
|
def test_blocked_state(tmp_path: Path) -> None:
|
||
|
|
task_dir = _make_task(
|
||
|
|
tmp_path,
|
||
|
|
"blocked-task",
|
||
|
|
{"SPEC.md": "# Spec", "VERDICT.md": "## Status: FAIL"},
|
||
|
|
)
|
||
|
|
state, _ = determine_task_state(task_dir)
|
||
|
|
assert state == TaskState.BLOCKED
|
||
|
|
|
||
|
|
|
||
|
|
def test_empty_verdict_is_blocked(tmp_path: Path) -> None:
|
||
|
|
task_dir = _make_task(tmp_path, "empty-verdict", {"VERDICT.md": ""})
|
||
|
|
state, _ = determine_task_state(task_dir)
|
||
|
|
assert state == TaskState.BLOCKED
|
||
|
|
|
||
|
|
|
||
|
|
def test_parse_sub_tasks(tmp_path: Path) -> None:
|
||
|
|
parent = tmp_path / "parent"
|
||
|
|
parent.mkdir()
|
||
|
|
sub = parent / "subtasks" / "sub-a"
|
||
|
|
sub.mkdir(parents=True)
|
||
|
|
(sub / "SPEC.md").write_text("# Spec")
|
||
|
|
(sub / "VERDICT.md").write_text("## Status: PASS")
|
||
|
|
|
||
|
|
sub_tasks = parse_sub_tasks(parent)
|
||
|
|
assert len(sub_tasks) == 1
|
||
|
|
assert sub_tasks[0].name == "sub-a"
|
||
|
|
assert sub_tasks[0].has_verdict is True
|
||
|
|
assert sub_tasks[0].verdict_status == "PASS"
|
||
|
|
|
||
|
|
|
||
|
|
def test_discover_tasks(tmp_path: Path) -> None:
|
||
|
|
_make_task(tmp_path, "aaa", {"SPEC.md": "# Spec"})
|
||
|
|
_make_task(tmp_path, "zzz", {"VERDICT.md": "## Status: PASS"})
|
||
|
|
tasks = discover_tasks(tmp_path)
|
||
|
|
assert len(tasks) == 2
|
||
|
|
# Done task should be first (sorted by advancement).
|
||
|
|
assert tasks[0].state == TaskState.DONE
|
||
|
|
assert tasks[1].state == TaskState.RESEARCH
|
||
|
|
|
||
|
|
|
||
|
|
def test_discover_tasks_skips_subtasks_root(tmp_path: Path) -> None:
|
||
|
|
parent = tmp_path / "parent"
|
||
|
|
parent.mkdir()
|
||
|
|
(parent / "SPEC.md").write_text("# Spec")
|
||
|
|
(parent / "subtasks" / "sub-a").mkdir(parents=True)
|
||
|
|
(parent / "subtasks" / "sub-a" / "SPEC.md").write_text("# Sub")
|
||
|
|
|
||
|
|
tasks = discover_tasks(tmp_path)
|
||
|
|
assert len(tasks) == 1
|
||
|
|
assert tasks[0].name == "parent"
|
||
|
|
assert len(tasks[0].sub_tasks) == 1
|