feat: add run_self_tests() tool for self-verification (#65)
Timmy can now run his own test suite via the run_self_tests() tool. Supports 'fast' (unit only), 'full', or specific path scopes. Returns structured results with pass/fail counts. Sovereign self-verification — a fundamental capability.
This commit is contained in:
@@ -158,3 +158,101 @@ class TestGetOllamaModelExactMatch:
|
||||
result = _get_ollama_model()
|
||||
|
||||
assert result == "qwen3:30b"
|
||||
|
||||
|
||||
class TestRunSelfTests:
|
||||
"""Tests for run_self_tests() — Timmy's self-verification tool."""
|
||||
|
||||
def test_returns_dict_with_expected_keys(self):
|
||||
"""run_self_tests should return structured test results."""
|
||||
from timmy.tools_intro import run_self_tests
|
||||
|
||||
result = run_self_tests(scope="tests/timmy/test_introspection.py")
|
||||
assert isinstance(result, dict)
|
||||
assert "success" in result
|
||||
# Should have count keys when tests ran
|
||||
if result["success"] or "passed" in result:
|
||||
assert "passed" in result
|
||||
assert "failed" in result
|
||||
assert "total" in result
|
||||
|
||||
def test_fast_scope_skips_integration(self, monkeypatch, tmp_path):
|
||||
"""Fast scope should exclude functional/e2e/integration dirs."""
|
||||
import subprocess
|
||||
|
||||
calls = []
|
||||
|
||||
def capture_run(*args, **kwargs):
|
||||
calls.append(args[0] if args else kwargs.get("cmd"))
|
||||
# Return a fake result
|
||||
return subprocess.CompletedProcess(
|
||||
args=args[0] if args else [], returncode=0, stdout="1 passed in 0.5s", stderr=""
|
||||
)
|
||||
|
||||
monkeypatch.setattr(subprocess, "run", capture_run)
|
||||
|
||||
# Create fake venv so check passes
|
||||
venv_python = tmp_path / ".venv" / "bin" / "python"
|
||||
venv_python.parent.mkdir(parents=True)
|
||||
venv_python.write_text("#!/bin/sh\necho mock")
|
||||
|
||||
from timmy.tools_intro import run_self_tests
|
||||
|
||||
run_self_tests(scope="fast", _repo_root=str(tmp_path))
|
||||
assert len(calls) == 1
|
||||
cmd = calls[0]
|
||||
assert "--ignore=tests/functional" in cmd
|
||||
assert "--ignore=tests/e2e" in cmd
|
||||
|
||||
def test_specific_path_scope(self, monkeypatch, tmp_path):
|
||||
"""Specific path scope passes path directly to pytest."""
|
||||
import subprocess
|
||||
|
||||
calls = []
|
||||
|
||||
def capture_run(*args, **kwargs):
|
||||
calls.append(args[0] if args else kwargs.get("cmd"))
|
||||
return subprocess.CompletedProcess(
|
||||
args=args[0] if args else [], returncode=0, stdout="5 passed in 1.0s", stderr=""
|
||||
)
|
||||
|
||||
monkeypatch.setattr(subprocess, "run", capture_run)
|
||||
|
||||
# Create fake venv so check passes
|
||||
venv_python = tmp_path / ".venv" / "bin" / "python"
|
||||
venv_python.parent.mkdir(parents=True)
|
||||
venv_python.write_text("#!/bin/sh\necho mock")
|
||||
|
||||
from timmy.tools_intro import run_self_tests
|
||||
|
||||
run_self_tests(scope="tests/timmy/", _repo_root=str(tmp_path))
|
||||
assert len(calls) == 1
|
||||
assert "tests/timmy/" in calls[0]
|
||||
|
||||
def test_missing_venv_returns_error(self, monkeypatch, tmp_path):
|
||||
"""Should handle missing venv gracefully."""
|
||||
from timmy.tools_intro import run_self_tests
|
||||
|
||||
result = run_self_tests(_repo_root=str(tmp_path))
|
||||
assert result["success"] is False
|
||||
assert "venv" in result.get("error", "").lower()
|
||||
|
||||
def test_timeout_returns_error(self, monkeypatch, tmp_path):
|
||||
"""Should handle subprocess timeout gracefully."""
|
||||
import subprocess
|
||||
|
||||
def timeout_run(*args, **kwargs):
|
||||
raise subprocess.TimeoutExpired(cmd="pytest", timeout=120)
|
||||
|
||||
monkeypatch.setattr(subprocess, "run", timeout_run)
|
||||
|
||||
# Create fake venv so check passes
|
||||
venv_python = tmp_path / ".venv" / "bin" / "python"
|
||||
venv_python.parent.mkdir(parents=True)
|
||||
venv_python.write_text("#!/bin/sh\necho mock")
|
||||
|
||||
from timmy.tools_intro import run_self_tests
|
||||
|
||||
result = run_self_tests(_repo_root=str(tmp_path))
|
||||
assert result["success"] is False
|
||||
assert "timed out" in result.get("error", "").lower()
|
||||
|
||||
Reference in New Issue
Block a user