package app
import (
"bytes"
"encoding/xml"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"olexsmir.xyz/x/is"
)
func TestFeedBuilderAddEntryDefaults(t *testing.T) {
feed := NewFeed("test", "feed-id")
feed.AddEntry(FeedEntry{Title: "entry", Content: "body"})
is.Equal(t, 1, len(feed.f.Entries))
entry := feed.f.Entries[0]
is.NotEqual(t, "", entry.ID)
is.NotEqual(t, "", entry.Updated)
}
func TestFeedBuilderBytesAndWriteTo(t *testing.T) {
updated := time.Date(2026, 4, 20, 12, 30, 0, 0, time.UTC)
feed := NewFeed("test", "feed-id", WithFeedSubtitle("subtitle")).AddText("entry", "content", updated)
raw, err := feed.Bytes()
is.Err(t, err, nil)
if !bytes.Contains(raw, []byte("subtitle")) {
t.Fatalf("expected subtitle in serialized feed")
}
var parsed AtomFeed
is.Err(t, xml.Unmarshal(raw, &parsed), nil)
is.Equal(t, "test", parsed.Title)
}
func TestFeedBuilderRender(t *testing.T) {
r := httptest.NewRecorder()
err := NewFeed("test", "feed-id").
Add("entry", "entry-id", "content", time.Date(2026, 4, 20, 8, 0, 0, 0, time.UTC)).
Render(r)
is.Err(t, err, nil)
is.Equal(t, http.StatusOK, r.Code)
if got := r.Header().Get("Content-Type"); !strings.Contains(got, "application/atom+xml") {
t.Fatalf("unexpected content type: %q", got)
}
}
func TestFeedEntryTextContent(t *testing.T) {
feed := NewFeed("test", "feed-id").
AddEntry(FeedEntry{
Title: "text entry",
Content: "plain text content",
ContentType: "text",
Updated: time.Date(2026, 4, 20, 12, 0, 0, 0, time.UTC),
})
raw, err := feed.Bytes()
is.Err(t, err, nil)
if !strings.Contains(string(raw), `plain text content`) {
t.Fatalf("expected text content with type attribute in serialized feed")
}
var parsed AtomFeed
is.Err(t, xml.Unmarshal(raw, &parsed), nil)
is.Equal(t, 1, len(parsed.Entries))
entry := parsed.Entries[0]
is.Equal(t, "text", entry.Content.Type)
is.Equal(t, "plain text content", entry.Content.Value)
}
func TestFeedEntryHtmlContent(t *testing.T) {
htmlContent := "
Hello World
"
feed := NewFeed("test", "feed-id").
AddEntry(FeedEntry{
Title: "html entry",
Content: htmlContent,
ContentType: "html",
Updated: time.Date(2026, 4, 20, 12, 0, 0, 0, time.UTC),
})
raw, err := feed.Bytes()
is.Err(t, err, nil)
if !strings.Contains(string(raw), ``) {
t.Fatalf("expected HTML content with type='html' attribute in serialized feed")
}
var parsed AtomFeed
is.Err(t, xml.Unmarshal(raw, &parsed), nil)
is.Equal(t, 1, len(parsed.Entries))
entry := parsed.Entries[0]
is.Equal(t, "html", entry.Content.Type)
is.Equal(t, htmlContent, entry.Content.Value)
}
func TestFeedMultipleEntriesWithMixedContentTypes(t *testing.T) {
updated := time.Date(2026, 4, 20, 12, 0, 0, 0, time.UTC)
feed := NewFeed("test", "feed-id").
AddEntry(FeedEntry{
Title: "text entry",
Content: "plain text",
ContentType: "text",
Updated: updated,
}).
AddEntry(FeedEntry{
Title: "html entry",
Content: "html content
",
ContentType: "html",
Updated: updated,
}).
AddEntry(FeedEntry{
Title: "default entry",
Content: "default content",
Updated: updated,
})
raw, err := feed.Bytes()
is.Err(t, err, nil)
var parsed AtomFeed
is.Err(t, xml.Unmarshal(raw, &parsed), nil)
is.Equal(t, 3, len(parsed.Entries))
tests := []struct {
name string
expectedType string
expectedText string
}{
{"text entry", "text", "plain text"},
{"html entry", "html", "html content
"},
{"default entry", "text", "default content"},
}
for i, tc := range tests {
is.Equal(t, tc.name, parsed.Entries[i].Title)
is.Equal(t, tc.expectedText, parsed.Entries[i].Content.Value)
is.Equal(t, tc.expectedType, parsed.Entries[i].Content.Type)
}
}