navidrome/plugins/lyrics_adapter_test.go
Deluan 873c41b465 test(plugins): validate plugin lyrics auto-detect across all formats
The test-lyrics WASM plugin now supports per-format modes via the
"format" config key: ttml, srt, yaml, lrc, and plain, in addition to
the existing default plain-text response. The plugin is rebuilt with the
standard Go wasip1 compiler.

lyrics_adapter_test.go gains a DescribeTable covering all five formats,
asserting both Synced (the discriminator that proves correct format
detection) and the exact line value. This validates the full
auto-detect chain (TTML → SRT → YAML/Lyricsfile → LRC → plain) end-to-end
through the real plugin → adapter → parser flow.
2026-06-19 14:26:52 -04:00

125 lines
4.1 KiB
Go

//go:build !windows
package plugins
import (
"github.com/navidrome/navidrome/model"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
var _ = Describe("LyricsPlugin", Ordered, func() {
var (
lyricsManager *Manager
provider *LyricsPlugin
)
BeforeAll(func() {
lyricsManager, _ = createTestManagerWithPlugins(nil,
"test-lyrics"+PackageExtension,
"test-metadata-agent"+PackageExtension,
)
p, ok := lyricsManager.LoadLyricsProvider("test-lyrics")
Expect(ok).To(BeTrue())
provider = p.(*LyricsPlugin)
})
Describe("LoadLyricsProvider", func() {
It("returns a lyrics provider for a plugin with Lyrics capability", func() {
Expect(provider).ToNot(BeNil())
})
It("returns false for a plugin without Lyrics capability", func() {
_, ok := lyricsManager.LoadLyricsProvider("test-metadata-agent")
Expect(ok).To(BeFalse())
})
It("returns false for non-existent plugin", func() {
_, ok := lyricsManager.LoadLyricsProvider("non-existent")
Expect(ok).To(BeFalse())
})
})
Describe("GetLyrics", func() {
It("successfully returns lyrics from the plugin", func() {
track := &model.MediaFile{
ID: "track-1",
Title: "Test Song",
Artist: "Test Artist",
}
result, err := provider.GetLyrics(GinkgoT().Context(), track)
Expect(err).ToNot(HaveOccurred())
Expect(result).To(HaveLen(1))
Expect(result[0].Line).ToNot(BeEmpty())
Expect(result[0].Line[0].Value).To(ContainSubstring("Test Song"))
})
It("defaults language to 'xxx' when plugin does not provide one", func() {
manager, _ := createTestManagerWithPlugins(map[string]map[string]string{
"test-lyrics": {"no_lang": "true"},
}, "test-lyrics"+PackageExtension)
p, ok := manager.LoadLyricsProvider("test-lyrics")
Expect(ok).To(BeTrue())
track := &model.MediaFile{ID: "track-1", Title: "Test Song", Artist: "Test Artist"}
result, err := p.GetLyrics(GinkgoT().Context(), track)
Expect(err).ToNot(HaveOccurred())
Expect(result).To(HaveLen(1))
Expect(result[0].Lang).To(Equal("xxx"))
})
It("returns error when plugin returns error", func() {
manager, _ := createTestManagerWithPlugins(map[string]map[string]string{
"test-lyrics": {"error": "service unavailable"},
}, "test-lyrics"+PackageExtension)
p, ok := manager.LoadLyricsProvider("test-lyrics")
Expect(ok).To(BeTrue())
track := &model.MediaFile{ID: "track-1", Title: "Test Song"}
_, err := p.GetLyrics(GinkgoT().Context(), track)
Expect(err).To(HaveOccurred())
})
// Each DescribeTable entry proves that the adapter's content-sniffing routes
// the plugin's rich payload to the right parser rather than mangling it as plain text.
DescribeTable("content-sniffs plugin responses across all supported formats",
func(format string, wantSynced bool, wantLine string) {
manager, _ := createTestManagerWithPlugins(map[string]map[string]string{
"test-lyrics": {"format": format},
}, "test-lyrics"+PackageExtension)
p, ok := manager.LoadLyricsProvider("test-lyrics")
Expect(ok).To(BeTrue())
track := &model.MediaFile{ID: "track-1", Title: "Test Song", Artist: "Test Artist"}
result, err := p.GetLyrics(GinkgoT().Context(), track)
Expect(err).ToNot(HaveOccurred())
Expect(result).To(HaveLen(1))
Expect(result[0].Synced).To(Equal(wantSynced), "unexpected Synced value for format %s", format)
Expect(result[0].Line).To(HaveLen(1))
Expect(result[0].Line[0].Value).To(Equal(wantLine))
},
Entry("ttml", "ttml", true, "plugin ttml line"),
Entry("srt", "srt", true, "plugin srt line"),
Entry("yaml", "yaml", true, "plugin yaml line"),
Entry("lrc", "lrc", true, "plugin lrc line"),
Entry("plain", "plain", false, "plugin plain line"),
)
})
Describe("PluginNames", func() {
It("returns plugin names with Lyrics capability", func() {
names := lyricsManager.PluginNames("Lyrics")
Expect(names).To(ContainElement("test-lyrics"))
})
It("does not return metadata agent plugins for Lyrics capability", func() {
names := lyricsManager.PluginNames("Lyrics")
Expect(names).ToNot(ContainElement("test-metadata-agent"))
})
})
})