Files
mal/internal/playback/skip_segments_test.go

151 lines
4.1 KiB
Go

package playback
import (
"context"
"io"
"net/http"
"strings"
"testing"
"mal/internal/db"
"mal/internal/domain"
)
type wantSkipSegment struct {
segmentType string
start float64
end float64
source string
}
func TestFetchSkipSegmentsFallsBackToOverridesWhenAniSkipFails(t *testing.T) {
t.Parallel()
svc := &playbackService{
repo: &skipSegmentRepo{
hasTable: true,
overrides: []db.SkipSegmentOverrideRow{{
UserID: "user-1",
AnimeID: 2167,
Episode: 13,
SkipType: "op",
StartTime: 90,
EndTime: 180,
}},
},
httpClient: &http.Client{Transport: roundTripFunc(func(*http.Request) (*http.Response, error) {
return &http.Response{
StatusCode: http.StatusInternalServerError,
Body: io.NopCloser(strings.NewReader("")),
Header: make(http.Header),
}, nil
})},
}
got, err := svc.fetchSkipSegments(context.Background(), "user-1", 2167, "13")
if err != nil {
t.Fatalf("fetchSkipSegments returned error with local fallback: %v", err)
}
if len(got) != 1 {
t.Fatalf("len(got) = %d, want 1", len(got))
}
assertSkipSegment(t, got[0], wantSkipSegment{segmentType: "opening", start: 90, end: 180, source: "override"})
}
func TestFetchSkipSegmentsReturnsAniSkipErrorWhenNoOverrideFallbackExists(t *testing.T) {
t.Parallel()
svc := &playbackService{
repo: &skipSegmentRepo{hasTable: true},
httpClient: &http.Client{Transport: roundTripFunc(func(*http.Request) (*http.Response, error) {
return &http.Response{
StatusCode: http.StatusInternalServerError,
Body: io.NopCloser(strings.NewReader("")),
Header: make(http.Header),
}, nil
})},
}
got, err := svc.fetchSkipSegments(context.Background(), "user-1", 2167, "13")
if err == nil {
t.Fatal("fetchSkipSegments returned nil error without local fallback")
}
if got != nil {
t.Fatalf("got segments = %+v, want nil", got)
}
if !strings.Contains(err.Error(), "aniskip: unexpected status: 500") {
t.Fatalf("err = %v, want ani-skip status context", err)
}
}
func TestFetchSkipSegmentsMergesOverridesWhenAniSkipSucceeds(t *testing.T) {
t.Parallel()
svc := &playbackService{
repo: &skipSegmentRepo{
hasTable: true,
overrides: []db.SkipSegmentOverrideRow{{
UserID: "user-1",
AnimeID: 2167,
Episode: 13,
SkipType: "op",
StartTime: 95,
EndTime: 185,
}},
},
httpClient: &http.Client{Transport: roundTripFunc(func(*http.Request) (*http.Response, error) {
return &http.Response{
StatusCode: http.StatusOK,
Body: io.NopCloser(strings.NewReader(`{
"found": true,
"results": [
{"skip_type": "op", "interval": {"start_time": 80, "end_time": 170}},
{"skip_type": "ed", "interval": {"start_time": 1300, "end_time": 1390}}
]
}`)),
Header: make(http.Header),
}, nil
})},
}
got, err := svc.fetchSkipSegments(context.Background(), "user-1", 2167, "13")
if err != nil {
t.Fatalf("fetchSkipSegments returned error: %v", err)
}
if len(got) != 2 {
t.Fatalf("len(got) = %d, want 2", len(got))
}
assertSkipSegment(t, got[0], wantSkipSegment{segmentType: "opening", start: 95, end: 185, source: "override"})
assertSkipSegment(t, got[1], wantSkipSegment{segmentType: "ending", start: 1300, end: 1390, source: "aniskip"})
}
func assertSkipSegment(t *testing.T, got domain.SkipSegment, want wantSkipSegment) {
t.Helper()
if got.Type != want.segmentType || got.Start != want.start || got.End != want.end || got.Source != want.source {
t.Fatalf("got segment = %+v, want type=%q start=%v end=%v source=%q", got, want.segmentType, want.start, want.end, want.source)
}
}
type roundTripFunc func(*http.Request) (*http.Response, error)
func (f roundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
return f(req)
}
type skipSegmentRepo struct {
domain.PlaybackRepository
hasTable bool
hasErr error
overrides []db.SkipSegmentOverrideRow
listErr error
}
func (r *skipSegmentRepo) HasSkipSegmentOverrideTable(context.Context) (bool, error) {
return r.hasTable, r.hasErr
}
func (r *skipSegmentRepo) ListSkipSegmentOverrides(context.Context, string, int64, int64) ([]db.SkipSegmentOverrideRow, error) {
return r.overrides, r.listErr
}