2014-12-09 16:51:17 +00:00
|
|
|
package proctl
|
2014-10-25 15:48:14 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"path/filepath"
|
2014-12-30 17:57:31 +00:00
|
|
|
"sort"
|
2014-10-25 15:48:14 +00:00
|
|
|
"testing"
|
|
|
|
)
|
|
|
|
|
2014-12-30 17:57:31 +00:00
|
|
|
type varTest struct {
|
|
|
|
name string
|
|
|
|
value string
|
|
|
|
varType string
|
|
|
|
}
|
|
|
|
|
|
|
|
func assertVariable(t *testing.T, variable *Variable, expected varTest) {
|
|
|
|
if variable.Name != expected.name {
|
|
|
|
t.Fatalf("Expected %s got %s\n", expected.name, variable.Name)
|
|
|
|
}
|
|
|
|
|
|
|
|
if variable.Type != expected.varType {
|
|
|
|
t.Fatalf("Expected %s got %s\n", expected.varType, variable.Type)
|
|
|
|
}
|
|
|
|
|
|
|
|
if variable.Value != expected.value {
|
|
|
|
t.Fatalf("Expected %#v got %#v\n", expected.value, variable.Value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-25 15:48:14 +00:00
|
|
|
func TestVariableEvaluation(t *testing.T) {
|
|
|
|
executablePath := "../_fixtures/testvariables"
|
|
|
|
|
|
|
|
fp, err := filepath.Abs(executablePath + ".go")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2014-12-30 17:57:31 +00:00
|
|
|
testcases := []varTest{
|
2014-10-25 15:48:14 +00:00
|
|
|
{"a1", "foo", "struct string"},
|
|
|
|
{"a2", "6", "int"},
|
|
|
|
{"a3", "7.23", "float64"},
|
2014-11-24 23:27:56 +00:00
|
|
|
{"a4", "[2]int [1 2]", "[2]int"},
|
2014-10-25 15:48:14 +00:00
|
|
|
{"a5", "len: 5 cap: 5 [1 2 3 4 5]", "struct []int"},
|
|
|
|
{"a6", "main.FooBar {Baz: 8, Bur: word}", "main.FooBar"},
|
|
|
|
{"a7", "*main.FooBar {Baz: 5, Bur: strum}", "*main.FooBar"},
|
2014-12-31 21:13:28 +00:00
|
|
|
{"a8", "main.FooBar2 {Bur: 10, Baz: feh}", "main.FooBar2"},
|
2014-10-25 15:48:14 +00:00
|
|
|
{"baz", "bazburzum", "struct string"},
|
2014-10-25 16:05:03 +00:00
|
|
|
{"neg", "-1", "int"},
|
|
|
|
{"i8", "1", "int8"},
|
2014-10-26 17:44:26 +00:00
|
|
|
{"f32", "1.2", "float32"},
|
2014-12-03 05:30:39 +00:00
|
|
|
{"a6.Baz", "8", "int"},
|
2014-12-31 21:13:28 +00:00
|
|
|
{"a8.Baz", "feh", "struct string"},
|
|
|
|
{"a8", "main.FooBar2 {Bur: 10, Baz: feh}", "main.FooBar2"}, // reread variable after member
|
2014-12-29 04:37:18 +00:00
|
|
|
{"i32", "[2]int32 [1 2]", "[2]int32"},
|
2014-10-25 15:48:14 +00:00
|
|
|
}
|
|
|
|
|
2014-12-09 16:51:17 +00:00
|
|
|
withTestProcess(executablePath, t, func(p *DebuggedProcess) {
|
2014-12-31 21:13:28 +00:00
|
|
|
pc, _, _ := p.GoSymTable.LineToPC(fp, 37)
|
2014-10-25 15:48:14 +00:00
|
|
|
|
|
|
|
_, err := p.Break(uintptr(pc))
|
|
|
|
assertNoError(err, t, "Break() returned an error")
|
|
|
|
|
|
|
|
err = p.Continue()
|
|
|
|
assertNoError(err, t, "Continue() returned an error")
|
|
|
|
|
|
|
|
for _, tc := range testcases {
|
|
|
|
variable, err := p.EvalSymbol(tc.name)
|
2014-12-30 17:57:31 +00:00
|
|
|
assertNoError(err, t, "EvalSymbol() returned an error")
|
|
|
|
assertVariable(t, variable, tc)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2014-10-25 15:48:14 +00:00
|
|
|
|
2014-12-30 17:57:31 +00:00
|
|
|
func TestVariableFunctionScoping(t *testing.T) {
|
|
|
|
executablePath := "../_fixtures/testvariables"
|
|
|
|
|
|
|
|
fp, err := filepath.Abs(executablePath + ".go")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
withTestProcess(executablePath, t, func(p *DebuggedProcess) {
|
2014-12-31 21:13:28 +00:00
|
|
|
pc, _, _ := p.GoSymTable.LineToPC(fp, 37)
|
2014-12-30 17:57:31 +00:00
|
|
|
|
|
|
|
_, err := p.Break(uintptr(pc))
|
|
|
|
assertNoError(err, t, "Break() returned an error")
|
|
|
|
|
|
|
|
err = p.Continue()
|
|
|
|
assertNoError(err, t, "Continue() returned an error")
|
|
|
|
|
|
|
|
_, err = p.EvalSymbol("a1")
|
|
|
|
assertNoError(err, t, "Unable to find variable a1")
|
|
|
|
|
|
|
|
_, err = p.EvalSymbol("a2")
|
|
|
|
assertNoError(err, t, "Unable to find variable a1")
|
|
|
|
|
|
|
|
// Move scopes, a1 exists here by a2 does not
|
2014-12-31 21:13:28 +00:00
|
|
|
pc, _, _ = p.GoSymTable.LineToPC(fp, 18)
|
2014-12-30 17:57:31 +00:00
|
|
|
|
|
|
|
_, err = p.Break(uintptr(pc))
|
|
|
|
assertNoError(err, t, "Break() returned an error")
|
|
|
|
|
|
|
|
err = p.Continue()
|
|
|
|
assertNoError(err, t, "Continue() returned an error")
|
|
|
|
|
|
|
|
_, err = p.EvalSymbol("a1")
|
|
|
|
assertNoError(err, t, "Unable to find variable a1")
|
|
|
|
|
|
|
|
_, err = p.EvalSymbol("a2")
|
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("Can eval out of scope variable a2")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
type varArray []*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) {
|
|
|
|
executablePath := "../_fixtures/testvariables"
|
|
|
|
|
|
|
|
fp, err := filepath.Abs(executablePath + ".go")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
testcases := []struct {
|
|
|
|
fn func(*ThreadContext) ([]*Variable, error)
|
|
|
|
output []varTest
|
|
|
|
}{
|
|
|
|
{(*ThreadContext).LocalVariables,
|
|
|
|
[]varTest{
|
|
|
|
{"a1", "foo", "struct string"},
|
|
|
|
{"a2", "6", "int"},
|
|
|
|
{"a3", "7.23", "float64"},
|
|
|
|
{"a4", "[2]int [1 2]", "[2]int"},
|
|
|
|
{"a5", "len: 5 cap: 5 [1 2 3 4 5]", "struct []int"},
|
|
|
|
{"a6", "main.FooBar {Baz: 8, Bur: word}", "main.FooBar"},
|
|
|
|
{"a7", "*main.FooBar {Baz: 5, Bur: strum}", "*main.FooBar"},
|
2014-12-31 21:13:28 +00:00
|
|
|
{"a8", "main.FooBar2 {Bur: 10, Baz: feh}", "main.FooBar2"},
|
2014-12-30 17:57:31 +00:00
|
|
|
{"f32", "1.2", "float32"},
|
|
|
|
{"i32", "[2]int32 [1 2]", "[2]int32"},
|
|
|
|
{"i8", "1", "int8"},
|
|
|
|
{"neg", "-1", "int"}}},
|
|
|
|
{(*ThreadContext).FunctionArguments,
|
|
|
|
[]varTest{
|
|
|
|
{"bar", "main.FooBar {Baz: 10, Bur: lorem}", "main.FooBar"},
|
|
|
|
{"baz", "bazburzum", "struct string"}}},
|
|
|
|
}
|
|
|
|
|
|
|
|
withTestProcess(executablePath, t, func(p *DebuggedProcess) {
|
2014-12-31 21:13:28 +00:00
|
|
|
pc, _, _ := p.GoSymTable.LineToPC(fp, 37)
|
2014-12-30 17:57:31 +00:00
|
|
|
|
|
|
|
_, err := p.Break(uintptr(pc))
|
|
|
|
assertNoError(err, t, "Break() returned an error")
|
|
|
|
|
|
|
|
err = p.Continue()
|
|
|
|
assertNoError(err, t, "Continue() returned an error")
|
|
|
|
|
|
|
|
for _, tc := range testcases {
|
|
|
|
vars, err := tc.fn(p.CurrentThread)
|
|
|
|
assertNoError(err, t, "LocalVariables() returned an error")
|
|
|
|
|
|
|
|
sort.Sort(varArray(vars))
|
2014-10-25 15:48:14 +00:00
|
|
|
|
2014-12-30 17:57:31 +00:00
|
|
|
if len(tc.output) != len(vars) {
|
|
|
|
t.Fatalf("Invalid variable count. Expected %d got %d.", len(tc.output), len(vars))
|
2014-10-25 15:48:14 +00:00
|
|
|
}
|
|
|
|
|
2014-12-30 17:57:31 +00:00
|
|
|
for i, variable := range vars {
|
|
|
|
assertVariable(t, variable, tc.output[i])
|
2014-10-25 15:48:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|