package main import ( "context" "net/http" "net/http/httptest" "strings" "testing" ) // Line breaks are the content here — LRC timestamps are per line — so cleanLyrics must not do what // clean() does to a title. func TestCleanLyrics(t *testing.T) { got := cleanLyrics(" [00:11.74] Rivi yksi\r\n[00:13.99] Rivi\x07 kaksi\r\n\n") want := "[00:11.74] Rivi yksi\n[00:13.99] Rivi kaksi" if got != want { t.Fatalf("cleanLyrics gave %q, want %q", got, want) } if n := len([]rune(cleanLyrics(strings.Repeat("a", maxLyrics+500)))); n != maxLyrics { t.Fatalf("truncated to %d runes, want %d", n, maxLyrics) } } // The lookup is a suggestion, so "nothing found" is a normal answer rather than an error, and a // synced hit always beats a plain one. func TestFetchLyrics(t *testing.T) { var lastPath string srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { lastPath = r.URL.Path w.Header().Set("Content-Type", "application/json") switch { case r.URL.Path == "/get" && r.URL.Query().Get("track_name") == "Paranoid": w.Write([]byte(`{"trackName":"Paranoid","artistName":"Black Sabbath","duration":168, "plainLyrics":"plain version","syncedLyrics":"[00:11.74] synced version"}`)) case r.URL.Path == "/get": http.Error(w, `{"code":404}`, http.StatusNotFound) case r.URL.Path == "/search" && strings.Contains(r.URL.Query().Get("q"), "Soittorasia"): // An instrumental and a wrong-length take come first: both must be skipped. w.Write([]byte(`[{"trackName":"Soittorasia","duration":200,"instrumental":true, "plainLyrics":"","syncedLyrics":"[00:01.00] should be skipped"}, {"trackName":"Soittorasia","duration":600, "plainLyrics":"wrong length take"}, {"trackName":"Soittorasia","duration":201, "plainLyrics":"right one"}]`)) default: w.Write([]byte(`[]`)) } })) defer srv.Close() old := lrclibBase lrclibBase = srv.URL defer func() { lrclibBase = old }() ctx := context.Background() got, err := fetchLyrics(ctx, "Paranoid", "Black Sabbath", 168) if err != nil { t.Fatal(err) } if got != "[00:11.74] synced version" { t.Fatalf("exact match returned %q, want the synced version", got) } got, err = fetchLyrics(ctx, "Soittorasia", "Joku", 200) if err != nil { t.Fatal(err) } if got != "right one" { t.Fatalf("search fallback returned %q — instrumental and wrong-length takes must be skipped", got) } if lastPath != "/search" { t.Fatalf("last request was %s, want the search fallback", lastPath) } // Nothing found is not an error: the submitter simply types their own. got, err = fetchLyrics(ctx, "Ei olemassa", "Kukaan", 100) if err != nil || got != "" { t.Fatalf("miss returned %q, %v — want empty and no error", got, err) } // No title means nothing to match on, and no request at all. if got, err := fetchLyrics(ctx, "", "Artisti", 100); err != nil || got != "" { t.Fatalf("empty title returned %q, %v", got, err) } }