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