package rss
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
const testRSS = `
Example Blog
https://example.com
An example blog feed
en-us
Mon, 01 Jan 2024 00:00:00 GMT
-
First Post
https://example.com/first
A short summary
Full content of the first post
]]>
Alice
Sun, 31 Dec 2023 12:00:00 GMT
https://example.com/first
Tech
Go
-
Second Post
https://example.com/second
Another summary
bob@example.com
Mon, 01 Jan 2024 00:00:00 GMT
https://example.com/second
`
func TestParseRSS_Basic(t *testing.T) {
feed, err := parseRSS([]byte(testRSS))
require.NoError(t, err)
assert.Equal(t, "rss2.0", feed.Format)
assert.Equal(t, "Example Blog", feed.Title)
assert.Equal(t, "https://example.com", feed.Link)
assert.Equal(t, "An example blog feed", feed.Description)
assert.Equal(t, "en-us", feed.Language)
assert.Equal(t, "Mon, 01 Jan 2024 00:00:00 GMT", feed.Updated)
assert.Nil(t, feed.Podcast, "non-podcast feed should have nil Podcast")
require.Len(t, feed.Items, 2)
// First item
item0 := feed.Items[0]
assert.Equal(t, "First Post", item0.Title)
assert.Equal(t, "https://example.com/first", item0.Link)
assert.Equal(t, "A short summary", item0.Description)
assert.Equal(t, "Full content of the first post
", item0.Content)
assert.Equal(t, "Alice", item0.Author) // dc:creator preferred
assert.Equal(t, "Sun, 31 Dec 2023 12:00:00 GMT", item0.Published)
assert.Equal(t, "https://example.com/first", item0.GUID)
assert.Equal(t, []string{"Tech", "Go"}, item0.Categories)
require.Len(t, item0.Enclosures, 1)
assert.Equal(t, "https://example.com/audio.mp3", item0.Enclosures[0].URL)
assert.Equal(t, "audio/mpeg", item0.Enclosures[0].Type)
assert.Equal(t, "12345678", item0.Enclosures[0].Length)
assert.Nil(t, item0.Episode)
// Second item
item1 := feed.Items[1]
assert.Equal(t, "Second Post", item1.Title)
assert.Equal(t, "bob@example.com", item1.Author) // fallback to
assert.Empty(t, item1.Categories)
assert.Empty(t, item1.Enclosures)
}
const testPodcast = `
My Awesome Podcast
https://podcast.example.com
A podcast about technology
en
Jane Doe
Weekly tech discussions
Jane Doe
jane@example.com
no
episodic
-
Episode 1: Getting Started
https://podcast.example.com/ep1
Our first episode
Wed, 15 Nov 2023 08:00:00 GMT
https://podcast.example.com/ep1
01:23:45
1
1
full
no
In this episode we discuss getting started with podcasting
-
Trailer
https://podcast.example.com/trailer
Preview of the show
120
trailer
yes
`
func TestParseRSS_Podcast(t *testing.T) {
feed, err := parseRSS([]byte(testPodcast))
require.NoError(t, err)
assert.Equal(t, "rss2.0", feed.Format)
assert.Equal(t, "My Awesome Podcast", feed.Title)
// Podcast metadata
require.NotNil(t, feed.Podcast)
p := feed.Podcast
assert.Equal(t, "Jane Doe", p.Author)
assert.Equal(t, "Weekly tech discussions", p.Summary)
assert.Equal(t, "https://podcast.example.com/cover.jpg", p.Image)
assert.Equal(t, false, p.Explicit)
assert.Equal(t, "episodic", p.Type)
require.NotNil(t, p.Owner)
assert.Equal(t, "Jane Doe", p.Owner.Name)
assert.Equal(t, "jane@example.com", p.Owner.Email)
// Categories: "Technology", "Technology > Podcasting", "Education"
require.Len(t, p.Category, 3)
assert.Equal(t, "Technology", p.Category[0])
assert.Equal(t, "Technology > Podcasting", p.Category[1])
assert.Equal(t, "Education", p.Category[2])
// Episodes
require.Len(t, feed.Items, 2)
ep0 := feed.Items[0]
require.NotNil(t, ep0.Episode)
assert.Equal(t, "01:23:45", ep0.Episode.Duration)
assert.Equal(t, 1, ep0.Episode.Season)
assert.Equal(t, 1, ep0.Episode.Number)
assert.Equal(t, "full", ep0.Episode.Type)
assert.Equal(t, false, ep0.Episode.Explicit)
assert.Equal(t, "https://podcast.example.com/ep1-cover.jpg", ep0.Episode.Image)
assert.Equal(t, "In this episode we discuss getting started with podcasting", ep0.Episode.Summary)
ep1 := feed.Items[1]
require.NotNil(t, ep1.Episode)
assert.Equal(t, "120", ep1.Episode.Duration)
assert.Equal(t, "trailer", ep1.Episode.Type)
assert.Equal(t, true, ep1.Episode.Explicit)
assert.Equal(t, 0, ep1.Episode.Season) // not set
assert.Equal(t, 0, ep1.Episode.Number) // not set
}
func TestParseRSS_MinimalFeed(t *testing.T) {
xml := `
Minimal
https://example.com
Bare minimum
`
feed, err := parseRSS([]byte(xml))
require.NoError(t, err)
assert.Equal(t, "Minimal", feed.Title)
assert.Empty(t, feed.Items)
assert.Nil(t, feed.Podcast)
}
func TestParseRSS_InvalidXML(t *testing.T) {
_, err := parseRSS([]byte(`broken`))
assert.Error(t, err)
}
func TestIsExplicit(t *testing.T) {
assert.True(t, isExplicit("yes"))
assert.True(t, isExplicit("Yes"))
assert.True(t, isExplicit("true"))
assert.True(t, isExplicit("explicit"))
assert.False(t, isExplicit("no"))
assert.False(t, isExplicit("false"))
assert.False(t, isExplicit("clean"))
assert.False(t, isExplicit(""))
}
func TestFirstNonEmpty(t *testing.T) {
assert.Equal(t, "a", firstNonEmpty("a", "b"))
assert.Equal(t, "b", firstNonEmpty("", "b"))
assert.Equal(t, "c", firstNonEmpty("", "", "c"))
assert.Equal(t, "", firstNonEmpty("", ""))
assert.Equal(t, "x", firstNonEmpty(" ", " x "))
}
func TestFlattenCategories(t *testing.T) {
cats := []itunesCategory{
{Text: "Technology", Sub: []itunesCategory{{Text: "Podcasting"}}},
{Text: "Education"},
}
result := flattenCategories(cats)
assert.Equal(t, []string{"Technology", "Technology > Podcasting", "Education"}, result)
}
func TestFlattenCategories_Empty(t *testing.T) {
result := flattenCategories(nil)
assert.Nil(t, result)
}