Home | History | Annotate | Download | only in types
      1 // Copyright 2012 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package types_test
      6 
      7 import (
      8 	"go/ast"
      9 	"go/importer"
     10 	"go/parser"
     11 	"go/token"
     12 	"internal/testenv"
     13 	"testing"
     14 
     15 	. "go/types"
     16 )
     17 
     18 const filename = "<src>"
     19 
     20 func makePkg(src string) (*Package, error) {
     21 	fset := token.NewFileSet()
     22 	file, err := parser.ParseFile(fset, filename, src, parser.DeclarationErrors)
     23 	if err != nil {
     24 		return nil, err
     25 	}
     26 	// use the package name as package path
     27 	conf := Config{Importer: importer.Default()}
     28 	return conf.Check(file.Name.Name, fset, []*ast.File{file}, nil)
     29 }
     30 
     31 type testEntry struct {
     32 	src, str string
     33 }
     34 
     35 // dup returns a testEntry where both src and str are the same.
     36 func dup(s string) testEntry {
     37 	return testEntry{s, s}
     38 }
     39 
     40 // types that don't depend on any other type declarations
     41 var independentTestTypes = []testEntry{
     42 	// basic types
     43 	dup("int"),
     44 	dup("float32"),
     45 	dup("string"),
     46 
     47 	// arrays
     48 	dup("[10]int"),
     49 
     50 	// slices
     51 	dup("[]int"),
     52 	dup("[][]int"),
     53 
     54 	// structs
     55 	dup("struct{}"),
     56 	dup("struct{x int}"),
     57 	{`struct {
     58 		x, y int
     59 		z float32 "foo"
     60 	}`, `struct{x int; y int; z float32 "foo"}`},
     61 	{`struct {
     62 		string
     63 		elems []complex128
     64 	}`, `struct{string; elems []complex128}`},
     65 
     66 	// pointers
     67 	dup("*int"),
     68 	dup("***struct{}"),
     69 	dup("*struct{a int; b float32}"),
     70 
     71 	// functions
     72 	dup("func()"),
     73 	dup("func(x int)"),
     74 	{"func(x, y int)", "func(x int, y int)"},
     75 	{"func(x, y int, z string)", "func(x int, y int, z string)"},
     76 	dup("func(int)"),
     77 	{"func(int, string, byte)", "func(int, string, byte)"},
     78 
     79 	dup("func() int"),
     80 	{"func() (string)", "func() string"},
     81 	dup("func() (u int)"),
     82 	{"func() (u, v int, w string)", "func() (u int, v int, w string)"},
     83 
     84 	dup("func(int) string"),
     85 	dup("func(x int) string"),
     86 	dup("func(x int) (u string)"),
     87 	{"func(x, y int) (u string)", "func(x int, y int) (u string)"},
     88 
     89 	dup("func(...int) string"),
     90 	dup("func(x ...int) string"),
     91 	dup("func(x ...int) (u string)"),
     92 	{"func(x, y ...int) (u string)", "func(x int, y ...int) (u string)"},
     93 
     94 	// interfaces
     95 	dup("interface{}"),
     96 	dup("interface{m()}"),
     97 	dup(`interface{String() string; m(int) float32}`),
     98 
     99 	// maps
    100 	dup("map[string]int"),
    101 	{"map[struct{x, y int}][]byte", "map[struct{x int; y int}][]byte"},
    102 
    103 	// channels
    104 	dup("chan<- chan int"),
    105 	dup("chan<- <-chan int"),
    106 	dup("<-chan <-chan int"),
    107 	dup("chan (<-chan int)"),
    108 	dup("chan<- func()"),
    109 	dup("<-chan []func() int"),
    110 }
    111 
    112 // types that depend on other type declarations (src in TestTypes)
    113 var dependentTestTypes = []testEntry{
    114 	// interfaces
    115 	dup(`interface{io.Reader; io.Writer}`),
    116 	dup(`interface{m() int; io.Writer}`),
    117 	{`interface{m() interface{T}}`, `interface{m() interface{p.T}}`},
    118 }
    119 
    120 func TestTypeString(t *testing.T) {
    121 	testenv.MustHaveGoBuild(t)
    122 
    123 	var tests []testEntry
    124 	tests = append(tests, independentTestTypes...)
    125 	tests = append(tests, dependentTestTypes...)
    126 
    127 	for _, test := range tests {
    128 		src := `package p; import "io"; type _ io.Writer; type T ` + test.src
    129 		pkg, err := makePkg(src)
    130 		if err != nil {
    131 			t.Errorf("%s: %s", src, err)
    132 			continue
    133 		}
    134 		typ := pkg.Scope().Lookup("T").Type().Underlying()
    135 		if got := typ.String(); got != test.str {
    136 			t.Errorf("%s: got %s, want %s", test.src, got, test.str)
    137 		}
    138 	}
    139 }
    140 
    141 func TestIncompleteInterfaces(t *testing.T) {
    142 	sig := NewSignature(nil, nil, nil, false)
    143 	for _, test := range []struct {
    144 		typ  *Interface
    145 		want string
    146 	}{
    147 		{new(Interface), "interface{/* incomplete */}"},
    148 		{new(Interface).Complete(), "interface{}"},
    149 		{NewInterface(nil, nil), "interface{/* incomplete */}"},
    150 		{NewInterface(nil, nil).Complete(), "interface{}"},
    151 		{NewInterface([]*Func{NewFunc(token.NoPos, nil, "m", sig)}, nil), "interface{m() /* incomplete */}"},
    152 		{NewInterface([]*Func{NewFunc(token.NoPos, nil, "m", sig)}, nil).Complete(), "interface{m()}"},
    153 	} {
    154 		got := test.typ.String()
    155 		if got != test.want {
    156 			t.Errorf("got: %s, want: %s", got, test.want)
    157 		}
    158 	}
    159 }
    160 
    161 func TestQualifiedTypeString(t *testing.T) {
    162 	p, _ := pkgFor("p.go", "package p; type T int", nil)
    163 	q, _ := pkgFor("q.go", "package q", nil)
    164 
    165 	pT := p.Scope().Lookup("T").Type()
    166 	for _, test := range []struct {
    167 		typ  Type
    168 		this *Package
    169 		want string
    170 	}{
    171 		{nil, nil, "<nil>"},
    172 		{pT, nil, "p.T"},
    173 		{pT, p, "T"},
    174 		{pT, q, "p.T"},
    175 		{NewPointer(pT), p, "*T"},
    176 		{NewPointer(pT), q, "*p.T"},
    177 	} {
    178 		qualifier := func(pkg *Package) string {
    179 			if pkg != test.this {
    180 				return pkg.Name()
    181 			}
    182 			return ""
    183 		}
    184 		if got := TypeString(test.typ, qualifier); got != test.want {
    185 			t.Errorf("TypeString(%s, %s) = %s, want %s",
    186 				test.this, test.typ, got, test.want)
    187 		}
    188 	}
    189 }
    190