go.tools/go/types: better error messages for api tests

R=adonovan
CC=golang-dev
https://golang.org/cl/22140043
This commit is contained in:
Robert Griesemer 2013-11-05 13:42:31 -08:00
parent 8b05c30f06
commit 8e64946a3a
1 changed files with 91 additions and 71 deletions

View File

@ -7,7 +7,7 @@
package types
import (
"fmt"
"bytes"
"go/ast"
"go/parser"
"go/token"
@ -31,12 +31,12 @@ func pkgFor(path, source string, info *Info) (*Package, error) {
return pkg, nil
}
func mustTypecheck(t *testing.T, path, source string, info *Info) *Package {
func mustTypecheck(t *testing.T, path, source string, info *Info) string {
pkg, err := pkgFor(path, source, info)
if err != nil {
t.Fatalf("%s: didn't type-check (%s)", path, err)
}
return pkg
return pkg.Name()
}
func TestCommaOkTypes(t *testing.T) {
@ -45,28 +45,27 @@ func TestCommaOkTypes(t *testing.T) {
expr string // comma-ok expression string
typ string // typestring of comma-ok value
}{
{`package p; var x interface{}; var _, _ = x.(int)`,
{`package p0; var x interface{}; var _, _ = x.(int)`,
`x.(int)`,
`(int, bool)`,
},
{`package p; var x interface{}; func _() { _, _ = x.(int) }`,
{`package p1; var x interface{}; func _() { _, _ = x.(int) }`,
`x.(int)`,
`(int, bool)`,
},
{`package p; type mybool bool; var m map[string]complex128; var b mybool; func _() { _, b = m["foo"] }`,
{`package p2; type mybool bool; var m map[string]complex128; var b mybool; func _() { _, b = m["foo"] }`,
`m["foo"]`,
`(complex128, p.mybool)`,
`(complex128, p2.mybool)`,
},
{`package p; var c chan string; var _, _ = <-c`,
{`package p3; var c chan string; var _, _ = <-c`,
`<-c`,
`(string, bool)`,
},
}
for i, test := range tests {
path := fmt.Sprintf("CommaOkTypes%d", i)
for _, test := range tests {
info := Info{Types: make(map[ast.Expr]Type)}
mustTypecheck(t, path, test.src, &info)
name := mustTypecheck(t, "CommaOkTypes", test.src, &info)
// look for comma-ok expression type
var typ Type
@ -77,13 +76,13 @@ func TestCommaOkTypes(t *testing.T) {
}
}
if typ == nil {
t.Errorf("%s: no type found for %s", path, test.expr)
t.Errorf("package %s: no type found for %s", name, test.expr)
continue
}
// check that type is correct
if got := typ.String(); got != test.typ {
t.Errorf("%s: got %s; want %s", path, got, test.typ)
t.Errorf("package %s: got %s; want %s", name, got, test.typ)
}
}
}
@ -93,79 +92,78 @@ func TestScopesInfo(t *testing.T) {
src string
scopes []string // list of scope descriptors of the form kind:varlist
}{
{`package p`, []string{
{`package p0`, []string{
"file:",
}},
{`package p; import ( "fmt"; m "math"; _ "os" ); var ( _ = fmt.Println; _ = m.Pi )`, []string{
{`package p1; import ( "fmt"; m "math"; _ "os" ); var ( _ = fmt.Println; _ = m.Pi )`, []string{
"file:fmt m",
}},
{`package p; func _() {}`, []string{
{`package p2; func _() {}`, []string{
"file:", "func:",
}},
{`package p; func _(x, y int) {}`, []string{
{`package p3; func _(x, y int) {}`, []string{
"file:", "func:x y",
}},
{`package p; func _(x, y int) { x, z := 1, 2; _ = z }`, []string{
{`package p4; func _(x, y int) { x, z := 1, 2; _ = z }`, []string{
"file:", "func:x y z", // redeclaration of x
}},
{`package p; func _(x, y int) (u, _ int) { return }`, []string{
{`package p5; func _(x, y int) (u, _ int) { return }`, []string{
"file:", "func:u x y",
}},
{`package p; func _() { { var x int; _ = x } }`, []string{
{`package p6; func _() { { var x int; _ = x } }`, []string{
"file:", "func:", "block:x",
}},
{`package p; func _() { if true {} }`, []string{
{`package p7; func _() { if true {} }`, []string{
"file:", "func:", "if:", "block:",
}},
{`package p; func _() { if x := 0; x < 0 { y := x; _ = y } }`, []string{
{`package p8; func _() { if x := 0; x < 0 { y := x; _ = y } }`, []string{
"file:", "func:", "if:x", "block:y",
}},
{`package p; func _() { switch x := 0; x {} }`, []string{
{`package p9; func _() { switch x := 0; x {} }`, []string{
"file:", "func:", "switch:x",
}},
{`package p; func _() { switch x := 0; x { case 1: y := x; _ = y; default: }}`, []string{
{`package p10; func _() { switch x := 0; x { case 1: y := x; _ = y; default: }}`, []string{
"file:", "func:", "switch:x", "case:y", "case:",
}},
{`package p; func _(t interface{}) { switch t.(type) {} }`, []string{
{`package p11; func _(t interface{}) { switch t.(type) {} }`, []string{
"file:", "func:t", "type switch:",
}},
{`package p; func _(t interface{}) { switch t := t; t.(type) {} }`, []string{
{`package p12; func _(t interface{}) { switch t := t; t.(type) {} }`, []string{
"file:", "func:t", "type switch:t",
}},
{`package p; func _(t interface{}) { switch x := t.(type) { case int: _ = x } }`, []string{
{`package p13; func _(t interface{}) { switch x := t.(type) { case int: _ = x } }`, []string{
"file:", "func:t", "type switch:", "case:x", // x implicitly declared
}},
{`package p; func _() { select{} }`, []string{
{`package p14; func _() { select{} }`, []string{
"file:", "func:",
}},
{`package p; func _(c chan int) { select{ case <-c: } }`, []string{
{`package p15; func _(c chan int) { select{ case <-c: } }`, []string{
"file:", "func:c", "comm:",
}},
{`package p; func _(c chan int) { select{ case i := <-c: x := i; _ = x} }`, []string{
{`package p16; func _(c chan int) { select{ case i := <-c: x := i; _ = x} }`, []string{
"file:", "func:c", "comm:i x",
}},
{`package p; func _() { for{} }`, []string{
{`package p17; func _() { for{} }`, []string{
"file:", "func:", "for:", "block:",
}},
{`package p; func _(n int) { for i := 0; i < n; i++ { _ = i } }`, []string{
{`package p18; func _(n int) { for i := 0; i < n; i++ { _ = i } }`, []string{
"file:", "func:n", "for:i", "block:",
}},
{`package p; func _(a []int) { for i := range a { _ = i} }`, []string{
{`package p19; func _(a []int) { for i := range a { _ = i} }`, []string{
"file:", "func:a", "range:i", "block:",
}},
{`package p; var s int; func _(a []int) { for i, x := range a { s += x; _ = i } }`, []string{
{`package p20; var s int; func _(a []int) { for i, x := range a { s += x; _ = i } }`, []string{
"file:", "func:a", "range:i x", "block:",
}},
}
for i, test := range tests {
path := fmt.Sprintf("ScopesInfo%d", i)
for _, test := range tests {
info := Info{Scopes: make(map[ast.Node]*Scope)}
mustTypecheck(t, path, test.src, &info)
name := mustTypecheck(t, "ScopesInfo", test.src, &info)
// number of scopes must match
if len(info.Scopes) != len(test.scopes) {
t.Errorf("%s: got %d scopes; want %d", path, len(info.Scopes), len(test.scopes))
t.Errorf("package %s: got %d scopes; want %d", name, len(info.Scopes), len(test.scopes))
}
// scope descriptions must match
@ -204,58 +202,80 @@ func TestScopesInfo(t *testing.T) {
}
}
if !found {
t.Errorf("%s: no matching scope found for %s", path, desc)
t.Errorf("package %s: no matching scope found for %s", name, desc)
}
}
}
}
func initString(init *Initializer) string {
var buf bytes.Buffer
for i, lhs := range init.Lhs {
if i > 0 {
buf.WriteString(", ")
}
buf.WriteString(lhs.name)
}
buf.WriteString(" = ")
writeExpr(&buf, init.Rhs)
return buf.String()
}
func TestInitOrder(t *testing.T) {
var tests = []struct {
src string
vars []string
// TODO(gri) check also init expression
src string
inits []string
}{
{`package p; var (x = 1; y = x)`, []string{"x", "y"}},
{`package p; var (a = 1; b = 2; c = 3)`, []string{"a", "b", "c"}},
{`package p; var (a, b, c = 1, 2, 3)`, []string{"a", "b", "c"}},
{`package p; var _ = f(); func f() int { return 1 }`, []string{"_"}}, // blank var
{`package p; var (a = 0; x = y; y = z; z = 0)`, []string{"a", "z", "y", "x"}},
{`package p; var (a, _ = m[0]; m map[int]string)`, []string{"a _"}}, // blank var
{`package p; var a, b = f(); func f() (_, _ int) { return z, z }; var z = 0`, []string{"z", "a b"}},
{`package p; var (a = func() int { return b }(); b = 1)`, []string{"b", "a"}},
{`package p; var (a, b = func() (_, _ int) { return c, c }(); c = 1)`, []string{"c", "a b"}},
{`package p; type T struct{}; func (T) m() int { _ = y; return 0 }; var x, y = T.m, 1`, []string{"y", "x"}},
{`package p0; var (x = 1; y = x)`, []string{
"x = 1", "y = x",
}},
{`package p1; var (a = 1; b = 2; c = 3)`, []string{
"a = 1", "b = 2", "c = 3",
}},
{`package p2; var (a, b, c = 1, 2, 3)`, []string{
"a = 1", "b = 2", "c = 3",
}},
{`package p3; var _ = f(); func f() int { return 1 }`, []string{
"_ = f()", // blank var
}},
{`package p4; var (a = 0; x = y; y = z; z = 0)`, []string{
"a = 0", "z = 0", "y = z", "x = y",
}},
{`package p5; var (a, _ = m[0]; m map[int]string)`, []string{
"a, _ = m[0]", // blank var
}},
{`package p6; var a, b = f(); func f() (_, _ int) { return z, z }; var z = 0`, []string{
"z = 0", "a, b = f()",
}},
{`package p7; var (a = func() int { return b }(); b = 1)`, []string{
"b = 1", "a = (func literal)()",
}},
{`package p8; var (a, b = func() (_, _ int) { return c, c }(); c = 1)`, []string{
"c = 1", "a, b = (func literal)()",
}},
{`package p9; type T struct{}; func (T) m() int { _ = y; return 0 }; var x, y = T.m, 1`, []string{
"y = 1", "x = T.m",
}},
// TODO(gri) add more tests
}
for i, test := range tests {
path := fmt.Sprintf("InitOrder%d", i)
for _, test := range tests {
info := Info{}
mustTypecheck(t, path, test.src, &info)
name := mustTypecheck(t, "InitOrder", test.src, &info)
// number of initializers must match
if len(info.InitOrder) != len(test.vars) {
t.Errorf("%s: got %d initializers; want %d", path, len(info.InitOrder), len(test.vars))
if len(info.InitOrder) != len(test.inits) {
t.Errorf("package %s: got %d initializers; want %d", name, len(info.InitOrder), len(test.inits))
continue
}
// initializer order and initialized variables must match
for i, got := range info.InitOrder {
want := strings.Split(test.vars[i], " ")
// number of variables must match
if len(got.Lhs) != len(want) {
t.Errorf("%s, %d.th initializer: got %d variables; want %d", path, i, len(got.Lhs), len(want))
// initializers must match
for i, want := range test.inits {
got := initString(info.InitOrder[i])
if got != want {
t.Errorf("package %s, init %d: got %s; want %s", name, i, got, want)
continue
}
// variable names must match
for j, got := range got.Lhs {
want := want[j]
if got.name != want {
t.Errorf("%s, %d.th initializer: got name %s; want %s", path, i, got.name, want)
}
}
}
}
}