Nik Afiq 88f4ee3d4a Add Danime episode metadata fetching and related API endpoint
- Implemented FetchEpisode function to retrieve episode metadata from dアニメストア.
- Added /api/v1/danime GET endpoint to fetch episode details by partId.
- Updated Swagger documentation for the new endpoint and response structure.
- Created DanimeEpisodeResponse type for API responses.
- Added tests for the new functionality and handlers.
2025-12-06 19:26:45 +09:00

119 lines
2.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package danime
import (
"bytes"
"context"
"encoding/json"
"io"
"net/http"
"os"
"testing"
)
func TestParseEpisodeNumber(t *testing.T) {
tests := []struct {
in string
want int
}{
{"第21話", 21},
{"第02話", 2},
{"21", 21},
{"第21話「タイトル」", 21},
{"", 21},
{"話", 0},
}
for _, tt := range tests {
if got := parseEpisodeNumber(tt.in); got != tt.want {
t.Fatalf("parseEpisodeNumber(%q) = %d, want %d", tt.in, got, tt.want)
}
}
}
func TestParsePartMeasure(t *testing.T) {
tests := []struct {
in string
want string
}{
{"23分50秒", "00:23:50"},
{"1時間2分3秒", "01:02:03"},
{"5分", "00:05:00"},
{"45秒", "00:00:45"},
}
for _, tt := range tests {
got, err := parsePartMeasure(tt.in)
if err != nil {
t.Fatalf("parsePartMeasure(%q) error: %v", tt.in, err)
}
if got != tt.want {
t.Fatalf("parsePartMeasure(%q) = %s, want %s", tt.in, got, tt.want)
}
}
}
func TestNormalizeEpisode_FromFixture(t *testing.T) {
f, err := os.Open("testdata/ws030101_part_23863021.json")
if err != nil {
t.Fatalf("open fixture: %v", err)
}
defer f.Close()
var raw RawPartInfo
if err := json.NewDecoder(f).Decode(&raw); err != nil {
t.Fatalf("decode: %v", err)
}
ep, err := normalizeEpisode(raw)
if err != nil {
t.Fatalf("normalize: %v", err)
}
if ep.EpNum != 21 || ep.EpTitle == "" || ep.PlaybackLength != "00:23:50" {
t.Fatalf("unexpected episode: %+v", ep)
}
}
func TestFetchEpisode_UsesHTTPClient(t *testing.T) {
rt := roundTripperFunc(func(r *http.Request) (*http.Response, error) {
if r.URL.Query().Get("partId") != "999" {
t.Fatalf("expected partId=999, got %s", r.URL.RawQuery)
}
f, err := os.Open("testdata/ws030101_part_23863021.json")
if err != nil {
t.Fatalf("open fixture: %v", err)
}
body, err := io.ReadAll(f)
if err != nil {
t.Fatalf("read: %v", err)
}
return &http.Response{
StatusCode: http.StatusOK,
Body: io.NopCloser(bytes.NewReader(body)),
Header: make(http.Header),
}, nil
})
mockClient := &http.Client{Transport: rt}
prevBase := baseURL
prevClient := httpClient
baseURL = "http://example.com/WS030101"
httpClient = mockClient
defer func() {
baseURL = prevBase
httpClient = prevClient
}()
ep, err := FetchEpisode(context.Background(), "999")
if err != nil {
t.Fatalf("FetchEpisode error: %v", err)
}
if ep == nil || ep.EpNum != 21 {
t.Fatalf("unexpected episode: %+v", ep)
}
}
type roundTripperFunc func(*http.Request) (*http.Response, error)
func (f roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) {
return f(req)
}