package services import ( "encoding/json" "errors" "strings" "testing" ) func TestSlugifyTitle(t *testing.T) { cases := []struct{ in, want string }{ {"UPC Klageschrift Strategie", "upc-klageschrift-strategie"}, {"Hülle für Münch (München!)", "huelle-fuer-muench-muenchen"}, {" ", ""}, {"&&&", ""}, {"A really really really really long title that ought to be clamped to forty chars max", "a-really-really-really-really-long-title"}, {"Straße ABC", "strasse-abc"}, {"---leading-and-trailing---", "leading-and-trailing"}, } for _, c := range cases { got := slugifyTitle(c.in) if got != c.want { t.Errorf("slugifyTitle(%q) = %q; want %q", c.in, got, c.want) } } } func TestNormaliseRegime(t *testing.T) { for _, valid := range []string{"upc", "DE", " epa ", "Other", ""} { if _, err := normaliseRegime(valid); err != nil { t.Errorf("normaliseRegime(%q) errored unexpectedly: %v", valid, err) } } if _, err := normaliseRegime("bogus"); !errors.Is(err, ErrInvalidInput) { t.Errorf("normaliseRegime(bogus) expected ErrInvalidInput, got %v", err) } } func TestNormaliseLang(t *testing.T) { for _, valid := range []string{"de", "EN", " ", ""} { if _, err := normaliseLang(valid); err != nil { t.Errorf("normaliseLang(%q) errored: %v", valid, err) } } if _, err := normaliseLang("fr"); !errors.Is(err, ErrInvalidInput) { t.Errorf("normaliseLang(fr) expected ErrInvalidInput, got %v", err) } } func TestNormaliseSliceAVisibility(t *testing.T) { // Slice B opened up 'shared' as a valid author-set visibility // (alongside 'private' and 'firm'). 'global' stays admin-only via // ChecklistPromotionService. for _, valid := range []string{"private", "firm", "shared", " ", ""} { if _, err := normaliseSliceAVisibility(valid); err != nil { t.Errorf("visibility(%q) errored: %v", valid, err) } } for _, bad := range []string{"global", "public"} { if _, err := normaliseSliceAVisibility(bad); !errors.Is(err, ErrInvalidInput) { t.Errorf("visibility(%q) expected ErrInvalidInput, got %v", bad, err) } } } func TestRequireNonEmptyTrimmed(t *testing.T) { if _, err := requireNonEmptyTrimmed(" ", "title", 200); !errors.Is(err, ErrInvalidInput) { t.Errorf("empty title should be rejected, got %v", err) } if got, err := requireNonEmptyTrimmed(" hello ", "title", 200); err != nil || got != "hello" { t.Errorf("expected 'hello', got %q (err=%v)", got, err) } if _, err := requireNonEmptyTrimmed(strings.Repeat("x", 201), "title", 200); !errors.Is(err, ErrInvalidInput) { t.Errorf("over-length title should be rejected, got %v", err) } } func TestValidateBodyShape(t *testing.T) { // Happy path: at least one group, at least one item. ok := json.RawMessage(`{"groups":[{"titleDE":"G1","titleEN":"G1","items":[{"labelDE":"X","labelEN":"X"}]}]}`) if err := validateBodyShape(ok); err != nil { t.Errorf("valid body rejected: %v", err) } // Empty groups. if err := validateBodyShape(json.RawMessage(`{"groups":[]}`)); !errors.Is(err, ErrInvalidInput) { t.Errorf("empty groups expected ErrInvalidInput, got %v", err) } // Group with no items. if err := validateBodyShape(json.RawMessage(`{"groups":[{"titleDE":"G","titleEN":"G","items":[]}]}`)); !errors.Is(err, ErrInvalidInput) { t.Errorf("empty items expected ErrInvalidInput, got %v", err) } // Missing field. if err := validateBodyShape(json.RawMessage(nil)); !errors.Is(err, ErrInvalidInput) { t.Errorf("nil body expected ErrInvalidInput, got %v", err) } // Malformed JSON. if err := validateBodyShape(json.RawMessage(`{not json`)); !errors.Is(err, ErrInvalidInput) { t.Errorf("malformed body expected ErrInvalidInput, got %v", err) } } func TestChecklistCatalogIsStaticSlug(t *testing.T) { // nil DB is fine — we never touch it in this test. cat := NewChecklistCatalogService(nil) if !cat.IsStaticSlug("upc-statement-of-claim") { t.Error("expected static slug to be detected") } if cat.IsStaticSlug("u-some-authored-slug") { t.Error("unexpected static-slug match for authored slug") } } func TestChecklistVisibilityPredicate(t *testing.T) { got := checklistVisibilityPredicate("c", 1) for _, want := range []string{"c.owner_id = $1", "c.visibility IN ('firm', 'global')", "u.global_role = 'global_admin'"} { if !strings.Contains(got, want) { t.Errorf("predicate missing %q in: %s", want, got) } } } func TestClampFreeText(t *testing.T) { if got := clampFreeText(" hello ", 200); got != "hello" { t.Errorf("expected trimmed 'hello', got %q", got) } if got := clampFreeText(strings.Repeat("x", 250), 200); len(got) != 200 { t.Errorf("expected clamp to 200, got len=%d", len(got)) } }