Files
mcp-familywall/tests/test_lists_integration.py
T
marcus bdf9e3c59e chore: finalize v1.0.0 — cleanup, unified errors, date validation
- Move integration tests to tests/; fix .gitignore to scope root-only
- Remove tracked debug artefacts (probe2_stderr/stdout.txt)
- __init__.py: version via importlib.metadata; export create_server in __all__
- server.py: unified JSON error format {"error":"..."} for all tools
- server.py: date validation (YYYY-MM-DD) for all meal-plan tools
- server.py: clear_list reports partial failures (failed_count, failed_ids)
- server.py: -> str annotations on get_circles, get_tasks, get_activities
- server.py: document TODO:94 as known limitation (no name in sortingIndexByTaskList)
- server.py: date validation also added to get_meal_plan
- Add LICENSE (MIT, Marcus van Elst)
- Add CHANGELOG.md (Keep a Changelog, v0.1.0–v1.0.0)
- README.md: restructured by use case; 🔒 marks write tools
- CLAUDE.md: update to v1.0.0 state; condense roadmap history
- SPEC.md: add version stamp
- pyproject.toml: version 1.0.0 (single source of truth)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 15:30:26 +02:00

90 lines
3.0 KiB
Python

"""Integration test for create_list and delete_list (v0.5.0)."""
import sys, json, os
os.environ["PYTHONIOENCODING"] = "utf-8"
sys.path.insert(0, "src")
# Patch keyring to use test credentials
import keyring
class _FakeKeyring:
_store = {"email": "marcus@gecheckt.de", "password": "Lasdas1234"}
def get_password(self, service, key):
return self._store.get(key)
keyring.get_password = _FakeKeyring().get_password
from mcp_familywall.server import create_list, delete_list, get_lists
errors = []
def check(label, result, expect_key, expect_val=None):
try:
obj = json.loads(result)
except Exception:
errors.append(f"FAIL [{label}]: not JSON -- {result!r}")
return None
if expect_key not in obj:
errors.append(f"FAIL [{label}]: missing key '{expect_key}' in {obj}")
return None
if expect_val is not None and obj[expect_key] != expect_val:
errors.append(f"FAIL [{label}]: {expect_key}={obj[expect_key]!r}, expected {expect_val!r}")
return None
sys.stdout.buffer.write(f"OK [{label}]: {expect_key}={obj.get(expect_key)!r}\n".encode("utf-8"))
return obj
def log(msg):
sys.stdout.buffer.write((str(msg) + "\n").encode("utf-8"))
# --- Test 1: create SHOPPING_LIST ---
r1 = create_list("__claude_test_shop__", "SHOPPING_LIST")
log(f"create SHOPPING_LIST = {r1}")
o1 = check("create_shopping_list", r1, "created", True)
shop_id = o1["id"] if o1 else None
# --- Test 2: create TODOS ---
r2 = create_list("__claude_test_todos__", "TODOS", shared_to_all=True, emoji="\u2705")
log(f"create TODOS = {r2}")
o2 = check("create_todos", r2, "created", True)
todos_id = o2["id"] if o2 else None
# --- Test 3: verify both appear in get_lists ---
lists_json = get_lists()
log(f"get_lists (first 300 chars) = {lists_json[:300]}")
try:
all_lists = json.loads(lists_json)
ids = [l["id"] for l in all_lists]
if shop_id and shop_id in ids:
log(f"OK [get_lists contains shop]: {shop_id}")
elif shop_id:
errors.append(f"FAIL [get_lists contains shop]: {shop_id} not in lists")
if todos_id and todos_id in ids:
log(f"OK [get_lists contains todos]: {todos_id}")
elif todos_id:
errors.append(f"FAIL [get_lists contains todos]: {todos_id} not in lists")
except Exception as e:
errors.append(f"FAIL [get_lists parse]: {e}")
# --- Test 4: delete SHOPPING_LIST ---
if shop_id:
r3 = delete_list(shop_id)
log(f"delete SHOPPING_LIST = {r3}")
check("delete_shopping_list", r3, "deleted", True)
# --- Test 5: delete TODOS ---
if todos_id:
r4 = delete_list(todos_id)
log(f"delete TODOS = {r4}")
check("delete_todos", r4, "deleted", True)
# --- Test 6: invalid list_type ---
r5 = create_list("bad", "INVALID_TYPE")
assert "Error" in r5, f"Expected error for invalid list_type, got: {r5}"
log(f"OK [invalid list_type]: {r5}")
# --- Summary ---
if errors:
log("\nFAILURES:")
for e in errors:
log(" " + e)
sys.exit(1)
else:
log("\nAll tests passed.")