github.com/undoio/delve@v1.9.0/service/dap/server_test.go (about)

     1  package dap
     2  
     3  import (
     4  	"bufio"
     5  	"flag"
     6  	"fmt"
     7  	"io"
     8  	"io/ioutil"
     9  	"math"
    10  	"math/rand"
    11  	"net"
    12  	"os"
    13  	"os/exec"
    14  	"path/filepath"
    15  	"reflect"
    16  	"regexp"
    17  	"runtime"
    18  	"strconv"
    19  	"strings"
    20  	"testing"
    21  	"time"
    22  
    23  	"github.com/undoio/delve/pkg/goversion"
    24  	"github.com/undoio/delve/pkg/logflags"
    25  	"github.com/undoio/delve/pkg/proc"
    26  	protest "github.com/undoio/delve/pkg/proc/test"
    27  	"github.com/undoio/delve/service"
    28  	"github.com/undoio/delve/service/api"
    29  	"github.com/undoio/delve/service/dap/daptest"
    30  	"github.com/undoio/delve/service/debugger"
    31  	"github.com/google/go-dap"
    32  )
    33  
    34  const stopOnEntry bool = true
    35  const hasChildren bool = true
    36  const noChildren bool = false
    37  
    38  const localsScope = 1000
    39  const globalsScope = 1001
    40  
    41  var testBackend string
    42  
    43  func TestMain(m *testing.M) {
    44  	logOutputVal := ""
    45  	if _, isTeamCityTest := os.LookupEnv("TEAMCITY_VERSION"); isTeamCityTest {
    46  		logOutputVal = "debugger,dap"
    47  	}
    48  	var logOutput string
    49  	flag.StringVar(&logOutput, "log-output", logOutputVal, "configures log output")
    50  	flag.Parse()
    51  	logflags.Setup(logOutput != "", logOutput, "")
    52  	protest.DefaultTestBackend(&testBackend)
    53  	os.Exit(protest.RunTestsWithFixtures(m))
    54  }
    55  
    56  // name is for _fixtures/<name>.go
    57  func runTest(t *testing.T, name string, test func(c *daptest.Client, f protest.Fixture)) {
    58  	runTestBuildFlags(t, name, test, protest.AllNonOptimized)
    59  }
    60  
    61  // name is for _fixtures/<name>.go
    62  func runTestBuildFlags(t *testing.T, name string, test func(c *daptest.Client, f protest.Fixture), buildFlags protest.BuildFlags) {
    63  	fixture := protest.BuildFixture(name, buildFlags)
    64  
    65  	// Start the DAP server.
    66  	serverStopped := make(chan struct{})
    67  	client := startDAPServerWithClient(t, serverStopped)
    68  	defer client.Close()
    69  
    70  	test(client, fixture)
    71  	<-serverStopped
    72  }
    73  
    74  func startDAPServerWithClient(t *testing.T, serverStopped chan struct{}) *daptest.Client {
    75  	server, _ := startDAPServer(t, serverStopped)
    76  	client := daptest.NewClient(server.config.Listener.Addr().String())
    77  	return client
    78  }
    79  
    80  // Starts an empty server and a stripped down config just to establish a client connection.
    81  // To mock a server created by dap.NewServer(config) or serving dap.NewSession(conn, config, debugger)
    82  // set those arg fields manually after the server creation.
    83  func startDAPServer(t *testing.T, serverStopped chan struct{}) (server *Server, forceStop chan struct{}) {
    84  	// Start the DAP server.
    85  	listener, err := net.Listen("tcp", ":0")
    86  	if err != nil {
    87  		t.Fatal(err)
    88  	}
    89  	disconnectChan := make(chan struct{})
    90  	server = NewServer(&service.Config{
    91  		Listener:       listener,
    92  		DisconnectChan: disconnectChan,
    93  	})
    94  	server.Run()
    95  	// Give server time to start listening for clients
    96  	time.Sleep(100 * time.Millisecond)
    97  
    98  	// Run a goroutine that stops the server when disconnectChan is signaled.
    99  	// This helps us test that certain events cause the server to stop as
   100  	// expected.
   101  	forceStop = make(chan struct{})
   102  	go func() {
   103  		defer func() {
   104  			if serverStopped != nil {
   105  				close(serverStopped)
   106  			}
   107  		}()
   108  		select {
   109  		case <-disconnectChan:
   110  			t.Log("server stop triggered internally")
   111  		case <-forceStop:
   112  			t.Log("server stop triggered externally")
   113  		}
   114  		server.Stop()
   115  	}()
   116  
   117  	return server, forceStop
   118  }
   119  
   120  func verifyServerStopped(t *testing.T, server *Server) {
   121  	t.Helper()
   122  	if server.listener != nil {
   123  		if server.listener.Close() == nil {
   124  			t.Error("server should have closed listener after shutdown")
   125  		}
   126  	}
   127  	verifySessionStopped(t, server.session)
   128  }
   129  
   130  func verifySessionStopped(t *testing.T, session *Session) {
   131  	t.Helper()
   132  	if session == nil {
   133  		return
   134  	}
   135  	if session.conn == nil {
   136  		t.Error("session must always have a set connection")
   137  	}
   138  	verifyConnStopped(t, session.conn)
   139  	if session.debugger != nil {
   140  		t.Error("session should have no pointer to debugger after shutdown")
   141  	}
   142  	if session.binaryToRemove != "" {
   143  		t.Error("session should have no binary to remove after shutdown")
   144  	}
   145  }
   146  
   147  func verifyConnStopped(t *testing.T, conn io.ReadWriteCloser) {
   148  	t.Helper()
   149  	if conn.Close() == nil {
   150  		t.Error("client connection should be closed after shutdown")
   151  	}
   152  }
   153  
   154  func TestStopNoClient(t *testing.T) {
   155  	for name, triggerStop := range map[string]func(s *Server, forceStop chan struct{}){
   156  		"force":        func(s *Server, forceStop chan struct{}) { close(forceStop) },
   157  		"accept error": func(s *Server, forceStop chan struct{}) { s.config.Listener.Close() },
   158  	} {
   159  		t.Run(name, func(t *testing.T) {
   160  			serverStopped := make(chan struct{})
   161  			server, forceStop := startDAPServer(t, serverStopped)
   162  			triggerStop(server, forceStop)
   163  			<-serverStopped
   164  			verifyServerStopped(t, server)
   165  		})
   166  	}
   167  }
   168  
   169  func TestStopNoTarget(t *testing.T) {
   170  	for name, triggerStop := range map[string]func(c *daptest.Client, forceStop chan struct{}){
   171  		"force":      func(c *daptest.Client, forceStop chan struct{}) { close(forceStop) },
   172  		"read error": func(c *daptest.Client, forceStop chan struct{}) { c.Close() },
   173  		"disconnect": func(c *daptest.Client, forceStop chan struct{}) { c.DisconnectRequest() },
   174  	} {
   175  		t.Run(name, func(t *testing.T) {
   176  			serverStopped := make(chan struct{})
   177  			server, forceStop := startDAPServer(t, serverStopped)
   178  			client := daptest.NewClient(server.config.Listener.Addr().String())
   179  			defer client.Close()
   180  
   181  			client.InitializeRequest()
   182  			client.ExpectInitializeResponseAndCapabilities(t)
   183  			triggerStop(client, forceStop)
   184  			<-serverStopped
   185  			verifyServerStopped(t, server)
   186  		})
   187  	}
   188  }
   189  
   190  func TestStopWithTarget(t *testing.T) {
   191  	for name, triggerStop := range map[string]func(c *daptest.Client, forceStop chan struct{}){
   192  		"force":                  func(c *daptest.Client, forceStop chan struct{}) { close(forceStop) },
   193  		"read error":             func(c *daptest.Client, forceStop chan struct{}) { c.Close() },
   194  		"disconnect before exit": func(c *daptest.Client, forceStop chan struct{}) { c.DisconnectRequest() },
   195  		"disconnect after  exit": func(c *daptest.Client, forceStop chan struct{}) {
   196  			c.ContinueRequest(1)
   197  			c.ExpectContinueResponse(t)
   198  			c.ExpectTerminatedEvent(t)
   199  			c.DisconnectRequest()
   200  		},
   201  	} {
   202  		t.Run(name, func(t *testing.T) {
   203  			serverStopped := make(chan struct{})
   204  			server, forceStop := startDAPServer(t, serverStopped)
   205  			client := daptest.NewClient(server.config.Listener.Addr().String())
   206  			defer client.Close()
   207  
   208  			client.InitializeRequest()
   209  			client.ExpectInitializeResponseAndCapabilities(t)
   210  			fixture := protest.BuildFixture("increment", protest.AllNonOptimized)
   211  			client.LaunchRequest("debug", fixture.Source, stopOnEntry)
   212  			client.ExpectInitializedEvent(t)
   213  			client.ExpectLaunchResponse(t)
   214  			triggerStop(client, forceStop)
   215  			<-serverStopped
   216  			verifyServerStopped(t, server)
   217  		})
   218  	}
   219  }
   220  
   221  func TestSessionStop(t *testing.T) {
   222  	verifySessionState := func(t *testing.T, s *Session, binaryToRemoveSet bool, debuggerSet bool, disconnectChanSet bool) {
   223  		t.Helper()
   224  		if binaryToRemoveSet && s.binaryToRemove == "" || !binaryToRemoveSet && s.binaryToRemove != "" {
   225  			t.Errorf("binaryToRemove: got %s, want set=%v", s.binaryToRemove, binaryToRemoveSet)
   226  		}
   227  		if debuggerSet && s.debugger == nil || !debuggerSet && s.debugger != nil {
   228  			t.Errorf("debugger: got %v, want set=%v", s.debugger, debuggerSet)
   229  		}
   230  		if disconnectChanSet && s.config.DisconnectChan == nil || !disconnectChanSet && s.config.DisconnectChan != nil {
   231  			t.Errorf("disconnectChan: got %v, want set=%v", s.config.DisconnectChan, disconnectChanSet)
   232  		}
   233  	}
   234  	for name, stopSession := range map[string]func(s *Session, c *daptest.Client, serveDone chan struct{}){
   235  		"force": func(s *Session, c *daptest.Client, serveDone chan struct{}) {
   236  			s.Close()
   237  			<-serveDone
   238  			verifySessionState(t, s, false /*binaryToRemoveSet*/, false /*debuggerSet*/, false /*disconnectChanSet*/)
   239  		},
   240  		"read error": func(s *Session, c *daptest.Client, serveDone chan struct{}) {
   241  			c.Close()
   242  			<-serveDone
   243  			verifyConnStopped(t, s.conn)
   244  			verifySessionState(t, s, true /*binaryToRemoveSet*/, true /*debuggerSet*/, false /*disconnectChanSet*/)
   245  			s.Close()
   246  		},
   247  		"disconnect before exit": func(s *Session, c *daptest.Client, serveDone chan struct{}) {
   248  			c.DisconnectRequest()
   249  			<-serveDone
   250  			verifyConnStopped(t, s.conn)
   251  			verifySessionState(t, s, true /*binaryToRemoveSet*/, false /*debuggerSet*/, false /*disconnectChanSet*/)
   252  			s.Close()
   253  		},
   254  		"disconnect after exit": func(s *Session, c *daptest.Client, serveDone chan struct{}) {
   255  			c.ContinueRequest(1)
   256  			c.ExpectContinueResponse(t)
   257  			c.ExpectTerminatedEvent(t)
   258  			c.DisconnectRequest()
   259  			<-serveDone
   260  			verifyConnStopped(t, s.conn)
   261  			verifySessionState(t, s, true /*binaryToRemoveSet*/, false /*debuggerSet*/, false /*disconnectChanSet*/)
   262  			s.Close()
   263  		},
   264  	} {
   265  		t.Run(name, func(t *testing.T) {
   266  			listener, err := net.Listen("tcp", ":0")
   267  			if err != nil {
   268  				t.Fatalf("cannot setup listener required for testing: %v", err)
   269  			}
   270  			defer listener.Close()
   271  			acceptDone := make(chan struct{})
   272  			var conn net.Conn
   273  			go func() {
   274  				conn, err = listener.Accept()
   275  				close(acceptDone)
   276  			}()
   277  			time.Sleep(10 * time.Millisecond) // give time to start listening
   278  			client := daptest.NewClient(listener.Addr().String())
   279  			defer client.Close()
   280  			<-acceptDone
   281  			if err != nil {
   282  				t.Fatalf("cannot accept client requireed for testing: %v", err)
   283  			}
   284  			session := NewSession(conn, &Config{
   285  				Config:        &service.Config{DisconnectChan: make(chan struct{})},
   286  				StopTriggered: make(chan struct{})}, nil)
   287  			serveDAPCodecDone := make(chan struct{})
   288  			go func() {
   289  				session.ServeDAPCodec()
   290  				close(serveDAPCodecDone)
   291  			}()
   292  			time.Sleep(10 * time.Millisecond) // give time to start reading
   293  			client.InitializeRequest()
   294  			client.ExpectInitializeResponseAndCapabilities(t)
   295  			fixture := protest.BuildFixture("increment", protest.AllNonOptimized)
   296  			client.LaunchRequest("debug", fixture.Source, stopOnEntry)
   297  			client.ExpectInitializedEvent(t)
   298  			client.ExpectLaunchResponse(t)
   299  			stopSession(session, client, serveDAPCodecDone)
   300  			verifySessionStopped(t, session)
   301  		})
   302  	}
   303  }
   304  
   305  func TestForceStopWhileStopping(t *testing.T) {
   306  	serverStopped := make(chan struct{})
   307  	server, forceStop := startDAPServer(t, serverStopped)
   308  	client := daptest.NewClient(server.config.Listener.Addr().String())
   309  
   310  	client.InitializeRequest()
   311  	client.ExpectInitializeResponseAndCapabilities(t)
   312  	fixture := protest.BuildFixture("increment", protest.AllNonOptimized)
   313  	client.LaunchRequest("exec", fixture.Path, stopOnEntry)
   314  	client.ExpectInitializedEvent(t)
   315  	client.Close() // depending on timing may trigger Stop()
   316  	time.Sleep(time.Microsecond)
   317  	close(forceStop) // depending on timing may trigger Stop()
   318  	<-serverStopped
   319  	verifyServerStopped(t, server)
   320  }
   321  
   322  // TestLaunchStopOnEntry emulates the message exchange that can be observed with
   323  // VS Code for the most basic launch debug session with "stopOnEntry" enabled:
   324  //
   325  //	User selects "Start Debugging":  1 >> initialize
   326  //	                              :  1 << initialize
   327  //	                              :  2 >> launch
   328  //	                              :    << initialized event
   329  //	                              :  2 << launch
   330  //	                              :  3 >> setBreakpoints (empty)
   331  //	                              :  3 << setBreakpoints
   332  //	                              :  4 >> setExceptionBreakpoints (empty)
   333  //	                              :  4 << setExceptionBreakpoints
   334  //	                              :  5 >> configurationDone
   335  //	Program stops upon launching  :    << stopped event
   336  //	                              :  5 << configurationDone
   337  //	                              :  6 >> threads
   338  //	                              :  6 << threads (Dummy)
   339  //	                              :  7 >> threads
   340  //	                              :  7 << threads (Dummy)
   341  //	                              :  8 >> stackTrace
   342  //	                              :  8 << error (Unable to produce stack trace)
   343  //	                              :  9 >> stackTrace
   344  //	                              :  9 << error (Unable to produce stack trace)
   345  //	User evaluates bad expression : 10 >> evaluate
   346  //	                              : 10 << error (unable to find function context)
   347  //	User evaluates good expression: 11 >> evaluate
   348  //	                              : 11 << evaluate
   349  //	User selects "Continue"       : 12 >> continue
   350  //	                              : 12 << continue
   351  //	Program runs to completion    :    << terminated event
   352  //	                              : 13 >> disconnect
   353  //	                              :    << output event (Process exited)
   354  //	                              :    << output event (Detaching)
   355  //	                              : 13 << disconnect
   356  //
   357  // This test exhaustively tests Seq and RequestSeq on all messages from the
   358  // server. Other tests do not necessarily need to repeat all these checks.
   359  func TestLaunchStopOnEntry(t *testing.T) {
   360  	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) {
   361  		// 1 >> initialize, << initialize
   362  		client.InitializeRequest()
   363  		initResp := client.ExpectInitializeResponseAndCapabilities(t)
   364  		if initResp.Seq != 0 || initResp.RequestSeq != 1 {
   365  			t.Errorf("\ngot %#v\nwant Seq=0, RequestSeq=1", initResp)
   366  		}
   367  
   368  		// 2 >> launch, << initialized, << launch
   369  		client.LaunchRequest("exec", fixture.Path, stopOnEntry)
   370  		initEvent := client.ExpectInitializedEvent(t)
   371  		if initEvent.Seq != 0 {
   372  			t.Errorf("\ngot %#v\nwant Seq=0", initEvent)
   373  		}
   374  		launchResp := client.ExpectLaunchResponse(t)
   375  		if launchResp.Seq != 0 || launchResp.RequestSeq != 2 {
   376  			t.Errorf("\ngot %#v\nwant Seq=0, RequestSeq=2", launchResp)
   377  		}
   378  
   379  		// 3 >> setBreakpoints, << setBreakpoints
   380  		client.SetBreakpointsRequest(fixture.Source, nil)
   381  		sbpResp := client.ExpectSetBreakpointsResponse(t)
   382  		if sbpResp.Seq != 0 || sbpResp.RequestSeq != 3 || len(sbpResp.Body.Breakpoints) != 0 {
   383  			t.Errorf("\ngot %#v\nwant Seq=0, RequestSeq=3, len(Breakpoints)=0", sbpResp)
   384  		}
   385  
   386  		// 4 >> setExceptionBreakpoints, << setExceptionBreakpoints
   387  		client.SetExceptionBreakpointsRequest()
   388  		sebpResp := client.ExpectSetExceptionBreakpointsResponse(t)
   389  		if sebpResp.Seq != 0 || sebpResp.RequestSeq != 4 {
   390  			t.Errorf("\ngot %#v\nwant Seq=0, RequestSeq=4", sebpResp)
   391  		}
   392  
   393  		// 5 >> configurationDone, << stopped, << configurationDone
   394  		client.ConfigurationDoneRequest()
   395  		stopEvent := client.ExpectStoppedEvent(t)
   396  		if stopEvent.Seq != 0 ||
   397  			stopEvent.Body.Reason != "entry" ||
   398  			stopEvent.Body.ThreadId != 1 ||
   399  			!stopEvent.Body.AllThreadsStopped {
   400  			t.Errorf("\ngot %#v\nwant Seq=0, Body={Reason=\"entry\", ThreadId=1, AllThreadsStopped=true}", stopEvent)
   401  		}
   402  		cdResp := client.ExpectConfigurationDoneResponse(t)
   403  		if cdResp.Seq != 0 || cdResp.RequestSeq != 5 {
   404  			t.Errorf("\ngot %#v\nwant Seq=0, RequestSeq=5", cdResp)
   405  		}
   406  
   407  		// 6 >> threads, << threads
   408  		client.ThreadsRequest()
   409  		tResp := client.ExpectThreadsResponse(t)
   410  		if tResp.Seq != 0 || tResp.RequestSeq != 6 || len(tResp.Body.Threads) != 1 {
   411  			t.Errorf("\ngot %#v\nwant Seq=0, RequestSeq=6 len(Threads)=1", tResp)
   412  		}
   413  		if tResp.Body.Threads[0].Id != 1 || tResp.Body.Threads[0].Name != "Dummy" {
   414  			t.Errorf("\ngot %#v\nwant Id=1, Name=\"Dummy\"", tResp)
   415  		}
   416  
   417  		// 7 >> threads, << threads
   418  		client.ThreadsRequest()
   419  		tResp = client.ExpectThreadsResponse(t)
   420  		if tResp.Seq != 0 || tResp.RequestSeq != 7 || len(tResp.Body.Threads) != 1 {
   421  			t.Errorf("\ngot %#v\nwant Seq=0, RequestSeq=7 len(Threads)=1", tResp)
   422  		}
   423  
   424  		// 8 >> stackTrace, << error
   425  		client.StackTraceRequest(1, 0, 20)
   426  		stResp := client.ExpectInvisibleErrorResponse(t)
   427  		if stResp.Seq != 0 || stResp.RequestSeq != 8 || stResp.Body.Error.Format != "Unable to produce stack trace: unknown goroutine 1" {
   428  			t.Errorf("\ngot %#v\nwant Seq=0, RequestSeq=8 Format=\"Unable to produce stack trace: unknown goroutine 1\"", stResp)
   429  		}
   430  
   431  		// 9 >> stackTrace, << error
   432  		client.StackTraceRequest(1, 0, 20)
   433  		stResp = client.ExpectInvisibleErrorResponse(t)
   434  		if stResp.Seq != 0 || stResp.RequestSeq != 9 || stResp.Body.Error.Id != UnableToProduceStackTrace {
   435  			t.Errorf("\ngot %#v\nwant Seq=0, RequestSeq=9 Id=%d", stResp, UnableToProduceStackTrace)
   436  		}
   437  
   438  		// 10 >> evaluate, << error
   439  		client.EvaluateRequest("foo", 0 /*no frame specified*/, "repl")
   440  		erResp := client.ExpectInvisibleErrorResponse(t)
   441  		if erResp.Seq != 0 || erResp.RequestSeq != 10 || erResp.Body.Error.Id != UnableToEvaluateExpression {
   442  			t.Errorf("\ngot %#v\nwant Seq=0, RequestSeq=10 Id=%d", erResp, UnableToEvaluateExpression)
   443  		}
   444  
   445  		// 11 >> evaluate, << evaluate
   446  		client.EvaluateRequest("1+1", 0 /*no frame specified*/, "repl")
   447  		evResp := client.ExpectEvaluateResponse(t)
   448  		if evResp.Seq != 0 || evResp.RequestSeq != 11 || evResp.Body.Result != "2" {
   449  			t.Errorf("\ngot %#v\nwant Seq=0, RequestSeq=10 Result=2", evResp)
   450  		}
   451  
   452  		// 12 >> continue, << continue, << terminated
   453  		client.ContinueRequest(1)
   454  		contResp := client.ExpectContinueResponse(t)
   455  		if contResp.Seq != 0 || contResp.RequestSeq != 12 || !contResp.Body.AllThreadsContinued {
   456  			t.Errorf("\ngot %#v\nwant Seq=0, RequestSeq=12 Body.AllThreadsContinued=true", contResp)
   457  		}
   458  		termEvent := client.ExpectTerminatedEvent(t)
   459  		if termEvent.Seq != 0 {
   460  			t.Errorf("\ngot %#v\nwant Seq=0", termEvent)
   461  		}
   462  
   463  		// 13 >> disconnect, << disconnect
   464  		client.DisconnectRequest()
   465  		oep := client.ExpectOutputEventProcessExited(t, 0)
   466  		if oep.Seq != 0 || oep.Body.Category != "console" {
   467  			t.Errorf("\ngot %#v\nwant Seq=0 Category='console'", oep)
   468  		}
   469  		oed := client.ExpectOutputEventDetaching(t)
   470  		if oed.Seq != 0 || oed.Body.Category != "console" {
   471  			t.Errorf("\ngot %#v\nwant Seq=0 Category='console'", oed)
   472  		}
   473  		dResp := client.ExpectDisconnectResponse(t)
   474  		if dResp.Seq != 0 || dResp.RequestSeq != 13 {
   475  			t.Errorf("\ngot %#v\nwant Seq=0, RequestSeq=13", dResp)
   476  		}
   477  		client.ExpectTerminatedEvent(t)
   478  	})
   479  }
   480  
   481  // TestAttachStopOnEntry is like TestLaunchStopOnEntry, but with attach request.
   482  func TestAttachStopOnEntry(t *testing.T) {
   483  	if runtime.GOOS == "freebsd" {
   484  		t.SkipNow()
   485  	}
   486  	runTest(t, "loopprog", func(client *daptest.Client, fixture protest.Fixture) {
   487  		// Start the program to attach to
   488  		cmd := exec.Command(fixture.Path)
   489  		stdout, err := cmd.StdoutPipe()
   490  		if err != nil {
   491  			t.Fatal(err)
   492  		}
   493  		cmd.Stderr = os.Stderr
   494  		if err := cmd.Start(); err != nil {
   495  			t.Fatal(err)
   496  		}
   497  		// Wait for output.
   498  		// This will give the target process time to initialize the runtime before we attach,
   499  		// so we can rely on having goroutines when they are requested on attach.
   500  		scanOut := bufio.NewScanner(stdout)
   501  		scanOut.Scan()
   502  		if scanOut.Text() != "past main" {
   503  			t.Errorf("expected loopprog.go to output \"past main\"")
   504  		}
   505  
   506  		// 1 >> initialize, << initialize
   507  		client.InitializeRequest()
   508  		initResp := client.ExpectInitializeResponseAndCapabilities(t)
   509  		if initResp.Seq != 0 || initResp.RequestSeq != 1 {
   510  			t.Errorf("\ngot %#v\nwant Seq=0, RequestSeq=1", initResp)
   511  		}
   512  
   513  		// 2 >> attach, << initialized, << attach
   514  		client.AttachRequest(
   515  			map[string]interface{}{"mode": "local", "processId": cmd.Process.Pid, "stopOnEntry": true, "backend": "default"})
   516  		client.ExpectCapabilitiesEventSupportTerminateDebuggee(t)
   517  		initEvent := client.ExpectInitializedEvent(t)
   518  		if initEvent.Seq != 0 {
   519  			t.Errorf("\ngot %#v\nwant Seq=0", initEvent)
   520  		}
   521  		attachResp := client.ExpectAttachResponse(t)
   522  		if attachResp.Seq != 0 || attachResp.RequestSeq != 2 {
   523  			t.Errorf("\ngot %#v\nwant Seq=0, RequestSeq=2", attachResp)
   524  		}
   525  
   526  		// 3 >> setBreakpoints, << setBreakpoints
   527  		client.SetBreakpointsRequest(fixture.Source, nil)
   528  		sbpResp := client.ExpectSetBreakpointsResponse(t)
   529  		if sbpResp.Seq != 0 || sbpResp.RequestSeq != 3 || len(sbpResp.Body.Breakpoints) != 0 {
   530  			t.Errorf("\ngot %#v\nwant Seq=0, RequestSeq=3, len(Breakpoints)=0", sbpResp)
   531  		}
   532  
   533  		// 4 >> setExceptionBreakpoints, << setExceptionBreakpoints
   534  		client.SetExceptionBreakpointsRequest()
   535  		sebpResp := client.ExpectSetExceptionBreakpointsResponse(t)
   536  		if sebpResp.Seq != 0 || sebpResp.RequestSeq != 4 {
   537  			t.Errorf("\ngot %#v\nwant Seq=0, RequestSeq=4", sebpResp)
   538  		}
   539  
   540  		// 5 >> configurationDone, << stopped, << configurationDone
   541  		client.ConfigurationDoneRequest()
   542  		stopEvent := client.ExpectStoppedEvent(t)
   543  		if stopEvent.Seq != 0 ||
   544  			stopEvent.Body.Reason != "entry" ||
   545  			stopEvent.Body.ThreadId != 1 ||
   546  			!stopEvent.Body.AllThreadsStopped {
   547  			t.Errorf("\ngot %#v\nwant Seq=0, Body={Reason=\"entry\", ThreadId=1, AllThreadsStopped=true}", stopEvent)
   548  		}
   549  		cdResp := client.ExpectConfigurationDoneResponse(t)
   550  		if cdResp.Seq != 0 || cdResp.RequestSeq != 5 {
   551  			t.Errorf("\ngot %#v\nwant Seq=0, RequestSeq=5", cdResp)
   552  		}
   553  
   554  		// 6 >> threads, << threads
   555  		client.ThreadsRequest()
   556  		tResp := client.ExpectThreadsResponse(t)
   557  		// Expect main goroutine plus runtime at this point.
   558  		if tResp.Seq != 0 || tResp.RequestSeq != 6 || len(tResp.Body.Threads) < 2 {
   559  			t.Errorf("\ngot %#v\nwant Seq=0, RequestSeq=6 len(Threads)>1", tResp)
   560  		}
   561  
   562  		// 7 >> threads, << threads
   563  		client.ThreadsRequest()
   564  		client.ExpectThreadsResponse(t)
   565  
   566  		// 8 >> stackTrace, << response
   567  		client.StackTraceRequest(1, 0, 20)
   568  		client.ExpectStackTraceResponse(t)
   569  
   570  		// 9 >> stackTrace, << response
   571  		client.StackTraceRequest(1, 0, 20)
   572  		client.ExpectStackTraceResponse(t)
   573  
   574  		// 10 >> evaluate, << error
   575  		client.EvaluateRequest("foo", 0 /*no frame specified*/, "repl")
   576  		erResp := client.ExpectInvisibleErrorResponse(t)
   577  		if erResp.Seq != 0 || erResp.RequestSeq != 10 || erResp.Body.Error.Id != UnableToEvaluateExpression {
   578  			t.Errorf("\ngot %#v\nwant Seq=0, RequestSeq=10 Id=%d", erResp, UnableToEvaluateExpression)
   579  		}
   580  
   581  		// 11 >> evaluate, << evaluate
   582  		client.EvaluateRequest("1+1", 0 /*no frame specified*/, "repl")
   583  		evResp := client.ExpectEvaluateResponse(t)
   584  		if evResp.Seq != 0 || evResp.RequestSeq != 11 || evResp.Body.Result != "2" {
   585  			t.Errorf("\ngot %#v\nwant Seq=0, RequestSeq=10 Result=2", evResp)
   586  		}
   587  
   588  		// 12 >> continue, << continue
   589  		client.ContinueRequest(1)
   590  		cResp := client.ExpectContinueResponse(t)
   591  		if cResp.Seq != 0 || cResp.RequestSeq != 12 {
   592  			t.Errorf("\ngot %#v\nwant Seq=0, RequestSeq=12", cResp)
   593  		}
   594  
   595  		// TODO(polina): once https://github.com/go-delve/delve/issues/2259 is
   596  		// fixed, test with kill=false.
   597  
   598  		// 13 >> disconnect, << disconnect
   599  		client.DisconnectRequestWithKillOption(true)
   600  
   601  		// Disconnect consists of Halt + Detach.
   602  		// Halt interrupts command in progress, which triggers
   603  		// a stopped event in parallel with the disconnect
   604  		// sequence. It might arrive before or during the sequence
   605  		// or never if the server exits before it is sent.
   606  		msg := expectMessageFilterStopped(t, client)
   607  		client.CheckOutputEvent(t, msg)
   608  		msg = expectMessageFilterStopped(t, client)
   609  		client.CheckDisconnectResponse(t, msg)
   610  		client.ExpectTerminatedEvent(t)
   611  
   612  		// If this call to KeepAlive isn't here there's a chance that stdout will
   613  		// be garbage collected (since it is no longer alive long before this
   614  		// point), when that happens, on unix-like OSes, the read end of the pipe
   615  		// will be closed by the finalizer and the target process will die by
   616  		// SIGPIPE, which the rest of this test does not expect.
   617  		runtime.KeepAlive(stdout)
   618  	})
   619  }
   620  
   621  // Like the test above, except the program is configured to continue on entry.
   622  func TestContinueOnEntry(t *testing.T) {
   623  	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) {
   624  		// 1 >> initialize, << initialize
   625  		client.InitializeRequest()
   626  		client.ExpectInitializeResponseAndCapabilities(t)
   627  
   628  		// 2 >> launch, << initialized, << launch
   629  		client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
   630  		client.ExpectInitializedEvent(t)
   631  		client.ExpectLaunchResponse(t)
   632  
   633  		// 3 >> setBreakpoints, << setBreakpoints
   634  		client.SetBreakpointsRequest(fixture.Source, nil)
   635  		client.ExpectSetBreakpointsResponse(t)
   636  
   637  		// 4 >> setExceptionBreakpoints, << setExceptionBreakpoints
   638  		client.SetExceptionBreakpointsRequest()
   639  		client.ExpectSetExceptionBreakpointsResponse(t)
   640  
   641  		// 5 >> configurationDone, << configurationDone
   642  		client.ConfigurationDoneRequest()
   643  		client.ExpectConfigurationDoneResponse(t)
   644  		// "Continue" happens behind the scenes on another goroutine
   645  
   646  		client.ExpectTerminatedEvent(t)
   647  
   648  		// 6 >> threads, << threads
   649  		client.ThreadsRequest()
   650  		tResp := client.ExpectThreadsResponse(t)
   651  		if tResp.Seq != 0 || tResp.RequestSeq != 6 || len(tResp.Body.Threads) != 1 {
   652  			t.Errorf("\ngot %#v\nwant Seq=0, RequestSeq=6 len(Threads)=1", tResp)
   653  		}
   654  		if tResp.Body.Threads[0].Id != 1 || tResp.Body.Threads[0].Name != "Dummy" {
   655  			t.Errorf("\ngot %#v\nwant Id=1, Name=\"Dummy\"", tResp)
   656  		}
   657  
   658  		// 7 >> disconnect, << disconnect
   659  		client.DisconnectRequest()
   660  		client.ExpectOutputEventProcessExited(t, 0)
   661  		client.ExpectOutputEventDetaching(t)
   662  		dResp := client.ExpectDisconnectResponse(t)
   663  		if dResp.Seq != 0 || dResp.RequestSeq != 7 {
   664  			t.Errorf("\ngot %#v\nwant Seq=0, RequestSeq=7", dResp)
   665  		}
   666  		client.ExpectTerminatedEvent(t)
   667  	})
   668  }
   669  
   670  // TestPreSetBreakpoint corresponds to a debug session that is configured to
   671  // continue on entry with a pre-set breakpoint.
   672  func TestPreSetBreakpoint(t *testing.T) {
   673  	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) {
   674  		client.InitializeRequest()
   675  		client.ExpectInitializeResponseAndCapabilities(t)
   676  
   677  		client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
   678  		client.ExpectInitializedEvent(t)
   679  		client.ExpectLaunchResponse(t)
   680  
   681  		client.SetBreakpointsRequest(fixture.Source, []int{8})
   682  		sResp := client.ExpectSetBreakpointsResponse(t)
   683  		if len(sResp.Body.Breakpoints) != 1 {
   684  			t.Errorf("got %#v, want len(Breakpoints)=1", sResp)
   685  		}
   686  		bkpt0 := sResp.Body.Breakpoints[0]
   687  		if !bkpt0.Verified || bkpt0.Line != 8 || bkpt0.Id != 1 || bkpt0.Source.Name != filepath.Base(fixture.Source) || bkpt0.Source.Path != fixture.Source {
   688  			t.Errorf("got breakpoints[0] = %#v, want Verified=true, Line=8, Id=1, Path=%q", bkpt0, fixture.Source)
   689  		}
   690  
   691  		client.SetExceptionBreakpointsRequest()
   692  		client.ExpectSetExceptionBreakpointsResponse(t)
   693  
   694  		client.ConfigurationDoneRequest()
   695  		client.ExpectConfigurationDoneResponse(t)
   696  		// This triggers "continue" on a separate goroutine
   697  
   698  		client.ThreadsRequest()
   699  		// Since we are in async mode while running, we might receive messages in either order.
   700  		for i := 0; i < 2; i++ {
   701  			msg := client.ExpectMessage(t)
   702  			switch m := msg.(type) {
   703  			case *dap.ThreadsResponse:
   704  				// If the thread request arrived while the program was running, we expect to get the dummy response
   705  				// with a single goroutine "Current".
   706  				// If the thread request arrived after the stop, we should get the goroutine stopped at main.Increment.
   707  				if (len(m.Body.Threads) != 1 || m.Body.Threads[0].Id != -1 || m.Body.Threads[0].Name != "Current") &&
   708  					(len(m.Body.Threads) < 1 || m.Body.Threads[0].Id != 1 || !strings.HasPrefix(m.Body.Threads[0].Name, "* [Go 1] main.Increment")) {
   709  					t.Errorf("\ngot  %#v\nwant Id=-1, Name=\"Current\" or Id=1, Name=\"* [Go 1] main.Increment ...\"", m.Body.Threads)
   710  				}
   711  			case *dap.StoppedEvent:
   712  				if m.Body.Reason != "breakpoint" || m.Body.ThreadId != 1 || !m.Body.AllThreadsStopped {
   713  					t.Errorf("got %#v, want Body={Reason=\"breakpoint\", ThreadId=1, AllThreadsStopped=true}", m)
   714  				}
   715  			default:
   716  				t.Fatalf("got %#v, want ThreadsResponse or StoppedEvent", m)
   717  			}
   718  		}
   719  
   720  		// Threads-StackTrace-Scopes-Variables request waterfall is
   721  		// triggered on stop event.
   722  		client.ThreadsRequest()
   723  		tResp := client.ExpectThreadsResponse(t)
   724  		if len(tResp.Body.Threads) < 2 { // 1 main + runtime
   725  			t.Errorf("\ngot  %#v\nwant len(Threads)>1", tResp.Body.Threads)
   726  		}
   727  		reMain, _ := regexp.Compile(`\* \[Go 1\] main.Increment \(Thread [0-9]+\)`)
   728  		wantMain := dap.Thread{Id: 1, Name: "* [Go 1] main.Increment (Thread ...)"}
   729  		wantRuntime := dap.Thread{Id: 2, Name: "[Go 2] runtime.gopark"}
   730  		for _, got := range tResp.Body.Threads {
   731  			if got.Id != 1 && !reMain.MatchString(got.Name) && !(strings.Contains(got.Name, "runtime.") || strings.Contains(got.Name, "runtime/")) {
   732  				t.Errorf("\ngot  %#v\nwant []dap.Thread{%#v, %#v, ...}", tResp.Body.Threads, wantMain, wantRuntime)
   733  			}
   734  		}
   735  
   736  		client.StackTraceRequest(1, 0, 20)
   737  		stResp := client.ExpectStackTraceResponse(t)
   738  
   739  		if stResp.Body.TotalFrames != 6 {
   740  			t.Errorf("\ngot %#v\nwant TotalFrames=6", stResp.Body.TotalFrames)
   741  		}
   742  		if len(stResp.Body.StackFrames) != 6 {
   743  			t.Errorf("\ngot %#v\nwant len(StackFrames)=6", stResp.Body.StackFrames)
   744  		} else {
   745  			checkFrame := func(got dap.StackFrame, id int, name string, sourceName string, line int) {
   746  				t.Helper()
   747  				if got.Id != id || got.Name != name {
   748  					t.Errorf("\ngot  %#v\nwant Id=%d Name=%s", got, id, name)
   749  				}
   750  				if (sourceName != "" && got.Source.Name != sourceName) || (line > 0 && got.Line != line) {
   751  					t.Errorf("\ngot  %#v\nwant Source.Name=%s Line=%d", got, sourceName, line)
   752  				}
   753  			}
   754  			checkFrame(stResp.Body.StackFrames[0], 1000, "main.Increment", "increment.go", 8)
   755  			checkFrame(stResp.Body.StackFrames[1], 1001, "main.Increment", "increment.go", 11)
   756  			checkFrame(stResp.Body.StackFrames[2], 1002, "main.Increment", "increment.go", 11)
   757  			checkFrame(stResp.Body.StackFrames[3], 1003, "main.main", "increment.go", 17)
   758  			checkFrame(stResp.Body.StackFrames[4], 1004, "runtime.main", "proc.go", -1)
   759  			checkFrame(stResp.Body.StackFrames[5], 1005, "runtime.goexit", "", -1)
   760  		}
   761  
   762  		client.ScopesRequest(1000)
   763  		scopes := client.ExpectScopesResponse(t)
   764  		if len(scopes.Body.Scopes) > 1 {
   765  			t.Errorf("\ngot  %#v\nwant len(Scopes)=1 (Locals)", scopes)
   766  		}
   767  		checkScope(t, scopes, 0, "Locals", localsScope)
   768  
   769  		client.VariablesRequest(localsScope)
   770  		args := client.ExpectVariablesResponse(t)
   771  		checkChildren(t, args, "Locals", 2)
   772  		checkVarExact(t, args, 0, "y", "y", "0 = 0x0", "uint", noChildren)
   773  		checkVarExact(t, args, 1, "~r1", "", "0 = 0x0", "uint", noChildren)
   774  
   775  		client.ContinueRequest(1)
   776  		ctResp := client.ExpectContinueResponse(t)
   777  		if !ctResp.Body.AllThreadsContinued {
   778  			t.Errorf("\ngot  %#v\nwant AllThreadsContinued=true", ctResp.Body)
   779  		}
   780  		// "Continue" is triggered after the response is sent
   781  
   782  		client.ExpectTerminatedEvent(t)
   783  
   784  		// Pause request after termination should result in an error.
   785  		// But in certain cases this request actually succeeds.
   786  		client.PauseRequest(1)
   787  		switch r := client.ExpectMessage(t).(type) {
   788  		case *dap.ErrorResponse:
   789  			if r.Message != "Unable to halt execution" {
   790  				t.Errorf("\ngot  %#v\nwant Message='Unable to halt execution'", r)
   791  			}
   792  		case *dap.PauseResponse:
   793  		default:
   794  			t.Fatalf("Unexpected response type: expect error or pause, got %#v", r)
   795  		}
   796  
   797  		client.DisconnectRequest()
   798  		client.ExpectOutputEventProcessExited(t, 0)
   799  		client.ExpectOutputEventDetaching(t)
   800  		client.ExpectDisconnectResponse(t)
   801  		client.ExpectTerminatedEvent(t)
   802  	})
   803  }
   804  
   805  // checkStackFramesExact is a helper for verifying the values within StackTraceResponse.
   806  //
   807  //	wantStartName - name of the first returned frame (ignored if "")
   808  //	wantStartLine - file line of the first returned frame (ignored if <0).
   809  //	wantStartID - id of the first frame returned (ignored if wantFrames is 0).
   810  //	wantFrames - number of frames returned (length of StackTraceResponse.Body.StackFrames array).
   811  //	wantTotalFrames - total number of stack frames available (StackTraceResponse.Body.TotalFrames).
   812  func checkStackFramesExact(t *testing.T, got *dap.StackTraceResponse,
   813  	wantStartName string, wantStartLine, wantStartID, wantFrames, wantTotalFrames int) {
   814  	t.Helper()
   815  	checkStackFramesNamed("", t, got, wantStartName, wantStartLine, wantStartID, wantFrames, wantTotalFrames, true)
   816  }
   817  
   818  func TestFilterGoroutines(t *testing.T) {
   819  	tt := []struct {
   820  		name    string
   821  		filter  string
   822  		want    []string
   823  		wantLen int
   824  		wantErr bool
   825  	}{
   826  		{
   827  			name:    "user goroutines",
   828  			filter:  "-with user",
   829  			want:    []string{"main.main", "main.agoroutine"},
   830  			wantLen: 11,
   831  		},
   832  		{
   833  			name:    "filter by user loc",
   834  			filter:  "-with userloc main.main",
   835  			want:    []string{"main.main"},
   836  			wantLen: 1,
   837  		},
   838  		{
   839  			name:    "multiple filters",
   840  			filter:  "-with user -with userloc main.agoroutine",
   841  			want:    []string{"main.agoroutine"},
   842  			wantLen: 10,
   843  		},
   844  		{
   845  			name:   "system goroutines",
   846  			filter: "-without user",
   847  			want:   []string{"runtime."},
   848  		},
   849  		// Filters that should return all goroutines.
   850  		{
   851  			name:    "empty filter string",
   852  			filter:  "",
   853  			want:    []string{"main.main", "main.agoroutine", "runtime."},
   854  			wantLen: -1,
   855  		},
   856  		{
   857  			name:    "bad filter string",
   858  			filter:  "not parsable to filters",
   859  			want:    []string{"main.main", "main.agoroutine", "runtime."},
   860  			wantLen: -1,
   861  			wantErr: true,
   862  		},
   863  		// Filters that should produce none.
   864  		{
   865  			name:    "no match to user loc",
   866  			filter:  "-with userloc main.NotAUserFrame",
   867  			want:    []string{"Dummy"},
   868  			wantLen: 1,
   869  		},
   870  		{
   871  			name:    "no match to user and not user",
   872  			filter:  "-with user -without user",
   873  			want:    []string{"Dummy"},
   874  			wantLen: 1,
   875  		},
   876  	}
   877  	runTest(t, "goroutinestackprog", func(client *daptest.Client, fixture protest.Fixture) {
   878  		runDebugSessionWithBPs(t, client, "launch",
   879  			// Launch
   880  			func() {
   881  				client.LaunchRequestWithArgs(map[string]interface{}{
   882  					"mode":        "exec",
   883  					"program":     fixture.Path,
   884  					"stopOnEntry": !stopOnEntry})
   885  			},
   886  			// Set breakpoints
   887  			fixture.Source, []int{30},
   888  			[]onBreakpoint{{
   889  				// Stop at line 30
   890  				execute: func() {
   891  					for _, tc := range tt {
   892  						command := fmt.Sprintf("dlv config goroutineFilters %s", tc.filter)
   893  						client.EvaluateRequest(command, 1000, "repl")
   894  						client.ExpectInvalidatedEvent(t)
   895  						client.ExpectEvaluateResponse(t)
   896  
   897  						client.ThreadsRequest()
   898  						if tc.wantErr {
   899  							client.ExpectOutputEvent(t)
   900  						}
   901  						tr := client.ExpectThreadsResponse(t)
   902  						if tc.wantLen > 0 && len(tr.Body.Threads) != tc.wantLen {
   903  							t.Errorf("got Threads=%#v, want Len=%d\n", tr.Body.Threads, tc.wantLen)
   904  						}
   905  						for i, frame := range tr.Body.Threads {
   906  							var found bool
   907  							for _, wantName := range tc.want {
   908  								if strings.Contains(frame.Name, wantName) {
   909  									found = true
   910  									break
   911  								}
   912  							}
   913  							if !found {
   914  								t.Errorf("got Threads[%d]=%#v, want Name=%v\n", i, frame, tc.want)
   915  							}
   916  						}
   917  					}
   918  				},
   919  				disconnect: false,
   920  			}})
   921  
   922  	})
   923  }
   924  
   925  func checkStackFramesHasMore(t *testing.T, got *dap.StackTraceResponse,
   926  	wantStartName string, wantStartLine, wantStartID, wantFrames, wantTotalFrames int) {
   927  	t.Helper()
   928  	checkStackFramesNamed("", t, got, wantStartName, wantStartLine, wantStartID, wantFrames, wantTotalFrames, false)
   929  }
   930  func checkStackFramesNamed(testName string, t *testing.T, got *dap.StackTraceResponse,
   931  	wantStartName string, wantStartLine, wantStartID, wantFrames, wantTotalFrames int, totalExact bool) {
   932  	t.Helper()
   933  	if totalExact && got.Body.TotalFrames != wantTotalFrames {
   934  		t.Errorf("%s\ngot  %#v\nwant TotalFrames=%d", testName, got.Body.TotalFrames, wantTotalFrames)
   935  	} else if !totalExact && got.Body.TotalFrames < wantTotalFrames {
   936  		t.Errorf("%s\ngot  %#v\nwant TotalFrames>=%d", testName, got.Body.TotalFrames, wantTotalFrames)
   937  	}
   938  
   939  	if len(got.Body.StackFrames) != wantFrames {
   940  		t.Errorf("%s\ngot  len(StackFrames)=%d\nwant %d", testName, len(got.Body.StackFrames), wantFrames)
   941  	} else {
   942  		// Verify that frame ids are consecutive numbers starting at wantStartID
   943  		for i := 0; i < wantFrames; i++ {
   944  			if got.Body.StackFrames[i].Id != wantStartID+i {
   945  				t.Errorf("%s\ngot  %#v\nwant Id=%d", testName, got.Body.StackFrames[i], wantStartID+i)
   946  			}
   947  		}
   948  		// Verify the name and line corresponding to the first returned frame (if any).
   949  		// This is useful when the first frame is the frame corresponding to the breakpoint at
   950  		// a predefined line. Line values < 0 are a signal to skip the check (which can be useful
   951  		// for frames in the third-party code, where we do not control the lines).
   952  		if wantFrames > 0 && wantStartLine > 0 && got.Body.StackFrames[0].Line != wantStartLine {
   953  			t.Errorf("%s\ngot  Line=%d\nwant %d", testName, got.Body.StackFrames[0].Line, wantStartLine)
   954  		}
   955  		if wantFrames > 0 && wantStartName != "" && got.Body.StackFrames[0].Name != wantStartName {
   956  			t.Errorf("%s\ngot  Name=%s\nwant %s", testName, got.Body.StackFrames[0].Name, wantStartName)
   957  		}
   958  	}
   959  }
   960  
   961  // checkScope is a helper for verifying the values within a ScopesResponse.
   962  //
   963  //	i - index of the scope within ScopesRespose.Body.Scopes array
   964  //	name - name of the scope
   965  //	varRef - reference to retrieve variables of this scope. If varRef is negative, the reference is not checked.
   966  func checkScope(t *testing.T, got *dap.ScopesResponse, i int, name string, varRef int) {
   967  	t.Helper()
   968  	if len(got.Body.Scopes) <= i {
   969  		t.Errorf("\ngot  %d\nwant len(Scopes)>%d", len(got.Body.Scopes), i)
   970  	}
   971  	goti := got.Body.Scopes[i]
   972  	if goti.Name != name || (varRef >= 0 && goti.VariablesReference != varRef) || goti.Expensive {
   973  		t.Errorf("\ngot  %#v\nwant Name=%q VariablesReference=%d Expensive=false", goti, name, varRef)
   974  	}
   975  }
   976  
   977  // checkChildren is a helper for verifying the number of variables within a VariablesResponse.
   978  //
   979  //	parentName - pseudoname of the enclosing variable or scope (used for error message only)
   980  //	numChildren - number of variables/fields/elements of this variable
   981  func checkChildren(t *testing.T, got *dap.VariablesResponse, parentName string, numChildren int) {
   982  	t.Helper()
   983  	if got.Body.Variables == nil {
   984  		t.Errorf("\ngot  %s children=%#v want []", parentName, got.Body.Variables)
   985  	}
   986  	if len(got.Body.Variables) != numChildren {
   987  		t.Errorf("\ngot  len(%s)=%d (children=%#v)\nwant len=%d", parentName, len(got.Body.Variables), got.Body.Variables, numChildren)
   988  	}
   989  }
   990  
   991  // checkVar is a helper for verifying the values within a VariablesResponse.
   992  //
   993  //	i - index of the variable within VariablesRespose.Body.Variables array (-1 will search all vars for a match)
   994  //	name - name of the variable
   995  //	evalName - fully qualified variable name or alternative expression to load this variable
   996  //	value - the value of the variable
   997  //	useExactMatch - true if name, evalName and value are to be compared to exactly, false if to be used as regex
   998  //	hasRef - true if the variable should have children and therefore a non-0 variable reference
   999  //	ref - reference to retrieve children of this variable (0 if none)
  1000  func checkVar(t *testing.T, got *dap.VariablesResponse, i int, name, evalName, value, typ string, useExactMatch, hasRef bool, indexed, named int) (ref int) {
  1001  	t.Helper()
  1002  	if len(got.Body.Variables) <= i {
  1003  		t.Errorf("\ngot  len=%d (children=%#v)\nwant len>%d", len(got.Body.Variables), got.Body.Variables, i)
  1004  		return
  1005  	}
  1006  	if i < 0 {
  1007  		for vi, v := range got.Body.Variables {
  1008  			if v.Name == name {
  1009  				i = vi
  1010  				break
  1011  			}
  1012  		}
  1013  	}
  1014  	if i < 0 {
  1015  		t.Errorf("\ngot  %#v\nwant Variables[i].Name=%q (not found)", got, name)
  1016  		return 0
  1017  	}
  1018  
  1019  	goti := got.Body.Variables[i]
  1020  	matchedName := false
  1021  	if useExactMatch {
  1022  		if strings.HasPrefix(name, "~r") {
  1023  			matchedName = strings.HasPrefix(goti.Name, "~r")
  1024  		} else {
  1025  			matchedName = (goti.Name == name)
  1026  		}
  1027  	} else {
  1028  		matchedName, _ = regexp.MatchString(name, goti.Name)
  1029  	}
  1030  	if !matchedName || (goti.VariablesReference > 0) != hasRef {
  1031  		t.Errorf("\ngot  %#v\nwant Name=%q hasRef=%t", goti, name, hasRef)
  1032  	}
  1033  	matchedEvalName := false
  1034  	if useExactMatch {
  1035  		matchedEvalName = (goti.EvaluateName == evalName)
  1036  	} else {
  1037  		matchedEvalName, _ = regexp.MatchString(evalName, goti.EvaluateName)
  1038  	}
  1039  	if !matchedEvalName {
  1040  		t.Errorf("\ngot  %q\nwant EvaluateName=%q", goti.EvaluateName, evalName)
  1041  	}
  1042  	matchedValue := false
  1043  	if useExactMatch {
  1044  		matchedValue = (goti.Value == value)
  1045  	} else {
  1046  		matchedValue, _ = regexp.MatchString(value, goti.Value)
  1047  	}
  1048  	if !matchedValue {
  1049  		t.Errorf("\ngot  %s=%q\nwant %q", name, goti.Value, value)
  1050  	}
  1051  	matchedType := false
  1052  	if useExactMatch {
  1053  		matchedType = (goti.Type == typ)
  1054  	} else {
  1055  		matchedType, _ = regexp.MatchString(typ, goti.Type)
  1056  	}
  1057  	if !matchedType {
  1058  		t.Errorf("\ngot  %s=%q\nwant %q", name, goti.Type, typ)
  1059  	}
  1060  	if indexed >= 0 && goti.IndexedVariables != indexed {
  1061  		t.Errorf("\ngot  %s=%d indexed\nwant %d indexed", name, goti.IndexedVariables, indexed)
  1062  	}
  1063  	if named >= 0 && goti.NamedVariables != named {
  1064  		t.Errorf("\ngot  %s=%d named\nwant %d named", name, goti.NamedVariables, named)
  1065  	}
  1066  	return goti.VariablesReference
  1067  }
  1068  
  1069  // checkVarExact is a helper like checkVar that matches value exactly.
  1070  func checkVarExact(t *testing.T, got *dap.VariablesResponse, i int, name, evalName, value, typ string, hasRef bool) (ref int) {
  1071  	t.Helper()
  1072  	return checkVarExactIndexed(t, got, i, name, evalName, value, typ, hasRef, -1, -1)
  1073  }
  1074  
  1075  // checkVarExact is a helper like checkVar that matches value exactly.
  1076  func checkVarExactIndexed(t *testing.T, got *dap.VariablesResponse, i int, name, evalName, value, typ string, hasRef bool, indexed, named int) (ref int) {
  1077  	t.Helper()
  1078  	return checkVar(t, got, i, name, evalName, value, typ, true, hasRef, indexed, named)
  1079  }
  1080  
  1081  // checkVarRegex is a helper like checkVar that treats value, evalName or name as a regex.
  1082  func checkVarRegex(t *testing.T, got *dap.VariablesResponse, i int, name, evalName, value, typ string, hasRef bool) (ref int) {
  1083  	t.Helper()
  1084  	return checkVarRegexIndexed(t, got, i, name, evalName, value, typ, hasRef, -1, -1)
  1085  }
  1086  
  1087  // checkVarRegex is a helper like checkVar that treats value, evalName or name as a regex.
  1088  func checkVarRegexIndexed(t *testing.T, got *dap.VariablesResponse, i int, name, evalName, value, typ string, hasRef bool, indexed, named int) (ref int) {
  1089  	t.Helper()
  1090  	return checkVar(t, got, i, name, evalName, value, typ, false, hasRef, indexed, named)
  1091  }
  1092  
  1093  func expectMessageFilterStopped(t *testing.T, client *daptest.Client) dap.Message {
  1094  	msg := client.ExpectMessage(t)
  1095  	if _, isStopped := msg.(*dap.StoppedEvent); isStopped {
  1096  		msg = client.ExpectMessage(t)
  1097  	}
  1098  	return msg
  1099  }
  1100  
  1101  // validateEvaluateName issues an evaluate request with evaluateName of a variable and
  1102  // confirms that it succeeds and returns the same variable record as the original.
  1103  func validateEvaluateName(t *testing.T, client *daptest.Client, got *dap.VariablesResponse, i int) {
  1104  	t.Helper()
  1105  	original := got.Body.Variables[i]
  1106  	client.EvaluateRequest(original.EvaluateName, 1000, "this context will be ignored")
  1107  	validated := client.ExpectEvaluateResponse(t)
  1108  	if original.VariablesReference == 0 && validated.Body.VariablesReference != 0 ||
  1109  		original.VariablesReference != 0 && validated.Body.VariablesReference == 0 {
  1110  		t.Errorf("\ngot  varref=%d\nwant %d", validated.Body.VariablesReference, original.VariablesReference)
  1111  	}
  1112  	// The variable might not be fully loaded, and when we reload it with an expression
  1113  	// more of the subvalues might be revealed, so we must match the loaded prefix only.
  1114  	if strings.Contains(original.Value, "...") {
  1115  		origLoaded := strings.Split(original.Value, "...")[0]
  1116  		if !strings.HasPrefix(validated.Body.Result, origLoaded) {
  1117  			t.Errorf("\ngot  value=%q\nwant %q", validated.Body.Result, original.Value)
  1118  		}
  1119  	} else if original.Value != validated.Body.Result {
  1120  		t.Errorf("\ngot  value=%q\nwant %q", validated.Body.Result, original.Value)
  1121  	}
  1122  }
  1123  
  1124  // TestStackTraceRequest executes to a breakpoint and tests different
  1125  // good and bad configurations of 'stackTrace' requests.
  1126  func TestStackTraceRequest(t *testing.T) {
  1127  	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) {
  1128  		var stResp *dap.StackTraceResponse
  1129  		runDebugSessionWithBPs(t, client, "launch",
  1130  			// Launch
  1131  			func() {
  1132  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  1133  			},
  1134  			// Set breakpoints
  1135  			fixture.Source, []int{8, 18},
  1136  			[]onBreakpoint{{
  1137  				// Stop at line 8
  1138  				execute: func() {
  1139  					// Even though the stack frames do not change,
  1140  					// repeated requests at the same breakpoint
  1141  					// would assign next block of unique ids to them each time.
  1142  					const NumFrames = 6
  1143  					reqIndex := 0
  1144  					frameID := func() int {
  1145  						return startHandle + reqIndex
  1146  					}
  1147  
  1148  					tests := map[string]struct {
  1149  						startFrame          int
  1150  						levels              int
  1151  						wantStartName       string
  1152  						wantStartLine       int
  1153  						wantStartFrame      int
  1154  						wantFramesReturned  int
  1155  						wantFramesAvailable int
  1156  						exact               bool
  1157  					}{
  1158  						"all frame levels from 0 to NumFrames":    {0, NumFrames, "main.Increment", 8, 0, NumFrames, NumFrames, true},
  1159  						"subset of frames from 1 to -1":           {1, NumFrames - 1, "main.Increment", 11, 1, NumFrames - 1, NumFrames, true},
  1160  						"load stack in pages: first half":         {0, NumFrames / 2, "main.Increment", 8, 0, NumFrames / 2, NumFrames, false},
  1161  						"load stack in pages: second half":        {NumFrames / 2, NumFrames, "main.main", 17, NumFrames / 2, NumFrames / 2, NumFrames, true},
  1162  						"zero levels means all levels":            {0, 0, "main.Increment", 8, 0, NumFrames, NumFrames, true},
  1163  						"zero levels means all remaining levels":  {NumFrames / 2, 0, "main.main", 17, NumFrames / 2, NumFrames / 2, NumFrames, true},
  1164  						"negative levels treated as 0 (all)":      {0, -10, "main.Increment", 8, 0, NumFrames, NumFrames, true},
  1165  						"OOB levels is capped at available len":   {0, NumFrames + 1, "main.Increment", 8, 0, NumFrames, NumFrames, true},
  1166  						"OOB levels is capped at available len 1": {1, NumFrames + 1, "main.Increment", 11, 1, NumFrames - 1, NumFrames, true},
  1167  						"negative startFrame treated as 0":        {-10, 0, "main.Increment", 8, 0, NumFrames, NumFrames, true},
  1168  						"OOB startFrame returns empty trace":      {NumFrames, 0, "main.Increment", -1, -1, 0, NumFrames, true},
  1169  					}
  1170  					for name, tc := range tests {
  1171  						client.StackTraceRequest(1, tc.startFrame, tc.levels)
  1172  						stResp = client.ExpectStackTraceResponse(t)
  1173  						checkStackFramesNamed(name, t, stResp,
  1174  							tc.wantStartName, tc.wantStartLine, frameID(), tc.wantFramesReturned, tc.wantFramesAvailable, tc.exact)
  1175  						reqIndex += len(stResp.Body.StackFrames)
  1176  					}
  1177  				},
  1178  				disconnect: false,
  1179  			}, {
  1180  				// Stop at line 18
  1181  				execute: func() {
  1182  					// Frame ids get reset at each breakpoint.
  1183  					client.StackTraceRequest(1, 0, 0)
  1184  					stResp = client.ExpectStackTraceResponse(t)
  1185  					checkStackFramesExact(t, stResp, "main.main", 18, startHandle, 3, 3)
  1186  
  1187  				},
  1188  				disconnect: false,
  1189  			}})
  1190  	})
  1191  	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) {
  1192  		var stResp *dap.StackTraceResponse
  1193  		runDebugSessionWithBPs(t, client, "launch",
  1194  			// Launch
  1195  			func() {
  1196  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  1197  			},
  1198  			// Set breakpoints
  1199  			fixture.Source, []int{8, 18},
  1200  			[]onBreakpoint{{
  1201  				// Stop at line 8
  1202  				execute: func() {
  1203  					// Even though the stack frames do not change,
  1204  					// repeated requests at the same breakpoint
  1205  					// would assign next block of unique ids to them each time.
  1206  					const NumFrames = 6
  1207  
  1208  					var frames []dap.StackFrame
  1209  
  1210  					for start, levels := 0, 1; start < NumFrames; {
  1211  						client.StackTraceRequest(1, start, levels)
  1212  						stResp = client.ExpectStackTraceResponse(t)
  1213  						frames = append(frames, stResp.Body.StackFrames...)
  1214  						if stResp.Body.TotalFrames < NumFrames {
  1215  							t.Errorf("got  %#v\nwant TotalFrames>=%d\n", stResp.Body.TotalFrames, NumFrames)
  1216  						}
  1217  
  1218  						if len(stResp.Body.StackFrames) < levels {
  1219  							t.Errorf("got  len(StackFrames)=%d\nwant >=%d\n", len(stResp.Body.StackFrames), levels)
  1220  						}
  1221  
  1222  						start += len(stResp.Body.StackFrames)
  1223  					}
  1224  
  1225  					// TODO check all the frames.
  1226  					want := []struct {
  1227  						wantName string
  1228  						wantLine int
  1229  					}{
  1230  						{"main.Increment", 8},
  1231  						{"main.Increment", 11},
  1232  						{"main.Increment", 11},
  1233  						{"main.main", 17},
  1234  						{"runtime.main", 0},
  1235  						{"runtime.goexit", 0},
  1236  					}
  1237  					for i, frame := range frames {
  1238  						frameId := startHandle + i
  1239  						if frame.Id != frameId {
  1240  							t.Errorf("got  %#v\nwant Id=%d\n", frame, frameId)
  1241  						}
  1242  
  1243  						// Verify the name and line corresponding to the first returned frame (if any).
  1244  						// This is useful when the first frame is the frame corresponding to the breakpoint at
  1245  						// a predefined line. Line values < 0 are a signal to skip the check (which can be useful
  1246  						// for frames in the third-party code, where we do not control the lines).
  1247  						if want[i].wantLine > 0 && frame.Line != want[i].wantLine {
  1248  							t.Errorf("got  Line=%d\nwant %d\n", frame.Line, want[i].wantLine)
  1249  						}
  1250  						if want[i].wantName != "" && frame.Name != want[i].wantName {
  1251  							t.Errorf("got  Name=%s\nwant %s\n", frame.Name, want[i].wantName)
  1252  						}
  1253  					}
  1254  				},
  1255  				disconnect: false,
  1256  			}, {
  1257  				// Stop at line 18
  1258  				execute: func() {
  1259  					// Frame ids get reset at each breakpoint.
  1260  					client.StackTraceRequest(1, 0, 0)
  1261  					stResp = client.ExpectStackTraceResponse(t)
  1262  					checkStackFramesExact(t, stResp, "main.main", 18, startHandle, 3, 3)
  1263  				},
  1264  				disconnect: false,
  1265  			}})
  1266  	})
  1267  }
  1268  
  1269  func TestSelectedThreadsRequest(t *testing.T) {
  1270  	runTest(t, "goroutinestackprog", func(client *daptest.Client, fixture protest.Fixture) {
  1271  		runDebugSessionWithBPs(t, client, "launch",
  1272  			// Launch
  1273  			func() {
  1274  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  1275  			},
  1276  			// Set breakpoints
  1277  			fixture.Source, []int{20},
  1278  			[]onBreakpoint{{
  1279  				execute: func() {
  1280  					checkStop(t, client, 1, "main.main", 20)
  1281  
  1282  					defaultMaxGoroutines := maxGoroutines
  1283  					defer func() { maxGoroutines = defaultMaxGoroutines }()
  1284  
  1285  					maxGoroutines = 1
  1286  					client.SetBreakpointsRequest(fixture.Source, []int{8})
  1287  					client.ExpectSetBreakpointsResponse(t)
  1288  
  1289  					client.ContinueRequest(1)
  1290  					client.ExpectContinueResponse(t)
  1291  
  1292  					se := client.ExpectStoppedEvent(t)
  1293  					if se.Body.Reason != "breakpoint" || se.Body.ThreadId == 1 {
  1294  						t.Errorf("got %#v, want Reason=%q, ThreadId!=1", se, "breakpoint")
  1295  					}
  1296  
  1297  					client.ThreadsRequest()
  1298  					oe := client.ExpectOutputEvent(t)
  1299  					if !strings.HasPrefix(oe.Body.Output, "Too many goroutines") {
  1300  						t.Errorf("got %#v, expected Output=\"Too many goroutines...\"\n", oe)
  1301  
  1302  					}
  1303  					tr := client.ExpectThreadsResponse(t)
  1304  
  1305  					if len(tr.Body.Threads) != 2 {
  1306  						t.Errorf("got %d threads, expected 2\n", len(tr.Body.Threads))
  1307  					}
  1308  
  1309  					var selectedFound bool
  1310  					for _, thread := range tr.Body.Threads {
  1311  						if thread.Id == se.Body.ThreadId {
  1312  							selectedFound = true
  1313  							break
  1314  						}
  1315  					}
  1316  					if !selectedFound {
  1317  						t.Errorf("got %#v, want ThreadId=%d\n", tr.Body.Threads, se.Body.ThreadId)
  1318  					}
  1319  				},
  1320  				disconnect: true,
  1321  			}})
  1322  
  1323  	})
  1324  }
  1325  
  1326  func TestHideSystemGoroutinesRequest(t *testing.T) {
  1327  	tests := []struct{ hideSystemGoroutines bool }{
  1328  		{hideSystemGoroutines: true},
  1329  		{hideSystemGoroutines: false},
  1330  	}
  1331  	for _, tt := range tests {
  1332  		runTest(t, "goroutinestackprog", func(client *daptest.Client, fixture protest.Fixture) {
  1333  			runDebugSessionWithBPs(t, client, "launch",
  1334  				// Launch
  1335  				func() {
  1336  					client.LaunchRequestWithArgs(map[string]interface{}{
  1337  						"mode":                 "exec",
  1338  						"program":              fixture.Path,
  1339  						"hideSystemGoroutines": tt.hideSystemGoroutines,
  1340  						"stopOnEntry":          !stopOnEntry,
  1341  					})
  1342  				},
  1343  				// Set breakpoints
  1344  				fixture.Source, []int{25},
  1345  				[]onBreakpoint{{
  1346  					execute: func() {
  1347  						checkStop(t, client, 1, "main.main", 25)
  1348  
  1349  						client.ThreadsRequest()
  1350  						tr := client.ExpectThreadsResponse(t)
  1351  
  1352  						// The user process creates 10 goroutines in addition to the
  1353  						// main goroutine, for a total of 11 goroutines.
  1354  						userCount := 11
  1355  						if tt.hideSystemGoroutines {
  1356  							if len(tr.Body.Threads) != userCount {
  1357  								t.Errorf("got %d goroutines, expected %d\n", len(tr.Body.Threads), userCount)
  1358  							}
  1359  						} else {
  1360  							if len(tr.Body.Threads) <= userCount {
  1361  								t.Errorf("got %d goroutines, expected >%d\n", len(tr.Body.Threads), userCount)
  1362  							}
  1363  						}
  1364  					},
  1365  					disconnect: true,
  1366  				}})
  1367  		})
  1368  	}
  1369  }
  1370  
  1371  // TestScopesAndVariablesRequests executes to a breakpoint and tests different
  1372  // configurations of 'scopes' and 'variables' requests.
  1373  func TestScopesAndVariablesRequests(t *testing.T) {
  1374  	runTest(t, "testvariables", func(client *daptest.Client, fixture protest.Fixture) {
  1375  		runDebugSessionWithBPs(t, client, "launch",
  1376  			// Launch
  1377  			func() {
  1378  				client.LaunchRequestWithArgs(map[string]interface{}{
  1379  					"mode": "exec", "program": fixture.Path, "showGlobalVariables": true, "backend": "default",
  1380  				})
  1381  			},
  1382  			// Breakpoints are set within the program
  1383  			fixture.Source, []int{},
  1384  			[]onBreakpoint{{
  1385  				// Stop at first breakpoint
  1386  				execute: func() {
  1387  					client.StackTraceRequest(1, 0, 20)
  1388  					stack := client.ExpectStackTraceResponse(t)
  1389  
  1390  					startLineno := 66
  1391  					if runtime.GOOS == "windows" && goversion.VersionAfterOrEqual(runtime.Version(), 1, 15) {
  1392  						// Go1.15 on windows inserts a NOP after the call to
  1393  						// runtime.Breakpoint and marks it same line as the
  1394  						// runtime.Breakpoint call, making this flaky, so skip the line check.
  1395  						startLineno = -1
  1396  					}
  1397  
  1398  					checkStackFramesExact(t, stack, "main.foobar", startLineno, 1000, 4, 4)
  1399  
  1400  					client.ScopesRequest(1000)
  1401  					scopes := client.ExpectScopesResponse(t)
  1402  					checkScope(t, scopes, 0, "Locals", localsScope)
  1403  					checkScope(t, scopes, 1, "Globals (package main)", globalsScope)
  1404  
  1405  					// Globals
  1406  
  1407  					client.VariablesRequest(globalsScope)
  1408  					globals := client.ExpectVariablesResponse(t)
  1409  					checkVarExact(t, globals, 0, "p1", "main.p1", "10", "int", noChildren)
  1410  
  1411  					// Locals
  1412  
  1413  					client.VariablesRequest(localsScope)
  1414  					locals := client.ExpectVariablesResponse(t)
  1415  					checkChildren(t, locals, "Locals", 33)
  1416  					checkVarExact(t, locals, 0, "baz", "baz", `"bazburzum"`, "string", noChildren)
  1417  					ref := checkVarExact(t, locals, 1, "bar", "bar", `main.FooBar {Baz: 10, Bur: "lorem"}`, "main.FooBar", hasChildren)
  1418  					if ref > 0 {
  1419  						client.VariablesRequest(ref)
  1420  						bar := client.ExpectVariablesResponse(t)
  1421  						checkChildren(t, bar, "bar", 2)
  1422  						checkVarExact(t, bar, 0, "Baz", "bar.Baz", "10", "int", noChildren)
  1423  						checkVarExact(t, bar, 1, "Bur", "bar.Bur", `"lorem"`, "string", noChildren)
  1424  						validateEvaluateName(t, client, bar, 0)
  1425  						validateEvaluateName(t, client, bar, 1)
  1426  					}
  1427  
  1428  					// reflect.Kind == Bool
  1429  					checkVarExact(t, locals, -1, "b1", "b1", "true", "bool", noChildren)
  1430  					checkVarExact(t, locals, -1, "b2", "b2", "false", "bool", noChildren)
  1431  					// reflect.Kind == Int
  1432  					checkVarExact(t, locals, -1, "a2", "a2", "6", "int", noChildren)
  1433  					checkVarExact(t, locals, -1, "neg", "neg", "-1", "int", noChildren)
  1434  					// reflect.Kind == Int8
  1435  					checkVarExact(t, locals, -1, "i8", "i8", "1", "int8", noChildren)
  1436  					// reflect.Kind == Int16 - see testvariables2
  1437  					// reflect.Kind == Int32 - see testvariables2
  1438  					// reflect.Kind == Int64 - see testvariables2
  1439  					// reflect.Kind == Uint
  1440  					// reflect.Kind == Uint8
  1441  					checkVarExact(t, locals, -1, "u8", "u8", "255 = 0xff", "uint8", noChildren)
  1442  					// reflect.Kind == Uint16
  1443  					checkVarExact(t, locals, -1, "u16", "u16", "65535 = 0xffff", "uint16", noChildren)
  1444  					// reflect.Kind == Uint32
  1445  					checkVarExact(t, locals, -1, "u32", "u32", "4294967295 = 0xffffffff", "uint32", noChildren)
  1446  					// reflect.Kind == Uint64
  1447  					checkVarExact(t, locals, -1, "u64", "u64", "18446744073709551615 = 0xffffffffffffffff", "uint64", noChildren)
  1448  					// reflect.Kind == Uintptr
  1449  					checkVarExact(t, locals, -1, "up", "up", "5 = 0x5", "uintptr", noChildren)
  1450  					// reflect.Kind == Float32
  1451  					checkVarExact(t, locals, -1, "f32", "f32", "1.2", "float32", noChildren)
  1452  					// reflect.Kind == Float64
  1453  					checkVarExact(t, locals, -1, "a3", "a3", "7.23", "float64", noChildren)
  1454  					// reflect.Kind == Complex64
  1455  					ref = checkVarExact(t, locals, -1, "c64", "c64", "(1 + 2i)", "complex64", hasChildren)
  1456  					if ref > 0 {
  1457  						client.VariablesRequest(ref)
  1458  						c64 := client.ExpectVariablesResponse(t)
  1459  						checkChildren(t, c64, "c64", 2)
  1460  						checkVarExact(t, c64, 0, "real", "", "1", "float32", noChildren)
  1461  						checkVarExact(t, c64, 1, "imaginary", "", "2", "float32", noChildren)
  1462  					}
  1463  					// reflect.Kind == Complex128
  1464  					ref = checkVarExact(t, locals, -1, "c128", "c128", "(2 + 3i)", "complex128", hasChildren)
  1465  					if ref > 0 {
  1466  						client.VariablesRequest(ref)
  1467  						c128 := client.ExpectVariablesResponse(t)
  1468  						checkChildren(t, c128, "c128", 2)
  1469  						checkVarExact(t, c128, 0, "real", "", "2", "float64", noChildren)
  1470  						checkVarExact(t, c128, 1, "imaginary", "", "3", "float64", noChildren)
  1471  					}
  1472  					// reflect.Kind == Array
  1473  					ref = checkVarExact(t, locals, -1, "a4", "a4", "[2]int [1,2]", "[2]int", hasChildren)
  1474  					if ref > 0 {
  1475  						client.VariablesRequest(ref)
  1476  						a4 := client.ExpectVariablesResponse(t)
  1477  						checkChildren(t, a4, "a4", 2)
  1478  						checkVarExact(t, a4, 0, "[0]", "a4[0]", "1", "int", noChildren)
  1479  						checkVarExact(t, a4, 1, "[1]", "a4[1]", "2", "int", noChildren)
  1480  					}
  1481  					ref = checkVarExact(t, locals, -1, "a11", "a11", `[3]main.FooBar [{Baz: 1, Bur: "a"},{Baz: 2, Bur: "b"},{Baz: 3, Bur: "c"}]`, "[3]main.FooBar", hasChildren)
  1482  					if ref > 0 {
  1483  						client.VariablesRequest(ref)
  1484  						a11 := client.ExpectVariablesResponse(t)
  1485  						checkChildren(t, a11, "a11", 3)
  1486  						checkVarExact(t, a11, 0, "[0]", "a11[0]", `main.FooBar {Baz: 1, Bur: "a"}`, "main.FooBar", hasChildren)
  1487  						ref = checkVarExact(t, a11, 1, "[1]", "a11[1]", `main.FooBar {Baz: 2, Bur: "b"}`, "main.FooBar", hasChildren)
  1488  						if ref > 0 {
  1489  							client.VariablesRequest(ref)
  1490  							a11_1 := client.ExpectVariablesResponse(t)
  1491  							checkChildren(t, a11_1, "a11[1]", 2)
  1492  							checkVarExact(t, a11_1, 0, "Baz", "a11[1].Baz", "2", "int", noChildren)
  1493  							checkVarExact(t, a11_1, 1, "Bur", "a11[1].Bur", `"b"`, "string", noChildren)
  1494  							validateEvaluateName(t, client, a11_1, 0)
  1495  							validateEvaluateName(t, client, a11_1, 1)
  1496  						}
  1497  						checkVarExact(t, a11, 2, "[2]", "a11[2]", `main.FooBar {Baz: 3, Bur: "c"}`, "main.FooBar", hasChildren)
  1498  					}
  1499  
  1500  					// reflect.Kind == Chan - see testvariables2
  1501  					// reflect.Kind == Func - see testvariables2
  1502  					// reflect.Kind == Interface - see testvariables2
  1503  					// reflect.Kind == Map - see testvariables2
  1504  					// reflect.Kind == Ptr
  1505  					ref = checkVarExact(t, locals, -1, "a7", "a7", `*main.FooBar {Baz: 5, Bur: "strum"}`, "*main.FooBar", hasChildren)
  1506  					if ref > 0 {
  1507  						client.VariablesRequest(ref)
  1508  						a7 := client.ExpectVariablesResponse(t)
  1509  						checkChildren(t, a7, "a7", 1)
  1510  						ref = checkVarExact(t, a7, 0, "", "(*a7)", `main.FooBar {Baz: 5, Bur: "strum"}`, "main.FooBar", hasChildren)
  1511  						if ref > 0 {
  1512  							client.VariablesRequest(ref)
  1513  							a7val := client.ExpectVariablesResponse(t)
  1514  							checkChildren(t, a7val, "*a7", 2)
  1515  							checkVarExact(t, a7val, 0, "Baz", "(*a7).Baz", "5", "int", noChildren)
  1516  							checkVarExact(t, a7val, 1, "Bur", "(*a7).Bur", `"strum"`, "string", noChildren)
  1517  							validateEvaluateName(t, client, a7val, 0)
  1518  							validateEvaluateName(t, client, a7val, 1)
  1519  						}
  1520  					}
  1521  					// TODO(polina): how to test for "nil" (without type) and "void"?
  1522  					checkVarExact(t, locals, -1, "a9", "a9", "*main.FooBar nil", "*main.FooBar", noChildren)
  1523  					// reflect.Kind == Slice
  1524  					ref = checkVarExact(t, locals, -1, "a5", "a5", "[]int len: 5, cap: 5, [1,2,3,4,5]", "[]int", hasChildren)
  1525  					if ref > 0 {
  1526  						client.VariablesRequest(ref)
  1527  						a5 := client.ExpectVariablesResponse(t)
  1528  						checkChildren(t, a5, "a5", 5)
  1529  						checkVarExact(t, a5, 0, "[0]", "a5[0]", "1", "int", noChildren)
  1530  						checkVarExact(t, a5, 4, "[4]", "a5[4]", "5", "int", noChildren)
  1531  						validateEvaluateName(t, client, a5, 0)
  1532  						validateEvaluateName(t, client, a5, 1)
  1533  					}
  1534  					ref = checkVarExact(t, locals, -1, "a12", "a12", `[]main.FooBar len: 2, cap: 2, [{Baz: 4, Bur: "d"},{Baz: 5, Bur: "e"}]`, "[]main.FooBar", hasChildren)
  1535  					if ref > 0 {
  1536  						client.VariablesRequest(ref)
  1537  						a12 := client.ExpectVariablesResponse(t)
  1538  						checkChildren(t, a12, "a12", 2)
  1539  						checkVarExact(t, a12, 0, "[0]", "a12[0]", `main.FooBar {Baz: 4, Bur: "d"}`, "main.FooBar", hasChildren)
  1540  						ref = checkVarExact(t, a12, 1, "[1]", "a12[1]", `main.FooBar {Baz: 5, Bur: "e"}`, "main.FooBar", hasChildren)
  1541  						if ref > 0 {
  1542  							client.VariablesRequest(ref)
  1543  							a12_1 := client.ExpectVariablesResponse(t)
  1544  							checkChildren(t, a12_1, "a12[1]", 2)
  1545  							checkVarExact(t, a12_1, 0, "Baz", "a12[1].Baz", "5", "int", noChildren)
  1546  							checkVarExact(t, a12_1, 1, "Bur", "a12[1].Bur", `"e"`, "string", noChildren)
  1547  							validateEvaluateName(t, client, a12_1, 0)
  1548  							validateEvaluateName(t, client, a12_1, 1)
  1549  						}
  1550  					}
  1551  					ref = checkVarExact(t, locals, -1, "a13", "a13", `[]*main.FooBar len: 3, cap: 3, [*{Baz: 6, Bur: "f"},*{Baz: 7, Bur: "g"},*{Baz: 8, Bur: "h"}]`, "[]*main.FooBar", hasChildren)
  1552  					if ref > 0 {
  1553  						client.VariablesRequest(ref)
  1554  						a13 := client.ExpectVariablesResponse(t)
  1555  						checkChildren(t, a13, "a13", 3)
  1556  						checkVarExact(t, a13, 0, "[0]", "a13[0]", `*main.FooBar {Baz: 6, Bur: "f"}`, "*main.FooBar", hasChildren)
  1557  						checkVarExact(t, a13, 1, "[1]", "a13[1]", `*main.FooBar {Baz: 7, Bur: "g"}`, "*main.FooBar", hasChildren)
  1558  						ref = checkVarExact(t, a13, 2, "[2]", "a13[2]", `*main.FooBar {Baz: 8, Bur: "h"}`, "*main.FooBar", hasChildren)
  1559  						if ref > 0 {
  1560  							client.VariablesRequest(ref)
  1561  							a13_2 := client.ExpectVariablesResponse(t)
  1562  							checkChildren(t, a13_2, "a13[2]", 1)
  1563  							ref = checkVarExact(t, a13_2, 0, "", "(*a13[2])", `main.FooBar {Baz: 8, Bur: "h"}`, "main.FooBar", hasChildren)
  1564  							validateEvaluateName(t, client, a13_2, 0)
  1565  							if ref > 0 {
  1566  								client.VariablesRequest(ref)
  1567  								val := client.ExpectVariablesResponse(t)
  1568  								checkChildren(t, val, "*a13[2]", 2)
  1569  								checkVarExact(t, val, 0, "Baz", "(*a13[2]).Baz", "8", "int", noChildren)
  1570  								checkVarExact(t, val, 1, "Bur", "(*a13[2]).Bur", `"h"`, "string", noChildren)
  1571  								validateEvaluateName(t, client, val, 0)
  1572  								validateEvaluateName(t, client, val, 1)
  1573  							}
  1574  						}
  1575  					}
  1576  					// reflect.Kind == String
  1577  					checkVarExact(t, locals, -1, "a1", "a1", `"foofoofoofoofoofoo"`, "string", noChildren)
  1578  					checkVarExact(t, locals, -1, "a10", "a10", `"ofo"`, "string", noChildren)
  1579  					// reflect.Kind == Struct
  1580  					ref = checkVarExact(t, locals, -1, "a6", "a6", `main.FooBar {Baz: 8, Bur: "word"}`, "main.FooBar", hasChildren)
  1581  					if ref > 0 {
  1582  						client.VariablesRequest(ref)
  1583  						a6 := client.ExpectVariablesResponse(t)
  1584  						checkChildren(t, a6, "a6", 2)
  1585  						checkVarExact(t, a6, 0, "Baz", "a6.Baz", "8", "int", noChildren)
  1586  						checkVarExact(t, a6, 1, "Bur", "a6.Bur", `"word"`, "string", noChildren)
  1587  					}
  1588  					ref = checkVarExact(t, locals, -1, "a8", "a8", `main.FooBar2 {Bur: 10, Baz: "feh"}`, "main.FooBar2", hasChildren)
  1589  					if ref > 0 {
  1590  						client.VariablesRequest(ref)
  1591  						a8 := client.ExpectVariablesResponse(t)
  1592  						checkChildren(t, a8, "a8", 2)
  1593  						checkVarExact(t, a8, 0, "Bur", "a8.Bur", "10", "int", noChildren)
  1594  						checkVarExact(t, a8, 1, "Baz", "a8.Baz", `"feh"`, "string", noChildren)
  1595  					}
  1596  					// reflect.Kind == UnsafePointer - see testvariables2
  1597  				},
  1598  				disconnect: false,
  1599  			}, {
  1600  				// Stop at second breakpoint
  1601  				execute: func() {
  1602  					// Frame ids get reset at each breakpoint.
  1603  					client.StackTraceRequest(1, 0, 20)
  1604  					stack := client.ExpectStackTraceResponse(t)
  1605  					checkStackFramesExact(t, stack, "main.barfoo", 27, 1000, 5, 5)
  1606  
  1607  					client.ScopesRequest(1000)
  1608  					scopes := client.ExpectScopesResponse(t)
  1609  					checkScope(t, scopes, 0, "Locals", localsScope)
  1610  					checkScope(t, scopes, 1, "Globals (package main)", globalsScope)
  1611  
  1612  					client.ScopesRequest(1111)
  1613  					erres := client.ExpectInvisibleErrorResponse(t)
  1614  					if erres.Body.Error.Format != "Unable to list locals: unknown frame id 1111" {
  1615  						t.Errorf("\ngot %#v\nwant Format=\"Unable to list locals: unknown frame id 1111\"", erres)
  1616  					}
  1617  
  1618  					client.VariablesRequest(localsScope)
  1619  					locals := client.ExpectVariablesResponse(t)
  1620  					checkChildren(t, locals, "Locals", 1)
  1621  					checkVarExact(t, locals, -1, "a1", "a1", `"bur"`, "string", noChildren)
  1622  
  1623  					client.VariablesRequest(globalsScope)
  1624  					globals := client.ExpectVariablesResponse(t)
  1625  					checkVarExact(t, globals, 0, "p1", "main.p1", "10", "int", noChildren)
  1626  
  1627  					client.VariablesRequest(7777)
  1628  					erres = client.ExpectInvisibleErrorResponse(t)
  1629  					if erres.Body.Error.Format != "Unable to lookup variable: unknown reference 7777" {
  1630  						t.Errorf("\ngot %#v\nwant Format=\"Unable to lookup variable: unknown reference 7777\"", erres)
  1631  					}
  1632  				},
  1633  				disconnect: false,
  1634  			}})
  1635  	})
  1636  }
  1637  
  1638  // TestScopesAndVariablesRequests2 executes to a breakpoint and tests different
  1639  // configurations of 'scopes' and 'variables' requests.
  1640  func TestScopesAndVariablesRequests2(t *testing.T) {
  1641  	runTest(t, "testvariables2", func(client *daptest.Client, fixture protest.Fixture) {
  1642  		runDebugSessionWithBPs(t, client, "launch",
  1643  			// Launch
  1644  			func() {
  1645  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  1646  			},
  1647  			// Breakpoints are set within the program
  1648  			fixture.Source, []int{},
  1649  			[]onBreakpoint{{
  1650  				execute: func() {
  1651  					client.StackTraceRequest(1, 0, 20)
  1652  					stack := client.ExpectStackTraceResponse(t)
  1653  					checkStackFramesExact(t, stack, "main.main", -1, 1000, 3, 3)
  1654  
  1655  					client.ScopesRequest(1000)
  1656  					scopes := client.ExpectScopesResponse(t)
  1657  					checkScope(t, scopes, 0, "Locals", localsScope)
  1658  				},
  1659  				disconnect: false,
  1660  			}, {
  1661  				execute: func() {
  1662  					client.StackTraceRequest(1, 0, 20)
  1663  					stack := client.ExpectStackTraceResponse(t)
  1664  					checkStackFramesExact(t, stack, "main.main", -1, 1000, 3, 3)
  1665  
  1666  					client.ScopesRequest(1000)
  1667  					scopes := client.ExpectScopesResponse(t)
  1668  					if len(scopes.Body.Scopes) > 1 {
  1669  						t.Errorf("\ngot  %#v\nwant len(scopes)=1 (Argumes & Locals)", scopes)
  1670  					}
  1671  					checkScope(t, scopes, 0, "Locals", localsScope)
  1672  
  1673  					// Locals
  1674  					client.VariablesRequest(localsScope)
  1675  					locals := client.ExpectVariablesResponse(t)
  1676  
  1677  					// reflect.Kind == Bool - see testvariables
  1678  					// reflect.Kind == Int - see testvariables
  1679  					// reflect.Kind == Int8
  1680  					checkVarExact(t, locals, -1, "ni8", "ni8", "-5", "int8", noChildren)
  1681  					// reflect.Kind == Int16
  1682  					checkVarExact(t, locals, -1, "ni16", "ni16", "-5", "int16", noChildren)
  1683  					// reflect.Kind == Int32
  1684  					checkVarExact(t, locals, -1, "ni32", "ni32", "-5", "int32", noChildren)
  1685  					// reflect.Kind == Int64
  1686  					checkVarExact(t, locals, -1, "ni64", "ni64", "-5", "int64", noChildren)
  1687  					// reflect.Kind == Uint
  1688  					// reflect.Kind == Uint8 - see testvariables
  1689  					// reflect.Kind == Uint16 - see testvariables
  1690  					// reflect.Kind == Uint32 - see testvariables
  1691  					// reflect.Kind == Uint64 - see testvariables
  1692  					// reflect.Kind == Uintptr - see testvariables
  1693  					// reflect.Kind == Float32 - see testvariables
  1694  					// reflect.Kind == Float64
  1695  					checkVarExact(t, locals, -1, "pinf", "pinf", "+Inf", "float64", noChildren)
  1696  					checkVarExact(t, locals, -1, "ninf", "ninf", "-Inf", "float64", noChildren)
  1697  					checkVarExact(t, locals, -1, "nan", "nan", "NaN", "float64", noChildren)
  1698  					// reflect.Kind == Complex64 - see testvariables
  1699  					// reflect.Kind == Complex128 - see testvariables
  1700  					// reflect.Kind == Array
  1701  					checkVarExact(t, locals, -1, "a0", "a0", "[0]int []", "[0]int", noChildren)
  1702  					// reflect.Kind == Chan
  1703  					ref := checkVarExact(t, locals, -1, "ch1", "ch1", "chan int 4/11", "chan int", hasChildren)
  1704  					if ref > 0 {
  1705  						client.VariablesRequest(ref)
  1706  						ch1 := client.ExpectVariablesResponse(t)
  1707  						checkChildren(t, ch1, "ch1", 11)
  1708  						checkVarExact(t, ch1, 0, "qcount", "ch1.qcount", "4 = 0x4", "uint", noChildren)
  1709  						checkVarRegex(t, ch1, 10, "lock", "ch1.lock", `runtime\.mutex {.*key: 0.*}`, `runtime\.mutex`, hasChildren)
  1710  						validateEvaluateName(t, client, ch1, 0)
  1711  						validateEvaluateName(t, client, ch1, 10)
  1712  					}
  1713  					checkVarExact(t, locals, -1, "chnil", "chnil", "chan int nil", "chan int", noChildren)
  1714  					// reflect.Kind == Func
  1715  					checkVarExact(t, locals, -1, "fn1", "fn1", "main.afunc", "main.functype", noChildren)
  1716  					checkVarExact(t, locals, -1, "fn2", "fn2", "nil", "main.functype", noChildren)
  1717  					// reflect.Kind == Interface
  1718  					checkVarExact(t, locals, -1, "ifacenil", "ifacenil", "interface {} nil", "interface {}", noChildren)
  1719  					ref = checkVarExact(t, locals, -1, "iface2", "iface2", "interface {}(string) \"test\"", "interface {}", hasChildren)
  1720  					if ref > 0 {
  1721  						client.VariablesRequest(ref)
  1722  						iface2 := client.ExpectVariablesResponse(t)
  1723  						checkChildren(t, iface2, "iface2", 1)
  1724  						checkVarExact(t, iface2, 0, "data", "iface2.(data)", `"test"`, "string", noChildren)
  1725  						validateEvaluateName(t, client, iface2, 0)
  1726  					}
  1727  					ref = checkVarExact(t, locals, -1, "iface4", "iface4", "interface {}([]go/constant.Value) [4]", "interface {}", hasChildren)
  1728  					if ref > 0 {
  1729  						client.VariablesRequest(ref)
  1730  						iface4 := client.ExpectVariablesResponse(t)
  1731  						checkChildren(t, iface4, "iface4", 1)
  1732  						ref = checkVarExact(t, iface4, 0, "data", "iface4.(data)", "[]go/constant.Value len: 1, cap: 1, [4]", "[]go/constant.Value", hasChildren)
  1733  						if ref > 0 {
  1734  							client.VariablesRequest(ref)
  1735  							iface4data := client.ExpectVariablesResponse(t)
  1736  							checkChildren(t, iface4data, "iface4.data", 1)
  1737  							ref = checkVarExact(t, iface4data, 0, "[0]", "iface4.(data)[0]", "go/constant.Value(go/constant.int64Val) 4", "go/constant.Value", hasChildren)
  1738  							if ref > 0 {
  1739  								client.VariablesRequest(ref)
  1740  								iface4data0 := client.ExpectVariablesResponse(t)
  1741  								checkChildren(t, iface4data0, "iface4.data[0]", 1)
  1742  								checkVarExact(t, iface4data0, 0, "data", "iface4.(data)[0].(data)", "4", "go/constant.int64Val", noChildren)
  1743  								validateEvaluateName(t, client, iface4data0, 0)
  1744  							}
  1745  						}
  1746  					}
  1747  					checkVarExact(t, locals, -1, "errnil", "errnil", "error nil", "error", noChildren)
  1748  					ref = checkVarExact(t, locals, -1, "err1", "err1", "error(*main.astruct) *{A: 1, B: 2}", "error", hasChildren)
  1749  					if ref > 0 {
  1750  						client.VariablesRequest(ref)
  1751  						err1 := client.ExpectVariablesResponse(t)
  1752  						checkChildren(t, err1, "err1", 1)
  1753  						checkVarExact(t, err1, 0, "data", "err1.(data)", "*main.astruct {A: 1, B: 2}", "*main.astruct", hasChildren)
  1754  						validateEvaluateName(t, client, err1, 0)
  1755  					}
  1756  					ref = checkVarExact(t, locals, -1, "ptrinf", "ptrinf", "*interface {}(**interface {}) **...", "*interface {}", hasChildren)
  1757  					if ref > 0 {
  1758  						client.VariablesRequest(ref)
  1759  						ptrinf_val := client.ExpectVariablesResponse(t)
  1760  						checkChildren(t, ptrinf_val, "*ptrinf", 1)
  1761  						ref = checkVarExact(t, ptrinf_val, 0, "", "(*ptrinf)", "interface {}(**interface {}) **...", "interface {}", hasChildren)
  1762  						if ref > 0 {
  1763  							client.VariablesRequest(ref)
  1764  							ptrinf_val_data := client.ExpectVariablesResponse(t)
  1765  							checkChildren(t, ptrinf_val_data, "(*ptrinf).data", 1)
  1766  							checkVarExact(t, ptrinf_val_data, 0, "data", "(*ptrinf).(data)", "**interface {}(**interface {}) ...", "**interface {}", hasChildren)
  1767  							validateEvaluateName(t, client, ptrinf_val_data, 0)
  1768  						}
  1769  					}
  1770  					// reflect.Kind == Map
  1771  					checkVarExact(t, locals, -1, "mnil", "mnil", "map[string]main.astruct nil", "map[string]main.astruct", noChildren)
  1772  					// key - scalar, value - compound
  1773  					ref = checkVarExact(t, locals, -1, "m2", "m2", "map[int]*main.astruct [1: *{A: 10, B: 11}, ]", "map[int]*main.astruct", hasChildren)
  1774  					if ref > 0 {
  1775  						client.VariablesRequest(ref)
  1776  						m2 := client.ExpectVariablesResponse(t)
  1777  						checkChildren(t, m2, "m2", 2) // each key-value represented by a single child
  1778  						checkVarExact(t, m2, 0, "len()", "len(m2)", "1", "int", noChildren)
  1779  						ref = checkVarExact(t, m2, 1, "1", "m2[1]", "*main.astruct {A: 10, B: 11}", "int: *main.astruct", hasChildren)
  1780  						if ref > 0 {
  1781  							client.VariablesRequest(ref)
  1782  							m2kv1 := client.ExpectVariablesResponse(t)
  1783  							checkChildren(t, m2kv1, "m2[1]", 1)
  1784  							ref = checkVarExact(t, m2kv1, 0, "", "(*m2[1])", "main.astruct {A: 10, B: 11}", "main.astruct", hasChildren)
  1785  							if ref > 0 {
  1786  								client.VariablesRequest(ref)
  1787  								m2kv1deref := client.ExpectVariablesResponse(t)
  1788  								checkChildren(t, m2kv1deref, "*m2[1]", 2)
  1789  								checkVarExact(t, m2kv1deref, 0, "A", "(*m2[1]).A", "10", "int", noChildren)
  1790  								checkVarExact(t, m2kv1deref, 1, "B", "(*m2[1]).B", "11", "int", noChildren)
  1791  								validateEvaluateName(t, client, m2kv1deref, 0)
  1792  								validateEvaluateName(t, client, m2kv1deref, 1)
  1793  							}
  1794  						}
  1795  					}
  1796  					// key - compound, value - scalar
  1797  					ref = checkVarExact(t, locals, -1, "m3", "m3", "map[main.astruct]int [{A: 1, B: 1}: 42, {A: 2, B: 2}: 43, ]", "map[main.astruct]int", hasChildren)
  1798  					if ref > 0 {
  1799  						client.VariablesRequest(ref)
  1800  						m3 := client.ExpectVariablesResponse(t)
  1801  						checkChildren(t, m3, "m3", 3) // each key-value represented by a single child
  1802  						checkVarExact(t, m3, 0, "len()", "len(m3)", "2", "int", noChildren)
  1803  						ref = checkVarRegex(t, m3, 1, `main\.astruct {A: 1, B: 1}`, `m3\[\(\*\(\*"main.astruct"\)\(0x[0-9a-f]+\)\)\]`, "42", "int", hasChildren)
  1804  						if ref > 0 {
  1805  							client.VariablesRequest(ref)
  1806  							m3kv0 := client.ExpectVariablesResponse(t)
  1807  							checkChildren(t, m3kv0, "m3[0]", 2)
  1808  							checkVarRegex(t, m3kv0, 0, "A", `\(*\(*"main\.astruct"\)\(0x[0-9a-f]+\)\)\.A`, "1", "int", noChildren)
  1809  							validateEvaluateName(t, client, m3kv0, 0)
  1810  						}
  1811  						ref = checkVarRegex(t, m3, 2, `main\.astruct {A: 2, B: 2}`, `m3\[\(\*\(\*"main.astruct"\)\(0x[0-9a-f]+\)\)\]`, "43", "", hasChildren)
  1812  						if ref > 0 { // inspect another key from another key-value child
  1813  							client.VariablesRequest(ref)
  1814  							m3kv1 := client.ExpectVariablesResponse(t)
  1815  							checkChildren(t, m3kv1, "m3[1]", 2)
  1816  							checkVarRegex(t, m3kv1, 1, "B", `\(*\(*"main\.astruct"\)\(0x[0-9a-f]+\)\)\.B`, "2", "int", noChildren)
  1817  							validateEvaluateName(t, client, m3kv1, 1)
  1818  						}
  1819  					}
  1820  					// key - compound, value - compound
  1821  					ref = checkVarExact(t, locals, -1, "m4", "m4", "map[main.astruct]main.astruct [{A: 1, B: 1}: {A: 11, B: 11}, {A: 2, B: 2}: {A: 22, B: 22}, ]", "map[main.astruct]main.astruct", hasChildren)
  1822  					if ref > 0 {
  1823  						client.VariablesRequest(ref)
  1824  						m4 := client.ExpectVariablesResponse(t)
  1825  						checkChildren(t, m4, "m4", 5) // each key and value represented by a child, so double the key-value count
  1826  						checkVarExact(t, m4, 0, "len()", "len(m4)", "2", "int", noChildren)
  1827  						checkVarRegex(t, m4, 1, `\[key 0\]`, `\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)`, `main\.astruct {A: 1, B: 1}`, `main\.astruct`, hasChildren)
  1828  						checkVarRegex(t, m4, 2, `\[val 0\]`, `m4\[\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\]`, `main\.astruct {A: 11, B: 11}`, `main\.astruct`, hasChildren)
  1829  						ref = checkVarRegex(t, m4, 3, `\[key 1\]`, `\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)`, `main\.astruct {A: 2, B: 2}`, `main\.astruct`, hasChildren)
  1830  						if ref > 0 {
  1831  							client.VariablesRequest(ref)
  1832  							m4Key1 := client.ExpectVariablesResponse(t)
  1833  							checkChildren(t, m4Key1, "m4Key1", 2)
  1834  							checkVarRegex(t, m4Key1, 0, "A", `\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\.A`, "2", "int", noChildren)
  1835  							checkVarRegex(t, m4Key1, 1, "B", `\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\.B`, "2", "int", noChildren)
  1836  							validateEvaluateName(t, client, m4Key1, 0)
  1837  							validateEvaluateName(t, client, m4Key1, 1)
  1838  						}
  1839  						ref = checkVarRegex(t, m4, 4, `\[val 1\]`, `m4\[\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\]`, `main\.astruct {A: 22, B: 22}`, "main.astruct", hasChildren)
  1840  						if ref > 0 {
  1841  							client.VariablesRequest(ref)
  1842  							m4Val1 := client.ExpectVariablesResponse(t)
  1843  							checkChildren(t, m4Val1, "m4Val1", 2)
  1844  							checkVarRegex(t, m4Val1, 0, "A", `m4\[\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\]\.A`, "22", "int", noChildren)
  1845  							checkVarRegex(t, m4Val1, 1, "B", `m4\[\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\]\.B`, "22", "int", noChildren)
  1846  							validateEvaluateName(t, client, m4Val1, 0)
  1847  							validateEvaluateName(t, client, m4Val1, 1)
  1848  						}
  1849  					}
  1850  					checkVarExact(t, locals, -1, "emptymap", "emptymap", "map[string]string []", "map[string]string", noChildren)
  1851  					// reflect.Kind == Ptr
  1852  					ref = checkVarExact(t, locals, -1, "pp1", "pp1", "**1", "**int", hasChildren)
  1853  					if ref > 0 {
  1854  						client.VariablesRequest(ref)
  1855  						pp1val := client.ExpectVariablesResponse(t)
  1856  						checkChildren(t, pp1val, "*pp1", 1)
  1857  						ref = checkVarExact(t, pp1val, 0, "", "(*pp1)", "*1", "*int", hasChildren)
  1858  						if ref > 0 {
  1859  							client.VariablesRequest(ref)
  1860  							pp1valval := client.ExpectVariablesResponse(t)
  1861  							checkChildren(t, pp1valval, "*(*pp1)", 1)
  1862  							checkVarExact(t, pp1valval, 0, "", "(*(*pp1))", "1", "int", noChildren)
  1863  							validateEvaluateName(t, client, pp1valval, 0)
  1864  						}
  1865  					}
  1866  					// reflect.Kind == Slice
  1867  					ref = checkVarExact(t, locals, -1, "zsslice", "zsslice", "[]struct {} len: 3, cap: 3, [{},{},{}]", "[]struct {}", hasChildren)
  1868  					if ref > 0 {
  1869  						client.VariablesRequest(ref)
  1870  						zsslice := client.ExpectVariablesResponse(t)
  1871  						checkChildren(t, zsslice, "zsslice", 3)
  1872  						checkVarExact(t, zsslice, 2, "[2]", "zsslice[2]", "struct {} {}", "struct {}", noChildren)
  1873  						validateEvaluateName(t, client, zsslice, 2)
  1874  					}
  1875  					checkVarExact(t, locals, -1, "emptyslice", "emptyslice", "[]string len: 0, cap: 0, []", "[]string", noChildren)
  1876  					checkVarExact(t, locals, -1, "nilslice", "nilslice", "[]int len: 0, cap: 0, nil", "[]int", noChildren)
  1877  					// reflect.Kind == String
  1878  					checkVarExact(t, locals, -1, "longstr", "longstr", longstr, "string", noChildren)
  1879  					// reflect.Kind == Struct
  1880  					checkVarExact(t, locals, -1, "zsvar", "zsvar", "struct {} {}", "struct {}", noChildren)
  1881  					// reflect.Kind == UnsafePointer
  1882  					// TODO(polina): how do I test for unsafe.Pointer(nil)?
  1883  					checkVarRegex(t, locals, -1, "upnil", "upnil", `unsafe\.Pointer\(0x0\)`, "int", noChildren)
  1884  					checkVarRegex(t, locals, -1, "up1", "up1", `unsafe\.Pointer\(0x[0-9a-f]+\)`, "int", noChildren)
  1885  
  1886  					// Test unreadable variable
  1887  					ref = checkVarRegex(t, locals, -1, "unread", "unread", `\*\(unreadable .+\)`, "int", hasChildren)
  1888  					if ref > 0 {
  1889  						client.VariablesRequest(ref)
  1890  						val := client.ExpectVariablesResponse(t)
  1891  						checkChildren(t, val, "*unread", 1)
  1892  						checkVarRegex(t, val, 0, "^$", `\(\*unread\)`, `\(unreadable .+\)`, "int", noChildren)
  1893  						validateEvaluateName(t, client, val, 0)
  1894  					}
  1895  				},
  1896  				disconnect: true,
  1897  			}})
  1898  	})
  1899  }
  1900  
  1901  // TestScopesRequestsOptimized executes to a breakpoint and tests different
  1902  // that the name of the "Locals" scope is correctly annotated with
  1903  // a warning about debugging an optimized function.
  1904  func TestScopesRequestsOptimized(t *testing.T) {
  1905  	runTestBuildFlags(t, "testvariables", func(client *daptest.Client, fixture protest.Fixture) {
  1906  		runDebugSessionWithBPs(t, client, "launch",
  1907  			// Launch
  1908  			func() {
  1909  				client.LaunchRequestWithArgs(map[string]interface{}{
  1910  					"mode": "exec", "program": fixture.Path, "showGlobalVariables": true,
  1911  				})
  1912  			},
  1913  			// Breakpoints are set within the program
  1914  			fixture.Source, []int{},
  1915  			[]onBreakpoint{{
  1916  				// Stop at first breakpoint
  1917  				execute: func() {
  1918  					client.StackTraceRequest(1, 0, 20)
  1919  					stack := client.ExpectStackTraceResponse(t)
  1920  
  1921  					startLineno := 66
  1922  					if runtime.GOOS == "windows" && goversion.VersionAfterOrEqual(runtime.Version(), 1, 15) {
  1923  						// Go1.15 on windows inserts a NOP after the call to
  1924  						// runtime.Breakpoint and marks it same line as the
  1925  						// runtime.Breakpoint call, making this flaky, so skip the line check.
  1926  						startLineno = -1
  1927  					}
  1928  
  1929  					checkStackFramesExact(t, stack, "main.foobar", startLineno, 1000, 4, 4)
  1930  
  1931  					client.ScopesRequest(1000)
  1932  					scopes := client.ExpectScopesResponse(t)
  1933  					checkScope(t, scopes, 0, "Locals (warning: optimized function)", localsScope)
  1934  					checkScope(t, scopes, 1, "Globals (package main)", globalsScope)
  1935  				},
  1936  				disconnect: false,
  1937  			}, {
  1938  				// Stop at second breakpoint
  1939  				execute: func() {
  1940  					// Frame ids get reset at each breakpoint.
  1941  					client.StackTraceRequest(1, 0, 20)
  1942  					stack := client.ExpectStackTraceResponse(t)
  1943  					checkStackFramesExact(t, stack, "main.barfoo", 27, 1000, 5, 5)
  1944  
  1945  					client.ScopesRequest(1000)
  1946  					scopes := client.ExpectScopesResponse(t)
  1947  					checkScope(t, scopes, 0, "Locals (warning: optimized function)", localsScope)
  1948  					checkScope(t, scopes, 1, "Globals (package main)", globalsScope)
  1949  				},
  1950  				disconnect: false,
  1951  			}})
  1952  	},
  1953  		protest.EnableOptimization)
  1954  }
  1955  
  1956  // TestVariablesLoading exposes test cases where variables might be partially or
  1957  // fully unloaded.
  1958  func TestVariablesLoading(t *testing.T) {
  1959  	runTest(t, "testvariables2", func(client *daptest.Client, fixture protest.Fixture) {
  1960  		runDebugSessionWithBPs(t, client, "launch",
  1961  			// Launch
  1962  			func() {
  1963  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  1964  			},
  1965  			// Breakpoints are set within the program
  1966  			fixture.Source, []int{},
  1967  			[]onBreakpoint{{
  1968  				execute:    func() {},
  1969  				disconnect: false,
  1970  			}, {
  1971  				execute: func() {
  1972  					// Change default config values to trigger certain unloaded corner cases
  1973  					saveDefaultConfig := DefaultLoadConfig
  1974  					DefaultLoadConfig.MaxStructFields = 5
  1975  					DefaultLoadConfig.MaxStringLen = 64
  1976  					defer func() {
  1977  						DefaultLoadConfig = saveDefaultConfig
  1978  					}()
  1979  
  1980  					client.StackTraceRequest(1, 0, 0)
  1981  					client.ExpectStackTraceResponse(t)
  1982  
  1983  					client.ScopesRequest(1000)
  1984  					client.ExpectScopesResponse(t)
  1985  
  1986  					client.VariablesRequest(localsScope)
  1987  					locals := client.ExpectVariablesResponse(t)
  1988  
  1989  					// String partially missing based on LoadConfig.MaxStringLen
  1990  					// See also TestVariableLoadingOfLongStrings
  1991  					checkVarExact(t, locals, -1, "longstr", "longstr", longstrLoaded64, "string", noChildren)
  1992  
  1993  					checkArrayChildren := func(t *testing.T, longarr *dap.VariablesResponse, parentName string, start int) {
  1994  						t.Helper()
  1995  						for i, child := range longarr.Body.Variables {
  1996  							idx := start + i
  1997  							if child.Name != fmt.Sprintf("[%d]", idx) || child.EvaluateName != fmt.Sprintf("%s[%d]", parentName, idx) {
  1998  								t.Errorf("Expected %s[%d] to have Name=\"[%d]\" EvaluateName=\"%s[%d]\", got %#v", parentName, idx, idx, parentName, idx, child)
  1999  							}
  2000  						}
  2001  					}
  2002  
  2003  					// Array not fully loaded based on LoadConfig.MaxArrayValues.
  2004  					// Expect to be able to load array by paging.
  2005  					ref := checkVarExactIndexed(t, locals, -1, "longarr", "longarr", "[100]int [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,...+36 more]", "[100]int", hasChildren, 100, 0)
  2006  					if ref > 0 {
  2007  						client.VariablesRequest(ref)
  2008  						longarr := client.ExpectVariablesResponse(t)
  2009  						checkChildren(t, longarr, "longarr", 64)
  2010  						checkArrayChildren(t, longarr, "longarr", 0)
  2011  
  2012  						client.IndexedVariablesRequest(ref, 0, 100)
  2013  						longarr = client.ExpectVariablesResponse(t)
  2014  						checkChildren(t, longarr, "longarr", 100)
  2015  						checkArrayChildren(t, longarr, "longarr", 0)
  2016  
  2017  						client.IndexedVariablesRequest(ref, 50, 50)
  2018  						longarr = client.ExpectVariablesResponse(t)
  2019  						checkChildren(t, longarr, "longarr", 50)
  2020  						checkArrayChildren(t, longarr, "longarr", 50)
  2021  					}
  2022  
  2023  					// Slice not fully loaded based on LoadConfig.MaxArrayValues.
  2024  					// Expect to be able to load slice by paging.
  2025  					ref = checkVarExactIndexed(t, locals, -1, "longslice", "longslice", "[]int len: 100, cap: 100, [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,...+36 more]", "[]int", hasChildren, 100, 0)
  2026  					if ref > 0 {
  2027  						client.VariablesRequest(ref)
  2028  						longarr := client.ExpectVariablesResponse(t)
  2029  						checkChildren(t, longarr, "longslice", 64)
  2030  						checkArrayChildren(t, longarr, "longslice", 0)
  2031  
  2032  						client.IndexedVariablesRequest(ref, 0, 100)
  2033  						longarr = client.ExpectVariablesResponse(t)
  2034  						checkChildren(t, longarr, "longslice", 100)
  2035  						checkArrayChildren(t, longarr, "longslice", 0)
  2036  
  2037  						client.IndexedVariablesRequest(ref, 50, 50)
  2038  						longarr = client.ExpectVariablesResponse(t)
  2039  						checkChildren(t, longarr, "longslice", 50)
  2040  						checkArrayChildren(t, longarr, "longslice", 50)
  2041  					}
  2042  
  2043  					// Map not fully loaded based on LoadConfig.MaxArrayValues
  2044  					// Expect to be able to load map by paging.
  2045  					ref = checkVarRegexIndexed(t, locals, -1, "m1", "m1", `map\[string\]main\.astruct \[.+\.\.\.`, `map\[string\]main\.astruct`, hasChildren, 66, 1)
  2046  					if ref > 0 {
  2047  						client.VariablesRequest(ref)
  2048  						m1 := client.ExpectVariablesResponse(t)
  2049  						checkChildren(t, m1, "m1", 65)
  2050  
  2051  						client.IndexedVariablesRequest(ref, 0, 66)
  2052  						m1 = client.ExpectVariablesResponse(t)
  2053  						checkChildren(t, m1, "m1", 66)
  2054  
  2055  						client.IndexedVariablesRequest(ref, 0, 33)
  2056  						m1part1 := client.ExpectVariablesResponse(t)
  2057  						checkChildren(t, m1part1, "m1", 33)
  2058  
  2059  						client.IndexedVariablesRequest(ref, 33, 33)
  2060  						m1part2 := client.ExpectVariablesResponse(t)
  2061  						checkChildren(t, m1part2, "m1", 33)
  2062  
  2063  						if len(m1part1.Body.Variables)+len(m1part2.Body.Variables) == len(m1.Body.Variables) {
  2064  							for i, got := range m1part1.Body.Variables {
  2065  								want := m1.Body.Variables[i]
  2066  								if got.Name != want.Name || got.Value != want.Value {
  2067  									t.Errorf("got %#v, want Name=%q Value=%q", got, want.Name, want.Value)
  2068  								}
  2069  							}
  2070  							for i, got := range m1part2.Body.Variables {
  2071  								want := m1.Body.Variables[i+len(m1part1.Body.Variables)]
  2072  								if got.Name != want.Name || got.Value != want.Value {
  2073  									t.Errorf("got %#v, want Name=%q Value=%q", got, want.Name, want.Value)
  2074  								}
  2075  							}
  2076  						}
  2077  						client.NamedVariablesRequest(ref)
  2078  						named := client.ExpectVariablesResponse(t)
  2079  						checkChildren(t, named, "m1", 1)
  2080  						checkVarExact(t, named, 0, "len()", "len(m1)", "66", "int", noChildren)
  2081  					}
  2082  
  2083  					// Struct partially missing based on LoadConfig.MaxStructFields
  2084  					ref = checkVarExact(t, locals, -1, "sd", "sd", "(loaded 5/6) main.D {u1: 0, u2: 0, u3: 0, u4: 0, u5: 0,...+1 more}", "main.D", hasChildren)
  2085  					if ref > 0 {
  2086  						client.VariablesRequest(ref)
  2087  						sd := client.ExpectVariablesResponse(t)
  2088  						checkChildren(t, sd, "sd", 5)
  2089  					}
  2090  
  2091  					// Fully missing struct auto-loaded when reaching LoadConfig.MaxVariableRecurse (also tests evaluateName corner case)
  2092  					ref = checkVarRegex(t, locals, -1, "c1", "c1", `main\.cstruct {pb: \*main\.bstruct {a: \(\*main\.astruct\)\(0x[0-9a-f]+\)}, sa: []\*main\.astruct len: 3, cap: 3, [\*\(\*main\.astruct\)\(0x[0-9a-f]+\),\*\(\*main\.astruct\)\(0x[0-9a-f]+\),\*\(\*main.astruct\)\(0x[0-9a-f]+\)]}`, `main\.cstruct`, hasChildren)
  2093  					if ref > 0 {
  2094  						client.VariablesRequest(ref)
  2095  						c1 := client.ExpectVariablesResponse(t)
  2096  						checkChildren(t, c1, "c1", 2)
  2097  						ref = checkVarRegex(t, c1, 1, "sa", `c1\.sa`, `\[\]\*main\.astruct len: 3, cap: 3, \[\*\(\*main\.astruct\)\(0x[0-9a-f]+\),\*\(\*main\.astruct\)\(0x[0-9a-f]+\),\*\(\*main\.astruct\)\(0x[0-9a-f]+\)\]`, `\[\]\*main\.astruct`, hasChildren)
  2098  						if ref > 0 {
  2099  							client.VariablesRequest(ref)
  2100  							c1sa := client.ExpectVariablesResponse(t)
  2101  							checkChildren(t, c1sa, "c1.sa", 3)
  2102  							ref = checkVarRegex(t, c1sa, 0, `\[0\]`, `c1\.sa\[0\]`, `\*\(\*main\.astruct\)\(0x[0-9a-f]+\)`, `\*main\.astruct`, hasChildren)
  2103  							if ref > 0 {
  2104  								// Auto-loading of fully missing struc children happens here
  2105  								client.VariablesRequest(ref)
  2106  								c1sa0 := client.ExpectVariablesResponse(t)
  2107  								checkChildren(t, c1sa0, "c1.sa[0]", 1)
  2108  								// TODO(polina): there should be children here once we support auto loading
  2109  								checkVarExact(t, c1sa0, 0, "", "(*c1.sa[0])", "main.astruct {A: 1, B: 2}", "main.astruct", hasChildren)
  2110  							}
  2111  						}
  2112  					}
  2113  
  2114  					// Fully missing struct auto-loaded when hitting LoadConfig.MaxVariableRecurse (also tests evaluteName corner case)
  2115  					ref = checkVarRegex(t, locals, -1, "aas", "aas", `\[\]main\.a len: 1, cap: 1, \[{aas: \[\]main\.a len: 1, cap: 1, \[\(\*main\.a\)\(0x[0-9a-f]+\)\]}\]`, `\[\]main\.a`, hasChildren)
  2116  					if ref > 0 {
  2117  						client.VariablesRequest(ref)
  2118  						aas := client.ExpectVariablesResponse(t)
  2119  						checkChildren(t, aas, "aas", 1)
  2120  						ref = checkVarRegex(t, aas, 0, "[0]", `aas\[0\]`, `main\.a {aas: \[\]main.a len: 1, cap: 1, \[\(\*main\.a\)\(0x[0-9a-f]+\)\]}`, `main\.a`, hasChildren)
  2121  						if ref > 0 {
  2122  							client.VariablesRequest(ref)
  2123  							aas0 := client.ExpectVariablesResponse(t)
  2124  							checkChildren(t, aas0, "aas[0]", 1)
  2125  							ref = checkVarRegex(t, aas0, 0, "aas", `aas\[0\]\.aas`, `\[\]main\.a len: 1, cap: 1, \[\(\*main\.a\)\(0x[0-9a-f]+\)\]`, `\[\]main\.a`, hasChildren)
  2126  							if ref > 0 {
  2127  								// Auto-loading of fully missing struct children happens here
  2128  								client.VariablesRequest(ref)
  2129  								aas0aas := client.ExpectVariablesResponse(t)
  2130  								checkChildren(t, aas0aas, "aas[0].aas", 1)
  2131  								// TODO(polina): there should be a child here once we support auto loading - test for "aas[0].aas[0].aas"
  2132  								ref = checkVarRegex(t, aas0aas, 0, "[0]", `aas\[0\]\.aas\[0\]`, `main\.a {aas: \[\]main\.a len: 1, cap: 1, \[\(\*main\.a\)\(0x[0-9a-f]+\)\]}`, "main.a", hasChildren)
  2133  								if ref > 0 {
  2134  									client.VariablesRequest(ref)
  2135  									aas0aas0 := client.ExpectVariablesResponse(t)
  2136  									checkChildren(t, aas0aas, "aas[0].aas[0]", 1)
  2137  									checkVarRegex(t, aas0aas0, 0, "aas", `aas\[0\]\.aas\[0\]\.aas`, `\[\]main\.a len: 1, cap: 1, \[\(\*main\.a\)\(0x[0-9a-f]+\)\]`, `\[\]main\.a`, hasChildren)
  2138  								}
  2139  							}
  2140  						}
  2141  					}
  2142  
  2143  					// Fully missing map auto-loaded when hitting LoadConfig.MaxVariableRecurse (also tests evaluateName corner case)
  2144  					ref = checkVarExact(t, locals, -1, "tm", "tm", "main.truncatedMap {v: []map[string]main.astruct len: 1, cap: 1, [[...]]}", "main.truncatedMap", hasChildren)
  2145  					if ref > 0 {
  2146  						client.VariablesRequest(ref)
  2147  						tm := client.ExpectVariablesResponse(t)
  2148  						checkChildren(t, tm, "tm", 1)
  2149  						ref = checkVarExact(t, tm, 0, "v", "tm.v", "[]map[string]main.astruct len: 1, cap: 1, [[...]]", "[]map[string]main.astruct", hasChildren)
  2150  						if ref > 0 {
  2151  							// Auto-loading of fully missing map chidlren happens here, but they get trancated at MaxArrayValuess
  2152  							client.VariablesRequest(ref)
  2153  							tmV := client.ExpectVariablesResponse(t)
  2154  							checkChildren(t, tmV, "tm.v", 1)
  2155  							ref = checkVarRegex(t, tmV, 0, `\[0\]`, `tm\.v\[0\]`, `map\[string\]main\.astruct \[.+\.\.\.`, `map\[string\]main\.astruct`, hasChildren)
  2156  							if ref > 0 {
  2157  								client.VariablesRequest(ref)
  2158  								tmV0 := client.ExpectVariablesResponse(t)
  2159  								checkChildren(t, tmV0, "tm.v[0]", 65)
  2160  							}
  2161  						}
  2162  					}
  2163  
  2164  					// Auto-loading works with call return variables as well
  2165  					protest.MustSupportFunctionCalls(t, testBackend)
  2166  					client.EvaluateRequest("call rettm()", 1000, "repl")
  2167  					got := client.ExpectEvaluateResponse(t)
  2168  					ref = checkEval(t, got, "main.truncatedMap {v: []map[string]main.astruct len: 1, cap: 1, [[...]]}", hasChildren)
  2169  					if ref > 0 {
  2170  						client.VariablesRequest(ref)
  2171  						rv := client.ExpectVariablesResponse(t)
  2172  						checkChildren(t, rv, "rv", 1)
  2173  						ref = checkVarExact(t, rv, 0, "~r0", "", "main.truncatedMap {v: []map[string]main.astruct len: 1, cap: 1, [[...]]}", "main.truncatedMap", hasChildren)
  2174  						if ref > 0 {
  2175  							client.VariablesRequest(ref)
  2176  							tm := client.ExpectVariablesResponse(t)
  2177  							checkChildren(t, tm, "tm", 1)
  2178  							ref = checkVarExact(t, tm, 0, "v", "", "[]map[string]main.astruct len: 1, cap: 1, [[...]]", "[]map[string]main.astruct", hasChildren)
  2179  							if ref > 0 {
  2180  								// Auto-loading of fully missing map chidlren happens here, but they get trancated at MaxArrayValuess
  2181  								client.VariablesRequest(ref)
  2182  								tmV := client.ExpectVariablesResponse(t)
  2183  								checkChildren(t, tmV, "tm.v", 1)
  2184  								// TODO(polina): this evaluate name is not usable - it should be empty
  2185  								ref = checkVarRegex(t, tmV, 0, `\[0\]`, `\[0\]`, `map\[string\]main\.astruct \[.+\.\.\.`, `map\[string\]main\.astruct`, hasChildren)
  2186  								if ref > 0 {
  2187  									client.VariablesRequest(ref)
  2188  									tmV0 := client.ExpectVariablesResponse(t)
  2189  									checkChildren(t, tmV0, "tm.v[0]", 65)
  2190  								}
  2191  							}
  2192  						}
  2193  					}
  2194  
  2195  					// TODO(polina): need fully missing array/slice test case
  2196  
  2197  					// Zero slices, structs and maps are not treated as fully missing
  2198  					// See zsvar, zsslice,, emptyslice, emptymap, a0
  2199  				},
  2200  				disconnect: true,
  2201  			}})
  2202  	})
  2203  	runTest(t, "testvariables", func(client *daptest.Client, fixture protest.Fixture) {
  2204  		runDebugSessionWithBPs(t, client, "launch",
  2205  			// Launch
  2206  			func() {
  2207  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  2208  			},
  2209  			// Breakpoints are set within the program
  2210  			fixture.Source, []int{},
  2211  			[]onBreakpoint{{
  2212  				execute: func() {
  2213  					DefaultLoadConfig.FollowPointers = false
  2214  					defer func() { DefaultLoadConfig.FollowPointers = true }()
  2215  
  2216  					client.StackTraceRequest(1, 0, 0)
  2217  					client.ExpectStackTraceResponse(t)
  2218  
  2219  					var loadvars = func(frame int) {
  2220  						client.ScopesRequest(frame)
  2221  						scopes := client.ExpectScopesResponse(t)
  2222  						localsRef := 0
  2223  						for _, s := range scopes.Body.Scopes {
  2224  							if s.Name == "Locals" {
  2225  								localsRef = s.VariablesReference
  2226  							}
  2227  						}
  2228  
  2229  						client.VariablesRequest(localsRef)
  2230  						locals := client.ExpectVariablesResponse(t)
  2231  
  2232  						// Interface auto-loaded when hitting LoadConfig.MaxVariableRecurse=1
  2233  
  2234  						ref := checkVarRegex(t, locals, -1, "ni", "ni", `\[\]interface {} len: 1, cap: 1, \[\[\]interface {} len: 1, cap: 1, \[\*\(\*interface {}\)\(0x[0-9a-f]+\)\]\]`, `\[\]interface {}`, hasChildren)
  2235  						if ref > 0 {
  2236  							client.VariablesRequest(ref)
  2237  							ni := client.ExpectVariablesResponse(t)
  2238  							ref = checkVarRegex(t, ni, 0, `\[0\]`, `ni\[0\]`, `interface \{\}\(\[\]interface \{\}\) \[\*\(\*interface \{\}\)\(0x[0-9a-f]+\)\]`, "interface {}", hasChildren)
  2239  							if ref > 0 {
  2240  								client.VariablesRequest(ref)
  2241  								niI1 := client.ExpectVariablesResponse(t)
  2242  								ref = checkVarRegex(t, niI1, 0, "data", `ni\[0\]\.\(data\)`, `\[\]interface {} len: 1, cap: 1, \[\*\(\*interface {}\)\(0x[0-9a-f]+\)`, `\[\]interface {}`, hasChildren)
  2243  								if ref > 0 {
  2244  									// Auto-loading happens here
  2245  									client.VariablesRequest(ref)
  2246  									niI1Data := client.ExpectVariablesResponse(t)
  2247  									ref = checkVarExact(t, niI1Data, 0, "[0]", "ni[0].(data)[0]", "interface {}(int) 123", "interface {}", hasChildren)
  2248  									if ref > 0 {
  2249  										client.VariablesRequest(ref)
  2250  										niI1DataI2 := client.ExpectVariablesResponse(t)
  2251  										checkVarExact(t, niI1DataI2, 0, "data", "ni[0].(data)[0].(data)", "123", "int", noChildren)
  2252  									}
  2253  								}
  2254  							}
  2255  						}
  2256  
  2257  						// Pointer values loaded even with LoadConfig.FollowPointers=false
  2258  						checkVarExact(t, locals, -1, "a7", "a7", "*main.FooBar {Baz: 5, Bur: \"strum\"}", "*main.FooBar", hasChildren)
  2259  
  2260  						// Auto-loading works on results of evaluate expressions as well
  2261  						client.EvaluateRequest("a7", frame, "repl")
  2262  						checkEval(t, client.ExpectEvaluateResponse(t), "*main.FooBar {Baz: 5, Bur: \"strum\"}", hasChildren)
  2263  
  2264  						client.EvaluateRequest("&a7", frame, "repl")
  2265  						pa7 := client.ExpectEvaluateResponse(t)
  2266  						ref = checkEvalRegex(t, pa7, `\*\(\*main\.FooBar\)\(0x[0-9a-f]+\)`, hasChildren)
  2267  						if ref > 0 {
  2268  							client.VariablesRequest(ref)
  2269  							a7 := client.ExpectVariablesResponse(t)
  2270  							checkVarExact(t, a7, 0, "a7", "(*(&a7))", "*main.FooBar {Baz: 5, Bur: \"strum\"}", "*main.FooBar", hasChildren)
  2271  						}
  2272  					}
  2273  
  2274  					// Frame-independent loading expressions allow us to auto-load
  2275  					// variables in any frame, not just topmost.
  2276  					loadvars(1000 /*first topmost frame*/)
  2277  					// step into another function
  2278  					client.StepInRequest(1)
  2279  					client.ExpectStepInResponse(t)
  2280  					client.ExpectStoppedEvent(t)
  2281  					checkStop(t, client, 1, "main.barfoo", 24)
  2282  					loadvars(1001 /*second frame here is same as topmost above*/)
  2283  				},
  2284  				disconnect: true,
  2285  			}})
  2286  	})
  2287  }
  2288  
  2289  // TestVariablesMetadata exposes test cases where variables contain metadata that
  2290  // can be accessed by requesting named variables.
  2291  func TestVariablesMetadata(t *testing.T) {
  2292  	runTest(t, "testvariables2", func(client *daptest.Client, fixture protest.Fixture) {
  2293  		runDebugSessionWithBPs(t, client, "launch",
  2294  			// Launch
  2295  			func() {
  2296  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  2297  			},
  2298  			// Breakpoints are set within the program
  2299  			fixture.Source, []int{},
  2300  			[]onBreakpoint{{
  2301  				execute:    func() {},
  2302  				disconnect: false,
  2303  			}, {
  2304  				execute: func() {
  2305  					checkStop(t, client, 1, "main.main", -1)
  2306  
  2307  					client.VariablesRequest(localsScope)
  2308  					locals := client.ExpectVariablesResponse(t)
  2309  
  2310  					checkNamedChildren := func(ref int, name, typeStr string, vals []string, evaluate bool) {
  2311  						// byteslice, request named variables
  2312  						client.NamedVariablesRequest(ref)
  2313  						named := client.ExpectVariablesResponse(t)
  2314  						checkChildren(t, named, name, 1)
  2315  						checkVarExact(t, named, 0, "string()", "", "\"tèst\"", "string", false)
  2316  
  2317  						client.VariablesRequest(ref)
  2318  						all := client.ExpectVariablesResponse(t)
  2319  						checkChildren(t, all, name, len(vals)+1)
  2320  						checkVarExact(t, all, 0, "string()", "", "\"tèst\"", "string", false)
  2321  						for i, v := range vals {
  2322  							idx := fmt.Sprintf("[%d]", i)
  2323  							evalName := fmt.Sprintf("%s[%d]", name, i)
  2324  							if evaluate {
  2325  								evalName = fmt.Sprintf("(%s)[%d]", name, i)
  2326  							}
  2327  							checkVarExact(t, all, i+1, idx, evalName, v, typeStr, false)
  2328  						}
  2329  					}
  2330  
  2331  					bytes := []string{"116 = 0x74", "195 = 0xc3", "168 = 0xa8", "115 = 0x73", "116 = 0x74"}
  2332  					runes := []string{"116", "232", "115", "116"}
  2333  
  2334  					// byteslice
  2335  					ref := checkVarExactIndexed(t, locals, -1, "byteslice", "byteslice", "[]uint8 len: 5, cap: 5, [116,195,168,115,116]", "[]uint8", true, 5, 1)
  2336  					checkNamedChildren(ref, "byteslice", "uint8", bytes, false)
  2337  
  2338  					client.EvaluateRequest("byteslice", 0, "")
  2339  					got := client.ExpectEvaluateResponse(t)
  2340  					ref = checkEvalIndexed(t, got, "[]uint8 len: 5, cap: 5, [116,195,168,115,116]", hasChildren, 5, 1)
  2341  					checkNamedChildren(ref, "byteslice", "uint8", bytes, true)
  2342  
  2343  					// runeslice
  2344  					ref = checkVarExactIndexed(t, locals, -1, "runeslice", "runeslice", "[]int32 len: 4, cap: 4, [116,232,115,116]", "[]int32", true, 4, 1)
  2345  					checkNamedChildren(ref, "runeslice", "int32", runes, false)
  2346  
  2347  					client.EvaluateRequest("runeslice", 0, "repl")
  2348  					got = client.ExpectEvaluateResponse(t)
  2349  					ref = checkEvalIndexed(t, got, "[]int32 len: 4, cap: 4, [116,232,115,116]", hasChildren, 4, 1)
  2350  					checkNamedChildren(ref, "runeslice", "int32", runes, true)
  2351  
  2352  					// bytearray
  2353  					ref = checkVarExactIndexed(t, locals, -1, "bytearray", "bytearray", "[5]uint8 [116,195,168,115,116]", "[5]uint8", true, 5, 1)
  2354  					checkNamedChildren(ref, "bytearray", "uint8", bytes, false)
  2355  
  2356  					client.EvaluateRequest("bytearray", 0, "hover")
  2357  					got = client.ExpectEvaluateResponse(t)
  2358  					ref = checkEvalIndexed(t, got, "[5]uint8 [116,195,168,115,116]", hasChildren, 5, 1)
  2359  					checkNamedChildren(ref, "bytearray", "uint8", bytes, true)
  2360  
  2361  					// runearray
  2362  					ref = checkVarExactIndexed(t, locals, -1, "runearray", "runearray", "[4]int32 [116,232,115,116]", "[4]int32", true, 4, 1)
  2363  					checkNamedChildren(ref, "runearray", "int32", runes, false)
  2364  
  2365  					client.EvaluateRequest("runearray", 0, "watch")
  2366  					got = client.ExpectEvaluateResponse(t)
  2367  					ref = checkEvalIndexed(t, got, "[4]int32 [116,232,115,116]", hasChildren, 4, 1)
  2368  					checkNamedChildren(ref, "runearray", "int32", runes, true)
  2369  
  2370  					// string feature is not available with user-defined byte types
  2371  					ref = checkVarExactIndexed(t, locals, -1, "bytestypeslice", "bytestypeslice", "[]main.Byte len: 5, cap: 5, [116,195,168,115,116]", "[]main.Byte", true, 5, 1)
  2372  					client.NamedVariablesRequest(ref)
  2373  					namedchildren := client.ExpectVariablesResponse(t)
  2374  					checkChildren(t, namedchildren, "bytestypeslice as string", 0)
  2375  					ref = checkVarExactIndexed(t, locals, -1, "bytetypearray", "bytetypearray", "[5]main.Byte [116,195,168,115,116]", "[5]main.Byte", true, 5, 1)
  2376  					client.NamedVariablesRequest(ref)
  2377  					namedchildren = client.ExpectVariablesResponse(t)
  2378  					checkChildren(t, namedchildren, "bytetypearray as string", 0)
  2379  				},
  2380  				disconnect: true,
  2381  			}})
  2382  	})
  2383  }
  2384  
  2385  // TestGlobalScopeAndVariables launches the program with showGlobalVariables
  2386  // arg set, executes to a breakpoint in the main package and tests that global
  2387  // package main variables got loaded. It then steps into a function
  2388  // in another package and tests that globals scope got updated to those vars.
  2389  func TestGlobalScopeAndVariables(t *testing.T) {
  2390  	runTest(t, "consts", func(client *daptest.Client, fixture protest.Fixture) {
  2391  		runDebugSessionWithBPs(t, client, "launch",
  2392  			// Launch
  2393  			func() {
  2394  				client.LaunchRequestWithArgs(map[string]interface{}{
  2395  					"mode": "exec", "program": fixture.Path, "showGlobalVariables": true, "showRegisters": true,
  2396  				})
  2397  			},
  2398  			// Breakpoints are set within the program
  2399  			fixture.Source, []int{},
  2400  			[]onBreakpoint{{
  2401  				// Stop at line 36
  2402  				execute: func() {
  2403  					if runtime.GOARCH == "386" && goversion.VersionAfterOrEqual(runtime.Version(), 1, 18) {
  2404  						client.StepInRequest(1)
  2405  						client.ExpectStepInResponse(t)
  2406  						client.ExpectStoppedEvent(t)
  2407  					}
  2408  					client.StackTraceRequest(1, 0, 20)
  2409  					stack := client.ExpectStackTraceResponse(t)
  2410  					checkStackFramesExact(t, stack, "main.main", 36, 1000, 3, 3)
  2411  
  2412  					client.ScopesRequest(1000)
  2413  					scopes := client.ExpectScopesResponse(t)
  2414  					checkScope(t, scopes, 0, "Locals", localsScope)
  2415  					checkScope(t, scopes, 1, "Globals (package main)", globalsScope)
  2416  					checkScope(t, scopes, 2, "Registers", globalsScope+1)
  2417  
  2418  					client.VariablesRequest(globalsScope)
  2419  					client.ExpectVariablesResponse(t)
  2420  					// The program has no user-defined globals.
  2421  					// Depending on the Go version, there might
  2422  					// be some runtime globals (e.g. main..inittask)
  2423  					// so testing for the total number is too fragile.
  2424  
  2425  					// Step into pkg.AnotherMethod()
  2426  					client.StepInRequest(1)
  2427  					client.ExpectStepInResponse(t)
  2428  					client.ExpectStoppedEvent(t)
  2429  
  2430  					client.StackTraceRequest(1, 0, 20)
  2431  					stack = client.ExpectStackTraceResponse(t)
  2432  					checkStackFramesExact(t, stack, "", 13, 1000, 4, 4)
  2433  
  2434  					client.ScopesRequest(1000)
  2435  					scopes = client.ExpectScopesResponse(t)
  2436  					checkScope(t, scopes, 0, "Locals", localsScope)
  2437  					checkScope(t, scopes, 1, "Globals (package github.com/undoio/delve/_fixtures/internal/dir0/pkg)", globalsScope)
  2438  
  2439  					client.VariablesRequest(globalsScope)
  2440  					globals := client.ExpectVariablesResponse(t)
  2441  					checkChildren(t, globals, "Globals", 1)
  2442  					ref := checkVarExact(t, globals, 0, "SomeVar", "github.com/undoio/delve/_fixtures/internal/dir0/pkg.SomeVar", "github.com/undoio/delve/_fixtures/internal/dir0/pkg.SomeType {X: 0}", "github.com/undoio/delve/_fixtures/internal/dir0/pkg.SomeType", hasChildren)
  2443  
  2444  					if ref > 0 {
  2445  						client.VariablesRequest(ref)
  2446  						somevar := client.ExpectVariablesResponse(t)
  2447  						checkChildren(t, somevar, "SomeVar", 1)
  2448  						// TODO(polina): unlike main.p, this prefix won't work
  2449  						checkVarExact(t, somevar, 0, "X", "github.com/undoio/delve/_fixtures/internal/dir0/pkg.SomeVar.X", "0", "float64", noChildren)
  2450  					}
  2451  				},
  2452  				disconnect: false,
  2453  			}})
  2454  	})
  2455  }
  2456  
  2457  // TestRegisterScopeAndVariables launches the program with showRegisters
  2458  // arg set, executes to a breakpoint in the main package and tests that the registers
  2459  // got loaded. It then steps into a function in another package and tests that
  2460  // the registers were updated by checking PC.
  2461  func TestRegistersScopeAndVariables(t *testing.T) {
  2462  	runTest(t, "consts", func(client *daptest.Client, fixture protest.Fixture) {
  2463  		runDebugSessionWithBPs(t, client, "launch",
  2464  			// Launch
  2465  			func() {
  2466  				client.LaunchRequestWithArgs(map[string]interface{}{
  2467  					"mode": "exec", "program": fixture.Path, "showRegisters": true,
  2468  				})
  2469  			},
  2470  			// Breakpoints are set within the program
  2471  			fixture.Source, []int{},
  2472  			[]onBreakpoint{{
  2473  				// Stop at line 36
  2474  				execute: func() {
  2475  					if runtime.GOARCH == "386" && goversion.VersionAfterOrEqual(runtime.Version(), 1, 18) {
  2476  						client.StepInRequest(1)
  2477  						client.ExpectStepInResponse(t)
  2478  						client.ExpectStoppedEvent(t)
  2479  					}
  2480  
  2481  					client.StackTraceRequest(1, 0, 20)
  2482  					stack := client.ExpectStackTraceResponse(t)
  2483  					checkStackFramesExact(t, stack, "main.main", 36, 1000, 3, 3)
  2484  
  2485  					client.ScopesRequest(1000)
  2486  					scopes := client.ExpectScopesResponse(t)
  2487  					checkScope(t, scopes, 0, "Locals", localsScope)
  2488  					registersScope := localsScope + 1
  2489  					checkScope(t, scopes, 1, "Registers", registersScope)
  2490  
  2491  					// Check that instructionPointer points to the InstructionPointerReference.
  2492  					pc, err := getPC(t, client, 1)
  2493  					if err != nil {
  2494  						t.Error(pc)
  2495  					}
  2496  
  2497  					client.VariablesRequest(registersScope)
  2498  					vr := client.ExpectVariablesResponse(t)
  2499  					if len(vr.Body.Variables) == 0 {
  2500  						t.Fatal("no registers returned")
  2501  					}
  2502  					idx := findPcReg(vr.Body.Variables)
  2503  					if idx < 0 {
  2504  						t.Fatalf("got %#v, want a reg with instruction pointer", vr.Body.Variables)
  2505  					}
  2506  					pcReg := vr.Body.Variables[idx]
  2507  					gotPc, err := strconv.ParseUint(pcReg.Value, 0, 64)
  2508  					if err != nil {
  2509  						t.Error(err)
  2510  					}
  2511  					name := strings.TrimSpace(pcReg.Name)
  2512  					if gotPc != pc || pcReg.EvaluateName != fmt.Sprintf("_%s", strings.ToUpper(name)) {
  2513  						t.Errorf("got %#v,\nwant Name=%s Value=%#x EvaluateName=%q", pcReg, name, pc, fmt.Sprintf("_%s", strings.ToUpper(name)))
  2514  					}
  2515  
  2516  					// The program has no user-defined globals.
  2517  					// Depending on the Go version, there might
  2518  					// be some runtime globals (e.g. main..inittask)
  2519  					// so testing for the total number is too fragile.
  2520  
  2521  					// Step into pkg.AnotherMethod()
  2522  					client.StepInRequest(1)
  2523  					client.ExpectStepInResponse(t)
  2524  					client.ExpectStoppedEvent(t)
  2525  
  2526  					client.StackTraceRequest(1, 0, 20)
  2527  					stack = client.ExpectStackTraceResponse(t)
  2528  					checkStackFramesExact(t, stack, "", 13, 1000, 4, 4)
  2529  
  2530  					client.ScopesRequest(1000)
  2531  					scopes = client.ExpectScopesResponse(t)
  2532  					checkScope(t, scopes, 0, "Locals", localsScope)
  2533  					checkScope(t, scopes, 1, "Registers", registersScope)
  2534  
  2535  					// Check that rip points to the InstructionPointerReference.
  2536  					pc, err = getPC(t, client, 1)
  2537  					if err != nil {
  2538  						t.Error(pc)
  2539  					}
  2540  					client.VariablesRequest(registersScope)
  2541  					vr = client.ExpectVariablesResponse(t)
  2542  					if len(vr.Body.Variables) == 0 {
  2543  						t.Fatal("no registers returned")
  2544  					}
  2545  
  2546  					idx = findPcReg(vr.Body.Variables)
  2547  					if idx < 0 {
  2548  						t.Fatalf("got %#v, want a reg with instruction pointer", vr.Body.Variables)
  2549  					}
  2550  					pcReg = vr.Body.Variables[idx]
  2551  					gotPc, err = strconv.ParseUint(pcReg.Value, 0, 64)
  2552  					if err != nil {
  2553  						t.Error(err)
  2554  					}
  2555  
  2556  					if gotPc != pc || pcReg.EvaluateName != fmt.Sprintf("_%s", strings.ToUpper(name)) {
  2557  						t.Errorf("got %#v,\nwant Name=%s Value=%#x EvaluateName=%q", pcReg, name, pc, fmt.Sprintf("_%s", strings.ToUpper(name)))
  2558  					}
  2559  				},
  2560  				disconnect: false,
  2561  			}})
  2562  	})
  2563  }
  2564  
  2565  func findPcReg(regs []dap.Variable) int {
  2566  	for i, reg := range regs {
  2567  		if isPcReg(reg) {
  2568  			return i
  2569  		}
  2570  	}
  2571  	return -1
  2572  }
  2573  
  2574  func isPcReg(reg dap.Variable) bool {
  2575  	pcRegNames := []string{"rip", "pc", "eip"}
  2576  	for _, name := range pcRegNames {
  2577  		if name == strings.TrimSpace(reg.Name) {
  2578  			return true
  2579  		}
  2580  	}
  2581  	return false
  2582  }
  2583  
  2584  // TestShadowedVariables executes to a breakpoint and checks the shadowed
  2585  // variable is named correctly.
  2586  func TestShadowedVariables(t *testing.T) {
  2587  	runTest(t, "testshadow", func(client *daptest.Client, fixture protest.Fixture) {
  2588  		runDebugSessionWithBPs(t, client, "launch",
  2589  			// Launch
  2590  			func() {
  2591  				client.LaunchRequestWithArgs(map[string]interface{}{
  2592  					"mode": "exec", "program": fixture.Path, "showGlobalVariables": true,
  2593  				})
  2594  			},
  2595  			// Breakpoints are set within the program
  2596  			fixture.Source, []int{},
  2597  			[]onBreakpoint{{
  2598  				// Stop at line 13
  2599  				execute: func() {
  2600  					client.StackTraceRequest(1, 0, 20)
  2601  					stack := client.ExpectStackTraceResponse(t)
  2602  					checkStackFramesExact(t, stack, "main.main", 13, 1000, 3, 3)
  2603  
  2604  					client.ScopesRequest(1000)
  2605  					scopes := client.ExpectScopesResponse(t)
  2606  					checkScope(t, scopes, 0, "Locals", localsScope)
  2607  					checkScope(t, scopes, 1, "Globals (package main)", globalsScope)
  2608  
  2609  					client.VariablesRequest(localsScope)
  2610  					locals := client.ExpectVariablesResponse(t)
  2611  
  2612  					checkVarExact(t, locals, 0, "(a)", "a", "0", "int", !hasChildren)
  2613  					checkVarExact(t, locals, 1, "a", "a", "1", "int", !hasChildren)
  2614  
  2615  					// Check that the non-shadowed of "a" is returned from evaluate request.
  2616  					validateEvaluateName(t, client, locals, 1)
  2617  				},
  2618  				disconnect: false,
  2619  			}})
  2620  	})
  2621  }
  2622  
  2623  // Tests that 'stackTraceDepth' from LaunchRequest is parsed and passed to
  2624  // stacktrace requests handlers.
  2625  func TestLaunchRequestWithStackTraceDepth(t *testing.T) {
  2626  	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) {
  2627  		var stResp *dap.StackTraceResponse
  2628  		runDebugSessionWithBPs(t, client, "launch",
  2629  			// Launch
  2630  			func() {
  2631  				client.LaunchRequestWithArgs(map[string]interface{}{
  2632  					"mode": "exec", "program": fixture.Path, "stackTraceDepth": 1,
  2633  				})
  2634  			},
  2635  			// Set breakpoints
  2636  			fixture.Source, []int{8},
  2637  			[]onBreakpoint{{ // Stop at line 8
  2638  				execute: func() {
  2639  					client.StackTraceRequest(1, 0, 0)
  2640  					stResp = client.ExpectStackTraceResponse(t)
  2641  					checkStackFramesHasMore(t, stResp, "main.Increment", 8, 1000, 1 /*returned*/, 2 /*available*/)
  2642  				},
  2643  				disconnect: false,
  2644  			}})
  2645  	})
  2646  }
  2647  
  2648  type Breakpoint struct {
  2649  	line      int
  2650  	path      string
  2651  	verified  bool
  2652  	msgPrefix string
  2653  }
  2654  
  2655  func expectSetBreakpointsResponse(t *testing.T, client *daptest.Client, bps []Breakpoint) {
  2656  	t.Helper()
  2657  	checkSetBreakpointsResponse(t, bps, client.ExpectSetBreakpointsResponse(t))
  2658  }
  2659  
  2660  func checkSetBreakpointsResponse(t *testing.T, bps []Breakpoint, got *dap.SetBreakpointsResponse) {
  2661  	t.Helper()
  2662  	checkBreakpoints(t, bps, got.Body.Breakpoints)
  2663  }
  2664  
  2665  func checkBreakpoints(t *testing.T, bps []Breakpoint, breakpoints []dap.Breakpoint) {
  2666  	t.Helper()
  2667  	if len(breakpoints) != len(bps) {
  2668  		t.Errorf("got %#v,\nwant len(Breakpoints)=%d", breakpoints, len(bps))
  2669  		return
  2670  	}
  2671  	for i, bp := range breakpoints {
  2672  		if bps[i].line < 0 && !bps[i].verified {
  2673  			if bp.Verified != bps[i].verified || !stringContainsCaseInsensitive(bp.Message, bps[i].msgPrefix) {
  2674  				t.Errorf("got breakpoints[%d] = %#v, \nwant %#v", i, bp, bps[i])
  2675  			}
  2676  			continue
  2677  		}
  2678  		if bp.Line != bps[i].line || bp.Verified != bps[i].verified || bp.Source.Path != bps[i].path ||
  2679  			!strings.HasPrefix(bp.Message, bps[i].msgPrefix) {
  2680  			t.Errorf("got breakpoints[%d] = %#v, \nwant %#v", i, bp, bps[i])
  2681  		}
  2682  	}
  2683  }
  2684  
  2685  // TestSetBreakpoint executes to a breakpoint and tests different
  2686  // configurations of setBreakpoint requests.
  2687  func TestSetBreakpoint(t *testing.T) {
  2688  	runTest(t, "loopprog", func(client *daptest.Client, fixture protest.Fixture) {
  2689  		runDebugSessionWithBPs(t, client, "launch",
  2690  			// Launch
  2691  			func() {
  2692  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  2693  			},
  2694  			// Set breakpoints
  2695  			fixture.Source, []int{16}, // b main.main
  2696  			[]onBreakpoint{{
  2697  				execute: func() {
  2698  					checkStop(t, client, 1, "main.main", 16)
  2699  
  2700  					// Set two breakpoints at the next two lines in main
  2701  					client.SetBreakpointsRequest(fixture.Source, []int{17, 18})
  2702  					expectSetBreakpointsResponse(t, client, []Breakpoint{{17, fixture.Source, true, ""}, {18, fixture.Source, true, ""}})
  2703  
  2704  					// Clear 17, reset 18
  2705  					client.SetBreakpointsRequest(fixture.Source, []int{18})
  2706  					expectSetBreakpointsResponse(t, client, []Breakpoint{{18, fixture.Source, true, ""}})
  2707  
  2708  					// Skip 17, continue to 18
  2709  					client.ContinueRequest(1)
  2710  					client.ExpectContinueResponse(t)
  2711  					client.ExpectStoppedEvent(t)
  2712  					checkStop(t, client, 1, "main.main", 18)
  2713  
  2714  					// Set another breakpoint inside the loop in loop(), twice to trigger error
  2715  					client.SetBreakpointsRequest(fixture.Source, []int{8, 8})
  2716  					expectSetBreakpointsResponse(t, client, []Breakpoint{{8, fixture.Source, true, ""}, {-1, "", false, "breakpoint already exists"}})
  2717  
  2718  					// Continue into the loop
  2719  					client.ContinueRequest(1)
  2720  					client.ExpectContinueResponse(t)
  2721  					client.ExpectStoppedEvent(t)
  2722  					checkStop(t, client, 1, "main.loop", 8)
  2723  					client.VariablesRequest(localsScope)
  2724  					locals := client.ExpectVariablesResponse(t)
  2725  					checkVarExact(t, locals, 0, "i", "i", "0", "int", noChildren) // i == 0
  2726  
  2727  					// Edit the breakpoint to add a condition
  2728  					client.SetBreakpointsRequestWithArgs(fixture.Source, []int{8}, map[int]string{8: "i == 3"}, nil, nil)
  2729  					expectSetBreakpointsResponse(t, client, []Breakpoint{{8, fixture.Source, true, ""}})
  2730  
  2731  					// Continue until condition is hit
  2732  					client.ContinueRequest(1)
  2733  					client.ExpectContinueResponse(t)
  2734  					client.ExpectStoppedEvent(t)
  2735  					checkStop(t, client, 1, "main.loop", 8)
  2736  					client.VariablesRequest(localsScope)
  2737  					locals = client.ExpectVariablesResponse(t)
  2738  					checkVarExact(t, locals, 0, "i", "i", "3", "int", noChildren) // i == 3
  2739  
  2740  					// Edit the breakpoint to remove a condition
  2741  					client.SetBreakpointsRequestWithArgs(fixture.Source, []int{8}, map[int]string{8: ""}, nil, nil)
  2742  					expectSetBreakpointsResponse(t, client, []Breakpoint{{8, fixture.Source, true, ""}})
  2743  
  2744  					// Continue for one more loop iteration
  2745  					client.ContinueRequest(1)
  2746  					client.ExpectContinueResponse(t)
  2747  					client.ExpectStoppedEvent(t)
  2748  					checkStop(t, client, 1, "main.loop", 8)
  2749  					client.VariablesRequest(localsScope)
  2750  					locals = client.ExpectVariablesResponse(t)
  2751  					checkVarExact(t, locals, 0, "i", "i", "4", "int", noChildren) // i == 4
  2752  
  2753  					// Set at a line without a statement
  2754  					client.SetBreakpointsRequest(fixture.Source, []int{1000})
  2755  					expectSetBreakpointsResponse(t, client, []Breakpoint{{-1, "", false, "could not find statement"}}) // all cleared, none set
  2756  				},
  2757  				// The program has an infinite loop, so we must kill it by disconnecting.
  2758  				disconnect: true,
  2759  			}})
  2760  	})
  2761  }
  2762  
  2763  // TestSetInstructionBreakpoint executes to a breakpoint and tests different
  2764  // configurations of setInstructionBreakpoint requests.
  2765  func TestSetInstructionBreakpoint(t *testing.T) {
  2766  	runTest(t, "loopprog", func(client *daptest.Client, fixture protest.Fixture) {
  2767  		runDebugSessionWithBPs(t, client, "launch",
  2768  			// Launch
  2769  			func() {
  2770  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  2771  			},
  2772  			// Set breakpoints
  2773  			fixture.Source, []int{16}, // b main.main
  2774  			[]onBreakpoint{{
  2775  				execute: func() {
  2776  					checkStop(t, client, 1, "main.main", 16)
  2777  
  2778  					// Set two breakpoints in the loop
  2779  					client.SetBreakpointsRequest(fixture.Source, []int{8, 9})
  2780  					expectSetBreakpointsResponse(t, client, []Breakpoint{{8, fixture.Source, true, ""}, {9, fixture.Source, true, ""}})
  2781  
  2782  					// Continue to the two breakpoints and get the instructionPointerReference.
  2783  					client.ContinueRequest(1)
  2784  					client.ExpectContinueResponse(t)
  2785  					client.ExpectStoppedEvent(t)
  2786  					checkStop(t, client, 1, "main.loop", 8)
  2787  
  2788  					client.StackTraceRequest(1, 0, 1)
  2789  					st := client.ExpectStackTraceResponse(t)
  2790  					if len(st.Body.StackFrames) < 1 {
  2791  						t.Fatalf("\ngot  %#v\nwant len(stackframes) => 1", st)
  2792  					}
  2793  					pc8 := st.Body.StackFrames[0].InstructionPointerReference
  2794  
  2795  					client.ContinueRequest(1)
  2796  					client.ExpectContinueResponse(t)
  2797  					client.ExpectStoppedEvent(t)
  2798  					checkStop(t, client, 1, "main.loop", 9)
  2799  
  2800  					client.StackTraceRequest(1, 0, 1)
  2801  					st = client.ExpectStackTraceResponse(t)
  2802  					if len(st.Body.StackFrames) < 1 {
  2803  						t.Fatalf("\ngot  %#v\nwant len(stackframes) => 1", st)
  2804  					}
  2805  					pc9 := st.Body.StackFrames[0].InstructionPointerReference
  2806  
  2807  					// Clear the source breakpoints.
  2808  					// TODO(suzmue): there is an existing issue that breakpoints with identical locations
  2809  					// from different setBreakpoints, setFunctionBreakpoints, setInstructionBreakpoints
  2810  					// requests will prevent subsequent ones from being set.
  2811  					client.SetBreakpointsRequest(fixture.Source, []int{})
  2812  					expectSetBreakpointsResponse(t, client, []Breakpoint{})
  2813  
  2814  					// Set the breakpoints using the instruction pointer references.
  2815  					client.SetInstructionBreakpointsRequest([]dap.InstructionBreakpoint{{InstructionReference: pc8}, {InstructionReference: pc9}})
  2816  					bps := client.ExpectSetInstructionBreakpointsResponse(t).Body.Breakpoints
  2817  					checkBreakpoints(t, []Breakpoint{{line: 8, path: fixture.Source, verified: true}, {line: 9, path: fixture.Source, verified: true}}, bps)
  2818  
  2819  					// Continue to the two breakpoints and get the instructionPointerReference.
  2820  					client.ContinueRequest(1)
  2821  					client.ExpectContinueResponse(t)
  2822  					client.ExpectStoppedEvent(t)
  2823  					checkStop(t, client, 1, "main.loop", 8)
  2824  
  2825  					client.ContinueRequest(1)
  2826  					client.ExpectContinueResponse(t)
  2827  					client.ExpectStoppedEvent(t)
  2828  					checkStop(t, client, 1, "main.loop", 9)
  2829  
  2830  					// Remove the breakpoint on line 8 and continue.
  2831  					client.SetInstructionBreakpointsRequest([]dap.InstructionBreakpoint{{InstructionReference: pc9}})
  2832  					bps = client.ExpectSetInstructionBreakpointsResponse(t).Body.Breakpoints
  2833  					checkBreakpoints(t, []Breakpoint{{line: 9, path: fixture.Source, verified: true}}, bps)
  2834  
  2835  					client.ContinueRequest(1)
  2836  					client.ExpectContinueResponse(t)
  2837  					client.ExpectStoppedEvent(t)
  2838  					checkStop(t, client, 1, "main.loop", 9)
  2839  
  2840  					// Set two breakpoints and expect an error on the second one.
  2841  					client.SetInstructionBreakpointsRequest([]dap.InstructionBreakpoint{{InstructionReference: pc8}, {InstructionReference: pc8}})
  2842  					bps = client.ExpectSetInstructionBreakpointsResponse(t).Body.Breakpoints
  2843  					checkBreakpoints(t, []Breakpoint{{line: 8, path: fixture.Source, verified: true}, {line: -1, path: "", verified: false, msgPrefix: "breakpoint already exists"}}, bps)
  2844  
  2845  					// Add a condition
  2846  					client.SetInstructionBreakpointsRequest([]dap.InstructionBreakpoint{{InstructionReference: pc8, Condition: "i == 100"}})
  2847  					bps = client.ExpectSetInstructionBreakpointsResponse(t).Body.Breakpoints
  2848  					checkBreakpoints(t, []Breakpoint{{line: 8, path: fixture.Source, verified: true}}, bps)
  2849  
  2850  					client.ContinueRequest(1)
  2851  					client.ExpectContinueResponse(t)
  2852  					client.ExpectStoppedEvent(t)
  2853  					checkStop(t, client, 1, "main.loop", 8)
  2854  
  2855  					client.VariablesRequest(localsScope)
  2856  					locals := client.ExpectVariablesResponse(t)
  2857  					checkVarExact(t, locals, 0, "i", "i", "100", "int", noChildren) // i == 100
  2858  				},
  2859  				// The program has an infinite loop, so we must kill it by disconnecting.
  2860  				disconnect: true,
  2861  			}})
  2862  	})
  2863  }
  2864  
  2865  func TestPauseAtStop(t *testing.T) {
  2866  	runTest(t, "loopprog", func(client *daptest.Client, fixture protest.Fixture) {
  2867  		runDebugSessionWithBPs(t, client, "launch",
  2868  			// Launch
  2869  			func() {
  2870  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  2871  			},
  2872  			// Set breakpoints
  2873  			fixture.Source, []int{16},
  2874  			[]onBreakpoint{{
  2875  				execute: func() {
  2876  					checkStop(t, client, 1, "main.main", 16)
  2877  
  2878  					client.SetBreakpointsRequest(fixture.Source, []int{6, 8})
  2879  					expectSetBreakpointsResponse(t, client, []Breakpoint{{6, fixture.Source, true, ""}, {8, fixture.Source, true, ""}})
  2880  
  2881  					// Send a pause request while stopped on a cleared breakpoint.
  2882  					client.PauseRequest(1)
  2883  					client.ExpectPauseResponse(t)
  2884  
  2885  					client.ContinueRequest(1)
  2886  					client.ExpectContinueResponse(t)
  2887  					client.ExpectStoppedEvent(t)
  2888  					checkStop(t, client, 1, "main.loop", 6)
  2889  
  2890  					// Send a pause request while stopped on a breakpoint.
  2891  					client.PauseRequest(1)
  2892  					client.ExpectPauseResponse(t)
  2893  
  2894  					client.ContinueRequest(1)
  2895  					client.ExpectContinueResponse(t)
  2896  					se := client.ExpectStoppedEvent(t)
  2897  					if se.Body.Reason != "breakpoint" {
  2898  						t.Errorf("got %#v, expected breakpoint", se)
  2899  					}
  2900  					checkStop(t, client, 1, "main.loop", 8)
  2901  
  2902  					// Send a pause request while stopped after stepping.
  2903  					client.NextRequest(1)
  2904  					client.ExpectNextResponse(t)
  2905  					client.ExpectStoppedEvent(t)
  2906  					checkStop(t, client, 1, "main.loop", 9)
  2907  
  2908  					client.PauseRequest(1)
  2909  					client.ExpectPauseResponse(t)
  2910  
  2911  					client.ContinueRequest(1)
  2912  					client.ExpectContinueResponse(t)
  2913  
  2914  					client.ExpectStoppedEvent(t)
  2915  					checkStop(t, client, 1, "main.loop", 8)
  2916  				},
  2917  				// The program has an infinite loop, so we must kill it by disconnecting.
  2918  				disconnect: true,
  2919  			}})
  2920  	})
  2921  }
  2922  
  2923  func checkHitBreakpointIds(t *testing.T, se *dap.StoppedEvent, reason string, id int) {
  2924  	if se.Body.ThreadId != 1 || se.Body.Reason != reason || len(se.Body.HitBreakpointIds) != 1 || se.Body.HitBreakpointIds[0] != id {
  2925  		t.Errorf("got %#v, want Reason=%q, ThreadId=1, HitBreakpointIds=[]int{%d}", se, reason, id)
  2926  	}
  2927  }
  2928  
  2929  // TestHitBreakpointIds executes to a breakpoint and tests that
  2930  // the breakpoint ids in the stopped event are correct.
  2931  func TestHitBreakpointIds(t *testing.T) {
  2932  	runTest(t, "locationsprog", func(client *daptest.Client, fixture protest.Fixture) {
  2933  		runDebugSessionWithBPs(t, client, "launch",
  2934  			// Launch
  2935  			func() {
  2936  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  2937  			},
  2938  			// Set breakpoints
  2939  			fixture.Source, []int{30}, // b main.main
  2940  			[]onBreakpoint{{
  2941  				execute: func() {
  2942  					checkStop(t, client, 1, "main.main", 30)
  2943  
  2944  					// Set two source breakpoints and two function breakpoints.
  2945  					client.SetBreakpointsRequest(fixture.Source, []int{23, 33})
  2946  					sourceBps := client.ExpectSetBreakpointsResponse(t).Body.Breakpoints
  2947  					checkBreakpoints(t, []Breakpoint{{line: 23, path: fixture.Source, verified: true}, {line: 33, path: fixture.Source, verified: true}}, sourceBps)
  2948  
  2949  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{
  2950  						{Name: "anotherFunction"},
  2951  						{Name: "anotherFunction:1"},
  2952  					})
  2953  					functionBps := client.ExpectSetFunctionBreakpointsResponse(t).Body.Breakpoints
  2954  					checkBreakpoints(t, []Breakpoint{{line: 26, path: fixture.Source, verified: true}, {line: 27, path: fixture.Source, verified: true}}, functionBps)
  2955  
  2956  					client.ContinueRequest(1)
  2957  					client.ExpectContinueResponse(t)
  2958  					se := client.ExpectStoppedEvent(t)
  2959  					checkHitBreakpointIds(t, se, "breakpoint", sourceBps[1].Id)
  2960  					checkStop(t, client, 1, "main.main", 33)
  2961  
  2962  					client.ContinueRequest(1)
  2963  					client.ExpectContinueResponse(t)
  2964  					se = client.ExpectStoppedEvent(t)
  2965  					checkHitBreakpointIds(t, se, "breakpoint", sourceBps[0].Id)
  2966  					checkStop(t, client, 1, "main.(*SomeType).SomeFunction", 23)
  2967  
  2968  					client.ContinueRequest(1)
  2969  					client.ExpectContinueResponse(t)
  2970  					se = client.ExpectStoppedEvent(t)
  2971  					checkHitBreakpointIds(t, se, "function breakpoint", functionBps[0].Id)
  2972  					checkStop(t, client, 1, "main.anotherFunction", 26)
  2973  
  2974  					client.ContinueRequest(1)
  2975  					client.ExpectContinueResponse(t)
  2976  					se = client.ExpectStoppedEvent(t)
  2977  
  2978  					checkHitBreakpointIds(t, se, "function breakpoint", functionBps[1].Id)
  2979  
  2980  					checkStop(t, client, 1, "main.anotherFunction", 27)
  2981  				},
  2982  				disconnect: true,
  2983  			}})
  2984  	})
  2985  }
  2986  
  2987  func stringContainsCaseInsensitive(got, want string) bool {
  2988  	return strings.Contains(strings.ToLower(got), strings.ToLower(want))
  2989  }
  2990  
  2991  // TestSetFunctionBreakpoints is inspired by service/test.TestClientServer_FindLocations.
  2992  func TestSetFunctionBreakpoints(t *testing.T) {
  2993  	runTest(t, "locationsprog", func(client *daptest.Client, fixture protest.Fixture) {
  2994  		runDebugSessionWithBPs(t, client, "launch",
  2995  			// Launch
  2996  			func() {
  2997  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  2998  			},
  2999  			// Set breakpoints
  3000  			fixture.Source, []int{30}, // b main.main
  3001  			[]onBreakpoint{{
  3002  				execute: func() {
  3003  					checkStop(t, client, 1, "main.main", 30)
  3004  
  3005  					type Breakpoint struct {
  3006  						line       int
  3007  						sourceName string
  3008  						verified   bool
  3009  						errMsg     string
  3010  					}
  3011  					expectSetFunctionBreakpointsResponse := func(bps []Breakpoint) {
  3012  						t.Helper()
  3013  						got := client.ExpectSetFunctionBreakpointsResponse(t)
  3014  						if len(got.Body.Breakpoints) != len(bps) {
  3015  							t.Errorf("got %#v,\nwant len(Breakpoints)=%d", got, len(bps))
  3016  							return
  3017  						}
  3018  						for i, bp := range got.Body.Breakpoints {
  3019  							if bps[i].line < 0 && !bps[i].verified {
  3020  								if bp.Verified != bps[i].verified || !stringContainsCaseInsensitive(bp.Message, bps[i].errMsg) {
  3021  									t.Errorf("got breakpoints[%d] = %#v, \nwant %#v", i, bp, bps[i])
  3022  								}
  3023  								continue
  3024  							}
  3025  							// Some function breakpoints may be in packages that have been imported and we do not control, so
  3026  							// we do not always want to check breakpoint lines.
  3027  							if (bps[i].line >= 0 && bp.Line != bps[i].line) || bp.Verified != bps[i].verified || bp.Source.Name != bps[i].sourceName {
  3028  								t.Errorf("got breakpoints[%d] = %#v, \nwant %#v", i, bp, bps[i])
  3029  							}
  3030  						}
  3031  					}
  3032  
  3033  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{
  3034  						{Name: "anotherFunction"},
  3035  					})
  3036  					expectSetFunctionBreakpointsResponse([]Breakpoint{{26, filepath.Base(fixture.Source), true, ""}})
  3037  
  3038  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{
  3039  						{Name: "main.anotherFunction"},
  3040  					})
  3041  					expectSetFunctionBreakpointsResponse([]Breakpoint{{26, filepath.Base(fixture.Source), true, ""}})
  3042  
  3043  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{
  3044  						{Name: "SomeType.String"},
  3045  					})
  3046  					expectSetFunctionBreakpointsResponse([]Breakpoint{{14, filepath.Base(fixture.Source), true, ""}})
  3047  
  3048  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{
  3049  						{Name: "(*SomeType).String"},
  3050  					})
  3051  					expectSetFunctionBreakpointsResponse([]Breakpoint{{14, filepath.Base(fixture.Source), true, ""}})
  3052  
  3053  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{
  3054  						{Name: "main.SomeType.String"},
  3055  					})
  3056  					expectSetFunctionBreakpointsResponse([]Breakpoint{{14, filepath.Base(fixture.Source), true, ""}})
  3057  
  3058  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{
  3059  						{Name: "main.(*SomeType).String"},
  3060  					})
  3061  					expectSetFunctionBreakpointsResponse([]Breakpoint{{14, filepath.Base(fixture.Source), true, ""}})
  3062  
  3063  					// Test line offsets
  3064  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{
  3065  						{Name: "main.anotherFunction:1"},
  3066  					})
  3067  					expectSetFunctionBreakpointsResponse([]Breakpoint{{27, filepath.Base(fixture.Source), true, ""}})
  3068  
  3069  					// Test function names in imported package.
  3070  					// Issue #275
  3071  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{
  3072  						{Name: "io/ioutil.ReadFile"},
  3073  					})
  3074  					expectSetFunctionBreakpointsResponse([]Breakpoint{{-1, "ioutil.go", true, ""}})
  3075  
  3076  					// Issue #296
  3077  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{
  3078  						{Name: "/io/ioutil.ReadFile"},
  3079  					})
  3080  					expectSetFunctionBreakpointsResponse([]Breakpoint{{-1, "ioutil.go", true, ""}})
  3081  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{
  3082  						{Name: "ioutil.ReadFile"},
  3083  					})
  3084  					expectSetFunctionBreakpointsResponse([]Breakpoint{{-1, "ioutil.go", true, ""}})
  3085  
  3086  					// Function Breakpoint name also accepts breakpoints that are specified as file:line.
  3087  					// TODO(suzmue): We could return an error, but it probably is not necessary since breakpoints,
  3088  					// and function breakpoints come in with different requests.
  3089  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{
  3090  						{Name: fmt.Sprintf("%s:14", fixture.Source)},
  3091  					})
  3092  					expectSetFunctionBreakpointsResponse([]Breakpoint{{14, filepath.Base(fixture.Source), true, ""}})
  3093  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{
  3094  						{Name: fmt.Sprintf("%s:14", filepath.Base(fixture.Source))},
  3095  					})
  3096  					expectSetFunctionBreakpointsResponse([]Breakpoint{{14, filepath.Base(fixture.Source), true, ""}})
  3097  
  3098  					// Expect error for ambiguous function name.
  3099  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{
  3100  						{Name: "String"},
  3101  					})
  3102  					expectSetFunctionBreakpointsResponse([]Breakpoint{{-1, "", false, "Location \"String\" ambiguous"}})
  3103  
  3104  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{
  3105  						{Name: "main.String"},
  3106  					})
  3107  					expectSetFunctionBreakpointsResponse([]Breakpoint{{-1, "", false, "Location \"main.String\" ambiguous"}})
  3108  
  3109  					// Expect error for function that does not exist.
  3110  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{
  3111  						{Name: "fakeFunction"},
  3112  					})
  3113  					expectSetFunctionBreakpointsResponse([]Breakpoint{{-1, "", false, "location \"fakeFunction\" not found"}})
  3114  
  3115  					// Expect error for negative line number.
  3116  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{
  3117  						{Name: "main.anotherFunction:-1"},
  3118  					})
  3119  					expectSetFunctionBreakpointsResponse([]Breakpoint{{-1, "", false, "line offset negative or not a number"}})
  3120  
  3121  					// Expect error when function name is regex.
  3122  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{
  3123  						{Name: `/^.*String.*$/`},
  3124  					})
  3125  					expectSetFunctionBreakpointsResponse([]Breakpoint{{-1, "", false, "breakpoint name \"/^.*String.*$/\" could not be parsed as a function"}})
  3126  
  3127  					// Expect error when function name is an offset.
  3128  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{
  3129  						{Name: "+1"},
  3130  					})
  3131  					expectSetFunctionBreakpointsResponse([]Breakpoint{{-1, filepath.Base(fixture.Source), false, "breakpoint name \"+1\" could not be parsed as a function"}})
  3132  
  3133  					// Expect error when function name is a line number.
  3134  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{
  3135  						{Name: "14"},
  3136  					})
  3137  					expectSetFunctionBreakpointsResponse([]Breakpoint{{-1, filepath.Base(fixture.Source), false, "breakpoint name \"14\" could not be parsed as a function"}})
  3138  
  3139  					// Expect error when function name is an address.
  3140  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{
  3141  						{Name: "*b"},
  3142  					})
  3143  					expectSetFunctionBreakpointsResponse([]Breakpoint{{-1, filepath.Base(fixture.Source), false, "breakpoint name \"*b\" could not be parsed as a function"}})
  3144  
  3145  					// Expect error when function name is a relative path.
  3146  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{
  3147  						{Name: fmt.Sprintf(".%s%s:14", string(filepath.Separator), filepath.Base(fixture.Source))},
  3148  					})
  3149  					// This relative path could also be caught by the parser, so we should not match the error message.
  3150  					expectSetFunctionBreakpointsResponse([]Breakpoint{{-1, filepath.Base(fixture.Source), false, ""}})
  3151  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{
  3152  						{Name: fmt.Sprintf("..%s%s:14", string(filepath.Separator), filepath.Base(fixture.Source))},
  3153  					})
  3154  					// This relative path could also be caught by the parser, so we should not match the error message.
  3155  					expectSetFunctionBreakpointsResponse([]Breakpoint{{-1, filepath.Base(fixture.Source), false, ""}})
  3156  
  3157  					// Test multiple function breakpoints.
  3158  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{
  3159  						{Name: "SomeType.String"}, {Name: "anotherFunction"},
  3160  					})
  3161  					expectSetFunctionBreakpointsResponse([]Breakpoint{{14, filepath.Base(fixture.Source), true, ""}, {26, filepath.Base(fixture.Source), true, ""}})
  3162  
  3163  					// Test multiple breakpoints to the same location.
  3164  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{
  3165  						{Name: "SomeType.String"}, {Name: "(*SomeType).String"},
  3166  					})
  3167  					expectSetFunctionBreakpointsResponse([]Breakpoint{{14, filepath.Base(fixture.Source), true, ""}, {-1, "", false, "breakpoint exists"}})
  3168  
  3169  					// Set two breakpoints at SomeType.String and SomeType.SomeFunction.
  3170  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{
  3171  						{Name: "SomeType.String"}, {Name: "SomeType.SomeFunction"},
  3172  					})
  3173  					expectSetFunctionBreakpointsResponse([]Breakpoint{{14, filepath.Base(fixture.Source), true, ""}, {22, filepath.Base(fixture.Source), true, ""}})
  3174  
  3175  					// Clear SomeType.String, reset SomeType.SomeFunction (SomeType.String is called before SomeType.SomeFunction).
  3176  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{
  3177  						{Name: "SomeType.SomeFunction"},
  3178  					})
  3179  					expectSetFunctionBreakpointsResponse([]Breakpoint{{22, filepath.Base(fixture.Source), true, ""}})
  3180  
  3181  					// Expect the next breakpoint to be at SomeType.SomeFunction.
  3182  					client.ContinueRequest(1)
  3183  					client.ExpectContinueResponse(t)
  3184  
  3185  					if se := client.ExpectStoppedEvent(t); se.Body.Reason != "function breakpoint" || se.Body.ThreadId != 1 {
  3186  						t.Errorf("got %#v, want Reason=\"function breakpoint\", ThreadId=1", se)
  3187  					}
  3188  					checkStop(t, client, 1, "main.(*SomeType).SomeFunction", 22)
  3189  
  3190  					// Set a breakpoint at the next line in the program.
  3191  					client.SetBreakpointsRequest(fixture.Source, []int{23})
  3192  					got := client.ExpectSetBreakpointsResponse(t)
  3193  					if len(got.Body.Breakpoints) != 1 {
  3194  						t.Errorf("got %#v,\nwant len(Breakpoints)=%d", got, 1)
  3195  						return
  3196  					}
  3197  					bp := got.Body.Breakpoints[0]
  3198  					if bp.Line != 23 || bp.Verified != true || bp.Source.Path != fixture.Source {
  3199  						t.Errorf("got breakpoints[0] = %#v, \nwant Line=23 Verified=true Source.Path=%q", bp, fixture.Source)
  3200  					}
  3201  
  3202  					// Set a function breakpoint, this should not clear the breakpoint that was set in the previous setBreakpoints request.
  3203  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{
  3204  						{Name: "anotherFunction"},
  3205  					})
  3206  					expectSetFunctionBreakpointsResponse([]Breakpoint{{26, filepath.Base(fixture.Source), true, ""}})
  3207  
  3208  					// Expect the next breakpoint to be at line 23.
  3209  					client.ContinueRequest(1)
  3210  					client.ExpectContinueResponse(t)
  3211  
  3212  					if se := client.ExpectStoppedEvent(t); se.Body.Reason != "breakpoint" || se.Body.ThreadId != 1 {
  3213  						t.Errorf("got %#v, want Reason=\"breakpoint\", ThreadId=1", se)
  3214  					}
  3215  					checkStop(t, client, 1, "main.(*SomeType).SomeFunction", 23)
  3216  
  3217  					// Set a breakpoint, this should not clear the breakpoint that was set in the previous setFunctionBreakpoints request.
  3218  					client.SetBreakpointsRequest(fixture.Source, []int{37})
  3219  					got = client.ExpectSetBreakpointsResponse(t)
  3220  					if len(got.Body.Breakpoints) != 1 {
  3221  						t.Errorf("got %#v,\nwant len(Breakpoints)=%d", got, 1)
  3222  						return
  3223  					}
  3224  					bp = got.Body.Breakpoints[0]
  3225  					if bp.Line != 37 || bp.Verified != true || bp.Source.Path != fixture.Source {
  3226  						t.Errorf("got breakpoints[0] = %#v, \nwant Line=23 Verified=true Source.Path=%q", bp, fixture.Source)
  3227  					}
  3228  
  3229  					// Expect the next breakpoint to be at line anotherFunction.
  3230  					client.ContinueRequest(1)
  3231  					client.ExpectContinueResponse(t)
  3232  
  3233  					if se := client.ExpectStoppedEvent(t); se.Body.Reason != "function breakpoint" || se.Body.ThreadId != 1 {
  3234  						t.Errorf("got %#v, want Reason=\"function breakpoint\", ThreadId=1", se)
  3235  					}
  3236  					checkStop(t, client, 1, "main.anotherFunction", 26)
  3237  
  3238  				},
  3239  				disconnect: true,
  3240  			}})
  3241  	})
  3242  }
  3243  
  3244  // TestLogPoints executes to a breakpoint and tests that log points
  3245  // send OutputEvents and do not halt program execution.
  3246  func TestLogPoints(t *testing.T) {
  3247  	runTest(t, "callme", func(client *daptest.Client, fixture protest.Fixture) {
  3248  		runDebugSessionWithBPs(t, client, "launch",
  3249  			// Launch
  3250  			func() {
  3251  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  3252  			},
  3253  			// Set breakpoints
  3254  			fixture.Source, []int{23},
  3255  			[]onBreakpoint{{
  3256  				// Stop at line 23
  3257  				execute: func() {
  3258  					checkStop(t, client, 1, "main.main", 23)
  3259  					bps := []int{6, 25, 27, 16}
  3260  					logMessages := map[int]string{6: "{i*2}: in callme!", 16: "in callme2!"}
  3261  					client.SetBreakpointsRequestWithArgs(fixture.Source, bps, nil, nil, logMessages)
  3262  					client.ExpectSetBreakpointsResponse(t)
  3263  
  3264  					client.ContinueRequest(1)
  3265  					client.ExpectContinueResponse(t)
  3266  
  3267  					for i := 0; i < 5; i++ {
  3268  						se := client.ExpectStoppedEvent(t)
  3269  						if se.Body.Reason != "breakpoint" || se.Body.ThreadId != 1 {
  3270  							t.Errorf("got stopped event = %#v, \nwant Reason=\"breakpoint\" ThreadId=1", se)
  3271  						}
  3272  						checkStop(t, client, 1, "main.main", 25)
  3273  
  3274  						client.ContinueRequest(1)
  3275  						client.ExpectContinueResponse(t)
  3276  						checkLogMessage(t, client.ExpectOutputEvent(t), 1, fmt.Sprintf("%d: in callme!", i*2), fixture.Source, 6)
  3277  					}
  3278  					se := client.ExpectStoppedEvent(t)
  3279  					if se.Body.Reason != "breakpoint" || se.Body.ThreadId != 1 {
  3280  						t.Errorf("got stopped event = %#v, \nwant Reason=\"breakpoint\" ThreadId=1", se)
  3281  					}
  3282  					checkStop(t, client, 1, "main.main", 27)
  3283  
  3284  					client.NextRequest(1)
  3285  					client.ExpectNextResponse(t)
  3286  
  3287  					checkLogMessage(t, client.ExpectOutputEvent(t), 1, "in callme2!", fixture.Source, 16)
  3288  
  3289  					se = client.ExpectStoppedEvent(t)
  3290  					if se.Body.Reason != "step" || se.Body.ThreadId != 1 {
  3291  						t.Errorf("got stopped event = %#v, \nwant Reason=\"step\" ThreadId=1", se)
  3292  					}
  3293  					checkStop(t, client, 1, "main.main", 28)
  3294  				},
  3295  				disconnect: true,
  3296  			}})
  3297  	})
  3298  }
  3299  
  3300  func checkLogMessage(t *testing.T, oe *dap.OutputEvent, goid int, text, path string, line int) {
  3301  	t.Helper()
  3302  	prefix := "> [Go "
  3303  	if goid >= 0 {
  3304  		prefix += strconv.Itoa(goid) + "]"
  3305  	}
  3306  	if oe.Body.Category != "stdout" || !strings.HasPrefix(oe.Body.Output, prefix) || !strings.HasSuffix(oe.Body.Output, text+"\n") {
  3307  		t.Errorf("got output event = %#v, \nwant Category=\"stdout\" Output=\"%s: %s\\n\"", oe, prefix, text)
  3308  	}
  3309  	if oe.Body.Line != line || oe.Body.Source.Path != path {
  3310  		t.Errorf("got output event = %#v, \nwant Line=%d Source.Path=%s", oe, line, path)
  3311  	}
  3312  }
  3313  
  3314  // TestHaltPreventsAutoResume tests that a pause request issued while processing
  3315  // log messages will result in a real stop.
  3316  func TestHaltPreventsAutoResume(t *testing.T) {
  3317  	runTest(t, "callme", func(client *daptest.Client, fixture protest.Fixture) {
  3318  		runDebugSessionWithBPs(t, client, "launch", // Launch
  3319  			func() {
  3320  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  3321  			},
  3322  			// Set breakpoints
  3323  			fixture.Source, []int{23},
  3324  			[]onBreakpoint{{
  3325  				execute: func() {
  3326  					savedResumeOnce := resumeOnceAndCheckStop
  3327  					defer func() {
  3328  						resumeOnceAndCheckStop = savedResumeOnce
  3329  					}()
  3330  					checkStop(t, client, 1, "main.main", 23)
  3331  					bps := []int{6, 25}
  3332  					logMessages := map[int]string{6: "in callme!"}
  3333  					client.SetBreakpointsRequestWithArgs(fixture.Source, bps, nil, nil, logMessages)
  3334  					client.ExpectSetBreakpointsResponse(t)
  3335  
  3336  					for i := 0; i < 5; i++ {
  3337  						// Reset the handler to the default behavior.
  3338  						resumeOnceAndCheckStop = savedResumeOnce
  3339  
  3340  						// Expect a pause request while stopped not to interrupt continue.
  3341  						client.PauseRequest(1)
  3342  						client.ExpectPauseResponse(t)
  3343  
  3344  						client.ContinueRequest(1)
  3345  						client.ExpectContinueResponse(t)
  3346  						se := client.ExpectStoppedEvent(t)
  3347  						if se.Body.Reason != "breakpoint" || se.Body.ThreadId != 1 {
  3348  							t.Errorf("got stopped event = %#v, \nwant Reason=\"breakpoint\" ThreadId=1", se)
  3349  						}
  3350  						checkStop(t, client, 1, "main.main", 25)
  3351  
  3352  						pauseDoneChan := make(chan struct{}, 1)
  3353  						outputDoneChan := make(chan struct{}, 1)
  3354  						// Send a halt request when trying to resume the program after being
  3355  						// interrupted. This should allow the log message to be processed,
  3356  						// but keep the process from continuing beyond the line.
  3357  						resumeOnceAndCheckStop = func(s *Session, command string, allowNextStateChange chan struct{}) (*api.DebuggerState, error) {
  3358  							// This should trigger after the log message is sent, but before
  3359  							// execution is resumed.
  3360  							if command == api.DirectionCongruentContinue {
  3361  								go func() {
  3362  									<-outputDoneChan
  3363  									defer close(pauseDoneChan)
  3364  									client.PauseRequest(1)
  3365  									client.ExpectPauseResponse(t)
  3366  								}()
  3367  								// Wait for the pause to be complete.
  3368  								<-pauseDoneChan
  3369  							}
  3370  							return s.resumeOnceAndCheckStop(command, allowNextStateChange)
  3371  						}
  3372  
  3373  						client.ContinueRequest(1)
  3374  						client.ExpectContinueResponse(t)
  3375  						checkLogMessage(t, client.ExpectOutputEvent(t), 1, "in callme!", fixture.Source, 6)
  3376  						// Signal that the output event has been received.
  3377  						close(outputDoneChan)
  3378  						// Wait for the pause to be complete.
  3379  						<-pauseDoneChan
  3380  						se = client.ExpectStoppedEvent(t)
  3381  						if se.Body.Reason != "pause" {
  3382  							t.Errorf("got stopped event = %#v, \nwant Reason=\"pause\"", se)
  3383  						}
  3384  						checkStop(t, client, 1, "main.callme", 6)
  3385  					}
  3386  				},
  3387  				disconnect: true,
  3388  			}})
  3389  	})
  3390  }
  3391  
  3392  // TestConcurrentBreakpointsLogPoints tests that a breakpoint set in the main
  3393  // goroutine is hit the correct number of times and log points set in the
  3394  // children goroutines produce the correct number of output events.
  3395  func TestConcurrentBreakpointsLogPoints(t *testing.T) {
  3396  	if runtime.GOOS == "freebsd" {
  3397  		t.SkipNow()
  3398  	}
  3399  	tests := []struct {
  3400  		name        string
  3401  		fixture     string
  3402  		start       int
  3403  		breakpoints []int
  3404  	}{
  3405  		{
  3406  			name:        "source breakpoints",
  3407  			fixture:     "goroutinestackprog",
  3408  			breakpoints: []int{23},
  3409  		},
  3410  		{
  3411  			name:    "hardcoded breakpoint",
  3412  			fixture: "goroutinebreak",
  3413  		},
  3414  	}
  3415  	for _, tt := range tests {
  3416  		t.Run(tt.name, func(t *testing.T) {
  3417  			runTest(t, tt.fixture, func(client *daptest.Client, fixture protest.Fixture) {
  3418  				client.InitializeRequest()
  3419  				client.ExpectInitializeResponseAndCapabilities(t)
  3420  
  3421  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  3422  				client.ExpectInitializedEvent(t)
  3423  				client.ExpectLaunchResponse(t)
  3424  
  3425  				bps := append([]int{8}, tt.breakpoints...)
  3426  				logMessages := map[int]string{8: "hello"}
  3427  				client.SetBreakpointsRequestWithArgs(fixture.Source, bps, nil, nil, logMessages)
  3428  				client.ExpectSetBreakpointsResponse(t)
  3429  
  3430  				client.ConfigurationDoneRequest()
  3431  				client.ExpectConfigurationDoneResponse(t)
  3432  
  3433  				// There may be up to 1 breakpoint and any number of log points that are
  3434  				// hit concurrently. We should get a stopped event everytime the breakpoint
  3435  				// is hit and an output event for each log point hit.
  3436  				var oeCount, seCount int
  3437  				for oeCount < 10 || seCount < 10 {
  3438  					switch m := client.ExpectMessage(t).(type) {
  3439  					case *dap.StoppedEvent:
  3440  						if m.Body.Reason != "breakpoint" || !m.Body.AllThreadsStopped || m.Body.ThreadId != 1 {
  3441  							t.Errorf("\ngot  %#v\nwant Reason='breakpoint' AllThreadsStopped=true ThreadId=1", m)
  3442  						}
  3443  						seCount++
  3444  						client.ContinueRequest(1)
  3445  					case *dap.OutputEvent:
  3446  						checkLogMessage(t, m, -1, "hello", fixture.Source, 8)
  3447  						oeCount++
  3448  					case *dap.ContinueResponse:
  3449  					case *dap.TerminatedEvent:
  3450  						t.Fatalf("\nexpected 10 output events and 10 stopped events, got %d output events and %d stopped events", oeCount, seCount)
  3451  					default:
  3452  						t.Fatalf("Unexpected message type: expect StoppedEvent, OutputEvent, or ContinueResponse, got %#v", m)
  3453  					}
  3454  				}
  3455  				// TODO(suzmue): The dap server may identify some false
  3456  				// positives for hard coded breakpoints, so there may still
  3457  				// be more stopped events.
  3458  				client.DisconnectRequestWithKillOption(true)
  3459  			})
  3460  		})
  3461  	}
  3462  }
  3463  
  3464  func TestSetBreakpointWhileRunning(t *testing.T) {
  3465  	runTest(t, "integrationprog", func(client *daptest.Client, fixture protest.Fixture) {
  3466  		runDebugSessionWithBPs(t, client, "launch",
  3467  			// Launch
  3468  			func() {
  3469  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  3470  			},
  3471  			// Set breakpoints
  3472  			fixture.Source, []int{16},
  3473  			[]onBreakpoint{{
  3474  				execute: func() {
  3475  					// The program loops 3 times over lines 14-15-8-9-10-16
  3476  					checkStop(t, client, 1, "main.main", 16) // Line that sleeps for 1 second
  3477  
  3478  					// We can set breakpoints while nexting
  3479  					client.NextRequest(1)
  3480  					client.ExpectNextResponse(t)
  3481  					client.SetBreakpointsRequest(fixture.Source, []int{15}) // [16,] => [15,]
  3482  					checkSetBreakpointsResponse(t, []Breakpoint{{15, fixture.Source, true, ""}}, client.ExpectSetBreakpointsResponse(t))
  3483  					se := client.ExpectStoppedEvent(t)
  3484  					if se.Body.Reason != "step" || !se.Body.AllThreadsStopped || se.Body.ThreadId != 1 {
  3485  						t.Errorf("\ngot  %#v\nwant Reason='step' AllThreadsStopped=true ThreadId=1", se)
  3486  					}
  3487  					checkStop(t, client, 1, "main.main", 14)
  3488  					client.ContinueRequest(1)
  3489  					client.ExpectContinueResponse(t)
  3490  					se = client.ExpectStoppedEvent(t)
  3491  					if se.Body.Reason != "breakpoint" || !se.Body.AllThreadsStopped || se.Body.ThreadId != 1 {
  3492  						t.Errorf("\ngot  %#v\nwant Reason='breakpoint' AllThreadsStopped=true ThreadId=1", se)
  3493  					}
  3494  					checkStop(t, client, 1, "main.main", 15)
  3495  
  3496  					// We can set breakpoints while continuing
  3497  					client.ContinueRequest(1)
  3498  					client.ExpectContinueResponse(t)
  3499  					client.SetBreakpointsRequest(fixture.Source, []int{9}) // [15,] => [9,]
  3500  					checkSetBreakpointsResponse(t, []Breakpoint{{9, fixture.Source, true, ""}}, client.ExpectSetBreakpointsResponse(t))
  3501  					se = client.ExpectStoppedEvent(t)
  3502  					if se.Body.Reason != "breakpoint" || !se.Body.AllThreadsStopped || se.Body.ThreadId != 1 {
  3503  						t.Errorf("\ngot  %#v\nwant Reason='breakpoint' AllThreadsStopped=true ThreadId=1", se)
  3504  					}
  3505  					checkStop(t, client, 1, "main.sayhi", 9)
  3506  
  3507  				},
  3508  				disconnect: true,
  3509  			}})
  3510  	})
  3511  }
  3512  
  3513  func TestSetFunctionBreakpointWhileRunning(t *testing.T) {
  3514  	runTest(t, "integrationprog", func(client *daptest.Client, fixture protest.Fixture) {
  3515  		runDebugSessionWithBPs(t, client, "launch",
  3516  			// Launch
  3517  			func() {
  3518  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  3519  			},
  3520  			// Set breakpoints
  3521  			fixture.Source, []int{16},
  3522  			[]onBreakpoint{{
  3523  				execute: func() {
  3524  					// The program loops 3 times over lines 14-15-8-9-10-16
  3525  					checkStop(t, client, 1, "main.main", 16) // Line that sleeps for 1 second
  3526  
  3527  					// We can set breakpoints while nexting
  3528  					client.NextRequest(1)
  3529  					client.ExpectNextResponse(t)
  3530  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{{Name: "main.sayhi"}}) // [16,] => [16, 8]
  3531  					checkBreakpoints(t, []Breakpoint{{8, fixture.Source, true, ""}}, client.ExpectSetFunctionBreakpointsResponse(t).Body.Breakpoints)
  3532  					client.SetBreakpointsRequest(fixture.Source, []int{}) // [16,8] => [8]
  3533  					expectSetBreakpointsResponse(t, client, []Breakpoint{})
  3534  					se := client.ExpectStoppedEvent(t)
  3535  					if se.Body.Reason != "step" || !se.Body.AllThreadsStopped || se.Body.ThreadId != 1 {
  3536  						t.Errorf("\ngot  %#v\nwant Reason='step' AllThreadsStopped=true ThreadId=1", se)
  3537  					}
  3538  					checkStop(t, client, 1, "main.main", 14)
  3539  
  3540  					// Make sure we can hit the breakpoints.
  3541  					client.ContinueRequest(1)
  3542  					client.ExpectContinueResponse(t)
  3543  					se = client.ExpectStoppedEvent(t)
  3544  					if se.Body.Reason != "function breakpoint" || !se.Body.AllThreadsStopped || se.Body.ThreadId != 1 {
  3545  						t.Errorf("\ngot  %#v\nwant Reason='function breakpoint' AllThreadsStopped=true ThreadId=1", se)
  3546  					}
  3547  					checkStop(t, client, 1, "main.sayhi", 8)
  3548  
  3549  					// We can set breakpoints while continuing
  3550  					client.ContinueRequest(1)
  3551  					client.ExpectContinueResponse(t)
  3552  					client.SetFunctionBreakpointsRequest([]dap.FunctionBreakpoint{}) // [8,] => []
  3553  					checkBreakpoints(t, []Breakpoint{}, client.ExpectSetFunctionBreakpointsResponse(t).Body.Breakpoints)
  3554  					client.SetBreakpointsRequest(fixture.Source, []int{16}) // [] => [16]
  3555  					expectSetBreakpointsResponse(t, client, []Breakpoint{{16, fixture.Source, true, ""}})
  3556  					se = client.ExpectStoppedEvent(t)
  3557  					if se.Body.Reason != "breakpoint" || !se.Body.AllThreadsStopped || se.Body.ThreadId != 1 {
  3558  						t.Errorf("\ngot  %#v\nwant Reason='breakpoint' AllThreadsStopped=true ThreadId=1", se)
  3559  					}
  3560  					checkStop(t, client, 1, "main.main", 16)
  3561  
  3562  				},
  3563  				disconnect: true,
  3564  			}})
  3565  	})
  3566  }
  3567  
  3568  func TestHitConditionBreakpoints(t *testing.T) {
  3569  	runTest(t, "break", func(client *daptest.Client, fixture protest.Fixture) {
  3570  		runDebugSessionWithBPs(t, client, "launch",
  3571  			// Launch
  3572  			func() {
  3573  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  3574  			},
  3575  			// Set breakpoints
  3576  			fixture.Source, []int{4},
  3577  			[]onBreakpoint{{
  3578  				execute: func() {
  3579  					client.SetBreakpointsRequestWithArgs(fixture.Source, []int{7}, nil, map[int]string{7: "4"}, nil)
  3580  					expectSetBreakpointsResponse(t, client, []Breakpoint{{7, fixture.Source, true, ""}})
  3581  
  3582  					client.ContinueRequest(1)
  3583  					client.ExpectContinueResponse(t)
  3584  					client.ExpectStoppedEvent(t)
  3585  					checkStop(t, client, 1, "main.main", 7)
  3586  
  3587  					// Check that we are stopped at the correct value of i.
  3588  					client.VariablesRequest(localsScope)
  3589  					locals := client.ExpectVariablesResponse(t)
  3590  					checkVarExact(t, locals, 0, "i", "i", "4", "int", noChildren)
  3591  
  3592  					// Change the hit condition.
  3593  					client.SetBreakpointsRequestWithArgs(fixture.Source, []int{7}, nil, map[int]string{7: "% 2"}, nil)
  3594  					expectSetBreakpointsResponse(t, client, []Breakpoint{{7, fixture.Source, true, ""}})
  3595  
  3596  					client.ContinueRequest(1)
  3597  					client.ExpectContinueResponse(t)
  3598  					client.ExpectStoppedEvent(t)
  3599  					checkStop(t, client, 1, "main.main", 7)
  3600  
  3601  					// Check that we are stopped at the correct value of i.
  3602  					client.VariablesRequest(localsScope)
  3603  					locals = client.ExpectVariablesResponse(t)
  3604  					checkVarExact(t, locals, 0, "i", "i", "6", "int", noChildren)
  3605  
  3606  					// Expect an error if an assignment is passed.
  3607  					client.SetBreakpointsRequestWithArgs(fixture.Source, []int{7}, nil, map[int]string{7: "= 2"}, nil)
  3608  					expectSetBreakpointsResponse(t, client, []Breakpoint{{-1, "", false, ""}})
  3609  
  3610  					// Change the hit condition.
  3611  					client.SetBreakpointsRequestWithArgs(fixture.Source, []int{7}, nil, map[int]string{7: "< 8"}, nil)
  3612  					expectSetBreakpointsResponse(t, client, []Breakpoint{{7, fixture.Source, true, ""}})
  3613  					client.ContinueRequest(1)
  3614  					client.ExpectContinueResponse(t)
  3615  					client.ExpectStoppedEvent(t)
  3616  					checkStop(t, client, 1, "main.main", 7)
  3617  
  3618  					// Check that we are stopped at the correct value of i.
  3619  					client.VariablesRequest(localsScope)
  3620  					locals = client.ExpectVariablesResponse(t)
  3621  					checkVarExact(t, locals, 0, "i", "i", "7", "int", noChildren)
  3622  
  3623  					client.ContinueRequest(1)
  3624  					client.ExpectContinueResponse(t)
  3625  
  3626  					client.ExpectTerminatedEvent(t)
  3627  				},
  3628  				disconnect: false,
  3629  			}})
  3630  	})
  3631  }
  3632  
  3633  // TestLaunchSubstitutePath sets a breakpoint using a path
  3634  // that does not exist and expects the substitutePath attribute
  3635  // in the launch configuration to take care of the mapping.
  3636  func TestLaunchSubstitutePath(t *testing.T) {
  3637  	runTest(t, "loopprog", func(client *daptest.Client, fixture protest.Fixture) {
  3638  		substitutePathTestHelper(t, fixture, client, "launch", map[string]interface{}{"mode": "exec", "program": fixture.Path})
  3639  	})
  3640  }
  3641  
  3642  // TestAttachSubstitutePath sets a breakpoint using a path
  3643  // that does not exist and expects the substitutePath attribute
  3644  // in the launch configuration to take care of the mapping.
  3645  func TestAttachSubstitutePath(t *testing.T) {
  3646  	if runtime.GOOS == "freebsd" {
  3647  		t.SkipNow()
  3648  	}
  3649  	if runtime.GOOS == "windows" {
  3650  		t.Skip("test skipped on windows, see https://delve.beta.teamcity.com/project/Delve_windows for details")
  3651  	}
  3652  	runTest(t, "loopprog", func(client *daptest.Client, fixture protest.Fixture) {
  3653  		cmd := execFixture(t, fixture)
  3654  
  3655  		substitutePathTestHelper(t, fixture, client, "attach", map[string]interface{}{"mode": "local", "processId": cmd.Process.Pid})
  3656  	})
  3657  }
  3658  
  3659  func substitutePathTestHelper(t *testing.T, fixture protest.Fixture, client *daptest.Client, request string, launchAttachConfig map[string]interface{}) {
  3660  	t.Helper()
  3661  	nonexistentDir := filepath.Join(string(filepath.Separator), "path", "that", "does", "not", "exist")
  3662  	if runtime.GOOS == "windows" {
  3663  		nonexistentDir = "C:" + nonexistentDir
  3664  	}
  3665  
  3666  	launchAttachConfig["stopOnEntry"] = false
  3667  	// The rules in 'substitutePath' will be applied as follows:
  3668  	// - mapping paths from client to server:
  3669  	//		The first rule["from"] to match a prefix of 'path' will be applied:
  3670  	//			strings.Replace(path, rule["from"], rule["to"], 1)
  3671  	// - mapping paths from server to client:
  3672  	//		The first rule["to"] to match a prefix of 'path' will be applied:
  3673  	//			strings.Replace(path, rule["to"], rule["from"], 1)
  3674  	launchAttachConfig["substitutePath"] = []map[string]string{
  3675  		{"from": nonexistentDir, "to": filepath.Dir(fixture.Source)},
  3676  		// Since the path mappings are ordered, when converting from client path to
  3677  		// server path, this mapping will not apply, because nonexistentDir appears in
  3678  		// an earlier rule.
  3679  		{"from": nonexistentDir, "to": "this_is_a_bad_path"},
  3680  		// Since the path mappings are ordered, when converting from server path to
  3681  		// client path, this mapping will not apply, because filepath.Dir(fixture.Source)
  3682  		// appears in an earlier rule.
  3683  		{"from": "this_is_a_bad_path", "to": filepath.Dir(fixture.Source)},
  3684  	}
  3685  
  3686  	runDebugSessionWithBPs(t, client, request,
  3687  		func() {
  3688  			switch request {
  3689  			case "attach":
  3690  				client.AttachRequest(launchAttachConfig)
  3691  				client.ExpectCapabilitiesEventSupportTerminateDebuggee(t)
  3692  			case "launch":
  3693  				client.LaunchRequestWithArgs(launchAttachConfig)
  3694  			default:
  3695  				t.Fatalf("invalid request: %s", request)
  3696  			}
  3697  		},
  3698  		// Set breakpoints
  3699  		filepath.Join(nonexistentDir, "loopprog.go"), []int{8},
  3700  		[]onBreakpoint{{
  3701  
  3702  			execute: func() {
  3703  				checkStop(t, client, 1, "main.loop", 8)
  3704  			},
  3705  			disconnect: true,
  3706  		}})
  3707  }
  3708  
  3709  // execFixture runs the binary fixture.Path and hooks up stdout and stderr
  3710  // to os.Stdout and os.Stderr.
  3711  func execFixture(t *testing.T, fixture protest.Fixture) *exec.Cmd {
  3712  	t.Helper()
  3713  	// TODO(polina): do I need to sanity check testBackend and runtime.GOOS?
  3714  	cmd := exec.Command(fixture.Path)
  3715  	cmd.Stdout = os.Stdout
  3716  	cmd.Stderr = os.Stderr
  3717  	if err := cmd.Start(); err != nil {
  3718  		t.Fatal(err)
  3719  	}
  3720  	return cmd
  3721  }
  3722  
  3723  // TestWorkingDir executes to a breakpoint and tests that the specified
  3724  // working directory is the one used to run the program.
  3725  func TestWorkingDir(t *testing.T) {
  3726  	runTest(t, "workdir", func(client *daptest.Client, fixture protest.Fixture) {
  3727  		wd := os.TempDir()
  3728  		// For Darwin `os.TempDir()` returns `/tmp` which is symlink to `/private/tmp`.
  3729  		if runtime.GOOS == "darwin" {
  3730  			wd = "/private/tmp"
  3731  		}
  3732  		runDebugSessionWithBPs(t, client, "launch",
  3733  			// Launch
  3734  			func() {
  3735  				client.LaunchRequestWithArgs(map[string]interface{}{
  3736  					"mode":        "exec",
  3737  					"program":     fixture.Path,
  3738  					"stopOnEntry": false,
  3739  					"cwd":         wd,
  3740  				})
  3741  			},
  3742  			// Set breakpoints
  3743  			fixture.Source, []int{10}, // b main.main
  3744  			[]onBreakpoint{{
  3745  				execute: func() {
  3746  					checkStop(t, client, 1, "main.main", 10)
  3747  					client.VariablesRequest(localsScope)
  3748  					locals := client.ExpectVariablesResponse(t)
  3749  					checkChildren(t, locals, "Locals", 2)
  3750  					for i := range locals.Body.Variables {
  3751  						switch locals.Body.Variables[i].Name {
  3752  						case "pwd":
  3753  							checkVarExact(t, locals, i, "pwd", "pwd", fmt.Sprintf("%q", wd), "string", noChildren)
  3754  						case "err":
  3755  							checkVarExact(t, locals, i, "err", "err", "error nil", "error", noChildren)
  3756  						}
  3757  					}
  3758  				},
  3759  				disconnect: false,
  3760  			}})
  3761  	})
  3762  }
  3763  
  3764  // checkEval is a helper for verifying the values within an EvaluateResponse.
  3765  //
  3766  //	value - the value of the evaluated expression
  3767  //	hasRef - true if the evaluated expression should have children and therefore a non-0 variable reference
  3768  //	ref - reference to retrieve children of this evaluated expression (0 if none)
  3769  func checkEval(t *testing.T, got *dap.EvaluateResponse, value string, hasRef bool) (ref int) {
  3770  	t.Helper()
  3771  	if got.Body.Result != value || (got.Body.VariablesReference > 0) != hasRef {
  3772  		t.Errorf("\ngot  %#v\nwant Result=%q hasRef=%t", got, value, hasRef)
  3773  	}
  3774  	return got.Body.VariablesReference
  3775  }
  3776  
  3777  // checkEvalIndexed is a helper for verifying the values within an EvaluateResponse.
  3778  //
  3779  //	value - the value of the evaluated expression
  3780  //	hasRef - true if the evaluated expression should have children and therefore a non-0 variable reference
  3781  //	ref - reference to retrieve children of this evaluated expression (0 if none)
  3782  func checkEvalIndexed(t *testing.T, got *dap.EvaluateResponse, value string, hasRef bool, indexed, named int) (ref int) {
  3783  	t.Helper()
  3784  	if got.Body.Result != value || (got.Body.VariablesReference > 0) != hasRef || got.Body.IndexedVariables != indexed || got.Body.NamedVariables != named {
  3785  		t.Errorf("\ngot  %#v\nwant Result=%q hasRef=%t IndexedVariables=%d NamedVariables=%d", got, value, hasRef, indexed, named)
  3786  	}
  3787  	return got.Body.VariablesReference
  3788  }
  3789  
  3790  func checkEvalRegex(t *testing.T, got *dap.EvaluateResponse, valueRegex string, hasRef bool) (ref int) {
  3791  	t.Helper()
  3792  	matched, _ := regexp.MatchString(valueRegex, got.Body.Result)
  3793  	if !matched || (got.Body.VariablesReference > 0) != hasRef {
  3794  		t.Errorf("\ngot  %#v\nwant Result=%q hasRef=%t", got, valueRegex, hasRef)
  3795  	}
  3796  	return got.Body.VariablesReference
  3797  }
  3798  
  3799  func TestEvaluateRequest(t *testing.T) {
  3800  	runTest(t, "testvariables", func(client *daptest.Client, fixture protest.Fixture) {
  3801  		runDebugSessionWithBPs(t, client, "launch",
  3802  			// Launch
  3803  			func() {
  3804  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  3805  			},
  3806  			fixture.Source, []int{}, // Breakpoint set in the program
  3807  			[]onBreakpoint{{ // Stop at first breakpoint
  3808  				execute: func() {
  3809  					checkStop(t, client, 1, "main.foobar", 66)
  3810  
  3811  					// Variable lookup
  3812  					client.EvaluateRequest("a2", 1000, "this context will be ignored")
  3813  					got := client.ExpectEvaluateResponse(t)
  3814  					checkEval(t, got, "6", noChildren)
  3815  
  3816  					client.EvaluateRequest("a5", 1000, "this context will be ignored")
  3817  					got = client.ExpectEvaluateResponse(t)
  3818  					ref := checkEval(t, got, "[]int len: 5, cap: 5, [1,2,3,4,5]", hasChildren)
  3819  					if ref > 0 {
  3820  						client.VariablesRequest(ref)
  3821  						a5 := client.ExpectVariablesResponse(t)
  3822  						checkChildren(t, a5, "a5", 5)
  3823  						checkVarExact(t, a5, 0, "[0]", "(a5)[0]", "1", "int", noChildren)
  3824  						checkVarExact(t, a5, 4, "[4]", "(a5)[4]", "5", "int", noChildren)
  3825  						validateEvaluateName(t, client, a5, 0)
  3826  						validateEvaluateName(t, client, a5, 4)
  3827  					}
  3828  
  3829  					// Variable lookup that's not fully loaded
  3830  					client.EvaluateRequest("ba", 1000, "this context will be ignored")
  3831  					got = client.ExpectEvaluateResponse(t)
  3832  					checkEvalIndexed(t, got, "[]int len: 200, cap: 200, [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,...+136 more]", hasChildren, 200, 0)
  3833  
  3834  					// All (binary and unary) on basic types except <-, ++ and --
  3835  					client.EvaluateRequest("1+1", 1000, "this context will be ignored")
  3836  					got = client.ExpectEvaluateResponse(t)
  3837  					checkEval(t, got, "2", noChildren)
  3838  
  3839  					// Comparison operators on any type
  3840  					client.EvaluateRequest("1<2", 1000, "this context will be ignored")
  3841  					got = client.ExpectEvaluateResponse(t)
  3842  					checkEval(t, got, "true", noChildren)
  3843  
  3844  					// Type casts between numeric types
  3845  					client.EvaluateRequest("int(2.3)", 1000, "this context will be ignored")
  3846  					got = client.ExpectEvaluateResponse(t)
  3847  					checkEval(t, got, "2", noChildren)
  3848  
  3849  					// Type casts of integer constants into any pointer type and vice versa
  3850  					client.EvaluateRequest("(*int)(2)", 1000, "this context will be ignored")
  3851  					got = client.ExpectEvaluateResponse(t)
  3852  					ref = checkEvalRegex(t, got, `\*\(unreadable .+\)`, hasChildren)
  3853  					if ref > 0 {
  3854  						client.VariablesRequest(ref)
  3855  						val := client.ExpectVariablesResponse(t)
  3856  						checkChildren(t, val, "*(*int)(2)", 1)
  3857  						checkVarRegex(t, val, 0, "^$", `\(\*\(\(\*int\)\(2\)\)\)`, `\(unreadable .+\)`, "int", noChildren)
  3858  						validateEvaluateName(t, client, val, 0)
  3859  					}
  3860  
  3861  					// Type casts between string, []byte and []rune
  3862  					client.EvaluateRequest("[]byte(\"ABC€\")", 1000, "this context will be ignored")
  3863  					got = client.ExpectEvaluateResponse(t)
  3864  					checkEvalIndexed(t, got, "[]uint8 len: 6, cap: 6, [65,66,67,226,130,172]", noChildren, 6, 0)
  3865  
  3866  					// Struct member access (i.e. somevar.memberfield)
  3867  					client.EvaluateRequest("ms.Nest.Level", 1000, "this context will be ignored")
  3868  					got = client.ExpectEvaluateResponse(t)
  3869  					checkEval(t, got, "1", noChildren)
  3870  
  3871  					// Slicing and indexing operators on arrays, slices and strings
  3872  					client.EvaluateRequest("a5[4]", 1000, "this context will be ignored")
  3873  					got = client.ExpectEvaluateResponse(t)
  3874  					checkEval(t, got, "5", noChildren)
  3875  
  3876  					// Map access
  3877  					client.EvaluateRequest("mp[1]", 1000, "this context will be ignored")
  3878  					got = client.ExpectEvaluateResponse(t)
  3879  					ref = checkEval(t, got, "interface {}(int) 42", hasChildren)
  3880  					if ref > 0 {
  3881  						client.VariablesRequest(ref)
  3882  						expr := client.ExpectVariablesResponse(t)
  3883  						checkChildren(t, expr, "mp[1]", 1)
  3884  						checkVarExact(t, expr, 0, "data", "(mp[1]).(data)", "42", "int", noChildren)
  3885  						validateEvaluateName(t, client, expr, 0)
  3886  					}
  3887  
  3888  					// Pointer dereference
  3889  					client.EvaluateRequest("*ms.Nest", 1000, "this context will be ignored")
  3890  					got = client.ExpectEvaluateResponse(t)
  3891  					ref = checkEvalRegex(t, got, `main\.Nest {Level: 1, Nest: \*main.Nest {Level: 2, Nest: \*\(\*main\.Nest\)\(0x[0-9a-f]+\)}}`, hasChildren)
  3892  					if ref > 0 {
  3893  						client.VariablesRequest(ref)
  3894  						expr := client.ExpectVariablesResponse(t)
  3895  						checkChildren(t, expr, "*ms.Nest", 2)
  3896  						checkVarExact(t, expr, 0, "Level", "(*ms.Nest).Level", "1", "int", noChildren)
  3897  						validateEvaluateName(t, client, expr, 0)
  3898  					}
  3899  
  3900  					// Calls to builtin functions: cap, len, complex, imag and real
  3901  					client.EvaluateRequest("len(a5)", 1000, "this context will be ignored")
  3902  					got = client.ExpectEvaluateResponse(t)
  3903  					checkEval(t, got, "5", noChildren)
  3904  
  3905  					// Type assertion on interface variables (i.e. somevar.(concretetype))
  3906  					client.EvaluateRequest("mp[1].(int)", 1000, "this context will be ignored")
  3907  					got = client.ExpectEvaluateResponse(t)
  3908  					checkEval(t, got, "42", noChildren)
  3909  				},
  3910  				disconnect: false,
  3911  			}, { // Stop at second breakpoint
  3912  				execute: func() {
  3913  					checkStop(t, client, 1, "main.barfoo", 27)
  3914  
  3915  					// Top-most frame
  3916  					client.EvaluateRequest("a1", 1000, "this context will be ignored")
  3917  					got := client.ExpectEvaluateResponse(t)
  3918  					checkEval(t, got, "\"bur\"", noChildren)
  3919  					// No frame defaults to top-most frame
  3920  					client.EvaluateRequest("a1", 0, "this context will be ignored")
  3921  					got = client.ExpectEvaluateResponse(t)
  3922  					checkEval(t, got, "\"bur\"", noChildren)
  3923  					// Next frame
  3924  					client.EvaluateRequest("a1", 1001, "this context will be ignored")
  3925  					got = client.ExpectEvaluateResponse(t)
  3926  					checkEval(t, got, "\"foofoofoofoofoofoo\"", noChildren)
  3927  					// Next frame
  3928  					client.EvaluateRequest("a1", 1002, "any context but watch")
  3929  					erres := client.ExpectVisibleErrorResponse(t)
  3930  					if erres.Body.Error.Format != "Unable to evaluate expression: could not find symbol value for a1" {
  3931  						t.Errorf("\ngot %#v\nwant Format=\"Unable to evaluate expression: could not find symbol value for a1\"", erres)
  3932  					}
  3933  					client.EvaluateRequest("a1", 1002, "watch")
  3934  					erres = client.ExpectInvisibleErrorResponse(t)
  3935  					if erres.Body.Error.Format != "Unable to evaluate expression: could not find symbol value for a1" {
  3936  						t.Errorf("\ngot %#v\nwant Format=\"Unable to evaluate expression: could not find symbol value for a1\"", erres)
  3937  					}
  3938  					client.EvaluateRequest("a1", 1002, "repl")
  3939  					erres = client.ExpectInvisibleErrorResponse(t)
  3940  					if erres.Body.Error.Format != "Unable to evaluate expression: could not find symbol value for a1" {
  3941  						t.Errorf("\ngot %#v\nwant Format=\"Unable to evaluate expression: could not find symbol value for a1\"", erres)
  3942  					}
  3943  					client.EvaluateRequest("a1", 1002, "hover")
  3944  					erres = client.ExpectInvisibleErrorResponse(t)
  3945  					if erres.Body.Error.Format != "Unable to evaluate expression: could not find symbol value for a1" {
  3946  						t.Errorf("\ngot %#v\nwant Format=\"Unable to evaluate expression: could not find symbol value for a1\"", erres)
  3947  					}
  3948  					client.EvaluateRequest("a1", 1002, "clipboard")
  3949  					erres = client.ExpectVisibleErrorResponse(t)
  3950  					if erres.Body.Error.Format != "Unable to evaluate expression: could not find symbol value for a1" {
  3951  						t.Errorf("\ngot %#v\nwant Format=\"Unable to evaluate expression: could not find symbol value for a1\"", erres)
  3952  					}
  3953  				},
  3954  				disconnect: false,
  3955  			}})
  3956  	})
  3957  }
  3958  
  3959  func formatConfig(depth int, showGlobals, showRegisters bool, goroutineFilters string, hideSystemGoroutines bool, substitutePath [][2]string) string {
  3960  	formatStr := `stackTraceDepth	%d
  3961  showGlobalVariables	%v
  3962  showRegisters	%v
  3963  goroutineFilters	%q
  3964  hideSystemGoroutines	%v
  3965  substitutePath	%v
  3966  `
  3967  	return fmt.Sprintf(formatStr, depth, showGlobals, showRegisters, goroutineFilters, hideSystemGoroutines, substitutePath)
  3968  }
  3969  
  3970  func TestEvaluateCommandRequest(t *testing.T) {
  3971  	runTest(t, "testvariables", func(client *daptest.Client, fixture protest.Fixture) {
  3972  		runDebugSessionWithBPs(t, client, "launch",
  3973  			// Launch
  3974  			func() {
  3975  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  3976  			},
  3977  			fixture.Source, []int{}, // Breakpoint set in the program
  3978  			[]onBreakpoint{{ // Stop at first breakpoint
  3979  				execute: func() {
  3980  					checkStop(t, client, 1, "main.foobar", 66)
  3981  
  3982  					// Request help.
  3983  					const dlvHelp = `The following commands are available:
  3984      dlv help (alias: h) 	 Prints the help message.
  3985      dlv config 	 Changes configuration parameters.
  3986      dlv sources (alias: s) 	 Print list of source files.
  3987  
  3988  Type 'dlv help' followed by a command for full documentation.
  3989  `
  3990  					client.EvaluateRequest("dlv help", 1000, "repl")
  3991  					got := client.ExpectEvaluateResponse(t)
  3992  					checkEval(t, got, dlvHelp, noChildren)
  3993  
  3994  					client.EvaluateRequest("dlv help config", 1000, "repl")
  3995  					got = client.ExpectEvaluateResponse(t)
  3996  					checkEval(t, got, msgConfig, noChildren)
  3997  
  3998  					// Test config.
  3999  					client.EvaluateRequest("dlv config -list", 1000, "repl")
  4000  					got = client.ExpectEvaluateResponse(t)
  4001  					checkEval(t, got, formatConfig(50, false, false, "", false, [][2]string{}), noChildren)
  4002  
  4003  					// Read and modify showGlobalVariables.
  4004  					client.EvaluateRequest("dlv config -list showGlobalVariables", 1000, "repl")
  4005  					got = client.ExpectEvaluateResponse(t)
  4006  					checkEval(t, got, "showGlobalVariables\tfalse\n", noChildren)
  4007  
  4008  					client.ScopesRequest(1000)
  4009  					scopes := client.ExpectScopesResponse(t)
  4010  					if len(scopes.Body.Scopes) > 1 {
  4011  						t.Errorf("\ngot  %#v\nwant len(scopes)=1 (Locals)", scopes)
  4012  					}
  4013  					checkScope(t, scopes, 0, "Locals", -1)
  4014  
  4015  					client.EvaluateRequest("dlv config showGlobalVariables true", 1000, "repl")
  4016  					client.ExpectInvalidatedEvent(t)
  4017  					got = client.ExpectEvaluateResponse(t)
  4018  					checkEval(t, got, "showGlobalVariables\ttrue\n\nUpdated", noChildren)
  4019  
  4020  					client.EvaluateRequest("dlv config -list", 1000, "repl")
  4021  					got = client.ExpectEvaluateResponse(t)
  4022  					checkEval(t, got, formatConfig(50, true, false, "", false, [][2]string{}), noChildren)
  4023  
  4024  					client.ScopesRequest(1000)
  4025  					scopes = client.ExpectScopesResponse(t)
  4026  					if len(scopes.Body.Scopes) < 2 {
  4027  						t.Errorf("\ngot  %#v\nwant len(scopes)=2 (Locals & Globals)", scopes)
  4028  					}
  4029  					checkScope(t, scopes, 0, "Locals", -1)
  4030  					checkScope(t, scopes, 1, "Globals (package main)", -1)
  4031  
  4032  					// Read and modify substitutePath.
  4033  					client.EvaluateRequest("dlv config -list substitutePath", 1000, "repl")
  4034  					got = client.ExpectEvaluateResponse(t)
  4035  					checkEval(t, got, "substitutePath\t[]\n", noChildren)
  4036  
  4037  					client.EvaluateRequest(fmt.Sprintf("dlv config substitutePath %q %q", "my/client/path", "your/server/path"), 1000, "repl")
  4038  					got = client.ExpectEvaluateResponse(t)
  4039  					checkEval(t, got, "substitutePath\t[[my/client/path your/server/path]]\n\nUpdated", noChildren)
  4040  
  4041  					client.EvaluateRequest(fmt.Sprintf("dlv config substitutePath %q %q", "my/client/path", "new/your/server/path"), 1000, "repl")
  4042  					got = client.ExpectEvaluateResponse(t)
  4043  					checkEval(t, got, "substitutePath\t[[my/client/path new/your/server/path]]\n\nUpdated", noChildren)
  4044  
  4045  					client.EvaluateRequest(fmt.Sprintf("dlv config substitutePath %q", "my/client/path"), 1000, "repl")
  4046  					got = client.ExpectEvaluateResponse(t)
  4047  					checkEval(t, got, "substitutePath\t[]\n\nUpdated", noChildren)
  4048  
  4049  					// Test sources.
  4050  					client.EvaluateRequest("dlv sources", 1000, "repl")
  4051  					got = client.ExpectEvaluateResponse(t)
  4052  					if !strings.Contains(got.Body.Result, fixture.Source) {
  4053  						t.Errorf("\ngot: %#v, want sources contains %s", got, fixture.Source)
  4054  					}
  4055  
  4056  					client.EvaluateRequest(fmt.Sprintf("dlv sources .*%s", strings.ReplaceAll(filepath.Base(fixture.Source), ".", "\\.")), 1000, "repl")
  4057  					got = client.ExpectEvaluateResponse(t)
  4058  					if got.Body.Result != fixture.Source {
  4059  						t.Errorf("\ngot: %#v, want sources=%q", got, fixture.Source)
  4060  					}
  4061  
  4062  					client.EvaluateRequest("dlv sources nonexistentsource", 1000, "repl")
  4063  					got = client.ExpectEvaluateResponse(t)
  4064  					if got.Body.Result != "" {
  4065  						t.Errorf("\ngot: %#v, want sources=\"\"", got)
  4066  					}
  4067  
  4068  					// Test bad inputs.
  4069  					client.EvaluateRequest("dlv help bad", 1000, "repl")
  4070  					client.ExpectErrorResponse(t)
  4071  
  4072  					client.EvaluateRequest("dlv bad", 1000, "repl")
  4073  					client.ExpectErrorResponse(t)
  4074  				},
  4075  				disconnect: true,
  4076  			}})
  4077  	})
  4078  }
  4079  
  4080  // From testvariables2 fixture
  4081  const (
  4082  	// As defined in the code
  4083  	longstr = `"very long string 0123456789a0123456789b0123456789c0123456789d0123456789e0123456789f0123456789g012345678h90123456789i0123456789j0123456789"`
  4084  	// Loaded with MaxStringLen=64
  4085  	longstrLoaded64   = `"very long string 0123456789a0123456789b0123456789c0123456789d012...+73 more"`
  4086  	longstrLoaded64re = `\"very long string 0123456789a0123456789b0123456789c0123456789d012\.\.\.\+73 more\"`
  4087  )
  4088  
  4089  // TestVariableValueTruncation tests that in certain cases
  4090  // we truncate the loaded variable values to make display more user-friendly.
  4091  func TestVariableValueTruncation(t *testing.T) {
  4092  	runTest(t, "testvariables2", func(client *daptest.Client, fixture protest.Fixture) {
  4093  		runDebugSessionWithBPs(t, client, "launch",
  4094  			// Launch
  4095  			func() {
  4096  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  4097  			},
  4098  			// Breakpoint set within the program
  4099  			fixture.Source, []int{},
  4100  			[]onBreakpoint{{
  4101  				execute: func() {
  4102  					checkStop(t, client, 1, "main.main", -1)
  4103  
  4104  					client.VariablesRequest(localsScope)
  4105  					locals := client.ExpectVariablesResponse(t)
  4106  
  4107  					// Compound variable values may be truncated
  4108  					m1Full := `map\[string\]main\.astruct \[(\"[A-Za-z]+\": {A: [0-9]+, B: [0-9]+}, )+,\.\.\.\+2 more\]`
  4109  					m1Part := `map\[string\]main\.astruct \[(\"[A-Za-z]+\": {A: [0-9]+, B: [0-9]+}, )+.+\.\.\.`
  4110  
  4111  					// In variable responses
  4112  					checkVarRegex(t, locals, -1, "m1", "m1", m1Part, `map\[string\]main\.astruct`, hasChildren)
  4113  
  4114  					// In evaluate responses (select contexts only)
  4115  					tests := []struct {
  4116  						context string
  4117  						want    string
  4118  					}{
  4119  						{"", m1Part},
  4120  						{"watch", m1Part},
  4121  						{"repl", m1Part},
  4122  						{"hover", m1Part},
  4123  						{"variables", m1Full}, // used for copy
  4124  						{"clipboard", m1Full}, // used for copy
  4125  						{"somethingelse", m1Part},
  4126  					}
  4127  					for _, tc := range tests {
  4128  						t.Run(tc.context, func(t *testing.T) {
  4129  							client.EvaluateRequest("m1", 0, tc.context)
  4130  							checkEvalRegex(t, client.ExpectEvaluateResponse(t), tc.want, hasChildren)
  4131  						})
  4132  					}
  4133  
  4134  					// Compound map keys may be truncated even further
  4135  					// As the keys are always inside of a map container,
  4136  					// this applies to variables requests only, not evalute requests.
  4137  
  4138  					// key - compound, value - scalar (inlined key:value display) => truncate key if too long
  4139  					ref := checkVarExact(t, locals, -1, "m5", "m5", "map[main.C]int [{s: "+longstr+"}: 1, ]", "map[main.C]int", hasChildren)
  4140  					if ref > 0 {
  4141  						client.VariablesRequest(ref)
  4142  						// Key format: <truncated>... @<address>
  4143  						checkVarRegex(t, client.ExpectVariablesResponse(t), 1, `main\.C {s: "very long string 0123456789.+\.\.\. @ 0x[0-9a-f]+`, `m5\[\(\*\(\*"main\.C"\)\(0x[0-9a-f]+\)\)\]`, "1", `int`, hasChildren)
  4144  					}
  4145  					// key - scalar, value - scalar (inlined key:value display) => key not truncated
  4146  					ref = checkVarExact(t, locals, -1, "m6", "m6", "map[string]int ["+longstr+": 123, ]", "map[string]int", hasChildren)
  4147  					if ref > 0 {
  4148  						client.VariablesRequest(ref)
  4149  						checkVarExact(t, client.ExpectVariablesResponse(t), 1, longstr, `m6[`+longstr+`]`, "123", "string: int", noChildren)
  4150  					}
  4151  					// key - compound, value - compound (array-like display) => key not truncated
  4152  					ref = checkVarExact(t, locals, -1, "m7", "m7", "map[main.C]main.C [{s: "+longstr+"}: {s: \"hello\"}, ]", "map[main.C]main.C", hasChildren)
  4153  					if ref > 0 {
  4154  						client.VariablesRequest(ref)
  4155  						m7 := client.ExpectVariablesResponse(t)
  4156  						checkVarRegex(t, m7, 1, "[key 0]", `\(\*\(\*\"main\.C\"\)\(0x[0-9a-f]+\)\)`, `main\.C {s: `+longstr+`}`, `main\.C`, hasChildren)
  4157  					}
  4158  				},
  4159  				disconnect: true,
  4160  			}})
  4161  	})
  4162  }
  4163  
  4164  // TestVariableLoadingOfLongStrings tests that different string loading limits
  4165  // apply that depending on the context.
  4166  func TestVariableLoadingOfLongStrings(t *testing.T) {
  4167  	protest.MustSupportFunctionCalls(t, testBackend)
  4168  	runTest(t, "longstrings", func(client *daptest.Client, fixture protest.Fixture) {
  4169  		runDebugSessionWithBPs(t, client, "launch",
  4170  			// Launch
  4171  			func() {
  4172  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  4173  			},
  4174  			// Breakpoint set within the program
  4175  			fixture.Source, []int{},
  4176  			[]onBreakpoint{{
  4177  				execute: func() {
  4178  					checkStop(t, client, 1, "main.main", -1)
  4179  
  4180  					client.VariablesRequest(localsScope)
  4181  					locals := client.ExpectVariablesResponse(t)
  4182  
  4183  					// Limits vary for evaluate requests with different contexts
  4184  					tests := []struct {
  4185  						context string
  4186  						limit   int
  4187  					}{
  4188  						{"", DefaultLoadConfig.MaxStringLen},
  4189  						{"watch", DefaultLoadConfig.MaxStringLen},
  4190  						{"repl", maxSingleStringLen},
  4191  						{"hover", maxSingleStringLen},
  4192  						{"variables", maxSingleStringLen},
  4193  						{"clipboard", maxSingleStringLen},
  4194  						{"somethingelse", DefaultLoadConfig.MaxStringLen},
  4195  					}
  4196  					for _, tc := range tests {
  4197  						t.Run(tc.context, func(t *testing.T) {
  4198  							// Long string by itself (limits vary)
  4199  							client.EvaluateRequest("s4097", 0, tc.context)
  4200  							want := fmt.Sprintf(`"x+\.\.\.\+%d more"`, 4097-tc.limit)
  4201  							checkEvalRegex(t, client.ExpectEvaluateResponse(t), want, noChildren)
  4202  
  4203  							// Evaluated container variables return values with minimally loaded
  4204  							// strings, which are further truncated for displaying, so we
  4205  							// can't test for loading limit except in contexts where an untruncated
  4206  							// value is returned.
  4207  							client.EvaluateRequest("&s4097", 0, tc.context)
  4208  							switch tc.context {
  4209  							case "variables", "clipboard":
  4210  								want = fmt.Sprintf(`\*"x+\.\.\.\+%d more`, 4097-DefaultLoadConfig.MaxStringLen)
  4211  							default:
  4212  								want = fmt.Sprintf(`\*"x{%d}\.\.\.`, maxVarValueLen-2)
  4213  							}
  4214  							checkEvalRegex(t, client.ExpectEvaluateResponse(t), want, hasChildren)
  4215  						})
  4216  					}
  4217  
  4218  					// Long strings returned from calls are subject to a different limit,
  4219  					// same limit regardless of context
  4220  					for _, context := range []string{"", "watch", "repl", "variables", "hover", "clipboard", "somethingelse"} {
  4221  						t.Run(context, func(t *testing.T) {
  4222  							client.EvaluateRequest(`call buildString(4097)`, 1000, context)
  4223  							want := fmt.Sprintf(`"x+\.\.\.\+%d more"`, 4097-maxStringLenInCallRetVars)
  4224  							got := client.ExpectEvaluateResponse(t)
  4225  							checkEvalRegex(t, got, want, hasChildren)
  4226  						})
  4227  					}
  4228  
  4229  					// Variables requests use the most conservative loading limit
  4230  					checkVarRegex(t, locals, -1, "s513", "s513", `"x{512}\.\.\.\+1 more"`, "string", noChildren)
  4231  					// Container variables are subject to additional stricter value truncation that drops +more part
  4232  					checkVarRegex(t, locals, -1, "nested", "nested", `map\[int\]string \[513: \"x+\.\.\.`, "string", hasChildren)
  4233  				},
  4234  				disconnect: true,
  4235  			}})
  4236  	})
  4237  }
  4238  
  4239  func TestEvaluateCallRequest(t *testing.T) {
  4240  	protest.MustSupportFunctionCalls(t, testBackend)
  4241  	runTest(t, "fncall", func(client *daptest.Client, fixture protest.Fixture) {
  4242  		runDebugSessionWithBPs(t, client, "launch",
  4243  			// Launch
  4244  			func() {
  4245  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  4246  			},
  4247  			fixture.Source, []int{88},
  4248  			[]onBreakpoint{{ // Stop in makeclos()
  4249  				execute: func() {
  4250  					checkStop(t, client, 1, "main.makeclos", 88)
  4251  
  4252  					// Topmost frame: both types of expressions should work
  4253  					client.EvaluateRequest("callstacktrace", 1000, "this context will be ignored")
  4254  					client.ExpectEvaluateResponse(t)
  4255  					client.EvaluateRequest("call callstacktrace()", 1000, "this context will be ignored")
  4256  					client.ExpectEvaluateResponse(t)
  4257  
  4258  					// Next frame: only non-call expressions will work
  4259  					client.EvaluateRequest("callstacktrace", 1001, "this context will be ignored")
  4260  					client.ExpectEvaluateResponse(t)
  4261  					client.EvaluateRequest("call callstacktrace()", 1001, "not watch")
  4262  					erres := client.ExpectVisibleErrorResponse(t)
  4263  					if erres.Body.Error.Format != "Unable to evaluate expression: call is only supported with topmost stack frame" {
  4264  						t.Errorf("\ngot %#v\nwant Format=\"Unable to evaluate expression: call is only supported with topmost stack frame\"", erres)
  4265  					}
  4266  
  4267  					// A call can stop on a breakpoint
  4268  					client.EvaluateRequest("call callbreak()", 1000, "not watch")
  4269  					s := client.ExpectStoppedEvent(t)
  4270  					if s.Body.Reason != "hardcoded breakpoint" {
  4271  						t.Errorf("\ngot %#v\nwant Reason=\"hardcoded breakpoint\"", s)
  4272  					}
  4273  					erres = client.ExpectVisibleErrorResponse(t)
  4274  					if erres.Body.Error.Format != "Unable to evaluate expression: call stopped" {
  4275  						t.Errorf("\ngot %#v\nwant Format=\"Unable to evaluate expression: call stopped\"", erres)
  4276  					}
  4277  
  4278  					// A call during a call causes an error
  4279  					client.EvaluateRequest("call callstacktrace()", 1000, "not watch")
  4280  					erres = client.ExpectVisibleErrorResponse(t)
  4281  					if erres.Body.Error.Format != "Unable to evaluate expression: cannot call function while another function call is already in progress" {
  4282  						t.Errorf("\ngot %#v\nwant Format=\"Unable to evaluate expression: cannot call function while another function call is already in progress\"", erres)
  4283  					}
  4284  
  4285  					// Complete the call and get back to original breakpoint in makeclos()
  4286  					client.ContinueRequest(1)
  4287  					client.ExpectContinueResponse(t)
  4288  					client.ExpectStoppedEvent(t)
  4289  					checkStop(t, client, 1, "main.makeclos", 88)
  4290  
  4291  					// Inject a call for the same function that is stopped at breakpoint:
  4292  					// it might stop at the exact same breakpoint on the same goroutine,
  4293  					// but we should still detect that its an injected call that stopped
  4294  					// and not the return to the original point of injection after it
  4295  					// completed.
  4296  					client.EvaluateRequest("call makeclos(nil)", 1000, "not watch")
  4297  					stopped := client.ExpectStoppedEvent(t)
  4298  					erres = client.ExpectVisibleErrorResponse(t)
  4299  					if erres.Body.Error.Format != "Unable to evaluate expression: call stopped" {
  4300  						t.Errorf("\ngot %#v\nwant Format=\"Unable to evaluate expression: call stopped\"", erres)
  4301  					}
  4302  					checkStop(t, client, stopped.Body.ThreadId, "main.makeclos", 88)
  4303  
  4304  					// Complete the call and get back to original breakpoint in makeclos()
  4305  					client.ContinueRequest(1)
  4306  					client.ExpectContinueResponse(t)
  4307  					client.ExpectStoppedEvent(t)
  4308  					checkStop(t, client, 1, "main.makeclos", 88)
  4309  				},
  4310  				disconnect: false,
  4311  			}, { // Stop at runtime breakpoint
  4312  				execute: func() {
  4313  					checkStop(t, client, 1, "main.main", -1)
  4314  
  4315  					// No return values
  4316  					client.EvaluateRequest("call call0(1, 2)", 1000, "this context will be ignored")
  4317  					got := client.ExpectEvaluateResponse(t)
  4318  					checkEval(t, got, "", noChildren)
  4319  					// One unnamed return value
  4320  					client.EvaluateRequest("call call1(one, two)", 1000, "this context will be ignored")
  4321  					got = client.ExpectEvaluateResponse(t)
  4322  					ref := checkEval(t, got, "3", hasChildren)
  4323  					if ref > 0 {
  4324  						client.VariablesRequest(ref)
  4325  						rv := client.ExpectVariablesResponse(t)
  4326  						checkChildren(t, rv, "rv", 1)
  4327  						checkVarExact(t, rv, 0, "~r2", "", "3", "int", noChildren)
  4328  					}
  4329  					// One named return value
  4330  					// Panic doesn't panic, but instead returns the error as a named return variable
  4331  					client.EvaluateRequest("call callpanic()", 1000, "this context will be ignored")
  4332  					got = client.ExpectEvaluateResponse(t)
  4333  					ref = checkEval(t, got, `interface {}(string) "callpanic panicked"`, hasChildren)
  4334  					if ref > 0 {
  4335  						client.VariablesRequest(ref)
  4336  						rv := client.ExpectVariablesResponse(t)
  4337  						checkChildren(t, rv, "rv", 1)
  4338  						ref = checkVarExact(t, rv, 0, "~panic", "", `interface {}(string) "callpanic panicked"`, "interface {}", hasChildren)
  4339  						if ref > 0 {
  4340  							client.VariablesRequest(ref)
  4341  							p := client.ExpectVariablesResponse(t)
  4342  							checkChildren(t, p, "~panic", 1)
  4343  							checkVarExact(t, p, 0, "data", "", "\"callpanic panicked\"", "string", noChildren)
  4344  						}
  4345  					}
  4346  					// Multiple return values
  4347  					client.EvaluateRequest("call call2(one, two)", 1000, "this context will be ignored")
  4348  					got = client.ExpectEvaluateResponse(t)
  4349  					ref = checkEval(t, got, "1, 2", hasChildren)
  4350  					if ref > 0 {
  4351  						client.VariablesRequest(ref)
  4352  						rvs := client.ExpectVariablesResponse(t)
  4353  						checkChildren(t, rvs, "rvs", 2)
  4354  						checkVarExact(t, rvs, 0, "~r2", "", "1", "int", noChildren)
  4355  						checkVarExact(t, rvs, 1, "~r3", "", "2", "int", noChildren)
  4356  					}
  4357  					// No frame defaults to top-most frame
  4358  					client.EvaluateRequest("call call1(one, two)", 0, "this context will be ignored")
  4359  					got = client.ExpectEvaluateResponse(t)
  4360  					checkEval(t, got, "3", hasChildren)
  4361  					// Extra spaces don't matter
  4362  					client.EvaluateRequest(" call  call1(one, one) ", 0, "this context will be ignored")
  4363  					got = client.ExpectEvaluateResponse(t)
  4364  					checkEval(t, got, "2", hasChildren)
  4365  					// Just 'call', even with extra space, is treated as {expression}
  4366  					client.EvaluateRequest("call ", 1000, "watch")
  4367  					got = client.ExpectEvaluateResponse(t)
  4368  					checkEval(t, got, "\"this is a variable named `call`\"", noChildren)
  4369  
  4370  					// Call error
  4371  					client.EvaluateRequest("call call1(one)", 1000, "watch")
  4372  					erres := client.ExpectInvisibleErrorResponse(t)
  4373  					if erres.Body.Error.Format != "Unable to evaluate expression: not enough arguments" {
  4374  						t.Errorf("\ngot %#v\nwant Format=\"Unable to evaluate expression: not enough arguments\"", erres)
  4375  					}
  4376  
  4377  					// Assignment - expect no error, but no return value.
  4378  					client.EvaluateRequest("call one = two", 1000, "this context will be ignored")
  4379  					got = client.ExpectEvaluateResponse(t)
  4380  					checkEval(t, got, "", noChildren)
  4381  					// Check one=two was applied.
  4382  					client.EvaluateRequest("one", 1000, "repl")
  4383  					got = client.ExpectEvaluateResponse(t)
  4384  					checkEval(t, got, "2", noChildren)
  4385  
  4386  					// Call can exit.
  4387  					client.EvaluateRequest("call callexit()", 1000, "this context will be ignored")
  4388  					client.ExpectTerminatedEvent(t)
  4389  					if res := client.ExpectVisibleErrorResponse(t); !strings.Contains(res.Body.Error.Format, "terminated") {
  4390  						t.Errorf("\ngot %#v\nwant Format=.*terminated.*", res)
  4391  					}
  4392  				},
  4393  				terminated: true,
  4394  				disconnect: true,
  4395  			}})
  4396  	})
  4397  }
  4398  
  4399  func TestNextAndStep(t *testing.T) {
  4400  	runTest(t, "testinline", func(client *daptest.Client, fixture protest.Fixture) {
  4401  		runDebugSessionWithBPs(t, client, "launch",
  4402  			// Launch
  4403  			func() {
  4404  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  4405  			},
  4406  			// Set breakpoints
  4407  			fixture.Source, []int{11},
  4408  			[]onBreakpoint{{ // Stop at line 11
  4409  				execute: func() {
  4410  					checkStop(t, client, 1, "main.initialize", 11)
  4411  
  4412  					expectStop := func(fun string, line int) {
  4413  						t.Helper()
  4414  						se := client.ExpectStoppedEvent(t)
  4415  						if se.Body.Reason != "step" || se.Body.ThreadId != 1 || !se.Body.AllThreadsStopped {
  4416  							t.Errorf("got %#v, want Reason=\"step\", ThreadId=1, AllThreadsStopped=true", se)
  4417  						}
  4418  						checkStop(t, client, 1, fun, line)
  4419  					}
  4420  
  4421  					client.StepOutRequest(1)
  4422  					client.ExpectStepOutResponse(t)
  4423  					expectStop("main.main", 18)
  4424  
  4425  					client.NextRequest(1)
  4426  					client.ExpectNextResponse(t)
  4427  					expectStop("main.main", 19)
  4428  
  4429  					client.StepInRequest(1)
  4430  					client.ExpectStepInResponse(t)
  4431  					expectStop("main.inlineThis", 5)
  4432  
  4433  					client.NextRequest(-1000)
  4434  					client.ExpectNextResponse(t)
  4435  					if se := client.ExpectStoppedEvent(t); se.Body.Reason != "error" || se.Body.Text != "unknown goroutine -1000" {
  4436  						t.Errorf("got %#v, want Reason=\"error\", Text=\"unknown goroutine -1000\"", se)
  4437  					}
  4438  					checkStop(t, client, 1, "main.inlineThis", 5)
  4439  				},
  4440  				disconnect: false,
  4441  			}})
  4442  	})
  4443  }
  4444  
  4445  func TestHardCodedBreakpoints(t *testing.T) {
  4446  	runTest(t, "consts", func(client *daptest.Client, fixture protest.Fixture) {
  4447  		runDebugSessionWithBPs(t, client, "launch",
  4448  			// Launch
  4449  			func() {
  4450  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  4451  			},
  4452  			fixture.Source, []int{28},
  4453  			[]onBreakpoint{{ // Stop at line 28
  4454  				execute: func() {
  4455  					checkStop(t, client, 1, "main.main", 28)
  4456  
  4457  					client.ContinueRequest(1)
  4458  					client.ExpectContinueResponse(t)
  4459  					se := client.ExpectStoppedEvent(t)
  4460  					if se.Body.ThreadId != 1 || se.Body.Reason != "breakpoint" {
  4461  						t.Errorf("\ngot  %#v\nwant ThreadId=1 Reason=\"breakpoint\"", se)
  4462  					}
  4463  				},
  4464  				disconnect: false,
  4465  			}})
  4466  	})
  4467  }
  4468  
  4469  // TestStepInstruction executes to a breakpoint and tests stepping
  4470  // a single instruction
  4471  func TestStepInstruction(t *testing.T) {
  4472  	runTest(t, "testvariables", func(client *daptest.Client, fixture protest.Fixture) {
  4473  		runDebugSessionWithBPs(t, client, "launch",
  4474  			// Launch
  4475  			func() {
  4476  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  4477  			},
  4478  			// Set breakpoints
  4479  			fixture.Source, []int{32}, // b main.foobar
  4480  			[]onBreakpoint{{
  4481  				execute: func() {
  4482  					checkStop(t, client, 1, "main.foobar", 32)
  4483  
  4484  					pc, err := getPC(t, client, 1)
  4485  					if err != nil {
  4486  						t.Fatal(err)
  4487  					}
  4488  
  4489  					// The exact instructions may change due to compiler changes,
  4490  					// but we want to make sure that all of our instructions are
  4491  					// instantiating variables, since these should not include
  4492  					// jumps.
  4493  					verifyExpectedLocation := func() {
  4494  						client.StackTraceRequest(1, 0, 20)
  4495  						st := client.ExpectStackTraceResponse(t)
  4496  						if len(st.Body.StackFrames) < 1 {
  4497  							t.Errorf("\ngot  %#v\nwant len(stackframes) => 1", st)
  4498  						} else {
  4499  							// There is a hardcoded breakpoint on line 32. All of the
  4500  							// steps should be completed before that line.
  4501  							if st.Body.StackFrames[0].Line < 32 {
  4502  								t.Errorf("\ngot  %#v\nwant Line<32", st)
  4503  							}
  4504  							if st.Body.StackFrames[0].Name != "main.foobar" {
  4505  								t.Errorf("\ngot  %#v\nwant Name=\"main.foobar\"", st)
  4506  							}
  4507  						}
  4508  					}
  4509  
  4510  					// Next instruction.
  4511  					client.NextInstructionRequest(1)
  4512  					client.ExpectNextResponse(t)
  4513  					se := client.ExpectStoppedEvent(t)
  4514  					if se.Body.ThreadId != 1 || se.Body.Reason != "step" {
  4515  						t.Errorf("\ngot  %#v\nwant ThreadId=1 Reason=\"step\"", se)
  4516  					}
  4517  					verifyExpectedLocation()
  4518  					nextPC, err := getPC(t, client, 1)
  4519  					if err != nil {
  4520  						t.Fatal(err)
  4521  					}
  4522  					if nextPC <= pc {
  4523  						t.Errorf("got %#x, expected InstructionPointerReference>%#x", nextPC, pc)
  4524  					}
  4525  
  4526  					// StepIn instruction.
  4527  					pc = nextPC
  4528  					client.StepInInstructionRequest(1)
  4529  					client.ExpectStepInResponse(t)
  4530  					se = client.ExpectStoppedEvent(t)
  4531  					if se.Body.ThreadId != 1 || se.Body.Reason != "step" {
  4532  						t.Errorf("\ngot  %#v\nwant ThreadId=1 Reason=\"step\"", se)
  4533  					}
  4534  					verifyExpectedLocation()
  4535  					nextPC, err = getPC(t, client, 1)
  4536  					if err != nil {
  4537  						t.Fatal(err)
  4538  					}
  4539  					if nextPC <= pc {
  4540  						t.Errorf("got %#x, expected InstructionPointerReference>%#x", nextPC, pc)
  4541  					}
  4542  
  4543  					// StepOut Instruction.
  4544  					pc = nextPC
  4545  					client.StepOutInstructionRequest(1)
  4546  					client.ExpectStepOutResponse(t)
  4547  					se = client.ExpectStoppedEvent(t)
  4548  					if se.Body.ThreadId != 1 || se.Body.Reason != "step" {
  4549  						t.Errorf("\ngot  %#v\nwant ThreadId=1 Reason=\"step\"", se)
  4550  					}
  4551  					verifyExpectedLocation()
  4552  					nextPC, err = getPC(t, client, 1)
  4553  					if err != nil {
  4554  						t.Fatal(err)
  4555  					}
  4556  					if nextPC <= pc {
  4557  						t.Errorf("got %#x, expected InstructionPointerReference>%#x", nextPC, pc)
  4558  					}
  4559  				},
  4560  				disconnect: true,
  4561  			}})
  4562  	})
  4563  }
  4564  
  4565  func getPC(t *testing.T, client *daptest.Client, threadId int) (uint64, error) {
  4566  	client.StackTraceRequest(threadId, 0, 1)
  4567  	st := client.ExpectStackTraceResponse(t)
  4568  	if len(st.Body.StackFrames) < 1 {
  4569  		t.Fatalf("\ngot  %#v\nwant len(stackframes) => 1", st)
  4570  	}
  4571  	return strconv.ParseUint(st.Body.StackFrames[0].InstructionPointerReference, 0, 64)
  4572  }
  4573  
  4574  // TestNextParked tests that we can switched selected goroutine to a parked one
  4575  // and perform next operation on it.
  4576  func TestNextParked(t *testing.T) {
  4577  	if runtime.GOOS == "freebsd" {
  4578  		t.SkipNow()
  4579  	}
  4580  	runTest(t, "parallel_next", func(client *daptest.Client, fixture protest.Fixture) {
  4581  		runDebugSessionWithBPs(t, client, "launch",
  4582  			// Launch
  4583  			func() {
  4584  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  4585  			},
  4586  			// Set breakpoints
  4587  			fixture.Source, []int{15},
  4588  			[]onBreakpoint{{ // Stop at line 15
  4589  				execute: func() {
  4590  					if parkedGoid := testNextParkedHelper(t, client, fixture); parkedGoid >= 0 {
  4591  						client.NextRequest(parkedGoid)
  4592  						client.ExpectNextResponse(t)
  4593  
  4594  						se := client.ExpectStoppedEvent(t)
  4595  						if se.Body.ThreadId != parkedGoid {
  4596  							t.Fatalf("Next did not continue on the newly selected goroutine, expected %d got %d", parkedGoid, se.Body.ThreadId)
  4597  						}
  4598  					}
  4599  				},
  4600  				// Let the test harness continue to process termination
  4601  				// if it hasn't gotten there already.
  4602  				disconnect: false,
  4603  			}})
  4604  	})
  4605  }
  4606  
  4607  // Finds a goroutine other than the selected one that is parked inside of main.sayhi and therefore
  4608  // still has a line to execute if resumed with next.
  4609  func testNextParkedHelper(t *testing.T, client *daptest.Client, fixture protest.Fixture) int {
  4610  	t.Helper()
  4611  	// Set a breakpoint at main.sayhi
  4612  	client.SetBreakpointsRequest(fixture.Source, []int{8})
  4613  	client.ExpectSetBreakpointsResponse(t)
  4614  
  4615  	var parkedGoid = -1
  4616  	for parkedGoid < 0 {
  4617  		client.ContinueRequest(1)
  4618  		client.ExpectContinueResponse(t)
  4619  		event := client.ExpectMessage(t)
  4620  		switch event.(type) {
  4621  		case *dap.StoppedEvent:
  4622  			// ok
  4623  		case *dap.TerminatedEvent:
  4624  			// This is very unlikely to happen. But in theory if all sayhi
  4625  			// gouritines are run serially, there will never be a second parked
  4626  			// sayhi goroutine when another breaks and we will keep trying
  4627  			// until process termination.
  4628  			return -1
  4629  		}
  4630  
  4631  		se := event.(*dap.StoppedEvent)
  4632  
  4633  		client.ThreadsRequest()
  4634  		threads := client.ExpectThreadsResponse(t)
  4635  
  4636  		// Search for a parked goroutine that we know for sure will have to be
  4637  		// resumed before the program can exit. This is a parked goroutine that:
  4638  		// 1. is executing main.sayhi
  4639  		// 2. hasn't called wg.Done yet
  4640  		// 3. is not the currently selected goroutine
  4641  		for _, g := range threads.Body.Threads {
  4642  			if g.Id == se.Body.ThreadId { // Skip selected goroutine
  4643  				continue
  4644  			}
  4645  			client.StackTraceRequest(g.Id, 0, 5)
  4646  			frames := client.ExpectStackTraceResponse(t)
  4647  			for _, frame := range frames.Body.StackFrames {
  4648  				// line 11 is the line where wg.Done is called
  4649  				if frame.Name == "main.sayhi" && frame.Line < 11 {
  4650  					parkedGoid = g.Id
  4651  					break
  4652  				}
  4653  			}
  4654  			if parkedGoid >= 0 {
  4655  				break
  4656  			}
  4657  		}
  4658  	}
  4659  
  4660  	// Clear all breakpoints.
  4661  	client.SetBreakpointsRequest(fixture.Source, []int{})
  4662  	client.ExpectSetBreakpointsResponse(t)
  4663  	return parkedGoid
  4664  }
  4665  
  4666  // TestStepOutPreservesGoroutine is inspired by proc_test.TestStepOutPreservesGoroutine
  4667  // and checks that StepOut preserves the currently selected goroutine.
  4668  func TestStepOutPreservesGoroutine(t *testing.T) {
  4669  	// Checks that StepOut preserves the currently selected goroutine.
  4670  	if runtime.GOOS == "freebsd" {
  4671  		t.SkipNow()
  4672  	}
  4673  	rand.Seed(time.Now().Unix())
  4674  	runTest(t, "issue2113", func(client *daptest.Client, fixture protest.Fixture) {
  4675  		runDebugSessionWithBPs(t, client, "launch",
  4676  			// Launch
  4677  			func() {
  4678  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  4679  			},
  4680  			// Set breakpoints
  4681  			fixture.Source, []int{25},
  4682  			[]onBreakpoint{{ // Stop at line 25
  4683  				execute: func() {
  4684  					client.ContinueRequest(1)
  4685  					client.ExpectContinueResponse(t)
  4686  
  4687  					// The program contains runtime.Breakpoint()
  4688  					se := client.ExpectStoppedEvent(t)
  4689  
  4690  					client.ThreadsRequest()
  4691  					gs := client.ExpectThreadsResponse(t)
  4692  
  4693  					candg := []int{}
  4694  					bestg := []int{}
  4695  					for _, g := range gs.Body.Threads {
  4696  						// We do not need to check the thread that the program
  4697  						// is currently stopped on.
  4698  						if g.Id == se.Body.ThreadId {
  4699  							continue
  4700  						}
  4701  
  4702  						client.StackTraceRequest(g.Id, 0, 20)
  4703  						frames := client.ExpectStackTraceResponse(t)
  4704  						for _, frame := range frames.Body.StackFrames {
  4705  							if frame.Name == "main.coroutine" {
  4706  								candg = append(candg, g.Id)
  4707  								if strings.HasPrefix(frames.Body.StackFrames[0].Name, "runtime.") {
  4708  									bestg = append(bestg, g.Id)
  4709  								}
  4710  								break
  4711  							}
  4712  						}
  4713  					}
  4714  					var goroutineId int
  4715  					if len(bestg) > 0 {
  4716  						goroutineId = bestg[rand.Intn(len(bestg))]
  4717  						t.Logf("selected goroutine %d (best)\n", goroutineId)
  4718  					} else if len(candg) > 0 {
  4719  						goroutineId = candg[rand.Intn(len(candg))]
  4720  						t.Logf("selected goroutine %d\n", goroutineId)
  4721  
  4722  					}
  4723  
  4724  					if goroutineId != 0 {
  4725  						client.StepOutRequest(goroutineId)
  4726  						client.ExpectStepOutResponse(t)
  4727  					} else {
  4728  						client.ContinueRequest(-1)
  4729  						client.ExpectContinueResponse(t)
  4730  					}
  4731  
  4732  					switch e := client.ExpectMessage(t).(type) {
  4733  					case *dap.StoppedEvent:
  4734  						if e.Body.ThreadId != goroutineId {
  4735  							t.Fatalf("StepOut did not continue on the selected goroutine, expected %d got %d", goroutineId, e.Body.ThreadId)
  4736  						}
  4737  					case *dap.TerminatedEvent:
  4738  						t.Logf("program terminated")
  4739  					default:
  4740  						t.Fatalf("Unexpected event type: expect stopped or terminated event, got %#v", e)
  4741  					}
  4742  				},
  4743  				disconnect: false,
  4744  			}})
  4745  	})
  4746  }
  4747  func checkStopOnNextWhileNextingError(t *testing.T, client *daptest.Client, threadID int) {
  4748  	t.Helper()
  4749  	oe := client.ExpectOutputEvent(t)
  4750  	if oe.Body.Category != "console" || oe.Body.Output != fmt.Sprintf("invalid command: %s\n", BetterNextWhileNextingError) {
  4751  		t.Errorf("\ngot  %#v\nwant Category=\"console\" Output=\"invalid command: %s\\n\"", oe, BetterNextWhileNextingError)
  4752  	}
  4753  	se := client.ExpectStoppedEvent(t)
  4754  	if se.Body.ThreadId != threadID || se.Body.Reason != "exception" || se.Body.Description != "invalid command" || se.Body.Text != BetterNextWhileNextingError {
  4755  		t.Errorf("\ngot  %#v\nwant ThreadId=%d Reason=\"exception\" Description=\"invalid command\" Text=\"%s\"", se, threadID, BetterNextWhileNextingError)
  4756  	}
  4757  	client.ExceptionInfoRequest(1)
  4758  	eInfo := client.ExpectExceptionInfoResponse(t)
  4759  	if eInfo.Body.ExceptionId != "invalid command" || eInfo.Body.Description != BetterNextWhileNextingError {
  4760  		t.Errorf("\ngot  %#v\nwant ExceptionId=\"invalid command\" Text=\"%s\"", eInfo, BetterNextWhileNextingError)
  4761  	}
  4762  }
  4763  
  4764  func TestBadAccess(t *testing.T) {
  4765  	if runtime.GOOS != "darwin" || testBackend != "lldb" {
  4766  		t.Skip("not applicable")
  4767  	}
  4768  	runTest(t, "issue2078", func(client *daptest.Client, fixture protest.Fixture) {
  4769  		runDebugSessionWithBPs(t, client, "launch",
  4770  			// Launch
  4771  			func() {
  4772  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  4773  			},
  4774  			// Set breakpoints
  4775  			fixture.Source, []int{4},
  4776  			[]onBreakpoint{{ // Stop at line 4
  4777  				execute: func() {
  4778  					checkStop(t, client, 1, "main.main", 4)
  4779  
  4780  					expectStoppedOnError := func(errorPrefix string) {
  4781  						t.Helper()
  4782  						se := client.ExpectStoppedEvent(t)
  4783  						if se.Body.ThreadId != 1 || se.Body.Reason != "exception" || se.Body.Description != "runtime error" || !strings.HasPrefix(se.Body.Text, errorPrefix) {
  4784  							t.Errorf("\ngot  %#v\nwant ThreadId=1 Reason=\"exception\" Description=\"runtime error\" Text=\"%s\"", se, errorPrefix)
  4785  						}
  4786  						client.ExceptionInfoRequest(1)
  4787  						eInfo := client.ExpectExceptionInfoResponse(t)
  4788  						if eInfo.Body.ExceptionId != "runtime error" || !strings.HasPrefix(eInfo.Body.Description, errorPrefix) {
  4789  							t.Errorf("\ngot  %#v\nwant ExceptionId=\"runtime error\" Text=\"%s\"", eInfo, errorPrefix)
  4790  						}
  4791  					}
  4792  
  4793  					client.ContinueRequest(1)
  4794  					client.ExpectContinueResponse(t)
  4795  					expectStoppedOnError("invalid memory address or nil pointer dereference")
  4796  
  4797  					client.NextRequest(1)
  4798  					client.ExpectNextResponse(t)
  4799  					expectStoppedOnError("invalid memory address or nil pointer dereference")
  4800  
  4801  					client.NextRequest(1)
  4802  					client.ExpectNextResponse(t)
  4803  					checkStopOnNextWhileNextingError(t, client, 1)
  4804  
  4805  					client.StepInRequest(1)
  4806  					client.ExpectStepInResponse(t)
  4807  					checkStopOnNextWhileNextingError(t, client, 1)
  4808  
  4809  					client.StepOutRequest(1)
  4810  					client.ExpectStepOutResponse(t)
  4811  					checkStopOnNextWhileNextingError(t, client, 1)
  4812  				},
  4813  				disconnect: true,
  4814  			}})
  4815  	})
  4816  }
  4817  
  4818  // TestNextWhileNexting is inspired by command_test.TestIssue387 and tests
  4819  // that when 'next' is interrupted by a 'breakpoint', calling 'next'
  4820  // again will produce an error with a helpful message, and 'continue'
  4821  // will resume the program.
  4822  func TestNextWhileNexting(t *testing.T) {
  4823  	if runtime.GOOS == "freebsd" {
  4824  		t.Skip("test is not valid on FreeBSD")
  4825  	}
  4826  	// a breakpoint triggering during a 'next' operation will interrupt 'next''
  4827  	// Unlike the test for the terminal package, we cannot be certain
  4828  	// of the number of breakpoints we expect to hit, since multiple
  4829  	// breakpoints being hit at the same time is not supported in DAP stopped
  4830  	// events.
  4831  	runTest(t, "issue387", func(client *daptest.Client, fixture protest.Fixture) {
  4832  		runDebugSessionWithBPs(t, client, "launch",
  4833  			// Launch
  4834  			func() {
  4835  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  4836  			},
  4837  			// Set breakpoints
  4838  			fixture.Source, []int{15},
  4839  			[]onBreakpoint{{ // Stop at line 15
  4840  				execute: func() {
  4841  					checkStop(t, client, 1, "main.main", 15)
  4842  
  4843  					client.SetBreakpointsRequest(fixture.Source, []int{8})
  4844  					client.ExpectSetBreakpointsResponse(t)
  4845  
  4846  					client.ContinueRequest(1)
  4847  					client.ExpectContinueResponse(t)
  4848  
  4849  					bpSe := client.ExpectStoppedEvent(t)
  4850  					threadID := bpSe.Body.ThreadId
  4851  					checkStop(t, client, threadID, "main.dostuff", 8)
  4852  
  4853  					for pos := 9; pos < 11; pos++ {
  4854  						client.NextRequest(threadID)
  4855  						client.ExpectNextResponse(t)
  4856  
  4857  						stepInProgress := true
  4858  						for stepInProgress {
  4859  							m := client.ExpectStoppedEvent(t)
  4860  							switch m.Body.Reason {
  4861  							case "step":
  4862  								if !m.Body.AllThreadsStopped {
  4863  									t.Errorf("got %#v, want Reason=\"step\", AllThreadsStopped=true", m)
  4864  								}
  4865  								checkStop(t, client, m.Body.ThreadId, "main.dostuff", pos)
  4866  								stepInProgress = false
  4867  							case "breakpoint":
  4868  								if !m.Body.AllThreadsStopped {
  4869  									t.Errorf("got %#v, want Reason=\"breakpoint\", AllThreadsStopped=true", m)
  4870  								}
  4871  
  4872  								if stepInProgress {
  4873  									// We encountered a breakpoint on a different thread. We should have to resume execution
  4874  									// using continue.
  4875  									oe := client.ExpectOutputEvent(t)
  4876  									if oe.Body.Category != "console" || !strings.Contains(oe.Body.Output, "Step interrupted by a breakpoint.") {
  4877  										t.Errorf("\ngot  %#v\nwant Category=\"console\" Output=\"Step interrupted by a breakpoint.\"", oe)
  4878  									}
  4879  									client.NextRequest(m.Body.ThreadId)
  4880  									client.ExpectNextResponse(t)
  4881  									checkStopOnNextWhileNextingError(t, client, m.Body.ThreadId)
  4882  									// Continue since we have not finished the step request.
  4883  									client.ContinueRequest(threadID)
  4884  									client.ExpectContinueResponse(t)
  4885  								} else {
  4886  									checkStop(t, client, m.Body.ThreadId, "main.dostuff", 8)
  4887  									// Switch to stepping on this thread instead.
  4888  									pos = 8
  4889  									threadID = m.Body.ThreadId
  4890  								}
  4891  							default:
  4892  								t.Fatalf("got %#v, want StoppedEvent on step or breakpoint", m)
  4893  							}
  4894  						}
  4895  					}
  4896  				},
  4897  				disconnect: true,
  4898  			}})
  4899  	})
  4900  }
  4901  
  4902  func TestPanicBreakpointOnContinue(t *testing.T) {
  4903  	runTest(t, "panic", func(client *daptest.Client, fixture protest.Fixture) {
  4904  		runDebugSessionWithBPs(t, client, "launch",
  4905  			// Launch
  4906  			func() {
  4907  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  4908  			},
  4909  			// Set breakpoints
  4910  			fixture.Source, []int{5},
  4911  			[]onBreakpoint{{
  4912  				execute: func() {
  4913  					checkStop(t, client, 1, "main.main", 5)
  4914  
  4915  					client.ContinueRequest(1)
  4916  					client.ExpectContinueResponse(t)
  4917  
  4918  					text := "\"BOOM!\""
  4919  					se := client.ExpectStoppedEvent(t)
  4920  					if se.Body.ThreadId != 1 || se.Body.Reason != "exception" || se.Body.Description != "panic" || se.Body.Text != text {
  4921  						t.Errorf("\ngot  %#v\nwant ThreadId=1 Reason=\"exception\" Description=\"panic\" Text=%q", se, text)
  4922  					}
  4923  
  4924  					client.ExceptionInfoRequest(1)
  4925  					eInfo := client.ExpectExceptionInfoResponse(t)
  4926  					if eInfo.Body.ExceptionId != "panic" || eInfo.Body.Description != text {
  4927  						t.Errorf("\ngot  %#v\nwant ExceptionId=\"panic\" Description=%q", eInfo, text)
  4928  					}
  4929  
  4930  					client.StackTraceRequest(se.Body.ThreadId, 0, 20)
  4931  					st := client.ExpectStackTraceResponse(t)
  4932  					for i, frame := range st.Body.StackFrames {
  4933  						if strings.HasPrefix(frame.Name, "runtime.") {
  4934  							if frame.PresentationHint != "subtle" {
  4935  								t.Errorf("\ngot Body.StackFrames[%d]=%#v\nwant Source.PresentationHint=\"subtle\"", i, frame)
  4936  							}
  4937  						} else if frame.Source.PresentationHint != "" {
  4938  							t.Errorf("\ngot Body.StackFrames[%d]=%#v\nwant Source.PresentationHint=\"\"", i, frame)
  4939  						}
  4940  
  4941  					}
  4942  				},
  4943  				disconnect: true,
  4944  			}})
  4945  	})
  4946  }
  4947  
  4948  func TestPanicBreakpointOnNext(t *testing.T) {
  4949  	if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 14) {
  4950  		// In Go 1.13, 'next' will step into the defer in the runtime
  4951  		// main function, instead of the next line in the main program.
  4952  		t.SkipNow()
  4953  	}
  4954  
  4955  	runTest(t, "panic", func(client *daptest.Client, fixture protest.Fixture) {
  4956  		runDebugSessionWithBPs(t, client, "launch",
  4957  			// Launch
  4958  			func() {
  4959  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  4960  			},
  4961  			// Set breakpoints
  4962  			fixture.Source, []int{5},
  4963  			[]onBreakpoint{{
  4964  				execute: func() {
  4965  					checkStop(t, client, 1, "main.main", 5)
  4966  
  4967  					client.NextRequest(1)
  4968  					client.ExpectNextResponse(t)
  4969  
  4970  					text := "\"BOOM!\""
  4971  					se := client.ExpectStoppedEvent(t)
  4972  					if se.Body.ThreadId != 1 || se.Body.Reason != "exception" || se.Body.Description != "panic" || se.Body.Text != text {
  4973  						t.Errorf("\ngot  %#v\nwant ThreadId=1 Reason=\"exception\" Description=\"panic\" Text=%q", se, text)
  4974  					}
  4975  
  4976  					client.ExceptionInfoRequest(1)
  4977  					eInfo := client.ExpectExceptionInfoResponse(t)
  4978  					if eInfo.Body.ExceptionId != "panic" || eInfo.Body.Description != text {
  4979  						t.Errorf("\ngot  %#v\nwant ExceptionId=\"panic\" Description=%q", eInfo, text)
  4980  					}
  4981  				},
  4982  				disconnect: true,
  4983  			}})
  4984  	})
  4985  }
  4986  
  4987  func TestFatalThrowBreakpoint(t *testing.T) {
  4988  	runTest(t, "fatalerror", func(client *daptest.Client, fixture protest.Fixture) {
  4989  		runDebugSessionWithBPs(t, client, "launch",
  4990  			// Launch
  4991  			func() {
  4992  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  4993  			},
  4994  			// Set breakpoints
  4995  			fixture.Source, []int{3},
  4996  			[]onBreakpoint{{
  4997  				execute: func() {
  4998  					checkStop(t, client, 1, "main.main", 3)
  4999  
  5000  					client.ContinueRequest(1)
  5001  					client.ExpectContinueResponse(t)
  5002  
  5003  					var text string
  5004  					// This does not work for Go 1.16.
  5005  					ver, _ := goversion.Parse(runtime.Version())
  5006  					if ver.Major != 1 || ver.Minor != 16 {
  5007  						text = "\"go of nil func value\""
  5008  					}
  5009  
  5010  					se := client.ExpectStoppedEvent(t)
  5011  					if se.Body.ThreadId != 1 || se.Body.Reason != "exception" || se.Body.Description != "fatal error" || se.Body.Text != text {
  5012  						t.Errorf("\ngot  %#v\nwant ThreadId=1 Reason=\"exception\" Description=\"fatal error\" Text=%q", se, text)
  5013  					}
  5014  
  5015  					// This does not work for Go 1.16.
  5016  					errorPrefix := text
  5017  					if errorPrefix == "" {
  5018  						errorPrefix = "Throw reason unavailable, see https://github.com/golang/go/issues/46425"
  5019  					}
  5020  					client.ExceptionInfoRequest(1)
  5021  					eInfo := client.ExpectExceptionInfoResponse(t)
  5022  					if eInfo.Body.ExceptionId != "fatal error" || !strings.HasPrefix(eInfo.Body.Description, errorPrefix) {
  5023  						t.Errorf("\ngot  %#v\nwant ExceptionId=\"runtime error\" Text=%s", eInfo, errorPrefix)
  5024  					}
  5025  
  5026  				},
  5027  				disconnect: true,
  5028  			}})
  5029  	})
  5030  	runTest(t, "testdeadlock", func(client *daptest.Client, fixture protest.Fixture) {
  5031  		runDebugSessionWithBPs(t, client, "launch",
  5032  			// Launch
  5033  			func() {
  5034  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  5035  			},
  5036  			// Set breakpoints
  5037  			fixture.Source, []int{3},
  5038  			[]onBreakpoint{{
  5039  				execute: func() {
  5040  					checkStop(t, client, 1, "main.main", 3)
  5041  
  5042  					client.ContinueRequest(1)
  5043  					client.ExpectContinueResponse(t)
  5044  
  5045  					// This does not work for Go 1.16 so skip by detecting versions before or after 1.16.
  5046  					var text string
  5047  					if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 16) || goversion.VersionAfterOrEqual(runtime.Version(), 1, 17) {
  5048  						text = "\"all goroutines are asleep - deadlock!\""
  5049  					}
  5050  					se := client.ExpectStoppedEvent(t)
  5051  					if se.Body.Reason != "exception" || se.Body.Description != "fatal error" || se.Body.Text != text {
  5052  						t.Errorf("\ngot  %#v\nwant Reason=\"exception\" Description=\"fatal error\" Text=%q", se, text)
  5053  					}
  5054  
  5055  					// TODO(suzmue): Get the exception info for the thread and check the description
  5056  					// includes "all goroutines are asleep - deadlock!".
  5057  					// Stopped events with no selected goroutines need to be supported to test deadlock.
  5058  				},
  5059  				disconnect: true,
  5060  			}})
  5061  	})
  5062  }
  5063  
  5064  // checkStop covers the standard sequence of requests issued by
  5065  // a client at a breakpoint or another non-terminal stop event.
  5066  // The details have been tested by other tests,
  5067  // so this is just a sanity check.
  5068  // Skips line check if line is -1.
  5069  func checkStop(t *testing.T, client *daptest.Client, thread int, fname string, line int) {
  5070  	t.Helper()
  5071  	client.ThreadsRequest()
  5072  	client.ExpectThreadsResponse(t)
  5073  
  5074  	client.CheckStopLocation(t, thread, fname, line)
  5075  
  5076  	client.ScopesRequest(1000)
  5077  	client.ExpectScopesResponse(t)
  5078  
  5079  	client.VariablesRequest(localsScope)
  5080  	client.ExpectVariablesResponse(t)
  5081  }
  5082  
  5083  // onBreakpoint specifies what the test harness should simulate at
  5084  // a stopped breakpoint. First execute() is to be called to test
  5085  // specified editor-driven or user-driven requests. Then if
  5086  // disconnect is true, the test harness will abort the program
  5087  // execution. Otherwise, a continue will be issued and the
  5088  // program will continue to the next breakpoint or termination.
  5089  // If terminated is true, we expect requests at this breakpoint
  5090  // to result in termination.
  5091  type onBreakpoint struct {
  5092  	execute    func()
  5093  	disconnect bool
  5094  	terminated bool
  5095  }
  5096  
  5097  // runDebugSessionWithBPs is a helper for executing the common init and shutdown
  5098  // sequences for a program that does not stop on entry
  5099  // while specifying breakpoints and unique launch/attach criteria via parameters.
  5100  //
  5101  //	cmd            - "launch" or "attach"
  5102  //	cmdRequest     - a function that sends a launch or attach request,
  5103  //	                 so the test author has full control of its arguments.
  5104  //	                 Note that he rest of the test sequence assumes that
  5105  //	                 stopOnEntry is false.
  5106  //	 source        - source file path, needed to set breakpoints, "" if none to be set.
  5107  //	 breakpoints   - list of lines, where breakpoints are to be set
  5108  //	 onBPs         - list of test sequences to execute at each of the set breakpoints.
  5109  func runDebugSessionWithBPs(t *testing.T, client *daptest.Client, cmd string, cmdRequest func(), source string, breakpoints []int, onBPs []onBreakpoint) {
  5110  	client.InitializeRequest()
  5111  	client.ExpectInitializeResponseAndCapabilities(t)
  5112  
  5113  	cmdRequest()
  5114  	client.ExpectInitializedEvent(t)
  5115  	if cmd == "launch" {
  5116  		client.ExpectLaunchResponse(t)
  5117  	} else if cmd == "attach" {
  5118  		client.ExpectAttachResponse(t)
  5119  	} else {
  5120  		panic("expected launch or attach command")
  5121  	}
  5122  
  5123  	if source != "" {
  5124  		client.SetBreakpointsRequest(source, breakpoints)
  5125  		client.ExpectSetBreakpointsResponse(t)
  5126  	}
  5127  
  5128  	// Skip no-op setExceptionBreakpoints
  5129  
  5130  	client.ConfigurationDoneRequest()
  5131  	client.ExpectConfigurationDoneResponse(t)
  5132  
  5133  	// Program automatically continues to breakpoint or completion
  5134  
  5135  	// TODO(polina): See if we can make this more like withTestProcessArgs in proc_test:
  5136  	// a single function pointer gets called here and then if it wants to continue it calls
  5137  	// client.ContinueRequest/client.ExpectContinueResponse/client.ExpectStoppedEvent
  5138  	// (possibly using a helper function).
  5139  	for _, onBP := range onBPs {
  5140  		client.ExpectStoppedEvent(t)
  5141  		onBP.execute()
  5142  		if onBP.disconnect {
  5143  			client.DisconnectRequestWithKillOption(true)
  5144  			if onBP.terminated {
  5145  				client.ExpectOutputEventProcessExitedAnyStatus(t)
  5146  				client.ExpectOutputEventDetaching(t)
  5147  			} else {
  5148  				client.ExpectOutputEventDetachingKill(t)
  5149  			}
  5150  			client.ExpectDisconnectResponse(t)
  5151  			client.ExpectTerminatedEvent(t)
  5152  			return
  5153  		}
  5154  		client.ContinueRequest(1)
  5155  		client.ExpectContinueResponse(t)
  5156  		// "Continue" is triggered after the response is sent
  5157  	}
  5158  
  5159  	if cmd == "launch" { // Let the program run to completion
  5160  		client.ExpectTerminatedEvent(t)
  5161  	}
  5162  	client.DisconnectRequestWithKillOption(true)
  5163  	if cmd == "launch" {
  5164  		client.ExpectOutputEventProcessExitedAnyStatus(t)
  5165  		client.ExpectOutputEventDetaching(t)
  5166  	} else if cmd == "attach" {
  5167  		client.ExpectOutputEventDetachingKill(t)
  5168  	}
  5169  	client.ExpectDisconnectResponse(t)
  5170  	client.ExpectTerminatedEvent(t)
  5171  }
  5172  
  5173  // runDebugSession is a helper for executing the standard init and shutdown
  5174  // sequences for a program that does not stop on entry
  5175  // while specifying unique launch criteria via parameters.
  5176  func runDebugSession(t *testing.T, client *daptest.Client, cmd string, cmdRequest func()) {
  5177  	runDebugSessionWithBPs(t, client, cmd, cmdRequest, "", nil, nil)
  5178  }
  5179  
  5180  func TestLaunchDebugRequest(t *testing.T) {
  5181  	rescueStderr := os.Stderr
  5182  	r, w, _ := os.Pipe()
  5183  	os.Stderr = w
  5184  	done := make(chan struct{})
  5185  
  5186  	var err []byte
  5187  
  5188  	go func() {
  5189  		err, _ = ioutil.ReadAll(r)
  5190  		t.Log(string(err))
  5191  		close(done)
  5192  	}()
  5193  
  5194  	tmpBin := "__tmpBin"
  5195  	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) {
  5196  		// We reuse the harness that builds, but ignore the built binary,
  5197  		// only relying on the source to be built in response to LaunchRequest.
  5198  		runDebugSession(t, client, "launch", func() {
  5199  			client.LaunchRequestWithArgs(map[string]interface{}{
  5200  				"mode": "debug", "program": fixture.Source, "output": tmpBin})
  5201  		})
  5202  	})
  5203  	// Wait for the test to finish to capture all stderr
  5204  	time.Sleep(100 * time.Millisecond)
  5205  
  5206  	w.Close()
  5207  	<-done
  5208  	os.Stderr = rescueStderr
  5209  
  5210  	rmErrRe, _ := regexp.Compile(`could not remove .*\n`)
  5211  	rmErr := rmErrRe.FindString(string(err))
  5212  	if rmErr != "" {
  5213  		// On Windows, a file in use cannot be removed, resulting in "Access is denied".
  5214  		// When the process exits, Delve releases the binary by calling
  5215  		// BinaryInfo.Close(), but it appears that it is still in use (by Windows?)
  5216  		// shortly after. gobuild.Remove has a delay to address this, but
  5217  		// to avoid any test flakiness we guard against this failure here as well.
  5218  		if runtime.GOOS != "windows" || !stringContainsCaseInsensitive(rmErr, "Access is denied") {
  5219  			t.Fatalf("Binary removal failure:\n%s\n", rmErr)
  5220  		}
  5221  	} else {
  5222  		tmpBin = cleanExeName(tmpBin)
  5223  		// We did not get a removal error, but did we even try to remove before exiting?
  5224  		// Confirm that the binary did get removed.
  5225  		if _, err := os.Stat(tmpBin); err == nil || os.IsExist(err) {
  5226  			t.Fatal("Failed to remove temp binary", tmpBin)
  5227  		}
  5228  	}
  5229  }
  5230  
  5231  // TestLaunchRequestDefaults tests defaults for launch attribute that are explicit in other tests.
  5232  func TestLaunchRequestDefaults(t *testing.T) {
  5233  	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) {
  5234  		runDebugSession(t, client, "launch", func() {
  5235  			client.LaunchRequestWithArgs(map[string]interface{}{
  5236  				"mode": "" /*"debug" by default*/, "program": fixture.Source, "output": "__mybin"})
  5237  		})
  5238  	})
  5239  	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) {
  5240  		runDebugSession(t, client, "launch", func() {
  5241  			client.LaunchRequestWithArgs(map[string]interface{}{
  5242  				/*"mode":"debug" by default*/ "program": fixture.Source, "output": "__mybin"})
  5243  		})
  5244  	})
  5245  	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) {
  5246  		runDebugSession(t, client, "launch", func() {
  5247  			// Use the temporary output binary.
  5248  			client.LaunchRequestWithArgs(map[string]interface{}{
  5249  				"mode": "debug", "program": fixture.Source})
  5250  		})
  5251  	})
  5252  }
  5253  
  5254  // TestLaunchRequestOutputPath verifies that relative output binary path
  5255  // is mapped to server's, not target's, working directory.
  5256  func TestLaunchRequestOutputPath(t *testing.T) {
  5257  	runTest(t, "testargs", func(client *daptest.Client, fixture protest.Fixture) {
  5258  		inrel := "__somebin"
  5259  		wd, _ := os.Getwd()
  5260  		outabs := cleanExeName(filepath.Join(wd, inrel))
  5261  		runDebugSessionWithBPs(t, client, "launch",
  5262  			// Launch
  5263  			func() {
  5264  				client.LaunchRequestWithArgs(map[string]interface{}{
  5265  					"mode": "debug", "program": fixture.Source, "output": inrel,
  5266  					"cwd": filepath.Dir(wd)})
  5267  			},
  5268  			// Set breakpoints
  5269  			fixture.Source, []int{12},
  5270  			[]onBreakpoint{{
  5271  				execute: func() {
  5272  					checkStop(t, client, 1, "main.main", 12)
  5273  					client.EvaluateRequest("os.Args[0]", 1000, "repl")
  5274  					checkEval(t, client.ExpectEvaluateResponse(t), fmt.Sprintf("%q", outabs), noChildren)
  5275  				},
  5276  				disconnect: true,
  5277  			}})
  5278  	})
  5279  }
  5280  
  5281  func TestExitNonZeroStatus(t *testing.T) {
  5282  	runTest(t, "pr1055", func(client *daptest.Client, fixture protest.Fixture) {
  5283  		client.InitializeRequest()
  5284  		client.ExpectInitializeResponseAndCapabilities(t)
  5285  
  5286  		client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  5287  		client.ExpectInitializedEvent(t)
  5288  		client.ExpectLaunchResponse(t)
  5289  
  5290  		client.ConfigurationDoneRequest()
  5291  		client.ExpectConfigurationDoneResponse(t)
  5292  
  5293  		client.ExpectTerminatedEvent(t)
  5294  
  5295  		client.DisconnectRequest()
  5296  		// Check that the process exit status is 2.
  5297  		oep := client.ExpectOutputEventProcessExited(t, 2)
  5298  		if oep.Body.Category != "console" {
  5299  			t.Errorf("\ngot %#v\nwant Category='console'", oep)
  5300  		}
  5301  		oed := client.ExpectOutputEventDetaching(t)
  5302  		if oed.Body.Category != "console" {
  5303  			t.Errorf("\ngot %#v\nwant Category='console'", oed)
  5304  		}
  5305  		client.ExpectDisconnectResponse(t)
  5306  		client.ExpectTerminatedEvent(t)
  5307  	})
  5308  }
  5309  
  5310  func TestNoDebug_GoodExitStatus(t *testing.T) {
  5311  	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) {
  5312  		runNoDebugSession(t, client, func() {
  5313  			client.LaunchRequestWithArgs(map[string]interface{}{
  5314  				"noDebug": true, "mode": "debug", "program": fixture.Source, "output": "__mybin"})
  5315  		}, 0)
  5316  	})
  5317  }
  5318  
  5319  func TestNoDebug_BadExitStatus(t *testing.T) {
  5320  	runTest(t, "issue1101", func(client *daptest.Client, fixture protest.Fixture) {
  5321  		runNoDebugSession(t, client, func() {
  5322  			client.LaunchRequestWithArgs(map[string]interface{}{
  5323  				"noDebug": true, "mode": "exec", "program": fixture.Path})
  5324  		}, 2)
  5325  	})
  5326  }
  5327  
  5328  // runNoDebugSession tests the session started with noDebug=true runs
  5329  // to completion and logs termination status.
  5330  func runNoDebugSession(t *testing.T, client *daptest.Client, launchRequest func(), exitStatus int) {
  5331  	client.InitializeRequest()
  5332  	client.ExpectInitializeResponseAndCapabilities(t)
  5333  
  5334  	launchRequest()
  5335  	// no initialized event.
  5336  	// noDebug mode applies only to "launch" requests.
  5337  	client.ExpectLaunchResponse(t)
  5338  
  5339  	client.ExpectOutputEventProcessExited(t, exitStatus)
  5340  	client.ExpectTerminatedEvent(t)
  5341  	client.DisconnectRequestWithKillOption(true)
  5342  	client.ExpectDisconnectResponse(t)
  5343  	client.ExpectTerminatedEvent(t)
  5344  }
  5345  
  5346  func TestNoDebug_AcceptNoRequestsButDisconnect(t *testing.T) {
  5347  	runTest(t, "http_server", func(client *daptest.Client, fixture protest.Fixture) {
  5348  		client.InitializeRequest()
  5349  		client.ExpectInitializeResponseAndCapabilities(t)
  5350  		client.LaunchRequestWithArgs(map[string]interface{}{
  5351  			"noDebug": true, "mode": "exec", "program": fixture.Path})
  5352  		client.ExpectLaunchResponse(t)
  5353  
  5354  		// Anything other than disconnect should get rejected
  5355  		var ExpectNoDebugError = func(cmd string) {
  5356  			er := client.ExpectErrorResponse(t)
  5357  			if er.Body.Error.Format != fmt.Sprintf("noDebug mode: unable to process '%s' request", cmd) {
  5358  				t.Errorf("\ngot %#v\nwant 'noDebug mode: unable to process '%s' request'", er, cmd)
  5359  			}
  5360  		}
  5361  		client.SetBreakpointsRequest(fixture.Source, []int{8})
  5362  		ExpectNoDebugError("setBreakpoints")
  5363  		client.SetFunctionBreakpointsRequest(nil)
  5364  		ExpectNoDebugError("setFunctionBreakpoints")
  5365  		client.PauseRequest(1)
  5366  		ExpectNoDebugError("pause")
  5367  		client.RestartRequest()
  5368  		client.ExpectUnsupportedCommandErrorResponse(t)
  5369  
  5370  		// Disconnect request is ok
  5371  		client.DisconnectRequestWithKillOption(true)
  5372  		terminated, disconnectResp := false, false
  5373  		for {
  5374  			m, err := client.ReadMessage()
  5375  			if err != nil {
  5376  				break
  5377  			}
  5378  			switch m := m.(type) {
  5379  			case *dap.OutputEvent:
  5380  				ok := false
  5381  				wants := []string{`Terminating process [0-9]+\n`, fmt.Sprintf(daptest.ProcessExited, "(-1|1)")}
  5382  				for _, want := range wants {
  5383  					if matched, _ := regexp.MatchString(want, m.Body.Output); matched {
  5384  						ok = true
  5385  						break
  5386  					}
  5387  				}
  5388  				if !ok {
  5389  					t.Errorf("\ngot %#v\nwant Output=%q\n", m, wants)
  5390  				}
  5391  			case *dap.TerminatedEvent:
  5392  				terminated = true
  5393  			case *dap.DisconnectResponse:
  5394  				disconnectResp = true
  5395  			default:
  5396  				t.Errorf("got unexpected message %#v", m)
  5397  			}
  5398  		}
  5399  		if !terminated {
  5400  			t.Errorf("did not get TerminatedEvent")
  5401  		}
  5402  		if !disconnectResp {
  5403  			t.Errorf("did not get DisconnectResponse")
  5404  		}
  5405  	})
  5406  }
  5407  
  5408  func TestLaunchRequestWithRelativeBuildPath(t *testing.T) {
  5409  	serverStopped := make(chan struct{})
  5410  	client := startDAPServerWithClient(t, serverStopped)
  5411  	defer client.Close()
  5412  
  5413  	fixdir := protest.FindFixturesDir()
  5414  	if filepath.IsAbs(fixdir) {
  5415  		t.Fatal("this test requires relative program path")
  5416  	}
  5417  	program := filepath.Join(protest.FindFixturesDir(), "buildtest")
  5418  
  5419  	// Use different working dir for target than dlv.
  5420  	// Program path will be interpreted relative to dlv's.
  5421  	dlvwd, _ := os.Getwd()
  5422  	runDebugSession(t, client, "launch", func() {
  5423  		client.LaunchRequestWithArgs(map[string]interface{}{
  5424  			"mode": "debug", "program": program, "cwd": filepath.Dir(dlvwd)})
  5425  	})
  5426  	<-serverStopped
  5427  }
  5428  
  5429  func TestLaunchRequestWithRelativeExecPath(t *testing.T) {
  5430  	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) {
  5431  		symlink := "./__thisexe"
  5432  		err := os.Symlink(fixture.Path, symlink)
  5433  		defer os.Remove(symlink)
  5434  		if err != nil {
  5435  			t.Fatal("unable to create relative symlink:", err)
  5436  		}
  5437  		runDebugSession(t, client, "launch", func() {
  5438  			client.LaunchRequestWithArgs(map[string]interface{}{
  5439  				"mode": "exec", "program": symlink})
  5440  		})
  5441  	})
  5442  }
  5443  
  5444  func TestLaunchTestRequest(t *testing.T) {
  5445  	orgWD, _ := os.Getwd()
  5446  	fixtures := protest.FindFixturesDir() // relative to current working directory.
  5447  	absoluteFixturesDir, _ := filepath.Abs(fixtures)
  5448  	absolutePkgDir, _ := filepath.Abs(filepath.Join(fixtures, "buildtest"))
  5449  	testFile := filepath.Join(absolutePkgDir, "main_test.go")
  5450  
  5451  	for _, tc := range []struct {
  5452  		name       string
  5453  		dlvWD      string
  5454  		launchArgs map[string]interface{}
  5455  		wantWD     string
  5456  	}{{
  5457  		name: "default",
  5458  		launchArgs: map[string]interface{}{
  5459  			"mode": "test", "program": absolutePkgDir,
  5460  		},
  5461  		wantWD: absolutePkgDir,
  5462  	}, {
  5463  		name: "output",
  5464  		launchArgs: map[string]interface{}{
  5465  			"mode": "test", "program": absolutePkgDir, "output": "test.out",
  5466  		},
  5467  		wantWD: absolutePkgDir,
  5468  	}, {
  5469  		name: "dlvCwd",
  5470  		launchArgs: map[string]interface{}{
  5471  			"mode": "test", "program": absolutePkgDir, "dlvCwd": ".",
  5472  		},
  5473  		wantWD: absolutePkgDir,
  5474  	}, {
  5475  		name: "dlvCwd2",
  5476  		launchArgs: map[string]interface{}{
  5477  			"mode": "test", "program": ".", "dlvCwd": absolutePkgDir,
  5478  		},
  5479  		wantWD: absolutePkgDir,
  5480  	}, {
  5481  		name: "cwd",
  5482  		launchArgs: map[string]interface{}{
  5483  			"mode": "test", "program": absolutePkgDir, "cwd": fixtures, // fixtures is relative to the current working directory.
  5484  		},
  5485  		wantWD: absoluteFixturesDir,
  5486  	}, {
  5487  		name:  "dlv runs outside of module",
  5488  		dlvWD: os.TempDir(),
  5489  		launchArgs: map[string]interface{}{
  5490  			"mode": "test", "program": absolutePkgDir, "dlvCwd": absoluteFixturesDir,
  5491  		},
  5492  		wantWD: absolutePkgDir,
  5493  	}, {
  5494  		name:  "dlv builds in dlvCwd but runs in cwd",
  5495  		dlvWD: fixtures,
  5496  		launchArgs: map[string]interface{}{
  5497  			"mode": "test", "program": absolutePkgDir, "dlvCwd": absolutePkgDir, "cwd": "..", // relative to dlvCwd.
  5498  		},
  5499  		wantWD: absoluteFixturesDir,
  5500  	}} {
  5501  		t.Run(tc.name, func(t *testing.T) {
  5502  			// Some test cases with dlvCwd or dlvWD change process working directory.
  5503  			defer os.Chdir(orgWD)
  5504  			if tc.dlvWD != "" {
  5505  				os.Chdir(tc.dlvWD)
  5506  				defer os.Chdir(orgWD)
  5507  			}
  5508  			serverStopped := make(chan struct{})
  5509  			client := startDAPServerWithClient(t, serverStopped)
  5510  			defer client.Close()
  5511  
  5512  			runDebugSessionWithBPs(t, client, "launch",
  5513  				func() { // Launch
  5514  					client.LaunchRequestWithArgs(tc.launchArgs)
  5515  				},
  5516  				testFile, []int{14},
  5517  				[]onBreakpoint{{
  5518  					execute: func() {
  5519  						checkStop(t, client, -1, "github.com/undoio/delve/_fixtures/buildtest.TestCurrentDirectory", 14)
  5520  						client.VariablesRequest(1001) // Locals
  5521  						locals := client.ExpectVariablesResponse(t)
  5522  						checkChildren(t, locals, "Locals", 1)
  5523  						for i := range locals.Body.Variables {
  5524  							switch locals.Body.Variables[i].Name {
  5525  							case "wd": // The test's working directory is the package directory by default.
  5526  								checkVarExact(t, locals, i, "wd", "wd", fmt.Sprintf("%q", tc.wantWD), "string", noChildren)
  5527  							}
  5528  						}
  5529  					}}})
  5530  
  5531  			<-serverStopped
  5532  		})
  5533  	}
  5534  }
  5535  
  5536  // Tests that 'args' from LaunchRequest are parsed and passed to the target
  5537  // program. The target program exits without an error on success, and
  5538  // panics on error, causing an unexpected StoppedEvent instead of
  5539  // Terminated Event.
  5540  func TestLaunchRequestWithArgs(t *testing.T) {
  5541  	runTest(t, "testargs", func(client *daptest.Client, fixture protest.Fixture) {
  5542  		runDebugSession(t, client, "launch", func() {
  5543  			client.LaunchRequestWithArgs(map[string]interface{}{
  5544  				"mode": "exec", "program": fixture.Path,
  5545  				"args": []string{"test", "pass flag"}})
  5546  		})
  5547  	})
  5548  }
  5549  
  5550  // Tests that 'buildFlags' from LaunchRequest are parsed and passed to the
  5551  // compiler. The target program exits without an error on success, and
  5552  // panics on error, causing an unexpected StoppedEvent instead of
  5553  // TerminatedEvent.
  5554  func TestLaunchRequestWithBuildFlags(t *testing.T) {
  5555  	runTest(t, "buildflagtest", func(client *daptest.Client, fixture protest.Fixture) {
  5556  		runDebugSession(t, client, "launch", func() {
  5557  			// We reuse the harness that builds, but ignore the built binary,
  5558  			// only relying on the source to be built in response to LaunchRequest.
  5559  			client.LaunchRequestWithArgs(map[string]interface{}{
  5560  				"mode": "debug", "program": fixture.Source, "output": "__mybin",
  5561  				"buildFlags": "-ldflags '-X main.Hello=World'"})
  5562  		})
  5563  	})
  5564  }
  5565  
  5566  func TestLaunchRequestWithEnv(t *testing.T) {
  5567  	// testenv fixture will lookup SOMEVAR with
  5568  	//   x, y := os.Lookup("SOMEVAR")
  5569  	// before stopping at runtime.Breakpoint.
  5570  
  5571  	type envMap map[string]*string
  5572  	strVar := func(s string) *string { return &s }
  5573  
  5574  	fixtures := protest.FindFixturesDir() // relative to current working directory.
  5575  	testFile, _ := filepath.Abs(filepath.Join(fixtures, "testenv.go"))
  5576  	for _, tc := range []struct {
  5577  		name      string
  5578  		initEnv   envMap
  5579  		launchEnv envMap
  5580  		wantX     string
  5581  		wantY     bool
  5582  	}{
  5583  		{
  5584  			name:    "no env",
  5585  			initEnv: envMap{"SOMEVAR": strVar("baz")},
  5586  			wantX:   "baz",
  5587  			wantY:   true,
  5588  		},
  5589  		{
  5590  			name:      "overwrite",
  5591  			initEnv:   envMap{"SOMEVAR": strVar("baz")},
  5592  			launchEnv: envMap{"SOMEVAR": strVar("bar")},
  5593  			wantX:     "bar",
  5594  			wantY:     true,
  5595  		},
  5596  		{
  5597  			name:      "unset",
  5598  			initEnv:   envMap{"SOMEVAR": strVar("baz")},
  5599  			launchEnv: envMap{"SOMEVAR": nil},
  5600  			wantX:     "",
  5601  			wantY:     false,
  5602  		},
  5603  		{
  5604  			name:      "empty value",
  5605  			initEnv:   envMap{"SOMEVAR": strVar("baz")},
  5606  			launchEnv: envMap{"SOMEVAR": strVar("")},
  5607  			wantX:     "",
  5608  			wantY:     true,
  5609  		},
  5610  		{
  5611  			name:      "set",
  5612  			launchEnv: envMap{"SOMEVAR": strVar("foo")},
  5613  			wantX:     "foo",
  5614  			wantY:     true,
  5615  		},
  5616  		{
  5617  			name:      "untouched",
  5618  			initEnv:   envMap{"SOMEVAR": strVar("baz")},
  5619  			launchEnv: envMap{"SOMEVAR2": nil, "SOMEVAR3": strVar("foo")},
  5620  			wantX:     "baz",
  5621  			wantY:     true,
  5622  		},
  5623  	} {
  5624  
  5625  		t.Run(tc.name, func(t *testing.T) {
  5626  			// cleanup
  5627  			defer func() {
  5628  				os.Unsetenv("SOMEVAR")
  5629  				os.Unsetenv("SOMEVAR2")
  5630  				os.Unsetenv("SOMEVAR3")
  5631  			}()
  5632  
  5633  			for k, v := range tc.initEnv {
  5634  				if v != nil {
  5635  					os.Setenv(k, *v)
  5636  				}
  5637  			}
  5638  
  5639  			serverStopped := make(chan struct{})
  5640  			client := startDAPServerWithClient(t, serverStopped)
  5641  			defer client.Close()
  5642  
  5643  			runDebugSessionWithBPs(t, client, "launch", func() { // launch
  5644  				client.LaunchRequestWithArgs(map[string]interface{}{
  5645  					"mode":    "debug",
  5646  					"program": testFile,
  5647  					"env":     tc.launchEnv,
  5648  				})
  5649  			}, testFile, nil, // runtime.Breakpoint
  5650  				[]onBreakpoint{{
  5651  					execute: func() {
  5652  						client.EvaluateRequest("x", 1000, "whatever")
  5653  						gotX := client.ExpectEvaluateResponse(t)
  5654  						checkEval(t, gotX, fmt.Sprintf("%q", tc.wantX), false)
  5655  						client.EvaluateRequest("y", 1000, "whatever")
  5656  						gotY := client.ExpectEvaluateResponse(t)
  5657  						checkEval(t, gotY, fmt.Sprintf("%v", tc.wantY), false)
  5658  					},
  5659  					disconnect: true,
  5660  				}})
  5661  			<-serverStopped
  5662  		})
  5663  	}
  5664  }
  5665  
  5666  func TestAttachRequest(t *testing.T) {
  5667  	if runtime.GOOS == "freebsd" {
  5668  		t.SkipNow()
  5669  	}
  5670  	if runtime.GOOS == "windows" {
  5671  		t.Skip("test skipped on windows, see https://delve.beta.teamcity.com/project/Delve_windows for details")
  5672  	}
  5673  	runTest(t, "loopprog", func(client *daptest.Client, fixture protest.Fixture) {
  5674  		// Start the program to attach to
  5675  		cmd := execFixture(t, fixture)
  5676  
  5677  		runDebugSessionWithBPs(t, client, "attach",
  5678  			// Attach
  5679  			func() {
  5680  				client.AttachRequest(map[string]interface{}{
  5681  					/*"mode": "local" by default*/ "processId": cmd.Process.Pid, "stopOnEntry": false})
  5682  				client.ExpectCapabilitiesEventSupportTerminateDebuggee(t)
  5683  			},
  5684  			// Set breakpoints
  5685  			fixture.Source, []int{8},
  5686  			[]onBreakpoint{{
  5687  				// Stop at line 8
  5688  				execute: func() {
  5689  					checkStop(t, client, 1, "main.loop", 8)
  5690  					client.VariablesRequest(localsScope)
  5691  					locals := client.ExpectVariablesResponse(t)
  5692  					checkChildren(t, locals, "Locals", 1)
  5693  					checkVarRegex(t, locals, 0, "i", "i", "[0-9]+", "int", noChildren)
  5694  				},
  5695  				disconnect: true,
  5696  			}})
  5697  	})
  5698  }
  5699  
  5700  // Since we are in async mode while running, we might receive thee messages after pause request
  5701  // in either order.
  5702  func expectPauseResponseAndStoppedEvent(t *testing.T, client *daptest.Client) {
  5703  	t.Helper()
  5704  	for i := 0; i < 2; i++ {
  5705  		msg := client.ExpectMessage(t)
  5706  		switch m := msg.(type) {
  5707  		case *dap.StoppedEvent:
  5708  			if m.Body.Reason != "pause" || m.Body.ThreadId != 0 && m.Body.ThreadId != 1 {
  5709  				t.Errorf("\ngot %#v\nwant ThreadId=0/1 Reason='pause'", m)
  5710  			}
  5711  		case *dap.PauseResponse:
  5712  		default:
  5713  			t.Fatalf("got %#v, want StoppedEvent or PauseResponse", m)
  5714  		}
  5715  	}
  5716  }
  5717  
  5718  func TestPauseAndContinue(t *testing.T) {
  5719  	runTest(t, "loopprog", func(client *daptest.Client, fixture protest.Fixture) {
  5720  		runDebugSessionWithBPs(t, client, "launch",
  5721  			// Launch
  5722  			func() {
  5723  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  5724  			},
  5725  			// Set breakpoints
  5726  			fixture.Source, []int{6},
  5727  			[]onBreakpoint{{
  5728  				execute: func() {
  5729  					client.CheckStopLocation(t, 1, "main.loop", 6)
  5730  
  5731  					// Continue resumes all goroutines, so thread id is ignored
  5732  					client.ContinueRequest(12345)
  5733  					client.ExpectContinueResponse(t)
  5734  
  5735  					time.Sleep(time.Second)
  5736  
  5737  					// Halt pauses all goroutines, so thread id is ignored
  5738  					client.PauseRequest(56789)
  5739  					expectPauseResponseAndStoppedEvent(t, client)
  5740  
  5741  					// Pause will be a no-op at a pause: there will be no additional stopped events
  5742  					client.PauseRequest(1)
  5743  					client.ExpectPauseResponse(t)
  5744  				},
  5745  				// The program has an infinite loop, so we must kill it by disconnecting.
  5746  				disconnect: true,
  5747  			}})
  5748  	})
  5749  }
  5750  
  5751  func TestUnupportedCommandResponses(t *testing.T) {
  5752  	var got *dap.ErrorResponse
  5753  	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) {
  5754  		seqCnt := 1
  5755  		expectUnsupportedCommand := func(cmd string) {
  5756  			t.Helper()
  5757  			got = client.ExpectUnsupportedCommandErrorResponse(t)
  5758  			if got.RequestSeq != seqCnt || got.Command != cmd {
  5759  				t.Errorf("\ngot  %#v\nwant RequestSeq=%d Command=%s", got, seqCnt, cmd)
  5760  			}
  5761  			seqCnt++
  5762  		}
  5763  
  5764  		client.RestartFrameRequest()
  5765  		expectUnsupportedCommand("restartFrame")
  5766  
  5767  		client.GotoRequest()
  5768  		expectUnsupportedCommand("goto")
  5769  
  5770  		client.SourceRequest()
  5771  		expectUnsupportedCommand("source")
  5772  
  5773  		client.TerminateThreadsRequest()
  5774  		expectUnsupportedCommand("terminateThreads")
  5775  
  5776  		client.StepInTargetsRequest()
  5777  		expectUnsupportedCommand("stepInTargets")
  5778  
  5779  		client.GotoTargetsRequest()
  5780  		expectUnsupportedCommand("gotoTargets")
  5781  
  5782  		client.CompletionsRequest()
  5783  		expectUnsupportedCommand("completions")
  5784  
  5785  		client.DataBreakpointInfoRequest()
  5786  		expectUnsupportedCommand("dataBreakpointInfo")
  5787  
  5788  		client.SetDataBreakpointsRequest()
  5789  		expectUnsupportedCommand("setDataBreakpoints")
  5790  
  5791  		client.BreakpointLocationsRequest()
  5792  		expectUnsupportedCommand("breakpointLocations")
  5793  
  5794  		client.ModulesRequest()
  5795  		expectUnsupportedCommand("modules")
  5796  
  5797  		client.DisconnectRequest()
  5798  		client.ExpectDisconnectResponse(t)
  5799  	})
  5800  }
  5801  
  5802  type helperForSetVariable struct {
  5803  	t *testing.T
  5804  	c *daptest.Client
  5805  }
  5806  
  5807  func (h *helperForSetVariable) expectSetVariable(ref int, name, value string) {
  5808  	h.t.Helper()
  5809  	h.expectSetVariable0(ref, name, value, false)
  5810  }
  5811  
  5812  func (h *helperForSetVariable) failSetVariable(ref int, name, value, wantErrInfo string) {
  5813  	h.t.Helper()
  5814  	h.failSetVariable0(ref, name, value, wantErrInfo, false)
  5815  }
  5816  
  5817  func (h *helperForSetVariable) failSetVariableAndStop(ref int, name, value, wantErrInfo string) {
  5818  	h.t.Helper()
  5819  	h.failSetVariable0(ref, name, value, wantErrInfo, true)
  5820  }
  5821  
  5822  func (h *helperForSetVariable) evaluate(expr, want string, hasRef bool) {
  5823  	h.t.Helper()
  5824  	h.c.EvaluateRequest(expr, 1000, "whatever")
  5825  	got := h.c.ExpectEvaluateResponse(h.t)
  5826  	checkEval(h.t, got, want, hasRef)
  5827  }
  5828  
  5829  func (h *helperForSetVariable) evaluateRegex(expr, want string, hasRef bool) {
  5830  	h.t.Helper()
  5831  	h.c.EvaluateRequest(expr, 1000, "whatever")
  5832  	got := h.c.ExpectEvaluateResponse(h.t)
  5833  	checkEvalRegex(h.t, got, want, hasRef)
  5834  }
  5835  
  5836  func (h *helperForSetVariable) expectSetVariable0(ref int, name, value string, wantStop bool) {
  5837  	h.t.Helper()
  5838  
  5839  	h.c.SetVariableRequest(ref, name, value)
  5840  	if wantStop {
  5841  		h.c.ExpectStoppedEvent(h.t)
  5842  	}
  5843  	if got, want := h.c.ExpectSetVariableResponse(h.t), value; got.Success != true || got.Body.Value != want {
  5844  		h.t.Errorf("SetVariableRequest(%v, %v)=%#v, want {Success=true, Body.Value=%q", name, value, got, want)
  5845  	}
  5846  }
  5847  
  5848  func (h *helperForSetVariable) failSetVariable0(ref int, name, value, wantErrInfo string, wantStop bool) {
  5849  	h.t.Helper()
  5850  
  5851  	h.c.SetVariableRequest(ref, name, value)
  5852  	if wantStop {
  5853  		h.c.ExpectStoppedEvent(h.t)
  5854  	}
  5855  	resp := h.c.ExpectErrorResponse(h.t)
  5856  	if got := resp.Body.Error.Format; !stringContainsCaseInsensitive(got, wantErrInfo) {
  5857  		h.t.Errorf("got %#v, want error string containing %v", got, wantErrInfo)
  5858  	}
  5859  }
  5860  
  5861  func (h *helperForSetVariable) variables(ref int) *dap.VariablesResponse {
  5862  	h.t.Helper()
  5863  	h.c.VariablesRequest(ref)
  5864  	return h.c.ExpectVariablesResponse(h.t)
  5865  }
  5866  
  5867  // TestSetVariable tests SetVariable features that do not need function call support.
  5868  func TestSetVariable(t *testing.T) {
  5869  	runTest(t, "testvariables", func(client *daptest.Client, fixture protest.Fixture) {
  5870  		runDebugSessionWithBPs(t, client, "launch",
  5871  			func() {
  5872  				client.LaunchRequestWithArgs(map[string]interface{}{
  5873  					"mode": "exec", "program": fixture.Path, "showGlobalVariables": true,
  5874  				})
  5875  			},
  5876  			fixture.Source, []int{}, // breakpoints are set within the program.
  5877  			[]onBreakpoint{{
  5878  				execute: func() {
  5879  					tester := &helperForSetVariable{t, client}
  5880  
  5881  					startLineno := 66 // after runtime.Breakpoint
  5882  					if runtime.GOOS == "windows" && goversion.VersionAfterOrEqual(runtime.Version(), 1, 15) {
  5883  						// Go1.15 on windows inserts a NOP after the call to
  5884  						// runtime.Breakpoint and marks it same line as the
  5885  						// runtime.Breakpoint call, making this flaky, so skip the line check.
  5886  						startLineno = -1
  5887  					}
  5888  
  5889  					checkStop(t, client, 1, "main.foobar", startLineno)
  5890  
  5891  					// Local variables
  5892  					locals := tester.variables(localsScope)
  5893  
  5894  					// Args of foobar(baz string, bar FooBar)
  5895  					checkVarExact(t, locals, 1, "bar", "bar", `main.FooBar {Baz: 10, Bur: "lorem"}`, "main.FooBar", hasChildren)
  5896  					tester.failSetVariable(localsScope, "bar", `main.FooBar {Baz: 42, Bur: "ipsum"}`, "*ast.CompositeLit not implemented")
  5897  
  5898  					// Nested field.
  5899  					barRef := checkVarExact(t, locals, 1, "bar", "bar", `main.FooBar {Baz: 10, Bur: "lorem"}`, "main.FooBar", hasChildren)
  5900  					tester.expectSetVariable(barRef, "Baz", "42")
  5901  					tester.evaluate("bar", `main.FooBar {Baz: 42, Bur: "lorem"}`, hasChildren)
  5902  
  5903  					tester.failSetVariable(barRef, "Baz", `"string"`, "can not convert")
  5904  
  5905  					// int
  5906  					checkVarExact(t, locals, -1, "a2", "a2", "6", "int", noChildren)
  5907  					tester.expectSetVariable(localsScope, "a2", "42")
  5908  					tester.evaluate("a2", "42", noChildren)
  5909  
  5910  					tester.failSetVariable(localsScope, "a2", "false", "can not convert")
  5911  
  5912  					// float
  5913  					checkVarExact(t, locals, -1, "a3", "a3", "7.23", "float64", noChildren)
  5914  					tester.expectSetVariable(localsScope, "a3", "-0.1")
  5915  					tester.evaluate("a3", "-0.1", noChildren)
  5916  
  5917  					// array of int
  5918  					a4Ref := checkVarExact(t, locals, -1, "a4", "a4", "[2]int [1,2]", "[2]int", hasChildren)
  5919  					tester.expectSetVariable(a4Ref, "[1]", "-7")
  5920  					tester.evaluate("a4", "[2]int [1,-7]", hasChildren)
  5921  
  5922  					tester.failSetVariable(localsScope, "a4", "[2]int{3, 4}", "not implemented")
  5923  
  5924  					// slice of int
  5925  					a5Ref := checkVarExact(t, locals, -1, "a5", "a5", "[]int len: 5, cap: 5, [1,2,3,4,5]", "[]int", hasChildren)
  5926  					tester.expectSetVariable(a5Ref, "[3]", "100")
  5927  					tester.evaluate("a5", "[]int len: 5, cap: 5, [1,2,3,100,5]", hasChildren)
  5928  
  5929  					// composite literal and its nested fields.
  5930  					a7Ref := checkVarExact(t, locals, -1, "a7", "a7", `*main.FooBar {Baz: 5, Bur: "strum"}`, "*main.FooBar", hasChildren)
  5931  					a7Val := tester.variables(a7Ref)
  5932  					a7ValRef := checkVarExact(t, a7Val, -1, "", "(*a7)", `main.FooBar {Baz: 5, Bur: "strum"}`, "main.FooBar", hasChildren)
  5933  					tester.expectSetVariable(a7ValRef, "Baz", "7")
  5934  					tester.evaluate("(*a7)", `main.FooBar {Baz: 7, Bur: "strum"}`, hasChildren)
  5935  
  5936  					// pointer
  5937  					checkVarExact(t, locals, -1, "a9", "a9", `*main.FooBar nil`, "*main.FooBar", noChildren)
  5938  					tester.expectSetVariable(localsScope, "a9", "&a6")
  5939  					tester.evaluate("a9", `*main.FooBar {Baz: 8, Bur: "word"}`, hasChildren)
  5940  
  5941  					// slice of pointers
  5942  					a13Ref := checkVarExact(t, locals, -1, "a13", "a13", `[]*main.FooBar len: 3, cap: 3, [*{Baz: 6, Bur: "f"},*{Baz: 7, Bur: "g"},*{Baz: 8, Bur: "h"}]`, "[]*main.FooBar", hasChildren)
  5943  					a13 := tester.variables(a13Ref)
  5944  					a13c0Ref := checkVarExact(t, a13, -1, "[0]", "a13[0]", `*main.FooBar {Baz: 6, Bur: "f"}`, "*main.FooBar", hasChildren)
  5945  					a13c0 := tester.variables(a13c0Ref)
  5946  					a13c0valRef := checkVarExact(t, a13c0, -1, "", "(*a13[0])", `main.FooBar {Baz: 6, Bur: "f"}`, "main.FooBar", hasChildren)
  5947  					tester.expectSetVariable(a13c0valRef, "Baz", "777")
  5948  					tester.evaluate("a13[0]", `*main.FooBar {Baz: 777, Bur: "f"}`, hasChildren)
  5949  
  5950  					// complex
  5951  					tester.evaluate("c64", `(1 + 2i)`, hasChildren)
  5952  					tester.expectSetVariable(localsScope, "c64", "(2 + 3i)")
  5953  					tester.evaluate("c64", `(2 + 3i)`, hasChildren)
  5954  					// note: complex's real, imaginary part can't be directly mutable.
  5955  
  5956  					//
  5957  					// Global variables
  5958  					//    p1 = 10
  5959  					client.VariablesRequest(globalsScope)
  5960  					globals := client.ExpectVariablesResponse(t)
  5961  
  5962  					checkVarExact(t, globals, -1, "p1", "main.p1", "10", "int", noChildren)
  5963  					tester.expectSetVariable(globalsScope, "p1", "-10")
  5964  					tester.evaluate("p1", "-10", noChildren)
  5965  					tester.failSetVariable(globalsScope, "p1", "0.1", "can not convert")
  5966  				},
  5967  				disconnect: true,
  5968  			}})
  5969  	})
  5970  
  5971  	runTest(t, "testvariables2", func(client *daptest.Client, fixture protest.Fixture) {
  5972  		runDebugSessionWithBPs(t, client, "launch",
  5973  			func() {
  5974  				client.LaunchRequestWithArgs(map[string]interface{}{
  5975  					"mode": "exec", "program": fixture.Path, "showGlobalVariables": true,
  5976  				})
  5977  			},
  5978  			fixture.Source, []int{}, // breakpoints are set within the program.
  5979  			[]onBreakpoint{{
  5980  				execute: func() {
  5981  					tester := &helperForSetVariable{t, client}
  5982  
  5983  					checkStop(t, client, 1, "main.main", -1)
  5984  					locals := tester.variables(localsScope)
  5985  
  5986  					// channel
  5987  					tester.evaluate("chnil", "chan int nil", noChildren)
  5988  					tester.expectSetVariable(localsScope, "chnil", "ch1")
  5989  					tester.evaluate("chnil", "chan int 4/11", hasChildren)
  5990  
  5991  					// func
  5992  					tester.evaluate("fn2", "nil", noChildren)
  5993  					tester.expectSetVariable(localsScope, "fn2", "fn1")
  5994  					tester.evaluate("fn2", "main.afunc", noChildren)
  5995  
  5996  					// interface
  5997  					tester.evaluate("ifacenil", "interface {} nil", noChildren)
  5998  					tester.expectSetVariable(localsScope, "ifacenil", "iface1")
  5999  					tester.evaluate("ifacenil", "interface {}(*main.astruct) *{A: 1, B: 2}", hasChildren)
  6000  
  6001  					// interface.(data)
  6002  					iface1Ref := checkVarExact(t, locals, -1, "iface1", "iface1", "interface {}(*main.astruct) *{A: 1, B: 2}", "interface {}", hasChildren)
  6003  					iface1 := tester.variables(iface1Ref)
  6004  					iface1DataRef := checkVarExact(t, iface1, -1, "data", "iface1.(data)", "*main.astruct {A: 1, B: 2}", "*main.astruct", hasChildren)
  6005  					iface1Data := tester.variables(iface1DataRef)
  6006  					iface1DataValueRef := checkVarExact(t, iface1Data, -1, "", "(*iface1.(data))", "main.astruct {A: 1, B: 2}", "main.astruct", hasChildren)
  6007  					tester.expectSetVariable(iface1DataValueRef, "A", "2021")
  6008  					tester.evaluate("iface1", "interface {}(*main.astruct) *{A: 2021, B: 2}", hasChildren)
  6009  
  6010  					// map: string -> struct
  6011  					tester.evaluate(`m1["Malone"]`, "main.astruct {A: 2, B: 3}", hasChildren)
  6012  					m1Ref := checkVarRegex(t, locals, -1, "m1", "m1", `.*map\[string\]main\.astruct.*`, `map\[string\]main\.astruct`, hasChildren)
  6013  					m1 := tester.variables(m1Ref)
  6014  					elem1 := m1.Body.Variables[1]
  6015  					tester.expectSetVariable(elem1.VariablesReference, "A", "-9999")
  6016  					tester.expectSetVariable(elem1.VariablesReference, "B", "10000")
  6017  					tester.evaluate(elem1.EvaluateName, "main.astruct {A: -9999, B: 10000}", hasChildren)
  6018  
  6019  					// map: struct -> int
  6020  					m3Ref := checkVarExact(t, locals, -1, "m3", "m3", "map[main.astruct]int [{A: 1, B: 1}: 42, {A: 2, B: 2}: 43, ]", "map[main.astruct]int", hasChildren)
  6021  					tester.expectSetVariable(m3Ref, "main.astruct {A: 1, B: 1}", "8888")
  6022  					// note: updating keys is possible, but let's not promise anything.
  6023  					tester.evaluateRegex("m3", `.*\[\{A: 1, B: 1\}: 8888,.*`, hasChildren)
  6024  
  6025  					// map: struct -> struct
  6026  					m4Ref := checkVarRegex(t, locals, -1, "m4", "m4", `map\[main\.astruct]main\.astruct.*\[\{A: 1, B: 1\}: \{A: 11, B: 11\}.*`, `map\[main\.astruct\]main\.astruct`, hasChildren)
  6027  					m4 := tester.variables(m4Ref)
  6028  					m4Val1Ref := checkVarRegex(t, m4, -1, "[val 0]", `.*0x[0-9a-f]+.*`, `main.astruct.*`, `main\.astruct`, hasChildren)
  6029  					tester.expectSetVariable(m4Val1Ref, "A", "-9999")
  6030  					tester.evaluateRegex("m4", `.*A: -9999,.*`, hasChildren)
  6031  
  6032  					// unsigned pointer
  6033  					checkVarRegex(t, locals, -1, "up1", "up1", `unsafe\.Pointer\(0x[0-9a-f]+\)`, "unsafe.Pointer", noChildren)
  6034  					tester.expectSetVariable(localsScope, "up1", "unsafe.Pointer(0x0)")
  6035  					tester.evaluate("up1", "unsafe.Pointer(0x0)", noChildren)
  6036  
  6037  					// val := A{val: 1}
  6038  					valRef := checkVarExact(t, locals, -1, "val", "val", `main.A {val: 1}`, "main.A", hasChildren)
  6039  					tester.expectSetVariable(valRef, "val", "3")
  6040  					tester.evaluate("val", `main.A {val: 3}`, hasChildren)
  6041  				},
  6042  				disconnect: true,
  6043  			}})
  6044  	})
  6045  }
  6046  
  6047  // TestSetVariableWithCall tests SetVariable features that do not depend on function calls support.
  6048  func TestSetVariableWithCall(t *testing.T) {
  6049  	protest.MustSupportFunctionCalls(t, testBackend)
  6050  
  6051  	runTest(t, "testvariables", func(client *daptest.Client, fixture protest.Fixture) {
  6052  		runDebugSessionWithBPs(t, client, "launch",
  6053  			func() {
  6054  				client.LaunchRequestWithArgs(map[string]interface{}{
  6055  					"mode": "exec", "program": fixture.Path, "showGlobalVariables": true,
  6056  				})
  6057  			},
  6058  			fixture.Source, []int{66, 67},
  6059  			[]onBreakpoint{{
  6060  				execute: func() {
  6061  					tester := &helperForSetVariable{t, client}
  6062  
  6063  					startLineno := 66
  6064  					if runtime.GOOS == "windows" && goversion.VersionAfterOrEqual(runtime.Version(), 1, 15) {
  6065  						// Go1.15 on windows inserts a NOP after the call to
  6066  						// runtime.Breakpoint and marks it same line as the
  6067  						// runtime.Breakpoint call, making this flaky, so skip the line check.
  6068  						startLineno = -1
  6069  					}
  6070  
  6071  					checkStop(t, client, 1, "main.foobar", startLineno)
  6072  
  6073  					// Local variables
  6074  					locals := tester.variables(localsScope)
  6075  
  6076  					// Args of foobar(baz string, bar FooBar)
  6077  					checkVarExact(t, locals, 0, "baz", "baz", `"bazburzum"`, "string", noChildren)
  6078  					tester.expectSetVariable(localsScope, "baz", `"BazBurZum"`)
  6079  					tester.evaluate("baz", `"BazBurZum"`, noChildren)
  6080  
  6081  					barRef := checkVarExact(t, locals, 1, "bar", "bar", `main.FooBar {Baz: 10, Bur: "lorem"}`, "main.FooBar", hasChildren)
  6082  					tester.expectSetVariable(barRef, "Bur", `"ipsum"`)
  6083  					tester.evaluate("bar", `main.FooBar {Baz: 10, Bur: "ipsum"}`, hasChildren)
  6084  
  6085  					checkVarExact(t, locals, -1, "a1", "a1", `"foofoofoofoofoofoo"`, "string", noChildren)
  6086  					tester.expectSetVariable(localsScope, "a1", `"barbarbar"`)
  6087  					tester.evaluate("a1", `"barbarbar"`, noChildren)
  6088  
  6089  					a6Ref := checkVarExact(t, locals, -1, "a6", "a6", `main.FooBar {Baz: 8, Bur: "word"}`, "main.FooBar", hasChildren)
  6090  					tester.failSetVariable(a6Ref, "Bur", "false", "can not convert")
  6091  
  6092  					tester.expectSetVariable(a6Ref, "Bur", `"sentence"`)
  6093  					tester.evaluate("a6", `main.FooBar {Baz: 8, Bur: "sentence"}`, hasChildren)
  6094  				},
  6095  			}, {
  6096  				// Stop at second breakpoint and set a1.
  6097  				execute: func() {
  6098  					tester := &helperForSetVariable{t, client}
  6099  
  6100  					checkStop(t, client, 1, "main.barfoo", -1)
  6101  					// Test: set string 'a1' in main.barfoo.
  6102  					// This shouldn't affect 'a1' in main.foobar - we will check that in the next breakpoint.
  6103  					locals := tester.variables(localsScope)
  6104  					checkVarExact(t, locals, -1, "a1", "a1", `"bur"`, "string", noChildren)
  6105  					tester.expectSetVariable(localsScope, "a1", `"fur"`)
  6106  					tester.evaluate("a1", `"fur"`, noChildren)
  6107  					// We will check a1 in main.foobar isn't affected from the next breakpoint.
  6108  
  6109  					client.StackTraceRequest(1, 1, 20)
  6110  					res := client.ExpectStackTraceResponse(t)
  6111  					if len(res.Body.StackFrames) < 1 {
  6112  						t.Fatalf("stack trace response = %#v, wanted at least one stack frame", res)
  6113  					}
  6114  					outerFrame := res.Body.StackFrames[0].Id
  6115  					client.EvaluateRequest("a1", outerFrame, "whatever_context")
  6116  					evalRes := client.ExpectEvaluateResponse(t)
  6117  					checkEval(t, evalRes, `"barbarbar"`, noChildren)
  6118  				},
  6119  				disconnect: true,
  6120  			}})
  6121  	})
  6122  
  6123  	runTest(t, "fncall", func(client *daptest.Client, fixture protest.Fixture) {
  6124  		runDebugSessionWithBPs(t, client, "launch",
  6125  			func() {
  6126  				client.LaunchRequestWithArgs(map[string]interface{}{
  6127  					"mode": "exec", "program": fixture.Path, "showGlobalVariables": true,
  6128  				})
  6129  			},
  6130  			fixture.Source, []int{}, // breakpoints are set within the program.
  6131  			[]onBreakpoint{{
  6132  				// Stop at second breakpoint and set a1.
  6133  				execute: func() {
  6134  					tester := &helperForSetVariable{t, client}
  6135  
  6136  					checkStop(t, client, 1, "main.main", -1)
  6137  
  6138  					_ = tester.variables(localsScope)
  6139  
  6140  					// successful variable set using a function call.
  6141  					tester.expectSetVariable(localsScope, "str", `callstacktrace()`)
  6142  					tester.evaluateRegex("str", `.*in main.callstacktrace at.*`, noChildren)
  6143  
  6144  					tester.failSetVariableAndStop(localsScope, "str", `callpanic()`, `callpanic panicked`)
  6145  					checkStop(t, client, 1, "main.main", -1)
  6146  
  6147  					// breakpoint during a function call.
  6148  					tester.failSetVariableAndStop(localsScope, "str", `callbreak()`, "call stopped")
  6149  
  6150  					// TODO(hyangah): continue after this causes runtime error while resuming
  6151  					// unfinished injected call.
  6152  					//   runtime error: can not convert %!s(<nil>) constant to string
  6153  					// This can be reproducible with dlv cli. (`call str = callbreak(); continue`)
  6154  				},
  6155  				disconnect: true,
  6156  			}})
  6157  	})
  6158  }
  6159  
  6160  func TestOptionalNotYetImplementedResponses(t *testing.T) {
  6161  	var got *dap.ErrorResponse
  6162  	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) {
  6163  		seqCnt := 1
  6164  		expectNotYetImplemented := func(cmd string) {
  6165  			t.Helper()
  6166  			got = client.ExpectNotYetImplementedErrorResponse(t)
  6167  			if got.RequestSeq != seqCnt || got.Command != cmd {
  6168  				t.Errorf("\ngot  %#v\nwant RequestSeq=%d Command=%s", got, seqCnt, cmd)
  6169  			}
  6170  			seqCnt++
  6171  		}
  6172  
  6173  		client.TerminateRequest()
  6174  		expectNotYetImplemented("terminate")
  6175  
  6176  		client.RestartRequest()
  6177  		expectNotYetImplemented("restart")
  6178  
  6179  		client.SetExpressionRequest()
  6180  		expectNotYetImplemented("setExpression")
  6181  
  6182  		client.LoadedSourcesRequest()
  6183  		expectNotYetImplemented("loadedSources")
  6184  
  6185  		client.ReadMemoryRequest()
  6186  		expectNotYetImplemented("readMemory")
  6187  
  6188  		client.CancelRequest()
  6189  		expectNotYetImplemented("cancel")
  6190  
  6191  		client.DisconnectRequest()
  6192  		client.ExpectDisconnectResponse(t)
  6193  	})
  6194  }
  6195  
  6196  func TestBadLaunchRequests(t *testing.T) {
  6197  	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) {
  6198  		seqCnt := 1
  6199  		checkFailedToLaunch := func(response *dap.ErrorResponse) {
  6200  			t.Helper()
  6201  			if response.RequestSeq != seqCnt {
  6202  				t.Errorf("RequestSeq got %d, want %d", seqCnt, response.RequestSeq)
  6203  			}
  6204  			if response.Command != "launch" {
  6205  				t.Errorf("Command got %q, want \"launch\"", response.Command)
  6206  			}
  6207  			if response.Message != "Failed to launch" {
  6208  				t.Errorf("Message got %q, want \"Failed to launch\"", response.Message)
  6209  			}
  6210  			if response.Body.Error.Id != FailedToLaunch {
  6211  				t.Errorf("Id got %d, want %d", response.Body.Error.Id, FailedToLaunch)
  6212  			}
  6213  			seqCnt++
  6214  		}
  6215  
  6216  		checkFailedToLaunchWithMessage := func(response *dap.ErrorResponse, errmsg string) {
  6217  			t.Helper()
  6218  			checkFailedToLaunch(response)
  6219  			if response.Body.Error.Format != errmsg {
  6220  				t.Errorf("\ngot  %q\nwant %q", response.Body.Error.Format, errmsg)
  6221  			}
  6222  		}
  6223  
  6224  		// Test for the DAP-specific detailed error message.
  6225  		client.LaunchRequest("exec", "", stopOnEntry)
  6226  		checkFailedToLaunchWithMessage(client.ExpectVisibleErrorResponse(t),
  6227  			"Failed to launch: The program attribute is missing in debug configuration.")
  6228  
  6229  		// Bad "program"
  6230  		client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": 12345})
  6231  		checkFailedToLaunchWithMessage(client.ExpectVisibleErrorResponse(t),
  6232  			"Failed to launch: invalid debug configuration - cannot unmarshal number into \"program\" of type string")
  6233  
  6234  		client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": nil})
  6235  		checkFailedToLaunchWithMessage(client.ExpectVisibleErrorResponse(t),
  6236  			"Failed to launch: The program attribute is missing in debug configuration.")
  6237  
  6238  		client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug"})
  6239  		checkFailedToLaunchWithMessage(client.ExpectVisibleErrorResponse(t),
  6240  			"Failed to launch: The program attribute is missing in debug configuration.")
  6241  
  6242  		// Bad "mode"
  6243  		client.LaunchRequest("remote", fixture.Path, stopOnEntry)
  6244  		checkFailedToLaunchWithMessage(client.ExpectVisibleErrorResponse(t),
  6245  			"Failed to launch: invalid debug configuration - unsupported 'mode' attribute \"remote\"")
  6246  
  6247  		client.LaunchRequest("notamode", fixture.Path, stopOnEntry)
  6248  		checkFailedToLaunchWithMessage(client.ExpectVisibleErrorResponse(t),
  6249  			"Failed to launch: invalid debug configuration - unsupported 'mode' attribute \"notamode\"")
  6250  
  6251  		client.LaunchRequestWithArgs(map[string]interface{}{"mode": 12345, "program": fixture.Path})
  6252  		checkFailedToLaunchWithMessage(client.ExpectVisibleErrorResponse(t),
  6253  			"Failed to launch: invalid debug configuration - cannot unmarshal number into \"mode\" of type string")
  6254  
  6255  		client.LaunchRequestWithArgs(map[string]interface{}{"mode": ""}) // empty mode defaults to "debug" (not an error)
  6256  		checkFailedToLaunchWithMessage(client.ExpectVisibleErrorResponse(t),
  6257  			"Failed to launch: The program attribute is missing in debug configuration.")
  6258  
  6259  		client.LaunchRequestWithArgs(map[string]interface{}{}) // missing mode defaults to "debug" (not an error)
  6260  		checkFailedToLaunchWithMessage(client.ExpectVisibleErrorResponse(t),
  6261  			"Failed to launch: The program attribute is missing in debug configuration.")
  6262  
  6263  		// Bad "args"
  6264  		client.LaunchRequestWithArgs(map[string]interface{}{"mode": "exec", "program": fixture.Path, "args": "foobar"})
  6265  		checkFailedToLaunchWithMessage(client.ExpectVisibleErrorResponse(t),
  6266  			"Failed to launch: invalid debug configuration - cannot unmarshal string into \"args\" of type []string")
  6267  
  6268  		client.LaunchRequestWithArgs(map[string]interface{}{"mode": "exec", "program": fixture.Path, "args": 12345})
  6269  		checkFailedToLaunchWithMessage(client.ExpectVisibleErrorResponse(t),
  6270  			"Failed to launch: invalid debug configuration - cannot unmarshal number into \"args\" of type []string")
  6271  
  6272  		client.LaunchRequestWithArgs(map[string]interface{}{"mode": "exec", "program": fixture.Path, "args": []int{1, 2}})
  6273  		checkFailedToLaunchWithMessage(client.ExpectVisibleErrorResponse(t),
  6274  			"Failed to launch: invalid debug configuration - cannot unmarshal number into \"args\" of type string")
  6275  
  6276  		// Bad "buildFlags"
  6277  		client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": fixture.Source, "buildFlags": 123})
  6278  		checkFailedToLaunchWithMessage(client.ExpectVisibleErrorResponse(t),
  6279  			"Failed to launch: invalid debug configuration - cannot unmarshal number into \"buildFlags\" of type string")
  6280  
  6281  		// Bad "backend"
  6282  		client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": fixture.Source, "backend": 123})
  6283  		checkFailedToLaunchWithMessage(client.ExpectVisibleErrorResponse(t),
  6284  			"Failed to launch: invalid debug configuration - cannot unmarshal number into \"backend\" of type string")
  6285  
  6286  		client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": fixture.Source, "backend": "foo"})
  6287  		checkFailedToLaunchWithMessage(client.ExpectVisibleErrorResponse(t),
  6288  			"Failed to launch: could not launch process: unknown backend \"foo\"")
  6289  
  6290  		// Bad "substitutePath"
  6291  		client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": fixture.Source, "substitutePath": 123})
  6292  		checkFailedToLaunchWithMessage(client.ExpectVisibleErrorResponse(t),
  6293  			"Failed to launch: invalid debug configuration - cannot unmarshal number into \"substitutePath\" of type {\"from\":string, \"to\":string}")
  6294  
  6295  		client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": fixture.Source, "substitutePath": []interface{}{123}})
  6296  		checkFailedToLaunchWithMessage(client.ExpectVisibleErrorResponse(t),
  6297  			"Failed to launch: invalid debug configuration - cannot use 123 as 'substitutePath' of type {\"from\":string, \"to\":string}")
  6298  
  6299  		client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": fixture.Source, "substitutePath": []interface{}{map[string]interface{}{"to": "path2"}}})
  6300  		checkFailedToLaunchWithMessage(client.ExpectVisibleErrorResponse(t),
  6301  			"Failed to launch: invalid debug configuration - 'substitutePath' requires both 'from' and 'to' entries")
  6302  
  6303  		client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": fixture.Source, "substitutePath": []interface{}{map[string]interface{}{"from": "path1", "to": 123}}})
  6304  		checkFailedToLaunchWithMessage(client.ExpectVisibleErrorResponse(t),
  6305  			"Failed to launch: invalid debug configuration - cannot use {\"from\":\"path1\",\"to\":123} as 'substitutePath' of type {\"from\":string, \"to\":string}")
  6306  		// Bad "cwd"
  6307  		client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": fixture.Source, "cwd": 123})
  6308  		checkFailedToLaunchWithMessage(client.ExpectVisibleErrorResponse(t),
  6309  			"Failed to launch: invalid debug configuration - cannot unmarshal number into \"cwd\" of type string")
  6310  
  6311  		// Skip detailed message checks for potentially different OS-specific errors.
  6312  		client.LaunchRequest("exec", fixture.Path+"_does_not_exist", stopOnEntry)
  6313  		checkFailedToLaunch(client.ExpectVisibleErrorResponse(t)) // No such file or directory
  6314  
  6315  		client.LaunchRequest("debug", fixture.Path+"_does_not_exist", stopOnEntry)
  6316  		oe := client.ExpectOutputEvent(t)
  6317  		if !strings.HasPrefix(oe.Body.Output, "Build Error: ") || oe.Body.Category != "stderr" {
  6318  			t.Errorf("got %#v, want Category=\"stderr\" Output=\"Build Error: ...\"", oe)
  6319  		}
  6320  		checkFailedToLaunch(client.ExpectInvisibleErrorResponse(t))
  6321  
  6322  		client.LaunchRequestWithArgs(map[string]interface{}{
  6323  			"request": "launch",
  6324  			/* mode: debug by default*/
  6325  			"program":     fixture.Path + "_does_not_exist",
  6326  			"stopOnEntry": stopOnEntry,
  6327  		})
  6328  		oe = client.ExpectOutputEvent(t)
  6329  		if !strings.HasPrefix(oe.Body.Output, "Build Error: ") || oe.Body.Category != "stderr" {
  6330  			t.Errorf("got %#v, want Category=\"stderr\" Output=\"Build Error: ...\"", oe)
  6331  		}
  6332  		checkFailedToLaunch(client.ExpectInvisibleErrorResponse(t))
  6333  
  6334  		client.LaunchRequest("exec", fixture.Source, stopOnEntry)
  6335  		checkFailedToLaunch(client.ExpectVisibleErrorResponse(t)) // Not an executable
  6336  
  6337  		client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": fixture.Source, "buildFlags": "-bad -flags"})
  6338  		oe = client.ExpectOutputEvent(t)
  6339  		if !strings.HasPrefix(oe.Body.Output, "Build Error: ") || oe.Body.Category != "stderr" {
  6340  			t.Errorf("got %#v, want Category=\"stderr\" Output=\"Build Error: ...\"", oe)
  6341  		}
  6342  		checkFailedToLaunchWithMessage(client.ExpectInvisibleErrorResponse(t), "Failed to launch: Build error: Check the debug console for details.")
  6343  		client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": fixture.Source, "noDebug": true, "buildFlags": "-bad -flags"})
  6344  		oe = client.ExpectOutputEvent(t)
  6345  		if !strings.HasPrefix(oe.Body.Output, "Build Error: ") || oe.Body.Category != "stderr" {
  6346  			t.Errorf("got %#v, want Category=\"stderr\" Output=\"Build Error: ...\"", oe)
  6347  		}
  6348  		checkFailedToLaunchWithMessage(client.ExpectInvisibleErrorResponse(t), "Failed to launch: Build error: Check the debug console for details.")
  6349  
  6350  		// Bad "cwd"
  6351  		client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": fixture.Source, "noDebug": false, "cwd": "dir/invalid"})
  6352  		checkFailedToLaunch(client.ExpectVisibleErrorResponse(t)) // invalid directory, the error message is system-dependent.
  6353  		client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": fixture.Source, "noDebug": true, "cwd": "dir/invalid"})
  6354  		checkFailedToLaunch(client.ExpectVisibleErrorResponse(t)) // invalid directory, the error message is system-dependent.
  6355  
  6356  		// Bad "noDebug"
  6357  		client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": fixture.Source, "noDebug": "true"})
  6358  		checkFailedToLaunchWithMessage(client.ExpectVisibleErrorResponse(t), "Failed to launch: invalid debug configuration - cannot unmarshal string into \"noDebug\" of type bool")
  6359  
  6360  		// Bad "replay" parameters
  6361  		// These errors come from dap layer
  6362  		client.LaunchRequestWithArgs(map[string]interface{}{"mode": "replay", "traceDirPath": ""})
  6363  		checkFailedToLaunchWithMessage(client.ExpectVisibleErrorResponse(t),
  6364  			"Failed to launch: The 'traceDirPath' attribute is missing in debug configuration.")
  6365  		client.LaunchRequestWithArgs(map[string]interface{}{"mode": "replay", "program": fixture.Source, "traceDirPath": ""})
  6366  		checkFailedToLaunchWithMessage(client.ExpectVisibleErrorResponse(t),
  6367  			"Failed to launch: The 'traceDirPath' attribute is missing in debug configuration.")
  6368  		// These errors come from debugger layer
  6369  		if _, err := exec.LookPath("rr"); err != nil {
  6370  			client.LaunchRequestWithArgs(map[string]interface{}{"mode": "replay", "backend": "ignored", "traceDirPath": ".."})
  6371  			checkFailedToLaunchWithMessage(client.ExpectVisibleErrorResponse(t),
  6372  				"Failed to launch: backend unavailable")
  6373  		}
  6374  
  6375  		// Bad "core" parameters
  6376  		// These errors come from dap layer
  6377  		client.LaunchRequestWithArgs(map[string]interface{}{"mode": "core", "coreFilePath": ""})
  6378  		checkFailedToLaunchWithMessage(client.ExpectVisibleErrorResponse(t),
  6379  			"Failed to launch: The program attribute is missing in debug configuration.")
  6380  		client.LaunchRequestWithArgs(map[string]interface{}{"mode": "core", "program": fixture.Source, "coreFilePath": ""})
  6381  		checkFailedToLaunchWithMessage(client.ExpectVisibleErrorResponse(t),
  6382  			"Failed to launch: The 'coreFilePath' attribute is missing in debug configuration.")
  6383  		// These errors come from debugger layer
  6384  		client.LaunchRequestWithArgs(map[string]interface{}{"mode": "core", "backend": "ignored", "program": fixture.Source, "coreFilePath": fixture.Source})
  6385  		checkFailedToLaunchWithMessage(client.ExpectVisibleErrorResponse(t),
  6386  			"Failed to launch: unrecognized core format")
  6387  
  6388  		// We failed to launch the program. Make sure shutdown still works.
  6389  		client.DisconnectRequest()
  6390  		dresp := client.ExpectDisconnectResponse(t)
  6391  		if dresp.RequestSeq != seqCnt {
  6392  			t.Errorf("got %#v, want RequestSeq=%d", dresp, seqCnt)
  6393  		}
  6394  	})
  6395  }
  6396  
  6397  func TestBadAttachRequest(t *testing.T) {
  6398  	runTest(t, "loopprog", func(client *daptest.Client, fixture protest.Fixture) {
  6399  		seqCnt := 1
  6400  		checkFailedToAttach := func(response *dap.ErrorResponse) {
  6401  			t.Helper()
  6402  			if response.RequestSeq != seqCnt {
  6403  				t.Errorf("RequestSeq got %d, want %d", seqCnt, response.RequestSeq)
  6404  			}
  6405  			if response.Command != "attach" {
  6406  				t.Errorf("Command got %q, want \"attach\"", response.Command)
  6407  			}
  6408  			if response.Message != "Failed to attach" {
  6409  				t.Errorf("Message got %q, want \"Failed to attach\"", response.Message)
  6410  			}
  6411  			if response.Body.Error.Id != FailedToAttach {
  6412  				t.Errorf("Id got %d, want %d", response.Body.Error.Id, FailedToAttach)
  6413  			}
  6414  			seqCnt++
  6415  		}
  6416  
  6417  		checkFailedToAttachWithMessage := func(response *dap.ErrorResponse, errmsg string) {
  6418  			t.Helper()
  6419  			checkFailedToAttach(response)
  6420  			if response.Body.Error.Format != errmsg {
  6421  				t.Errorf("\ngot  %q\nwant %q", response.Body.Error.Format, errmsg)
  6422  			}
  6423  		}
  6424  
  6425  		// Bad "mode"
  6426  		client.AttachRequest(map[string]interface{}{"mode": "blah blah blah"})
  6427  		checkFailedToAttachWithMessage(client.ExpectVisibleErrorResponse(t),
  6428  			"Failed to attach: invalid debug configuration - unsupported 'mode' attribute \"blah blah blah\"")
  6429  
  6430  		client.AttachRequest(map[string]interface{}{"mode": 123})
  6431  		checkFailedToAttachWithMessage(client.ExpectVisibleErrorResponse(t),
  6432  			"Failed to attach: invalid debug configuration - cannot unmarshal number into \"mode\" of type string")
  6433  
  6434  		client.AttachRequest(map[string]interface{}{"mode": ""}) // empty mode defaults to "local" (not an error)
  6435  		checkFailedToAttachWithMessage(client.ExpectVisibleErrorResponse(t),
  6436  			"Failed to attach: The 'processId' attribute is missing in debug configuration")
  6437  
  6438  		client.AttachRequest(map[string]interface{}{}) // no mode defaults to "local" (not an error)
  6439  		checkFailedToAttachWithMessage(client.ExpectVisibleErrorResponse(t),
  6440  			"Failed to attach: The 'processId' attribute is missing in debug configuration")
  6441  
  6442  		// Bad "processId"
  6443  		client.AttachRequest(map[string]interface{}{"mode": "local"})
  6444  		checkFailedToAttachWithMessage(client.ExpectVisibleErrorResponse(t),
  6445  			"Failed to attach: The 'processId' attribute is missing in debug configuration")
  6446  
  6447  		client.AttachRequest(map[string]interface{}{"mode": "local", "processId": nil})
  6448  		checkFailedToAttachWithMessage(client.ExpectVisibleErrorResponse(t),
  6449  			"Failed to attach: The 'processId' attribute is missing in debug configuration")
  6450  
  6451  		client.AttachRequest(map[string]interface{}{"mode": "local", "processId": 0})
  6452  		checkFailedToAttachWithMessage(client.ExpectVisibleErrorResponse(t),
  6453  			"Failed to attach: The 'processId' attribute is missing in debug configuration")
  6454  
  6455  		client.AttachRequest(map[string]interface{}{"mode": "local", "processId": "1"})
  6456  		checkFailedToAttachWithMessage(client.ExpectVisibleErrorResponse(t),
  6457  			"Failed to attach: invalid debug configuration - cannot unmarshal string into \"processId\" of type int")
  6458  
  6459  		client.AttachRequest(map[string]interface{}{"mode": "local", "processId": 1})
  6460  		// The exact message varies on different systems, so skip that check
  6461  		checkFailedToAttach(client.ExpectVisibleErrorResponse(t)) // could not attach to pid 1
  6462  
  6463  		// This will make debugger.(*Debugger) panic, which we will catch as an internal error.
  6464  		client.AttachRequest(map[string]interface{}{"mode": "local", "processId": -1})
  6465  		er := client.ExpectInvisibleErrorResponse(t)
  6466  		if er.RequestSeq != seqCnt {
  6467  			t.Errorf("RequestSeq got %d, want %d", seqCnt, er.RequestSeq)
  6468  		}
  6469  		seqCnt++
  6470  		if er.Command != "" {
  6471  			t.Errorf("Command got %q, want \"attach\"", er.Command)
  6472  		}
  6473  		if er.Body.Error.Format != "Internal Error: runtime error: index out of range [0] with length 0" {
  6474  			t.Errorf("Message got %q, want \"Internal Error: runtime error: index out of range [0] with length 0\"", er.Message)
  6475  		}
  6476  		if er.Body.Error.Id != InternalError {
  6477  			t.Errorf("Id got %d, want %d", er.Body.Error.Id, InternalError)
  6478  		}
  6479  
  6480  		// Bad "backend"
  6481  		client.AttachRequest(map[string]interface{}{"mode": "local", "processId": 1, "backend": 123})
  6482  		checkFailedToAttachWithMessage(client.ExpectVisibleErrorResponse(t),
  6483  			"Failed to attach: invalid debug configuration - cannot unmarshal number into \"backend\" of type string")
  6484  
  6485  		client.AttachRequest(map[string]interface{}{"mode": "local", "processId": 1, "backend": "foo"})
  6486  		checkFailedToAttachWithMessage(client.ExpectVisibleErrorResponse(t),
  6487  			"Failed to attach: could not attach to pid 1: unknown backend \"foo\"")
  6488  
  6489  		// We failed to attach to the program. Make sure shutdown still works.
  6490  		client.DisconnectRequest()
  6491  		dresp := client.ExpectDisconnectResponse(t)
  6492  		if dresp.RequestSeq != seqCnt {
  6493  			t.Errorf("got %#v, want RequestSeq=%d", dresp, seqCnt)
  6494  		}
  6495  	})
  6496  }
  6497  
  6498  func launchDebuggerWithTargetRunning(t *testing.T, fixture string) (*protest.Fixture, *debugger.Debugger) {
  6499  	t.Helper()
  6500  	fixbin, dbg := launchDebuggerWithTargetHalted(t, fixture)
  6501  	running := make(chan struct{})
  6502  	var err error
  6503  	go func() {
  6504  		t.Helper()
  6505  		_, err = dbg.Command(&api.DebuggerCommand{Name: api.Continue}, running)
  6506  		select {
  6507  		case <-running:
  6508  		default:
  6509  			close(running)
  6510  		}
  6511  	}()
  6512  	<-running
  6513  	if err != nil {
  6514  		t.Fatal("failed to continue on launch", err)
  6515  	}
  6516  	return fixbin, dbg
  6517  }
  6518  
  6519  func launchDebuggerWithTargetHalted(t *testing.T, fixture string) (*protest.Fixture, *debugger.Debugger) {
  6520  	t.Helper()
  6521  	fixbin := protest.BuildFixture(fixture, protest.AllNonOptimized)
  6522  	cfg := service.Config{
  6523  		ProcessArgs: []string{fixbin.Path},
  6524  		Debugger:    debugger.Config{Backend: "default"},
  6525  	}
  6526  	dbg, err := debugger.New(&cfg.Debugger, cfg.ProcessArgs) // debugger halts process on entry
  6527  	if err != nil {
  6528  		t.Fatal("failed to start debugger:", err)
  6529  	}
  6530  	return &fixbin, dbg
  6531  }
  6532  
  6533  func attachDebuggerWithTargetHalted(t *testing.T, fixture string) (*exec.Cmd, *debugger.Debugger) {
  6534  	t.Helper()
  6535  	fixbin := protest.BuildFixture(fixture, protest.AllNonOptimized)
  6536  	cmd := execFixture(t, fixbin)
  6537  	cfg := service.Config{Debugger: debugger.Config{Backend: "default", AttachPid: cmd.Process.Pid}}
  6538  	dbg, err := debugger.New(&cfg.Debugger, nil) // debugger halts process on entry
  6539  	if err != nil {
  6540  		t.Fatal("failed to start debugger:", err)
  6541  	}
  6542  	return cmd, dbg
  6543  }
  6544  
  6545  // runTestWithDebugger starts the server and sets its debugger, initializes a debug session,
  6546  // runs test, then disconnects. Expects no running async handler at the end of test() (either
  6547  // process is halted or debug session never launched.)
  6548  func runTestWithDebugger(t *testing.T, dbg *debugger.Debugger, test func(c *daptest.Client)) {
  6549  	serverStopped := make(chan struct{})
  6550  	server, _ := startDAPServer(t, serverStopped)
  6551  	client := daptest.NewClient(server.listener.Addr().String())
  6552  	time.Sleep(100 * time.Millisecond) // Give time for connection to be set as dap.Session
  6553  	server.sessionMu.Lock()
  6554  	if server.session == nil {
  6555  		t.Fatal("DAP session is not ready")
  6556  	}
  6557  	// Mock dap.NewSession arguments, so
  6558  	// this dap.Server can be used as a proxy for
  6559  	// rpccommon.Server running dap.Session.
  6560  	server.session.config.Debugger.AttachPid = dbg.AttachPid()
  6561  	server.session.debugger = dbg
  6562  	server.sessionMu.Unlock()
  6563  	defer client.Close()
  6564  	client.InitializeRequest()
  6565  	client.ExpectInitializeResponseAndCapabilities(t)
  6566  
  6567  	test(client)
  6568  
  6569  	client.DisconnectRequest()
  6570  	if dbg.AttachPid() == 0 { // launched target
  6571  		client.ExpectOutputEventDetachingKill(t)
  6572  	} else { // attached to target
  6573  		client.ExpectOutputEventDetachingNoKill(t)
  6574  	}
  6575  	client.ExpectDisconnectResponse(t)
  6576  	client.ExpectTerminatedEvent(t)
  6577  
  6578  	<-serverStopped
  6579  }
  6580  
  6581  func TestAttachRemoteToDlvLaunchHaltedStopOnEntry(t *testing.T) {
  6582  	// Halted + stop on entry
  6583  	_, dbg := launchDebuggerWithTargetHalted(t, "increment")
  6584  	runTestWithDebugger(t, dbg, func(client *daptest.Client) {
  6585  		client.AttachRequest(map[string]interface{}{"mode": "remote", "stopOnEntry": true})
  6586  		client.ExpectInitializedEvent(t)
  6587  		client.ExpectAttachResponse(t)
  6588  		client.ConfigurationDoneRequest()
  6589  		client.ExpectStoppedEvent(t)
  6590  		client.ExpectConfigurationDoneResponse(t)
  6591  	})
  6592  }
  6593  
  6594  func TestAttachRemoteToDlvAttachHaltedStopOnEntry(t *testing.T) {
  6595  	if runtime.GOOS == "freebsd" || runtime.GOOS == "windows" {
  6596  		t.SkipNow()
  6597  	}
  6598  	cmd, dbg := attachDebuggerWithTargetHalted(t, "http_server")
  6599  	runTestWithDebugger(t, dbg, func(client *daptest.Client) {
  6600  		client.AttachRequest(map[string]interface{}{"mode": "remote", "stopOnEntry": true})
  6601  		client.ExpectCapabilitiesEventSupportTerminateDebuggee(t)
  6602  		client.ExpectInitializedEvent(t)
  6603  		client.ExpectAttachResponse(t)
  6604  		client.ConfigurationDoneRequest()
  6605  		client.ExpectStoppedEvent(t)
  6606  		client.ExpectConfigurationDoneResponse(t)
  6607  	})
  6608  	cmd.Process.Kill()
  6609  }
  6610  
  6611  func TestAttachRemoteToHaltedTargetContinueOnEntry(t *testing.T) {
  6612  	// Halted + continue on entry
  6613  	_, dbg := launchDebuggerWithTargetHalted(t, "http_server")
  6614  	runTestWithDebugger(t, dbg, func(client *daptest.Client) {
  6615  		client.AttachRequest(map[string]interface{}{"mode": "remote", "stopOnEntry": false})
  6616  		client.ExpectInitializedEvent(t)
  6617  		client.ExpectAttachResponse(t)
  6618  		client.ConfigurationDoneRequest()
  6619  		client.ExpectConfigurationDoneResponse(t)
  6620  		// Continuing
  6621  		time.Sleep(time.Second)
  6622  		// Halt to make the disconnect sequence more predictable.
  6623  		client.PauseRequest(1)
  6624  		expectPauseResponseAndStoppedEvent(t, client)
  6625  	})
  6626  }
  6627  
  6628  func TestAttachRemoteToRunningTargetStopOnEntry(t *testing.T) {
  6629  	fixture, dbg := launchDebuggerWithTargetRunning(t, "loopprog")
  6630  	runTestWithDebugger(t, dbg, func(client *daptest.Client) {
  6631  		client.AttachRequest(map[string]interface{}{"mode": "remote", "stopOnEntry": true})
  6632  		client.ExpectInitializedEvent(t)
  6633  		client.ExpectAttachResponse(t)
  6634  		// Target is halted here
  6635  		client.SetBreakpointsRequest(fixture.Source, []int{8})
  6636  		expectSetBreakpointsResponse(t, client, []Breakpoint{{8, fixture.Source, true, ""}})
  6637  		client.ConfigurationDoneRequest()
  6638  		client.ExpectStoppedEvent(t)
  6639  		client.ExpectConfigurationDoneResponse(t)
  6640  		client.ContinueRequest(1)
  6641  		client.ExpectContinueResponse(t)
  6642  		client.ExpectStoppedEvent(t)
  6643  		checkStop(t, client, 1, "main.loop", 8)
  6644  	})
  6645  }
  6646  
  6647  func TestAttachRemoteToRunningTargetContinueOnEntry(t *testing.T) {
  6648  	fixture, dbg := launchDebuggerWithTargetRunning(t, "loopprog")
  6649  	runTestWithDebugger(t, dbg, func(client *daptest.Client) {
  6650  		client.AttachRequest(map[string]interface{}{"mode": "remote", "stopOnEntry": false})
  6651  		client.ExpectInitializedEvent(t)
  6652  		client.ExpectAttachResponse(t)
  6653  		// Target is halted here
  6654  		client.SetBreakpointsRequest(fixture.Source, []int{8})
  6655  		expectSetBreakpointsResponse(t, client, []Breakpoint{{8, fixture.Source, true, ""}})
  6656  		client.ConfigurationDoneRequest()
  6657  		// Target is restarted here
  6658  		client.ExpectConfigurationDoneResponse(t)
  6659  		client.ExpectStoppedEvent(t)
  6660  		checkStop(t, client, 1, "main.loop", 8)
  6661  	})
  6662  }
  6663  
  6664  // MultiClientCloseServerMock mocks the rpccommon.Server using a dap.Server to exercise
  6665  // the shutdown logic in dap.Session where it does NOT take down the server on close
  6666  // in multi-client mode. (The dap mode of the rpccommon.Server is tested in dlv_test).
  6667  // The dap.Server is a single-use server. Once its one and only session is closed,
  6668  // the server and the target must be taken down manually for the test not to leak.
  6669  type MultiClientCloseServerMock struct {
  6670  	impl      *Server
  6671  	debugger  *debugger.Debugger
  6672  	forceStop chan struct{}
  6673  	stopped   chan struct{}
  6674  }
  6675  
  6676  func NewMultiClientCloseServerMock(t *testing.T, fixture string) *MultiClientCloseServerMock {
  6677  	var s MultiClientCloseServerMock
  6678  	s.stopped = make(chan struct{})
  6679  	s.impl, s.forceStop = startDAPServer(t, s.stopped)
  6680  	_, s.debugger = launchDebuggerWithTargetHalted(t, "http_server")
  6681  	return &s
  6682  }
  6683  
  6684  func (s *MultiClientCloseServerMock) acceptNewClient(t *testing.T) *daptest.Client {
  6685  	client := daptest.NewClient(s.impl.listener.Addr().String())
  6686  	time.Sleep(100 * time.Millisecond) // Give time for connection to be set as dap.Session
  6687  	s.impl.sessionMu.Lock()
  6688  	if s.impl.session == nil {
  6689  		t.Fatal("dap session is not ready")
  6690  	}
  6691  	// A dap.Server doesn't support accept-multiclient, but we can use this
  6692  	// hack to test the inner connection logic that is used by a server that does.
  6693  	s.impl.session.config.AcceptMulti = true
  6694  	s.impl.session.debugger = s.debugger
  6695  	s.impl.sessionMu.Unlock()
  6696  	return client
  6697  }
  6698  
  6699  func (s *MultiClientCloseServerMock) stop(t *testing.T) {
  6700  	close(s.forceStop)
  6701  	// If the server doesn't have an active session,
  6702  	// closing it would leak the debbuger with the target because
  6703  	// they are part of dap.Session.
  6704  	// We must take it down manually as if we are in rpccommon::ServerImpl::Stop.
  6705  	if s.debugger.IsRunning() {
  6706  		s.debugger.Command(&api.DebuggerCommand{Name: api.Halt}, nil)
  6707  	}
  6708  	s.debugger.Detach(true)
  6709  }
  6710  
  6711  func (s *MultiClientCloseServerMock) verifyStopped(t *testing.T) {
  6712  	if state, err := s.debugger.State(true /*nowait*/); err != proc.ErrProcessDetached && !processExited(state, err) {
  6713  		t.Errorf("target leak")
  6714  	}
  6715  	verifyServerStopped(t, s.impl)
  6716  }
  6717  
  6718  // TestAttachRemoteMultiClientDisconnect tests that that remote attach doesn't take down
  6719  // the server in multi-client mode unless terminateDebuggee is explicitely set.
  6720  func TestAttachRemoteMultiClientDisconnect(t *testing.T) {
  6721  	closingClientSessionOnly := fmt.Sprintf(daptest.ClosingClient, "halted")
  6722  	detachingAndTerminating := "Detaching and terminating target process"
  6723  	tests := []struct {
  6724  		name              string
  6725  		disconnectRequest func(client *daptest.Client)
  6726  		expect            string
  6727  	}{
  6728  		{"default", func(c *daptest.Client) { c.DisconnectRequest() }, closingClientSessionOnly},
  6729  		{"terminate=true", func(c *daptest.Client) { c.DisconnectRequestWithKillOption(true) }, detachingAndTerminating},
  6730  		{"terminate=false", func(c *daptest.Client) { c.DisconnectRequestWithKillOption(false) }, closingClientSessionOnly},
  6731  	}
  6732  	for _, tc := range tests {
  6733  		t.Run(tc.name, func(t *testing.T) {
  6734  			server := NewMultiClientCloseServerMock(t, "increment")
  6735  			client := server.acceptNewClient(t)
  6736  			defer client.Close()
  6737  
  6738  			client.InitializeRequest()
  6739  			client.ExpectInitializeResponseAndCapabilities(t)
  6740  
  6741  			client.AttachRequest(map[string]interface{}{"mode": "remote", "stopOnEntry": true})
  6742  			client.ExpectCapabilitiesEventSupportTerminateDebuggee(t)
  6743  			client.ExpectInitializedEvent(t)
  6744  			client.ExpectAttachResponse(t)
  6745  			client.ConfigurationDoneRequest()
  6746  			client.ExpectStoppedEvent(t)
  6747  			client.ExpectConfigurationDoneResponse(t)
  6748  
  6749  			tc.disconnectRequest(client)
  6750  			e := client.ExpectOutputEvent(t)
  6751  			if matched, _ := regexp.MatchString(tc.expect, e.Body.Output); !matched {
  6752  				t.Errorf("\ngot %#v\nwant Output=%q", e, tc.expect)
  6753  			}
  6754  			client.ExpectDisconnectResponse(t)
  6755  			client.ExpectTerminatedEvent(t)
  6756  			time.Sleep(10 * time.Millisecond) // give time for things to shut down
  6757  
  6758  			if tc.expect == closingClientSessionOnly {
  6759  				// At this point a multi-client server is still running. but session should be done.
  6760  				verifySessionStopped(t, server.impl.session)
  6761  				// Verify target's running state.
  6762  				if server.debugger.IsRunning() {
  6763  					t.Errorf("\ngot running=true, want false")
  6764  				}
  6765  				server.stop(t)
  6766  			}
  6767  			<-server.stopped
  6768  			server.verifyStopped(t)
  6769  		})
  6770  	}
  6771  }
  6772  
  6773  func TestLaunchAttachErrorWhenDebugInProgress(t *testing.T) {
  6774  	tests := []struct {
  6775  		name string
  6776  		dbg  func() *debugger.Debugger
  6777  	}{
  6778  		{"halted", func() *debugger.Debugger { _, dbg := launchDebuggerWithTargetHalted(t, "increment"); return dbg }},
  6779  		{"running", func() *debugger.Debugger { _, dbg := launchDebuggerWithTargetRunning(t, "loopprog"); return dbg }},
  6780  	}
  6781  	for _, tc := range tests {
  6782  		t.Run(tc.name, func(t *testing.T) {
  6783  			runTestWithDebugger(t, tc.dbg(), func(client *daptest.Client) {
  6784  				client.EvaluateRequest("1==1", 0 /*no frame specified*/, "repl")
  6785  				if tc.name == "running" {
  6786  					client.ExpectInvisibleErrorResponse(t)
  6787  				} else {
  6788  					client.ExpectEvaluateResponse(t)
  6789  				}
  6790  
  6791  				// Both launch and attach requests should go through for additional error checking
  6792  				client.AttachRequest(map[string]interface{}{"mode": "local", "processId": 100})
  6793  				er := client.ExpectVisibleErrorResponse(t)
  6794  				msgRe, _ := regexp.Compile("Failed to attach: debug session already in progress at [0-9]+:[0-9]+ - use remote mode to connect to a server with an active debug session")
  6795  				if er.Body.Error.Id != FailedToAttach || msgRe.MatchString(er.Body.Error.Format) {
  6796  					t.Errorf("got %#v, want Id=%d Format=%q", er, FailedToAttach, msgRe)
  6797  				}
  6798  				tests := []string{"debug", "test", "exec", "replay", "core"}
  6799  				for _, mode := range tests {
  6800  					t.Run(mode, func(t *testing.T) {
  6801  						client.LaunchRequestWithArgs(map[string]interface{}{"mode": mode})
  6802  						er := client.ExpectVisibleErrorResponse(t)
  6803  						msgRe, _ := regexp.Compile("Failed to launch: debug session already in progress at [0-9]+:[0-9]+ - use remote attach mode to connect to a server with an active debug session")
  6804  						if er.Body.Error.Id != FailedToLaunch || msgRe.MatchString(er.Body.Error.Format) {
  6805  							t.Errorf("got %#v, want Id=%d Format=%q", er, FailedToLaunch, msgRe)
  6806  						}
  6807  					})
  6808  				}
  6809  			})
  6810  		})
  6811  	}
  6812  }
  6813  
  6814  func TestBadInitializeRequest(t *testing.T) {
  6815  	runInitializeTest := func(args dap.InitializeRequestArguments, err string) {
  6816  		t.Helper()
  6817  		// Only one initialize request is allowed, so use a new server
  6818  		// for each test.
  6819  		serverStopped := make(chan struct{})
  6820  		client := startDAPServerWithClient(t, serverStopped)
  6821  		defer client.Close()
  6822  
  6823  		client.InitializeRequestWithArgs(args)
  6824  		response := client.ExpectErrorResponse(t)
  6825  		if response.Command != "initialize" {
  6826  			t.Errorf("Command got %q, want \"launch\"", response.Command)
  6827  		}
  6828  		if response.Message != "Failed to initialize" {
  6829  			t.Errorf("Message got %q, want \"Failed to launch\"", response.Message)
  6830  		}
  6831  		if response.Body.Error.Id != FailedToInitialize {
  6832  			t.Errorf("Id got %d, want %d", response.Body.Error.Id, FailedToInitialize)
  6833  		}
  6834  		if response.Body.Error.Format != err {
  6835  			t.Errorf("\ngot  %q\nwant %q", response.Body.Error.Format, err)
  6836  		}
  6837  
  6838  		client.DisconnectRequest()
  6839  		client.ExpectDisconnectResponse(t)
  6840  		<-serverStopped
  6841  	}
  6842  
  6843  	// Bad path format.
  6844  	runInitializeTest(dap.InitializeRequestArguments{
  6845  		AdapterID:       "go",
  6846  		PathFormat:      "url", // unsupported 'pathFormat'
  6847  		LinesStartAt1:   true,
  6848  		ColumnsStartAt1: true,
  6849  		Locale:          "en-us",
  6850  	},
  6851  		"Failed to initialize: Unsupported 'pathFormat' value 'url'.",
  6852  	)
  6853  
  6854  	// LinesStartAt1 must be true.
  6855  	runInitializeTest(dap.InitializeRequestArguments{
  6856  		AdapterID:       "go",
  6857  		PathFormat:      "path",
  6858  		LinesStartAt1:   false, // only 1-based line numbers are supported
  6859  		ColumnsStartAt1: true,
  6860  		Locale:          "en-us",
  6861  	},
  6862  		"Failed to initialize: Only 1-based line numbers are supported.",
  6863  	)
  6864  
  6865  	// ColumnsStartAt1 must be true.
  6866  	runInitializeTest(dap.InitializeRequestArguments{
  6867  		AdapterID:       "go",
  6868  		PathFormat:      "path",
  6869  		LinesStartAt1:   true,
  6870  		ColumnsStartAt1: false, // only 1-based column numbers are supported
  6871  		Locale:          "en-us",
  6872  	},
  6873  		"Failed to initialize: Only 1-based column numbers are supported.",
  6874  	)
  6875  }
  6876  
  6877  func TestBadlyFormattedMessageToServer(t *testing.T) {
  6878  	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) {
  6879  		// Send a badly formatted message to the server, and expect it to close the
  6880  		// connection.
  6881  		client.BadRequest()
  6882  		time.Sleep(100 * time.Millisecond)
  6883  
  6884  		_, err := client.ReadMessage()
  6885  
  6886  		if err != io.EOF {
  6887  			t.Errorf("got err=%v, want io.EOF", err)
  6888  		}
  6889  	})
  6890  	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) {
  6891  		// Send an unknown request message to the server, and expect it to send
  6892  		// an error response.
  6893  		client.UnknownRequest()
  6894  		err := client.ExpectErrorResponse(t)
  6895  		if err.Body.Error.Format != "Internal Error: Request command 'unknown' is not supported (seq: 1)" || err.RequestSeq != 1 {
  6896  			t.Errorf("got %v, want  RequestSeq=1 Error=\"Internal Error: Request command 'unknown' is not supported (seq: 1)\"", err)
  6897  		}
  6898  
  6899  		// Make sure that the unknown request did not kill the server.
  6900  		client.InitializeRequest()
  6901  		client.ExpectInitializeResponse(t)
  6902  
  6903  		client.DisconnectRequest()
  6904  		client.ExpectDisconnectResponse(t)
  6905  	})
  6906  }
  6907  
  6908  func TestParseLogPoint(t *testing.T) {
  6909  	tests := []struct {
  6910  		name           string
  6911  		msg            string
  6912  		wantTracepoint bool
  6913  		wantFormat     string
  6914  		wantArgs       []string
  6915  		wantErr        bool
  6916  	}{
  6917  		// Test simple log messages.
  6918  		{name: "simple string", msg: "hello, world!", wantTracepoint: true, wantFormat: "hello, world!"},
  6919  		{name: "empty string", msg: "", wantTracepoint: false, wantErr: false},
  6920  		// Test parse eval expressions.
  6921  		{
  6922  			name:           "simple eval",
  6923  			msg:            "{x}",
  6924  			wantTracepoint: true,
  6925  			wantFormat:     "%s",
  6926  			wantArgs:       []string{"x"},
  6927  		},
  6928  		{
  6929  			name:           "type cast",
  6930  			msg:            "hello {string(x)}",
  6931  			wantTracepoint: true,
  6932  			wantFormat:     "hello %s",
  6933  			wantArgs:       []string{"string(x)"},
  6934  		},
  6935  		{
  6936  			name:           "multiple eval",
  6937  			msg:            "{x} {y} {z}",
  6938  			wantTracepoint: true,
  6939  			wantFormat:     "%s %s %s",
  6940  			wantArgs:       []string{"x", "y", "z"},
  6941  		},
  6942  		{
  6943  			name:           "eval expressions contain braces",
  6944  			msg:            "{interface{}(x)} {myType{y}} {[]myType{{z}}}",
  6945  			wantTracepoint: true,
  6946  			wantFormat:     "%s %s %s",
  6947  			wantArgs:       []string{"interface{}(x)", "myType{y}", "[]myType{{z}}"},
  6948  		},
  6949  		// Test parse errors.
  6950  		{name: "empty evaluation", msg: "{}", wantErr: true},
  6951  		{name: "empty space evaluation", msg: "{   \n}", wantErr: true},
  6952  		{name: "open brace missing closed", msg: "{", wantErr: true},
  6953  		{name: "closed brace missing open", msg: "}", wantErr: true},
  6954  		{name: "open brace in expression", msg: `{m["{"]}`, wantErr: true},
  6955  		{name: "closed brace in expression", msg: `{m["}"]}`, wantErr: true},
  6956  	}
  6957  	for _, tt := range tests {
  6958  		t.Run(tt.name, func(t *testing.T) {
  6959  			gotTracepoint, gotLogMessage, err := parseLogPoint(tt.msg)
  6960  			if gotTracepoint != tt.wantTracepoint {
  6961  				t.Errorf("parseLogPoint() tracepoint = %v, wantTracepoint %v", gotTracepoint, tt.wantTracepoint)
  6962  				return
  6963  			}
  6964  			if (err != nil) != tt.wantErr {
  6965  				t.Errorf("parseLogPoint() error = %v, wantErr %v", err, tt.wantErr)
  6966  				return
  6967  			}
  6968  			if !tt.wantTracepoint {
  6969  				return
  6970  			}
  6971  			if gotLogMessage == nil {
  6972  				t.Errorf("parseLogPoint() gotLogMessage = nil, want log message")
  6973  				return
  6974  			}
  6975  			if gotLogMessage.format != tt.wantFormat {
  6976  				t.Errorf("parseLogPoint() gotFormat = %v, want %v", gotLogMessage.format, tt.wantFormat)
  6977  			}
  6978  			if !reflect.DeepEqual(gotLogMessage.args, tt.wantArgs) {
  6979  				t.Errorf("parseLogPoint() gotArgs = %v, want %v", gotLogMessage.args, tt.wantArgs)
  6980  			}
  6981  		})
  6982  	}
  6983  }
  6984  
  6985  func TestDisassemble(t *testing.T) {
  6986  	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) {
  6987  		runDebugSessionWithBPs(t, client, "launch",
  6988  			// Launch
  6989  			func() {
  6990  				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
  6991  			},
  6992  			// Set breakpoints
  6993  			fixture.Source, []int{17},
  6994  			[]onBreakpoint{{
  6995  				// Stop at line 17
  6996  				execute: func() {
  6997  					checkStop(t, client, 1, "main.main", 17)
  6998  
  6999  					client.StackTraceRequest(1, 0, 1)
  7000  					st := client.ExpectStackTraceResponse(t)
  7001  					if len(st.Body.StackFrames) < 1 {
  7002  						t.Fatalf("\ngot  %#v\nwant len(stackframes) => 1", st)
  7003  					}
  7004  					// Request the single instruction that the program is stopped at.
  7005  					pc := st.Body.StackFrames[0].InstructionPointerReference
  7006  					client.DisassembleRequest(pc, 0, 1)
  7007  					dr := client.ExpectDisassembleResponse(t)
  7008  					if len(dr.Body.Instructions) != 1 {
  7009  						t.Errorf("\ngot %#v\nwant len(instructions) = 1", dr)
  7010  					} else if dr.Body.Instructions[0].Address != pc {
  7011  						t.Errorf("\ngot %#v\nwant instructions[0].Address = %s", dr, pc)
  7012  					}
  7013  
  7014  					// Request the instruction that the program is stopped at, and the two
  7015  					// surrounding it.
  7016  					client.DisassembleRequest(pc, -1, 3)
  7017  					dr = client.ExpectDisassembleResponse(t)
  7018  					if len(dr.Body.Instructions) != 3 {
  7019  						t.Errorf("\ngot %#v\nwant len(instructions) = 3", dr)
  7020  					} else if dr.Body.Instructions[1].Address != pc {
  7021  						t.Errorf("\ngot %#v\nwant instructions[1].Address = %s", dr, pc)
  7022  					}
  7023  
  7024  					// Request zero instrutions.
  7025  					client.DisassembleRequest(pc, 0, 0)
  7026  					dr = client.ExpectDisassembleResponse(t)
  7027  					if len(dr.Body.Instructions) != 0 {
  7028  						t.Errorf("\ngot %#v\nwant len(instructions) = 0", dr)
  7029  					}
  7030  
  7031  					// Request invalid instructions.
  7032  					var checkInvalidInstruction = func(instructions []dap.DisassembledInstruction, count int, address uint64) {
  7033  						if len(instructions) != count {
  7034  							t.Errorf("\ngot %#v\nwant len(instructions) = %d", dr, count)
  7035  						}
  7036  						for i, got := range instructions {
  7037  							if got.Instruction != invalidInstruction.Instruction {
  7038  								t.Errorf("\ngot [%d].Instruction=%q\nwant = %#v", i, got.Instruction, invalidInstruction.Address)
  7039  							}
  7040  							addr, err := strconv.ParseUint(got.Address, 0, 64)
  7041  							if err != nil {
  7042  								t.Error(err)
  7043  								continue
  7044  							}
  7045  							if addr != address {
  7046  								t.Errorf("\ngot [%d].Address=%s\nwant = %#x", i, got.Address, address)
  7047  							}
  7048  						}
  7049  					}
  7050  					client.DisassembleRequest("0x0", 0, 10)
  7051  					checkInvalidInstruction(client.ExpectDisassembleResponse(t).Body.Instructions, 10, 0)
  7052  
  7053  					client.DisassembleRequest(fmt.Sprintf("%#x", uint64(math.MaxUint64)), 0, 10)
  7054  					checkInvalidInstruction(client.ExpectDisassembleResponse(t).Body.Instructions, 10, uint64(math.MaxUint64))
  7055  
  7056  					// Bad request, not a number.
  7057  					client.DisassembleRequest("hello, world!", 0, 1)
  7058  					client.ExpectErrorResponse(t)
  7059  
  7060  					// Bad request, not an address in program.
  7061  					client.DisassembleRequest("0x5", 0, 100)
  7062  					client.ExpectErrorResponse(t)
  7063  				},
  7064  				disconnect: true,
  7065  			}},
  7066  		)
  7067  	})
  7068  }
  7069  
  7070  func TestAlignPCs(t *testing.T) {
  7071  	NUM_FUNCS := 10
  7072  	// Create fake functions to test align PCs.
  7073  	funcs := make([]proc.Function, NUM_FUNCS)
  7074  	for i := 0; i < len(funcs); i++ {
  7075  		funcs[i] = proc.Function{
  7076  			Entry: uint64(100 + i*10),
  7077  			End:   uint64(100 + i*10 + 5),
  7078  		}
  7079  	}
  7080  	bi := &proc.BinaryInfo{
  7081  		Functions: funcs,
  7082  	}
  7083  	type args struct {
  7084  		start uint64
  7085  		end   uint64
  7086  	}
  7087  	tests := []struct {
  7088  		name      string
  7089  		args      args
  7090  		wantStart uint64
  7091  		wantEnd   uint64
  7092  	}{
  7093  		{
  7094  			name: "out of bounds",
  7095  			args: args{
  7096  				start: funcs[0].Entry - 5,
  7097  				end:   funcs[NUM_FUNCS-1].End + 5,
  7098  			},
  7099  			wantStart: funcs[0].Entry,         // start of first function
  7100  			wantEnd:   funcs[NUM_FUNCS-1].End, // end of last function
  7101  		},
  7102  		{
  7103  			name: "same function",
  7104  			args: args{
  7105  				start: funcs[1].Entry + 1,
  7106  				end:   funcs[1].Entry + 2,
  7107  			},
  7108  			wantStart: funcs[1].Entry, // start of containing function
  7109  			wantEnd:   funcs[1].End,   // end of containing function
  7110  		},
  7111  		{
  7112  			name: "between functions",
  7113  			args: args{
  7114  				start: funcs[1].End + 1,
  7115  				end:   funcs[1].End + 2,
  7116  			},
  7117  			wantStart: funcs[1].Entry, // start of function before
  7118  			wantEnd:   funcs[2].Entry, // start of function after
  7119  		},
  7120  		{
  7121  			name: "start of function",
  7122  			args: args{
  7123  				start: funcs[2].Entry,
  7124  				end:   funcs[5].Entry,
  7125  			},
  7126  			wantStart: funcs[2].Entry, // start of current function
  7127  			wantEnd:   funcs[5].End,   // end of current function
  7128  		},
  7129  		{
  7130  			name: "end of function",
  7131  			args: args{
  7132  				start: funcs[4].End,
  7133  				end:   funcs[8].End,
  7134  			},
  7135  			wantStart: funcs[4].Entry, // start of current function
  7136  			wantEnd:   funcs[9].Entry, // start of next function
  7137  		},
  7138  	}
  7139  	for _, tt := range tests {
  7140  		t.Run(tt.name, func(t *testing.T) {
  7141  			gotStart, gotEnd := alignPCs(bi, tt.args.start, tt.args.end)
  7142  			if gotStart != tt.wantStart {
  7143  				t.Errorf("alignPCs() got start = %v, want %v", gotStart, tt.wantStart)
  7144  			}
  7145  			if gotEnd != tt.wantEnd {
  7146  				t.Errorf("alignPCs() got end = %v, want %v", gotEnd, tt.wantEnd)
  7147  			}
  7148  		})
  7149  	}
  7150  }
  7151  
  7152  func TestFindInstructions(t *testing.T) {
  7153  	numInstructions := 100
  7154  	startPC := 0x1000
  7155  	procInstructions := make([]proc.AsmInstruction, numInstructions)
  7156  	for i := 0; i < len(procInstructions); i++ {
  7157  		procInstructions[i] = proc.AsmInstruction{
  7158  			Loc: proc.Location{
  7159  				PC: uint64(startPC + 2*i),
  7160  			},
  7161  		}
  7162  	}
  7163  	type args struct {
  7164  		addr   uint64
  7165  		offset int
  7166  		count  int
  7167  	}
  7168  	tests := []struct {
  7169  		name             string
  7170  		args             args
  7171  		wantInstructions []proc.AsmInstruction
  7172  		wantOffset       int
  7173  		wantErr          bool
  7174  	}{
  7175  		{
  7176  			name: "request all",
  7177  			args: args{
  7178  				addr:   uint64(startPC),
  7179  				offset: 0,
  7180  				count:  100,
  7181  			},
  7182  			wantInstructions: procInstructions,
  7183  			wantOffset:       0,
  7184  			wantErr:          false,
  7185  		},
  7186  		{
  7187  			name: "request all (with offset)",
  7188  			args: args{
  7189  				addr:   uint64(startPC + numInstructions), // the instruction addr at numInstructions/2
  7190  				offset: -numInstructions / 2,
  7191  				count:  numInstructions,
  7192  			},
  7193  			wantInstructions: procInstructions,
  7194  			wantOffset:       0,
  7195  			wantErr:          false,
  7196  		},
  7197  		{
  7198  			name: "request half (with offset)",
  7199  			args: args{
  7200  				addr:   uint64(startPC),
  7201  				offset: 0,
  7202  				count:  numInstructions / 2,
  7203  			},
  7204  			wantInstructions: procInstructions[:numInstructions/2],
  7205  			wantOffset:       0,
  7206  			wantErr:          false,
  7207  		},
  7208  		{
  7209  			name: "request half (with offset)",
  7210  			args: args{
  7211  				addr:   uint64(startPC),
  7212  				offset: numInstructions / 2,
  7213  				count:  numInstructions / 2,
  7214  			},
  7215  			wantInstructions: procInstructions[numInstructions/2:],
  7216  			wantOffset:       0,
  7217  			wantErr:          false,
  7218  		},
  7219  		{
  7220  			name: "request too many",
  7221  			args: args{
  7222  				addr:   uint64(startPC),
  7223  				offset: 0,
  7224  				count:  numInstructions * 2,
  7225  			},
  7226  			wantInstructions: procInstructions,
  7227  			wantOffset:       0,
  7228  			wantErr:          false,
  7229  		},
  7230  		{
  7231  			name: "request too many with offset",
  7232  			args: args{
  7233  				addr:   uint64(startPC),
  7234  				offset: -numInstructions,
  7235  				count:  numInstructions * 2,
  7236  			},
  7237  			wantInstructions: procInstructions,
  7238  			wantOffset:       numInstructions,
  7239  			wantErr:          false,
  7240  		},
  7241  		{
  7242  			name: "request out of bounds",
  7243  			args: args{
  7244  				addr:   uint64(startPC),
  7245  				offset: -numInstructions,
  7246  				count:  numInstructions,
  7247  			},
  7248  			wantInstructions: []proc.AsmInstruction{},
  7249  			wantOffset:       0,
  7250  			wantErr:          false,
  7251  		},
  7252  		{
  7253  			name: "request out of bounds",
  7254  			args: args{
  7255  				addr:   uint64(uint64(startPC + 2*(numInstructions-1))),
  7256  				offset: 1,
  7257  				count:  numInstructions,
  7258  			},
  7259  			wantInstructions: []proc.AsmInstruction{},
  7260  			wantOffset:       0,
  7261  			wantErr:          false,
  7262  		},
  7263  		{
  7264  			name: "addr out of bounds (low)",
  7265  			args: args{
  7266  				addr:   0,
  7267  				offset: 0,
  7268  				count:  100,
  7269  			},
  7270  			wantInstructions: nil,
  7271  			wantOffset:       -1,
  7272  			wantErr:          true,
  7273  		},
  7274  		{
  7275  			name: "addr out of bounds (high)",
  7276  			args: args{
  7277  				addr:   uint64(startPC + 2*(numInstructions+1)),
  7278  				offset: -10,
  7279  				count:  20,
  7280  			},
  7281  			wantInstructions: nil,
  7282  			wantOffset:       -1,
  7283  			wantErr:          true,
  7284  		},
  7285  		{
  7286  			name: "addr not aligned",
  7287  			args: args{
  7288  				addr:   uint64(startPC + 1),
  7289  				offset: 0,
  7290  				count:  20,
  7291  			},
  7292  			wantInstructions: nil,
  7293  			wantOffset:       -1,
  7294  			wantErr:          true,
  7295  		},
  7296  	}
  7297  	for _, tt := range tests {
  7298  		t.Run(tt.name, func(t *testing.T) {
  7299  			gotInstructions, gotOffset, err := findInstructions(procInstructions, tt.args.addr, tt.args.offset, tt.args.count)
  7300  			if (err != nil) != tt.wantErr {
  7301  				t.Errorf("findInstructions() error = %v, wantErr %v", err, tt.wantErr)
  7302  				return
  7303  			}
  7304  			if !reflect.DeepEqual(gotInstructions, tt.wantInstructions) {
  7305  				t.Errorf("findInstructions() got instructions = %v, want %v", gotInstructions, tt.wantInstructions)
  7306  			}
  7307  			if gotOffset != tt.wantOffset {
  7308  				t.Errorf("findInstructions() got offset = %v, want %v", gotOffset, tt.wantOffset)
  7309  			}
  7310  		})
  7311  	}
  7312  }