Files
better-claude-config/test_core.py
T
2026-06-29 14:12:50 -04:00

92 lines
4.3 KiB
Python

import json, tempfile, shutil
from pathlib import Path
import bcc_core as c
tmp = Path(tempfile.mkdtemp())
ok = []
def check(name, cond):
ok.append(cond)
print(("PASS" if cond else "FAIL"), "-", name)
# ---- 1. discovery (monkeypatch the base dir) ----
base = tmp / "AppSupport"
for d in ("Claude", "Claude-Work", "NotClaude"):
(base / d).mkdir(parents=True)
(base / "Claude" / c.CONFIG_FILENAME).write_text("{}")
# Claude-Work has no config yet; NotClaude shouldn't match
c.app_support_base = lambda: base
profs = c.discover_profiles()
labels = sorted(p.label for p in profs)
check("discovers Claude + Claude-Work, not NotClaude", labels == ["Claude", "Claude-Work"])
check("flags missing config file", any(p.label=="Claude-Work" and not p.config_exists for p in profs))
# ---- 2. write preserves OTHER keys + order, only touches mcpServers ----
cfgpath = tmp / "real.json"
original = {
"globalShortcut": "Cmd+Shift+Space",
"mcpServers": {"old": {"command": "node", "args": ["x.js"]}},
"someOtherTool": {"keep": True},
}
cfgpath.write_text(json.dumps(original, indent=2))
cfg = c.load_config(cfgpath)
servers = c.extract_servers(cfg)
# add a new one, disable the old one
servers.append(c.ServerEntry("brave", {"command": "npx", "args": ["-y", "@x/brave"]}, True))
servers[0].enabled = False
c.apply_servers(cfg, servers)
c.write_config(cfgpath, cfg)
written = json.loads(cfgpath.read_text())
keys = list(written.keys())
check("preserved globalShortcut", written.get("globalShortcut") == "Cmd+Shift+Space")
check("preserved someOtherTool", written.get("someOtherTool") == {"keep": True})
check("disabled server parked in _disabledMcpServers", "old" in written.get("_disabledMcpServers", {}))
check("enabled server in mcpServers", "brave" in written.get("mcpServers", {}))
check("old not in active mcpServers", "old" not in written.get("mcpServers", {}))
check("key order kept (globalShortcut before mcpServers)", keys.index("globalShortcut") < keys.index("mcpServers"))
check("backup created", (cfgpath.parent / c.BACKUP_DIRNAME).is_dir() and any((cfgpath.parent / c.BACKUP_DIRNAME).iterdir()))
# ---- 3. paste parser, all shapes ----
full = '{"mcpServers": {"a": {"command": "node", "args": ["a.js"]}}}'
check("parse full config shape", list(c.parse_pasted_json(full)) == ["a"])
inner = '{"b": {"command": "uvx", "args": ["mcp-server-git"]}}'
check("parse inner block shape", list(c.parse_pasted_json(inner)) == ["b"])
bare = '{"command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]}'
parsed = c.parse_pasted_json(bare)
check("parse bare server + suggests name 'filesystem'", "filesystem" in parsed)
remote = '{"url": "https://mcp.asana.com/sse"}'
check("parse remote, suggests host name", "mcp" in c.parse_pasted_json(remote))
try:
c.parse_pasted_json('{"junk": 5}')
check("rejects junk", False)
except ValueError:
check("rejects junk", True)
# ---- 4. validation ----
bad = [c.ServerEntry("", {"command": "x"}, True),
c.ServerEntry("dup", {"command": "x"}, True),
c.ServerEntry("dup", {"command": "x"}, True),
c.ServerEntry("r", {"url": ""}, True),
c.ServerEntry("nocmd", {"command": ""}, True)]
probs = c.validate_servers(bad)
check("validation catches empty name", any("empty name" in p for p in probs))
check("validation catches duplicate", any("Duplicate" in p for p in probs))
check("validation catches missing url", any("no URL" in p for p in probs))
check("validation catches missing command", any("no command" in p for p in probs))
check("valid set passes clean", c.validate_servers([c.ServerEntry("good", {"command":"node"}, True)]) == [])
# ---- 5. dependency check (python3 exists; bogusxyz does not) ----
r_ok = c.check_dependency({"command": "python3"})
check("dep check finds python3", r_ok["status"] == "ok")
r_missing = c.check_dependency({"command": "definitely-not-real-binary-xyz"})
check("dep check flags missing", r_missing["status"] == "missing")
r_remote = c.check_dependency({"url": "https://example.com/mcp"})
check("dep check marks remote", r_remote["status"] == "remote")
# windows-style wrapper: cmd /c npx ... -> should look past cmd to npx
r_wrap = c.check_dependency({"command": "cmd", "args": ["/c", "definitely-not-real-xyz", "foo"]})
check("dep check sees through shell wrapper", "definitely-not-real-xyz" in r_wrap["label"])
print()
print(f"{sum(ok)}/{len(ok)} passed")
shutil.rmtree(tmp)