...
Run Format

Source file src/go/types/eval_test.go

Documentation: go/types

  // Copyright 2013 The Go Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style
  // license that can be found in the LICENSE file.
  
  // This file contains tests for Eval.
  
  package types_test
  
  import (
  	"go/ast"
  	"go/importer"
  	"go/parser"
  	"go/token"
  	"internal/testenv"
  	"strings"
  	"testing"
  
  	. "go/types"
  )
  
  func testEval(t *testing.T, fset *token.FileSet, pkg *Package, pos token.Pos, expr string, typ Type, typStr, valStr string) {
  	gotTv, err := Eval(fset, pkg, pos, expr)
  	if err != nil {
  		t.Errorf("Eval(%q) failed: %s", expr, err)
  		return
  	}
  	if gotTv.Type == nil {
  		t.Errorf("Eval(%q) got nil type but no error", expr)
  		return
  	}
  
  	// compare types
  	if typ != nil {
  		// we have a type, check identity
  		if !Identical(gotTv.Type, typ) {
  			t.Errorf("Eval(%q) got type %s, want %s", expr, gotTv.Type, typ)
  			return
  		}
  	} else {
  		// we have a string, compare type string
  		gotStr := gotTv.Type.String()
  		if gotStr != typStr {
  			t.Errorf("Eval(%q) got type %s, want %s", expr, gotStr, typStr)
  			return
  		}
  	}
  
  	// compare values
  	gotStr := ""
  	if gotTv.Value != nil {
  		gotStr = gotTv.Value.ExactString()
  	}
  	if gotStr != valStr {
  		t.Errorf("Eval(%q) got value %s, want %s", expr, gotStr, valStr)
  	}
  }
  
  func TestEvalBasic(t *testing.T) {
  	fset := token.NewFileSet()
  	for _, typ := range Typ[Bool : String+1] {
  		testEval(t, fset, nil, token.NoPos, typ.Name(), typ, "", "")
  	}
  }
  
  func TestEvalComposite(t *testing.T) {
  	fset := token.NewFileSet()
  	for _, test := range independentTestTypes {
  		testEval(t, fset, nil, token.NoPos, test.src, nil, test.str, "")
  	}
  }
  
  func TestEvalArith(t *testing.T) {
  	var tests = []string{
  		`true`,
  		`false == false`,
  		`12345678 + 87654321 == 99999999`,
  		`10 * 20 == 200`,
  		`(1<<1000)*2 >> 100 == 2<<900`,
  		`"foo" + "bar" == "foobar"`,
  		`"abc" <= "bcd"`,
  		`len([10]struct{}{}) == 2*5`,
  	}
  	fset := token.NewFileSet()
  	for _, test := range tests {
  		testEval(t, fset, nil, token.NoPos, test, Typ[UntypedBool], "", "true")
  	}
  }
  
  func TestEvalPos(t *testing.T) {
  	testenv.MustHaveGoBuild(t)
  
  	// The contents of /*-style comments are of the form
  	//	expr => value, type
  	// where value may be the empty string.
  	// Each expr is evaluated at the position of the comment
  	// and the result is compared with the expected value
  	// and type.
  	var sources = []string{
  		`
  		package p
  		import "fmt"
  		import m "math"
  		const c = 3.0
  		type T []int
  		func f(a int, s string) float64 {
  			fmt.Println("calling f")
  			_ = m.Pi // use package math
  			const d int = c + 1
  			var x int
  			x = a + len(s)
  			return float64(x)
  			/* true => true, untyped bool */
  			/* fmt.Println => , func(a ...interface{}) (n int, err error) */
  			/* c => 3, untyped float */
  			/* T => , p.T */
  			/* a => , int */
  			/* s => , string */
  			/* d => 4, int */
  			/* x => , int */
  			/* d/c => 1, int */
  			/* c/2 => 3/2, untyped float */
  			/* m.Pi < m.E => false, untyped bool */
  		}
  		`,
  		`
  		package p
  		/* c => 3, untyped float */
  		type T1 /* T1 => , p.T1 */ struct {}
  		var v1 /* v1 => , int */ = 42
  		func /* f1 => , func(v1 float64) */ f1(v1 float64) {
  			/* f1 => , func(v1 float64) */
  			/* v1 => , float64 */
  			var c /* c => 3, untyped float */ = "foo" /* c => , string */
  			{
  				var c struct {
  					c /* c => , string */ int
  				}
  				/* c => , struct{c int} */
  				_ = c
  			}
  			_ = func(a, b, c int) /* c => , string */ {
  				/* c => , int */
  			}
  			_ = c
  			type FT /* FT => , p.FT */ interface{}
  		}
  		`,
  		`
  		package p
  		/* T => , p.T */
  		`,
  	}
  
  	fset := token.NewFileSet()
  	var files []*ast.File
  	for i, src := range sources {
  		file, err := parser.ParseFile(fset, "p", src, parser.ParseComments)
  		if err != nil {
  			t.Fatalf("could not parse file %d: %s", i, err)
  		}
  		files = append(files, file)
  	}
  
  	conf := Config{Importer: importer.Default()}
  	pkg, err := conf.Check("p", fset, files, nil)
  	if err != nil {
  		t.Fatal(err)
  	}
  
  	for _, file := range files {
  		for _, group := range file.Comments {
  			for _, comment := range group.List {
  				s := comment.Text
  				if len(s) >= 4 && s[:2] == "/*" && s[len(s)-2:] == "*/" {
  					str, typ := split(s[2:len(s)-2], ", ")
  					str, val := split(str, "=>")
  					testEval(t, fset, pkg, comment.Pos(), str, nil, typ, val)
  				}
  			}
  		}
  	}
  }
  
  // split splits string s at the first occurrence of s.
  func split(s, sep string) (string, string) {
  	i := strings.Index(s, sep)
  	return strings.TrimSpace(s[:i]), strings.TrimSpace(s[i+len(sep):])
  }
  

View as plain text