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"
|
2016-09-06 17:26:56 +00:00
|
|
|
"runtime"
|
2015-10-18 17:37:13 +00:00
|
|
|
"sort"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
|
2017-05-04 10:22:08 +00:00
|
|
|
"github.com/derekparker/delve/pkg/goversion"
|
2017-02-08 16:00:44 +00:00
|
|
|
"github.com/derekparker/delve/pkg/proc"
|
2017-04-21 06:55:53 +00:00
|
|
|
"github.com/derekparker/delve/pkg/proc/gdbserial"
|
|
|
|
"github.com/derekparker/delve/pkg/proc/native"
|
2017-04-19 02:56:20 +00:00
|
|
|
"github.com/derekparker/delve/service/api"
|
2015-10-18 17:37:13 +00:00
|
|
|
|
2017-02-08 16:00:44 +00:00
|
|
|
protest "github.com/derekparker/delve/pkg/proc/test"
|
2015-10-18 17:37:13 +00:00
|
|
|
)
|
|
|
|
|
2016-04-24 17:15:39 +00:00
|
|
|
var pnormalLoadConfig = proc.LoadConfig{true, 1, 64, 64, -1}
|
|
|
|
var pshortLoadConfig = proc.LoadConfig{false, 0, 64, 0, 3}
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-05 22:17:52 +00:00
|
|
|
func findFirstNonRuntimeFrame(p proc.Process) (proc.Stackframe, error) {
|
|
|
|
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")
|
|
|
|
}
|
|
|
|
|
|
|
|
func evalVariable(p proc.Process, symbol string, cfg proc.LoadConfig) (*proc.Variable, error) {
|
|
|
|
var scope *proc.EvalScope
|
|
|
|
var err error
|
|
|
|
|
|
|
|
if testBackend == "rr" {
|
|
|
|
var frame proc.Stackframe
|
|
|
|
frame, err = findFirstNonRuntimeFrame(p)
|
|
|
|
if err == nil {
|
2018-02-13 17:20:45 +00:00
|
|
|
scope = proc.FrameToScope(p.BinInfo(), p.CurrentThread(), nil, frame)
|
2017-05-05 22:17:52 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
scope, err = proc.GoroutineScope(p.CurrentThread())
|
|
|
|
}
|
|
|
|
|
2017-06-29 18:15:59 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2016-04-24 17:15:39 +00:00
|
|
|
return scope.EvalVariable(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
|
|
|
|
}
|
|
|
|
|
2017-04-21 07:50:38 +00:00
|
|
|
func setVariable(p proc.Process, symbol, value string) error {
|
2017-02-15 13:41:03 +00:00
|
|
|
scope, err := proc.GoroutineScope(p.CurrentThread())
|
2015-10-18 17:37:13 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return scope.SetVariable(symbol, value)
|
|
|
|
}
|
|
|
|
|
2017-04-21 07:50:38 +00:00
|
|
|
func withTestProcess(name string, t *testing.T, fn func(p proc.Process, fixture protest.Fixture)) {
|
2018-05-29 15:01:51 +00:00
|
|
|
var buildFlags protest.BuildFlags
|
|
|
|
if buildMode == "pie" {
|
|
|
|
buildFlags = protest.BuildModePIE
|
|
|
|
}
|
|
|
|
fixture := protest.BuildFixture(name, buildFlags)
|
2017-04-21 07:50:38 +00:00
|
|
|
var p proc.Process
|
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":
|
2018-04-16 10:01:08 +00:00
|
|
|
p, err = native.Launch([]string{fixture.Path}, ".", false)
|
2017-02-10 14:11:40 +00:00
|
|
|
case "lldb":
|
2018-04-16 10:01:08 +00:00
|
|
|
p, err = gdbserial.LLDBLaunch([]string{fixture.Path}, ".", false)
|
2017-05-05 22:17:52 +00:00
|
|
|
case "rr":
|
|
|
|
protest.MustHaveRecordingAllowed(t)
|
|
|
|
t.Log("recording")
|
|
|
|
p, tracedir, err = gdbserial.RecordAndReplay([]string{fixture.Path}, ".", true)
|
|
|
|
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)
|
2017-05-05 22:17:52 +00:00
|
|
|
if tracedir != "" {
|
|
|
|
protest.SafeRemoveAll(tracedir)
|
|
|
|
}
|
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)
|
2017-04-21 07:50:38 +00:00
|
|
|
withTestProcess("testvariables", t, func(p proc.Process, fixture protest.Fixture) {
|
2017-02-22 08:35:21 +00:00
|
|
|
err := proc.Continue(p)
|
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"},
|
|
|
|
{"ch1", "chan int", "chan int 4/10", "nil", "chan int nil"},
|
|
|
|
{"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]"},
|
|
|
|
}
|
|
|
|
|
|
|
|
withTestProcess("testvariables2", t, func(p proc.Process, fixture protest.Fixture) {
|
|
|
|
assertNoError(proc.Continue(p), t, "Continue()")
|
|
|
|
|
|
|
|
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)
|
2017-04-21 07:50:38 +00:00
|
|
|
withTestProcess("testvariables", t, func(p proc.Process, fixture protest.Fixture) {
|
2017-02-22 08:35:21 +00:00
|
|
|
err := proc.Continue(p)
|
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)
|
2017-04-21 07:50:38 +00:00
|
|
|
withTestProcess("testvariables", t, func(p proc.Process, fixture protest.Fixture) {
|
2017-02-22 08:35:21 +00:00
|
|
|
err := proc.Continue(p)
|
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")
|
|
|
|
if ms := api.ConvertVar(variable).MultilineString(""); !matchStringOrPrefix(ms, tc.value) {
|
|
|
|
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},
|
|
|
|
{"ms", true, "main.Nest {Level: 0, Nest: *main.Nest {Level: 1, Nest: *(*main.Nest)…", "", "main.Nest", nil},
|
|
|
|
{"neg", true, "-1", "", "int", nil},
|
|
|
|
{"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)
|
2017-04-21 07:50:38 +00:00
|
|
|
withTestProcess("testvariables", t, func(p proc.Process, fixture protest.Fixture) {
|
2017-02-22 08:35:21 +00:00
|
|
|
err := proc.Continue(p)
|
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 {
|
2018-02-13 17:20:45 +00:00
|
|
|
scope = proc.FrameToScope(p.BinInfo(), p.CurrentThread(), nil, frame)
|
2017-05-05 22:17:52 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
scope, err = proc.GoroutineScope(p.CurrentThread())
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
2017-04-21 07:50:38 +00:00
|
|
|
withTestProcess("testvariables2", t, func(p proc.Process, 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},
|
2015-10-18 17:37:13 +00:00
|
|
|
}
|
2017-02-22 08:35:21 +00:00
|
|
|
assertNoError(proc.Continue(p), t, "Continue()")
|
2015-10-18 17:37:13 +00:00
|
|
|
|
2017-05-04 10:22:08 +00:00
|
|
|
ver, _ := goversion.Parse(runtime.Version())
|
|
|
|
if ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{1, 9, -1, 0, 0, ""}) {
|
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) {
|
2017-04-21 07:50:38 +00:00
|
|
|
withTestProcess("testvariables", t, func(p proc.Process, fixture protest.Fixture) {
|
2017-02-22 08:35:21 +00:00
|
|
|
err := proc.Continue(p)
|
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")},
|
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
|
2017-10-26 14:14:31 +00:00
|
|
|
{"ch1", true, "chan int 4/10", "chan int 4/10", "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},
|
2017-10-26 14:14:31 +00:00
|
|
|
{"cap(ch1)", false, "10", "10", "", nil},
|
|
|
|
{"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},
|
|
|
|
{"len(m1)", false, "41", "41", "", nil},
|
|
|
|
{"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")},
|
|
|
|
{"i2 << -1", false, "", "", "", fmt.Errorf("shift count type int, must be unsigned integer")},
|
|
|
|
{"i2 << i3", false, "", "", "int", fmt.Errorf("shift count type int, must be unsigned integer")},
|
|
|
|
{"*(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")},
|
2016-04-24 23:14:42 +00:00
|
|
|
{"fmt.Println(\"hello\")", false, "", "", "", fmt.Errorf("no type entry found, use 'types' for a list of valid types")},
|
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},
|
|
|
|
{"ch1.dataqsiz", false, "10", "10", "uint", nil},
|
|
|
|
{"ch1.buf", false, `*[10]int [1,4,3,2,0,0,0,0,0,0]`, `(*[10]int)(…`, "*[10]int", nil},
|
|
|
|
{"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},
|
2015-10-30 11:39:32 +00:00
|
|
|
}
|
|
|
|
|
2017-05-04 10:22:08 +00:00
|
|
|
ver, _ := goversion.Parse(runtime.Version())
|
|
|
|
if ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{1, 7, -1, 0, 0, ""}) {
|
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)
|
2017-04-21 07:50:38 +00:00
|
|
|
withTestProcess("testvariables2", t, func(p proc.Process, fixture protest.Fixture) {
|
2017-02-22 08:35:21 +00:00
|
|
|
assertNoError(proc.Continue(p), 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())
|
|
|
|
}
|
|
|
|
}
|
2016-04-24 17:15:39 +00:00
|
|
|
|
2015-10-30 11:39:32 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestEvalAddrAndCast(t *testing.T) {
|
2017-05-05 22:17:52 +00:00
|
|
|
protest.AllowRecording(t)
|
2017-04-21 07:50:38 +00:00
|
|
|
withTestProcess("testvariables2", t, func(p proc.Process, fixture protest.Fixture) {
|
2017-02-22 08:35:21 +00:00
|
|
|
assertNoError(proc.Continue(p), 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)
|
2017-04-21 07:50:38 +00:00
|
|
|
withTestProcess("testvariables2", t, func(p proc.Process, fixture protest.Fixture) {
|
2017-02-22 08:35:21 +00:00
|
|
|
assertNoError(proc.Continue(p), 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)
|
|
|
|
t.Logf("m1 = %v", m1.MultilineString(""))
|
|
|
|
|
|
|
|
if m1.Type != "map[string]main.astruct" {
|
|
|
|
t.Fatalf("Wrong type: %s", m1.Type)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(m1.Children)/2 != 41 {
|
|
|
|
t.Fatalf("Wrong number of children: %d", len(m1.Children)/2)
|
|
|
|
}
|
|
|
|
|
|
|
|
found := false
|
|
|
|
for i := range m1.Children {
|
|
|
|
if i%2 == 0 && m1.Children[i].Value == "Malone" {
|
|
|
|
found = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !found {
|
|
|
|
t.Fatalf("Could not find Malone")
|
|
|
|
}
|
|
|
|
|
2016-04-24 17:15:39 +00:00
|
|
|
m1sliced, err := evalVariable(p, "m1[10:]", pnormalLoadConfig)
|
2015-11-05 17:25:52 +00:00
|
|
|
assertNoError(err, t, "EvalVariable(m1[10:])")
|
|
|
|
if len(m1sliced.Children)/2 != int(m1.Len-10) {
|
|
|
|
t.Fatalf("Wrong number of children (after slicing): %d", len(m1sliced.Children)/2)
|
|
|
|
}
|
|
|
|
})
|
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)
|
2017-04-21 07:50:38 +00:00
|
|
|
withTestProcess("testvariables2", t, func(p proc.Process, fixture protest.Fixture) {
|
2017-02-22 08:35:21 +00:00
|
|
|
assertNoError(proc.Continue(p), 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())
|
|
|
|
if ver.Major < 0 || ver.AfterOrEqual(goversion.GoVersion{1, 8, -1, 0, 0, ""}) {
|
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)
|
2017-04-21 07:50:38 +00:00
|
|
|
withTestProcess("testvariables2", t, func(p proc.Process, fixture protest.Fixture) {
|
2017-02-22 08:35:21 +00:00
|
|
|
assertNoError(proc.Continue(p), 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
|
|
|
|
|
|
|
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},
|
|
|
|
{"amap", true, "interface {}(map[go/ast.BadExpr]net/http.Request) [{From: 2, To: 3}: *{Method: \"othermethod\", …", "", "interface {}", nil},
|
|
|
|
|
|
|
|
// Package name that doesn't match import path
|
|
|
|
{"iface3", true, `interface {}(*github.com/derekparker/delve/_fixtures/vendor/dir0/renamedpackage.SomeType) *{A: true}`, "", "interface {}", nil},
|
|
|
|
|
|
|
|
// Interfaces to anonymous types
|
|
|
|
{"amap2", true, "interface {}(*map[go/ast.BadExpr]net/http.Request) *[{From: 2, To: 3}: *{Method: \"othermethod\", …", "", "interface {}", nil},
|
|
|
|
{"dir0someType", true, "interface {}(*github.com/derekparker/delve/_fixtures/vendor/dir0/pkg.SomeType) *{X: 3}", "", "interface {}", nil},
|
2017-06-29 18:17:52 +00:00
|
|
|
{"dir1someType", true, "interface {}(github.com/derekparker/delve/_fixtures/vendor/dir1/pkg.SomeType) {X: 1, Y: 2}", "", "interface {}", nil},
|
2016-09-08 16:11:20 +00:00
|
|
|
{"amap3", true, "interface {}(map[github.com/derekparker/delve/_fixtures/vendor/dir0/pkg.SomeType]github.com/derekparker/delve/_fixtures/vendor/dir1/pkg.SomeType) [{X: 4}: {X: 5, Y: 6}, ]", "", "interface {}", nil},
|
2017-06-29 18:17:52 +00:00
|
|
|
{"anarray", true, `interface {}([2]github.com/derekparker/delve/_fixtures/vendor/dir0/pkg.SomeType) [{X: 1},{X: 2}]`, "", "interface {}", nil},
|
2016-09-08 16:11:20 +00:00
|
|
|
{"achan", true, `interface {}(chan github.com/derekparker/delve/_fixtures/vendor/dir0/pkg.SomeType) chan github.com/derekparker/delve/_fixtures/vendor/dir0/pkg.SomeType 0/0`, "", "interface {}", nil},
|
2017-06-29 18:17:52 +00:00
|
|
|
{"aslice", true, `interface {}([]github.com/derekparker/delve/_fixtures/vendor/dir0/pkg.SomeType) [{X: 3},{X: 4}]`, "", "interface {}", nil},
|
2016-09-08 16:11:20 +00:00
|
|
|
{"afunc", true, `interface {}(func(github.com/derekparker/delve/_fixtures/vendor/dir0/pkg.SomeType, github.com/derekparker/delve/_fixtures/vendor/dir1/pkg.SomeType)) main.main.func1`, "", "interface {}", nil},
|
|
|
|
{"astruct", true, `interface {}(*struct { A github.com/derekparker/delve/_fixtures/vendor/dir1/pkg.SomeType; B github.com/derekparker/delve/_fixtures/vendor/dir0/pkg.SomeType }) *{A: github.com/derekparker/delve/_fixtures/vendor/dir1/pkg.SomeType {X: 1, Y: 2}, B: github.com/derekparker/delve/_fixtures/vendor/dir0/pkg.SomeType {X: 3}}`, "", "interface {}", nil},
|
2017-05-03 07:56:59 +00:00
|
|
|
{"astruct2", true, `interface {}(*struct { github.com/derekparker/delve/_fixtures/vendor/dir1/pkg.SomeType; X int }) *{SomeType: github.com/derekparker/delve/_fixtures/vendor/dir1/pkg.SomeType {X: 1, Y: 2}, X: 10}`, "", "interface {}", nil},
|
2016-09-08 16:11:20 +00:00
|
|
|
{"iface2iface", true, `interface {}(*interface { AMethod(int) int; AnotherMethod(int) int }) **github.com/derekparker/delve/_fixtures/vendor/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
|
|
|
}
|
|
|
|
|
2017-05-04 10:22:08 +00:00
|
|
|
ver, _ := goversion.Parse(runtime.Version())
|
|
|
|
if ver.Major > 0 && !ver.AfterOrEqual(goversion.GoVersion{1, 7, -1, 0, 0, ""}) {
|
2016-09-08 16:11:20 +00:00
|
|
|
// Not supported on 1.6 or earlier
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2017-05-05 22:17:52 +00:00
|
|
|
protest.AllowRecording(t)
|
2017-04-21 07:50:38 +00:00
|
|
|
withTestProcess("pkgrenames", t, func(p proc.Process, fixture protest.Fixture) {
|
2017-02-22 08:35:21 +00:00
|
|
|
assertNoError(proc.Continue(p), t, "Continue() returned an error")
|
2016-09-08 16:11:20 +00:00
|
|
|
for _, tc := range testcases {
|
2017-05-04 10:22:08 +00:00
|
|
|
if ver.Major > 0 && !ver.AfterOrEqual(goversion.GoVersion{1, 9, -1, 0, 0, ""}) {
|
2017-05-03 07:56:59 +00:00
|
|
|
// before 1.9 embedded struct field have fieldname == type
|
|
|
|
if tc.name == "astruct2" {
|
|
|
|
tc.value = `interface {}(*struct { github.com/derekparker/delve/_fixtures/vendor/dir1/pkg.SomeType; X int }) *{github.com/derekparker/delve/_fixtures/vendor/dir1/pkg.SomeType: github.com/derekparker/delve/_fixtures/vendor/dir1/pkg.SomeType {X: 1, Y: 2}, X: 10}`
|
|
|
|
}
|
|
|
|
}
|
2016-09-08 16:11:20 +00:00
|
|
|
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())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2017-09-08 10:31:20 +00:00
|
|
|
|
|
|
|
func TestConstants(t *testing.T) {
|
|
|
|
testcases := []varTest{
|
|
|
|
{"a", true, "constTwo", "", "main.ConstType", nil},
|
|
|
|
{"b", true, "constThree", "", "main.ConstType", nil},
|
|
|
|
{"c", true, "bitZero|bitOne", "", "main.BitFieldType", nil},
|
|
|
|
{"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},
|
2018-03-17 10:14:34 +00:00
|
|
|
{"pkg.SomeConst", true, "2", "", "int", nil},
|
2017-09-08 10:31:20 +00:00
|
|
|
}
|
|
|
|
ver, _ := goversion.Parse(runtime.Version())
|
|
|
|
if ver.Major > 0 && !ver.AfterOrEqual(goversion.GoVersion{1, 10, -1, 0, 0, ""}) {
|
|
|
|
// 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
|
|
|
}
|
|
|
|
withTestProcess("consts", t, func(p proc.Process, fixture protest.Fixture) {
|
|
|
|
assertNoError(proc.Continue(p), t, "Continue")
|
|
|
|
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
|
|
|
|
|
|
|
func setFunctionBreakpoint(p proc.Process, fname string) (*proc.Breakpoint, error) {
|
|
|
|
addr, err := proc.FindFunctionLocation(p, fname, true, 0)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return p.SetBreakpoint(addr, proc.UserBreakpoint, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestIssue1075(t *testing.T) {
|
|
|
|
withTestProcess("clientdo", t, func(p proc.Process, fixture protest.Fixture) {
|
|
|
|
_, err := setFunctionBreakpoint(p, "net/http.(*Client).Do")
|
|
|
|
assertNoError(err, t, "setFunctionBreakpoint")
|
|
|
|
assertNoError(proc.Continue(p), t, "Continue()")
|
|
|
|
for i := 0; i < 10; i++ {
|
|
|
|
scope, err := proc.GoroutineScope(p.CurrentThread())
|
|
|
|
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
|
|
|
|
|
|
|
func TestCallFunction(t *testing.T) {
|
|
|
|
protest.MustSupportFunctionCalls(t, testBackend)
|
|
|
|
|
|
|
|
var testcases = []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
|
|
|
|
}{
|
|
|
|
{"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, ",")`, nil, errors.New("can not set variables of type string (not implemented)")},
|
|
|
|
{`stringsJoin(stringslice, comma)`, []string{`:string:"one,two,three"`}, nil},
|
|
|
|
{`stringsJoin(s1, comma)`, nil, errors.New("could not find symbol value for s1")},
|
|
|
|
{`stringsJoin(intslice, comma)`, nil, errors.New("can not convert value of type []int to []string")},
|
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
|
|
|
|
|
|
|
|
{`a.VRcvr(1)`, []string{`:string:"1 + 3 = 4"`}, nil}, // direct call of a method with value receiver / on a value
|
|
|
|
{`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-07-28 19:12:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
withTestProcess("fncall", t, func(p proc.Process, fixture protest.Fixture) {
|
|
|
|
_, err := proc.FindFunctionLocation(p, "runtime.debugCallV1", true, 0)
|
|
|
|
if err != nil {
|
|
|
|
t.Skip("function calls not supported on this version of go")
|
|
|
|
}
|
|
|
|
assertNoError(proc.Continue(p), t, "Continue()")
|
|
|
|
for _, tc := range testcases {
|
|
|
|
err := proc.CallFunction(p, tc.expr, &pnormalLoadConfig)
|
|
|
|
if tc.err != nil {
|
|
|
|
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())
|
|
|
|
}
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("call %q: error %q", tc.expr, err.Error())
|
|
|
|
}
|
|
|
|
|
2018-07-31 16:32:30 +00:00
|
|
|
retvalsVar := p.CurrentThread().Common().ReturnValues(pnormalLoadConfig)
|
|
|
|
retvals := make([]*api.Variable, len(retvalsVar))
|
|
|
|
|
|
|
|
for i := range retvals {
|
|
|
|
retvals[i] = api.ConvertVar(retvalsVar[i])
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Logf("call %q", tc.expr)
|
|
|
|
for i := range retvals {
|
|
|
|
t.Logf("\t%s = %s", retvals[i].Name, retvals[i].SinglelineString())
|
|
|
|
}
|
2018-07-28 19:12:07 +00:00
|
|
|
|
|
|
|
if len(retvals) != len(tc.outs) {
|
|
|
|
t.Fatalf("call %q: wrong number of return parameters", tc.expr)
|
|
|
|
}
|
|
|
|
|
|
|
|
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-31 16:32:30 +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)
|
2018-07-28 19:12:07 +00:00
|
|
|
}
|
2018-07-31 16:32:30 +00:00
|
|
|
if cvs := retvals[i].SinglelineString(); cvs != tgtValue {
|
2018-07-28 19:12:07 +00:00
|
|
|
t.Fatalf("call %q, output parameter %d: expected value %q, got %q", tc.expr, i, tgtValue, cvs)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|