blob: 2bc3cc9042289fb604bbf79949b6a04a059fafa8 [file] [log] [blame]
// Copyright 2015 The Vanadium 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 opconst
import (
"fmt"
"math/big"
"testing"
"v.io/v23/vdl"
)
const (
noType = "must be assigned a type"
cantConvert = "can't convert"
overflows = "overflows"
underflows = "underflows"
losesPrecision = "loses precision"
nonzeroImaginary = "nonzero imaginary"
notSupported = "not supported"
divByZero = "divide by zero"
)
var (
bi0 = new(big.Int)
bi1, bi2, bi3 = big.NewInt(1), big.NewInt(2), big.NewInt(3)
bi4, bi5, bi6 = big.NewInt(4), big.NewInt(5), big.NewInt(6)
bi7, bi8, bi9 = big.NewInt(7), big.NewInt(8), big.NewInt(9)
bi_neg1, bi_neg2 = big.NewInt(-1), big.NewInt(-2)
br0 = new(big.Rat)
br1, br2, br3 = big.NewRat(1, 1), big.NewRat(2, 1), big.NewRat(3, 1)
br4, br5, br6 = big.NewRat(4, 1), big.NewRat(5, 1), big.NewRat(6, 1)
br7, br8, br9 = big.NewRat(7, 1), big.NewRat(8, 1), big.NewRat(9, 1)
br_neg1, br_neg2 = big.NewRat(-1, 1), big.NewRat(-2, 1)
)
func boolConst(t *vdl.Type, x bool) Const { return FromValue(vdl.BoolValue(t, x)) }
func stringConst(t *vdl.Type, x string) Const { return FromValue(vdl.StringValue(t, x)) }
func bytesConst(t *vdl.Type, x string) Const { return FromValue(vdl.BytesValue(t, []byte(x))) }
func intConst(t *vdl.Type, x int64) Const { return FromValue(vdl.IntValue(t, x)) }
func uintConst(t *vdl.Type, x uint64) Const { return FromValue(vdl.UintValue(t, x)) }
func floatConst(t *vdl.Type, x float64) Const { return FromValue(vdl.FloatValue(t, x)) }
func structNumConst(t *vdl.Type, x float64) Const {
return FromValue(structNumValue(t, sn{"A", x}))
}
func constEqual(a, b Const) bool {
if !a.IsValid() && !b.IsValid() {
return true
}
res, err := EvalBinary(EQ, a, b)
if err != nil || !res.IsValid() {
return false
}
val, err := res.ToValue()
return err == nil && val != nil && val.Kind() == vdl.Bool && val.Bool()
}
func TestConstInvalid(t *testing.T) {
x := Const{}
if x.IsValid() {
t.Errorf("zero Const IsValid")
}
if got, want := x.String(), "invalid"; got != want {
t.Errorf("ToValue got string %v, want %v", got, want)
}
{
value, err := x.ToValue()
if value != nil {
t.Errorf("ToValue got valid value %v, want nil", value)
}
if got, want := fmt.Sprint(err), "invalid const"; got != want {
t.Errorf("ToValue got error %q, want %q", got, want)
}
}
{
result, err := x.Convert(vdl.BoolType)
if result.IsValid() {
t.Errorf("Convert got valid result %v, want invalid", result)
}
if got, want := fmt.Sprint(err), "invalid const"; got != want {
t.Errorf("Convert got error %q, want %q", got, want)
}
}
unary := []UnaryOp{LogicNot, Pos, Neg, BitNot}
for _, op := range unary {
result, err := EvalUnary(op, Const{})
if result.IsValid() {
t.Errorf("EvalUnary got valid result %v, want invalid", result)
}
if got, want := fmt.Sprint(err), "invalid const"; got != want {
t.Errorf("EvalUnary got error %q, want %q", got, want)
}
}
binary := []BinaryOp{LogicAnd, LogicOr, EQ, NE, LT, LE, GT, GE, Add, Sub, Mul, Div, Mod, BitAnd, BitOr, BitXor, LeftShift, RightShift}
for _, op := range binary {
result, err := EvalBinary(op, Const{}, Const{})
if result.IsValid() {
t.Errorf("EvalBinary got valid result %v, want invalid", result)
}
if got, want := fmt.Sprint(err), "invalid const"; got != want {
t.Errorf("EvalBinary got error %q, want %q", got, want)
}
}
}
func TestConstToValueOK(t *testing.T) {
abcBytes := []byte("abc")
tests := []*vdl.Value{
vdl.BoolValue(nil, true), vdl.BoolValue(boolTypeN, true),
vdl.StringValue(nil, "abc"), vdl.StringValue(stringTypeN, "abc"),
vdl.BytesValue(nil, abcBytes), vdl.BytesValue(bytesTypeN, abcBytes),
vdl.BytesValue(bytes3Type, abcBytes), vdl.BytesValue(bytes3TypeN, abcBytes),
vdl.IntValue(vdl.Int32Type, 123), vdl.IntValue(int32TypeN, 123),
vdl.UintValue(vdl.Uint32Type, 123), vdl.UintValue(uint32TypeN, 123),
vdl.FloatValue(vdl.Float32Type, 123), vdl.FloatValue(float32TypeN, 123),
structNumValue(structAIntType, sn{"A", 123}), structNumValue(structAIntTypeN, sn{"A", 123}),
}
for _, test := range tests {
c := FromValue(test)
v, err := c.ToValue()
if got, want := v, test; !vdl.EqualValue(got, want) {
t.Errorf("%v.ToValue got %v, want %v", c, got, want)
}
expectErr(t, err, "", "%v.ToValue", c)
}
}
func TestConstToValueImplicit(t *testing.T) {
tests := []struct {
C Const
V *vdl.Value
}{
{Boolean(true), vdl.BoolValue(nil, true)},
{String("abc"), vdl.StringValue(nil, "abc")},
}
for _, test := range tests {
c := FromValue(test.V)
if got, want := c, test.C; !constEqual(got, want) {
t.Errorf("FromValue(%v) got %v, want %v", test.C, got, want)
}
v, err := test.C.ToValue()
if got, want := v, test.V; !vdl.EqualValue(got, want) {
t.Errorf("%v.ToValue got %v, want %v", test.C, got, want)
}
expectErr(t, err, "", "%v.ToValue", test.C)
}
}
func TestConstToValueError(t *testing.T) {
tests := []struct {
C Const
errstr string
}{
{Integer(bi1), noType},
{Rational(br1), noType},
}
for _, test := range tests {
v, err := test.C.ToValue()
if v != nil {
t.Errorf("%v.ToValue got %v, want nil", test.C, v)
}
expectErr(t, err, test.errstr, "%v.ToValue", test.C)
}
}
type c []Const
type v []*vdl.Value
func TestConstConvertOK(t *testing.T) {
abcBytes := []byte("abc")
// Each test has a set of consts C and values V that are all convertible to
// each other and equivalent.
tests := []struct {
C c
V v
}{
{c{Boolean(true)},
v{vdl.BoolValue(nil, true), vdl.BoolValue(boolTypeN, true)}},
{c{String("abc")},
v{vdl.StringValue(nil, "abc"), vdl.StringValue(stringTypeN, "abc"),
vdl.BytesValue(nil, abcBytes), vdl.BytesValue(bytesTypeN, abcBytes),
vdl.BytesValue(bytes3Type, abcBytes), vdl.BytesValue(bytes3TypeN, abcBytes)}},
{c{Integer(bi1), Rational(br1)},
v{vdl.IntValue(vdl.Int32Type, 1), vdl.IntValue(int32TypeN, 1),
vdl.UintValue(vdl.Uint32Type, 1), vdl.UintValue(uint32TypeN, 1),
vdl.FloatValue(vdl.Float32Type, 1), vdl.FloatValue(float32TypeN, 1)}},
{c{Integer(bi_neg1), Rational(br_neg1)},
v{vdl.IntValue(vdl.Int32Type, -1), vdl.IntValue(int32TypeN, -1),
vdl.FloatValue(vdl.Float32Type, -1), vdl.FloatValue(float32TypeN, -1)}},
{c{Rational(big.NewRat(1, 2))},
v{vdl.FloatValue(vdl.Float32Type, 0.5), vdl.FloatValue(float32TypeN, 0.5)}},
// Check implicit conversion of untyped bool and string consts.
{c{Boolean(true)},
v{vdl.BoolValue(nil, true), vdl.AnyValue(vdl.BoolValue(nil, true))}},
{c{String("abc")},
v{vdl.StringValue(nil, "abc"), vdl.AnyValue(vdl.StringValue(nil, "abc"))}},
}
for _, test := range tests {
// Create a slice of consts containing everything in C and V.
consts := make([]Const, len(test.C))
copy(consts, test.C)
for _, v := range test.V {
consts = append(consts, FromValue(v))
}
// Loop through the consts, and convert each one to each item in V.
for _, c := range consts {
for _, v := range test.V {
vt := v.Type()
got, err := c.Convert(vt)
if want := FromValue(v); !constEqual(got, want) {
t.Errorf("%v.Convert(%v) got %v, want %v", c, vt, got, want)
}
expectErr(t, err, "", "%v.Convert(%v)", c, vt)
}
}
}
}
type ty []*vdl.Type
func TestConstConvertError(t *testing.T) {
// Each test has a single const C that returns an error that contains errstr
// when converted to any of the types in the set T.
tests := []struct {
C Const
T ty
errstr string
}{
{Boolean(true),
ty{vdl.StringType, stringTypeN, bytesType, bytesTypeN, bytes3Type, bytes3TypeN,
vdl.Int32Type, int32TypeN, vdl.Uint32Type, uint32TypeN,
vdl.Float32Type, float32TypeN,
structAIntType, structAIntTypeN},
cantConvert},
{String("abc"),
ty{vdl.BoolType, boolTypeN,
vdl.Int32Type, int32TypeN, vdl.Uint32Type, uint32TypeN,
vdl.Float32Type, float32TypeN,
structAIntType, structAIntTypeN},
cantConvert},
{Integer(bi1),
ty{vdl.BoolType, boolTypeN,
vdl.StringType, stringTypeN, bytesType, bytesTypeN, bytes3Type, bytes3TypeN,
structAIntType, structAIntTypeN},
cantConvert},
{Rational(br1),
ty{vdl.BoolType, boolTypeN,
vdl.StringType, stringTypeN, bytesType, bytesTypeN, bytes3Type, bytes3TypeN,
structAIntType, structAIntTypeN},
cantConvert},
// Bounds tests
{Integer(bi_neg1), ty{vdl.Uint32Type, uint32TypeN}, overflows},
{Integer(big.NewInt(1 << 32)), ty{vdl.Int32Type, int32TypeN}, overflows},
{Integer(big.NewInt(1 << 33)), ty{vdl.Uint32Type, uint32TypeN}, overflows},
{Rational(br_neg1), ty{vdl.Uint32Type, uint32TypeN}, overflows},
{Rational(big.NewRat(1<<32, 1)), ty{vdl.Int32Type, int32TypeN}, overflows},
{Rational(big.NewRat(1<<33, 1)), ty{vdl.Uint32Type, uint32TypeN}, overflows},
{Rational(big.NewRat(1, 2)),
ty{vdl.Int32Type, int32TypeN, vdl.Uint32Type, uint32TypeN},
losesPrecision},
{Rational(bigRatAbsMin64), ty{vdl.Float32Type, float32TypeN}, underflows},
{Rational(bigRatAbsMax64), ty{vdl.Float32Type, float32TypeN}, overflows},
}
for _, test := range tests {
for _, ct := range test.T {
result, err := test.C.Convert(ct)
if result.IsValid() {
t.Errorf("%v.Convert(%v) result got %v, want invalid", test.C, ct, result)
}
expectErr(t, err, test.errstr, "%v.Convert(%v)", test.C, ct)
}
}
}
func TestConstUnaryOpOK(t *testing.T) {
tests := []struct {
op UnaryOp
x, expect Const
}{
{LogicNot, Boolean(true), Boolean(false)},
{LogicNot, boolConst(vdl.BoolType, false), boolConst(vdl.BoolType, true)},
{LogicNot, boolConst(boolTypeN, true), boolConst(boolTypeN, false)},
{Pos, Integer(bi1), Integer(bi1)},
{Pos, Rational(br1), Rational(br1)},
{Pos, intConst(vdl.Int32Type, 1), intConst(vdl.Int32Type, 1)},
{Pos, floatConst(float32TypeN, 1), floatConst(float32TypeN, 1)},
{Neg, Integer(bi1), Integer(bi_neg1)},
{Neg, Rational(br1), Rational(br_neg1)},
{Neg, intConst(vdl.Int32Type, 1), intConst(vdl.Int32Type, -1)},
{Neg, floatConst(float32TypeN, 1), floatConst(float32TypeN, -1)},
{BitNot, Integer(bi1), Integer(bi_neg2)},
{BitNot, Rational(br1), Integer(bi_neg2)},
{BitNot, intConst(vdl.Int32Type, 1), intConst(vdl.Int32Type, -2)},
{BitNot, uintConst(uint32TypeN, 1), uintConst(uint32TypeN, 1<<32-2)},
}
for _, test := range tests {
result, err := EvalUnary(test.op, test.x)
if got, want := result, test.expect; !constEqual(got, want) {
t.Errorf("EvalUnary(%v, %v) result got %v, want %v", test.op, test.x, got, want)
}
expectErr(t, err, "", "EvalUnary(%v, %v)", test.op, test.x)
}
}
func TestConstUnaryOpError(t *testing.T) {
tests := []struct {
op UnaryOp
x Const
errstr string
}{
{LogicNot, String("abc"), notSupported},
{LogicNot, Integer(bi1), notSupported},
{LogicNot, Rational(br1), notSupported},
{LogicNot, structNumConst(structAIntTypeN, 999), notSupported},
{Pos, Boolean(false), notSupported},
{Pos, String("abc"), notSupported},
{Pos, structNumConst(structAIntTypeN, 999), notSupported},
{Neg, Boolean(false), notSupported},
{Neg, String("abc"), notSupported},
{Neg, structNumConst(structAIntTypeN, 999), notSupported},
{Neg, intConst(vdl.Int32Type, -1<<31), overflows},
{BitNot, Boolean(false), cantConvert},
{BitNot, String("abc"), cantConvert},
{BitNot, Rational(big.NewRat(1, 2)), losesPrecision},
{BitNot, structNumConst(structAIntTypeN, 999), notSupported},
{BitNot, floatConst(float32TypeN, 1), cantConvert},
}
for _, test := range tests {
result, err := EvalUnary(test.op, test.x)
if result.IsValid() {
t.Errorf("EvalUnary(%v, %v) result got %v, want invalid", test.op, test.x, result)
}
expectErr(t, err, test.errstr, "EvalUnary(%v, %v)", test.op, test.x)
}
}
func TestConstBinaryOpOK(t *testing.T) {
tests := []struct {
op BinaryOp
x, y, expect Const
}{
{LogicAnd, Boolean(true), Boolean(true), Boolean(true)},
{LogicAnd, Boolean(true), Boolean(false), Boolean(false)},
{LogicAnd, Boolean(false), Boolean(true), Boolean(false)},
{LogicAnd, Boolean(false), Boolean(false), Boolean(false)},
{LogicAnd, boolConst(boolTypeN, true), boolConst(boolTypeN, true), boolConst(boolTypeN, true)},
{LogicAnd, boolConst(boolTypeN, true), boolConst(boolTypeN, false), boolConst(boolTypeN, false)},
{LogicAnd, boolConst(boolTypeN, false), boolConst(boolTypeN, true), boolConst(boolTypeN, false)},
{LogicAnd, boolConst(boolTypeN, false), boolConst(boolTypeN, false), boolConst(boolTypeN, false)},
{LogicOr, Boolean(true), Boolean(true), Boolean(true)},
{LogicOr, Boolean(true), Boolean(false), Boolean(true)},
{LogicOr, Boolean(false), Boolean(true), Boolean(true)},
{LogicOr, Boolean(false), Boolean(false), Boolean(false)},
{LogicOr, boolConst(boolTypeN, true), boolConst(boolTypeN, true), boolConst(boolTypeN, true)},
{LogicOr, boolConst(boolTypeN, true), boolConst(boolTypeN, false), boolConst(boolTypeN, true)},
{LogicOr, boolConst(boolTypeN, false), boolConst(boolTypeN, true), boolConst(boolTypeN, true)},
{LogicOr, boolConst(boolTypeN, false), boolConst(boolTypeN, false), boolConst(boolTypeN, false)},
{Add, String("abc"), String("def"), String("abcdef")},
{Add, Integer(bi1), Integer(bi1), Integer(bi2)},
{Add, Rational(br1), Rational(br1), Rational(br2)},
{Add, stringConst(stringTypeN, "abc"), stringConst(stringTypeN, "def"), stringConst(stringTypeN, "abcdef")},
{Add, bytesConst(bytesTypeN, "abc"), bytesConst(bytesTypeN, "def"), bytesConst(bytesTypeN, "abcdef")},
{Add, intConst(int32TypeN, 1), intConst(int32TypeN, 1), intConst(int32TypeN, 2)},
{Add, uintConst(uint32TypeN, 1), uintConst(uint32TypeN, 1), uintConst(uint32TypeN, 2)},
{Add, floatConst(float32TypeN, 1), floatConst(float32TypeN, 1), floatConst(float32TypeN, 2)},
{Sub, Integer(bi2), Integer(bi1), Integer(bi1)},
{Sub, Rational(br2), Rational(br1), Rational(br1)},
{Sub, intConst(int32TypeN, 2), intConst(int32TypeN, 1), intConst(int32TypeN, 1)},
{Sub, uintConst(uint32TypeN, 2), uintConst(uint32TypeN, 1), uintConst(uint32TypeN, 1)},
{Sub, floatConst(float32TypeN, 2), floatConst(float32TypeN, 1), floatConst(float32TypeN, 1)},
{Mul, Integer(bi2), Integer(bi2), Integer(bi4)},
{Mul, Rational(br2), Rational(br2), Rational(br4)},
{Mul, intConst(int32TypeN, 2), intConst(int32TypeN, 2), intConst(int32TypeN, 4)},
{Mul, uintConst(uint32TypeN, 2), uintConst(uint32TypeN, 2), uintConst(uint32TypeN, 4)},
{Mul, floatConst(float32TypeN, 2), floatConst(float32TypeN, 2), floatConst(float32TypeN, 4)},
{Div, Integer(bi4), Integer(bi2), Integer(bi2)},
{Div, Rational(br4), Rational(br2), Rational(br2)},
{Div, intConst(int32TypeN, 4), intConst(int32TypeN, 2), intConst(int32TypeN, 2)},
{Div, uintConst(uint32TypeN, 4), uintConst(uint32TypeN, 2), uintConst(uint32TypeN, 2)},
{Div, floatConst(float32TypeN, 4), floatConst(float32TypeN, 2), floatConst(float32TypeN, 2)},
{Mod, Integer(bi3), Integer(bi2), Integer(bi1)},
{Mod, Rational(br3), Rational(br2), Rational(br1)},
{Mod, intConst(int32TypeN, 3), intConst(int32TypeN, 2), intConst(int32TypeN, 1)},
{Mod, uintConst(uint32TypeN, 3), uintConst(uint32TypeN, 2), uintConst(uint32TypeN, 1)},
{BitAnd, Integer(bi3), Integer(bi2), Integer(bi2)},
{BitAnd, Rational(br3), Rational(br2), Rational(br2)},
{BitAnd, intConst(int32TypeN, 3), intConst(int32TypeN, 2), intConst(int32TypeN, 2)},
{BitAnd, uintConst(uint32TypeN, 3), uintConst(uint32TypeN, 2), uintConst(uint32TypeN, 2)},
{BitOr, Integer(bi5), Integer(bi3), Integer(bi7)},
{BitOr, Rational(br5), Rational(br3), Rational(br7)},
{BitOr, intConst(int32TypeN, 5), intConst(int32TypeN, 3), intConst(int32TypeN, 7)},
{BitOr, uintConst(uint32TypeN, 5), uintConst(uint32TypeN, 3), uintConst(uint32TypeN, 7)},
{BitXor, Integer(bi5), Integer(bi3), Integer(bi6)},
{BitXor, Rational(br5), Rational(br3), Rational(br6)},
{BitXor, intConst(int32TypeN, 5), intConst(int32TypeN, 3), intConst(int32TypeN, 6)},
{BitXor, uintConst(uint32TypeN, 5), uintConst(uint32TypeN, 3), uintConst(uint32TypeN, 6)},
{LeftShift, Integer(bi3), Integer(bi1), Integer(bi6)},
{LeftShift, Rational(br3), Rational(br1), Rational(br6)},
{LeftShift, intConst(int32TypeN, 3), intConst(int32TypeN, 1), intConst(int32TypeN, 6)},
{LeftShift, uintConst(uint32TypeN, 3), uintConst(uint32TypeN, 1), uintConst(uint32TypeN, 6)},
{RightShift, Integer(bi5), Integer(bi1), Integer(bi2)},
{RightShift, Rational(br5), Rational(br1), Rational(br2)},
{RightShift, intConst(int32TypeN, 5), intConst(int32TypeN, 1), intConst(int32TypeN, 2)},
{RightShift, uintConst(uint32TypeN, 5), uintConst(uint32TypeN, 1), uintConst(uint32TypeN, 2)},
}
for _, test := range tests {
result, err := EvalBinary(test.op, test.x, test.y)
if got, want := result, test.expect; !constEqual(got, want) {
t.Errorf("EvalBinary(%v, %v, %v) result got %v, want %v", test.op, test.x, test.y, got, want)
}
expectErr(t, err, "", "EvalBinary(%v, %v, %v)", test.op, test.x, test.y)
}
}
func expectComp(t *testing.T, op BinaryOp, x, y Const, expect bool) {
result, err := EvalBinary(op, x, y)
if got, want := result, Boolean(expect); !constEqual(got, want) {
t.Errorf("EvalBinary(%v, %v, %v) result got %v, want %v", op, x, y, got, want)
}
expectErr(t, err, "", "EvalBinary(%v, %v, %v)", op, x, y)
}
func TestConstEQNE(t *testing.T) {
tests := []struct {
x, y Const // x != y
}{
{Boolean(false), Boolean(true)},
{String("abc"), String("def")},
{boolConst(boolTypeN, false), boolConst(boolTypeN, true)},
{structNumConst(structAIntTypeN, 1), structNumConst(structAIntTypeN, 2)},
}
for _, test := range tests {
expectComp(t, EQ, test.x, test.x, true)
expectComp(t, EQ, test.x, test.y, false)
expectComp(t, EQ, test.y, test.x, false)
expectComp(t, EQ, test.y, test.y, true)
expectComp(t, NE, test.x, test.x, false)
expectComp(t, NE, test.x, test.y, true)
expectComp(t, NE, test.y, test.x, true)
expectComp(t, NE, test.y, test.y, false)
}
}
func TestConstOrdered(t *testing.T) {
tests := []struct {
x, y Const // x < y
}{
{String("abc"), String("def")},
{Integer(bi1), Integer(bi2)},
{Rational(br1), Rational(br2)},
{stringConst(stringTypeN, "abc"), stringConst(stringTypeN, "def")},
{bytesConst(bytesTypeN, "abc"), bytesConst(bytesTypeN, "def")},
{bytesConst(bytes3TypeN, "abc"), bytesConst(bytes3TypeN, "def")},
{intConst(int32TypeN, 1), intConst(int32TypeN, 2)},
{uintConst(uint32TypeN, 1), uintConst(uint32TypeN, 2)},
{floatConst(float32TypeN, 1), floatConst(float32TypeN, 2)},
}
for _, test := range tests {
expectComp(t, EQ, test.x, test.x, true)
expectComp(t, EQ, test.x, test.y, false)
expectComp(t, EQ, test.y, test.x, false)
expectComp(t, EQ, test.y, test.y, true)
expectComp(t, NE, test.x, test.x, false)
expectComp(t, NE, test.x, test.y, true)
expectComp(t, NE, test.y, test.x, true)
expectComp(t, NE, test.y, test.y, false)
expectComp(t, LT, test.x, test.x, false)
expectComp(t, LT, test.x, test.y, true)
expectComp(t, LT, test.y, test.x, false)
expectComp(t, LT, test.y, test.y, false)
expectComp(t, LE, test.x, test.x, true)
expectComp(t, LE, test.x, test.y, true)
expectComp(t, LE, test.y, test.x, false)
expectComp(t, LE, test.y, test.y, true)
expectComp(t, GT, test.x, test.x, false)
expectComp(t, GT, test.x, test.y, false)
expectComp(t, GT, test.y, test.x, true)
expectComp(t, GT, test.y, test.y, false)
expectComp(t, GE, test.x, test.x, true)
expectComp(t, GE, test.x, test.y, false)
expectComp(t, GE, test.y, test.x, true)
expectComp(t, GE, test.y, test.y, true)
}
}
type bo []BinaryOp
func TestConstBinaryOpError(t *testing.T) {
// For each op in Bops and each x in C, (x op x) returns errstr.
tests := []struct {
Bops bo
C c
errstr string
}{
// Type not supported / can't convert errors
{bo{LogicAnd, LogicOr},
c{String("abc"),
stringConst(stringTypeN, "abc"),
bytesConst(bytesTypeN, "abc"), bytesConst(bytes3TypeN, "abc"),
Integer(bi1), intConst(int32TypeN, 1), uintConst(uint32TypeN, 1),
Rational(br1), floatConst(float32TypeN, 1),
structNumConst(structAIntType, 1), structNumConst(structAIntTypeN, 1)},
notSupported},
{bo{LT, LE, GT, GE},
c{Boolean(true), boolConst(boolTypeN, false),
structNumConst(structAIntType, 1), structNumConst(structAIntTypeN, 1)},
notSupported},
{bo{Add},
c{structNumConst(structAIntType, 1), structNumConst(structAIntTypeN, 1)},
notSupported},
{bo{Sub, Mul, Div},
c{String("abc"), stringConst(stringTypeN, "abc"),
bytesConst(bytesTypeN, "abc"), bytesConst(bytes3TypeN, "abc"),
structNumConst(structAIntType, 1), structNumConst(structAIntTypeN, 1)},
notSupported},
{bo{Mod, BitAnd, BitOr, BitXor, LeftShift, RightShift},
c{String("abc"), stringConst(stringTypeN, "abc"),
bytesConst(bytesTypeN, "abc"), bytesConst(bytes3TypeN, "abc"),
structNumConst(structAIntType, 1), structNumConst(structAIntTypeN, 1)},
cantConvert},
// Bounds checking
{bo{Add}, c{uintConst(uint32TypeN, 1<<31)}, overflows},
{bo{Mul}, c{uintConst(uint32TypeN, 1<<16)}, overflows},
{bo{Div}, c{uintConst(uint32TypeN, 0)}, divByZero},
{bo{LeftShift}, c{uintConst(uint32TypeN, 32)}, overflows},
}
for _, test := range tests {
for _, op := range test.Bops {
for _, c := range test.C {
result, err := EvalBinary(op, c, c)
if result.IsValid() {
t.Errorf("EvalBinary(%v, %v, %v) result got %v, want invalid", op, c, c, result)
}
expectErr(t, err, test.errstr, "EvalBinary(%v, %v, %v)", op, c, c)
}
}
}
}