Files
jellybit/internal/httpapi/providerurl_test.go
T
avandClaude Opus 4.8 aac3ced262 Реализовал выбор источника и предпросмотр в ревью (review-source-selection)
Экран ревью теперь показывает единый список источников совпадения: строка
«распознано нейронкой» наравне с кандидатами баз; выбор/переключение/снятие
в пользу нейронки; ручное добавление по id или URL (TMDB/IMDb — по URL,
TVDB — по числовому id); предпросмотр полей и целевых путей каждого источника
до применения (место под режиссёра зарезервировано). «Раскладка» осталась
отдельной секцией для активного источника, инлайн-превью неактивных — по клику.

Ядро: единая деривация «источник → overrides» (sourcePins), общая для превью
и коммита → preview == apply; заодно чинит латентный залипший override
title/year при переключении источника. Превью считается эфемерно, без записи
в БД; пользовательский URL только парсится (SSRF нет).

Ревью дизайна и кода пройдены; правки ревьюеров учтены (сообщение об ошибке
ручного ввода доходит до пользователя, URL без схемы принимается).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 10:29:27 +03:00

98 lines
3.9 KiB
Go

package httpapi
import (
"testing"
"git.vakhrushev.me/av/jellybit/internal/store"
"git.vakhrushev.me/av/jellybit/internal/worker"
)
func TestProviderURL(t *testing.T) {
cases := []struct {
name string
provider string
id string
mtype string
want string
}{
{"tmdb movie", "tmdb", "693134", "movie", "https://www.themoviedb.org/movie/693134"},
{"tmdb series", "tmdb", "60622", "series", "https://www.themoviedb.org/tv/60622"},
{"tvdb series", "tvdb", "269613", "series", "https://www.thetvdb.com/dereferrer/series/269613"},
{"tvdb movie", "tvdb", "12345", "movie", "https://www.thetvdb.com/dereferrer/movie/12345"},
{"imdb", "imdb", "tt0111161", "movie", "https://www.imdb.com/title/tt0111161"},
{"unknown provider → пусто", "kinopoisk", "42", "movie", ""},
{"пустой id → пусто", "tmdb", "", "movie", ""},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
if got := providerURL(c.provider, c.id, c.mtype); got != c.want {
t.Errorf("providerURL(%q,%q,%q) = %q, want %q", c.provider, c.id, c.mtype, got, c.want)
}
})
}
}
func TestParseManualSource(t *testing.T) {
cases := []struct {
name string
provider string
raw string
wantProvider string
wantID string
wantErr bool
}{
{"id с провайдером", "tmdb", "60622", "tmdb", "60622", false},
{"id обрезается позже воркером", "TVDB", "269613", "tvdb", "269613", false},
{"URL TMDB со slug", "", "https://www.themoviedb.org/tv/60622-fargo", "tmdb", "60622", false},
{"URL TMDB без схемы", "", "themoviedb.org/tv/60622", "tmdb", "60622", false},
{"URL TMDB movie", "", "https://www.themoviedb.org/movie/693134", "tmdb", "693134", false},
{"URL IMDb", "", "https://www.imdb.com/title/tt0111161/", "imdb", "tt0111161", false},
{"URL TVDB dereferrer", "", "https://www.thetvdb.com/dereferrer/series/269613", "tvdb", "269613", false},
{"URL TVDB slug — без id → ошибка", "", "https://www.thetvdb.com/series/fargo", "", "", true},
{"мусорный URL → ошибка", "", "https://example.com/foo/bar", "", "", true},
{"пустой ввод → ошибка", "tmdb", " ", "", "", true},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
p, id, err := parseManualSource(c.provider, c.raw)
if c.wantErr {
if err == nil {
t.Fatalf("ожидалась ошибка, получено %q:%q", p, id)
}
return
}
if err != nil {
t.Fatalf("неожиданная ошибка: %v", err)
}
if p != c.wantProvider || id != c.wantID {
t.Errorf("parseManualSource(%q,%q) = %q:%q, want %q:%q", c.provider, c.raw, p, id, c.wantProvider, c.wantID)
}
})
}
}
// TestMatchURLNoLinkWhenUnbuildable — эффективный провайдер, для которого URL не
// строится и совпадающего кандидата нет, даёт пустую ссылку (транспорт покажет
// матч текстом — сценарий «URL записи неизвестен»).
func TestMatchURLNoLinkWhenUnbuildable(t *testing.T) {
rd := &worker.ReviewData{Provider: "kinopoisk", ProviderID: "42"}
if got := matchURL(rd, "movie"); got != "" {
t.Errorf("matchURL = %q, want пусто (URL не строится, кандидата нет)", got)
}
}
// TestMatchURLPrefersMatchingCandidate — URL берётся у выбранного кандидата,
// когда его provider+id совпадают с эффективными.
func TestMatchURLPrefersMatchingCandidate(t *testing.T) {
rd := &worker.ReviewData{
Provider: "tmdb", ProviderID: "693134",
Candidates: []store.MetadataCandidate{{
Provider: "tmdb", ProviderID: "693134", Chosen: true,
URL: store.NullString("https://custom.example/x"),
}},
}
if got := matchURL(rd, "movie"); got != "https://custom.example/x" {
t.Errorf("matchURL = %q, want URL выбранного кандидата", got)
}
}