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