Files
wehub-resource-sync ead81af521
Deploy to GitHub Pages / deploy (push) Failing after 0s
CI / go (push) Has been cancelled
CI / build (darwin, macos-14) (push) Has been cancelled
CI / build (windows, windows-2025) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:31:13 +08:00

258 lines
6.6 KiB
Go

package resolve
import (
"os"
"path/filepath"
"slices"
"strings"
"testing"
)
func TestCollectAudioFilesSingleFile(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "song.mp3")
if err := os.WriteFile(path, []byte(""), 0o644); err != nil {
t.Fatalf("WriteFile: %v", err)
}
got, err := CollectAudioFiles(path)
if err != nil {
t.Fatalf("CollectAudioFiles: %v", err)
}
if len(got) != 1 || got[0] != path {
t.Errorf("got %v, want [%s]", got, path)
}
}
func TestCollectAudioFilesUnsupportedExt(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "notes.txt")
if err := os.WriteFile(path, []byte(""), 0o644); err != nil {
t.Fatalf("WriteFile: %v", err)
}
got, err := CollectAudioFiles(path)
if err != nil {
t.Fatalf("CollectAudioFiles: %v", err)
}
if got != nil {
t.Errorf("non-audio file should return nil, got %v", got)
}
}
func TestCollectAudioFilesDirectoryWalk(t *testing.T) {
dir := t.TempDir()
paths := []string{
filepath.Join(dir, "a.mp3"),
filepath.Join(dir, "nested", "b.flac"),
filepath.Join(dir, "README.txt"), // ignored
filepath.Join(dir, "nested", "c.wav"),
}
for _, p := range paths {
if err := os.MkdirAll(filepath.Dir(p), 0o755); err != nil {
t.Fatalf("MkdirAll: %v", err)
}
if err := os.WriteFile(p, []byte(""), 0o644); err != nil {
t.Fatalf("WriteFile: %v", err)
}
}
got, err := CollectAudioFiles(dir)
if err != nil {
t.Fatalf("CollectAudioFiles: %v", err)
}
// Expect 3 audio files, sorted.
if len(got) != 3 {
t.Fatalf("got %d files, want 3 — paths=%v", len(got), got)
}
// slices.IsSorted confirms deterministic order.
if !slices.IsSorted(got) {
t.Errorf("files not sorted: %v", got)
}
// README should not be in the result.
for _, p := range got {
if strings.HasSuffix(p, "README.txt") {
t.Errorf("README included in audio files: %v", got)
}
}
}
func TestCollectAudioFilesMissing(t *testing.T) {
_, err := CollectAudioFiles(filepath.Join(t.TempDir(), "nonexistent"))
if err == nil {
t.Error("CollectAudioFiles on missing path should error")
}
}
func TestArgsLocalFile(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "song.mp3")
if err := os.WriteFile(path, []byte(""), 0o644); err != nil {
t.Fatalf("WriteFile: %v", err)
}
got, err := Args([]string{path})
if err != nil {
t.Fatalf("Args: %v", err)
}
if len(got.Tracks) != 1 {
t.Fatalf("got %d tracks, want 1", len(got.Tracks))
}
if got.Tracks[0].Path != path {
t.Errorf("Path = %q, want %q", got.Tracks[0].Path, path)
}
if len(got.Pending) != 0 {
t.Errorf("Pending = %v, want empty", got.Pending)
}
}
func TestArgsLocalDirectory(t *testing.T) {
dir := t.TempDir()
files := []string{"a.mp3", "b.flac", "c.ogg"}
for _, f := range files {
p := filepath.Join(dir, f)
if err := os.WriteFile(p, []byte(""), 0o644); err != nil {
t.Fatalf("WriteFile: %v", err)
}
}
got, err := Args([]string{dir})
if err != nil {
t.Fatalf("Args: %v", err)
}
if len(got.Tracks) != 3 {
t.Fatalf("got %d tracks, want 3", len(got.Tracks))
}
// Results preserve on-disk sort order (CollectAudioFiles sorts).
names := make([]string, len(got.Tracks))
for i, tr := range got.Tracks {
names[i] = filepath.Base(tr.Path)
}
if !slices.IsSorted(names) {
t.Errorf("tracks not sorted: %v", names)
}
}
func TestArgsRemoteFeedURLGoesToPending(t *testing.T) {
// .xml URL is recognised as a feed.
feedURL := "https://example.com/podcast.xml"
got, err := Args([]string{feedURL})
if err != nil {
t.Fatalf("Args: %v", err)
}
if len(got.Pending) != 1 || got.Pending[0] != feedURL {
t.Errorf("Pending = %v, want [%s]", got.Pending, feedURL)
}
if len(got.Tracks) != 0 {
t.Errorf("Tracks should be empty, got %+v", got.Tracks)
}
}
func TestArgsRemoteAudioURLBecomesTrack(t *testing.T) {
audioURL := "https://stream.example.com/song.mp3"
got, err := Args([]string{audioURL})
if err != nil {
t.Fatalf("Args: %v", err)
}
if len(got.Tracks) != 1 {
t.Fatalf("got %d tracks, want 1", len(got.Tracks))
}
if got.Tracks[0].Path != audioURL {
t.Errorf("Path = %q, want %q", got.Tracks[0].Path, audioURL)
}
}
func TestArgsLocalM3U(t *testing.T) {
dir := t.TempDir()
// Write a local m3u that points at a dummy audio file.
audio := filepath.Join(dir, "song.mp3")
if err := os.WriteFile(audio, []byte(""), 0o644); err != nil {
t.Fatalf("WriteFile: %v", err)
}
m3u := filepath.Join(dir, "pl.m3u")
content := `#EXTM3U
#EXTINF:120,My Song
song.mp3
`
if err := os.WriteFile(m3u, []byte(content), 0o644); err != nil {
t.Fatalf("WriteFile: %v", err)
}
got, err := Args([]string{m3u})
if err != nil {
t.Fatalf("Args: %v", err)
}
if len(got.Tracks) != 1 {
t.Fatalf("got %d tracks, want 1", len(got.Tracks))
}
if got.Tracks[0].Title != "My Song" {
t.Errorf("Title = %q, want My Song", got.Tracks[0].Title)
}
}
func TestArgsLocalPLS(t *testing.T) {
dir := t.TempDir()
audio := filepath.Join(dir, "song.mp3")
if err := os.WriteFile(audio, []byte(""), 0o644); err != nil {
t.Fatalf("WriteFile: %v", err)
}
pls := filepath.Join(dir, "pl.pls")
content := "[playlist]\nFile1=" + audio + "\nTitle1=Track 1\nLength1=60\nNumberOfEntries=1\nVersion=2\n"
if err := os.WriteFile(pls, []byte(content), 0o644); err != nil {
t.Fatalf("WriteFile: %v", err)
}
got, err := Args([]string{pls})
if err != nil {
t.Fatalf("Args: %v", err)
}
if len(got.Tracks) != 1 {
t.Fatalf("got %d tracks, want 1", len(got.Tracks))
}
if got.Tracks[0].Title != "Track 1" {
t.Errorf("Title = %q, want Track 1", got.Tracks[0].Title)
}
}
func TestArgsMissingFileErrors(t *testing.T) {
// CollectAudioFiles stat's the path and Args wraps the os.Stat failure
// into "scanning X: ..." — missing paths are surfaced, not swallowed.
path := filepath.Join(t.TempDir(), "ghost.mp3")
_, err := Args([]string{path})
if err == nil {
t.Error("Args for missing file should error")
}
if !strings.Contains(err.Error(), "scanning") {
t.Errorf("error = %q, want to mention 'scanning'", err.Error())
}
}
func TestScanTracksEmpty(t *testing.T) {
got := scanTracks(nil)
if got != nil {
t.Errorf("scanTracks(nil) = %v, want nil", got)
}
got = scanTracks([]string{})
if got != nil {
t.Errorf("scanTracks(empty) = %v, want nil", got)
}
}
func TestScanTracksPreservesOrder(t *testing.T) {
dir := t.TempDir()
paths := make([]string, 12) // more than workers = 8
for i := range paths {
paths[i] = filepath.Join(dir, "a.mp3")
}
tracks := scanTracks(paths)
if len(tracks) != len(paths) {
t.Fatalf("len = %d, want %d", len(tracks), len(paths))
}
for i, tr := range tracks {
if tr.Path != paths[i] {
t.Errorf("tracks[%d].Path = %q, want %q", i, tr.Path, paths[i])
}
}
}