feat: add tests for plan modifiers configuration and resource schema handling

This commit is contained in:
Andre_Harms 2026-02-10 08:08:47 +01:00
parent c4b31d0ba8
commit 062fd98870
2 changed files with 224 additions and 0 deletions

View file

@ -0,0 +1,224 @@
package utils
import (
"testing"
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/stackitcloud/stackit-sdk-go/core/utils"
)
func TestReadModifiersConfig(t *testing.T) {
testcases := []struct {
name string
content []byte
wantErr bool
}{
{
name: "valid yaml",
content: []byte(`
fields:
- name: 'id'
modifiers:
- 'UseStateForUnknown'
`),
wantErr: false,
},
{
name: "invalid yaml",
content: []byte(`invalid: yaml: :`),
wantErr: true,
},
}
for _, tc := range testcases {
t.Run(
tc.name, func(t *testing.T) {
_, err := ReadModifiersConfig(tc.content)
if (err != nil) != tc.wantErr {
t.Errorf("ReadModifiersConfig() error = %v, wantErr %v", err, tc.wantErr)
}
},
)
}
}
func TestAddPlanModifiersToResourceSchema(t *testing.T) {
testcases := []struct {
name string
fields *Fields
sch *schema.Schema
wantErr bool
}{
{
name: "full coverage - all types and nested structures",
fields: &Fields{
Fields: []*Field{
{
Name: "string_attr",
Modifiers: []*string{utils.Ptr("RequiresReplace"), utils.Ptr("UseStateForUnknown")},
},
{Name: "bool_attr", Modifiers: []*string{utils.Ptr("RequiresReplace")}},
{Name: "int_attr", Modifiers: []*string{utils.Ptr("UseStateForUnknown")}},
{Name: "list_attr", Modifiers: []*string{utils.Ptr("RequiresReplace")}},
{Name: "Nested.sub_string", Modifiers: []*string{utils.Ptr("RequiresReplace")}},
},
},
sch: &schema.Schema{
Attributes: map[string]schema.Attribute{
"StringAttr": schema.StringAttribute{},
"BoolAttr": schema.BoolAttribute{},
"IntAttr": schema.Int64Attribute{},
"ListAttr": schema.ListAttribute{},
"Nested": schema.SingleNestedAttribute{
Attributes: map[string]schema.Attribute{
"SubString": schema.StringAttribute{},
},
},
"Unsupported": schema.MapAttribute{ElementType: types.StringType}, // Triggers default/warn case
},
},
wantErr: false,
},
{
name: "validation error - invalid modifier",
fields: &Fields{
Fields: []*Field{
{Name: "id", Modifiers: []*string{utils.Ptr("InvalidModifier")}},
},
},
sch: &schema.Schema{
Attributes: map[string]schema.Attribute{"id": schema.StringAttribute{}},
},
wantErr: true,
},
{
name: "validation error - empty modifier",
fields: &Fields{
Fields: []*Field{
{Name: "id", Modifiers: []*string{utils.Ptr("")}},
},
},
sch: &schema.Schema{},
wantErr: true,
},
{
name: "nil fields - should return nil",
fields: nil,
sch: &schema.Schema{},
wantErr: false,
},
}
for _, tc := range testcases {
t.Run(
tc.name, func(t *testing.T) {
err := AddPlanModifiersToResourceSchema(tc.fields, tc.sch)
if (err != nil) != tc.wantErr {
t.Fatalf("AddPlanModifiersToResourceSchema() error = %v, wantErr %v", err, tc.wantErr)
}
if !tc.wantErr && tc.name == "full coverage - all types and nested structures" {
// Check StringAttr
if sAttr, ok := tc.sch.Attributes["StringAttr"].(schema.StringAttribute); ok {
if len(sAttr.PlanModifiers) != 2 {
t.Errorf("StringAttr: expected 2 modifiers, got %d", len(sAttr.PlanModifiers))
}
}
// Check Nested Sub-Attribute
if nested, ok := tc.sch.Attributes["Nested"].(schema.SingleNestedAttribute); ok {
if subAttr, ok := nested.Attributes["SubString"].(schema.StringAttribute); ok {
if len(subAttr.PlanModifiers) != 1 {
// Dies schlug vorher fehl, weil der Prefix "Nested" statt "nested" war
t.Errorf("Nested SubString: expected 1 modifier, got %d", len(subAttr.PlanModifiers))
}
} else {
t.Error("SubString attribute not found in Nested")
}
} else {
t.Error("Nested attribute not found")
}
}
},
)
}
}
func TestFieldListToMap(t *testing.T) {
testcases := []struct {
name string
fields *Fields
want map[string][]*string
}{
{
name: "convert list to map",
fields: &Fields{
Fields: []*Field{
{Name: "test", Modifiers: []*string{utils.Ptr("mod")}},
},
},
want: map[string][]*string{
"test": {utils.Ptr("mod")},
},
},
{
name: "nil fields",
fields: nil,
want: map[string][]*string{},
},
}
for _, tc := range testcases {
t.Run(
tc.name, func(t *testing.T) {
got := fieldListToMap(tc.fields)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("fieldListToMap() mismatch (-want +got):\n%s", diff)
}
},
)
}
}
func TestHandleTypeMismatches(t *testing.T) {
modifiers := []*string{utils.Ptr("RequiresReplace")}
t.Run(
"bool type mismatch", func(t *testing.T) {
_, err := handleBoolPlanModifiers(schema.StringAttribute{}, modifiers)
if err == nil {
t.Error("expected error for type mismatch in handleBoolPlanModifiers")
}
},
)
t.Run(
"string type mismatch", func(t *testing.T) {
_, err := handleStringPlanModifiers(schema.BoolAttribute{}, modifiers)
if err == nil {
t.Error("expected error for type mismatch in handleStringPlanModifiers")
}
},
)
t.Run(
"int64 type mismatch", func(t *testing.T) {
_, err := handleInt64PlanModifiers(schema.StringAttribute{}, modifiers)
if err == nil {
t.Error("expected error for type mismatch in handleInt64PlanModifiers")
}
},
)
t.Run(
"list type mismatch", func(t *testing.T) {
_, err := handleListPlanModifiers(schema.StringAttribute{}, modifiers)
if err == nil {
t.Error("expected error for type mismatch in handleListPlanModifiers")
}
},
)
}