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)