2017-04-19 02:56:20 +00:00
package service_test
2015-10-18 17:37:13 +00:00
import (
2018-07-28 19:12:07 +00:00
"errors"
2015-10-18 17:37:13 +00:00
"fmt"
2019-04-26 17:23:43 +00:00
"go/constant"
2020-12-10 17:03:11 +00:00
"io/ioutil"
2019-08-14 15:57:05 +00:00
"path/filepath"
2016-09-06 17:26:56 +00:00
"runtime"
2015-10-18 17:37:13 +00:00
"sort"
"strings"
"testing"
2019-01-04 18:39:25 +00:00
"github.com/go-delve/delve/pkg/goversion"
"github.com/go-delve/delve/pkg/proc"
"github.com/go-delve/delve/pkg/proc/gdbserial"
"github.com/go-delve/delve/pkg/proc/native"
"github.com/go-delve/delve/service/api"
2015-10-18 17:37:13 +00:00
2019-01-04 18:39:25 +00:00
protest "github.com/go-delve/delve/pkg/proc/test"
2015-10-18 17:37:13 +00:00
)
2020-03-18 16:25:32 +00:00
var pnormalLoadConfig = proc . LoadConfig {
FollowPointers : true ,
MaxVariableRecurse : 1 ,
MaxStringLen : 64 ,
MaxArrayValues : 64 ,
MaxStructFields : - 1 ,
}
var pshortLoadConfig = proc . LoadConfig {
MaxStringLen : 64 ,
MaxStructFields : 3 ,
}
2016-04-24 17:15:39 +00:00
2015-10-18 17:37:13 +00:00
type varTest struct {
2015-10-30 11:39:32 +00:00
name string
preserveName bool
value string
2016-04-24 17:15:39 +00:00
alternate string
2015-10-30 11:39:32 +00:00
varType string
err error
2015-10-18 17:37:13 +00:00
}
func matchStringOrPrefix ( output , target string ) bool {
if strings . HasSuffix ( target , "…" ) {
prefix := target [ : len ( target ) - len ( "…" ) ]
b := strings . HasPrefix ( output , prefix )
return b
} else {
return output == target
}
}
func assertVariable ( t * testing . T , variable * proc . Variable , expected varTest ) {
2015-10-30 11:39:32 +00:00
if expected . preserveName {
if variable . Name != expected . name {
t . Fatalf ( "Expected %s got %s\n" , expected . name , variable . Name )
}
2015-10-18 17:37:13 +00:00
}
cv := api . ConvertVar ( variable )
if cv . Type != expected . varType {
t . Fatalf ( "Expected %s got %s (for variable %s)\n" , expected . varType , cv . Type , expected . name )
}
if ss := cv . SinglelineString ( ) ; ! matchStringOrPrefix ( ss , expected . value ) {
t . Fatalf ( "Expected %#v got %#v (for variable %s)\n" , expected . value , ss , expected . name )
}
}
2020-01-21 20:41:24 +00:00
func findFirstNonRuntimeFrame ( p * proc . Target ) ( proc . Stackframe , error ) {
2017-05-05 22:17:52 +00:00
frames , err := proc . ThreadStacktrace ( p . CurrentThread ( ) , 10 )
2015-10-18 17:37:13 +00:00
if err != nil {
2017-05-05 22:17:52 +00:00
return proc . Stackframe { } , err
}
for _ , frame := range frames {
if frame . Current . Fn != nil && ! strings . HasPrefix ( frame . Current . Fn . Name , "runtime." ) {
return frame , nil
}
2015-10-18 17:37:13 +00:00
}
2017-05-05 22:17:52 +00:00
return proc . Stackframe { } , fmt . Errorf ( "non-runtime frame not found" )
}
2020-01-21 20:41:24 +00:00
func evalScope ( p * proc . Target ) ( * proc . EvalScope , error ) {
2019-05-08 21:06:38 +00:00
if testBackend != "rr" {
2021-07-02 16:37:55 +00:00
return proc . GoroutineScope ( p , p . CurrentThread ( ) )
2017-05-05 22:17:52 +00:00
}
2019-05-08 21:06:38 +00:00
frame , err := findFirstNonRuntimeFrame ( p )
if err != nil {
return nil , err
}
2021-08-09 17:16:24 +00:00
return proc . FrameToScope ( p , p . Memory ( ) , nil , frame ) , nil
2019-05-08 21:06:38 +00:00
}
2017-05-05 22:17:52 +00:00
2020-01-21 20:41:24 +00:00
func evalVariable ( p * proc . Target , symbol string , cfg proc . LoadConfig ) ( * proc . Variable , error ) {
2019-05-08 21:06:38 +00:00
scope , err := evalScope ( p )
2017-06-29 18:15:59 +00:00
if err != nil {
return nil , err
}
2021-11-26 16:06:23 +00:00
return scope . EvalExpression ( symbol , cfg )
2015-10-18 17:37:13 +00:00
}
2016-04-24 17:15:39 +00:00
func ( tc * varTest ) alternateVarTest ( ) varTest {
2015-10-18 17:37:13 +00:00
r := * tc
2016-04-24 17:15:39 +00:00
r . value = r . alternate
2015-10-18 17:37:13 +00:00
return r
}
2020-01-21 20:41:24 +00:00
func setVariable ( p * proc . Target , symbol , value string ) error {
2021-07-02 16:37:55 +00:00
scope , err := proc . GoroutineScope ( p , p . CurrentThread ( ) )
2015-10-18 17:37:13 +00:00
if err != nil {
return err
}
return scope . SetVariable ( symbol , value )
}
2020-01-21 20:41:24 +00:00
func withTestProcess ( name string , t * testing . T , fn func ( p * proc . Target , fixture protest . Fixture ) ) {
2019-05-08 21:06:38 +00:00
withTestProcessArgs ( name , t , "." , [ ] string { } , 0 , fn )
}
2020-01-21 20:41:24 +00:00
func withTestProcessArgs ( name string , t * testing . T , wd string , args [ ] string , buildFlags protest . BuildFlags , fn func ( p * proc . Target , fixture protest . Fixture ) ) {
2018-05-29 15:01:51 +00:00
if buildMode == "pie" {
2019-05-08 21:06:38 +00:00
buildFlags |= protest . BuildModePIE
2018-05-29 15:01:51 +00:00
}
fixture := protest . BuildFixture ( name , buildFlags )
2020-01-21 20:41:24 +00:00
var p * proc . Target
2017-02-10 14:11:40 +00:00
var err error
2017-05-05 22:17:52 +00:00
var tracedir string
2017-02-10 14:11:40 +00:00
switch testBackend {
case "native" :
2020-10-21 19:50:52 +00:00
p , err = native . Launch ( append ( [ ] string { fixture . Path } , args ... ) , wd , 0 , [ ] string { } , "" , [ 3 ] string { } )
2017-02-10 14:11:40 +00:00
case "lldb" :
2020-10-21 19:50:52 +00:00
p , err = gdbserial . LLDBLaunch ( append ( [ ] string { fixture . Path } , args ... ) , wd , 0 , [ ] string { } , "" , [ 3 ] string { } )
2017-05-05 22:17:52 +00:00
case "rr" :
protest . MustHaveRecordingAllowed ( t )
t . Log ( "recording" )
2020-08-21 14:14:02 +00:00
p , tracedir , err = gdbserial . RecordAndReplay ( append ( [ ] string { fixture . Path } , args ... ) , wd , true , [ ] string { } , [ 3 ] string { } )
2017-05-05 22:17:52 +00:00
t . Logf ( "replaying %q" , tracedir )
2017-02-10 14:11:40 +00:00
default :
t . Fatalf ( "unknown backend %q" , testBackend )
}
2015-10-18 17:37:13 +00:00
if err != nil {
t . Fatal ( "Launch():" , err )
}
defer func ( ) {
2017-02-10 14:11:40 +00:00
p . Detach ( true )
2015-10-18 17:37:13 +00:00
} ( )
fn ( p , fixture )
}
func TestVariableEvaluation ( t * testing . T ) {
testcases := [ ] varTest {
2016-01-24 09:25:54 +00:00
{ "a1" , true , "\"foofoofoofoofoofoo\"" , "" , "string" , nil } ,
2015-10-30 11:39:32 +00:00
{ "a11" , true , "[3]main.FooBar [{Baz: 1, Bur: \"a\"},{Baz: 2, Bur: \"b\"},{Baz: 3, Bur: \"c\"}]" , "" , "[3]main.FooBar" , nil } ,
2016-01-24 09:25:54 +00:00
{ "a12" , true , "[]main.FooBar len: 2, cap: 2, [{Baz: 4, Bur: \"d\"},{Baz: 5, Bur: \"e\"}]" , "" , "[]main.FooBar" , nil } ,
{ "a13" , true , "[]*main.FooBar len: 3, cap: 3, [*{Baz: 6, Bur: \"f\"},*{Baz: 7, Bur: \"g\"},*{Baz: 8, Bur: \"h\"}]" , "" , "[]*main.FooBar" , nil } ,
2015-10-30 11:39:32 +00:00
{ "a2" , true , "6" , "10" , "int" , nil } ,
{ "a3" , true , "7.23" , "3.1" , "float64" , nil } ,
{ "a4" , true , "[2]int [1,2]" , "" , "[2]int" , nil } ,
2016-01-24 09:25:54 +00:00
{ "a5" , true , "[]int len: 5, cap: 5, [1,2,3,4,5]" , "" , "[]int" , nil } ,
2015-10-30 11:39:32 +00:00
{ "a6" , true , "main.FooBar {Baz: 8, Bur: \"word\"}" , "" , "main.FooBar" , nil } ,
{ "a7" , true , "*main.FooBar {Baz: 5, Bur: \"strum\"}" , "" , "*main.FooBar" , nil } ,
{ "a8" , true , "main.FooBar2 {Bur: 10, Baz: \"feh\"}" , "" , "main.FooBar2" , nil } ,
{ "a9" , true , "*main.FooBar nil" , "" , "*main.FooBar" , nil } ,
2016-01-24 09:25:54 +00:00
{ "baz" , true , "\"bazburzum\"" , "" , "string" , nil } ,
2015-10-30 11:39:32 +00:00
{ "neg" , true , "-1" , "-20" , "int" , nil } ,
{ "f32" , true , "1.2" , "1.1" , "float32" , nil } ,
{ "c64" , true , "(1 + 2i)" , "(4 + 5i)" , "complex64" , nil } ,
{ "c128" , true , "(2 + 3i)" , "(6.3 + 7i)" , "complex128" , nil } ,
{ "a6.Baz" , true , "8" , "20" , "int" , nil } ,
{ "a7.Baz" , true , "5" , "25" , "int" , nil } ,
2016-01-24 09:25:54 +00:00
{ "a8.Baz" , true , "\"feh\"" , "" , "string" , nil } ,
2015-10-30 11:39:32 +00:00
{ "a9.Baz" , true , "nil" , "" , "int" , fmt . Errorf ( "a9 is nil" ) } ,
{ "a9.NonExistent" , true , "nil" , "" , "int" , fmt . Errorf ( "a9 has no member NonExistent" ) } ,
{ "a8" , true , "main.FooBar2 {Bur: 10, Baz: \"feh\"}" , "" , "main.FooBar2" , nil } , // reread variable after member
{ "i32" , true , "[2]int32 [1,2]" , "" , "[2]int32" , nil } ,
{ "b1" , true , "true" , "false" , "bool" , nil } ,
{ "b2" , true , "false" , "true" , "bool" , nil } ,
{ "i8" , true , "1" , "2" , "int8" , nil } ,
{ "u16" , true , "65535" , "0" , "uint16" , nil } ,
{ "u32" , true , "4294967295" , "1" , "uint32" , nil } ,
{ "u64" , true , "18446744073709551615" , "2" , "uint64" , nil } ,
{ "u8" , true , "255" , "3" , "uint8" , nil } ,
{ "up" , true , "5" , "4" , "uintptr" , nil } ,
{ "f" , true , "main.barfoo" , "" , "func()" , nil } ,
2016-01-24 09:25:54 +00:00
{ "ba" , true , "[]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]" , "" , "[]int" , nil } ,
2015-10-30 11:39:32 +00:00
{ "ms" , true , "main.Nest {Level: 0, Nest: *main.Nest {Level: 1, Nest: *(*main.Nest)(…" , "" , "main.Nest" , nil } ,
{ "ms.Nest.Nest" , true , "*main.Nest {Level: 2, Nest: *main.Nest {Level: 3, Nest: *(*main.Nest)(…" , "" , "*main.Nest" , nil } ,
{ "ms.Nest.Nest.Nest.Nest.Nest" , true , "*main.Nest nil" , "" , "*main.Nest" , nil } ,
{ "ms.Nest.Nest.Nest.Nest.Nest.Nest" , true , "" , "" , "*main.Nest" , fmt . Errorf ( "ms.Nest.Nest.Nest.Nest.Nest is nil" ) } ,
{ "main.p1" , true , "10" , "12" , "int" , nil } ,
{ "p1" , true , "10" , "13" , "int" , nil } ,
{ "NonExistent" , true , "" , "" , "" , fmt . Errorf ( "could not find symbol value for NonExistent" ) } ,
2015-10-18 17:37:13 +00:00
}
2017-05-05 22:17:52 +00:00
protest . AllowRecording ( t )
2020-01-21 20:41:24 +00:00
withTestProcess ( "testvariables" , t , func ( p * proc . Target , fixture protest . Fixture ) {
2020-03-24 16:16:58 +00:00
err := p . Continue ( )
2015-10-18 17:37:13 +00:00
assertNoError ( err , t , "Continue() returned an error" )
for _ , tc := range testcases {
2016-04-24 17:15:39 +00:00
variable , err := evalVariable ( p , tc . name , pnormalLoadConfig )
2015-10-18 17:37:13 +00:00
if tc . err == nil {
assertNoError ( err , t , "EvalVariable() returned an error" )
assertVariable ( t , variable , tc )
} else {
if err == nil {
t . Fatalf ( "Expected error %s, got no error: %s\n" , tc . err . Error ( ) , api . ConvertVar ( variable ) . SinglelineString ( ) )
}
if tc . err . Error ( ) != err . Error ( ) {
t . Fatalf ( "Unexpected error. Expected %s got %s" , tc . err . Error ( ) , err . Error ( ) )
}
}
2017-05-05 22:17:52 +00:00
if tc . alternate != "" && testBackend != "rr" {
2016-04-24 17:15:39 +00:00
assertNoError ( setVariable ( p , tc . name , tc . alternate ) , t , "SetVariable()" )
variable , err = evalVariable ( p , tc . name , pnormalLoadConfig )
2015-10-18 17:37:13 +00:00
assertNoError ( err , t , "EvalVariable()" )
2016-04-24 17:15:39 +00:00
assertVariable ( t , variable , tc . alternateVarTest ( ) )
2015-10-18 17:37:13 +00:00
assertNoError ( setVariable ( p , tc . name , tc . value ) , t , "SetVariable()" )
2016-04-24 17:15:39 +00:00
variable , err := evalVariable ( p , tc . name , pnormalLoadConfig )
2015-10-18 17:37:13 +00:00
assertNoError ( err , t , "EvalVariable()" )
assertVariable ( t , variable , tc )
}
}
} )
}
2018-07-27 17:19:01 +00:00
func TestSetVariable ( t * testing . T ) {
var testcases = [ ] struct {
name string
typ string // type of <name>
startVal string // original value of <name>
expr string
finalVal string // new value of <name> after executing <name> = <expr>
} {
{ "b.ptr" , "*main.A" , "*main.A {val: 1337}" , "nil" , "*main.A nil" } ,
{ "m2" , "map[int]*main.astruct" , "map[int]*main.astruct [1: *{A: 10, B: 11}, ]" , "nil" , "map[int]*main.astruct nil" } ,
{ "fn1" , "main.functype" , "main.afunc" , "nil" , "nil" } ,
2019-10-26 15:15:33 +00:00
{ "ch1" , "chan int" , "chan int 4/11" , "nil" , "chan int nil" } ,
2018-07-27 17:19:01 +00:00
{ "s2" , "[]main.astruct" , "[]main.astruct len: 8, cap: 8, [{A: 1, B: 2},{A: 3, B: 4},{A: 5, B: 6},{A: 7, B: 8},{A: 9, B: 10},{A: 11, B: 12},{A: 13, B: 14},{A: 15, B: 16}]" , "nil" , "[]main.astruct len: 0, cap: 0, nil" } ,
{ "err1" , "error" , "error(*main.astruct) *{A: 1, B: 2}" , "nil" , "error nil" } ,
{ "s1[0]" , "string" , ` "one" ` , ` "" ` , ` "" ` } ,
{ "as1" , "main.astruct" , "main.astruct {A: 1, B: 1}" , ` m1["Malone"] ` , "main.astruct {A: 2, B: 3}" } ,
{ "iface1" , "interface {}" , "interface {}(*main.astruct) *{A: 1, B: 2}" , "nil" , "interface {} nil" } ,
{ "iface1" , "interface {}" , "interface {} nil" , "iface2" , "interface {}(string) \"test\"" } ,
{ "iface1" , "interface {}" , "interface {}(string) \"test\"" , "parr" , "interface {}(*[4]int) *[0,1,2,3]" } ,
{ "s3" , "[]int" , ` []int len: 0, cap: 6, [] ` , "s4[2:5]" , "[]int len: 3, cap: 3, [3,4,5]" } ,
{ "s3" , "[]int" , "[]int len: 3, cap: 3, [3,4,5]" , "arr1[:]" , "[]int len: 4, cap: 4, [0,1,2,3]" } ,
}
2020-01-21 20:41:24 +00:00
withTestProcess ( "testvariables2" , t , func ( p * proc . Target , fixture protest . Fixture ) {
2020-03-24 16:16:58 +00:00
assertNoError ( p . Continue ( ) , t , "Continue()" )
2018-07-27 17:19:01 +00:00
for _ , tc := range testcases {
if tc . name == "iface1" && tc . expr == "parr" {
if ! goversion . VersionAfterOrEqual ( runtime . Version ( ) , 1 , 11 ) {
// conversion pointer -> eface not supported prior to Go 1.11
continue
}
}
variable , err := evalVariable ( p , tc . name , pnormalLoadConfig )
assertNoError ( err , t , "EvalVariable()" )
assertVariable ( t , variable , varTest { tc . name , true , tc . startVal , "" , tc . typ , nil } )
assertNoError ( setVariable ( p , tc . name , tc . expr ) , t , "SetVariable()" )
variable , err = evalVariable ( p , tc . name , pnormalLoadConfig )
assertNoError ( err , t , "EvalVariable()" )
assertVariable ( t , variable , varTest { tc . name , true , tc . finalVal , "" , tc . typ , nil } )
}
} )
}
2016-04-24 17:15:39 +00:00
func TestVariableEvaluationShort ( t * testing . T ) {
testcases := [ ] varTest {
{ "a1" , true , "\"foofoofoofoofoofoo\"" , "" , "string" , nil } ,
{ "a11" , true , "[3]main.FooBar [...]" , "" , "[3]main.FooBar" , nil } ,
{ "a12" , true , "[]main.FooBar len: 2, cap: 2, [...]" , "" , "[]main.FooBar" , nil } ,
{ "a13" , true , "[]*main.FooBar len: 3, cap: 3, [...]" , "" , "[]*main.FooBar" , nil } ,
{ "a2" , true , "6" , "" , "int" , nil } ,
{ "a3" , true , "7.23" , "" , "float64" , nil } ,
{ "a4" , true , "[2]int [...]" , "" , "[2]int" , nil } ,
{ "a5" , true , "[]int len: 5, cap: 5, [...]" , "" , "[]int" , nil } ,
{ "a6" , true , "main.FooBar {Baz: 8, Bur: \"word\"}" , "" , "main.FooBar" , nil } ,
{ "a7" , true , "(*main.FooBar)(0x…" , "" , "*main.FooBar" , nil } ,
{ "a8" , true , "main.FooBar2 {Bur: 10, Baz: \"feh\"}" , "" , "main.FooBar2" , nil } ,
{ "a9" , true , "*main.FooBar nil" , "" , "*main.FooBar" , nil } ,
{ "baz" , true , "\"bazburzum\"" , "" , "string" , nil } ,
{ "neg" , true , "-1" , "" , "int" , nil } ,
{ "f32" , true , "1.2" , "" , "float32" , nil } ,
{ "c64" , true , "(1 + 2i)" , "" , "complex64" , nil } ,
{ "c128" , true , "(2 + 3i)" , "" , "complex128" , nil } ,
{ "a6.Baz" , true , "8" , "" , "int" , nil } ,
{ "a7.Baz" , true , "5" , "" , "int" , nil } ,
{ "a8.Baz" , true , "\"feh\"" , "" , "string" , nil } ,
{ "a9.Baz" , true , "nil" , "" , "int" , fmt . Errorf ( "a9 is nil" ) } ,
{ "a9.NonExistent" , true , "nil" , "" , "int" , fmt . Errorf ( "a9 has no member NonExistent" ) } ,
{ "a8" , true , "main.FooBar2 {Bur: 10, Baz: \"feh\"}" , "" , "main.FooBar2" , nil } , // reread variable after member
{ "i32" , true , "[2]int32 [...]" , "" , "[2]int32" , nil } ,
{ "b1" , true , "true" , "false" , "bool" , nil } ,
{ "b2" , true , "false" , "true" , "bool" , nil } ,
{ "i8" , true , "1" , "2" , "int8" , nil } ,
{ "u16" , true , "65535" , "0" , "uint16" , nil } ,
{ "u32" , true , "4294967295" , "1" , "uint32" , nil } ,
{ "u64" , true , "18446744073709551615" , "2" , "uint64" , nil } ,
{ "u8" , true , "255" , "3" , "uint8" , nil } ,
{ "up" , true , "5" , "4" , "uintptr" , nil } ,
{ "f" , true , "main.barfoo" , "" , "func()" , nil } ,
{ "ba" , true , "[]int len: 200, cap: 200, [...]" , "" , "[]int" , nil } ,
{ "ms" , true , "main.Nest {Level: 0, Nest: (*main.Nest)(0x…" , "" , "main.Nest" , nil } ,
{ "ms.Nest.Nest" , true , "(*main.Nest)(0x…" , "" , "*main.Nest" , nil } ,
{ "ms.Nest.Nest.Nest.Nest.Nest" , true , "*main.Nest nil" , "" , "*main.Nest" , nil } ,
{ "ms.Nest.Nest.Nest.Nest.Nest.Nest" , true , "" , "" , "*main.Nest" , fmt . Errorf ( "ms.Nest.Nest.Nest.Nest.Nest is nil" ) } ,
{ "main.p1" , true , "10" , "" , "int" , nil } ,
{ "p1" , true , "10" , "" , "int" , nil } ,
{ "NonExistent" , true , "" , "" , "" , fmt . Errorf ( "could not find symbol value for NonExistent" ) } ,
}
2017-05-05 22:17:52 +00:00
protest . AllowRecording ( t )
2020-01-21 20:41:24 +00:00
withTestProcess ( "testvariables" , t , func ( p * proc . Target , fixture protest . Fixture ) {
2020-03-24 16:16:58 +00:00
err := p . Continue ( )
2016-04-24 17:15:39 +00:00
assertNoError ( err , t , "Continue() returned an error" )
for _ , tc := range testcases {
variable , err := evalVariable ( p , tc . name , pshortLoadConfig )
if tc . err == nil {
assertNoError ( err , t , "EvalVariable() returned an error" )
assertVariable ( t , variable , tc )
} else {
if err == nil {
t . Fatalf ( "Expected error %s, got no error: %s\n" , tc . err . Error ( ) , api . ConvertVar ( variable ) . SinglelineString ( ) )
}
if tc . err . Error ( ) != err . Error ( ) {
t . Fatalf ( "Unexpected error. Expected %s got %s" , tc . err . Error ( ) , err . Error ( ) )
}
}
}
} )
}
2015-10-18 17:37:13 +00:00
func TestMultilineVariableEvaluation ( t * testing . T ) {
testcases := [ ] varTest {
2016-01-24 09:25:54 +00:00
{ "a1" , true , "\"foofoofoofoofoofoo\"" , "" , "string" , nil } ,
2015-10-30 11:39:32 +00:00
{ "a11" , true , ` [ 3 ] main . FooBar [
2015-10-18 17:37:13 +00:00
{ Baz : 1 , Bur : "a" } ,
{ Baz : 2 , Bur : "b" } ,
{ Baz : 3 , Bur : "c" } ,
] ` , "" , "[3]main.FooBar" , nil } ,
2015-10-30 11:39:32 +00:00
{ "a12" , true , ` [ ] main . FooBar len : 2 , cap : 2 , [
2015-10-18 17:37:13 +00:00
{ Baz : 4 , Bur : "d" } ,
{ Baz : 5 , Bur : "e" } ,
2016-01-24 09:25:54 +00:00
] ` , "" , "[]main.FooBar" , nil } ,
2015-10-30 11:39:32 +00:00
{ "a13" , true , ` [ ] * main . FooBar len : 3 , cap : 3 , [
2015-10-18 17:37:13 +00:00
* { Baz : 6 , Bur : "f" } ,
* { Baz : 7 , Bur : "g" } ,
* { Baz : 8 , Bur : "h" } ,
2016-01-24 09:25:54 +00:00
] ` , "" , "[]*main.FooBar" , nil } ,
2015-10-30 11:39:32 +00:00
{ "a2" , true , "6" , "10" , "int" , nil } ,
{ "a4" , true , "[2]int [1,2]" , "" , "[2]int" , nil } ,
2016-01-24 09:25:54 +00:00
{ "a5" , true , "[]int len: 5, cap: 5, [1,2,3,4,5]" , "" , "[]int" , nil } ,
2015-10-30 11:39:32 +00:00
{ "a6" , true , "main.FooBar {Baz: 8, Bur: \"word\"}" , "" , "main.FooBar" , nil } ,
{ "a7" , true , "*main.FooBar {Baz: 5, Bur: \"strum\"}" , "" , "*main.FooBar" , nil } ,
{ "a8" , true , "main.FooBar2 {Bur: 10, Baz: \"feh\"}" , "" , "main.FooBar2" , nil } ,
{ "a9" , true , "*main.FooBar nil" , "" , "*main.FooBar" , nil } ,
{ "a8" , true , "main.FooBar2 {Bur: 10, Baz: \"feh\"}" , "" , "main.FooBar2" , nil } , // reread variable after member
{ "i32" , true , "[2]int32 [1,2]" , "" , "[2]int32" , nil } ,
2016-01-24 09:25:54 +00:00
{ "ba" , true , "[]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]" , "" , "[]int" , nil } ,
2015-10-30 11:39:32 +00:00
{ "ms" , true , ` main . Nest {
2015-10-18 17:37:13 +00:00
Level : 0 ,
Nest : * main . Nest {
Level : 1 ,
Nest : * ( * main . Nest ) ( … ` , "" , "main.Nest" , nil } ,
}
2017-05-05 22:17:52 +00:00
protest . AllowRecording ( t )
2020-01-21 20:41:24 +00:00
withTestProcess ( "testvariables" , t , func ( p * proc . Target , fixture protest . Fixture ) {
2020-03-24 16:16:58 +00:00
err := p . Continue ( )
2015-10-18 17:37:13 +00:00
assertNoError ( err , t , "Continue() returned an error" )
for _ , tc := range testcases {
2016-04-24 17:15:39 +00:00
variable , err := evalVariable ( p , tc . name , pnormalLoadConfig )
2015-10-18 17:37:13 +00:00
assertNoError ( err , t , "EvalVariable() returned an error" )
2021-03-25 16:45:30 +00:00
if ms := api . ConvertVar ( variable ) . MultilineString ( "" , "" ) ; ! matchStringOrPrefix ( ms , tc . value ) {
2015-10-18 17:37:13 +00:00
t . Fatalf ( "Expected %s got %s (variable %s)\n" , tc . value , ms , variable . Name )
}
}
} )
}
type varArray [ ] * proc . Variable
// Len is part of sort.Interface.
func ( s varArray ) Len ( ) int {
return len ( s )
}
// Swap is part of sort.Interface.
func ( s varArray ) Swap ( i , j int ) {
s [ i ] , s [ j ] = s [ j ] , s [ i ]
}
// Less is part of sort.Interface. It is implemented by calling the "by" closure in the sorter.
func ( s varArray ) Less ( i , j int ) bool {
return s [ i ] . Name < s [ j ] . Name
}
func TestLocalVariables ( t * testing . T ) {
testcases := [ ] struct {
2016-04-24 17:15:39 +00:00
fn func ( * proc . EvalScope , proc . LoadConfig ) ( [ ] * proc . Variable , error )
2015-10-18 17:37:13 +00:00
output [ ] varTest
} {
{ ( * proc . EvalScope ) . LocalVariables ,
[ ] varTest {
2016-01-24 09:25:54 +00:00
{ "a1" , true , "\"foofoofoofoofoofoo\"" , "" , "string" , nil } ,
{ "a10" , true , "\"ofo\"" , "" , "string" , nil } ,
2015-10-30 11:39:32 +00:00
{ "a11" , true , "[3]main.FooBar [{Baz: 1, Bur: \"a\"},{Baz: 2, Bur: \"b\"},{Baz: 3, Bur: \"c\"}]" , "" , "[3]main.FooBar" , nil } ,
2016-01-24 09:25:54 +00:00
{ "a12" , true , "[]main.FooBar len: 2, cap: 2, [{Baz: 4, Bur: \"d\"},{Baz: 5, Bur: \"e\"}]" , "" , "[]main.FooBar" , nil } ,
{ "a13" , true , "[]*main.FooBar len: 3, cap: 3, [*{Baz: 6, Bur: \"f\"},*{Baz: 7, Bur: \"g\"},*{Baz: 8, Bur: \"h\"}]" , "" , "[]*main.FooBar" , nil } ,
2015-10-30 11:39:32 +00:00
{ "a2" , true , "6" , "" , "int" , nil } ,
{ "a3" , true , "7.23" , "" , "float64" , nil } ,
{ "a4" , true , "[2]int [1,2]" , "" , "[2]int" , nil } ,
2016-01-24 09:25:54 +00:00
{ "a5" , true , "[]int len: 5, cap: 5, [1,2,3,4,5]" , "" , "[]int" , nil } ,
2015-10-30 11:39:32 +00:00
{ "a6" , true , "main.FooBar {Baz: 8, Bur: \"word\"}" , "" , "main.FooBar" , nil } ,
{ "a7" , true , "*main.FooBar {Baz: 5, Bur: \"strum\"}" , "" , "*main.FooBar" , nil } ,
{ "a8" , true , "main.FooBar2 {Bur: 10, Baz: \"feh\"}" , "" , "main.FooBar2" , nil } ,
{ "a9" , true , "*main.FooBar nil" , "" , "*main.FooBar" , nil } ,
{ "b1" , true , "true" , "" , "bool" , nil } ,
{ "b2" , true , "false" , "" , "bool" , nil } ,
2016-01-24 09:25:54 +00:00
{ "ba" , true , "[]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]" , "" , "[]int" , nil } ,
2015-10-30 11:39:32 +00:00
{ "c128" , true , "(2 + 3i)" , "" , "complex128" , nil } ,
{ "c64" , true , "(1 + 2i)" , "" , "complex64" , nil } ,
{ "f" , true , "main.barfoo" , "" , "func()" , nil } ,
{ "f32" , true , "1.2" , "" , "float32" , nil } ,
{ "i32" , true , "[2]int32 [1,2]" , "" , "[2]int32" , nil } ,
{ "i8" , true , "1" , "" , "int8" , nil } ,
2020-11-12 23:24:31 +00:00
{ "mp" , true , "map[int]interface {} [1: 42, 2: 43, ]" , "" , "map[int]interface {}" , nil } ,
2015-10-30 11:39:32 +00:00
{ "ms" , true , "main.Nest {Level: 0, Nest: *main.Nest {Level: 1, Nest: *(*main.Nest)…" , "" , "main.Nest" , nil } ,
{ "neg" , true , "-1" , "" , "int" , nil } ,
2021-03-08 17:41:47 +00:00
{ "ni" , true , "[]interface {} len: 1, cap: 1, [[]interface {} len: 1, cap: 1, [*(*interface {})…" , "" , "[]interface {}" , nil } ,
2015-10-30 11:39:32 +00:00
{ "u16" , true , "65535" , "" , "uint16" , nil } ,
{ "u32" , true , "4294967295" , "" , "uint32" , nil } ,
{ "u64" , true , "18446744073709551615" , "" , "uint64" , nil } ,
{ "u8" , true , "255" , "" , "uint8" , nil } ,
{ "up" , true , "5" , "" , "uintptr" , nil } } } ,
2015-10-18 17:37:13 +00:00
{ ( * proc . EvalScope ) . FunctionArguments ,
[ ] varTest {
2015-10-30 11:39:32 +00:00
{ "bar" , true , "main.FooBar {Baz: 10, Bur: \"lorem\"}" , "" , "main.FooBar" , nil } ,
2016-01-24 09:25:54 +00:00
{ "baz" , true , "\"bazburzum\"" , "" , "string" , nil } } } ,
2015-10-18 17:37:13 +00:00
}
2017-05-05 22:17:52 +00:00
protest . AllowRecording ( t )
2020-01-21 20:41:24 +00:00
withTestProcess ( "testvariables" , t , func ( p * proc . Target , fixture protest . Fixture ) {
2020-03-24 16:16:58 +00:00
err := p . Continue ( )
2015-10-18 17:37:13 +00:00
assertNoError ( err , t , "Continue() returned an error" )
for _ , tc := range testcases {
2017-05-05 22:17:52 +00:00
var scope * proc . EvalScope
var err error
if testBackend == "rr" {
var frame proc . Stackframe
frame , err = findFirstNonRuntimeFrame ( p )
if err == nil {
2021-08-09 17:16:24 +00:00
scope = proc . FrameToScope ( p , p . Memory ( ) , nil , frame )
2017-05-05 22:17:52 +00:00
}
} else {
2021-07-02 16:37:55 +00:00
scope , err = proc . GoroutineScope ( p , p . CurrentThread ( ) )
2017-05-05 22:17:52 +00:00
}
assertNoError ( err , t , "scope" )
2016-04-24 17:15:39 +00:00
vars , err := tc . fn ( scope , pnormalLoadConfig )
2015-10-18 17:37:13 +00:00
assertNoError ( err , t , "LocalVariables() returned an error" )
sort . Sort ( varArray ( vars ) )
if len ( tc . output ) != len ( vars ) {
t . Fatalf ( "Invalid variable count. Expected %d got %d." , len ( tc . output ) , len ( vars ) )
}
for i , variable := range vars {
assertVariable ( t , variable , tc . output [ i ] )
}
}
} )
}
func TestEmbeddedStruct ( t * testing . T ) {
2017-05-05 22:17:52 +00:00
protest . AllowRecording ( t )
2020-01-21 20:41:24 +00:00
withTestProcess ( "testvariables2" , t , func ( p * proc . Target , fixture protest . Fixture ) {
2015-10-18 17:37:13 +00:00
testcases := [ ] varTest {
2016-04-24 17:15:39 +00:00
{ "b.val" , true , "-314" , "-314" , "int" , nil } ,
{ "b.A.val" , true , "-314" , "-314" , "int" , nil } ,
{ "b.a.val" , true , "42" , "42" , "int" , nil } ,
{ "b.ptr.val" , true , "1337" , "1337" , "int" , nil } ,
{ "b.C.s" , true , "\"hello\"" , "\"hello\"" , "string" , nil } ,
{ "b.s" , true , "\"hello\"" , "\"hello\"" , "string" , nil } ,
2017-05-03 07:56:59 +00:00
{ "b2" , true , "main.B {A: main.A {val: 42}, C: *main.C nil, a: main.A {val: 47}, ptr: *main.A nil}" , "main.B {A: (*main.A)(0x…" , "main.B" , nil } ,
2021-01-29 17:25:31 +00:00
// Issue 2316: field promotion is breadth first and embedded interfaces never get promoted
{ "w2.W1.T.F" , true , ` "T-inside-W1" ` , ` "T-inside-W1" ` , "string" , nil } ,
{ "w2.W1.F" , true , ` "T-inside-W1" ` , ` "T-inside-W1" ` , "string" , nil } ,
{ "w2.T.F" , true , ` "T-inside-W2" ` , ` "T-inside-W2" ` , "string" , nil } ,
{ "w2.F" , true , ` "T-inside-W2" ` , ` "T-inside-W2" ` , "string" , nil } ,
{ "w3.I.T.F" , false , ` "T-inside-W1" ` , ` "T-inside-W1" ` , "string" , nil } ,
{ "w3.I.F" , false , ` "T-inside-W1" ` , ` "T-inside-W1" ` , "string" , nil } ,
{ "w3.T.F" , true , ` "T-inside-W3" ` , ` "T-inside-W3" ` , "string" , nil } ,
{ "w3.F" , true , ` "T-inside-W3" ` , ` "T-inside-W3" ` , "string" , nil } ,
{ "w4.I.T.F" , false , ` "T-inside-W1" ` , ` "T-inside-W1" ` , "string" , nil } ,
{ "w4.I.F" , false , ` "T-inside-W1" ` , ` "T-inside-W1" ` , "string" , nil } ,
{ "w4.F" , false , ` ` , ` ` , "" , errors . New ( "w4 has no member F" ) } ,
{ "w5.F" , false , ` ` , ` ` , "" , errors . New ( "w5 has no member F" ) } ,
2015-10-18 17:37:13 +00:00
}
2020-03-24 16:16:58 +00:00
assertNoError ( p . Continue ( ) , t , "Continue()" )
2015-10-18 17:37:13 +00:00
2017-05-04 10:22:08 +00:00
ver , _ := goversion . Parse ( runtime . Version ( ) )
2020-03-18 16:25:32 +00:00
if ver . Major >= 0 && ! ver . AfterOrEqual ( goversion . GoVersion { Major : 1 , Minor : 9 , Rev : - 1 } ) {
2017-05-03 07:56:59 +00:00
// on go < 1.9 embedded fields had different names
for i := range testcases {
if testcases [ i ] . name == "b2" {
testcases [ i ] . value = "main.B {main.A: main.A {val: 42}, *main.C: *main.C nil, a: main.A {val: 47}, ptr: *main.A nil}"
testcases [ i ] . alternate = "main.B {main.A: (*main.A)(0x…"
}
}
}
2015-10-18 17:37:13 +00:00
for _ , tc := range testcases {
2016-04-24 17:15:39 +00:00
variable , err := evalVariable ( p , tc . name , pnormalLoadConfig )
2015-10-18 17:37:13 +00:00
if tc . err == nil {
2016-04-24 17:15:39 +00:00
assertNoError ( err , t , fmt . Sprintf ( "EvalVariable(%s) returned an error" , tc . name ) )
2015-10-18 17:37:13 +00:00
assertVariable ( t , variable , tc )
2016-04-24 17:15:39 +00:00
variable , err = evalVariable ( p , tc . name , pshortLoadConfig )
assertNoError ( err , t , fmt . Sprintf ( "EvalVariable(%s, pshortLoadConfig) returned an error" , tc . name ) )
assertVariable ( t , variable , tc . alternateVarTest ( ) )
2015-10-18 17:37:13 +00:00
} else {
if tc . err . Error ( ) != err . Error ( ) {
t . Fatalf ( "Unexpected error. Expected %s got %s" , tc . err . Error ( ) , err . Error ( ) )
}
}
}
} )
}
func TestComplexSetting ( t * testing . T ) {
2020-01-21 20:41:24 +00:00
withTestProcess ( "testvariables" , t , func ( p * proc . Target , fixture protest . Fixture ) {
2020-03-24 16:16:58 +00:00
err := p . Continue ( )
2015-10-18 17:37:13 +00:00
assertNoError ( err , t , "Continue() returned an error" )
h := func ( setExpr , value string ) {
assertNoError ( setVariable ( p , "c128" , setExpr ) , t , "SetVariable()" )
2016-04-24 17:15:39 +00:00
variable , err := evalVariable ( p , "c128" , pnormalLoadConfig )
2015-10-18 17:37:13 +00:00
assertNoError ( err , t , "EvalVariable()" )
if s := api . ConvertVar ( variable ) . SinglelineString ( ) ; s != value {
t . Fatalf ( "Wrong value of c128: \"%s\", expected \"%s\" after setting it to \"%s\"" , s , value , setExpr )
}
}
h ( "3.2i" , "(0 + 3.2i)" )
h ( "1.1" , "(1.1 + 0i)" )
h ( "1 + 3.3i" , "(1 + 3.3i)" )
2015-11-12 17:53:01 +00:00
h ( "complex(1.2, 3.4)" , "(1.2 + 3.4i)" )
2015-10-18 17:37:13 +00:00
} )
}
2015-10-30 11:39:32 +00:00
func TestEvalExpression ( t * testing . T ) {
testcases := [ ] varTest {
// slice/array/string subscript
2016-04-24 17:15:39 +00:00
{ "s1[0]" , false , "\"one\"" , "\"one\"" , "string" , nil } ,
{ "s1[1]" , false , "\"two\"" , "\"two\"" , "string" , nil } ,
{ "s1[2]" , false , "\"three\"" , "\"three\"" , "string" , nil } ,
{ "s1[3]" , false , "\"four\"" , "\"four\"" , "string" , nil } ,
{ "s1[4]" , false , "\"five\"" , "\"five\"" , "string" , nil } ,
2016-01-24 09:25:54 +00:00
{ "s1[5]" , false , "" , "" , "string" , fmt . Errorf ( "index out of bounds" ) } ,
2016-04-24 17:15:39 +00:00
{ "a1[0]" , false , "\"one\"" , "\"one\"" , "string" , nil } ,
{ "a1[1]" , false , "\"two\"" , "\"two\"" , "string" , nil } ,
{ "a1[2]" , false , "\"three\"" , "\"three\"" , "string" , nil } ,
{ "a1[3]" , false , "\"four\"" , "\"four\"" , "string" , nil } ,
{ "a1[4]" , false , "\"five\"" , "\"five\"" , "string" , nil } ,
2016-01-24 09:25:54 +00:00
{ "a1[5]" , false , "" , "" , "string" , fmt . Errorf ( "index out of bounds" ) } ,
2016-04-24 17:15:39 +00:00
{ "str1[0]" , false , "48" , "48" , "byte" , nil } ,
{ "str1[1]" , false , "49" , "49" , "byte" , nil } ,
{ "str1[2]" , false , "50" , "50" , "byte" , nil } ,
{ "str1[10]" , false , "48" , "48" , "byte" , nil } ,
2015-10-30 11:39:32 +00:00
{ "str1[11]" , false , "" , "" , "byte" , fmt . Errorf ( "index out of bounds" ) } ,
// slice/array/string reslicing
2016-04-24 17:15:39 +00:00
{ "a1[2:4]" , false , "[]string len: 2, cap: 2, [\"three\",\"four\"]" , "[]string len: 2, cap: 2, [...]" , "[]string" , nil } ,
{ "s1[2:4]" , false , "[]string len: 2, cap: 2, [\"three\",\"four\"]" , "[]string len: 2, cap: 2, [...]" , "[]string" , nil } ,
{ "str1[2:4]" , false , "\"23\"" , "\"23\"" , "string" , nil } ,
{ "str1[0:11]" , false , "\"01234567890\"" , "\"01234567890\"" , "string" , nil } ,
{ "str1[:3]" , false , "\"012\"" , "\"012\"" , "string" , nil } ,
{ "str1[3:]" , false , "\"34567890\"" , "\"34567890\"" , "string" , nil } ,
2016-01-24 09:25:54 +00:00
{ "str1[0:12]" , false , "" , "" , "string" , fmt . Errorf ( "index out of bounds" ) } ,
{ "str1[5:3]" , false , "" , "" , "string" , fmt . Errorf ( "index out of bounds" ) } ,
2022-03-29 16:57:11 +00:00
{ "str1[11:]" , false , "\"\"" , "\"\"" , "string" , nil } ,
2015-10-30 11:39:32 +00:00
2017-01-20 22:22:36 +00:00
// NaN and Inf floats
{ "pinf" , false , "+Inf" , "+Inf" , "float64" , nil } ,
{ "ninf" , false , "-Inf" , "-Inf" , "float64" , nil } ,
{ "nan" , false , "NaN" , "NaN" , "float64" , nil } ,
2015-10-30 11:39:32 +00:00
// pointers
2016-04-24 17:15:39 +00:00
{ "*p2" , false , "5" , "5" , "int" , nil } ,
{ "p2" , true , "*5" , "(*int)(0x…" , "*int" , nil } ,
{ "p3" , true , "*int nil" , "*int nil" , "*int" , nil } ,
2015-10-30 11:39:32 +00:00
{ "*p3" , false , "" , "" , "int" , fmt . Errorf ( "nil pointer dereference" ) } ,
2015-11-03 18:11:08 +00:00
// channels
2019-10-26 15:15:33 +00:00
{ "ch1" , true , "chan int 4/11" , "chan int 4/11" , "chan int" , nil } ,
2016-04-24 17:15:39 +00:00
{ "chnil" , true , "chan int nil" , "chan int nil" , "chan int" , nil } ,
2015-11-03 18:11:08 +00:00
{ "ch1+1" , false , "" , "" , "" , fmt . Errorf ( "can not convert 1 constant to chan int" ) } ,
2015-11-05 17:25:52 +00:00
// maps
2016-05-29 19:20:09 +00:00
{ "m1[\"Malone\"]" , false , "main.astruct {A: 2, B: 3}" , "main.astruct {A: 2, B: 3}" , "main.astruct" , nil } ,
2016-04-24 17:15:39 +00:00
{ "m2[1].B" , false , "11" , "11" , "int" , nil } ,
{ "m2[c1.sa[2].B-4].A" , false , "10" , "10" , "int" , nil } ,
{ "m2[*p1].B" , false , "11" , "11" , "int" , nil } ,
{ "m3[as1]" , false , "42" , "42" , "int" , nil } ,
2015-11-05 17:25:52 +00:00
{ "mnil[\"Malone\"]" , false , "" , "" , "" , fmt . Errorf ( "key not found" ) } ,
2015-11-07 10:48:33 +00:00
{ "m1[80:]" , false , "" , "" , "" , fmt . Errorf ( "map index out of bounds" ) } ,
2015-11-05 17:25:52 +00:00
2015-11-12 11:30:41 +00:00
// interfaces
2016-05-29 19:20:09 +00:00
{ "err1" , true , "error(*main.astruct) *{A: 1, B: 2}" , "error(*main.astruct) 0x…" , "error" , nil } ,
{ "err2" , true , "error(*main.bstruct) *{a: main.astruct {A: 1, B: 2}}" , "error(*main.bstruct) 0x…" , "error" , nil } ,
2016-04-24 17:15:39 +00:00
{ "errnil" , true , "error nil" , "error nil" , "error" , nil } ,
2016-05-29 19:20:09 +00:00
{ "iface1" , true , "interface {}(*main.astruct) *{A: 1, B: 2}" , "interface {}(*main.astruct) 0x…" , "interface {}" , nil } ,
2017-10-26 16:08:01 +00:00
{ "iface1.A" , false , "1" , "1" , "int" , nil } ,
{ "iface1.B" , false , "2" , "2" , "int" , nil } ,
2017-06-29 18:17:52 +00:00
{ "iface2" , true , "interface {}(string) \"test\"" , "interface {}(string) \"test\"" , "interface {}" , nil } ,
2016-09-08 16:11:20 +00:00
{ "iface3" , true , "interface {}(map[string]go/constant.Value) []" , "interface {}(map[string]go/constant.Value) []" , "interface {}" , nil } ,
2017-06-29 18:17:52 +00:00
{ "iface4" , true , "interface {}([]go/constant.Value) [4]" , "interface {}([]go/constant.Value) [...]" , "interface {}" , nil } ,
2016-04-24 17:15:39 +00:00
{ "ifacenil" , true , "interface {} nil" , "interface {} nil" , "interface {}" , nil } ,
{ "err1 == err2" , false , "false" , "false" , "" , nil } ,
2015-11-12 11:30:41 +00:00
{ "err1 == iface1" , false , "" , "" , "" , fmt . Errorf ( "mismatched types \"error\" and \"interface {}\"" ) } ,
2017-07-07 18:08:36 +00:00
{ "errnil == nil" , false , "true" , "true" , "" , nil } ,
{ "errtypednil == nil" , false , "false" , "false" , "" , nil } ,
{ "nil == errnil" , false , "true" , "true" , "" , nil } ,
2016-05-29 19:20:09 +00:00
{ "err1.(*main.astruct)" , false , "*main.astruct {A: 1, B: 2}" , "(*main.astruct)(0x…" , "*main.astruct" , nil } ,
{ "err1.(*main.bstruct)" , false , "" , "" , "" , fmt . Errorf ( "interface conversion: error is *main.astruct, not *main.bstruct" ) } ,
2015-11-12 11:30:41 +00:00
{ "errnil.(*main.astruct)" , false , "" , "" , "" , fmt . Errorf ( "interface conversion: error is nil, not *main.astruct" ) } ,
2017-06-29 18:17:52 +00:00
{ "const1" , true , "go/constant.Value(go/constant.int64Val) 3" , "go/constant.Value(go/constant.int64Val) 3" , "go/constant.Value" , nil } ,
2015-11-12 11:30:41 +00:00
2015-10-30 11:39:32 +00:00
// combined expressions
2016-04-24 17:15:39 +00:00
{ "c1.pb.a.A" , true , "1" , "1" , "int" , nil } ,
{ "c1.sa[1].B" , false , "3" , "3" , "int" , nil } ,
{ "s2[5].B" , false , "12" , "12" , "int" , nil } ,
{ "s2[c1.sa[2].B].A" , false , "11" , "11" , "int" , nil } ,
{ "s2[*p2].B" , false , "12" , "12" , "int" , nil } ,
2015-10-30 11:39:32 +00:00
// constants
2016-04-24 17:15:39 +00:00
{ "1.1" , false , "1.1" , "1.1" , "" , nil } ,
{ "10" , false , "10" , "10" , "" , nil } ,
{ "1 + 2i" , false , "(1 + 2i)" , "(1 + 2i)" , "" , nil } ,
{ "true" , false , "true" , "true" , "" , nil } ,
{ "\"test\"" , false , "\"test\"" , "\"test\"" , "" , nil } ,
2015-10-30 11:39:32 +00:00
// binary operators
2016-04-24 17:15:39 +00:00
{ "i2 + i3" , false , "5" , "5" , "int" , nil } ,
{ "i2 - i3" , false , "-1" , "-1" , "int" , nil } ,
{ "i3 - i2" , false , "1" , "1" , "int" , nil } ,
{ "i2 * i3" , false , "6" , "6" , "int" , nil } ,
{ "i2/i3" , false , "0" , "0" , "int" , nil } ,
{ "f1/2.0" , false , "1.5" , "1.5" , "float64" , nil } ,
{ "i2 << 2" , false , "8" , "8" , "int" , nil } ,
2015-10-30 11:39:32 +00:00
// unary operators
2016-04-24 17:15:39 +00:00
{ "-i2" , false , "-2" , "-2" , "int" , nil } ,
{ "+i2" , false , "2" , "2" , "int" , nil } ,
{ "^i2" , false , "-3" , "-3" , "int" , nil } ,
2015-10-30 11:39:32 +00:00
// comparison operators
2016-04-24 17:15:39 +00:00
{ "i2 == i3" , false , "false" , "false" , "" , nil } ,
{ "i2 == 2" , false , "true" , "true" , "" , nil } ,
{ "i2 == 2" , false , "true" , "true" , "" , nil } ,
{ "i2 == 3" , false , "false" , "false" , "" , nil } ,
{ "i2 != i3" , false , "true" , "true" , "" , nil } ,
{ "i2 < i3" , false , "true" , "true" , "" , nil } ,
{ "i2 <= i3" , false , "true" , "true" , "" , nil } ,
{ "i2 > i3" , false , "false" , "false" , "" , nil } ,
{ "i2 >= i3" , false , "false" , "false" , "" , nil } ,
{ "i2 >= 2" , false , "true" , "true" , "" , nil } ,
{ "str1 == \"01234567890\"" , false , "true" , "true" , "" , nil } ,
{ "str1 < \"01234567890\"" , false , "false" , "false" , "" , nil } ,
{ "str1 < \"11234567890\"" , false , "true" , "true" , "" , nil } ,
{ "str1 > \"00234567890\"" , false , "true" , "true" , "" , nil } ,
{ "str1 == str1" , false , "true" , "true" , "" , nil } ,
{ "c1.pb.a == *(c1.sa[0])" , false , "true" , "true" , "" , nil } ,
{ "c1.pb.a != *(c1.sa[0])" , false , "false" , "false" , "" , nil } ,
{ "c1.pb.a == *(c1.sa[1])" , false , "false" , "false" , "" , nil } ,
{ "c1.pb.a != *(c1.sa[1])" , false , "true" , "true" , "" , nil } ,
2018-03-31 16:43:02 +00:00
{ ` longstr == "not this" ` , false , "false" , "false" , "" , nil } ,
2015-10-30 11:39:32 +00:00
2015-11-12 17:53:01 +00:00
// builtins
2016-04-24 17:15:39 +00:00
{ "cap(parr)" , false , "4" , "4" , "" , nil } ,
{ "len(parr)" , false , "4" , "4" , "" , nil } ,
2015-11-12 17:53:01 +00:00
{ "cap(p1)" , false , "" , "" , "" , fmt . Errorf ( "invalid argument p1 (type *int) for cap" ) } ,
{ "len(p1)" , false , "" , "" , "" , fmt . Errorf ( "invalid argument p1 (type *int) for len" ) } ,
2016-04-24 17:15:39 +00:00
{ "cap(a1)" , false , "5" , "5" , "" , nil } ,
{ "len(a1)" , false , "5" , "5" , "" , nil } ,
{ "cap(s3)" , false , "6" , "6" , "" , nil } ,
{ "len(s3)" , false , "0" , "0" , "" , nil } ,
{ "cap(nilslice)" , false , "0" , "0" , "" , nil } ,
{ "len(nilslice)" , false , "0" , "0" , "" , nil } ,
2019-10-26 15:15:33 +00:00
{ "cap(ch1)" , false , "11" , "11" , "" , nil } ,
2017-10-26 14:14:31 +00:00
{ "len(ch1)" , false , "4" , "4" , "" , nil } ,
2016-04-24 17:15:39 +00:00
{ "cap(chnil)" , false , "0" , "0" , "" , nil } ,
{ "len(chnil)" , false , "0" , "0" , "" , nil } ,
2019-10-07 16:35:58 +00:00
{ "len(m1)" , false , "66" , "66" , "" , nil } ,
2016-04-24 17:15:39 +00:00
{ "len(mnil)" , false , "0" , "0" , "" , nil } ,
{ "imag(cpx1)" , false , "2" , "2" , "" , nil } ,
{ "real(cpx1)" , false , "1" , "1" , "" , nil } ,
{ "imag(3i)" , false , "3" , "3" , "" , nil } ,
{ "real(4)" , false , "4" , "4" , "" , nil } ,
2015-11-12 17:53:01 +00:00
2015-10-30 11:39:32 +00:00
// nil
2016-04-24 17:15:39 +00:00
{ "nil" , false , "nil" , "nil" , "" , nil } ,
2015-10-30 11:39:32 +00:00
{ "nil+1" , false , "" , "" , "" , fmt . Errorf ( "operator + can not be applied to \"nil\"" ) } ,
2016-04-24 17:15:39 +00:00
{ "fn1" , false , "main.afunc" , "main.afunc" , "main.functype" , nil } ,
{ "fn2" , false , "nil" , "nil" , "main.functype" , nil } ,
2017-09-06 14:54:17 +00:00
{ "nilslice" , false , "[]int len: 0, cap: 0, nil" , "[]int len: 0, cap: 0, nil" , "[]int" , nil } ,
2015-10-30 11:39:32 +00:00
{ "fn1 == fn2" , false , "" , "" , "" , fmt . Errorf ( "can not compare func variables" ) } ,
2016-04-24 17:15:39 +00:00
{ "fn1 == nil" , false , "false" , "false" , "" , nil } ,
{ "fn1 != nil" , false , "true" , "true" , "" , nil } ,
{ "fn2 == nil" , false , "true" , "true" , "" , nil } ,
{ "fn2 != nil" , false , "false" , "false" , "" , nil } ,
{ "c1.sa == nil" , false , "false" , "false" , "" , nil } ,
{ "c1.sa != nil" , false , "true" , "true" , "" , nil } ,
{ "c1.sa[0] == nil" , false , "false" , "false" , "" , nil } ,
{ "c1.sa[0] != nil" , false , "true" , "true" , "" , nil } ,
{ "nilslice == nil" , false , "true" , "true" , "" , nil } ,
{ "nil == nilslice" , false , "true" , "true" , "" , nil } ,
{ "nilslice != nil" , false , "false" , "false" , "" , nil } ,
{ "nilptr == nil" , false , "true" , "true" , "" , nil } ,
{ "nilptr != nil" , false , "false" , "false" , "" , nil } ,
{ "p1 == nil" , false , "false" , "false" , "" , nil } ,
{ "p1 != nil" , false , "true" , "true" , "" , nil } ,
{ "ch1 == nil" , false , "false" , "false" , "" , nil } ,
{ "chnil == nil" , false , "true" , "true" , "" , nil } ,
2015-11-03 18:11:08 +00:00
{ "ch1 == chnil" , false , "" , "" , "" , fmt . Errorf ( "can not compare chan variables" ) } ,
2016-04-24 17:15:39 +00:00
{ "m1 == nil" , false , "false" , "false" , "" , nil } ,
2015-11-05 17:25:52 +00:00
{ "mnil == m1" , false , "" , "" , "" , fmt . Errorf ( "can not compare map variables" ) } ,
2016-04-24 17:15:39 +00:00
{ "mnil == nil" , false , "true" , "true" , "" , nil } ,
2015-11-12 11:29:53 +00:00
{ "nil == 2" , false , "" , "" , "" , fmt . Errorf ( "can not compare int to nil" ) } ,
{ "2 == nil" , false , "" , "" , "" , fmt . Errorf ( "can not compare int to nil" ) } ,
2015-10-30 11:39:32 +00:00
// errors
{ "&3" , false , "" , "" , "" , fmt . Errorf ( "can not take address of \"3\"" ) } ,
2015-11-12 11:29:53 +00:00
{ "*3" , false , "" , "" , "" , fmt . Errorf ( "expression \"3\" (int) can not be dereferenced" ) } ,
2015-10-30 11:39:32 +00:00
{ "&(i2 + i3)" , false , "" , "" , "" , fmt . Errorf ( "can not take address of \"(i2 + i3)\"" ) } ,
{ "i2 + p1" , false , "" , "" , "" , fmt . Errorf ( "mismatched types \"int\" and \"*int\"" ) } ,
{ "i2 + f1" , false , "" , "" , "" , fmt . Errorf ( "mismatched types \"int\" and \"float64\"" ) } ,
{ "i2 << f1" , false , "" , "" , "" , fmt . Errorf ( "shift count type float64, must be unsigned integer" ) } ,
2019-06-30 17:34:47 +00:00
{ "i2 << -1" , false , "" , "" , "" , fmt . Errorf ( "shift count must not be negative" ) } ,
2015-10-30 11:39:32 +00:00
{ "*(i2 + i3)" , false , "" , "" , "" , fmt . Errorf ( "expression \"(i2 + i3)\" (int) can not be dereferenced" ) } ,
{ "i2.member" , false , "" , "" , "" , fmt . Errorf ( "i2 (type int) is not a struct" ) } ,
2019-05-09 15:29:58 +00:00
{ "fmt.Println(\"hello\")" , false , "" , "" , "" , fmt . Errorf ( "function calls not allowed without using 'call'" ) } ,
2015-11-12 11:29:53 +00:00
{ "*nil" , false , "" , "" , "" , fmt . Errorf ( "nil can not be dereferenced" ) } ,
{ "!nil" , false , "" , "" , "" , fmt . Errorf ( "operator ! can not be applied to \"nil\"" ) } ,
{ "&nil" , false , "" , "" , "" , fmt . Errorf ( "can not take address of \"nil\"" ) } ,
{ "nil[0]" , false , "" , "" , "" , fmt . Errorf ( "expression \"nil\" (nil) does not support indexing" ) } ,
{ "nil[2:10]" , false , "" , "" , "" , fmt . Errorf ( "can not slice \"nil\" (type nil)" ) } ,
2016-04-24 17:15:39 +00:00
{ "nil.member" , false , "" , "" , "" , fmt . Errorf ( "nil (type nil) is not a struct" ) } ,
2016-01-24 09:25:54 +00:00
{ "(map[string]main.astruct)(0x4000)" , false , "" , "" , "" , fmt . Errorf ( "can not convert \"0x4000\" to map[string]main.astruct" ) } ,
2015-11-07 13:50:26 +00:00
// typecasts
2016-04-24 17:15:39 +00:00
{ "uint(i2)" , false , "2" , "2" , "uint" , nil } ,
{ "int8(i2)" , false , "2" , "2" , "int8" , nil } ,
{ "int(f1)" , false , "3" , "3" , "int" , nil } ,
{ "complex128(f1)" , false , "(3 + 0i)" , "(3 + 0i)" , "complex128" , nil } ,
{ "uint8(i4)" , false , "32" , "32" , "uint8" , nil } ,
{ "uint8(i5)" , false , "253" , "253" , "uint8" , nil } ,
{ "int8(i5)" , false , "-3" , "-3" , "int8" , nil } ,
{ "int8(i6)" , false , "12" , "12" , "int8" , nil } ,
2018-09-14 14:46:22 +00:00
{ "string(byteslice[0])" , false , ` "t" ` , ` "t" ` , "string" , nil } ,
{ "string(runeslice[0])" , false , ` "t" ` , ` "t" ` , "string" , nil } ,
2016-01-04 15:20:23 +00:00
// misc
2016-04-24 17:15:39 +00:00
{ "i1" , true , "1" , "1" , "int" , nil } ,
{ "mainMenu" , true , ` main.Menu len: 3, cap: 3, [ { Name: "home", Route: "/", Active: 1}, { Name: "About", Route: "/about", Active: 1}, { Name: "Login", Route: "/login", Active: 1}] ` , ` main.Menu len: 3, cap: 3, [...] ` , "main.Menu" , nil } ,
{ "mainMenu[0]" , false , ` main.Item { Name: "home", Route: "/", Active: 1} ` , ` main.Item { Name: "home", Route: "/", Active: 1} ` , "main.Item" , nil } ,
{ "sd" , false , "main.D {u1: 0, u2: 0, u3: 0, u4: 0, u5: 0, u6: 0}" , "main.D {u1: 0, u2: 0, u3: 0,...+3 more}" , "main.D" , nil } ,
2016-10-22 05:14:43 +00:00
{ "ifacearr" , false , "[]error len: 2, cap: 2, [*main.astruct {A: 0, B: 0},nil]" , "[]error len: 2, cap: 2, [...]" , "[]error" , nil } ,
2017-06-29 18:17:52 +00:00
{ "efacearr" , false , ` []interface { } len: 3, cap: 3, [*main.astruct { A: 0, B: 0},"test",nil] ` , "[]interface {} len: 3, cap: 3, [...]" , "[]interface {}" , nil } ,
2017-05-26 18:36:28 +00:00
{ "zsslice" , false , ` []struct { } len: 3, cap: 3, [ { }, { }, { }] ` , ` []struct { } len: 3, cap: 3, [...] ` , "[]struct {}" , nil } ,
{ "zsvmap" , false , ` map[string]struct { } ["testkey": { }, ] ` , ` map[string]struct { } [...] ` , "map[string]struct {}" , nil } ,
2017-05-30 21:26:10 +00:00
{ "tm" , false , "main.truncatedMap {v: []map[string]main.astruct len: 1, cap: 1, [[...]]}" , "main.truncatedMap {v: []map[string]main.astruct len: 1, cap: 1, [...]}" , "main.truncatedMap" , nil } ,
2017-09-06 14:54:17 +00:00
{ "emptyslice" , false , ` []string len: 0, cap: 0, [] ` , ` []string len: 0, cap: 0, [] ` , "[]string" , nil } ,
{ "emptymap" , false , ` map[string]string [] ` , ` map[string]string [] ` , "map[string]string" , nil } ,
{ "mnil" , false , ` map[string]main.astruct nil ` , ` map[string]main.astruct nil ` , "map[string]main.astruct" , nil } ,
2017-09-14 10:01:13 +00:00
// conversions between string/[]byte/[]rune (issue #548)
{ "runeslice" , true , ` []int32 len: 4, cap: 4, [116,232,115,116] ` , ` []int32 len: 4, cap: 4, [...] ` , "[]int32" , nil } ,
{ "byteslice" , true , ` []uint8 len: 5, cap: 5, [116,195,168,115,116] ` , ` []uint8 len: 5, cap: 5, [...] ` , "[]uint8" , nil } ,
{ "[]byte(str1)" , false , ` []uint8 len: 11, cap: 11, [48,49,50,51,52,53,54,55,56,57,48] ` , ` []uint8 len: 11, cap: 11, [48,49,50,51,52,53,54,55,56,57,48] ` , "[]uint8" , nil } ,
{ "[]uint8(str1)" , false , ` []uint8 len: 11, cap: 11, [48,49,50,51,52,53,54,55,56,57,48] ` , ` []uint8 len: 11, cap: 11, [48,49,50,51,52,53,54,55,56,57,48] ` , "[]uint8" , nil } ,
{ "[]rune(str1)" , false , ` []int32 len: 11, cap: 11, [48,49,50,51,52,53,54,55,56,57,48] ` , ` []int32 len: 11, cap: 11, [48,49,50,51,52,53,54,55,56,57,48] ` , "[]int32" , nil } ,
{ "[]int32(str1)" , false , ` []int32 len: 11, cap: 11, [48,49,50,51,52,53,54,55,56,57,48] ` , ` []int32 len: 11, cap: 11, [48,49,50,51,52,53,54,55,56,57,48] ` , "[]int32" , nil } ,
{ "string(byteslice)" , false , ` "tèst" ` , ` "" ` , "string" , nil } ,
{ "[]int32(string(byteslice))" , false , ` []int32 len: 4, cap: 4, [116,232,115,116] ` , ` []int32 len: 0, cap: 0, nil ` , "[]int32" , nil } ,
{ "string(runeslice)" , false , ` "tèst" ` , ` "" ` , "string" , nil } ,
{ "[]byte(string(runeslice))" , false , ` []uint8 len: 5, cap: 5, [116,195,168,115,116] ` , ` []uint8 len: 0, cap: 0, nil ` , "[]uint8" , nil } ,
{ "*(*[5]byte)(uintptr(&byteslice[0]))" , false , ` [5]uint8 [116,195,168,115,116] ` , ` [5]uint8 [...] ` , "[5]uint8" , nil } ,
2018-10-12 17:00:13 +00:00
{ "string(bytearray)" , false , ` "tèst" ` , ` "" ` , "string" , nil } ,
{ "string(runearray)" , false , ` "tèst" ` , ` "" ` , "string" , nil } ,
{ "string(str1)" , false , ` "01234567890" ` , ` "01234567890" ` , "string" , nil } ,
2017-10-26 14:14:31 +00:00
// access to channel field members
{ "ch1.qcount" , false , "4" , "4" , "uint" , nil } ,
2019-10-26 15:15:33 +00:00
{ "ch1.dataqsiz" , false , "11" , "11" , "uint" , nil } ,
{ "ch1.buf" , false , ` *[11]int [1,4,3,2,0,0,0,0,0,0,0] ` , ` (*[11]int)(… ` , "*[11]int" , nil } ,
2017-10-26 14:14:31 +00:00
{ "ch1.buf[0]" , false , "1" , "1" , "int" , nil } ,
2018-04-13 17:05:55 +00:00
// shortcircuited logical operators
{ "nilstruct != nil && nilstruct.A == 1" , false , "false" , "false" , "" , nil } ,
{ "nilstruct == nil || nilstruct.A == 1" , false , "true" , "true" , "" , nil } ,
2018-05-04 17:31:45 +00:00
{ "afunc" , true , ` main.afunc ` , ` main.afunc ` , ` func() ` , nil } ,
{ "main.afunc2" , true , ` main.afunc2 ` , ` main.afunc2 ` , ` func() ` , nil } ,
2018-07-30 19:02:35 +00:00
{ "s2[0].Error" , false , "main.(*astruct).Error" , "main.(*astruct).Error" , "func() string" , nil } ,
{ "s2[0].NonPointerRecieverMethod" , false , "main.astruct.NonPointerRecieverMethod" , "main.astruct.NonPointerRecieverMethod" , "func()" , nil } ,
{ "as2.Error" , false , "main.(*astruct).Error" , "main.(*astruct).Error" , "func() string" , nil } ,
{ "as2.NonPointerRecieverMethod" , false , "main.astruct.NonPointerRecieverMethod" , "main.astruct.NonPointerRecieverMethod" , "func()" , nil } ,
2018-09-14 11:52:41 +00:00
{ ` iface2map.(data) ` , false , "…" , "…" , "map[string]interface {}" , nil } ,
2019-06-13 00:35:00 +00:00
{ "issue1578" , false , "main.Block {cache: *main.Cache nil}" , "main.Block {cache: *main.Cache nil}" , "main.Block" , nil } ,
2021-05-17 17:31:05 +00:00
{ "ni8 << 2" , false , "-20" , "-20" , "int8" , nil } ,
{ "ni8 << 8" , false , "0" , "0" , "int8" , nil } ,
{ "ni8 >> 1" , false , "-3" , "-3" , "int8" , nil } ,
{ "bytearray[0] * bytearray[0]" , false , "144" , "144" , "uint8" , nil } ,
2022-02-22 17:55:59 +00:00
// function call / typecast errors
{ "unknownthing(1, 2)" , false , "" , "" , "" , errors . New ( "function calls not allowed without using 'call'" ) } ,
{ "(unknownthing)(1, 2)" , false , "" , "" , "" , errors . New ( "function calls not allowed without using 'call'" ) } ,
{ "afunc(2)" , false , "" , "" , "" , errors . New ( "function calls not allowed without using 'call'" ) } ,
{ "(afunc)(2)" , false , "" , "" , "" , errors . New ( "function calls not allowed without using 'call'" ) } ,
{ "(*afunc)(2)" , false , "" , "" , "" , errors . New ( "could not evaluate function or type (*afunc): expression \"afunc\" (func()) can not be dereferenced" ) } ,
{ "unknownthing(2)" , false , "" , "" , "" , errors . New ( "could not evaluate function or type unknownthing: could not find symbol value for unknownthing" ) } ,
{ "(*unknownthing)(2)" , false , "" , "" , "" , errors . New ( "could not evaluate function or type (*unknownthing): could not find symbol value for unknownthing" ) } ,
{ "(*strings.Split)(2)" , false , "" , "" , "" , errors . New ( "could not evaluate function or type (*strings.Split): could not find symbol value for strings" ) } ,
2022-03-25 20:59:57 +00:00
// pretty printing special types
{ "tim1" , false , ` time.Time(1977-05-25T18:00:00Z)… ` , ` time.Time(1977-05-25T18:00:00Z)… ` , "time.Time" , nil } ,
{ "tim2" , false , ` time.Time(2022-06-07T02:03:04-06:00)… ` , ` time.Time(2022-06-07T02:03:04-06:00)… ` , "time.Time" , nil } ,
2015-10-30 11:39:32 +00:00
}
2017-05-04 10:22:08 +00:00
ver , _ := goversion . Parse ( runtime . Version ( ) )
2020-03-18 16:25:32 +00:00
if ver . Major >= 0 && ! ver . AfterOrEqual ( goversion . GoVersion { Major : 1 , Minor : 7 , Rev : - 1 } ) {
2016-09-08 16:11:20 +00:00
for i := range testcases {
if testcases [ i ] . name == "iface3" {
testcases [ i ] . value = "interface {}(*map[string]go/constant.Value) *[]"
testcases [ i ] . alternate = "interface {}(*map[string]go/constant.Value) 0x…"
}
}
}
2017-05-05 22:17:52 +00:00
protest . AllowRecording ( t )
2020-01-21 20:41:24 +00:00
withTestProcess ( "testvariables2" , t , func ( p * proc . Target , fixture protest . Fixture ) {
2020-03-24 16:16:58 +00:00
assertNoError ( p . Continue ( ) , t , "Continue() returned an error" )
2015-10-30 11:39:32 +00:00
for _ , tc := range testcases {
2016-04-24 17:15:39 +00:00
variable , err := evalVariable ( p , tc . name , pnormalLoadConfig )
2018-07-30 19:02:35 +00:00
if err != nil && err . Error ( ) == "evaluating methods not supported on this version of Go" {
// this type of eval is unsupported with the current version of Go.
continue
}
2015-10-30 11:39:32 +00:00
if tc . err == nil {
assertNoError ( err , t , fmt . Sprintf ( "EvalExpression(%s) returned an error" , tc . name ) )
assertVariable ( t , variable , tc )
2016-04-24 17:15:39 +00:00
variable , err := evalVariable ( p , tc . name , pshortLoadConfig )
assertNoError ( err , t , fmt . Sprintf ( "EvalExpression(%s, pshortLoadConfig) returned an error" , tc . name ) )
assertVariable ( t , variable , tc . alternateVarTest ( ) )
2015-10-30 11:39:32 +00:00
} else {
if err == nil {
2015-11-12 11:29:53 +00:00
t . Fatalf ( "Expected error %s, got no error (%s)" , tc . err . Error ( ) , tc . name )
2015-10-30 11:39:32 +00:00
}
if tc . err . Error ( ) != err . Error ( ) {
t . Fatalf ( "Unexpected error. Expected %s got %s" , tc . err . Error ( ) , err . Error ( ) )
}
}
}
} )
}
func TestEvalAddrAndCast ( t * testing . T ) {
2017-05-05 22:17:52 +00:00
protest . AllowRecording ( t )
2020-01-21 20:41:24 +00:00
withTestProcess ( "testvariables2" , t , func ( p * proc . Target , fixture protest . Fixture ) {
2020-03-24 16:16:58 +00:00
assertNoError ( p . Continue ( ) , t , "Continue() returned an error" )
2016-04-24 17:15:39 +00:00
c1addr , err := evalVariable ( p , "&c1" , pnormalLoadConfig )
2015-10-30 11:39:32 +00:00
assertNoError ( err , t , "EvalExpression(&c1)" )
c1addrstr := api . ConvertVar ( c1addr ) . SinglelineString ( )
t . Logf ( "&c1 → %s" , c1addrstr )
if ! strings . HasPrefix ( c1addrstr , "(*main.cstruct)(0x" ) {
t . Fatalf ( "Invalid value of EvalExpression(&c1) \"%s\"" , c1addrstr )
}
2016-04-24 17:15:39 +00:00
aaddr , err := evalVariable ( p , "&(c1.pb.a)" , pnormalLoadConfig )
2015-10-30 11:39:32 +00:00
assertNoError ( err , t , "EvalExpression(&(c1.pb.a))" )
aaddrstr := api . ConvertVar ( aaddr ) . SinglelineString ( )
t . Logf ( "&(c1.pb.a) → %s" , aaddrstr )
if ! strings . HasPrefix ( aaddrstr , "(*main.astruct)(0x" ) {
t . Fatalf ( "invalid value of EvalExpression(&(c1.pb.a)) \"%s\"" , aaddrstr )
}
2016-04-24 17:15:39 +00:00
a , err := evalVariable ( p , "*" + aaddrstr , pnormalLoadConfig )
2015-10-30 11:39:32 +00:00
assertNoError ( err , t , fmt . Sprintf ( "EvalExpression(*%s)" , aaddrstr ) )
t . Logf ( "*%s → %s" , aaddrstr , api . ConvertVar ( a ) . SinglelineString ( ) )
2016-05-29 19:20:09 +00:00
assertVariable ( t , a , varTest { aaddrstr , false , "main.astruct {A: 1, B: 2}" , "" , "main.astruct" , nil } )
2015-10-30 11:39:32 +00:00
} )
}
2015-11-05 17:25:52 +00:00
func TestMapEvaluation ( t * testing . T ) {
2017-05-05 22:17:52 +00:00
protest . AllowRecording ( t )
2020-01-21 20:41:24 +00:00
withTestProcess ( "testvariables2" , t , func ( p * proc . Target , fixture protest . Fixture ) {
2020-03-24 16:16:58 +00:00
assertNoError ( p . Continue ( ) , t , "Continue() returned an error" )
2016-04-24 17:15:39 +00:00
m1v , err := evalVariable ( p , "m1" , pnormalLoadConfig )
2015-11-05 17:25:52 +00:00
assertNoError ( err , t , "EvalVariable()" )
m1 := api . ConvertVar ( m1v )
2021-03-25 16:45:30 +00:00
t . Logf ( "m1 = %v" , m1 . MultilineString ( "" , "" ) )
2015-11-05 17:25:52 +00:00
if m1 . Type != "map[string]main.astruct" {
t . Fatalf ( "Wrong type: %s" , m1 . Type )
}
2019-10-07 16:35:58 +00:00
if len ( m1 . Children ) / 2 != 64 {
2015-11-05 17:25:52 +00:00
t . Fatalf ( "Wrong number of children: %d" , len ( m1 . Children ) / 2 )
}
2019-10-07 16:35:58 +00:00
m1sliced , err := evalVariable ( p , "m1[64:]" , pnormalLoadConfig )
assertNoError ( err , t , "EvalVariable(m1[64:])" )
if len ( m1sliced . Children ) / 2 != int ( m1 . Len - 64 ) {
t . Fatalf ( "Wrong number of children (after slicing): %d" , len ( m1sliced . Children ) / 2 )
2015-11-05 17:25:52 +00:00
}
2019-10-07 16:35:58 +00:00
countMalone := func ( m * api . Variable ) int {
found := 0
for i := range m . Children {
if i % 2 == 0 && m . Children [ i ] . Value == "Malone" {
found ++
}
}
return found
2015-11-05 17:25:52 +00:00
}
2019-10-07 16:35:58 +00:00
found := countMalone ( m1 )
found += countMalone ( api . ConvertVar ( m1sliced ) )
if found != 1 {
t . Fatalf ( "Could not find Malone exactly 1 time: found %d" , found )
2015-11-05 17:25:52 +00:00
}
} )
2015-11-05 17:27:50 +00:00
}
2015-11-05 17:25:52 +00:00
2015-11-05 17:27:50 +00:00
func TestUnsafePointer ( t * testing . T ) {
2017-05-05 22:17:52 +00:00
protest . AllowRecording ( t )
2020-01-21 20:41:24 +00:00
withTestProcess ( "testvariables2" , t , func ( p * proc . Target , fixture protest . Fixture ) {
2020-03-24 16:16:58 +00:00
assertNoError ( p . Continue ( ) , t , "Continue() returned an error" )
2016-04-24 17:15:39 +00:00
up1v , err := evalVariable ( p , "up1" , pnormalLoadConfig )
2015-11-05 17:27:50 +00:00
assertNoError ( err , t , "EvalVariable(up1)" )
up1 := api . ConvertVar ( up1v )
if ss := up1 . SinglelineString ( ) ; ! strings . HasPrefix ( ss , "unsafe.Pointer(" ) {
t . Fatalf ( "wrong value for up1: %s" , ss )
}
} )
2015-11-05 17:25:52 +00:00
}
2016-04-24 23:14:42 +00:00
type issue426TestCase struct {
name string
typ string
}
func TestIssue426 ( t * testing . T ) {
// type casts using quoted type names
testcases := [ ] issue426TestCase {
{ "iface1" , ` interface { } ` } ,
{ "mapanonstruct1" , ` map[string]struct { } ` } ,
{ "anonstruct1" , ` struct { val go/constant.Value } ` } ,
{ "anonfunc" , ` func(struct { i int }, interface { }, struct { val go/constant.Value }) ` } ,
{ "anonstruct2" , ` struct { i int; j int } ` } ,
{ "anoniface1" , ` interface { OtherFunction(int, int); SomeFunction(struct { val go/constant.Value }) } ` } ,
}
2017-05-04 10:22:08 +00:00
ver , _ := goversion . Parse ( runtime . Version ( ) )
2020-03-18 16:25:32 +00:00
if ver . Major < 0 || ver . AfterOrEqual ( goversion . GoVersion { Major : 1 , Minor : 8 , Rev : - 1 } ) {
2016-09-06 17:26:56 +00:00
testcases [ 2 ] . typ = ` struct { main.val go/constant.Value } `
testcases [ 3 ] . typ = ` func(struct { main.i int }, interface { }, struct { main.val go/constant.Value }) `
testcases [ 4 ] . typ = ` struct { main.i int; main.j int } `
testcases [ 5 ] . typ = ` interface { OtherFunction(int, int); SomeFunction(struct { main.val go/constant.Value }) } `
}
2016-04-24 23:14:42 +00:00
// Serialization of type expressions (go/ast.Expr) containing anonymous structs or interfaces
// differs from the serialization used by the linker to produce DWARF type information
2017-05-05 22:17:52 +00:00
protest . AllowRecording ( t )
2020-01-21 20:41:24 +00:00
withTestProcess ( "testvariables2" , t , func ( p * proc . Target , fixture protest . Fixture ) {
2020-03-24 16:16:58 +00:00
assertNoError ( p . Continue ( ) , t , "Continue() returned an error" )
2016-04-24 23:14:42 +00:00
for _ , testcase := range testcases {
v , err := evalVariable ( p , testcase . name , pnormalLoadConfig )
assertNoError ( err , t , fmt . Sprintf ( "EvalVariable(%s)" , testcase . name ) )
t . Logf ( "%s → %s" , testcase . name , v . RealType . String ( ) )
expr := fmt . Sprintf ( "(*%q)(%d)" , testcase . typ , v . Addr )
_ , err = evalVariable ( p , expr , pnormalLoadConfig )
assertNoError ( err , t , fmt . Sprintf ( "EvalVariable(%s)" , expr ) )
}
} )
}
2016-09-08 16:11:20 +00:00
2020-01-21 20:41:24 +00:00
func testPackageRenamesHelper ( t * testing . T , p * proc . Target , testcases [ ] varTest ) {
2019-11-25 17:10:18 +00:00
for _ , tc := range testcases {
variable , err := evalVariable ( p , tc . name , pnormalLoadConfig )
if tc . err == nil {
assertNoError ( err , t , fmt . Sprintf ( "EvalExpression(%s) returned an error" , tc . name ) )
assertVariable ( t , variable , tc )
} else {
if err == nil {
t . Fatalf ( "Expected error %s, got no error (%s)" , tc . err . Error ( ) , tc . name )
}
if tc . err . Error ( ) != err . Error ( ) {
t . Fatalf ( "Unexpected error. Expected %s got %s" , tc . err . Error ( ) , err . Error ( ) )
}
}
}
}
2016-09-08 16:11:20 +00:00
func TestPackageRenames ( t * testing . T ) {
// Tests that the concrete type of an interface variable is resolved
// correctly in a few edge cases, in particular:
// - in the presence of renamed imports
// - when two packages with the same name are imported
// - when a package has a canonical name that's different from its
// path (for example the last element of the path contains a '.' or a
// '-' or because the package name is different)
// all of those edge cases are tested within composite types
testcases := [ ] varTest {
// Renamed imports
{ "badexpr" , true , ` interface { }(*go/ast.BadExpr) * { From: 1, To: 2} ` , "" , "interface {}" , nil } ,
{ "req" , true , ` interface { }(*net/http.Request) * { Method: "amethod", … ` , "" , "interface {}" , nil } ,
// Package name that doesn't match import path
2019-01-04 18:39:25 +00:00
{ "iface3" , true , ` interface { }(*github.com/go-delve/delve/_fixtures/internal/dir0/renamedpackage.SomeType) * { A: true} ` , "" , "interface {}" , nil } ,
2016-09-08 16:11:20 +00:00
// Interfaces to anonymous types
2019-01-04 18:39:25 +00:00
{ "dir0someType" , true , "interface {}(*github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeType) *{X: 3}" , "" , "interface {}" , nil } ,
{ "dir1someType" , true , "interface {}(github.com/go-delve/delve/_fixtures/internal/dir1/pkg.SomeType) {X: 1, Y: 2}" , "" , "interface {}" , nil } ,
{ "amap3" , true , "interface {}(map[github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeType]github.com/go-delve/delve/_fixtures/internal/dir1/pkg.SomeType) [{X: 4}: {X: 5, Y: 6}, ]" , "" , "interface {}" , nil } ,
{ "anarray" , true , ` interface { }([2]github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeType) [ { X: 1}, { X: 2}] ` , "" , "interface {}" , nil } ,
{ "achan" , true , ` interface { }(chan github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeType) chan github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeType 0/0 ` , "" , "interface {}" , nil } ,
{ "aslice" , true , ` interface { }([]github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeType) [ { X: 3}, { X: 4}] ` , "" , "interface {}" , nil } ,
{ "afunc" , true , ` interface { }(func(github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeType, github.com/go-delve/delve/_fixtures/internal/dir1/pkg.SomeType)) main.main.func1 ` , "" , "interface {}" , nil } ,
{ "astruct" , true , ` interface { }(*struct { A github.com/go-delve/delve/_fixtures/internal/dir1/pkg.SomeType; B github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeType }) * { A: github.com/go-delve/delve/_fixtures/internal/dir1/pkg.SomeType { X: 1, Y: 2}, B: github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeType { X: 3}} ` , "" , "interface {}" , nil } ,
{ "iface2iface" , true , ` interface { }(*interface { AMethod(int) int; AnotherMethod(int) int }) **github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeType { X: 4} ` , "" , "interface {}" , nil } ,
2018-06-14 12:45:04 +00:00
{ ` "dir0/pkg".A ` , false , "0" , "" , "int" , nil } ,
{ ` "dir1/pkg".A ` , false , "1" , "" , "int" , nil } ,
2016-09-08 16:11:20 +00:00
}
2020-03-10 16:34:40 +00:00
testcases_i386 := [ ] varTest {
{ "amap" , true , "interface {}(map[go/ast.BadExpr]net/http.Request) [{From: 2, To: 3}: {Method: \"othermethod\", …" , "" , "interface {}" , nil } ,
{ "amap2" , true , "interface {}(*map[go/ast.BadExpr]net/http.Request) *[{From: 2, To: 3}: {Method: \"othermethod\", …" , "" , "interface {}" , nil } ,
}
testcases_64bit := [ ] varTest {
{ "amap" , true , "interface {}(map[go/ast.BadExpr]net/http.Request) [{From: 2, To: 3}: *{Method: \"othermethod\", …" , "" , "interface {}" , nil } ,
{ "amap2" , true , "interface {}(*map[go/ast.BadExpr]net/http.Request) *[{From: 2, To: 3}: *{Method: \"othermethod\", …" , "" , "interface {}" , nil } ,
}
2019-11-25 17:10:18 +00:00
testcases1_8 := [ ] varTest {
// before 1.9 embedded struct fields have fieldname == type
{ "astruct2" , true , ` interface { }(*struct { github.com/go-delve/delve/_fixtures/internal/dir1/pkg.SomeType; X int }) * { github.com/go-delve/delve/_fixtures/internal/dir1/pkg.SomeType: github.com/go-delve/delve/_fixtures/internal/dir1/pkg.SomeType { X: 1, Y: 2}, X: 10} ` , "" , "interface {}" , nil } ,
}
testcases1_9 := [ ] varTest {
{ "astruct2" , true , ` interface { }(*struct { github.com/go-delve/delve/_fixtures/internal/dir1/pkg.SomeType; X int }) * { SomeType: github.com/go-delve/delve/_fixtures/internal/dir1/pkg.SomeType { X: 1, Y: 2}, X: 10} ` , "" , "interface {}" , nil } ,
}
testcases1_13 := [ ] varTest {
// needs DW_AT_go_package_name attribute added to Go1.13
{ ` dirio.A ` , false , ` "something" ` , "" , "string" , nil } ,
}
if ! goversion . VersionAfterOrEqual ( runtime . Version ( ) , 1 , 7 ) {
2016-09-08 16:11:20 +00:00
return
}
2017-05-05 22:17:52 +00:00
protest . AllowRecording ( t )
2020-01-21 20:41:24 +00:00
withTestProcess ( "pkgrenames" , t , func ( p * proc . Target , fixture protest . Fixture ) {
2020-03-24 16:16:58 +00:00
assertNoError ( p . Continue ( ) , t , "Continue() returned an error" )
2019-11-25 17:10:18 +00:00
testPackageRenamesHelper ( t , p , testcases )
if goversion . VersionAfterOrEqual ( runtime . Version ( ) , 1 , 9 ) {
testPackageRenamesHelper ( t , p , testcases1_9 )
} else {
testPackageRenamesHelper ( t , p , testcases1_8 )
}
if goversion . VersionAfterOrEqual ( runtime . Version ( ) , 1 , 13 ) {
testPackageRenamesHelper ( t , p , testcases1_13 )
2016-09-08 16:11:20 +00:00
}
2020-03-10 16:34:40 +00:00
if runtime . GOARCH == "386" {
testPackageRenamesHelper ( t , p , testcases_i386 )
} else {
testPackageRenamesHelper ( t , p , testcases_64bit )
}
2016-09-08 16:11:20 +00:00
} )
}
2017-09-08 10:31:20 +00:00
func TestConstants ( t * testing . T ) {
testcases := [ ] varTest {
2019-03-29 16:14:16 +00:00
{ "a" , true , "constTwo (2)" , "" , "main.ConstType" , nil } ,
{ "b" , true , "constThree (3)" , "" , "main.ConstType" , nil } ,
{ "c" , true , "bitZero|bitOne (3)" , "" , "main.BitFieldType" , nil } ,
2017-09-08 10:31:20 +00:00
{ "d" , true , "33" , "" , "main.BitFieldType" , nil } ,
{ "e" , true , "10" , "" , "main.ConstType" , nil } ,
{ "f" , true , "0" , "" , "main.BitFieldType" , nil } ,
{ "bitZero" , true , "1" , "" , "main.BitFieldType" , nil } ,
{ "bitOne" , true , "2" , "" , "main.BitFieldType" , nil } ,
{ "constTwo" , true , "2" , "" , "main.ConstType" , nil } ,
2019-11-25 17:10:18 +00:00
{ "pkg.SomeConst" , false , "2" , "" , "int" , nil } ,
2017-09-08 10:31:20 +00:00
}
ver , _ := goversion . Parse ( runtime . Version ( ) )
2020-03-18 16:25:32 +00:00
if ver . Major > 0 && ! ver . AfterOrEqual ( goversion . GoVersion { Major : 1 , Minor : 10 , Rev : - 1 } ) {
2017-09-08 10:31:20 +00:00
// Not supported on 1.9 or earlier
2017-10-13 20:13:43 +00:00
t . Skip ( "constants added in go 1.10" )
2017-09-08 10:31:20 +00:00
}
2020-01-21 20:41:24 +00:00
withTestProcess ( "consts" , t , func ( p * proc . Target , fixture protest . Fixture ) {
2020-03-24 16:16:58 +00:00
assertNoError ( p . Continue ( ) , t , "Continue" )
2017-09-08 10:31:20 +00:00
for _ , testcase := range testcases {
variable , err := evalVariable ( p , testcase . name , pnormalLoadConfig )
assertNoError ( err , t , fmt . Sprintf ( "EvalVariable(%s)" , testcase . name ) )
assertVariable ( t , variable , testcase )
}
} )
}
2018-01-19 14:50:28 +00:00
2020-01-21 20:41:24 +00:00
func setFunctionBreakpoint ( p * proc . Target , t testing . TB , fname string ) * proc . Breakpoint {
2019-08-14 15:57:05 +00:00
_ , f , l , _ := runtime . Caller ( 1 )
f = filepath . Base ( f )
2019-11-01 19:41:06 +00:00
addrs , err := proc . FindFunctionLocation ( p , fname , 0 )
2018-01-19 14:50:28 +00:00
if err != nil {
2019-08-14 15:57:05 +00:00
t . Fatalf ( "%s:%d: FindFunctionLocation(%s): %v" , f , l , fname , err )
2018-01-19 14:50:28 +00:00
}
2019-11-01 19:41:06 +00:00
if len ( addrs ) != 1 {
t . Fatalf ( "%s:%d: setFunctionBreakpoint(%s): too many results %v" , f , l , fname , addrs )
}
2022-02-25 09:09:53 +00:00
bp , err := p . SetBreakpoint ( int ( addrs [ 0 ] ) , addrs [ 0 ] , proc . UserBreakpoint , nil )
2019-08-14 15:57:05 +00:00
if err != nil {
t . Fatalf ( "%s:%d: FindFunctionLocation(%s): %v" , f , l , fname , err )
}
return bp
2018-01-19 14:50:28 +00:00
}
func TestIssue1075 ( t * testing . T ) {
2020-01-21 20:41:24 +00:00
withTestProcess ( "clientdo" , t , func ( p * proc . Target , fixture protest . Fixture ) {
2019-08-14 15:57:05 +00:00
setFunctionBreakpoint ( p , t , "net/http.(*Client).Do" )
2020-03-24 16:16:58 +00:00
assertNoError ( p . Continue ( ) , t , "Continue()" )
2018-01-19 14:50:28 +00:00
for i := 0 ; i < 10 ; i ++ {
2021-07-02 16:37:55 +00:00
scope , err := proc . GoroutineScope ( p , p . CurrentThread ( ) )
2018-01-19 14:50:28 +00:00
assertNoError ( err , t , fmt . Sprintf ( "GoroutineScope (%d)" , i ) )
vars , err := scope . LocalVariables ( pnormalLoadConfig )
assertNoError ( err , t , fmt . Sprintf ( "LocalVariables (%d)" , i ) )
for _ , v := range vars {
api . ConvertVar ( v ) . SinglelineString ( )
}
}
} )
}
2018-07-28 19:12:07 +00:00
2019-05-30 15:08:37 +00:00
type testCaseCallFunction struct {
expr string // call expression to evaluate
outs [ ] string // list of return parameters in this format: <param name>:<param type>:<param value>
err error // if not nil should return an error
}
2018-07-28 19:12:07 +00:00
func TestCallFunction ( t * testing . T ) {
protest . MustSupportFunctionCalls ( t , testBackend )
2021-10-14 18:06:14 +00:00
protest . AllowRecording ( t )
2018-07-28 19:12:07 +00:00
2019-05-30 15:08:37 +00:00
var testcases = [ ] testCaseCallFunction {
2019-05-09 15:29:58 +00:00
// Basic function call injection tests
2018-07-28 19:12:07 +00:00
{ "call1(one, two)" , [ ] string { ":int:3" } , nil } ,
{ "call1(one+two, 4)" , [ ] string { ":int:7" } , nil } ,
{ "callpanic()" , [ ] string { ` ~panic:interface { }:interface { }(string) "callpanic panicked" ` } , nil } ,
{ ` stringsJoin(nil, "") ` , [ ] string { ` :string:"" ` } , nil } ,
{ ` stringsJoin(stringslice, comma) ` , [ ] string { ` :string:"one,two,three" ` } , nil } ,
2019-09-25 17:23:02 +00:00
{ ` stringsJoin(s1, comma) ` , nil , errors . New ( ` error evaluating "s1" as argument v in function main.stringsJoin: could not find symbol value for s1 ` ) } ,
2018-07-28 19:12:07 +00:00
{ ` stringsJoin(intslice, comma) ` , nil , errors . New ( "can not convert value of type []int to []string" ) } ,
2019-06-17 16:51:29 +00:00
{ ` noreturncall(2) ` , nil , nil } ,
2018-07-31 12:50:10 +00:00
2019-05-09 15:29:58 +00:00
// Expression tests
{ ` square(2) + 1 ` , [ ] string { ":int:5" } , nil } ,
{ ` intcallpanic(1) + 1 ` , [ ] string { ":int:2" } , nil } ,
{ ` intcallpanic(0) + 1 ` , [ ] string { ` ~panic:interface { }:interface { }(string) "panic requested" ` } , nil } ,
{ ` onetwothree(5)[1] + 2 ` , [ ] string { ":int:9" } , nil } ,
// Call types tests (methods, function pointers, etc.)
2018-07-31 12:50:10 +00:00
// The following set of calls was constructed using https://docs.google.com/document/d/1bMwCey-gmqZVTpRax-ESeVuZGmjwbocYs1iHplK-cjo/pub as a reference
2018-08-18 08:53:21 +00:00
{ ` a.VRcvr(1) ` , [ ] string { ` :string:"1 + 3 = 4" ` } , nil } , // direct call of a method with value receiver / on a value
2018-07-31 12:50:10 +00:00
{ ` a.PRcvr(2) ` , [ ] string { ` :string:"2 - 3 = -1" ` } , nil } , // direct call of a method with pointer receiver / on a value
{ ` pa.VRcvr(3) ` , [ ] string { ` :string:"3 + 6 = 9" ` } , nil } , // direct call of a method with value receiver / on a pointer
{ ` pa.PRcvr(4) ` , [ ] string { ` :string:"4 - 6 = -2" ` } , nil } , // direct call of a method with pointer receiver / on a pointer
{ ` vable_pa.VRcvr(6) ` , [ ] string { ` :string:"6 + 6 = 12" ` } , nil } , // indirect call of method on interface / containing value with value method
{ ` pable_pa.PRcvr(7) ` , [ ] string { ` :string:"7 - 6 = 1" ` } , nil } , // indirect call of method on interface / containing pointer with value method
{ ` vable_a.VRcvr(5) ` , [ ] string { ` :string:"5 + 3 = 8" ` } , nil } , // indirect call of method on interface / containing pointer with pointer method
{ ` pa.nonexistent() ` , nil , errors . New ( "pa has no member nonexistent" ) } ,
{ ` a.nonexistent() ` , nil , errors . New ( "a has no member nonexistent" ) } ,
{ ` vable_pa.nonexistent() ` , nil , errors . New ( "vable_pa has no member nonexistent" ) } ,
{ ` vable_a.nonexistent() ` , nil , errors . New ( "vable_a has no member nonexistent" ) } ,
{ ` pable_pa.nonexistent() ` , nil , errors . New ( "pable_pa has no member nonexistent" ) } ,
2018-07-31 16:32:30 +00:00
{ ` fn2glob(10, 20) ` , [ ] string { ":int:30" } , nil } , // indirect call of func value / set to top-level func
{ ` fn2clos(11) ` , [ ] string { ` :string:"1 + 6 + 11 = 18" ` } , nil } , // indirect call of func value / set to func literal
{ ` fn2clos(12) ` , [ ] string { ` :string:"2 + 6 + 12 = 20" ` } , nil } ,
{ ` fn2valmeth(13) ` , [ ] string { ` :string:"13 + 6 = 19" ` } , nil } , // indirect call of func value / set to value method
{ ` fn2ptrmeth(14) ` , [ ] string { ` :string:"14 - 6 = 8" ` } , nil } , // indirect call of func value / set to pointer method
{ "fn2nil()" , nil , errors . New ( "nil pointer dereference" ) } ,
2018-08-17 06:17:22 +00:00
{ "ga.PRcvr(2)" , [ ] string { ` :string:"2 - 0 = 2" ` } , nil } ,
2018-08-18 08:53:21 +00:00
2020-02-18 22:19:06 +00:00
{ "x.CallMe()" , nil , nil } ,
{ "x2.CallMe(5)" , [ ] string { ":int:25" } , nil } ,
2020-03-18 16:26:24 +00:00
{ "\"delve\".CallMe()" , nil , errors . New ( "\"delve\" (type string) is not a struct" ) } ,
2019-06-17 16:51:29 +00:00
// Nested function calls tests
2019-05-30 15:08:37 +00:00
{ ` onetwothree(intcallpanic(2)) ` , [ ] string { ` :[]int:[]int len: 3, cap: 3, [3,4,5] ` } , nil } ,
{ ` onetwothree(intcallpanic(0)) ` , [ ] string { ` ~panic:interface { }:interface { }(string) "panic requested" ` } , nil } ,
{ ` onetwothree(intcallpanic(2)+1) ` , [ ] string { ` :[]int:[]int len: 3, cap: 3, [4,5,6] ` } , nil } ,
2022-02-22 17:55:59 +00:00
{ ` onetwothree(intcallpanic("not a number")) ` , nil , errors . New ( "error evaluating \"intcallpanic(\\\"not a number\\\")\" as argument n in function main.onetwothree: can not convert \"not a number\" constant to int" ) } ,
2019-05-30 15:08:37 +00:00
2019-06-17 16:51:29 +00:00
// Variable setting tests
{ ` pa2 = getAStructPtr(8); pa2 ` , [ ] string { ` pa2:*main.astruct:*main.astruct { X: 8} ` } , nil } ,
2019-05-09 15:29:58 +00:00
// Escape tests
2018-08-18 08:53:21 +00:00
{ "escapeArg(&a2)" , nil , errors . New ( "cannot use &a2 as argument pa2 in function main.escapeArg: stack object passed to escaping pointer: pa2" ) } ,
2019-06-30 17:44:30 +00:00
// Issue 1577
{ "1+2" , [ ] string { ` ::3 ` } , nil } ,
{ ` "de"+"mo" ` , [ ] string { ` ::"demo" ` } , nil } ,
2018-07-28 19:12:07 +00:00
}
2019-06-17 16:51:29 +00:00
var testcases112 = [ ] testCaseCallFunction {
// string allocation requires trusted argument order, which we don't have in Go 1.11
{ ` stringsJoin(stringslice, ",") ` , [ ] string { ` :string:"one,two,three" ` } , nil } ,
{ ` str = "a new string"; str ` , [ ] string { ` str:string:"a new string" ` } , nil } ,
2019-09-25 17:23:02 +00:00
// support calling optimized functions
{ ` strings.Join(nil, "") ` , [ ] string { ` :string:"" ` } , nil } ,
{ ` strings.Join(stringslice, comma) ` , [ ] string { ` :string:"one,two,three" ` } , nil } ,
{ ` strings.Join(intslice, comma) ` , nil , errors . New ( "can not convert value of type []int to []string" ) } ,
{ ` strings.Join(stringslice, ",") ` , [ ] string { ` :string:"one,two,three" ` } , nil } ,
{ ` strings.LastIndexByte(stringslice[1], 'w') ` , [ ] string { ":int:1" } , nil } ,
{ ` strings.LastIndexByte(stringslice[1], 'o') ` , [ ] string { ":int:2" } , nil } ,
2019-10-26 15:15:33 +00:00
{ ` d.Base.Method() ` , [ ] string { ` :int:4 ` } , nil } ,
{ ` d.Method() ` , [ ] string { ` :int:4 ` } , nil } ,
2019-06-17 16:51:29 +00:00
}
2019-05-30 15:08:37 +00:00
var testcases113 = [ ] testCaseCallFunction {
{ ` curriedAdd(2)(3) ` , [ ] string { ` :int:5 ` } , nil } ,
// Method calls on a value returned by a function
{ ` getAStruct(3).VRcvr(1) ` , [ ] string { ` :string:"1 + 3 = 4" ` } , nil } , // direct call of a method with value receiver / on a value
{ ` getAStruct(3).PRcvr(2) ` , nil , errors . New ( "cannot use getAStruct(3).PRcvr as argument pa in function main.(*astruct).PRcvr: stack object passed to escaping pointer: pa" ) } , // direct call of a method with pointer receiver / on a value
{ ` getAStructPtr(6).VRcvr(3) ` , [ ] string { ` :string:"3 + 6 = 9" ` } , nil } , // direct call of a method with value receiver / on a pointer
{ ` getAStructPtr(6).PRcvr(4) ` , [ ] string { ` :string:"4 - 6 = -2" ` } , nil } , // direct call of a method with pointer receiver / on a pointer
{ ` getVRcvrableFromAStruct(3).VRcvr(6) ` , [ ] string { ` :string:"6 + 3 = 9" ` } , nil } , // indirect call of method on interface / containing value with value method
{ ` getPRcvrableFromAStructPtr(6).PRcvr(7) ` , [ ] string { ` :string:"7 - 6 = 1" ` } , nil } , // indirect call of method on interface / containing pointer with value method
{ ` getVRcvrableFromAStructPtr(6).VRcvr(5) ` , [ ] string { ` :string:"5 + 6 = 11" ` } , nil } , // indirect call of method on interface / containing pointer with pointer method
}
2018-08-18 08:53:21 +00:00
2020-02-11 01:31:54 +00:00
var testcasesBefore114After112 = [ ] testCaseCallFunction {
{ ` strings.Join(s1, comma) ` , nil , errors . New ( ` error evaluating "s1" as argument a in function strings.Join: could not find symbol value for s1 ` ) } ,
}
var testcases114 = [ ] testCaseCallFunction {
{ ` strings.Join(s1, comma) ` , nil , errors . New ( ` error evaluating "s1" as argument elems in function strings.Join: could not find symbol value for s1 ` ) } ,
}
2021-07-08 15:47:53 +00:00
var testcases117 = [ ] testCaseCallFunction {
{ ` regabistacktest("one", "two", "three", "four", "five", 4) ` , [ ] string { ` :string:"onetwo" ` , ` :string:"twothree" ` , ` :string:"threefour" ` , ` :string:"fourfive" ` , ` :string:"fiveone" ` , ":uint8:8" } , nil } ,
{ ` regabistacktest2(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) ` , [ ] string { ":int:3" , ":int:5" , ":int:7" , ":int:9" , ":int:11" , ":int:13" , ":int:15" , ":int:17" , ":int:19" , ":int:11" } , nil } ,
2021-09-24 22:27:44 +00:00
{ ` issue2698.String() ` , [ ] string { ` :string:"1 2 3 4" ` } , nil } ,
2021-07-08 15:47:53 +00:00
}
2020-12-10 17:03:11 +00:00
2021-07-08 15:47:53 +00:00
withTestProcessArgs ( "fncall" , t , "." , nil , protest . AllNonOptimized , func ( p * proc . Target , fixture protest . Fixture ) {
2020-12-10 17:03:11 +00:00
testCallFunctionSetBreakpoint ( t , p , fixture )
2020-03-24 16:16:58 +00:00
assertNoError ( p . Continue ( ) , t , "Continue()" )
2018-07-28 19:12:07 +00:00
for _ , tc := range testcases {
2019-05-30 15:08:37 +00:00
testCallFunction ( t , p , tc )
}
2018-07-28 19:12:07 +00:00
2019-06-17 16:51:29 +00:00
if goversion . VersionAfterOrEqual ( runtime . Version ( ) , 1 , 12 ) {
for _ , tc := range testcases112 {
testCallFunction ( t , p , tc )
}
2020-02-11 01:31:54 +00:00
if ! goversion . VersionAfterOrEqual ( runtime . Version ( ) , 1 , 14 ) {
for _ , tc := range testcasesBefore114After112 {
testCallFunction ( t , p , tc )
}
}
2019-06-17 16:51:29 +00:00
}
2019-05-30 15:08:37 +00:00
if goversion . VersionAfterOrEqual ( runtime . Version ( ) , 1 , 13 ) {
for _ , tc := range testcases113 {
testCallFunction ( t , p , tc )
2018-07-28 19:12:07 +00:00
}
2019-05-30 15:08:37 +00:00
}
2018-07-28 19:12:07 +00:00
2020-02-11 01:31:54 +00:00
if goversion . VersionAfterOrEqual ( runtime . Version ( ) , 1 , 14 ) {
for _ , tc := range testcases114 {
testCallFunction ( t , p , tc )
}
}
2021-07-08 15:47:53 +00:00
if goversion . VersionAfterOrEqual ( runtime . Version ( ) , 1 , 17 ) {
for _ , tc := range testcases117 {
testCallFunction ( t , p , tc )
}
}
2019-05-30 15:08:37 +00:00
// LEAVE THIS AS THE LAST ITEM, IT BREAKS THE TARGET PROCESS!!!
testCallFunction ( t , p , testCaseCallFunction { "-unsafe escapeArg(&a2)" , nil , nil } )
} )
}
2018-07-31 16:32:30 +00:00
2020-12-10 17:03:11 +00:00
func testCallFunctionSetBreakpoint ( t * testing . T , p * proc . Target , fixture protest . Fixture ) {
buf , err := ioutil . ReadFile ( fixture . Source )
assertNoError ( err , t , "ReadFile" )
for i , line := range strings . Split ( string ( buf ) , "\n" ) {
if strings . Contains ( line , "// breakpoint here" ) {
setFileBreakpoint ( p , t , fixture , i + 1 )
return
}
}
}
2020-01-21 20:41:24 +00:00
func testCallFunction ( t * testing . T , p * proc . Target , tc testCaseCallFunction ) {
2019-05-30 15:08:37 +00:00
const unsafePrefix = "-unsafe "
2018-07-31 16:32:30 +00:00
2019-06-17 16:51:29 +00:00
var callExpr , varExpr string
if semicolon := strings . Index ( tc . expr , ";" ) ; semicolon >= 0 {
callExpr = tc . expr [ : semicolon ]
varExpr = tc . expr [ semicolon + 1 : ]
} else {
callExpr = tc . expr
}
2019-05-30 15:08:37 +00:00
checkEscape := true
2019-06-17 16:51:29 +00:00
if strings . HasPrefix ( callExpr , unsafePrefix ) {
callExpr = callExpr [ len ( unsafePrefix ) : ]
2019-05-30 15:08:37 +00:00
checkEscape = false
}
t . Logf ( "call %q" , tc . expr )
2019-06-30 17:44:30 +00:00
err := proc . EvalExpressionWithCalls ( p , p . SelectedGoroutine ( ) , callExpr , pnormalLoadConfig , checkEscape )
2019-05-30 15:08:37 +00:00
if tc . err != nil {
t . Logf ( "\terr = %v\n" , err )
if err == nil {
t . Fatalf ( "call %q: expected error %q, got no error" , tc . expr , tc . err . Error ( ) )
}
if tc . err . Error ( ) != err . Error ( ) {
t . Fatalf ( "call %q: expected error %q, got %q" , tc . expr , tc . err . Error ( ) , err . Error ( ) )
}
return
}
2018-07-28 19:12:07 +00:00
2019-05-30 15:08:37 +00:00
if err != nil {
t . Fatalf ( "call %q: error %q" , tc . expr , err . Error ( ) )
}
2018-07-28 19:12:07 +00:00
2019-05-30 15:08:37 +00:00
retvalsVar := p . CurrentThread ( ) . Common ( ) . ReturnValues ( pnormalLoadConfig )
retvals := make ( [ ] * api . Variable , len ( retvalsVar ) )
2018-07-28 19:12:07 +00:00
2019-05-30 15:08:37 +00:00
for i := range retvals {
retvals [ i ] = api . ConvertVar ( retvalsVar [ i ] )
}
2018-07-28 19:12:07 +00:00
2019-06-17 16:51:29 +00:00
if varExpr != "" {
2021-07-02 16:37:55 +00:00
scope , err := proc . GoroutineScope ( p , p . CurrentThread ( ) )
2019-06-17 16:51:29 +00:00
assertNoError ( err , t , "GoroutineScope" )
v , err := scope . EvalExpression ( varExpr , pnormalLoadConfig )
assertNoError ( err , t , fmt . Sprintf ( "EvalExpression(%s)" , varExpr ) )
retvals = append ( retvals , api . ConvertVar ( v ) )
}
2019-05-30 15:08:37 +00:00
for i := range retvals {
t . Logf ( "\t%s = %s" , retvals [ i ] . Name , retvals [ i ] . SinglelineString ( ) )
}
if len ( retvals ) != len ( tc . outs ) {
2021-10-14 18:06:14 +00:00
t . Fatalf ( "call %q: wrong number of return parameters (%#v)" , tc . expr , retvals )
2019-05-30 15:08:37 +00:00
}
for i := range retvals {
outfields := strings . SplitN ( tc . outs [ i ] , ":" , 3 )
tgtName , tgtType , tgtValue := outfields [ 0 ] , outfields [ 1 ] , outfields [ 2 ]
if tgtName != "" && tgtName != retvals [ i ] . Name {
t . Fatalf ( "call %q output parameter %d: expected name %q, got %q" , tc . expr , i , tgtName , retvals [ i ] . Name )
2018-07-28 19:12:07 +00:00
}
2019-05-30 15:08:37 +00:00
if retvals [ i ] . Type != tgtType {
t . Fatalf ( "call %q, output parameter %d: expected type %q, got %q" , tc . expr , i , tgtType , retvals [ i ] . Type )
}
if cvs := retvals [ i ] . SinglelineString ( ) ; cvs != tgtValue {
t . Fatalf ( "call %q, output parameter %d: expected value %q, got %q" , tc . expr , i , tgtValue , cvs )
}
}
2018-07-28 19:12:07 +00:00
}
2019-04-26 17:23:43 +00:00
func TestIssue1531 ( t * testing . T ) {
// Go 1.12 introduced a change to the map representation where empty cells can be marked with 1 instead of just 0.
2020-01-21 20:41:24 +00:00
withTestProcess ( "issue1531" , t , func ( p * proc . Target , fixture protest . Fixture ) {
2020-03-24 16:16:58 +00:00
assertNoError ( p . Continue ( ) , t , "Continue()" )
2019-04-26 17:23:43 +00:00
hasKeys := func ( mv * proc . Variable , keys ... string ) {
n := 0
for i := 0 ; i < len ( mv . Children ) ; i += 2 {
cv := & mv . Children [ i ]
s := constant . StringVal ( cv . Value )
found := false
for j := range keys {
if keys [ j ] == s {
found = true
break
}
}
if ! found {
t . Errorf ( "key %q not allowed" , s )
return
}
n ++
}
if n != len ( keys ) {
t . Fatalf ( "wrong number of keys found" )
}
}
mv , err := evalVariable ( p , "m" , pnormalLoadConfig )
assertNoError ( err , t , "EvalVariable(m)" )
cmv := api . ConvertVar ( mv )
t . Logf ( "m = %s" , cmv . SinglelineString ( ) )
hasKeys ( mv , "s" , "r" , "v" )
mmv , err := evalVariable ( p , "mm" , pnormalLoadConfig )
assertNoError ( err , t , "EvalVariable(mm)" )
cmmv := api . ConvertVar ( mmv )
t . Logf ( "mm = %s" , cmmv . SinglelineString ( ) )
hasKeys ( mmv , "r" , "t" , "v" )
} )
}
2019-05-08 21:06:38 +00:00
2020-01-21 20:41:24 +00:00
func setFileBreakpoint ( p * proc . Target , t * testing . T , fixture protest . Fixture , lineno int ) * proc . Breakpoint {
2019-08-14 15:57:05 +00:00
_ , f , l , _ := runtime . Caller ( 1 )
f = filepath . Base ( f )
2019-11-01 19:41:06 +00:00
addrs , err := proc . FindFileLocation ( p , fixture . Source , lineno )
2019-05-08 21:06:38 +00:00
if err != nil {
2019-08-14 15:57:05 +00:00
t . Fatalf ( "%s:%d: FindFileLocation(%s, %d): %v" , f , l , fixture . Source , lineno , err )
2019-05-08 21:06:38 +00:00
}
2019-11-01 19:41:06 +00:00
if len ( addrs ) != 1 {
t . Fatalf ( "%s:%d: setFileLineBreakpoint(%s, %d): too many results %v" , f , l , fixture . Source , lineno , addrs )
}
2022-02-25 09:09:53 +00:00
bp , err := p . SetBreakpoint ( int ( addrs [ 0 ] ) , addrs [ 0 ] , proc . UserBreakpoint , nil )
2019-05-08 21:06:38 +00:00
if err != nil {
2019-08-14 15:57:05 +00:00
t . Fatalf ( "%s:%d: SetBreakpoint: %v" , f , l , err )
2019-05-08 21:06:38 +00:00
}
return bp
}
2020-01-21 20:41:24 +00:00
func currentLocation ( p * proc . Target , t * testing . T ) ( pc uint64 , f string , ln int , fn * proc . Function ) {
2020-05-13 18:56:50 +00:00
regs , err := p . CurrentThread ( ) . Registers ( )
2019-05-08 21:06:38 +00:00
if err != nil {
t . Fatalf ( "Registers error: %v" , err )
}
f , l , fn := p . BinInfo ( ) . PCToLine ( regs . PC ( ) )
t . Logf ( "at %#x %s:%d %v" , regs . PC ( ) , f , l , fn )
return regs . PC ( ) , f , l , fn
}
2020-01-21 20:41:24 +00:00
func assertCurrentLocationFunction ( p * proc . Target , t * testing . T , fnname string ) {
2019-05-08 21:06:38 +00:00
_ , _ , _ , fn := currentLocation ( p , t )
if fn == nil {
t . Fatalf ( "Not in a function" )
}
if fn . Name != fnname {
t . Fatalf ( "Wrong function %s %s" , fn . Name , fnname )
}
}
func TestPluginVariables ( t * testing . T ) {
2019-06-30 17:34:47 +00:00
pluginFixtures := protest . WithPlugins ( t , protest . AllNonOptimized , "plugin1/" , "plugin2/" )
2019-05-08 21:06:38 +00:00
2020-01-21 20:41:24 +00:00
withTestProcessArgs ( "plugintest2" , t , "." , [ ] string { pluginFixtures [ 0 ] . Path , pluginFixtures [ 1 ] . Path } , protest . AllNonOptimized , func ( p * proc . Target , fixture protest . Fixture ) {
2019-08-14 15:57:05 +00:00
setFileBreakpoint ( p , t , fixture , 41 )
2020-03-24 16:16:58 +00:00
assertNoError ( p . Continue ( ) , t , "Continue 1" )
2019-05-08 21:06:38 +00:00
2019-08-14 15:57:05 +00:00
bp := setFunctionBreakpoint ( p , t , "github.com/go-delve/delve/_fixtures/plugin2.TypesTest" )
2019-05-08 21:06:38 +00:00
t . Logf ( "bp.Addr = %#x" , bp . Addr )
2019-08-14 15:57:05 +00:00
setFunctionBreakpoint ( p , t , "github.com/go-delve/delve/_fixtures/plugin2.aIsNotNil" )
2019-05-08 21:06:38 +00:00
for _ , image := range p . BinInfo ( ) . Images {
t . Logf ( "%#x %s\n" , image . StaticBase , image . Path )
}
2020-03-24 16:16:58 +00:00
assertNoError ( p . Continue ( ) , t , "Continue 2" )
2019-05-08 21:06:38 +00:00
// test that PackageVariables returns variables from the executable and plugins
scope , err := evalScope ( p )
assertNoError ( err , t , "evalScope" )
allvars , err := scope . PackageVariables ( pnormalLoadConfig )
assertNoError ( err , t , "PackageVariables" )
var plugin2AFound , mainExeGlobalFound bool
for _ , v := range allvars {
switch v . Name {
case "github.com/go-delve/delve/_fixtures/plugin2.A" :
plugin2AFound = true
case "main.ExeGlobal" :
mainExeGlobalFound = true
}
}
if ! plugin2AFound {
t . Fatalf ( "variable plugin2.A not found in the output of PackageVariables" )
}
if ! mainExeGlobalFound {
t . Fatalf ( "variable main.ExeGlobal not found in the output of PackageVariables" )
}
// read interface variable, inside plugin code, with a concrete type defined in the executable
vs , err := evalVariable ( p , "s" , pnormalLoadConfig )
assertNoError ( err , t , "Eval(s)" )
assertVariable ( t , vs , varTest { "s" , true , ` github.com/go-delve/delve/_fixtures/internal/pluginsupport.Something(*main.asomething) * { n: 2} ` , ` ` , ` github.com/go-delve/delve/_fixtures/internal/pluginsupport.Something ` , nil } )
// test that the concrete type -> interface{} conversion works across plugins (mostly tests proc.dwarfToRuntimeType)
assertNoError ( setVariable ( p , "plugin2.A" , "main.ExeGlobal" ) , t , "setVariable(plugin2.A = main.ExeGlobal)" )
2020-03-24 16:16:58 +00:00
assertNoError ( p . Continue ( ) , t , "Continue 3" )
2019-05-08 21:06:38 +00:00
assertCurrentLocationFunction ( p , t , "github.com/go-delve/delve/_fixtures/plugin2.aIsNotNil" )
vstr , err := evalVariable ( p , "str" , pnormalLoadConfig )
assertNoError ( err , t , "Eval(str)" )
assertVariable ( t , vstr , varTest { "str" , true , ` "success" ` , ` ` , ` string ` , nil } )
2020-03-24 16:16:58 +00:00
assertNoError ( p . StepOut ( ) , t , "StepOut" )
assertNoError ( p . StepOut ( ) , t , "StepOut" )
assertNoError ( p . Next ( ) , t , "Next" )
2019-05-08 21:06:38 +00:00
// read interface variable, inside executable code, with a concrete type defined in a plugin
vb , err := evalVariable ( p , "b" , pnormalLoadConfig )
assertNoError ( err , t , "Eval(b)" )
assertVariable ( t , vb , varTest { "b" , true , ` github.com/go-delve/delve/_fixtures/internal/pluginsupport.SomethingElse(*github.com/go-delve/delve/_fixtures/plugin2.asomethingelse) * { x: 1, y: 4} ` , ` ` , ` github.com/go-delve/delve/_fixtures/internal/pluginsupport.SomethingElse ` , nil } )
} )
}
2020-06-05 18:22:40 +00:00
func TestCgoEval ( t * testing . T ) {
2021-01-29 21:39:33 +00:00
protest . MustHaveCgo ( t )
2020-06-05 18:22:40 +00:00
testcases := [ ] varTest {
{ "s" , true , ` "a string" ` , ` "a string" ` , "*char" , nil } ,
{ "longstring" , true , ` "averylongstring0123456789a0123456789b0123456789c0123456789d01234...+1 more" ` , ` "averylongstring0123456789a0123456789b0123456789c0123456789d01234...+1 more" ` , "*const char" , nil } ,
{ "longstring[64:]" , false , ` "56789e0123456789f0123456789g0123456789h0123456789" ` , ` "56789e0123456789f0123456789g0123456789h0123456789" ` , "*const char" , nil } ,
{ "s[3]" , false , "116" , "116" , "char" , nil } ,
{ "v" , true , "*0" , "(*int)(…" , "*int" , nil } ,
{ "v[1]" , false , "1" , "1" , "int" , nil } ,
{ "v[90]" , false , "90" , "90" , "int" , nil } ,
{ "v[:5]" , false , "[]int len: 5, cap: 5, [0,1,2,3,4]" , "[]int len: 5, cap: 5, [...]" , "[]int" , nil } ,
{ "v_align_check" , true , "*align_check {a: 0, b: 0}" , "(*struct align_check)(…" , "*struct align_check" , nil } ,
{ "v_align_check[1]" , false , "align_check {a: 1, b: 1}" , "align_check {a: 1, b: 1}" , "align_check" , nil } ,
{ "v_align_check[90]" , false , "align_check {a: 90, b: 90}" , "align_check {a: 90, b: 90}" , "align_check" , nil } ,
}
2021-03-08 17:35:56 +00:00
if runtime . GOOS == "darwin" && runtime . GOARCH == "arm64" {
t . Skip ( "cgo doesn't work on darwin/arm64" )
}
2020-06-05 18:22:40 +00:00
protest . AllowRecording ( t )
withTestProcess ( "testvariablescgo/" , t , func ( p * proc . Target , fixture protest . Fixture ) {
assertNoError ( p . Continue ( ) , t , "Continue() returned an error" )
for _ , tc := range testcases {
variable , err := evalVariable ( p , tc . name , pnormalLoadConfig )
if err != nil && err . Error ( ) == "evaluating methods not supported on this version of Go" {
// this type of eval is unsupported with the current version of Go.
continue
}
if tc . err == nil {
assertNoError ( err , t , fmt . Sprintf ( "EvalExpression(%s) returned an error" , tc . name ) )
assertVariable ( t , variable , tc )
variable , err := evalVariable ( p , tc . name , pshortLoadConfig )
assertNoError ( err , t , fmt . Sprintf ( "EvalExpression(%s, pshortLoadConfig) returned an error" , tc . name ) )
assertVariable ( t , variable , tc . alternateVarTest ( ) )
} else {
if err == nil {
t . Fatalf ( "Expected error %s, got no error (%s)" , tc . err . Error ( ) , tc . name )
}
if tc . err . Error ( ) != err . Error ( ) {
t . Fatalf ( "Unexpected error. Expected %s got %s" , tc . err . Error ( ) , err . Error ( ) )
}
}
2021-09-16 19:26:36 +00:00
}
} )
}
func TestEvalExpressionGenerics ( t * testing . T ) {
if ! goversion . VersionAfterOrEqual ( runtime . Version ( ) , 1 , 18 ) {
t . Skip ( "generics not supported" )
}
testcases := [ ] [ ] varTest {
// testfn[int, float32]
[ ] varTest {
{ "arg1" , true , "3" , "" , "int" , nil } ,
{ "arg2" , true , "2.1" , "" , "float32" , nil } ,
{ "m" , true , "map[float32]int [2.1: 3, ]" , "" , "map[float32]int" , nil } ,
} ,
// testfn[*astruct, astruct]
[ ] varTest {
{ "arg1" , true , "*main.astruct {x: 0, y: 1}" , "" , "*main.astruct" , nil } ,
{ "arg2" , true , "main.astruct {x: 2, y: 3}" , "" , "main.astruct" , nil } ,
{ "m" , true , "map[main.astruct]*main.astruct [{x: 2, y: 3}: *{x: 0, y: 1}, ]" , "" , "map[main.astruct]*main.astruct" , nil } ,
} ,
}
2020-06-05 18:22:40 +00:00
2021-09-16 19:26:36 +00:00
withTestProcess ( "testvariables_generic" , t , func ( p * proc . Target , fixture protest . Fixture ) {
for i , tcs := range testcases {
assertNoError ( p . Continue ( ) , t , fmt . Sprintf ( "Continue() returned an error (%d)" , i ) )
for _ , tc := range tcs {
variable , err := evalVariable ( p , tc . name , pnormalLoadConfig )
if tc . err == nil {
assertNoError ( err , t , fmt . Sprintf ( "EvalExpression(%s) returned an error" , tc . name ) )
assertVariable ( t , variable , tc )
} else {
if err == nil {
t . Fatalf ( "Expected error %s, got no error (%s)" , tc . err . Error ( ) , tc . name )
}
if tc . err . Error ( ) != err . Error ( ) {
t . Fatalf ( "Unexpected error. Expected %s got %s" , tc . err . Error ( ) , err . Error ( ) )
}
}
}
2020-06-05 18:22:40 +00:00
}
} )
}