From 4ad36769342ae8f817e4956cf4ae8a28c9a6768e Mon Sep 17 00:00:00 2001 From: Kristin Laemmert Date: Wed, 23 May 2018 12:41:55 -0700 Subject: [PATCH] port ceil function --- lang/funcs/number.go | 33 ++++++++++++++++++++++++++++ lang/funcs/number_test.go | 46 +++++++++++++++++++++++++++++++++++++++ lang/functions.go | 2 +- 3 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 lang/funcs/number.go create mode 100644 lang/funcs/number_test.go diff --git a/lang/funcs/number.go b/lang/funcs/number.go new file mode 100644 index 000000000..930b8ed48 --- /dev/null +++ b/lang/funcs/number.go @@ -0,0 +1,33 @@ +package funcs + +import ( + "math" + + "github.com/zclconf/go-cty/cty" + "github.com/zclconf/go-cty/cty/function" + "github.com/zclconf/go-cty/cty/gocty" +) + +// CeilFunc contructs a function that returns the closest whole number greater +// than or equal to the given value. +var CeilFunc = function.New(&function.Spec{ + Params: []function.Parameter{ + { + Name: "num", + Type: cty.Number, + }, + }, + Type: function.StaticReturnType(cty.Number), + Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { + var val float64 + if err := gocty.FromCtyValue(args[0], &val); err != nil { + return cty.UnknownVal(cty.String), err + } + return cty.NumberIntVal(int64(math.Ceil(val))), nil + }, +}) + +// Ceil returns the closest whole number greater than or equal to the given value. +func Ceil(num cty.Value) (cty.Value, error) { + return CeilFunc.Call([]cty.Value{num}) +} diff --git a/lang/funcs/number_test.go b/lang/funcs/number_test.go new file mode 100644 index 000000000..30896c2bb --- /dev/null +++ b/lang/funcs/number_test.go @@ -0,0 +1,46 @@ +package funcs + +import ( + "fmt" + "testing" + + "github.com/zclconf/go-cty/cty" +) + +func TestCeil(t *testing.T) { + tests := []struct { + Num cty.Value + Want cty.Value + Err bool + }{ + { + cty.NumberFloatVal(-1.8), + cty.NumberFloatVal(-1), + false, + }, + { + cty.NumberFloatVal(1.2), + cty.NumberFloatVal(2), + false, + }, + } + + for _, test := range tests { + t.Run(fmt.Sprintf("Ceil(%#v)", test.Num), func(t *testing.T) { + got, err := Ceil(test.Num) + + if test.Err { + if err == nil { + t.Fatal("succeeded; want error") + } + return + } else if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + if !got.RawEquals(test.Want) { + t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) + } + }) + } +} diff --git a/lang/functions.go b/lang/functions.go index 7a9e9d5dd..93e2bdc3b 100644 --- a/lang/functions.go +++ b/lang/functions.go @@ -37,7 +37,7 @@ func (s *Scope) Functions() map[string]function.Function { "base64sha256": funcs.Base64Sha256Func, "base64sha512": funcs.Base64Sha512Func, "bcrypt": funcs.BcryptFunc, - "ceil": unimplFunc, // TODO + "ceil": funcs.CeilFunc, "chomp": unimplFunc, // TODO "cidrhost": unimplFunc, // TODO "cidrnetmask": unimplFunc, // TODO