github.com/neilgarb/delve@v1.9.2-nobreaks/service/dap/daptest/client.go (about) 1 // Package daptest provides a sample client with utilities 2 // for DAP mode testing. 3 package daptest 4 5 //go:generate go run ./gen/main.go -o ./resp.go 6 7 import ( 8 "bufio" 9 "encoding/json" 10 "fmt" 11 "log" 12 "net" 13 "path/filepath" 14 "reflect" 15 "regexp" 16 "testing" 17 18 "github.com/google/go-dap" 19 ) 20 21 // Client is a debugger service client that uses Debug Adaptor Protocol. 22 // It does not (yet?) implement service.Client interface. 23 // All client methods are synchronous. 24 type Client struct { 25 conn net.Conn 26 reader *bufio.Reader 27 // seq is used to track the sequence number of each 28 // requests that the client sends to the server 29 seq int 30 } 31 32 // NewClient creates a new Client over a TCP connection. 33 // Call Close() to close the connection. 34 func NewClient(addr string) *Client { 35 fmt.Println("Connecting to server at:", addr) 36 conn, err := net.Dial("tcp", addr) 37 if err != nil { 38 log.Fatal("dialing:", err) 39 } 40 return NewClientFromConn(conn) 41 } 42 43 // NewClientFromConn creates a new Client with the given TCP connection. 44 // Call Close to close the connection. 45 func NewClientFromConn(conn net.Conn) *Client { 46 c := &Client{conn: conn, reader: bufio.NewReader(conn)} 47 c.seq = 1 // match VS Code numbering 48 return c 49 } 50 51 // Close closes the client connection. 52 func (c *Client) Close() { 53 c.conn.Close() 54 } 55 56 func (c *Client) send(request dap.Message) { 57 dap.WriteProtocolMessage(c.conn, request) 58 } 59 60 func (c *Client) ReadMessage() (dap.Message, error) { 61 return dap.ReadProtocolMessage(c.reader) 62 } 63 64 func (c *Client) ExpectMessage(t *testing.T) dap.Message { 65 t.Helper() 66 m, err := dap.ReadProtocolMessage(c.reader) 67 if err != nil { 68 t.Fatal(err) 69 } 70 return m 71 } 72 73 func (c *Client) ExpectInvisibleErrorResponse(t *testing.T) *dap.ErrorResponse { 74 t.Helper() 75 er := c.ExpectErrorResponse(t) 76 if er.Body.Error.ShowUser { 77 t.Errorf("\ngot %#v\nwant ShowUser=false", er) 78 } 79 return er 80 } 81 82 func (c *Client) ExpectVisibleErrorResponse(t *testing.T) *dap.ErrorResponse { 83 t.Helper() 84 er := c.ExpectErrorResponse(t) 85 if !er.Body.Error.ShowUser { 86 t.Errorf("\ngot %#v\nwant ShowUser=true", er) 87 } 88 return er 89 } 90 91 func (c *Client) ExpectErrorResponseWith(t *testing.T, id int, message string, showUser bool) *dap.ErrorResponse { 92 t.Helper() 93 er := c.ExpectErrorResponse(t) 94 if matched, _ := regexp.MatchString(message, er.Body.Error.Format); !matched || er.Body.Error.Id != id || er.Body.Error.ShowUser != showUser { 95 t.Errorf("got %#v, want Id=%d Format=%q ShowUser=%v", er, id, message, showUser) 96 } 97 return er 98 } 99 100 func (c *Client) ExpectInitializeResponseAndCapabilities(t *testing.T) *dap.InitializeResponse { 101 t.Helper() 102 initResp := c.ExpectInitializeResponse(t) 103 wantCapabilities := dap.Capabilities{ 104 // the values set by dap.(*Server).onInitializeRequest. 105 SupportsConfigurationDoneRequest: true, 106 SupportsConditionalBreakpoints: true, 107 SupportsDelayedStackTraceLoading: true, 108 SupportsExceptionInfoRequest: true, 109 SupportsSetVariable: true, 110 SupportsFunctionBreakpoints: true, 111 SupportsInstructionBreakpoints: true, 112 SupportsEvaluateForHovers: true, 113 SupportsClipboardContext: true, 114 SupportsSteppingGranularity: true, 115 SupportsLogPoints: true, 116 SupportsDisassembleRequest: true, 117 } 118 if !reflect.DeepEqual(initResp.Body, wantCapabilities) { 119 t.Errorf("capabilities in initializeResponse: got %+v, want %v", pretty(initResp.Body), pretty(wantCapabilities)) 120 } 121 return initResp 122 } 123 124 func pretty(v interface{}) string { 125 s, _ := json.MarshalIndent(v, "", "\t") 126 return string(s) 127 } 128 129 func (c *Client) ExpectNotYetImplementedErrorResponse(t *testing.T) *dap.ErrorResponse { 130 t.Helper() 131 return c.ExpectErrorResponseWith(t, 7777, "Not yet implemented", false) 132 } 133 134 func (c *Client) ExpectUnsupportedCommandErrorResponse(t *testing.T) *dap.ErrorResponse { 135 t.Helper() 136 return c.ExpectErrorResponseWith(t, 9999, "Unsupported command", false) 137 } 138 139 func (c *Client) ExpectCapabilitiesEventSupportTerminateDebuggee(t *testing.T) *dap.CapabilitiesEvent { 140 t.Helper() 141 e := c.ExpectCapabilitiesEvent(t) 142 if !e.Body.Capabilities.SupportTerminateDebuggee { 143 t.Errorf("\ngot %#v\nwant SupportTerminateDebuggee=true", e.Body.Capabilities.SupportTerminateDebuggee) 144 } 145 return e 146 } 147 148 func (c *Client) ExpectOutputEventRegex(t *testing.T, want string) *dap.OutputEvent { 149 t.Helper() 150 e := c.ExpectOutputEvent(t) 151 if matched, _ := regexp.MatchString(want, e.Body.Output); !matched { 152 t.Errorf("\ngot %#v\nwant Output=%q", e, want) 153 } 154 return e 155 } 156 157 const ProcessExited = `Process [0-9]+ has exited with status %s\n` 158 159 func (c *Client) ExpectOutputEventProcessExited(t *testing.T, status int) *dap.OutputEvent { 160 t.Helper() 161 // We sometimes fail to return the correct exit status on Linux, so allow -1 here as well. 162 return c.ExpectOutputEventRegex(t, fmt.Sprintf(ProcessExited, fmt.Sprintf("(%d|-1)", status))) 163 } 164 165 func (c *Client) ExpectOutputEventProcessExitedAnyStatus(t *testing.T) *dap.OutputEvent { 166 t.Helper() 167 return c.ExpectOutputEventRegex(t, fmt.Sprintf(ProcessExited, `-?\d+`)) 168 } 169 170 func (c *Client) ExpectOutputEventDetaching(t *testing.T) *dap.OutputEvent { 171 t.Helper() 172 return c.ExpectOutputEventRegex(t, `Detaching\n`) 173 } 174 175 func (c *Client) ExpectOutputEventDetachingKill(t *testing.T) *dap.OutputEvent { 176 t.Helper() 177 return c.ExpectOutputEventRegex(t, `Detaching and terminating target process\n`) 178 } 179 180 func (c *Client) ExpectOutputEventDetachingNoKill(t *testing.T) *dap.OutputEvent { 181 t.Helper() 182 return c.ExpectOutputEventRegex(t, `Detaching without terminating target process\n`) 183 } 184 185 func (c *Client) ExpectOutputEventTerminating(t *testing.T) *dap.OutputEvent { 186 t.Helper() 187 return c.ExpectOutputEventRegex(t, `Terminating process [0-9]+\n`) 188 } 189 190 const ClosingClient = "Closing client session, but leaving multi-client DAP server at .+:[0-9]+ with debuggee %s\n" 191 192 func (c *Client) ExpectOutputEventClosingClient(t *testing.T, status string) *dap.OutputEvent { 193 t.Helper() 194 return c.ExpectOutputEventRegex(t, fmt.Sprintf(ClosingClient, status)) 195 } 196 197 func (c *Client) CheckStopLocation(t *testing.T, thread int, name string, line int) { 198 t.Helper() 199 c.StackTraceRequest(thread, 0, 20) 200 st := c.ExpectStackTraceResponse(t) 201 if len(st.Body.StackFrames) < 1 { 202 t.Errorf("\ngot %#v\nwant len(stackframes) => 1", st) 203 } else { 204 if line != -1 && st.Body.StackFrames[0].Line != line { 205 t.Errorf("\ngot %#v\nwant Line=%d", st, line) 206 } 207 if st.Body.StackFrames[0].Name != name { 208 t.Errorf("\ngot %#v\nwant Name=%q", st, name) 209 } 210 } 211 } 212 213 // InitializeRequest sends an 'initialize' request. 214 func (c *Client) InitializeRequest() { 215 request := &dap.InitializeRequest{Request: *c.newRequest("initialize")} 216 request.Arguments = dap.InitializeRequestArguments{ 217 AdapterID: "go", 218 PathFormat: "path", 219 LinesStartAt1: true, 220 ColumnsStartAt1: true, 221 SupportsVariableType: true, 222 SupportsVariablePaging: true, 223 SupportsRunInTerminalRequest: true, 224 Locale: "en-us", 225 } 226 c.send(request) 227 } 228 229 // InitializeRequestWithArgs sends an 'initialize' request with specified arguments. 230 func (c *Client) InitializeRequestWithArgs(args dap.InitializeRequestArguments) { 231 request := &dap.InitializeRequest{Request: *c.newRequest("initialize")} 232 request.Arguments = args 233 c.send(request) 234 } 235 236 func toRawMessage(in interface{}) json.RawMessage { 237 out, _ := json.Marshal(in) 238 return out 239 } 240 241 // LaunchRequest sends a 'launch' request with the specified args. 242 func (c *Client) LaunchRequest(mode, program string, stopOnEntry bool) { 243 request := &dap.LaunchRequest{Request: *c.newRequest("launch")} 244 request.Arguments = toRawMessage(map[string]interface{}{ 245 "request": "launch", 246 "mode": mode, 247 "program": program, 248 "stopOnEntry": stopOnEntry, 249 }) 250 c.send(request) 251 } 252 253 // LaunchRequestWithArgs takes a map of untyped implementation-specific 254 // arguments to send a 'launch' request. This version can be used to 255 // test for values of unexpected types or unspecified values. 256 func (c *Client) LaunchRequestWithArgs(arguments map[string]interface{}) { 257 request := &dap.LaunchRequest{Request: *c.newRequest("launch")} 258 request.Arguments = toRawMessage(arguments) 259 c.send(request) 260 } 261 262 // AttachRequest sends an 'attach' request with the specified 263 // arguments. 264 func (c *Client) AttachRequest(arguments map[string]interface{}) { 265 request := &dap.AttachRequest{Request: *c.newRequest("attach")} 266 request.Arguments = toRawMessage(arguments) 267 c.send(request) 268 } 269 270 // DisconnectRequest sends a 'disconnect' request. 271 func (c *Client) DisconnectRequest() { 272 request := &dap.DisconnectRequest{Request: *c.newRequest("disconnect")} 273 c.send(request) 274 } 275 276 // DisconnectRequestWithKillOption sends a 'disconnect' request with an option to specify 277 // `terminateDebuggee`. 278 func (c *Client) DisconnectRequestWithKillOption(kill bool) { 279 request := &dap.DisconnectRequest{Request: *c.newRequest("disconnect")} 280 request.Arguments.TerminateDebuggee = kill 281 c.send(request) 282 } 283 284 // SetBreakpointsRequest sends a 'setBreakpoints' request. 285 func (c *Client) SetBreakpointsRequest(file string, lines []int) { 286 c.SetBreakpointsRequestWithArgs(file, lines, nil, nil, nil) 287 } 288 289 // SetBreakpointsRequestWithArgs sends a 'setBreakpoints' request with an option to 290 // specify conditions, hit conditions, and log messages. 291 func (c *Client) SetBreakpointsRequestWithArgs(file string, lines []int, conditions, hitConditions, logMessages map[int]string) { 292 request := &dap.SetBreakpointsRequest{Request: *c.newRequest("setBreakpoints")} 293 request.Arguments = dap.SetBreakpointsArguments{ 294 Source: dap.Source{ 295 Name: filepath.Base(file), 296 Path: file, 297 }, 298 Breakpoints: make([]dap.SourceBreakpoint, len(lines)), 299 } 300 for i, l := range lines { 301 request.Arguments.Breakpoints[i].Line = l 302 if cond, ok := conditions[l]; ok { 303 request.Arguments.Breakpoints[i].Condition = cond 304 } 305 if hitCond, ok := hitConditions[l]; ok { 306 request.Arguments.Breakpoints[i].HitCondition = hitCond 307 } 308 if logMessage, ok := logMessages[l]; ok { 309 request.Arguments.Breakpoints[i].LogMessage = logMessage 310 } 311 } 312 c.send(request) 313 } 314 315 // SetExceptionBreakpointsRequest sends a 'setExceptionBreakpoints' request. 316 func (c *Client) SetExceptionBreakpointsRequest() { 317 request := &dap.SetBreakpointsRequest{Request: *c.newRequest("setExceptionBreakpoints")} 318 c.send(request) 319 } 320 321 // ConfigurationDoneRequest sends a 'configurationDone' request. 322 func (c *Client) ConfigurationDoneRequest() { 323 request := &dap.ConfigurationDoneRequest{Request: *c.newRequest("configurationDone")} 324 c.send(request) 325 } 326 327 // ContinueRequest sends a 'continue' request. 328 func (c *Client) ContinueRequest(thread int) { 329 request := &dap.ContinueRequest{Request: *c.newRequest("continue")} 330 request.Arguments.ThreadId = thread 331 c.send(request) 332 } 333 334 // NextRequest sends a 'next' request. 335 func (c *Client) NextRequest(thread int) { 336 request := &dap.NextRequest{Request: *c.newRequest("next")} 337 request.Arguments.ThreadId = thread 338 c.send(request) 339 } 340 341 // NextInstructionRequest sends a 'next' request with granularity 'instruction'. 342 func (c *Client) NextInstructionRequest(thread int) { 343 request := &dap.NextRequest{Request: *c.newRequest("next")} 344 request.Arguments.ThreadId = thread 345 request.Arguments.Granularity = "instruction" 346 c.send(request) 347 } 348 349 // StepInRequest sends a 'stepIn' request. 350 func (c *Client) StepInRequest(thread int) { 351 request := &dap.StepInRequest{Request: *c.newRequest("stepIn")} 352 request.Arguments.ThreadId = thread 353 c.send(request) 354 } 355 356 // StepInInstructionRequest sends a 'stepIn' request with granularity 'instruction'. 357 func (c *Client) StepInInstructionRequest(thread int) { 358 request := &dap.StepInRequest{Request: *c.newRequest("stepIn")} 359 request.Arguments.ThreadId = thread 360 request.Arguments.Granularity = "instruction" 361 c.send(request) 362 } 363 364 // StepOutRequest sends a 'stepOut' request. 365 func (c *Client) StepOutRequest(thread int) { 366 request := &dap.StepOutRequest{Request: *c.newRequest("stepOut")} 367 request.Arguments.ThreadId = thread 368 c.send(request) 369 } 370 371 // StepOutInstructionRequest sends a 'stepOut' request with granularity 'instruction'. 372 func (c *Client) StepOutInstructionRequest(thread int) { 373 request := &dap.StepOutRequest{Request: *c.newRequest("stepOut")} 374 request.Arguments.ThreadId = thread 375 request.Arguments.Granularity = "instruction" 376 c.send(request) 377 } 378 379 // PauseRequest sends a 'pause' request. 380 func (c *Client) PauseRequest(threadId int) { 381 request := &dap.PauseRequest{Request: *c.newRequest("pause")} 382 request.Arguments.ThreadId = threadId 383 c.send(request) 384 } 385 386 // ThreadsRequest sends a 'threads' request. 387 func (c *Client) ThreadsRequest() { 388 request := &dap.ThreadsRequest{Request: *c.newRequest("threads")} 389 c.send(request) 390 } 391 392 // StackTraceRequest sends a 'stackTrace' request. 393 func (c *Client) StackTraceRequest(threadID, startFrame, levels int) { 394 request := &dap.StackTraceRequest{Request: *c.newRequest("stackTrace")} 395 request.Arguments.ThreadId = threadID 396 request.Arguments.StartFrame = startFrame 397 request.Arguments.Levels = levels 398 c.send(request) 399 } 400 401 // ScopesRequest sends a 'scopes' request. 402 func (c *Client) ScopesRequest(frameID int) { 403 request := &dap.ScopesRequest{Request: *c.newRequest("scopes")} 404 request.Arguments.FrameId = frameID 405 c.send(request) 406 } 407 408 // VariablesRequest sends a 'variables' request. 409 func (c *Client) VariablesRequest(variablesReference int) { 410 request := &dap.VariablesRequest{Request: *c.newRequest("variables")} 411 request.Arguments.VariablesReference = variablesReference 412 c.send(request) 413 } 414 415 // IndexedVariablesRequest sends a 'variables' request. 416 func (c *Client) IndexedVariablesRequest(variablesReference, start, count int) { 417 request := &dap.VariablesRequest{Request: *c.newRequest("variables")} 418 request.Arguments.VariablesReference = variablesReference 419 request.Arguments.Filter = "indexed" 420 request.Arguments.Start = start 421 request.Arguments.Count = count 422 c.send(request) 423 } 424 425 // NamedVariablesRequest sends a 'variables' request. 426 func (c *Client) NamedVariablesRequest(variablesReference int) { 427 request := &dap.VariablesRequest{Request: *c.newRequest("variables")} 428 request.Arguments.VariablesReference = variablesReference 429 request.Arguments.Filter = "named" 430 c.send(request) 431 } 432 433 // TerminateRequest sends a 'terminate' request. 434 func (c *Client) TerminateRequest() { 435 c.send(&dap.TerminateRequest{Request: *c.newRequest("terminate")}) 436 } 437 438 // RestartRequest sends a 'restart' request. 439 func (c *Client) RestartRequest() { 440 c.send(&dap.RestartRequest{Request: *c.newRequest("restart")}) 441 } 442 443 // SetFunctionBreakpointsRequest sends a 'setFunctionBreakpoints' request. 444 func (c *Client) SetFunctionBreakpointsRequest(breakpoints []dap.FunctionBreakpoint) { 445 c.send(&dap.SetFunctionBreakpointsRequest{ 446 Request: *c.newRequest("setFunctionBreakpoints"), 447 Arguments: dap.SetFunctionBreakpointsArguments{ 448 Breakpoints: breakpoints, 449 }, 450 }) 451 } 452 453 // SetInstructionBreakpointsRequest sends a 'setInstructionBreakpoints' request. 454 func (c *Client) SetInstructionBreakpointsRequest(breakpoints []dap.InstructionBreakpoint) { 455 c.send(&dap.SetInstructionBreakpointsRequest{ 456 Request: *c.newRequest("setInstructionBreakpoints"), 457 Arguments: dap.SetInstructionBreakpointsArguments{ 458 Breakpoints: breakpoints, 459 }, 460 }) 461 } 462 463 // StepBackRequest sends a 'stepBack' request. 464 func (c *Client) StepBackRequest() { 465 c.send(&dap.StepBackRequest{Request: *c.newRequest("stepBack")}) 466 } 467 468 // ReverseContinueRequest sends a 'reverseContinue' request. 469 func (c *Client) ReverseContinueRequest() { 470 c.send(&dap.ReverseContinueRequest{Request: *c.newRequest("reverseContinue")}) 471 } 472 473 // SetVariableRequest sends a 'setVariable' request. 474 func (c *Client) SetVariableRequest(variablesRef int, name, value string) { 475 request := &dap.SetVariableRequest{Request: *c.newRequest("setVariable")} 476 request.Arguments.VariablesReference = variablesRef 477 request.Arguments.Name = name 478 request.Arguments.Value = value 479 c.send(request) 480 } 481 482 // RestartFrameRequest sends a 'restartFrame' request. 483 func (c *Client) RestartFrameRequest() { 484 c.send(&dap.RestartFrameRequest{Request: *c.newRequest("restartFrame")}) 485 } 486 487 // GotoRequest sends a 'goto' request. 488 func (c *Client) GotoRequest() { 489 c.send(&dap.GotoRequest{Request: *c.newRequest("goto")}) 490 } 491 492 // SetExpressionRequest sends a 'setExpression' request. 493 func (c *Client) SetExpressionRequest() { 494 c.send(&dap.SetExpressionRequest{Request: *c.newRequest("setExpression")}) 495 } 496 497 // SourceRequest sends a 'source' request. 498 func (c *Client) SourceRequest() { 499 c.send(&dap.SourceRequest{Request: *c.newRequest("source")}) 500 } 501 502 // TerminateThreadsRequest sends a 'terminateThreads' request. 503 func (c *Client) TerminateThreadsRequest() { 504 c.send(&dap.TerminateThreadsRequest{Request: *c.newRequest("terminateThreads")}) 505 } 506 507 // EvaluateRequest sends a 'evaluate' request. 508 func (c *Client) EvaluateRequest(expr string, fid int, context string) { 509 request := &dap.EvaluateRequest{Request: *c.newRequest("evaluate")} 510 request.Arguments.Expression = expr 511 request.Arguments.FrameId = fid 512 request.Arguments.Context = context 513 c.send(request) 514 } 515 516 // StepInTargetsRequest sends a 'stepInTargets' request. 517 func (c *Client) StepInTargetsRequest() { 518 c.send(&dap.StepInTargetsRequest{Request: *c.newRequest("stepInTargets")}) 519 } 520 521 // GotoTargetsRequest sends a 'gotoTargets' request. 522 func (c *Client) GotoTargetsRequest() { 523 c.send(&dap.GotoTargetsRequest{Request: *c.newRequest("gotoTargets")}) 524 } 525 526 // CompletionsRequest sends a 'completions' request. 527 func (c *Client) CompletionsRequest() { 528 c.send(&dap.CompletionsRequest{Request: *c.newRequest("completions")}) 529 } 530 531 // ExceptionInfoRequest sends a 'exceptionInfo' request. 532 func (c *Client) ExceptionInfoRequest(threadID int) { 533 request := &dap.ExceptionInfoRequest{Request: *c.newRequest("exceptionInfo")} 534 request.Arguments.ThreadId = threadID 535 c.send(request) 536 } 537 538 // LoadedSourcesRequest sends a 'loadedSources' request. 539 func (c *Client) LoadedSourcesRequest() { 540 c.send(&dap.LoadedSourcesRequest{Request: *c.newRequest("loadedSources")}) 541 } 542 543 // DataBreakpointInfoRequest sends a 'dataBreakpointInfo' request. 544 func (c *Client) DataBreakpointInfoRequest() { 545 c.send(&dap.DataBreakpointInfoRequest{Request: *c.newRequest("dataBreakpointInfo")}) 546 } 547 548 // SetDataBreakpointsRequest sends a 'setDataBreakpoints' request. 549 func (c *Client) SetDataBreakpointsRequest() { 550 c.send(&dap.SetDataBreakpointsRequest{Request: *c.newRequest("setDataBreakpoints")}) 551 } 552 553 // ReadMemoryRequest sends a 'readMemory' request. 554 func (c *Client) ReadMemoryRequest() { 555 c.send(&dap.ReadMemoryRequest{Request: *c.newRequest("readMemory")}) 556 } 557 558 // DisassembleRequest sends a 'disassemble' request. 559 func (c *Client) DisassembleRequest(memoryReference string, instructionOffset, inctructionCount int) { 560 c.send(&dap.DisassembleRequest{ 561 Request: *c.newRequest("disassemble"), 562 Arguments: dap.DisassembleArguments{ 563 MemoryReference: memoryReference, 564 Offset: 0, 565 InstructionOffset: instructionOffset, 566 InstructionCount: inctructionCount, 567 ResolveSymbols: false, 568 }, 569 }) 570 } 571 572 // CancelRequest sends a 'cancel' request. 573 func (c *Client) CancelRequest() { 574 c.send(&dap.CancelRequest{Request: *c.newRequest("cancel")}) 575 } 576 577 // BreakpointLocationsRequest sends a 'breakpointLocations' request. 578 func (c *Client) BreakpointLocationsRequest() { 579 c.send(&dap.BreakpointLocationsRequest{Request: *c.newRequest("breakpointLocations")}) 580 } 581 582 // ModulesRequest sends a 'modules' request. 583 func (c *Client) ModulesRequest() { 584 c.send(&dap.ModulesRequest{Request: *c.newRequest("modules")}) 585 } 586 587 // UnknownRequest triggers dap.DecodeProtocolMessageFieldError. 588 func (c *Client) UnknownRequest() { 589 request := c.newRequest("unknown") 590 c.send(request) 591 } 592 593 // UnknownEvent triggers dap.DecodeProtocolMessageFieldError. 594 func (c *Client) UnknownEvent() { 595 event := &dap.Event{} 596 event.Type = "event" 597 event.Seq = -1 598 event.Event = "unknown" 599 c.send(event) 600 } 601 602 // BadRequest triggers an unmarshal error. 603 func (c *Client) BadRequest() { 604 content := []byte("{malformedString}") 605 contentLengthHeaderFmt := "Content-Length: %d\r\n\r\n" 606 header := fmt.Sprintf(contentLengthHeaderFmt, len(content)) 607 c.conn.Write([]byte(header)) 608 c.conn.Write(content) 609 } 610 611 // KnownEvent passes decode checks, but delve has no 'case' to 612 // handle it. This behaves the same way a new request type 613 // added to go-dap, but not to delve. 614 func (c *Client) KnownEvent() { 615 event := &dap.Event{} 616 event.Type = "event" 617 event.Seq = -1 618 event.Event = "terminated" 619 c.send(event) 620 } 621 622 func (c *Client) newRequest(command string) *dap.Request { 623 request := &dap.Request{} 624 request.Type = "request" 625 request.Command = command 626 request.Seq = c.seq 627 c.seq++ 628 return request 629 }