a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
103 lines
3.1 KiB
Go
103 lines
3.1 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"testing"
|
|
)
|
|
|
|
// TestBuildToolCallFrame_PinsJSON asserts every relayed tools/call forces
|
|
// format:"json" so the per-tool decode is stable regardless of the
|
|
// daemon's client-based wire-format auto-selection.
|
|
func TestBuildToolCallFrame_PinsJSON(t *testing.T) {
|
|
frame, err := buildToolCallFrame(1, "search_symbols", map[string]any{"query": "Foo"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var m struct {
|
|
Method string `json:"method"`
|
|
Params struct {
|
|
Name string `json:"name"`
|
|
Arguments map[string]any `json:"arguments"`
|
|
} `json:"params"`
|
|
}
|
|
if err := json.Unmarshal(frame, &m); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if m.Method != "tools/call" || m.Params.Name != "search_symbols" {
|
|
t.Fatalf("unexpected frame: %s", frame)
|
|
}
|
|
if m.Params.Arguments["format"] != "json" {
|
|
t.Fatalf("format must be pinned to json, got %v", m.Params.Arguments["format"])
|
|
}
|
|
if m.Params.Arguments["query"] != "Foo" {
|
|
t.Fatalf("caller args must be preserved, got %v", m.Params.Arguments)
|
|
}
|
|
}
|
|
|
|
// TestBuildToolCallFrame_NilArgs asserts a nil args map still pins json.
|
|
func TestBuildToolCallFrame_NilArgs(t *testing.T) {
|
|
frame, err := buildToolCallFrame(2, "graph_stats", nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !contains(frame, `"format":"json"`) {
|
|
t.Fatalf("nil args must still pin json: %s", frame)
|
|
}
|
|
}
|
|
|
|
func contains(b []byte, sub string) bool {
|
|
return len(b) >= len(sub) && (string(b) == sub || indexOf(string(b), sub) >= 0)
|
|
}
|
|
|
|
func indexOf(s, sub string) int {
|
|
for i := 0; i+len(sub) <= len(s); i++ {
|
|
if s[i:i+len(sub)] == sub {
|
|
return i
|
|
}
|
|
}
|
|
return -1
|
|
}
|
|
|
|
// TestExtractToolResult_RepoNotTracked maps the daemon's typed refusal to
|
|
// the sentinel so the CLI falls back instead of erroring.
|
|
func TestExtractToolResult_RepoNotTracked(t *testing.T) {
|
|
resp := []byte(`{"jsonrpc":"2.0","id":1,"error":{"code":-32000,"message":"repository not tracked","data":{"error_code":"repo_not_tracked"}}}`)
|
|
_, err := extractToolResult(resp)
|
|
if !errors.Is(err, ErrRepoNotTracked) {
|
|
t.Fatalf("want ErrRepoNotTracked, got %v", err)
|
|
}
|
|
}
|
|
|
|
// TestExtractToolResult_RealErrorSurfaced asserts a genuine tool error is
|
|
// surfaced verbatim (not swallowed as "not tracked").
|
|
func TestExtractToolResult_RealErrorSurfaced(t *testing.T) {
|
|
resp := []byte(`{"jsonrpc":"2.0","id":1,"error":{"code":-32602,"message":"bad symbol id"}}`)
|
|
_, err := extractToolResult(resp)
|
|
if err == nil || errors.Is(err, ErrRepoNotTracked) {
|
|
t.Fatalf("a real error must surface, got %v", err)
|
|
}
|
|
if err.Error() != "bad symbol id" {
|
|
t.Fatalf("error message should be verbatim, got %q", err.Error())
|
|
}
|
|
}
|
|
|
|
// TestExtractToolResult_Success returns the tool JSON payload from the
|
|
// result content block.
|
|
func TestExtractToolResult_Success(t *testing.T) {
|
|
resp := []byte(`{"jsonrpc":"2.0","id":1,"result":{"content":[{"type":"text","text":"{\"total\":3}"}]}}`)
|
|
out, err := extractToolResult(resp)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var payload struct {
|
|
Total int `json:"total"`
|
|
}
|
|
if err := json.Unmarshal(out, &payload); err != nil {
|
|
t.Fatalf("payload should be the tool json: %v (%s)", err, out)
|
|
}
|
|
if payload.Total != 3 {
|
|
t.Fatalf("want total 3, got %d", payload.Total)
|
|
}
|
|
}
|