Skip to content

Commit

Permalink
feat: add value function
Browse files Browse the repository at this point in the history
  • Loading branch information
bschaatsbergen committed Apr 5, 2024
1 parent 0271dbf commit 9270aa6
Show file tree
Hide file tree
Showing 10 changed files with 328 additions and 2 deletions.
2 changes: 1 addition & 1 deletion docs/functions/key.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
page_title: "key function - terraform-provider-assert"
subcategory: "IP Address Functions"
subcategory: "Map Functions"
description: |-
Checks whether a key exists in a map
---
Expand Down
53 changes: 53 additions & 0 deletions docs/functions/value.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
page_title: "value function - terraform-provider-assert"
subcategory: "Map Functions"
description: |-
Checks whether a value exists in a map
---

# function: value



## Terraform Test Example

```terraform
run "check_if_lambda_function_tags_has_value" {
command = plan
assert {
condition = provider::assert::value(aws_lambda_function.example.tags, "value1")
error_message = "The tags map must contain the value 'value1'"
}
}
```

## Variable Validation Example

```terraform
variable "tags" {
type = map(string)
validation {
condition = provider::assert::value(var.tags, "value1")
error_message = "The tags map must contain the value 'value1'"
}
}
```

## Signature

<!-- signature generated by tfplugindocs -->
```text
value(map map of string, value string) bool
```

## Arguments

<!-- arguments generated by tfplugindocs -->
1. `map` (Map of String) The map to check
1. `value` (String) The value to check


## Return Type

The return type of `value` is a boolean.
8 changes: 8 additions & 0 deletions examples/functions/value/function.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
run "check_if_lambda_function_tags_has_value" {
command = plan

assert {
condition = provider::assert::value(aws_lambda_function.example.tags, "value1")
error_message = "The tags map must contain the value 'value1'"
}
}
7 changes: 7 additions & 0 deletions examples/functions/value/variable.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
variable "tags" {
type = map(string)
validation {
condition = provider::assert::value(var.tags, "value1")
error_message = "The tags map must contain the value 'value1'"
}
}
4 changes: 4 additions & 0 deletions internal/provider/key_function.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ func (r KeyFunction) Run(ctx context.Context, req function.RunRequest, resp *fun
}

func hasKey(mapValue *map[string]string, key *string) bool {
if mapValue == nil {
return false
}

_, ok := (*mapValue)[*key]
return ok
}
1 change: 1 addition & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ func (p *AssertProvider) Functions(ctx context.Context) []func() function.Functi
NewNegativeFunction,
NewPositiveFunction,
NewKeyFunction,
NewValueFunction,
}
}

Expand Down
73 changes: 73 additions & 0 deletions internal/provider/value_function.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package provider

import (
"context"

"github.com/hashicorp/terraform-plugin-framework/function"
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
)

var (
_ function.Function = ValueFunction{}
)

func NewValueFunction() function.Function {
return ValueFunction{}
}

type ValueFunction struct{}

func (r ValueFunction) Metadata(_ context.Context, req function.MetadataRequest, resp *function.MetadataResponse) {
resp.Name = "value"
}

func (r ValueFunction) Definition(_ context.Context, _ function.DefinitionRequest, resp *function.DefinitionResponse) {
resp.Definition = function.Definition{
Summary: "Checks whether a value exists in a map",
Parameters: []function.Parameter{
function.MapParameter{
AllowNullValue: false,
AllowUnknownValues: true,
Description: "The map to check",
Name: "map",
ElementType: basetypes.StringType{},
},
function.StringParameter{
AllowNullValue: false,
AllowUnknownValues: true,
Description: "The value to check",
Name: "value",
},
},
Return: function.BoolReturn{},
}
}

func (r ValueFunction) Run(ctx context.Context, req function.RunRequest, resp *function.RunResponse) {
var mapValue *map[string]string
var value *string

resp.Error = function.ConcatFuncErrors(req.Arguments.Get(ctx, &mapValue, &value))
if resp.Error != nil {
return
}

resp.Error = function.ConcatFuncErrors(resp.Result.Set(ctx, hasValue(mapValue, value)))
}

func hasValue(mapValue *map[string]string, value *string) bool {
if mapValue == nil {
return false
}

for _, v := range *mapValue {
if v == *value {
return true
}
}

return false
}
145 changes: 145 additions & 0 deletions internal/provider/value_function_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package provider

import (
"testing"

"github.com/hashicorp/go-version"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/tfversion"
)

func TestValueFunction(t *testing.T) {
t.Parallel()
resource.UnitTest(t, resource.TestCase{
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
tfversion.SkipBelow(version.Must(version.NewVersion(MinimalRequiredTerraformVersion))),
},
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
{
Config: `
locals {
my_map = {
"key1" = "value1"
"key2" = "value2"
}
}
output "test" {
value = provider::assert::value(local.my_map, "value1")
}
`,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckOutput("test", "true"),
),
},
},
})
}

func TestValueFunction_mixed(t *testing.T) {
t.Parallel()
resource.UnitTest(t, resource.TestCase{
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
tfversion.SkipBelow(version.Must(version.NewVersion(MinimalRequiredTerraformVersion))),
},
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
{
Config: `
locals {
my_map = {
"key1" = true
"key2" = "value2"
3 = "value3"
"4" = "value4"
5 = 5
"6" = false
}
}
output "test" {
value = provider::assert::value(local.my_map, "5")
}
`,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckOutput("test", "true"),
),
},
},
})
}

func TestValueFunction_nested_map(t *testing.T) {
t.Parallel()
resource.UnitTest(t, resource.TestCase{
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
tfversion.SkipBelow(version.Must(version.NewVersion(MinimalRequiredTerraformVersion))),
},
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
{
Config: `
locals {
my_map = {
"key1" = {
"nested" = "value2"
}
}
}
output "test" {
value = provider::assert::value(local.my_map["key1"], "value2")
}
`,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckOutput("test", "true"),
),
},
},
})
}

func TestValueFunction_falseCases(t *testing.T) {
t.Parallel()
resource.UnitTest(t, resource.TestCase{
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
tfversion.SkipBelow(version.Must(version.NewVersion(MinimalRequiredTerraformVersion))),
},
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
{
Config: `
locals {
my_map = {
"key1" = "value1"
}
}
output "test" {
value = provider::assert::value(local.my_map, "value2")
}
`,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckOutput("test", "false"),
),
},
{
Config: `
locals {
my_map = {
"key1" = {
"nested" = "value2"
}
}
}
output "test" {
value = provider::assert::value(local.my_map["key1"], "nested2")
}
`,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckOutput("test", "false"),
),
},
},
})
}
2 changes: 1 addition & 1 deletion templates/functions/key.md.tmpl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}"
subcategory: "IP Address Functions"
subcategory: "Map Functions"
description: |-
{{ .Summary | plainmarkdown | trimspace | prefixlines " " }}
---
Expand Down
35 changes: 35 additions & 0 deletions templates/functions/value.md.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}"
subcategory: "Map Functions"
description: |-
{{ .Summary | plainmarkdown | trimspace | prefixlines " " }}
---

# {{.Type}}: {{.Name}}

{{ .Description | trimspace }}

{{ if .HasExample -}}
## Terraform Test Example

{{tffile .ExampleFile }}
{{- end }}

## Variable Validation Example

{{ tffile (printf "examples/functions/%s/variable.tf" .Name)}}

## Signature

{{ .FunctionSignatureMarkdown }}

## Arguments

{{ .FunctionArgumentsMarkdown }}
{{ if .HasVariadic -}}
{{ .FunctionVariadicArgumentMarkdown }}
{{- end }}

## Return Type

The return type of `{{.Name}}` is a boolean.

0 comments on commit 9270aa6

Please sign in to comment.