github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/src/go/types/eval_test.go (about) 1 // Copyright 2013 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 // This file contains tests for Eval. 6 7 package types_test 8 9 import ( 10 "go/ast" 11 "go/importer" 12 "go/parser" 13 "go/token" 14 "internal/testenv" 15 "strings" 16 "testing" 17 18 . "go/types" 19 ) 20 21 func testEval(t *testing.T, fset *token.FileSet, pkg *Package, pos token.Pos, expr string, typ Type, typStr, valStr string) { 22 gotTv, err := Eval(fset, pkg, pos, expr) 23 if err != nil { 24 t.Errorf("Eval(%q) failed: %s", expr, err) 25 return 26 } 27 if gotTv.Type == nil { 28 t.Errorf("Eval(%q) got nil type but no error", expr) 29 return 30 } 31 32 // compare types 33 if typ != nil { 34 // we have a type, check identity 35 if !Identical(gotTv.Type, typ) { 36 t.Errorf("Eval(%q) got type %s, want %s", expr, gotTv.Type, typ) 37 return 38 } 39 } else { 40 // we have a string, compare type string 41 gotStr := gotTv.Type.String() 42 if gotStr != typStr { 43 t.Errorf("Eval(%q) got type %s, want %s", expr, gotStr, typStr) 44 return 45 } 46 } 47 48 // compare values 49 gotStr := "" 50 if gotTv.Value != nil { 51 gotStr = gotTv.Value.ExactString() 52 } 53 if gotStr != valStr { 54 t.Errorf("Eval(%q) got value %s, want %s", expr, gotStr, valStr) 55 } 56 } 57 58 func TestEvalBasic(t *testing.T) { 59 fset := token.NewFileSet() 60 for _, typ := range Typ[Bool : String+1] { 61 testEval(t, fset, nil, token.NoPos, typ.Name(), typ, "", "") 62 } 63 } 64 65 func TestEvalComposite(t *testing.T) { 66 fset := token.NewFileSet() 67 for _, test := range independentTestTypes { 68 testEval(t, fset, nil, token.NoPos, test.src, nil, test.str, "") 69 } 70 } 71 72 func TestEvalArith(t *testing.T) { 73 var tests = []string{ 74 `true`, 75 `false == false`, 76 `12345678 + 87654321 == 99999999`, 77 `10 * 20 == 200`, 78 `(1<<1000)*2 >> 100 == 2<<900`, 79 `"foo" + "bar" == "foobar"`, 80 `"abc" <= "bcd"`, 81 `len([10]struct{}{}) == 2*5`, 82 } 83 fset := token.NewFileSet() 84 for _, test := range tests { 85 testEval(t, fset, nil, token.NoPos, test, Typ[UntypedBool], "", "true") 86 } 87 } 88 89 func TestEvalPos(t *testing.T) { 90 testenv.MustHaveGoBuild(t) 91 92 // The contents of /*-style comments are of the form 93 // expr => value, type 94 // where value may be the empty string. 95 // Each expr is evaluated at the position of the comment 96 // and the result is compared with the expected value 97 // and type. 98 var sources = []string{ 99 ` 100 package p 101 import "fmt" 102 import m "math" 103 const c = 3.0 104 type T []int 105 func f(a int, s string) float64 { 106 fmt.Println("calling f") 107 _ = m.Pi // use package math 108 const d int = c + 1 109 var x int 110 x = a + len(s) 111 return float64(x) 112 /* true => true, untyped bool */ 113 /* fmt.Println => , func(a ...interface{}) (n int, err error) */ 114 /* c => 3, untyped float */ 115 /* T => , p.T */ 116 /* a => , int */ 117 /* s => , string */ 118 /* d => 4, int */ 119 /* x => , int */ 120 /* d/c => 1, int */ 121 /* c/2 => 3/2, untyped float */ 122 /* m.Pi < m.E => false, untyped bool */ 123 } 124 `, 125 ` 126 package p 127 /* c => 3, untyped float */ 128 type T1 /* T1 => , p.T1 */ struct {} 129 var v1 /* v1 => , int */ = 42 130 func /* f1 => , func(v1 float64) */ f1(v1 float64) { 131 /* f1 => , func(v1 float64) */ 132 /* v1 => , float64 */ 133 var c /* c => 3, untyped float */ = "foo" /* c => , string */ 134 { 135 var c struct { 136 c /* c => , string */ int 137 } 138 /* c => , struct{c int} */ 139 _ = c 140 } 141 _ = func(a, b, c int) /* c => , string */ { 142 /* c => , int */ 143 } 144 _ = c 145 type FT /* FT => , p.FT */ interface{} 146 } 147 `, 148 ` 149 package p 150 /* T => , p.T */ 151 `, 152 } 153 154 fset := token.NewFileSet() 155 var files []*ast.File 156 for i, src := range sources { 157 file, err := parser.ParseFile(fset, "p", src, parser.ParseComments) 158 if err != nil { 159 t.Fatalf("could not parse file %d: %s", i, err) 160 } 161 files = append(files, file) 162 } 163 164 conf := Config{Importer: importer.Default()} 165 pkg, err := conf.Check("p", fset, files, nil) 166 if err != nil { 167 t.Fatal(err) 168 } 169 170 for _, file := range files { 171 for _, group := range file.Comments { 172 for _, comment := range group.List { 173 s := comment.Text 174 if len(s) >= 4 && s[:2] == "/*" && s[len(s)-2:] == "*/" { 175 str, typ := split(s[2:len(s)-2], ", ") 176 str, val := split(str, "=>") 177 testEval(t, fset, pkg, comment.Pos(), str, nil, typ, val) 178 } 179 } 180 } 181 } 182 } 183 184 // split splits string s at the first occurrence of s. 185 func split(s, sep string) (string, string) { 186 i := strings.Index(s, sep) 187 return strings.TrimSpace(s[:i]), strings.TrimSpace(s[i+len(sep):]) 188 }