package main import ( "encoding/json" "os" "path/filepath" "testing" "github.com/wailsapp/wails/v3/pkg/application" ) type goldenFixture struct { Contract string `json:"contract"` Cases []goldenCase `json:"cases"` } type goldenCase struct { ID string `json:"id"` Expected goldenExpected `json:"expected"` Envelopes []wireEnvelope `json:"envelopes"` Transitions []hostTransition `json:"transitions"` } type goldenExpected struct { ItemKind string `json:"item_kind"` Fallback string `json:"fallback"` KernelToolStatus string `json:"kernel_tool_status"` } type hostTransition struct { AfterEnvelope int `json:"after_envelope"` Kind string `json:"kind"` CallID string `json:"call_id"` } type wireEnvelope struct { Version int `json:"v"` Type string `json:"type"` Payload map[string]interface{} `json:"payload"` } // TestGoldenContract is deliberately independent of Wails' JS bindings. It // proves that a Wails Host can run the exact versioned fixture, and that the // host's admission gate remains data-only before a WebView receives anything. func TestGoldenContract(t *testing.T) { var fixture goldenFixture path := filepath.Join("..", "tauri", "src", "runtime", "golden", "lineup-v1.json") bytes, err := os.ReadFile(path) if err != nil { t.Fatalf("read shared golden fixture: %v", err) } if err := json.Unmarshal(bytes, &fixture); err != nil { t.Fatalf("parse shared golden fixture: %v", err) } if fixture.Contract != "lineup-v1-golden-1" { t.Fatalf("unexpected golden fixture contract %q", fixture.Contract) } if len(fixture.Cases) != 6 { t.Fatalf("expected six shared cases, got %d", len(fixture.Cases)) } for _, test := range fixture.Cases { t.Run(test.ID, func(t *testing.T) { status := map[string]string{} kind := "" fallback := "" for index, envelope := range test.Envelopes { kind, fallback = project(envelope) if kind == "tool-call" { status[stringValue(envelope.Payload["call_id"])] = "pending" } if kind == "tool-result" { callID := stringValue(envelope.Payload["call_id"]) if status[callID] == "submitted" { status[callID] = stringValue(envelope.Payload["status"]) } } for _, transition := range test.Transitions { if transition.AfterEnvelope == index && transition.Kind == "submit_tool_call" && status[transition.CallID] == "pending" { status[transition.CallID] = "submitted" } } } if kind != test.Expected.ItemKind { t.Fatalf("projection = %q, want %q (fallback %q)", kind, test.Expected.ItemKind, fallback) } if fallback != test.Expected.Fallback { t.Fatalf("fallback = %q, want %q", fallback, test.Expected.Fallback) } if test.Expected.KernelToolStatus != "" { matched := false for _, got := range status { matched = matched || got == test.Expected.KernelToolStatus } if !matched { t.Fatalf("no tool lifecycle reached %q: %#v", test.Expected.KernelToolStatus, status) } } }) } } // Compile-time integration boundary: the Spike uses the actual Wails v3 API, // but LineUp never grants a Surface a Wails binding. Any future production // implementation must retain this separation. func TestWailsApplicationBoundaryCompiles(t *testing.T) { var options application.Options if options.Name != "" { t.Fatal("zero-value options changed unexpectedly") } } func project(envelope wireEnvelope) (kind, fallback string) { if envelope.Version != 1 { return "fallback", "unsupported_version" } switch envelope.Type { case "lineup.v1.tool.call": if stringValue(envelope.Payload["call_id"]) == "" || stringValue(envelope.Payload["tool"]) == "" { return "fallback", "invalid_payload" } return "tool-call", "" case "lineup.v1.tool.result": if stringValue(envelope.Payload["call_id"]) == "" || stringValue(envelope.Payload["status"]) == "" { return "fallback", "invalid_payload" } return "tool-result", "" case "lineup.v1.ui.open", "lineup.v1.ui.patch", "lineup.v1.ui.close": for _, forbidden := range []string{"bundle", "bundle_id", "bundle_url", "url", "html", "css", "javascript", "js", "script", "source"} { if _, exists := envelope.Payload[forbidden]; exists { return "fallback", "invalid_payload" } } return "surface", "" case "lineup.v1.app.call": if stringValue(envelope.Payload["call_id"]) == "" || stringValue(envelope.Payload["capability"]) == "" || stringValue(envelope.Payload["reason"]) == "" || stringValue(envelope.Payload["expires_at"]) == "" { return "fallback", "invalid_payload" } if _, ok := envelope.Payload["arguments"].(map[string]interface{}); !ok { return "fallback", "invalid_payload" } return "app-call", "" default: return "fallback", "unsupported_type" } } func stringValue(value interface{}) string { text, _ := value.(string) return text }