返回 DeepSeek-Reasonix
wire_extension_test.go
根目录 / internal / eventwire / wire_extension_test.go
1 package eventwire
2
3 import (
4 "encoding/json"
5 "strings"
6 "testing"
7
8 "reasonix/internal/event"
9 )
10
11 // TestToWireExtensionSurfacePayloads covers the stage-8a extension surface
12 // events: status rides ExtensionStatus, card/form/notification ride
13 // ExtensionSurface, and each carries exactly its own sub-struct.
14 func TestToWireExtensionSurfacePayloads(t *testing.T) {
15 progress := 0.5
16 tests := []struct {
17 name string
18 in event.Event
19 want []string
20 }{
21 {
22 name: "status",
23 in: event.Event{Kind: event.ExtensionStatus, Extension: &event.ExtensionSurfacePayload{
24 PluginID: "alpha", SurfaceID: "s1", SessionID: "sess", Generation: 7,
25 Kind: event.ExtensionSurfaceStatus,
26 Status: &event.ExtensionStatusView{Label: "working", Detail: "half", Severity: "warn", Progress: &progress},
27 }},
28 want: []string{
29 `"kind":"extension_status"`, `"extension":{"pluginId":"alpha","surfaceId":"s1","sessionId":"sess","generation":7,"kind":"status"`,
30 `"status":{"label":"working","detail":"half","severity":"warn","progress":0.5}`,
31 },
32 },
33 {
34 name: "card",
35 in: event.Event{Kind: event.ExtensionSurface, Extension: &event.ExtensionSurfacePayload{
36 PluginID: "alpha", SurfaceID: "c1", Kind: event.ExtensionSurfaceCard,
37 Card: &event.ExtensionCardView{
38 Title: "T", Markdown: "**m**", Text: "x", Progress: &progress,
39 Fields: []event.ExtensionKeyValue{{Key: "k", Value: "v"}},
40 Actions: []event.ExtensionActionRef{{ActionID: "act1", Label: "go"}},
41 },
42 }},
43 want: []string{
44 `"kind":"extension_surface"`, `"kind":"card"`,
45 `"card":{"title":"T","markdown":"**m**","text":"x","fields":[{"key":"k","value":"v"}],"progress":0.5,"actions":[{"actionId":"act1","label":"go"}]}`,
46 },
47 },
48 {
49 name: "form",
50 in: event.Event{Kind: event.ExtensionSurface, Extension: &event.ExtensionSurfacePayload{
51 PluginID: "alpha", SurfaceID: "f1", Kind: event.ExtensionSurfaceForm,
52 Form: &event.ExtensionFormView{
53 Title: "f", Message: "m",
54 Fields: []event.ExtensionFormField{{
55 Key: "field1", Label: "L", Kind: "multiselect",
56 Options: []string{"a", "b"}, Default: "a", Required: true,
57 }},
58 },
59 }},
60 want: []string{
61 `"kind":"extension_surface"`, `"kind":"form"`,
62 `"form":{"title":"f","message":"m","fields":[{"key":"field1","label":"L","kind":"multiselect","options":["a","b"],"default":"a","required":true}]}`,
63 },
64 },
65 {
66 name: "notification",
67 in: event.Event{Kind: event.ExtensionSurface, Extension: &event.ExtensionSurfacePayload{
68 PluginID: "alpha", SurfaceID: "n1", Kind: event.ExtensionSurfaceNotification,
69 Notification: &event.ExtensionNotificationView{Title: "n", Body: "b", Severity: "error"},
70 }},
71 want: []string{
72 `"kind":"extension_surface"`, `"kind":"notification"`,
73 `"notification":{"title":"n","body":"b","severity":"error"}`,
74 },
75 },
76 }
77 for _, tt := range tests {
78 t.Run(tt.name, func(t *testing.T) {
79 b, err := json.Marshal(ToWire(tt.in))
80 if err != nil {
81 t.Fatalf("marshal: %v", err)
82 }
83 s := string(b)
84 for _, want := range tt.want {
85 if !strings.Contains(s, want) {
86 t.Fatalf("%s JSON = %s, want it to contain %s", tt.name, s, want)
87 }
88 }
89 })
90 }
91 }
92
93 // TestToWireExtensionNilPayload marshals no extension object instead of a
94 // half-filled one when the payload is missing.
95 func TestToWireExtensionNilPayload(t *testing.T) {
96 b, err := json.Marshal(ToWire(event.Event{Kind: event.ExtensionStatus}))
97 if err != nil {
98 t.Fatalf("marshal: %v", err)
99 }
100 if strings.Contains(string(b), `"extension"`) {
101 t.Fatalf("nil payload JSON = %s, must omit the extension field", b)
102 }
103 }
104
104 lines GO