package fieldgroups import ( "testing" "pdf-wizard/internal/models" ) func TestDefaultFillValues(t *testing.T) { tests := []struct { name string fields []models.FormField values map[int]string expected map[int]string }{ { name: "all fields have values", fields: []models.FormField{ {ID: 1, FieldName: "name"}, {ID: 2, FieldName: "email"}, }, values: map[int]string{ 1: "Alice", 2: "alice@example.com", }, expected: map[int]string{ 1: "Alice", 2: "alice@example.com", }, }, { name: "some fields missing values", fields: []models.FormField{ {ID: 1, FieldName: "name"}, {ID: 2, FieldName: "email"}, {ID: 3, FieldName: "phone"}, }, values: map[int]string{ 1: "Alice", }, expected: map[int]string{ 1: "Alice", 2: "", 3: "", }, }, { name: "no fields", fields: []models.FormField{}, values: map[int]string{1: "val"}, expected: map[int]string{}, }, { name: "no values", fields: []models.FormField{ {ID: 1, FieldName: "name"}, }, values: map[int]string{}, expected: map[int]string{ 1: "", }, }, { name: "empty values for all fields", fields: []models.FormField{ {ID: 1, FieldName: "a"}, {ID: 2, FieldName: "b"}, }, values: map[int]string{ 1: "", 2: "", }, expected: map[int]string{ 1: "", 2: "", }, }, { name: "extra values ignored", fields: []models.FormField{ {ID: 1, FieldName: "name"}, }, values: map[int]string{ 1: "Alice", 999: "extra", }, expected: map[int]string{ 1: "Alice", }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := DefaultFillValues(tt.fields, tt.values) if len(got) != len(tt.expected) { t.Fatalf("DefaultFillValues returned %d entries, want %d: %v", len(got), len(tt.expected), got) } for k, v := range tt.expected { if got[k] != v { t.Errorf("DefaultFillValues[%d] = %q, want %q", k, got[k], v) } } }) } } func TestGet(t *testing.T) { t.Run("multiline exists", func(t *testing.T) { h, err := Get("multiline") if err != nil { t.Fatalf("Get('multiline') returned error: %v", err) } if h.Type() != "multiline" { t.Errorf("handler.Type() = %q, want 'multiline'", h.Type()) } }) t.Run("single_select exists", func(t *testing.T) { h, err := Get("single_select") if err != nil { t.Fatalf("Get('single_select') returned error: %v", err) } if h.Type() != "single_select" { t.Errorf("handler.Type() = %q, want 'single_select'", h.Type()) } }) t.Run("multi_select exists", func(t *testing.T) { h, err := Get("multi_select") if err != nil { t.Fatalf("Get('multi_select') returned error: %v", err) } if h.Type() != "multi_select" { t.Errorf("handler.Type() = %q, want 'multi_select'", h.Type()) } }) t.Run("conditional_other exists", func(t *testing.T) { h, err := Get("conditional_other") if err != nil { t.Fatalf("Get('conditional_other') returned error: %v", err) } if h.Type() != "conditional_other" { t.Errorf("handler.Type() = %q, want 'conditional_other'", h.Type()) } }) t.Run("unknown type returns error", func(t *testing.T) { _, err := Get("nonexistent_type") if err == nil { t.Fatal("Get('nonexistent_type') should return error") } }) } func TestGetFillValuesForGroup(t *testing.T) { t.Run("multiline group", func(t *testing.T) { group := models.FieldGroup{GroupType: "multiline"} fields := []models.FormField{ {ID: 1, FieldName: "line1"}, {ID: 2, FieldName: "line2"}, } values := map[int]string{ 1: "hello", } result, err := GetFillValuesForGroup(group, fields, values) if err != nil { t.Fatalf("GetFillValuesForGroup returned error: %v", err) } if result[1] != "" || result[2] != "" { // Multiline splits the first found value across fields // With "hello" (1 line) across 2 fields, line 1 gets "hello", line 2 gets "" if result[1] != "hello" || result[2] != "" { t.Errorf("unexpected multiline result: %v", result) } } }) t.Run("single_select group", func(t *testing.T) { group := models.FieldGroup{GroupType: "single_select"} fields := []models.FormField{ {ID: 1, FieldName: "opt1"}, {ID: 2, FieldName: "opt2"}, } values := map[int]string{ 1: "1", } result, err := GetFillValuesForGroup(group, fields, values) if err != nil { t.Fatalf("GetFillValuesForGroup returned error: %v", err) } if result[1] != "1" { t.Errorf("result[1] = %q, want '1'", result[1]) } if result[2] != "" { t.Errorf("result[2] = %q, want ''", result[2]) } }) t.Run("unknown group type returns error", func(t *testing.T) { group := models.FieldGroup{GroupType: "bogus_type"} _, err := GetFillValuesForGroup(group, nil, nil) if err == nil { t.Fatal("GetFillValuesForGroup with unknown type should return error") } }) } func TestValidateGroup(t *testing.T) { t.Run("single_select with one option selected", func(t *testing.T) { group := models.FieldGroup{GroupType: "single_select"} fields := []models.FormField{ {ID: 1, Type: "button", FieldName: "opt1"}, {ID: 2, Type: "button", FieldName: "opt2"}, } values := map[int]string{ 1: "1", } err := ValidateGroup(group, fields, values) if err != nil { t.Errorf("ValidateGroup should pass with one option selected: %v", err) } }) t.Run("single_select with no options selected", func(t *testing.T) { group := models.FieldGroup{GroupType: "single_select"} fields := []models.FormField{ {ID: 1, Type: "button", FieldName: "opt1"}, {ID: 2, Type: "button", FieldName: "opt2"}, } values := map[int]string{} err := ValidateGroup(group, fields, values) if err == nil { t.Error("ValidateGroup should fail with no options selected") } }) t.Run("single_select with multiple options", func(t *testing.T) { group := models.FieldGroup{GroupType: "single_select"} fields := []models.FormField{ {ID: 1, Type: "button", FieldName: "opt1"}, {ID: 2, Type: "button", FieldName: "opt2"}, } values := map[int]string{ 1: "1", 2: "1", } err := ValidateGroup(group, fields, values) if err == nil { t.Error("ValidateGroup should fail with multiple options selected") } }) t.Run("multiline always passes", func(t *testing.T) { group := models.FieldGroup{GroupType: "multiline"} fields := []models.FormField{ {ID: 1, FieldName: "line1"}, } values := map[int]string{} err := ValidateGroup(group, fields, values) if err != nil { t.Errorf("ValidateGroup for multiline should always pass: %v", err) } }) t.Run("unknown group type returns error", func(t *testing.T) { group := models.FieldGroup{GroupType: "nonexistent"} err := ValidateGroup(group, nil, nil) if err == nil { t.Fatal("ValidateGroup with unknown type should return error") } }) } func TestConditionalOtherValidation(t *testing.T) { tests := []struct { name string fields []models.FormField values map[int]string wantErr bool }{ { name: "checkbox unchecked, text fields empty — passes", fields: []models.FormField{ {ID: 1, Type: "button", FieldName: "other_checkbox"}, {ID: 2, Type: "text", FieldName: "other_text"}, }, values: map[int]string{}, wantErr: false, }, { name: "checkbox checked, text filled — passes", fields: []models.FormField{ {ID: 1, Type: "button", FieldName: "other_checkbox"}, {ID: 2, Type: "text", FieldName: "other_text"}, }, values: map[int]string{ 1: "1", 2: "some value", }, wantErr: false, }, { name: "checkbox checked, text empty — fails", fields: []models.FormField{ {ID: 1, Type: "button", FieldName: "other_checkbox"}, {ID: 2, Type: "text", FieldName: "other_text"}, }, values: map[int]string{ 1: "1", }, wantErr: true, }, { name: "checkbox checked, text missing — fails", fields: []models.FormField{ {ID: 1, Type: "button", FieldName: "other_checkbox"}, {ID: 2, Type: "text", FieldName: "other_text"}, }, values: map[int]string{ 1: "1", 2: "", }, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { h := ConditionalHandler{} err := h.Validate(tt.fields, tt.values) if tt.wantErr && err == nil { t.Error("expected error, got nil") } if !tt.wantErr && err != nil { t.Errorf("expected no error, got: %v", err) } }) } } func TestMultiLineConvertToFillValues(t *testing.T) { tests := []struct { name string fields []models.FormField values map[int]string expected map[int]string }{ { name: "three lines across three fields", fields: []models.FormField{ {ID: 1, FieldName: "line1"}, {ID: 2, FieldName: "line2"}, {ID: 3, FieldName: "line3"}, }, values: map[int]string{ 1: "first\nsecond\nthird", }, expected: map[int]string{ 1: "first", 2: "second", 3: "third", }, }, { name: "three lines across two fields (first gets extra)", fields: []models.FormField{ {ID: 1, FieldName: "line1"}, {ID: 2, FieldName: "line2"}, }, values: map[int]string{ 1: "first\nsecond\nthird", }, expected: map[int]string{ 1: "first\nsecond", 2: "third", }, }, { name: "no value submitted", fields: []models.FormField{ {ID: 1, FieldName: "line1"}, {ID: 2, FieldName: "line2"}, }, values: map[int]string{}, expected: map[int]string{ 1: "", 2: "", }, }, { name: "empty fields list", fields: []models.FormField{}, values: map[int]string{1: "some value"}, expected: map[int]string{}, }, { name: "single line across multiple fields", fields: []models.FormField{ {ID: 1, FieldName: "line1"}, {ID: 2, FieldName: "line2"}, }, values: map[int]string{ 1: "only line", }, expected: map[int]string{ 1: "only line", 2: "", }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { h := MultiLineHandler{} got := h.ConvertToFillValues(tt.fields, tt.values) if len(got) != len(tt.expected) { t.Fatalf("ConvertToFillValues returned %d entries, want %d: %v", len(got), len(tt.expected), got) } for k, v := range tt.expected { if got[k] != v { t.Errorf("ConvertToFillValues[%d] = %q, want %q", k, got[k], v) } } }) } } func TestMultiSelectConvertToFillValues(t *testing.T) { h := MultiSelectHandler{} fields := []models.FormField{ {ID: 1, Type: "button", FieldName: "opt1"}, {ID: 2, Type: "button", FieldName: "opt2"}, {ID: 3, Type: "button", FieldName: "opt3"}, } values := map[int]string{ 1: "1", 3: "1", } got := h.ConvertToFillValues(fields, values) if got[1] != "1" { t.Errorf("got[1] = %q, want '1'", got[1]) } if got[2] != "" { t.Errorf("got[2] = %q, want ''", got[2]) } if got[3] != "1" { t.Errorf("got[3] = %q, want '1'", got[3]) } } func TestAllTypes(t *testing.T) { types := AllTypes() if len(types) < 4 { t.Errorf("AllTypes() returned %d types, expected at least 4: %v", len(types), types) } // Verify known types are present typeSet := make(map[string]bool) for _, t := range types { typeSet[t] = true } expected := []string{"multiline", "single_select", "multi_select", "conditional_other"} for _, want := range expected { if !typeSet[want] { t.Errorf("AllTypes() missing %q: %v", want, types) } } }