blob: d637955120b36c9e3b6c73c4e8025d4236f462ee [file] [log] [blame]
// 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/parser"
"go/token"
"strings"
"testing"
_ "llvm.org/llgo/third_party/gotools/go/gcimporter"
. "llvm.org/llgo/third_party/gotools/go/types"
)
func testEval(t *testing.T, pkg *Package, scope *Scope, str string, typ Type, typStr, valStr string) {
gotTv, err := Eval(str, pkg, scope)
if err != nil {
t.Errorf("Eval(%q) failed: %s", str, err)
return
}
if gotTv.Type == nil {
t.Errorf("Eval(%q) got nil type but no error", str)
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", str, 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", str, gotStr, typStr)
return
}
}
// compare values
gotStr := ""
if gotTv.Value != nil {
gotStr = gotTv.Value.String()
}
if gotStr != valStr {
t.Errorf("Eval(%q) got value %s, want %s", str, gotStr, valStr)
}
}
func TestEvalBasic(t *testing.T) {
for _, typ := range Typ[Bool : String+1] {
testEval(t, nil, nil, typ.Name(), typ, "", "")
}
}
func TestEvalComposite(t *testing.T) {
for _, test := range independentTestTypes {
testEval(t, nil, nil, 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`,
}
for _, test := range tests {
testEval(t, nil, nil, test, Typ[UntypedBool], "", "true")
}
}
func TestEvalContext(t *testing.T) {
src := `
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)
}
`
fset := token.NewFileSet()
file, err := parser.ParseFile(fset, "p", src, 0)
if err != nil {
t.Fatal(err)
}
pkg, err := Check("p", fset, []*ast.File{file})
if err != nil {
t.Fatal(err)
}
pkgScope := pkg.Scope()
if n := pkgScope.NumChildren(); n != 1 {
t.Fatalf("got %d file scopes, want 1", n)
}
fileScope := pkgScope.Child(0)
if n := fileScope.NumChildren(); n != 1 {
t.Fatalf("got %d functions scopes, want 1", n)
}
funcScope := fileScope.Child(0)
var tests = []string{
`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`,
}
for _, test := range tests {
str, typ := split(test, ", ")
str, val := split(str, "=>")
testEval(t, pkg, funcScope, 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):])
}