1package systemviewsbridge
2
3import (
4 "bytes"
5 "encoding/json"
6 "testing"
7)
8
9func TestDecodeBrowserRequest_DirectConfigEndpoint(t *testing.T) {
10 t.Parallel()
11
12 body, err := buildMessageEnvelope("/api/config", struct {
13 RequestID string `json:"requestId"`
14 }{RequestID: "req-1"})
15 if err != nil {
16 t.Fatalf("buildMessageEnvelope() error = %v", err)
17 }
18
19 req, err := decodeBrowserRequest(body)
20 if err != nil {
21 t.Fatalf("decodeBrowserRequest() error = %v", err)
22 }
23 if req.messageType != "/api/config" {
24 t.Fatalf("messageType = %q, want %q", req.messageType, "/api/config")
25 }
26 if req.requestID != "req-1" {
27 t.Fatalf("requestID = %q, want %q", req.requestID, "req-1")
28 }
29 if !req.directAPI {
30 t.Fatal("directAPI = false, want true")
31 }
32}
33
34func TestDecodeBrowserRequest_MessageEnvelopeUsesBridgeShim(t *testing.T) {
35 t.Parallel()
36
37 body, err := buildMessageEnvelope("history_timeline", struct {
38 RequestID string `json:"requestId"`
39 Limit int `json:"limit"`
40 }{RequestID: "req-2", Limit: 25})
41 if err != nil {
42 t.Fatalf("buildMessageEnvelope() error = %v", err)
43 }
44
45 req, err := decodeBrowserRequest(body)
46 if err != nil {
47 t.Fatalf("decodeBrowserRequest() error = %v", err)
48 }
49 if req.messageType != "history_timeline" {
50 t.Fatalf("messageType = %q, want %q", req.messageType, "history_timeline")
51 }
52 if req.requestID != "req-2" {
53 t.Fatalf("requestID = %q, want %q", req.requestID, "req-2")
54 }
55 if req.directAPI {
56 t.Fatal("directAPI = true, want false")
57 }
58 if !bytes.Equal(req.body, body) {
59 t.Fatalf("body = %s, want %s", req.body, body)
60 }
61}
62
63func TestNormalizeBridgeShimResponse_UnwrapsNestedBridgeEnvelope(t *testing.T) {
64 t.Parallel()
65
66 got, err := normalizeBridgeShimResponse("req-3", []byte(`{"data":{"requestId":"req-3","success":true,"data":[{"title":"Example"}]},"_callback":"__dumber_homepage_response"}`))
67 if err != nil {
68 t.Fatalf("normalizeBridgeShimResponse() error = %v", err)
69 }
70
71 var resp bridgeResponse
72 if err := json.Unmarshal(got, &resp); err != nil {
73 t.Fatalf("json.Unmarshal() error = %v", err)
74 }
75 if !resp.Success {
76 t.Fatal("success = false, want true")
77 }
78 if resp.RequestID != "req-3" {
79 t.Fatalf("requestId = %q, want %q", resp.RequestID, "req-3")
80 }
81 if string(resp.Data) != `[{"title":"Example"}]` {
82 t.Fatalf("data = %s, want %s", resp.Data, `[{"title":"Example"}]`)
83 }
84}
85
86func TestNormalizeBridgeShimResponse_DoesNotTreatRequestIDDataAsEnvelope(t *testing.T) {
87 t.Parallel()
88
89 got, err := normalizeBridgeShimResponse("req-raw", []byte(`{"data":{"requestId":"external-id","title":"Example"},"_callback":"__dumber_homepage_response"}`))
90 if err != nil {
91 t.Fatalf("normalizeBridgeShimResponse() error = %v", err)
92 }
93
94 var resp bridgeResponse
95 if err := json.Unmarshal(got, &resp); err != nil {
96 t.Fatalf("json.Unmarshal() error = %v", err)
97 }
98 if string(resp.Data) != `{"requestId":"external-id","title":"Example"}` {
99 t.Fatalf("data = %s, want raw payload", resp.Data)
100 }
101}
102
103func TestNormalizeBridgeShimResponse_DoesNotTreatNonBooleanSuccessDataAsEnvelope(t *testing.T) {
104 t.Parallel()
105
106 got, err := normalizeBridgeShimResponse("req-raw-success", []byte(`{"data":{"success":"yes","title":"Example"},"_callback":"__dumber_homepage_response"}`))
107 if err != nil {
108 t.Fatalf("normalizeBridgeShimResponse() error = %v", err)
109 }
110
111 var resp bridgeResponse
112 if err := json.Unmarshal(got, &resp); err != nil {
113 t.Fatalf("json.Unmarshal() error = %v", err)
114 }
115 if string(resp.Data) != `{"success":"yes","title":"Example"}` {
116 t.Fatalf("data = %s, want raw payload", resp.Data)
117 }
118}
119
120func TestNormalizeBridgeShimResponse_WrapsRawCallbackPayload(t *testing.T) {
121 t.Parallel()
122
123 got, err := normalizeBridgeShimResponse("req-4", []byte(`{"data":{"status":"success"},"_callback":"__dumber_config_saved"}`))
124 if err != nil {
125 t.Fatalf("normalizeBridgeShimResponse() error = %v", err)
126 }
127
128 var resp bridgeResponse
129 if err := json.Unmarshal(got, &resp); err != nil {
130 t.Fatalf("json.Unmarshal() error = %v", err)
131 }
132 if !resp.Success {
133 t.Fatal("success = false, want true")
134 }
135 if resp.RequestID != "req-4" {
136 t.Fatalf("requestId = %q, want %q", resp.RequestID, "req-4")
137 }
138 if string(resp.Data) != `{"status":"success"}` {
139 t.Fatalf("data = %s, want %s", resp.Data, `{"status":"success"}`)
140 }
141}
142
143func TestNormalizeBridgeShimResponse_WrapsTopLevelErrorWithoutData(t *testing.T) {
144 t.Parallel()
145
146 got, err := normalizeBridgeShimResponse("req-error", []byte(`{"error":"bridge failed"}`))
147 if err != nil {
148 t.Fatalf("normalizeBridgeShimResponse() error = %v", err)
149 }
150
151 var resp bridgeResponse
152 if err := json.Unmarshal(got, &resp); err != nil {
153 t.Fatalf("json.Unmarshal() error = %v", err)
154 }
155 if resp.RequestID != "req-error" {
156 t.Fatalf("requestId = %q, want %q", resp.RequestID, "req-error")
157 }
158 if resp.Error != "bridge failed" {
159 t.Fatalf("error = %q, want %q", resp.Error, "bridge failed")
160 }
161}
162
163func TestNormalizeBridgeShimResponse_RejectsMalformedJSON(t *testing.T) {
164 t.Parallel()
165
166 if _, err := normalizeBridgeShimResponse("req-bad", []byte(`{"data":`)); err == nil {
167 t.Fatal("normalizeBridgeShimResponse() error = nil, want error")
168 }
169}
170
171func TestNormalizeBridgeShimResponse_RejectsMissingData(t *testing.T) {
172 t.Parallel()
173
174 if _, err := normalizeBridgeShimResponse("req-missing", []byte(`{"_callback":"__dumber_config_saved"}`)); err == nil {
175 t.Fatal("normalizeBridgeShimResponse() error = nil, want error")
176 }
177}
178
179func TestNormalizeBridgeShimResponse_RejectsEmptyBody(t *testing.T) {
180 t.Parallel()
181
182 if _, err := normalizeBridgeShimResponse("req-empty", nil); err == nil {
183 t.Fatal("normalizeBridgeShimResponse() error = nil, want error")
184 }
185}
186
187func TestWrapDirectAPIResponse_PreservesPayload(t *testing.T) {
188 t.Parallel()
189
190 got, err := wrapDirectAPIResponse("req-5", []byte(`{"engine_type":"webkit"}`))
191 if err != nil {
192 t.Fatalf("wrapDirectAPIResponse() error = %v", err)
193 }
194
195 var resp bridgeResponse
196 if err := json.Unmarshal(got, &resp); err != nil {
197 t.Fatalf("json.Unmarshal() error = %v", err)
198 }
199 if !resp.Success {
200 t.Fatal("success = false, want true")
201 }
202 if resp.RequestID != "req-5" {
203 t.Fatalf("requestId = %q, want %q", resp.RequestID, "req-5")
204 }
205 if string(resp.Data) != `{"engine_type":"webkit"}` {
206 t.Fatalf("data = %s, want %s", resp.Data, `{"engine_type":"webkit"}`)
207 }
208}