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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] new functions: startswith and endswith #63

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
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
4 changes: 2 additions & 2 deletions .travis.yml
@@ -1,8 +1,8 @@
language: go

go:
- 1.11.x
- 1.12.x
- oldstable
- stable
- tip

before_install:
Expand Down
53 changes: 52 additions & 1 deletion cty/function/stdlib/string.go
Expand Up @@ -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{
{
Expand Down Expand Up @@ -151,7 +199,6 @@ var SubstrFunc = function.New(&function.Spec{
return cty.StringVal(""), nil
}


sub := in
pos := 0
var i int
Expand Down Expand Up @@ -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 StartsWithFunc.Call([]cty.Value{str, prefix})
}

// Substr is a Function that extracts a sequence of characters from another
// string and creates a new string.
//
Expand Down
58 changes: 58 additions & 0 deletions cty/function/stdlib/string_test.go
Expand Up @@ -268,6 +268,64 @@ 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),
},
{
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) {
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
Expand Down