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