- Remove dead code: browser cdp/content_scrape strategies, writer package, printUsage, downloadAndStoreCoverCLI in main.go - Fix bugs: defer-in-loop in pocketbase deleteWhere, listAll() pagination hard cap removed, splitChapterTitle off-by-one in date extraction - Split server.go (~1700 lines) into focused handler files: handlers_audio, handlers_browse, handlers_progress, handlers_ranking, handlers_scrape - Export htmlutil.AttrVal/TextContent/ResolveURL; add storage/coverutil.go to consolidate duplicate helpers - Flatten deeply nested conditionals: voices() early-return guards, ScrapeCatalogue next-link double attr scan, chapterNumberFromKey dead strings.Cut line, splitChapterTitle double-nested unit/suffix loop - Add unit tests: htmlutil (9 funcs), novelfire ScrapeMetadata (3 cases), orchestrator Run (5 cases), storage chapterNumberFromKey/splitChapterTitle (22 cases); all pass with go build/vet/test clean
78 lines
2.7 KiB
Go
78 lines
2.7 KiB
Go
package storage
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
// ── chapterNumberFromKey ──────────────────────────────────────────────────────
|
|
|
|
func TestChapterNumberFromKey(t *testing.T) {
|
|
cases := []struct {
|
|
key string
|
|
want int
|
|
}{
|
|
// Standard four-segment key.
|
|
{"my-novel/vol-0/1-50/chapter-1.md", 1},
|
|
{"my-novel/vol-0/1-50/chapter-42.md", 42},
|
|
{"my-novel/vol-0/51-100/chapter-99.md", 99},
|
|
// Large chapter numbers.
|
|
{"some-novel/vol-1/1001-1050/chapter-1024.md", 1024},
|
|
// Nested deeper paths should still work (last segment used).
|
|
{"a/b/c/d/chapter-7.md", 7},
|
|
// Malformed / unexpected inputs — should return 0 without panicking.
|
|
{"chapter-notanumber.md", 0},
|
|
{"", 0},
|
|
// No .md extension — TrimSuffix is a no-op; TrimPrefix still strips
|
|
// "chapter-", so the number is parsed successfully.
|
|
{"no-md-extension/chapter-5", 5},
|
|
{"my-novel/vol-0/1-50/chapter-0.md", 0}, // 0 is invalid (chapters are 1-based)
|
|
{"my-novel/vol-0/1-50/chapter--1.md", 0},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
got := chapterNumberFromKey(tc.key)
|
|
if got != tc.want {
|
|
t.Errorf("chapterNumberFromKey(%q) = %d, want %d", tc.key, got, tc.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// ── splitChapterTitle ─────────────────────────────────────────────────────────
|
|
|
|
func TestSplitChapterTitle(t *testing.T) {
|
|
cases := []struct {
|
|
raw string
|
|
wantTitle string
|
|
wantDate string
|
|
}{
|
|
// No date — title is returned as-is.
|
|
{"The Great Battle", "The Great Battle", ""},
|
|
// Leading numeric index is stripped.
|
|
{"42 The Great Battle", "The Great Battle", ""},
|
|
// Relative date with plural unit.
|
|
{"The Storm Arrives 3 days ago", "The Storm Arrives", "3 days ago"},
|
|
// Singular unit.
|
|
{"A New Hope 1 week ago", "A New Hope", "1 week ago"},
|
|
// Minutes and seconds.
|
|
{"Flash Fight 5 minutes ago", "Flash Fight", "5 minutes ago"},
|
|
{"Quick Strike 30 seconds ago", "Quick Strike", "30 seconds ago"},
|
|
// Months and years.
|
|
{"Old Chapter 2 months ago", "Old Chapter", "2 months ago"},
|
|
{"Ancient Story 1 year ago", "Ancient Story", "1 year ago"},
|
|
// Leading index AND trailing date.
|
|
{"5 The Final Chapter 2 hours ago", "The Final Chapter", "2 hours ago"},
|
|
// Extra whitespace.
|
|
{" The Calm ", "The Calm", ""},
|
|
// Empty string.
|
|
{"", "", ""},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
title, date := splitChapterTitle(tc.raw)
|
|
if title != tc.wantTitle || date != tc.wantDate {
|
|
t.Errorf("splitChapterTitle(%q) = (%q, %q), want (%q, %q)",
|
|
tc.raw, title, date, tc.wantTitle, tc.wantDate)
|
|
}
|
|
}
|
|
}
|