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  }