1
0
mirror of https://github.com/golang/go synced 2024-11-26 14:08:37 -07:00
go/usr/austin/eval/eval_test.go
Austin Clements 851497bc65 Thread Thread into Value Get/Set/Assign so other Value
implementations can abort.  Make genConstant get values lazily
since we need the Thread now.

R=rsc
APPROVED=rsc
DELTA=299  (8 added, 19 deleted, 272 changed)
OCL=34353
CL=34353
2009-09-03 17:14:49 -07:00

267 lines
5.6 KiB
Go

// 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;
}