- 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.
119 lines
2.6 KiB
Go
119 lines
2.6 KiB
Go
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", 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)
|
||
}
|