wip, rework bridge

This commit is contained in:
2026-07-13 18:33:39 +02:00
parent 265dbe2580
commit 86039811ce
6 changed files with 1137 additions and 308 deletions

View File

@@ -0,0 +1,214 @@
package bridge
import (
"encoding/json"
"strings"
"testing"
)
func messageID(id uint64) *uint64 {
return &id
}
func TestMessageValidate(t *testing.T) {
tests := []struct {
name string
message Message
wantErr string
}{
{
name: "request",
message: Message{
Version: ProtocolVersion,
Type: Request,
RequestId: messageID(1),
Name: "locals/get",
},
},
{
name: "successful response",
message: Message{
Version: ProtocolVersion,
Type: Response,
RequestId: messageID(1),
Name: "locals/get",
Body: json.RawMessage(`{"variables":{}}`),
},
},
{
name: "error response",
message: Message{
Version: ProtocolVersion,
Type: Response,
RequestId: messageID(1),
Name: "locals/get",
Error: &ProtocolError{
Code: "not_paused",
Message: "execution is not paused",
},
},
},
{
name: "event",
message: Message{
Version: ProtocolVersion,
Type: Event,
Name: "execution/stopped",
Body: json.RawMessage(`{"reason":"step","file":"test.py","line":1}`),
},
},
{
name: "unsupported version",
message: Message{
Version: ProtocolVersion + 1,
Type: Request,
RequestId: messageID(1),
Name: "locals/get",
},
wantErr: "unsupported protocol version",
},
{
name: "missing name",
message: Message{
Version: ProtocolVersion,
Type: Request,
RequestId: messageID(1),
},
wantErr: "message name is required",
},
{
name: "request without ID",
message: Message{
Version: ProtocolVersion,
Type: Request,
Name: "locals/get",
},
wantErr: "request ID is required",
},
{
name: "request with error",
message: Message{
Version: ProtocolVersion,
Type: Request,
RequestId: messageID(1),
Name: "locals/get",
Error: &ProtocolError{Code: "invalid"},
},
wantErr: "request cannot contain an error",
},
{
name: "response without ID",
message: Message{
Version: ProtocolVersion,
Type: Response,
Name: "locals/get",
},
wantErr: "response ID is required",
},
{
name: "response with body and error",
message: Message{
Version: ProtocolVersion,
Type: Response,
RequestId: messageID(1),
Name: "locals/get",
Body: json.RawMessage(`{}`),
Error: &ProtocolError{Code: "invalid"},
},
wantErr: "response cannot contain both body and error",
},
{
name: "event with ID",
message: Message{
Version: ProtocolVersion,
Type: Event,
RequestId: messageID(1),
Name: "execution/stopped",
},
wantErr: "event cannot contain a request ID",
},
{
name: "event with error",
message: Message{
Version: ProtocolVersion,
Type: Event,
Name: "execution/stopped",
Error: &ProtocolError{Code: "invalid"},
},
wantErr: "event cannot contain an error",
},
{
name: "unknown type",
message: Message{
Version: ProtocolVersion,
Type: MessageType("notification"),
RequestId: messageID(1),
Name: "locals/get",
},
wantErr: "unknown message type",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.message.Validate()
if tt.wantErr == "" {
if err != nil {
t.Fatalf("Validate() error = %v", err)
}
return
}
if err == nil {
t.Fatalf("Validate() error = nil, want error containing %q", tt.wantErr)
}
if !strings.Contains(err.Error(), tt.wantErr) {
t.Fatalf("Validate() error = %q, want error containing %q", err, tt.wantErr)
}
})
}
}
func TestNewMessageEncodesTypedBody(t *testing.T) {
id := uint64(7)
msg, err := newMessage(Request, &id, "breakpoint/set", SetBreakpointRequest{
File: "example.py",
Line: 42,
})
if err != nil {
t.Fatalf("newMessage() error = %v", err)
}
if err := msg.Validate(); err != nil {
t.Fatalf("Validate() error = %v", err)
}
var body SetBreakpointRequest
if err := json.Unmarshal(msg.Body, &body); err != nil {
t.Fatalf("unmarshal body: %v", err)
}
if body.File != "example.py" || body.Line != 42 {
t.Fatalf("decoded body = %+v", body)
}
}
func TestProtocolErrorString(t *testing.T) {
tests := []struct {
name string
err *ProtocolError
want string
}{
{name: "code and message", err: &ProtocolError{Code: "not_paused", Message: "execution is not paused"}, want: "not_paused: execution is not paused"},
{name: "message only", err: &ProtocolError{Message: "execution is not paused"}, want: "execution is not paused"},
{name: "nil", err: nil, want: ""},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.err.Error(); got != tt.want {
t.Fatalf("Error() = %q, want %q", got, tt.want)
}
})
}
}