github.com/cnboonhan/delve@v0.0.0-20230908061759-363f2388c2fb/service/dap/server_test.go (about)

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