feat(system): test(seedgo): cover all 117 untested functions per TDPLAN-0003 — 826 tests passing, 100% function coverage
Co-Authored-By: @devpulse <devpulse@aipass>
This commit is contained in:
@@ -0,0 +1,607 @@
|
||||
"""Tests for seedgo handler functions (audit_display, diagnostics, json extras, readme, hooks_ext)."""
|
||||
|
||||
# =================== META ====================
|
||||
# Name: test_handler_functions.py
|
||||
# Description: Unit tests for handler-level functions across multiple handler packages
|
||||
# Version: 1.0.0
|
||||
# Created: 2026-04-25
|
||||
# Modified: 2026-04-25
|
||||
# =============================================
|
||||
|
||||
import json
|
||||
import pytest
|
||||
from typing import Dict
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Fixtures
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _mock_infrastructure(monkeypatch):
|
||||
"""Mock heavy infrastructure imports for handler functions."""
|
||||
import sys
|
||||
|
||||
mock_logger = MagicMock()
|
||||
mock_json_handler = MagicMock()
|
||||
mock_json_handler.log_operation = MagicMock(return_value=True)
|
||||
|
||||
# -- prax ---------------------------------------------------------------
|
||||
prax_mod = MagicMock()
|
||||
prax_mod.logger = mock_logger
|
||||
monkeypatch.setitem(sys.modules, "aipass.prax", prax_mod)
|
||||
|
||||
# -- seedgo json handler ------------------------------------------------
|
||||
json_pkg = MagicMock()
|
||||
json_pkg.json_handler = mock_json_handler
|
||||
monkeypatch.setitem(sys.modules, "aipass.seedgo.apps.handlers.json", json_pkg)
|
||||
json_mod = MagicMock()
|
||||
json_mod.log_operation = mock_json_handler.log_operation
|
||||
monkeypatch.setitem(sys.modules, "aipass.seedgo.apps.handlers.json.json_handler", json_mod)
|
||||
|
||||
# -- bypass handler -----------------------------------------------------
|
||||
bypass_pkg = MagicMock()
|
||||
bypass_ignore = MagicMock()
|
||||
bypass_ignore.get_template_ignore_patterns = MagicMock(return_value=[])
|
||||
bypass_ignore.get_audit_ignore_patterns = MagicMock(return_value=[])
|
||||
bypass_pkg.ignore_handler = bypass_ignore
|
||||
monkeypatch.setitem(sys.modules, "aipass.seedgo.apps.handlers.bypass", bypass_pkg)
|
||||
monkeypatch.setitem(
|
||||
sys.modules,
|
||||
"aipass.seedgo.apps.handlers.bypass.ignore_handler",
|
||||
bypass_ignore,
|
||||
)
|
||||
|
||||
# -- cli (console for audit_display) ------------------------------------
|
||||
mock_console = MagicMock()
|
||||
cli_mod = MagicMock()
|
||||
cli_mod.console = mock_console
|
||||
monkeypatch.setitem(sys.modules, "aipass.cli", cli_mod)
|
||||
|
||||
# -- cli.apps.modules (warning function for hooks_ext) ------------------
|
||||
cli_apps = MagicMock()
|
||||
cli_apps_modules = MagicMock()
|
||||
cli_apps_modules.warning = MagicMock()
|
||||
cli_apps.modules = cli_apps_modules
|
||||
cli_mod.apps = cli_apps
|
||||
monkeypatch.setitem(sys.modules, "aipass.cli.apps", cli_apps)
|
||||
monkeypatch.setitem(sys.modules, "aipass.cli.apps.modules", cli_apps_modules)
|
||||
|
||||
# -- file handler (for hooks_ext) ---------------------------------------
|
||||
file_handler_mod = MagicMock()
|
||||
file_handler_mod.read_lines_safe = MagicMock(return_value=[])
|
||||
file_handler_mod.read_text_safe = MagicMock(return_value=None)
|
||||
monkeypatch.setitem(sys.modules, "aipass.seedgo.apps.handlers.file", file_handler_mod)
|
||||
|
||||
# -- hooks handler (for hooks_ext) --------------------------------------
|
||||
hooks_handler_mod = MagicMock()
|
||||
hooks_handler_mod.run_pytest_file = MagicMock(return_value=(3, 0, 1.5))
|
||||
monkeypatch.setitem(sys.modules, "aipass.seedgo.apps.handlers.hooks", hooks_handler_mod)
|
||||
|
||||
# -- rich.table (for hooks_ext) -----------------------------------------
|
||||
rich_table_mod = MagicMock()
|
||||
monkeypatch.setitem(sys.modules, "rich.table", rich_table_mod)
|
||||
monkeypatch.setitem(sys.modules, "rich", MagicMock())
|
||||
monkeypatch.setitem(sys.modules, "rich.console", MagicMock())
|
||||
|
||||
# Force re-imports so handler modules pick up fresh mocks
|
||||
for mod_name in [
|
||||
"aipass.seedgo.apps.handlers.audit.audit_display",
|
||||
"aipass.seedgo.apps.handlers.diagnostics.diagnostics_check",
|
||||
"aipass.seedgo.apps.handlers.json.json_handler",
|
||||
"aipass.seedgo.apps.handlers.readme.readme_ops",
|
||||
"aipass.seedgo.apps.handlers.readme.readme_generator",
|
||||
"aipass.seedgo.apps.modules.hooks_ext",
|
||||
]:
|
||||
monkeypatch.delitem(sys.modules, mod_name, raising=False)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# 1. audit_display -- print_branch_summary
|
||||
# ===========================================================================
|
||||
|
||||
|
||||
def test_print_branch_summary_basic():
|
||||
"""print_branch_summary runs without error on minimal audit result."""
|
||||
from aipass.seedgo.apps.handlers.audit.audit_display import print_branch_summary
|
||||
|
||||
audit_result: Dict = {
|
||||
"branch": {"name": "seedgo"},
|
||||
"scores": {"meta": 100, "naming": 90},
|
||||
"average": 95,
|
||||
"files_checked": 10,
|
||||
"results": {},
|
||||
}
|
||||
# Should not raise
|
||||
print_branch_summary(audit_result)
|
||||
|
||||
|
||||
def test_print_branch_summary_with_violations():
|
||||
"""print_branch_summary handles violation lists."""
|
||||
from aipass.seedgo.apps.handlers.audit.audit_display import print_branch_summary
|
||||
|
||||
audit_result: Dict = {
|
||||
"branch": {"name": "testbranch"},
|
||||
"scores": {"meta": 60, "naming": 80},
|
||||
"average": 70,
|
||||
"files_checked": 5,
|
||||
"results": {
|
||||
"meta": {"checks": [{"name": "META block present", "passed": False, "message": "Missing META block"}]}
|
||||
},
|
||||
"meta_violations": [{"path": "file.py", "score": 50, "issues": ["Missing META block"]}],
|
||||
}
|
||||
# Should not raise
|
||||
print_branch_summary(audit_result)
|
||||
|
||||
|
||||
def test_print_branch_summary_with_system_averages():
|
||||
"""print_branch_summary handles optional system averages."""
|
||||
from aipass.seedgo.apps.handlers.audit.audit_display import print_branch_summary
|
||||
|
||||
audit_result: Dict = {
|
||||
"branch": {"name": "seedgo"},
|
||||
"scores": {"meta": 100},
|
||||
"average": 100,
|
||||
"files_checked": 1,
|
||||
"results": {},
|
||||
}
|
||||
system_averages: Dict[str, int] = {"meta": 90}
|
||||
# Should not raise
|
||||
print_branch_summary(audit_result, system_averages, 90)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# 2. diagnostics_check -- check_directory
|
||||
# ===========================================================================
|
||||
|
||||
|
||||
def test_check_directory_missing(tmp_path):
|
||||
"""check_directory on nonexistent directory returns error."""
|
||||
from aipass.seedgo.apps.handlers.diagnostics.diagnostics_check import (
|
||||
check_directory,
|
||||
)
|
||||
|
||||
result = check_directory(str(tmp_path / "nonexistent"))
|
||||
assert result["total_files"] == 0
|
||||
assert "error" in result
|
||||
assert "not found" in result["error"].lower()
|
||||
|
||||
|
||||
def test_check_directory_exists(tmp_path):
|
||||
"""check_directory on existing directory calls pyright."""
|
||||
# Create a Python file
|
||||
py_file = tmp_path / "example.py"
|
||||
py_file.write_text("x = 1\n", encoding="utf-8")
|
||||
|
||||
from aipass.seedgo.apps.handlers.diagnostics.diagnostics_check import (
|
||||
check_directory,
|
||||
)
|
||||
|
||||
with patch("subprocess.run") as mock_run:
|
||||
mock_run.return_value = MagicMock(
|
||||
stdout=json.dumps(
|
||||
{
|
||||
"generalDiagnostics": [],
|
||||
"summary": {"filesAnalyzed": 1},
|
||||
}
|
||||
),
|
||||
stderr="",
|
||||
)
|
||||
result = check_directory(str(tmp_path))
|
||||
|
||||
assert result["total_errors"] == 0
|
||||
assert result["total_files"] == 1
|
||||
|
||||
|
||||
def test_check_directory_with_errors(tmp_path):
|
||||
"""check_directory reports errors from pyright output."""
|
||||
py_file = tmp_path / "bad.py"
|
||||
py_file.write_text("x: int = 'not_int'\n", encoding="utf-8")
|
||||
|
||||
from aipass.seedgo.apps.handlers.diagnostics.diagnostics_check import (
|
||||
check_directory,
|
||||
)
|
||||
|
||||
with patch("subprocess.run") as mock_run:
|
||||
mock_run.return_value = MagicMock(
|
||||
stdout=json.dumps(
|
||||
{
|
||||
"generalDiagnostics": [
|
||||
{
|
||||
"file": str(py_file),
|
||||
"severity": "error",
|
||||
"range": {"start": {"line": 0}},
|
||||
"message": "Type mismatch",
|
||||
"rule": "reportAssignment",
|
||||
}
|
||||
],
|
||||
"summary": {"filesAnalyzed": 1},
|
||||
}
|
||||
),
|
||||
stderr="",
|
||||
)
|
||||
result = check_directory(str(tmp_path))
|
||||
|
||||
assert result["total_errors"] == 1
|
||||
assert result["files_with_errors"] == 1
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# 3. json_handler -- increment_counter
|
||||
# ===========================================================================
|
||||
|
||||
|
||||
def _get_real_json_handler(tmp_path, monkeypatch):
|
||||
"""Import the real json_handler module with a tmp_path JSON directory."""
|
||||
import importlib
|
||||
import sys
|
||||
|
||||
# Remove ALL json_handler mocks/caches so a fresh import is forced
|
||||
keys_to_remove = [k for k in sys.modules if "json_handler" in k or "handlers.json" in k]
|
||||
for key in keys_to_remove:
|
||||
sys.modules.pop(key, None)
|
||||
|
||||
# Ensure prax logger mock is in place for the real module
|
||||
prax = MagicMock()
|
||||
sys.modules["aipass.prax"] = prax
|
||||
|
||||
# Fresh import of the real module
|
||||
jh_mod = importlib.import_module("aipass.seedgo.apps.handlers.json.json_handler")
|
||||
|
||||
monkeypatch.setattr(jh_mod, "_BRANCH_ROOT", tmp_path)
|
||||
monkeypatch.setattr(jh_mod, "_BRANCH_NAME", "test")
|
||||
monkeypatch.setattr(jh_mod, "JSON_DIR", tmp_path / "test_json")
|
||||
return jh_mod
|
||||
|
||||
|
||||
def test_increment_counter(tmp_path, monkeypatch):
|
||||
"""increment_counter increments a named counter in data JSON."""
|
||||
jh = _get_real_json_handler(tmp_path, monkeypatch)
|
||||
|
||||
result = jh.increment_counter("testmod", "runs", 1)
|
||||
assert result is True
|
||||
|
||||
# Verify counter was set
|
||||
data = jh.load_json("testmod", "data")
|
||||
assert data is not None
|
||||
assert data["runs"] == 1
|
||||
|
||||
# Increment again
|
||||
jh.increment_counter("testmod", "runs", 5)
|
||||
data = jh.load_json("testmod", "data")
|
||||
assert data is not None
|
||||
assert data["runs"] == 6
|
||||
|
||||
|
||||
def test_increment_counter_new_counter(tmp_path, monkeypatch):
|
||||
"""increment_counter creates a new counter if it does not exist."""
|
||||
jh = _get_real_json_handler(tmp_path, monkeypatch)
|
||||
|
||||
result = jh.increment_counter("testmod", "new_counter", 10)
|
||||
assert result is True
|
||||
|
||||
data = jh.load_json("testmod", "data")
|
||||
assert data is not None
|
||||
assert data["new_counter"] == 10
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# 4. json_handler -- update_data_metrics
|
||||
# ===========================================================================
|
||||
|
||||
|
||||
def test_update_data_metrics(tmp_path, monkeypatch):
|
||||
"""update_data_metrics sets arbitrary metrics in data JSON."""
|
||||
jh = _get_real_json_handler(tmp_path, monkeypatch)
|
||||
|
||||
result = jh.update_data_metrics("testmod", score=95, status="ok")
|
||||
assert result is True
|
||||
|
||||
data = jh.load_json("testmod", "data")
|
||||
assert data is not None
|
||||
assert data["score"] == 95
|
||||
assert data["status"] == "ok"
|
||||
|
||||
|
||||
def test_update_data_metrics_overwrites(tmp_path, monkeypatch):
|
||||
"""update_data_metrics overwrites existing metrics."""
|
||||
jh = _get_real_json_handler(tmp_path, monkeypatch)
|
||||
|
||||
jh.update_data_metrics("testmod", score=50)
|
||||
jh.update_data_metrics("testmod", score=99)
|
||||
|
||||
data = jh.load_json("testmod", "data")
|
||||
assert data is not None
|
||||
assert data["score"] == 99
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# 5. readme_ops -- resolve_branch
|
||||
# ===========================================================================
|
||||
|
||||
|
||||
def test_resolve_branch_found(tmp_path, monkeypatch):
|
||||
"""resolve_branch finds a branch in the registry."""
|
||||
registry_data = {
|
||||
"branches": [
|
||||
{"name": "seedgo", "path": "/src/aipass/seedgo"},
|
||||
{"name": "drone", "path": "/src/aipass/drone"},
|
||||
]
|
||||
}
|
||||
registry_path = tmp_path / "AIPASS_REGISTRY.json"
|
||||
registry_path.write_text(json.dumps(registry_data), encoding="utf-8")
|
||||
|
||||
from aipass.seedgo.apps.handlers.readme import readme_ops
|
||||
|
||||
monkeypatch.setattr(readme_ops, "_find_registry", lambda: registry_path)
|
||||
|
||||
result = readme_ops.resolve_branch("@seedgo")
|
||||
assert result is not None
|
||||
assert result["name"] == "seedgo"
|
||||
|
||||
|
||||
def test_resolve_branch_not_found(tmp_path, monkeypatch):
|
||||
"""resolve_branch returns None for unknown branch."""
|
||||
registry_data = {"branches": [{"name": "seedgo"}]}
|
||||
registry_path = tmp_path / "AIPASS_REGISTRY.json"
|
||||
registry_path.write_text(json.dumps(registry_data), encoding="utf-8")
|
||||
|
||||
from aipass.seedgo.apps.handlers.readme import readme_ops
|
||||
|
||||
monkeypatch.setattr(readme_ops, "_find_registry", lambda: registry_path)
|
||||
|
||||
result = readme_ops.resolve_branch("@nonexistent")
|
||||
assert result is None
|
||||
|
||||
|
||||
def test_resolve_branch_no_registry(tmp_path, monkeypatch):
|
||||
"""resolve_branch returns None when registry does not exist."""
|
||||
from aipass.seedgo.apps.handlers.readme import readme_ops
|
||||
|
||||
monkeypatch.setattr(readme_ops, "_find_registry", lambda: tmp_path / "MISSING.json")
|
||||
|
||||
result = readme_ops.resolve_branch("@seedgo")
|
||||
assert result is None
|
||||
|
||||
|
||||
def test_resolve_branch_alias(tmp_path, monkeypatch):
|
||||
"""resolve_branch resolves aliases."""
|
||||
registry_data = {
|
||||
"branches": [
|
||||
{"name": "seedgo", "aliases": ["@sg", "@standards"]},
|
||||
]
|
||||
}
|
||||
registry_path = tmp_path / "AIPASS_REGISTRY.json"
|
||||
registry_path.write_text(json.dumps(registry_data), encoding="utf-8")
|
||||
|
||||
from aipass.seedgo.apps.handlers.readme import readme_ops
|
||||
|
||||
monkeypatch.setattr(readme_ops, "_find_registry", lambda: registry_path)
|
||||
|
||||
result = readme_ops.resolve_branch("@sg")
|
||||
assert result is not None
|
||||
assert result["name"] == "seedgo"
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# 6. readme_ops -- get_all_branches
|
||||
# ===========================================================================
|
||||
|
||||
|
||||
def test_get_all_branches(tmp_path, monkeypatch):
|
||||
"""get_all_branches returns all branches from registry."""
|
||||
registry_data = {
|
||||
"branches": [
|
||||
{"name": "seedgo"},
|
||||
{"name": "drone"},
|
||||
{"name": "spawn"},
|
||||
]
|
||||
}
|
||||
registry_path = tmp_path / "AIPASS_REGISTRY.json"
|
||||
registry_path.write_text(json.dumps(registry_data), encoding="utf-8")
|
||||
|
||||
from aipass.seedgo.apps.handlers.readme import readme_ops
|
||||
|
||||
monkeypatch.setattr(readme_ops, "_find_registry", lambda: registry_path)
|
||||
|
||||
branches = readme_ops.get_all_branches()
|
||||
assert len(branches) == 3
|
||||
|
||||
|
||||
def test_get_all_branches_empty_registry(tmp_path, monkeypatch):
|
||||
"""get_all_branches returns empty list when registry has no branches."""
|
||||
registry_path = tmp_path / "AIPASS_REGISTRY.json"
|
||||
registry_path.write_text(json.dumps({"branches": []}), encoding="utf-8")
|
||||
|
||||
from aipass.seedgo.apps.handlers.readme import readme_ops
|
||||
|
||||
monkeypatch.setattr(readme_ops, "_find_registry", lambda: registry_path)
|
||||
|
||||
branches = readme_ops.get_all_branches()
|
||||
assert branches == []
|
||||
|
||||
|
||||
def test_get_all_branches_no_registry(tmp_path, monkeypatch):
|
||||
"""get_all_branches returns empty list when registry is missing."""
|
||||
from aipass.seedgo.apps.handlers.readme import readme_ops
|
||||
|
||||
monkeypatch.setattr(readme_ops, "_find_registry", lambda: tmp_path / "MISSING.json")
|
||||
|
||||
branches = readme_ops.get_all_branches()
|
||||
assert branches == []
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# 7. readme_generator -- generate_commands_section
|
||||
# ===========================================================================
|
||||
|
||||
|
||||
def test_generate_commands_section_no_entry_point(tmp_path):
|
||||
"""generate_commands_section returns empty when no entry point exists."""
|
||||
branch_dir = tmp_path / "mybranch"
|
||||
apps_dir = branch_dir / "apps"
|
||||
apps_dir.mkdir(parents=True)
|
||||
|
||||
from aipass.seedgo.apps.handlers.readme.readme_generator import (
|
||||
generate_commands_section,
|
||||
)
|
||||
|
||||
result = generate_commands_section(str(branch_dir))
|
||||
assert result == ""
|
||||
|
||||
|
||||
def test_generate_commands_section_with_help(tmp_path):
|
||||
"""generate_commands_section parses help output."""
|
||||
branch_dir = tmp_path / "mybranch"
|
||||
apps_dir = branch_dir / "apps"
|
||||
apps_dir.mkdir(parents=True)
|
||||
entry = apps_dir / "mybranch.py"
|
||||
entry.write_text("pass", encoding="utf-8")
|
||||
|
||||
from aipass.seedgo.apps.handlers.readme.readme_generator import (
|
||||
generate_commands_section,
|
||||
)
|
||||
|
||||
with patch("subprocess.run") as mock_run:
|
||||
mock_run.return_value = MagicMock(
|
||||
stdout="Commands: audit, report, check\n",
|
||||
stderr="",
|
||||
)
|
||||
result = generate_commands_section(str(branch_dir))
|
||||
|
||||
assert "audit" in result
|
||||
assert "report" in result
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# 8. readme_generator -- generate_header_section
|
||||
# ===========================================================================
|
||||
|
||||
|
||||
def test_generate_header_section_with_passport(tmp_path):
|
||||
"""generate_header_section reads passport.json and produces header."""
|
||||
branch_dir = tmp_path / "mybranch"
|
||||
trinity_dir = branch_dir / ".trinity"
|
||||
trinity_dir.mkdir(parents=True)
|
||||
passport = {
|
||||
"branch_info": {
|
||||
"branch_name": "MYBRANCH",
|
||||
"path": str(branch_dir),
|
||||
"profile": "library",
|
||||
"created": "2026-01-01",
|
||||
"role": "Testing branch",
|
||||
}
|
||||
}
|
||||
(trinity_dir / "passport.json").write_text(json.dumps(passport), encoding="utf-8")
|
||||
|
||||
from aipass.seedgo.apps.handlers.readme.readme_generator import (
|
||||
generate_header_section,
|
||||
)
|
||||
|
||||
result = generate_header_section(str(branch_dir))
|
||||
assert "MYBRANCH" in result
|
||||
assert "library" in result
|
||||
assert "Testing branch" in result
|
||||
|
||||
|
||||
def test_generate_header_section_no_passport(tmp_path):
|
||||
"""generate_header_section returns empty when passport is missing."""
|
||||
branch_dir = tmp_path / "mybranch"
|
||||
branch_dir.mkdir()
|
||||
|
||||
from aipass.seedgo.apps.handlers.readme.readme_generator import (
|
||||
generate_header_section,
|
||||
)
|
||||
|
||||
result = generate_header_section(str(branch_dir))
|
||||
assert result == ""
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# 9. readme_generator -- update_readme_auto_sections
|
||||
# ===========================================================================
|
||||
|
||||
|
||||
def test_update_readme_auto_sections_dry_run(tmp_path):
|
||||
"""update_readme_auto_sections in dry_run mode does not modify the file."""
|
||||
branch_dir = tmp_path / "mybranch"
|
||||
branch_dir.mkdir()
|
||||
readme = branch_dir / "README.md"
|
||||
original = "# Branch\n<!-- AUTO:LAST_UPDATED -->\n*Last Updated: 2025-01-01*\n<!-- /AUTO:LAST_UPDATED -->\n"
|
||||
readme.write_text(original, encoding="utf-8")
|
||||
|
||||
from aipass.seedgo.apps.handlers.readme.readme_generator import (
|
||||
update_readme_auto_sections,
|
||||
)
|
||||
|
||||
result = update_readme_auto_sections(str(branch_dir), dry_run=True)
|
||||
assert result["dry_run"] is True
|
||||
# File should not be modified in dry run
|
||||
assert readme.read_text(encoding="utf-8") == original
|
||||
|
||||
|
||||
def test_update_readme_auto_sections_no_readme(tmp_path):
|
||||
"""update_readme_auto_sections reports error when README is missing."""
|
||||
branch_dir = tmp_path / "mybranch"
|
||||
branch_dir.mkdir()
|
||||
|
||||
from aipass.seedgo.apps.handlers.readme.readme_generator import (
|
||||
update_readme_auto_sections,
|
||||
)
|
||||
|
||||
result = update_readme_auto_sections(str(branch_dir))
|
||||
assert "README.md not found" in result["errors"]
|
||||
|
||||
|
||||
def test_update_readme_auto_sections_missing_markers(tmp_path):
|
||||
"""update_readme_auto_sections reports missing markers."""
|
||||
branch_dir = tmp_path / "mybranch"
|
||||
branch_dir.mkdir()
|
||||
readme = branch_dir / "README.md"
|
||||
readme.write_text("# Branch\nNo markers here.\n", encoding="utf-8")
|
||||
|
||||
from aipass.seedgo.apps.handlers.readme.readme_generator import (
|
||||
update_readme_auto_sections,
|
||||
)
|
||||
|
||||
result = update_readme_auto_sections(str(branch_dir))
|
||||
# Some sections should report missing markers
|
||||
assert len(result["missing_markers"]) > 0 or len(result["updated"]) == 0
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# 10. hooks_ext -- run_hooks_test
|
||||
# ===========================================================================
|
||||
|
||||
|
||||
def test_run_hooks_test_no_files(tmp_path):
|
||||
"""run_hooks_test with no test files shows warning."""
|
||||
from aipass.seedgo.apps.modules.hooks_ext import run_hooks_test
|
||||
|
||||
# repo_root with no test_hooks*.py files
|
||||
run_hooks_test(tmp_path)
|
||||
# Should call warning() -- verify through mock
|
||||
import sys
|
||||
|
||||
cli_modules = sys.modules["aipass.cli.apps.modules"]
|
||||
cli_modules.warning.assert_called()
|
||||
|
||||
|
||||
def test_run_hooks_test_with_files(tmp_path):
|
||||
"""run_hooks_test with test files builds and prints table."""
|
||||
import sys
|
||||
|
||||
# Create the expected directory structure
|
||||
test_dir = tmp_path / "src" / "aipass" / "seedgo" / "tests"
|
||||
test_dir.mkdir(parents=True)
|
||||
(test_dir / "test_hooks_basic.py").write_text("pass", encoding="utf-8")
|
||||
|
||||
from aipass.seedgo.apps.modules.hooks_ext import run_hooks_test
|
||||
|
||||
run_hooks_test(tmp_path)
|
||||
|
||||
# Verify console.print was called (table output)
|
||||
cli_mod = sys.modules["aipass.cli"]
|
||||
assert cli_mod.console.print.called
|
||||
Reference in New Issue
Block a user