Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the duration declarations in the new style when UTC is enabled #565

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 22 additions & 6 deletions cel/cel_test.go
Expand Up @@ -202,8 +202,10 @@ func TestCustomEnvError(t *testing.T) {
}

func TestCustomEnv(t *testing.T) {
e, _ := NewCustomEnv(Variable("a.b.c", BoolType))

e, err := NewCustomEnv(Variable("a.b.c", BoolType))
if err != nil {
t.Fatalf("NewCustomEnv(a.b.c:bool) failed: %v", err)
}
t.Run("err", func(t *testing.T) {
_, iss := e.Compile("a.b.c == true")
if iss.Err() == nil {
Expand Down Expand Up @@ -1704,28 +1706,42 @@ func TestDefaultUTCTimeZone(t *testing.T) {
}

func TestDefaultUTCTimeZoneExtension(t *testing.T) {
env, err := NewEnv(Variable("x", TimestampType), DefaultUTCTimeZone(true))
env, err := NewEnv(
Variable("x", TimestampType),
Variable("y", DurationType),
DefaultUTCTimeZone(true),
)
if err != nil {
t.Fatalf("NewEnv() failed: %v", err)
}
env, err = env.Extend()
if err != nil {
t.Fatalf("env.Extend() failed: %v", err)
}
ast, iss := env.Compile(`x.getFullYear() == 1970`)
ast, iss := env.Compile(`
x.getFullYear() == 1970
&& y.getHours() == 2
&& y.getMinutes() == 120
&& y.getSeconds() == 7235
&& y.getMilliseconds() == 7235000`)
if iss.Err() != nil {
t.Fatalf("env.Compile() failed: %v", iss.Err())
}
prg, err := env.Program(ast)
if err != nil {
t.Fatalf("env.Program() failed: %v", err)
}
out, _, err := prg.Eval(map[string]interface{}{"x": time.Unix(7506, 1000000).Local()})
out, _, err := prg.Eval(
map[string]interface{}{
"x": time.Unix(7506, 1000000).Local(),
"y": time.Duration(7235) * time.Second,
},
)
if err != nil {
t.Fatalf("prg.Eval() failed: %v", err)
}
if out != types.True {
t.Errorf("Eval() got %v, wanted true", out)
t.Errorf("Eval() got %v, wanted true", out.Value())
}
}

Expand Down
12 changes: 5 additions & 7 deletions cel/decls.go
Expand Up @@ -662,20 +662,18 @@ func (f *functionDecl) merge(other *functionDecl) (*functionDecl, error) {
return merged, nil
}

// addOverload ensures that the new overload does not collide with an existing overload signature,
// nor does it redefine an existing overload binding.
// addOverload ensures that the new overload does not collide with an existing overload signature;
// however, if the function signatures are identical, the implementation may be rewritten as its
// difficult to compare functions by object identity.
func (f *functionDecl) addOverload(overload *overloadDecl) error {
for id, o := range f.overloads {
if id != overload.id && o.signatureOverlaps(overload) {
return fmt.Errorf("overload signature collision in function %s: %s collides with %s", f.name, o.id, overload.id)
}
if id == overload.id {
if o.signatureEquals(overload) && o.nonStrict == overload.nonStrict {
if !o.hasBinding() && overload.hasBinding() {
f.overloads[id] = overload
} else if o.hasBinding() && overload.hasBinding() && o != overload {
return fmt.Errorf("overload binding collision in function %s: %s has multiple bindings", f.name, o.id)
}
// Allow redefinition of an overload implementation so long as the signatures match.
f.overloads[id] = overload
} else {
return fmt.Errorf("overload redefinition in function. %s: %s has multiple definitions", f.name, o.id)
}
Expand Down
4 changes: 0 additions & 4 deletions cel/decls_test.go
Expand Up @@ -147,10 +147,6 @@ func TestFunctionMerge(t *testing.T) {
t.Errorf("prg.Eval() got %v, wanted %v", out, want)
}

_, err = NewCustomEnv(vectorExt, vectorExt)
if err == nil || !strings.Contains(err.Error(), "overload binding collision") {
t.Errorf("NewCustomEnv(vectorExt, vectorExt) did not produce expected error: %v", err)
}
_, err = NewCustomEnv(size, size)
if err == nil || !strings.Contains(err.Error(), "already has a binding") {
t.Errorf("NewCustomEnv(size, size) did not produce the expected error: %v", err)
Expand Down
28 changes: 26 additions & 2 deletions cel/library.go
Expand Up @@ -85,7 +85,7 @@ func (stdLibrary) ProgramOptions() []ProgramOption {
type timeUTCLibrary struct{}

func (timeUTCLibrary) CompileOptions() []EnvOption {
return timestampOverloadDeclarations
return timeOverloadDeclarations
}

func (timeUTCLibrary) ProgramOptions() []ProgramOption {
Expand All @@ -97,7 +97,31 @@ func (timeUTCLibrary) ProgramOptions() []ProgramOption {
var (
utcTZ = types.String("UTC")

timestampOverloadDeclarations = []EnvOption{
timeOverloadDeclarations = []EnvOption{
Function(overloads.TimeGetHours,
MemberOverload(overloads.DurationToHours, []*Type{DurationType}, IntType,
UnaryBinding(func(dur ref.Val) ref.Val {
d := dur.(types.Duration)
return types.Int(d.Hours())
}))),
Function(overloads.TimeGetMinutes,
MemberOverload(overloads.DurationToMinutes, []*Type{DurationType}, IntType,
UnaryBinding(func(dur ref.Val) ref.Val {
d := dur.(types.Duration)
return types.Int(d.Minutes())
}))),
Function(overloads.TimeGetSeconds,
MemberOverload(overloads.DurationToSeconds, []*Type{DurationType}, IntType,
UnaryBinding(func(dur ref.Val) ref.Val {
d := dur.(types.Duration)
return types.Int(d.Seconds())
}))),
Function(overloads.TimeGetMilliseconds,
MemberOverload(overloads.DurationToMilliseconds, []*Type{DurationType}, IntType,
UnaryBinding(func(dur ref.Val) ref.Val {
d := dur.(types.Duration)
return types.Int(d.Milliseconds())
}))),
Function(overloads.TimeGetFullYear,
MemberOverload(overloads.TimestampToYear, []*Type{TimestampType}, IntType,
UnaryBinding(func(ts ref.Val) ref.Val {
Expand Down