318 lines
11 KiB
Go
318 lines
11 KiB
Go
package sections
|
||||
|
|
|
|||
|
|
import (
|
|||
|
|
"encoding/json"
|
|||
|
|
"testing"
|
|||
|
|
|
|||
|
|
"github.com/Silo-Server/silo-server/internal/catalog"
|
|||
|
|
"github.com/Silo-Server/silo-server/internal/models"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
func TestDefaultHomeSectionsWithoutLibraries(t *testing.T) {
|
|||
|
|
sections := DefaultHomeSections(nil)
|
|||
|
|
// 1 continue-watching + 3 recipe-rich defaults (hidden_gems, trending, seasonal-auto-cycle)
|
|||
|
|
if len(sections) != 4 {
|
|||
|
|
t.Fatalf("expected 4 default home sections, got %d", len(sections))
|
|||
|
|
}
|
|||
|
|
if sections[0].SectionType != SectionContinueWatching {
|
|||
|
|
t.Fatalf("expected continue watching, got %s", sections[0].SectionType)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func TestDefaultHomeSectionsWithLibraries(t *testing.T) {
|
|||
|
|
libraries := []*models.MediaFolder{
|
|||
|
|
{ID: 7, Name: "Movies", SortOrder: 1},
|
|||
|
|
{ID: 9, Name: "Shows", SortOrder: 2},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
got := DefaultHomeSections(libraries)
|
|||
|
|
// 1 continue-watching + 2 libraries × 2 types + 3 recipe-rich defaults
|
|||
|
|
if len(got) != 8 {
|
|||
|
|
t.Fatalf("expected 8 default home sections, got %d", len(got))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
tests := []struct {
|
|||
|
|
index int
|
|||
|
|
id string
|
|||
|
|
sectionType SectionType
|
|||
|
|
title string
|
|||
|
|
position int
|
|||
|
|
libraryID int
|
|||
|
|
}{
|
|||
|
|
{index: 0, id: "default-continue-watching", sectionType: SectionContinueWatching, title: "Continue Watching", position: 0},
|
|||
|
|
{index: 1, id: "default-home-recently_added-library-7", sectionType: SectionRecentlyAdded, title: "Recently Added in Movies", position: 1, libraryID: 7},
|
|||
|
|
{index: 2, id: "default-home-recently_released-library-7", sectionType: SectionRecentlyReleased, title: "Recently Released in Movies", position: 2, libraryID: 7},
|
|||
|
|
{index: 3, id: "default-home-recently_added-library-9", sectionType: SectionRecentlyAdded, title: "Recently Added in Shows", position: 3, libraryID: 9},
|
|||
|
|
{index: 4, id: "default-home-recently_released-library-9", sectionType: SectionRecentlyReleased, title: "Recently Released in Shows", position: 4, libraryID: 9},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for _, tt := range tests {
|
|||
|
|
section := got[tt.index]
|
|||
|
|
if section.ID != tt.id {
|
|||
|
|
t.Fatalf("section %d id = %q, want %q", tt.index, section.ID, tt.id)
|
|||
|
|
}
|
|||
|
|
if section.SectionType != tt.sectionType {
|
|||
|
|
t.Fatalf("section %d type = %q, want %q", tt.index, section.SectionType, tt.sectionType)
|
|||
|
|
}
|
|||
|
|
if section.Title != tt.title {
|
|||
|
|
t.Fatalf("section %d title = %q, want %q", tt.index, section.Title, tt.title)
|
|||
|
|
}
|
|||
|
|
if section.Position != tt.position {
|
|||
|
|
t.Fatalf("section %d position = %d, want %d", tt.index, section.Position, tt.position)
|
|||
|
|
}
|
|||
|
|
if tt.libraryID == 0 {
|
|||
|
|
continue
|
|||
|
|
}
|
|||
|
|
libraryID, ok := ParseGeneratedHomeLibraryRecentConfig(section.Config)
|
|||
|
|
if !ok {
|
|||
|
|
t.Fatalf("section %d expected generated home config", tt.index)
|
|||
|
|
}
|
|||
|
|
if libraryID != tt.libraryID {
|
|||
|
|
t.Fatalf("section %d config library id = %d, want %d", tt.index, libraryID, tt.libraryID)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func TestDefaultLibrarySectionsForTypeMovies(t *testing.T) {
|
|||
|
|
libraryID := 42
|
|||
|
|
got := DefaultLibrarySectionsForType(&libraryID, "movies")
|
|||
|
|
|
|||
|
|
if len(got) != 6 {
|
|||
|
|
t.Fatalf("expected 6 movie default sections, got %d", len(got))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
tests := []struct {
|
|||
|
|
index int
|
|||
|
|
id string
|
|||
|
|
sectionType SectionType
|
|||
|
|
title string
|
|||
|
|
position int
|
|||
|
|
}{
|
|||
|
|
{index: 0, id: "default-continue-watching", sectionType: SectionContinueWatching, title: "Continue Watching", position: 0},
|
|||
|
|
{index: 1, id: "default-recently-added-movies", sectionType: SectionRecentlyAdded, title: "Recently Added Movies", position: 1},
|
|||
|
|
{index: 2, id: "default-recently-released-movies", sectionType: SectionRecentlyReleased, title: "Recently Released Movies", position: 2},
|
|||
|
|
{index: 3, id: "default-top-rated-movies", sectionType: SectionCustomFilter, title: "Top Rated Movies", position: 3},
|
|||
|
|
{index: 4, id: "default-recommended-for-you", sectionType: SectionRecommendedForYou, title: "Recommended for You", position: 4},
|
|||
|
|
{index: 5, id: "default-random-movies", sectionType: SectionRandom, title: "Random Picks", position: 5},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for _, tt := range tests {
|
|||
|
|
section := got[tt.index]
|
|||
|
|
if section.ID != tt.id {
|
|||
|
|
t.Fatalf("section %d id = %q, want %q", tt.index, section.ID, tt.id)
|
|||
|
|
}
|
|||
|
|
if section.SectionType != tt.sectionType {
|
|||
|
|
t.Fatalf("section %d type = %q, want %q", tt.index, section.SectionType, tt.sectionType)
|
|||
|
|
}
|
|||
|
|
if section.Title != tt.title {
|
|||
|
|
t.Fatalf("section %d title = %q, want %q", tt.index, section.Title, tt.title)
|
|||
|
|
}
|
|||
|
|
if section.Position != tt.position {
|
|||
|
|
t.Fatalf("section %d position = %d, want %d", tt.index, section.Position, tt.position)
|
|||
|
|
}
|
|||
|
|
if section.Featured {
|
|||
|
|
t.Fatalf("section %d featured = true, want false", tt.index)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
assertQueryDefinition(t, got[1].Config, catalog.QueryDefinition{
|
|||
|
|
MediaScope: "movie",
|
|||
|
|
Match: "all",
|
|||
|
|
Groups: []catalog.QueryGroup{},
|
|||
|
|
Sort: catalog.QuerySort{Field: "added_at", Order: "desc"},
|
|||
|
|
})
|
|||
|
|
assertQueryDefinition(t, got[3].Config, catalog.QueryDefinition{
|
|||
|
|
MediaScope: "movie",
|
|||
|
|
Match: "all",
|
|||
|
|
Groups: []catalog.QueryGroup{},
|
|||
|
|
Sort: catalog.QuerySort{Field: "rating_imdb", Order: "desc"},
|
|||
|
|
})
|
|||
|
|
assertEmptyJSON(t, got[4].Config)
|
|||
|
|
assertQueryDefinition(t, got[5].Config, catalog.QueryDefinition{
|
|||
|
|
MediaScope: "movie",
|
|||
|
|
Match: "all",
|
|||
|
|
Groups: []catalog.QueryGroup{},
|
|||
|
|
Sort: catalog.QuerySort{Field: "added_at", Order: "desc"},
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func TestDefaultLibrarySectionsForTypeSeries(t *testing.T) {
|
|||
|
|
libraryID := 17
|
|||
|
|
got := DefaultLibrarySectionsForType(&libraryID, "series")
|
|||
|
|
|
|||
|
|
if len(got) != 7 {
|
|||
|
|
t.Fatalf("expected 7 series default sections, got %d", len(got))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
tests := []struct {
|
|||
|
|
index int
|
|||
|
|
id string
|
|||
|
|
sectionType SectionType
|
|||
|
|
title string
|
|||
|
|
position int
|
|||
|
|
}{
|
|||
|
|
{index: 0, id: "default-continue-watching", sectionType: SectionContinueWatching, title: "Continue Watching", position: 0},
|
|||
|
|
{index: 1, id: "default-recently-added-tv", sectionType: SectionRecentlyAdded, title: "Recently Added TV", position: 1},
|
|||
|
|
{index: 2, id: "default-recently-released-episodes", sectionType: SectionCustomFilter, title: "Recently Released Episodes", position: 2},
|
|||
|
|
{index: 3, id: "default-recently-released-tv-shows", sectionType: SectionCustomFilter, title: "Recently Released TV Shows", position: 3},
|
|||
|
|
{index: 4, id: "default-top-rated-tv", sectionType: SectionCustomFilter, title: "Top Rated TV", position: 4},
|
|||
|
|
{index: 5, id: "default-recommended-for-you", sectionType: SectionRecommendedForYou, title: "Recommended for You", position: 5},
|
|||
|
|
{index: 6, id: "default-random-tv", sectionType: SectionRandom, title: "Random Picks", position: 6},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for _, tt := range tests {
|
|||
|
|
section := got[tt.index]
|
|||
|
|
if section.ID != tt.id {
|
|||
|
|
t.Fatalf("section %d id = %q, want %q", tt.index, section.ID, tt.id)
|
|||
|
|
}
|
|||
|
|
if section.SectionType != tt.sectionType {
|
|||
|
|
t.Fatalf("section %d type = %q, want %q", tt.index, section.SectionType, tt.sectionType)
|
|||
|
|
}
|
|||
|
|
if section.Title != tt.title {
|
|||
|
|
t.Fatalf("section %d title = %q, want %q", tt.index, section.Title, tt.title)
|
|||
|
|
}
|
|||
|
|
if section.Position != tt.position {
|
|||
|
|
t.Fatalf("section %d position = %d, want %d", tt.index, section.Position, tt.position)
|
|||
|
|
}
|
|||
|
|
if section.Featured {
|
|||
|
|
t.Fatalf("section %d featured = true, want false", tt.index)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
assertQueryDefinition(t, got[1].Config, catalog.QueryDefinition{
|
|||
|
|
MediaScope: "series",
|
|||
|
|
Match: "all",
|
|||
|
|
Groups: []catalog.QueryGroup{},
|
|||
|
|
Sort: catalog.QuerySort{Field: "added_at", Order: "desc"},
|
|||
|
|
})
|
|||
|
|
assertQueryDefinition(t, got[2].Config, catalog.QueryDefinition{
|
|||
|
|
MediaScope: "episode",
|
|||
|
|
Match: "all",
|
|||
|
|
Groups: []catalog.QueryGroup{},
|
|||
|
|
Sort: catalog.QuerySort{Field: "release_date", Order: "desc"},
|
|||
|
|
})
|
|||
|
|
assertQueryDefinition(t, got[3].Config, catalog.QueryDefinition{
|
|||
|
|
MediaScope: "series",
|
|||
|
|
Match: "all",
|
|||
|
|
Groups: []catalog.QueryGroup{},
|
|||
|
|
Sort: catalog.QuerySort{Field: "last_air_date", Order: "desc"},
|
|||
|
|
})
|
|||
|
|
assertQueryDefinition(t, got[4].Config, catalog.QueryDefinition{
|
|||
|
|
MediaScope: "series",
|
|||
|
|
Match: "all",
|
|||
|
|
Groups: []catalog.QueryGroup{},
|
|||
|
|
Sort: catalog.QuerySort{Field: "rating_imdb", Order: "desc"},
|
|||
|
|
})
|
|||
|
|
assertEmptyJSON(t, got[5].Config)
|
|||
|
|
assertQueryDefinition(t, got[6].Config, catalog.QueryDefinition{
|
|||
|
|
MediaScope: "series",
|
|||
|
|
Match: "all",
|
|||
|
|
Groups: []catalog.QueryGroup{},
|
|||
|
|
Sort: catalog.QuerySort{Field: "added_at", Order: "desc"},
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func TestDefaultLibrarySectionsForTypeMixed(t *testing.T) {
|
|||
|
|
libraryID := 99
|
|||
|
|
got := DefaultLibrarySectionsForType(&libraryID, "mixed")
|
|||
|
|
|
|||
|
|
if len(got) != 3 {
|
|||
|
|
t.Fatalf("expected 3 mixed default sections, got %d", len(got))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
tests := []struct {
|
|||
|
|
index int
|
|||
|
|
id string
|
|||
|
|
sectionType SectionType
|
|||
|
|
title string
|
|||
|
|
position int
|
|||
|
|
}{
|
|||
|
|
{index: 0, id: "default-continue-watching", sectionType: SectionContinueWatching, title: "Continue Watching", position: 0},
|
|||
|
|
{index: 1, id: "default-recently-added", sectionType: SectionRecentlyAdded, title: "Recently Added", position: 1},
|
|||
|
|
{index: 2, id: "default-recently-released", sectionType: SectionRecentlyReleased, title: "Recently Released", position: 2},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for _, tt := range tests {
|
|||
|
|
section := got[tt.index]
|
|||
|
|
if section.ID != tt.id {
|
|||
|
|
t.Fatalf("section %d id = %q, want %q", tt.index, section.ID, tt.id)
|
|||
|
|
}
|
|||
|
|
if section.SectionType != tt.sectionType {
|
|||
|
|
t.Fatalf("section %d type = %q, want %q", tt.index, section.SectionType, tt.sectionType)
|
|||
|
|
}
|
|||
|
|
if section.Title != tt.title {
|
|||
|
|
t.Fatalf("section %d title = %q, want %q", tt.index, section.Title, tt.title)
|
|||
|
|
}
|
|||
|
|
if section.Position != tt.position {
|
|||
|
|
t.Fatalf("section %d position = %d, want %d", tt.index, section.Position, tt.position)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func assertQueryDefinition(t *testing.T, raw json.RawMessage, want catalog.QueryDefinition) {
|
|||
|
|
t.Helper()
|
|||
|
|
|
|||
|
|
got, err := ParseQueryDefinition(raw)
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("ParseQueryDefinition() error = %v", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
got = got.Normalize()
|
|||
|
|
want = want.Normalize()
|
|||
|
|
|
|||
|
|
if got.MediaScope != want.MediaScope {
|
|||
|
|
t.Fatalf("media_scope = %q, want %q", got.MediaScope, want.MediaScope)
|
|||
|
|
}
|
|||
|
|
if got.Match != want.Match {
|
|||
|
|
t.Fatalf("match = %q, want %q", got.Match, want.Match)
|
|||
|
|
}
|
|||
|
|
if got.Sort != want.Sort {
|
|||
|
|
t.Fatalf("sort = %+v, want %+v", got.Sort, want.Sort)
|
|||
|
|
}
|
|||
|
|
if len(got.Groups) != len(want.Groups) {
|
|||
|
|
t.Fatalf("groups len = %d, want %d", len(got.Groups), len(want.Groups))
|
|||
|
|
}
|
|||
|
|
for i := range want.Groups {
|
|||
|
|
if got.Groups[i].Match != want.Groups[i].Match {
|
|||
|
|
t.Fatalf("groups[%d].match = %q, want %q", i, got.Groups[i].Match, want.Groups[i].Match)
|
|||
|
|
}
|
|||
|
|
if len(got.Groups[i].Rules) != len(want.Groups[i].Rules) {
|
|||
|
|
t.Fatalf("groups[%d].rules len = %d, want %d", i, len(got.Groups[i].Rules), len(want.Groups[i].Rules))
|
|||
|
|
}
|
|||
|
|
for j := range want.Groups[i].Rules {
|
|||
|
|
if got.Groups[i].Rules[j] != want.Groups[i].Rules[j] {
|
|||
|
|
t.Fatalf("groups[%d].rules[%d] = %+v, want %+v", i, j, got.Groups[i].Rules[j], want.Groups[i].Rules[j])
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func assertEmptyJSON(t *testing.T, raw json.RawMessage) {
|
|||
|
|
t.Helper()
|
|||
|
|
if string(raw) != "{}" {
|
|||
|
|
t.Fatalf("config = %s, want {}", string(raw))
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func TestHomeDefaultsIncludeRecipeRichSet(t *testing.T) {
|
|||
|
|
defs := DefaultHomeSections(nil)
|
|||
|
|
want := []SectionType{
|
|||
|
|
SectionContinueWatching,
|
|||
|
|
SectionHiddenGems,
|
|||
|
|
SectionTrendingOnServer,
|
|||
|
|
SectionSeasonalThemed,
|
|||
|
|
}
|
|||
|
|
for _, w := range want {
|
|||
|
|
found := false
|
|||
|
|
for _, d := range defs {
|
|||
|
|
if d.SectionType == w {
|
|||
|
|
found = true
|
|||
|
|
break
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if !found {
|
|||
|
|
t.Errorf("default home sections missing %s", w)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|