diff --git a/WORKSPACE b/WORKSPACE index 2f2ccf86..4da558de 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -109,7 +109,7 @@ go_repository( # CEL Spec deps go_repository( name = "com_google_cel_spec", - commit = "1a26bb4e2a611b694367e7579e74b68b17ebc536", + commit = "ad5c42c7f0a66f7ea43bd7299c0397ceef23beb5", importpath = "github.com/google/cel-spec", ) diff --git a/common/types/double.go b/common/types/double.go index 54c66faa..2a679137 100644 --- a/common/types/double.go +++ b/common/types/double.go @@ -16,7 +16,6 @@ package types import ( "fmt" - "math" "reflect" "github.com/google/cel-go/common/types/ref" @@ -52,7 +51,7 @@ var ( func (d Double) Add(other ref.Val) ref.Val { otherDouble, ok := other.(Double) if !ok { - return ValOrErr(other, "no such overload") + return MaybeNoSuchOverloadErr(other) } return d + otherDouble } @@ -61,7 +60,7 @@ func (d Double) Add(other ref.Val) ref.Val { func (d Double) Compare(other ref.Val) ref.Val { otherDouble, ok := other.(Double) if !ok { - return ValOrErr(other, "no such overload") + return MaybeNoSuchOverloadErr(other) } if d < otherDouble { return IntNegOne @@ -127,17 +126,17 @@ func (d Double) ConvertToNative(typeDesc reflect.Type) (interface{}, error) { func (d Double) ConvertToType(typeVal ref.Type) ref.Val { switch typeVal { case IntType: - i := math.Round(float64(d)) - if i > math.MaxInt64 || i < math.MinInt64 { - return NewErr("range error converting %g to int", float64(d)) + i, err := doubleToInt64Checked(float64(d)) + if err != nil { + return wrapErr(err) } - return Int(float64(i)) + return Int(i) case UintType: - i := math.Round(float64(d)) - if i > math.MaxUint64 || i < 0 { - return NewErr("range error converting %g to int", float64(d)) + i, err := doubleToUint64Checked(float64(d)) + if err != nil { + return wrapErr(err) } - return Uint(float64(i)) + return Uint(i) case DoubleType: return d case StringType: @@ -152,7 +151,7 @@ func (d Double) ConvertToType(typeVal ref.Type) ref.Val { func (d Double) Divide(other ref.Val) ref.Val { otherDouble, ok := other.(Double) if !ok { - return ValOrErr(other, "no such overload") + return MaybeNoSuchOverloadErr(other) } return d / otherDouble } @@ -161,7 +160,7 @@ func (d Double) Divide(other ref.Val) ref.Val { func (d Double) Equal(other ref.Val) ref.Val { otherDouble, ok := other.(Double) if !ok { - return ValOrErr(other, "no such overload") + return MaybeNoSuchOverloadErr(other) } // TODO: Handle NaNs properly. return Bool(d == otherDouble) @@ -171,7 +170,7 @@ func (d Double) Equal(other ref.Val) ref.Val { func (d Double) Multiply(other ref.Val) ref.Val { otherDouble, ok := other.(Double) if !ok { - return ValOrErr(other, "no such overload") + return MaybeNoSuchOverloadErr(other) } return d * otherDouble } @@ -185,7 +184,7 @@ func (d Double) Negate() ref.Val { func (d Double) Subtract(subtrahend ref.Val) ref.Val { subtraDouble, ok := subtrahend.(Double) if !ok { - return ValOrErr(subtrahend, "no such overload") + return MaybeNoSuchOverloadErr(subtrahend) } return d - subtraDouble } diff --git a/common/types/double_test.go b/common/types/double_test.go index f5703b52..683690aa 100644 --- a/common/types/double_test.go +++ b/common/types/double_test.go @@ -15,10 +15,13 @@ package types import ( + "errors" "math" "reflect" + "strings" "testing" + "github.com/google/cel-go/common/types/ref" "google.golang.org/protobuf/proto" anypb "google.golang.org/protobuf/types/known/anypb" @@ -167,23 +170,110 @@ func TestDoubleConvertToNative_Wrapper(t *testing.T) { } func TestDoubleConvertToType(t *testing.T) { - if !Double(-4.5).ConvertToType(IntType).Equal(Int(-5)).(Bool) { - t.Error("Unsuccessful type conversion to int") - } - if !IsError(Double(-4.5).ConvertToType(UintType)) { - t.Error("Got uint, expected error") - } - if !Double(-4.5).ConvertToType(DoubleType).Equal(Double(-4.5)).(Bool) { - t.Error("Unsuccessful type conversion to double") - } - if !Double(-4.5).ConvertToType(StringType).Equal(String("-4.5")).(Bool) { - t.Error("Unsuccessful type conversion to string") - } - if !Double(-4.5).ConvertToType(TypeType).Equal(DoubleType).(Bool) { - t.Error("Unsuccessful type conversion to type") - } - if !IsError(Double(-4.5).ConvertToType(TimestampType)) { - t.Error("Got value, expected error") + tests := []struct { + name string + in float64 + toType ref.Type + out interface{} + }{ + { + name: "DoubleToDouble", + in: float64(-4.2), + toType: DoubleType, + out: float64(-4.2), + }, + { + name: "DoubleToType", + in: float64(-4.2), + toType: TypeType, + out: DoubleType.TypeName(), + }, + { + name: "DoubleToInt", + in: float64(4.2), + toType: IntType, + out: int64(4), + }, + { + name: "DoubleToIntNaN", + in: math.NaN(), + toType: IntType, + out: errIntOverflow, + }, + { + name: "DoubleToIntPosInf", + in: math.Inf(1), + toType: IntType, + out: errIntOverflow, + }, + { + name: "DoubleToIntPosOverflow", + in: float64(math.MaxInt64), + toType: IntType, + out: errIntOverflow, + }, + { + name: "DoubleToIntNegOverflow", + in: float64(math.MinInt64), + toType: IntType, + out: errIntOverflow, + }, + { + name: "DoubleToUint", + in: float64(4.7), + toType: UintType, + out: uint64(4), + }, + { + name: "DoubleToUintNaN", + in: math.NaN(), + toType: UintType, + out: errUintOverflow, + }, + { + name: "DoubleToUintPosInf", + in: math.Inf(1), + toType: UintType, + out: errUintOverflow, + }, + { + name: "DoubleToUintPosOverflow", + in: float64(math.MaxUint64), + toType: UintType, + out: errUintOverflow, + }, + { + name: "DoubleToUintNegOverflow", + in: float64(-0.1), + toType: UintType, + out: errUintOverflow, + }, + { + name: "DoubleToString", + in: float64(4.5), + toType: StringType, + out: "4.5", + }, + { + name: "DoubleToUnsupportedType", + in: float64(4), + toType: MapType, + out: errors.New("type conversion error"), + }, + } + for _, tst := range tests { + got := Double(tst.in).ConvertToType(tst.toType).Value() + var eq bool + switch gotVal := got.(type) { + case error: + eq = strings.Contains(gotVal.Error(), tst.out.(error).Error()) + default: + eq = reflect.DeepEqual(gotVal, tst.out) + } + if !eq { + t.Errorf("Double(%v).ConvertToType(%v) failed, got: %v, wanted: %v", + tst.in, tst.toType, got, tst.out) + } } } diff --git a/common/types/duration.go b/common/types/duration.go index 28132206..e9be4e32 100644 --- a/common/types/duration.go +++ b/common/types/duration.go @@ -55,25 +55,27 @@ func (d Duration) Add(other ref.Val) ref.Val { switch other.Type() { case DurationType: dur2 := other.(Duration) - if val, ok := addDurationChecked(d.Duration, dur2.Duration); ok { + if val, err := addDurationChecked(d.Duration, dur2.Duration); err != nil { + return wrapErr(err) + } else { return durationOf(val) } - return errDurationOverflow case TimestampType: ts := other.(Timestamp).Time - if val, ok := addTimeDurationChecked(ts, d.Duration); ok { + if val, err := addTimeDurationChecked(ts, d.Duration); err != nil { + return wrapErr(err) + } else { return timestampOf(val) } - return errTimestampOverflow } - return ValOrErr(other, "no such overload") + return MaybeNoSuchOverloadErr(other) } // Compare implements traits.Comparer.Compare. func (d Duration) Compare(other ref.Val) ref.Val { otherDur, ok := other.(Duration) if !ok { - return ValOrErr(other, "no such overload") + return MaybeNoSuchOverloadErr(other) } d1 := d.Duration d2 := otherDur.Duration @@ -134,17 +136,18 @@ func (d Duration) ConvertToType(typeVal ref.Type) ref.Val { func (d Duration) Equal(other ref.Val) ref.Val { otherDur, ok := other.(Duration) if !ok { - return ValOrErr(other, "no such overload") + return MaybeNoSuchOverloadErr(other) } return Bool(d.Duration == otherDur.Duration) } // Negate implements traits.Negater.Negate. func (d Duration) Negate() ref.Val { - if val, ok := negateDurationChecked(d.Duration); ok { + if val, err := negateDurationChecked(d.Duration); err != nil { + return wrapErr(err) + } else { return durationOf(val) } - return errDurationOverflow } // Receive implements traits.Receiver.Receive. @@ -154,19 +157,20 @@ func (d Duration) Receive(function string, overload string, args []ref.Val) ref. return f(d.Duration) } } - return NewErr("no such overload") + return NoSuchOverloadErr() } // Subtract implements traits.Subtractor.Subtract. func (d Duration) Subtract(subtrahend ref.Val) ref.Val { subtraDur, ok := subtrahend.(Duration) if !ok { - return ValOrErr(subtrahend, "no such overload") + return MaybeNoSuchOverloadErr(subtrahend) } - if val, ok := subtractDurationChecked(d.Duration, subtraDur.Duration); ok { + if val, err := subtractDurationChecked(d.Duration, subtraDur.Duration); err != nil { + return wrapErr(err) + } else { return durationOf(val) } - return errDurationOverflow } // Type implements ref.Val.Type. diff --git a/common/types/duration_test.go b/common/types/duration_test.go index 0a598482..7815742b 100644 --- a/common/types/duration_test.go +++ b/common/types/duration_test.go @@ -29,23 +29,83 @@ import ( structpb "google.golang.org/protobuf/types/known/structpb" ) -func TestDurationAdd(t *testing.T) { - dur := &dpb.Duration{Seconds: 7506} - d := Duration{Duration: dur.AsDuration()} - if !d.Add(d).Equal(Duration{(&dpb.Duration{Seconds: 15012}).AsDuration()}).(Bool) { - t.Error("Adding duration and itself did not double it.") - } - if lhs, rhs := time.Duration(math.MaxInt64), time.Duration(1); !IsError(durationOf(lhs).Add(durationOf(rhs))) { - t.Errorf("Expected adding %d and %d to result in overflow.", lhs, rhs) - } - if lhs, rhs := time.Duration(math.MinInt64), time.Duration(-1); !IsError(durationOf(lhs).Add(durationOf(rhs))) { - t.Errorf("Expected adding %d and %d to result in overflow.", lhs, rhs) - } - if lhs, rhs := time.Duration(math.MaxInt64-1), time.Duration(1); !durationOf(lhs).Add(durationOf(rhs)).Equal(durationOf(math.MaxInt64)).(Bool) { - t.Errorf("Expected adding %d and %d to yield %d", lhs, rhs, math.MaxInt64) - } - if lhs, rhs := time.Duration(math.MinInt64+1), time.Duration(-1); !durationOf(lhs).Add(durationOf(rhs)).Equal(durationOf(math.MinInt64)).(Bool) { - t.Errorf("Expected adding %d and %d to yield %d", lhs, rhs, math.MaxInt64) +func TestDurationOperators(t *testing.T) { + d := duration(7506, 567) + dSecond := duration(1, 0) + dNano := duration(0, 1) + dMax := duration(0, math.MaxInt64) + dMin := duration(0, math.MinInt64) + + tests := []struct { + name string + op func() ref.Val + out interface{} + }{ + // Addition tests. + { + name: "DurationAddSelf", + op: func() ref.Val { + return durationOf(d).Add(durationOf(d)) + }, + out: d + d, + }, + { + name: "DurationMaxAddOneNanoOverflow", + op: func() ref.Val { + return durationOf(dMax).Add(durationOf(dNano)) + }, + out: errIntOverflow, + }, + { + name: "DurationMaxAddOneSecondOverflow", + op: func() ref.Val { + return durationOf(dMax).Add(durationOf(dSecond)) + }, + out: errIntOverflow, + }, + { + name: "DurationMinAddMinusOneOverflow", + op: func() ref.Val { + return durationOf(dMin).Add(durationOf(-dSecond)) + }, + out: errIntOverflow, + }, + + // Subtraction tests. + { + name: "DurationSubSelf", + op: func() ref.Val { + return durationOf(d).Subtract(durationOf(d)) + }, + out: duration(0, 0), + }, + { + name: "DurationMaxSubMinusOneOverflow", + op: func() ref.Val { + return durationOf(dMax).Subtract(durationOf(-dNano)) + }, + out: errIntOverflow, + }, + { + name: "DurationMinSubOneOverflow", + op: func() ref.Val { + return durationOf(dMin).Subtract(durationOf(dNano)) + }, + out: errIntOverflow, + }, + } + for _, tst := range tests { + got := tst.op() + switch v := got.Value().(type) { + case error: + if want, ok := tst.out.(error); !ok || v.Error() != want.Error() { + t.Errorf("%s: got %v, wanted %v", tst.name, v, tst.out) + } + default: + if !reflect.DeepEqual(v, tst.out) { + t.Errorf("%s: got %v, wanted %v", tst.name, v, tst.out) + } + } } } @@ -194,25 +254,6 @@ func TestDurationGetMilliseconds(t *testing.T) { } } -func TestDurationSubtract(t *testing.T) { - d := Duration{Duration: duration(7506, 0)} - if !d.Subtract(d).ConvertToType(IntType).Equal(IntZero).(Bool) { - t.Error("Subtracting a duration from itself did not equal zero.") - } - if lhs, rhs := time.Duration(math.MaxInt64), time.Duration(-1); !IsError(durationOf(lhs).Subtract(durationOf(rhs))) { - t.Errorf("Expected subtracting %d and %d to result in overflow.", lhs, rhs) - } - if lhs, rhs := time.Duration(math.MinInt64), time.Duration(1); !IsError(durationOf(lhs).Subtract(durationOf(rhs))) { - t.Errorf("Expected subtracting %d and %d to result in overflow.", lhs, rhs) - } - if lhs, rhs := time.Duration(math.MaxInt64-1), time.Duration(-1); !durationOf(lhs).Subtract(durationOf(rhs)).Equal(durationOf(math.MaxInt64)).(Bool) { - t.Errorf("Expected subtracting %d and %d to yield %d", lhs, rhs, math.MaxInt64) - } - if lhs, rhs := time.Duration(math.MinInt64+1), time.Duration(1); !durationOf(lhs).Subtract(durationOf(rhs)).Equal(durationOf(math.MinInt64)).(Bool) { - t.Errorf("Expected subtracting %d and %d to yield %d", lhs, rhs, math.MinInt64) - } -} - func duration(seconds, nanos int64) time.Duration { return time.Duration(seconds)*time.Second + time.Duration(nanos) } diff --git a/common/types/err.go b/common/types/err.go index 55700c90..1ae247f4 100644 --- a/common/types/err.go +++ b/common/types/err.go @@ -15,6 +15,7 @@ package types import ( + "errors" "fmt" "reflect" @@ -30,14 +31,22 @@ var ( // ErrType singleton. ErrType = NewTypeValue("error") + // errDivideByZero is an error indicating a division by zero of an integer value. + errDivideByZero = errors.New("division by zero") + // errModulusByZero is an error indicating a modulus by zero of an integer value. + errModulusByZero = errors.New("modulus by zero") // errIntOverflow is an error representing integer overflow. - errIntOverflow = NewErr("integer overflow") + errIntOverflow = errors.New("integer overflow") // errUintOverflow is an error representing unsigned integer overflow. - errUintOverflow = NewErr("unsigned integer overflow") + errUintOverflow = errors.New("unsigned integer overflow") // errDurationOverflow is an error representing duration overflow. - errDurationOverflow = NewErr("duration overflow") + errDurationOverflow = errors.New("duration overflow") // errTimestampOverflow is an error representing timestamp overflow. - errTimestampOverflow = NewErr("timestamp overflow") + errTimestampOverflow = errors.New("timestamp overflow") + celErrTimestampOverflow = &Err{error: errTimestampOverflow} + + // celErrNoSuchOverload indicates that the call arguments did not match a supported method signature. + celErrNoSuchOverload = NewErr("no such overload") ) // NewErr creates a new Err described by the format string and args. @@ -48,7 +57,7 @@ func NewErr(format string, args ...interface{}) ref.Val { // NoSuchOverloadErr returns a new types.Err instance with a no such overload message. func NoSuchOverloadErr() ref.Val { - return NewErr("no such overload") + return celErrNoSuchOverload } // UnsupportedRefValConversionErr returns a types.NewErr instance with a no such conversion @@ -77,6 +86,11 @@ func ValOrErr(val ref.Val, format string, args ...interface{}) ref.Val { } } +// wrapErr wraps an existing Go error value into a CEL Err value. +func wrapErr(err error) ref.Val { + return &Err{error: err} +} + // ConvertToNative implements ref.Val.ConvertToNative. func (e *Err) ConvertToNative(typeDesc reflect.Type) (interface{}, error) { return nil, e.error diff --git a/common/types/int.go b/common/types/int.go index e604da42..5a282cb3 100644 --- a/common/types/int.go +++ b/common/types/int.go @@ -61,19 +61,20 @@ var ( func (i Int) Add(other ref.Val) ref.Val { otherInt, ok := other.(Int) if !ok { - return ValOrErr(other, "no such overload") + return MaybeNoSuchOverloadErr(other) } - if val, ok := addInt64Checked(int64(i), int64(otherInt)); ok { + if val, err := addInt64Checked(int64(i), int64(otherInt)); err != nil { + return wrapErr(err) + } else { return Int(val) } - return errIntOverflow } // Compare implements traits.Comparer.Compare. func (i Int) Compare(other ref.Val) ref.Val { otherInt, ok := other.(Int) if !ok { - return ValOrErr(other, "no such overload") + return MaybeNoSuchOverloadErr(other) } if i < otherInt { return IntNegOne @@ -87,11 +88,17 @@ func (i Int) Compare(other ref.Val) ref.Val { // ConvertToNative implements ref.Val.ConvertToNative. func (i Int) ConvertToNative(typeDesc reflect.Type) (interface{}, error) { switch typeDesc.Kind() { - case reflect.Int, reflect.Int32, reflect.Int64: + case reflect.Int, reflect.Int32: // Enums are also mapped as int32 derivations. // Note, the code doesn't convert to the enum value directly since this is not known, but // the net effect with respect to proto-assignment is handled correctly by the reflection // Convert method. + v, err := int64ToInt32Checked(int64(i)) + if err != nil { + return nil, err + } + return reflect.ValueOf(v).Convert(typeDesc).Interface(), nil + case reflect.Int64: return reflect.ValueOf(i).Convert(typeDesc).Interface(), nil case reflect.Ptr: switch typeDesc { @@ -99,8 +106,12 @@ func (i Int) ConvertToNative(typeDesc reflect.Type) (interface{}, error) { // Primitives must be wrapped before being set on an Any field. return anypb.New(wrapperspb.Int64(int64(i))) case int32WrapperType: - // Convert the value to a wrapperspb.Int32Value (with truncation). - return wrapperspb.Int32(int32(i)), nil + // Convert the value to a wrapperspb.Int32Value, error on overflow. + v, err := int64ToInt32Checked(int64(i)) + if err != nil { + return nil, err + } + return wrapperspb.Int32(v), nil case int64WrapperType: // Convert the value to a wrapperspb.Int64Value. return wrapperspb.Int64(int64(i)), nil @@ -128,7 +139,11 @@ func (i Int) ConvertToNative(typeDesc reflect.Type) (interface{}, error) { } switch typeDesc.Elem().Kind() { case reflect.Int32: - v := int32(i) + // Convert the value to a wrapperspb.Int32Value, error on overflow. + v, err := int64ToInt32Checked(int64(i)) + if err != nil { + return nil, err + } p := reflect.New(typeDesc.Elem()) p.Elem().Set(reflect.ValueOf(v).Convert(typeDesc.Elem())) return p.Interface(), nil @@ -156,10 +171,11 @@ func (i Int) ConvertToType(typeVal ref.Type) ref.Val { case IntType: return i case UintType: - if i < 0 { - return NewErr("range error converting %d to uint", i) + u, err := int64ToUint64Checked(int64(i)) + if err != nil { + return wrapErr(err) } - return Uint(i) + return Uint(u) case DoubleType: return Double(i) case StringType: @@ -168,7 +184,7 @@ func (i Int) ConvertToType(typeVal ref.Type) ref.Val { // The maximum positive value that can be passed to time.Unix is math.MaxInt64 minus the number // of seconds between year 1 and year 1970. See comments on unixToInternal. if int64(i) < minUnixTime || int64(i) > maxUnixTime { - return errTimestampOverflow + return celErrTimestampOverflow } return timestampOf(time.Unix(int64(i), 0).UTC()) case TypeType: @@ -181,22 +197,20 @@ func (i Int) ConvertToType(typeVal ref.Type) ref.Val { func (i Int) Divide(other ref.Val) ref.Val { otherInt, ok := other.(Int) if !ok { - return ValOrErr(other, "no such overload") + return MaybeNoSuchOverloadErr(other) } - if otherInt == IntZero { - return NewErr("divide by zero") - } - if val, ok := divideInt64Checked(int64(i), int64(otherInt)); ok { + if val, err := divideInt64Checked(int64(i), int64(otherInt)); err != nil { + return wrapErr(err) + } else { return Int(val) } - return errIntOverflow } // Equal implements ref.Val.Equal. func (i Int) Equal(other ref.Val) ref.Val { otherInt, ok := other.(Int) if !ok { - return ValOrErr(other, "no such overload") + return MaybeNoSuchOverloadErr(other) } return Bool(i == otherInt) } @@ -205,47 +219,48 @@ func (i Int) Equal(other ref.Val) ref.Val { func (i Int) Modulo(other ref.Val) ref.Val { otherInt, ok := other.(Int) if !ok { - return ValOrErr(other, "no such overload") - } - if otherInt == IntZero { - return NewErr("modulus by zero") + return MaybeNoSuchOverloadErr(other) } - if val, ok := moduloInt64Checked(int64(i), int64(otherInt)); ok { + if val, err := moduloInt64Checked(int64(i), int64(otherInt)); err != nil { + return wrapErr(err) + } else { return Int(val) } - return errIntOverflow } // Multiply implements traits.Multiplier.Multiply. func (i Int) Multiply(other ref.Val) ref.Val { otherInt, ok := other.(Int) if !ok { - return ValOrErr(other, "no such overload") + return MaybeNoSuchOverloadErr(other) } - if val, ok := multiplyInt64Checked(int64(i), int64(otherInt)); ok { + if val, err := multiplyInt64Checked(int64(i), int64(otherInt)); err != nil { + return wrapErr(err) + } else { return Int(val) } - return errIntOverflow } // Negate implements traits.Negater.Negate. func (i Int) Negate() ref.Val { - if val, ok := negateInt64Checked(int64(i)); ok { + if val, err := negateInt64Checked(int64(i)); err != nil { + return wrapErr(err) + } else { return Int(val) } - return errIntOverflow } // Subtract implements traits.Subtractor.Subtract. func (i Int) Subtract(subtrahend ref.Val) ref.Val { subtraInt, ok := subtrahend.(Int) if !ok { - return ValOrErr(subtrahend, "no such overload") + return MaybeNoSuchOverloadErr(subtrahend) } - if val, ok := subtractInt64Checked(int64(i), int64(subtraInt)); ok { + if val, err := subtractInt64Checked(int64(i), int64(subtraInt)); err != nil { + return wrapErr(err) + } else { return Int(val) } - return errIntOverflow } // Type implements ref.Val.Type. diff --git a/common/types/int_test.go b/common/types/int_test.go index 884e5e12..07e46dde 100644 --- a/common/types/int_test.go +++ b/common/types/int_test.go @@ -15,11 +15,14 @@ package types import ( + "errors" "math" "reflect" + "strings" "testing" "time" + "github.com/google/cel-go/common/types/ref" "google.golang.org/protobuf/proto" anypb "google.golang.org/protobuf/types/known/anypb" @@ -89,10 +92,17 @@ func TestIntConvertToNative_Error(t *testing.T) { func TestIntConvertToNative_Int32(t *testing.T) { val, err := Int(20050).ConvertToNative(reflect.TypeOf(int32(0))) if err != nil { - t.Error(err) - } else if val.(int32) != 20050 { + t.Fatalf("Int.ConvertToNative(int32) failed: %v", err) + } + if val.(int32) != 20050 { t.Errorf("Got '%v', expected 20050", val) } + val, err = Int(math.MaxInt32 + 1).ConvertToNative(reflect.TypeOf(int32(0))) + if err == nil { + t.Errorf("(MaxInt+1).ConvertToNative(int32) did not error, got: %v", val) + } else if !strings.Contains(err.Error(), "integer overflow") { + t.Errorf("ConvertToNative(int32) returned unexpected error: %v, wanted integer overflow", err) + } } func TestIntConvertToNative_Int64(t *testing.T) { @@ -172,28 +182,88 @@ func TestIntConvertToNative_Wrapper(t *testing.T) { } func TestIntConvertToType(t *testing.T) { - if !Int(-4).ConvertToType(IntType).Equal(Int(-4)).(Bool) { - t.Error("Unsuccessful type conversion to int") - } - if !IsError(Int(-4).ConvertToType(UintType)) { - t.Error("Got uint, expected error.") - } - if !Int(-4).ConvertToType(DoubleType).Equal(Double(-4)).(Bool) { - t.Error("Unsuccessful type conversion to double") - } - if !Int(-4).ConvertToType(StringType).Equal(String("-4")).(Bool) { - t.Error("Unsuccessful type conversion to string") - } - if !Int(-4).ConvertToType(TypeType).Equal(IntType).(Bool) { - t.Error("Unsuccessful type conversion to type") - } - if !IsError(Int(-4).ConvertToType(DurationType)) { - t.Error("Got duration, expected error.") - } - tm := time.Unix(946684800, 0).UTC() - celts := Timestamp{Time: tm} - if !Int(946684800).ConvertToType(TimestampType).Equal(celts).(Bool) { - t.Error("unsuccessful type conversion to timestamp") + tests := []struct { + name string + in int64 + toType ref.Type + out interface{} + }{ + { + name: "IntToType", + in: int64(4), + toType: TypeType, + out: IntType.TypeName(), + }, + { + name: "IntToInt", + in: int64(4), + toType: IntType, + out: int64(4), + }, + { + name: "IntToUint", + in: int64(4), + toType: UintType, + out: uint64(4), + }, + { + name: "IntToUintOverflow", + in: -1, + toType: UintType, + out: errUintOverflow, + }, + { + name: "IntToDouble", + in: int64(4), + toType: DoubleType, + out: float64(4), + }, + { + name: "IntToString", + in: int64(-4), + toType: StringType, + out: "-4", + }, + { + name: "IntToTimestamp", + in: int64(946684800), + toType: TimestampType, + out: time.Unix(946684800, 0).UTC(), + }, + { + name: "IntToTimestampPosOverflow", + in: maxUnixTime + 1, + toType: TimestampType, + out: errTimestampOverflow, + }, + { + name: "IntToTimestampMinOverflow", + in: minUnixTime - 1, + toType: TimestampType, + out: errTimestampOverflow, + }, + { + name: "IntToUnsupportedType", + in: int64(4), + toType: DurationType, + out: errors.New("type conversion error"), + }, + } + for _, tst := range tests { + got := Int(tst.in).ConvertToType(tst.toType).Value() + var eq bool + switch gotVal := got.(type) { + case time.Time: + eq = gotVal.Equal(tst.out.(time.Time)) + case error: + eq = strings.Contains(gotVal.Error(), tst.out.(error).Error()) + default: + eq = reflect.DeepEqual(gotVal, tst.out) + } + if !eq { + t.Errorf("Int(%v).ConvertToType(%v) failed, got: %v, wanted: %v", + tst.in, tst.toType, got, tst.out) + } } } diff --git a/common/types/overflow.go b/common/types/overflow.go index d288bbeb..48cc6ece 100644 --- a/common/types/overflow.go +++ b/common/types/overflow.go @@ -19,41 +19,45 @@ import ( "time" ) -// addInt64Checked performs addition with overflow detection of two int64, returning the result of -// the addition if no overflow occurred as the first return value and a bool indicating whether no -// overflow occurred as the second return value. -func addInt64Checked(x, y int64) (int64, bool) { +var ( + doubleTwoTo64 = math.Ldexp(1.0, 64) +) + +// addInt64Checked performs addition with overflow detection of two int64 values. +// +// If the operation fails the error return value will be non-nil. +func addInt64Checked(x, y int64) (int64, error) { if (y > 0 && x > math.MaxInt64-y) || (y < 0 && x < math.MinInt64-y) { - return 0, false + return 0, errIntOverflow } - return x + y, true + return x + y, nil } -// subtractInt64Checked performs subtraction with overflow detection of two int64, returning the -// result of the subtraction if no overflow occurred as the first return value and a bool indicating -// whether no overflow occurred as the second return value. -func subtractInt64Checked(x, y int64) (int64, bool) { +// subtractInt64Checked performs subtraction with overflow detection of two int64 values. +// +// If the operation fails the error return value will be non-nil. +func subtractInt64Checked(x, y int64) (int64, error) { if (y < 0 && x > math.MaxInt64+y) || (y > 0 && x < math.MinInt64+y) { - return 0, false + return 0, errIntOverflow } - return x - y, true + return x - y, nil } -// negateInt64Checked performs negation with overflow detection of an int64, returning the -// result of the negation if no overflow occurred as the first return value and a bool indicating -// whether no overflow occurred as the second return value. -func negateInt64Checked(x int64) (int64, bool) { +// negateInt64Checked performs negation with overflow detection of an int64. +// +// If the operation fails the error return value will be non-nil. +func negateInt64Checked(x int64) (int64, error) { // In twos complement, negating MinInt64 would result in a valid of MaxInt64+1. if x == math.MinInt64 { - return 0, false + return 0, errIntOverflow } - return -x, true + return -x, nil } -// multiplyInt64Checked performs multiplication with overflow detection of two int64, returning the -// result of the multiplication if no overflow occurred as the first return value and a bool -// indicating whether no overflow occurred as the second return value. -func multiplyInt64Checked(x, y int64) (int64, bool) { +// multiplyInt64Checked performs multiplication with overflow detection of two int64 value. +// +// If the operation fails the error return value will be non-nil. +func multiplyInt64Checked(x, y int64) (int64, error) { // Detecting multiplication overflow is more complicated than the others. The first two detect // attempting to negate MinInt64, which would result in MaxInt64+1. The other four detect normal // overflow conditions. @@ -66,97 +70,130 @@ func multiplyInt64Checked(x, y int64) (int64, bool) { (x < 0 && y > 0 && x < math.MinInt64/y) || // x is negative, y is negative (x < 0 && y < 0 && y < math.MaxInt64/x) { - return 0, false + return 0, errIntOverflow } - return x * y, true + return x * y, nil } -// divideInt64Checked performs division with overflow detection of two int64, returning the -// result of the division if no overflow occurred as the first return value and a bool -// indicating whether no overflow occurred as the second return value. -func divideInt64Checked(x, y int64) (int64, bool) { +// divideInt64Checked performs division with overflow detection of two int64 values, +// as well as a division by zero check. +// +// If the operation fails the error return value will be non-nil. +func divideInt64Checked(x, y int64) (int64, error) { + // Division by zero. + if y == 0 { + return 0, errDivideByZero + } // In twos complement, negating MinInt64 would result in a valid of MaxInt64+1. if x == math.MinInt64 && y == -1 { - return 0, false + return 0, errIntOverflow } - return x / y, true + return x / y, nil } -// moduloInt64Checked performs modulo with overflow detection of two int64, returning the -// result of the modulo if no overflow occurred as the first return value and a bool -// indicating whether no overflow occurred as the second return value. -func moduloInt64Checked(x, y int64) (int64, bool) { +// moduloInt64Checked performs modulo with overflow detection of two int64 values +// as well as a modulus by zero check. +// +// If the operation fails the error return value will be non-nil. +func moduloInt64Checked(x, y int64) (int64, error) { + // Modulus by zero. + if y == 0 { + return 0, errModulusByZero + } // In twos complement, negating MinInt64 would result in a valid of MaxInt64+1. if x == math.MinInt64 && y == -1 { - return 0, false + return 0, errIntOverflow } - return x % y, true + return x % y, nil } -// addUint64Checked performs addition with overflow detection of two uint64, returning the result of -// the addition if no overflow occurred as the first return value and a bool indicating whether no -// overflow occurred as the second return value. -func addUint64Checked(x, y uint64) (uint64, bool) { +// addUint64Checked performs addition with overflow detection of two uint64 values. +// +// If the operation fails due to overflow the error return value will be non-nil. +func addUint64Checked(x, y uint64) (uint64, error) { if y > 0 && x > math.MaxUint64-y { - return 0, false + return 0, errUintOverflow } - return x + y, true + return x + y, nil } -// subtractUint64Checked performs subtraction with overflow detection of two uint64, returning the -// result of the subtraction if no overflow occurred as the first return value and a bool indicating -// whether no overflow occurred as the second return value. -func subtractUint64Checked(x, y uint64) (uint64, bool) { +// subtractUint64Checked performs subtraction with overflow detection of two uint64 values. +// +// If the operation fails due to overflow the error return value will be non-nil. +func subtractUint64Checked(x, y uint64) (uint64, error) { if y > x { - return 0, false + return 0, errUintOverflow } - return x - y, true + return x - y, nil } -// multiplyUint64Checked performs multiplication with overflow detection of two uint64, returning -// the result of the multiplication if no overflow occurred as the first return value and a bool -// indicating whether no overflow occurred as the second return value. -func multiplyUint64Checked(x, y uint64) (uint64, bool) { +// multiplyUint64Checked performs multiplication with overflow detection of two uint64 values. +// +// If the operation fails due to overflow the error return value will be non-nil. +func multiplyUint64Checked(x, y uint64) (uint64, error) { if y != 0 && x > math.MaxUint64/y { - return 0, false + return 0, errUintOverflow } - return x * y, true + return x * y, nil } -// addDurationChecked performs addition with overflow detection of two time.Duration, returning the -// result of the addition if no overflow occurred as the first return value and a bool indicating -// whether no overflow occurred as the second return value. -func addDurationChecked(x, y time.Duration) (time.Duration, bool) { - if val, ok := addInt64Checked(int64(x), int64(y)); ok { - return time.Duration(val), true +// divideUint64Checked performs division with a test for division by zero. +// +// If the operation fails the error return value will be non-nil. +func divideUint64Checked(x, y uint64) (uint64, error) { + if y == 0 { + return 0, errDivideByZero } - return time.Duration(0), false + return x / y, nil } -// subtractDurationChecked performs subtraction with overflow detection of two time.Duration, -// returning the result of the subtraction if no overflow occurred as the first return value and a -// bool indicating whether no overflow occurred as the second return value. -func subtractDurationChecked(x, y time.Duration) (time.Duration, bool) { - if val, ok := subtractInt64Checked(int64(x), int64(y)); ok { - return time.Duration(val), true +// moduloUint64Checked performs modulo with a test for modulus by zero. +// +// If the operation fails the error return value will be non-nil. +func moduloUint64Checked(x, y uint64) (uint64, error) { + if y == 0 { + return 0, errModulusByZero } - return time.Duration(0), false + return x % y, nil } -// negateDurationChecked performs negation with overflow detection of a time.Duration, returning the -// result of the negation if no overflow occurred as the first return value and a bool indicating -// whether no overflow occurred as the second return value. -func negateDurationChecked(x time.Duration) (time.Duration, bool) { - if val, ok := negateInt64Checked(int64(x)); ok { - return time.Duration(val), true +// addDurationChecked performs addition with overflow detection of two time.Durations. +// +// If the operation fails due to overflow the error return value will be non-nil. +func addDurationChecked(x, y time.Duration) (time.Duration, error) { + val, err := addInt64Checked(int64(x), int64(y)) + if err != nil { + return time.Duration(0), err } - return time.Duration(0), false + return time.Duration(val), nil } -// addDurationChecked performs addition with overflow detection of a time.Time and time.Duration, -// returning the result of the addition if no overflow occurred as the first return value and a bool -// indicating whether no overflow occurred as the second return value. -func addTimeDurationChecked(x time.Time, y time.Duration) (time.Time, bool) { +// subtractDurationChecked performs subtraction with overflow detection of two time.Durations. +// +// If the operation fails due to overflow the error return value will be non-nil. +func subtractDurationChecked(x, y time.Duration) (time.Duration, error) { + val, err := subtractInt64Checked(int64(x), int64(y)) + if err != nil { + return time.Duration(0), err + } + return time.Duration(val), nil +} + +// negateDurationChecked performs negation with overflow detection of a time.Duration. +// +// If the operation fails due to overflow the error return value will be non-nil. +func negateDurationChecked(x time.Duration) (time.Duration, error) { + val, err := negateInt64Checked(int64(x)) + if err != nil { + return time.Duration(0), err + } + return time.Duration(val), nil +} + +// addDurationChecked performs addition with overflow detection of a time.Time and time.Duration. +// +// If the operation fails due to overflow the error return value will be non-nil. +func addTimeDurationChecked(x time.Time, y time.Duration) (time.Time, error) { // This is tricky. A time is represented as (int64, int32) where the first is seconds and second // is nanoseconds. A duration is int64 representing nanoseconds. We cannot normalize time to int64 // as it could potentially overflow. The only way to proceed is to break time and duration into @@ -171,11 +208,10 @@ func addTimeDurationChecked(x time.Time, y time.Duration) (time.Time, bool) { nsec2 := int64(y) % int64(time.Second) // Get remainder. // Add seconds first, detecting any overflow. - sec, ok := addInt64Checked(sec1, sec2) - if !ok { - return time.Time{}, false + sec, err := addInt64Checked(sec1, sec2) + if err != nil { + return time.Time{}, err } - // Nanoseconds cannot overflow as time.Time normalizes them to [0, 999999999]. nsec := nsec1 + nsec2 @@ -183,16 +219,17 @@ func addTimeDurationChecked(x time.Time, y time.Duration) (time.Time, bool) { // Adapted from time.Unix(int64, int64). if nsec < 0 || nsec >= int64(time.Second) { // Add seconds. - sec, ok = addInt64Checked(sec, nsec/int64(time.Second)) - if !ok { - return time.Time{}, false + sec, err = addInt64Checked(sec, nsec/int64(time.Second)) + if err != nil { + return time.Time{}, err } + nsec -= (nsec / int64(time.Second)) * int64(time.Second) if nsec < 0 { // Subtract an extra second - sec, ok = addInt64Checked(sec, -1) - if !ok { - return time.Time{}, false + sec, err = addInt64Checked(sec, -1) + if err != nil { + return time.Time{}, err } nsec += int64(time.Second) } @@ -200,17 +237,17 @@ func addTimeDurationChecked(x time.Time, y time.Duration) (time.Time, bool) { // Check if the the number of seconds from Unix epoch is within our acceptable range. if sec < minUnixTime || sec > maxUnixTime { - return time.Time{}, false + return time.Time{}, errTimestampOverflow } // Return resulting time and propagate time zone. - return time.Unix(sec, nsec).In(x.Location()), true + return time.Unix(sec, nsec).In(x.Location()), nil } -// subtractTimeChecked performs subtraction with overflow detection of two time.Time, returning the -// result of the subtraction if no overflow occurred as the first return value and a bool indicating -// whether no overflow occurred as the second return value. -func subtractTimeChecked(x, y time.Time) (time.Duration, bool) { +// subtractTimeChecked performs subtraction with overflow detection of two time.Time. +// +// If the operation fails due to overflow the error return value will be non-nil. +func subtractTimeChecked(x, y time.Time) (time.Duration, error) { // Similar to addTimeDurationOverflow() above. // First we break time into its components by truncating and subtracting. @@ -222,57 +259,99 @@ func subtractTimeChecked(x, y time.Time) (time.Duration, bool) { nsec2 := y.Sub(y.Truncate(time.Second)).Nanoseconds() // Get nanoseconds by truncating and subtracting. // Subtract seconds first, detecting any overflow. - sec, ok := subtractInt64Checked(sec1, sec2) - if !ok { - return time.Duration(0), false + sec, err := subtractInt64Checked(sec1, sec2) + if err != nil { + return time.Duration(0), err } // Nanoseconds cannot overflow as time.Time normalizes them to [0, 999999999]. nsec := nsec1 - nsec2 - // We need to normalize nanoseconds to be positive and carry extra nanoseconds to seconds. - // Adapted from time.Unix(int64, int64). - if nsec < 0 || nsec >= int64(time.Second) { - // Add an extra second. - sec, ok = addInt64Checked(sec, nsec/int64(time.Second)) - if !ok { - return time.Duration(0), false - } - nsec -= (nsec / int64(time.Second)) * int64(time.Second) - if nsec < 0 { - // Subtract an extra second - sec, ok = addInt64Checked(sec, -1) - if !ok { - return time.Duration(0), false - } - nsec += int64(time.Second) - } - } - // Scale seconds to nanoseconds detecting overflow. - tsec, ok := multiplyInt64Checked(sec, int64(time.Second)) - if !ok { - return time.Duration(0), false + tsec, err := multiplyInt64Checked(sec, int64(time.Second)) + if err != nil { + return time.Duration(0), err } // Lastly we need to add the two nanoseconds together. - val, ok := addInt64Checked(tsec, nsec) - if !ok { - return time.Duration(0), false + val, err := addInt64Checked(tsec, nsec) + if err != nil { + return time.Duration(0), err } - return time.Duration(val), true + return time.Duration(val), nil } // subtractTimeDurationChecked performs subtraction with overflow detection of a time.Time and -// time.Duration, returning the result of the subtraction if no overflow occurred as the first -// return value and a bool indicating whether no overflow occurred as the second return value. -func subtractTimeDurationChecked(x time.Time, y time.Duration) (time.Time, bool) { +// time.Duration. +// +// If the operation fails due to overflow the error return value will be non-nil. +func subtractTimeDurationChecked(x time.Time, y time.Duration) (time.Time, error) { // The easiest way to implement this is to negate y and add them. // x - y = x + -y - val, ok := negateDurationChecked(y) - if !ok { - return time.Time{}, false + val, err := negateDurationChecked(y) + if err != nil { + return time.Time{}, err } return addTimeDurationChecked(x, val) } + +// doubleToInt64Checked converts a double to an int64 value. +// +// If the conversion fails due to overflow the error return value will be non-nil. +func doubleToInt64Checked(v float64) (int64, error) { + if math.IsInf(v, 0) || math.IsNaN(v) || v <= float64(math.MinInt64) || v >= float64(math.MaxInt64) { + return 0, errIntOverflow + } + return int64(v), nil +} + +// doubleToInt64Checked converts a double to a uint64 value. +// +// If the conversion fails due to overflow the error return value will be non-nil. +func doubleToUint64Checked(v float64) (uint64, error) { + if math.IsInf(v, 0) || math.IsNaN(v) || v < 0 || v >= doubleTwoTo64 { + return 0, errUintOverflow + } + return uint64(v), nil +} + +// int64toUint64Checked converts an int64 to a uint64 value. +// +// If the conversion fails due to overflow the error return value will be non-nil. +func int64ToUint64Checked(v int64) (uint64, error) { + if v < 0 { + return 0, errUintOverflow + } + return uint64(v), nil +} + +// int64toInt32Checked converts an int64 to an int32 value. +// +// If the conversion fails due to overflow the error return value will be non-nil. +func int64ToInt32Checked(v int64) (int32, error) { + if v < math.MinInt32 || v > math.MaxInt32 { + return 0, errIntOverflow + } + return int32(v), nil +} + +// uint64toUint32Checked converts a uint64 to a uint32 value. +// +// If the conversion fails due to overflow the error return value will be non-nil. +func uint64ToUint32Checked(v uint64) (uint32, error) { + if v > math.MaxUint32 { + return 0, errUintOverflow + } + return uint32(v), nil +} + +// uint64toInt64Checked converts a uint64 to an int64 value. +// +// If the conversion fails due to overflow the error return value will be non-nil. +func uint64ToInt64Checked(v uint64) (int64, error) { + if v > math.MaxInt64 { + return 0, errIntOverflow + } + return int64(v), nil +} diff --git a/common/types/string.go b/common/types/string.go index b4bb82d1..354d99b2 100644 --- a/common/types/string.go +++ b/common/types/string.go @@ -57,7 +57,7 @@ var ( func (s String) Add(other ref.Val) ref.Val { otherString, ok := other.(String) if !ok { - return ValOrErr(other, "no such overload") + return MaybeNoSuchOverloadErr(other) } return s + otherString } @@ -66,7 +66,7 @@ func (s String) Add(other ref.Val) ref.Val { func (s String) Compare(other ref.Val) ref.Val { otherString, ok := other.(String) if !ok { - return ValOrErr(other, "no such overload") + return MaybeNoSuchOverloadErr(other) } return Int(strings.Compare(s.Value().(string), otherString.Value().(string))) } @@ -136,7 +136,7 @@ func (s String) ConvertToType(typeVal ref.Type) ref.Val { case TimestampType: if t, err := time.Parse(time.RFC3339, s.Value().(string)); err == nil { if t.Unix() < minUnixTime || t.Unix() > maxUnixTime { - return errTimestampOverflow + return celErrTimestampOverflow } return timestampOf(t) } @@ -152,7 +152,7 @@ func (s String) ConvertToType(typeVal ref.Type) ref.Val { func (s String) Equal(other ref.Val) ref.Val { otherString, ok := other.(String) if !ok { - return ValOrErr(other, "no such overload") + return MaybeNoSuchOverloadErr(other) } return Bool(s == otherString) } @@ -161,7 +161,7 @@ func (s String) Equal(other ref.Val) ref.Val { func (s String) Match(pattern ref.Val) ref.Val { pat, ok := pattern.(String) if !ok { - return ValOrErr(pattern, "no such overload") + return MaybeNoSuchOverloadErr(pattern) } matched, err := regexp.MatchString(pat.Value().(string), s.Value().(string)) if err != nil { @@ -178,7 +178,7 @@ func (s String) Receive(function string, overload string, args []ref.Val) ref.Va return f(s, args[0]) } } - return NewErr("no such overload") + return NoSuchOverloadErr() } // Size implements traits.Sizer.Size. @@ -199,7 +199,7 @@ func (s String) Value() interface{} { func stringContains(s String, sub ref.Val) ref.Val { subStr, ok := sub.(String) if !ok { - return ValOrErr(sub, "no such overload") + return MaybeNoSuchOverloadErr(sub) } return Bool(strings.Contains(string(s), string(subStr))) } @@ -207,7 +207,7 @@ func stringContains(s String, sub ref.Val) ref.Val { func stringEndsWith(s String, suf ref.Val) ref.Val { sufStr, ok := suf.(String) if !ok { - return ValOrErr(suf, "no such overload") + return MaybeNoSuchOverloadErr(suf) } return Bool(strings.HasSuffix(string(s), string(sufStr))) } @@ -215,7 +215,7 @@ func stringEndsWith(s String, suf ref.Val) ref.Val { func stringStartsWith(s String, pre ref.Val) ref.Val { preStr, ok := pre.(String) if !ok { - return ValOrErr(pre, "no such overload") + return MaybeNoSuchOverloadErr(pre) } return Bool(strings.HasPrefix(string(s), string(preStr))) } diff --git a/common/types/timestamp.go b/common/types/timestamp.go index b4d40e35..1f77581a 100644 --- a/common/types/timestamp.go +++ b/common/types/timestamp.go @@ -38,7 +38,7 @@ type Timestamp struct { } func timestampOf(t time.Time) Timestamp { - // Note that this function does not valiate that time.Time is in our supported range. + // Note that this function does not validate that time.Time is in our supported range. return Timestamp{Time: t} } @@ -68,13 +68,13 @@ func (t Timestamp) Add(other ref.Val) ref.Val { case DurationType: return other.(Duration).Add(t) } - return ValOrErr(other, "no such overload") + return MaybeNoSuchOverloadErr(other) } // Compare implements traits.Comparer.Compare. func (t Timestamp) Compare(other ref.Val) ref.Val { if TimestampType != other.Type() { - return ValOrErr(other, "no such overload") + return MaybeNoSuchOverloadErr(other) } ts1 := t.Time ts2 := other.(Timestamp).Time @@ -152,7 +152,7 @@ func (t Timestamp) Receive(function string, overload string, args []ref.Val) ref return f(t.Time, args[0]) } } - return NewErr("no such overload") + return NoSuchOverloadErr() } // Subtract implements traits.Subtractor.Subtract. @@ -160,18 +160,20 @@ func (t Timestamp) Subtract(subtrahend ref.Val) ref.Val { switch subtrahend.Type() { case DurationType: dur := subtrahend.(Duration) - if val, ok := subtractTimeDurationChecked(t.Time, dur.Duration); ok { + if val, err := subtractTimeDurationChecked(t.Time, dur.Duration); err != nil { + return wrapErr(err) + } else { return timestampOf(val) } - return errTimestampOverflow case TimestampType: t2 := subtrahend.(Timestamp).Time - if val, ok := subtractTimeChecked(t.Time, t2); ok { + if val, err := subtractTimeChecked(t.Time, t2); err != nil { + return wrapErr(err) + } else { return durationOf(val) } - return errDurationOverflow } - return ValOrErr(subtrahend, "no such overload") + return MaybeNoSuchOverloadErr(subtrahend) } // Type implements ref.Val.Type. @@ -281,14 +283,14 @@ func timestampGetMillisecondsWithTz(t time.Time, tz ref.Val) ref.Val { func timeZone(tz ref.Val, visitor timestampVisitor) timestampVisitor { return func(t time.Time) ref.Val { if StringType != tz.Type() { - return ValOrErr(tz, "no such overload") + return MaybeNoSuchOverloadErr(tz) } val := string(tz.(String)) ind := strings.Index(val, ":") if ind == -1 { loc, err := time.LoadLocation(val) if err != nil { - return &Err{err} + return wrapErr(err) } return visitor(t.In(loc)) } @@ -297,11 +299,11 @@ func timeZone(tz ref.Val, visitor timestampVisitor) timestampVisitor { // in the format ^(+|-)(0[0-9]|1[0-4]):[0-5][0-9]$. The numerical input is parsed in terms of hours and minutes. hr, err := strconv.Atoi(string(val[0:ind])) if err != nil { - return &Err{err} + return wrapErr(err) } min, err := strconv.Atoi(string(val[ind+1])) if err != nil { - return &Err{err} + return wrapErr(err) } var offset int if string(val[0]) == "-" { diff --git a/common/types/timestamp_test.go b/common/types/timestamp_test.go index 976f641a..88264c87 100644 --- a/common/types/timestamp_test.go +++ b/common/types/timestamp_test.go @@ -15,6 +15,8 @@ package types import ( + "errors" + "math" "reflect" "testing" "time" @@ -28,30 +30,221 @@ import ( tpb "google.golang.org/protobuf/types/known/timestamppb" ) -func TestTimestampAdd(t *testing.T) { - ts := Timestamp{Time: time.Unix(7506, 0).UTC()} - val := ts.Add(Duration{time.Duration(3600)*time.Second + time.Duration(1000)}) - if val.ConvertToType(TypeType) != TimestampType { - t.Error("Could not add duration and timestamp") - } - expected := Timestamp{Time: time.Unix(11106, 1000).UTC()} - if !expected.Compare(val).Equal(IntZero).(Bool) { - t.Errorf("Got '%v', expected '%v'", val, expected) +func TestTimestampConvertToType(t *testing.T) { + ts := Timestamp{Time: time.Unix(7654, 321).UTC()} + if ts.ConvertToType(TypeType) != TimestampType { + t.Errorf("ConvertToType(type) failed to return timestamp type: %v", ts.ConvertToType(TypeType)) } - if !IsError(ts.Add(expected)) { - t.Error("Cannot add two timestamps together") + if ts.ConvertToType(IntType) != Int(7654) { + t.Errorf("ConvertToType(int) failed to truncate a timestamp to a unix epoch: %v", ts.ConvertToType(IntType)) } - if lhs, rhs := time.Unix(maxUnixTime, 999999999), 1*time.Nanosecond; !IsError(timestampOf(lhs).Add(durationOf(rhs))) { - t.Errorf("Expected adding %s and %s to result in overflow.", lhs, rhs) + if ts.ConvertToType(StringType) != String("1970-01-01T02:07:34.000000321Z") { + t.Errorf("ConvertToType(string) failed to convert to a human readable timestamp. "+ + "got %v, wanted: 1970-01-01T02:07:34.000000321Z", + ts.ConvertToType(StringType)) } - if lhs, rhs := time.Unix(minUnixTime, 0), -1*time.Nanosecond; !IsError(timestampOf(lhs).Add(durationOf(rhs))) { - t.Errorf("Expected adding %s and %s to result in overflow.", lhs, rhs) + if ts.ConvertToType(TimestampType) != ts { + t.Error("ConvertToType(timestamp) failed an identity conversion") } - if lhs, rhs := time.Unix(maxUnixTime, 999999999), -1*time.Nanosecond; !timestampOf(lhs).Add(durationOf(rhs)).Equal(timestampOf(lhs.Add(rhs))).(Bool) { - t.Errorf("Expected adding %s and %s to yield %s", lhs, rhs, lhs.Add(rhs)) + if !IsError(ts.ConvertToType(DurationType)) { + t.Error("ConvertToType(duration) failed to error") } - if lhs, rhs := time.Unix(minUnixTime, 0), 1*time.Nanosecond; !timestampOf(lhs).Add(durationOf(rhs)).Equal(timestampOf(lhs.Add(rhs))).(Bool) { - t.Errorf("Expected adding %s and %s to yield %s", lhs, rhs, lhs.Add(rhs)) +} + +func TestTimestampOperators(t *testing.T) { + unixTimestamp := func(epoch int64) Timestamp { + return timestampOf(time.Unix(epoch, 0).UTC()) + } + tests := []struct { + name string + op func() ref.Val + out interface{} + }{ + // Addition tests. + { + name: "DateAddOneHourMinusOneMilli", + op: func() ref.Val { + return unixTimestamp(3506).Add(durationOf(time.Hour - time.Millisecond)) + }, + out: time.Unix(7106, 0).Add(-time.Millisecond).UTC(), + }, + { + name: "DateAddOneHourOneNano", + op: func() ref.Val { + return unixTimestamp(3506).Add(durationOf(time.Hour + time.Nanosecond)) + }, + out: time.Unix(7106, 1).UTC(), + }, + { + name: "IntMaxAddOneSecond", + op: func() ref.Val { + return unixTimestamp(math.MaxInt64).Add(durationOf(time.Second)) + }, + out: errIntOverflow, + }, + { + name: "MaxTimestampAddOneSecond", + op: func() ref.Val { + return unixTimestamp(maxUnixTime).Add(durationOf(time.Second)) + }, + out: errTimestampOverflow, + }, + { + name: "MaxIntAddOneViaNanos", + op: func() ref.Val { + return timestampOf(time.Unix(math.MaxInt64, 999_999_999).UTC()).Add(durationOf(time.Nanosecond)) + }, + out: errIntOverflow, + }, + { + name: "SecondsWithNanosNegative", + op: func() ref.Val { + ts1 := unixTimestamp(1).Add(durationOf(time.Nanosecond)).(Timestamp) + return ts1.Add(durationOf(-999_999_999)) + }, + out: time.Unix(0, 2).UTC(), + }, + { + name: "SecondsWithNanosPositive", + op: func() ref.Val { + ts1 := unixTimestamp(1).Add(durationOf(999_999_999 * time.Nanosecond)).(Timestamp) + return ts1.Add(durationOf(999_999_999)) + }, + out: time.Unix(2, 999_999_998).UTC(), + }, + { + name: "DateAddDateError", + op: func() ref.Val { + return unixTimestamp(1).Add(unixTimestamp(1)) + }, + out: errors.New("no such overload"), + }, + + // Comparison tests. + { + name: "DateCompareEqual", + op: func() ref.Val { + return unixTimestamp(1).Compare(unixTimestamp(1)) + }, + out: int64(0), + }, + { + name: "DateCompareBefore", + op: func() ref.Val { + return unixTimestamp(1).Compare(unixTimestamp(200)) + }, + out: int64(-1), + }, + { + name: "DateCompareAfter", + op: func() ref.Val { + return unixTimestamp(1000).Compare(unixTimestamp(200)) + }, + out: int64(1), + }, + { + name: "DateCompareError", + op: func() ref.Val { + return unixTimestamp(1000).Compare(durationOf(1000)) + }, + out: errors.New("no such overload"), + }, + + // Time subtraction tests. + { + name: "TimeSubOneSecond", + op: func() ref.Val { + return unixTimestamp(100).Subtract(unixTimestamp(1)) + }, + out: 99 * time.Second, + }, + { + name: "DateSubOneHour", + op: func() ref.Val { + return unixTimestamp(3506).Subtract(durationOf(time.Hour)) + }, + out: time.Unix(-94, 0).UTC(), + }, + { + name: "MinTimestampSubOneSecond", + op: func() ref.Val { + return unixTimestamp(-62135596800).Subtract(durationOf(time.Second)) + }, + out: errTimestampOverflow, + }, + { + name: "MinTimestampSubMinusOneViaNanos", + op: func() ref.Val { + return timestampOf(time.Unix(-62135596800, 2).UTC()).Subtract(durationOf(-999_999_999 * time.Nanosecond)) + }, + out: time.Unix(-62135596799, 1).UTC(), + }, + { + name: "MinIntSubOneViaNanosOverflow", + op: func() ref.Val { + return timestampOf(time.Unix(math.MinInt64, 0).UTC()).Subtract(durationOf(time.Nanosecond)) + }, + out: errIntOverflow, + }, + { + name: "TimeWithNanosPositive", + op: func() ref.Val { + return timestampOf(time.Unix(2, 1)).Subtract(timestampOf(time.Unix(0, 999_999_999))) + }, + out: time.Second + 2*time.Nanosecond, + }, + { + name: "TimeWithNanosNegative", + op: func() ref.Val { + return timestampOf(time.Unix(1, 1)).Subtract(timestampOf(time.Unix(2, 999_999_999))) + }, + out: -2*time.Second + 2*time.Nanosecond, + }, + { + name: "MinTimestampMinusOne", + op: func() ref.Val { + return unixTimestamp(math.MinInt64).Subtract(unixTimestamp(1)) + }, + out: errIntOverflow, + }, + { + name: "DateMinusDateDurationOverflow", + op: func() ref.Val { + return unixTimestamp(maxUnixTime).Subtract(unixTimestamp(minUnixTime)) + }, + out: errIntOverflow, + }, + { + name: "MinTimestampMinusOneViaNanosScaleOverflow", + op: func() ref.Val { + return timestampOf(time.Unix(math.MinInt64, 1)).Subtract(timestampOf(time.Unix(0, -999_999_999))) + }, + out: errIntOverflow, + }, + { + name: "DateSubMinDuration", + op: func() ref.Val { + return unixTimestamp(1).Subtract(durationOf(math.MinInt64)) + }, + out: errIntOverflow, + }, + } + for _, tst := range tests { + got := tst.op() + switch v := got.Value().(type) { + case time.Time: + if want, ok := tst.out.(time.Time); !ok || !v.Equal(want) { + t.Errorf("%s: got %v, wanted %v", tst.name, v, tst.out) + } + case error: + if want, ok := tst.out.(error); !ok || v.Error() != want.Error() { + t.Errorf("%s: got %v, wanted %v", tst.name, v, tst.out) + } + default: + if !reflect.DeepEqual(v, tst.out) { + t.Errorf("%s: got %v, wanted %v", tst.name, v, tst.out) + } + } } } @@ -119,27 +312,6 @@ func TestTimestampConvertToNative(t *testing.T) { } } -func TestTimestampSubtract(t *testing.T) { - ts := Timestamp{Time: time.Unix(7506, 0).UTC()} - val := ts.Subtract(Duration{Duration: time.Duration(3600)*time.Second + time.Duration(1000)}) - if val.ConvertToType(TypeType) != TimestampType { - t.Error("Could not add duration and timestamp") - } - expected := Timestamp{Time: time.Unix(3905, 999999000).UTC()} - if !expected.Compare(val).Equal(IntZero).(Bool) { - t.Errorf("Got '%v', expected '%v'", val, expected) - } - ts2 := Timestamp{Time: time.Unix(6506, 0).UTC()} - val = ts.Subtract(ts2) - if val.ConvertToType(TypeType) != DurationType { - t.Error("Could not subtract timestamps") - } - expectedDur := Duration{Duration: time.Duration(1000000000000)} - if !expectedDur.Compare(val).Equal(IntZero).(Bool) { - t.Errorf("Got '%v', expected '%v'", val, expectedDur) - } -} - func TestTimestampGetDayOfYear(t *testing.T) { // 1970-01-01T02:05:06Z ts := Timestamp{Time: time.Unix(7506, 0).UTC()} diff --git a/common/types/uint.go b/common/types/uint.go index 2e6c44ca..81c315da 100644 --- a/common/types/uint.go +++ b/common/types/uint.go @@ -16,7 +16,6 @@ package types import ( "fmt" - "math" "reflect" "strconv" @@ -55,19 +54,20 @@ const ( func (i Uint) Add(other ref.Val) ref.Val { otherUint, ok := other.(Uint) if !ok { - return ValOrErr(other, "no such overload") + return MaybeNoSuchOverloadErr(other) } - if val, ok := addUint64Checked(uint64(i), uint64(otherUint)); ok { + if val, err := addUint64Checked(uint64(i), uint64(otherUint)); err != nil { + return wrapErr(err) + } else { return Uint(val) } - return errUintOverflow } // Compare implements traits.Comparer.Compare. func (i Uint) Compare(other ref.Val) ref.Val { otherUint, ok := other.(Uint) if !ok { - return ValOrErr(other, "no such overload") + return MaybeNoSuchOverloadErr(other) } if i < otherUint { return IntNegOne @@ -81,7 +81,13 @@ func (i Uint) Compare(other ref.Val) ref.Val { // ConvertToNative implements ref.Val.ConvertToNative. func (i Uint) ConvertToNative(typeDesc reflect.Type) (interface{}, error) { switch typeDesc.Kind() { - case reflect.Uint, reflect.Uint32, reflect.Uint64: + case reflect.Uint, reflect.Uint32: + v, err := uint64ToUint32Checked(uint64(i)) + if err != nil { + return 0, err + } + return reflect.ValueOf(v).Convert(typeDesc).Interface(), nil + case reflect.Uint64: return reflect.ValueOf(i).Convert(typeDesc).Interface(), nil case reflect.Ptr: switch typeDesc { @@ -97,15 +103,22 @@ func (i Uint) ConvertToNative(typeDesc reflect.Type) (interface{}, error) { // since the conversion to floating point would result in truncation. return structpb.NewStringValue(strconv.FormatUint(uint64(i), 10)), nil case uint32WrapperType: - // Convert the value to a wrapperspb.UInt32Value (with truncation). - return wrapperspb.UInt32(uint32(i)), nil + // Convert the value to a wrapperspb.UInt32Value, error on overflow. + v, err := uint64ToUint32Checked(uint64(i)) + if err != nil { + return 0, err + } + return wrapperspb.UInt32(v), nil case uint64WrapperType: // Convert the value to a wrapperspb.UInt64Value. return wrapperspb.UInt64(uint64(i)), nil } switch typeDesc.Elem().Kind() { case reflect.Uint32: - v := uint32(i) + v, err := uint64ToUint32Checked(uint64(i)) + if err != nil { + return 0, err + } p := reflect.New(typeDesc.Elem()) p.Elem().Set(reflect.ValueOf(v).Convert(typeDesc.Elem())) return p.Interface(), nil @@ -131,10 +144,11 @@ func (i Uint) ConvertToNative(typeDesc reflect.Type) (interface{}, error) { func (i Uint) ConvertToType(typeVal ref.Type) ref.Val { switch typeVal { case IntType: - if i > math.MaxInt64 { - return NewErr("range error converting %d to int", i) + if v, err := uint64ToInt64Checked(uint64(i)); err != nil { + return wrapErr(err) + } else { + return Int(v) } - return Int(i) case UintType: return i case DoubleType: @@ -151,19 +165,20 @@ func (i Uint) ConvertToType(typeVal ref.Type) ref.Val { func (i Uint) Divide(other ref.Val) ref.Val { otherUint, ok := other.(Uint) if !ok { - return ValOrErr(other, "no such overload") + return MaybeNoSuchOverloadErr(other) } - if otherUint == uintZero { - return NewErr("divide by zero") + if div, err := divideUint64Checked(uint64(i), uint64(otherUint)); err != nil { + return wrapErr(err) + } else { + return Uint(div) } - return i / otherUint } // Equal implements ref.Val.Equal. func (i Uint) Equal(other ref.Val) ref.Val { otherUint, ok := other.(Uint) if !ok { - return ValOrErr(other, "no such overload") + return MaybeNoSuchOverloadErr(other) } return Bool(i == otherUint) } @@ -172,36 +187,39 @@ func (i Uint) Equal(other ref.Val) ref.Val { func (i Uint) Modulo(other ref.Val) ref.Val { otherUint, ok := other.(Uint) if !ok { - return ValOrErr(other, "no such overload") + return MaybeNoSuchOverloadErr(other) } - if otherUint == uintZero { - return NewErr("modulus by zero") + if mod, err := moduloUint64Checked(uint64(i), uint64(otherUint)); err != nil { + return wrapErr(err) + } else { + return Uint(mod) } - return i % otherUint } // Multiply implements traits.Multiplier.Multiply. func (i Uint) Multiply(other ref.Val) ref.Val { otherUint, ok := other.(Uint) if !ok { - return ValOrErr(other, "no such overload") + return MaybeNoSuchOverloadErr(other) } - if val, ok := multiplyUint64Checked(uint64(i), uint64(otherUint)); ok { + if val, err := multiplyUint64Checked(uint64(i), uint64(otherUint)); err != nil { + return wrapErr(err) + } else { return Uint(val) } - return errUintOverflow } // Subtract implements traits.Subtractor.Subtract. func (i Uint) Subtract(subtrahend ref.Val) ref.Val { subtraUint, ok := subtrahend.(Uint) if !ok { - return ValOrErr(subtrahend, "no such overload") + return MaybeNoSuchOverloadErr(subtrahend) } - if val, ok := subtractUint64Checked(uint64(i), uint64(subtraUint)); ok { + if val, err := subtractUint64Checked(uint64(i), uint64(subtraUint)); err != nil { + return wrapErr(err) + } else { return Uint(val) } - return errUintOverflow } // Type implements ref.Val.Type. diff --git a/common/types/uint_test.go b/common/types/uint_test.go index 7f37c1bf..d6ec6033 100644 --- a/common/types/uint_test.go +++ b/common/types/uint_test.go @@ -15,10 +15,13 @@ package types import ( + "errors" "math" "reflect" + "strings" "testing" + "github.com/google/cel-go/common/types/ref" "google.golang.org/protobuf/proto" anypb "google.golang.org/protobuf/types/known/anypb" @@ -90,7 +93,7 @@ func TestUint_ConvertToNative_Json(t *testing.T) { } // Value converts to a JSON decimal string - val, err = Int(maxIntJSON + 1).ConvertToNative(jsonValueType) + val, err = Uint(maxIntJSON + 1).ConvertToNative(jsonValueType) if err != nil { t.Error(err) } else if !proto.Equal(val.(proto.Message), structpb.NewStringValue("9007199254740992")) { @@ -98,6 +101,22 @@ func TestUint_ConvertToNative_Json(t *testing.T) { } } +func TestUintConvertToNative_Uint32(t *testing.T) { + val, err := Uint(20050).ConvertToNative(reflect.TypeOf(uint32(0))) + if err != nil { + t.Fatalf("Uint.ConvertToNative(uint32) failed: %v", err) + } + if val.(uint32) != 20050 { + t.Errorf("Got '%v', expected 20050", val) + } + val, err = Uint(math.MaxUint32 + 1).ConvertToNative(reflect.TypeOf(uint32(0))) + if err == nil { + t.Errorf("(MaxUint+1).ConvertToNative(uint32) did not error, got: %v", val) + } else if !strings.Contains(err.Error(), "unsigned integer overflow") { + t.Errorf("ConvertToNative(uint32) returned unexpected error: %v, wanted unsigned integer overflow", err) + } +} + func TestUint_ConvertToNative_Ptr_Uint32(t *testing.T) { ptrType := uint32(0) val, err := Uint(10000).ConvertToNative(reflect.TypeOf(&ptrType)) @@ -139,26 +158,68 @@ func TestUint_ConvertToNative_Wrapper(t *testing.T) { } func TestUint_ConvertToType(t *testing.T) { - if !IsError(Uint(18446744073709551612).ConvertToType(IntType)) { - t.Error("Got int, expected error") - } - if !Uint(4).ConvertToType(IntType).Equal(Int(4)).(Bool) { - t.Error("Unsuccessful type conversion to int") - } - if !Uint(4).ConvertToType(UintType).Equal(Uint(4)).(Bool) { - t.Error("Unsuccessful type conversion to uint") - } - if !Uint(4).ConvertToType(DoubleType).Equal(Double(4)).(Bool) { - t.Error("Unsuccessful type conversion to double") - } - if !Uint(4).ConvertToType(StringType).Equal(String("4")).(Bool) { - t.Error("Unsuccessful type conversion to string") - } - if !Uint(4).ConvertToType(TypeType).Equal(UintType).(Bool) { - t.Error("Unsuccessful type conversion to type") - } - if !IsError(Uint(4).ConvertToType(MapType)) { - t.Error("Unsupported uint type conversion resulted in value") + tests := []struct { + name string + in uint64 + toType ref.Type + out interface{} + }{ + { + name: "UintToUint", + in: uint64(4), + toType: UintType, + out: uint64(4), + }, + { + name: "UintToType", + in: uint64(4), + toType: TypeType, + out: UintType.TypeName(), + }, + { + name: "UintToInt", + in: uint64(4), + toType: IntType, + out: int64(4), + }, + { + name: "UintToIntOverflow", + in: uint64(math.MaxInt64) + 1, + toType: IntType, + out: errIntOverflow, + }, + { + name: "UintToDouble", + in: uint64(4), + toType: DoubleType, + out: float64(4), + }, + { + name: "UintToString", + in: uint64(4), + toType: StringType, + out: "4", + }, + { + name: "UintToUnsupportedType", + in: uint64(4), + toType: MapType, + out: errors.New("type conversion error"), + }, + } + for _, tst := range tests { + got := Uint(tst.in).ConvertToType(tst.toType).Value() + var eq bool + switch gotVal := got.(type) { + case error: + eq = strings.Contains(gotVal.Error(), tst.out.(error).Error()) + default: + eq = reflect.DeepEqual(gotVal, tst.out) + } + if !eq { + t.Errorf("Uint(%v).ConvertToType(%v) failed, got: %v, wanted: %v", + tst.in, tst.toType, got, tst.out) + } } } diff --git a/conformance/BUILD.bazel b/conformance/BUILD.bazel index c90bb4ae..3297ca3c 100644 --- a/conformance/BUILD.bazel +++ b/conformance/BUILD.bazel @@ -1,61 +1,43 @@ +ALL_TESTS = [ + "@com_google_cel_spec//tests/simple:testdata/basic.textproto", + "@com_google_cel_spec//tests/simple:testdata/comparisons.textproto", + "@com_google_cel_spec//tests/simple:testdata/conversions.textproto", + "@com_google_cel_spec//tests/simple:testdata/dynamic.textproto", + "@com_google_cel_spec//tests/simple:testdata/enums.textproto", + "@com_google_cel_spec//tests/simple:testdata/fields.textproto", + "@com_google_cel_spec//tests/simple:testdata/fp_math.textproto", + "@com_google_cel_spec//tests/simple:testdata/integer_math.textproto", + "@com_google_cel_spec//tests/simple:testdata/lists.textproto", + "@com_google_cel_spec//tests/simple:testdata/logic.textproto", + "@com_google_cel_spec//tests/simple:testdata/macros.textproto", + "@com_google_cel_spec//tests/simple:testdata/namespace.textproto", + "@com_google_cel_spec//tests/simple:testdata/parse.textproto", + "@com_google_cel_spec//tests/simple:testdata/plumbing.textproto", + "@com_google_cel_spec//tests/simple:testdata/proto2.textproto", + "@com_google_cel_spec//tests/simple:testdata/proto3.textproto", + "@com_google_cel_spec//tests/simple:testdata/string.textproto", + "@com_google_cel_spec//tests/simple:testdata/timestamps.textproto", + "@com_google_cel_spec//tests/simple:testdata/unknowns.textproto", +] + sh_test( name = "ct", srcs = ["@com_google_cel_spec//tests:conftest.sh"], args = [ "$(location @com_google_cel_spec//tests/simple:simple_test)", "--server=$(location //server/main:cel_server)", - "--skip_test=dynamic/int32/field_assign_proto2_range,field_assign_proto3_range", - "--skip_test=dynamic/uint32/field_assign_proto2_range,field_assign_proto3_range", - "--skip_test=dynamic/float/field_assign_proto2_range,field_assign_proto3_range", - "--skip_test=dynamic/value_null/literal_unset,field_read_proto2_unset,field_read_proto3_unset", - "--skip_test=enums/legacy_proto2/assign_standalone_int_too_big,assign_standalone_int_too_neg", - "--skip_test=enums/legacy_proto3/assign_standalone_int_too_big,assign_standalone_int_too_neg", + + # Failing conformance tests. + "--skip_test=fields/qualified_identifier_resolution/map_key_float,map_key_null,map_value_repeat_key", + + # Future enhancments. "--skip_test=enums/strong_proto2", "--skip_test=enums/strong_proto3", - "--skip_test=fields/qualified_identifier_resolution/map_key_float,map_key_null,map_value_repeat_key", - "$(location @com_google_cel_spec//tests/simple:testdata/plumbing.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/basic.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/comparisons.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/conversions.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/dynamic.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/enums.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/fields.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/fp_math.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/integer_math.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/lists.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/logic.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/macros.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/namespace.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/parse.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/proto2.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/proto3.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/string.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/timestamps.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/unknowns.textproto)", - ], + ] + ["$(location " + test + ")" for test in ALL_TESTS], data = [ "//server/main:cel_server", "@com_google_cel_spec//tests/simple:simple_test", - "@com_google_cel_spec//tests/simple:testdata/basic.textproto", - "@com_google_cel_spec//tests/simple:testdata/comparisons.textproto", - "@com_google_cel_spec//tests/simple:testdata/conversions.textproto", - "@com_google_cel_spec//tests/simple:testdata/dynamic.textproto", - "@com_google_cel_spec//tests/simple:testdata/enums.textproto", - "@com_google_cel_spec//tests/simple:testdata/fields.textproto", - "@com_google_cel_spec//tests/simple:testdata/fp_math.textproto", - "@com_google_cel_spec//tests/simple:testdata/integer_math.textproto", - "@com_google_cel_spec//tests/simple:testdata/lists.textproto", - "@com_google_cel_spec//tests/simple:testdata/logic.textproto", - "@com_google_cel_spec//tests/simple:testdata/macros.textproto", - "@com_google_cel_spec//tests/simple:testdata/namespace.textproto", - "@com_google_cel_spec//tests/simple:testdata/parse.textproto", - "@com_google_cel_spec//tests/simple:testdata/plumbing.textproto", - "@com_google_cel_spec//tests/simple:testdata/proto2.textproto", - "@com_google_cel_spec//tests/simple:testdata/proto3.textproto", - "@com_google_cel_spec//tests/simple:testdata/string.textproto", - "@com_google_cel_spec//tests/simple:testdata/timestamps.textproto", - "@com_google_cel_spec//tests/simple:testdata/unknowns.textproto", - ], + ] + ALL_TESTS, ) # ct_dashboard is a target for the conformance dashboard and includes all simple textproto files, including those that are broken. @@ -65,50 +47,12 @@ sh_test( args = [ "$(location @com_google_cel_spec//tests/simple:simple_test)", "--server=$(location //server/main:cel_server)", - "-test.v", + # Failing due to a GCB builder issue "--skip_test=timestamps/timestamp_selectors_tz/getDate,getDayOfMonth_name_neg,getDayOfMonth_name_pos,getDayOfYear,getMinutes", - "$(location @com_google_cel_spec//tests/simple:testdata/plumbing.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/basic.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/comparisons.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/conversions.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/dynamic.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/enums.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/fields.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/fp_math.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/integer_math.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/lists.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/logic.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/parse.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/macros.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/namespace.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/proto2.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/proto3.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/string.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/timestamps.textproto)", - "$(location @com_google_cel_spec//tests/simple:testdata/unknowns.textproto)", - ], + ] + ["$(location " + test + ")" for test in ALL_TESTS], data = [ "//server/main:cel_server", "@com_google_cel_spec//tests/simple:simple_test", - "@com_google_cel_spec//tests/simple:testdata/basic.textproto", - "@com_google_cel_spec//tests/simple:testdata/comparisons.textproto", - "@com_google_cel_spec//tests/simple:testdata/conversions.textproto", - "@com_google_cel_spec//tests/simple:testdata/dynamic.textproto", - "@com_google_cel_spec//tests/simple:testdata/enums.textproto", - "@com_google_cel_spec//tests/simple:testdata/fields.textproto", - "@com_google_cel_spec//tests/simple:testdata/fp_math.textproto", - "@com_google_cel_spec//tests/simple:testdata/integer_math.textproto", - "@com_google_cel_spec//tests/simple:testdata/lists.textproto", - "@com_google_cel_spec//tests/simple:testdata/logic.textproto", - "@com_google_cel_spec//tests/simple:testdata/macros.textproto", - "@com_google_cel_spec//tests/simple:testdata/namespace.textproto", - "@com_google_cel_spec//tests/simple:testdata/parse.textproto", - "@com_google_cel_spec//tests/simple:testdata/plumbing.textproto", - "@com_google_cel_spec//tests/simple:testdata/proto2.textproto", - "@com_google_cel_spec//tests/simple:testdata/proto3.textproto", - "@com_google_cel_spec//tests/simple:testdata/string.textproto", - "@com_google_cel_spec//tests/simple:testdata/timestamps.textproto", - "@com_google_cel_spec//tests/simple:testdata/unknowns.textproto", - ], + ] + ALL_TESTS, ) diff --git a/go.mod b/go.mod index ebd735cc..6aec3b29 100644 --- a/go.mod +++ b/go.mod @@ -3,15 +3,15 @@ module github.com/google/cel-go go 1.16 require ( - github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210803070921-b358b509191a - github.com/golang/glog v0.0.0-20210429001901-424d2337a529 + github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e + github.com/golang/glog v1.0.0 github.com/golang/protobuf v1.5.2 - github.com/google/cel-spec v0.5.1 + github.com/google/cel-spec v0.6.0 github.com/stoewer/go-strcase v1.2.0 - golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d // indirect - golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069 // indirect - golang.org/x/text v0.3.6 - google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67 - google.golang.org/grpc v1.39.1 + golang.org/x/net v0.0.0-20210825183410-e898025ed96a // indirect + golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e // indirect + golang.org/x/text v0.3.7 + google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2 + google.golang.org/grpc v1.40.0 google.golang.org/protobuf v1.27.1 ) diff --git a/go.sum b/go.sum index 2dd2a28c..b85ba930 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,12 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210803070921-b358b509191a h1:6tPeghyQyDji+Q+jYDjpHNlLz/aexx/Cvk1ao92Nfbg= -github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210803070921-b358b509191a/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= +github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e h1:GCzyKMDDjSGnlpl3clrdAK7I1AaVoaiKDOYkUzChZzg= +github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -19,8 +21,8 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v0.0.0-20210429001901-424d2337a529 h1:2voWjNECnrZRbfwXxHB1/j8wa6xdKn85B5NzgVL/pTU= -github.com/golang/glog v0.0.0-20210429001901-424d2337a529/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -36,8 +38,8 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/cel-spec v0.5.1 h1:3uwWs3lBmX2dY3l9ppOAOa3sGivFoeYz8NSpD/uD68E= -github.com/google/cel-spec v0.5.1/go.mod h1:Nwjgxy5CbjlPrtCWjeDjUyKMl8w41YBYGjsyDdqk0xA= +github.com/google/cel-spec v0.6.0 h1:xuthJSiJGoSzq+lVEBIW1MTpaaZXknMCYC4WzVAWOsE= +github.com/google/cel-spec v0.6.0/go.mod h1:Nwjgxy5CbjlPrtCWjeDjUyKMl8w41YBYGjsyDdqk0xA= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -51,6 +53,7 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -78,8 +81,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210825183410-e898025ed96a h1:bRuuGXV8wwSdGTB+CtJf+FjgO1APK1CoO39T4BN/XBw= +golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -96,15 +99,16 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069 h1:siQdpVirKtzPhKl3lZWozZraCFObP8S1v6PRp0bLrtU= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e h1:XMgFehsDnnLGtjvjOfqWSUzt0alpTR1RSEuznObga2c= +golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -125,8 +129,8 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20201102152239-715cce707fb0/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67 h1:VmMSf20ssFK0+u1dscyTH9bU4/M4y+X/xNfkvD6kGtM= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2 h1:NHN4wOCScVzKhPenJ2dt+BTs3X/XkBVI/Rh4iDt55T8= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= @@ -134,9 +138,8 @@ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8 google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1 h1:f37vZbBVTiJ6jKG5mWz8ySOBxNqy6ViPgyhSdVnxF3E= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/interpreter/interpreter_test.go b/interpreter/interpreter_test.go index 08d9fcd7..6f4c9256 100644 --- a/interpreter/interpreter_test.go +++ b/interpreter/interpreter_test.go @@ -95,14 +95,14 @@ var ( expr: `1/0 != 0 && true`, cost: []int64{2, 3}, exhaustiveCost: []int64{3, 3}, - err: "divide by zero", + err: "division by zero", }, { name: "and_error_2nd_error", expr: `true && 1/0 != 0`, cost: []int64{0, 3}, exhaustiveCost: []int64{3, 3}, - err: "divide by zero", + err: "division by zero", }, { name: "call_no_args", @@ -743,14 +743,14 @@ var ( expr: `1/0 != 0 || false`, cost: []int64{2, 3}, exhaustiveCost: []int64{3, 3}, - err: "divide by zero", + err: "division by zero", }, { name: "or_error_2nd_error", expr: `false || 1/0 != 0`, cost: []int64{0, 3}, exhaustiveCost: []int64{3, 3}, - err: "divide by zero", + err: "division by zero", }, { name: "or_error_1st_true", @@ -1058,7 +1058,7 @@ var ( Unary: func(val ref.Val) ref.Val { str, ok := val.(types.String) if !ok { - return types.ValOrErr(val, "no such overload") + return types.MaybeNoSuchOverloadErr(val) } m := make(map[string]interface{}) err := json.Unmarshal([]byte(str), &m) @@ -1231,7 +1231,7 @@ func TestInterpreter_ProtoAttributeOpt(t *testing.T) { in: map[string]interface{}{ "pb3": &proto3pb.TestAllTypes{ MapInt64NestedType: map[int64]*proto3pb.NestedTestAllTypes{ - 0: &proto3pb.NestedTestAllTypes{ + 0: { Child: &proto3pb.NestedTestAllTypes{ Payload: &proto3pb.TestAllTypes{ SingleInt32: 1,