package tools_test import ( "context" "encoding/json" "testing" "ollie/tools" ) // stubRunner is a minimal Runner used to verify the contract. type stubRunner struct { name string tools []tools.ToolInfo } func (s *stubRunner) ListTools() ([]tools.ToolInfo, error) { return s.tools, nil } func (s *stubRunner) CallTool(_ context.Context, tool string, _ json.RawMessage) (json.RawMessage, error) { return json.RawMessage(`{"tool":"` + tool + `"}`), nil } func newStub(name string, toolNames ...string) *stubRunner { var ti []tools.ToolInfo for _, n := range toolNames { ti = append(ti, tools.ToolInfo{Name: n, Description: n + " desc"}) } return &stubRunner{name: name, tools: ti} } // checkRunnerContract verifies Runner invariants. func checkRunnerContract(t *testing.T, r tools.Runner) { t.Helper() tl, err := r.ListTools() if err != nil { t.Fatalf("ListTools: %v", err) } if tl == nil { t.Fatal("ListTools returned nil") } for _, ti := range tl { res, err := r.CallTool(context.Background(), ti.Name, json.RawMessage(`{}`)) if err != nil { t.Errorf("CallTool(%q): %v", ti.Name, err) } if len(res) == 0 { t.Errorf("CallTool(%q) returned empty result", ti.Name) } } } func TestStubRunnerContract(t *testing.T) { checkRunnerContract(t, newStub("s", "a", "b")) }