From 96885960164557fb71bd2e76706b40153cb65045 Mon Sep 17 00:00:00 2001 From: Alex Jurkiewicz Date: Tue, 1 Sep 2020 17:01:06 +1000 Subject: [PATCH 1/4] Add StartsWith function --- cty/function/stdlib/string.go | 53 +++++++++++++++++++++++++++++- cty/function/stdlib/string_test.go | 28 ++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/cty/function/stdlib/string.go b/cty/function/stdlib/string.go index 01ebc47f..054f96c0 100644 --- a/cty/function/stdlib/string.go +++ b/cty/function/stdlib/string.go @@ -96,6 +96,54 @@ var StrlenFunc = function.New(&function.Spec{ }, }) +var StartsWithFunc = function.New(&function.Spec{ + Params: []function.Parameter{ + { + Name: "str", + Type: cty.String, + AllowDynamicType: true, + }, + { + Name: "prefix", + Type: cty.String, + AllowDynamicType: true, + }, + }, + Type: function.StaticReturnType(cty.Bool), + Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { + str := []byte(args[0].AsString()) + prefix := []byte(args[1].AsString()) + + // Empty prefix always matches + prefixLenNum, err := Strlen(args[1]) + if err != nil { + // should never happen + panic("Stdlen returned an error") + } + var prefixLen int + err = gocty.FromCtyValue(prefixLenNum, &prefixLen) + if err != nil { + // should never happen + panic("Stdlen returned a non-int number") + } + if prefixLen == 0 { + return cty.BoolVal(true), nil + } + + // For each character of prefix, check the matching character of str. + // If they don't match, fail + var i int + for i = 0; i < prefixLen; { + if str[i] != prefix[i] { + return cty.BoolVal(false), nil + } + } + + // We do match + return cty.BoolVal(true), nil + }, +}) + var SubstrFunc = function.New(&function.Spec{ Params: []function.Parameter{ { @@ -151,7 +199,6 @@ var SubstrFunc = function.New(&function.Spec{ return cty.StringVal(""), nil } - sub := in pos := 0 var i int @@ -473,6 +520,10 @@ func Strlen(str cty.Value) (cty.Value, error) { return StrlenFunc.Call([]cty.Value{str}) } +func StartsWith(str cty.Value, prefix cty.Value) (cty.Value, error) { + return SubstrFunc.Call([]cty.Value{str, prefix}) +} + // Substr is a Function that extracts a sequence of characters from another // string and creates a new string. // diff --git a/cty/function/stdlib/string_test.go b/cty/function/stdlib/string_test.go index 234386cf..569ffa55 100644 --- a/cty/function/stdlib/string_test.go +++ b/cty/function/stdlib/string_test.go @@ -268,6 +268,34 @@ func TestStrlen(t *testing.T) { } } +func TestStartsWith(t *testing.T) { + tests := []struct { + String cty.Value + Prefix cty.Value + Want cty.Value + }{ + { + cty.StringVal("hello"), + cty.StringVal("h"), + cty.BoolVal(true), + }, + } + for _, test := range tests { + t.Run(test.String.GoString(), func(t *testing.T) { + got, err := StartsWith(test.String, test.Prefix) + + 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) + } + }) + } + +} + func TestSubstr(t *testing.T) { tests := []struct { Input cty.Value From 1f143821f315a4907a7f4b28717b24d02c271c33 Mon Sep 17 00:00:00 2001 From: Alex Jurkiewicz Date: Tue, 1 Sep 2020 17:09:36 +1000 Subject: [PATCH 2/4] Always test against oldstable, stable, and tip --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4b488582..5fc0b584 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,8 @@ language: go go: - - 1.11.x - - 1.12.x + - oldstable + - stable - tip before_install: From 9facf4349193ff8e1f88d4f05b61fc9ff16d8b23 Mon Sep 17 00:00:00 2001 From: Alex Jurkiewicz Date: Tue, 1 Sep 2020 17:11:10 +1000 Subject: [PATCH 3/4] fixup! Add StartsWith function --- cty/function/stdlib/string.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cty/function/stdlib/string.go b/cty/function/stdlib/string.go index 054f96c0..0b8eee23 100644 --- a/cty/function/stdlib/string.go +++ b/cty/function/stdlib/string.go @@ -521,7 +521,7 @@ func Strlen(str cty.Value) (cty.Value, error) { } func StartsWith(str cty.Value, prefix cty.Value) (cty.Value, error) { - return SubstrFunc.Call([]cty.Value{str, prefix}) + return StartsWithFunc.Call([]cty.Value{str, prefix}) } // Substr is a Function that extracts a sequence of characters from another From 687a2af1cbff7033737608c49ffe72504a9b0534 Mon Sep 17 00:00:00 2001 From: Alex Jurkiewicz Date: Tue, 1 Sep 2020 17:17:09 +1000 Subject: [PATCH 4/4] fixup! fixup! Add StartsWith function --- cty/function/stdlib/string_test.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/cty/function/stdlib/string_test.go b/cty/function/stdlib/string_test.go index 569ffa55..cf7bfa21 100644 --- a/cty/function/stdlib/string_test.go +++ b/cty/function/stdlib/string_test.go @@ -279,6 +279,36 @@ func TestStartsWith(t *testing.T) { cty.StringVal("h"), cty.BoolVal(true), }, + { + cty.StringVal("HELLO"), + cty.StringVal("h"), + cty.BoolVal(false), + }, + { + cty.StringVal(""), + cty.StringVal("foo"), + cty.BoolVal(true), + } + { + cty.StringVal("foo"), + cty.StringVal(""), + cty.BoolVal(true), + }, + { + cty.StringVal(""), + cty.StringVal(""), + cty.BoolVal(true), + }, + { + cty.StringVal("short1"), + cty.StringVal("short1extra"), + cty.BoolVal(false), + }, + { + cty.StringVal("short2"), + cty.StringVal("longerprefix"), + cty.BoolVal(false), + }, } for _, test := range tests { t.Run(test.String.GoString(), func(t *testing.T) {