Skip to content

Commit

Permalink
Feat: Add strcontains function and documentation (#33069)
Browse files Browse the repository at this point in the history
* add strcontains function and documentation
  • Loading branch information
Cliftonz committed Apr 26, 2023
1 parent fa3980b commit 3bb6a58
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 0 deletions.
4 changes: 4 additions & 0 deletions internal/lang/funcs/descriptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,10 @@ var DescriptionList = map[string]descriptionEntry{
Description: "`startswith` takes two values: a string to check and a prefix string. The function returns true if the string begins with that exact prefix.",
ParamDescription: []string{"", ""},
},
"strcontains": {
Description: "`strcontains` takes two values: a string to check and an expected substring. The function returns true if the string has the substring contained within it.",
ParamDescription: []string{"", ""},
},
"strrev": {
Description: "`strrev` reverses the characters in a string. Note that the characters are treated as _Unicode characters_ (in technical terms, Unicode [grapheme cluster boundaries](https://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries) are respected).",
ParamDescription: []string{""},
Expand Down
26 changes: 26 additions & 0 deletions internal/lang/funcs/string.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,29 @@ var ReplaceFunc = function.New(&function.Spec{
func Replace(str, substr, replace cty.Value) (cty.Value, error) {
return ReplaceFunc.Call([]cty.Value{str, substr, replace})
}

// StrContainsFunc searches a given string for another given substring,
// if found the function returns true, otherwise returns false.
var StrContainsFunc = function.New(&function.Spec{
Params: []function.Parameter{
{
Name: "str",
Type: cty.String,
},
{
Name: "substr",
Type: cty.String,
},
},
Type: function.StaticReturnType(cty.Bool),
Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
str := args[0].AsString()
substr := args[1].AsString()

if strings.Contains(str, substr) {
return cty.True, nil
}

return cty.False, nil
},
})
63 changes: 63 additions & 0 deletions internal/lang/funcs/string_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,66 @@ func TestReplace(t *testing.T) {
})
}
}

func TestStrContains(t *testing.T) {
tests := []struct {
String cty.Value
Substr cty.Value
Want cty.Value
Err bool
}{
{
cty.StringVal("hello"),
cty.StringVal("hel"),
cty.BoolVal(true),
false,
},
{
cty.StringVal("hello"),
cty.StringVal("lo"),
cty.BoolVal(true),
false,
},
{
cty.StringVal("hello1"),
cty.StringVal("1"),
cty.BoolVal(true),
false,
},
{
cty.StringVal("hello1"),
cty.StringVal("heo"),
cty.BoolVal(false),
false,
},
{
cty.StringVal("hello1"),
cty.NumberIntVal(1),
cty.UnknownVal(cty.Bool),
true,
},
}

for _, test := range tests {
t.Run(fmt.Sprintf("includes(%#v, %#v)", test.String, test.Substr), func(t *testing.T) {
got, err := StrContains(test.String, test.Substr)

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)
}
})
}
}

func StrContains(str, substr cty.Value) (cty.Value, error) {
return StrContainsFunc.Call([]cty.Value{str, substr})
}
1 change: 1 addition & 0 deletions internal/lang/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ func (s *Scope) Functions() map[string]function.Function {
"sort": stdlib.SortFunc,
"split": stdlib.SplitFunc,
"startswith": funcs.StartsWithFunc,
"strcontains": funcs.StrContainsFunc,
"strrev": stdlib.ReverseFunc,
"substr": stdlib.SubstrFunc,
"sum": funcs.SumFunc,
Expand Down
11 changes: 11 additions & 0 deletions internal/lang/functions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -906,6 +906,17 @@ func TestFunctions(t *testing.T) {
},
},

"strcontains": {
{
`strcontains("hello", "llo")`,
cty.BoolVal(true),
},
{
`strcontains("hello", "a")`,
cty.BoolVal(false),
},
},

"strrev": {
{
`strrev("hello world")`,
Expand Down
4 changes: 4 additions & 0 deletions website/data/language-nav-data.json
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,10 @@
"title": "<code>startswith</code>",
"href": "/language/functions/startswith"
},
{
"title": "<code>strcontains</code>",
"href": "/language/functions/strcontains"
},
{
"title": "<code>strrev</code>",
"href": "/language/functions/strrev"
Expand Down
25 changes: 25 additions & 0 deletions website/docs/language/functions/strcontains.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
page_title: strcontains - Functions - Configuration Language
description: |-
The strcontains function checks whether a given string can be found within another string.
---

# `strcontains` Function

`strcontains` function checks whether a substring is within another string.

```hcl
strcontains(string, substr)
```

## Examples

```
> strcontains("hello world", "wor")
true
```

```
> strcontains("hello world", "wod")
false
```
4 changes: 4 additions & 0 deletions website/layouts/language.erb
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,10 @@
<a href="/docs/language/functions/startswith.html">startswith</a>
</li>

<li>
<a href="/docs/language/functions/strcontains.html">strcontains</a>
</li>

<li>
<a href="/docs/language/functions/strrev.html">strrev</a>
</li>
Expand Down

0 comments on commit 3bb6a58

Please sign in to comment.