With a Trakt client ID, the details of a movie or series show the director(s) or creators and up to 8 cast members with their roles below the plot, in every view. The title is found on Trakt by its TMDb/TVDB (else IMDb) id, then its people are read. Casts are cached and, like posters, only loaded once the selection rests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
140 lines
5.9 KiB
Go
140 lines
5.9 KiB
Go
package trakt
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
)
|
|
|
|
func TestEntries(t *testing.T) {
|
|
var got http.Header
|
|
var gotQuery string
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
got, gotQuery = r.Header, r.URL.RawQuery
|
|
switch r.URL.Path {
|
|
case "/movies/trending":
|
|
w.Write([]byte(`[{"watchers":1234,"movie":{"title":"Dune","year":2021,"ids":{"trakt":1,"slug":"dune-2021","imdb":"tt1160419","tmdb":438631}}},
|
|
{"watchers":7,"movie":{"title":"No Year","year":null,"ids":{"trakt":2,"slug":"x","imdb":null,"tmdb":null}}}]`))
|
|
case "/movies/popular":
|
|
w.Write([]byte(`[{"title":"Heat","year":1995,"ids":{"trakt":3,"slug":"heat-1995","tmdb":949}}]`))
|
|
case "/shows/watched/weekly":
|
|
w.Write([]byte(`[{"watcher_count":52000,"play_count":1,"collected_count":2,"collector_count":3,"show":{"title":"Andor","year":2022,"ids":{"trakt":4,"slug":"andor","tvdb":393189,"tmdb":83867}}}]`))
|
|
case "/movies/boxoffice":
|
|
w.Write([]byte(`[{"revenue":48464322,"movie":{"title":"Big","year":2026,"ids":{"trakt":5,"tmdb":5}}}]`))
|
|
default:
|
|
http.NotFound(w, r)
|
|
}
|
|
}))
|
|
defer srv.Close()
|
|
|
|
c := NewClient(" my-id ", "arr-tui/test")
|
|
c.SetBaseURL(srv.URL)
|
|
movies, err := c.Entries(context.Background(), MovieLists[0], 20)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got.Get("trakt-api-key") != "my-id" || got.Get("trakt-api-version") != "2" || got.Get("User-Agent") != "arr-tui/test" ||
|
|
got.Get("Content-Type") != "application/json" {
|
|
t.Errorf("headers: %v", got)
|
|
}
|
|
if gotQuery != "limit=20&page=1" {
|
|
t.Errorf("query %q", gotQuery)
|
|
}
|
|
if len(movies) != 2 || movies[0].Title != "Dune" || movies[0].IDs.TMDB != 438631 || movies[0].Count != 1234 || movies[1].IDs.TMDB != 0 {
|
|
t.Errorf("trending: %+v", movies)
|
|
}
|
|
if note := MovieLists[0].Note(movies[0].Count); note != "1.2k watching" {
|
|
t.Errorf("note %q", note)
|
|
}
|
|
|
|
popular, err := c.Entries(context.Background(), MovieLists[3], 20)
|
|
if err != nil || len(popular) != 1 || popular[0].Title != "Heat" || popular[0].IDs.TMDB != 949 || MovieLists[3].Note(popular[0].Count) != "" {
|
|
t.Errorf("popular (bare items): %+v %v", popular, err)
|
|
}
|
|
shows, err := c.Entries(context.Background(), ShowLists[1], 20)
|
|
if err != nil || len(shows) != 1 || shows[0].IDs.TVDB != 393189 || shows[0].Count != 52000 || ShowLists[1].Note(52000) != "52k watched it" {
|
|
t.Errorf("most watched shows: %+v %v", shows, err)
|
|
}
|
|
box, err := c.Entries(context.Background(), MovieLists[4], 20)
|
|
if err != nil || box[0].Count != 48464322 || MovieLists[4].Note(box[0].Count) != "$48M last weekend" {
|
|
t.Errorf("box office: %+v %v", box, err)
|
|
}
|
|
}
|
|
|
|
func TestEntriesErrors(t *testing.T) {
|
|
if _, err := NewClient("", "ua").Entries(context.Background(), MovieLists[0], 5); !errors.Is(err, ErrNotConfigured) {
|
|
t.Errorf("no client id: %v", err)
|
|
}
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusForbidden)
|
|
}))
|
|
defer srv.Close()
|
|
c := NewClient("bad", "ua")
|
|
c.SetBaseURL(srv.URL)
|
|
if _, err := c.Entries(context.Background(), MovieLists[0], 5); err == nil || err.Error() != "trakt: the client ID was not accepted (HTTP 403)" {
|
|
t.Errorf("rejected id: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestCompact(t *testing.T) {
|
|
for n, want := range map[int64]string{0: "0", 950: "950", 1000: "1k", 1234: "1.2k", 34567: "34k", 1500000: "1.5M", 48464322: "48M"} {
|
|
if got := Compact(n); got != want {
|
|
t.Errorf("Compact(%d) = %q, want %q", n, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPeople(t *testing.T) {
|
|
var paths []string
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
paths = append(paths, r.URL.RequestURI())
|
|
switch r.URL.Path {
|
|
case "/search/tmdb/272":
|
|
w.Write([]byte(`[{"type":"movie","score":1000,"movie":{"title":"Batman Begins","year":2005,"ids":{"trakt":1,"slug":"batman-begins-2005","tmdb":272}}}]`))
|
|
case "/movies/1/people":
|
|
w.Write([]byte(`{"cast":[{"character":"Bruce Wayne","characters":["Bruce Wayne","Batman"],"person":{"name":"Christian Bale","ids":{"trakt":1}}},
|
|
{"character":"Alfred","characters":["Alfred"],"person":{"name":"Michael Caine","ids":{"trakt":2}}}],
|
|
"crew":{"directing":[{"job":"Director","jobs":["Director"],"person":{"name":"Christopher Nolan"}},{"job":"Assistant Director","jobs":["Assistant Director"],"person":{"name":"Someone"}}],
|
|
"writing":[{"job":"Screenplay","jobs":["Screenplay"],"person":{"name":"David S. Goyer"}}]}}`))
|
|
case "/search/tvdb/81189":
|
|
w.Write([]byte(`[{"type":"show","score":1000,"show":{"title":"Breaking Bad","year":2008,"ids":{"trakt":1388,"tvdb":81189}}}]`))
|
|
case "/shows/1388/people":
|
|
w.Write([]byte(`{"cast":[{"character":"Walter White","characters":["Walter White"],"episode_count":62,"person":{"name":"Bryan Cranston"}}],
|
|
"crew":{"created by":[{"job":"Creator","jobs":["Creator"],"person":{"name":"Vince Gilligan"}}]}}`))
|
|
case "/search/tmdb/5":
|
|
w.Write([]byte(`[]`))
|
|
default:
|
|
http.NotFound(w, r)
|
|
}
|
|
}))
|
|
defer srv.Close()
|
|
c := NewClient("id", "ua")
|
|
c.SetBaseURL(srv.URL)
|
|
|
|
movie, err := c.People(context.Background(), Ref{Kind: Movies, TMDB: 272, IMDB: "tt0372784"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(movie.Cast) != 2 || movie.Cast[0].Name != "Christian Bale" || movie.Cast[0].Role != "Bruce Wayne / Batman" {
|
|
t.Errorf("cast %+v", movie.Cast)
|
|
}
|
|
if len(movie.Leaders) != 1 || movie.Leaders[0].Name != "Christopher Nolan" {
|
|
t.Errorf("directors %+v", movie.Leaders)
|
|
}
|
|
if paths[0] != "/search/tmdb/272?type=movie" {
|
|
t.Errorf("lookup %q", paths[0])
|
|
}
|
|
show, err := c.People(context.Background(), Ref{Kind: Shows, TVDB: 81189})
|
|
if err != nil || show.Cast[0].Name != "Bryan Cranston" || len(show.Leaders) != 1 || show.Leaders[0].Name != "Vince Gilligan" {
|
|
t.Errorf("show %+v %v", show, err)
|
|
}
|
|
if _, err := c.People(context.Background(), Ref{Kind: Movies, TMDB: 5}); !errors.Is(err, ErrNotFound) {
|
|
t.Errorf("unknown title: %v", err)
|
|
}
|
|
if (Ref{Kind: Shows, TVDB: 81189}).Key() != "show:tvdb:81189" || (Ref{Kind: Movies}).Key() != "" {
|
|
t.Error("keys")
|
|
}
|
|
}
|