CI / ci (push) Successful in 2m33s
Co-authored-by: orchestrator-agent <20+orchestrator-agent@code.cubecraftcreations.com>
77 lines
2.5 KiB
Go
77 lines
2.5 KiB
Go
package dinners_test
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
|
|
"code.cubecraftlabs.com/Maniacs_Mansion/Meal-Quest/internal/dinners"
|
|
)
|
|
|
|
// TestCreateRegularNeverNamesFromLink: a Regular added with a recipe link
|
|
// is named only by the household, so no part of the link — host, path,
|
|
// query or fragment — is stored as its name or shown in a dinner or a
|
|
// duplicate error, even a token of plain letters in the path.
|
|
func TestCreateRegularNeverNamesFromLink(t *testing.T) {
|
|
t.Parallel()
|
|
e := newUnstartedEnv(t)
|
|
const link = "https://c.example/stew-key-abcdefghijklmno?sig=zyxwvut#lookup"
|
|
// Each leak holds a character no ULID has (Crockford base32 has no I, L,
|
|
// O, U, "-", "." or "/"), so a dinner's id never matches one.
|
|
leaks := []string{link, "c.example", "stew-key", "abcdefghijklmno", "sig", "zyxwvut", "lookup"}
|
|
check := func(what, text string) {
|
|
t.Helper()
|
|
lower := strings.ToLower(text)
|
|
for _, leak := range leaks {
|
|
if strings.Contains(lower, leak) {
|
|
t.Errorf("%s contains %q: %s", what, leak, text)
|
|
}
|
|
}
|
|
}
|
|
|
|
_, err := e.svc.CreateRegular(t.Context(), dinners.NewRegular{RecipeURL: ptr(link)}, member)
|
|
var verr *dinners.ValidationError
|
|
if !errors.As(err, &verr) {
|
|
t.Fatalf("link without a name: err = %v, want a *ValidationError", err)
|
|
}
|
|
check("validation error", verr.Error())
|
|
|
|
c, err := e.svc.CreateRegular(t.Context(), dinners.NewRegular{Name: ptr(" Sunday stew "), RecipeURL: ptr(link)}, member)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if c.Name != "Sunday stew" {
|
|
t.Errorf("name = %q, want the household's %q", c.Name, "Sunday stew")
|
|
}
|
|
created, err := json.Marshal(c)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
check("create response", string(created))
|
|
row := e.dinner(t, c.ID)
|
|
check("stored name", row.Name+" "+row.NormalizedName)
|
|
if row.RecipeUrl.String != link {
|
|
t.Errorf("stored recipe_url = %q, want %q kept for grounding", row.RecipeUrl.String, link)
|
|
}
|
|
|
|
list, err := e.svc.List(t.Context(), dinners.StatusRegular)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
listed, err := json.Marshal(list)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
check("list response", string(listed))
|
|
|
|
// The same link under another name is still a duplicate, and its error
|
|
// names the existing dinner by the household's name.
|
|
_, err = e.svc.CreateRegular(t.Context(), dinners.NewRegular{Name: ptr("Weeknight chili"), RecipeURL: ptr(link)}, member)
|
|
var dup *dinners.DuplicateError
|
|
if !errors.As(err, &dup) || dup.Existing.ID != c.ID {
|
|
t.Fatalf("same link again: err = %v, want a duplicate of %s", err, c.ID)
|
|
}
|
|
check("duplicate error", dup.Error())
|
|
}
|