service/dap: separate tests for var value truncation and str loading limits (#2539)

Co-authored-by: Polina Sokolova <polinasok@users.noreply.github.com>
This commit is contained in:
polinasok 2021-06-16 13:27:38 -07:00 committed by GitHub
parent 29825d41a6
commit 69485a639d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 103 additions and 41 deletions

@ -328,7 +328,9 @@ func main() {
longstr := "very long string 0123456789a0123456789b0123456789c0123456789d0123456789e0123456789f0123456789g012345678h90123456789i0123456789j0123456789"
m5 := map[C]int{{longstr}: 1}
m6 := C{s: longstr}
m6 := map[string]int{longstr: 123}
m7 := map[C]C{{longstr}: {longstr}}
cl := C{s: longstr}
var nilstruct *astruct = nil
val := A{val: 1} // val vs val.val
@ -363,5 +365,5 @@ func main() {
longslice := make([]int, 100, 100)
runtime.Breakpoint()
fmt.Println(i1, i2, i3, p1, pp1, amb1, s1, s3, a0, a1, p2, p3, s2, as1, str1, f1, fn1, fn2, nilslice, nilptr, ch1, chnil, m1, mnil, m2, m3, m4, m5, upnil, up1, i4, i5, i6, err1, err2, errnil, iface1, iface2, ifacenil, arr1, parr, cpx1, const1, iface3, iface4, recursive1, recursive1.x, iface5, iface2fn1, iface2fn2, bencharr, benchparr, mapinf, mainMenu, b, b2, sd, anonstruct1, anonstruct2, anoniface1, anonfunc, mapanonstruct1, ifacearr, efacearr, ni8, ni16, ni32, ni64, pinf, ninf, nan, zsvmap, zsslice, zsvar, tm, rettm, errtypednil, emptyslice, emptymap, byteslice, runeslice, bytearray, runearray, longstr, nilstruct, as2, as2.NonPointerRecieverMethod, s4, iface2map, issue1578, ll, unread, w2, w3, w4, w5, longarr, longslice, val, m6)
fmt.Println(i1, i2, i3, p1, pp1, amb1, s1, s3, a0, a1, p2, p3, s2, as1, str1, f1, fn1, fn2, nilslice, nilptr, ch1, chnil, m1, mnil, m2, m3, m4, m5, upnil, up1, i4, i5, i6, err1, err2, errnil, iface1, iface2, ifacenil, arr1, parr, cpx1, const1, iface3, iface4, recursive1, recursive1.x, iface5, iface2fn1, iface2fn2, bencharr, benchparr, mapinf, mainMenu, b, b2, sd, anonstruct1, anonstruct2, anoniface1, anonfunc, mapanonstruct1, ifacearr, efacearr, ni8, ni16, ni32, ni64, pinf, ninf, nan, zsvmap, zsslice, zsvar, tm, rettm, errtypednil, emptyslice, emptymap, byteslice, runeslice, bytearray, runearray, longstr, nilstruct, as2, as2.NonPointerRecieverMethod, s4, iface2map, issue1578, ll, unread, w2, w3, w4, w5, longarr, longslice, val, m6, m7, cl)
}

@ -1322,14 +1322,6 @@ func TestScopesAndVariablesRequests2(t *testing.T) {
validateEvaluateName(t, client, m3kv1, 1)
}
}
// key - compound + truncated, value - scalar
ref = checkVarExact(t, locals, -1, "m5", "m5", `map[main.C]int [{s: "very long string 0123456789a0123456789b0123456789c0123456789d012...+73 more"}: 1, ]`, "map[main.C]int", hasChildren)
if ref > 0 {
client.VariablesRequest(ref)
m5 := client.ExpectVariablesResponse(t)
checkChildren(t, m5, "m5", 1)
checkVarRegex(t, m5, 0, `main\.C {s: "very long string 0123456789a0123456789b0123456789c01\.\.\. @ 0x[0-9a-f]+`, `m5\[\(\*\(\*"main\.C"\)\(0x[0-9a-f]+\)\)\]`, "1", `int`, hasChildren)
}
// key - compound, value - compound
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)
if ref > 0 {
@ -2832,7 +2824,94 @@ func TestEvaluateRequest(t *testing.T) {
})
}
func TestEvaluateRequestLongStrLargeValue(t *testing.T) {
// From testvariables2 fixture
const (
// As defined in the code
longstrFull = `"very long string 0123456789a0123456789b0123456789c0123456789d0123456789e0123456789f0123456789g012345678h90123456789i0123456789j0123456789"`
// Loaded with MaxStringLen=64
longstrLoaded64 = `"very long string 0123456789a0123456789b0123456789c0123456789d012...+73 more"`
longstrLoaded64re = `\"very long string 0123456789a0123456789b0123456789c0123456789d012\.\.\.\+73 more\"`
)
// TestVariableValueTruncation tests that in certain cases
// we truncate the loaded variable values to make display more user-friendly.
func TestVariableValueTruncation(t *testing.T) {
runTest(t, "testvariables2", func(client *daptest.Client, fixture protest.Fixture) {
runDebugSessionWithBPs(t, client, "launch",
// Launch
func() {
client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
},
// Breakpoint set within the program
fixture.Source, []int{},
[]onBreakpoint{{
execute: func() {
checkStop(t, client, 1, "main.main", -1)
client.VariablesRequest(1001) // Locals
locals := client.ExpectVariablesResponse(t)
// Compound variable values may be truncated
m1Full := `map\[string\]main\.astruct \[(\"[A-Za-z]+\": {A: [0-9]+, B: [0-9]+}, )+,\.\.\.\+2 more\]`
m1Part := `map\[string\]main\.astruct \[(\"[A-Za-z]+\": {A: [0-9]+, B: [0-9]+}, )+.+\.\.\.`
// In variable responses
checkVarRegex(t, locals, -1, "m1", "m1", m1Part, `map\[string\]main\.astruct`, hasChildren)
// In evaluate responses (select contexts only)
tests := []struct {
context string
want string
}{
{"", m1Part},
{"watch", m1Part},
{"repl", m1Part},
{"hover", m1Part},
{"variables", m1Full}, // used for copy
{"clipboard", m1Full}, // used for copy
{"somethingelse", m1Part},
}
for _, tc := range tests {
t.Run(tc.context, func(t *testing.T) {
client.EvaluateRequest("m1", 0, tc.context)
checkEvalRegex(t, client.ExpectEvaluateResponse(t), tc.want, hasChildren)
})
}
// Compound map keys may be truncated even further
// As the keys are always inside of a map container,
// this applies to variable requests.
// key - compound, value - scalar (inlined key:value display) => truncate key if too long
ref := checkVarExact(t, locals, -1, "m5", "m5", "map[main.C]int [{s: "+longstrLoaded64+"}: 1, ]", "map[main.C]int", hasChildren)
if ref > 0 {
client.VariablesRequest(ref)
// Key format: <truncated>... @<address>
checkVarRegex(t, client.ExpectVariablesResponse(t), 0, `main\.C {s: "very long string 0123456789.+\.\.\. @ 0x[0-9a-f]+`, `m5\[\(\*\(\*"main\.C"\)\(0x[0-9a-f]+\)\)\]`, "1", `int`, hasChildren)
}
// key - scalar, value - scalar (inlined key:value display) => not truncated
ref = checkVarExact(t, locals, -1, "m6", "m6", "map[string]int ["+longstrLoaded64+": 123, ]", "map[string]int", hasChildren)
if ref > 0 {
client.VariablesRequest(ref)
checkVarRegex(t, client.ExpectVariablesResponse(t), 0, longstrLoaded64re, `m6[\(\*\(\*\"string\"\)\(0x[0-9a-f]+\)\)]`, "123", "string: int", noChildren)
}
// key - compound, value - compound (array-like display) => not truncated
ref = checkVarExact(t, locals, -1, "m7", "m7", "map[main.C]main.C [{s: "+longstrLoaded64+"}: {s: "+longstrLoaded64+"}, ]", "map[main.C]main.C", hasChildren)
if ref > 0 {
client.VariablesRequest(ref)
m7 := client.ExpectVariablesResponse(t)
checkVarRegex(t, m7, 0, "[key 0]", `\(\*\(\*\"main\.C\"\)\(0x[0-9a-f]+\)\)`, `main\.C {s: `+longstrLoaded64re+`}`, `main\.C`, hasChildren)
checkVarRegex(t, m7, 1, "[val 0]", `\(\*\(\*\"main\.C\"\)\(0x[0-9a-f]+\)\)`, `main\.C {s: `+longstrLoaded64re+`}`, `main\.C`, hasChildren)
}
},
disconnect: true,
}})
})
}
// TestVariableLoadingOfLargeStrings tests that different string loading limits
// apply that depending on the context.
func TestVariableLoadingOfLargeStrings(t *testing.T) {
runTest(t, "testvariables2", func(client *daptest.Client, fixture protest.Fixture) {
runDebugSessionWithBPs(t, client, "launch",
// Launch
@ -2843,53 +2922,34 @@ func TestEvaluateRequestLongStrLargeValue(t *testing.T) {
fixture.Source, []int{},
[]onBreakpoint{{
execute: func() {
checkStop(t, client, 1, "main.main", -1)
client.VariablesRequest(1001) // Locals
locals := client.ExpectVariablesResponse(t)
// reflect.Kind == String, load with longer load limit if evaluated in repl/variables context.
// Limits vary for evaluate requests
for _, evalContext := range []string{"", "watch", "repl", "variables", "hover", "clipboard", "somethingelse"} {
t.Run(evalContext, func(t *testing.T) {
// long string
longstr := `"very long string 0123456789a0123456789b0123456789c0123456789d0123456789e0123456789f0123456789g012345678h90123456789i0123456789j0123456789"`
longstrTruncated := `"very long string 0123456789a0123456789b0123456789c0123456789d012...+73 more"`
// long string by itself (limits vary)
client.EvaluateRequest("longstr", 0, evalContext)
got := client.ExpectEvaluateResponse(t)
want := longstrTruncated
want := longstrLoaded64
switch evalContext {
case "repl", "variables", "hover", "clipboard":
want = longstr
want = longstrFull
}
checkEval(t, got, want, false)
// long string as a struct field
client.EvaluateRequest("(m6).s", 0, evalContext)
// long string as a child (same limits)
client.EvaluateRequest("(cl).s", 0, evalContext)
got2 := client.ExpectEvaluateResponse(t)
checkEval(t, got2, want, false)
// variables are not affected.
checkVarExact(t, locals, -1, "longstr", "longstr", longstrTruncated, "string", noChildren)
checkVarExact(t, locals, -1, "m6", "m6", `main.C {s: `+longstrTruncated+`}`, "main.C", hasChildren)
// large array
m1 := `map\[string\]main\.astruct \[.+\.\.\.\+2 more\]`
m1Truncated := `map\[string\]main\.astruct \[.+\.\.\.`
client.EvaluateRequest("m1", 0, evalContext)
got3 := client.ExpectEvaluateResponse(t)
want3 := m1Truncated
switch evalContext {
case "variables", "clipboard":
want3 = m1
}
checkEvalRegex(t, got3, want3, true)
checkVarRegex(t, locals, -1, "m1", "m1", m1Truncated, `map\[string\]main\.astruct`, true)
})
}
// Variables requests are not affected.
checkVarExact(t, locals, -1, "longstr", "longstr", longstrLoaded64, "string", noChildren)
checkVarExact(t, locals, -1, "cl", "cl", `main.C {s: `+longstrLoaded64+`}`, "main.C", hasChildren)
},
disconnect: true,
}})
@ -4058,7 +4118,7 @@ func TestSetVariable(t *testing.T) {
execute: func() {
tester := &helperForSetVariable{t, client}
startLineno := 358 // after runtime.Breakpoint
startLineno := 360 // after runtime.Breakpoint
if runtime.GOOS == "windows" && goversion.VersionAfterOrEqual(runtime.Version(), 1, 15) {
startLineno = -1
}