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  }