"""Exercise the MCP server tools as plain Python callables. FastMCP tools are registered on the server instance, but the underlying functions are ordinary Python functions decorated with ``@mcp.tool()``. We import the module and invoke those functions directly to verify the end-to-end wiring (schemas validated, dispatch correct, JSON-serializable). """ import humeo_core.server as srv from humeo_core.schemas import LayoutKind def test_list_layouts_lists_all_three(): result = srv.list_layouts() kinds = {layout["kind"] for layout in result["layouts"]} assert kinds == {k.value for k in LayoutKind} def test_plan_layout_tool_returns_filtergraph(): for k in LayoutKind: out = srv.plan_layout(layout=k.value) assert out["out_label"] == "vout" assert "[vout]" in out["filtergraph"] def test_build_render_cmd_dry_run(): req = { "source_path": "/tmp/src.mp4", "clip": { "clip_id": "1", "topic": "t", "start_time_sec": 0.0, "end_time_sec": 30.0, }, "layout": {"clip_id": "1", "layout": LayoutKind.SIT_CENTER.value}, "output_path": "/tmp/out.mp4", } out = srv.build_render_cmd(request=req) assert out["success"] is True assert out["output_path"] == "/tmp/out.mp4" assert any("-filter_complex" == part for part in out["ffmpeg_cmd"]) def test_select_clips_tool_happy_path(): words = [ {"word": f"w{i}", "start_time": float(i), "end_time": float(i) + 0.5} for i in range(120) ] plan = srv.select_clips( source_path="/tmp/x.mp4", transcript_words=words, duration_sec=120.0, target_count=2, min_sec=30.0, max_sec=60.0, ) assert plan["source_path"] == "/tmp/x.mp4" assert 1 <= len(plan["clips"]) <= 2 def test_classify_scenes_tool_no_keyframes(): scenes = [{"scene_id": "s0", "start_time": 0.0, "end_time": 5.0}] out = srv.classify_scenes(scenes=scenes) assert out["classifications"][0]["scene_id"] == "s0" assert out["classifications"][0]["layout"] in {k.value for k in LayoutKind} def test_detect_scene_regions_returns_jobs_and_prompt(): scenes = [ {"scene_id": "s0", "start_time": 0.0, "end_time": 5.0, "keyframe_path": "/tmp/k0.jpg"}, {"scene_id": "s1", "start_time": 5.0, "end_time": 10.0, "keyframe_path": "/tmp/k1.jpg"}, ] out = srv.detect_scene_regions(scenes=scenes) assert "STRICT JSON" in out["prompt"] assert len(out["jobs"]) == 2 assert out["jobs"][0]["scene_id"] == "s0" assert out["jobs"][0]["keyframe_path"] == "/tmp/k0.jpg" def test_classify_scenes_with_vision_derives_instructions(): regions = [ { "scene_id": "s0", "chart_bbox": {"x1": 0.0, "y1": 0.0, "x2": 0.66, "y2": 1.0}, "person_bbox": {"x1": 0.72, "y1": 0.1, "x2": 0.99, "y2": 0.95}, "ocr_text": "CPI YoY", } ] out = srv.classify_scenes_with_vision(regions=regions) assert out["classifications"][0]["layout"] == LayoutKind.SPLIT_CHART_PERSON.value instr = out["layout_instructions"][0] assert instr["chart_x_norm"] == 0.0 assert 0.8 < instr["person_x_norm"] < 0.9