// 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 ( "bignum"; "flag"; "fmt"; "go/parser"; "go/scanner"; "go/token"; "log"; "os"; "reflect"; "testing"; ) // 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; if noisy { println("code:", src); } code, err := w.Compile(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, errstr := testing.MatchString(pat, err.String()); if errstr != "" { t.Fatalf("compile regexp %s: %v", pat, errstr); } return ok; } /* * Test constructors */ // Expression compile error func CErr(expr string, cerr string) test { return test([]job{job{code: expr, cerr: cerr}}) } // Expression runtime error func RErr(expr string, rterr string) test { return test([]job{job{code: expr, rterr: rterr}}) } // Expression value func Val(expr string, val interface{}) test { return test([]job{job{code: expr, val: toValue(val)}}) } // Statement runs without error func Run(stmts string) test { return test([]job{job{code: stmts, noval: true}}) } // Statement runs and test one expression's value func Val1(stmts string, expr1 string, val1 interface{}) test { return test([]job{ job{code: stmts, noval: true}, job{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{ job{code: stmts, noval: true}, job{code: expr1, val: toValue(val1)}, job{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 *bignum.Integer: return &idealIntV{val}; case float: r := floatV(val); return &r; case *bignum.Rational: 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.Crashf("toValue(%T) not implemented", val); panic(); } /* * Default test scope */ type testFunc struct {}; func (*testFunc) NewFrame() *Frame { return &Frame{nil, &[2]Value {}}; } 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, &[2]Value {}}; } 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(bignum.Int(1))); def("i", IntType, 1); def("i2", IntType, 2); def("u", UintType, uint(1)); def("f", FloatType, 1.0); def("s", StringType, "abc"); def("t", NewStructType([]StructField {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; }