summaryrefslogtreecommitdiff
path: root/libgo/go/exp/eval/eval_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/exp/eval/eval_test.go')
-rw-r--r--libgo/go/exp/eval/eval_test.go259
1 files changed, 259 insertions, 0 deletions
diff --git a/libgo/go/exp/eval/eval_test.go b/libgo/go/exp/eval/eval_test.go
new file mode 100644
index 000000000..ff28cf1a9
--- /dev/null
+++ b/libgo/go/exp/eval/eval_test.go
@@ -0,0 +1,259 @@
+// Copyright 2009 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.
+
+package eval
+
+import (
+ "big"
+ "flag"
+ "fmt"
+ "go/token"
+ "log"
+ "os"
+ "reflect"
+ "regexp"
+ "testing"
+)
+
+// All tests are done using the same file set.
+var fset = token.NewFileSet()
+
+// Print each statement or expression before parsing it
+var noisy = false
+
+func init() { flag.BoolVar(&noisy, "noisy", false, "chatter during eval tests") }
+
+/*
+ * Generic statement/expression test framework
+ */
+
+type test []job
+
+type job struct {
+ code string
+ cerr string
+ rterr string
+ val Value
+ noval bool
+}
+
+func runTests(t *testing.T, baseName string, tests []test) {
+ for i, test := range tests {
+ name := fmt.Sprintf("%s[%d]", baseName, i)
+ test.run(t, name)
+ }
+}
+
+func (a test) run(t *testing.T, name string) {
+ w := newTestWorld()
+ for _, j := range a {
+ src := j.code + ";" // trailing semicolon to finish statement
+ if noisy {
+ println("code:", src)
+ }
+
+ code, err := w.Compile(fset, src)
+ if err != nil {
+ if j.cerr == "" {
+ t.Errorf("%s: Compile %s: %v", name, src, err)
+ break
+ }
+ if !match(t, err, j.cerr) {
+ t.Errorf("%s: Compile %s = error %s; want %v", name, src, err, j.cerr)
+ break
+ }
+ continue
+ }
+ if j.cerr != "" {
+ t.Errorf("%s: Compile %s succeeded; want %s", name, src, j.cerr)
+ break
+ }
+
+ val, err := code.Run()
+ if err != nil {
+ if j.rterr == "" {
+ t.Errorf("%s: Run %s: %v", name, src, err)
+ break
+ }
+ if !match(t, err, j.rterr) {
+ t.Errorf("%s: Run %s = error %s; want %v", name, src, err, j.rterr)
+ break
+ }
+ continue
+ }
+ if j.rterr != "" {
+ t.Errorf("%s: Run %s succeeded; want %s", name, src, j.rterr)
+ break
+ }
+
+ if !j.noval && !reflect.DeepEqual(val, j.val) {
+ t.Errorf("%s: Run %s = %T(%v) want %T(%v)", name, src, val, val, j.val, j.val)
+ }
+ }
+}
+
+func match(t *testing.T, err os.Error, pat string) bool {
+ ok, err1 := regexp.MatchString(pat, err.String())
+ if err1 != nil {
+ t.Fatalf("compile regexp %s: %v", pat, err1)
+ }
+ return ok
+}
+
+
+/*
+ * Test constructors
+ */
+
+// Expression compile error
+func CErr(expr string, cerr string) test { return test([]job{{code: expr, cerr: cerr}}) }
+
+// Expression runtime error
+func RErr(expr string, rterr string) test { return test([]job{{code: expr, rterr: rterr}}) }
+
+// Expression value
+func Val(expr string, val interface{}) test {
+ return test([]job{{code: expr, val: toValue(val)}})
+}
+
+// Statement runs without error
+func Run(stmts string) test { return test([]job{{code: stmts, noval: true}}) }
+
+// Two statements without error.
+// TODO(rsc): Should be possible with Run but the parser
+// won't let us do both top-level and non-top-level statements.
+func Run2(stmt1, stmt2 string) test {
+ return test([]job{{code: stmt1, noval: true}, {code: stmt2, noval: true}})
+}
+
+// Statement runs and test one expression's value
+func Val1(stmts string, expr1 string, val1 interface{}) test {
+ return test([]job{
+ {code: stmts, noval: true},
+ {code: expr1, val: toValue(val1)},
+ })
+}
+
+// Statement runs and test two expressions' values
+func Val2(stmts string, expr1 string, val1 interface{}, expr2 string, val2 interface{}) test {
+ return test([]job{
+ {code: stmts, noval: true},
+ {code: expr1, val: toValue(val1)},
+ {code: expr2, val: toValue(val2)},
+ })
+}
+
+/*
+ * Value constructors
+ */
+
+type vstruct []interface{}
+
+type varray []interface{}
+
+type vslice struct {
+ arr varray
+ len, cap int
+}
+
+func toValue(val interface{}) Value {
+ switch val := val.(type) {
+ case bool:
+ r := boolV(val)
+ return &r
+ case uint8:
+ r := uint8V(val)
+ return &r
+ case uint:
+ r := uintV(val)
+ return &r
+ case int:
+ r := intV(val)
+ return &r
+ case *big.Int:
+ return &idealIntV{val}
+ case float64:
+ r := float64V(val)
+ return &r
+ case *big.Rat:
+ return &idealFloatV{val}
+ case string:
+ r := stringV(val)
+ return &r
+ case vstruct:
+ elems := make([]Value, len(val))
+ for i, e := range val {
+ elems[i] = toValue(e)
+ }
+ r := structV(elems)
+ return &r
+ case varray:
+ elems := make([]Value, len(val))
+ for i, e := range val {
+ elems[i] = toValue(e)
+ }
+ r := arrayV(elems)
+ return &r
+ case vslice:
+ return &sliceV{Slice{toValue(val.arr).(ArrayValue), int64(val.len), int64(val.cap)}}
+ case Func:
+ return &funcV{val}
+ }
+ log.Panicf("toValue(%T) not implemented", val)
+ panic("unreachable")
+}
+
+/*
+ * Default test scope
+ */
+
+type testFunc struct{}
+
+func (*testFunc) NewFrame() *Frame { return &Frame{nil, make([]Value, 2)} }
+
+func (*testFunc) Call(t *Thread) {
+ n := t.f.Vars[0].(IntValue).Get(t)
+
+ res := n + 1
+
+ t.f.Vars[1].(IntValue).Set(t, res)
+}
+
+type oneTwoFunc struct{}
+
+func (*oneTwoFunc) NewFrame() *Frame { return &Frame{nil, make([]Value, 2)} }
+
+func (*oneTwoFunc) Call(t *Thread) {
+ t.f.Vars[0].(IntValue).Set(t, 1)
+ t.f.Vars[1].(IntValue).Set(t, 2)
+}
+
+type voidFunc struct{}
+
+func (*voidFunc) NewFrame() *Frame { return &Frame{nil, []Value{}} }
+
+func (*voidFunc) Call(t *Thread) {}
+
+func newTestWorld() *World {
+ w := NewWorld()
+
+ def := func(name string, t Type, val interface{}) { w.DefineVar(name, t, toValue(val)) }
+
+ w.DefineConst("c", IdealIntType, toValue(big.NewInt(1)))
+ def("i", IntType, 1)
+ def("i2", IntType, 2)
+ def("u", UintType, uint(1))
+ def("f", Float64Type, 1.0)
+ def("s", StringType, "abc")
+ def("t", NewStructType([]StructField{{"a", IntType, false}}), vstruct{1})
+ def("ai", NewArrayType(2, IntType), varray{1, 2})
+ def("aai", NewArrayType(2, NewArrayType(2, IntType)), varray{varray{1, 2}, varray{3, 4}})
+ def("aai2", NewArrayType(2, NewArrayType(2, IntType)), varray{varray{5, 6}, varray{7, 8}})
+ def("fn", NewFuncType([]Type{IntType}, false, []Type{IntType}), &testFunc{})
+ def("oneTwo", NewFuncType([]Type{}, false, []Type{IntType, IntType}), &oneTwoFunc{})
+ def("void", NewFuncType([]Type{}, false, []Type{}), &voidFunc{})
+ def("sli", NewSliceType(IntType), vslice{varray{1, 2, 3}, 2, 3})
+
+ return w
+}