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  }