variables_test.go 5.5 KB
Newer Older
1
package proctl
2 3

import (
4
	"errors"
5
	"path/filepath"
E
epipho 已提交
6
	"sort"
7 8 9
	"testing"
)

E
epipho 已提交
10 11 12 13
type varTest struct {
	name    string
	value   string
	varType string
14
	err     error
E
epipho 已提交
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
}

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)
	}
}

31 32 33 34 35 36 37 38
func TestVariableEvaluation(t *testing.T) {
	executablePath := "../_fixtures/testvariables"

	fp, err := filepath.Abs(executablePath + ".go")
	if err != nil {
		t.Fatal(err)
	}

E
epipho 已提交
39
	testcases := []varTest{
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
		{"a1", "foo", "struct string", nil},
		{"a2", "6", "int", nil},
		{"a3", "7.23", "float64", nil},
		{"a4", "[2]int [1 2]", "[2]int", nil},
		{"a5", "len: 5 cap: 5 [1 2 3 4 5]", "struct []int", nil},
		{"a6", "main.FooBar {Baz: 8, Bur: word}", "main.FooBar", nil},
		{"a7", "*main.FooBar {Baz: 5, Bur: strum}", "*main.FooBar", nil},
		{"a8", "main.FooBar2 {Bur: 10, Baz: feh}", "main.FooBar2", nil},
		{"a9", "*main.FooBar nil", "*main.FooBar", nil},
		{"baz", "bazburzum", "struct string", nil},
		{"neg", "-1", "int", nil},
		{"i8", "1", "int8", nil},
		{"f32", "1.2", "float32", nil},
		{"a6.Baz", "8", "int", nil},
		{"a7.Baz", "5", "int", nil},
		{"a8.Baz", "feh", "struct string", nil},
		{"a9.Baz", "nil", "int", errors.New("a9 is nil")},
		{"a9.NonExistent", "nil", "int", errors.New("a9 has no member NonExistent")},
		{"a8", "main.FooBar2 {Bur: 10, Baz: feh}", "main.FooBar2", nil}, // reread variable after member
		{"i32", "[2]int32 [1 2]", "[2]int32", nil},
		{"NonExistent", "", "", errors.New("could not find symbol value for NonExistent")},
61 62
	}

63
	withTestProcess(executablePath, t, func(p *DebuggedProcess) {
64
		pc, _, _ := p.GoSymTable.LineToPC(fp, 38)
65

66
		_, err := p.Break(pc)
67 68 69 70 71 72 73
		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)
74 75 76 77 78 79 80 81
			if tc.err == nil {
				assertNoError(err, t, "EvalSymbol() returned an error")
				assertVariable(t, variable, tc)
			} else {
				if tc.err.Error() != err.Error() {
					t.Fatalf("Unexpected error. Expected %s got %s", tc.err.Error(), err.Error())
				}
			}
E
epipho 已提交
82 83 84
		}
	})
}
85

E
epipho 已提交
86 87 88 89 90 91 92 93 94
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) {
95
		pc, _, _ := p.GoSymTable.LineToPC(fp, 38)
E
epipho 已提交
96

97
		_, err := p.Break(pc)
E
epipho 已提交
98 99 100 101 102 103 104 105 106 107 108 109
		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
110
		pc, _, _ = p.GoSymTable.LineToPC(fp, 18)
E
epipho 已提交
111

112
		_, err = p.Break(pc)
E
epipho 已提交
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
		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{
159 160 161 162 163 164 165 166 167 168 169 170 171
				{"a1", "foo", "struct string", nil},
				{"a2", "6", "int", nil},
				{"a3", "7.23", "float64", nil},
				{"a4", "[2]int [1 2]", "[2]int", nil},
				{"a5", "len: 5 cap: 5 [1 2 3 4 5]", "struct []int", nil},
				{"a6", "main.FooBar {Baz: 8, Bur: word}", "main.FooBar", nil},
				{"a7", "*main.FooBar {Baz: 5, Bur: strum}", "*main.FooBar", nil},
				{"a8", "main.FooBar2 {Bur: 10, Baz: feh}", "main.FooBar2", nil},
				{"a9", "*main.FooBar nil", "*main.FooBar", nil},
				{"f32", "1.2", "float32", nil},
				{"i32", "[2]int32 [1 2]", "[2]int32", nil},
				{"i8", "1", "int8", nil},
				{"neg", "-1", "int", nil}}},
E
epipho 已提交
172 173
		{(*ThreadContext).FunctionArguments,
			[]varTest{
174 175
				{"bar", "main.FooBar {Baz: 10, Bur: lorem}", "main.FooBar", nil},
				{"baz", "bazburzum", "struct string", nil}}},
E
epipho 已提交
176 177 178
	}

	withTestProcess(executablePath, t, func(p *DebuggedProcess) {
179
		pc, _, _ := p.GoSymTable.LineToPC(fp, 38)
E
epipho 已提交
180

181
		_, err := p.Break(pc)
E
epipho 已提交
182 183 184 185 186 187 188 189 190 191
		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))
192

E
epipho 已提交
193 194
			if len(tc.output) != len(vars) {
				t.Fatalf("Invalid variable count. Expected %d got %d.", len(tc.output), len(vars))
195 196
			}

E
epipho 已提交
197 198
			for i, variable := range vars {
				assertVariable(t, variable, tc.output[i])
199 200 201 202
			}
		}
	})
}