120 lines
4.1 KiB
Go
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)
|
|
}
|
|
}
|