Skip to content

Commit

Permalink
Merge pull request #59 from mmourick/feat/add-string-assert-functions
Browse files Browse the repository at this point in the history
feat: add `empty` and `not_empty` functions
  • Loading branch information
bschaatsbergen committed Aug 29, 2024
2 parents 0093070 + 674110d commit 1542821
Show file tree
Hide file tree
Showing 13 changed files with 782 additions and 0 deletions.
54 changes: 54 additions & 0 deletions docs/functions/empty.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
page_title: "empty function - terraform-provider-assert"
subcategory: "String Functions"
description: |-
Checks wether a given string is empty
---

# function: empty



## Terraform Test Example

```terraform
run "check_cloudwatch_log_subscription_match_all" {
command = plan
assert {
condition = provider::assert::empty(aws_cloudwatch_log_subscription_filter.example.filter_pattern)
error_message = "CloudWatch log subscription filter pattern must be empty, as it is a match all."
}
}
```

## Variable Validation Example

```terraform
variable "example" {
type = string
validation {
condition = provider::assert::empty(var.example)
error_message = "Variable 'example' must be empty."
}
}
```

## Signature

<!-- signature generated by tfplugindocs -->
```text
empty(s string) bool
```

## Arguments

<!-- arguments generated by tfplugindocs -->
1. `s` (String) The string to check


## Return Type

The return type of `empty` is a boolean.
54 changes: 54 additions & 0 deletions docs/functions/not_empty.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
page_title: "not_empty function - terraform-provider-assert"
subcategory: "String Functions"
description: |-
Checks wether a given string is not empty
---

# function: not_empty



## Terraform Test Example

```terraform
run "check_security_group_description" {
command = plan
assert {
condition = provider::assert::not_empty(aws_security_group.example.description)
error_message = "Security group description must not be empty."
}
}
```

## Variable Validation Example

```terraform
variable "example" {
type = string
validation {
condition = provider::assert::not_empty(var.example)
error_message = "Variable 'example' must not be empty."
}
}
```

## Signature

<!-- signature generated by tfplugindocs -->
```text
not_empty(s string) bool
```

## Arguments

<!-- arguments generated by tfplugindocs -->
1. `s` (String) The string to check


## Return Type

The return type of `not_empty` is a boolean.
9 changes: 9 additions & 0 deletions examples/functions/empty/function.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
run "check_cloudwatch_log_subscription_match_all" {

command = plan

assert {
condition = provider::assert::empty(aws_cloudwatch_log_subscription_filter.example.filter_pattern)
error_message = "CloudWatch log subscription filter pattern must be empty, as it is a match all."
}
}
8 changes: 8 additions & 0 deletions examples/functions/empty/variable.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
variable "example" {
type = string

validation {
condition = provider::assert::empty(var.example)
error_message = "Variable 'example' must be empty."
}
}
9 changes: 9 additions & 0 deletions examples/functions/not_empty/function.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
run "check_security_group_description" {

command = plan

assert {
condition = provider::assert::not_empty(aws_security_group.example.description)
error_message = "Security group description must not be empty."
}
}
8 changes: 8 additions & 0 deletions examples/functions/not_empty/variable.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
variable "example" {
type = string

validation {
condition = provider::assert::not_empty(var.example)
error_message = "Variable 'example' must not be empty."
}
}
53 changes: 53 additions & 0 deletions internal/provider/empty_function.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package provider

import (
"context"

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

var (
_ function.Function = EmptyFunction{}
)

func NewEmptyFunction() function.Function {
return EmptyFunction{}
}

type EmptyFunction struct{}

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

func (r EmptyFunction) Definition(_ context.Context, _ function.DefinitionRequest, resp *function.DefinitionResponse) {
resp.Definition = function.Definition{
Summary: "Checks wether a given string is empty",
Parameters: []function.Parameter{
function.StringParameter{
AllowNullValue: false,
AllowUnknownValues: false,
Description: "The string to check",
Name: "s",
},
},
Return: function.BoolReturn{},
}
}

func (r EmptyFunction) Run(ctx context.Context, req function.RunRequest, resp *function.RunResponse) {
var argument string

resp.Error = function.ConcatFuncErrors(req.Arguments.Get(ctx, &argument))
if resp.Error != nil {
return
}
resp.Error = function.ConcatFuncErrors(resp.Result.Set(ctx, isEmpty(argument)))
}

func isEmpty(argument string) bool {
return len(argument) == 0
}
171 changes: 171 additions & 0 deletions internal/provider/empty_function_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package provider

import (
"regexp"
"testing"

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

func TestEmptyFunction_stringEmpty(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: `
output "test" {
value = provider::assert::empty("")
}
`,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckOutput("test", "true"),
),
},
},
})
}

func TestEmptyFunction_stringNotEmpty(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: `
output "test" {
value = provider::assert::empty("notempty")
}
`,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckOutput("test", "false"),
),
},
},
})
}

func TestEmptyFunction_whitespaceString(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: `
output "test" {
value = provider::assert::empty(" ")
}
`,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckOutput("test", "false"),
),
},
},
})
}

func TestEmptyFunction_null(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 {
example = null
}
output "test" {
value = provider::assert::empty(local.example)
}
`,
ExpectError: regexp.MustCompile(`Invalid value for "string" parameter: argument must not be null`),
},
},
})
}

func TestEmptyFunction_listError(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: `
output "test" {
value = provider::assert::empty([])
}
`,
ExpectError: regexp.MustCompile(`Invalid value for "string" parameter: string required`),
},
},
})
}

func TestEmptyFunction_trimmedWhitespaceTrue(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 {
example = ""
}
output "test" {
value = provider::assert::empty(trimspace(local.example))
}
`,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckOutput("test", "true"),
),
},
},
})
}

func TestEmptyFunction_specialCharacters(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: `
output "test" {
value = provider::assert::empty("!@#$%^&*()")
}
`,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckOutput("test", "false"),
),
},
},
})
}
Loading

0 comments on commit 1542821

Please sign in to comment.