Files
memby/server/internal/api/requests_ready_row_test.go
T
2026-08-28 23:00:02 +12:00

120 lines
4.1 KiB
Go

package api
import (
"encoding/json"
"testing"
"github.com/ponzischeme89/memby/server/internal/store"
)
func readyReq(itemID, mediaType string) store.SurfacedReadyRequest {
return store.SurfacedReadyRequest{MediaType: mediaType, ItemID: itemID, Title: itemID}
}
func isStamped(t *testing.T, raw json.RawMessage) bool {
t.Helper()
var item struct {
Ready bool `json:"MembyRequestReady"`
Label string `json:"MembyRequestReadyLabel"`
}
if err := json.Unmarshal(raw, &item); err != nil {
t.Fatalf("unmarshal: %v", err)
}
return item.Ready && item.Label == requestReadyLabel
}
// The overwhelmingly common case: nobody is waiting on anything, so the row is untouched.
func TestMergeRequestReadyNoArrivalsIsANoOp(t *testing.T) {
items := []json.RawMessage{resumeItem(t, "film", "", "2026-08-01T20:00:00Z")}
got := mergeRequestReady(items, nil, nil)
if !equalIDs(mergedIDs(t, got), []string{"film"}) {
t.Fatalf("ids = %v", mergedIDs(t, got))
}
if isStamped(t, got[0]) {
t.Fatal("item stamped with no arrivals")
}
}
// An arrival not in the row is prepended and tagged.
func TestMergeRequestReadyPrependsMissingTitle(t *testing.T) {
items := []json.RawMessage{resumeItem(t, "film", "", "2026-08-01T20:00:00Z")}
surfaced := []store.SurfacedReadyRequest{readyReq("new-movie", "movie")}
fetched := map[string]json.RawMessage{
"new-movie": continueRaw(t, map[string]any{"Id": "new-movie", "Type": "Movie"}),
}
got := mergeRequestReady(items, surfaced, fetched)
if want := []string{"new-movie", "film"}; !equalIDs(mergedIDs(t, got), want) {
t.Fatalf("ids = %v, want %v", mergedIDs(t, got), want)
}
if !isStamped(t, got[0]) {
t.Fatal("prepended card not stamped")
}
if isStamped(t, got[1]) {
t.Fatal("existing card wrongly stamped")
}
}
// Newest arrival first when several are prepended (surfaced is ordered newest first).
func TestMergeRequestReadyKeepsNewestArrivalFirst(t *testing.T) {
items := []json.RawMessage{resumeItem(t, "film", "", "2026-08-01T20:00:00Z")}
surfaced := []store.SurfacedReadyRequest{readyReq("newer", "movie"), readyReq("older", "movie")}
fetched := map[string]json.RawMessage{
"newer": continueRaw(t, map[string]any{"Id": "newer", "Type": "Movie"}),
"older": continueRaw(t, map[string]any{"Id": "older", "Type": "Movie"}),
}
got := mergedIDs(t, mergeRequestReady(items, surfaced, fetched))
if want := []string{"newer", "older", "film"}; !equalIDs(got, want) {
t.Fatalf("ids = %v, want %v", got, want)
}
}
// A surfaced title already in Continue Watching — by its own id, or as the series an
// episode belongs to — is tagged in place, never duplicated.
func TestMergeRequestReadyTagsExistingCardInPlace(t *testing.T) {
items := []json.RawMessage{
resumeItem(t, "s1e3", "severance", "2026-08-06T19:00:00Z"),
resumeItem(t, "the-film", "", "2026-08-01T20:00:00Z"),
}
surfaced := []store.SurfacedReadyRequest{
readyReq("severance", "series"),
readyReq("the-film", "movie"),
}
got := mergeRequestReady(items, surfaced, nil)
if want := []string{"s1e3", "the-film"}; !equalIDs(mergedIDs(t, got), want) {
t.Fatalf("ids = %v, want %v", mergedIDs(t, got), want)
}
if !isStamped(t, got[0]) || !isStamped(t, got[1]) {
t.Fatal("existing cards not tagged in place")
}
}
// A fetch that returned nothing for an arrival degrades to leaving it out rather than
// inserting a blank card.
func TestMergeRequestReadyDropsUnfetchableArrival(t *testing.T) {
items := []json.RawMessage{resumeItem(t, "film", "", "2026-08-01T20:00:00Z")}
surfaced := []store.SurfacedReadyRequest{readyReq("gone", "movie")}
got := mergeRequestReady(items, surfaced, map[string]json.RawMessage{})
if !equalIDs(mergedIDs(t, got), []string{"film"}) {
t.Fatalf("ids = %v", mergedIDs(t, got))
}
}
func TestStampRequestReadyPreservesOtherFields(t *testing.T) {
raw := continueRaw(t, map[string]any{"Id": "x", "Name": "Keep me", "Type": "Movie"})
stamped := stampRequestReady(raw)
var item struct {
Name string `json:"Name"`
Ready bool `json:"MembyRequestReady"`
}
if err := json.Unmarshal(stamped, &item); err != nil {
t.Fatalf("unmarshal: %v", err)
}
if item.Name != "Keep me" || !item.Ready {
t.Fatalf("stamp lost fields: %+v", item)
}
}